diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..664c5544 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +*.lua text eol=lf +*.md text eol=lf \ No newline at end of file diff --git a/docs/Index.md b/docs/Index.md index 02053b6e..913c042c 100644 --- a/docs/Index.md +++ b/docs/Index.md @@ -1,6 +1,6 @@ -## RedMew Documentation Index - - [Installing and Using the RedMew Scenario](Installation.md) - - [Creating a New Scenario Using the RedMew Framework](NewScenario.md) - -### Scenario Specific Documentation - - [Diggy Installation and Configuration](scenarios/Diggy.md) +## RedMew Documentation Index + - [Installing and Using the RedMew Scenario](Installation.md) + - [Creating a New Scenario Using the RedMew Framework](NewScenario.md) + +### Scenario Specific Documentation + - [Diggy Installation and Configuration](scenarios/Diggy.md) diff --git a/docs/Installation.md b/docs/Installation.md index 663158c9..b462e761 100644 --- a/docs/Installation.md +++ b/docs/Installation.md @@ -1,49 +1,49 @@ -## Installing and Using the RedMew Scenario -Some scenarios have more detailed information, please check [the index](Index.md) before continuing with the generic -RedMew installation. To install the RedMew scenario directly into something playable, [download the -archive](https://github.com/Valansch/RedMew/archive/develop.zip) and take the next step based on your Operating System. - -- **Windows**: extract the the zip file into `%appdata%\Factorio\Scenarios\RedMew` -- **MacOS**: extract the the zip file into `~/Library/Application Support/factorio/Scenarios/RedMew` -- **Linux**: extract the the zip file into `~/.factorio/scenarios/RedMew` - -Make sure it's called RedMew and there's a `control.lua` in the root of that directory. If you are using the RedMew -scenario for a public-facing multi-player server, be sure to provide attribution back to github and keep links to the -Discord, Patreon and website intact. - -> _Note_: these locations are based on the default configuration [defined by -factorio](https://wiki.factorio.com/Application_directory). If your installation is not default, you have to find your -scenarios directory in another way. - -## Generating maps -There are 3 ways to generate maps using our scenario: Vanilla, FactorioMapConverter and Custom Maps. - -### Vanilla -Start the scenario from the scenario menu and you are ready to go. Additionally you can turn features on or off via -[`control.lua`](../control.lua) if desired. - -### Custom Maps -There are many pre-made map modules that can be combined to create a unique map. - -Map module previews can be found in [map_gen/data/.map_previews](../map_gen/data/.map_previews). You can select and -activate a module by removing the `--` in front of the require in [`map_layout.lua`](../map_layout.lua). - -You can mix as many modules as you want, as long as they logically fit together. - -### FactorioMapConverter (Windows only) - -You can generate your own maps from images. First convert the image file into a lua file (For example `image_data.lua`). -Then use our scenario to load the `image_data.lua` file and generate the map from it. - -To create your own map preview: -1. Download the Map Converter [here](https://github.com/grilledham/FactorioMapConverter/releases) to generate the - `image_data.lua`. -2. Place your `image_data.lua` file in the `map_gen/data/presets/` directory. -3. Create new lua file (for example `my_image.lua`) inside the folder `map_gen/presets/`. This file is used to configure - your map (scale, translate etc.). To do this, you can copy `map_gen/presets/template.lua` and replace line 8 to point - to your `image_data.lua` -4. Load your new preset by adding a new line to `map_layout.lua`. This should look similar to this: - ```lua - MAP_GEN = require "map_gen.presets.my_image.lua" - ``` -5. Load the scenario from the scenario menu. +## Installing and Using the RedMew Scenario +Some scenarios have more detailed information, please check [the index](Index.md) before continuing with the generic +RedMew installation. To install the RedMew scenario directly into something playable, [download the +archive](https://github.com/Valansch/RedMew/archive/develop.zip) and take the next step based on your Operating System. + +- **Windows**: extract the the zip file into `%appdata%\Factorio\Scenarios\RedMew` +- **MacOS**: extract the the zip file into `~/Library/Application Support/factorio/Scenarios/RedMew` +- **Linux**: extract the the zip file into `~/.factorio/scenarios/RedMew` + +Make sure it's called RedMew and there's a `control.lua` in the root of that directory. If you are using the RedMew +scenario for a public-facing multi-player server, be sure to provide attribution back to github and keep links to the +Discord, Patreon and website intact. + +> _Note_: these locations are based on the default configuration [defined by +factorio](https://wiki.factorio.com/Application_directory). If your installation is not default, you have to find your +scenarios directory in another way. + +## Generating maps +There are 3 ways to generate maps using our scenario: Vanilla, FactorioMapConverter and Custom Maps. + +### Vanilla +Start the scenario from the scenario menu and you are ready to go. Additionally you can turn features on or off via +[`control.lua`](../control.lua) if desired. + +### Custom Maps +There are many pre-made map modules that can be combined to create a unique map. + +Map module previews can be found in [map_gen/data/.map_previews](../map_gen/data/.map_previews). You can select and +activate a module by removing the `--` in front of the require in [`map_layout.lua`](../map_layout.lua). + +You can mix as many modules as you want, as long as they logically fit together. + +### FactorioMapConverter (Windows only) + +You can generate your own maps from images. First convert the image file into a lua file (For example `image_data.lua`). +Then use our scenario to load the `image_data.lua` file and generate the map from it. + +To create your own map preview: +1. Download the Map Converter [here](https://github.com/grilledham/FactorioMapConverter/releases) to generate the + `image_data.lua`. +2. Place your `image_data.lua` file in the `map_gen/data/presets/` directory. +3. Create new lua file (for example `my_image.lua`) inside the folder `map_gen/presets/`. This file is used to configure + your map (scale, translate etc.). To do this, you can copy `map_gen/presets/template.lua` and replace line 8 to point + to your `image_data.lua` +4. Load your new preset by adding a new line to `map_layout.lua`. This should look similar to this: + ```lua + MAP_GEN = require "map_gen.presets.my_image.lua" + ``` +5. Load the scenario from the scenario menu. diff --git a/docs/NewScenario.md b/docs/NewScenario.md index 87774181..f6b635a2 100644 --- a/docs/NewScenario.md +++ b/docs/NewScenario.md @@ -1,28 +1,28 @@ -## Creating a New Scenario Using the RedMew Framework -To add a new scenario and make it available to everyone that wants to use RedMew, make a Pull Request on github to -request adding your scenario to the repository. - -### Starting From Scratch -Depending on the size of the scenario, it could be desired to have its own dedicated directory. By default a scenario -is added in `map_gen/combined/your_scenario.lua`. - -#### Step 1 -If you're not experienced with git, it's advised to read up on how git works first or ask someone else to help out. To -get your change into the repository, you need to [fork the repository](https://help.github.com/articles/fork-a-repo/) -and eventually make your Pull Request from there. [Clone](https://help.github.com/articles/cloning-a-repository/) the -fork to your local environment and get your favorite IDE or Editor ready. - -#### Step 2 -Small scenarios can go into a single lua file, bigger scenarios might need their own dedicated directory. To follow the -RedMew structure for scenarios, create your scenario file: `map_gen/combined/your_scenario_file.lua`. - -#### Step 3 (Optional) -If you plan on making a bigger scenario, create a directory: `map_gen/combined/your_scenario_file/` where you can place -your scenario specific lua files. - -#### Step 4 -Regardless, the `map_gen/combined/your_scenario_file.lua` file will be the entry point for your scenario and will be -loaded via `map_layout.lua`. Underneath `--combined--`, add your require: `require map_gen.combined.your_scenario_file`. - -When making the Pull Request, make sure to comment the require in `map_layout.lua` as by default it should be off. To -enable debugging and get some extra feedback during development, enable `_DEBUG` in `config.lua`. +## Creating a New Scenario Using the RedMew Framework +To add a new scenario and make it available to everyone that wants to use RedMew, make a Pull Request on github to +request adding your scenario to the repository. + +### Starting From Scratch +Depending on the size of the scenario, it could be desired to have its own dedicated directory. By default a scenario +is added in `map_gen/combined/your_scenario.lua`. + +#### Step 1 +If you're not experienced with git, it's advised to read up on how git works first or ask someone else to help out. To +get your change into the repository, you need to [fork the repository](https://help.github.com/articles/fork-a-repo/) +and eventually make your Pull Request from there. [Clone](https://help.github.com/articles/cloning-a-repository/) the +fork to your local environment and get your favorite IDE or Editor ready. + +#### Step 2 +Small scenarios can go into a single lua file, bigger scenarios might need their own dedicated directory. To follow the +RedMew structure for scenarios, create your scenario file: `map_gen/combined/your_scenario_file.lua`. + +#### Step 3 (Optional) +If you plan on making a bigger scenario, create a directory: `map_gen/combined/your_scenario_file/` where you can place +your scenario specific lua files. + +#### Step 4 +Regardless, the `map_gen/combined/your_scenario_file.lua` file will be the entry point for your scenario and will be +loaded via `map_layout.lua`. Underneath `--combined--`, add your require: `require map_gen.combined.your_scenario_file`. + +When making the Pull Request, make sure to comment the require in `map_layout.lua` as by default it should be off. To +enable debugging and get some extra feedback during development, enable `_DEBUG` in `config.lua`. diff --git a/docs/scenarios/Diggy.md b/docs/scenarios/Diggy.md index b2065d7c..281725ff 100644 --- a/docs/scenarios/Diggy.md +++ b/docs/scenarios/Diggy.md @@ -1,79 +1,79 @@ -## Diggy Installation and Configuration -Diggy is a custom [RedMew](../../README.md) scenario. You start out with nothing but a market, your pick-axe and some -walls [deep, deep in the mine](https://www.youtube.com/watch?v=ov5pxaIbJlM). The goal is to launch a rocket, but be -careful, there's not a lot of space and the mine is unstable! - -- Gameplay: https://www.youtube.com/watch?v=J3lheDK-6Cw -- Time lapse video: https://www.youtube.com/watch?v=4cRsx-wl_fk (By Namelesshunter Gaming) - -> _Note_: Scenarios- also known as soft-mods- are scripted maps. They can be played online without having to download -any mods as the script is included in the map. - -### Scenario Information -The idea of Diggy is similar to vanilla, except that it greatly changes how to build your factory. As you're in a cave, -each rock you dig, each support entity you remove and every tile you mine, can cause a collapse. You can use walls, -stone paths and (refined) concrete floor to increase the strength of your mine and reduce the chance of a collapse. - -Whenever you place or remove a wall for example, the stress level of the area around it (9x9 tiles) will rise or lower. -When a certain threshold is reached, the cave will collapse. You can stop this by quickly placing walls or run away as -fast as you can. Letting the cave collapse _will_ destroy structures below it! The recommended pattern on dirt is to -place a wall every 4th tile. Using stone paths and concrete will increase this to 5 tiles while refined concrete will -make it 6. - -## How to start Diggy for Single-player mode - -#### Step 1 -Download the zip file from -[https://github.com/Valansch/RedMew/archive/develop.zip](https://github.com/Valansch/RedMew/archive/develop.zip) - -#### Step 2 -- **Windows**: extract the the zip file into `%appdata%\Factorio\Scenarios\Diggy` -- **MacOS**: extract the the zip file into `~/Library/Application Support/factorio/Scenarios/Diggy` -- **Linux**: extract the the zip file into `~/.factorio/scenarios/Diggy` - -Make sure it's called Diggy and there's a `control.lua` in the root of that directory. - -> _Note_: these locations are based on the default configuration [defined by -factorio](https://wiki.factorio.com/Application_directory). If your installation is not default, you have to find your -scenarios directory in another way. - -#### Step 3 -Open `map_layout.lua` in that directory and look for `--require "map_gen.combined.diggy"`. -Change this to `require "map_gen.combined.diggy"`, by removing the double dashes. - -#### Step 4 -In factorio start either a local or online game via Scenarios. Select `Diggy` under -`User scenarios` and start it up. - -> _Note:_ Downloading the latest version might not always be a functional version, please consult on discord for a -working version if this is the case. - -#### Step 5 (optional) -Diggy is designed to work for at least 15 players online, working together. It's advised to change the configuration -to adjust the difficulty for your needs. You can find the config in `map_gen/Diggy/Config.lua`. Most options should be -well-explained. For Single-player it's recommend to enable cheats with modified values. You can change the starting -items and some pre-defined cheat values (if cheats are enabled) under the `SetupPlayer` config item. - -## Configuring Diggy - -### Changing or Disabling Biter Spawning -You can find the biter spawning feature in the config file under `AlienSpawner`. If you don't want biters to spawn -according to the Diggy scenario, turn this feature off completely. - -### Disabling Collapses -While one of the core features, it can also be fun to play without. To turn off collapses completely, you can turn off -this feature under `DiggyCaveCollapse`. If you experience performance issues while digging, you can turn off this -feature as well as it can be quite heavy. - -### Configuring Resource Spawning -At the moment, Diggy is not yet using any of the build-in mechanics to spawn resources and you will have to manually add -them. The resource spawning mechanism is quite complex, so don't hesitate to us how to configure it on Discord. Most -basic configuration can be found under `ScatteredResources`. To customize the resource weights, you have to configure -those specifics in the `map_gen/Diggy/Orepattern` directory. Resources are defined with a weight, meaning you can add -your own resources (for example bobs or angels) with a value and the scenario will automatically calculate the proper -spawn chances. - -### Adding Market Items -Items can be configured by adding the desired item under the `MarketExchange` configuration. You only have to define a -level at which it unlocks, a price or prices in case it can cost more, and what the item prototype is. For a list of -items, you can look up each possible item on the [Factorio raw data page](https://wiki.factorio.com/Data.raw#item). +## Diggy Installation and Configuration +Diggy is a custom [RedMew](../../README.md) scenario. You start out with nothing but a market, your pick-axe and some +walls [deep, deep in the mine](https://www.youtube.com/watch?v=ov5pxaIbJlM). The goal is to launch a rocket, but be +careful, there's not a lot of space and the mine is unstable! + +- Gameplay: https://www.youtube.com/watch?v=J3lheDK-6Cw +- Time lapse video: https://www.youtube.com/watch?v=4cRsx-wl_fk (By Namelesshunter Gaming) + +> _Note_: Scenarios- also known as soft-mods- are scripted maps. They can be played online without having to download +any mods as the script is included in the map. + +### Scenario Information +The idea of Diggy is similar to vanilla, except that it greatly changes how to build your factory. As you're in a cave, +each rock you dig, each support entity you remove and every tile you mine, can cause a collapse. You can use walls, +stone paths and (refined) concrete floor to increase the strength of your mine and reduce the chance of a collapse. + +Whenever you place or remove a wall for example, the stress level of the area around it (9x9 tiles) will rise or lower. +When a certain threshold is reached, the cave will collapse. You can stop this by quickly placing walls or run away as +fast as you can. Letting the cave collapse _will_ destroy structures below it! The recommended pattern on dirt is to +place a wall every 4th tile. Using stone paths and concrete will increase this to 5 tiles while refined concrete will +make it 6. + +## How to start Diggy for Single-player mode + +#### Step 1 +Download the zip file from +[https://github.com/Valansch/RedMew/archive/develop.zip](https://github.com/Valansch/RedMew/archive/develop.zip) + +#### Step 2 +- **Windows**: extract the the zip file into `%appdata%\Factorio\Scenarios\Diggy` +- **MacOS**: extract the the zip file into `~/Library/Application Support/factorio/Scenarios/Diggy` +- **Linux**: extract the the zip file into `~/.factorio/scenarios/Diggy` + +Make sure it's called Diggy and there's a `control.lua` in the root of that directory. + +> _Note_: these locations are based on the default configuration [defined by +factorio](https://wiki.factorio.com/Application_directory). If your installation is not default, you have to find your +scenarios directory in another way. + +#### Step 3 +Open `map_layout.lua` in that directory and look for `--require "map_gen.combined.diggy"`. +Change this to `require "map_gen.combined.diggy"`, by removing the double dashes. + +#### Step 4 +In factorio start either a local or online game via Scenarios. Select `Diggy` under +`User scenarios` and start it up. + +> _Note:_ Downloading the latest version might not always be a functional version, please consult on discord for a +working version if this is the case. + +#### Step 5 (optional) +Diggy is designed to work for at least 15 players online, working together. It's advised to change the configuration +to adjust the difficulty for your needs. You can find the config in `map_gen/Diggy/Config.lua`. Most options should be +well-explained. For Single-player it's recommend to enable cheats with modified values. You can change the starting +items and some pre-defined cheat values (if cheats are enabled) under the `SetupPlayer` config item. + +## Configuring Diggy + +### Changing or Disabling Biter Spawning +You can find the biter spawning feature in the config file under `AlienSpawner`. If you don't want biters to spawn +according to the Diggy scenario, turn this feature off completely. + +### Disabling Collapses +While one of the core features, it can also be fun to play without. To turn off collapses completely, you can turn off +this feature under `DiggyCaveCollapse`. If you experience performance issues while digging, you can turn off this +feature as well as it can be quite heavy. + +### Configuring Resource Spawning +At the moment, Diggy is not yet using any of the build-in mechanics to spawn resources and you will have to manually add +them. The resource spawning mechanism is quite complex, so don't hesitate to us how to configure it on Discord. Most +basic configuration can be found under `ScatteredResources`. To customize the resource weights, you have to configure +those specifics in the `map_gen/Diggy/Orepattern` directory. Resources are defined with a weight, meaning you can add +your own resources (for example bobs or angels) with a value and the scenario will automatically calculate the proper +spawn chances. + +### Adding Market Items +Items can be configured by adding the desired item under the `MarketExchange` configuration. You only have to define a +level at which it unlocks, a price or prices in case it can cost more, and what the item prototype is. For a list of +items, you can look up each possible item on the [Factorio raw data page](https://wiki.factorio.com/Data.raw#item). diff --git a/features/report.lua b/features/report.lua index 293c3bf2..2467dae3 100644 --- a/features/report.lua +++ b/features/report.lua @@ -1,360 +1,360 @@ -local Module = {} - -local Gui = require("utils.gui") -local Utils = require("utils.utils"); -local Game = require 'utils.game' - -local report_frame_name = Gui.uid_name() -local report_close_button_name = Gui.uid_name() -local report_tab_button_name = Gui.uid_name() -local jail_offender_button_name = Gui.uid_name() -local report_body_name = Gui.uid_name() -local prefix = '------------------NOTICE-------------------' -local prefix_e = '--------------------------------------------' - -global.reports = {} -global.player_report_data = {} - - -local function draw_report(parent, report_id) - local report = global.reports[report_id] - if report_id == 0 or not report then - parent.add {type = "label", caption="No reports yet."} - return - end - - local reported_player_name = Game.get_player_by_index(report.reported_player_index).name - local reporting_player_name = "<script>" - if report.reporting_player_index then - reporting_player_name = Game.get_player_by_index(report.reporting_player_index).name - end - local time = Utils.format_time(report.tick) - local time_ago = Utils.format_time(game.tick - report.tick) - - local message = report.message - Gui.clear(parent) - - parent.add {type="label", caption="Offender: " .. reported_player_name} - local msg_label_pane = parent.add {type="scroll-pane", vertical_scroll_policy = "auto-and-reserve-space", horizontal_scroll_policy="never"} - msg_label_pane.style.maximal_height = 400 - local msg_label = msg_label_pane.add {type="label", caption="Message: " .. message} - local jail_offender_button = parent.add {type = 'button', name = jail_offender_button_name, caption = 'Jail ' .. reported_player_name} - jail_offender_button.style.height = 24 - jail_offender_button.style.font = 'default-small' - jail_offender_button.style.top_padding = 0 - jail_offender_button.style.bottom_padding = 0 - jail_offender_button.style.left_padding = 0 - jail_offender_button.style.right_padding = 0 - msg_label.style.single_line = false - msg_label.style.maximal_width = 680 - parent.add {type="label", caption=string.format("Time: %s (%s ago)", time, time_ago)} - parent.add {type="label", caption="Reported by: " .. reporting_player_name} -end - -Module.show_reports = function(player) - local reports = global.reports or {} - - local center = player.gui.center - - local report_frame = center[report_frame_name] - if report_frame and report_frame.valid then - Gui.destroy(report_frame) - end - - report_frame = center.add { - type = 'frame', - name = report_frame_name, - direction = 'vertical', - caption = 'User reports' - } - report_frame.style.maximal_width = 700 - player.opened = report_frame - - if #reports > 1 then - local scroll_pane = report_frame.add{type = "scroll-pane", horizontal_scroll_policy = "auto-and-reserve-space", vertical_scroll_policy="never"} - local tab_flow = scroll_pane.add{type="flow"} - for k,report in pairs(reports) do - local button_cell = tab_flow.add{type="flow", caption="reportuid" .. k} - button_cell.add { - type="button", - name=report_tab_button_name, - caption = Game.get_player_by_index(report.reported_player_index).name - } - end - end - local report_body = report_frame.add {type = "scroll-pane", name = report_body_name, horizontal_scroll_policy = "never", vertical_scroll_policy="never"} - report_frame.add {type = 'button', name = report_close_button_name, caption = 'Close'} - - draw_report(report_body, #reports) -end - -function Module.report(reporting_player, reported_player, message) - local player_index - if reporting_player then - player_index = reporting_player.index - end - table.insert(global.reports, {reporting_player_index = player_index, reported_player_index = reported_player.index, message = message, tick = game.tick}) - - local notified = false - for _,p in pairs(game.players) do - if p.admin and p.connected then - p.play_sound{path='utility/tutorial_notice', volume_modifier = 1} - Module.show_reports(p) - if p.afk_time < 3600 then notified = true end - end - end - if not notified then - for _,p in pairs(game.players) do - if p.admin then - Module.show_reports(p) - end - end - end -end - -function Module.cmd_report(cmd) - local reporting_player = game.player - if reporting_player then - local params = {} - for param in string.gmatch(cmd.parameter, '%S+') do - table.insert(params, param) - end - if #params < 2 then - reporting_player.print('Please enter then name of the offender and the reason for the report.') - return nil - end - local reported_player_name = params[1] or '' - local reported_player = game.players[reported_player_name] - - if not reported_player then - reporting_player.print(reported_player_name .. ' does not exist.') - return nil - end - Module.report(reporting_player, reported_player, string.sub(cmd.parameter, string.len(params[1]) + 2)) - end -end - --- Places a target in jail as long as player is admin or server -function Module.jail(target_player, player) - -- Set the name of the jail permission group - local jail_name = 'Jail' - - local print - local jailed_by - if player then - jailed_by = "a server admin" - print = player.print - else - jailed_by = "script for causing too many collapses" - print = log - end - - if not target_player then - print('Unknown player.') - return - end - - local permissions = game.permissions - - -- Check if the permission group exists, if it doesn't, create it. - local permission_group = permissions.get_group(jail_name) - if not permission_group then - permission_group = permissions.create_group(jail_name) - end - - if target_player.permission_group == permission_group then - print('Player ' .. target_player.name .. ' is already in jail.') - return - end - - -- Set all permissions to disabled - for action_name, _ in pairs(defines.input_action) do - permission_group.set_allows_action(defines.input_action[action_name], false) - end - -- Enable writing to console to allow a person to speak - permission_group.set_allows_action(defines.input_action.write_to_console, true) - permission_group.set_allows_action(defines.input_action.edit_permission_group, true) - - -- Kick player out of vehicle - target_player.driving=false - -- Add player to jail group - permission_group.add_player(target_player) - -- If a player is shooting when they're jailed they can't stop shooting, so we change their shooting state - if target_player.shooting_state.state ~= 0 then - target_player.shooting_state.state = {state = defines.shooting.not_shooting, position = {0,0}} - end - - -- Check that it worked - if target_player.permission_group == permission_group then - -- Let admin know it worked, let target know what's going on. - print(target_player.name .. ' has been jailed. They have been advised of this.') - target_player.print(prefix) - target_player.print('You have been placed in jail by ' .. jailed_by .. '. The only action avaliable to you is chatting.') - target_player.print('Please respond to inquiries from the admins.', {r = 1, g = 1, b = 0, a = 1}) - Utils.print_admins(target_player.name .. 'has been jailed by' .. player.name) - Utils.log_command(player, 'jail', target_player.name) - else - -- Let admin know it didn't work. - print('Something went wrong in the jailing of ' .. target_player.name .. '. You can still change their group via /permissions.') - end -end - -function Module.unjail_player(cmd) - local default_group = 'Default' - local player = game.player - -- Check if the player can run the command - if player and not player.admin then - Utils.cant_run(cmd.name) - return - end - -- Check if the target is valid (copied from the invoke command) - local target = cmd['parameter'] - if target == nil then - Game.player_print('Usage: /unjail <player>') - return - end - - local target_player = game.players[target] - if not target_player then - Game.player_print('Unknown player.') - return - end - - local permissions = game.permissions - - -- Check if the permission group exists, if it doesn't, create it. - local permission_group = permissions.get_group(default_group) - if not permission_group then - permission_group = permissions.create_group(default_group) - end - - local jail_permission_group = permissions.get_group('Jail') - if (not jail_permission_group) or target_player.permission_group ~= jail_permission_group then - Game.player_print('The player ' .. target .. ' is already not in Jail.') - return - end - - -- Move player - permission_group.add_player(target) - -- Set player to a non-shooting state (solves a niche case where players jailed while shooting will be locked into a shooting state) - target_player.shooting_state.state = 0 - - -- Check that it worked - if target_player.permission_group == permission_group then - -- Let admin know it worked, let target know what's going on. - Game.player_print(target .. ' has been returned to the default group. They have been advised of this.') - target_player.print(prefix) - target_player.print('Your ability to perform actions has been restored', {r = 0, g = 1, b = 0, a = 1}) - target_player.print(prefix_e) - else - -- Let admin know it didn't work. - Game.player_print( - 'Something went wrong in the unjailing of ' .. - target .. '. You can still change their group via /permissions and inform them.' - ) - end -end - -Gui.on_custom_close( - report_frame_name, - function(event) - Gui.destroy(event.element) - end -) - -Gui.on_click( - report_close_button_name, - function(event) - Gui.destroy(event.element.parent) - end -) - -Gui.on_click( - jail_offender_button_name, - function(event) - local target_name = string.sub(event.element.caption, 6) - local target = game.players[target_name] - Module.jail(target, event.player) - end -) - -Gui.on_click( - report_tab_button_name, - function(event) - local center = event.player.gui.center - local report_frame = center[report_frame_name] - local report_uid_str = string.sub(event.element.parent.caption, 10) - local report_uid = tonumber(report_uid_str) - draw_report(report_frame[report_body_name], report_uid) - end -) - - -local reporting_popup_name = Gui.uid_name() -local reporting_cancel_button_name = Gui.uid_name() -local reporting_submit_button_name = Gui.uid_name() -local reporting_input_name = Gui.uid_name() - -Module.spawn_reporting_popup = function(player, reported_player) - - local center = player.gui.center - - local reporting_popup = center[reporting_popup_name] - if reporting_popup and reporting_popup.valid then - Gui.destroy(reporting_popup) - end - reporting_popup = center.add { - type = 'frame', - name = reporting_popup_name, - direction = 'vertical', - caption = 'Report player ' .. reported_player.name - } - Gui.set_data(reporting_popup, {reported_player_index = reported_player.index}) - - reporting_popup.style.maximal_width = 500 - player.opened = reporting_popup - reporting_popup.add { - type = 'label', - caption = 'Report message:' - } - local input = reporting_popup.add {type = 'text-box', name=reporting_input_name} - input.style.width = 400 - input.style.height = 85 - local button_flow = reporting_popup.add {type = "flow"} - button_flow.add {type = "button", name = reporting_submit_button_name, caption="Submit"} - button_flow.add {type = "button", name = reporting_cancel_button_name, caption="Cancel"} -end - -Gui.on_custom_close( - reporting_popup_name, - function(event) - Gui.destroy(event.element) - end -) - -Gui.on_click( - reporting_cancel_button_name, - function(event) - local frame = event.element.parent.parent - Gui.destroy(frame) - end -) - -Gui.on_click( - reporting_submit_button_name, - function(event) - local frame = event.element.parent.parent - local msg = frame[reporting_input_name].text - local data = Gui.get_data(frame) - local reported_player_index = data["reported_player_index"] - local print = event.player.print - - Gui.destroy(frame) - Module.report(event.player, Game.get_player_by_index(reported_player_index), msg) - print(prefix) - print("You have successfully reported the player: " .. Game.get_player_by_index(reported_player_index).name) - print(prefix_e) - end -) - -return Module +local Module = {} + +local Gui = require("utils.gui") +local Utils = require("utils.utils"); +local Game = require 'utils.game' + +local report_frame_name = Gui.uid_name() +local report_close_button_name = Gui.uid_name() +local report_tab_button_name = Gui.uid_name() +local jail_offender_button_name = Gui.uid_name() +local report_body_name = Gui.uid_name() +local prefix = '------------------NOTICE-------------------' +local prefix_e = '--------------------------------------------' + +global.reports = {} +global.player_report_data = {} + + +local function draw_report(parent, report_id) + local report = global.reports[report_id] + if report_id == 0 or not report then + parent.add {type = "label", caption="No reports yet."} + return + end + + local reported_player_name = Game.get_player_by_index(report.reported_player_index).name + local reporting_player_name = "<script>" + if report.reporting_player_index then + reporting_player_name = Game.get_player_by_index(report.reporting_player_index).name + end + local time = Utils.format_time(report.tick) + local time_ago = Utils.format_time(game.tick - report.tick) + + local message = report.message + Gui.clear(parent) + + parent.add {type="label", caption="Offender: " .. reported_player_name} + local msg_label_pane = parent.add {type="scroll-pane", vertical_scroll_policy = "auto-and-reserve-space", horizontal_scroll_policy="never"} + msg_label_pane.style.maximal_height = 400 + local msg_label = msg_label_pane.add {type="label", caption="Message: " .. message} + local jail_offender_button = parent.add {type = 'button', name = jail_offender_button_name, caption = 'Jail ' .. reported_player_name} + jail_offender_button.style.height = 24 + jail_offender_button.style.font = 'default-small' + jail_offender_button.style.top_padding = 0 + jail_offender_button.style.bottom_padding = 0 + jail_offender_button.style.left_padding = 0 + jail_offender_button.style.right_padding = 0 + msg_label.style.single_line = false + msg_label.style.maximal_width = 680 + parent.add {type="label", caption=string.format("Time: %s (%s ago)", time, time_ago)} + parent.add {type="label", caption="Reported by: " .. reporting_player_name} +end + +Module.show_reports = function(player) + local reports = global.reports or {} + + local center = player.gui.center + + local report_frame = center[report_frame_name] + if report_frame and report_frame.valid then + Gui.destroy(report_frame) + end + + report_frame = center.add { + type = 'frame', + name = report_frame_name, + direction = 'vertical', + caption = 'User reports' + } + report_frame.style.maximal_width = 700 + player.opened = report_frame + + if #reports > 1 then + local scroll_pane = report_frame.add{type = "scroll-pane", horizontal_scroll_policy = "auto-and-reserve-space", vertical_scroll_policy="never"} + local tab_flow = scroll_pane.add{type="flow"} + for k,report in pairs(reports) do + local button_cell = tab_flow.add{type="flow", caption="reportuid" .. k} + button_cell.add { + type="button", + name=report_tab_button_name, + caption = Game.get_player_by_index(report.reported_player_index).name + } + end + end + local report_body = report_frame.add {type = "scroll-pane", name = report_body_name, horizontal_scroll_policy = "never", vertical_scroll_policy="never"} + report_frame.add {type = 'button', name = report_close_button_name, caption = 'Close'} + + draw_report(report_body, #reports) +end + +function Module.report(reporting_player, reported_player, message) + local player_index + if reporting_player then + player_index = reporting_player.index + end + table.insert(global.reports, {reporting_player_index = player_index, reported_player_index = reported_player.index, message = message, tick = game.tick}) + + local notified = false + for _,p in pairs(game.players) do + if p.admin and p.connected then + p.play_sound{path='utility/tutorial_notice', volume_modifier = 1} + Module.show_reports(p) + if p.afk_time < 3600 then notified = true end + end + end + if not notified then + for _,p in pairs(game.players) do + if p.admin then + Module.show_reports(p) + end + end + end +end + +function Module.cmd_report(cmd) + local reporting_player = game.player + if reporting_player then + local params = {} + for param in string.gmatch(cmd.parameter, '%S+') do + table.insert(params, param) + end + if #params < 2 then + reporting_player.print('Please enter then name of the offender and the reason for the report.') + return nil + end + local reported_player_name = params[1] or '' + local reported_player = game.players[reported_player_name] + + if not reported_player then + reporting_player.print(reported_player_name .. ' does not exist.') + return nil + end + Module.report(reporting_player, reported_player, string.sub(cmd.parameter, string.len(params[1]) + 2)) + end +end + +-- Places a target in jail as long as player is admin or server +function Module.jail(target_player, player) + -- Set the name of the jail permission group + local jail_name = 'Jail' + + local print + local jailed_by + if player then + jailed_by = "a server admin" + print = player.print + else + jailed_by = "script for causing too many collapses" + print = log + end + + if not target_player then + print('Unknown player.') + return + end + + local permissions = game.permissions + + -- Check if the permission group exists, if it doesn't, create it. + local permission_group = permissions.get_group(jail_name) + if not permission_group then + permission_group = permissions.create_group(jail_name) + end + + if target_player.permission_group == permission_group then + print('Player ' .. target_player.name .. ' is already in jail.') + return + end + + -- Set all permissions to disabled + for action_name, _ in pairs(defines.input_action) do + permission_group.set_allows_action(defines.input_action[action_name], false) + end + -- Enable writing to console to allow a person to speak + permission_group.set_allows_action(defines.input_action.write_to_console, true) + permission_group.set_allows_action(defines.input_action.edit_permission_group, true) + + -- Kick player out of vehicle + target_player.driving=false + -- Add player to jail group + permission_group.add_player(target_player) + -- If a player is shooting when they're jailed they can't stop shooting, so we change their shooting state + if target_player.shooting_state.state ~= 0 then + target_player.shooting_state.state = {state = defines.shooting.not_shooting, position = {0,0}} + end + + -- Check that it worked + if target_player.permission_group == permission_group then + -- Let admin know it worked, let target know what's going on. + print(target_player.name .. ' has been jailed. They have been advised of this.') + target_player.print(prefix) + target_player.print('You have been placed in jail by ' .. jailed_by .. '. The only action avaliable to you is chatting.') + target_player.print('Please respond to inquiries from the admins.', {r = 1, g = 1, b = 0, a = 1}) + Utils.print_admins(target_player.name .. 'has been jailed by' .. player.name) + Utils.log_command(player, 'jail', target_player.name) + else + -- Let admin know it didn't work. + print('Something went wrong in the jailing of ' .. target_player.name .. '. You can still change their group via /permissions.') + end +end + +function Module.unjail_player(cmd) + local default_group = 'Default' + local player = game.player + -- Check if the player can run the command + if player and not player.admin then + Utils.cant_run(cmd.name) + return + end + -- Check if the target is valid (copied from the invoke command) + local target = cmd['parameter'] + if target == nil then + Game.player_print('Usage: /unjail <player>') + return + end + + local target_player = game.players[target] + if not target_player then + Game.player_print('Unknown player.') + return + end + + local permissions = game.permissions + + -- Check if the permission group exists, if it doesn't, create it. + local permission_group = permissions.get_group(default_group) + if not permission_group then + permission_group = permissions.create_group(default_group) + end + + local jail_permission_group = permissions.get_group('Jail') + if (not jail_permission_group) or target_player.permission_group ~= jail_permission_group then + Game.player_print('The player ' .. target .. ' is already not in Jail.') + return + end + + -- Move player + permission_group.add_player(target) + -- Set player to a non-shooting state (solves a niche case where players jailed while shooting will be locked into a shooting state) + target_player.shooting_state.state = 0 + + -- Check that it worked + if target_player.permission_group == permission_group then + -- Let admin know it worked, let target know what's going on. + Game.player_print(target .. ' has been returned to the default group. They have been advised of this.') + target_player.print(prefix) + target_player.print('Your ability to perform actions has been restored', {r = 0, g = 1, b = 0, a = 1}) + target_player.print(prefix_e) + else + -- Let admin know it didn't work. + Game.player_print( + 'Something went wrong in the unjailing of ' .. + target .. '. You can still change their group via /permissions and inform them.' + ) + end +end + +Gui.on_custom_close( + report_frame_name, + function(event) + Gui.destroy(event.element) + end +) + +Gui.on_click( + report_close_button_name, + function(event) + Gui.destroy(event.element.parent) + end +) + +Gui.on_click( + jail_offender_button_name, + function(event) + local target_name = string.sub(event.element.caption, 6) + local target = game.players[target_name] + Module.jail(target, event.player) + end +) + +Gui.on_click( + report_tab_button_name, + function(event) + local center = event.player.gui.center + local report_frame = center[report_frame_name] + local report_uid_str = string.sub(event.element.parent.caption, 10) + local report_uid = tonumber(report_uid_str) + draw_report(report_frame[report_body_name], report_uid) + end +) + + +local reporting_popup_name = Gui.uid_name() +local reporting_cancel_button_name = Gui.uid_name() +local reporting_submit_button_name = Gui.uid_name() +local reporting_input_name = Gui.uid_name() + +Module.spawn_reporting_popup = function(player, reported_player) + + local center = player.gui.center + + local reporting_popup = center[reporting_popup_name] + if reporting_popup and reporting_popup.valid then + Gui.destroy(reporting_popup) + end + reporting_popup = center.add { + type = 'frame', + name = reporting_popup_name, + direction = 'vertical', + caption = 'Report player ' .. reported_player.name + } + Gui.set_data(reporting_popup, {reported_player_index = reported_player.index}) + + reporting_popup.style.maximal_width = 500 + player.opened = reporting_popup + reporting_popup.add { + type = 'label', + caption = 'Report message:' + } + local input = reporting_popup.add {type = 'text-box', name=reporting_input_name} + input.style.width = 400 + input.style.height = 85 + local button_flow = reporting_popup.add {type = "flow"} + button_flow.add {type = "button", name = reporting_submit_button_name, caption="Submit"} + button_flow.add {type = "button", name = reporting_cancel_button_name, caption="Cancel"} +end + +Gui.on_custom_close( + reporting_popup_name, + function(event) + Gui.destroy(event.element) + end +) + +Gui.on_click( + reporting_cancel_button_name, + function(event) + local frame = event.element.parent.parent + Gui.destroy(frame) + end +) + +Gui.on_click( + reporting_submit_button_name, + function(event) + local frame = event.element.parent.parent + local msg = frame[reporting_input_name].text + local data = Gui.get_data(frame) + local reported_player_index = data["reported_player_index"] + local print = event.player.print + + Gui.destroy(frame) + Module.report(event.player, Game.get_player_by_index(reported_player_index), msg) + print(prefix) + print("You have successfully reported the player: " .. Game.get_player_by_index(reported_player_index).name) + print(prefix_e) + end +) + +return Module diff --git a/map_gen/Diggy/AlienEvolutionProgress.lua b/map_gen/Diggy/AlienEvolutionProgress.lua index 7570fe29..5f3950c4 100644 --- a/map_gen/Diggy/AlienEvolutionProgress.lua +++ b/map_gen/Diggy/AlienEvolutionProgress.lua @@ -1,159 +1,159 @@ ---[[-- info - Original (javascript) version: https://hastebin.com/udakacavap.js - Can be tested against: https://wiki.factorio.com/Enemies#Spawn_chances_by_evolution_factor -]] - --- dependencies -local Global = require 'utils.global' -local random = math.random -local round = math.round - --- this -local AlienEvolutionProgress = {} - -local alien_cache = { - biters = { - evolution = -1, - cache = {}, - }, - spitters = { - evolution = -1, - cache = {}, - }, -} - -Global.register({ - alien_cache = alien_cache, -}, function(tbl) - alien_cache = tbl.alien_cache -end) - --- values are in the form {evolution, weight} -local biters = { - {'small-biter', {{0.0, 0.3}, {0.6, 0.0}}}, - {'medium-biter', {{0.2, 0.0}, {0.6, 0.3}, {0.7, 0.1}}}, - {'big-biter', {{0.5, 0.0}, {1.0, 0.4}}}, - {'behemoth-biter', {{0.9, 0.0}, {1.0, 0.3}}}, -} - -local spitters = { - {'small-biter', {{0.0, 0.3}, {0.35, 0.0}}}, - {'small-spitter', {{0.25, 0.0}, {0.5, 0.3}, {0.7, 0.0}}}, - {'medium-spitter', {{0.4, 0.0}, {0.7, 0.3}, {0.9, 0.1}}}, - {'big-spitter', {{0.5, 0.0}, {1.0, 0.4}}}, - {'behemoth-spitter', {{0.9, 0.0}, {1.0, 0.3}}}, -} - -local function lerp(low, high, pos) - local s = high[1] - low[1]; - local l = (pos - low[1]) / s; - return (low[2] * (1 - l)) + (high[2] * l) -end - -local function get_values(map, evo) - local result = {} - local sum = 0 - - for _, data in pairs(map) do - local list = data[2]; - local low = list[1]; - local high = list[#list]; - - for _, val in pairs(list) do - if(val[1] <= evo and val[1] > low[1]) then - low = val; - end - if(val[1] >= evo and val[1] < high[1]) then - high = val - end - end - - local val - if (evo <= low[1]) then - val = low[2] - elseif (evo >= high[1]) then - val = high[2]; - else - val = lerp(low, high, evo) - end - sum = sum + val; - - result[data[1]] = val; - end - - for index, _ in pairs(result) do - result[index] = result[index] / sum - end - - return result; -end - -local function get_name_by_random(collection) - local pre_calculated = random() - local current = 0 - - for name, probability in pairs(collection) do - current = current + probability - if (current >= pre_calculated) then - return name - end - end - - Debug.print('AlienEvolutionProgress.get_name_by_random: Current \'' .. current .. '\' should be higher or equal to random \'' .. pre_calculated .. '\'') -end - -function AlienEvolutionProgress.getBiterValues(evolution) - local evolution_value = round(evolution * 100) - - if (alien_cache.biters.evolution < evolution_value) then - alien_cache.biters.evolution = evolution_value - alien_cache.biters.cache = get_values(biters, evolution) - end - - return alien_cache.biters.cache -end - -function AlienEvolutionProgress.getSpitterValues(evolution) - local evolution_value = round(evolution * 100) - - if (alien_cache.spitters.evolution < evolution_value) then - alien_cache.spitters.evolution = evolution_value - alien_cache.spitters.cache = get_values(spitters, evolution) - end - - return alien_cache.spitters.cache -end - -function AlienEvolutionProgress.getBitersByEvolution(total_biters, evolution) - local biters_calculated = {} - local map = AlienEvolutionProgress.getBiterValues(evolution) - - for i = 1, total_biters do - local name = get_name_by_random(map) - if (nil == biters_calculated[name]) then - biters_calculated[name] = 1 - else - biters_calculated[name] = biters_calculated[name] + 1 - end - end - - return biters_calculated -end - -function AlienEvolutionProgress.getSpittersByEvolution(total_spitters, evolution) - local spitters_calculated = {} - local map = AlienEvolutionProgress.getSpitterValues(evolution) - - for i = 1, total_spitters do - local name = get_name_by_random(map) - if (nil == spitters_calculated[name]) then - spitters_calculated[name] = 1 - else - spitters_calculated[name] = spitters_calculated[name] + 1 - end - end - - return spitters_calculated -end - -return AlienEvolutionProgress +--[[-- info + Original (javascript) version: https://hastebin.com/udakacavap.js + Can be tested against: https://wiki.factorio.com/Enemies#Spawn_chances_by_evolution_factor +]] + +-- dependencies +local Global = require 'utils.global' +local random = math.random +local round = math.round + +-- this +local AlienEvolutionProgress = {} + +local alien_cache = { + biters = { + evolution = -1, + cache = {}, + }, + spitters = { + evolution = -1, + cache = {}, + }, +} + +Global.register({ + alien_cache = alien_cache, +}, function(tbl) + alien_cache = tbl.alien_cache +end) + +-- values are in the form {evolution, weight} +local biters = { + {'small-biter', {{0.0, 0.3}, {0.6, 0.0}}}, + {'medium-biter', {{0.2, 0.0}, {0.6, 0.3}, {0.7, 0.1}}}, + {'big-biter', {{0.5, 0.0}, {1.0, 0.4}}}, + {'behemoth-biter', {{0.9, 0.0}, {1.0, 0.3}}}, +} + +local spitters = { + {'small-biter', {{0.0, 0.3}, {0.35, 0.0}}}, + {'small-spitter', {{0.25, 0.0}, {0.5, 0.3}, {0.7, 0.0}}}, + {'medium-spitter', {{0.4, 0.0}, {0.7, 0.3}, {0.9, 0.1}}}, + {'big-spitter', {{0.5, 0.0}, {1.0, 0.4}}}, + {'behemoth-spitter', {{0.9, 0.0}, {1.0, 0.3}}}, +} + +local function lerp(low, high, pos) + local s = high[1] - low[1]; + local l = (pos - low[1]) / s; + return (low[2] * (1 - l)) + (high[2] * l) +end + +local function get_values(map, evo) + local result = {} + local sum = 0 + + for _, data in pairs(map) do + local list = data[2]; + local low = list[1]; + local high = list[#list]; + + for _, val in pairs(list) do + if(val[1] <= evo and val[1] > low[1]) then + low = val; + end + if(val[1] >= evo and val[1] < high[1]) then + high = val + end + end + + local val + if (evo <= low[1]) then + val = low[2] + elseif (evo >= high[1]) then + val = high[2]; + else + val = lerp(low, high, evo) + end + sum = sum + val; + + result[data[1]] = val; + end + + for index, _ in pairs(result) do + result[index] = result[index] / sum + end + + return result; +end + +local function get_name_by_random(collection) + local pre_calculated = random() + local current = 0 + + for name, probability in pairs(collection) do + current = current + probability + if (current >= pre_calculated) then + return name + end + end + + Debug.print('AlienEvolutionProgress.get_name_by_random: Current \'' .. current .. '\' should be higher or equal to random \'' .. pre_calculated .. '\'') +end + +function AlienEvolutionProgress.getBiterValues(evolution) + local evolution_value = round(evolution * 100) + + if (alien_cache.biters.evolution < evolution_value) then + alien_cache.biters.evolution = evolution_value + alien_cache.biters.cache = get_values(biters, evolution) + end + + return alien_cache.biters.cache +end + +function AlienEvolutionProgress.getSpitterValues(evolution) + local evolution_value = round(evolution * 100) + + if (alien_cache.spitters.evolution < evolution_value) then + alien_cache.spitters.evolution = evolution_value + alien_cache.spitters.cache = get_values(spitters, evolution) + end + + return alien_cache.spitters.cache +end + +function AlienEvolutionProgress.getBitersByEvolution(total_biters, evolution) + local biters_calculated = {} + local map = AlienEvolutionProgress.getBiterValues(evolution) + + for i = 1, total_biters do + local name = get_name_by_random(map) + if (nil == biters_calculated[name]) then + biters_calculated[name] = 1 + else + biters_calculated[name] = biters_calculated[name] + 1 + end + end + + return biters_calculated +end + +function AlienEvolutionProgress.getSpittersByEvolution(total_spitters, evolution) + local spitters_calculated = {} + local map = AlienEvolutionProgress.getSpitterValues(evolution) + + for i = 1, total_spitters do + local name = get_name_by_random(map) + if (nil == spitters_calculated[name]) then + spitters_calculated[name] = 1 + else + spitters_calculated[name] = spitters_calculated[name] + 1 + end + end + + return spitters_calculated +end + +return AlienEvolutionProgress diff --git a/map_gen/Diggy/Debug.lua b/map_gen/Diggy/Debug.lua index aa977634..eb4dfff4 100644 --- a/map_gen/Diggy/Debug.lua +++ b/map_gen/Diggy/Debug.lua @@ -1,224 +1,224 @@ --- dependencies -local min = math.min -local max = math.max -local floor = math.floor -local abs = math.abs - --- this -local Debug = {} - --- private state -local debug = false -local cheats = false - -function Debug.enable_debug() - debug = true -end - -function Debug.disable_debug() - debug = false -end - -function Debug.enable_cheats() - cheats = true -end - -function Debug.disable_cheats() - cheats = true -end - -global.message_count = 0 - ---[[-- - Shows the given message if debug is enabled. - - @param message string -]] -function Debug.print(message) - if type(message) ~= 'string' and type(message) ~= 'number' and type(message) ~= 'boolean' then message = type(message) end - global.message_count = global.message_count + 1 - if (debug) then - game.print('[' .. global.message_count .. '] ' .. tostring(message)) - log('[' .. global.message_count .. '] ' .. tostring(message)) - end -end - ---[[-- - Shows the given message with serpent enabled, if debug is enabled. - - @param message string -]] -function Debug.print_serpent(message) - Debug.print(serpent.line(message)) -end - ---[[-- - Shows the given message if _DEBUG == true for a given position. - - @param x number - @param y number - @param message string -]] -function Debug.print_position(position, message) - message = message or '' - if type(message) ~= 'string' and type(message) ~= 'number' and type(message) ~= 'boolean' then message = type(message) end - global.message_count = global.message_count + 1 - if (debug) then - game.print('[' .. global.message_count .. '] {x=' .. position.x .. ', y=' .. position.y .. '} ' .. tostring(message)) - end -end - ---[[-- - Executes the given callback if cheating is enabled. - - @param callback function -]] -function Debug.cheat(callback) - if (cheats) then - callback() - end -end - ---[[-- - Prints a colored value on a location. - - @param value between -1 and 1 - @param surface LuaSurface - @param position Position {x, y} - @param scale float - @param offset float - @param immutable bool if immutable, only set, never do a surface lookup, values never change -]] -function Debug.print_grid_value(value, surface, position, scale, offset, immutable) - local is_string = type(value) == 'string' - local color = {r = 1, g = 1, b = 1} - text = value - - if type(immutable) ~= 'boolean' then - immutable = false - end - - if not is_string then - scale = scale or 1 - offset = offset or 0 - position = {x = position.x + offset, y = position.y + offset} - local r = max(1, value) / scale - local g = 1 - abs(value) / scale - local b = min(1, value) / scale - - if (r > 0) then - r = 0 - end - - if (b < 0) then - b = 0 - end - - if (g < 0) then - g = 0 - end - - r = abs(r) - - color = { r = r, g = g, b = b} - - -- round at precision of 2 - text = floor(100 * value) * 0.01 - - if (0 == text) then - text = '0.00' - end - end - - if not immutable then - local text_entity = surface.find_entity('flying-text', position) - - if text_entity then - text_entity.text = text - text_entity.color = color - return - end - end - - surface.create_entity{ - name = 'flying-text', - color = color, - text = text, - position = position - }.active = false -end - ---[[-- - Prints a colored value on a location. When given a color_value and a delta_color, - will change the color of the text from the base to base + value * delta. This will - make the color of the text range from 'base_color' to 'base_color + delta_color' - as the color_value ranges from 0 to 1 - - @param value of number to be displayed - @param surface LuaSurface - @param position Position {x, y} - @param scale float - @param offset float position offset - @param immutable bool if immutable, only set, never do a surface lookup, values never change - @param color_value float How far along the range of values of colors the value is to be displayed - @param base_color {r,g,b} The color for the text to be if color_value is 0 - @param delta_color {r,g,b} The amount to correct the base_color if color_value is 1 - @param under_bound {r,g,b} The color to be used if color_value < 0 - @param over_bound {r,g,b} The color to be used if color_value > 1 -]] -function Debug.print_colored_grid_value(value, surface, position, scale, offset, immutable, - color_value, base_color, delta_color, under_bound, over_bound) - local is_string = type(value) == 'string' - -- default values: - local color = base_color or {r = 1, g = 1, b = 1} - local d_color = delta_color or {r = 0, g = 0, b = 0} - local u_color = under_bound or color - local o_color = over_bound or color - - if (color_value < 0) then - color = u_color - elseif (color_value > 1) then - color = o_color - else - color = { r = color.r + color_value * d_color.r, - g = color.g + color_value * d_color.g, - b = color.b + color_value * d_color.b } - end - - text = value - - if type(immutable) ~= 'boolean' then - immutable = false - end - - if not is_string then - offset = offset or 0 - position = {x = position.x + offset, y = position.y + offset} - - -- round at precision of 2 - text = floor(100 * value) * 0.01 - - if (0 == text) then - text = '0.00' - end - end - - if not immutable then - local text_entity = surface.find_entity('flying-text', position) - - if text_entity then - text_entity.text = text - text_entity.color = color - return - end - end - - surface.create_entity{ - name = 'flying-text', - color = color, - text = text, - position = position - }.active = false -end - -return Debug +-- dependencies +local min = math.min +local max = math.max +local floor = math.floor +local abs = math.abs + +-- this +local Debug = {} + +-- private state +local debug = false +local cheats = false + +function Debug.enable_debug() + debug = true +end + +function Debug.disable_debug() + debug = false +end + +function Debug.enable_cheats() + cheats = true +end + +function Debug.disable_cheats() + cheats = true +end + +global.message_count = 0 + +--[[-- + Shows the given message if debug is enabled. + + @param message string +]] +function Debug.print(message) + if type(message) ~= 'string' and type(message) ~= 'number' and type(message) ~= 'boolean' then message = type(message) end + global.message_count = global.message_count + 1 + if (debug) then + game.print('[' .. global.message_count .. '] ' .. tostring(message)) + log('[' .. global.message_count .. '] ' .. tostring(message)) + end +end + +--[[-- + Shows the given message with serpent enabled, if debug is enabled. + + @param message string +]] +function Debug.print_serpent(message) + Debug.print(serpent.line(message)) +end + +--[[-- + Shows the given message if _DEBUG == true for a given position. + + @param x number + @param y number + @param message string +]] +function Debug.print_position(position, message) + message = message or '' + if type(message) ~= 'string' and type(message) ~= 'number' and type(message) ~= 'boolean' then message = type(message) end + global.message_count = global.message_count + 1 + if (debug) then + game.print('[' .. global.message_count .. '] {x=' .. position.x .. ', y=' .. position.y .. '} ' .. tostring(message)) + end +end + +--[[-- + Executes the given callback if cheating is enabled. + + @param callback function +]] +function Debug.cheat(callback) + if (cheats) then + callback() + end +end + +--[[-- + Prints a colored value on a location. + + @param value between -1 and 1 + @param surface LuaSurface + @param position Position {x, y} + @param scale float + @param offset float + @param immutable bool if immutable, only set, never do a surface lookup, values never change +]] +function Debug.print_grid_value(value, surface, position, scale, offset, immutable) + local is_string = type(value) == 'string' + local color = {r = 1, g = 1, b = 1} + text = value + + if type(immutable) ~= 'boolean' then + immutable = false + end + + if not is_string then + scale = scale or 1 + offset = offset or 0 + position = {x = position.x + offset, y = position.y + offset} + local r = max(1, value) / scale + local g = 1 - abs(value) / scale + local b = min(1, value) / scale + + if (r > 0) then + r = 0 + end + + if (b < 0) then + b = 0 + end + + if (g < 0) then + g = 0 + end + + r = abs(r) + + color = { r = r, g = g, b = b} + + -- round at precision of 2 + text = floor(100 * value) * 0.01 + + if (0 == text) then + text = '0.00' + end + end + + if not immutable then + local text_entity = surface.find_entity('flying-text', position) + + if text_entity then + text_entity.text = text + text_entity.color = color + return + end + end + + surface.create_entity{ + name = 'flying-text', + color = color, + text = text, + position = position + }.active = false +end + +--[[-- + Prints a colored value on a location. When given a color_value and a delta_color, + will change the color of the text from the base to base + value * delta. This will + make the color of the text range from 'base_color' to 'base_color + delta_color' + as the color_value ranges from 0 to 1 + + @param value of number to be displayed + @param surface LuaSurface + @param position Position {x, y} + @param scale float + @param offset float position offset + @param immutable bool if immutable, only set, never do a surface lookup, values never change + @param color_value float How far along the range of values of colors the value is to be displayed + @param base_color {r,g,b} The color for the text to be if color_value is 0 + @param delta_color {r,g,b} The amount to correct the base_color if color_value is 1 + @param under_bound {r,g,b} The color to be used if color_value < 0 + @param over_bound {r,g,b} The color to be used if color_value > 1 +]] +function Debug.print_colored_grid_value(value, surface, position, scale, offset, immutable, + color_value, base_color, delta_color, under_bound, over_bound) + local is_string = type(value) == 'string' + -- default values: + local color = base_color or {r = 1, g = 1, b = 1} + local d_color = delta_color or {r = 0, g = 0, b = 0} + local u_color = under_bound or color + local o_color = over_bound or color + + if (color_value < 0) then + color = u_color + elseif (color_value > 1) then + color = o_color + else + color = { r = color.r + color_value * d_color.r, + g = color.g + color_value * d_color.g, + b = color.b + color_value * d_color.b } + end + + text = value + + if type(immutable) ~= 'boolean' then + immutable = false + end + + if not is_string then + offset = offset or 0 + position = {x = position.x + offset, y = position.y + offset} + + -- round at precision of 2 + text = floor(100 * value) * 0.01 + + if (0 == text) then + text = '0.00' + end + end + + if not immutable then + local text_entity = surface.find_entity('flying-text', position) + + if text_entity then + text_entity.text = text + text_entity.color = color + return + end + end + + surface.create_entity{ + name = 'flying-text', + color = color, + text = text, + position = position + }.active = false +end + +return Debug diff --git a/map_gen/Diggy/Feature/AlienSpawner.lua b/map_gen/Diggy/Feature/AlienSpawner.lua index 9142446f..15051901 100644 --- a/map_gen/Diggy/Feature/AlienSpawner.lua +++ b/map_gen/Diggy/Feature/AlienSpawner.lua @@ -1,66 +1,66 @@ ---[[-- info - Provides the ability to spawn aliens. -]] - --- dependencies -local Event = require 'utils.event' -local AlienEvolutionProgress = require 'map_gen.Diggy.AlienEvolutionProgress' -local Debug = require 'map_gen.Diggy.Debug' -local Template = require 'map_gen.Diggy.Template' -local insert = table.insert -local random = math.random - --- this -local AlienSpawner = {} - -local function spawn_alien(surface, x, y) - local enemy_force = game.forces.enemy - local enemy_force_evolution = enemy_force.evolution_factor - local position = {x = x, y = y} - local biters = AlienEvolutionProgress.getBitersByEvolution(random(1, 2), enemy_force_evolution) - local spitters = AlienEvolutionProgress.getSpittersByEvolution(random(1, 2), enemy_force_evolution) - - local units = {} - for name, amount in pairs(biters) do - insert(units, {name = name, position = position, force = enemy_force, amount = amount}) - end - for name, amount in pairs(spitters) do - insert(units, {name = name, position = position, force = enemy_force, amount = amount}) - end - - Template.units(surface, units, 1.5, 'small-biter') -end - ---[[-- - Registers all event handlers. -]] -function AlienSpawner.register(config) - local alien_minimum_distance_square = config.alien_minimum_distance ^ 2 - - Event.add(Template.events.on_void_removed, function (event) - game.forces.enemy.evolution_factor = game.forces.enemy.evolution_factor + 0.0000012 - - local position = event.position - local x = position.x - local y = position.y - - if (x * x + y * y < alien_minimum_distance_square or config.alien_probability < random()) then - return - end - - spawn_alien(event.surface, x, y) - end) -end - -function AlienSpawner.get_extra_map_info(config) - return [[Alien Spawner, aliens might spawn when mining! -Spawn chance: ]] .. (config.alien_probability * 100) .. [[% -Minimum spawn distance: ]] .. config.alien_minimum_distance .. ' tiles' -end - -function AlienSpawner.on_init() - -- base factorio = pollution_factor = 0.000015 - game.map_settings.enemy_evolution.pollution_factor = 0.000004 -end - -return AlienSpawner +--[[-- info + Provides the ability to spawn aliens. +]] + +-- dependencies +local Event = require 'utils.event' +local AlienEvolutionProgress = require 'map_gen.Diggy.AlienEvolutionProgress' +local Debug = require 'map_gen.Diggy.Debug' +local Template = require 'map_gen.Diggy.Template' +local insert = table.insert +local random = math.random + +-- this +local AlienSpawner = {} + +local function spawn_alien(surface, x, y) + local enemy_force = game.forces.enemy + local enemy_force_evolution = enemy_force.evolution_factor + local position = {x = x, y = y} + local biters = AlienEvolutionProgress.getBitersByEvolution(random(1, 2), enemy_force_evolution) + local spitters = AlienEvolutionProgress.getSpittersByEvolution(random(1, 2), enemy_force_evolution) + + local units = {} + for name, amount in pairs(biters) do + insert(units, {name = name, position = position, force = enemy_force, amount = amount}) + end + for name, amount in pairs(spitters) do + insert(units, {name = name, position = position, force = enemy_force, amount = amount}) + end + + Template.units(surface, units, 1.5, 'small-biter') +end + +--[[-- + Registers all event handlers. +]] +function AlienSpawner.register(config) + local alien_minimum_distance_square = config.alien_minimum_distance ^ 2 + + Event.add(Template.events.on_void_removed, function (event) + game.forces.enemy.evolution_factor = game.forces.enemy.evolution_factor + 0.0000012 + + local position = event.position + local x = position.x + local y = position.y + + if (x * x + y * y < alien_minimum_distance_square or config.alien_probability < random()) then + return + end + + spawn_alien(event.surface, x, y) + end) +end + +function AlienSpawner.get_extra_map_info(config) + return [[Alien Spawner, aliens might spawn when mining! +Spawn chance: ]] .. (config.alien_probability * 100) .. [[% +Minimum spawn distance: ]] .. config.alien_minimum_distance .. ' tiles' +end + +function AlienSpawner.on_init() + -- base factorio = pollution_factor = 0.000015 + game.map_settings.enemy_evolution.pollution_factor = 0.000004 +end + +return AlienSpawner diff --git a/map_gen/Diggy/Feature/Antigrief.lua b/map_gen/Diggy/Feature/Antigrief.lua index 3f2f89a1..c72a9afd 100644 --- a/map_gen/Diggy/Feature/Antigrief.lua +++ b/map_gen/Diggy/Feature/Antigrief.lua @@ -1,57 +1,57 @@ ---[[-- info - Provides the ability to setup a player when first joined. -]] - --- dependencies -local Event = require 'utils.event' -local Global = require 'utils.global' -local CaveCollapse = require 'map_gen.Diggy.Feature.DiggyCaveCollapse' -local Game = require 'utils.game' -local Report = require 'features.report' - --- this -local Antigrief = {} - -global.Antigrief = { - autojail = false, - jailed_players = {}, - last_collapse = 0 -} - -local allowed_collapses_first_hour = 0 - -local player_collapses = {} - -Global.register({ - cave_collapse_disabled = cave_collapse_disabled -}, function(tbl) - cave_collapse_disabled = tbl.cave_collapse_disabled -end) - - ---[[-- - Registers all event handlers. -]] -function Antigrief.register(config) - global.Antigrief.autojail = config.autojail - allowed_collapses_first_hour = config.allowed_collapses_first_hour -end - - -Event.add(CaveCollapse.events.on_collapse, function(event) - local player_index = event.player_index - if player_index and global.Antigrief.last_collapse ~= game.tick then - global.Antigrief.last_collapse = game.tick - local count = player_collapses[player_index] or 0 - count = count + 1 - player_collapses[player_index] = count - local player = Game.get_player_by_index(player_index) - if global.Antigrief.autojail and count > allowed_collapses_first_hour and player.online_time < 216000 and not global.Antigrief.jailed_players[player_index] then - Report.jail(player) - Report.report(nil, player, string.format("Caused %d collapses in the first hour", count)) - global.Antigrief.jailed_players[player_index] = true - end - end -end) - -return Antigrief +--[[-- info + Provides the ability to setup a player when first joined. +]] + +-- dependencies +local Event = require 'utils.event' +local Global = require 'utils.global' +local CaveCollapse = require 'map_gen.Diggy.Feature.DiggyCaveCollapse' +local Game = require 'utils.game' +local Report = require 'features.report' + +-- this +local Antigrief = {} + +global.Antigrief = { + autojail = false, + jailed_players = {}, + last_collapse = 0 +} + +local allowed_collapses_first_hour = 0 + +local player_collapses = {} + +Global.register({ + cave_collapse_disabled = cave_collapse_disabled +}, function(tbl) + cave_collapse_disabled = tbl.cave_collapse_disabled +end) + + +--[[-- + Registers all event handlers. +]] +function Antigrief.register(config) + global.Antigrief.autojail = config.autojail + allowed_collapses_first_hour = config.allowed_collapses_first_hour +end + + +Event.add(CaveCollapse.events.on_collapse, function(event) + local player_index = event.player_index + if player_index and global.Antigrief.last_collapse ~= game.tick then + global.Antigrief.last_collapse = game.tick + local count = player_collapses[player_index] or 0 + count = count + 1 + player_collapses[player_index] = count + local player = Game.get_player_by_index(player_index) + if global.Antigrief.autojail and count > allowed_collapses_first_hour and player.online_time < 216000 and not global.Antigrief.jailed_players[player_index] then + Report.jail(player) + Report.report(nil, player, string.format("Caused %d collapses in the first hour", count)) + global.Antigrief.jailed_players[player_index] = true + end + end +end) + +return Antigrief diff --git a/map_gen/Diggy/Feature/ArtefactHunting.lua b/map_gen/Diggy/Feature/ArtefactHunting.lua index ef7a637e..e133fd9f 100644 --- a/map_gen/Diggy/Feature/ArtefactHunting.lua +++ b/map_gen/Diggy/Feature/ArtefactHunting.lua @@ -1,242 +1,242 @@ ---[[-- info - Provides the ability to collect coins and send them to space. -]] - --- dependencies -local Event = require 'utils.event' -local Game = require 'utils.game' -local ScoreTable = require 'map_gen.Diggy.ScoreTable' -local Debug = require 'map_gen.Diggy.Debug' -local Template = require 'map_gen.Diggy.Template' -local Perlin = require 'map_gen.shared.perlin_noise' -local random = math.random -local ceil = math.ceil -local Gui = require 'utils.gui' -local utils = require 'utils.utils' - --- this -local ArtefactHunting = {} - --- some GUI stuff -local function redraw_table(data) - local list = data.list - Gui.clear(list) - - data.frame.caption = 'Scoretable' - - local score_keys = ScoreTable.all_keys() - - for _, data in pairs(score_keys) do - local val = ScoreTable.get(data) - - local table = list.add({type = 'table', column_count = 2}) - - local key = table.add({type = 'label', name = 'Diggy.ArtefactHunting.Frame.List.Key', caption = data}) - key.style.minimal_width = 175 - - local val = table.add({type = 'label', name = 'Diggy.ArtefactHunting.Frame.List.Val', caption = utils.comma_value(val)}) - val.style.minimal_width = 225 - end -end - - -local function toggle(event) - local player = event.player - local center = player.gui.left - local frame = center['Diggy.ArtefactHunting.Frame'] - - if (frame and event.trigger == nil) then - Gui.destroy(frame) - return - elseif (frame) then - local data = Gui.get_data(frame) - redraw_table(data) - return - end - - frame = center.add({name = 'Diggy.ArtefactHunting.Frame', type = 'frame', direction = 'vertical'}) - - local scroll_pane = frame.add({type = 'scroll-pane'}) - scroll_pane.style.maximal_height = 400 - - frame.add({ type = 'button', name = 'Diggy.ArtefactHunting.Button', caption = 'Close'}) - - local data = { - frame = frame, - list = scroll_pane - } - - redraw_table(data) - - Gui.set_data(frame, data) -end - -local function on_player_created(event) - Game.get_player_by_index(event.player_index).gui.top.add({ - name = 'Diggy.ArtefactHunting.Button', - type = 'sprite-button', - sprite = 'item/steel-axe', - }) -end - -Gui.on_click('Diggy.ArtefactHunting.Button', toggle) -Gui.on_custom_close('Diggy.ArtefactHunting.Frame', function (event) - event.element.destroy() -end) - -function ArtefactHunting.update_gui() - for _, p in ipairs(game.connected_players) do - local frame = p.gui.left['Diggy.ArtefactHunting.Frame'] - - if frame and frame.valid then - local data = {player = p, trigger = 'update_gui'} - toggle(data) - end - end -end - ---[[-- - Registers all event handlers. -]] -function ArtefactHunting.register(config) - Event.add(defines.events.on_player_created, on_player_created) - Event.on_nth_tick(61, ArtefactHunting.update_gui) - - ScoreTable.reset('Coins sent to space') - - local seed - local function get_noise(surface, x, y) - seed = seed or surface.map_gen_settings.seed + surface.index + 300 - return Perlin.noise(x * config.noise_variance * 0.9, y * config.noise_variance * 1.1, seed) - end - - local distance_required = config.minimal_treasure_chest_distance * config.minimal_treasure_chest_distance - - Event.add(defines.events.on_rocket_launched, function (event) - local coins = event.rocket.get_inventory(defines.inventory.rocket).get_item_count('coin') - if coins > 0 then - local sum = ScoreTable.add('Coins sent to space', coins) - game.print('sent ' .. coins .. ' coins into space! The space station is now holding ' .. sum .. ' coins.') - end - end) - - Event.add(Template.events.on_void_removed, function (event) - local position = event.position - local x = position.x - local y = position.y - - if (x * x + y * y <= distance_required) then - return - end - - local surface = event.surface - - if get_noise(surface, x, y) < config.treasure_chest_noise_threshold then - return - end - - local chest = surface.create_entity({name = 'steel-chest', position = position, force = game.forces.player}) - - if not chest then - return - end - - for name, prototype in pairs(config.treasure_chest_raffle) do - if random() <= prototype.chance then - chest.insert({name = name, count = random(prototype.min, prototype.max)}) - end - end - end) - - local modifiers = config.alien_coin_modifiers - - local function picked_up_coins(player_index, count) - local text - if count == 1 then - text = '+1 coin' - ScoreTable.increment('Collected coins') - else - text = '+' .. count ..' coins' - ScoreTable.add('Collected coins', count) - end - - Game.print_player_floating_text(player_index, text, {r = 255, g = 215, b = 0}) - end - - ScoreTable.reset('Collected coins') - - Event.add(defines.events.on_entity_died, function (event) - local entity = event.entity - local force = entity.force - - if force.name ~= 'enemy' then - return - end - - local cause = event.cause - - if not cause or cause.type ~= 'player' or not cause.valid then - return - end - - local modifier = modifiers[entity.name] or 1 - local evolution_multiplier = force.evolution_factor * 11 - local count = random( - ceil(2 * evolution_multiplier * 0.1), - ceil(5 * (evolution_multiplier * evolution_multiplier + modifier) * 0.1) - ) - - entity.surface.create_entity({ - name = 'item-on-ground', - position = entity.position, - stack = {name = 'coin', count = count} - }) - end) - - Event.add(defines.events.on_picked_up_item, function (event) - local stack = event.item_stack - if stack.name ~= 'coin' then - return - end - - picked_up_coins(event.player_index, stack.count) - end) - - Event.add(defines.events.on_pre_player_mined_item, function (event) - if event.entity.type ~= 'simple-entity' then - return - end - - if random() > config.mining_artefact_chance then - return - end - - local count = random(config.mining_artefact_amount.min, config.mining_artefact_amount.max) - local player_index = event.player_index - - Game.get_player_by_index(player_index).insert({name = 'coin', count = count}) - picked_up_coins(player_index, count) - end) - - if (config.display_chest_locations) then - Event.add(defines.events.on_chunk_generated, function (event) - local surface = event.surface - local area = event.area - - for x = area.left_top.x, area.left_top.x + 31 do - local sq_x = x * x - for y = area.left_top.y, area.left_top.y + 31 do - if sq_x + y * y >= distance_required and get_noise(surface, x, y) >= config.treasure_chest_noise_threshold then - Debug.print_grid_value('chest', surface, {x = x, y = y}, nil, nil, true) - end - end - end - end) - end -end - -function ArtefactHunting.get_extra_map_info(config) - return 'Artefact Hunting, find precious coins while mining and launch them to the surface!' -end - -return ArtefactHunting +--[[-- info + Provides the ability to collect coins and send them to space. +]] + +-- dependencies +local Event = require 'utils.event' +local Game = require 'utils.game' +local ScoreTable = require 'map_gen.Diggy.ScoreTable' +local Debug = require 'map_gen.Diggy.Debug' +local Template = require 'map_gen.Diggy.Template' +local Perlin = require 'map_gen.shared.perlin_noise' +local random = math.random +local ceil = math.ceil +local Gui = require 'utils.gui' +local utils = require 'utils.utils' + +-- this +local ArtefactHunting = {} + +-- some GUI stuff +local function redraw_table(data) + local list = data.list + Gui.clear(list) + + data.frame.caption = 'Scoretable' + + local score_keys = ScoreTable.all_keys() + + for _, data in pairs(score_keys) do + local val = ScoreTable.get(data) + + local table = list.add({type = 'table', column_count = 2}) + + local key = table.add({type = 'label', name = 'Diggy.ArtefactHunting.Frame.List.Key', caption = data}) + key.style.minimal_width = 175 + + local val = table.add({type = 'label', name = 'Diggy.ArtefactHunting.Frame.List.Val', caption = utils.comma_value(val)}) + val.style.minimal_width = 225 + end +end + + +local function toggle(event) + local player = event.player + local center = player.gui.left + local frame = center['Diggy.ArtefactHunting.Frame'] + + if (frame and event.trigger == nil) then + Gui.destroy(frame) + return + elseif (frame) then + local data = Gui.get_data(frame) + redraw_table(data) + return + end + + frame = center.add({name = 'Diggy.ArtefactHunting.Frame', type = 'frame', direction = 'vertical'}) + + local scroll_pane = frame.add({type = 'scroll-pane'}) + scroll_pane.style.maximal_height = 400 + + frame.add({ type = 'button', name = 'Diggy.ArtefactHunting.Button', caption = 'Close'}) + + local data = { + frame = frame, + list = scroll_pane + } + + redraw_table(data) + + Gui.set_data(frame, data) +end + +local function on_player_created(event) + Game.get_player_by_index(event.player_index).gui.top.add({ + name = 'Diggy.ArtefactHunting.Button', + type = 'sprite-button', + sprite = 'item/steel-axe', + }) +end + +Gui.on_click('Diggy.ArtefactHunting.Button', toggle) +Gui.on_custom_close('Diggy.ArtefactHunting.Frame', function (event) + event.element.destroy() +end) + +function ArtefactHunting.update_gui() + for _, p in ipairs(game.connected_players) do + local frame = p.gui.left['Diggy.ArtefactHunting.Frame'] + + if frame and frame.valid then + local data = {player = p, trigger = 'update_gui'} + toggle(data) + end + end +end + +--[[-- + Registers all event handlers. +]] +function ArtefactHunting.register(config) + Event.add(defines.events.on_player_created, on_player_created) + Event.on_nth_tick(61, ArtefactHunting.update_gui) + + ScoreTable.reset('Coins sent to space') + + local seed + local function get_noise(surface, x, y) + seed = seed or surface.map_gen_settings.seed + surface.index + 300 + return Perlin.noise(x * config.noise_variance * 0.9, y * config.noise_variance * 1.1, seed) + end + + local distance_required = config.minimal_treasure_chest_distance * config.minimal_treasure_chest_distance + + Event.add(defines.events.on_rocket_launched, function (event) + local coins = event.rocket.get_inventory(defines.inventory.rocket).get_item_count('coin') + if coins > 0 then + local sum = ScoreTable.add('Coins sent to space', coins) + game.print('sent ' .. coins .. ' coins into space! The space station is now holding ' .. sum .. ' coins.') + end + end) + + Event.add(Template.events.on_void_removed, function (event) + local position = event.position + local x = position.x + local y = position.y + + if (x * x + y * y <= distance_required) then + return + end + + local surface = event.surface + + if get_noise(surface, x, y) < config.treasure_chest_noise_threshold then + return + end + + local chest = surface.create_entity({name = 'steel-chest', position = position, force = game.forces.player}) + + if not chest then + return + end + + for name, prototype in pairs(config.treasure_chest_raffle) do + if random() <= prototype.chance then + chest.insert({name = name, count = random(prototype.min, prototype.max)}) + end + end + end) + + local modifiers = config.alien_coin_modifiers + + local function picked_up_coins(player_index, count) + local text + if count == 1 then + text = '+1 coin' + ScoreTable.increment('Collected coins') + else + text = '+' .. count ..' coins' + ScoreTable.add('Collected coins', count) + end + + Game.print_player_floating_text(player_index, text, {r = 255, g = 215, b = 0}) + end + + ScoreTable.reset('Collected coins') + + Event.add(defines.events.on_entity_died, function (event) + local entity = event.entity + local force = entity.force + + if force.name ~= 'enemy' then + return + end + + local cause = event.cause + + if not cause or cause.type ~= 'player' or not cause.valid then + return + end + + local modifier = modifiers[entity.name] or 1 + local evolution_multiplier = force.evolution_factor * 11 + local count = random( + ceil(2 * evolution_multiplier * 0.1), + ceil(5 * (evolution_multiplier * evolution_multiplier + modifier) * 0.1) + ) + + entity.surface.create_entity({ + name = 'item-on-ground', + position = entity.position, + stack = {name = 'coin', count = count} + }) + end) + + Event.add(defines.events.on_picked_up_item, function (event) + local stack = event.item_stack + if stack.name ~= 'coin' then + return + end + + picked_up_coins(event.player_index, stack.count) + end) + + Event.add(defines.events.on_pre_player_mined_item, function (event) + if event.entity.type ~= 'simple-entity' then + return + end + + if random() > config.mining_artefact_chance then + return + end + + local count = random(config.mining_artefact_amount.min, config.mining_artefact_amount.max) + local player_index = event.player_index + + Game.get_player_by_index(player_index).insert({name = 'coin', count = count}) + picked_up_coins(player_index, count) + end) + + if (config.display_chest_locations) then + Event.add(defines.events.on_chunk_generated, function (event) + local surface = event.surface + local area = event.area + + for x = area.left_top.x, area.left_top.x + 31 do + local sq_x = x * x + for y = area.left_top.y, area.left_top.y + 31 do + if sq_x + y * y >= distance_required and get_noise(surface, x, y) >= config.treasure_chest_noise_threshold then + Debug.print_grid_value('chest', surface, {x = x, y = y}, nil, nil, true) + end + end + end + end) + end +end + +function ArtefactHunting.get_extra_map_info(config) + return 'Artefact Hunting, find precious coins while mining and launch them to the surface!' +end + +return ArtefactHunting diff --git a/map_gen/Diggy/Feature/DiggyCaveCollapse.lua b/map_gen/Diggy/Feature/DiggyCaveCollapse.lua index eb335f85..639795ba 100644 --- a/map_gen/Diggy/Feature/DiggyCaveCollapse.lua +++ b/map_gen/Diggy/Feature/DiggyCaveCollapse.lua @@ -1,646 +1,646 @@ ---[[-- info - Provides the ability to collapse caves when digging. -]] --- dependencies -require 'utils.list_utils' - -local Event = require 'utils.event' -local Template = require 'map_gen.Diggy.Template' -local ScoreTable = require 'map_gen.Diggy.ScoreTable' -local Debug = require 'map_gen.Diggy.Debug' -local Task = require 'utils.Task' -local Token = require 'utils.global_token' -local Global = require 'utils.global' -local Game = require 'utils.game' -local insert = table.insert -local random = math.random -local floor = math.floor -local abs = math.abs - --- this -local DiggyCaveCollapse = {} - -local config = {} - -local n = 9 -local radius = 0 -local radius_sq = 0 -local center_radius_sq = 0 -local disc_radius_sq = 0 - -local center_weight -local disc_weight -local ring_weight - -local disc_blur_sum = 0 - -local center_value = 0 -local disc_value = 0 -local ring_value = 0 - -local enable_stress_grid = 0 -local stress_map_add -local mask_disc_blur -local stress_map_check_stress_in_threshold -local support_beam_entities -local on_surface_created - -local stress_threshold_causing_collapse = 3.57 - -local show_deconstruction_alert_message = {} -local stress_map_storage = {} -local new_tile_map = {} -local collapse_positions_storage = {} - -Global.register({ - new_tile_map = new_tile_map, - stress_map_storage = stress_map_storage, - deconstruction_alert_message_shown = show_deconstruction_alert_message, - collapse_positions_storage = collapse_positions_storage, -}, function(tbl) - new_tile_map = tbl.new_tile_map - stress_map_storage = tbl.stress_map_storage - show_deconstruction_alert_message = tbl.deconstruction_alert_message_shown - collapse_positions_storage = tbl.collapse_positions_storage -end) - -local defaultValue = 0 - -DiggyCaveCollapse.events = { - --[[-- - When stress at certain position is above the collapse threshold - - position LuaPosition - - surface LuaSurface - - player_index Number (index of player that caused the collapse) - ]] - on_collapse_triggered = script.generate_event_name(), - - --[[-- - After a collapse - - position LuaPosition - - surface LuaSurface - - player_index Number (index of player that caused the collapse) - ]] - on_collapse = script.generate_event_name() -} - -local function create_collapse_template(positions, surface) - local entities = {} - - local find_entities_filtered = surface.find_entities_filtered - - for _, position in pairs(positions) do - local x = position.x - local y = position.y - local do_insert = true - - for _, entity in pairs(find_entities_filtered{area = {{x, y}, {x + 1, y + 1}}}) do - pcall(function() - local strength = support_beam_entities[entity.name] - if strength then - do_insert = false - else - entity.die() - end - end) - end - if do_insert then - insert(entities, {position = {x = x, y = y}, name = 'sand-rock-big'}) - end - end - return entities -end - -local function create_collapse_alert(surface, position) - local target = surface.create_entity{position = position, name = "sand-rock-big"} - for _,player in pairs(game.connected_players) do - player.add_custom_alert(target, {type="item", name="stone"}, "Cave collapsed!", true) - end - target.destroy() -end - -local function collapse(args) - local position = args.position - local surface = args.surface - local positions = {} - local strength = config.collapse_threshold_total_strength - local player_index = args.player_index - create_collapse_alert(surface, position) - mask_disc_blur( - position.x, position.y, - strength, - function(x, y, value) - stress_map_check_stress_in_threshold( - surface, - {x = x, y = y}, - value, - function(_, position) - insert(positions, position) - end - ) - end - ) - local entities = create_collapse_template(positions, surface) - Template.insert(surface, {}, entities) - - script.raise_event(DiggyCaveCollapse.events.on_collapse, args) - ScoreTable.increment('Cave collapse') -end - -local on_collapse_timeout_finished = Token.register(collapse) - -local function spawn_cracking_sound_text(surface, position) - local text = config.cracking_sounds[random(1, #config.cracking_sounds)] - - local color = { - r = 1, - g = random(1, 100) * 0.01, - b = 0 - } - - local create_entity = surface.create_entity - - for i = 1, #text do - local x_offset = (i - #text / 2 - 1) / 3 - local char = text:sub(i, i) - create_entity { - name = 'flying-text', - color = color, - text = char, - position = {x = position.x + x_offset, y = position.y - ((i + 1) % 2) * 0.25} - }.active = true - end -end - -local function on_collapse_triggered(event) - if global.cave_collapse_disabled then return end --kill switch - - local surface = event.surface - local position = event.position - local x = position.x - local y = position.y - - local x_t = new_tile_map[x] - if x_t and x_t[y] then - Template.insert(surface, {}, {{position = position, name = 'sand-rock-big'}}) - return - end - spawn_cracking_sound_text(surface, position) - Task.set_timeout( - config.collapse_delay, - on_collapse_timeout_finished, - event - ) -end - -local function on_built_tile(surface, new_tile, tiles) - local new_tile_strength = support_beam_entities[new_tile.name] - - for _, tile in pairs(tiles) do - if new_tile_strength then - stress_map_add(surface, tile.position, -1 * new_tile_strength, true) - end - - local old_tile_strength = support_beam_entities[tile.old_tile.name] - if (old_tile_strength) then - stress_map_add(surface, tile.position, old_tile_strength, true) - end - end -end - ---It is impossible to track which player marked the tile for deconstruction -local function on_robot_mined_tile(event) - local surface - for _, tile in pairs(event.tiles) do - local strength = support_beam_entities[tile.old_tile.name] - if strength then - surface = surface or event.robot.surface - stress_map_add(surface, tile.position, strength, true) - end - end -end - -local function on_player_mined_tile(event) - local surface = game.surfaces[event.surface_index] - for _, tile in pairs(event.tiles) do - local strength = support_beam_entities[tile.old_tile.name] - - if strength then - stress_map_add(surface, tile.position, strength, true, event.player_index) - end - end -end - -local function on_robot_mined_entity(event) - local entity = event.entity - local strength = support_beam_entities[entity.name] - - if strength then - stress_map_add(entity.surface, entity.position, strength, false, entity.last_user.index) - end -end - -local function on_mined_entity(event) - local entity = event.entity - local name = entity.name - local strength = support_beam_entities[name] - if strength then - stress_map_add(entity.surface, entity.position, strength, false, (not (name == "sand-rock-big" or name == "rock-huge")) and event.player_index) - end -end - -local function on_entity_died(event) - local entity = event.entity - local name = entity.name - local strength = support_beam_entities[name] - if strength then - local cause = event.cause or {} - stress_map_add(entity.surface, entity.position, strength, false, (not (name == "sand-rock-big" or name == "rock-huge")) and cause.index) - end -end - -local function on_built_entity(event) - local entity = event.created_entity - local strength = support_beam_entities[entity.name] - - if strength then - stress_map_add(entity.surface, entity.position, -1 * strength) - end -end - -local function on_placed_entity(event) - local strength = support_beam_entities[event.entity.name] - - if strength then - stress_map_add(event.entity.surface, event.entity.position, -1 * strength) - end -end - - -local on_new_tile_timeout_finished = Token.register(function(args) - local x_t = new_tile_map[args.x] - if x_t then - x_t[args.y] = nil --reset new tile status. This tile can cause a chain collapse now - end -end) - -local function on_void_removed(event) - local strength = support_beam_entities['out-of-map'] - - local position = event.position - if strength then - stress_map_add(event.surface, position, strength) - end - - local x = position.x - local y = position.y - - --To avoid room collapse: - local x_t = new_tile_map[x] - if x_t then - x_t[y] = true - else - x_t = { - [y] = true - } - new_tile_map[x] = x_t - end - Task.set_timeout(3, on_new_tile_timeout_finished, {x = x, y = y}) -end - ---[[-- - Registers all event handlers.] - - @param global_config Table {@see Diggy.Config}. -]] -function DiggyCaveCollapse.register(cfg) - config = cfg - support_beam_entities = config.support_beam_entities - - if support_beam_entities['stone-path'] then - support_beam_entities['stone-brick'] = support_beam_entities['stone-path'] - else - support_beam_entities['stone-brick'] = nil - end - - if support_beam_entities['hazard-concrete'] then - support_beam_entities['hazard-concrete-left'] = support_beam_entities['hazard-concrete'] - support_beam_entities['hazard-concrete-right'] = support_beam_entities['hazard-concrete'] - else - support_beam_entities['hazard-concrete-left'] = nil - support_beam_entities['hazard-concrete-right'] = nil - end - - if support_beam_entities['refined-hazard-concrete'] then - support_beam_entities['refined-hazard-concrete-left'] = support_beam_entities['refined-hazard-concrete'] - support_beam_entities['refined-hazard-concrete-right'] = support_beam_entities['refined-hazard-concrete'] - else - support_beam_entities['refined-hazard-concrete-left'] = nil - support_beam_entities['refined-hazard-concrete-right'] = nil - end - - ScoreTable.reset('Cave collapse') - - Event.add(DiggyCaveCollapse.events.on_collapse_triggered, on_collapse_triggered) - Event.add(defines.events.on_robot_built_entity, on_built_entity) - Event.add(defines.events.on_robot_built_tile, function (event) - on_built_tile(event.robot.surface, event.item, event.tiles) - end) - Event.add(defines.events.on_player_built_tile, function (event) - on_built_tile(game.surfaces[event.surface_index], event.item, event.tiles) - end) - Event.add(defines.events.on_robot_mined_tile, on_robot_mined_tile) - Event.add(defines.events.on_player_mined_tile, on_player_mined_tile) - Event.add(defines.events.on_robot_mined_entity, on_robot_mined_entity) - Event.add(defines.events.on_built_entity, on_built_entity) - Event.add(Template.events.on_placed_entity, on_placed_entity) - Event.add(defines.events.on_entity_died, on_entity_died) - Event.add(defines.events.on_player_mined_entity, on_mined_entity) - Event.add(Template.events.on_void_removed, on_void_removed) - Event.add(defines.events.on_surface_created, on_surface_created) - - Event.add(defines.events.on_marked_for_deconstruction, function (event) - if (nil ~= support_beam_entities[event.entity.name]) then - event.entity.cancel_deconstruction(Game.get_player_by_index(event.player_index).force) - end - end) - - Event.add(defines.events.on_player_created, function (event) - show_deconstruction_alert_message[event.player_index] = true - end) - - Event.add(defines.events.on_pre_player_mined_item, function (event) - local player_index = event.player_index - if not show_deconstruction_alert_message[player_index] then - return - end - - if (nil ~= support_beam_entities[event.entity.name]) then - require 'features.gui.popup'.player( - Game.get_player_by_index(player_index),[[ -Mining entities such as walls, stone paths, concrete -and rocks, can cause a cave-in, be careful miner! - -Foreman's advice: Place a wall every 4th tile to -prevent a cave-in. Use stone paths and concrete -to reinforce it further. -]] - ) - show_deconstruction_alert_message[player_index] = nil - end - end) - - enable_stress_grid = config.enable_stress_grid - - on_surface_created({surface_index = 1}) - - mask_init(config) - if (config.enable_mask_debug) then - local surface = game.surfaces.nauvis - mask_disc_blur(0, 0, 10, function(x, y, fraction) - Debug.print_grid_value(fraction, surface, {x = x, y = y}) - end) - end - - - if config.enable_debug_commands then - commands.add_command('test-tile-support-range', '<tilename> <range> creates a square of tiles with length <range>. It is spawned one <range> north of the player.', function(cmd) - local params = {} - for param in string.gmatch(cmd.parameter, '%S+') do - table.insert(params, param) - end - - local tilename = params[1] - local range = tonumber(params[2]) - - local position = {x = math.floor(game.player.position.x), y = math.floor(game.player.position.y) - 5 * range - 1} - local surface = game.player.surface - local tiles = {} - local entities = {} - for x = position.x, position.x + range * 5 do - for y = position.y, position.y + range * 5 do - if y % range + x % range == 0 then - insert(entities,{name = "stone-wall", position = {x=x,y=y}}) - end - insert(tiles, {position = {x = x, y = y}, name = tilename}) - - local strength = support_beam_entities[tilename] - if strength then - stress_map_add(surface, {x =x, y=y}, - strength) - end - for _, entity in pairs(surface.find_entities_filtered({position = {x=x,y=y}})) do - pcall(function() - local strength = support_beam_entities[entity.name] - local position = entity.position - entity.die() - if strength then - stress_map_add(surface, position, strength) - end - end - ) - end - end - end - Template.insert(surface, tiles, entities) - end - ) - end - - commands.add_command('toggle-cave-collapse', 'Toggles cave collapse (admins only).', function() - pcall(function() --better safe than sorry - if not game.player or game.player.admin then - cave_collapse_disabled = not cave_collapse_disabled - if cave_collapse_disabled then - game.print("Cave collapse: Disabled.") - else - game.print("Cave collapse: Enabled.") - end - end - end) - end) -end - --- ---STRESS MAP --- ---[[-- - Adds a fraction to a given location on the stress_map. Returns the new - fraction value of that position. - - @param stress_map Table of {x,y} - @param position Table with x and y - @param number fraction - - @return number sum of old fraction + new fraction -]] -local function add_fraction(stress_map, x, y, fraction, player_index) - x = 2 * floor(x * 0.5) - y = 2 * floor(y * 0.5) - - local x_t = stress_map[x] - if not x_t then - x_t = {} - stress_map[x] = x_t - end - - local value = x_t[y] - if not value then - value = defaultValue - end - - value = value + fraction - - x_t[y] = value - - if (fraction > 0 and value > stress_threshold_causing_collapse) then - script.raise_event( - DiggyCaveCollapse.events.on_collapse_triggered, - {surface = game.surfaces[stress_map.surface_index], position = {x = x, y = y}, player_index = player_index} - ) - end - if (enable_stress_grid) then - local surface = game.surfaces[stress_map.surface_index] - Debug.print_colored_grid_value(value, surface, {x = x, y = y}, 4, 0.5, false, - value / stress_threshold_causing_collapse, {r = 0, g = 1, b = 0}, {r = 1, g = -1, b = 0}, - {r = 0, g = 1, b = 0}, {r = 1, g = 1, b = 1}) - end - return value -end - -on_surface_created = function (event) - stress_map_storage[event.surface_index] = {} - - local map = stress_map_storage[event.surface_index] - - map['surface_index'] = event.surface_index - map[1] = {index = 1} - map[2] = {index = 2} - map[3] = {index = 3} - map[4] = {index = 4} -end - ---[[-- - Checks whether a tile's pressure is within a given threshold and calls the handler if not. - @param surface LuaSurface - @param position Position with x and y - @param number threshold - @param callback -]] -stress_map_check_stress_in_threshold = function(surface, position, threshold, callback) - local stress_map = stress_map_storage[surface.index] - local value = add_fraction(stress_map, position.x, position.y, 0) - - if (value >= stress_threshold_causing_collapse - threshold) then - callback(surface, position) - end -end - -stress_map_add = function(surface, position, factor, no_blur, player_index) - local x_start = floor(position.x) - local y_start = floor(position.y) - - local stress_map = stress_map_storage[surface.index] - if not stress_map then - return - end - - if no_blur then - add_fraction(stress_map, x_start, y_start, factor, player_index) - return - end - - for x = -radius, radius do - for y = -radius, radius do - local value = 0 - local distance_sq = x * x + y * y - if distance_sq <= center_radius_sq then - value = center_value - elseif distance_sq <= disc_radius_sq then - value = disc_value - elseif distance_sq <= radius_sq then - value = ring_value - end - if abs(value) > 0.001 then - add_fraction(stress_map, x + x_start, y + y_start, value * factor, player_index) - end - end - end -end - -DiggyCaveCollapse.stress_map_add = stress_map_add - --- --- MASK --- - -function mask_init(config) - n = config.mask_size - - ring_weight = config.mask_relative_ring_weights[1] - disc_weight = config.mask_relative_ring_weights[2] - center_weight = config.mask_relative_ring_weights[3] - - radius = floor(n * 0.5) - - radius_sq = (radius + 0.2) * (radius + 0.2) - center_radius_sq = radius_sq / 9 - disc_radius_sq = radius_sq * 4 / 9 - - for x = -radius, radius do - for y = -radius, radius do - local distance_sq = x * x + y * y - if distance_sq <= center_radius_sq then - disc_blur_sum = disc_blur_sum + center_weight - elseif distance_sq <= disc_radius_sq then - disc_blur_sum = disc_blur_sum + disc_weight - elseif distance_sq <= radius_sq then - disc_blur_sum = disc_blur_sum + ring_weight - end - end - end - center_value = center_weight / disc_blur_sum - disc_value = disc_weight / disc_blur_sum - ring_value = ring_weight / disc_blur_sum -end - ---[[-- - Applies a blur - Applies the disc in 3 discs: center, (middle) disc and (outer) ring. - The relative weights for tiles in a disc are: - center: 3/3 - disc: 2/3 - ring: 1/3 - The sum of all values is 1 - - @param x_start number center point - @param y_start number center point - @param factor the factor to multiply the cell value with (value = cell_value * factor) - @param callback function to execute on each tile within the mask callback(x, y, value) -]] -mask_disc_blur = function(x_start, y_start, factor, callback) - x_start = floor(x_start) - y_start = floor(y_start) - for x = -radius, radius do - for y = -radius, radius do - local value = 0 - local distance_sq = x * x + y * y - if distance_sq <= center_radius_sq then - value = center_value - elseif distance_sq <= disc_radius_sq then - value = disc_value - elseif distance_sq <= radius_sq then - value = ring_value - end - if abs(value) > 0.001 then - callback(x_start + x, y_start + y, value * factor) - end - end - end -end - -function DiggyCaveCollapse.get_extra_map_info(config) - return [[Alien Spawner, aliens might spawn when mining! -Place stone walls, stone paths and (refined) concrete to reinforce the mine. If you see cracks appear, run!]] -end - -return DiggyCaveCollapse +--[[-- info + Provides the ability to collapse caves when digging. +]] +-- dependencies +require 'utils.list_utils' + +local Event = require 'utils.event' +local Template = require 'map_gen.Diggy.Template' +local ScoreTable = require 'map_gen.Diggy.ScoreTable' +local Debug = require 'map_gen.Diggy.Debug' +local Task = require 'utils.Task' +local Token = require 'utils.global_token' +local Global = require 'utils.global' +local Game = require 'utils.game' +local insert = table.insert +local random = math.random +local floor = math.floor +local abs = math.abs + +-- this +local DiggyCaveCollapse = {} + +local config = {} + +local n = 9 +local radius = 0 +local radius_sq = 0 +local center_radius_sq = 0 +local disc_radius_sq = 0 + +local center_weight +local disc_weight +local ring_weight + +local disc_blur_sum = 0 + +local center_value = 0 +local disc_value = 0 +local ring_value = 0 + +local enable_stress_grid = 0 +local stress_map_add +local mask_disc_blur +local stress_map_check_stress_in_threshold +local support_beam_entities +local on_surface_created + +local stress_threshold_causing_collapse = 3.57 + +local show_deconstruction_alert_message = {} +local stress_map_storage = {} +local new_tile_map = {} +local collapse_positions_storage = {} + +Global.register({ + new_tile_map = new_tile_map, + stress_map_storage = stress_map_storage, + deconstruction_alert_message_shown = show_deconstruction_alert_message, + collapse_positions_storage = collapse_positions_storage, +}, function(tbl) + new_tile_map = tbl.new_tile_map + stress_map_storage = tbl.stress_map_storage + show_deconstruction_alert_message = tbl.deconstruction_alert_message_shown + collapse_positions_storage = tbl.collapse_positions_storage +end) + +local defaultValue = 0 + +DiggyCaveCollapse.events = { + --[[-- + When stress at certain position is above the collapse threshold + - position LuaPosition + - surface LuaSurface + - player_index Number (index of player that caused the collapse) + ]] + on_collapse_triggered = script.generate_event_name(), + + --[[-- + After a collapse + - position LuaPosition + - surface LuaSurface + - player_index Number (index of player that caused the collapse) + ]] + on_collapse = script.generate_event_name() +} + +local function create_collapse_template(positions, surface) + local entities = {} + + local find_entities_filtered = surface.find_entities_filtered + + for _, position in pairs(positions) do + local x = position.x + local y = position.y + local do_insert = true + + for _, entity in pairs(find_entities_filtered{area = {{x, y}, {x + 1, y + 1}}}) do + pcall(function() + local strength = support_beam_entities[entity.name] + if strength then + do_insert = false + else + entity.die() + end + end) + end + if do_insert then + insert(entities, {position = {x = x, y = y}, name = 'sand-rock-big'}) + end + end + return entities +end + +local function create_collapse_alert(surface, position) + local target = surface.create_entity{position = position, name = "sand-rock-big"} + for _,player in pairs(game.connected_players) do + player.add_custom_alert(target, {type="item", name="stone"}, "Cave collapsed!", true) + end + target.destroy() +end + +local function collapse(args) + local position = args.position + local surface = args.surface + local positions = {} + local strength = config.collapse_threshold_total_strength + local player_index = args.player_index + create_collapse_alert(surface, position) + mask_disc_blur( + position.x, position.y, + strength, + function(x, y, value) + stress_map_check_stress_in_threshold( + surface, + {x = x, y = y}, + value, + function(_, position) + insert(positions, position) + end + ) + end + ) + local entities = create_collapse_template(positions, surface) + Template.insert(surface, {}, entities) + + script.raise_event(DiggyCaveCollapse.events.on_collapse, args) + ScoreTable.increment('Cave collapse') +end + +local on_collapse_timeout_finished = Token.register(collapse) + +local function spawn_cracking_sound_text(surface, position) + local text = config.cracking_sounds[random(1, #config.cracking_sounds)] + + local color = { + r = 1, + g = random(1, 100) * 0.01, + b = 0 + } + + local create_entity = surface.create_entity + + for i = 1, #text do + local x_offset = (i - #text / 2 - 1) / 3 + local char = text:sub(i, i) + create_entity { + name = 'flying-text', + color = color, + text = char, + position = {x = position.x + x_offset, y = position.y - ((i + 1) % 2) * 0.25} + }.active = true + end +end + +local function on_collapse_triggered(event) + if global.cave_collapse_disabled then return end --kill switch + + local surface = event.surface + local position = event.position + local x = position.x + local y = position.y + + local x_t = new_tile_map[x] + if x_t and x_t[y] then + Template.insert(surface, {}, {{position = position, name = 'sand-rock-big'}}) + return + end + spawn_cracking_sound_text(surface, position) + Task.set_timeout( + config.collapse_delay, + on_collapse_timeout_finished, + event + ) +end + +local function on_built_tile(surface, new_tile, tiles) + local new_tile_strength = support_beam_entities[new_tile.name] + + for _, tile in pairs(tiles) do + if new_tile_strength then + stress_map_add(surface, tile.position, -1 * new_tile_strength, true) + end + + local old_tile_strength = support_beam_entities[tile.old_tile.name] + if (old_tile_strength) then + stress_map_add(surface, tile.position, old_tile_strength, true) + end + end +end + +--It is impossible to track which player marked the tile for deconstruction +local function on_robot_mined_tile(event) + local surface + for _, tile in pairs(event.tiles) do + local strength = support_beam_entities[tile.old_tile.name] + if strength then + surface = surface or event.robot.surface + stress_map_add(surface, tile.position, strength, true) + end + end +end + +local function on_player_mined_tile(event) + local surface = game.surfaces[event.surface_index] + for _, tile in pairs(event.tiles) do + local strength = support_beam_entities[tile.old_tile.name] + + if strength then + stress_map_add(surface, tile.position, strength, true, event.player_index) + end + end +end + +local function on_robot_mined_entity(event) + local entity = event.entity + local strength = support_beam_entities[entity.name] + + if strength then + stress_map_add(entity.surface, entity.position, strength, false, entity.last_user.index) + end +end + +local function on_mined_entity(event) + local entity = event.entity + local name = entity.name + local strength = support_beam_entities[name] + if strength then + stress_map_add(entity.surface, entity.position, strength, false, (not (name == "sand-rock-big" or name == "rock-huge")) and event.player_index) + end +end + +local function on_entity_died(event) + local entity = event.entity + local name = entity.name + local strength = support_beam_entities[name] + if strength then + local cause = event.cause or {} + stress_map_add(entity.surface, entity.position, strength, false, (not (name == "sand-rock-big" or name == "rock-huge")) and cause.index) + end +end + +local function on_built_entity(event) + local entity = event.created_entity + local strength = support_beam_entities[entity.name] + + if strength then + stress_map_add(entity.surface, entity.position, -1 * strength) + end +end + +local function on_placed_entity(event) + local strength = support_beam_entities[event.entity.name] + + if strength then + stress_map_add(event.entity.surface, event.entity.position, -1 * strength) + end +end + + +local on_new_tile_timeout_finished = Token.register(function(args) + local x_t = new_tile_map[args.x] + if x_t then + x_t[args.y] = nil --reset new tile status. This tile can cause a chain collapse now + end +end) + +local function on_void_removed(event) + local strength = support_beam_entities['out-of-map'] + + local position = event.position + if strength then + stress_map_add(event.surface, position, strength) + end + + local x = position.x + local y = position.y + + --To avoid room collapse: + local x_t = new_tile_map[x] + if x_t then + x_t[y] = true + else + x_t = { + [y] = true + } + new_tile_map[x] = x_t + end + Task.set_timeout(3, on_new_tile_timeout_finished, {x = x, y = y}) +end + +--[[-- + Registers all event handlers.] + + @param global_config Table {@see Diggy.Config}. +]] +function DiggyCaveCollapse.register(cfg) + config = cfg + support_beam_entities = config.support_beam_entities + + if support_beam_entities['stone-path'] then + support_beam_entities['stone-brick'] = support_beam_entities['stone-path'] + else + support_beam_entities['stone-brick'] = nil + end + + if support_beam_entities['hazard-concrete'] then + support_beam_entities['hazard-concrete-left'] = support_beam_entities['hazard-concrete'] + support_beam_entities['hazard-concrete-right'] = support_beam_entities['hazard-concrete'] + else + support_beam_entities['hazard-concrete-left'] = nil + support_beam_entities['hazard-concrete-right'] = nil + end + + if support_beam_entities['refined-hazard-concrete'] then + support_beam_entities['refined-hazard-concrete-left'] = support_beam_entities['refined-hazard-concrete'] + support_beam_entities['refined-hazard-concrete-right'] = support_beam_entities['refined-hazard-concrete'] + else + support_beam_entities['refined-hazard-concrete-left'] = nil + support_beam_entities['refined-hazard-concrete-right'] = nil + end + + ScoreTable.reset('Cave collapse') + + Event.add(DiggyCaveCollapse.events.on_collapse_triggered, on_collapse_triggered) + Event.add(defines.events.on_robot_built_entity, on_built_entity) + Event.add(defines.events.on_robot_built_tile, function (event) + on_built_tile(event.robot.surface, event.item, event.tiles) + end) + Event.add(defines.events.on_player_built_tile, function (event) + on_built_tile(game.surfaces[event.surface_index], event.item, event.tiles) + end) + Event.add(defines.events.on_robot_mined_tile, on_robot_mined_tile) + Event.add(defines.events.on_player_mined_tile, on_player_mined_tile) + Event.add(defines.events.on_robot_mined_entity, on_robot_mined_entity) + Event.add(defines.events.on_built_entity, on_built_entity) + Event.add(Template.events.on_placed_entity, on_placed_entity) + Event.add(defines.events.on_entity_died, on_entity_died) + Event.add(defines.events.on_player_mined_entity, on_mined_entity) + Event.add(Template.events.on_void_removed, on_void_removed) + Event.add(defines.events.on_surface_created, on_surface_created) + + Event.add(defines.events.on_marked_for_deconstruction, function (event) + if (nil ~= support_beam_entities[event.entity.name]) then + event.entity.cancel_deconstruction(Game.get_player_by_index(event.player_index).force) + end + end) + + Event.add(defines.events.on_player_created, function (event) + show_deconstruction_alert_message[event.player_index] = true + end) + + Event.add(defines.events.on_pre_player_mined_item, function (event) + local player_index = event.player_index + if not show_deconstruction_alert_message[player_index] then + return + end + + if (nil ~= support_beam_entities[event.entity.name]) then + require 'features.gui.popup'.player( + Game.get_player_by_index(player_index),[[ +Mining entities such as walls, stone paths, concrete +and rocks, can cause a cave-in, be careful miner! + +Foreman's advice: Place a wall every 4th tile to +prevent a cave-in. Use stone paths and concrete +to reinforce it further. +]] + ) + show_deconstruction_alert_message[player_index] = nil + end + end) + + enable_stress_grid = config.enable_stress_grid + + on_surface_created({surface_index = 1}) + + mask_init(config) + if (config.enable_mask_debug) then + local surface = game.surfaces.nauvis + mask_disc_blur(0, 0, 10, function(x, y, fraction) + Debug.print_grid_value(fraction, surface, {x = x, y = y}) + end) + end + + + if config.enable_debug_commands then + commands.add_command('test-tile-support-range', '<tilename> <range> creates a square of tiles with length <range>. It is spawned one <range> north of the player.', function(cmd) + local params = {} + for param in string.gmatch(cmd.parameter, '%S+') do + table.insert(params, param) + end + + local tilename = params[1] + local range = tonumber(params[2]) + + local position = {x = math.floor(game.player.position.x), y = math.floor(game.player.position.y) - 5 * range - 1} + local surface = game.player.surface + local tiles = {} + local entities = {} + for x = position.x, position.x + range * 5 do + for y = position.y, position.y + range * 5 do + if y % range + x % range == 0 then + insert(entities,{name = "stone-wall", position = {x=x,y=y}}) + end + insert(tiles, {position = {x = x, y = y}, name = tilename}) + + local strength = support_beam_entities[tilename] + if strength then + stress_map_add(surface, {x =x, y=y}, - strength) + end + for _, entity in pairs(surface.find_entities_filtered({position = {x=x,y=y}})) do + pcall(function() + local strength = support_beam_entities[entity.name] + local position = entity.position + entity.die() + if strength then + stress_map_add(surface, position, strength) + end + end + ) + end + end + end + Template.insert(surface, tiles, entities) + end + ) + end + + commands.add_command('toggle-cave-collapse', 'Toggles cave collapse (admins only).', function() + pcall(function() --better safe than sorry + if not game.player or game.player.admin then + cave_collapse_disabled = not cave_collapse_disabled + if cave_collapse_disabled then + game.print("Cave collapse: Disabled.") + else + game.print("Cave collapse: Enabled.") + end + end + end) + end) +end + +-- +--STRESS MAP +-- +--[[-- + Adds a fraction to a given location on the stress_map. Returns the new + fraction value of that position. + + @param stress_map Table of {x,y} + @param position Table with x and y + @param number fraction + + @return number sum of old fraction + new fraction +]] +local function add_fraction(stress_map, x, y, fraction, player_index) + x = 2 * floor(x * 0.5) + y = 2 * floor(y * 0.5) + + local x_t = stress_map[x] + if not x_t then + x_t = {} + stress_map[x] = x_t + end + + local value = x_t[y] + if not value then + value = defaultValue + end + + value = value + fraction + + x_t[y] = value + + if (fraction > 0 and value > stress_threshold_causing_collapse) then + script.raise_event( + DiggyCaveCollapse.events.on_collapse_triggered, + {surface = game.surfaces[stress_map.surface_index], position = {x = x, y = y}, player_index = player_index} + ) + end + if (enable_stress_grid) then + local surface = game.surfaces[stress_map.surface_index] + Debug.print_colored_grid_value(value, surface, {x = x, y = y}, 4, 0.5, false, + value / stress_threshold_causing_collapse, {r = 0, g = 1, b = 0}, {r = 1, g = -1, b = 0}, + {r = 0, g = 1, b = 0}, {r = 1, g = 1, b = 1}) + end + return value +end + +on_surface_created = function (event) + stress_map_storage[event.surface_index] = {} + + local map = stress_map_storage[event.surface_index] + + map['surface_index'] = event.surface_index + map[1] = {index = 1} + map[2] = {index = 2} + map[3] = {index = 3} + map[4] = {index = 4} +end + +--[[-- + Checks whether a tile's pressure is within a given threshold and calls the handler if not. + @param surface LuaSurface + @param position Position with x and y + @param number threshold + @param callback +]] +stress_map_check_stress_in_threshold = function(surface, position, threshold, callback) + local stress_map = stress_map_storage[surface.index] + local value = add_fraction(stress_map, position.x, position.y, 0) + + if (value >= stress_threshold_causing_collapse - threshold) then + callback(surface, position) + end +end + +stress_map_add = function(surface, position, factor, no_blur, player_index) + local x_start = floor(position.x) + local y_start = floor(position.y) + + local stress_map = stress_map_storage[surface.index] + if not stress_map then + return + end + + if no_blur then + add_fraction(stress_map, x_start, y_start, factor, player_index) + return + end + + for x = -radius, radius do + for y = -radius, radius do + local value = 0 + local distance_sq = x * x + y * y + if distance_sq <= center_radius_sq then + value = center_value + elseif distance_sq <= disc_radius_sq then + value = disc_value + elseif distance_sq <= radius_sq then + value = ring_value + end + if abs(value) > 0.001 then + add_fraction(stress_map, x + x_start, y + y_start, value * factor, player_index) + end + end + end +end + +DiggyCaveCollapse.stress_map_add = stress_map_add + +-- +-- MASK +-- + +function mask_init(config) + n = config.mask_size + + ring_weight = config.mask_relative_ring_weights[1] + disc_weight = config.mask_relative_ring_weights[2] + center_weight = config.mask_relative_ring_weights[3] + + radius = floor(n * 0.5) + + radius_sq = (radius + 0.2) * (radius + 0.2) + center_radius_sq = radius_sq / 9 + disc_radius_sq = radius_sq * 4 / 9 + + for x = -radius, radius do + for y = -radius, radius do + local distance_sq = x * x + y * y + if distance_sq <= center_radius_sq then + disc_blur_sum = disc_blur_sum + center_weight + elseif distance_sq <= disc_radius_sq then + disc_blur_sum = disc_blur_sum + disc_weight + elseif distance_sq <= radius_sq then + disc_blur_sum = disc_blur_sum + ring_weight + end + end + end + center_value = center_weight / disc_blur_sum + disc_value = disc_weight / disc_blur_sum + ring_value = ring_weight / disc_blur_sum +end + +--[[-- + Applies a blur + Applies the disc in 3 discs: center, (middle) disc and (outer) ring. + The relative weights for tiles in a disc are: + center: 3/3 + disc: 2/3 + ring: 1/3 + The sum of all values is 1 + + @param x_start number center point + @param y_start number center point + @param factor the factor to multiply the cell value with (value = cell_value * factor) + @param callback function to execute on each tile within the mask callback(x, y, value) +]] +mask_disc_blur = function(x_start, y_start, factor, callback) + x_start = floor(x_start) + y_start = floor(y_start) + for x = -radius, radius do + for y = -radius, radius do + local value = 0 + local distance_sq = x * x + y * y + if distance_sq <= center_radius_sq then + value = center_value + elseif distance_sq <= disc_radius_sq then + value = disc_value + elseif distance_sq <= radius_sq then + value = ring_value + end + if abs(value) > 0.001 then + callback(x_start + x, y_start + y, value * factor) + end + end + end +end + +function DiggyCaveCollapse.get_extra_map_info(config) + return [[Alien Spawner, aliens might spawn when mining! +Place stone walls, stone paths and (refined) concrete to reinforce the mine. If you see cracks appear, run!]] +end + +return DiggyCaveCollapse diff --git a/map_gen/Diggy/Feature/DiggyHole.lua b/map_gen/Diggy/Feature/DiggyHole.lua index 264eb4c1..fdb852d1 100644 --- a/map_gen/Diggy/Feature/DiggyHole.lua +++ b/map_gen/Diggy/Feature/DiggyHole.lua @@ -1,307 +1,307 @@ ---[[-- info - Provides the ability to "mine" through out-of-map tiles by destroying or - mining rocks next to it. -]] - --- dependencies -local Event = require 'utils.event' -local Global = require 'utils.global' -local Game = require 'utils.game' -local Scanner = require 'map_gen.Diggy.Scanner' -local Template = require 'map_gen.Diggy.Template' -local ScoreTable = require 'map_gen.Diggy.ScoreTable' -local Debug = require 'map_gen.Diggy.Debug' -local insert = table.insert -local random = math.random - --- todo remove this dependency -local ResourceConfig = require 'map_gen.Diggy.Config'.features.ScatteredResources - -local Perlin = require 'map_gen.shared.perlin_noise' -local Simplex = require 'map_gen.shared.simplex_noise' - --- this -local DiggyHole = {} - --- keeps track of the amount of times per player when they mined with a full inventory in a row -local full_inventory_mining_cache = {} - -Global.register({ - full_inventory_mining_cache = full_inventory_mining_cache, -}, function (tbl) - full_inventory_mining_cache = tbl.full_inventory_mining_cache -end) - -local function reset_player_full_inventory_cache(player) - if not full_inventory_mining_cache[player.index] then - return - end - - full_inventory_mining_cache[player.index] = nil -end - -local full_inventory_message = 'Miner, you have a full inventory!\n\nMake sure to empty it before you continue digging.' - -local function trigger_inventory_warning(player) - local player_index = player.index - local count = full_inventory_mining_cache[player_index] - if not count then - full_inventory_mining_cache[player_index] = 1 - player.print('## - ' .. full_inventory_message, {r = 1, g = 1, b = 0, a = 1}) - player.play_sound{path='utility/new_objective', volume_modifier = 1 } - return - end - - full_inventory_mining_cache[player_index] = count + 1 - - if count % 5 == 0 then - require 'features.gui.popup'.player(player, full_inventory_message) - end -end - ---[[-- - Triggers a diggy diggy hole for a given sand-rock-big or rock-huge. - - Will return true even if the tile behind it is immune. - - @param entity LuaEntity -]] -local function diggy_hole(entity) - if ((entity.name ~= 'sand-rock-big') and (entity.name ~= 'rock-huge')) then - return - end - - local tiles = {} - local rocks = {} - local surface = entity.surface - local position = entity.position - local x = position.x - local y = position.y - - local out_of_map_found = Scanner.scan_around_position(surface, position, 'out-of-map'); - local distance = ResourceConfig.distance(x, y) - - -- source of noise for resource generation - -- index determines offset - -- '-1' is reserved for cluster mode - -- compound clusters use as many indexes as needed > 1 - local base_seed - local function seeded_noise(surface, x, y, index, sources) - base_seed = base_seed or surface.map_gen_settings.seed + surface.index + 4000 - local noise = 0 - for _, settings in ipairs(sources) do - settings.type = settings.type or 'perlin' - settings.offset = settings.offset or 0 - if settings.type == 'zero' then - noise = noise + 0 - elseif settings.type == 'one' then - noise = noise + settings.weight * 1 - elseif settings.type == 'perlin' then - noise = noise + settings.weight * Perlin.noise(x/settings.variance, y/settings.variance, - base_seed + 2000*index + settings.offset) - elseif settings.type == 'simplex' then - noise = noise + settings.weight * Simplex.d2(x/settings.variance, y/settings.variance, - base_seed + 2000*index + settings.offset) - else - Debug.print('noise type \'' .. settings.type .. '\' not recognized') - end - - end - return noise - end - - -- global config values - local resource_richness_weights = ResourceConfig.resource_richness_weights - local resource_richness_weights_sum = 0 - for _, weight in pairs(resource_richness_weights) do - resource_richness_weights_sum = resource_richness_weights_sum + weight - end - - local s_resource_weights = ResourceConfig.scattered_resource_weights - local s_resource_weights_sum = 0 - for _, weight in pairs(s_resource_weights) do - s_resource_weights_sum = s_resource_weights_sum + weight - end - - -- compound cluster spawning - local c_mode = ResourceConfig.cluster_mode --- local c_clusters = Config.features.ScatteredResources.clusters - local c_clusters = require(ResourceConfig.cluster_file_location) - if ('table' ~= type(c_clusters)) then - error('cluster_file_location invalid') - end - - local c_count = 0 - for _, cluster in ipairs(c_clusters) do - c_count = c_count + 1 - cluster.weights_sum = 0 - for _, weight in pairs(cluster.weights) do - cluster.weights_sum = cluster.weights_sum + weight - end - end - - local function spawn_cluster_resource(surface, x, y, cluster_index, cluster) - for name, weight in pairs(cluster.weights) do - if name == 'skip' then return false end - end - return true - end - - local huge_rock_inserted = false - for _, position in pairs(out_of_map_found) do - insert(tiles, {name = 'dirt-' .. random(1, 7), position = position}) --- if (random() > 0.50) then --- insert(rocks, {name = 'rock-huge', position = position}) - - - if c_mode then - for index,cluster in ipairs(c_clusters) do - if distance >= cluster.min_distance and cluster.noise_settings.type ~= 'skip' then - if cluster.noise_settings.type == "connected_tendril" then - local noise = seeded_noise(surface, x, y, index, cluster.noise_settings.sources) - if -1 * cluster.noise_settings.threshold < noise and noise < cluster.noise_settings.threshold then - if spawn_cluster_resource(surface, x, y, index, cluster) then - insert(rocks, {name = 'rock-huge', position = position}) - huge_rock_inserted = true - end - end - elseif cluster.noise_settings.type == "fragmented_tendril" then - local noise1 = seeded_noise(surface, x, y, index, cluster.noise_settings.sources) - local noise2 = seeded_noise(surface, x, y, index, cluster.noise_settings.discriminator) - if -1 * cluster.noise_settings.threshold < noise1 and noise1 < cluster.noise_settings.threshold - and -1 * cluster.noise_settings.discriminator_threshold < noise2 - and noise2 < cluster.noise_settings.discriminator_threshold then - if spawn_cluster_resource(surface, x, y, index, cluster) then - insert(rocks, {name = 'rock-huge', position = position}) - huge_rock_inserted = true - end - end - else - local noise = seeded_noise(surface, x, y, index, cluster.noise_settings.sources) - if noise >= cluster.noise_settings.threshold then - if spawn_cluster_resource(surface, x, y, index, cluster) then - insert(rocks, {name = 'rock-huge', position = position}) - huge_rock_inserted = true - end - end - end - end - end - end - - if (huge_rock_inserted == false) then - insert(rocks, {name = 'sand-rock-big', position = position}) - end - end - - Template.insert(surface, tiles, rocks) -end - -local artificial_tiles = { - ['stone-brick'] = true, - ['stone-path'] = true, - ['concrete'] = true, - ['hazard-concrete-left'] = true, - ['hazard-concrete-right'] = true, - ['refined-concrete'] = true, - ['refined-hazard-concrete-left'] = true, - ['refined-hazard-concrete-right'] = true, -} - -local function on_mined_tile(surface, tiles) - local new_tiles = {} - - for _, tile in pairs(tiles) do - if (artificial_tiles[tile.old_tile.name]) then - insert(new_tiles, { name = 'dirt-' .. random(1, 7), position = tile.position}) - end - end - - Template.insert(surface, new_tiles, {}) -end - ---[[-- - Registers all event handlers. -]] -function DiggyHole.register(config) - ScoreTable.reset('Void removed') - - Event.add(defines.events.on_entity_died, function (event) - diggy_hole(event.entity) - end) - - local enable_digging_warning = config.enable_digging_warning - - Event.add(defines.events.on_player_mined_entity, function (event) - local entity = event.entity - local name = entity.name - - if name == 'sand-rock-big' or name == 'rock-huge' then - event.buffer.remove({name = 'coal', count = 100}) - - -- this logic can be replaced once we've fully replaced the stone to surface functionality - if enable_digging_warning then - local player = Game.get_player_by_index(event.player_index) - if player and player.valid then - if player.get_main_inventory().can_insert({name = 'stone'}) then - reset_player_full_inventory_cache(player) - else - trigger_inventory_warning(player) - end - end - end - end - - diggy_hole(entity) - end) - - Event.add(defines.events.on_robot_mined_tile, function (event) - on_mined_tile(event.robot.surface, event.tiles) - end) - - Event.add(defines.events.on_player_mined_tile, function (event) - on_mined_tile(game.surfaces[event.surface_index], event.tiles) - end) - - Event.add(Template.events.on_void_removed, function () - ScoreTable.increment('Void removed') - end) - - if config.enable_debug_commands then - commands.add_command('clear-void', '<left top x> <left top y> <width> <height> <surface index> triggers Template.insert for the given area.', function(cmd) - local params = {} - local args = cmd.parameter or '' - for param in string.gmatch(args, '%S+') do - table.insert(params, param) - end - - if (#params ~= 5) then - game.player.print('/clear-void requires exactly 5 arguments: <left top x> <left top y> <width> <height> <surface index>') - return - end - - local left_top_x = tonumber(params[1]) - local left_top_y = tonumber(params[2]) - local width = tonumber(params[3]) - local height = tonumber(params[4]) - local surface_index = params[5] - local tiles = {} - local entities = {} - - for x = 0, width do - for y = 0, height do - insert(tiles, {name = 'dirt-' .. random(1, 7), position = {x = x + left_top_x, y = y + left_top_y}}) - end - end - - Template.insert(game.surfaces[surface_index], tiles, entities) - end - ) - end -end - -function DiggyHole.on_init() - game.forces.player.technologies['landfill'].enabled = false -end - -return DiggyHole +--[[-- info + Provides the ability to "mine" through out-of-map tiles by destroying or + mining rocks next to it. +]] + +-- dependencies +local Event = require 'utils.event' +local Global = require 'utils.global' +local Game = require 'utils.game' +local Scanner = require 'map_gen.Diggy.Scanner' +local Template = require 'map_gen.Diggy.Template' +local ScoreTable = require 'map_gen.Diggy.ScoreTable' +local Debug = require 'map_gen.Diggy.Debug' +local insert = table.insert +local random = math.random + +-- todo remove this dependency +local ResourceConfig = require 'map_gen.Diggy.Config'.features.ScatteredResources + +local Perlin = require 'map_gen.shared.perlin_noise' +local Simplex = require 'map_gen.shared.simplex_noise' + +-- this +local DiggyHole = {} + +-- keeps track of the amount of times per player when they mined with a full inventory in a row +local full_inventory_mining_cache = {} + +Global.register({ + full_inventory_mining_cache = full_inventory_mining_cache, +}, function (tbl) + full_inventory_mining_cache = tbl.full_inventory_mining_cache +end) + +local function reset_player_full_inventory_cache(player) + if not full_inventory_mining_cache[player.index] then + return + end + + full_inventory_mining_cache[player.index] = nil +end + +local full_inventory_message = 'Miner, you have a full inventory!\n\nMake sure to empty it before you continue digging.' + +local function trigger_inventory_warning(player) + local player_index = player.index + local count = full_inventory_mining_cache[player_index] + if not count then + full_inventory_mining_cache[player_index] = 1 + player.print('## - ' .. full_inventory_message, {r = 1, g = 1, b = 0, a = 1}) + player.play_sound{path='utility/new_objective', volume_modifier = 1 } + return + end + + full_inventory_mining_cache[player_index] = count + 1 + + if count % 5 == 0 then + require 'features.gui.popup'.player(player, full_inventory_message) + end +end + +--[[-- + Triggers a diggy diggy hole for a given sand-rock-big or rock-huge. + + Will return true even if the tile behind it is immune. + + @param entity LuaEntity +]] +local function diggy_hole(entity) + if ((entity.name ~= 'sand-rock-big') and (entity.name ~= 'rock-huge')) then + return + end + + local tiles = {} + local rocks = {} + local surface = entity.surface + local position = entity.position + local x = position.x + local y = position.y + + local out_of_map_found = Scanner.scan_around_position(surface, position, 'out-of-map'); + local distance = ResourceConfig.distance(x, y) + + -- source of noise for resource generation + -- index determines offset + -- '-1' is reserved for cluster mode + -- compound clusters use as many indexes as needed > 1 + local base_seed + local function seeded_noise(surface, x, y, index, sources) + base_seed = base_seed or surface.map_gen_settings.seed + surface.index + 4000 + local noise = 0 + for _, settings in ipairs(sources) do + settings.type = settings.type or 'perlin' + settings.offset = settings.offset or 0 + if settings.type == 'zero' then + noise = noise + 0 + elseif settings.type == 'one' then + noise = noise + settings.weight * 1 + elseif settings.type == 'perlin' then + noise = noise + settings.weight * Perlin.noise(x/settings.variance, y/settings.variance, + base_seed + 2000*index + settings.offset) + elseif settings.type == 'simplex' then + noise = noise + settings.weight * Simplex.d2(x/settings.variance, y/settings.variance, + base_seed + 2000*index + settings.offset) + else + Debug.print('noise type \'' .. settings.type .. '\' not recognized') + end + + end + return noise + end + + -- global config values + local resource_richness_weights = ResourceConfig.resource_richness_weights + local resource_richness_weights_sum = 0 + for _, weight in pairs(resource_richness_weights) do + resource_richness_weights_sum = resource_richness_weights_sum + weight + end + + local s_resource_weights = ResourceConfig.scattered_resource_weights + local s_resource_weights_sum = 0 + for _, weight in pairs(s_resource_weights) do + s_resource_weights_sum = s_resource_weights_sum + weight + end + + -- compound cluster spawning + local c_mode = ResourceConfig.cluster_mode +-- local c_clusters = Config.features.ScatteredResources.clusters + local c_clusters = require(ResourceConfig.cluster_file_location) + if ('table' ~= type(c_clusters)) then + error('cluster_file_location invalid') + end + + local c_count = 0 + for _, cluster in ipairs(c_clusters) do + c_count = c_count + 1 + cluster.weights_sum = 0 + for _, weight in pairs(cluster.weights) do + cluster.weights_sum = cluster.weights_sum + weight + end + end + + local function spawn_cluster_resource(surface, x, y, cluster_index, cluster) + for name, weight in pairs(cluster.weights) do + if name == 'skip' then return false end + end + return true + end + + local huge_rock_inserted = false + for _, position in pairs(out_of_map_found) do + insert(tiles, {name = 'dirt-' .. random(1, 7), position = position}) +-- if (random() > 0.50) then +-- insert(rocks, {name = 'rock-huge', position = position}) + + + if c_mode then + for index,cluster in ipairs(c_clusters) do + if distance >= cluster.min_distance and cluster.noise_settings.type ~= 'skip' then + if cluster.noise_settings.type == "connected_tendril" then + local noise = seeded_noise(surface, x, y, index, cluster.noise_settings.sources) + if -1 * cluster.noise_settings.threshold < noise and noise < cluster.noise_settings.threshold then + if spawn_cluster_resource(surface, x, y, index, cluster) then + insert(rocks, {name = 'rock-huge', position = position}) + huge_rock_inserted = true + end + end + elseif cluster.noise_settings.type == "fragmented_tendril" then + local noise1 = seeded_noise(surface, x, y, index, cluster.noise_settings.sources) + local noise2 = seeded_noise(surface, x, y, index, cluster.noise_settings.discriminator) + if -1 * cluster.noise_settings.threshold < noise1 and noise1 < cluster.noise_settings.threshold + and -1 * cluster.noise_settings.discriminator_threshold < noise2 + and noise2 < cluster.noise_settings.discriminator_threshold then + if spawn_cluster_resource(surface, x, y, index, cluster) then + insert(rocks, {name = 'rock-huge', position = position}) + huge_rock_inserted = true + end + end + else + local noise = seeded_noise(surface, x, y, index, cluster.noise_settings.sources) + if noise >= cluster.noise_settings.threshold then + if spawn_cluster_resource(surface, x, y, index, cluster) then + insert(rocks, {name = 'rock-huge', position = position}) + huge_rock_inserted = true + end + end + end + end + end + end + + if (huge_rock_inserted == false) then + insert(rocks, {name = 'sand-rock-big', position = position}) + end + end + + Template.insert(surface, tiles, rocks) +end + +local artificial_tiles = { + ['stone-brick'] = true, + ['stone-path'] = true, + ['concrete'] = true, + ['hazard-concrete-left'] = true, + ['hazard-concrete-right'] = true, + ['refined-concrete'] = true, + ['refined-hazard-concrete-left'] = true, + ['refined-hazard-concrete-right'] = true, +} + +local function on_mined_tile(surface, tiles) + local new_tiles = {} + + for _, tile in pairs(tiles) do + if (artificial_tiles[tile.old_tile.name]) then + insert(new_tiles, { name = 'dirt-' .. random(1, 7), position = tile.position}) + end + end + + Template.insert(surface, new_tiles, {}) +end + +--[[-- + Registers all event handlers. +]] +function DiggyHole.register(config) + ScoreTable.reset('Void removed') + + Event.add(defines.events.on_entity_died, function (event) + diggy_hole(event.entity) + end) + + local enable_digging_warning = config.enable_digging_warning + + Event.add(defines.events.on_player_mined_entity, function (event) + local entity = event.entity + local name = entity.name + + if name == 'sand-rock-big' or name == 'rock-huge' then + event.buffer.remove({name = 'coal', count = 100}) + + -- this logic can be replaced once we've fully replaced the stone to surface functionality + if enable_digging_warning then + local player = Game.get_player_by_index(event.player_index) + if player and player.valid then + if player.get_main_inventory().can_insert({name = 'stone'}) then + reset_player_full_inventory_cache(player) + else + trigger_inventory_warning(player) + end + end + end + end + + diggy_hole(entity) + end) + + Event.add(defines.events.on_robot_mined_tile, function (event) + on_mined_tile(event.robot.surface, event.tiles) + end) + + Event.add(defines.events.on_player_mined_tile, function (event) + on_mined_tile(game.surfaces[event.surface_index], event.tiles) + end) + + Event.add(Template.events.on_void_removed, function () + ScoreTable.increment('Void removed') + end) + + if config.enable_debug_commands then + commands.add_command('clear-void', '<left top x> <left top y> <width> <height> <surface index> triggers Template.insert for the given area.', function(cmd) + local params = {} + local args = cmd.parameter or '' + for param in string.gmatch(args, '%S+') do + table.insert(params, param) + end + + if (#params ~= 5) then + game.player.print('/clear-void requires exactly 5 arguments: <left top x> <left top y> <width> <height> <surface index>') + return + end + + local left_top_x = tonumber(params[1]) + local left_top_y = tonumber(params[2]) + local width = tonumber(params[3]) + local height = tonumber(params[4]) + local surface_index = params[5] + local tiles = {} + local entities = {} + + for x = 0, width do + for y = 0, height do + insert(tiles, {name = 'dirt-' .. random(1, 7), position = {x = x + left_top_x, y = y + left_top_y}}) + end + end + + Template.insert(game.surfaces[surface_index], tiles, entities) + end + ) + end +end + +function DiggyHole.on_init() + game.forces.player.technologies['landfill'].enabled = false +end + +return DiggyHole diff --git a/map_gen/Diggy/Feature/MarketExchange.lua b/map_gen/Diggy/Feature/MarketExchange.lua index 9d6b0a92..3d23506a 100644 --- a/map_gen/Diggy/Feature/MarketExchange.lua +++ b/map_gen/Diggy/Feature/MarketExchange.lua @@ -1,649 +1,649 @@ ---[[-- info - Provides the ability to purchase items from the market. -]] - --- dependencies -local Event = require 'utils.event' -local Token = require 'utils.global_token' -local Task = require 'utils.Task' -local Gui = require 'utils.gui' -local Debug = require 'map_gen.Diggy.Debug' -local Template = require 'map_gen.Diggy.Template' -local Global = require 'utils.global' -local Game = require 'utils.game' -local MarketUnlockables = require 'map_gen.Diggy.MarketUnlockables' -local calculate_level = MarketUnlockables.calculate_level -local insert = table.insert -local max = math.max -local utils = require 'utils.utils' -local prefix = '## - ' - --- this -local MarketExchange = {} - -local config = {} - -local stone_tracker = { - stone_sent_to_surface = 0, - previous_stone_sent_to_surface = 0, - current_level = 0, -} - -local stone_collecting = { - initial_value = 0, - active_modifier = 0, - research_modifier = 0, - market_modifier = 0, -} - -local mining_efficiency = { - active_modifier = 0, - research_modifier = 0, - market_modifier = 0, -} - -local inventory_slots = { - active_modifier = 0, - research_modifier = 0, - market_modifier = 0, -} - -Global.register({ - stone_collecting = stone_collecting, - stone_tracker = stone_tracker, - mining_efficiency = mining_efficiency, - inventory_slots = inventory_slots, -}, function(tbl) - stone_collecting = tbl.stone_collecting - stone_tracker = tbl.stone_tracker - mining_efficiency = tbl.mining_efficiency - inventory_slots = tbl.inventory_slots -end) - -local function send_stone_to_surface(total) - stone_tracker.previous_stone_sent_to_surface = stone_tracker.stone_sent_to_surface - stone_tracker.stone_sent_to_surface = stone_tracker.stone_sent_to_surface + total -end - -local on_market_timeout_finished = Token.register(function(params) - Template.market(params.surface, params.position, params.player_force, {}) - - local tiles = {} - for _, position in pairs(params.void_chest_tiles) do - insert(tiles, {name = 'tutorial-grid', position = position}) - end - - params.surface.set_tiles(tiles) -end) - -local function update_mining_speed(force) - -- remove the current buff - local old_modifier = force.manual_mining_speed_modifier - mining_efficiency.active_modifier - - -- update the active modifier - mining_efficiency.active_modifier = mining_efficiency.research_modifier + mining_efficiency.market_modifier - - -- add the new active modifier to the non-buffed modifier - force.manual_mining_speed_modifier = old_modifier + mining_efficiency.active_modifier -end - -local function update_inventory_slots(force) - -- remove the current buff - local old_modifier = force.character_inventory_slots_bonus - inventory_slots.active_modifier - - -- update the active modifier - inventory_slots.active_modifier = inventory_slots.research_modifier + inventory_slots.market_modifier - - -- add the new active modifier to the non-buffed modifier - force.character_inventory_slots_bonus = old_modifier + inventory_slots.active_modifier -end - -local function update_stone_collecting() - -- remove the current buff - local old_modifier = stone_collecting.initial_value - stone_collecting.active_modifier - - -- update the active modifier - stone_collecting.active_modifier = stone_collecting.research_modifier + stone_collecting.market_modifier - - -- add the new active modifier to the non-buffed modifier - stone_collecting.initial_value = old_modifier + stone_collecting.active_modifier -end - - ---Handles the updating of market items when unlocked, also handles the buffs -local function update_market_contents(market) - if (stone_tracker.previous_stone_sent_to_surface == stone_tracker.stone_sent_to_surface) then - return - end - - local should_update_mining_speed = false - local should_update_inventory_slots = false - local should_update_stone_collecting = false - local add_market_item - local old_level = stone_tracker.current_level - local print = game.print - local item_unlocked = false - - if (calculate_level(stone_tracker.current_level+1) <= stone_tracker.stone_sent_to_surface) then - stone_tracker.current_level = stone_tracker.current_level + 1 - end - - for _, unlockable in pairs(config.unlockables) do - local stone_unlock = calculate_level(unlockable.level) - local is_in_range = stone_unlock > stone_tracker.previous_stone_sent_to_surface and stone_unlock <= stone_tracker.stone_sent_to_surface - - -- only add the item to the market if it's between the old and new stone range - if (is_in_range and unlockable.type == 'market') then - add_market_item = add_market_item or market.add_market_item - - local name = unlockable.prototype.name - local price = unlockable.prototype.price - if type(price) == 'number' then - add_market_item({ - price = {{config.currency_item, price}}, - offer = {type = 'give-item', item = name, count = 1} - }) - elseif type(price) == 'table' then - add_market_item({ - price = price, - offer = {type = 'give-item', item = name, count = 1} - }) - end - item_unlocked = true - - end - end - - MarketExchange.update_gui() - - if (old_level < stone_tracker.current_level) then - if item_unlocked then - print(prefix..'We have reached level ' .. stone_tracker.current_level .. '! New items are available from the market!') - else - print(prefix..'We have reached level ' .. stone_tracker.current_level .. '!') - end - for _, buffs in pairs(config.buffs) do - if (buffs.prototype.name == 'mining_speed') then - local value = buffs.prototype.value - Debug.print('Mining Foreman: Increased mining speed by ' .. value .. '%!') - should_update_mining_speed = true - mining_efficiency.market_modifier = mining_efficiency.market_modifier + (value / 100) - elseif (buffs.prototype.name == 'inventory_slot') then - local value = buffs.prototype.value - Debug.print('Mining Foreman: Increased inventory slots by ' .. value .. '!') - should_update_inventory_slots = true - inventory_slots.market_modifier = inventory_slots.market_modifier + value - elseif (buffs.prototype.name == 'stone_automation') then - local value = buffs.prototype.value - if (stone_tracker.current_level == 1) then - print('Mining Foreman: We can now automatically send stone to the surface from a chest below the market!') - else - Debug.print('Mining Foreman: We can now automatically send ' .. value .. ' more stones!') - end - should_update_stone_collecting = true - stone_collecting.market_modifier = stone_collecting.market_modifier + value - end - end - end - - local force - - if (should_update_mining_speed) then - force = force or game.forces.player - update_mining_speed(force) - end - - if (should_update_inventory_slots) then - force = force or game.forces.player - update_inventory_slots(force) - end - - if (should_update_stone_collecting) then - update_stone_collecting() - end -end - -local function on_research_finished(event) - local force = game.forces.player - local current_modifier = mining_efficiency.research_modifier - local new_modifier = force.mining_drill_productivity_bonus * config.mining_speed_productivity_multiplier * 0.5 - - if (current_modifier == new_modifier) then - -- something else was researched - return - end - - mining_efficiency.research_modifier = new_modifier - inventory_slots.research_modifier = force.mining_drill_productivity_bonus * 50 -- 1 per level - stone_collecting.research_modifier = force.mining_drill_productivity_bonus * 1250 -- 25 per level - - update_inventory_slots(force) - update_mining_speed(force) - update_stone_collecting() -end - -local function redraw_title(data) - data.frame.caption = utils.comma_value(stone_tracker.stone_sent_to_surface) .. ' ' .. config.currency_item .. ' sent to the surface' -end - -local function get_data(unlocks, stone, type) - local result = {} - - for _, data in pairs(unlocks) do - if calculate_level(data.level) == stone and data.type == type then - insert(result, data) - end - end - - return result -end - -local tag_label_stone = Gui.uid_name() -local tag_label_buff = Gui.uid_name() -local tag_label_item = Gui.uid_name() - -local function apply_heading_style(style, width) - style.font = 'default-bold' - style.width = width -end - -local function redraw_heading(data, header) - local head_condition = (header == 1) - local frame = (head_condition) and data.market_list_heading or data.buff_list_heading - local header_caption = (head_condition) and 'Reward Item' or 'Reward Buff' - Gui.clear(frame) - - local heading_table = frame.add({type = 'table', column_count = 2}) - apply_heading_style(heading_table.add({type = 'label', name = tag_label_stone, caption = 'Requirement'}).style, 100) - apply_heading_style(heading_table.add({type = 'label', name = tag_label_buff, caption = header_caption}).style, 220) -end - -local function redraw_progressbar(data) - - local flow = data.market_progressbars - Gui.clear(flow) - - -- progress bar for next level - local act_stone = (stone_tracker.current_level ~= 0) and calculate_level(stone_tracker.current_level) or 0 - local next_stone = calculate_level(stone_tracker.current_level+1) - - local range = next_stone - act_stone - local sent = stone_tracker.stone_sent_to_surface - act_stone - local percentage = (math.floor((sent / range)*1000))*0.001 - percentage = (percentage < 0) and (percentage*-1) or percentage - - apply_heading_style(flow.add({type = 'label', tooltip = 'Currently at level: ' .. stone_tracker.current_level .. '\nNext level at: ' .. utils.comma_value(next_stone) ..'\nRemaining stone: ' .. utils.comma_value(range - sent), name = 'Diggy.MarketExchange.Frame.Progress.Level', caption = 'Progress to next level:'}).style) - local level_progressbar = flow.add({type = 'progressbar', tooltip = percentage * 100 .. '% stone to next level'}) - level_progressbar.style.width = 350 - level_progressbar.value = percentage -end - -local function redraw_table(data) - local market_scroll_pane = data.market_scroll_pane - Gui.clear(market_scroll_pane) - - local buffs = {} - local items = {} - local last_stone = 0 - local number_of_rows = 0 - local row = {} - - -- create the progress bars in the window - redraw_progressbar(data) - - -- create table headings - redraw_heading(data, 1) - - -- create table - for i = 1, #config.unlockables do - if calculate_level(config.unlockables[i].level) ~= last_stone then - - -- get items and buffs for each stone value - items = get_data(config.unlockables, calculate_level(config.unlockables[i].level), 'market') - - -- get number of rows - number_of_rows = max(#buffs, #items) - - -- loop through buffs and items for number of rows - for j = 1, number_of_rows do - local result = {} - local item = items[j] - local level = item.level - - -- 1st column - result[6] = calculate_level(level) - result[1] = 'Level ' ..level - -- 3rd column - if items[j] ~= nil then - result[3] = '+ ' .. item.prototype.name - else - result[3] = '' - end - -- indicator to stop print stone number - if j > 1 then - result[4] = true - else - result[4] = false - end - -- indicator to draw horizontal line - if j == number_of_rows then - result[5] = true - else - result[5] = false - end - - insert(row, result) - end - end - - -- save lastStone - last_stone = calculate_level(config.unlockables[i].level) - end - - -- print table - for _, unlockable in pairs(row) do - local is_unlocked = unlockable[6] <= stone_tracker.stone_sent_to_surface - local list = market_scroll_pane.add {type = 'table', column_count = 2 } - - list.style.horizontal_spacing = 16 - - local caption = '' - if unlockable[4] ~= true then - caption = unlockable[1] - else - caption = '' - end - local tag_stone = list.add {type = 'label', name = tag_label_stone, caption = caption} - tag_stone.style.minimal_width = 100 - - local tag_items = list.add {type = 'label', name = tag_label_item, caption = unlockable[3]} - tag_items.style.minimal_width = 220 - - -- draw horizontal line - if unlockable[5] == true then - list.draw_horizontal_line_after_headers = true - end - - if (is_unlocked) then - tag_stone.style.font_color = {r = 1, g = 1, b = 1 } - tag_items.style.font_color = {r = 1, g = 1, b = 1 } - else - tag_stone.style.font_color = {r = 0.5, g = 0.5, b = 0.5 } - tag_items.style.font_color = {r = 0.5, g = 0.5, b = 0.5 } - end - end -end - -local function redraw_buff(data) --! Almost equals to the redraw_table() function ! - local buff_scroll_pane = data.buff_scroll_pane - Gui.clear(buff_scroll_pane) - - local buffs = {} - local number_of_rows = 0 - local row = {} - - for i = 1, #config.buffs do - -- get items and buffs for each stone value - buffs = config.buffs - - local result = {} - - -- 1st column - result[1] = 'All levels' - - -- 2nd column - if buffs[i].prototype.name == 'mining_speed' then - result[2] = '+ '.. buffs[i].prototype.value .. '% mining speed' - elseif buffs[i].prototype.name == 'inventory_slot' then - if buffs[i].prototype.value > 1 then - result[2] = '+ '.. buffs[i].prototype.value .. ' inventory slots' - else - result[2] = '+ '.. buffs[i].prototype.value .. ' inventory slot' - end - elseif buffs[i].prototype.name == 'stone_automation' then - result[2] = '+ '.. buffs[i].prototype.value .. ' stones automatically sent' - else - result[2] = 'Description missing: unknown buff. Please contact admin' - end - - -- 3rd column - result[3] = '' - -- indicator to stop print level number - if i > 1 then - result[4] = true - else - result[4] = false - end - insert(row, result) - end - for _, unlockable in pairs(row) do - local list = buff_scroll_pane.add {type = 'table', column_count = 2 } - list.style.horizontal_spacing = 16 - - local caption = '' - if unlockable[4] ~= true then - caption = unlockable[1] - else - caption = '' - end - local tag_stone = list.add {type = 'label', name = buff_tag_label_stone, caption = caption} - tag_stone.style.minimal_width = 100 - - local tag_buffs = list.add {type = 'label', name = buff_tag_label_buff, caption = unlockable[2]} - tag_buffs.style.minimal_width = 220 - - tag_stone.style.font_color = {r = 1, g = 1, b = 1 } - tag_buffs.style.font_color = {r = 1, g = 1, b = 1 } - end -end - -local function on_market_item_purchased(event) - if (1 ~= event.offer_index) then - return - end - - local sum = config.stone_to_surface_amount * event.count - Game.print_player_floating_text(event.player_index, '-' .. sum .. ' stone', {r = 0.6, g = 0.55, b = 0.42}) - - send_stone_to_surface(sum) - update_market_contents(event.market) -end - -local function on_placed_entity(event) - local market = event.entity - if ('market' ~= market.name) then - return - end - - market.add_market_item({ - price = {{config.currency_item, 50}}, - offer = {type = 'nothing', effect_description = 'Send ' .. config.stone_to_surface_amount .. ' ' .. config.currency_item .. ' to the surface. To see the overall progress and rewards, click the market button in the menu.'} - }) - - update_market_contents(market) -end - -function MarketExchange.get_extra_map_info(config) - return 'Market Exchange, trade your stone or send it to the surface' -end - -local function toggle(event) - local player = event.player - local left = player.gui.left - local frame = left['Diggy.MarketExchange.Frame'] - - if (frame and event.trigger == nil) then - Gui.destroy(frame) - return - elseif (frame) then - local data = Gui.get_data(frame) - redraw_title(data) - redraw_progressbar(data) - redraw_table(data) - return - end - - frame = left.add({name = 'Diggy.MarketExchange.Frame', type = 'frame', direction = 'vertical'}) - - local market_progressbars = frame.add({type = 'flow', direction = 'vertical'}) - local market_list_heading = frame.add({type = 'flow', direction = 'horizontal'}) - - local market_scroll_pane = frame.add({type = 'scroll-pane'}) - market_scroll_pane.style.maximal_height = 300 - - local buff_list_heading = frame.add({type = 'flow', direction = 'horizontal'}) - - local buff_scroll_pane = frame.add({type = 'scroll-pane'}) - buff_scroll_pane.style.maximal_height = 100 - - frame.add({ type = 'button', name = 'Diggy.MarketExchange.Button', caption = 'Close'}) - - local data = { - frame = frame, - market_progressbars = market_progressbars, - market_list_heading = market_list_heading, - market_scroll_pane = market_scroll_pane, - buff_list_heading = buff_list_heading, - buff_scroll_pane = buff_scroll_pane, - } - - redraw_title(data) - redraw_table(data) - - redraw_heading(data, 2) - redraw_buff(data) - - Gui.set_data(frame, data) - -end - -local function on_player_created(event) - Game.get_player_by_index(event.player_index).gui.top.add({ - name = 'Diggy.MarketExchange.Button', - type = 'sprite-button', - sprite = 'entity/market', - }) -end - -Gui.on_click('Diggy.MarketExchange.Button', toggle) -Gui.on_custom_close('Diggy.MarketExchange.Frame', function (event) - event.element.destroy() -end) - -function MarketExchange.update_gui() - for _, p in ipairs(game.connected_players) do - local frame = p.gui.left['Diggy.MarketExchange.Frame'] - - if frame and frame.valid then - local data = {player = p, trigger = 'update_gui'} - toggle(data) - --toggle(data) - end - end -end - -function MarketExchange.on_init() - Task.set_timeout_in_ticks(50, on_market_timeout_finished, { - surface = game.surfaces.nauvis, - position = config.market_spawn_position, - player_force = game.forces.player, - void_chest_tiles = config.void_chest_tiles, - }) - - update_mining_speed(game.forces.player) -end - ---[[-- - Registers all event handlers. -]] -function MarketExchange.register(cfg) - config = cfg - - Event.add(defines.events.on_research_finished, on_research_finished) - Event.add(defines.events.on_market_item_purchased, on_market_item_purchased) - Event.add(Template.events.on_placed_entity, on_placed_entity) - Event.add(defines.events.on_player_created, on_player_created) - - local x_min - local y_min - local x_max - local y_max - - for _, position in pairs(config.void_chest_tiles) do - local x = position.x - local y = position.y - - if (nil == x_min or x < x_min) then - x_min = x - end - - if (nil == x_max or x > x_max) then - x_max = x - end - - if (nil == y_min or y < y_min) then - y_min = y - end - - if (nil == y_max or y > y_max) then - y_max = y - end - end - - local area = {{x_min, y_min}, {x_max + 1, y_max + 1}} - local message_x = (x_max + x_min) * 0.5 - local message_y = (y_max + y_min) * 0.5 - - Event.on_nth_tick(config.void_chest_frequency, function () - local send_to_surface = 0 - local surface = game.surfaces.nauvis - local find_entities_filtered = surface.find_entities_filtered - local chests = find_entities_filtered({area = area, type = {'container', 'logistic-container'}}) - local to_fetch = stone_collecting.active_modifier - - for _, chest in pairs(chests) do - local chest_contents = chest.get_inventory(defines.inventory.chest) - local stone_in_chest = chest_contents.get_item_count(config.currency_item) - local delta = to_fetch - - if (stone_in_chest < delta) then - delta = stone_in_chest - end - - if (delta > 0) then - chest_contents.remove({name = config.currency_item, count = delta}) - send_to_surface = send_to_surface + delta - end - end - - if (send_to_surface == 0) then - if (0 == to_fetch) then - return - end - - local message = 'Missing chests below market' - if (#chests > 0) then - message = 'No stone in chests found' - end - - Game.print_floating_text(surface, {x = message_x, y = message_y}, message, { r = 220, g = 100, b = 50}) - return - end - - local markets = find_entities_filtered({name = 'market', position = config.market_spawn_position, limit = 1}) - - if (#markets == 0) then - Debug.print_position(config.market_spawn_position, 'Unable to find a market') - return - end - - local message = send_to_surface .. ' stone sent to the surface' - - Game.print_floating_text(surface, {x = message_x, y = message_y}, message, { r = 0.6, g = 0.55, b = 0.42}) - - send_stone_to_surface(send_to_surface) - update_market_contents(markets[1]) - end) -end - -return MarketExchange +--[[-- info + Provides the ability to purchase items from the market. +]] + +-- dependencies +local Event = require 'utils.event' +local Token = require 'utils.global_token' +local Task = require 'utils.Task' +local Gui = require 'utils.gui' +local Debug = require 'map_gen.Diggy.Debug' +local Template = require 'map_gen.Diggy.Template' +local Global = require 'utils.global' +local Game = require 'utils.game' +local MarketUnlockables = require 'map_gen.Diggy.MarketUnlockables' +local calculate_level = MarketUnlockables.calculate_level +local insert = table.insert +local max = math.max +local utils = require 'utils.utils' +local prefix = '## - ' + +-- this +local MarketExchange = {} + +local config = {} + +local stone_tracker = { + stone_sent_to_surface = 0, + previous_stone_sent_to_surface = 0, + current_level = 0, +} + +local stone_collecting = { + initial_value = 0, + active_modifier = 0, + research_modifier = 0, + market_modifier = 0, +} + +local mining_efficiency = { + active_modifier = 0, + research_modifier = 0, + market_modifier = 0, +} + +local inventory_slots = { + active_modifier = 0, + research_modifier = 0, + market_modifier = 0, +} + +Global.register({ + stone_collecting = stone_collecting, + stone_tracker = stone_tracker, + mining_efficiency = mining_efficiency, + inventory_slots = inventory_slots, +}, function(tbl) + stone_collecting = tbl.stone_collecting + stone_tracker = tbl.stone_tracker + mining_efficiency = tbl.mining_efficiency + inventory_slots = tbl.inventory_slots +end) + +local function send_stone_to_surface(total) + stone_tracker.previous_stone_sent_to_surface = stone_tracker.stone_sent_to_surface + stone_tracker.stone_sent_to_surface = stone_tracker.stone_sent_to_surface + total +end + +local on_market_timeout_finished = Token.register(function(params) + Template.market(params.surface, params.position, params.player_force, {}) + + local tiles = {} + for _, position in pairs(params.void_chest_tiles) do + insert(tiles, {name = 'tutorial-grid', position = position}) + end + + params.surface.set_tiles(tiles) +end) + +local function update_mining_speed(force) + -- remove the current buff + local old_modifier = force.manual_mining_speed_modifier - mining_efficiency.active_modifier + + -- update the active modifier + mining_efficiency.active_modifier = mining_efficiency.research_modifier + mining_efficiency.market_modifier + + -- add the new active modifier to the non-buffed modifier + force.manual_mining_speed_modifier = old_modifier + mining_efficiency.active_modifier +end + +local function update_inventory_slots(force) + -- remove the current buff + local old_modifier = force.character_inventory_slots_bonus - inventory_slots.active_modifier + + -- update the active modifier + inventory_slots.active_modifier = inventory_slots.research_modifier + inventory_slots.market_modifier + + -- add the new active modifier to the non-buffed modifier + force.character_inventory_slots_bonus = old_modifier + inventory_slots.active_modifier +end + +local function update_stone_collecting() + -- remove the current buff + local old_modifier = stone_collecting.initial_value - stone_collecting.active_modifier + + -- update the active modifier + stone_collecting.active_modifier = stone_collecting.research_modifier + stone_collecting.market_modifier + + -- add the new active modifier to the non-buffed modifier + stone_collecting.initial_value = old_modifier + stone_collecting.active_modifier +end + + +--Handles the updating of market items when unlocked, also handles the buffs +local function update_market_contents(market) + if (stone_tracker.previous_stone_sent_to_surface == stone_tracker.stone_sent_to_surface) then + return + end + + local should_update_mining_speed = false + local should_update_inventory_slots = false + local should_update_stone_collecting = false + local add_market_item + local old_level = stone_tracker.current_level + local print = game.print + local item_unlocked = false + + if (calculate_level(stone_tracker.current_level+1) <= stone_tracker.stone_sent_to_surface) then + stone_tracker.current_level = stone_tracker.current_level + 1 + end + + for _, unlockable in pairs(config.unlockables) do + local stone_unlock = calculate_level(unlockable.level) + local is_in_range = stone_unlock > stone_tracker.previous_stone_sent_to_surface and stone_unlock <= stone_tracker.stone_sent_to_surface + + -- only add the item to the market if it's between the old and new stone range + if (is_in_range and unlockable.type == 'market') then + add_market_item = add_market_item or market.add_market_item + + local name = unlockable.prototype.name + local price = unlockable.prototype.price + if type(price) == 'number' then + add_market_item({ + price = {{config.currency_item, price}}, + offer = {type = 'give-item', item = name, count = 1} + }) + elseif type(price) == 'table' then + add_market_item({ + price = price, + offer = {type = 'give-item', item = name, count = 1} + }) + end + item_unlocked = true + + end + end + + MarketExchange.update_gui() + + if (old_level < stone_tracker.current_level) then + if item_unlocked then + print(prefix..'We have reached level ' .. stone_tracker.current_level .. '! New items are available from the market!') + else + print(prefix..'We have reached level ' .. stone_tracker.current_level .. '!') + end + for _, buffs in pairs(config.buffs) do + if (buffs.prototype.name == 'mining_speed') then + local value = buffs.prototype.value + Debug.print('Mining Foreman: Increased mining speed by ' .. value .. '%!') + should_update_mining_speed = true + mining_efficiency.market_modifier = mining_efficiency.market_modifier + (value / 100) + elseif (buffs.prototype.name == 'inventory_slot') then + local value = buffs.prototype.value + Debug.print('Mining Foreman: Increased inventory slots by ' .. value .. '!') + should_update_inventory_slots = true + inventory_slots.market_modifier = inventory_slots.market_modifier + value + elseif (buffs.prototype.name == 'stone_automation') then + local value = buffs.prototype.value + if (stone_tracker.current_level == 1) then + print('Mining Foreman: We can now automatically send stone to the surface from a chest below the market!') + else + Debug.print('Mining Foreman: We can now automatically send ' .. value .. ' more stones!') + end + should_update_stone_collecting = true + stone_collecting.market_modifier = stone_collecting.market_modifier + value + end + end + end + + local force + + if (should_update_mining_speed) then + force = force or game.forces.player + update_mining_speed(force) + end + + if (should_update_inventory_slots) then + force = force or game.forces.player + update_inventory_slots(force) + end + + if (should_update_stone_collecting) then + update_stone_collecting() + end +end + +local function on_research_finished(event) + local force = game.forces.player + local current_modifier = mining_efficiency.research_modifier + local new_modifier = force.mining_drill_productivity_bonus * config.mining_speed_productivity_multiplier * 0.5 + + if (current_modifier == new_modifier) then + -- something else was researched + return + end + + mining_efficiency.research_modifier = new_modifier + inventory_slots.research_modifier = force.mining_drill_productivity_bonus * 50 -- 1 per level + stone_collecting.research_modifier = force.mining_drill_productivity_bonus * 1250 -- 25 per level + + update_inventory_slots(force) + update_mining_speed(force) + update_stone_collecting() +end + +local function redraw_title(data) + data.frame.caption = utils.comma_value(stone_tracker.stone_sent_to_surface) .. ' ' .. config.currency_item .. ' sent to the surface' +end + +local function get_data(unlocks, stone, type) + local result = {} + + for _, data in pairs(unlocks) do + if calculate_level(data.level) == stone and data.type == type then + insert(result, data) + end + end + + return result +end + +local tag_label_stone = Gui.uid_name() +local tag_label_buff = Gui.uid_name() +local tag_label_item = Gui.uid_name() + +local function apply_heading_style(style, width) + style.font = 'default-bold' + style.width = width +end + +local function redraw_heading(data, header) + local head_condition = (header == 1) + local frame = (head_condition) and data.market_list_heading or data.buff_list_heading + local header_caption = (head_condition) and 'Reward Item' or 'Reward Buff' + Gui.clear(frame) + + local heading_table = frame.add({type = 'table', column_count = 2}) + apply_heading_style(heading_table.add({type = 'label', name = tag_label_stone, caption = 'Requirement'}).style, 100) + apply_heading_style(heading_table.add({type = 'label', name = tag_label_buff, caption = header_caption}).style, 220) +end + +local function redraw_progressbar(data) + + local flow = data.market_progressbars + Gui.clear(flow) + + -- progress bar for next level + local act_stone = (stone_tracker.current_level ~= 0) and calculate_level(stone_tracker.current_level) or 0 + local next_stone = calculate_level(stone_tracker.current_level+1) + + local range = next_stone - act_stone + local sent = stone_tracker.stone_sent_to_surface - act_stone + local percentage = (math.floor((sent / range)*1000))*0.001 + percentage = (percentage < 0) and (percentage*-1) or percentage + + apply_heading_style(flow.add({type = 'label', tooltip = 'Currently at level: ' .. stone_tracker.current_level .. '\nNext level at: ' .. utils.comma_value(next_stone) ..'\nRemaining stone: ' .. utils.comma_value(range - sent), name = 'Diggy.MarketExchange.Frame.Progress.Level', caption = 'Progress to next level:'}).style) + local level_progressbar = flow.add({type = 'progressbar', tooltip = percentage * 100 .. '% stone to next level'}) + level_progressbar.style.width = 350 + level_progressbar.value = percentage +end + +local function redraw_table(data) + local market_scroll_pane = data.market_scroll_pane + Gui.clear(market_scroll_pane) + + local buffs = {} + local items = {} + local last_stone = 0 + local number_of_rows = 0 + local row = {} + + -- create the progress bars in the window + redraw_progressbar(data) + + -- create table headings + redraw_heading(data, 1) + + -- create table + for i = 1, #config.unlockables do + if calculate_level(config.unlockables[i].level) ~= last_stone then + + -- get items and buffs for each stone value + items = get_data(config.unlockables, calculate_level(config.unlockables[i].level), 'market') + + -- get number of rows + number_of_rows = max(#buffs, #items) + + -- loop through buffs and items for number of rows + for j = 1, number_of_rows do + local result = {} + local item = items[j] + local level = item.level + + -- 1st column + result[6] = calculate_level(level) + result[1] = 'Level ' ..level + -- 3rd column + if items[j] ~= nil then + result[3] = '+ ' .. item.prototype.name + else + result[3] = '' + end + -- indicator to stop print stone number + if j > 1 then + result[4] = true + else + result[4] = false + end + -- indicator to draw horizontal line + if j == number_of_rows then + result[5] = true + else + result[5] = false + end + + insert(row, result) + end + end + + -- save lastStone + last_stone = calculate_level(config.unlockables[i].level) + end + + -- print table + for _, unlockable in pairs(row) do + local is_unlocked = unlockable[6] <= stone_tracker.stone_sent_to_surface + local list = market_scroll_pane.add {type = 'table', column_count = 2 } + + list.style.horizontal_spacing = 16 + + local caption = '' + if unlockable[4] ~= true then + caption = unlockable[1] + else + caption = '' + end + local tag_stone = list.add {type = 'label', name = tag_label_stone, caption = caption} + tag_stone.style.minimal_width = 100 + + local tag_items = list.add {type = 'label', name = tag_label_item, caption = unlockable[3]} + tag_items.style.minimal_width = 220 + + -- draw horizontal line + if unlockable[5] == true then + list.draw_horizontal_line_after_headers = true + end + + if (is_unlocked) then + tag_stone.style.font_color = {r = 1, g = 1, b = 1 } + tag_items.style.font_color = {r = 1, g = 1, b = 1 } + else + tag_stone.style.font_color = {r = 0.5, g = 0.5, b = 0.5 } + tag_items.style.font_color = {r = 0.5, g = 0.5, b = 0.5 } + end + end +end + +local function redraw_buff(data) --! Almost equals to the redraw_table() function ! + local buff_scroll_pane = data.buff_scroll_pane + Gui.clear(buff_scroll_pane) + + local buffs = {} + local number_of_rows = 0 + local row = {} + + for i = 1, #config.buffs do + -- get items and buffs for each stone value + buffs = config.buffs + + local result = {} + + -- 1st column + result[1] = 'All levels' + + -- 2nd column + if buffs[i].prototype.name == 'mining_speed' then + result[2] = '+ '.. buffs[i].prototype.value .. '% mining speed' + elseif buffs[i].prototype.name == 'inventory_slot' then + if buffs[i].prototype.value > 1 then + result[2] = '+ '.. buffs[i].prototype.value .. ' inventory slots' + else + result[2] = '+ '.. buffs[i].prototype.value .. ' inventory slot' + end + elseif buffs[i].prototype.name == 'stone_automation' then + result[2] = '+ '.. buffs[i].prototype.value .. ' stones automatically sent' + else + result[2] = 'Description missing: unknown buff. Please contact admin' + end + + -- 3rd column + result[3] = '' + -- indicator to stop print level number + if i > 1 then + result[4] = true + else + result[4] = false + end + insert(row, result) + end + for _, unlockable in pairs(row) do + local list = buff_scroll_pane.add {type = 'table', column_count = 2 } + list.style.horizontal_spacing = 16 + + local caption = '' + if unlockable[4] ~= true then + caption = unlockable[1] + else + caption = '' + end + local tag_stone = list.add {type = 'label', name = buff_tag_label_stone, caption = caption} + tag_stone.style.minimal_width = 100 + + local tag_buffs = list.add {type = 'label', name = buff_tag_label_buff, caption = unlockable[2]} + tag_buffs.style.minimal_width = 220 + + tag_stone.style.font_color = {r = 1, g = 1, b = 1 } + tag_buffs.style.font_color = {r = 1, g = 1, b = 1 } + end +end + +local function on_market_item_purchased(event) + if (1 ~= event.offer_index) then + return + end + + local sum = config.stone_to_surface_amount * event.count + Game.print_player_floating_text(event.player_index, '-' .. sum .. ' stone', {r = 0.6, g = 0.55, b = 0.42}) + + send_stone_to_surface(sum) + update_market_contents(event.market) +end + +local function on_placed_entity(event) + local market = event.entity + if ('market' ~= market.name) then + return + end + + market.add_market_item({ + price = {{config.currency_item, 50}}, + offer = {type = 'nothing', effect_description = 'Send ' .. config.stone_to_surface_amount .. ' ' .. config.currency_item .. ' to the surface. To see the overall progress and rewards, click the market button in the menu.'} + }) + + update_market_contents(market) +end + +function MarketExchange.get_extra_map_info(config) + return 'Market Exchange, trade your stone or send it to the surface' +end + +local function toggle(event) + local player = event.player + local left = player.gui.left + local frame = left['Diggy.MarketExchange.Frame'] + + if (frame and event.trigger == nil) then + Gui.destroy(frame) + return + elseif (frame) then + local data = Gui.get_data(frame) + redraw_title(data) + redraw_progressbar(data) + redraw_table(data) + return + end + + frame = left.add({name = 'Diggy.MarketExchange.Frame', type = 'frame', direction = 'vertical'}) + + local market_progressbars = frame.add({type = 'flow', direction = 'vertical'}) + local market_list_heading = frame.add({type = 'flow', direction = 'horizontal'}) + + local market_scroll_pane = frame.add({type = 'scroll-pane'}) + market_scroll_pane.style.maximal_height = 300 + + local buff_list_heading = frame.add({type = 'flow', direction = 'horizontal'}) + + local buff_scroll_pane = frame.add({type = 'scroll-pane'}) + buff_scroll_pane.style.maximal_height = 100 + + frame.add({ type = 'button', name = 'Diggy.MarketExchange.Button', caption = 'Close'}) + + local data = { + frame = frame, + market_progressbars = market_progressbars, + market_list_heading = market_list_heading, + market_scroll_pane = market_scroll_pane, + buff_list_heading = buff_list_heading, + buff_scroll_pane = buff_scroll_pane, + } + + redraw_title(data) + redraw_table(data) + + redraw_heading(data, 2) + redraw_buff(data) + + Gui.set_data(frame, data) + +end + +local function on_player_created(event) + Game.get_player_by_index(event.player_index).gui.top.add({ + name = 'Diggy.MarketExchange.Button', + type = 'sprite-button', + sprite = 'entity/market', + }) +end + +Gui.on_click('Diggy.MarketExchange.Button', toggle) +Gui.on_custom_close('Diggy.MarketExchange.Frame', function (event) + event.element.destroy() +end) + +function MarketExchange.update_gui() + for _, p in ipairs(game.connected_players) do + local frame = p.gui.left['Diggy.MarketExchange.Frame'] + + if frame and frame.valid then + local data = {player = p, trigger = 'update_gui'} + toggle(data) + --toggle(data) + end + end +end + +function MarketExchange.on_init() + Task.set_timeout_in_ticks(50, on_market_timeout_finished, { + surface = game.surfaces.nauvis, + position = config.market_spawn_position, + player_force = game.forces.player, + void_chest_tiles = config.void_chest_tiles, + }) + + update_mining_speed(game.forces.player) +end + +--[[-- + Registers all event handlers. +]] +function MarketExchange.register(cfg) + config = cfg + + Event.add(defines.events.on_research_finished, on_research_finished) + Event.add(defines.events.on_market_item_purchased, on_market_item_purchased) + Event.add(Template.events.on_placed_entity, on_placed_entity) + Event.add(defines.events.on_player_created, on_player_created) + + local x_min + local y_min + local x_max + local y_max + + for _, position in pairs(config.void_chest_tiles) do + local x = position.x + local y = position.y + + if (nil == x_min or x < x_min) then + x_min = x + end + + if (nil == x_max or x > x_max) then + x_max = x + end + + if (nil == y_min or y < y_min) then + y_min = y + end + + if (nil == y_max or y > y_max) then + y_max = y + end + end + + local area = {{x_min, y_min}, {x_max + 1, y_max + 1}} + local message_x = (x_max + x_min) * 0.5 + local message_y = (y_max + y_min) * 0.5 + + Event.on_nth_tick(config.void_chest_frequency, function () + local send_to_surface = 0 + local surface = game.surfaces.nauvis + local find_entities_filtered = surface.find_entities_filtered + local chests = find_entities_filtered({area = area, type = {'container', 'logistic-container'}}) + local to_fetch = stone_collecting.active_modifier + + for _, chest in pairs(chests) do + local chest_contents = chest.get_inventory(defines.inventory.chest) + local stone_in_chest = chest_contents.get_item_count(config.currency_item) + local delta = to_fetch + + if (stone_in_chest < delta) then + delta = stone_in_chest + end + + if (delta > 0) then + chest_contents.remove({name = config.currency_item, count = delta}) + send_to_surface = send_to_surface + delta + end + end + + if (send_to_surface == 0) then + if (0 == to_fetch) then + return + end + + local message = 'Missing chests below market' + if (#chests > 0) then + message = 'No stone in chests found' + end + + Game.print_floating_text(surface, {x = message_x, y = message_y}, message, { r = 220, g = 100, b = 50}) + return + end + + local markets = find_entities_filtered({name = 'market', position = config.market_spawn_position, limit = 1}) + + if (#markets == 0) then + Debug.print_position(config.market_spawn_position, 'Unable to find a market') + return + end + + local message = send_to_surface .. ' stone sent to the surface' + + Game.print_floating_text(surface, {x = message_x, y = message_y}, message, { r = 0.6, g = 0.55, b = 0.42}) + + send_stone_to_surface(send_to_surface) + update_market_contents(markets[1]) + end) +end + +return MarketExchange diff --git a/map_gen/Diggy/Feature/RefreshMap.lua b/map_gen/Diggy/Feature/RefreshMap.lua index 9918b08e..51822d14 100644 --- a/map_gen/Diggy/Feature/RefreshMap.lua +++ b/map_gen/Diggy/Feature/RefreshMap.lua @@ -1,40 +1,40 @@ ---[[-- info - Provides the ability to refresh the map and generate darkness. -]] - --- dependencies -local Event = require 'utils.event' -local insert = table.insert - --- this -local RefreshMap = {} - ---[[-- - Registers all event handlers. -]] -function RefreshMap.register(config) - Event.add(defines.events.on_chunk_generated, function (event) - local tiles = {} - - for x = 0, 31, 1 do - for y = 0, 31, 1 do - local target_x = event.area.left_top.x + x - local target_y = event.area.left_top.y + y - local tile = 'out-of-map' - - if (target_x < 1 and target_y < 1 and target_x > -2 and target_y > -2) then - tile = 'lab-dark-1' - end - - insert(tiles, { - name = tile, - position = {x = target_x, y = target_y} - }) - end - end - - event.surface.set_tiles(tiles) - end) -end - -return RefreshMap +--[[-- info + Provides the ability to refresh the map and generate darkness. +]] + +-- dependencies +local Event = require 'utils.event' +local insert = table.insert + +-- this +local RefreshMap = {} + +--[[-- + Registers all event handlers. +]] +function RefreshMap.register(config) + Event.add(defines.events.on_chunk_generated, function (event) + local tiles = {} + + for x = 0, 31, 1 do + for y = 0, 31, 1 do + local target_x = event.area.left_top.x + x + local target_y = event.area.left_top.y + y + local tile = 'out-of-map' + + if (target_x < 1 and target_y < 1 and target_x > -2 and target_y > -2) then + tile = 'lab-dark-1' + end + + insert(tiles, { + name = tile, + position = {x = target_x, y = target_y} + }) + end + end + + event.surface.set_tiles(tiles) + end) +end + +return RefreshMap diff --git a/map_gen/Diggy/Feature/ScatteredResources.lua b/map_gen/Diggy/Feature/ScatteredResources.lua index 4abd730e..45a1efe0 100644 --- a/map_gen/Diggy/Feature/ScatteredResources.lua +++ b/map_gen/Diggy/Feature/ScatteredResources.lua @@ -1,262 +1,262 @@ ---[[-- info - Provides the ability to spawn random ores all over the place. -]] - --- dependencies -local Event = require 'utils.event' -local Debug = require 'map_gen.Diggy.Debug' -local Template = require 'map_gen.Diggy.Template' -local Perlin = require 'map_gen.shared.perlin_noise' -local Simplex = require 'map_gen.shared.simplex_noise' -local random = math.random -local sqrt = math.sqrt -local ceil = math.ceil -local floor = math.floor - --- this -local ScatteredResources = {} - -local function get_name_by_weight(collection, sum) - local pre_calculated = random() - local current = 0 - local target = pre_calculated * sum - - for name, weight in pairs(collection) do - current = current + weight - if (current >= target) then - return name - end - end - - Debug.print('Current \'' .. current .. '\' should be higher or equal to random \'' .. target .. '\'') -end - ---[[-- - Registers all event handlers. -]] -function ScatteredResources.register(config) - - -- source of noise for resource generation - -- index determines offset - -- '-1' is reserved for cluster mode - -- compound clusters use as many indexes as needed > 1 - local base_seed - local function seeded_noise(surface, x, y, index, sources) - base_seed = base_seed or surface.map_gen_settings.seed + surface.index + 4000 - local noise = 0 - for _, settings in ipairs(sources) do - settings.type = settings.type or 'perlin' - settings.offset = settings.offset or 0 - if settings.type == 'zero' then - noise = noise + 0 - elseif settings.type == 'one' then - noise = noise + settings.weight * 1 - elseif settings.type == 'perlin' then - noise = noise + settings.weight * Perlin.noise(x/settings.variance, y/settings.variance, - base_seed + 2000*index + settings.offset) - elseif settings.type == 'simplex' then - noise = noise + settings.weight * Simplex.d2(x/settings.variance, y/settings.variance, - base_seed + 2000*index + settings.offset) - else - Debug.print('noise type \'' .. settings.type .. '\' not recognized') - end - - end - return noise - end - - -- global config values - - local resource_richness_weights = config.resource_richness_weights - local resource_richness_weights_sum = 0 - for _, weight in pairs(resource_richness_weights) do - resource_richness_weights_sum = resource_richness_weights_sum + weight - end - local resource_richness_values = config.resource_richness_values - local resource_type_scalar = config.resource_type_scalar - - -- scattered config values - local s_mode = config.scattered_mode - local s_dist_mod = config.scattered_distance_probability_modifier - local s_min_prob = config.scattered_min_probability - local s_max_prob = config.scattered_max_probability - local s_dist_richness = config.scattered_distance_richness_modifier - local s_cluster_prob = config.scattered_cluster_probability_multiplier - local s_cluster_mult = config.scattered_cluster_yield_multiplier - - local s_resource_weights = config.scattered_resource_weights - local s_resource_weights_sum = 0 - for _, weight in pairs(s_resource_weights) do - s_resource_weights_sum = s_resource_weights_sum + weight - end - local s_min_dist = config.scattered_minimum_resource_distance - - -- cluster config values - local cluster_mode = config.cluster_mode - - -- compound cluster spawning - local c_mode = config.cluster_mode - local c_clusters = require(config.cluster_file_location) - if ('table' ~= type(c_clusters)) then - error('cluster_file_location invalid') - end - local c_count = 0 - for _, cluster in ipairs(c_clusters) do - c_count = c_count + 1 - cluster.weights_sum = 0 - -- ensure the cluster colors are valid otherwise it fails silently - -- and breaks things elsewhere - if cluster.color then - local c = cluster.color - if (not c.r) or (not c.g) or (not c.b) then - cluster.color = nil - elseif c.r < 0 or c.r > 1 or c.g < 0 or c.g > 1 or c.b < 0 or c.b > 1 then - cluster.color = nil - end - end - for _, weight in pairs(cluster.weights) do - cluster.weights_sum = cluster.weights_sum + weight - end - end - - local function spawn_cluster_resource(surface, x, y, cluster_index, cluster) - local distance = sqrt(x * x + y * y) - local resource_name = get_name_by_weight(cluster.weights, cluster.weights_sum) - if resource_name == 'skip' then - return false - end - if cluster.distances[resource_name] then - if distance < cluster.distances[resource_name] then - return false - end - end - - local range = resource_richness_values[get_name_by_weight(resource_richness_weights, resource_richness_weights_sum)] - local amount = random(range[1], range[2]) - amount = amount * (1 + ((distance / cluster.distance_richness) * 0.01)) - amount = amount * cluster.yield - - if resource_type_scalar[resource_name] then - amount = amount * resource_type_scalar[resource_name] - end - - Template.resources(surface, {{name = resource_name, position = {x = x, y = y}, amount = ceil(amount)}}) - return true - end - - -- event registration - Event.add(Template.events.on_void_removed, function (event) - local position = event.position - local x = position.x - local y = position.y - local surface = event.surface - - local distance = config.distance(x, y) - - if c_mode then - for index,cluster in ipairs(c_clusters) do - if distance >= cluster.min_distance and cluster.noise_settings.type ~= 'skip' then - if cluster.noise_settings.type == "connected_tendril" then - local noise = seeded_noise(surface, x, y, index, cluster.noise_settings.sources) - if -1 * cluster.noise_settings.threshold < noise and noise < cluster.noise_settings.threshold then - if spawn_cluster_resource(surface, x, y, index, cluster) then - return -- resource spawned - end - end - elseif cluster.noise_settings.type == "fragmented_tendril" then - local noise1 = seeded_noise(surface, x, y, index, cluster.noise_settings.sources) - local noise2 = seeded_noise(surface, x, y, index, cluster.noise_settings.discriminator) - if -1 * cluster.noise_settings.threshold < noise1 and noise1 < cluster.noise_settings.threshold - and -1 * cluster.noise_settings.discriminator_threshold < noise2 - and noise2 < cluster.noise_settings.discriminator_threshold then - if spawn_cluster_resource(surface, x, y, index, cluster) then - return -- resource spawned - end - end - else - local noise = seeded_noise(surface, x, y, index, cluster.noise_settings.sources) - if noise >= cluster.noise_settings.threshold then - if spawn_cluster_resource(surface, x, y, index, cluster) then - return -- resource spawned - end - end - end - end - end - end - - if s_mode then - local probability = math.min(s_max_prob, s_min_prob + 0.01 * (distance / s_dist_mod)) - - if (cluster_mode) then - probability = probability * s_cluster_prob - end - - if (probability > random()) then - -- spawn single resource point for scatter mode - local resource_name = get_name_by_weight(s_resource_weights, s_resource_weights_sum) - if resource_name == 'skip' or s_min_dist[resource_name] > distance then - return - end - - local range = resource_richness_values[get_name_by_weight(resource_richness_weights, resource_richness_weights_sum)] - local amount = random(range[1], range[2]) - amount = amount * (1 + ((distance / s_dist_richness) * 0.01)) - - if resource_type_scalar[resource_name] then - amount = amount * resource_type_scalar[resource_name] - end - - if (cluster_mode) then - amount = amount * s_cluster_mult - end - - Template.resources(surface, {{name = resource_name, position={x=x,y=y}, amount = ceil(amount)}}) - end - end - end) - - if (config.display_ore_clusters) then - local color = {} - Event.add(defines.events.on_chunk_generated, function (event) - local surface = event.surface - local area = event.area - - for x = area.left_top.x, area.left_top.x + 31 do - for y = area.left_top.y, area.left_top.y + 31 do - for index,cluster in ipairs(c_clusters) do - if cluster.noise_settings.type == "connected_tendril" then - local noise = seeded_noise(surface, x, y, index, cluster.noise_settings.sources) - if -1 * cluster.noise_settings.threshold < noise and noise < cluster.noise_settings.threshold then - color[index] = color[index] or cluster.color or {r=random(), g=random(), b=random()} - Debug.print_colored_grid_value('o' .. index, surface, {x = x, y = y}, nil, nil, true, 0, color[index]) - end - elseif cluster.noise_settings.type == "fragmented_tendril" then - local noise1 = seeded_noise(surface, x, y, index, cluster.noise_settings.sources) - local noise2 = seeded_noise(surface, x, y, index, cluster.noise_settings.discriminator) - if -1 * cluster.noise_settings.threshold < noise1 and noise1 < cluster.noise_settings.threshold - and -1 * cluster.noise_settings.discriminator_threshold < noise2 - and noise2 < cluster.noise_settings.discriminator_threshold then - color[index] = color[index] or cluster.color or {r=random(), g=random(), b=random()} - Debug.print_colored_grid_value('o' .. index, surface, {x = x, y = y}, nil, nil, true, 0, color[index]) - end - elseif cluster.noise_settings.type ~= 'skip' then - local noise = seeded_noise(surface, x, y, index, cluster.noise_settings.sources) - if noise >= cluster.noise_settings.threshold then - color[index] = color[index] or cluster.color or {r=random(), g=random(), b=random()} - Debug.print_colored_grid_value('o' .. index, surface, {x = x, y = y}, nil, nil, true, 0, color[index]) - end - end - end - end - end - end) - end -end - -function ScatteredResources.get_extra_map_info(config) - return [[Scattered Resources, resources are everywhere! -Scans of the mine have shown greater amounts of resources to be deeper in the mine]] -end - -return ScatteredResources +--[[-- info + Provides the ability to spawn random ores all over the place. +]] + +-- dependencies +local Event = require 'utils.event' +local Debug = require 'map_gen.Diggy.Debug' +local Template = require 'map_gen.Diggy.Template' +local Perlin = require 'map_gen.shared.perlin_noise' +local Simplex = require 'map_gen.shared.simplex_noise' +local random = math.random +local sqrt = math.sqrt +local ceil = math.ceil +local floor = math.floor + +-- this +local ScatteredResources = {} + +local function get_name_by_weight(collection, sum) + local pre_calculated = random() + local current = 0 + local target = pre_calculated * sum + + for name, weight in pairs(collection) do + current = current + weight + if (current >= target) then + return name + end + end + + Debug.print('Current \'' .. current .. '\' should be higher or equal to random \'' .. target .. '\'') +end + +--[[-- + Registers all event handlers. +]] +function ScatteredResources.register(config) + + -- source of noise for resource generation + -- index determines offset + -- '-1' is reserved for cluster mode + -- compound clusters use as many indexes as needed > 1 + local base_seed + local function seeded_noise(surface, x, y, index, sources) + base_seed = base_seed or surface.map_gen_settings.seed + surface.index + 4000 + local noise = 0 + for _, settings in ipairs(sources) do + settings.type = settings.type or 'perlin' + settings.offset = settings.offset or 0 + if settings.type == 'zero' then + noise = noise + 0 + elseif settings.type == 'one' then + noise = noise + settings.weight * 1 + elseif settings.type == 'perlin' then + noise = noise + settings.weight * Perlin.noise(x/settings.variance, y/settings.variance, + base_seed + 2000*index + settings.offset) + elseif settings.type == 'simplex' then + noise = noise + settings.weight * Simplex.d2(x/settings.variance, y/settings.variance, + base_seed + 2000*index + settings.offset) + else + Debug.print('noise type \'' .. settings.type .. '\' not recognized') + end + + end + return noise + end + + -- global config values + + local resource_richness_weights = config.resource_richness_weights + local resource_richness_weights_sum = 0 + for _, weight in pairs(resource_richness_weights) do + resource_richness_weights_sum = resource_richness_weights_sum + weight + end + local resource_richness_values = config.resource_richness_values + local resource_type_scalar = config.resource_type_scalar + + -- scattered config values + local s_mode = config.scattered_mode + local s_dist_mod = config.scattered_distance_probability_modifier + local s_min_prob = config.scattered_min_probability + local s_max_prob = config.scattered_max_probability + local s_dist_richness = config.scattered_distance_richness_modifier + local s_cluster_prob = config.scattered_cluster_probability_multiplier + local s_cluster_mult = config.scattered_cluster_yield_multiplier + + local s_resource_weights = config.scattered_resource_weights + local s_resource_weights_sum = 0 + for _, weight in pairs(s_resource_weights) do + s_resource_weights_sum = s_resource_weights_sum + weight + end + local s_min_dist = config.scattered_minimum_resource_distance + + -- cluster config values + local cluster_mode = config.cluster_mode + + -- compound cluster spawning + local c_mode = config.cluster_mode + local c_clusters = require(config.cluster_file_location) + if ('table' ~= type(c_clusters)) then + error('cluster_file_location invalid') + end + local c_count = 0 + for _, cluster in ipairs(c_clusters) do + c_count = c_count + 1 + cluster.weights_sum = 0 + -- ensure the cluster colors are valid otherwise it fails silently + -- and breaks things elsewhere + if cluster.color then + local c = cluster.color + if (not c.r) or (not c.g) or (not c.b) then + cluster.color = nil + elseif c.r < 0 or c.r > 1 or c.g < 0 or c.g > 1 or c.b < 0 or c.b > 1 then + cluster.color = nil + end + end + for _, weight in pairs(cluster.weights) do + cluster.weights_sum = cluster.weights_sum + weight + end + end + + local function spawn_cluster_resource(surface, x, y, cluster_index, cluster) + local distance = sqrt(x * x + y * y) + local resource_name = get_name_by_weight(cluster.weights, cluster.weights_sum) + if resource_name == 'skip' then + return false + end + if cluster.distances[resource_name] then + if distance < cluster.distances[resource_name] then + return false + end + end + + local range = resource_richness_values[get_name_by_weight(resource_richness_weights, resource_richness_weights_sum)] + local amount = random(range[1], range[2]) + amount = amount * (1 + ((distance / cluster.distance_richness) * 0.01)) + amount = amount * cluster.yield + + if resource_type_scalar[resource_name] then + amount = amount * resource_type_scalar[resource_name] + end + + Template.resources(surface, {{name = resource_name, position = {x = x, y = y}, amount = ceil(amount)}}) + return true + end + + -- event registration + Event.add(Template.events.on_void_removed, function (event) + local position = event.position + local x = position.x + local y = position.y + local surface = event.surface + + local distance = config.distance(x, y) + + if c_mode then + for index,cluster in ipairs(c_clusters) do + if distance >= cluster.min_distance and cluster.noise_settings.type ~= 'skip' then + if cluster.noise_settings.type == "connected_tendril" then + local noise = seeded_noise(surface, x, y, index, cluster.noise_settings.sources) + if -1 * cluster.noise_settings.threshold < noise and noise < cluster.noise_settings.threshold then + if spawn_cluster_resource(surface, x, y, index, cluster) then + return -- resource spawned + end + end + elseif cluster.noise_settings.type == "fragmented_tendril" then + local noise1 = seeded_noise(surface, x, y, index, cluster.noise_settings.sources) + local noise2 = seeded_noise(surface, x, y, index, cluster.noise_settings.discriminator) + if -1 * cluster.noise_settings.threshold < noise1 and noise1 < cluster.noise_settings.threshold + and -1 * cluster.noise_settings.discriminator_threshold < noise2 + and noise2 < cluster.noise_settings.discriminator_threshold then + if spawn_cluster_resource(surface, x, y, index, cluster) then + return -- resource spawned + end + end + else + local noise = seeded_noise(surface, x, y, index, cluster.noise_settings.sources) + if noise >= cluster.noise_settings.threshold then + if spawn_cluster_resource(surface, x, y, index, cluster) then + return -- resource spawned + end + end + end + end + end + end + + if s_mode then + local probability = math.min(s_max_prob, s_min_prob + 0.01 * (distance / s_dist_mod)) + + if (cluster_mode) then + probability = probability * s_cluster_prob + end + + if (probability > random()) then + -- spawn single resource point for scatter mode + local resource_name = get_name_by_weight(s_resource_weights, s_resource_weights_sum) + if resource_name == 'skip' or s_min_dist[resource_name] > distance then + return + end + + local range = resource_richness_values[get_name_by_weight(resource_richness_weights, resource_richness_weights_sum)] + local amount = random(range[1], range[2]) + amount = amount * (1 + ((distance / s_dist_richness) * 0.01)) + + if resource_type_scalar[resource_name] then + amount = amount * resource_type_scalar[resource_name] + end + + if (cluster_mode) then + amount = amount * s_cluster_mult + end + + Template.resources(surface, {{name = resource_name, position={x=x,y=y}, amount = ceil(amount)}}) + end + end + end) + + if (config.display_ore_clusters) then + local color = {} + Event.add(defines.events.on_chunk_generated, function (event) + local surface = event.surface + local area = event.area + + for x = area.left_top.x, area.left_top.x + 31 do + for y = area.left_top.y, area.left_top.y + 31 do + for index,cluster in ipairs(c_clusters) do + if cluster.noise_settings.type == "connected_tendril" then + local noise = seeded_noise(surface, x, y, index, cluster.noise_settings.sources) + if -1 * cluster.noise_settings.threshold < noise and noise < cluster.noise_settings.threshold then + color[index] = color[index] or cluster.color or {r=random(), g=random(), b=random()} + Debug.print_colored_grid_value('o' .. index, surface, {x = x, y = y}, nil, nil, true, 0, color[index]) + end + elseif cluster.noise_settings.type == "fragmented_tendril" then + local noise1 = seeded_noise(surface, x, y, index, cluster.noise_settings.sources) + local noise2 = seeded_noise(surface, x, y, index, cluster.noise_settings.discriminator) + if -1 * cluster.noise_settings.threshold < noise1 and noise1 < cluster.noise_settings.threshold + and -1 * cluster.noise_settings.discriminator_threshold < noise2 + and noise2 < cluster.noise_settings.discriminator_threshold then + color[index] = color[index] or cluster.color or {r=random(), g=random(), b=random()} + Debug.print_colored_grid_value('o' .. index, surface, {x = x, y = y}, nil, nil, true, 0, color[index]) + end + elseif cluster.noise_settings.type ~= 'skip' then + local noise = seeded_noise(surface, x, y, index, cluster.noise_settings.sources) + if noise >= cluster.noise_settings.threshold then + color[index] = color[index] or cluster.color or {r=random(), g=random(), b=random()} + Debug.print_colored_grid_value('o' .. index, surface, {x = x, y = y}, nil, nil, true, 0, color[index]) + end + end + end + end + end + end) + end +end + +function ScatteredResources.get_extra_map_info(config) + return [[Scattered Resources, resources are everywhere! +Scans of the mine have shown greater amounts of resources to be deeper in the mine]] +end + +return ScatteredResources diff --git a/map_gen/Diggy/Feature/SetupPlayer.lua b/map_gen/Diggy/Feature/SetupPlayer.lua index 71415810..4ec36b98 100644 --- a/map_gen/Diggy/Feature/SetupPlayer.lua +++ b/map_gen/Diggy/Feature/SetupPlayer.lua @@ -1,53 +1,53 @@ ---[[-- info - Provides the ability to setup a player when first joined. -]] - --- dependencies -local Event = require 'utils.event' -local Debug = require 'map_gen.Diggy.Debug' -local Game = require 'utils.game' - --- this -local SetupPlayer = {} - -global.SetupPlayer = { - first_player_spawned = false, -} - ---[[-- - Registers all event handlers. -]] -function SetupPlayer.register(config) - Event.add(defines.events.on_player_created, function (event) - local player = Game.get_player_by_index(event.player_index) - local player_insert = player.insert - local position = {0, 0} - local surface = player.surface - - for _, item in pairs(config.starting_items) do - player_insert(item) - end - - if (global.SetupPlayer.first_player_spawned) then - position = surface.find_non_colliding_position('player', position, 3, 0.1) - else - global.SetupPlayer.first_player_spawned = true - end - - player.force.set_spawn_position(position, surface) - player.teleport(position) - - Debug.cheat(function() - local cheats = config.cheats - player.force.manual_mining_speed_modifier = cheats.manual_mining_speed_modifier - player.force.character_inventory_slots_bonus = cheats.character_inventory_slots_bonus - player.force.character_running_speed_modifier = cheats.character_running_speed_modifier - - for _, item in pairs(cheats.starting_items) do - player_insert(item) - end - end) - end) -end - -return SetupPlayer +--[[-- info + Provides the ability to setup a player when first joined. +]] + +-- dependencies +local Event = require 'utils.event' +local Debug = require 'map_gen.Diggy.Debug' +local Game = require 'utils.game' + +-- this +local SetupPlayer = {} + +global.SetupPlayer = { + first_player_spawned = false, +} + +--[[-- + Registers all event handlers. +]] +function SetupPlayer.register(config) + Event.add(defines.events.on_player_created, function (event) + local player = Game.get_player_by_index(event.player_index) + local player_insert = player.insert + local position = {0, 0} + local surface = player.surface + + for _, item in pairs(config.starting_items) do + player_insert(item) + end + + if (global.SetupPlayer.first_player_spawned) then + position = surface.find_non_colliding_position('player', position, 3, 0.1) + else + global.SetupPlayer.first_player_spawned = true + end + + player.force.set_spawn_position(position, surface) + player.teleport(position) + + Debug.cheat(function() + local cheats = config.cheats + player.force.manual_mining_speed_modifier = cheats.manual_mining_speed_modifier + player.force.character_inventory_slots_bonus = cheats.character_inventory_slots_bonus + player.force.character_running_speed_modifier = cheats.character_running_speed_modifier + + for _, item in pairs(cheats.starting_items) do + player_insert(item) + end + end) + end) +end + +return SetupPlayer diff --git a/map_gen/Diggy/Feature/SimpleRoomGenerator.lua b/map_gen/Diggy/Feature/SimpleRoomGenerator.lua index 3d555856..a6431ac8 100644 --- a/map_gen/Diggy/Feature/SimpleRoomGenerator.lua +++ b/map_gen/Diggy/Feature/SimpleRoomGenerator.lua @@ -1,108 +1,108 @@ ---[[-- info - Provides the ability to make a simple room with contents -]] - --- dependencies -local Template = require 'map_gen.Diggy.Template' -local Perlin = require 'map_gen.shared.perlin_noise' -local Event = require 'utils.event' -local Debug = require'map_gen.Diggy.Debug' -local Task = require 'utils.Task' -local Token = require 'utils.global_token' -local raise_event = script.raise_event - --- this -local SimpleRoomGenerator = {} - -local do_spawn_tile = Token.register(function(params) - Template.insert(params.surface, {params.tile}, {}) -end) - -local do_mine = Token.register(function(params) - local surface = params.surface - local position = params.position - local rocks = surface.find_entities_filtered({ position = position, name = { 'sand-rock-big', 'rock-huge'}}) - - if (0 == #rocks) then - return - end - - for _, rock in pairs(rocks) do - raise_event(defines.events.on_entity_died, {entity = rock}) - rock.destroy() - end -end) - -local function handle_noise(name, surface, position) - Task.set_timeout_in_ticks(1, do_mine, {surface = surface, position = position}) - - if ('water' == name) then - -- water is slower because for some odd reason it doesn't always want to mine it properly - Task.set_timeout_in_ticks(4, do_spawn_tile, { surface = surface, tile = { name = 'deepwater-green', position = position}}) - return - end - - if ('dirt' == name) then - return - end - - error('No noise handled for type \'' .. name .. '\'') -end - ---[[-- - Registers all event handlers. -]] -function SimpleRoomGenerator.register(config) - local room_noise_minimum_distance_sq = config.room_noise_minimum_distance * config.room_noise_minimum_distance - - local seed - local function get_noise(surface, x, y) - seed = seed or surface.map_gen_settings.seed + surface.index + 100 - return Perlin.noise(x * config.noise_variance, y * config.noise_variance, seed) - end - - Event.add(Template.events.on_void_removed, function (event) - local position = event.position - local x = position.x - local y = position.y - - local distance_sq = x * x + y * y - - if (distance_sq <= room_noise_minimum_distance_sq) then - return - end - - local surface = event.surface - local noise = get_noise(surface, x, y) - - for _, noise_range in pairs(config.room_noise_ranges) do - if (noise >= noise_range.min and noise <= noise_range.max) then - handle_noise(noise_range.name, surface, position) - end - end - end) - - if (config.display_room_locations) then - Event.add(defines.events.on_chunk_generated, function (event) - local surface = event.surface - local area = event.area - - for x = area.left_top.x, area.left_top.x + 31 do - for y = area.left_top.y, area.left_top.y + 31 do - for _, noise_range in pairs(config.room_noise_ranges) do - local noise = get_noise(surface, x, y) - if (noise >= noise_range.min and noise <= noise_range.max) then - Debug.print_grid_value(noise_range.name, surface, {x = x, y = y}, nil, nil, true) - end - end - end - end - end) - end -end - -function SimpleRoomGenerator.get_extra_map_info(config) - return 'Simple Room Generator, digging around might open rooms!' -end - -return SimpleRoomGenerator +--[[-- info + Provides the ability to make a simple room with contents +]] + +-- dependencies +local Template = require 'map_gen.Diggy.Template' +local Perlin = require 'map_gen.shared.perlin_noise' +local Event = require 'utils.event' +local Debug = require'map_gen.Diggy.Debug' +local Task = require 'utils.Task' +local Token = require 'utils.global_token' +local raise_event = script.raise_event + +-- this +local SimpleRoomGenerator = {} + +local do_spawn_tile = Token.register(function(params) + Template.insert(params.surface, {params.tile}, {}) +end) + +local do_mine = Token.register(function(params) + local surface = params.surface + local position = params.position + local rocks = surface.find_entities_filtered({ position = position, name = { 'sand-rock-big', 'rock-huge'}}) + + if (0 == #rocks) then + return + end + + for _, rock in pairs(rocks) do + raise_event(defines.events.on_entity_died, {entity = rock}) + rock.destroy() + end +end) + +local function handle_noise(name, surface, position) + Task.set_timeout_in_ticks(1, do_mine, {surface = surface, position = position}) + + if ('water' == name) then + -- water is slower because for some odd reason it doesn't always want to mine it properly + Task.set_timeout_in_ticks(4, do_spawn_tile, { surface = surface, tile = { name = 'deepwater-green', position = position}}) + return + end + + if ('dirt' == name) then + return + end + + error('No noise handled for type \'' .. name .. '\'') +end + +--[[-- + Registers all event handlers. +]] +function SimpleRoomGenerator.register(config) + local room_noise_minimum_distance_sq = config.room_noise_minimum_distance * config.room_noise_minimum_distance + + local seed + local function get_noise(surface, x, y) + seed = seed or surface.map_gen_settings.seed + surface.index + 100 + return Perlin.noise(x * config.noise_variance, y * config.noise_variance, seed) + end + + Event.add(Template.events.on_void_removed, function (event) + local position = event.position + local x = position.x + local y = position.y + + local distance_sq = x * x + y * y + + if (distance_sq <= room_noise_minimum_distance_sq) then + return + end + + local surface = event.surface + local noise = get_noise(surface, x, y) + + for _, noise_range in pairs(config.room_noise_ranges) do + if (noise >= noise_range.min and noise <= noise_range.max) then + handle_noise(noise_range.name, surface, position) + end + end + end) + + if (config.display_room_locations) then + Event.add(defines.events.on_chunk_generated, function (event) + local surface = event.surface + local area = event.area + + for x = area.left_top.x, area.left_top.x + 31 do + for y = area.left_top.y, area.left_top.y + 31 do + for _, noise_range in pairs(config.room_noise_ranges) do + local noise = get_noise(surface, x, y) + if (noise >= noise_range.min and noise <= noise_range.max) then + Debug.print_grid_value(noise_range.name, surface, {x = x, y = y}, nil, nil, true) + end + end + end + end + end) + end +end + +function SimpleRoomGenerator.get_extra_map_info(config) + return 'Simple Room Generator, digging around might open rooms!' +end + +return SimpleRoomGenerator diff --git a/map_gen/Diggy/Feature/StartingZone.lua b/map_gen/Diggy/Feature/StartingZone.lua index e70dc7e1..fb982260 100644 --- a/map_gen/Diggy/Feature/StartingZone.lua +++ b/map_gen/Diggy/Feature/StartingZone.lua @@ -1,81 +1,81 @@ ---[[-- info - Provides the ability to create a pre-configured starting zone. -]] --- dependencies -local Event = require 'utils.event' -local Token = require 'utils.global_token' -local Template = require 'map_gen.Diggy.Template' -local Debug = require 'map_gen.Diggy.Debug' -local DiggyCaveCollapse = require 'map_gen.Diggy.Feature.DiggyCaveCollapse' -local insert = table.insert -local random = math.random -local sqrt = math.sqrt -local floor = math.floor - --- this -local StartingZone = {} - ---[[-- - Registers all event handlers. -]] -function StartingZone.register(config) - local callback_token - local starting_zone_size = config.starting_size - - local function on_chunk_generated(event) - local start_point_area = {{-0.9, -0.9}, {0.9, 0.9}} - local start_point_cleanup = {{-0.9, -0.9}, {1.9, 1.9}} - local surface = event.surface - - -- hack to figure out whether the important chunks are generated via Diggy.Feature.RefreshMap. - if (4 ~= surface.count_tiles_filtered({start_point_area, name = 'lab-dark-1'})) then - return - end - - -- ensure a clean starting point - for _, entity in pairs(surface.find_entities_filtered({area = start_point_cleanup, type = 'resource'})) do - entity.destroy() - end - - local tiles = {} - local rocks = {} - - local dirt_range = floor(starting_zone_size * 0.5) - local rock_range = starting_zone_size - 2 - local stress_hack = floor(starting_zone_size * 0.1) - - for x = -starting_zone_size, starting_zone_size do - for y = -starting_zone_size, starting_zone_size do - local distance = floor(sqrt(x * x + y * y)) - - if (distance < starting_zone_size) then - if (distance > dirt_range) then - insert(tiles, {name = 'dirt-' .. random(1, 7), position = {x = x, y = y}}) - else - insert(tiles, {name = 'stone-path', position = {x = x, y = y}}) - end - - if (distance > rock_range) then - insert(rocks, {name = 'sand-rock-big', position = {x = x, y = y}}) - end - - -- hack to avoid starting area from collapsing - if (distance > stress_hack) then - DiggyCaveCollapse.stress_map_add(surface, {x = x, y = y}, -0.5) - end - end - end - end - - Template.insert(event.surface, tiles, rocks) - - Event.remove_removable(defines.events.on_chunk_generated, callback_token) - end - - callback_token = Token.register(on_chunk_generated) - - Event.add_removable(defines.events.on_chunk_generated, callback_token) -end - - -return StartingZone +--[[-- info + Provides the ability to create a pre-configured starting zone. +]] +-- dependencies +local Event = require 'utils.event' +local Token = require 'utils.global_token' +local Template = require 'map_gen.Diggy.Template' +local Debug = require 'map_gen.Diggy.Debug' +local DiggyCaveCollapse = require 'map_gen.Diggy.Feature.DiggyCaveCollapse' +local insert = table.insert +local random = math.random +local sqrt = math.sqrt +local floor = math.floor + +-- this +local StartingZone = {} + +--[[-- + Registers all event handlers. +]] +function StartingZone.register(config) + local callback_token + local starting_zone_size = config.starting_size + + local function on_chunk_generated(event) + local start_point_area = {{-0.9, -0.9}, {0.9, 0.9}} + local start_point_cleanup = {{-0.9, -0.9}, {1.9, 1.9}} + local surface = event.surface + + -- hack to figure out whether the important chunks are generated via Diggy.Feature.RefreshMap. + if (4 ~= surface.count_tiles_filtered({start_point_area, name = 'lab-dark-1'})) then + return + end + + -- ensure a clean starting point + for _, entity in pairs(surface.find_entities_filtered({area = start_point_cleanup, type = 'resource'})) do + entity.destroy() + end + + local tiles = {} + local rocks = {} + + local dirt_range = floor(starting_zone_size * 0.5) + local rock_range = starting_zone_size - 2 + local stress_hack = floor(starting_zone_size * 0.1) + + for x = -starting_zone_size, starting_zone_size do + for y = -starting_zone_size, starting_zone_size do + local distance = floor(sqrt(x * x + y * y)) + + if (distance < starting_zone_size) then + if (distance > dirt_range) then + insert(tiles, {name = 'dirt-' .. random(1, 7), position = {x = x, y = y}}) + else + insert(tiles, {name = 'stone-path', position = {x = x, y = y}}) + end + + if (distance > rock_range) then + insert(rocks, {name = 'sand-rock-big', position = {x = x, y = y}}) + end + + -- hack to avoid starting area from collapsing + if (distance > stress_hack) then + DiggyCaveCollapse.stress_map_add(surface, {x = x, y = y}, -0.5) + end + end + end + end + + Template.insert(event.surface, tiles, rocks) + + Event.remove_removable(defines.events.on_chunk_generated, callback_token) + end + + callback_token = Token.register(on_chunk_generated) + + Event.add_removable(defines.events.on_chunk_generated, callback_token) +end + + +return StartingZone diff --git a/map_gen/Diggy/Readme.md b/map_gen/Diggy/Readme.md index 05300b0a..f147d062 100644 --- a/map_gen/Diggy/Readme.md +++ b/map_gen/Diggy/Readme.md @@ -1,3 +1,3 @@ -## RedMew - Diggy, Custom Scenario - -The documentation for Diggy has moved to [docs/scenarios/Diggy.md](../../docs/scenarios/Diggy.md). +## RedMew - Diggy, Custom Scenario + +The documentation for Diggy has moved to [docs/scenarios/Diggy.md](../../docs/scenarios/Diggy.md). diff --git a/map_gen/Diggy/Scanner.lua b/map_gen/Diggy/Scanner.lua index 03f8a646..40fa2a93 100644 --- a/map_gen/Diggy/Scanner.lua +++ b/map_gen/Diggy/Scanner.lua @@ -1,42 +1,42 @@ --- dependencies -local insert = table.insert - --- this -local Scanner = {} - ---[[-- - returns a list with all direct positions that contain tile_search. - - @param surface LuaSurface - @param position Position - @param tile_search string name of the tile to search for - @return table with 0~4 directions of which have the tile searched for adjacent -]] -function Scanner.scan_around_position(surface, position, tile_search) - local tile_found = {} - local get_tile = surface.get_tile - - -- north - if (tile_search == get_tile(position.x, position.y - 1).name) then - insert(tile_found, {x = position.x, y = position.y - 1}) - end - - -- east - if (tile_search == get_tile(position.x + 1, position.y).name) then - insert(tile_found, {x = position.x + 1, y = position.y}) - end - - -- south - if (tile_search == get_tile(position.x, position.y + 1).name) then - insert(tile_found, {x = position.x, y = position.y + 1}) - end - - -- west - if (tile_search == get_tile(position.x - 1, position.y).name) then - insert(tile_found, {x = position.x - 1, y = position.y}) - end - - return tile_found; -end - -return Scanner +-- dependencies +local insert = table.insert + +-- this +local Scanner = {} + +--[[-- + returns a list with all direct positions that contain tile_search. + + @param surface LuaSurface + @param position Position + @param tile_search string name of the tile to search for + @return table with 0~4 directions of which have the tile searched for adjacent +]] +function Scanner.scan_around_position(surface, position, tile_search) + local tile_found = {} + local get_tile = surface.get_tile + + -- north + if (tile_search == get_tile(position.x, position.y - 1).name) then + insert(tile_found, {x = position.x, y = position.y - 1}) + end + + -- east + if (tile_search == get_tile(position.x + 1, position.y).name) then + insert(tile_found, {x = position.x + 1, y = position.y}) + end + + -- south + if (tile_search == get_tile(position.x, position.y + 1).name) then + insert(tile_found, {x = position.x, y = position.y + 1}) + end + + -- west + if (tile_search == get_tile(position.x - 1, position.y).name) then + insert(tile_found, {x = position.x - 1, y = position.y}) + end + + return tile_found; +end + +return Scanner diff --git a/map_gen/Diggy/Scenario.lua b/map_gen/Diggy/Scenario.lua index 13411257..ea1870d0 100644 --- a/map_gen/Diggy/Scenario.lua +++ b/map_gen/Diggy/Scenario.lua @@ -1,96 +1,96 @@ --- dependencies -local Config = require 'map_gen.Diggy.Config' -local Debug = require 'map_gen.Diggy.Debug' -local ScenarioInfo = require 'features.gui.info' -local Event = require 'utils.event' - -require 'utils.list_utils' -require 'utils.utils' - --- this -local Scenario = {} - -global.diggy_scenario_registered = false - ---[[-- - Allows calling a callback for each enabled feature. - - Signature: callback(feature_name, Table feature_data) from {@see Config.features}. - - @param if_enabled function to be called if enabled -]] -local function each_enabled_feature(if_enabled) - local type = type(if_enabled) - if ('function' ~= type) then - error('each_enabled_feature expects callback to be a function, given type: ' .. type) - end - - for current_name, feature_data in pairs(Config.features) do - if (nil == feature_data.enabled) then - error('Feature ' .. current_name .. ' did not define the enabled property.') - end - - if (feature_data.enabled) then - if_enabled(current_name, feature_data) - end - end -end - ---[[-- - Register the events required to initialize the scenario. -]] -function Scenario.register(debug) - if global.diggy_scenario_registered then - error('Cannot register the Diggy scenario multiple times.') - return - end - - global.scenario.config.player_list.enable_coin_col = false - if global.scenario.config then - global.scenario.config.fish_market.enable = nil - end - - if ('boolean' == type(debug)) then - Config.Debug = debug - end - - if (Config.debug) then - Debug.enable_debug() - end - - if (Config.cheats) then - Debug.enable_cheats() - end - - local extra_map_info = '' - - each_enabled_feature( - function(feature_name, feature_config) - local feature = require ('map_gen.Diggy.Feature.' .. feature_name) - if ('function' ~= type(feature.register)) then - error('Feature ' .. feature_name .. ' did not define a register function.') - end - - feature.register(feature_config) - - if ('function' == type(feature.get_extra_map_info)) then - extra_map_info = extra_map_info .. feature.get_extra_map_info(feature_config) .. '\n\n' - end - - if ('function' == type(feature.on_init)) then - Event.on_init(feature.on_init) - end - end - ) - - local landfill_tiles = {'dirt-1','dirt-2','dirt-3','dirt-4','dirt-5','dirt-6','dirt-7'} - require ('map_gen.misc.change_landfill_tile')(landfill_tiles) - - ScenarioInfo.set_map_name('Diggy') - ScenarioInfo.set_map_description('Dig your way through!') - ScenarioInfo.set_map_extra_info(extra_map_info) - - global.diggy_scenario_registered = true -end - -return Scenario +-- dependencies +local Config = require 'map_gen.Diggy.Config' +local Debug = require 'map_gen.Diggy.Debug' +local ScenarioInfo = require 'features.gui.info' +local Event = require 'utils.event' + +require 'utils.list_utils' +require 'utils.utils' + +-- this +local Scenario = {} + +global.diggy_scenario_registered = false + +--[[-- + Allows calling a callback for each enabled feature. + + Signature: callback(feature_name, Table feature_data) from {@see Config.features}. + + @param if_enabled function to be called if enabled +]] +local function each_enabled_feature(if_enabled) + local type = type(if_enabled) + if ('function' ~= type) then + error('each_enabled_feature expects callback to be a function, given type: ' .. type) + end + + for current_name, feature_data in pairs(Config.features) do + if (nil == feature_data.enabled) then + error('Feature ' .. current_name .. ' did not define the enabled property.') + end + + if (feature_data.enabled) then + if_enabled(current_name, feature_data) + end + end +end + +--[[-- + Register the events required to initialize the scenario. +]] +function Scenario.register(debug) + if global.diggy_scenario_registered then + error('Cannot register the Diggy scenario multiple times.') + return + end + + global.scenario.config.player_list.enable_coin_col = false + if global.scenario.config then + global.scenario.config.fish_market.enable = nil + end + + if ('boolean' == type(debug)) then + Config.Debug = debug + end + + if (Config.debug) then + Debug.enable_debug() + end + + if (Config.cheats) then + Debug.enable_cheats() + end + + local extra_map_info = '' + + each_enabled_feature( + function(feature_name, feature_config) + local feature = require ('map_gen.Diggy.Feature.' .. feature_name) + if ('function' ~= type(feature.register)) then + error('Feature ' .. feature_name .. ' did not define a register function.') + end + + feature.register(feature_config) + + if ('function' == type(feature.get_extra_map_info)) then + extra_map_info = extra_map_info .. feature.get_extra_map_info(feature_config) .. '\n\n' + end + + if ('function' == type(feature.on_init)) then + Event.on_init(feature.on_init) + end + end + ) + + local landfill_tiles = {'dirt-1','dirt-2','dirt-3','dirt-4','dirt-5','dirt-6','dirt-7'} + require ('map_gen.misc.change_landfill_tile')(landfill_tiles) + + ScenarioInfo.set_map_name('Diggy') + ScenarioInfo.set_map_description('Dig your way through!') + ScenarioInfo.set_map_extra_info(extra_map_info) + + global.diggy_scenario_registered = true +end + +return Scenario diff --git a/map_gen/Diggy/ScoreTable.lua b/map_gen/Diggy/ScoreTable.lua index 041a709d..4a24a310 100644 --- a/map_gen/Diggy/ScoreTable.lua +++ b/map_gen/Diggy/ScoreTable.lua @@ -1,84 +1,84 @@ --- dependencies -local Global = require 'utils.global' - --- this -local ScoreTable = {} - -local scores = {} - -Global.register({ - scores = scores, -}, function (tbl) - scores = tbl.scores -end) - ---[[-- - Resets the score 0 for the given name - - @param name String -]] -function ScoreTable.reset(name) - scores[name] = 0 -end - ---[[-- - Adds score. - - @param name String - @param value int amount to add - - @return int the sum for the score added by name -]] -function ScoreTable.add(name, value) - local new = (scores[name] or 0) + value - scores[name] = new - return new -end - ---[[-- - Increments the score by 1 for name. - - @param name String - - @return int the sum for the score incremented by name -]] -function ScoreTable.increment(name) - return ScoreTable.add(name, 1) -end - ---[[-- - Returns the score for a single key. - - @param -]] -function ScoreTable.get(name) - return scores[name] or 0 -end - ---[[-- - Returns all scores. - - @return table {[string] = int} -]] -function ScoreTable.all() - return scores -end - ---[[-- - Returns all keys of table scores. - - @return table {[string] = name of key} -]] -function ScoreTable.all_keys() - local keyset = {} - local n = 0 - - for k, v in pairs(scores) do - n = n + 1 - keyset[n] = k - end - - return keyset -end - -return ScoreTable +-- dependencies +local Global = require 'utils.global' + +-- this +local ScoreTable = {} + +local scores = {} + +Global.register({ + scores = scores, +}, function (tbl) + scores = tbl.scores +end) + +--[[-- + Resets the score 0 for the given name + + @param name String +]] +function ScoreTable.reset(name) + scores[name] = 0 +end + +--[[-- + Adds score. + + @param name String + @param value int amount to add + + @return int the sum for the score added by name +]] +function ScoreTable.add(name, value) + local new = (scores[name] or 0) + value + scores[name] = new + return new +end + +--[[-- + Increments the score by 1 for name. + + @param name String + + @return int the sum for the score incremented by name +]] +function ScoreTable.increment(name) + return ScoreTable.add(name, 1) +end + +--[[-- + Returns the score for a single key. + + @param +]] +function ScoreTable.get(name) + return scores[name] or 0 +end + +--[[-- + Returns all scores. + + @return table {[string] = int} +]] +function ScoreTable.all() + return scores +end + +--[[-- + Returns all keys of table scores. + + @return table {[string] = name of key} +]] +function ScoreTable.all_keys() + local keyset = {} + local n = 0 + + for k, v in pairs(scores) do + n = n + 1 + keyset[n] = k + end + + return keyset +end + +return ScoreTable diff --git a/map_gen/Diggy/Template.lua b/map_gen/Diggy/Template.lua index 605a91e5..0f2bb488 100644 --- a/map_gen/Diggy/Template.lua +++ b/map_gen/Diggy/Template.lua @@ -1,216 +1,216 @@ --- dependencies -local Task = require 'utils.Task' -local Token = require 'utils.global_token' -local Debug = require 'map_gen.Diggy.Debug' -local insert = table.insert -local min = math.min -local ceil = math.ceil -local raise_event = script.raise_event - --- this -local Template = {} - -local tiles_per_call = 5 --how many tiles are inserted with each call of insert_action -local entities_per_call = 5 --how many entities are inserted with each call of insert_action - -Template.events = { - --[[-- - When an entity is placed via the template function. - - event.entity LuaEntity - ]] - on_placed_entity = script.generate_event_name(), - - --[[-- - Triggers when an 'out-of-map' tile is replaced by something else. - - {surface, old_tile={name, position={x, y}}} - ]] - on_void_removed = script.generate_event_name(), -} - -local function insert_next_tiles(data) - local void_removed = {} - local surface = data.surface - local get_tile = surface.get_tile - local tiles = {} - - pcall( - function() - --use pcall to assure tile_iterator is always incremented, to avoid endless loops - for i = data.tile_iterator, min(data.tile_iterator + tiles_per_call - 1, data.tiles_n) do - local new_tile = data.tiles[i] - insert(tiles, new_tile) - local current_tile = get_tile(new_tile.position.x, new_tile.position.y) - local current_is_void = current_tile.name == 'out-of-map' - local new_is_void = new_tile.name == 'out-of-map' - - if (current_is_void and not new_is_void) then - insert(void_removed, {surface = surface, position = current_tile.position}) - end - end - end - ) - - data.tile_iterator = data.tile_iterator + tiles_per_call - - surface.set_tiles(tiles) - - for _, event in pairs(void_removed) do - raise_event(Template.events.on_void_removed, event) - end -end - -local function insert_next_entities(data) - local created_entities = {} - local surface = data.surface - local create_entity = surface.create_entity - - pcall( - function() - --use pcall to assure tile_iterator is always incremented, to avoid endless loops - for i = data.entity_iterator, min(data.entity_iterator + entities_per_call - 1, data.entities_n) do - local entity = data.entities[i] - local created_entity = create_entity(entity) - if (nil == created_entity) then - error('Failed creating entity ' .. entity.name .. ' on surface.') - end - - insert(created_entities, created_entity) - end - end - ) - - data.entity_iterator = data.entity_iterator + entities_per_call - - for _, entity in pairs(created_entities) do - raise_event(Template.events.on_placed_entity, {entity = entity}) - end - - return data.entity_iterator <= data.entities_n -end - -local function insert_action(data) - if data.tile_iterator <= data.tiles_n then - insert_next_tiles(data) - return true - end - - return insert_next_entities(data) -end - -local insert_token = Token.register(insert_action) - ---[[-- - Inserts a batch of tiles and then entities. - - @see LuaSurface.set_tiles - @see LuaSurface.entity - - @param surface LuaSurface to put the tiles and entities on - @param tiles table of tiles as required by set_tiles - @param entities table of entities as required by create_entity -]] -function Template.insert(surface, tiles, entities) - tiles = tiles or {} - entities = entities or {} - - local tiles_n = #tiles - local entities_n = #entities - local total_calls = ceil(tiles_n / tiles_per_call) + (entities_n / entities_per_call) - local data = { - tiles_n = tiles_n, - tile_iterator = 1, - entities_n = entities_n, - entity_iterator = 1, - surface = surface, - tiles = tiles, - entities = entities - } - - local continue = true - for i = 1, 4 do - continue = insert_action(data) - if not continue then - return - end - end - - if continue then - Task.queue_task(insert_token, data, total_calls - 4) - end -end - ---[[-- - Designed to spawn aliens, uses find_non_colliding_position. - - @see LuaSurface.entity - - @param surface LuaSurface to put the tiles and entities on - @param units table of entities as required by create_entity - @param non_colliding_distance int amount of tiles to scan around original position in case it's already taken - @param generic_unit_name_for_spawn_size String allows setting a custom unit name for spawn size, will overwrite the actual -]] -function Template.units(surface, units, non_colliding_distance, generic_unit_name_for_spawn_size) - non_colliding_distance = non_colliding_distance or 1 - generic_unit_name_for_spawn_size = generic_unit_name_for_spawn_size or 'player' - - local create_entity = surface.create_entity - local position - - for _, entity in pairs(units) do - position = position or surface.find_non_colliding_position( - generic_unit_name_for_spawn_size, - entity.position, non_colliding_distance, - 0.5 - ) - - if (nil ~= position) then - entity.position = position - create_entity(entity) - elseif (nil == create_entity(entity)) then - Debug.print_position(entity.position, "Failed to spawn '" .. entity.name .. "'") - end - end -end - ---[[-- - Designed to spawn resources. - - @see LuaSurface.entity - - @param surface LuaSurface to put the tiles and entities on - @param resources table of entities as required by create_entity -]] -function Template.resources(surface, resources) - local create_entity = surface.create_entity - for _, entity in pairs(resources) do - create_entity(entity) - end -end - ---[[-- - Designed to spawn a market. - - @param surface LuaSurface - @param position Position - @param force LuaForce - @param market_items Table -]] -function Template.market(surface, position, force, market_inventory) - local market = surface.create_entity({name = 'market', position = position}) - local add_market_item = market.add_market_item - market.destructible = false - - for _, item in ipairs(market_inventory) do - add_market_item(item) - end - - force.add_chart_tag(surface, { - text = 'Market', - position = position, - }) - - raise_event(Template.events.on_placed_entity, {entity = market}) -end - -return Template +-- dependencies +local Task = require 'utils.Task' +local Token = require 'utils.global_token' +local Debug = require 'map_gen.Diggy.Debug' +local insert = table.insert +local min = math.min +local ceil = math.ceil +local raise_event = script.raise_event + +-- this +local Template = {} + +local tiles_per_call = 5 --how many tiles are inserted with each call of insert_action +local entities_per_call = 5 --how many entities are inserted with each call of insert_action + +Template.events = { + --[[-- + When an entity is placed via the template function. + - event.entity LuaEntity + ]] + on_placed_entity = script.generate_event_name(), + + --[[-- + Triggers when an 'out-of-map' tile is replaced by something else. + + {surface, old_tile={name, position={x, y}}} + ]] + on_void_removed = script.generate_event_name(), +} + +local function insert_next_tiles(data) + local void_removed = {} + local surface = data.surface + local get_tile = surface.get_tile + local tiles = {} + + pcall( + function() + --use pcall to assure tile_iterator is always incremented, to avoid endless loops + for i = data.tile_iterator, min(data.tile_iterator + tiles_per_call - 1, data.tiles_n) do + local new_tile = data.tiles[i] + insert(tiles, new_tile) + local current_tile = get_tile(new_tile.position.x, new_tile.position.y) + local current_is_void = current_tile.name == 'out-of-map' + local new_is_void = new_tile.name == 'out-of-map' + + if (current_is_void and not new_is_void) then + insert(void_removed, {surface = surface, position = current_tile.position}) + end + end + end + ) + + data.tile_iterator = data.tile_iterator + tiles_per_call + + surface.set_tiles(tiles) + + for _, event in pairs(void_removed) do + raise_event(Template.events.on_void_removed, event) + end +end + +local function insert_next_entities(data) + local created_entities = {} + local surface = data.surface + local create_entity = surface.create_entity + + pcall( + function() + --use pcall to assure tile_iterator is always incremented, to avoid endless loops + for i = data.entity_iterator, min(data.entity_iterator + entities_per_call - 1, data.entities_n) do + local entity = data.entities[i] + local created_entity = create_entity(entity) + if (nil == created_entity) then + error('Failed creating entity ' .. entity.name .. ' on surface.') + end + + insert(created_entities, created_entity) + end + end + ) + + data.entity_iterator = data.entity_iterator + entities_per_call + + for _, entity in pairs(created_entities) do + raise_event(Template.events.on_placed_entity, {entity = entity}) + end + + return data.entity_iterator <= data.entities_n +end + +local function insert_action(data) + if data.tile_iterator <= data.tiles_n then + insert_next_tiles(data) + return true + end + + return insert_next_entities(data) +end + +local insert_token = Token.register(insert_action) + +--[[-- + Inserts a batch of tiles and then entities. + + @see LuaSurface.set_tiles + @see LuaSurface.entity + + @param surface LuaSurface to put the tiles and entities on + @param tiles table of tiles as required by set_tiles + @param entities table of entities as required by create_entity +]] +function Template.insert(surface, tiles, entities) + tiles = tiles or {} + entities = entities or {} + + local tiles_n = #tiles + local entities_n = #entities + local total_calls = ceil(tiles_n / tiles_per_call) + (entities_n / entities_per_call) + local data = { + tiles_n = tiles_n, + tile_iterator = 1, + entities_n = entities_n, + entity_iterator = 1, + surface = surface, + tiles = tiles, + entities = entities + } + + local continue = true + for i = 1, 4 do + continue = insert_action(data) + if not continue then + return + end + end + + if continue then + Task.queue_task(insert_token, data, total_calls - 4) + end +end + +--[[-- + Designed to spawn aliens, uses find_non_colliding_position. + + @see LuaSurface.entity + + @param surface LuaSurface to put the tiles and entities on + @param units table of entities as required by create_entity + @param non_colliding_distance int amount of tiles to scan around original position in case it's already taken + @param generic_unit_name_for_spawn_size String allows setting a custom unit name for spawn size, will overwrite the actual +]] +function Template.units(surface, units, non_colliding_distance, generic_unit_name_for_spawn_size) + non_colliding_distance = non_colliding_distance or 1 + generic_unit_name_for_spawn_size = generic_unit_name_for_spawn_size or 'player' + + local create_entity = surface.create_entity + local position + + for _, entity in pairs(units) do + position = position or surface.find_non_colliding_position( + generic_unit_name_for_spawn_size, + entity.position, non_colliding_distance, + 0.5 + ) + + if (nil ~= position) then + entity.position = position + create_entity(entity) + elseif (nil == create_entity(entity)) then + Debug.print_position(entity.position, "Failed to spawn '" .. entity.name .. "'") + end + end +end + +--[[-- + Designed to spawn resources. + + @see LuaSurface.entity + + @param surface LuaSurface to put the tiles and entities on + @param resources table of entities as required by create_entity +]] +function Template.resources(surface, resources) + local create_entity = surface.create_entity + for _, entity in pairs(resources) do + create_entity(entity) + end +end + +--[[-- + Designed to spawn a market. + + @param surface LuaSurface + @param position Position + @param force LuaForce + @param market_items Table +]] +function Template.market(surface, position, force, market_inventory) + local market = surface.create_entity({name = 'market', position = position}) + local add_market_item = market.add_market_item + market.destructible = false + + for _, item in ipairs(market_inventory) do + add_market_item(item) + end + + force.add_chart_tag(surface, { + text = 'Market', + position = position, + }) + + raise_event(Template.events.on_placed_entity, {entity = market}) +end + +return Template diff --git a/map_gen/combined/diggy.lua b/map_gen/combined/diggy.lua index b71f5236..7304a920 100644 --- a/map_gen/combined/diggy.lua +++ b/map_gen/combined/diggy.lua @@ -1,2 +1,2 @@ --- authors Linaori, valansch -require 'map_gen.Diggy.Scenario'.register(_DEBUG) +-- authors Linaori, valansch +require 'map_gen.Diggy.Scenario'.register(_DEBUG) diff --git a/map_gen/data/presets/plus.lua b/map_gen/data/presets/plus.lua index 165a8836..e755538f 100644 --- a/map_gen/data/presets/plus.lua +++ b/map_gen/data/presets/plus.lua @@ -1,191 +1,191 @@ -return { -height = 185, -width = 337, -data = { - {2,11,1,28,2,85,1,30,2,183,}, - {2,11,1,28,2,85,1,30,2,183,}, - {2,11,1,28,2,85,1,30,2,183,}, - {2,11,1,28,2,85,1,30,2,183,}, - {2,11,1,28,2,85,1,30,2,183,}, - {2,11,1,28,2,85,1,30,2,183,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,10,1,30,2,84,1,30,2,80,1,29,2,74,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, - {2,10,1,30,2,84,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,195,1,29,2,74,}, - {2,11,1,28,2,195,1,29,2,74,}, - {2,11,1,28,2,195,1,29,2,74,}, - {2,11,1,28,2,195,1,29,2,74,}, - {2,11,1,28,2,195,1,29,2,74,}, - {2,11,1,28,2,195,1,29,2,74,}, - {2,11,1,28,2,195,1,29,2,74,}, - {2,11,1,28,2,195,1,29,2,74,}, - {2,11,1,28,2,195,1,29,2,74,}, - {2,11,1,28,2,195,1,29,2,74,}, - {2,11,1,28,2,195,1,29,2,74,}, - {2,11,1,28,2,195,1,29,2,74,}, - {2,11,1,28,2,195,1,29,2,74,}, - {2,11,1,28,2,195,1,29,2,74,}, - {2,11,1,28,2,195,1,29,2,74,}, - {2,11,1,28,2,195,1,29,2,74,}, - {2,11,1,28,2,195,1,29,2,74,}, - {2,11,1,28,2,195,1,29,2,74,}, - {2,11,1,28,2,195,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,79,1,31,2,73,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, - {2,11,1,28,2,85,1,30,2,79,1,31,2,73,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,124,1,30,2,80,1,29,2,74,}, - {2,124,1,30,2,80,1,29,2,74,}, - {2,124,1,30,2,80,1,29,2,74,}, - {2,124,1,30,2,80,1,29,2,74,}, - {2,124,1,30,2,80,1,29,2,74,}, - {2,124,1,30,2,80,1,29,2,74,}, - {2,124,1,30,2,80,1,29,2,74,}, - {2,124,1,30,2,80,1,29,2,74,}, - {2,124,1,30,2,80,1,29,2,74,}, - {2,124,1,30,2,80,1,29,2,74,}, - {2,124,1,30,2,80,1,29,2,74,}, - {2,124,1,30,2,80,1,29,2,74,}, - {2,124,1,30,2,80,1,29,2,74,}, - {2,124,1,30,2,80,1,29,2,74,}, - {2,124,1,30,2,80,1,29,2,74,}, - {2,124,1,30,2,80,1,29,2,74,}, - {2,124,1,30,2,80,1,29,2,74,}, - {2,124,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, - {2,11,1,28,2,85,1,30,2,183,}, - {2,11,1,28,2,85,1,30,2,183,}, - {2,11,1,28,2,85,1,30,2,183,}, - {2,11,1,28,2,85,1,30,2,183,}, - {2,11,1,28,2,85,1,30,2,183,}, - {2,11,1,28,2,85,1,30,2,183,}, - {2,11,1,28,2,85,1,30,2,183,}, - {2,11,1,28,2,85,1,30,2,183,}, - {2,11,1,28,2,85,1,30,2,183,}, - {2,11,1,28,2,85,1,30,2,183,}, - {2,11,1,28,2,85,1,30,2,183,}, - {2,11,1,28,2,85,1,30,2,183,}, - {2,11,1,28,2,85,1,30,2,183,}, -} +return { +height = 185, +width = 337, +data = { + {2,11,1,28,2,85,1,30,2,183,}, + {2,11,1,28,2,85,1,30,2,183,}, + {2,11,1,28,2,85,1,30,2,183,}, + {2,11,1,28,2,85,1,30,2,183,}, + {2,11,1,28,2,85,1,30,2,183,}, + {2,11,1,28,2,85,1,30,2,183,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,10,1,30,2,84,1,30,2,80,1,29,2,74,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {1,108,2,16,1,30,2,80,1,29,2,16,1,58,}, + {2,10,1,30,2,84,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,195,1,29,2,74,}, + {2,11,1,28,2,195,1,29,2,74,}, + {2,11,1,28,2,195,1,29,2,74,}, + {2,11,1,28,2,195,1,29,2,74,}, + {2,11,1,28,2,195,1,29,2,74,}, + {2,11,1,28,2,195,1,29,2,74,}, + {2,11,1,28,2,195,1,29,2,74,}, + {2,11,1,28,2,195,1,29,2,74,}, + {2,11,1,28,2,195,1,29,2,74,}, + {2,11,1,28,2,195,1,29,2,74,}, + {2,11,1,28,2,195,1,29,2,74,}, + {2,11,1,28,2,195,1,29,2,74,}, + {2,11,1,28,2,195,1,29,2,74,}, + {2,11,1,28,2,195,1,29,2,74,}, + {2,11,1,28,2,195,1,29,2,74,}, + {2,11,1,28,2,195,1,29,2,74,}, + {2,11,1,28,2,195,1,29,2,74,}, + {2,11,1,28,2,195,1,29,2,74,}, + {2,11,1,28,2,195,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,79,1,31,2,73,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,11,1,167,2,5,}, + {2,11,1,28,2,85,1,30,2,79,1,31,2,73,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,124,1,30,2,80,1,29,2,74,}, + {2,124,1,30,2,80,1,29,2,74,}, + {2,124,1,30,2,80,1,29,2,74,}, + {2,124,1,30,2,80,1,29,2,74,}, + {2,124,1,30,2,80,1,29,2,74,}, + {2,124,1,30,2,80,1,29,2,74,}, + {2,124,1,30,2,80,1,29,2,74,}, + {2,124,1,30,2,80,1,29,2,74,}, + {2,124,1,30,2,80,1,29,2,74,}, + {2,124,1,30,2,80,1,29,2,74,}, + {2,124,1,30,2,80,1,29,2,74,}, + {2,124,1,30,2,80,1,29,2,74,}, + {2,124,1,30,2,80,1,29,2,74,}, + {2,124,1,30,2,80,1,29,2,74,}, + {2,124,1,30,2,80,1,29,2,74,}, + {2,124,1,30,2,80,1,29,2,74,}, + {2,124,1,30,2,80,1,29,2,74,}, + {2,124,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,17,1,166,2,12,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,80,1,29,2,74,}, + {2,11,1,28,2,85,1,30,2,183,}, + {2,11,1,28,2,85,1,30,2,183,}, + {2,11,1,28,2,85,1,30,2,183,}, + {2,11,1,28,2,85,1,30,2,183,}, + {2,11,1,28,2,85,1,30,2,183,}, + {2,11,1,28,2,85,1,30,2,183,}, + {2,11,1,28,2,85,1,30,2,183,}, + {2,11,1,28,2,85,1,30,2,183,}, + {2,11,1,28,2,85,1,30,2,183,}, + {2,11,1,28,2,85,1,30,2,183,}, + {2,11,1,28,2,85,1,30,2,183,}, + {2,11,1,28,2,85,1,30,2,183,}, + {2,11,1,28,2,85,1,30,2,183,}, +} } \ No newline at end of file diff --git a/map_gen/ores/neko_crazy_ores.lua b/map_gen/ores/neko_crazy_ores.lua index c6bbbec9..a626325e 100644 --- a/map_gen/ores/neko_crazy_ores.lua +++ b/map_gen/ores/neko_crazy_ores.lua @@ -1,48 +1,48 @@ -local perlin = require 'map_gen.shared.perlin_noise' -local Event = require 'utils.event' - -local random_ores = {'iron-ore', 'coal', 'copper-ore', 'stone', 'uranium-ore'} -local random_dense = {1.6, 0.8, 1, 0.6, 0.5} --ore density reference - -local function run_ores_module_setup() - local seed = game.surfaces[1].map_gen_settings.seed - if not global.ores_seed_A then - global.ores_seed_A = seed - end - if not global.ores_seed_B then - global.ores_seed_B = seed * 2 - end -end - -Event.on_init(run_ores_module_setup) - -return function(x, y, world) - local d_sq = world.x * world.x + world.y * world.y - if d_sq < 9216 then - return - end - - local distance_bonus = 100 + 0.4 * d ^ 1.2 - - local wiggle = 100 + perlin.noise((x * 0.005), (y * 0.005), global.ores_seed_A + 41) * 60 - local Ores_A = perlin.noise((x * 0.01), (y * 0.01), global.ores_seed_B + 57) * wiggle - - if Ores_A > 35 then --we place ores - local Ores_B = perlin.noise((x * 0.02), (y * 0.02), global.ores_seed_B + 13) * wiggle - local a = 5 - -- - if Ores_A < 76 then - a = math.floor(Ores_A * 0.75 + Ores_B * 0.5) % 4 + 1 - end --if its not super high we place normal ores - -- - local res_amount = distance_bonus - res_amount = math.floor(res_amount * random_dense[a]) - -- - - return {name = random_ores[a], amount = res_amount} - elseif Ores_A < -60 then - if math.random(1, 200) == 1 then - return {name = 'crude-oil', amount = 5000 + math.floor(distance_bonus) * 500} - end - end -end +local perlin = require 'map_gen.shared.perlin_noise' +local Event = require 'utils.event' + +local random_ores = {'iron-ore', 'coal', 'copper-ore', 'stone', 'uranium-ore'} +local random_dense = {1.6, 0.8, 1, 0.6, 0.5} --ore density reference + +local function run_ores_module_setup() + local seed = game.surfaces[1].map_gen_settings.seed + if not global.ores_seed_A then + global.ores_seed_A = seed + end + if not global.ores_seed_B then + global.ores_seed_B = seed * 2 + end +end + +Event.on_init(run_ores_module_setup) + +return function(x, y, world) + local d_sq = world.x * world.x + world.y * world.y + if d_sq < 9216 then + return + end + + local distance_bonus = 100 + 0.4 * d ^ 1.2 + + local wiggle = 100 + perlin.noise((x * 0.005), (y * 0.005), global.ores_seed_A + 41) * 60 + local Ores_A = perlin.noise((x * 0.01), (y * 0.01), global.ores_seed_B + 57) * wiggle + + if Ores_A > 35 then --we place ores + local Ores_B = perlin.noise((x * 0.02), (y * 0.02), global.ores_seed_B + 13) * wiggle + local a = 5 + -- + if Ores_A < 76 then + a = math.floor(Ores_A * 0.75 + Ores_B * 0.5) % 4 + 1 + end --if its not super high we place normal ores + -- + local res_amount = distance_bonus + res_amount = math.floor(res_amount * random_dense[a]) + -- + + return {name = random_ores[a], amount = res_amount} + elseif Ores_A < -60 then + if math.random(1, 200) == 1 then + return {name = 'crude-oil', amount = 5000 + math.floor(distance_bonus) * 500} + end + end +end diff --git a/map_gen/presets/maltease_crossings.lua b/map_gen/presets/maltease_crossings.lua index 1adfe924..eee60602 100644 --- a/map_gen/presets/maltease_crossings.lua +++ b/map_gen/presets/maltease_crossings.lua @@ -1,178 +1,178 @@ --- Map by Jayefuu, plague006 and grilledham --- Map in the shape of a maltese cross, with narrow water bridges around the spawn to force "interesting" transfer of materials - -local b = require 'map_gen.shared.builders' -local math = require "utils.math" -local degrees = math.rad - -local function value(base, mult, pow) - return function(x, y) - local d_sq = x * x + y * y - return base + mult * d_sq ^ (pow / 2) -- d ^ pow - end -end - -local function no_trees(world, tile) - if not tile then - return - end - for _, e in ipairs( - world.surface.find_entities_filtered( - {type = 'tree', area = {{world.x, world.y}, {world.x + 1, world.y + 1}}} - ) - ) do - e.destroy() - end - return tile -end - -local function no_resources(world, tile) - for _, e in ipairs( - world.surface.find_entities_filtered( - {type = 'resource', area = {{world.x, world.y}, {world.x + 1, world.y + 1}}} - ) - ) do - e.destroy() - end - return tile -end - -local starting_area = 59 - -local gradient = 0.05 -local tiles_half = (starting_area) * 0.5 - -local function maltese_cross(x,y) - --Create maltese shape - - local abs_x = math.abs(x) - local abs_y = math.abs(y) - - return not (abs_x > (tiles_half+(abs_y*gradient)) and abs_y > (tiles_half+(abs_x*gradient))) -end - --- create water crossings and pattern -local water_line = - b.any { - b.rectangle(10,8) - } -water_line = b.change_tile(water_line, true, 'water') - -local waters = b.single_y_pattern(water_line, 9) -local bounds = b.rectangle(10, starting_area+1) -waters = b.choose(bounds, waters, b.empty_shape) -waters = b.translate(waters,34,0) - -local water_pattern = b.any{ - waters, - b.rotate(waters,degrees(90)), - b.rotate(waters,degrees(180)), - b.rotate(waters,degrees(270)) - } - --- create the starting area as a grass square -local starting_square = b.rectangle(60, 60) -starting_square = b.change_tile(starting_square, true, 'grass-1') - -local starting_patch = b.circle(20) -local starting_coal = b.resource(starting_patch, 'coal', value(1800, 0.8, 1.5)) -local starting_iron = b.resource(starting_patch, 'iron-ore', value(3000, 0.8, 1.5)) -local starting_copper = b.resource(starting_patch, 'copper-ore', value(2200, 0.75, 1.5)) -local starting_stone = b.resource(starting_patch, 'stone', value(1100, 0.75, 1.5)) -local null = b.no_entity -local starting_resources = b.segment_pattern({null,starting_coal,null,starting_copper,null,starting_stone,null,starting_iron}) -starting_resources = b.rotate(starting_resources, degrees(45/2)) --- starting_circle = b.circle(14) - --- ore generation -local patch = b.circle(20) -local small_patch = b.circle(8) -local patches = b.single_pattern(patch, 220, 220) - -local stone = b.resource(patch, 'stone', value(100, 0.75, 1.1)) -local oil = b.resource(b.throttle_world_xy(small_patch,1,4,1,4), 'crude-oil', value(33000, 50, 1.05)) -local coal = b.resource(patch, 'coal', value(100, 0.75, 1.1)) -local uranium = b.resource(small_patch, 'uranium-ore', value(200, 0.75, 1.1)) - -local pattern1 = -{ - {stone, oil,stone}, - {stone, oil, oil}, - {stone, stone, stone} -} -local stone_arm = b.grid_pattern(pattern1, 3, 3, 220,220) - -local pattern2 = -{ - {coal, coal, coal}, - {coal, coal, coal}, - {coal, coal, uranium} -} -local coal_arm = b.grid_pattern(pattern2, 3, 3, 220, 220) -local iron = b.resource(patches, 'iron-ore', value(500, 0.8, 1.075)) -local copper = b.resource(patches, 'copper-ore', value(400, 0.75, 1.1)) - -local resources = b.segment_pattern({null,coal_arm,null,copper,null,stone_arm,null,iron}) -resources = b.rotate(resources, degrees(45/2)) - --- worm islands -local worm_island = b.rectangle(20,300) -local worm_island_end = b.circle(10) -worm_island = b.any{ - worm_island_end, - b.translate(worm_island,0,-150), - b.translate(worm_island_end,0,-300) -} -worm_island = b.change_tile(worm_island, true, 'grass-1') - ---[[ -local worm_names = { - 'small-worm-turret', - 'medium-worm-turret', - 'big-worm-turret' -} -]]-- - -local max_worm_chance = 64 / 128 -local worm_chance_factor = 1 --/ (192 * 512) -local function worms(_, _, world) - local wx, wy = world.x, world.y - local d = math.sqrt(wx * wx + wy * wy) - local worm_chance = d - 20 - if worm_chance > 0 then - worm_chance = worm_chance * worm_chance_factor - worm_chance = math.min(worm_chance, max_worm_chance) - if math.random() < worm_chance then - return {name = 'big-worm-turret'} - - end - end -end - -worm_island = b.apply_entity(worm_island, worms) -worm_island = b.apply_effect(worm_island, no_trees) - -local worm_islands = b.any{ - b.rotate(b.translate(worm_island,0,-110),degrees(45)), - b.rotate(b.translate(worm_island,0,-110),degrees(45+90)), - b.rotate(b.translate(worm_island,0,-110),degrees(45+180)), - b.rotate(b.translate(worm_island,0,-110),degrees(45+270)) -} - --- create the start area using the water and grass square -local start_area = - b.any { - water_pattern, - starting_square -} - --- finalising some bits -start_area = b.apply_entity(start_area, starting_resources) -- adds a different density ore patch to start -maltese_cross = b.change_tile(maltese_cross, true, 'grass-1') -maltese_cross = b.apply_entity(maltese_cross, resources) -- adds our custom ore gen -local sea = b.change_tile(b.full_shape, true, 'water') -- turn the void to water -sea = b.fish(sea, 0.00125) -- feesh! -local map = b.any{worm_islands, start_area, maltese_cross, sea} -- combine everything -map = b.apply_effect(map, no_resources) -- removes vanilla ores - +-- Map by Jayefuu, plague006 and grilledham +-- Map in the shape of a maltese cross, with narrow water bridges around the spawn to force "interesting" transfer of materials + +local b = require 'map_gen.shared.builders' +local math = require "utils.math" +local degrees = math.rad + +local function value(base, mult, pow) + return function(x, y) + local d_sq = x * x + y * y + return base + mult * d_sq ^ (pow / 2) -- d ^ pow + end +end + +local function no_trees(world, tile) + if not tile then + return + end + for _, e in ipairs( + world.surface.find_entities_filtered( + {type = 'tree', area = {{world.x, world.y}, {world.x + 1, world.y + 1}}} + ) + ) do + e.destroy() + end + return tile +end + +local function no_resources(world, tile) + for _, e in ipairs( + world.surface.find_entities_filtered( + {type = 'resource', area = {{world.x, world.y}, {world.x + 1, world.y + 1}}} + ) + ) do + e.destroy() + end + return tile +end + +local starting_area = 59 + +local gradient = 0.05 +local tiles_half = (starting_area) * 0.5 + +local function maltese_cross(x,y) + --Create maltese shape + + local abs_x = math.abs(x) + local abs_y = math.abs(y) + + return not (abs_x > (tiles_half+(abs_y*gradient)) and abs_y > (tiles_half+(abs_x*gradient))) +end + +-- create water crossings and pattern +local water_line = + b.any { + b.rectangle(10,8) + } +water_line = b.change_tile(water_line, true, 'water') + +local waters = b.single_y_pattern(water_line, 9) +local bounds = b.rectangle(10, starting_area+1) +waters = b.choose(bounds, waters, b.empty_shape) +waters = b.translate(waters,34,0) + +local water_pattern = b.any{ + waters, + b.rotate(waters,degrees(90)), + b.rotate(waters,degrees(180)), + b.rotate(waters,degrees(270)) + } + +-- create the starting area as a grass square +local starting_square = b.rectangle(60, 60) +starting_square = b.change_tile(starting_square, true, 'grass-1') + +local starting_patch = b.circle(20) +local starting_coal = b.resource(starting_patch, 'coal', value(1800, 0.8, 1.5)) +local starting_iron = b.resource(starting_patch, 'iron-ore', value(3000, 0.8, 1.5)) +local starting_copper = b.resource(starting_patch, 'copper-ore', value(2200, 0.75, 1.5)) +local starting_stone = b.resource(starting_patch, 'stone', value(1100, 0.75, 1.5)) +local null = b.no_entity +local starting_resources = b.segment_pattern({null,starting_coal,null,starting_copper,null,starting_stone,null,starting_iron}) +starting_resources = b.rotate(starting_resources, degrees(45/2)) +-- starting_circle = b.circle(14) + +-- ore generation +local patch = b.circle(20) +local small_patch = b.circle(8) +local patches = b.single_pattern(patch, 220, 220) + +local stone = b.resource(patch, 'stone', value(100, 0.75, 1.1)) +local oil = b.resource(b.throttle_world_xy(small_patch,1,4,1,4), 'crude-oil', value(33000, 50, 1.05)) +local coal = b.resource(patch, 'coal', value(100, 0.75, 1.1)) +local uranium = b.resource(small_patch, 'uranium-ore', value(200, 0.75, 1.1)) + +local pattern1 = +{ + {stone, oil,stone}, + {stone, oil, oil}, + {stone, stone, stone} +} +local stone_arm = b.grid_pattern(pattern1, 3, 3, 220,220) + +local pattern2 = +{ + {coal, coal, coal}, + {coal, coal, coal}, + {coal, coal, uranium} +} +local coal_arm = b.grid_pattern(pattern2, 3, 3, 220, 220) +local iron = b.resource(patches, 'iron-ore', value(500, 0.8, 1.075)) +local copper = b.resource(patches, 'copper-ore', value(400, 0.75, 1.1)) + +local resources = b.segment_pattern({null,coal_arm,null,copper,null,stone_arm,null,iron}) +resources = b.rotate(resources, degrees(45/2)) + +-- worm islands +local worm_island = b.rectangle(20,300) +local worm_island_end = b.circle(10) +worm_island = b.any{ + worm_island_end, + b.translate(worm_island,0,-150), + b.translate(worm_island_end,0,-300) +} +worm_island = b.change_tile(worm_island, true, 'grass-1') + +--[[ +local worm_names = { + 'small-worm-turret', + 'medium-worm-turret', + 'big-worm-turret' +} +]]-- + +local max_worm_chance = 64 / 128 +local worm_chance_factor = 1 --/ (192 * 512) +local function worms(_, _, world) + local wx, wy = world.x, world.y + local d = math.sqrt(wx * wx + wy * wy) + local worm_chance = d - 20 + if worm_chance > 0 then + worm_chance = worm_chance * worm_chance_factor + worm_chance = math.min(worm_chance, max_worm_chance) + if math.random() < worm_chance then + return {name = 'big-worm-turret'} + + end + end +end + +worm_island = b.apply_entity(worm_island, worms) +worm_island = b.apply_effect(worm_island, no_trees) + +local worm_islands = b.any{ + b.rotate(b.translate(worm_island,0,-110),degrees(45)), + b.rotate(b.translate(worm_island,0,-110),degrees(45+90)), + b.rotate(b.translate(worm_island,0,-110),degrees(45+180)), + b.rotate(b.translate(worm_island,0,-110),degrees(45+270)) +} + +-- create the start area using the water and grass square +local start_area = + b.any { + water_pattern, + starting_square +} + +-- finalising some bits +start_area = b.apply_entity(start_area, starting_resources) -- adds a different density ore patch to start +maltese_cross = b.change_tile(maltese_cross, true, 'grass-1') +maltese_cross = b.apply_entity(maltese_cross, resources) -- adds our custom ore gen +local sea = b.change_tile(b.full_shape, true, 'water') -- turn the void to water +sea = b.fish(sea, 0.00125) -- feesh! +local map = b.any{worm_islands, start_area, maltese_cross, sea} -- combine everything +map = b.apply_effect(map, no_resources) -- removes vanilla ores + return map \ No newline at end of file diff --git a/map_gen/shape/right.lua b/map_gen/shape/right.lua index b09b30e6..00a75582 100644 --- a/map_gen/shape/right.lua +++ b/map_gen/shape/right.lua @@ -1,3 +1,3 @@ -return function(x, y, world) - return not (x < -150 or y > 32 or y < -568) -end +return function(x, y, world) + return not (x < -150 or y > 32 or y < -568) +end diff --git a/map_gen/shape/spiral.lua b/map_gen/shape/spiral.lua index 79ffe8e2..5d99f216 100644 --- a/map_gen/shape/spiral.lua +++ b/map_gen/shape/spiral.lua @@ -1,16 +1,16 @@ -local thickness = 72 -- change this to change the spiral thickness. - -local inv_pi = 1 / math.pi -local thickness2 = thickness * 2 - -return function(x, y) - local d_sq = x * x + y * y - if d_sq < 16384 then --d < 128 - return true - end - - local angle = 1 + inv_pi * math.atan2(x, y) - local offset = d + (angle * thickness) - - return offset % thickness2 >= thickness -end +local thickness = 72 -- change this to change the spiral thickness. + +local inv_pi = 1 / math.pi +local thickness2 = thickness * 2 + +return function(x, y) + local d_sq = x * x + y * y + if d_sq < 16384 then --d < 128 + return true + end + + local angle = 1 + inv_pi * math.atan2(x, y) + local offset = d + (angle * thickness) + + return offset % thickness2 >= thickness +end diff --git a/map_gen/shape/spiral2.lua b/map_gen/shape/spiral2.lua index e202595d..accb0a19 100644 --- a/map_gen/shape/spiral2.lua +++ b/map_gen/shape/spiral2.lua @@ -1,20 +1,20 @@ -return function(x, y, world) - local distance = math.sqrt(x * x + y * y) - if distance > 128 then - local angle = 180 + math.deg(math.atan2(x, y)) - - local offset = distance - local offset2 = distance - if angle ~= 0 then - offset2 = offset - angle / 3.75 - offset = offset + angle / 3.75 - end - --if angle ~= 0 then offset = offset + angle /1.33333333 end - - if offset % 96 < 64 then - return offset2 % 96 >= 64 - end - end - - return true -end +return function(x, y, world) + local distance = math.sqrt(x * x + y * y) + if distance > 128 then + local angle = 180 + math.deg(math.atan2(x, y)) + + local offset = distance + local offset2 = distance + if angle ~= 0 then + offset2 = offset - angle / 3.75 + offset = offset + angle / 3.75 + end + --if angle ~= 0 then offset = offset + angle /1.33333333 end + + if offset % 96 < 64 then + return offset2 % 96 >= 64 + end + end + + return true +end diff --git a/map_gen/shape/spiral_tri.lua b/map_gen/shape/spiral_tri.lua index 4c0f289c..8ae452cd 100644 --- a/map_gen/shape/spiral_tri.lua +++ b/map_gen/shape/spiral_tri.lua @@ -1,23 +1,23 @@ -return function(x, y, world) - local distance = math.sqrt(x * x + y * y) - if distance > 128 then - local angle = (180 + math.deg(math.atan2(x, y))) * 3 - - local offset = distance * 0.75 - if angle ~= 0 then - offset = offset + angle / 3.75 - end - --if angle ~= 0 then offset = offset + angle /1.33333333 end - - if offset % 96 < 48 then - local offset2 = distance * 0.125 - if angle ~= 0 then - offset2 = offset2 - angle / 3.75 - end - - return offset2 % 96 >= 80 - end - end - - return true -end +return function(x, y, world) + local distance = math.sqrt(x * x + y * y) + if distance > 128 then + local angle = (180 + math.deg(math.atan2(x, y))) * 3 + + local offset = distance * 0.75 + if angle ~= 0 then + offset = offset + angle / 3.75 + end + --if angle ~= 0 then offset = offset + angle /1.33333333 end + + if offset % 96 < 48 then + local offset2 = distance * 0.125 + if angle ~= 0 then + offset2 = offset2 - angle / 3.75 + end + + return offset2 % 96 >= 80 + end + end + + return true +end diff --git a/map_gen/shape/threaded_spirals.lua b/map_gen/shape/threaded_spirals.lua index b85aafe0..aed98eaf 100644 --- a/map_gen/shape/threaded_spirals.lua +++ b/map_gen/shape/threaded_spirals.lua @@ -1,21 +1,21 @@ --- Author: flowild - -local arm_width = 96 - -local function is_on_spiral(x, y, distance, angle_offset) - local angle = angle_offset + math.deg(math.atan2(x, y)) - - local offset = distance - if angle ~= 0 then - offset = offset + angle / 3.75 * 2 - end - return offset % 96 * 2 >= 48 * 2 -end - -return function(x, y, world) - local pseudo_x = x / (arm_width / 48) - local pseudo_y = y / (arm_width / 48) - local distance = math.sqrt(pseudo_x * pseudo_x + pseudo_y * pseudo_y) - - return not (distance > 100 and not is_on_spiral(x, y, distance, 0)) -end +-- Author: flowild + +local arm_width = 96 + +local function is_on_spiral(x, y, distance, angle_offset) + local angle = angle_offset + math.deg(math.atan2(x, y)) + + local offset = distance + if angle ~= 0 then + offset = offset + angle / 3.75 * 2 + end + return offset % 96 * 2 >= 48 * 2 +end + +return function(x, y, world) + local pseudo_x = x / (arm_width / 48) + local pseudo_y = y / (arm_width / 48) + local distance = math.sqrt(pseudo_x * pseudo_x + pseudo_y * pseudo_y) + + return not (distance > 100 and not is_on_spiral(x, y, distance, 0)) +end diff --git a/map_gen/shape/up.lua b/map_gen/shape/up.lua index d9ca0d7e..70d9d539 100644 --- a/map_gen/shape/up.lua +++ b/map_gen/shape/up.lua @@ -1,3 +1,3 @@ -return function(x, y, world) - return not (x > 180 or x < -180 or y > 80) -end +return function(x, y, world) + return not (x > 180 or x < -180 or y > 80) +end diff --git a/map_gen/shared/ent_functions.lua b/map_gen/shared/ent_functions.lua index a84d2b9e..8c8a8610 100644 --- a/map_gen/shared/ent_functions.lua +++ b/map_gen/shared/ent_functions.lua @@ -1,535 +1,535 @@ ---allows any gen to access these functions - -function place_entities(surface, entity_list) - local directions = {defines.direction.north, defines.direction.east, defines.direction.south, defines.direction.west} - for _, entity in pairs(entity_list) do - local r = math.random(1,entity.chance) - if r == 1 then - if not entity.force then entity.force = "player" end - local r = math.random(1,4) - if surface.can_place_entity {name=entity.name, position=entity.pos, direction=directions[r], force=entity.force} then - local e = surface.create_entity {name=entity.name, position=entity.pos, direction=directions[r], force=entity.force} - if entity.health then - if entity.health == "low" then e.health = ((e.health / 1000) * math.random(33,330)) end - if entity.health == "medium" then e.health = ((e.health / 1000) * math.random(333,666)) end - if entity.health == "high" then e.health = ((e.health / 1000) * math.random(666,999)) end - if entity.health == "random" then e.health = ((e.health / 1000) * math.random(1,1000)) end - end - return true, e - end - end - end - return false -end - -function auto_place_entity_around_target(entity, scan_radius, mode, density, surface) - local x = entity.pos.x - local y = entity.pos.y - if not surface then surface = game.surfaces[1] end - if not scan_radius then scan_radius = 6 end - if not entity then return end - if not mode then mode = "ball" end - if not density then density = 1 end - - if surface.can_place_entity {name=entity.name, position={x,y}} then - local e = surface.create_entity {name=entity.name, position={x,y}} - return true, e - end - - local i = 2 - local r = 1 - - if mode == "ball" then - if math.random(1,2) == 1 then - density = density * -1 - end - r = math.random(1,4) - end - if mode == "line" then - density = 1 - r = math.random(1,4) - end - if mode == "line_down" then - density = density * -1 - r = math.random(1,4) - end - if mode == "line_up" then - density = 1 - r = math.random(1,4) - end - if mode == "block" then - r = 1 - density = 1 - end - - if r == 1 then - --start placing at -1,-1 - while i <= scan_radius do - y = y - density - x = x - density - for a = 1, i, 1 do - if surface.can_place_entity {name=entity.name, position={x,y}} then - local e = surface.create_entity {name=entity.name, position={x,y}} - return true, e - end - x = x + density - end - for a = 1, i, 1 do - if surface.can_place_entity {name=entity.name, position={x,y}} then - local e = surface.create_entity {name=entity.name, position={x,y}} - return true, e - end - y = y + density - end - for a = 1, i, 1 do - if surface.can_place_entity {name=entity.name, position={x,y}} then - local e = surface.create_entity {name=entity.name, position={x,y}} - return true, e - end - x = x - density - end - for a = 1, i, 1 do - if surface.can_place_entity {name=entity.name, position={x,y}} then - local e = surface.create_entity {name=entity.name, position={x,y}} - return true, e - end - y = y - density - end - i = i + 2 - end - end - - if r == 2 then - --start placing at 0,-1 - while i <= scan_radius do - y = y - density - x = x - density - for a = 1, i, 1 do - x = x + density - if surface.can_place_entity {name=entity.name, position={x,y}} then - local e = surface.create_entity {name=entity.name, position={x,y}} - return true, e - end - end - for a = 1, i, 1 do - y = y + density - if surface.can_place_entity {name=entity.name, position={x,y}} then - local e = surface.create_entity {name=entity.name, position={x,y}} - return true, e - end - end - for a = 1, i, 1 do - x = x - density - if surface.can_place_entity {name=entity.name, position={x,y}} then - local e = surface.create_entity {name=entity.name, position={x,y}} - return true, e - end - end - for a = 1, i, 1 do - y = y - density - if surface.can_place_entity {name=entity.name, position={x,y}} then - local e = surface.create_entity {name=entity.name, position={x,y}} - return true, e - end - end - i = i + 2 - end - end - - if r == 3 then - --start placing at 1,-1 - while i <= scan_radius do - y = y - density - x = x + density - for a = 1, i, 1 do - if surface.can_place_entity {name=entity.name, position={x,y}} then - local e = surface.create_entity {name=entity.name, position={x,y}} - return true, e - end - y = y + density - end - for a = 1, i, 1 do - if surface.can_place_entity {name=entity.name, position={x,y}} then - local e = surface.create_entity {name=entity.name, position={x,y}} - return true, e - end - x = x - density - end - for a = 1, i, 1 do - if surface.can_place_entity {name=entity.name, position={x,y}} then - local e = surface.create_entity {name=entity.name, position={x,y}} - return true, e - end - y = y - density - end - for a = 1, i, 1 do - if surface.can_place_entity {name=entity.name, position={x,y}} then - local e = surface.create_entity {name=entity.name, position={x,y}} - return true, e - end - x = x + density - end - i = i + 2 - end - end - - if r == 4 then - --start placing at 1,0 - while i <= scan_radius do - y = y - density - x = x + density - for a = 1, i, 1 do - y = y + density - if surface.can_place_entity {name=entity.name, position={x,y}} then - local e = surface.create_entity {name=entity.name, position={x,y}} - return true, e - end - end - for a = 1, i, 1 do - x = x - density - if surface.can_place_entity {name=entity.name, position={x,y}} then - local e = surface.create_entity {name=entity.name, position={x,y}} - return true, e - end - end - for a = 1, i, 1 do - y = y - density - if surface.can_place_entity {name=entity.name, position={x,y}} then - local e = surface.create_entity {name=entity.name, position={x,y}} - return true, e - end - end - for a = 1, i, 1 do - x = x + density - if surface.can_place_entity {name=entity.name, position={x,y}} then - local e = surface.create_entity {name=entity.name, position={x,y}} - return true, e - end - end - i = i + 2 - end - end - - return false -end - -function create_entitie_cluster(name, pos, amount) - - local surface = game.surfaces[1] - local entity = {} - entity.pos = pos - entity.name = name - local mode = "ball" - - for i = 1, amount, 1 do - local b, e = auto_place_entity_around_target(entity, 30, mode) - if b == true then - if 1 == math.random(1,40) then - entity.pos = e.position - end - if e.type == "resource" then - e.amount = math.random(500,1500) - end - end - end - return b, e -end - -function create_rock_cluster(pos, amount) - if not pos then return false end - if amount == nil then amount = 7 end - local scan_radius = amount * 2 - local mode = "line_down" - if math.random(1,2) == 1 then mode = "line_up" end - local entity = {} - entity.pos = pos - for i = 1, amount, 1 do - if 1 == math.random(1,3) then - entity.name = "sand-rock-big" - else - entity.name = "sand-rock-big" - end - local b, e = auto_place_entity_around_target(entity, scan_radius, mode) - if b == true then - if 1 ~= math.random(1,20) then - entity.pos = e.position - end - end - end - return b, e -end - -function create_tree_cluster(pos, amount) - if not pos then return false end - if amount == nil then amount = 7 end - local scan_radius = amount * 2 - --local mode = "line_down" - --if math.random(1,2) == 1 then mode = "line_up" end - local mode = "ball" - local entity = {} - entity.pos = pos - for i = 1, amount, 1 do - entity.name = "tree-06" - local density = 2 - if 1 == math.random(1,20) then entity.name = "tree-07" end - if 1 == math.random(1,70) then entity.name = "tree-09" end - if 1 == math.random(1,10) then entity.name = "tree-04" end - if 1 == math.random(1,9) then density = 1 end - if 1 == math.random(1,3) then density = 3 end - if 1 == math.random(1,3) then density = 4 end - - local b, e = auto_place_entity_around_target(entity, scan_radius, mode, density) - if b == true then - if 1 == math.random(1,3) then - entity.pos = e.position - end - end - end - return b, e -end - -function find_tile_placement_spot_around_target_position(tilename, position, mode, density) - local x = position.x - local y = position.y - if not surface then surface = game.surfaces[1] end - local scan_radius = 50 - if not tilename then return end - if not mode then mode = "ball" end - if not density then density = 1 end - local cluster_tiles = {} - local auto_correct = false - - local scanned_tile = surface.get_tile(x,y) - if scanned_tile.name ~= tilename then - table.insert(cluster_tiles, {name = tilename, position = {x,y}}) - surface.set_tiles(cluster_tiles,false) - return true, x, y - end - - local i = 2 - local r = 1 - - if mode == "ball" then - if math.random(1,2) == 1 then - density = density * -1 - end - r = math.random(1,4) - end - if mode == "line" then - density = 1 - r = math.random(1,4) - end - if mode == "line_down" then - density = density * -1 - r = math.random(1,4) - end - if mode == "line_up" then - density = 1 - r = math.random(1,4) - end - if mode == "block" then - r = 1 - density = 1 - end - - if r == 1 then - --start placing at -1,-1 - while i <= scan_radius do - y = y - density - x = x - density - for a = 1, i, 1 do - local scanned_tile = surface.get_tile(x,y) - if scanned_tile.name ~= tilename then - table.insert(cluster_tiles, {name = tilename, position = {x,y}}) - surface.set_tiles(cluster_tiles,auto_correct) - return true, x, y - end - x = x + density - end - for a = 1, i, 1 do - local scanned_tile = surface.get_tile(x,y) - if scanned_tile.name ~= tilename then - table.insert(cluster_tiles, {name = tilename, position = {x,y}}) - surface.set_tiles(cluster_tiles,auto_correct) - return true, x, y - end - y = y + density - end - for a = 1, i, 1 do - local scanned_tile = surface.get_tile(x,y) - if scanned_tile.name ~= tilename then - table.insert(cluster_tiles, {name = tilename, position = {x,y}}) - surface.set_tiles(cluster_tiles,auto_correct) - return true, x, y - end - x = x - density - end - for a = 1, i, 1 do - local scanned_tile = surface.get_tile(x,y) - if scanned_tile.name ~= tilename then - table.insert(cluster_tiles, {name = tilename, position = {x,y}}) - surface.set_tiles(cluster_tiles,auto_correct) - return true, x, y - end - y = y - density - end - i = i + 2 - end - end - - if r == 2 then - --start placing at 0,-1 - while i <= scan_radius do - y = y - density - x = x - density - for a = 1, i, 1 do - x = x + density - local scanned_tile = surface.get_tile(x,y) - if scanned_tile.name ~= tilename then - table.insert(cluster_tiles, {name = tilename, position = {x,y}}) - surface.set_tiles(cluster_tiles,auto_correct) - return true, x, y - end - end - for a = 1, i, 1 do - y = y + density - local scanned_tile = surface.get_tile(x,y) - if scanned_tile.name ~= tilename then - table.insert(cluster_tiles, {name = tilename, position = {x,y}}) - surface.set_tiles(cluster_tiles,auto_correct) - return true, x, y - end - end - for a = 1, i, 1 do - x = x - density - local scanned_tile = surface.get_tile(x,y) - if scanned_tile.name ~= tilename then - table.insert(cluster_tiles, {name = tilename, position = {x,y}}) - surface.set_tiles(cluster_tiles,auto_correct) - return true, x, y - end - end - for a = 1, i, 1 do - y = y - density - local scanned_tile = surface.get_tile(x,y) - if scanned_tile.name ~= tilename then - table.insert(cluster_tiles, {name = tilename, position = {x,y}}) - surface.set_tiles(cluster_tiles,auto_correct) - return true, x, y - end - end - i = i + 2 - end - end - - if r == 3 then - --start placing at 1,-1 - while i <= scan_radius do - y = y - density - x = x + density - for a = 1, i, 1 do - local scanned_tile = surface.get_tile(x,y) - if scanned_tile.name ~= tilename then - table.insert(cluster_tiles, {name = tilename, position = {x,y}}) - surface.set_tiles(cluster_tiles,auto_correct) - return true, x, y - end - y = y + density - end - for a = 1, i, 1 do - local scanned_tile = surface.get_tile(x,y) - if scanned_tile.name ~= tilename then - table.insert(cluster_tiles, {name = tilename, position = {x,y}}) - surface.set_tiles(cluster_tiles,auto_correct) - return true, x, y - end - x = x - density - end - for a = 1, i, 1 do - local scanned_tile = surface.get_tile(x,y) - if scanned_tile.name ~= tilename then - table.insert(cluster_tiles, {name = tilename, position = {x,y}}) - surface.set_tiles(cluster_tiles,auto_correct) - return true, x, y - end - y = y - density - end - for a = 1, i, 1 do - local scanned_tile = surface.get_tile(x,y) - if scanned_tile.name ~= tilename then - table.insert(cluster_tiles, {name = tilename, position = {x,y}}) - surface.set_tiles(cluster_tiles,auto_correct) - return true, x, y - end - x = x + density - end - i = i + 2 - end - end - - if r == 4 then - --start placing at 1,0 - while i <= scan_radius do - y = y - density - x = x + density - for a = 1, i, 1 do - y = y + density - local scanned_tile = surface.get_tile(x,y) - if scanned_tile.name ~= tilename then - table.insert(cluster_tiles, {name = tilename, position = {x,y}}) - surface.set_tiles(cluster_tiles,auto_correct) - return true, x, y - end - end - for a = 1, i, 1 do - x = x - density - local scanned_tile = surface.get_tile(x,y) - if scanned_tile.name ~= tilename then - table.insert(cluster_tiles, {name = tilename, position = {x,y}}) - surface.set_tiles(cluster_tiles,auto_correct) - return true, x, y - end - end - for a = 1, i, 1 do - y = y - density - local scanned_tile = surface.get_tile(x,y) - if scanned_tile.name ~= tilename then - table.insert(cluster_tiles, {name = tilename, position = {x,y}}) - surface.set_tiles(cluster_tiles,auto_correct) - return true, x, y - end - end - for a = 1, i, 1 do - x = x + density - local scanned_tile = surface.get_tile(x,y) - if scanned_tile.name ~= tilename then - table.insert(cluster_tiles, {name = tilename, position = {x,y}}) - surface.set_tiles(cluster_tiles,auto_correct) - return true, x, y - end - end - i = i + 2 - end - end - return false -end - -function create_tile_cluster(tilename,position,amount) - local mode = "ball" - local cluster_tiles = {} - local surface = game.surfaces[1] - local pos = position - local x = pos.x - local y = pos.y - for i = 1, amount, 1 do - local b,x,y = find_tile_placement_spot_around_target_position(tilename, pos, mode) - if b == true then - if 1 == math.random(1,2) then - pos.x = x - pos.y = y - end - end - if b == false then return false,x,y end - if i >= amount then return true,x,y end - end -end +--allows any gen to access these functions + +function place_entities(surface, entity_list) + local directions = {defines.direction.north, defines.direction.east, defines.direction.south, defines.direction.west} + for _, entity in pairs(entity_list) do + local r = math.random(1,entity.chance) + if r == 1 then + if not entity.force then entity.force = "player" end + local r = math.random(1,4) + if surface.can_place_entity {name=entity.name, position=entity.pos, direction=directions[r], force=entity.force} then + local e = surface.create_entity {name=entity.name, position=entity.pos, direction=directions[r], force=entity.force} + if entity.health then + if entity.health == "low" then e.health = ((e.health / 1000) * math.random(33,330)) end + if entity.health == "medium" then e.health = ((e.health / 1000) * math.random(333,666)) end + if entity.health == "high" then e.health = ((e.health / 1000) * math.random(666,999)) end + if entity.health == "random" then e.health = ((e.health / 1000) * math.random(1,1000)) end + end + return true, e + end + end + end + return false +end + +function auto_place_entity_around_target(entity, scan_radius, mode, density, surface) + local x = entity.pos.x + local y = entity.pos.y + if not surface then surface = game.surfaces[1] end + if not scan_radius then scan_radius = 6 end + if not entity then return end + if not mode then mode = "ball" end + if not density then density = 1 end + + if surface.can_place_entity {name=entity.name, position={x,y}} then + local e = surface.create_entity {name=entity.name, position={x,y}} + return true, e + end + + local i = 2 + local r = 1 + + if mode == "ball" then + if math.random(1,2) == 1 then + density = density * -1 + end + r = math.random(1,4) + end + if mode == "line" then + density = 1 + r = math.random(1,4) + end + if mode == "line_down" then + density = density * -1 + r = math.random(1,4) + end + if mode == "line_up" then + density = 1 + r = math.random(1,4) + end + if mode == "block" then + r = 1 + density = 1 + end + + if r == 1 then + --start placing at -1,-1 + while i <= scan_radius do + y = y - density + x = x - density + for a = 1, i, 1 do + if surface.can_place_entity {name=entity.name, position={x,y}} then + local e = surface.create_entity {name=entity.name, position={x,y}} + return true, e + end + x = x + density + end + for a = 1, i, 1 do + if surface.can_place_entity {name=entity.name, position={x,y}} then + local e = surface.create_entity {name=entity.name, position={x,y}} + return true, e + end + y = y + density + end + for a = 1, i, 1 do + if surface.can_place_entity {name=entity.name, position={x,y}} then + local e = surface.create_entity {name=entity.name, position={x,y}} + return true, e + end + x = x - density + end + for a = 1, i, 1 do + if surface.can_place_entity {name=entity.name, position={x,y}} then + local e = surface.create_entity {name=entity.name, position={x,y}} + return true, e + end + y = y - density + end + i = i + 2 + end + end + + if r == 2 then + --start placing at 0,-1 + while i <= scan_radius do + y = y - density + x = x - density + for a = 1, i, 1 do + x = x + density + if surface.can_place_entity {name=entity.name, position={x,y}} then + local e = surface.create_entity {name=entity.name, position={x,y}} + return true, e + end + end + for a = 1, i, 1 do + y = y + density + if surface.can_place_entity {name=entity.name, position={x,y}} then + local e = surface.create_entity {name=entity.name, position={x,y}} + return true, e + end + end + for a = 1, i, 1 do + x = x - density + if surface.can_place_entity {name=entity.name, position={x,y}} then + local e = surface.create_entity {name=entity.name, position={x,y}} + return true, e + end + end + for a = 1, i, 1 do + y = y - density + if surface.can_place_entity {name=entity.name, position={x,y}} then + local e = surface.create_entity {name=entity.name, position={x,y}} + return true, e + end + end + i = i + 2 + end + end + + if r == 3 then + --start placing at 1,-1 + while i <= scan_radius do + y = y - density + x = x + density + for a = 1, i, 1 do + if surface.can_place_entity {name=entity.name, position={x,y}} then + local e = surface.create_entity {name=entity.name, position={x,y}} + return true, e + end + y = y + density + end + for a = 1, i, 1 do + if surface.can_place_entity {name=entity.name, position={x,y}} then + local e = surface.create_entity {name=entity.name, position={x,y}} + return true, e + end + x = x - density + end + for a = 1, i, 1 do + if surface.can_place_entity {name=entity.name, position={x,y}} then + local e = surface.create_entity {name=entity.name, position={x,y}} + return true, e + end + y = y - density + end + for a = 1, i, 1 do + if surface.can_place_entity {name=entity.name, position={x,y}} then + local e = surface.create_entity {name=entity.name, position={x,y}} + return true, e + end + x = x + density + end + i = i + 2 + end + end + + if r == 4 then + --start placing at 1,0 + while i <= scan_radius do + y = y - density + x = x + density + for a = 1, i, 1 do + y = y + density + if surface.can_place_entity {name=entity.name, position={x,y}} then + local e = surface.create_entity {name=entity.name, position={x,y}} + return true, e + end + end + for a = 1, i, 1 do + x = x - density + if surface.can_place_entity {name=entity.name, position={x,y}} then + local e = surface.create_entity {name=entity.name, position={x,y}} + return true, e + end + end + for a = 1, i, 1 do + y = y - density + if surface.can_place_entity {name=entity.name, position={x,y}} then + local e = surface.create_entity {name=entity.name, position={x,y}} + return true, e + end + end + for a = 1, i, 1 do + x = x + density + if surface.can_place_entity {name=entity.name, position={x,y}} then + local e = surface.create_entity {name=entity.name, position={x,y}} + return true, e + end + end + i = i + 2 + end + end + + return false +end + +function create_entitie_cluster(name, pos, amount) + + local surface = game.surfaces[1] + local entity = {} + entity.pos = pos + entity.name = name + local mode = "ball" + + for i = 1, amount, 1 do + local b, e = auto_place_entity_around_target(entity, 30, mode) + if b == true then + if 1 == math.random(1,40) then + entity.pos = e.position + end + if e.type == "resource" then + e.amount = math.random(500,1500) + end + end + end + return b, e +end + +function create_rock_cluster(pos, amount) + if not pos then return false end + if amount == nil then amount = 7 end + local scan_radius = amount * 2 + local mode = "line_down" + if math.random(1,2) == 1 then mode = "line_up" end + local entity = {} + entity.pos = pos + for i = 1, amount, 1 do + if 1 == math.random(1,3) then + entity.name = "sand-rock-big" + else + entity.name = "sand-rock-big" + end + local b, e = auto_place_entity_around_target(entity, scan_radius, mode) + if b == true then + if 1 ~= math.random(1,20) then + entity.pos = e.position + end + end + end + return b, e +end + +function create_tree_cluster(pos, amount) + if not pos then return false end + if amount == nil then amount = 7 end + local scan_radius = amount * 2 + --local mode = "line_down" + --if math.random(1,2) == 1 then mode = "line_up" end + local mode = "ball" + local entity = {} + entity.pos = pos + for i = 1, amount, 1 do + entity.name = "tree-06" + local density = 2 + if 1 == math.random(1,20) then entity.name = "tree-07" end + if 1 == math.random(1,70) then entity.name = "tree-09" end + if 1 == math.random(1,10) then entity.name = "tree-04" end + if 1 == math.random(1,9) then density = 1 end + if 1 == math.random(1,3) then density = 3 end + if 1 == math.random(1,3) then density = 4 end + + local b, e = auto_place_entity_around_target(entity, scan_radius, mode, density) + if b == true then + if 1 == math.random(1,3) then + entity.pos = e.position + end + end + end + return b, e +end + +function find_tile_placement_spot_around_target_position(tilename, position, mode, density) + local x = position.x + local y = position.y + if not surface then surface = game.surfaces[1] end + local scan_radius = 50 + if not tilename then return end + if not mode then mode = "ball" end + if not density then density = 1 end + local cluster_tiles = {} + local auto_correct = false + + local scanned_tile = surface.get_tile(x,y) + if scanned_tile.name ~= tilename then + table.insert(cluster_tiles, {name = tilename, position = {x,y}}) + surface.set_tiles(cluster_tiles,false) + return true, x, y + end + + local i = 2 + local r = 1 + + if mode == "ball" then + if math.random(1,2) == 1 then + density = density * -1 + end + r = math.random(1,4) + end + if mode == "line" then + density = 1 + r = math.random(1,4) + end + if mode == "line_down" then + density = density * -1 + r = math.random(1,4) + end + if mode == "line_up" then + density = 1 + r = math.random(1,4) + end + if mode == "block" then + r = 1 + density = 1 + end + + if r == 1 then + --start placing at -1,-1 + while i <= scan_radius do + y = y - density + x = x - density + for a = 1, i, 1 do + local scanned_tile = surface.get_tile(x,y) + if scanned_tile.name ~= tilename then + table.insert(cluster_tiles, {name = tilename, position = {x,y}}) + surface.set_tiles(cluster_tiles,auto_correct) + return true, x, y + end + x = x + density + end + for a = 1, i, 1 do + local scanned_tile = surface.get_tile(x,y) + if scanned_tile.name ~= tilename then + table.insert(cluster_tiles, {name = tilename, position = {x,y}}) + surface.set_tiles(cluster_tiles,auto_correct) + return true, x, y + end + y = y + density + end + for a = 1, i, 1 do + local scanned_tile = surface.get_tile(x,y) + if scanned_tile.name ~= tilename then + table.insert(cluster_tiles, {name = tilename, position = {x,y}}) + surface.set_tiles(cluster_tiles,auto_correct) + return true, x, y + end + x = x - density + end + for a = 1, i, 1 do + local scanned_tile = surface.get_tile(x,y) + if scanned_tile.name ~= tilename then + table.insert(cluster_tiles, {name = tilename, position = {x,y}}) + surface.set_tiles(cluster_tiles,auto_correct) + return true, x, y + end + y = y - density + end + i = i + 2 + end + end + + if r == 2 then + --start placing at 0,-1 + while i <= scan_radius do + y = y - density + x = x - density + for a = 1, i, 1 do + x = x + density + local scanned_tile = surface.get_tile(x,y) + if scanned_tile.name ~= tilename then + table.insert(cluster_tiles, {name = tilename, position = {x,y}}) + surface.set_tiles(cluster_tiles,auto_correct) + return true, x, y + end + end + for a = 1, i, 1 do + y = y + density + local scanned_tile = surface.get_tile(x,y) + if scanned_tile.name ~= tilename then + table.insert(cluster_tiles, {name = tilename, position = {x,y}}) + surface.set_tiles(cluster_tiles,auto_correct) + return true, x, y + end + end + for a = 1, i, 1 do + x = x - density + local scanned_tile = surface.get_tile(x,y) + if scanned_tile.name ~= tilename then + table.insert(cluster_tiles, {name = tilename, position = {x,y}}) + surface.set_tiles(cluster_tiles,auto_correct) + return true, x, y + end + end + for a = 1, i, 1 do + y = y - density + local scanned_tile = surface.get_tile(x,y) + if scanned_tile.name ~= tilename then + table.insert(cluster_tiles, {name = tilename, position = {x,y}}) + surface.set_tiles(cluster_tiles,auto_correct) + return true, x, y + end + end + i = i + 2 + end + end + + if r == 3 then + --start placing at 1,-1 + while i <= scan_radius do + y = y - density + x = x + density + for a = 1, i, 1 do + local scanned_tile = surface.get_tile(x,y) + if scanned_tile.name ~= tilename then + table.insert(cluster_tiles, {name = tilename, position = {x,y}}) + surface.set_tiles(cluster_tiles,auto_correct) + return true, x, y + end + y = y + density + end + for a = 1, i, 1 do + local scanned_tile = surface.get_tile(x,y) + if scanned_tile.name ~= tilename then + table.insert(cluster_tiles, {name = tilename, position = {x,y}}) + surface.set_tiles(cluster_tiles,auto_correct) + return true, x, y + end + x = x - density + end + for a = 1, i, 1 do + local scanned_tile = surface.get_tile(x,y) + if scanned_tile.name ~= tilename then + table.insert(cluster_tiles, {name = tilename, position = {x,y}}) + surface.set_tiles(cluster_tiles,auto_correct) + return true, x, y + end + y = y - density + end + for a = 1, i, 1 do + local scanned_tile = surface.get_tile(x,y) + if scanned_tile.name ~= tilename then + table.insert(cluster_tiles, {name = tilename, position = {x,y}}) + surface.set_tiles(cluster_tiles,auto_correct) + return true, x, y + end + x = x + density + end + i = i + 2 + end + end + + if r == 4 then + --start placing at 1,0 + while i <= scan_radius do + y = y - density + x = x + density + for a = 1, i, 1 do + y = y + density + local scanned_tile = surface.get_tile(x,y) + if scanned_tile.name ~= tilename then + table.insert(cluster_tiles, {name = tilename, position = {x,y}}) + surface.set_tiles(cluster_tiles,auto_correct) + return true, x, y + end + end + for a = 1, i, 1 do + x = x - density + local scanned_tile = surface.get_tile(x,y) + if scanned_tile.name ~= tilename then + table.insert(cluster_tiles, {name = tilename, position = {x,y}}) + surface.set_tiles(cluster_tiles,auto_correct) + return true, x, y + end + end + for a = 1, i, 1 do + y = y - density + local scanned_tile = surface.get_tile(x,y) + if scanned_tile.name ~= tilename then + table.insert(cluster_tiles, {name = tilename, position = {x,y}}) + surface.set_tiles(cluster_tiles,auto_correct) + return true, x, y + end + end + for a = 1, i, 1 do + x = x + density + local scanned_tile = surface.get_tile(x,y) + if scanned_tile.name ~= tilename then + table.insert(cluster_tiles, {name = tilename, position = {x,y}}) + surface.set_tiles(cluster_tiles,auto_correct) + return true, x, y + end + end + i = i + 2 + end + end + return false +end + +function create_tile_cluster(tilename,position,amount) + local mode = "ball" + local cluster_tiles = {} + local surface = game.surfaces[1] + local pos = position + local x = pos.x + local y = pos.y + for i = 1, amount, 1 do + local b,x,y = find_tile_placement_spot_around_target_position(tilename, pos, mode) + if b == true then + if 1 == math.random(1,2) then + pos.x = x + pos.y = y + end + end + if b == false then return false,x,y end + if i >= amount then return true,x,y end + end +end diff --git a/map_gen/shared/simplex_noise.lua b/map_gen/shared/simplex_noise.lua index 61bad5dc..6dfb0a7a 100644 --- a/map_gen/shared/simplex_noise.lua +++ b/map_gen/shared/simplex_noise.lua @@ -1,106 +1,106 @@ ---from https://github.com/thenumbernine/lua-simplexnoise/blob/master/2d.lua ---Mostly as a test, does not give same results as perlin but is designed to give patterns all the same - -local Simplex = {} - --- 2D simplex noise - -local grad3 = { - {1,1,0},{-1,1,0},{1,-1,0},{-1,-1,0}, - {1,0,1},{-1,0,1},{1,0,-1},{-1,0,-1}, - {0,1,1},{0,-1,1},{0,1,-1},{0,-1,-1} -} - -local p = {151,160,137,91,90,15, - 131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, - 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, - 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166, - 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244, - 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196, - 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123, - 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42, - 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9, - 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228, - 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, - 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, - 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180} -local perm = {} -for i=0,511 do - perm[i+1] = p[bit32.band(i, 255) + 1] -end - -local function dot(g, ...) - local v = {...} - local sum = 0 - for i=1,#v do - sum = sum + v[i] * g[i] - end - return sum -end - -local F2 = 0.5*(math.sqrt(3.0)-1.0) -local G2 = (3.0-math.sqrt(3.0))/6.0 -function Simplex.d2(xin, yin,seed) - xin = xin + seed - yin = yin + seed - local n0, n1, n2 -- Noise contributions from the three corners - -- Skew the input space to determine which simplex cell we're in - local s = (xin+yin)*F2; -- Hairy factor for 2D - local i = math.floor(xin+s) - local j = math.floor(yin+s) - local t = (i+j)*G2 - local X0 = i-t -- Unskew the cell origin back to (x,y) space - local Y0 = j-t - local x0 = xin-X0 -- The x,y distances from the cell origin - local y0 = yin-Y0 - -- For the 2D case, the simplex shape is an equilateral triangle. - -- Determine which simplex we are in. - local i1, j1 -- Offsets for second (middle) corner of simplex in (i,j) coords - if x0 > y0 then - i1 = 1 - j1 = 0 -- lower triangle, XY order: (0,0)->(1,0)->(1,1) - else - i1 = 0 - j1 = 1 - end-- upper triangle, YX order: (0,0)->(0,1)->(1,1) - -- A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and - -- a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where - -- c = (3-sqrt(3))/6 - local x1 = x0 - i1 + G2 -- Offsets for middle corner in (x,y) unskewed coords - local y1 = y0 - j1 + G2 - local x2 = x0 - 1 + 2 * G2 -- Offsets for last corner in (x,y) unskewed coords - local y2 = y0 - 1 + 2 * G2 - -- Work out the hashed gradient indices of the three simplex corners - local ii = bit32.band(i, 255) - local jj = bit32.band(j, 255) - local gi0 = perm[ii + perm[jj+1]+1] % 12 - local gi1 = perm[ii + i1 + perm[jj + j1+1]+1] % 12 - local gi2 = perm[ii + 1 + perm[jj + 1+1]+1] % 12 - -- Calculate the contribution from the three corners - local t0 = 0.5 - x0 * x0 - y0 * y0 - if t0 < 0 then - n0 = 0.0 - else - t0 = t0 * t0 - n0 = t0 * t0 * dot(grad3[gi0+1], x0, y0) -- (x,y) of grad3 used for 2D gradient - end - local t1 = 0.5 - x1 * x1 - y1 * y1 - if t1 < 0 then - n1 = 0.0 - else - t1 = t1 * t1 - n1 = t1 * t1 * dot(grad3[gi1+1], x1, y1) - end - local t2 = 0.5 - x2 * x2 - y2 * y2 - if t2 < 0 then - n2 = 0.0 - else - t2 = t2 * t2 - n2 = t2 * t2 * dot(grad3[gi2+1], x2, y2) - end - -- Add contributions from each corner to get the final noise value. - -- The result is scaled to return values in the interval [-1,1]. - return 70.0 * (n0 + n1 + n2) -end - -return Simplex +--from https://github.com/thenumbernine/lua-simplexnoise/blob/master/2d.lua +--Mostly as a test, does not give same results as perlin but is designed to give patterns all the same + +local Simplex = {} + +-- 2D simplex noise + +local grad3 = { + {1,1,0},{-1,1,0},{1,-1,0},{-1,-1,0}, + {1,0,1},{-1,0,1},{1,0,-1},{-1,0,-1}, + {0,1,1},{0,-1,1},{0,1,-1},{0,-1,-1} +} + +local p = {151,160,137,91,90,15, + 131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, + 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, + 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166, + 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244, + 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196, + 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123, + 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42, + 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9, + 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228, + 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, + 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, + 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180} +local perm = {} +for i=0,511 do + perm[i+1] = p[bit32.band(i, 255) + 1] +end + +local function dot(g, ...) + local v = {...} + local sum = 0 + for i=1,#v do + sum = sum + v[i] * g[i] + end + return sum +end + +local F2 = 0.5*(math.sqrt(3.0)-1.0) +local G2 = (3.0-math.sqrt(3.0))/6.0 +function Simplex.d2(xin, yin,seed) + xin = xin + seed + yin = yin + seed + local n0, n1, n2 -- Noise contributions from the three corners + -- Skew the input space to determine which simplex cell we're in + local s = (xin+yin)*F2; -- Hairy factor for 2D + local i = math.floor(xin+s) + local j = math.floor(yin+s) + local t = (i+j)*G2 + local X0 = i-t -- Unskew the cell origin back to (x,y) space + local Y0 = j-t + local x0 = xin-X0 -- The x,y distances from the cell origin + local y0 = yin-Y0 + -- For the 2D case, the simplex shape is an equilateral triangle. + -- Determine which simplex we are in. + local i1, j1 -- Offsets for second (middle) corner of simplex in (i,j) coords + if x0 > y0 then + i1 = 1 + j1 = 0 -- lower triangle, XY order: (0,0)->(1,0)->(1,1) + else + i1 = 0 + j1 = 1 + end-- upper triangle, YX order: (0,0)->(0,1)->(1,1) + -- A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and + -- a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where + -- c = (3-sqrt(3))/6 + local x1 = x0 - i1 + G2 -- Offsets for middle corner in (x,y) unskewed coords + local y1 = y0 - j1 + G2 + local x2 = x0 - 1 + 2 * G2 -- Offsets for last corner in (x,y) unskewed coords + local y2 = y0 - 1 + 2 * G2 + -- Work out the hashed gradient indices of the three simplex corners + local ii = bit32.band(i, 255) + local jj = bit32.band(j, 255) + local gi0 = perm[ii + perm[jj+1]+1] % 12 + local gi1 = perm[ii + i1 + perm[jj + j1+1]+1] % 12 + local gi2 = perm[ii + 1 + perm[jj + 1+1]+1] % 12 + -- Calculate the contribution from the three corners + local t0 = 0.5 - x0 * x0 - y0 * y0 + if t0 < 0 then + n0 = 0.0 + else + t0 = t0 * t0 + n0 = t0 * t0 * dot(grad3[gi0+1], x0, y0) -- (x,y) of grad3 used for 2D gradient + end + local t1 = 0.5 - x1 * x1 - y1 * y1 + if t1 < 0 then + n1 = 0.0 + else + t1 = t1 * t1 + n1 = t1 * t1 * dot(grad3[gi1+1], x1, y1) + end + local t2 = 0.5 - x2 * x2 - y2 * y2 + if t2 < 0 then + n2 = 0.0 + else + t2 = t2 * t2 + n2 = t2 * t2 * dot(grad3[gi2+1], x2, y2) + end + -- Add contributions from each corner to get the final noise value. + -- The result is scaled to return values in the interval [-1,1]. + return 70.0 * (n0 + n1 + n2) +end + +return Simplex diff --git a/map_gen/terrain/neko_bridged_rivers.lua b/map_gen/terrain/neko_bridged_rivers.lua index 9b8e772c..6f0176fa 100644 --- a/map_gen/terrain/neko_bridged_rivers.lua +++ b/map_gen/terrain/neko_bridged_rivers.lua @@ -1,178 +1,178 @@ -local perlin = require 'map_gen.shared.perlin_noise' -local simplex = require 'map_gen.shared.simplex_noise' - -local tree_to_place = {'dry-tree', 'dry-hairy-tree', 'tree-06', 'tree-06', 'tree-01', 'tree-02', 'tree-03'} - -function run_terrain_module(event) - if not global.terrain_seed_A then - global.terrain_seed_A = math.random(10, 10000) - end - if not global.terrain_seed_B then - global.terrain_seed_B = math.random(10, 10000) - end - - local area = event.area - local surface = event.surface - local tiles = {} - local tileswater = {} - - local entities = surface.find_entities(area) - for _, entity in pairs(entities) do - --if entity.type == "simple-entity" or entity.type == "resource" or entity.type == "tree" then - if entity.type == 'simple-entity' or entity.type == 'tree' then - --end - entity.destroy() - elseif (run_ores_module ~= nil and entity.type == 'resource') then - entity.destroy() - end - end - - local top_left = area.left_top --make a more direct reference - - --do it only per chunk, cause cheaper than every square, and who care anyway. - --local distance_bonus = 200 + math.sqrt(top_left.x*top_left.x + top_left.y*top_left.y) * 0.2 - - --for x = 0, 31, 1 do - -- for y = 0, 31, 1 do - - --game.print(top_left.x .."-" ..top_left.y .. " to " .. area.right_bottom.x .. "-" .. area.right_bottom.y) - - for x = top_left.x - 1, top_left.x + 32 do - for y = top_left.y - 1, top_left.y + 32 do - --local pos_x = top_left.x + x - --local pos_y = top_left.y + y - local tile = surface.get_tile(x, y) - - if tile.name ~= 'out-of-map' then - local tile_to_insert = 'grass-3' - - local wiggle = 50 + perlin.noise((x * 0.005), (y * 0.005), global.terrain_seed_A + 71) * 60 - local terrain_A = perlin.noise((x * 0.005), (y * 0.005), global.terrain_seed_A + 19) * wiggle --For determining where water is - local terrain_sqr = terrain_A * terrain_A --we can use this again to mess with other layers as well - local terrain_D = 10 + perlin.noise((x * 0.001), (y * 0.001), global.terrain_seed_A + 5) * wiggle --terrain layer - - --local wiggle = 50 + Simplex.d2((x*0.005),(y*0.005),global.terrain_seed_A + 71) * 60 - --local terrain_A = Simplex.d2((x*0.005),(y*0.005),global.terrain_seed_A + 19) * wiggle --For determining where water is - --local terrain_sqr = terrain_A * terrain_A --we can use this again to mess with other layers as well - --local terrain_D = 10 + Simplex.d2((x*0.001),(y*0.001),global.terrain_seed_A + 5) * wiggle --terrain layer - - if terrain_sqr < 50 then --Main water areas - --local deep = (terrain_sqr < 20) and true or false - terrain_A = perlin.noise((x * 0.01), (y * 0.01), global.terrain_seed_A + 31) * 90 + (wiggle * -0.2) --we only gen this when we consider placing water - --terrain_A = Simplex.d2((x*0.01),(y*0.01),global.terrain_seed_A + 31) * 90 + (wiggle * -0.2) --we only gen this when we consider placing water - - if terrain_A * terrain_A > 40 then --creates random bridges over the water by overlapping with another noise layer - --table.insert(tileswater, {name = "water", position = {x,y}}) - --table.insert(tileswater, {name = "water", position = {x+1,y}}) - --table.insert(tileswater, {name = "water", position = {x,y+1}}) - --table.insert(tileswater, {name = "water", position = {x+1,y+1}}) - tile_to_insert = 'water' - else - if terrain_D >= 20 then - tile_to_insert = 'sand-1' - end - end - elseif terrain_sqr > 70 then - wiggle = 100 + perlin.noise((x * 0.01), (y * 0.01), global.terrain_seed_B + 41) * 60 - local terrain_C = perlin.noise((x * 0.02), (y * 0.02), global.terrain_seed_A + 13) * wiggle --tree layer - - --wiggle = 100 + Simplex.d2((x*0.01),(y*0.01),global.terrain_seed_B + 41) * 60 - --local terrain_C = Simplex.d2((x*0.02),(y*0.02),global.terrain_seed_A + 13) * wiggle --tree layer - - --if surface.can_place_entity {name="stone", position={x,y}} then - -- surface.create_entity {name="stone", position={x,y}, amount=math.floor(terrain_sqr)} - --end - - if run_ores_module ~= nil then - run_ores_module_setup() - if x > top_left.x - 1 and x < top_left.x + 32 and y > top_left.y - 1 and y < top_left.y + 32 then - run_ores_module_tile(surface, x, y) - end - end - - --if terrain_B > 35 then --we place ores - -- local a = 5 - -- - -- if terrain_B < 76 then a = math.floor(terrain_B*0.75 + terrain_C*0.5) % 4 + 1 end --if its not super high we place normal ores - -- - -- local res_amount = distance_bonus + terrain_sqr * 0.1 - -- res_amount = math.floor(res_amount * random_dense[a]) - -- - -- if surface.can_place_entity {name=random_ores[a], position={pos_x,pos_y}} then - -- surface.create_entity {name=random_ores[a], position={pos_x,pos_y}, amount=res_amount} - -- end - --end - - --wiggle = 100 + perlin.noise((pos_x*0.02),(pos_y*0.02),global.terrain_seed_B + 71) * 60 - - if terrain_D < 20 then - if terrain_C < 4 then --we set grass-1 around near forest areas - tile_to_insert = 'grass-1' - - if terrain_C < -20 and math.random(1, 3) == 1 then --dense trees - local treenum = math.random(3, 7) - if surface.can_place_entity {name = tree_to_place[treenum], position = {x, y}} then - surface.create_entity {name = tree_to_place[treenum], position = {x, y}} - end - else - if terrain_C < 0 and math.random(1, 7) == 1 then --less dense trees - local treenum = math.random(3, 5) - if surface.can_place_entity {name = tree_to_place[treenum], position = {x, y}} then - surface.create_entity {name = tree_to_place[treenum], position = {x, y}} - end - end - end - end - else - if terrain_D < 30 then - tile_to_insert = 'sand-1' - - if terrain_C < -20 and math.random(1, 7) == 1 then --dense trees - local treenum = math.random(1, 3) - if surface.can_place_entity {name = tree_to_place[treenum], position = {x, y}} then - surface.create_entity {name = tree_to_place[treenum], position = {x, y}} - end - elseif terrain_C < 0 and math.random(1, 13) == 1 then --less dense trees - local treenum = math.random(1, 2) - if surface.can_place_entity {name = tree_to_place[treenum], position = {x, y}} then - surface.create_entity {name = tree_to_place[treenum], position = {x, y}} - end - end - else - --if terrain_C > 40 and math.random(1,200) == 1 and surface.can_place_entity {name="crude-oil", position={pos_x,pos_y}} then - -- surface.create_entity {name="crude-oil", position={pos_x,pos_y}, amount = math.random(20000,60000) +distance_bonus* 2000 } - --end - tile_to_insert = 'sand-3' - end - end - - if - math.floor(terrain_D) % 5 == 1 and math.random(1, 70) == 1 and - surface.can_place_entity {name = 'rock-big', position = {x, y}} - then - surface.create_entity {name = 'rock-big', position = {x, y}} - end - else - if terrain_D >= 20 then - if terrain_D < 30 then - tile_to_insert = 'sand-1' - else - tile_to_insert = 'sand-3' - end - end - end - - --if tile_to_insert == "water" then - --table.insert(tileswater, {name = tile_to_insert, position = {x,y}}) - --else - table.insert(tiles, {name = tile_to_insert, position = {x, y}}) - --end - end - end - end - --game.print("break end") - --game.print(lowest .. " to " .. highest) - - surface.set_tiles(tiles, true) - --surface.set_tiles(tileswater,true) -end +local perlin = require 'map_gen.shared.perlin_noise' +local simplex = require 'map_gen.shared.simplex_noise' + +local tree_to_place = {'dry-tree', 'dry-hairy-tree', 'tree-06', 'tree-06', 'tree-01', 'tree-02', 'tree-03'} + +function run_terrain_module(event) + if not global.terrain_seed_A then + global.terrain_seed_A = math.random(10, 10000) + end + if not global.terrain_seed_B then + global.terrain_seed_B = math.random(10, 10000) + end + + local area = event.area + local surface = event.surface + local tiles = {} + local tileswater = {} + + local entities = surface.find_entities(area) + for _, entity in pairs(entities) do + --if entity.type == "simple-entity" or entity.type == "resource" or entity.type == "tree" then + if entity.type == 'simple-entity' or entity.type == 'tree' then + --end + entity.destroy() + elseif (run_ores_module ~= nil and entity.type == 'resource') then + entity.destroy() + end + end + + local top_left = area.left_top --make a more direct reference + + --do it only per chunk, cause cheaper than every square, and who care anyway. + --local distance_bonus = 200 + math.sqrt(top_left.x*top_left.x + top_left.y*top_left.y) * 0.2 + + --for x = 0, 31, 1 do + -- for y = 0, 31, 1 do + + --game.print(top_left.x .."-" ..top_left.y .. " to " .. area.right_bottom.x .. "-" .. area.right_bottom.y) + + for x = top_left.x - 1, top_left.x + 32 do + for y = top_left.y - 1, top_left.y + 32 do + --local pos_x = top_left.x + x + --local pos_y = top_left.y + y + local tile = surface.get_tile(x, y) + + if tile.name ~= 'out-of-map' then + local tile_to_insert = 'grass-3' + + local wiggle = 50 + perlin.noise((x * 0.005), (y * 0.005), global.terrain_seed_A + 71) * 60 + local terrain_A = perlin.noise((x * 0.005), (y * 0.005), global.terrain_seed_A + 19) * wiggle --For determining where water is + local terrain_sqr = terrain_A * terrain_A --we can use this again to mess with other layers as well + local terrain_D = 10 + perlin.noise((x * 0.001), (y * 0.001), global.terrain_seed_A + 5) * wiggle --terrain layer + + --local wiggle = 50 + Simplex.d2((x*0.005),(y*0.005),global.terrain_seed_A + 71) * 60 + --local terrain_A = Simplex.d2((x*0.005),(y*0.005),global.terrain_seed_A + 19) * wiggle --For determining where water is + --local terrain_sqr = terrain_A * terrain_A --we can use this again to mess with other layers as well + --local terrain_D = 10 + Simplex.d2((x*0.001),(y*0.001),global.terrain_seed_A + 5) * wiggle --terrain layer + + if terrain_sqr < 50 then --Main water areas + --local deep = (terrain_sqr < 20) and true or false + terrain_A = perlin.noise((x * 0.01), (y * 0.01), global.terrain_seed_A + 31) * 90 + (wiggle * -0.2) --we only gen this when we consider placing water + --terrain_A = Simplex.d2((x*0.01),(y*0.01),global.terrain_seed_A + 31) * 90 + (wiggle * -0.2) --we only gen this when we consider placing water + + if terrain_A * terrain_A > 40 then --creates random bridges over the water by overlapping with another noise layer + --table.insert(tileswater, {name = "water", position = {x,y}}) + --table.insert(tileswater, {name = "water", position = {x+1,y}}) + --table.insert(tileswater, {name = "water", position = {x,y+1}}) + --table.insert(tileswater, {name = "water", position = {x+1,y+1}}) + tile_to_insert = 'water' + else + if terrain_D >= 20 then + tile_to_insert = 'sand-1' + end + end + elseif terrain_sqr > 70 then + wiggle = 100 + perlin.noise((x * 0.01), (y * 0.01), global.terrain_seed_B + 41) * 60 + local terrain_C = perlin.noise((x * 0.02), (y * 0.02), global.terrain_seed_A + 13) * wiggle --tree layer + + --wiggle = 100 + Simplex.d2((x*0.01),(y*0.01),global.terrain_seed_B + 41) * 60 + --local terrain_C = Simplex.d2((x*0.02),(y*0.02),global.terrain_seed_A + 13) * wiggle --tree layer + + --if surface.can_place_entity {name="stone", position={x,y}} then + -- surface.create_entity {name="stone", position={x,y}, amount=math.floor(terrain_sqr)} + --end + + if run_ores_module ~= nil then + run_ores_module_setup() + if x > top_left.x - 1 and x < top_left.x + 32 and y > top_left.y - 1 and y < top_left.y + 32 then + run_ores_module_tile(surface, x, y) + end + end + + --if terrain_B > 35 then --we place ores + -- local a = 5 + -- + -- if terrain_B < 76 then a = math.floor(terrain_B*0.75 + terrain_C*0.5) % 4 + 1 end --if its not super high we place normal ores + -- + -- local res_amount = distance_bonus + terrain_sqr * 0.1 + -- res_amount = math.floor(res_amount * random_dense[a]) + -- + -- if surface.can_place_entity {name=random_ores[a], position={pos_x,pos_y}} then + -- surface.create_entity {name=random_ores[a], position={pos_x,pos_y}, amount=res_amount} + -- end + --end + + --wiggle = 100 + perlin.noise((pos_x*0.02),(pos_y*0.02),global.terrain_seed_B + 71) * 60 + + if terrain_D < 20 then + if terrain_C < 4 then --we set grass-1 around near forest areas + tile_to_insert = 'grass-1' + + if terrain_C < -20 and math.random(1, 3) == 1 then --dense trees + local treenum = math.random(3, 7) + if surface.can_place_entity {name = tree_to_place[treenum], position = {x, y}} then + surface.create_entity {name = tree_to_place[treenum], position = {x, y}} + end + else + if terrain_C < 0 and math.random(1, 7) == 1 then --less dense trees + local treenum = math.random(3, 5) + if surface.can_place_entity {name = tree_to_place[treenum], position = {x, y}} then + surface.create_entity {name = tree_to_place[treenum], position = {x, y}} + end + end + end + end + else + if terrain_D < 30 then + tile_to_insert = 'sand-1' + + if terrain_C < -20 and math.random(1, 7) == 1 then --dense trees + local treenum = math.random(1, 3) + if surface.can_place_entity {name = tree_to_place[treenum], position = {x, y}} then + surface.create_entity {name = tree_to_place[treenum], position = {x, y}} + end + elseif terrain_C < 0 and math.random(1, 13) == 1 then --less dense trees + local treenum = math.random(1, 2) + if surface.can_place_entity {name = tree_to_place[treenum], position = {x, y}} then + surface.create_entity {name = tree_to_place[treenum], position = {x, y}} + end + end + else + --if terrain_C > 40 and math.random(1,200) == 1 and surface.can_place_entity {name="crude-oil", position={pos_x,pos_y}} then + -- surface.create_entity {name="crude-oil", position={pos_x,pos_y}, amount = math.random(20000,60000) +distance_bonus* 2000 } + --end + tile_to_insert = 'sand-3' + end + end + + if + math.floor(terrain_D) % 5 == 1 and math.random(1, 70) == 1 and + surface.can_place_entity {name = 'rock-big', position = {x, y}} + then + surface.create_entity {name = 'rock-big', position = {x, y}} + end + else + if terrain_D >= 20 then + if terrain_D < 30 then + tile_to_insert = 'sand-1' + else + tile_to_insert = 'sand-3' + end + end + end + + --if tile_to_insert == "water" then + --table.insert(tileswater, {name = tile_to_insert, position = {x,y}}) + --else + table.insert(tiles, {name = tile_to_insert, position = {x, y}}) + --end + end + end + end + --game.print("break end") + --game.print(lowest .. " to " .. highest) + + surface.set_tiles(tiles, true) + --surface.set_tiles(tileswater,true) +end diff --git a/utils/utils.lua b/utils/utils.lua index cbc81df8..6995a863 100644 --- a/utils/utils.lua +++ b/utils/utils.lua @@ -1,157 +1,157 @@ -local Module = {} -local Game = require 'utils.game' -local prefix = '## - ' - -Module.distance = function(pos1, pos2) - local dx = pos2.x - pos1.x - local dy = pos2.y - pos1.y - return math.sqrt(dx * dx + dy * dy) -end - -Module.print_except = function(msg, player) - for _, p in pairs(game.players) do - if p.connected and p ~= player then - p.print(msg) - end - end -end - --- Takes a LuaPlayer or string as source -Module.print_admins = function(msg, source) - local source_name - local chat_color - if source then - if type(source) == 'string' then - source_name = source - chat_colot = game.players[source].chat_color - else - source_name = source.name - chat_color = source.chat_color - end - else - source_name = "Server" - chat_color = {r=255, g=255, b=255} - end - for _, p in pairs(game.connected_players) do - if p.admin then - p.print(string.format('%s(ADMIN) %s: %s', prefix, source_name, msg), chat_color) - end - end -end - -Module.get_actor = function() - if game.player then - return game.player.name - end - return '<server>' -end - -Module.cast_bool = function(var) - if var then - return true - else - return false - end -end - -Module.find_entities_by_last_user = - function(player, surface, filters) - if type(player) == 'string' or not player then - error( - "bad argument #1 to '" .. - debug.getinfo(1, 'n').name .. "' (number or LuaPlayer expected, got " .. type(player) .. ')', - 1 - ) - return - end - if type(surface) ~= 'table' and type(surface) ~= 'number' then - error( - "bad argument #2 to '" .. - debug.getinfo(1, 'n').name .. "' (number or LuaSurface expected, got " .. type(surface) .. ')', - 1 - ) - return - end - local entities = {} - local surface = surface - local player = player - local filters = filters or {} - if type(surface) == 'number' then - surface = game.surfaces[surface] - end - if type(player) == 'number' then - player = Game.get_player_by_index(player) - end - filters.force = player.force.name - for _, e in pairs(surface.find_entities_filtered(filters)) do - if e.last_user == player then - table.insert(entities, e) - end - end - return entities -end - -Module.ternary = function(c, t, f) - if c then - return t - else - return f - end -end - - -local minutes_to_ticks = 60 * 60 -local hours_to_ticks = 60 * 60 * 60 -local ticks_to_minutes = 1 / minutes_to_ticks -local ticks_to_hours = 1 / hours_to_ticks -Module.format_time = function(ticks) - local result = {} - - local hours = math.floor(ticks * ticks_to_hours) - if hours > 0 then - ticks = ticks - hours * hours_to_ticks - table.insert(result, hours) - if hours == 1 then - table.insert(result, 'hour') - else - table.insert(result, 'hours') - end - end - - local minutes = math.floor(ticks * ticks_to_minutes) - table.insert(result, minutes) - if minutes == 1 then - table.insert(result, 'minute') - else - table.insert(result, 'minutes') - end - - return table.concat(result, ' ') -end - -Module.cant_run = function(name) - Game.player_print("Can't run command (" .. name .. ') - insufficient permission.') -end - -Module.log_command = function(user, command, parameters) - local name - - -- We can use a LuaPlayer or a string (ex. "Server"). - if type(user) == 'string' then - name = user - else - name = user.name - end - local action = table.concat {'[Admin-Command] ', name, ' used: ', command} - if parameters then - action = table.concat {'[Admin-Command] ', name, ' used: ', command, ' ', parameters} - end - log(action) -end - -Module.comma_value = function(n) -- credit http://richard.warburton.it - local left,num,right = string.match(n, '^([^%d]*%d)(%d*)(.-)$') - return left .. (num:reverse():gsub('(%d%d%d)', '%1,'):reverse()) .. right -end - -return Module +local Module = {} +local Game = require 'utils.game' +local prefix = '## - ' + +Module.distance = function(pos1, pos2) + local dx = pos2.x - pos1.x + local dy = pos2.y - pos1.y + return math.sqrt(dx * dx + dy * dy) +end + +Module.print_except = function(msg, player) + for _, p in pairs(game.players) do + if p.connected and p ~= player then + p.print(msg) + end + end +end + +-- Takes a LuaPlayer or string as source +Module.print_admins = function(msg, source) + local source_name + local chat_color + if source then + if type(source) == 'string' then + source_name = source + chat_colot = game.players[source].chat_color + else + source_name = source.name + chat_color = source.chat_color + end + else + source_name = "Server" + chat_color = {r=255, g=255, b=255} + end + for _, p in pairs(game.connected_players) do + if p.admin then + p.print(string.format('%s(ADMIN) %s: %s', prefix, source_name, msg), chat_color) + end + end +end + +Module.get_actor = function() + if game.player then + return game.player.name + end + return '<server>' +end + +Module.cast_bool = function(var) + if var then + return true + else + return false + end +end + +Module.find_entities_by_last_user = + function(player, surface, filters) + if type(player) == 'string' or not player then + error( + "bad argument #1 to '" .. + debug.getinfo(1, 'n').name .. "' (number or LuaPlayer expected, got " .. type(player) .. ')', + 1 + ) + return + end + if type(surface) ~= 'table' and type(surface) ~= 'number' then + error( + "bad argument #2 to '" .. + debug.getinfo(1, 'n').name .. "' (number or LuaSurface expected, got " .. type(surface) .. ')', + 1 + ) + return + end + local entities = {} + local surface = surface + local player = player + local filters = filters or {} + if type(surface) == 'number' then + surface = game.surfaces[surface] + end + if type(player) == 'number' then + player = Game.get_player_by_index(player) + end + filters.force = player.force.name + for _, e in pairs(surface.find_entities_filtered(filters)) do + if e.last_user == player then + table.insert(entities, e) + end + end + return entities +end + +Module.ternary = function(c, t, f) + if c then + return t + else + return f + end +end + + +local minutes_to_ticks = 60 * 60 +local hours_to_ticks = 60 * 60 * 60 +local ticks_to_minutes = 1 / minutes_to_ticks +local ticks_to_hours = 1 / hours_to_ticks +Module.format_time = function(ticks) + local result = {} + + local hours = math.floor(ticks * ticks_to_hours) + if hours > 0 then + ticks = ticks - hours * hours_to_ticks + table.insert(result, hours) + if hours == 1 then + table.insert(result, 'hour') + else + table.insert(result, 'hours') + end + end + + local minutes = math.floor(ticks * ticks_to_minutes) + table.insert(result, minutes) + if minutes == 1 then + table.insert(result, 'minute') + else + table.insert(result, 'minutes') + end + + return table.concat(result, ' ') +end + +Module.cant_run = function(name) + Game.player_print("Can't run command (" .. name .. ') - insufficient permission.') +end + +Module.log_command = function(user, command, parameters) + local name + + -- We can use a LuaPlayer or a string (ex. "Server"). + if type(user) == 'string' then + name = user + else + name = user.name + end + local action = table.concat {'[Admin-Command] ', name, ' used: ', command} + if parameters then + action = table.concat {'[Admin-Command] ', name, ' used: ', command, ' ', parameters} + end + log(action) +end + +Module.comma_value = function(n) -- credit http://richard.warburton.it + local left,num,right = string.match(n, '^([^%d]*%d)(%d*)(.-)$') + return left .. (num:reverse():gsub('(%d%d%d)', '%1,'):reverse()) .. right +end + +return Module