├── locale
└── .gitignore
├── thumbnail.png
├── sounds
└── attacks
│ ├── acid-end.ogg
│ └── acid-mid.ogg
├── graphics
├── tiles
│ └── fillableDirt
│ │ ├── dirt1.png
│ │ ├── dirt2.png
│ │ ├── dirt4.png
│ │ ├── dirt-side.png
│ │ ├── dirt-inner-corner.png
│ │ └── dirt-outer-corner.png
├── icons
│ └── thief
│ │ ├── crystal-drain.png
│ │ └── crystal-drain-pole.png
├── acid-splash-purple
│ ├── splash-1.png
│ ├── splash-2.png
│ ├── splash-3.png
│ └── splash-4.png
├── entities
│ ├── thief
│ │ ├── crystal-drain.png
│ │ └── crystal-drain-pole.png
│ └── tunnel
│ │ └── tunnelEntrance.png
└── acid-projectile-purple
│ ├── acid-projectile-purple.png
│ └── acid-projectile-purple-shadow.png
├── visualizer.sh
├── info.json
├── .luacheckrc
├── .gitignore
├── NOTICE
├── .github
└── FUNDING.yml
├── prototypes
├── utils
│ ├── ColorUtils.lua
│ ├── StickerUtils.lua
│ ├── BombUtils.lua
│ ├── ThiefUtils.lua
│ ├── ProjectileUtils.lua
│ ├── AttackFlame.lua
│ ├── UnitSpawnerUtils.lua
│ ├── StreamUtils.lua
│ ├── UpdatesVanilla.lua
│ ├── BeamUtils.lua
│ ├── AttackBall.lua
│ ├── ImageUtils.lua
│ └── DroneUtils.lua
├── buildings
│ ├── tunnel.lua
│ ├── ChunkScanner.lua
│ └── UpdatesVanilla.lua
├── UnitClasses.lua
├── tile
│ └── fillableDirt.lua
├── Poison.lua
├── samples
│ └── healingBiter.lua
└── EnergyThief.lua
├── .dir-locals.el
├── data-updates.lua
├── README.md
├── action.fish
├── libs
├── Utils.lua
├── UnitUtils.lua
└── MathUtils.lua
├── data-final-fixes.lua
├── data.lua
├── visualizer
├── parseState.rkt
└── visual.rkt
└── tests.lua
/locale/.gitignore:
--------------------------------------------------------------------------------
1 | /.directory
2 |
--------------------------------------------------------------------------------
/thumbnail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/veden/Rampant/HEAD/thumbnail.png
--------------------------------------------------------------------------------
/sounds/attacks/acid-end.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/veden/Rampant/HEAD/sounds/attacks/acid-end.ogg
--------------------------------------------------------------------------------
/sounds/attacks/acid-mid.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/veden/Rampant/HEAD/sounds/attacks/acid-mid.ogg
--------------------------------------------------------------------------------
/graphics/tiles/fillableDirt/dirt1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/veden/Rampant/HEAD/graphics/tiles/fillableDirt/dirt1.png
--------------------------------------------------------------------------------
/graphics/tiles/fillableDirt/dirt2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/veden/Rampant/HEAD/graphics/tiles/fillableDirt/dirt2.png
--------------------------------------------------------------------------------
/graphics/tiles/fillableDirt/dirt4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/veden/Rampant/HEAD/graphics/tiles/fillableDirt/dirt4.png
--------------------------------------------------------------------------------
/graphics/icons/thief/crystal-drain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/veden/Rampant/HEAD/graphics/icons/thief/crystal-drain.png
--------------------------------------------------------------------------------
/graphics/acid-splash-purple/splash-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/veden/Rampant/HEAD/graphics/acid-splash-purple/splash-1.png
--------------------------------------------------------------------------------
/graphics/acid-splash-purple/splash-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/veden/Rampant/HEAD/graphics/acid-splash-purple/splash-2.png
--------------------------------------------------------------------------------
/graphics/acid-splash-purple/splash-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/veden/Rampant/HEAD/graphics/acid-splash-purple/splash-3.png
--------------------------------------------------------------------------------
/graphics/acid-splash-purple/splash-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/veden/Rampant/HEAD/graphics/acid-splash-purple/splash-4.png
--------------------------------------------------------------------------------
/graphics/entities/thief/crystal-drain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/veden/Rampant/HEAD/graphics/entities/thief/crystal-drain.png
--------------------------------------------------------------------------------
/graphics/tiles/fillableDirt/dirt-side.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/veden/Rampant/HEAD/graphics/tiles/fillableDirt/dirt-side.png
--------------------------------------------------------------------------------
/graphics/entities/tunnel/tunnelEntrance.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/veden/Rampant/HEAD/graphics/entities/tunnel/tunnelEntrance.png
--------------------------------------------------------------------------------
/graphics/icons/thief/crystal-drain-pole.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/veden/Rampant/HEAD/graphics/icons/thief/crystal-drain-pole.png
--------------------------------------------------------------------------------
/graphics/entities/thief/crystal-drain-pole.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/veden/Rampant/HEAD/graphics/entities/thief/crystal-drain-pole.png
--------------------------------------------------------------------------------
/graphics/tiles/fillableDirt/dirt-inner-corner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/veden/Rampant/HEAD/graphics/tiles/fillableDirt/dirt-inner-corner.png
--------------------------------------------------------------------------------
/graphics/tiles/fillableDirt/dirt-outer-corner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/veden/Rampant/HEAD/graphics/tiles/fillableDirt/dirt-outer-corner.png
--------------------------------------------------------------------------------
/graphics/acid-projectile-purple/acid-projectile-purple.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/veden/Rampant/HEAD/graphics/acid-projectile-purple/acid-projectile-purple.png
--------------------------------------------------------------------------------
/visualizer.sh:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env racket
2 | #lang racket
3 |
4 | (require "visualizer/visual.rkt")
5 | (provide (all-from-out "visualizer/visual.rkt"))
6 |
7 | (visualize)
8 |
--------------------------------------------------------------------------------
/graphics/acid-projectile-purple/acid-projectile-purple-shadow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/veden/Rampant/HEAD/graphics/acid-projectile-purple/acid-projectile-purple-shadow.png
--------------------------------------------------------------------------------
/info.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "Rampant",
3 | "factorio_version" : "1.1",
4 | "version" : "3.3.4",
5 | "title" : "Rampant",
6 | "author" : "Veden",
7 | "homepage" : "https://forums.factorio.com/viewtopic.php?f=94&t=31445",
8 | "dependencies" : ["base >= 1.1.81", "? bobenemies", "? Natural_Evolution_Enemies >= 0.17.0", "? Clockwork", "? Kux-OrbitalIonCannon", "? Orbital Ion Cannon", "? ArmouredBiters", "? Krastorio2", "? SchallAlienLoot >= 0.17.6", "! zhcnremake"]
9 | }
10 |
--------------------------------------------------------------------------------
/.luacheckrc:
--------------------------------------------------------------------------------
1 | globals = {
2 | "mods",
3 | "game",
4 | "util",
5 | "data",
6 | "remote",
7 | "settings",
8 | "commands",
9 | "global",
10 | "rendering",
11 | "table_size",
12 | "script",
13 | "defines",
14 | "ProcessorG",
15 | "ConstantsG",
16 | "ChunkPropertyUtilsG",
17 | "ChunkUtilsG",
18 | "MapUtilsG",
19 | "MathUtilsG",
20 | "SquadG",
21 | "unitUtilsG",
22 | "BaseUtilsG",
23 | "UtilsG"
24 | }
25 |
26 | max_line_length = false
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled Lua sources
2 | luac.out
3 |
4 | # luarocks build files
5 | *.src.rock
6 | *.zip
7 | *.tar.gz
8 |
9 | # Object files
10 | *.o
11 | *.os
12 | *.ko
13 | *.obj
14 | *.elf
15 |
16 | # Precompiled Headers
17 | *.gch
18 | *.pch
19 |
20 | # Libraries
21 | *.lib
22 | *.a
23 | *.la
24 | *.lo
25 | *.def
26 | *.exp
27 |
28 | # Shared objects (inc. Windows DLLs)
29 | *.dll
30 | *.so
31 | *.so.*
32 | *.dylib
33 |
34 | # Executables
35 | *.exe
36 | *.out
37 | *.app
38 | *.i*86
39 | *.x86_64
40 | *.hex
41 | *.bat
42 |
43 | # extra
44 | *.lua#
45 | *.rkt~
46 | *.lua~
47 | *.dumpjump
48 | /.emacs.desktop
49 | /.emacs.desktop.lock
50 | /README.html
51 | /c.org
52 |
--------------------------------------------------------------------------------
/NOTICE:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 |
17 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
13 |
14 | ko_fi: rampant
15 |
--------------------------------------------------------------------------------
/prototypes/utils/ColorUtils.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 |
17 | local colorUtils = {}
18 |
19 | -- module code
20 |
21 | function colorUtils.makeColor(r_,g_,b_,a_)
22 | return { r = r_ * a_, g = g_ * a_, b = b_ * a_, a = a_ }
23 | end
24 |
25 | return colorUtils
26 |
--------------------------------------------------------------------------------
/prototypes/buildings/tunnel.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 |
17 | data:extend({
18 | {
19 | type = "simple-entity",
20 | name = "tunnel-entrance-rampant",
21 | flags = {"placeable-neutral", "placeable-off-grid", "not-on-map"},
22 | icon = "__base__/graphics/icons/small-scorchmark.png",
23 | icon_size = 32,
24 | subgroup = "grass",
25 | order = "b[decorative]-k[tunnel-entrance]-a[big]",
26 | collision_box = {{-1.3, -1.3}, {1.3, 1.3}},
27 | selection_box = {{-1.5, -1.5}, {1.5, 1.5}},
28 | render_layer = "remnants",
29 | destructible = "false",
30 | max_health = 1,
31 | pictures =
32 | {
33 | {
34 | filename = "__Rampant__/graphics/entities/tunnel/tunnelEntrance.png",
35 | width = 142,
36 | height = 104,
37 | shift = {0, 0}
38 | }
39 | }
40 | }
41 | })
42 |
--------------------------------------------------------------------------------
/.dir-locals.el:
--------------------------------------------------------------------------------
1 | ;; for configuration - projectile-project-configure-cmd
2 | ;; for compilation - projectile-project-compilation-cmd
3 | ;; for testing - projectile-project-test-cmd
4 | ;; for installation - projectile-project-install-cmd
5 | ;; for packaging - projectile-project-package-cmd
6 | ;; for running - projectile-project-run-cmd
7 | ;; for configuring the test prefix - projectile-project-test-prefix
8 | ;; for configuring the test suffix - projectile-project-test-suffix
9 | ;; for configuring the related-files-fn property - projectile-project-related-files-fn
10 | ;; for configuring the src-dir property - projectile-project-src-dir
11 | ;; for configuring the test-dir property - projectile-project-test-dir
12 | ;; projectile-configure-use-separate-buffer
13 | ;; projectile-compile-use-separate-buffer
14 | ;; projectile-test-use-separate-buffer
15 | ;; projectile-package-use-separate-buffer
16 | ;; projectile-run-use-separate-buffer
17 | ;; projectile-install-use-separate-buffer
18 |
19 |
20 | ((nil . ((projectile-project-install-cmd . "./make.sh copy")
21 | (projectile-install-buffer-suffix . "install")
22 |
23 | (projectile-project-compilation-cmd . "luacheck .")
24 | (projectile-compile-buffer-suffix . "lint")
25 |
26 | (projectile-project-package-cmd . "./make.sh zip")
27 | (projectile-package-buffer-suffix . "install")
28 |
29 | (projectile-project-uninstall-cmd . "./make.sh clear")
30 | (projectile-uninstall-buffer-suffix . "install")
31 |
32 | (projectile-project-test-cmd . "./make.sh visualize")
33 | (projectile-test-buffer-suffix . "visual")
34 |
35 | (projectile-project-run-cmd . "factorio"))))
36 |
--------------------------------------------------------------------------------
/prototypes/buildings/ChunkScanner.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 | local smokeUtils = require("prototypes/utils/SmokeUtils")
17 |
18 | smokeUtils.makeNewCloud(
19 | {
20 | name = "build-clear",
21 | wind = false,
22 | scale = 9,
23 | duration = 540,
24 | cooldown = 10,
25 | tint = { r=0.7, g=0.2, b=0.7 }
26 | },
27 | {
28 | type = "area",
29 | radius = 17,
30 | force = "not-same",
31 | action_delivery =
32 | {
33 | type = "instant",
34 | target_effects =
35 | {
36 | {
37 | type = "damage",
38 | damage = { amount = 1.1, type = "poison"}
39 | },
40 | {
41 | type = "damage",
42 | damage = { amount = 1.1, type = "acid"}
43 | },
44 | {
45 | type = "damage",
46 | damage = { amount = 1.1, type = "fire"}
47 | }
48 | }
49 | }
50 | }
51 | )
52 |
--------------------------------------------------------------------------------
/data-updates.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 |
17 | local vanillaUpdates = require("prototypes/utils/UpdatesVanilla")
18 | local attackBall = require("prototypes/utils/AttackBall")
19 |
20 | if settings.startup["rampant--useDumbProjectiles"].value or settings.startup["rampant--newEnemies"].value then
21 | attackBall.generateVanilla()
22 | vanillaUpdates.useDumbProjectiles()
23 | end
24 |
25 | for _, robot in pairs(data.raw["logistic-robot"]) do
26 | if (settings.startup["rampant--unkillableLogisticRobots"].value) then
27 | robot.resistances = {}
28 | for damageType, _ in pairs(data.raw["damage-type"]) do
29 | robot.resistances[damageType] = {
30 | type = damageType,
31 | percent = 100
32 | }
33 | end
34 | end
35 | end
36 |
37 | for _, robot in pairs(data.raw["construction-robot"]) do
38 | if (settings.startup["rampant--unkillableConstructionRobots"].value) then
39 | robot.resistances = {}
40 | for damageType, _ in pairs(data.raw["damage-type"]) do
41 | robot.resistances[damageType] = {
42 | type = damageType,
43 | percent = 100
44 | }
45 | end
46 | end
47 | end
48 |
49 |
--------------------------------------------------------------------------------
/prototypes/UnitClasses.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 |
17 | -- module code
18 |
19 | function generateMigration()
20 | local factions = {"neutral", "acid", "physical", "electric", "suicide", "nuclear", "fire", "inferno", "troll", "laser", "fast", "wasp", "spawner", "energy-thief", "poison"}
21 |
22 | for fi = 1, #factions do
23 | local faction = factions[fi]
24 | for t = 1, 10 do
25 | local adjT = t
26 | -- if t > 5 then
27 | -- adjT = t - 5
28 | -- end
29 | for v = 8, 20 do
30 | print(" [\"" .. faction .. "-biter-spawner-v" .. v .. "-t" .. t .. "-rampant\", \"" .. faction .. "-biter-spawner-v1-t" .. adjT .. "-rampant\"],")
31 | print(" [\"" .. faction .. "-spitter-spawner-v" .. v .. "-t" .. t .. "-rampant\", \"" .. faction .. "-spitter-spawner-v1-t" .. adjT .. "-rampant\"],")
32 | print(" [\"" .. faction .. "-worm-v" .. v .. "-t" .. t .. "-rampant\", \"" .. faction .. "-worm-v1-t" .. adjT .. "-rampant\"],")
33 | print(" [\"" .. faction .. "-hive-v" .. v .. "-t" .. t .. "-rampant\", \"" .. faction .. "-hive-v1-t" .. adjT .. "-rampant\"],")
34 | print(" [\"" .. faction .. "-biter-v" .. v .. "-t" .. t .. "-rampant\", \"" .. faction .. "-biter-v1-t" .. adjT .. "-rampant\"],")
35 | print(" [\"" .. faction .. "-spitter-v" .. v .. "-t" .. t .. "-rampant\", \"" .. faction .. "-spitter-v1-t" .. adjT .. "-rampant\"],")
36 | end
37 | end
38 | end
39 | end
40 |
--------------------------------------------------------------------------------
/prototypes/buildings/UpdatesVanilla.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 |
17 | local vanillaUpdates = {}
18 |
19 | function vanillaUpdates.addWallAcidResistance()
20 | local walls = data.raw["wall"]
21 |
22 | for _,wall in pairs(walls) do
23 | local foundAcid = false
24 | if wall.resistances then
25 | for _,resistance in pairs(wall.resistances) do
26 | if resistance.type == "acid" then
27 | if resistance.percent < 60 then
28 | resistance.percent = 60
29 | end
30 | foundAcid = true
31 | break
32 | end
33 | end
34 | if not foundAcid then
35 | wall.resistances[#wall.resistances+1] = {type="acid",percent=60}
36 | end
37 | end
38 | end
39 |
40 | walls = data.raw["gate"]
41 | for _,wall in pairs(walls) do
42 | local foundAcid = false
43 | if wall.resistances then
44 | for _,resistance in pairs(wall.resistances) do
45 | if resistance.type == "acid" then
46 | if resistance.percent < 60 then
47 | resistance.percent = 60
48 | end
49 | foundAcid = true
50 | break
51 | end
52 | end
53 | if not foundAcid then
54 | wall.resistances[#wall.resistances+1] = {type="acid",percent=60}
55 | end
56 | end
57 | end
58 | end
59 |
60 | return vanillaUpdates
61 |
--------------------------------------------------------------------------------
/prototypes/tile/fillableDirt.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 |
17 | data:extend({
18 | {
19 | type = "tile",
20 | name = "fillableDirt",
21 | needs_correction = false,
22 | collision_mask =
23 | {
24 | "water-tile",
25 | },
26 | layer = 40,
27 | variants =
28 | {
29 | main =
30 | {
31 | {
32 | picture = "__Rampant__/graphics/tiles/fillableDirt/dirt1.png",
33 | count = 8,
34 | size = 1
35 | }
36 | ,
37 | {
38 | picture = "__Rampant__/graphics/tiles/fillableDirt/dirt2.png",
39 | count = 8,
40 | size = 2
41 | },
42 | {
43 | picture = "__Rampant__/graphics/tiles/fillableDirt/dirt4.png",
44 | count = 6,
45 | size = 4
46 | }
47 | },
48 | inner_corner =
49 | {
50 | picture = "__Rampant__/graphics/tiles/fillableDirt/dirt-inner-corner.png",
51 | count = 6
52 | },
53 | outer_corner =
54 | {
55 | picture = "__Rampant__/graphics/tiles/fillableDirt/dirt-outer-corner.png",
56 | count = 6
57 | },
58 | side =
59 | {
60 | picture = "__Rampant__/graphics/tiles/fillableDirt/dirt-side.png",
61 | count = 8
62 | }
63 | },
64 | map_color={r=0.4196, g=0.3294, b=0.2196},
65 | ageing=0
66 | }
67 | })
68 |
--------------------------------------------------------------------------------
/prototypes/utils/StickerUtils.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 |
17 |
18 | local stickerUtils = {}
19 |
20 | -- imported
21 |
22 | local math3d = require("math3d")
23 |
24 | -- module code
25 |
26 | function stickerUtils.makeSticker(attributes)
27 | local name = attributes.name .. "-sticker-rampant"
28 |
29 | local o = {
30 | type = "sticker",
31 | name = name,
32 | flags = {"not-on-map"},
33 |
34 | animation = attributes.stickerAnimation or
35 | {
36 | filename = "__base__/graphics/entity/fire-flame/fire-flame-13.png",
37 | line_length = 8,
38 | width = 60,
39 | height = 118,
40 | frame_count = 25,
41 | axially_symmetrical = false,
42 | direction_count = 1,
43 | blend_mode = "normal",
44 | animation_speed = 2,
45 | scale = 0.175,
46 | tint = attributes.tint2 or { r = 1, g = 1, b = 1, a = 0.35 },
47 | shift = math3d.vector2.mul({-0.078125, -1.8125}, 0.1),
48 | },
49 |
50 | duration_in_ticks = attributes.stickerDuration or (30 * 60),
51 | target_movement_modifier_from = attributes.stickerMovementModifier or 1,
52 | target_movement_modifier_to = 1,
53 | vehicle_speed_modifier_from = (attributes.stickerMovementModifier and math.min(attributes.stickerMovementModifier * 1.25, 1)) or 1,
54 | vehicle_speed_modifier_to = 1,
55 |
56 | stickers_per_square_meter = 2,
57 |
58 | damage_per_tick = attributes.stickerDamagePerTick and { amount = attributes.stickerDamagePerTick or 100 / 60,
59 | type = attributes.stickerDamagePerTickType or "fire" },
60 | spread_fire_entity = attributes.spawnEntityName,
61 | fire_spread_cooldown = attributes.fireSpreadCooldown,
62 | fire_spread_radius = attributes.fireSpreadRadius
63 | }
64 |
65 | data:extend({o})
66 | return name
67 | end
68 |
69 |
70 | return stickerUtils
71 |
--------------------------------------------------------------------------------
/prototypes/utils/BombUtils.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 |
17 | local bombUtils = {}
18 |
19 | function bombUtils.makeAtomicBlast(attributes)
20 | local name = attributes.name .. "-atomic-blast-rampant"
21 | data:extend({{
22 | type = "projectile",
23 | name = name,
24 | flags = {"not-on-map"},
25 | acceleration = 0,
26 | action =
27 | {
28 | {
29 | type = "direct",
30 | action_delivery =
31 | {
32 | type = "instant",
33 | target_effects =
34 | {
35 | {
36 | type = "create-entity",
37 | entity_name = "explosion"
38 | }
39 | }
40 | }
41 | },
42 | {
43 | type = "area",
44 | radius = 3,
45 | action_delivery =
46 | {
47 | type = "instant",
48 | target_effects =
49 | {
50 | type = "damage",
51 | damage = {amount = (attributes.damage * 2) or 400,
52 | type = attributes.damageType or "explosion"}
53 | }
54 | }
55 | }
56 | },
57 | animation =
58 | {
59 | filename = "__core__/graphics/empty.png",
60 | frame_count = 1,
61 | width = 1,
62 | height = 1,
63 | priority = "high"
64 | },
65 | shadow =
66 | {
67 | filename = "__core__/graphics/empty.png",
68 | frame_count = 1,
69 | width = 1,
70 | height = 1,
71 | priority = "high"
72 | }
73 | }})
74 | return name
75 | end
76 |
77 | return bombUtils
78 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Rampant Tactics
2 | Factorio Mod - Improves the enemies tactics by using potential fields (pheromones) allowing probing of defenses, retreats, reinforcements, counterattacking, breaching, raids, rallying death cry, and player hunting. Uses blockable biter projectiles. Adds new Enemies which can be disabled in mod settings. Difficulty setting in mod options menu.
3 |
4 | # Site
5 |
6 | https://mods.factorio.com/mod/Rampant
7 |
8 | # Forum Post
9 |
10 | https://forums.factorio.com/viewtopic.php?f=94&t=31445
11 |
12 | # Features
13 |
14 | - New Enemy Factions - Neutral, Acid, Fast, Physical, Electric, Inferno, Suicide, Fire, Nuclear, Laser, Troll, Wasp, Spawner
15 | - Swarming - Units will smoothly slide by one another allowing for streamlined attacking
16 | - Difficulty Scaling - A mod option to control how quickly the ai can perform actions like making attack waves.
17 | - Nocturnal Mode - A mod option to force biters to only attack at night. Does not yet affect vanilla attacks. Best use with clockwork or daynight extender mod
18 | - Recycling Biters - When large groups of biters form on the game map and aren't assigned to a unit group or near a base will be periodically removed and refunded to the ai causing attack waves proportional to the number of units removed.
19 | - Breaching - When biters are destroying structures nearby unit groups will come to join them
20 | - Frenzy squads - When a unit group gets close to a player or start combat they switch to attacking everything in there path for a set radius or until there is nothing left
21 | - Rabid squads - Is in a permanent frenzied state as soon as the group is formed
22 | - Tactical Retreats - These will take place when a unit group is in a chunk that has reached a death threshold
23 | - Unit Group Forming - Any chunks with spawners in it that is covered by a pollution or player clouds will form groups based on the evolution factor
24 | - Probing Behavior Against Defenses - unit groups will attempt to avoid chunks that are soaked in death
25 | - Player Hunting - Unit groups will track the player based on there emitted pheromone cloud
26 | - Rallying Death Cry - When a unit is killed on a chunk that is past the retreat threshold, the unit will attempt to summon reinforcements to help them
27 | - Counterattacks - When the player is in combat near nests they will send reinforcements to unit groups
28 | - Reinforcements - Nests will send assistance to nearby nests under attack by the player
29 | - No Homing Projectiles - All projectiles are fired at locations and no longer track the player
30 | - Pathfinding - Unit groups will use potential fields to perform only single step pathfinding allowing for efficient and dynamic pathing
31 | - Peace mode - If something sets peace mode, Rampant will respect it
32 | - Ion Cannon Reaction - Firing the Ion Cannon will cause nests around the blast site to form into an attack wave and agitate all biters
33 | - Rocket Reaction - Firing the rocket from the rocket silo will cause the biters to form extra attack waves
34 | - Blockable Projectiles - Some of the biters projectiles can now be blocked by walls and trees
35 | - Raiding AI state - The AI will periodically send attack waves based on building proximity and not just pollution
36 | - Migration AI State - Where the ai looks for resources patches to setup new bases
37 | - Sieging AI state - Where the ai does a migration event but also builds towards the player and their base
38 | - Onslaught AI state - Where the ai gains 2x credits per logic cycle that can be used on units and buildings
39 | - Vanilla AI Replacement - The default expansion and attack waves can be completely turned off and allow Rampant to work its magic
40 |
41 |
--------------------------------------------------------------------------------
/action.fish:
--------------------------------------------------------------------------------
1 | #!/bin/fish
2 |
3 | argparse --min-args=1 --max-args=1 'dir=?' 'serverDir=?' 'silent' 'auth=?' 'help' -- $argv
4 | or return 2
5 |
6 | if test $_flag_help
7 | echo "commands are:
8 | copy: --dir, --serverDir
9 | zip: --dir, --serverDir, --silent
10 | upload: --dir, --auth
11 | options:
12 | --dir=
13 | --serverDir=
14 | --auth=
15 | --help="
16 | return 0
17 | end
18 |
19 | function copyFiles --argument-names copyFolder
20 | mkdir -p $copyFolder
21 |
22 | cp --verbose ./*.lua $copyFolder
23 | cp --verbose ./*.png $copyFolder
24 | cp --verbose ./*.json $copyFolder
25 | cp --verbose -r ./sounds $copyFolder
26 | cp --verbose -r ./locale $copyFolder
27 | cp --verbose -r ./libs $copyFolder
28 | cp --verbose -r ./graphics $copyFolder
29 | cp --verbose -r ./prototypes $copyFolder
30 | cp --verbose -r ./migrations $copyFolder
31 | cp --verbose ./COPYING $copyFolder
32 | cp --verbose ./changelog.txt $copyFolder
33 | cp --verbose ./README.md $copyFolder
34 | end
35 |
36 | set modFolder $_flag_dir
37 | if test -z "$modFolder"
38 | set modFolder "/mnt/gallery/gameFiles/factorio/mods"
39 | end
40 |
41 | set modName (jq -r .name info.json)
42 | set modVersion (jq -r .version info.json)
43 | set title $modName"_"$modVersion
44 | set zipName "$modFolder/$title.zip"
45 | set modPath "$modFolder/$title"
46 |
47 | switch $argv[1]
48 | case copy
49 | echo "copying"
50 | rm -f $zipName
51 |
52 | copyFiles $modPath
53 |
54 | if test -n "$_flag_serverDir"
55 | copyFiles $_flag_serverDir
56 | end
57 | case zip
58 | if test -z "$_flag_silent"
59 | echo "zipping"
60 | end
61 | rm -rf $modPath
62 | rm -f $zipName
63 | ln -s (pwd) $title
64 |
65 | set zipProgress (zip $zipName \
66 | $title/*.lua $title/*.png $title/*.json $title/sounds/**/* $title/locale/**/* \
67 | $title/libs/**/* $title/graphics/**/* $title/prototypes/**/* $title/migrations/**/* \
68 | $title/COPYING $title/changelog.txt $title/README.md)
69 |
70 | if test -z "$_flag_silent"
71 | echo $zipProgress
72 | end
73 |
74 | if test -n "$_flag_serverDir"
75 | cp $zipName $_flag_serverDir
76 | end
77 |
78 | rm ./$title
79 |
80 | echo $zipName
81 |
82 | case upload
83 | echo "init uploading"
84 |
85 | set initResponse (curl --no-progress-meter -X POST "https://mods.factorio.com/api/v2/mods/releases/init_upload" \
86 | -H "Authorization: Bearer $_flag_auth" -H "Content-Type: multipart/form-data" \
87 | -F mod=$modName)
88 |
89 | if test (echo "$initResponse" | jq -r .error '-') != "null"
90 | echo "init upload failed: $initResponse"
91 | return 3
92 | end
93 |
94 | echo "uploading"
95 |
96 | set finishResponse (curl --no-progress-meter -X POST (echo "$initResponse" | jq -r .upload_url '-') \
97 | -H "Authorization: Bearer $_flag_auth" -H "Content-Type: multipart/form-data" \
98 | -F file="@$_flag_dir")
99 |
100 | if test (echo "$finishResponse" | jq -r .error '-') != "null"
101 | echo "finish upload failed: $finishResponse"
102 | return 4
103 | else
104 | echo "upload success: $finishResponse"
105 | end
106 |
107 | case '*'
108 | echo "commands are: copy, zip"
109 | return 1
110 | end
111 |
--------------------------------------------------------------------------------
/prototypes/Poison.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 |
17 | -- imports
18 |
19 | local constants = require("__Rampant__/libs/Constants")
20 | local smokeUtils = require("utils/SmokeUtils")
21 |
22 | -- constants
23 |
24 | local poison = {}
25 |
26 | -- imported functions
27 |
28 | local makeCloud = smokeUtils.makeCloud
29 |
30 | function poison.addFactionAddon()
31 |
32 | for i=1,constants.TIERS do
33 | makeCloud(
34 | {
35 | name = "poison-cloud-v" .. i,
36 | scale = 0.80 + (i * 0.15),
37 | wind = true,
38 | slowdown = -1.3,
39 | duration = 10 * (i * 5),
40 | cooldown = 5
41 | },
42 | {
43 | type = "direct",
44 | action_delivery =
45 | {
46 | type = "instant",
47 | target_effects =
48 | {
49 | type = "nested-result",
50 | action =
51 | {
52 | {
53 | type = "area",
54 | radius = 2 + (i * 0.5),
55 | force = "ally",
56 | entity_flags = {"placeable-enemy"},
57 | action_delivery =
58 | {
59 | type = "instant",
60 | target_effects =
61 | {
62 | type = "damage",
63 | damage = { amount = -2 * i, type = "healing"}
64 | }
65 | }
66 | },
67 | {
68 | type = "area",
69 | radius = 2 + (i * 0.5),
70 | force = "enemy",
71 | action_delivery =
72 | {
73 | type = "instant",
74 | target_effects =
75 | {
76 | type = "damage",
77 | damage = { amount = 0.9 * i, type = "poison"}
78 | }
79 | }
80 | }
81 | }
82 | }
83 | }
84 | }
85 | )
86 | end
87 |
88 | end
89 |
90 | return poison
91 |
--------------------------------------------------------------------------------
/libs/Utils.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 |
17 | if UtilsG then
18 | return UtilsG
19 | end
20 | local Utils = {}
21 |
22 | --
23 |
24 | local Constants = require("Constants")
25 |
26 | --
27 |
28 | local CHUNK_SIZE = Constants.CHUNK_SIZE
29 |
30 | --
31 |
32 | local mFloor = math.floor
33 | local sSub = string.sub
34 | local sGMatch = string.gmatch
35 |
36 | --
37 |
38 | function Utils.isRampantSetting(str)
39 | return sSub(str, 1, #"rampant--") == "rampant--"
40 | end
41 |
42 | function Utils.split(str)
43 | local result = {}
44 | for i in sGMatch(str, "[a-zA-Z-]+") do
45 | result[#result+1] = i
46 | end
47 | return result
48 | end
49 |
50 | function Utils.isMember(str, set)
51 | for _,s in pairs(set) do
52 | if str == s then
53 | return true
54 | end
55 | end
56 | return false
57 | end
58 |
59 | function Utils.intersection(set1, set2)
60 | local result = {}
61 | for s1 in pairs(set1) do
62 | for s2 in pairs(set2) do
63 | if s1 == s2 then
64 | result[#result+1] = s1
65 | break
66 | end
67 | end
68 | end
69 | return result
70 | end
71 |
72 | function Utils.setPositionInQuery(query, position)
73 | local point = query.position
74 | point[1] = position.x
75 | point[2] = position.y
76 | end
77 |
78 | function Utils.setPositionInCommand(cmd, position)
79 | local point = cmd.destination
80 | point[1] = position.x
81 | point[2] = position.y
82 | end
83 |
84 | function Utils.setPositionXYInQuery(query, x, y)
85 | local point = query.position
86 | point[1] = x
87 | point[2] = y
88 | end
89 |
90 | function Utils.setAreaInQuery(query, topLeftPosition, size)
91 | local area = query.area
92 | area[1][1] = topLeftPosition.x
93 | area[1][2] = topLeftPosition.y
94 | area[2][1] = topLeftPosition.x + size
95 | area[2][2] = topLeftPosition.y + size
96 | end
97 |
98 | function Utils.setAreaInQueryChunkSize(query, topLeftPosition)
99 | local area = query.area
100 | area[1][1] = topLeftPosition.x
101 | area[1][2] = topLeftPosition.y
102 | area[2][1] = topLeftPosition.x + CHUNK_SIZE
103 | area[2][2] = topLeftPosition.y + CHUNK_SIZE
104 | end
105 |
106 | function Utils.setPointAreaInQuery(query, position, size)
107 | local area = query.area
108 | area[1][1] = position.x - size
109 | area[1][2] = position.y - size
110 | area[2][1] = position.x + size
111 | area[2][2] = position.y + size
112 | end
113 |
114 | function Utils.setAreaYInQuery(query, y1, y2)
115 | local area = query.area
116 | area[1][2] = y1
117 | area[2][2] = y2
118 | end
119 |
120 | function Utils.setAreaXInQuery(query, x1, x2)
121 | local area = query.area
122 | area[1][1] = x1
123 | area[2][1] = x2
124 | end
125 |
126 | function Utils.validPlayer(player)
127 | if player and player.valid then
128 | local char = player.character
129 | return char and char.valid
130 | end
131 | return false
132 | end
133 |
134 | function Utils.getTimeStringFromTick(tick)
135 |
136 | local tickToSeconds = tick / 60
137 |
138 | local days = mFloor(tickToSeconds / 86400)
139 | local hours = mFloor((tickToSeconds % 86400) / 3600)
140 | local minutes = mFloor((tickToSeconds % 3600) / 60)
141 | local seconds = mFloor(tickToSeconds % 60)
142 | return days .. "d " .. hours .. "h " .. minutes .. "m " .. seconds .. "s"
143 | end
144 |
145 | UtilsG = Utils
146 | return Utils
147 |
--------------------------------------------------------------------------------
/prototypes/utils/ThiefUtils.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 |
17 | local thiefUtils = {}
18 |
19 | -- module code
20 |
21 | function thiefUtils.makeDrainCrystal(attributes)
22 | local name = attributes.name .. "-drain-rampant"
23 | local itemName = attributes.name .. "-item-drain-rampant"
24 |
25 | data:extend({
26 | {
27 | type = "item",
28 | name = itemName,
29 | icon = "__Rampant__/graphics/icons/thief/crystal-drain.png",
30 | icon_size = 32,
31 | flags = {"hidden"},
32 | subgroup = "energy",
33 | order = "e[accumulator]-a[accumulator]",
34 | place_result = name,
35 | stack_size = 50
36 | },
37 |
38 | {
39 | type = "radar",
40 | name = name,
41 | icon = "__Rampant__/graphics/icons/thief/crystal-drain.png",
42 | icon_size = 32,
43 | flags = {"placeable-enemy"},
44 | minable = {hardness = 0.2, mining_time = 0.5, result = itemName},
45 | max_health = attributes.health or 500,
46 | corpse = nil,
47 | collision_box = {{-0.9 * attributes.scale, -0.9 * attributes.scale}, {0.9 * attributes.scale, 0.9 * attributes.scale}},
48 | selection_box = {{-1.1 * attributes.scale, -1.1 * attributes.scale}, {1.1 * attributes.scale, 1.1 * attributes.scale}},
49 | energy_per_sector = "100MJ",
50 | max_distance_of_sector_revealed = 0,
51 | max_distance_of_nearby_sector_revealed = 0,
52 | energy_per_nearby_scan = "750kJ",
53 | dying_explosion = "radar-explosion",
54 | resistances = {
55 | {
56 | type = "physical",
57 | percent = 25
58 | },
59 | {
60 | type = "fire",
61 | percent = 85
62 | },
63 | {
64 | type = "electric",
65 | percent = 95
66 | },
67 | {
68 | type = "laser",
69 | percent = 90
70 | }
71 | },
72 | energy_source =
73 | {
74 | type = "electric",
75 | usage_priority = "primary-input"
76 | },
77 | energy_usage = attributes.drain or "500kW",
78 | pictures =
79 | {
80 | filename = "__Rampant__/graphics/entities/thief/crystal-drain.png",
81 | priority = "low",
82 | width = 128,
83 | height = 128,
84 | scale = attributes.scale,
85 | apply_projection = false,
86 | direction_count = 32,
87 | animation_speed = 0.5,
88 | line_length = 8,
89 | shift = {0.65, 0}
90 | },
91 | vehicle_impact_sound = { filename = "__base__/sound/car-metal-impact.ogg", volume = 0.65 },
92 | working_sound =
93 | {
94 | sound = {
95 | {
96 | filename = "__base__/sound/accumulator-working.ogg"
97 | }
98 | },
99 | apparent_volume = 2,
100 | },
101 | radius_minimap_visualisation_color = { r = 0.059, g = 0.092, b = 0.8, a = 0.275 },
102 | }
103 | })
104 | return
105 | end
106 |
107 | return thiefUtils
108 |
--------------------------------------------------------------------------------
/prototypes/utils/ProjectileUtils.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 |
17 | local projectileUtils = {}
18 |
19 | function projectileUtils.makeProjectile(attributes, attack)
20 | local n = attributes.name .. "-projectile-rampant"
21 |
22 | data:extend({{
23 | type = "projectile",
24 | name = n,
25 | flags = {"not-on-map"},
26 | collision_box = attributes.attackCollisionBox or {{-0.025, -0.025}, {0.025, 0.025}},
27 | hit_collision_mask = attributes.attackCollisionMask or {"player-layer", "train-layer", RampantGlobalVariables.projectileCollisionLayer},
28 | direction_only = attributes.attackDirectionOnly,
29 | hit_at_collision_position = true,
30 | piercing_damage = attributes.attackPiercingDamage or 0,
31 | acceleration = attributes.attackAcceleration or 0.000001,
32 | max_speed = math.min(math.max(attributes.scale*0.60, 0.4), 0.7),
33 | force_condition = (settings.startup["rampant--disableCollidingProjectiles"].value and "not-same") or nil,
34 | action = attack,
35 | animation =
36 | {
37 | filename = "__base__/graphics/entity/acid-projectile/acid-projectile-head.png",
38 | line_length = 5,
39 | width = 22,
40 | height = 84,
41 | frame_count = 15,
42 | shift = util.mul_shift(util.by_pixel(-2, 30), attributes.scale*1.2 or 1),
43 | tint = attributes.tint2,
44 | priority = "high",
45 | scale = (attributes.scale*1.2 or 1),
46 | animation_speed = 1,
47 | hr_version =
48 | {
49 | filename = "__base__/graphics/entity/acid-projectile/hr-acid-projectile-head.png",
50 | line_length = 5,
51 | width = 42,
52 | height = 164,
53 | frame_count = 15,
54 | shift = util.mul_shift(util.by_pixel(-2, 31), attributes.scale*1.2 or 1),
55 | tint = attributes.tint2,
56 | priority = "high",
57 | scale = 0.5 * (attributes.scale*1.2 or 1),
58 | animation_speed = 1,
59 | }
60 | },
61 | shadow =
62 | {
63 | filename = "__base__/graphics/entity/acid-projectile/acid-projectile-shadow.png",
64 | line_length = 15,
65 | width = 22,
66 | height = 84,
67 | frame_count = 15,
68 | priority = "high",
69 | shift = util.mul_shift(util.by_pixel(-2, 30), attributes.scale*1.2 or 1),
70 | draw_as_shadow = true,
71 | scale = (attributes.scale*1.2 or 1),
72 | animation_speed = 1,
73 | hr_version =
74 | {
75 | filename = "__base__/graphics/entity/acid-projectile/hr-acid-projectile-shadow.png",
76 | line_length = 15,
77 | width = 42,
78 | height = 164,
79 | frame_count = 15,
80 | shift = util.mul_shift(util.by_pixel(-2, 31), attributes.scale*1.2 or 1),
81 | draw_as_shadow = true,
82 | priority = "high",
83 | scale = 0.5 * (attributes.scale*1.2 or 1),
84 | animation_speed = 1,
85 | }
86 | },
87 | -- rotatable = false,
88 | oriented_particle = true,
89 | shadow_scale_enabled = true,
90 |
91 | }})
92 |
93 | return n
94 | end
95 |
96 | return projectileUtils
97 |
--------------------------------------------------------------------------------
/libs/UnitUtils.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 |
17 | if (unitUtilsG) then
18 | return unitUtilsG
19 | end
20 | local unitUtils = {}
21 |
22 | -- imports
23 |
24 | local constants = require("Constants")
25 | local chunkPropertyUtils = require("ChunkPropertyUtils")
26 |
27 | -- constants
28 |
29 | local DEFINES_WIRE_TYPE_RED = defines.wire_type.red
30 | local DEFINES_WIRE_TYPE_GREEN = defines.wire_type.green
31 |
32 | local ENERGY_THIEF_CONVERSION_TABLE = constants.ENERGY_THIEF_CONVERSION_TABLE
33 | local ENERGY_THIEF_LOOKUP = constants.ENERGY_THIEF_LOOKUP
34 |
35 | local ENERGY_THIEF_DRAIN_CRYSTALS = constants.ENERGY_THIEF_DRAIN_CRYSTALS
36 |
37 | -- imported functions
38 |
39 | local setDrainPylons = chunkPropertyUtils.setDrainPylons
40 |
41 | -- module code
42 |
43 | local function convertTypeToDrainCrystal(evolutionFactor, entity)
44 | if (entity == "pole") then
45 | return "crystal-drain-pole-rampant"
46 | else
47 | if (entity == "smallUnit") then
48 | if (evolutionFactor < 0.25) then
49 | return ENERGY_THIEF_DRAIN_CRYSTALS[1]
50 | elseif (evolutionFactor < 0.50) then
51 | return ENERGY_THIEF_DRAIN_CRYSTALS[2]
52 | elseif (evolutionFactor < 0.75) then
53 | return ENERGY_THIEF_DRAIN_CRYSTALS[3]
54 | else
55 | return ENERGY_THIEF_DRAIN_CRYSTALS[4]
56 | end
57 | elseif (entity == "unit") then
58 | if (evolutionFactor < 0.25) then
59 | return ENERGY_THIEF_DRAIN_CRYSTALS[4]
60 | elseif (evolutionFactor < 0.50) then
61 | return ENERGY_THIEF_DRAIN_CRYSTALS[5]
62 | elseif (evolutionFactor < 0.75) then
63 | return ENERGY_THIEF_DRAIN_CRYSTALS[6]
64 | else
65 | return ENERGY_THIEF_DRAIN_CRYSTALS[7]
66 | end
67 | else
68 | if (evolutionFactor < 0.25) then
69 | return ENERGY_THIEF_DRAIN_CRYSTALS[7]
70 | elseif (evolutionFactor < 0.50) then
71 | return ENERGY_THIEF_DRAIN_CRYSTALS[8]
72 | elseif (evolutionFactor < 0.75) then
73 | return ENERGY_THIEF_DRAIN_CRYSTALS[9]
74 | else
75 | return ENERGY_THIEF_DRAIN_CRYSTALS[10]
76 | end
77 | end
78 | end
79 | end
80 |
81 | function unitUtils.createDrainPylon(map, cause, entity, entityType)
82 | if ((cause and ENERGY_THIEF_LOOKUP[cause.name]) or (not cause)) then
83 | local conversion = ENERGY_THIEF_CONVERSION_TABLE[entityType]
84 | if conversion then
85 | local newEntity = map.surface.create_entity({
86 | position=entity.position,
87 | name=convertTypeToDrainCrystal(entity.force.evolution_factor, conversion),
88 | direction=entity.direction
89 | })
90 | if (conversion == "pole") then
91 | local targetEntity = map.surface.create_entity({
92 | position=entity.position,
93 | name="pylon-target-rampant",
94 | direction=entity.direction
95 | })
96 | targetEntity.backer_name = ""
97 | local wires = entity.neighbours
98 | if wires then
99 | for _,v in pairs(wires.copper) do
100 | if (v.valid) then
101 | newEntity.connect_neighbour(v);
102 | end
103 | end
104 | for _,v in pairs(wires.red) do
105 | if (v.valid) then
106 | newEntity.connect_neighbour({
107 | wire = DEFINES_WIRE_TYPE_RED,
108 | target_entity = v
109 | });
110 | end
111 | end
112 | for _,v in pairs(wires.green) do
113 | if (v.valid) then
114 | newEntity.connect_neighbour({
115 | wire = DEFINES_WIRE_TYPE_GREEN,
116 | target_entity = v
117 | });
118 | end
119 | end
120 | end
121 | setDrainPylons(map, targetEntity, newEntity)
122 | elseif newEntity.backer_name then
123 | newEntity.backer_name = ""
124 | end
125 | end
126 | end
127 | end
128 |
129 | unitUtilsG = unitUtils
130 | return unitUtils
131 |
--------------------------------------------------------------------------------
/libs/MathUtils.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 |
17 | if MathUtilsG then
18 | return MathUtilsG
19 | end
20 | local MathUtils = {}
21 |
22 | -- imports
23 |
24 | -- constants
25 |
26 | local TICKS_A_MINUTE = 60 * 60
27 |
28 | -- imported functions
29 |
30 | local mSqrt = math.sqrt
31 | local mLog10 = math.log10
32 |
33 | local mFloor = math.floor
34 | local mAbs = math.abs
35 |
36 | -- module code
37 |
38 | function MathUtils.roundToFloor(number, multiple)
39 | return mFloor(number / multiple) * multiple
40 | end
41 |
42 | function MathUtils.roundToNearest(number, multiple)
43 | local num = number + (multiple * 0.5)
44 | return num - (num % multiple)
45 | end
46 |
47 | function MathUtils.randomTickEvent(rg, tick, low, high)
48 | return tick + MathUtils.randomTickDuration(rg, low, high)
49 | end
50 |
51 | function MathUtils.randomTickDuration(rg, low, high)
52 | local range = high - low
53 | local minutesToTick = (range * rg()) + low
54 | return MathUtils.roundToNearest(TICKS_A_MINUTE * minutesToTick, 1)
55 | end
56 |
57 | function MathUtils.distort(xorRandom, num, stdDev, min, max)
58 | local amin = min or num * 0.70
59 | local amax = max or num * 1.30
60 | local sd = stdDev or 0.17
61 | if (num < 0) then
62 | local t = amin
63 | amin = amax
64 | amax = t
65 | end
66 | return MathUtils.roundToNearest(MathUtils.gaussianRandomRangeRG(num, num * sd, amin, amax, xorRandom), 0.01)
67 | end
68 |
69 | function MathUtils.linearInterpolation(percent, min, max)
70 | return ((max - min) * percent) + min
71 | end
72 |
73 | function MathUtils.xorRandom(state)
74 | local xor = bit32.bxor
75 | local lshift = bit32.lshift
76 | local rshift = bit32.rshift
77 |
78 | local seed = state + 32685453
79 |
80 | return function()
81 | seed = xor(seed, lshift(seed, 13))
82 | seed = xor(seed, rshift(seed, 17))
83 | seed = xor(seed, lshift(seed, 5))
84 | return seed * 2.32830643654e-10 -- 2.32830643654e-10 = 1 / 2^32, 2.32830643708e-10 = 1 / ((2^32)-1)
85 | end
86 | end
87 |
88 | --[[
89 | Used for gaussian random numbers
90 | --]]
91 | function MathUtils.gaussianRandomRG(mean, std_dev, rg)
92 | -- marsagliaPolarMethod
93 | local iid1
94 | local iid2
95 | local q
96 | repeat
97 | iid1 = 2 * rg() + -1
98 | iid2 = 2 * rg() + -1
99 | q = (iid1 * iid1) + (iid2 * iid2)
100 | until (q ~= 0) and (q < 1)
101 | local s = mSqrt((-2 * mLog10(q)) / q)
102 | local v = iid1 * s
103 |
104 | return mean + (v * std_dev)
105 | end
106 |
107 | function MathUtils.gaussianRandomRangeRG(mean, std_dev, min, max, rg)
108 | local r
109 | if (min >= max) then
110 | return min
111 | end
112 | repeat
113 | local iid1
114 | local iid2
115 | local q
116 | repeat
117 | iid1 = 2 * rg() + -1
118 | iid2 = 2 * rg() + -1
119 | q = (iid1 * iid1) + (iid2 * iid2)
120 | until (q ~= 0) and (q < 1)
121 | local s = mSqrt((-2 * mLog10(q)) / q)
122 | local v = iid1 * s
123 | r = mean + (v * std_dev)
124 | until (r >= min) and (r <= max)
125 | return r
126 | end
127 |
128 | function MathUtils.euclideanDistanceNamed(p1, p2)
129 | local xs = p1.x - p2.x
130 | local ys = p1.y - p2.y
131 | return ((xs * xs) + (ys * ys)) ^ 0.5
132 | end
133 |
134 | function MathUtils.euclideanDistancePoints(x1, y1, x2, y2)
135 | local xs = x1 - x2
136 | local ys = y1 - y2
137 | return ((xs * xs) + (ys * ys)) ^ 0.5
138 | end
139 |
140 | function MathUtils.manhattenDistancePoints(x1, y1, x2, y2)
141 | return mAbs((x1 - x2) + (y1 - y2))
142 | end
143 |
144 | function MathUtils.euclideanDistanceArray(p1, p2)
145 | local xs = p1[1] - p2[1]
146 | local ys = p1[2] - p2[2]
147 | return ((xs * xs) + (ys * ys)) ^ 0.5
148 | end
149 |
150 | function MathUtils.distortPosition(rg, position, size)
151 | local xDistort = MathUtils.gaussianRandomRangeRG(1, 0.5, 0, 2, rg) - 1
152 | local yDistort = MathUtils.gaussianRandomRangeRG(1, 0.5, 0, 2, rg) - 1
153 | position.x = position.x + (xDistort * size)
154 | position.y = position.y + (yDistort * size)
155 | end
156 |
157 | function MathUtils.distortPositionConcentricCircles(rg, position, size, min)
158 | local xDistort = MathUtils.gaussianRandomRangeRG(1, 0.5, 0, 2, rg) - 1
159 | local yDistort = MathUtils.gaussianRandomRangeRG(1, 0.5, 0, 2, rg) - 1
160 | local xModifier = (xDistort * size)
161 | if xModifier < 0 then
162 | xModifier = xModifier + -min
163 | else
164 | xModifier = xModifier + min
165 | end
166 | local yModifier = (yDistort * size)
167 | if yModifier < 0 then
168 | yModifier = yModifier + -min
169 | else
170 | yModifier = yModifier + min
171 | end
172 |
173 | position.x = position.x + xModifier
174 | position.y = position.y + yModifier
175 | end
176 |
177 | MathUtilsG = MathUtils
178 | return MathUtils
179 |
--------------------------------------------------------------------------------
/prototypes/utils/AttackFlame.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 |
17 | local attackFlame = {}
18 |
19 | -- imported
20 |
21 | local streamUtils = require("StreamUtils")
22 | local fireUtils = require("FireUtils")
23 | local stickerUtils = require("StickerUtils")
24 |
25 | -- constants
26 |
27 | local DISALLOW_FRIENDLY_FIRE = settings.startup["rampant--disallowFriendlyFire"].value
28 |
29 | -- imported functions
30 |
31 | local makeStream = streamUtils.makeStream
32 | local makeFire = fireUtils.makeFire
33 | local makeSticker = stickerUtils.makeSticker
34 | local makeSpreadEffect = fireUtils.makeSpreadEffect
35 |
36 | -- module code
37 |
38 | function attackFlame.createAttackFlame(attributes)
39 |
40 | local spawnEntityName = makeSpreadEffect({
41 | name = attributes.name,
42 | tint2 = attributes.tint2,
43 | fireDamagePerTick = attributes.fireDamagePerTick,
44 | fireDamagePerTickType = attributes.fireDamagePerTickType,
45 | })
46 | local stickerName = makeSticker({
47 | name = attributes.name,
48 | spawnEntityName = spawnEntityName,
49 | stickerDuration = attributes.stickerDuration,
50 | stickerDamagePerTick = attributes.stickerDamagePerTick,
51 | stickerDamagePerTickType = attributes.stickerDamagePerTickType,
52 | stickerMovementModifier = attributes.stickerMovementModifier,
53 | tint2 = attributes.tint2,
54 | fireSpreadRadius = attributes.fireSpreadRadius
55 | })
56 | local fireName = makeFire({
57 | name = attributes.name,
58 | tint2 = attributes.tint2 or {r=0, g=0.9, b=0, a=0.5},
59 | spawnEntityName = spawnEntityName,
60 | fireDamagePerTick = attributes.fireDamagePerTick,
61 | fireDamagePerTickType = attributes.fireDamagePerTickType,
62 | damageMaxMultipler = attributes.damageMaxMultipler,
63 | multiplerIncrease = attributes.multiplerIncrease,
64 | multiplerDecrease = attributes.multiplerDecrease,
65 | stickerName = stickerName
66 | })
67 |
68 | return makeStream({
69 | name = attributes.name,
70 | tint2 = attributes.tint2 or {r=0, g=1, b=1, a=0.5},
71 | particleTimeout = attributes.particleTimeout,
72 | scale = attributes.scale,
73 | actions = {
74 | {
75 | type = "area",
76 | radius = attributes.radius or 2.5,
77 | force = (DISALLOW_FRIENDLY_FIRE and "not-same") or nil,
78 | action_delivery =
79 | {
80 | type = "instant",
81 | target_effects =
82 | {
83 | {
84 | type = "create-sticker",
85 | sticker = stickerName,
86 | check_buildability = true
87 | },
88 | {
89 | type = "create-entity",
90 | entity_name = "water-splash",
91 | tile_collision_mask = { "ground-tile" }
92 | },
93 | {
94 | type = "damage",
95 | damage = { amount = attributes.damage, type = attributes.damageType or "fire" }
96 | }
97 | }
98 | }
99 | },
100 | {
101 | type = "cluster",
102 | cluster_count = 2,
103 | distance = 2 + (0.1 * attributes.effectiveLevel),
104 | distance_deviation = 1.5,
105 | action_delivery = {
106 | type = "instant",
107 | target_effects = {
108 | {
109 | type="create-fire",
110 | entity_name = fireName,
111 | check_buildability = true,
112 | initial_ground_flame_count = 2,
113 | show_in_tooltip = true
114 | }
115 | }
116 | }
117 | },
118 | {
119 | type = "direct",
120 | action_delivery = {
121 | type = "instant",
122 | target_effects = {
123 | type= "create-fire",
124 | entity_name = fireName,
125 | check_buildability = true,
126 | show_in_tooltip = true
127 | }
128 | }
129 | }
130 | }
131 | })
132 | end
133 |
134 | return attackFlame
135 |
--------------------------------------------------------------------------------
/data-final-fixes.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 | local vanillaBuildings = require("prototypes/buildings/UpdatesVanilla")
17 | local constants = require("libs/Constants")
18 |
19 | if settings.startup["rampant--newEnemies"].value and mods["SchallAlienLoot"] then
20 | local SizeLootRampant = {1, 2, 3, 3, 4, 4, 4, 5, 5, 6}
21 | for _,faction in pairs(constants.FACTION_SET) do
22 | for v=1,settings.startup["rampant--newEnemyVariations"].value do
23 | for factionSize = 1, constants.TIERS do
24 | local effectiveLevel = constants.TIER_UPGRADE_SET[factionSize]
25 | SchallAlienLoot_add_spawner(faction.type.."-hive-v"..v.."-t"..factionSize.."-rampant")
26 | SchallAlienLoot_add_spawner(faction.type.."-spitter-spawner-v"..v.."-t"..factionSize.."-rampant")
27 | SchallAlienLoot_add_spawner(faction.type.."-biter-spawner-v"..v.."-t"..factionSize.."-rampant")
28 | SchallAlienLoot_add_worm(faction.type.."-worm-v"..v.."-t"..factionSize.."-rampant", factionSize)
29 | SchallAlienLoot_add_mover(faction.type.."-spitter-v"..v.."-t"..factionSize.."-rampant", SizeLootRampant[effectiveLevel])
30 | SchallAlienLoot_add_mover(faction.type.."-biter-v"..v.."-t"..factionSize.."-rampant", SizeLootRampant[effectiveLevel])
31 | end
32 | end
33 | end
34 | end
35 |
36 | for _, projectile in pairs(data.raw["projectile"]) do
37 | if not projectile.hit_collision_mask then
38 | projectile.hit_collision_mask = {
39 | "player-layer",
40 | "train-layer",
41 | RampantGlobalVariables.projectileCollisionLayer
42 | }
43 | else
44 | projectile.hit_collision_mask[#projectile.hit_collision_mask+1] = RampantGlobalVariables.projectileCollisionLayer
45 | end
46 | end
47 |
48 | if settings.startup["rampant--removeBloodParticles"].value then
49 | local explosions = data.raw["explosion"]
50 |
51 | for k,v in pairs(explosions) do
52 | if string.find(k, "blood") then
53 | v["created_effect"] = nil
54 | end
55 | end
56 | end
57 |
58 | if settings.startup["rampant--unitSpawnerBreath"].value then
59 | for _, unitSpawner in pairs(data.raw["unit-spawner"]) do
60 | if (string.find(unitSpawner.name, "hive") or string.find(unitSpawner.name, "biter") or
61 | string.find(unitSpawner.name, "spitter")) then
62 | if not unitSpawner.flags then
63 | unitSpawner.flags = {}
64 | end
65 | unitSpawner.flags[#unitSpawner.flags+1] = "breaths-air"
66 | end
67 | end
68 | end
69 |
70 |
71 | for k, unit in pairs(data.raw["unit"]) do
72 | if (string.find(k, "biter") or string.find(k, "spitter")) and unit.collision_box then
73 | if settings.startup["rampant--enableSwarm"].value then
74 | unit.collision_box = {
75 | {unit.collision_box[1][1] * 0.70, unit.collision_box[1][2] * 0.70},
76 | {unit.collision_box[2][1] * 0.70, unit.collision_box[2][2] * 0.70}
77 | }
78 | end
79 |
80 | unit.affected_by_tiles = settings.startup["rampant--unitsAffectedByTiles"].value
81 |
82 | unit.ai_settings = {
83 | destroy_when_commands_fail = false,
84 | allow_try_return_to_spawner = true
85 | }
86 | end
87 | end
88 |
89 | if settings.startup["rampant--enableShrinkNestsAndWorms"].value then
90 | for k, unit in pairs(data.raw["unit-spawner"]) do
91 | if (string.find(k, "biter") or string.find(k, "spitter") or string.find(k, "hive")) and unit.collision_box then
92 | unit.collision_box = {
93 | {unit.collision_box[1][1] * 0.75, unit.collision_box[1][2] * 0.75},
94 | {unit.collision_box[2][1] * 0.75, unit.collision_box[2][2] * 0.75}
95 | }
96 | end
97 | end
98 |
99 | for k, unit in pairs(data.raw["turret"]) do
100 | if string.find(k, "worm") and unit.collision_box then
101 | unit.collision_box = {
102 | {unit.collision_box[1][1] * 0.75, unit.collision_box[1][2] * 0.75},
103 | {unit.collision_box[2][1] * 0.75, unit.collision_box[2][2] * 0.75}
104 | }
105 | end
106 | end
107 | end
108 |
109 | if settings.startup["rampant--enableLandfillOnDeath"].value then
110 | local particles = {
111 | "guts-entrails-particle-small-medium",
112 | "guts-entrails-particle-big"
113 | }
114 |
115 | for _,particleName in pairs(particles) do
116 | data.raw["optimized-particle"][particleName].ended_in_water_trigger_effect = {
117 | {
118 | type = "set-tile",
119 | tile_name = "landfill",
120 | radius = 0.5,
121 | },
122 | {
123 | type = "script",
124 | effect_id = "deathLandfillParticle--rampant"
125 | }
126 | }
127 | end
128 | end
129 |
130 | if settings.startup["rampant--enableFadeTime"].value then
131 | for k, corpse in pairs(data.raw["corpse"]) do
132 | if (string.find(k, "biter") or string.find(k, "spitter") or string.find(k, "hive") or
133 | string.find(k, "worm") or string.find(k, "spawner")) then
134 | corpse.time_before_removed = settings.startup["rampant--unitAndSpawnerFadeTime"].value * 60
135 | end
136 | end
137 | end
138 |
139 | if settings.startup["rampant--addWallResistanceAcid"].value then
140 | vanillaBuildings.addWallAcidResistance()
141 | end
142 |
--------------------------------------------------------------------------------
/prototypes/samples/healingBiter.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 |
17 | local smallbiterscale = 0.5
18 | local small_biter_tint1 = {r=0.56, g=0.46, b=0.42, a=0.65}
19 | local small_biter_tint2 = {r=1, g=0.63, b=0, a=0.4}
20 |
21 | data:extend({
22 | { -- this defines a damage type so resistances don't effect this damage
23 | type = "damage-type",
24 | name = "healing"
25 | },
26 | { -- this defines your healing cloud
27 | type = "smoke-with-trigger",
28 | name = "healing-cloud-overlord",
29 | flags = {"not-on-map"},
30 | show_when_smoke_off = true,
31 | animation =
32 | {
33 | filename = "__base__/graphics/entity/cloud/cloud-45-frames.png",
34 | flags = { "compressed" },
35 | priority = "low",
36 | width = 256,
37 | height = 256,
38 | frame_count = 45,
39 | animation_speed = 0.5,
40 | line_length = 7,
41 | scale = 3,
42 | },
43 | slow_down_factor = 0,
44 | affected_by_wind = false,
45 | cyclic = true,
46 | duration = 60 * 5,
47 | fade_away_duration = 5 * 60,
48 | spread_duration = 10,
49 | color = { r = 0.0, g = 0.0, b = 0.9, a = 0.2 },
50 | action =
51 | {
52 | type = "direct",
53 | action_delivery =
54 | {
55 | type = "instant",
56 | target_effects =
57 | {
58 | type = "nested-result",
59 | action =
60 | {
61 | type = "area",
62 | perimeter = 11,
63 | entity_flags = {"breaths-air"},
64 | action_delivery =
65 | {
66 | type = "instant",
67 | target_effects =
68 | {
69 | type = "damage",
70 | damage = { amount = -2, type = "healing"}
71 | }
72 | }
73 | }
74 | }
75 | }
76 | },
77 | action_cooldown = 30
78 | },
79 | { -- this is your custom projectile that will create the healing cloud
80 | type = "projectile",
81 | name = "healing-orb-overlord",
82 | flags = {"not-on-map"},
83 | acceleration = 0.005,
84 | action =
85 | {
86 | type = "direct",
87 | action_delivery =
88 | {
89 | type = "instant",
90 | target_effects =
91 | {
92 | {
93 | type = "play-sound",
94 | sound =
95 | {
96 | {
97 | filename = "__base__/sound/creatures/projectile-acid-burn-1.ogg",
98 | volume = 0.8
99 | },
100 | {
101 | filename = "__base__/sound/creatures/projectile-acid-burn-2.ogg",
102 | volume = 0.8
103 | },
104 | {
105 | filename = "__base__/sound/creatures/projectile-acid-burn-long-1.ogg",
106 | volume = 0.8
107 | },
108 | {
109 | filename = "__base__/sound/creatures/projectile-acid-burn-long-2.ogg",
110 | volume = 0.8
111 | }
112 | }
113 | },
114 | {
115 | type = "create-entity",
116 | entity_name = "healing-cloud-overlord"
117 | }
118 | }
119 | }
120 | },
121 | animation =
122 | {
123 | filename = "__base__/graphics/entity/acid-projectile-purple/acid-projectile-purple.png",
124 | line_length = 5,
125 | width = 16,
126 | height = 18,
127 | frame_count = 33,
128 | priority = "high"
129 | },
130 | shadow =
131 | {
132 | filename = "__base__/graphics/entity/acid-projectile-purple/acid-projectile-purple-shadow.png",
133 | line_length = 5,
134 | width = 28,
135 | height = 16,
136 | frame_count = 33,
137 | priority = "high",
138 | shift = {-0.09, 0.395}
139 | },
140 | rotatable = false
141 | },
142 | {
143 | type = "unit",
144 | name = "small-healing-biter-overlord",
145 | icon = "__base__/graphics/icons/small-biter.png",
146 | flags = {"placeable-player", "placeable-enemy", "placeable-off-grid", "breaths-air"},
147 | max_health = 15,
148 | order = "b-b-a",
149 | subgroup="enemies",
150 | healing_per_tick = 0.01,
151 | collision_box = {{-0.2, -0.2}, {0.2, 0.2}},
152 | selection_box = {{-0.4, -0.7}, {0.7, 0.4}},
153 | attack_parameters = {
154 | type = "projectile",
155 | ammo_category = "rocket",
156 | damage_modifier = 10,
157 | cooldown = 150,
158 | projectile_center = {0, 0},
159 | projectile_creation_distance = 0.6,
160 | range = 15, -- make this whatever distance you want the unit to stop at
161 | animation = biterattackanimation(smallbiterscale, small_biter_tint1, small_biter_tint2),
162 | sound = {
163 | filename = "__base__/sound/fight/pulse.ogg",
164 | volume = 0.7
165 | },
166 | ammo_type = {
167 | type = "projectile",
168 | category = "biological",
169 | speed = 1,
170 | action =
171 | {
172 | {
173 | type = "direct",
174 | action_delivery =
175 | {
176 | type = "projectile",
177 | projectile = "healing-orb-overlord",
178 | starting_speed = 0.5,
179 | max_range = 1 -- the distance you want the cloud to appear from the unit
180 | }
181 | },
182 | {
183 | type = "direct",
184 | action_delivery =
185 | {
186 | type = "projectile",
187 | projectile = "acid-projectile-purple",
188 | starting_speed = 0.5,
189 | max_range = 15 -- should be whatever range you want the unit to shoot for
190 | }
191 | }
192 | }
193 | }
194 | },
195 | vision_distance = 30,
196 | movement_speed = 0.2,
197 | distance_per_frame = 0.1,
198 | pollution_to_join_attack = 200,
199 | distraction_cooldown = 300,
200 | min_pursue_time = 10 * 60,
201 | max_pursue_distance = 50,
202 | corpse = "small-biter-corpse",
203 | dying_explosion = "blood-explosion-small",
204 | dying_sound = make_biter_dying_sounds(0.4),
205 | working_sound = make_biter_calls(0.3),
206 | run_animation = biterrunanimation(smallbiterscale, small_biter_tint1, small_biter_tint2)
207 | }
208 | })
209 |
--------------------------------------------------------------------------------
/data.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 |
17 | -- import
18 |
19 | local colorUtils = require("prototypes/utils/ColorUtils")
20 | local smokeUtils = require("prototypes/utils/SmokeUtils")
21 | local swarmUtils = require("prototypes/SwarmUtils")
22 | local collision_mask_util = require("collision-mask-util")
23 |
24 | -- imported functions
25 |
26 | local makeSmokeSoft = smokeUtils.makeSmokeSoft
27 | local makeSmokeWithGlow = smokeUtils.makeSmokeWithGlow
28 | local makeSmokeWithoutGlow = smokeUtils.makeSmokeWithoutGlow
29 | local makeSmokeAddingFuel = smokeUtils.makeSmokeAddingFuel
30 |
31 | local makeColor = colorUtils.makeColor
32 |
33 | -- module code
34 |
35 | makeSmokeSoft({name="the", softSmokeTint=makeColor(0.3, 0.75, 0.3, 0.1)})
36 | makeSmokeWithGlow({name="the", smokeWithGlowTint=makeColor(0.3, 0.75, 0.3, 0.1)})
37 | makeSmokeWithoutGlow({name="the", smokeWithoutGlowTint=makeColor(0.3, 0.75, 0.3, 0.1)})
38 | makeSmokeAddingFuel({name="the"})
39 |
40 | require("prototypes/buildings/ChunkScanner")
41 |
42 | RampantGlobalVariables = {}
43 | RampantGlobalVariables.projectileCollisionLayer = collision_mask_util.get_first_unused_layer()
44 |
45 | if not data.raw["corpse"]["acid-splash-purple"] then
46 | local attributes = {}
47 |
48 | data:extend({
49 | {
50 | type = "corpse",
51 | name = "acid-splash-purple",
52 | flags = {"not-on-map"},
53 | time_before_removed = 60 * 30,
54 | final_render_layer = "corpse",
55 | splash =
56 | {
57 | {
58 | filename = "__base__/graphics/entity/acid-splash/acid-splash-1.png",
59 | line_length = 8,
60 | direction_count = 1,
61 | width = 106,
62 | height = 116,
63 | frame_count = 26,
64 | shift = util.mul_shift(util.by_pixel(-12, -10), attributes.scale or 1),
65 | tint = attributes.tint,
66 | scale = (attributes.scale or 1),
67 | hr_version = {
68 | filename = "__base__/graphics/entity/acid-splash/hr-acid-splash-1.png",
69 | line_length = 8,
70 | direction_count = 1,
71 | width = 210,
72 | height = 224,
73 | frame_count = 26,
74 | shift = util.mul_shift(util.by_pixel(-12, -8), attributes.scale or 1),
75 | tint = attributes.tint,
76 | scale = 0.5 * (attributes.scale or 1),
77 | }
78 | },
79 | {
80 | filename = "__base__/graphics/entity/acid-splash/acid-splash-2.png",
81 | line_length = 8,
82 | direction_count = 1,
83 | width = 88,
84 | height = 76,
85 | frame_count = 29,
86 | shift = util.mul_shift(util.by_pixel(-10, -18), attributes.scale or 1),
87 | tint = attributes.tint,
88 | scale = (attributes.scale or 1),
89 | hr_version = {
90 | filename = "__base__/graphics/entity/acid-splash/hr-acid-splash-2.png",
91 | line_length = 8,
92 | direction_count = 1,
93 | width = 174,
94 | height = 150,
95 | frame_count = 29,
96 | shift = util.mul_shift(util.by_pixel(-9, -17), attributes.scale or 1),
97 | tint = attributes.tint,
98 | scale = 0.5 * (attributes.scale or 1),
99 | }
100 | },
101 | {
102 | filename = "__base__/graphics/entity/acid-splash/acid-splash-3.png",
103 | line_length = 8,
104 | direction_count = 1,
105 | width = 118,
106 | height = 104,
107 | frame_count = 29,
108 | shift = util.mul_shift(util.by_pixel(22, -16), attributes.scale or 1),
109 | tint = attributes.tint,
110 | scale = (attributes.scale or 1),
111 | hr_version = {
112 | filename = "__base__/graphics/entity/acid-splash/hr-acid-splash-3.png",
113 | line_length = 8,
114 | direction_count = 1,
115 | width = 236,
116 | height = 208,
117 | frame_count = 29,
118 | shift = util.mul_shift(util.by_pixel(22, -16), attributes.scale or 1),
119 | tint = attributes.tint,
120 | scale = 0.5 * (attributes.scale or 1),
121 | }
122 | },
123 | {
124 | filename = "__base__/graphics/entity/acid-splash/acid-splash-4.png",
125 | line_length = 8,
126 | direction_count = 1,
127 | width = 128,
128 | height = 80,
129 | frame_count = 24,
130 | shift = util.mul_shift(util.by_pixel(16, -20), attributes.scale or 1),
131 | tint = attributes.tint,
132 | scale = (attributes.scale or 1),
133 | hr_version = {
134 | filename = "__base__/graphics/entity/acid-splash/hr-acid-splash-4.png",
135 | line_length = 8,
136 | direction_count = 1,
137 | width = 252,
138 | height = 154,
139 | frame_count = 24,
140 | shift = util.mul_shift(util.by_pixel(17, -19), attributes.scale or 1),
141 | tint = attributes.tint,
142 | scale = 0.5 * (attributes.scale or 1),
143 | }
144 | }
145 | },
146 | splash_speed = 0.03
147 | }
148 | })
149 | end
150 |
151 | if settings.startup["rampant--newEnemies"].value then
152 | swarmUtils.processFactions()
153 | end
154 |
--------------------------------------------------------------------------------
/prototypes/utils/UnitSpawnerUtils.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 |
17 |
18 | local unitSpawnerUtils = {}
19 |
20 | function unitSpawnerUtils.spawner_integration(scale)
21 | return
22 | {
23 | filename = "__base__/graphics/entity/spawner/spawner-idle-integration.png",
24 | variation_count = 4,
25 | width = 258,
26 | height = 188,
27 | shift = util.by_pixel(2, -2),
28 | frame_count = 1,
29 | scale = scale * 1.01,
30 | line_length = 1,
31 | hr_version =
32 | {
33 | filename = "__base__/graphics/entity/spawner/hr-spawner-idle-integration.png",
34 | variation_count = 4,
35 | width = 522,
36 | height = 380,
37 | shift = util.by_pixel(3, -3),
38 | frame_count = 1,
39 | line_length = 1,
40 | scale = scale * 0.51
41 | }
42 | }
43 | end
44 |
45 | function unitSpawnerUtils.spawner_idle_animation(variation, tint, scale, tint2)
46 | return
47 | {
48 | layers =
49 | {
50 | {
51 | filename = "__base__/graphics/entity/spawner/spawner-idle.png",
52 | line_length = 4,
53 | width = 248,
54 | height = 180,
55 | frame_count = 8,
56 | animation_speed = 0.18,
57 | direction_count = 1,
58 | scale = scale,
59 | run_mode = "forward-then-backward",
60 | shift = util.by_pixel(2, -4),
61 | tint = tint,
62 | y = variation * 180 * 2,
63 | hr_version =
64 | {
65 | filename = "__base__/graphics/entity/spawner/hr-spawner-idle.png",
66 | line_length = 4,
67 | width = 490,
68 | height = 354,
69 | frame_count = 8,
70 | animation_speed = 0.18,
71 | direction_count = 1,
72 | scale = scale * 0.5,
73 | tint = tint,
74 | run_mode = "forward-then-backward",
75 | shift = util.by_pixel(3, -2),
76 | y = variation * 354 * 2,
77 | }
78 | },
79 | {
80 | filename = "__base__/graphics/entity/spawner/spawner-idle-mask.png",
81 | flags = { "mask" },
82 | width = 140,
83 | height = 118,
84 | frame_count = 8,
85 | animation_speed = 0.18,
86 | run_mode = "forward-then-backward",
87 | shift = util.by_pixel(-1.5 + (-0.5 * scale), -11 + (-3 * scale)),
88 | line_length = 4,
89 | tint = tint2,
90 | scale = scale,
91 | y = variation * 118 * 2,
92 | hr_version =
93 | {
94 | filename = "__base__/graphics/entity/spawner/hr-spawner-idle-mask.png",
95 | flags = { "mask" },
96 | width = 276,
97 | height = 234,
98 | frame_count = 8,
99 | animation_speed = 0.18,
100 | run_mode = "forward-then-backward",
101 | shift = util.by_pixel(3 + (-2 * (scale * 2.5)), -0.8 + (-8 * (scale * 1.55))),
102 | line_length = 4,
103 | tint = tint2,
104 | y = variation * 234 * 2,
105 | scale = scale * 0.5
106 | }
107 | }
108 | }
109 | }
110 | end
111 |
112 | function unitSpawnerUtils.spawner_die_animation(variation, tint, scale, tint2)
113 | return
114 | {
115 | layers =
116 | {
117 | {
118 | filename = "__base__/graphics/entity/spawner/spawner-die.png",
119 | line_length = 8,
120 | width = 248,
121 | height = 178,
122 | frame_count = 8,
123 | direction_count = 1,
124 | shift = util.by_pixel(2, -2),
125 | y = variation * 178,
126 | tint = tint,
127 | scale = scale,
128 | hr_version =
129 | {
130 | filename = "__base__/graphics/entity/spawner/hr-spawner-die.png",
131 | line_length = 8,
132 | width = 490,
133 | height = 354,
134 | frame_count = 8,
135 | direction_count = 1,
136 | tint = tint,
137 | shift = util.by_pixel(3, -2),
138 | y = variation * 354,
139 | scale = scale * 0.5
140 | }
141 | },
142 | {
143 | filename = "__base__/graphics/entity/spawner/spawner-die-mask.png",
144 | flags = { "mask" },
145 | width = 140,
146 | height = 118,
147 | frame_count = 8,
148 | direction_count = 1,
149 | shift = util.by_pixel(-2, -14),
150 | scale = scale,
151 | line_length = 8,
152 | tint = tint2,
153 | y = variation * 118,
154 | he_version =
155 | {
156 | filename = "__base__/graphics/entity/spawner/hr-spawner-die-mask.png",
157 | flags = { "mask" },
158 | width = 276,
159 | height = 234,
160 | frame_count = 8,
161 | direction_count = 1,
162 | shift = util.by_pixel(-1, -14),
163 | line_length = 8,
164 | tint = tint2,
165 | y = variation * 234,
166 | scale = scale * 0.5
167 | }
168 | }
169 | }
170 | }
171 | end
172 |
173 | return unitSpawnerUtils
174 |
--------------------------------------------------------------------------------
/prototypes/utils/StreamUtils.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 |
17 | local streamUtils = {}
18 |
19 | -- module code
20 |
21 | function streamUtils.makeStream(attributes)
22 | local softSmokeName = "the-soft-smoke-rampant"
23 | local name = attributes.name .. "-stream-rampant"
24 | data:extend(
25 | {
26 | {
27 | type = "stream",
28 | name = name,
29 | flags = {"not-on-map"},
30 | stream_light = {intensity = 1, size = 4},
31 | ground_light = {intensity = 0.8, size = 4},
32 |
33 | smoke_sources =
34 | {
35 | {
36 | name = softSmokeName,
37 | frequency = 0.05, --0.25,
38 | position = {0.0, 0}, -- -0.8},
39 | starting_frame_deviation = 60
40 | }
41 | },
42 | particle_buffer_size = 90,
43 | particle_spawn_interval = 1,
44 | particle_spawn_timeout = attributes.particleTimeout or 6,
45 | particle_vertical_acceleration = attributes.particleVerticalAcceleration or 0.01,
46 | particle_horizontal_speed = attributes.particleHoizontalSpeed or 0.6,
47 | particle_horizontal_speed_deviation = attributes.particleHoizontalSpeedDeviation or 0.0025,
48 | particle_start_alpha = 0.5,
49 | particle_end_alpha = 1,
50 | particle_start_scale = 0.2,
51 | particle_loop_frame_count = 3,
52 | particle_fade_out_threshold = 0.9,
53 | particle_loop_exit_threshold = 0.25,
54 | action = attributes.actions,
55 |
56 | spine_animation =
57 | {
58 | filename = "__base__/graphics/entity/flamethrower-fire-stream/flamethrower-fire-stream-spine.png",
59 | blend_mode = "additive",
60 | tint = attributes.tint2,
61 | line_length = 4,
62 | width = 32,
63 | height = 18,
64 | frame_count = 32,
65 | axially_symmetrical = false,
66 | direction_count = 1,
67 | animation_speed = 2,
68 | shift = {0, 0},
69 | },
70 |
71 | shadow =
72 | {
73 | filename = "__Rampant__/graphics/acid-projectile-purple/acid-projectile-purple-shadow.png",
74 | line_length = 5,
75 | width = 28,
76 | height = 16,
77 | frame_count = 33,
78 | priority = "high",
79 | shift = {-0.09, 0.395}
80 | },
81 |
82 | particle =
83 | {
84 | filename = "__base__/graphics/entity/flamethrower-fire-stream/flamethrower-explosion.png",
85 | priority = "extra-high",
86 | width = 64,
87 | tint = attributes.tint2,
88 | height = 64,
89 | frame_count = 32,
90 | line_length = 8
91 | },
92 | oriented_particle = true,
93 | shadow_scale_enabled = true
94 | }
95 | }
96 | )
97 | return name
98 | end
99 |
100 | function streamUtils.makeAcidStream(info)
101 | local attributes = util.table.deepcopy(info)
102 | local name = attributes.name .. "-acid-stream-rampant"
103 |
104 | local acidStream = {
105 | type = "stream",
106 | name = name,
107 | flags = {"not-on-map"},
108 | --stream_light = {intensity = 1, size = 4},
109 | --ground_light = {intensity = 0.8, size = 4},
110 |
111 | particle_buffer_size = 90,
112 | particle_spawn_timeout = attributes.particleTimeout or 6,
113 | particle_vertical_acceleration = attributes.particleVerticalAcceleration or 0.01,
114 | particle_horizontal_speed = attributes.particleHoizontalSpeed or 0.6,
115 | particle_horizontal_speed_deviation = attributes.particleHoizontalSpeedDeviation or 0.0025,
116 | particle_spawn_interval = 1,
117 | -- particle_spawn_timeout = attributes.particle_spawn_timeout,
118 | -- particle_vertical_acceleration = 0.005 * 0.60 *1.5, --x
119 | -- particle_horizontal_speed = 0.2* 0.75 * 1.5 * 1.5, --x
120 | -- particle_horizontal_speed_deviation = 0.005 * 0.70,
121 | particle_start_alpha = 0.5,
122 | particle_end_alpha = 1,
123 | particle_alpha_per_part = 0.8,
124 | particle_scale_per_part = 0.8,
125 | particle_loop_frame_count = 15,
126 | --particle_fade_out_threshold = 0.95,
127 | particle_fade_out_duration = 2,
128 | particle_loop_exit_threshold = 0.25,
129 | special_neutral_target_damage = {amount = 1, type = "acid"},
130 | initial_action = attributes.actions,
131 | particle = {
132 | filename = "__base__/graphics/entity/acid-projectile/acid-projectile-head.png",
133 | line_length = 5,
134 | width = 22,
135 | height = 84,
136 | frame_count = 15,
137 | shift = util.mul_shift(util.by_pixel(-2, 30), attributes.scale),
138 | tint = attributes.tint2,
139 | priority = "high",
140 | scale = attributes.scale,
141 | animation_speed = 1,
142 | hr_version =
143 | {
144 | filename = "__base__/graphics/entity/acid-projectile/hr-acid-projectile-head.png",
145 | line_length = 5,
146 | width = 42,
147 | height = 164,
148 | frame_count = 15,
149 | shift = util.mul_shift(util.by_pixel(-2, 31), attributes.scale),
150 | tint = attributes.tint2,
151 | priority = "high",
152 | scale = 0.5 * attributes.scale,
153 | animation_speed = 1,
154 | }
155 | },
156 | spine_animation = {
157 | filename = "__base__/graphics/entity/acid-projectile/acid-projectile-tail.png",
158 | line_length = 5,
159 | width = 66,
160 | height = 12,
161 | frame_count = 15,
162 | shift = util.mul_shift(util.by_pixel(0, -2), attributes.scale),
163 | tint = attributes.tint2,
164 | priority = "high",
165 | scale = attributes.scale,
166 | animation_speed = 1,
167 | hr_version =
168 | {
169 | filename = "__base__/graphics/entity/acid-projectile/hr-acid-projectile-tail.png",
170 | line_length = 5,
171 | width = 132,
172 | height = 20,
173 | frame_count = 15,
174 | shift = util.mul_shift(util.by_pixel(0, -1), attributes.scale),
175 | tint = attributes.tint2,
176 | priority = "high",
177 | scale = 0.5 * attributes.scale,
178 | animation_speed = 1,
179 | }
180 | },
181 | shadow = {
182 | filename = "__base__/graphics/entity/acid-projectile/acid-projectile-shadow.png",
183 | line_length = 15,
184 | width = 22,
185 | height = 84,
186 | frame_count = 15,
187 | priority = "high",
188 | shift = util.mul_shift(util.by_pixel(-2, 30), attributes.scale),
189 | draw_as_shadow = true,
190 | scale = attributes.scale,
191 | animation_speed = 1,
192 | hr_version =
193 | {
194 | filename = "__base__/graphics/entity/acid-projectile/hr-acid-projectile-shadow.png",
195 | line_length = 15,
196 | width = 42,
197 | height = 164,
198 | frame_count = 15,
199 | shift = util.mul_shift(util.by_pixel(-2, 31), attributes.scale),
200 | draw_as_shadow = true,
201 | priority = "high",
202 | scale = 0.5 * attributes.scale,
203 | animation_speed = 1,
204 | }
205 | },
206 |
207 | oriented_particle = true,
208 | shadow_scale_enabled = true,
209 | }
210 |
211 | data:extend({
212 | acidStream
213 | })
214 | return name
215 | end
216 |
217 | return streamUtils
218 |
--------------------------------------------------------------------------------
/prototypes/utils/UpdatesVanilla.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 |
17 | local vanillaUpdates = {}
18 |
19 | local biterUtils = require("BiterUtils")
20 |
21 | function vanillaUpdates.useDumbProjectiles()
22 | local turrets = data.raw["turret"];
23 |
24 | local attackType = "projectile"
25 |
26 | turrets["small-worm-turret"]["attack_parameters"] = biterUtils.createRangedAttack(
27 | {
28 | cooldown = 60,
29 | range = 25,
30 | min_range = 5,
31 | turn_range = 1,
32 | attackType = "projectile",
33 | fire_penalty = 0,
34 | damageModifier = 0.9,
35 | effectiveLevel = 1,
36 | scale = 0.8
37 | },
38 | "acid-ball-2-" .. attackType .. "-rampant")
39 |
40 | turrets["medium-worm-turret"]["attack_parameters"] = biterUtils.createRangedAttack(
41 | {
42 | cooldown = 60,
43 | range = 30,
44 | min_range = 3,
45 | turn_range = 1,
46 | attackType = "projectile",
47 | fire_penalty = 0,
48 | damageModifier = 0.87,
49 | effectiveLevel = 3,
50 | scale = 1
51 | },
52 | "acid-ball-3-" .. attackType .. "-rampant")
53 |
54 |
55 | turrets["big-worm-turret"]["attack_parameters"] = biterUtils.createRangedAttack(
56 | {
57 | cooldown = 60,
58 | range = 38,
59 | min_range = 3,
60 | attackType = "projectile",
61 | turn_range = 1,
62 | fire_penalty = 0,
63 | effectiveLevel = 5,
64 | scale = 1.2
65 | },
66 | "acid-ball-4-" .. attackType .. "-rampant")
67 |
68 | turrets["behemoth-worm-turret"]["attack_parameters"] = biterUtils.createRangedAttack(
69 | {
70 | cooldown = 60,
71 | range = 48,
72 | min_range = 3,
73 | attackType = "projectile",
74 | turn_range = 1,
75 | fire_penalty = 0,
76 | effectiveLevel = 7,
77 | scale = 1.5
78 | },
79 | "acid-ball-5-" .. attackType .. "-rampant")
80 |
81 | local units = data.raw["unit"];
82 |
83 | local unit = units["small-spitter"]
84 | unit["attack_parameters"] = biterUtils.createRangedAttack(
85 | {
86 | cooldown = 100,
87 | range = 13,
88 | warmup = 30,
89 | min_range = 3,
90 | turn_range = 1,
91 | attackType = "projectile",
92 | effectiveLevel = 1,
93 | fire_penalty = 15,
94 | scale = biterUtils.findRunScale(unit)
95 | },
96 | "acid-ball-" .. attackType .. "-rampant",
97 | spitterattackanimation(biterUtils.findRunScale(unit),
98 | tint_1_spitter_small,
99 | tint_2_spitter_small))
100 |
101 | unit = units["medium-spitter"]
102 | unit["attack_parameters"] = biterUtils.createRangedAttack(
103 | {
104 | cooldown = 95,
105 | range = 14,
106 | min_range = 3,
107 | attackType = "projectile",
108 | warmup = 30,
109 | turn_range = 1,
110 | effectiveLevel = 3,
111 | fire_penalty = 15,
112 | scale = biterUtils.findRunScale(unit)
113 | },
114 | "acid-ball-1-" .. attackType .. "-rampant",
115 | spitterattackanimation(biterUtils.findRunScale(unit),
116 | tint_1_spitter_medium,
117 | tint_2_spitter_medium))
118 |
119 | unit = units["big-spitter"]
120 | unit["attack_parameters"] = biterUtils.createRangedAttack(
121 | {
122 | cooldown = 90,
123 | range = 15,
124 | min_range = 3,
125 | attackType = "projectile",
126 | warmup = 30,
127 | turn_range = 1,
128 | effectiveLevel = 5,
129 | fire_penalty = 15,
130 | scale = biterUtils.findRunScale(unit)
131 | },
132 | "acid-ball-2-direction-" .. attackType .. "-rampant",
133 | spitterattackanimation(biterUtils.findRunScale(unit),
134 | tint_1_spitter_big,
135 | tint_2_spitter_big))
136 |
137 | unit = units["behemoth-spitter"]
138 | unit["attack_parameters"] = biterUtils.createRangedAttack(
139 | {
140 | cooldown = 90,
141 | range = 16,
142 | min_range = 3,
143 | warmup = 30,
144 | attackType = "projectile",
145 | turn_range = 1,
146 | effectiveLevel = 7,
147 | fire_penalty = 15,
148 | scale = biterUtils.findRunScale(unit)
149 | },
150 | "acid-ball-3-direction-" .. attackType .. "-rampant",
151 | spitterattackanimation(biterUtils.findRunScale(unit),
152 | tint_1_spitter_behemoth,
153 | tint_2_spitter_behemoth))
154 |
155 | unit = units["small-biter"]
156 | unit["attack_parameters"]["ammo_type"]["action"] = {
157 | {
158 | type = "area",
159 | radius = 0.2,
160 | force = "enemy",
161 | ignore_collision_condition = true,
162 | action_delivery =
163 | {
164 | type = "instant",
165 | target_effects =
166 | {
167 | type = "damage",
168 | damage = { amount = 7 * 0.75, type = "physical" }
169 | }
170 | }
171 | },
172 | {
173 | type = "direct",
174 | action_delivery =
175 | {
176 | type = "instant",
177 | target_effects =
178 | {
179 | type = "damage",
180 | damage = { amount = 7 * 0.25, type = "physical" }
181 | }
182 | }
183 | }
184 | }
185 |
186 | unit = units["medium-biter"]
187 | unit["attack_parameters"]["ammo_type"]["action"] = {
188 | {
189 | type = "area",
190 | radius = 0.6,
191 | force = "enemy",
192 | ignore_collision_condition = true,
193 | action_delivery =
194 | {
195 | type = "instant",
196 | target_effects =
197 | {
198 | type = "damage",
199 | damage = { amount = 15 * 0.75, type = "physical" }
200 | }
201 | }
202 | },
203 | {
204 | type = "direct",
205 | action_delivery =
206 | {
207 | type = "instant",
208 | target_effects =
209 | {
210 | type = "damage",
211 | damage = { amount = 15 * 0.25, type = "physical" }
212 | }
213 | }
214 | }
215 | }
216 |
217 | unit = units["big-biter"]
218 | unit["attack_parameters"]["ammo_type"]["action"] = {
219 | {
220 | type = "area",
221 | radius = 0.9,
222 | force = "enemy",
223 | ignore_collision_condition = true,
224 | action_delivery =
225 | {
226 | type = "instant",
227 | target_effects =
228 | {
229 | type = "damage",
230 | damage = { amount = 30 * 0.75, type = "physical" }
231 | }
232 | }
233 | },
234 | {
235 | type = "direct",
236 | action_delivery =
237 | {
238 | type = "instant",
239 | target_effects =
240 | {
241 | type = "damage",
242 | damage = { amount = 30 * 0.25, type = "physical" }
243 | }
244 | }
245 | }
246 | }
247 |
248 | unit = units["behemoth-biter"]
249 | unit["attack_parameters"]["ammo_type"]["action"] = {
250 | {
251 | type = "area",
252 | radius = 1.2,
253 | force = "enemy",
254 | ignore_collision_condition = true,
255 | action_delivery =
256 | {
257 | type = "instant",
258 | target_effects =
259 | {
260 | type = "damage",
261 | damage = { amount = 90 * 0.75, type = "physical" }
262 | }
263 | }
264 | },
265 | {
266 | type = "direct",
267 | action_delivery =
268 | {
269 | type = "instant",
270 | target_effects =
271 | {
272 | type = "damage",
273 | damage = { amount = 90 * 0.25, type = "physical" }
274 | }
275 | }
276 | }
277 | }
278 | end
279 |
280 | return vanillaUpdates
281 |
--------------------------------------------------------------------------------
/visualizer/parseState.rkt:
--------------------------------------------------------------------------------
1 | ;; Copyright (C) 2022 veden
2 |
3 | ;; This program is free software: you can redistribute it and/or modify
4 | ;; it under the terms of the GNU General Public License as published by
5 | ;; the Free Software Foundation, either version 3 of the License, or
6 | ;; (at your option) any later version.
7 |
8 | ;; This program is distributed in the hope that it will be useful,
9 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | ;; GNU General Public License for more details.
12 |
13 | ;; You should have received a copy of the GNU General Public License
14 | ;; along with this program. If not, see .
15 |
16 |
17 | (module AiState racket
18 | (provide (all-defined-out))
19 |
20 | (require math/statistics)
21 |
22 | (struct AiState (chunks
23 | chunksLookup
24 | minMaxes)
25 | #:transparent)
26 |
27 | (struct MinMax (min max)
28 | #:transparent)
29 |
30 | (struct ChunkRange (x
31 | y
32 | movement
33 | base
34 | player
35 | resource
36 | enemy
37 | passable
38 | tick
39 | rating
40 | nests
41 | worms
42 | rally
43 | retreat
44 | resourceGen
45 | playerGen
46 | deathGen
47 | scoreResourceKamikaze
48 | scoreResource
49 | scoreSiegeKamikaze
50 | scoreSiege
51 | scoreAttackKamikaze
52 | scoreAttack
53 | pollution
54 | aNe
55 | aRNe
56 | squads
57 | baseAlign
58 | hives
59 | traps
60 | utility
61 | vg
62 | kamikaze)
63 | #:transparent)
64 |
65 | (struct Chunk (x
66 | y
67 | movement
68 | base
69 | player
70 | resource
71 | enemy
72 | passable
73 | tick
74 | rating
75 | nests
76 | worms
77 | rally
78 | retreat
79 | resourceGen
80 | playerGen
81 | deathGen
82 | scoreResourceKamikaze
83 | scoreResource
84 | scoreSiegeKamikaze
85 | scoreSiege
86 | scoreAttackKamikaze
87 | scoreAttack
88 | pollution
89 | aNe
90 | aRNe
91 | squads
92 | baseAlign
93 | hives
94 | traps
95 | utility
96 | vg
97 | kamikaze)
98 | #:transparent)
99 |
100 | (require threading)
101 |
102 | (define (getFile filePath)
103 | (call-with-input-file filePath
104 | (lambda (port)
105 | (port->string port))))
106 |
107 | (define (stringToChunk str)
108 | (apply Chunk
109 | (map string->number
110 | (string-split str ","))))
111 |
112 | (define (chunk->string chunk)
113 | (string-append "x:" (~v (Chunk-x chunk)) "\n"
114 | "y:" (~v (Chunk-y chunk)) "\n"
115 | "m:" (~v (Chunk-movement chunk)) "\n"
116 | "b:" (~v (Chunk-base chunk)) "\n"
117 | "p:" (~v (Chunk-player chunk)) "\n"
118 | "r:" (~v (Chunk-resource chunk)) "\n"
119 | "e:" (~v (Chunk-enemy chunk)) "\n"
120 | "pa:" (~v (Chunk-passable chunk)) "\n"
121 | "t:" (~v (Chunk-tick chunk)) "\n"
122 | "rat:" (~v (Chunk-rating chunk)) "\n"
123 | "ne:" (~v (Chunk-nests chunk)) "\n"
124 | "wo:" (~v (Chunk-worms chunk)) "\n"))
125 |
126 | (define (chunk->string2 chunk)
127 | (string-append "ral:" (~v (Chunk-rally chunk)) "\n"
128 | "ret:" (~v (Chunk-retreat chunk)) "\n"
129 | "rG:" (~v (Chunk-resourceGen chunk)) "\n"
130 | "pG:" (~v (Chunk-playerGen chunk)) "\n"
131 | "dG:" (~v (Chunk-deathGen chunk)) "\n"
132 | "sA:" (~v (Chunk-scoreAttack chunk)) "\n"
133 | "sAK:" (~v (Chunk-scoreAttackKamikaze chunk)) "\n"
134 | "sS:" (~v (Chunk-scoreSiege chunk)) "\n"
135 | "sSK:" (~v (Chunk-scoreSiegeKamikaze chunk)) "\n"
136 | "sR:" (~v (Chunk-scoreResource chunk)) "\n"))
137 |
138 | (define (chunk->string3 chunk)
139 | (string-append "sRK:" (~v (Chunk-scoreResourceKamikaze chunk)) "\n"
140 | "pu:" (~v (Chunk-pollution chunk)) "\n"
141 | "aN:" (~v (Chunk-aNe chunk)) "\n"
142 | "aRN:" (~v (Chunk-aRNe chunk)) "\n"
143 | "sqs:" (~v (Chunk-squads chunk)) "\n"
144 | "bA:" (~v (Chunk-baseAlign chunk)) "\n"
145 | "H:" (~v (Chunk-hives chunk)) "\n"
146 | "T:" (~v (Chunk-traps chunk)) "\n"
147 | "U:" (~v (Chunk-utility chunk)) "\n"
148 | "vg:" (~v (Chunk-vg chunk)) "\n"
149 | "kam:" (~v (Chunk-kamikaze chunk)) "\n"))
150 |
151 | (define (normalizeRange xs)
152 | (let* ((sDev (stddev xs))
153 | (sMean (mean xs))
154 | (target (* 2.5 sDev))
155 | (cleanXs (filter (lambda (x)
156 | (<= (abs (- x sMean)) target))
157 | xs)))
158 | (MinMax (apply min cleanXs)
159 | (apply max cleanXs))))
160 |
161 | (define (findChunkPropertiesMinMax chunks)
162 | (let ((xs (map Chunk-x chunks))
163 | (ys (map Chunk-y chunks))
164 | (movements (map Chunk-movement chunks))
165 | (bases (map Chunk-base chunks))
166 | (players (map Chunk-player chunks))
167 | (resources (map Chunk-resource chunks))
168 | (enemy (map Chunk-enemy chunks))
169 | (passables (map Chunk-passable chunks))
170 | (ticks (map Chunk-tick chunks))
171 | (ratings (map Chunk-rating chunks))
172 | (nests (map Chunk-nests chunks))
173 | (worms (map Chunk-worms chunks))
174 | (rallys (map Chunk-rally chunks))
175 | (retreats (map Chunk-retreat chunks))
176 | (rGens (map Chunk-resourceGen chunks))
177 | (pGens (map Chunk-playerGen chunks))
178 | (dGens (map Chunk-deathGen chunks))
179 | (sRKs (map Chunk-scoreResourceKamikaze chunks))
180 | (sRs (map Chunk-scoreResource chunks))
181 | (sSKs (map Chunk-scoreSiegeKamikaze chunks))
182 | (sSs (map Chunk-scoreSiege chunks))
183 | (sAKs (map Chunk-scoreAttackKamikaze chunks))
184 | (sAs (map Chunk-scoreAttack chunks))
185 | (pol (map Chunk-pollution chunks))
186 | (aNe (map Chunk-aNe chunks))
187 | (aRNe (map Chunk-aRNe chunks))
188 | (sqs (map Chunk-squads chunks))
189 | (bA (map Chunk-baseAlign chunks))
190 | (H (map Chunk-hives chunks))
191 | (T (map Chunk-traps chunks))
192 | (U (map Chunk-utility chunks))
193 | (vg (map Chunk-vg chunks))
194 | (kamikaze (map Chunk-kamikaze chunks)))
195 |
196 | (ChunkRange (MinMax (apply min xs) (apply max xs))
197 | (MinMax (apply min ys) (apply max ys))
198 | (normalizeRange movements)
199 | (normalizeRange bases)
200 | (normalizeRange players)
201 | (normalizeRange resources)
202 | (normalizeRange enemy)
203 | (MinMax (apply min passables) (apply max passables))
204 | (normalizeRange ticks)
205 | (normalizeRange ratings)
206 | (MinMax (apply min nests) (apply max nests))
207 | (MinMax (apply min worms) (apply max worms))
208 | (MinMax (apply min rallys) (apply max rallys))
209 | (MinMax (apply min retreats) (apply max retreats))
210 | (MinMax (apply min rGens) (apply max rGens))
211 | (MinMax (apply min pGens) (apply max pGens))
212 | (MinMax (apply min dGens) (apply max dGens))
213 | (normalizeRange sRKs)
214 | (normalizeRange sRs)
215 | (normalizeRange sSKs)
216 | (normalizeRange sSs)
217 | (normalizeRange sAKs)
218 | (normalizeRange sAs)
219 | (normalizeRange pol)
220 | (MinMax (apply min aNe) (apply max aNe))
221 | (MinMax (apply min aRNe) (apply max aRNe))
222 | (MinMax (apply min sqs) (apply max sqs))
223 | (MinMax (apply min bA) (apply max bA))
224 | (MinMax (apply min H) (apply max H))
225 | (MinMax (apply min T) (apply max T))
226 | (MinMax (apply min U) (apply max U))
227 | (MinMax (apply min vg) (apply max vg))
228 | (normalizeRange kamikaze)
229 | )))
230 |
231 | (define (readState filePath)
232 | (let* ((replayChunks (getFile filePath))
233 | (chunks (map stringToChunk (string-split replayChunks "\n")))
234 | (minMaxes (findChunkPropertiesMinMax chunks)))
235 | (AiState chunks
236 | (apply hash
237 | (apply append
238 | (map (lambda (chunk)
239 | (list (list (Chunk-x chunk)
240 | (Chunk-y chunk))
241 | chunk))
242 | chunks)))
243 | minMaxes)))
244 |
245 | (define (test)
246 | (AiState-minMaxes (readState "/data/games/factorio/script-output/rampantState.txt"))))
247 |
--------------------------------------------------------------------------------
/prototypes/utils/BeamUtils.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 |
17 | local beamUtils = {}
18 |
19 | local DISALLOW_FRIENDLY_FIRE = settings.startup["rampant--disallowFriendlyFire"].value
20 |
21 | function beamUtils.makeBubble(attributes)
22 | local name = attributes.name .. "-bubble-rampant"
23 | data:extend({{
24 | type = "explosion",
25 | name = name,
26 | flags = {"not-on-map"},
27 | animation_speed = 1,
28 | animations =
29 | {
30 | {
31 | filename = "__base__/graphics/entity/laser-bubble/laser-bubble.png",
32 | priority = "extra-high",
33 | width = 8,
34 | height = 8,
35 | tint = attributes.tint2,
36 | frame_count = 5
37 | }
38 | },
39 | light = {intensity = 1, size = 10, color = attributes.tint2 or {r = 1.0, g = 1.0, b = 1.0}},
40 | smoke = "smoke-fast",
41 | smoke_count = 2,
42 | smoke_slow_down_factor = 1
43 | }})
44 | return name
45 | end
46 |
47 | function beamUtils.makeLaser(attributes)
48 | local name = attributes.name .. "-laser-rampant"
49 | data:extend({{
50 | type = "projectile",
51 | name = name ,
52 | flags = {"not-on-map"},
53 | collision_box = attributes.collisionBox or {{-0.3, -1.1}, {0.3, 1.1}},
54 | acceleration = attributes.acceleration or 0.03,
55 | force_condition = (settings.startup["rampant--disableCollidingProjectiles"].value and "not-same") or nil,
56 | action =
57 | {
58 | type = "direct",
59 | force = (DISALLOW_FRIENDLY_FIRE and "not-same") or nil,
60 | action_delivery =
61 | {
62 | type = "instant",
63 | target_effects =
64 | {
65 | {
66 | type = "create-entity",
67 | entity_name = attributes.attackBubble or "laser-bubble"
68 | },
69 | {
70 | type = "damage",
71 | damage = { amount = attributes.damage or 5, type = attributes.damageType or "laser"}
72 | }
73 | }
74 | }
75 | },
76 | light = {intensity = 0.5, size = 10},
77 | animation =
78 | {
79 | filename = "__base__/graphics/entity/laser/laser-to-tint-medium.png",
80 | tint = attributes.tint2 or {r=1.0, g=0.0, b=0.0},
81 | frame_count = 1,
82 | width = 12,
83 | height = 33,
84 | priority = "high",
85 | blend_mode = "additive"
86 | },
87 | speed = 0.15
88 | }})
89 | return name
90 | end
91 |
92 | function beamUtils.makeBeam(attributes)
93 | local result =
94 | {
95 | type = "beam",
96 | flags = {"not-on-map"},
97 | width = attributes.width or 0.5,
98 | collision_box = attributes.collisionBox or {{-0.3, -1.1}, {0.3, 1.1}},
99 | damage_interval = attributes.damageInterval or 20,
100 | action =
101 | {
102 | type = "direct",
103 | force = (DISALLOW_FRIENDLY_FIRE and "not-same") or nil,
104 | action_delivery =
105 | {
106 | type = "instant",
107 | target_effects =
108 | {
109 | {
110 | type = "damage",
111 | damage = { amount = attributes.damage or 10, type = attributes.damageType or "electric"}
112 | }
113 | }
114 | }
115 | },
116 | start =
117 | {
118 | filename = "__base__/graphics/entity/beam/tileable-beam-START.png",
119 | line_length = 4,
120 | width = 52,
121 | height = 40,
122 | frame_count = 16,
123 | axially_symmetrical = false,
124 | direction_count = 1,
125 | shift = {-0.03125, 0},
126 | hr_version = {
127 | filename = "__base__/graphics/entity/beam/hr-tileable-beam-START.png",
128 | line_length = 4,
129 | width = 94,
130 | height = 66,
131 | frame_count = 16,
132 | axially_symmetrical = false,
133 | direction_count = 1,
134 | shift = {0.53125, 0},
135 | scale = 0.5,
136 | }
137 | },
138 | ending =
139 | {
140 | filename = "__base__/graphics/entity/beam/tileable-beam-END.png",
141 | line_length = 4,
142 | width = 49,
143 | height = 54,
144 | frame_count = 16,
145 | axially_symmetrical = false,
146 | direction_count = 1,
147 | shift = {-0.046875, 0},
148 | hr_version = {
149 | filename = "__base__/graphics/entity/beam/hr-tileable-beam-END.png",
150 | line_length = 4,
151 | width = 91,
152 | height = 93,
153 | frame_count = 16,
154 | axially_symmetrical = false,
155 | direction_count = 1,
156 | shift = {-0.078125, -0.046875},
157 | scale = 0.5,
158 | }
159 | },
160 | head =
161 | {
162 | filename = "__base__/graphics/entity/beam/beam-head.png",
163 | line_length = 16,
164 | width = 45,
165 | height = 39,
166 | frame_count = 16,
167 | animation_speed = 0.5,
168 | blend_mode = "additive-soft",
169 | },
170 | tail =
171 | {
172 | filename = "__base__/graphics/entity/beam/beam-tail.png",
173 | line_length = 16,
174 | width = 45,
175 | height = 39,
176 | frame_count = 16,
177 | blend_mode = "additive-soft",
178 | },
179 | body =
180 | {
181 | {
182 | filename = "__base__/graphics/entity/beam/beam-body-1.png",
183 | line_length = 16,
184 | width = 45,
185 | height = 39,
186 | frame_count = 16,
187 | blend_mode = "additive-soft",
188 | },
189 | {
190 | filename = "__base__/graphics/entity/beam/beam-body-2.png",
191 | line_length = 16,
192 | width = 45,
193 | height = 39,
194 | frame_count = 16,
195 | blend_mode = "additive-soft",
196 | },
197 | {
198 | filename = "__base__/graphics/entity/beam/beam-body-3.png",
199 | line_length = 16,
200 | width = 45,
201 | height = 39,
202 | frame_count = 16,
203 | blend_mode = "additive-soft",
204 | },
205 | {
206 | filename = "__base__/graphics/entity/beam/beam-body-4.png",
207 | line_length = 16,
208 | width = 45,
209 | height = 39,
210 | frame_count = 16,
211 | blend_mode = "additive-soft",
212 | },
213 | {
214 | filename = "__base__/graphics/entity/beam/beam-body-5.png",
215 | line_length = 16,
216 | width = 45,
217 | height = 39,
218 | frame_count = 16,
219 | blend_mode = "additive-soft",
220 | },
221 | {
222 | filename = "__base__/graphics/entity/beam/beam-body-6.png",
223 | line_length = 16,
224 | width = 45,
225 | height = 39,
226 | frame_count = 16,
227 | blend_mode = "additive-soft",
228 | },
229 | }
230 | }
231 |
232 | result.working_sound =
233 | {
234 | {
235 | filename = "__base__/sound/fight/electric-beam.ogg",
236 | volume = 0.7
237 | }
238 | }
239 |
240 | local name = attributes.name .. "-beam-rampant"
241 | result.name = name
242 |
243 | data:extend({result})
244 | return name
245 | end
246 |
247 | return beamUtils
248 |
--------------------------------------------------------------------------------
/prototypes/EnergyThief.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 |
17 |
18 | -- imports
19 |
20 | local thiefUtils = require("utils/ThiefUtils")
21 | local constants = require("libs/Constants")
22 |
23 | -- constants
24 |
25 | local energyThief = {}
26 |
27 | -- imported functions
28 |
29 | local TIERS = constants.TIERS
30 |
31 | local makeDrainCrystal = thiefUtils.makeDrainCrystal
32 |
33 | function energyThief.addFactionAddon()
34 |
35 | data:extend({
36 | {
37 | type = "simple-entity-with-force",
38 | name = "drain-trigger-rampant",
39 | render_layer = "object",
40 | icon = "__base__/graphics/icons/steel-chest.png",
41 | icon_size = 32,
42 | flags = {"placeable-neutral", "player-creation"},
43 | order = "s-e-w-f",
44 | minable = {mining_time = 1, result = "drain-trigger-rampant"},
45 | max_health = 100,
46 | selectable_in_game = false,
47 | corpse = nil,
48 | collision_box = {{-0.35, -0.35}, {0.35, 0.35}},
49 | selection_box = {{-0.5, -0.5}, {0.5, 0.5}},
50 | picture =
51 | {
52 | filename = "__core__/graphics/empty.png",
53 | priority = "extra-high",
54 | width = 1,
55 | height = 1,
56 | shift = {0, 0}
57 | }
58 | },
59 |
60 | {
61 | type = "item",
62 | name = "drain-trigger-rampant",
63 | icon = "__Rampant__/graphics/icons/thief/crystal-drain.png",
64 | icon_size = 32,
65 | icon_mipmaps = 1,
66 | flags = {"hidden"},
67 | subgroup = "energy",
68 | order = "e[accumulator]-a[accumulator]",
69 | place_result = "drain-trigger-rampant",
70 | stack_size = 50
71 | },
72 |
73 | {
74 | type = "item",
75 | name = "crystal-drain-pole-rampant",
76 | icon = "__Rampant__/graphics/icons/thief/crystal-drain.png",
77 | icon_size = 32,
78 | icon_mipmaps = 1,
79 | flags = {"hidden"},
80 | subgroup = "energy",
81 | order = "e[accumulator]-a[accumulator]",
82 | place_result = "crystal-drain-pole-rampant",
83 | stack_size = 50
84 | },
85 |
86 | {
87 | type = "electric-pole",
88 | name = "crystal-drain-pole-rampant",
89 | icon = "__Rampant__/graphics/icons/thief/crystal-drain.png",
90 | icon_size = 32,
91 | icon_mipmaps = 1,
92 | flags = {"hidden"},
93 | selectable_in_game = false,
94 | minable = {hardness = 0.2, mining_time = 0.5, result = "big-electric-pole"},
95 | max_health = 750,
96 | healing_per_tick = 0.02,
97 | corpse = nil,
98 | resistances =
99 | {
100 | {
101 | type = "physical",
102 | percent = 25
103 | },
104 | {
105 | type = "fire",
106 | percent = 85
107 | },
108 | {
109 | type = "electric",
110 | percent = 95
111 | },
112 | {
113 | type = "laser",
114 | percent = 90
115 | }
116 | },
117 | collision_box = {{-0.55, -0.55}, {0.55, 0.55}},
118 | selection_box = {{-0.55, -0.55}, {0.55, 0.55}},
119 | drawing_box = {{-1, -3}, {1, 0.5}},
120 | maximum_wire_distance = 30,
121 | supply_area_distance = 9,
122 | vehicle_impact_sound = { filename = "__base__/sound/car-metal-impact.ogg", volume = 0.65 },
123 | pictures =
124 | {
125 | filename = "__Rampant__/graphics/entities/thief/crystal-drain-pole.png",
126 | priority = "high",
127 | width = 168,
128 | height = 130,
129 | direction_count = 4,
130 | shift = {1.6, -1.4}
131 | },
132 | connection_points =
133 | {
134 | {
135 | shadow =
136 | {
137 | copper = {2.7, 0},
138 | green = {1.8, 0},
139 | red = {3.6, 0}
140 | },
141 | wire =
142 | {
143 | copper = {0, -2.5},
144 | green = {-0.59375, -2.5},
145 | red = {0.625, -2.5}
146 | }
147 | },
148 | {
149 | shadow =
150 | {
151 | copper = {3.1, 0.2},
152 | green = {2.3, -0.3},
153 | red = {3.8, 0.6}
154 | },
155 | wire =
156 | {
157 | copper = {-0.0625, -2.5},
158 | green = {-0.5, -3},
159 | red = {0.34375, -2}
160 | }
161 | },
162 | {
163 | shadow =
164 | {
165 | copper = {2.9, 0.06},
166 | green = {3.0, -0.6},
167 | red = {3.0, 0.8}
168 | },
169 | wire =
170 | {
171 | copper = {-0.09375, -2.5},
172 | green = {-0.09375, -3},
173 | red = {-0.09375, -2}
174 | }
175 | },
176 | {
177 | shadow =
178 | {
179 | copper = {3.1, 0.2},
180 | green = {3.8, -0.3},
181 | red = {2.35, 0.6}
182 | },
183 | wire =
184 | {
185 | copper = {-0.0625, -2.4},
186 | green = {0.375, -2.9},
187 | red = {-0.46875, -2.4}
188 | }
189 | }
190 | },
191 | radius_visualisation_picture =
192 | {
193 | filename = "__base__/graphics/entity/small-electric-pole/electric-pole-radius-visualization.png",
194 | width = 12,
195 | height = 12,
196 | priority = "extra-high-no-scale"
197 | }
198 | }
199 | })
200 |
201 | local chest = util.table.deepcopy(data.raw["radar"]["radar"])
202 | chest.name = "pylon-target-rampant"
203 | chest.icon = "__Rampant__/graphics/icons/thief/crystal-drain.png"
204 | chest.icon_size = 32
205 | chest.corpse = nil
206 | chest.icon_mipmaps = 1
207 | chest.flags = {"not-repairable", "not-on-map", "hidden"}
208 | chest.subgroup = "enemies"
209 | chest.next_upgrade = nil
210 | chest.backer_name = false
211 | chest.rotation_speed = 0
212 | data.raw["simple-entity-with-force"]["drain-trigger-rampant"].dying_explosion = chest.dying_explosion
213 | chest.pictures = {
214 | layers={
215 | {
216 | filename = "__Rampant__/graphics/entities/thief/crystal-drain-pole.png",
217 | priority = "high",
218 | width = 168,
219 | height = 130,
220 | direction_count = 4,
221 | shift = {1.6, -1.4}
222 | }
223 | }
224 | }
225 | chest.max_health = 750
226 | chest.resistances =
227 | {
228 | {
229 | type = "physical",
230 | percent = 25
231 | },
232 | {
233 | type = "fire",
234 | percent = 85
235 | },
236 | {
237 | type = "electric",
238 | percent = 95
239 | },
240 | {
241 | type = "laser",
242 | percent = 90
243 | }
244 | }
245 | chest.energy_usage = "500kW"
246 | -- chest.collision_mask = {}
247 | chest.collision_box = nil
248 | chest.selection_box = {{-0.55, -0.55}, {0.55, 0.55}}
249 | chest.minable.result = "pylon-target-rampant"
250 | chest.working_sound = {
251 | sound = {
252 | {
253 | filename = "__base__/sound/accumulator-working.ogg"
254 | }
255 | },
256 | apparent_volume = 2,
257 | }
258 |
259 | data:extend({
260 | chest,
261 |
262 | {
263 | type = "item",
264 | name = "pylon-target-rampant",
265 | icon = "__Rampant__/graphics/icons/thief/crystal-drain.png",
266 | icon_size = 32,
267 | icon_mipmaps = 1,
268 | flags = {"hidden"},
269 | subgroup = "enemies",
270 | order = "a[items]-h[steel-collector]",
271 | place_result = "pylon-target-rampant",
272 | stack_size = 50
273 | }
274 | })
275 |
276 |
277 | for i=1,TIERS do
278 | local drainCrystalAttributes = {
279 | name = "crystal-v" .. i,
280 | drain = i * 1.3 .. "MW",
281 | scale = (i * 0.1) + 0.5,
282 | health = 400 * i
283 | }
284 |
285 | makeDrainCrystal(drainCrystalAttributes)
286 | end
287 |
288 | end
289 |
290 | return energyThief
291 |
--------------------------------------------------------------------------------
/tests.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 |
17 | local tests = {}
18 |
19 | local constants = require("libs/Constants")
20 | local chunkUtils = require("libs/ChunkUtils")
21 | local chunkPropertyUtils = require("libs/ChunkPropertyUtils")
22 |
23 | function tests.chunkCount()
24 | local count = 0
25 | for _,map in pairs(global.universe.maps) do
26 | count = count + #map.processQueue
27 | end
28 | print(count)
29 | end
30 |
31 | function tests.fillableDirtTest()
32 | local playerPosition = game.players[1].position
33 | local chunkX = math.floor(playerPosition.x * 0.03125) * 32
34 | local chunkY = math.floor(playerPosition.y * 0.03125) * 32
35 | game.get_surface(global.natives.activeSurface).set_tiles({{name="fillableDirt", position={chunkX-1, chunkY-1}},
36 | {name="fillableDirt", position={chunkX, chunkY-1}},
37 | {name="fillableDirt", position={chunkX-1, chunkY}},
38 | {name="fillableDirt", position={chunkX, chunkY}}},
39 | false)
40 | end
41 |
42 | function tests.tunnelTest()
43 | local playerPosition = game.players[1].position
44 | local chunkX = math.floor(playerPosition.x * 0.03125) * 32
45 | local chunkY = math.floor(playerPosition.y * 0.03125) * 32
46 | game.get_surface(global.natives.activeSurface).create_entity({name="tunnel-entrance-rampant", position={chunkX, chunkY}})
47 | end
48 |
49 | function tests.reveal (size)
50 | local pos = game.player.character.position
51 | game.player.force.chart(game.player.surface,
52 | {{x=-size+pos.x, y=-size+pos.y}, {x=size+pos.x, y=size+pos.y}})
53 | end
54 |
55 | function tests.showBaseGrid(time)
56 | local map = global.universe.maps[game.player.surface.index]
57 | local chunks = map.chunkToBase
58 | for chunk in pairs(chunks) do
59 | local count = chunkPropertyUtils.getEnemyStructureCount(map, chunk)
60 | chunkUtils.mapScanEnemyChunk(chunk, map, game.tick)
61 | local newCount = chunkPropertyUtils.getEnemyStructureCount(map, chunk)
62 | if newCount ~= count then
63 | constants.gpsDebug(chunk.x+16,chunk.y+16, "f2:" .. tostring(count) .. "/" .. tostring(newCount))
64 | chunkUtils.colorChunk(chunk, game.player.surface.index, {0.3, 0.1, 0.1, 0.6}, time and tonumber(time))
65 | else
66 | chunkUtils.colorChunk(chunk, game.player.surface.index, nil, time and tonumber(time))
67 | end
68 | end
69 | end
70 |
71 | -- function tests.showMovementGrid()
72 | -- local chunks = global.map.processQueue
73 | -- for i=1,#chunks do
74 | -- local chunk = chunks[i]
75 | -- local color = "concrete"
76 | -- if (chunkPropertyUtils.getPassable(global.map, chunk) == constants.CHUNK_ALL_DIRECTIONS) then
77 | -- color = "hazard-concrete-left"
78 | -- elseif (chunkPropertyUtils.getPassable(global.map, chunk) == constants.CHUNK_NORTH_SOUTH) then
79 | -- color = "concrete"
80 | -- elseif (chunkPropertyUtils.getPassable(global.map, chunk) == constants.CHUNK_EAST_WEST) then
81 | -- color = "stone-path"
82 | -- end
83 | -- chunkUtils.colorChunk(chunk.x, chunk.y, color, game.get_surface(global.natives.activeSurface))
84 | -- end
85 | -- end
86 |
87 | -- function tests.colorResourcePoints()
88 | -- local chunks = global.map.processQueue
89 | -- for i=1,#chunks do
90 | -- local chunk = chunks[i]
91 | -- local color = "concrete"
92 | -- if (chunk[constants.RESOURCE_GENERATOR] ~= 0) and (chunk[constants.NEST_COUNT] ~= 0) then
93 | -- color = "hazard-concrete-left"
94 | -- elseif (chunk[constants.RESOURCE_GENERATOR] ~= 0) then
95 | -- color = "deepwater"
96 | -- elseif (chunk[constants.NEST_COUNT] ~= 0) then
97 | -- color = "stone-path"
98 | -- end
99 | -- chunkUtils.colorChunk(chunk.x, chunk.y, color, game.get_surface(global.natives.activeSurface))
100 | -- end
101 | -- end
102 |
103 | function tests.entityStats(name, d)
104 | local playerPosition = game.players[1].position
105 | local chunkX = math.floor(playerPosition.x * 0.03125) * 32
106 | local chunkY = math.floor(playerPosition.y * 0.03125) * 32
107 | local a = game.get_surface(global.natives.activeSurface).create_entity({name=name, position={chunkX, chunkY}})
108 | if d then
109 | a['direction'] = d
110 | end
111 | print(serpent.dump(a))
112 | a.destroy()
113 | end
114 |
115 | local function lookupIndexFaction(targetFaction)
116 | for i=1,#constants.FACTION_SET do
117 | if constants.FACTION_SET[i].type == targetFaction then
118 | return i
119 | end
120 | end
121 | return 0
122 | end
123 |
124 | local function scoreResourceLocationKamikaze(_, neighborChunk)
125 | local settle = neighborChunk[constants.RESOURCE_PHEROMONE]
126 | return settle
127 | - (neighborChunk[constants.PLAYER_PHEROMONE] * constants.PLAYER_PHEROMONE_MULTIPLER)
128 | - neighborChunk[constants.ENEMY_PHEROMONE]
129 | end
130 |
131 | local function scoreSiegeLocationKamikaze(_, neighborChunk)
132 | local settle = neighborChunk[constants.BASE_PHEROMONE]
133 | + neighborChunk[constants.RESOURCE_PHEROMONE] * 0.5
134 | + (neighborChunk[constants.PLAYER_PHEROMONE] * constants.PLAYER_PHEROMONE_MULTIPLER)
135 | - neighborChunk[constants.ENEMY_PHEROMONE]
136 |
137 | return settle
138 | end
139 |
140 | local function scoreResourceLocation(map, neighborChunk)
141 | local settle = (neighborChunk[constants.RESOURCE_PHEROMONE])
142 | return settle
143 | - (neighborChunk[constants.PLAYER_PHEROMONE] * constants.PLAYER_PHEROMONE_MULTIPLER)
144 | - neighborChunk[constants.ENEMY_PHEROMONE]
145 | end
146 |
147 | local function scoreSiegeLocation(map, neighborChunk)
148 | local settle = neighborChunk[constants.BASE_PHEROMONE]
149 | + neighborChunk[constants.RESOURCE_PHEROMONE] * 0.5
150 | + (neighborChunk[constants.PLAYER_PHEROMONE] * constants.PLAYER_PHEROMONE_MULTIPLER)
151 | - neighborChunk[constants.ENEMY_PHEROMONE]
152 |
153 | return settle
154 | end
155 |
156 | local function scoreAttackLocation(map, neighborChunk)
157 | local damage = neighborChunk[constants.BASE_PHEROMONE] +
158 | (neighborChunk[constants.PLAYER_PHEROMONE] * constants.PLAYER_PHEROMONE_MULTIPLER)
159 | return damage
160 | end
161 |
162 | local function scoreAttackKamikazeLocation(_, neighborChunk)
163 | local damage = neighborChunk[constants.BASE_PHEROMONE] + (neighborChunk[constants.PLAYER_PHEROMONE] * constants.PLAYER_PHEROMONE_MULTIPLER)
164 | return damage
165 | end
166 |
167 | function tests.exportAiState()
168 |
169 | local printState = function ()
170 | local map = global.universe.maps[game.players[1].surface.index]
171 | local chunks = map.processQueue
172 | local s = ""
173 | for i=1,#chunks do
174 | local chunk = chunks[i]
175 |
176 | local base = chunk.base
177 | local alignmentCount = 0
178 |
179 | if base then
180 | if (#base.alignment == 2) then
181 | alignmentCount = (math.abs(base.x) * 10000) + (math.abs(base.y) * 10000) + (lookupIndexFaction(base.alignment[1]) * 100) + lookupIndexFaction(base.alignment[2])
182 | else
183 | alignmentCount = (math.abs(base.x) * 10000) + (math.abs(base.y) * 10000) + lookupIndexFaction(base.alignment[1])
184 | end
185 | end
186 |
187 | s = s .. table.concat({chunk.x,
188 | chunk.y,
189 | chunkPropertyUtils.getCombinedDeathGeneratorRating(chunk),
190 | chunk[constants.BASE_PHEROMONE],
191 | chunk[constants.PLAYER_PHEROMONE],
192 | chunk[constants.RESOURCE_PHEROMONE],
193 | chunk[constants.ENEMY_PHEROMONE],
194 | chunkPropertyUtils.getPassable(chunk),
195 | chunk[constants.CHUNK_TICK],
196 | chunkPropertyUtils.getPathRating(chunk),
197 | chunk.nestCount or 0,
198 | chunk.turretCount or 0,
199 | chunkPropertyUtils.getRallyTick(chunk) or 0,
200 | chunkPropertyUtils.getRetreatTick(chunk) or 0,
201 | chunk.resourceGenerator or 0,
202 | chunk.playerBaseGenerator or 0,
203 | chunkPropertyUtils.getCombinedDeathGenerator(chunk),
204 | scoreResourceLocationKamikaze(map, chunk),
205 | scoreResourceLocation(map, chunk),
206 | scoreSiegeLocationKamikaze(map, chunk),
207 | scoreSiegeLocation(map, chunk),
208 | scoreAttackKamikazeLocation(map, chunk),
209 | scoreAttackLocation(map, chunk),
210 | game.get_surface(game.players[1].surface.index).get_pollution(chunk),
211 | (chunkPropertyUtils.isActiveNest(chunk) and 1) or 0,
212 | (chunkPropertyUtils.isActiveRaidNest(chunk) and 1) or 0,
213 | table_size(chunk.squads or {}),
214 | alignmentCount,
215 | chunk.hiveCount or 0,
216 | chunk.trapCount or 0,
217 | chunk.utilityCount or 0,
218 | global.universe.chunkToVictory[chunk.id] or 0,
219 | chunk[constants.KAMIKAZE_PHEROMONE]
220 | }, ",") .. "\n"
221 | end
222 | game.write_file("rampantState.txt", s, false)
223 | end
224 |
225 | return function(interval)
226 | if not interval then
227 | interval = 0
228 | else
229 | interval = tonumber(interval)
230 | end
231 |
232 | printState()
233 |
234 | if (interval > 0) then
235 | script.on_nth_tick(interval, printState)
236 | end
237 | end
238 | end
239 |
240 | function tests.dumpEnvironment(x)
241 | print (serpent.dump(global[x]))
242 | end
243 |
244 | return tests
245 |
--------------------------------------------------------------------------------
/visualizer/visual.rkt:
--------------------------------------------------------------------------------
1 | ;; Copyright (C) 2022 veden
2 |
3 | ;; This program is free software: you can redistribute it and/or modify
4 | ;; it under the terms of the GNU General Public License as published by
5 | ;; the Free Software Foundation, either version 3 of the License, or
6 | ;; (at your option) any later version.
7 |
8 | ;; This program is distributed in the hope that it will be useful,
9 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | ;; GNU General Public License for more details.
12 |
13 | ;; You should have received a copy of the GNU General Public License
14 | ;; along with this program. If not, see .
15 |
16 | (module AiVisualizer racket
17 | (provide (all-defined-out))
18 |
19 | (require "parseState.rkt")
20 | (provide (all-from-out "parseState.rkt"))
21 | (require racket/gui/base)
22 | (require plot)
23 |
24 | (define CHUNK_SIZE 32)
25 |
26 | (define INVALID_CHUNK (Chunk -1 -1 0 0 0
27 | 0 0 0 0 0
28 | 0 0 0 0 0
29 | 0 0 0 0 0
30 | 0 0 0 0 0
31 | 0 0 0 0 0
32 | 0 0 0))
33 |
34 | (define windowX 500)
35 | (define windowY 0)
36 | (define windowWidth 1024)
37 | (define windowHeight 1024)
38 |
39 | (define activeHighlight null)
40 | (define activeLayer "movement")
41 |
42 | (define (normalize v low high)
43 | (/ (- v low)
44 | (- high low)))
45 |
46 | (define (fromNormalize x low high)
47 | (+ (* (- high low)
48 | x)
49 | low))
50 |
51 | (define (roundTo x digits)
52 | (* (floor (/ x digits))
53 | digits))
54 |
55 | (define (visualize)
56 | (define frameWithEvents% (class frame%
57 | (define/override (on-subwindow-char r event)
58 | (when (eq? (send event get-key-code) #\c)
59 | (exit))
60 | (super on-subwindow-char r event))
61 | (super-new)))
62 |
63 | (define (newFrame width height x y [label ""])
64 | (new frameWithEvents%
65 | [label label]
66 | [width width]
67 | [height height]
68 | [x x]
69 | [y y]))
70 |
71 | (define templates (list '(250 750 0 0 "controls")
72 | (list windowWidth windowHeight windowX windowY "map")))
73 | (define frames (map (lambda (frame)
74 | (match-let (((list width height x y name) frame))
75 | (newFrame width height x y name)))
76 | templates))
77 |
78 | (define mainFrame (first frames))
79 | (define mapFrame (second frames))
80 |
81 | (define activeChunkSet null)
82 | (define activeChunkSetLookup null)
83 | (define activeChunkMinMaxSet null)
84 |
85 | (define topPanel (new panel%
86 | [parent mainFrame]
87 | (alignment '(left top))))
88 |
89 | (define botPanel (new panel%
90 | [parent mainFrame]
91 | (alignment '(right bottom))))
92 |
93 | (define statusBox (new message%
94 | [parent topPanel]
95 | [label (~v "")]
96 | [vert-margin 16]))
97 | (define siteBox (new message%
98 | [parent topPanel]
99 | [label ""]
100 | [vert-margin 30]))
101 | (define siteBox2 (new message%
102 | [parent topPanel]
103 | [label ""]
104 | [horiz-margin 300]))
105 | (define siteBox3 (new message%
106 | [parent topPanel]
107 | [label ""]
108 | [vert-margin 300]))
109 |
110 | (new button%
111 | [parent mainFrame]
112 | [label "Quit"]
113 | (callback (lambda (button event)
114 | (exit))))
115 |
116 | (define tileWidth 0)
117 | (define tileHeight 0)
118 |
119 | (define minX 0)
120 | (define maxX 0)
121 | (define minY 0)
122 | (define maxY 0)
123 |
124 | (define canvasWithEvents% (class canvas%
125 | (define/override (on-event event)
126 | (match (send event get-event-type)
127 | ((== 'motion) (displayChunk (send event get-x) (send event get-y)))
128 | ((== 'left-down) (displayHighlight (send event get-x) (send event get-y)))
129 | ((== 'right-down) (begin (set! activeHighlight null)
130 | (refresh (send this get-dc))))
131 | (t (super on-event event))))
132 | (super-new)))
133 |
134 | (define (refresh dc)
135 | (when (not (null? dc))
136 | (drawFrame dc)))
137 |
138 | (define drawFrame (lambda (context)
139 | null))
140 |
141 | (define canvass (map (lambda (frame)
142 | (let ((c (new canvasWithEvents%
143 | [parent frame]
144 | [paint-callback (lambda (canvas dc)
145 | (drawFrame dc))])))
146 | (send c set-canvas-background (make-object color% 111 111 111))
147 | c))
148 | (cdr frames)))
149 | (define dcs (map (lambda (canvas)
150 | (send canvas get-dc))
151 | canvass))
152 |
153 | (define (showVisual dc aiState)
154 | (let* ((chunkMinMaxes (AiState-minMaxes aiState))
155 | (minMaxX (ChunkRange-x chunkMinMaxes))
156 | (minMaxY (ChunkRange-y chunkMinMaxes)))
157 | (set! activeChunkSet (AiState-chunks aiState))
158 | (set! activeChunkMinMaxSet chunkMinMaxes)
159 | (set! activeChunkSetLookup (AiState-chunksLookup aiState))
160 |
161 | (when (Chunk? activeHighlight)
162 | (set! activeHighlight (findChunk (Chunk-x activeHighlight)
163 | (Chunk-y activeHighlight))))
164 |
165 | (set! minX (MinMax-min minMaxX))
166 | (set! maxX (MinMax-max minMaxX))
167 | (set! minY (MinMax-min minMaxY))
168 | (set! maxY (MinMax-max minMaxY))
169 |
170 | (set! tileWidth (ceiling (/ windowWidth (+ (abs (/ (- maxX minX) CHUNK_SIZE)) 3))))
171 | (set! tileHeight (ceiling (/ windowHeight (+ (abs (/ (- maxY minY) CHUNK_SIZE)) 3))))
172 |
173 | (refresh dc)
174 |
175 | (thread (lambda ()
176 | (sync (filesystem-change-evt "/mnt/gallery/gameFiles/factorio/script-output/rampantState.txt"))
177 | (showVisual dc (readState "/mnt/gallery/gameFiles/factorio/script-output/rampantState.txt"))))))
178 |
179 | (define dcMap (first dcs))
180 |
181 | (showVisual dcMap (readState "/mnt/gallery/gameFiles/factorio/script-output/rampantState.txt"))
182 |
183 | (define (chunkX->screenX x)
184 | (roundTo (* (normalize x minX maxX)
185 | windowWidth)
186 | tileWidth))
187 |
188 | (define (chunkY->screenY y)
189 | (roundTo (* (normalize y minY maxY)
190 | windowHeight)
191 | tileHeight))
192 |
193 | (define (screenX->chunkX x)
194 | (roundTo (fromNormalize (/ x windowWidth)
195 | minX
196 | maxX)
197 | CHUNK_SIZE))
198 |
199 | (define (screenY->chunkY y)
200 | (roundTo (fromNormalize (/ y windowHeight)
201 | minY
202 | maxY)
203 | CHUNK_SIZE))
204 |
205 | (set! drawFrame (lambda (context)
206 | (send context suspend-flush)
207 | (send context clear)
208 | (let ((chunkField (eval (string->symbol (string-append "Chunk-" activeLayer))))
209 | (chunkRangeField (eval (string->symbol (string-append "ChunkRange-" activeLayer)))))
210 | (map (lambda (chunk)
211 | (let ((x (chunkX->screenX (Chunk-x chunk)))
212 | (y (chunkY->screenY (Chunk-y chunk))))
213 | (if (eq? activeHighlight chunk)
214 | (send context set-pen (make-object color% 255 255 255) 1 'solid)
215 | (send context set-pen (make-object color% 0 0 0) 1 'solid))
216 | (define (dcDraw dc property minMax)
217 | (scaleColor dc property (MinMax-min minMax) (MinMax-max minMax))
218 | (send dc draw-rectangle x y tileWidth tileHeight))
219 | (dcDraw context
220 | (chunkField chunk)
221 | (chunkRangeField activeChunkMinMaxSet))))
222 | activeChunkSet))
223 | (send context resume-flush)))
224 |
225 | (define (findChunk x y)
226 | (hash-ref activeChunkSetLookup (list x y) INVALID_CHUNK))
227 |
228 | (define (displayChunk x y)
229 | (let ((chunk (if (Chunk? activeHighlight)
230 | activeHighlight
231 | (findChunk (screenX->chunkX x)
232 | (screenY->chunkY y)))))
233 | (send siteBox set-label
234 | (chunk->string chunk))
235 | (send siteBox2 set-label
236 | (chunk->string2 chunk))
237 | (send siteBox3 set-label
238 | (chunk->string3 chunk))))
239 |
240 | (define (displayHighlight x y)
241 | ;; (display (list (screenX->chunkX x)
242 | ;; (screenY->chunkY y)
243 | ;; x
244 | ;; y))
245 | ;; (display "\n")
246 |
247 | (let ((chunk (findChunk (screenX->chunkX x)
248 | (screenY->chunkY y))))
249 | (set! activeHighlight chunk))
250 | (refresh dcMap))
251 |
252 | (define (normalizeLog x low high)
253 | (if (= (- high low) 0)
254 | 0
255 | (/ (- x low)
256 | (- high low))))
257 |
258 | (define (scaleColor dc value low high)
259 | (let* ((v (normalizeLog value low high))
260 | (r (cond ((= v 0) 0)
261 | ((> 0.75 v) 150)
262 | ((> 0.50 v) 100)
263 | (#t 50)))
264 | (g (inexact->exact (round (* v 255)))))
265 | (send dc
266 | set-brush
267 | (make-object color%
268 | (min (max r 0) 255)
269 | (min (max g 0) 255)
270 | 0)
271 | 'solid)))
272 |
273 |
274 | (new button%
275 | [parent mainFrame]
276 | [label "Retry"]
277 | (callback (lambda (button event)
278 | (showVisual dcMap (readState "/mnt/gallery/gameFiles/factorio/script-output/rampantState.txt")))))
279 |
280 | (new radio-box%
281 | [label "Show Layer"]
282 | [choices (list "movement" "base" "player" "resource" "enemy" "passable" "tick" "rating" "nests" "worms" "rally" "retreat" "resourceGen" "playerGen" "deathGen" "scoreResourceKamikaze" "scoreResource" "scoreSiegeKamikaze" "scoreSiege" "scoreAttackKamikaze" "scoreAttack" "pollution" "aNe" "aRNe" "squads" "baseAlign" "hives" "traps" "utility" "vg" "kamikaze")]
283 | [selection 0]
284 | [parent botPanel]
285 | (callback (lambda (radioButton event)
286 | (set! activeLayer (send radioButton get-item-label (send radioButton get-selection)))
287 | (refresh dcMap))))
288 |
289 | (map (lambda (f)
290 | (send f show #t))
291 | frames)))
292 |
--------------------------------------------------------------------------------
/prototypes/utils/AttackBall.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 |
17 | -- import
18 |
19 | local fireUtils = require("FireUtils")
20 | local stickerUtils = require("StickerUtils")
21 | local streamUtils = require("StreamUtils")
22 | local projectileUtils = require("ProjectileUtils")
23 |
24 | -- constants
25 |
26 | local DISALLOW_FRIENDLY_FIRE = settings.startup["rampant--disallowFriendlyFire"].value
27 |
28 | -- imported functions
29 |
30 | local makeStream = streamUtils.makeStream
31 | local makeSticker = stickerUtils.makeSticker
32 | local makeProjectile = projectileUtils.makeProjectile
33 | local makeAcidSplashFire = fireUtils.makeAcidSplashFire
34 | local makeFire = fireUtils.makeFire
35 | local makeSpreadEffect = fireUtils.makeSpreadEffect
36 |
37 | -- dumb acid projectiles
38 | local AttackBall = {}
39 |
40 | function AttackBall.createAttackBall(attributes)
41 |
42 | local templateAOEDamage = { amount = attributes.damage * 0.75, type = attributes.damageType or "acid" }
43 | local templateDirectDamage = { amount = attributes.damage * 0.25, type = attributes.damageType or "acid" }
44 | local templateArea = {
45 | type = "area",
46 | radius = attributes.radius,
47 | force = (DISALLOW_FRIENDLY_FIRE and "not-same") or attributes.force or nil,
48 | ignore_collision_condition = true,
49 | action_delivery = (attributes.areaActionDelivery and attributes.areaActionDelivery(attributes)) or
50 | {
51 | {
52 | type = "instant",
53 | target_effects = (attributes.areaEffects and attributes.areaEffects(attributes)) or
54 | {
55 | {
56 | type = "damage",
57 | damage = templateAOEDamage
58 | }
59 | }
60 | }
61 | }
62 | }
63 |
64 | local targetEffects
65 | if attributes.attackPointEffects then
66 | targetEffects = (attributes.attackPointEffects and attributes.attackPointEffects(attributes))
67 | else
68 | local rec = {
69 | {
70 | type = "damage",
71 | damage = templateDirectDamage
72 | },
73 | {
74 | type = "create-entity",
75 | entity_name = "water-splash",
76 | tile_collision_mask = { "ground-tile" }
77 | },
78 | {
79 | type = "play-sound",
80 | sound =
81 | {
82 | {
83 | filename = "__base__/sound/creatures/projectile-acid-burn-1.ogg",
84 | volume = 0.25 + (attributes.effectiveLevel * 0.05)
85 | },
86 | {
87 | filename = "__base__/sound/creatures/projectile-acid-burn-2.ogg",
88 | volume = 0.25 + (attributes.effectiveLevel * 0.05)
89 | },
90 | {
91 | filename = "__base__/sound/creatures/projectile-acid-burn-long-1.ogg",
92 | volume = 0.25 + (attributes.effectiveLevel * 0.05)
93 | },
94 | {
95 | filename = "__base__/sound/creatures/projectile-acid-burn-long-2.ogg",
96 | volume = 0.25 + (attributes.effectiveLevel * 0.05)
97 | }
98 | }
99 | }
100 | }
101 | if not attributes.noAcidPuddle then
102 | rec[#rec+1] = {
103 | type="create-fire",
104 | entity_name = makeAcidSplashFire(attributes, attributes.stickerName or makeSticker(attributes)),
105 | check_buildability = true,
106 | initial_ground_flame_count = 1,
107 | show_in_tooltip = true
108 | }
109 | end
110 | targetEffects = rec
111 | end
112 |
113 | local templateActions = {
114 | templateArea,
115 | {
116 | type = "direct",
117 | force = (DISALLOW_FRIENDLY_FIRE and "not-same") or nil,
118 | action_delivery = {
119 | type = "instant",
120 | target_effects = targetEffects
121 | }
122 | }
123 | }
124 |
125 | local name
126 | if (attributes.attackType == "stream") then
127 | attributes.actions = templateActions
128 | name = makeStream(attributes)
129 | else
130 | name = makeProjectile(attributes, templateActions)
131 | end
132 |
133 | return name
134 | end
135 |
136 | function AttackBall.createSpitFire(attributes)
137 | local spawnEntityName = makeSpreadEffect({
138 | name = attributes.name,
139 | tint2 = attributes.tint2,
140 | fireDamagePerTick = attributes.fireDamagePerTick,
141 | fireDamagePerTickType = attributes.fireDamagePerTickType,
142 | })
143 | local stickerName = makeSticker({
144 | name = attributes.name,
145 | spawnEntityName = spawnEntityName,
146 | stickerDuration = attributes.stickerDuration,
147 | stickerDamagePerTick = attributes.stickerDamagePerTick,
148 | stickerDamagePerTickType = attributes.stickerDamagePerTickType,
149 | stickerMovementModifier = attributes.stickerMovementModifier,
150 | tint2 = attributes.tint2,
151 | fireSpreadRadius = attributes.fireSpreadRadius
152 | })
153 | local fireName = makeFire({
154 | name = attributes.name,
155 | tint2 = attributes.tint2 or {r=0, g=0.9, b=0, a=0.5},
156 | spawnEntityName = spawnEntityName,
157 | fireDamagePerTick = attributes.fireDamagePerTick,
158 | fireDamagePerTickType = attributes.fireDamagePerTickType,
159 | damageMaxMultipler = attributes.damageMaxMultipler,
160 | multiplerIncrease = attributes.multiplerIncrease,
161 | multiplerDecrease = attributes.multiplerDecrease,
162 | stickerName = stickerName
163 | })
164 |
165 | return makeProjectile(attributes,
166 | {
167 | {
168 | type = "area",
169 | radius = attributes.radius or 2.5,
170 | force = "not-same",
171 | action_delivery =
172 | {
173 | type = "instant",
174 | target_effects =
175 | {
176 | {
177 | type = "create-sticker",
178 | sticker = stickerName,
179 | check_buildability = true
180 | },
181 | {
182 | type = "create-entity",
183 | entity_name = "water-splash",
184 | tile_collision_mask = { "ground-tile" }
185 | },
186 | {
187 | type = "damage",
188 | damage = { amount = attributes.damage, type = attributes.damageType or "fire" }
189 | }
190 | }
191 | }
192 | },
193 | {
194 | type = "cluster",
195 | cluster_count = 2,
196 | distance = 2 + (0.1 * attributes.effectiveLevel),
197 | distance_deviation = 1.5,
198 | action_delivery = {
199 | type = "instant",
200 | target_effects = {
201 | {
202 | type="create-fire",
203 | entity_name = fireName,
204 | check_buildability = true,
205 | initial_ground_flame_count = 2,
206 | show_in_tooltip = true
207 | }
208 | }
209 | }
210 | },
211 | {
212 | type = "direct",
213 | action_delivery = {
214 | type = "instant",
215 | target_effects = {
216 | type= "create-fire",
217 | entity_name = fireName,
218 | check_buildability = true,
219 | show_in_tooltip = true
220 | }
221 | }
222 | }
223 | }
224 | )
225 | end
226 |
227 | function AttackBall.generateVanilla()
228 | AttackBall.createAttackBall({name="acid-ball", scale=0.5, directionOnly=true, attackType="projectile", tint2={r=0, g=1, b=0.3, a=0.5}, damage=4, damagePerTick=0.1, stickerName="acid-sticker-small", radius=1.2, effectiveLevel=1})
229 | AttackBall.createAttackBall({name="acid-ball-1", scale=0.65, directionOnly=true, attackType="projectile", tint2={r=0, g=1, b=0.3, a=0.5}, damage=7.5, damagePerTick=0.2, stickerName="acid-sticker-medium", radius=1.3, effectiveLevel=3})
230 |
231 | AttackBall.createAttackBall({name="acid-ball-2-direction", scale=0.85, directionOnly=true, attackType="projectile", tint2={r=0, g=1, b=0.3, a=0.5}, damage=11.25, damagePerTick=0.03, stickerName="acid-sticker-big", radius=1.4, effectiveLevel=5})
232 | AttackBall.createAttackBall({name="acid-ball-3-direction", scale=1.0, directionOnly=true, attackType="projectile", tint2={r=0, g=1, b=0.3, a=0.5}, damage=15, damagePerTick=0.55, stickerName="acid-sticker-behemoth", radius=1.5, effectiveLevel=7})
233 |
234 | AttackBall.createAttackBall({name="acid-ball-2", scale=0.85, attackType="projectile", tint2={r=0, g=1, b=0.3, a=0.5}, damage=11.25, damagePerTick=0.2, stickerName="acid-sticker-small", radius=1.4, effectiveLevel=3})
235 | AttackBall.createAttackBall({name="acid-ball-3", scale=1.0, attackType="projectile", tint2={r=0, g=1, b=0.3, a=0.5}, damage=15, damagePerTick=0.5, stickerName="acid-sticker-medium", radius=1.5, effectiveLevel=5})
236 | AttackBall.createAttackBall({name="acid-ball-4", scale=1.2, attackType="projectile", tint2={r=0, g=1, b=0.3, a=0.5}, damage=22.5, damagePerTick=0.75, stickerName="acid-sticker-big", radius=1.75, effectiveLevel=7})
237 | AttackBall.createAttackBall({name="acid-ball-5", scale=1.3, attackType="projectile", tint2={r=0, g=1, b=0.3, a=0.5}, damage=32.5, damagePerTick=1, stickerName="acid-sticker-behemoth", radius=2, effectiveLevel=8})
238 | end
239 |
240 | return AttackBall
241 |
--------------------------------------------------------------------------------
/prototypes/utils/ImageUtils.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 |
17 | local imageUtils = {}
18 |
19 | -- module code
20 |
21 | local function foreach(table_, fun_)
22 | for _, tab in pairs(table_) do fun_(tab) end
23 | return table_
24 | end
25 |
26 | function imageUtils.create_burnt_patch_pictures(attributes)
27 | local base = {
28 | filename = "__base__/graphics/entity/fire-flame/burnt-patch.png",
29 | line_length = 3,
30 | width = 115,
31 | height = 56,
32 | frame_count = 9,
33 | axially_symmetrical = false,
34 | tint = attributes.tint2,
35 | direction_count = 1,
36 | shift = {-0.09375, 0.125},
37 | }
38 |
39 | local variations = {}
40 |
41 | for y=1,(base.frame_count / base.line_length) do
42 | for x=1,base.line_length do
43 | table.insert(variations,
44 | {
45 | filename = base.filename,
46 | width = base.width,
47 | height = base.height,
48 | tint = base.tint,
49 | shift = base.shift,
50 | x = (x-1) * base.width,
51 | y = (y-1) * base.height,
52 | })
53 | end
54 | end
55 |
56 | return variations
57 | end
58 |
59 |
60 | function imageUtils.create_small_tree_flame_animations(opts)
61 | local fire_blend_mode = opts.blend_mode or "additive"
62 | local fire_animation_speed = opts.animation_speed or 0.5
63 | local fire_scale = opts.scale or 1
64 | local fire_tint = opts.tint2
65 | local fire_flags = { "compressed" }
66 | local retval = {
67 | {
68 | filename = "__base__/graphics/entity/fire-flame/tree-fire-flame-01-a.png",
69 | line_length = 8,
70 | width = 38,
71 | height = 110,
72 | frame_count = 32,
73 | axially_symmetrical = false,
74 | direction_count = 1,
75 | shift = {-0.03125, -1.5},
76 | blend_mode = fire_blend_mode,
77 | animation_speed = fire_animation_speed,
78 | scale = fire_scale,
79 | tint = fire_tint,
80 | flags = fire_flags
81 | },
82 | {
83 | filename = "__base__/graphics/entity/fire-flame/tree-fire-flame-01-b.png",
84 | line_length = 8,
85 | width = 39,
86 | height = 111,
87 | frame_count = 32,
88 | axially_symmetrical = false,
89 | direction_count = 1,
90 | shift = {-0.078125, -1.51562},
91 | blend_mode = fire_blend_mode,
92 | animation_speed = fire_animation_speed,
93 | scale = fire_scale,
94 | tint = fire_tint,
95 | flags = fire_flags
96 | },
97 | {
98 | filename = "__base__/graphics/entity/fire-flame/tree-fire-flame-01-c.png",
99 | line_length = 8,
100 | width = 44,
101 | height = 108,
102 | frame_count = 32,
103 | axially_symmetrical = false,
104 | direction_count = 1,
105 | shift = {-0.15625, -1.5},
106 | blend_mode = fire_blend_mode,
107 | animation_speed = fire_animation_speed,
108 | scale = fire_scale,
109 | tint = fire_tint,
110 | flags = fire_flags
111 | },
112 | {
113 | filename = "__base__/graphics/entity/fire-flame/tree-fire-flame-03-a.png",
114 | line_length = 8,
115 | width = 38,
116 | height = 110,
117 | frame_count = 23,
118 | axially_symmetrical = false,
119 | direction_count = 1,
120 | shift = {-0.03125, -1.5},
121 | blend_mode = fire_blend_mode,
122 | animation_speed = fire_animation_speed,
123 | scale = fire_scale,
124 | tint = fire_tint,
125 | flags = fire_flags
126 | },
127 | {
128 | filename = "__base__/graphics/entity/fire-flame/tree-fire-flame-03-b.png",
129 | line_length = 8,
130 | width = 34,
131 | height = 98,
132 | frame_count = 23,
133 | axially_symmetrical = false,
134 | direction_count = 1,
135 | shift = {-0.03125, -1.34375},
136 | blend_mode = fire_blend_mode,
137 | animation_speed = fire_animation_speed,
138 | scale = fire_scale,
139 | tint = fire_tint,
140 | flags = fire_flags
141 | },
142 | {
143 | filename = "__base__/graphics/entity/fire-flame/tree-fire-flame-03-c.png",
144 | line_length = 8,
145 | width = 39,
146 | height = 111,
147 | frame_count = 23,
148 | axially_symmetrical = false,
149 | direction_count = 1,
150 | shift = {-0.078125, -1.51562},
151 | blend_mode = fire_blend_mode,
152 | animation_speed = fire_animation_speed,
153 | scale = fire_scale,
154 | tint = fire_tint,
155 | flags = fire_flags
156 | }
157 | }
158 |
159 | return foreach(retval, function(tab)
160 | if tab.shift and tab.scale then tab.shift = { tab.shift[1] * tab.scale, tab.shift[2] * tab.scale } end
161 | end)
162 | end
163 |
164 | function imageUtils.create_fire_pictures(opts)
165 | local fire_blend_mode = opts.blend_mode or "additive"
166 | local fire_animation_speed = opts.animation_speed or 0.5
167 | local fire_scale = opts.scale or 1
168 | local fire_tint = opts.tint2
169 | local fire_flags = { "compressed" }
170 | local retval = {
171 | {
172 | filename = "__base__/graphics/entity/fire-flame/fire-flame-13.png",
173 | line_length = 8,
174 | width = 60,
175 | height = 118,
176 | frame_count = 25,
177 | axially_symmetrical = false,
178 | direction_count = 1,
179 | blend_mode = fire_blend_mode,
180 | animation_speed = fire_animation_speed,
181 | scale = fire_scale,
182 | tint = fire_tint,
183 | flags = fire_flags,
184 | shift = { -0.0390625, -0.90625 }
185 | },
186 | {
187 | filename = "__base__/graphics/entity/fire-flame/fire-flame-12.png",
188 | line_length = 8,
189 | width = 63,
190 | height = 116,
191 | frame_count = 25,
192 | axially_symmetrical = false,
193 | direction_count = 1,
194 | blend_mode = fire_blend_mode,
195 | animation_speed = fire_animation_speed,
196 | scale = fire_scale,
197 | tint = fire_tint,
198 | flags = fire_flags,
199 | shift = { -0.015625, -0.914065 }
200 | },
201 | {
202 | filename = "__base__/graphics/entity/fire-flame/fire-flame-11.png",
203 | line_length = 8,
204 | width = 61,
205 | height = 122,
206 | frame_count = 25,
207 | axially_symmetrical = false,
208 | direction_count = 1,
209 | blend_mode = fire_blend_mode,
210 | animation_speed = fire_animation_speed,
211 | scale = fire_scale,
212 | tint = fire_tint,
213 | flags = fire_flags,
214 | shift = { -0.0078125, -0.90625 }
215 | },
216 | {
217 | filename = "__base__/graphics/entity/fire-flame/fire-flame-10.png",
218 | line_length = 8,
219 | width = 65,
220 | height = 108,
221 | frame_count = 25,
222 | axially_symmetrical = false,
223 | direction_count = 1,
224 | blend_mode = fire_blend_mode,
225 | animation_speed = fire_animation_speed,
226 | scale = fire_scale,
227 | tint = fire_tint,
228 | flags = fire_flags,
229 | shift = { -0.0625, -0.64844 }
230 | },
231 | {
232 | filename = "__base__/graphics/entity/fire-flame/fire-flame-09.png",
233 | line_length = 8,
234 | width = 64,
235 | height = 101,
236 | frame_count = 25,
237 | axially_symmetrical = false,
238 | direction_count = 1,
239 | blend_mode = fire_blend_mode,
240 | animation_speed = fire_animation_speed,
241 | scale = fire_scale,
242 | tint = fire_tint,
243 | flags = fire_flags,
244 | shift = { -0.03125, -0.695315 }
245 | },
246 | {
247 | filename = "__base__/graphics/entity/fire-flame/fire-flame-08.png",
248 | line_length = 8,
249 | width = 50,
250 | height = 98,
251 | frame_count = 32,
252 | axially_symmetrical = false,
253 | direction_count = 1,
254 | blend_mode = fire_blend_mode,
255 | animation_speed = fire_animation_speed,
256 | scale = fire_scale,
257 | tint = fire_tint,
258 | flags = fire_flags,
259 | shift = { -0.0546875, -0.77344 }
260 | },
261 | {
262 | filename = "__base__/graphics/entity/fire-flame/fire-flame-07.png",
263 | line_length = 8,
264 | width = 54,
265 | height = 84,
266 | frame_count = 32,
267 | axially_symmetrical = false,
268 | direction_count = 1,
269 | blend_mode = fire_blend_mode,
270 | animation_speed = fire_animation_speed,
271 | scale = fire_scale,
272 | tint = fire_tint,
273 | flags = fire_flags,
274 | shift = { 0.015625, -0.640625 }
275 | },
276 | {
277 | filename = "__base__/graphics/entity/fire-flame/fire-flame-06.png",
278 | line_length = 8,
279 | width = 65,
280 | height = 92,
281 | frame_count = 32,
282 | axially_symmetrical = false,
283 | direction_count = 1,
284 | blend_mode = fire_blend_mode,
285 | animation_speed = fire_animation_speed,
286 | scale = fire_scale,
287 | tint = fire_tint,
288 | flags = fire_flags,
289 | shift = { 0, -0.83594 }
290 | },
291 | {
292 | filename = "__base__/graphics/entity/fire-flame/fire-flame-05.png",
293 | line_length = 8,
294 | width = 59,
295 | height = 103,
296 | frame_count = 32,
297 | axially_symmetrical = false,
298 | direction_count = 1,
299 | blend_mode = fire_blend_mode,
300 | animation_speed = fire_animation_speed,
301 | scale = fire_scale,
302 | tint = fire_tint,
303 | flags = fire_flags,
304 | shift = { 0.03125, -0.882815 }
305 | },
306 | {
307 | filename = "__base__/graphics/entity/fire-flame/fire-flame-04.png",
308 | line_length = 8,
309 | width = 67,
310 | height = 130,
311 | frame_count = 32,
312 | axially_symmetrical = false,
313 | direction_count = 1,
314 | blend_mode = fire_blend_mode,
315 | animation_speed = fire_animation_speed,
316 | scale = fire_scale,
317 | tint = fire_tint,
318 | flags = fire_flags,
319 | shift = { 0.015625, -1.109375 }
320 | },
321 | {
322 | filename = "__base__/graphics/entity/fire-flame/fire-flame-03.png",
323 | line_length = 8,
324 | width = 74,
325 | height = 117,
326 | frame_count = 32,
327 | axially_symmetrical = false,
328 | direction_count = 1,
329 | blend_mode = fire_blend_mode,
330 | animation_speed = fire_animation_speed,
331 | scale = fire_scale,
332 | tint = fire_tint,
333 | flags = fire_flags,
334 | shift = { 0.046875, -0.984375 }
335 | },
336 | {
337 | filename = "__base__/graphics/entity/fire-flame/fire-flame-02.png",
338 | line_length = 8,
339 | width = 74,
340 | height = 114,
341 | frame_count = 32,
342 | axially_symmetrical = false,
343 | direction_count = 1,
344 | blend_mode = fire_blend_mode,
345 | animation_speed = fire_animation_speed,
346 | scale = fire_scale,
347 | tint = fire_tint,
348 | flags = fire_flags,
349 | shift = { 0.0078125, -0.96875 }
350 | },
351 | {
352 | filename = "__base__/graphics/entity/fire-flame/fire-flame-01.png",
353 | line_length = 8,
354 | width = 66,
355 | height = 119,
356 | frame_count = 32,
357 | axially_symmetrical = false,
358 | direction_count = 1,
359 | blend_mode = fire_blend_mode,
360 | animation_speed = fire_animation_speed,
361 | scale = fire_scale,
362 | tint = fire_tint,
363 | flags = fire_flags,
364 | shift = { -0.0703125, -1.039065 }
365 | },
366 | }
367 | return foreach(retval, function(tab)
368 | if tab.shift and tab.scale then tab.shift = { tab.shift[1] * tab.scale, tab.shift[2] * tab.scale } end
369 | end)
370 | end
371 |
372 | return imageUtils
373 |
--------------------------------------------------------------------------------
/prototypes/utils/DroneUtils.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2022 veden
2 |
3 | -- This program is free software: you can redistribute it and/or modify
4 | -- it under the terms of the GNU General Public License as published by
5 | -- the Free Software Foundation, either version 3 of the License, or
6 | -- (at your option) any later version.
7 |
8 | -- This program is distributed in the hope that it will be useful,
9 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | -- GNU General Public License for more details.
12 |
13 | -- You should have received a copy of the GNU General Public License
14 | -- along with this program. If not, see .
15 |
16 | local biterUtils = require("BiterUtils")
17 | local util = require ("util")
18 |
19 | local droneUtils = {}
20 |
21 | local DISALLOW_FRIENDLY_FIRE = settings.startup["rampant--disallowFriendlyFire"].value
22 |
23 | function droneUtils.makeDrone(attributes)
24 | local n = attributes.name .. "-drone-rampant"
25 | local resistances = {}
26 | for k,v in pairs(attributes.resistances) do
27 | v.type = k
28 | resistances[#resistances+1] = v
29 | end
30 | -- attributes.name = name
31 |
32 | local drone = {
33 | type = "combat-robot",
34 | name = n,
35 | localised_name = biterUtils.getLocalisedName(attributes),
36 | icon = "__base__/graphics/icons/defender.png",
37 | icon_size = 32,
38 | flags = attributes.flags or {"placeable-off-grid", "not-on-map", "not-repairable", "breaths-air", "hidden"},
39 | subgroup="capsule",
40 | order="e-a-a",
41 | max_health = attributes.health or 60,
42 | healing_per_tick = attributes.healing,
43 | alert_when_damaged = false,
44 | collision_box = {{0, 0}, {0, 0}},
45 | collision_mask = {RampantGlobalVariables.projectileCollisionLayer},
46 | selection_box = {{-0.5, -1.5}, {0.5, -0.5}},
47 | distance_per_frame = attributes.distancePerFrame or 0,
48 | time_to_live = attributes.ttl or (60 * 45),
49 | follows_player = attributes.followsPlayer,
50 | friction = attributes.friction or 0.01,
51 | range_from_player = attributes.rangeFromPlayer or 6.0,
52 | speed = attributes.movement or 0,
53 | destroy_action = attributes.death,
54 | attack_parameters = attributes.attack,
55 | idle =
56 | {
57 | layers =
58 | {
59 | {
60 | filename = "__base__/graphics/entity/defender-robot/defender-robot.png",
61 | priority = "high",
62 | line_length = 16,
63 | width = 32,
64 | tint = attributes.tint2,
65 | height = 33,
66 | frame_count = 1,
67 | direction_count = 16,
68 | shift = {0, 0.015625},
69 | scale = attributes.scale,
70 | hr_version = {
71 | filename = "__base__/graphics/entity/defender-robot/hr-defender-robot.png",
72 | priority = "high",
73 | line_length = 16,
74 | width = 56,
75 | height = 59,
76 | tint = attributes.tint2,
77 | frame_count = 1,
78 | direction_count = 16,
79 | shift = util.by_pixel(0, 0.25),
80 | scale = attributes.scale * 0.5
81 | }
82 | },
83 | {
84 | filename = "__base__/graphics/entity/defender-robot/defender-robot-mask.png",
85 | priority = "high",
86 | line_length = 16,
87 | width = 18,
88 | height = 16,
89 | tint = attributes.tint2,
90 | frame_count = 1,
91 | direction_count = 16,
92 | shift = {0, -0.125},
93 | -- apply_runtime_tint = true,
94 | scale = attributes.scale,
95 | hr_version = {
96 | filename = "__base__/graphics/entity/defender-robot/hr-defender-robot-mask.png",
97 | priority = "high",
98 | line_length = 16,
99 | width = 28,
100 | height = 21,
101 | tint = attributes.tint2,
102 | frame_count = 1,
103 | direction_count = 16,
104 | shift = util.by_pixel(0, -4.75),
105 | -- apply_runtime_tint = true,
106 | scale = attributes.scale * 0.5
107 | }
108 | },
109 | }
110 | },
111 | shadow_idle =
112 | {
113 | filename = "__base__/graphics/entity/defender-robot/defender-robot-shadow.png",
114 | priority = "high",
115 | line_length = 16,
116 | width = 43,
117 | height = 23,
118 | frame_count = 1,
119 | direction_count = 16,
120 | shift = {0.859375, 0.609375},
121 | scale = attributes.scale,
122 | hr_version = {
123 | filename = "__base__/graphics/entity/defender-robot/hr-defender-robot-shadow.png",
124 | priority = "high",
125 | line_length = 16,
126 | width = 88,
127 | height = 50,
128 | frame_count = 1,
129 | direction_count = 16,
130 | shift = util.by_pixel(25.5, 19),
131 | scale = attributes.scale * 0.5
132 | }
133 | },
134 | in_motion =
135 | {
136 | layers =
137 | {
138 | {
139 | filename = "__base__/graphics/entity/defender-robot/defender-robot.png",
140 | priority = "high",
141 | line_length = 16,
142 | width = 32,
143 | tint = attributes.tint,
144 | height = 33,
145 | frame_count = 1,
146 | direction_count = 16,
147 | shift = {0, 0.015625},
148 | y = 33,
149 | scale = attributes.scale,
150 | hr_version = {
151 | filename = "__base__/graphics/entity/defender-robot/hr-defender-robot.png",
152 | priority = "high",
153 | line_length = 16,
154 | width = 56,
155 | tint = attributes.tint,
156 | height = 59,
157 | frame_count = 1,
158 | direction_count = 16,
159 | shift = util.by_pixel(0, 0.25),
160 | y = 59,
161 | scale = attributes.scale * 0.5
162 | }
163 | },
164 | {
165 | filename = "__base__/graphics/entity/defender-robot/defender-robot-mask.png",
166 | priority = "high",
167 | line_length = 16,
168 | width = 18,
169 | height = 16,
170 | frame_count = 1,
171 | direction_count = 16,
172 | tint = attributes.tint2,
173 | shift = {0, -0.125},
174 | y = 16,
175 | scale = attributes.scale,
176 | hr_version = {
177 | filename = "__base__/graphics/entity/defender-robot/hr-defender-robot-mask.png",
178 | priority = "high",
179 | line_length = 16,
180 | width = 28,
181 | height = 21,
182 | frame_count = 1,
183 | direction_count = 16,
184 | tint = attributes.tint2,
185 | shift = util.by_pixel(0, -4.75),
186 | y = 21,
187 | scale = attributes.scale * 0.5
188 | }
189 | },
190 | }
191 | },
192 | shadow_in_motion =
193 | {
194 | filename = "__base__/graphics/entity/defender-robot/defender-robot-shadow.png",
195 | priority = "high",
196 | line_length = 16,
197 | width = 43,
198 | height = 23,
199 | frame_count = 1,
200 | direction_count = 16,
201 | shift = {0.859375, 0.609375},
202 | scale = attributes.scale,
203 | hr_version = {
204 | filename = "__base__/graphics/entity/defender-robot/hr-defender-robot-shadow.png",
205 | priority = "high",
206 | line_length = 16,
207 | width = 88,
208 | height = 50,
209 | frame_count = 1,
210 | direction_count = 16,
211 | shift = util.by_pixel(25.5, 19),
212 | scale = attributes.scale * 0.5
213 | }
214 | }
215 | }
216 | if attributes.appendFlags then
217 | for flag in pairs(attributes.appendFlags) do
218 | drone.flags[#drone.flags+1] = flag
219 | end
220 | end
221 | return drone
222 | end
223 |
224 | function droneUtils.createCapsuleProjectile(attributes, entityName)
225 | local n = attributes.name .. "-capsule-rampant"
226 |
227 | local actions = {
228 | {
229 | type = "direct",
230 | force = (DISALLOW_FRIENDLY_FIRE and "not-same") or nil,
231 | action_delivery =
232 | {
233 | type = "instant",
234 | source_effects = attributes.sourceEffect and attributes.sourceEffect(attributes),
235 | target_effects =
236 | {
237 | {
238 | type = "create-entity",
239 | show_in_tooltip = true,
240 | trigger_created_entity = attributes.triggerCreated,
241 | entity_name = entityName,
242 | check_buildability = attributes.checkBuildability
243 | },
244 | {
245 | type = "damage",
246 | damage = {amount = attributes.damage or 5, type = attributes.damageType or "explosion"}
247 | }
248 | }
249 | }
250 | }
251 | }
252 |
253 | -- if attributes.sourceEffect then
254 | -- actions[#actions+1] = attributes.sourceEffect(attributes)
255 | -- end
256 |
257 | local cap = {
258 | type = "projectile",
259 | name = n,
260 | flags = {"not-on-map"},
261 | collision_box = attributes.collisionBox or {{-0.01, -0.01}, {0.01, 0.01}},
262 | collision_mask = attributes.collisionMask,
263 | direction_only = attributes.attackDirectionOnly,
264 | piercing_damage = attributes.piercingDamage or 0,
265 | force_condition = (settings.startup["rampant--disableCollidingProjectiles"].value and "not-same") or nil,
266 | acceleration = attributes.acceleration or 0.01,
267 | action = actions,
268 | light = {intensity = 0.5, size = 4},
269 | enable_drawing_with_mask = true,
270 | animation = {
271 | layers = {
272 | {
273 | filename = "__base__/graphics/entity/combat-robot-capsule/defender-capsule.png",
274 | flags = { "no-crop" },
275 | frame_count = 1,
276 | width = 28,
277 | height = 20,
278 | tint = attributes.tint2,
279 | scale = attributes.scale,
280 | priority = "high"
281 | },
282 | {
283 | filename = "__base__/graphics/entity/combat-robot-capsule/defender-capsule-mask.png",
284 | flags = { "no-crop" },
285 | frame_count = 1,
286 | width = 28,
287 | height = 20,
288 | tint = attributes.tint2,
289 | scale = attributes.scale,
290 | priority = "high",
291 | },
292 | },
293 | },
294 | shadow =
295 | {
296 | filename = "__base__/graphics/entity/combat-robot-capsule/defender-capsule-shadow.png",
297 | flags = { "no-crop" },
298 | frame_count = 1,
299 | width = 26,
300 | height = 20,
301 | scale = attributes.scale,
302 | priority = "high"
303 | },
304 | smoke = {
305 | {
306 | name = "the-soft-smoke-rampant",
307 | deviation = {0.15, 0.15},
308 | frequency = 1,
309 | position = {0, 0},
310 | starting_frame = 3,
311 | starting_frame_deviation = 5,
312 | starting_frame_speed_deviation = 5
313 | }
314 | }
315 | }
316 |
317 | data:extend({cap})
318 | return n
319 | end
320 |
321 | return droneUtils
322 |
--------------------------------------------------------------------------------