mirror of
https://github.com/Refactorio/RedMew.git
synced 2025-03-03 14:53:01 +02:00
Merge branch 'develop' into Quadrants
This commit is contained in:
commit
7b0156b1c9
@ -16,6 +16,7 @@ install:
|
||||
script:
|
||||
- "if [[ $TRAVIS_EVENT_TYPE != 'cron' && $TRAVIS_EVENT_TYPE != 'api' ]]; then luacheck .; fi"
|
||||
before_deploy:
|
||||
- ./.travis/check_locale.sh
|
||||
- git config --local user.name "$github_user_name"
|
||||
- git config --local user.email "$github_user_email"
|
||||
- DATE_FORMATTED=$(date +'%Y-%m-%d')
|
||||
|
40
.travis/check_locale.sh
Executable file
40
.travis/check_locale.sh
Executable file
@ -0,0 +1,40 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd ~/build/Refactorio/RedMew/locale/ || exit
|
||||
echo "Changing working directory to: "
|
||||
pwd
|
||||
|
||||
ldiff() {
|
||||
|
||||
while read file; do
|
||||
|
||||
cat en/$file | sed 's/=.*//' | sed '/^#/ d' >diff_file.tmp
|
||||
count=$(cat "$1/$file" | sed 's/=.*//' | sed '/^#/ d' | git --no-pager diff --no-index -- diff_file.tmp - | tail -n +6 | grep -o '\-.*' | sed '/^-$/d' | wc -l)
|
||||
if [ "$count" -ne 0 ]; then
|
||||
echo
|
||||
echo "locale/$1/$file: ($count differences)"
|
||||
echo "------------------------------"
|
||||
|
||||
cat "$1/$file" | sed 's/=.*//' | sed '/^#/ d' | git --no-pager diff --no-index -- diff_file.tmp - | tail -n +6 | grep -o '\-.*' | sed '/^-$/d' | sed 's/^-//'
|
||||
|
||||
echo "------------------------------"
|
||||
rm diff_file.tmp
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
echo "##############################"
|
||||
echo "Checking locale for misplaced/missing keys."
|
||||
for dir in *; do
|
||||
if [ "$dir" != "en" ]; then
|
||||
ls en | ldiff $dir
|
||||
fi
|
||||
done
|
||||
|
||||
echo
|
||||
echo "Done checking locale"
|
||||
echo "##############################"
|
||||
|
||||
cd ../../../
|
||||
echo "Changing working directory back to: "
|
||||
pwd
|
67
config.lua
67
config.lua
@ -196,27 +196,52 @@ global.config = {
|
||||
-- spawns more units when one dies
|
||||
hail_hydra = {
|
||||
enabled = false,
|
||||
-- at which scale the evolution will increase the additional hydra spawns
|
||||
-- to disable scaling with evolution, set to 0.
|
||||
-- the formula: chance = hydra_chance + (evolution_factor * evolution_scale)
|
||||
-- example: small spitter has 0.2, which is 20% at 0% and 120% at an evolution_factor of 1
|
||||
evolution_scale = 1,
|
||||
-- enables difficulty scaling with number of online players
|
||||
-- if enabled you can disable it for individual spawns by setting {locked = true}
|
||||
online_player_scale_enabled = true,
|
||||
-- the number of players required for regular values.
|
||||
-- less online players than this number decreases the spawn chances
|
||||
-- more online players than this number increases the spawn chances
|
||||
-- the spawn chance is increased or decreased with 0.01 * (#connected_players - online_player_scale)
|
||||
online_player_scale = 20,
|
||||
-- any non-rounded number will turn into a chance to spawn an additional alien
|
||||
-- example: 2.5 would spawn 2 for sure and 50% chance to spawn one additionally
|
||||
-- min defines the lowest chance, max defines the max chance at evolution 1.
|
||||
-- trigger defines when the chance is active
|
||||
-- setting max to less than min or nil will ignore set the max = min
|
||||
-- Hail Hydra scales between min and max with a custom formula.
|
||||
-- Key values shown in evolution = (percentage of max):
|
||||
-- | 0.25 evolution = 10% | 0.50 evolution = 29% | 0.60 evolution = 45% | 0.75 evolution = 58% |
|
||||
-- | 0.80 evolution = 65% | 0.90 evolution = 81% | 1.00 evolution = 100% |
|
||||
-- eg. {min = 0.2, max = 2, trigger = 0.3} means that after evolution 0.3 this hydra spawns with a chance of at least 0.2
|
||||
-- and at evolution = 1.00 it spawns with a chance of 2.
|
||||
-- At evolution 0.60 it would spawn with a chance of min + max * (percentage of max) = 1.1
|
||||
-- Example of all available options (only min is required):
|
||||
-- ['behemoth-biter'] = {min = 0.1, max = 0.5, trigger = 0.90, locked = true}}
|
||||
hydras = {
|
||||
-- spitters
|
||||
['small-spitter'] = {['small-worm-turret'] = 0.2},
|
||||
['medium-spitter'] = {['medium-worm-turret'] = 0.2},
|
||||
['big-spitter'] = {['big-worm-turret'] = 0.2},
|
||||
['behemoth-spitter'] = {['big-worm-turret'] = 0.4},
|
||||
['small-spitter'] = {['small-worm-turret'] = {min = 0.2, max = 1}},
|
||||
['medium-spitter'] = {['medium-worm-turret'] = {min = 0.2, max = 1}},
|
||||
['big-spitter'] = {['big-worm-turret'] = {min = 0.2, max = 1}},
|
||||
['behemoth-spitter'] = {['behemoth-worm-turret'] = {min = 0.2, max = 1}},
|
||||
-- biters
|
||||
['medium-biter'] = {['small-biter'] = 1.2},
|
||||
['big-biter'] = {['medium-biter'] = 1.2},
|
||||
['behemoth-biter'] = {['big-biter'] = 1.2},
|
||||
['medium-biter'] = {['small-biter'] = {min = 1, max = 2}},
|
||||
['big-biter'] = {['medium-biter'] = {min = 1, max = 2}},
|
||||
['behemoth-biter'] = {['big-biter'] = {min = 1, max = 2}},
|
||||
-- worms
|
||||
['small-worm-turret'] = {['small-biter'] = 2.5},
|
||||
['medium-worm-turret'] = {['small-biter'] = 2.5, ['medium-biter'] = 0.6},
|
||||
['big-worm-turret'] = {['small-biter'] = 3.8, ['medium-biter'] = 1.3, ['big-biter'] = 1.1}
|
||||
['small-worm-turret'] = {['small-biter'] = {min = 1.5, max = 2.5}},
|
||||
['medium-worm-turret'] = {['small-biter'] = {min = 2.5, max = 3.5}, ['medium-biter'] = {min = 1.0, max = 2}},
|
||||
['big-worm-turret'] = {
|
||||
['small-biter'] = {min = 2.5, max = 4},
|
||||
['medium-biter'] = {min = 1.5, max = 2.2},
|
||||
['big-biter'] = {min = 0.7, max = 1.5}
|
||||
},
|
||||
['behemoth-worm-turret'] = {
|
||||
['small-biter'] = {min = 4, max = 5.2},
|
||||
['medium-biter'] = {min = 2.5, max = 3.8},
|
||||
['big-biter'] = {min = 1.2, max = 2.4},
|
||||
['behemoth-biter'] = {min = 0.8, max = -1}
|
||||
}
|
||||
}
|
||||
},
|
||||
-- grants reward coins for certain actions
|
||||
@ -254,10 +279,6 @@ global.config = {
|
||||
player_colors = {
|
||||
enabled = true
|
||||
},
|
||||
-- adds a command that switches a player to the enemy force and teleports them far away for some time to calm down
|
||||
walkabout = {
|
||||
enabled = true
|
||||
},
|
||||
-- adds a command to generate a popup dialog box for players to see, useful for important announcements
|
||||
popup = {
|
||||
enabled = true
|
||||
@ -284,7 +305,9 @@ global.config = {
|
||||
-- adds craftable loaders.
|
||||
loaders = true,
|
||||
-- turns on entity info aka alt-mode on first joining
|
||||
set_alt_on_create = true
|
||||
set_alt_on_create = true,
|
||||
-- prevents personal construction robots from being mined by other players
|
||||
save_bots = true
|
||||
},
|
||||
-- adds a useless button with the biter percentage
|
||||
evolution_progress = {
|
||||
@ -310,6 +333,10 @@ global.config = {
|
||||
-- enables a command which allows for an end-game event
|
||||
apocalypse = {
|
||||
enabled = true
|
||||
},
|
||||
-- gradually informs players of features such as chat, toasts, etc.
|
||||
player_onboarding = {
|
||||
enabled = true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,9 +65,6 @@ end
|
||||
if config.reactor_meltdown.enabled then
|
||||
require 'features.reactor_meltdown'
|
||||
end
|
||||
if config.walkabout.enabled then
|
||||
require 'features.walkabout'
|
||||
end
|
||||
if config.performance.enabled then
|
||||
require 'features.performance'
|
||||
end
|
||||
@ -89,6 +86,9 @@ end
|
||||
if config.apocalypse.enabled then
|
||||
require 'features.apocalypse'
|
||||
end
|
||||
if config.player_onboarding.enabled then
|
||||
require 'features.player_onboarding'
|
||||
end
|
||||
|
||||
-- GUIs
|
||||
-- The order determines the order they appear from left to right.
|
||||
|
@ -1,5 +1,3 @@
|
||||
local Task = require 'utils.task'
|
||||
local Token = require 'utils.token'
|
||||
local Global = require 'utils.global'
|
||||
local Rank = require 'features.rank_system'
|
||||
local Report = require 'features.report'
|
||||
@ -10,7 +8,6 @@ local Command = require 'utils.command'
|
||||
local Color = require 'resources.color_presets'
|
||||
local Ranks = require 'resources.ranks'
|
||||
|
||||
local format = string.format
|
||||
local loadstring = loadstring
|
||||
|
||||
--- A table of players with tpmode turned on
|
||||
@ -68,16 +65,16 @@ end
|
||||
--- Toggles cheat mode for a player
|
||||
local function toggle_cheat_mode(_, player)
|
||||
player.cheat_mode = not player.cheat_mode
|
||||
Game.player_print('Cheat mode set to ' .. tostring(player.cheat_mode))
|
||||
Game.player_print({'admin_commands.toggle_cheat_mode', tostring(player.cheat_mode)})
|
||||
end
|
||||
|
||||
--- Promote someone to regular
|
||||
local function add_regular(args)
|
||||
local target_name = args['player']
|
||||
local target_player = game.players[target_name]
|
||||
local target_ident = args.player
|
||||
local target, target_name = Utils.validate_player(target_ident)
|
||||
|
||||
if not target_player or not target_player.valid then
|
||||
print_no_target(target_name)
|
||||
if not target then
|
||||
print_no_target(target_ident)
|
||||
return
|
||||
end
|
||||
|
||||
@ -89,7 +86,7 @@ local function add_regular(args)
|
||||
local success = Rank.increase_player_rank_to(target_name, Ranks.regular)
|
||||
if success then
|
||||
game.print({'admin_commands.regular_add_success', Utils.get_actor(), target_name}, Color.info)
|
||||
target_player.print({'admin_commands.regular_add_notify_target'}, Color.warning)
|
||||
target.print({'admin_commands.regular_add_notify_target'}, Color.warning)
|
||||
else
|
||||
Game.player_print({'admin_commands.regular_add_fail', target_name, Rank.get_player_rank_name(target_name)}, Color.fail)
|
||||
end
|
||||
@ -97,17 +94,20 @@ end
|
||||
|
||||
--- Demote someone from regular
|
||||
local function remove_regular(args)
|
||||
local target_name = args['player']
|
||||
local target_player = game.players[target_name]
|
||||
local target_ident = args.player
|
||||
local target, target_name = Utils.validate_player(target_ident)
|
||||
|
||||
if not target_player or not target_player.valid then
|
||||
Game.player_print({'common.warn_no_target', target_name}, Color.warning)
|
||||
if not target then
|
||||
print_no_target(target_ident)
|
||||
return
|
||||
end
|
||||
|
||||
if Rank.equal(target_name, Ranks.regular) then
|
||||
local _, new_rank = Rank.reset_player_rank(target_name)
|
||||
game.print({'admin_commands.regular_remove_success', Utils.get_actor(), target_name, new_rank}, Color.info)
|
||||
target_player.print({'admin_commands.regular_remove_notify_target'}, Color.warning)
|
||||
if target then
|
||||
target.print({'admin_commands.regular_remove_notify_target'}, Color.warning)
|
||||
end
|
||||
else
|
||||
local rank_name = Rank.get_player_rank_name(target_name)
|
||||
Game.player_print({'admin_commands.regular_remove_fail', target_name, rank_name}, Color.fail)
|
||||
@ -116,23 +116,28 @@ end
|
||||
|
||||
--- Put someone on probation
|
||||
local function probation_add(args)
|
||||
local target_name = args['player']
|
||||
local target_player = game.players[target_name]
|
||||
local target_ident = args.player
|
||||
local target, target_name = Utils.validate_player(target_ident)
|
||||
|
||||
if not target_player or not target_player.valid then
|
||||
Game.player_print({'common.warn_no_target', target_name}, Color.warning)
|
||||
if not target then
|
||||
print_no_target(target_ident)
|
||||
return
|
||||
end
|
||||
|
||||
if Rank.equal(target_name, Ranks.admin) then
|
||||
target_player.print({'admin_commands.probation_warn_admin', Utils.get_actor()}, Color.warning)
|
||||
Game.player_print({'admin_commands.probation_add_fail_admin'}, Color.fail)
|
||||
if target then
|
||||
target.print({'admin_commands.probation_warn_admin', Utils.get_actor()}, Color.warning)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local success = Rank.decrease_player_rank_to(target_name, Ranks.probation)
|
||||
if success then
|
||||
game.print({'admin_commands.probation_add_success', Utils.get_actor(), target_name}, Color.info)
|
||||
target_player.print({'admin_commands.probation_add_notify_target'}, Color.warning)
|
||||
if target then
|
||||
target.print({'admin_commands.probation_add_notify_target'}, Color.warning)
|
||||
end
|
||||
else
|
||||
Game.player_print({'admin_commands.probation_add_fail', target_name}, Color.fail)
|
||||
end
|
||||
@ -140,17 +145,20 @@ end
|
||||
|
||||
--- Remove someone from probation
|
||||
local function probation_remove(args)
|
||||
local target_name = args['player']
|
||||
local target_player = game.players[target_name]
|
||||
local target_ident = args.player
|
||||
local target, target_name = Utils.validate_player(target_ident)
|
||||
|
||||
if not target_player or not target_player.valid then
|
||||
Game.player_print({'common.warn_no_target', target_name}, Color.warning)
|
||||
if not target then
|
||||
print_no_target(target_ident)
|
||||
return
|
||||
end
|
||||
|
||||
if Rank.equal(target_name, Ranks.probation) then
|
||||
Rank.reset_player_rank(target_name)
|
||||
game.print({'admin_commands.probation_remove_success', Utils.get_actor(), target_name}, Color.info)
|
||||
target_player.print({'admin_commands.probation_remove_notify_target'}, Color.warning)
|
||||
if target then
|
||||
target.print({'admin_commands.probation_remove_notify_target'}, Color.warning)
|
||||
end
|
||||
else
|
||||
Game.player_print({'admin_commands.probation_remove_fail', target_name}, Color.fail)
|
||||
end
|
||||
@ -163,68 +171,27 @@ end
|
||||
|
||||
--- Places a target in jail (a permissions group which is unable to act aside from chatting)
|
||||
local function jail_player(args, player)
|
||||
-- Check if the target is valid
|
||||
local target = game.players[args.player]
|
||||
local target_ident = args.player
|
||||
local target = Utils.validate_player(target_ident)
|
||||
|
||||
if not target then
|
||||
print_no_target(target_ident)
|
||||
return
|
||||
end
|
||||
|
||||
Report.jail(target, player)
|
||||
end
|
||||
|
||||
--- Removes a target from jail
|
||||
local function unjail_player(args, player)
|
||||
-- Check if the target is valid
|
||||
local target = game.players[args.player]
|
||||
Report.unjail(target, player)
|
||||
end
|
||||
local target_ident = args.player
|
||||
local target = Utils.validate_player(target_ident)
|
||||
|
||||
--- Checks if we have a permission group named 'banned' and if we don't, create it
|
||||
local function get_tempban_group()
|
||||
local group = game.permissions.get_group('Banned')
|
||||
if not group then
|
||||
game.permissions.create_group('Banned')
|
||||
group = game.permissions.get_group('Banned')
|
||||
if group then
|
||||
for i = 2, 174 do
|
||||
group.set_allows_action(i, false)
|
||||
end
|
||||
end
|
||||
end
|
||||
return group
|
||||
end
|
||||
|
||||
--- Removes player from the tempban list (by changing them back to the default permissions group)
|
||||
local redmew_commands_untempban =
|
||||
Token.register(
|
||||
function(param)
|
||||
game.print(param.name .. ' is out of timeout.')
|
||||
game.permissions.get_group('Default').add_player(param.name)
|
||||
end
|
||||
)
|
||||
|
||||
--- Gives a player a temporary ban
|
||||
local function tempban(args, player)
|
||||
local target_name = args.player
|
||||
local target = game.players[target_name]
|
||||
local duration = args.minutes
|
||||
if not target then
|
||||
print_no_target(target_name)
|
||||
print_no_target(target_ident)
|
||||
return
|
||||
end
|
||||
if not tonumber(duration) then
|
||||
Game.player_print('Tempban failed. Minutes must be a number.')
|
||||
return
|
||||
end
|
||||
|
||||
local group = get_tempban_group()
|
||||
local actor
|
||||
if player then
|
||||
actor = player.name
|
||||
else
|
||||
actor = 'server'
|
||||
end
|
||||
game.print(format('%s put %s in timeout for %s minutes.', actor, target_name, duration))
|
||||
if group then
|
||||
group.add_player(target_name)
|
||||
Task.set_timeout(60 * tonumber(duration), redmew_commands_untempban, {name = target_name})
|
||||
end
|
||||
Report.unjail(target, player)
|
||||
end
|
||||
|
||||
--- Creates a rectangle of water below an admin
|
||||
@ -242,56 +209,58 @@ end
|
||||
|
||||
--- Takes a target and teleports them to player
|
||||
local function invoke(args, player)
|
||||
local target_name = args.player
|
||||
local target = game.players[target_name]
|
||||
local target_ident = args.player
|
||||
local target = Utils.validate_player(target_ident)
|
||||
|
||||
if not target then
|
||||
print_no_target(target_name)
|
||||
print_no_target(target_ident)
|
||||
return
|
||||
end
|
||||
|
||||
local pos = player.surface.find_non_colliding_position('player', player.position, 50, 1)
|
||||
if not pos then
|
||||
Game.player_print('Unable to find suitable location to teleport to.')
|
||||
Game.player_print({'admin_commands.invoke_fail_no_location'})
|
||||
return
|
||||
end
|
||||
target.teleport({pos.x, pos.y}, player.surface)
|
||||
game.print(args.player .. ', get your ass over here!')
|
||||
game.print({'admin_commands.invoke_announce', target.name})
|
||||
end
|
||||
|
||||
--- Takes a target and teleports player to target. (admin only)
|
||||
local function teleport_player(args, player)
|
||||
local target_name = args.player
|
||||
local target
|
||||
if target_name then
|
||||
target = game.players[target_name]
|
||||
end
|
||||
local target_ident = args.player
|
||||
local target = Utils.validate_player(target_ident)
|
||||
|
||||
if not target then
|
||||
print_no_target(target_name)
|
||||
print_no_target(target_ident)
|
||||
return
|
||||
end
|
||||
|
||||
local target_name = target.name
|
||||
local surface = target.surface
|
||||
local pos = surface.find_non_colliding_position('player', target.position, 50, 1)
|
||||
if not pos then
|
||||
Game.player_print('Unable to find suitable location to teleport to.')
|
||||
Game.player_print({'admin_commands.tp_fail_no_location'})
|
||||
return
|
||||
end
|
||||
player.teleport(pos, surface)
|
||||
game.print(target_name .. "! watcha doin'?!")
|
||||
Game.player_print('You have teleported to ' .. target_name)
|
||||
game.print({'admin_commands.tp_player_announce', target_name})
|
||||
Game.player_print({'admin_commands.tp_player_success', target_name})
|
||||
end
|
||||
|
||||
--- Takes a selected entity and teleports player to it
|
||||
local function teleport_location(_, player)
|
||||
if not player.selected then
|
||||
Game.player_print('No entity under cursor.')
|
||||
Game.player_print({'admin_commands.tp_ent_fail_no_ent'})
|
||||
return
|
||||
end
|
||||
local pos = player.surface.find_non_colliding_position('player', player.selected.position, 50, 1)
|
||||
if not pos then
|
||||
Game.player_print('Unable to find suitable location to teleport to.')
|
||||
Game.player_print({'admin_commands.tp_fail_no_location'})
|
||||
return
|
||||
end
|
||||
player.teleport(pos)
|
||||
Game.player_print('Teleporting to your selected entity.')
|
||||
Game.player_print({'admin_commands.tp_end_success'})
|
||||
end
|
||||
|
||||
--- If a player is in the tp_players list, remove ghosts they place and teleport them to that position
|
||||
@ -317,10 +286,10 @@ local function toggle_tp_mode(_, player)
|
||||
|
||||
if toggled then
|
||||
tp_players[index] = nil
|
||||
Game.player_print('tp mode is now off')
|
||||
Game.player_print({'admin_commands.tp_mode_off'})
|
||||
else
|
||||
tp_players[index] = true
|
||||
Game.player_print('tp mode is now on - place a ghost entity to teleport there.')
|
||||
Game.player_print({'admin_commands.tp_mode_on'})
|
||||
end
|
||||
end
|
||||
|
||||
@ -349,10 +318,10 @@ end
|
||||
local function destroy_selected(_, player)
|
||||
local ent = player.selected
|
||||
if ent then
|
||||
Game.player_print(ent.name .. ' destroyed')
|
||||
Game.player_print({'admin_commands.destroy_success', ent.localised_name})
|
||||
ent.destroy()
|
||||
else
|
||||
Game.player_print('Nothing found to destroy. (You must have an entity under your cursor when you hit enter)')
|
||||
Game.player_print({'admin_commands.destroy_fail'})
|
||||
end
|
||||
end
|
||||
|
||||
@ -365,7 +334,7 @@ Event.add(defines.events.on_built_entity, built_entity)
|
||||
Command.add(
|
||||
'a',
|
||||
{
|
||||
description = 'Admin chat. Messages all other admins.',
|
||||
description = {'command_description.a'},
|
||||
arguments = {'msg'},
|
||||
required_rank = Ranks.admin,
|
||||
capture_excess_arguments = true,
|
||||
@ -377,7 +346,7 @@ Command.add(
|
||||
Command.add(
|
||||
'dc',
|
||||
{
|
||||
description = 'silent-command',
|
||||
description = {'command_description.dc'},
|
||||
arguments = {'str'},
|
||||
required_rank = Ranks.admin,
|
||||
capture_excess_arguments = true,
|
||||
@ -389,7 +358,7 @@ Command.add(
|
||||
Command.add(
|
||||
'hax',
|
||||
{
|
||||
description = 'Toggles your hax (makes recipes cost nothing)',
|
||||
description = {'command_description.hax'},
|
||||
required_rank = Ranks.admin
|
||||
},
|
||||
toggle_cheat_mode
|
||||
@ -398,7 +367,7 @@ Command.add(
|
||||
Command.add(
|
||||
'regular',
|
||||
{
|
||||
description = 'Gives a player the regualar rank.',
|
||||
description = {'command_description.regular'},
|
||||
arguments = {'player'},
|
||||
required_rank = Ranks.admin,
|
||||
allowed_by_server = true
|
||||
@ -409,7 +378,7 @@ Command.add(
|
||||
Command.add(
|
||||
'regular-remove',
|
||||
{
|
||||
description = 'Demotes a player from regular to the next lowest rank',
|
||||
description = {'command_description.regular_remove'},
|
||||
arguments = {'player'},
|
||||
required_rank = Ranks.admin,
|
||||
allowed_by_server = true
|
||||
@ -420,7 +389,7 @@ Command.add(
|
||||
Command.add(
|
||||
'probation',
|
||||
{
|
||||
description = 'Put player on probation. (They will be unable to use redmew commands and will never gain auto-trusted rank.)',
|
||||
description = {'command_description.probation'},
|
||||
arguments = {'player'},
|
||||
required_rank = Ranks.admin,
|
||||
allowed_by_server = true
|
||||
@ -431,7 +400,7 @@ Command.add(
|
||||
Command.add(
|
||||
'probation-remove',
|
||||
{
|
||||
description = 'Remove player from probation.',
|
||||
description = {'command_description.probation_remove'},
|
||||
arguments = {'player'},
|
||||
required_rank = Ranks.admin,
|
||||
allowed_by_server = true
|
||||
@ -442,7 +411,7 @@ Command.add(
|
||||
Command.add(
|
||||
'showreports',
|
||||
{
|
||||
description = 'Shows user reports',
|
||||
description = {'command_description.showreports'},
|
||||
required_rank = Ranks.admin
|
||||
},
|
||||
show_reports
|
||||
@ -451,7 +420,7 @@ Command.add(
|
||||
Command.add(
|
||||
'jail',
|
||||
{
|
||||
description = 'Puts a player in jail',
|
||||
description = {'command_description.jail'},
|
||||
arguments = {'player'},
|
||||
required_rank = Ranks.admin,
|
||||
allowed_by_server = true
|
||||
@ -462,7 +431,7 @@ Command.add(
|
||||
Command.add(
|
||||
'unjail',
|
||||
{
|
||||
description = 'Removes a player from jail',
|
||||
description = {'command_description.unjail'},
|
||||
arguments = {'player'},
|
||||
required_rank = Ranks.admin,
|
||||
allowed_by_server = true
|
||||
@ -470,21 +439,10 @@ Command.add(
|
||||
unjail_player
|
||||
)
|
||||
|
||||
Command.add(
|
||||
'tempban',
|
||||
{
|
||||
description = 'Temporarily bans a player',
|
||||
arguments = {'player', 'minutes'},
|
||||
required_rank = Ranks.admin,
|
||||
allowed_by_server = true
|
||||
},
|
||||
tempban
|
||||
)
|
||||
|
||||
Command.add(
|
||||
'pool',
|
||||
{
|
||||
description = 'Spawns a pool of water',
|
||||
description = {'command_description.pool'},
|
||||
required_rank = Ranks.admin
|
||||
},
|
||||
pool
|
||||
@ -493,7 +451,7 @@ Command.add(
|
||||
Command.add(
|
||||
'invoke',
|
||||
{
|
||||
description = 'Teleports the player to you.',
|
||||
description = {'command_description.invoke'},
|
||||
arguments = {'player'},
|
||||
required_rank = Ranks.admin
|
||||
},
|
||||
@ -503,11 +461,11 @@ Command.add(
|
||||
Command.add(
|
||||
'tp',
|
||||
{
|
||||
description = 'if blank, teleport to selected entity. mode = toggle tp mode where you can teleport to a placed ghost. player = teleport to player.',
|
||||
description = {'command_description.tp'},
|
||||
arguments = {'mode|player'},
|
||||
default_values = {['mode|player'] = false},
|
||||
required_rank = Ranks.admin,
|
||||
custom_help_text = '<blank|mode|player> 3 different uses: "/tp" to tp to selected entity. "/tp mode" to toggle tp mode. "/tp Newcott" to tp to Newcott'
|
||||
custom_help_text = {'command_custom_help.tp'}
|
||||
},
|
||||
teleport_command
|
||||
)
|
||||
@ -515,7 +473,7 @@ Command.add(
|
||||
Command.add(
|
||||
'revive-ghosts',
|
||||
{
|
||||
description = 'Revives the ghosts within the provided radius around you',
|
||||
description = {'command_description.revive_ghosts'},
|
||||
arguments = {'radius'},
|
||||
default_values = {radius = 10},
|
||||
required_rank = Ranks.admin
|
||||
@ -526,7 +484,7 @@ Command.add(
|
||||
Command.add(
|
||||
'destroy',
|
||||
{
|
||||
description = 'Destroys the entity under your cursor when you run this command',
|
||||
description = {'command_description.destroy'},
|
||||
required_rank = Ranks.admin
|
||||
},
|
||||
destroy_selected
|
||||
|
@ -103,8 +103,8 @@ end
|
||||
Command.add(
|
||||
'apocalypse',
|
||||
{
|
||||
description = "This really ends the map. When you first run it, the game will save. When run a second time, the apocalypse will begin.",
|
||||
required_rank = Ranks.admin,
|
||||
description = {'command_description.apocalypse'},
|
||||
required_rank = Ranks.admin
|
||||
},
|
||||
Public.begin_apocalypse
|
||||
)
|
||||
|
@ -9,10 +9,10 @@ local Hodor = require 'resources.hodor_messages'
|
||||
local prefix = '## - '
|
||||
|
||||
local auto_replies = {
|
||||
['discord'] = {'Did you ask about our discord server?', 'You can find it here: redmew.com/discord'},
|
||||
['patreon'] = {'Did you ask about our patreon?', 'You can find it here: patreon.com/redmew'},
|
||||
['donate'] = {'Did you ask about donating to the server?', 'You can find our patreon here: patreon.com/redmew'},
|
||||
['grief'] = {'To report grief please use the /report function.', 'If no admins are online use #moderation-requests on the discord and make sure the @mention the appropriate role.'}
|
||||
['discord'] = {{'chat_triggers.discord'}},
|
||||
['patreon'] = {{'chat_triggers.patreon'}},
|
||||
['donate'] = {{'chat_triggers.donate'}},
|
||||
['grief'] = {{'chat_triggers.grief'}}
|
||||
}
|
||||
|
||||
--- Check for player and get player
|
||||
@ -44,7 +44,7 @@ local function auto_respond(event)
|
||||
local message = event.message:lower()
|
||||
local player = get_player(event)
|
||||
|
||||
if player and not player.admin then
|
||||
if player and player.valid and not player.admin then
|
||||
for trigger, replies in pairs(auto_replies) do
|
||||
if message:match(trigger) then
|
||||
for _, reply in pairs(replies) do
|
||||
@ -88,7 +88,7 @@ local function mentions(event)
|
||||
word = 'admin'
|
||||
end
|
||||
if admin_call and p.admin then
|
||||
local message = string.format('%s%s mentioned %s!', prefix, Game.get_player_by_index(event.player_index).name, word )
|
||||
local message = {'chat_triggers.mention_success', prefix, Game.get_player_by_index(event.player_index).name, word}
|
||||
p.print(message, Color.yellow)
|
||||
p.play_sound {path = 'utility/new_objective', volume_modifier = 1}
|
||||
success = true
|
||||
@ -96,7 +96,7 @@ local function mentions(event)
|
||||
if not admin_call and (p.name:lower() == word_front_trim or p.name:lower() == word_back_trim or p.name:lower() == word_back_double_trim or p.name:lower() == word_front_back_trim) then
|
||||
if p.name == player.name then
|
||||
if _DEBUG then
|
||||
player.print(prefix .. "Can't mention yourself!", Color.red)
|
||||
player.print({'chat_triggers.mention_fail_mention_self', prefix}, Color.red)
|
||||
end
|
||||
success = true
|
||||
break
|
||||
@ -125,9 +125,9 @@ local function mentions(event)
|
||||
if missing_player_string ~= nil then
|
||||
missing_player_string = string.sub(missing_player_string, 1, (string.len(missing_player_string) - 2))
|
||||
if not_found > 1 then
|
||||
player.print(prefix .. 'Players not found: ' .. missing_player_string, Color.yellow)
|
||||
player.print({'chat_triggers.mention_not_found_plural', prefix, missing_player_string}, Color.yellow)
|
||||
else
|
||||
player.print(prefix .. 'Player not found: ' .. missing_player_string, Color.yellow)
|
||||
player.print({'chat_triggers.mention_not_found_singular', prefix, missing_player_string}, Color.yellow)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -53,7 +53,7 @@ Event.on_nth_tick(63, function ()
|
||||
end)
|
||||
|
||||
Command.add('particle-scale', {
|
||||
description = 'Provide a fraction between 0 and 1 to lower or increase the amount of (max) particles. Leave empty to view the current values.',
|
||||
description = {'command_description.particle_scale'},
|
||||
arguments = {'fraction'},
|
||||
default_values = {fraction = false},
|
||||
required_rank = Ranks.admin,
|
||||
|
22
features/debug_tools.lua
Normal file
22
features/debug_tools.lua
Normal file
@ -0,0 +1,22 @@
|
||||
local Command = require 'utils.command'
|
||||
local Ranks = require 'resources.ranks'
|
||||
|
||||
Command.add(
|
||||
'debug-reveal',
|
||||
{
|
||||
description = {'command_description.reveal'},
|
||||
arguments = {'radius'},
|
||||
default_values = {radius = 500},
|
||||
required_rank = Ranks.admin,
|
||||
debug_only = true,
|
||||
allowed_by_server = true
|
||||
},
|
||||
function(args, p)
|
||||
local radius = args.radius
|
||||
if not p then
|
||||
p = {force = game.forces.player, surface = game.surfaces.redmew or game.surfaces.nauvis, position = {x = 0, y = 0}}
|
||||
end
|
||||
local pos = p.position
|
||||
p.force.chart(p.surface, {{pos.x - radius, pos.y - radius}, {pos.x + radius, pos.y + radius}})
|
||||
end
|
||||
)
|
@ -78,7 +78,7 @@ end
|
||||
Command.add(
|
||||
'donator-welcome-message',
|
||||
{
|
||||
description = 'Adds, deletes, or lists donator welcome messages.',
|
||||
description = {'command_description.donator_welcome_message'},
|
||||
arguments = {'add|delete|list', 'value'},
|
||||
default_values = {value = false},
|
||||
capture_excess_arguments = true,
|
||||
@ -90,7 +90,7 @@ Command.add(
|
||||
Command.add(
|
||||
'donator-death-message',
|
||||
{
|
||||
description = 'Adds, deletes, or lists donator death messages.',
|
||||
description = {'command_description.donator_death_message'},
|
||||
arguments = {'add|delete|list', 'value'},
|
||||
default_values = {value = false},
|
||||
capture_excess_arguments = true,
|
||||
|
@ -12,7 +12,7 @@ local ForceControl = {}
|
||||
ForceControl.events = {
|
||||
--- triggered when the force levels up
|
||||
--- uses event = {level_reached = number, force = LuaForce}
|
||||
on_level_up = script.generate_event_name()
|
||||
on_level_up = Event.generate_event_name('on_level_up')
|
||||
}
|
||||
|
||||
-- the builder, can only be accessed through ForceControl.register() and should be avoided used run-time
|
||||
|
@ -71,7 +71,7 @@ local function create_camera(args, player)
|
||||
mainframe.add {type = 'frame', name = 'cameraframe', style = 'captionless_frame'}
|
||||
end
|
||||
|
||||
mainframe.add {type = 'label', caption = 'Following: ' .. args.target}
|
||||
mainframe.add {type = 'label', caption = 'Following: ' .. target.name}
|
||||
local close_button = mainframe.add {type = 'button', name = main_button_name, caption = 'Close'}
|
||||
apply_button_style(close_button)
|
||||
local target_index = target.index
|
||||
@ -193,7 +193,7 @@ end
|
||||
Command.add(
|
||||
'watch',
|
||||
{
|
||||
description = 'Allows you to watch other players.',
|
||||
description = {'command_description.watch'},
|
||||
arguments = {'target'},
|
||||
default_values = {target = false}
|
||||
},
|
||||
|
@ -4,8 +4,8 @@ local Command = require 'utils.command'
|
||||
Command.add(
|
||||
'debug',
|
||||
{
|
||||
debug_only = true,
|
||||
description = 'Opens the debugger'
|
||||
description = {'command_descriptiondebuger'},
|
||||
debug_only = true
|
||||
},
|
||||
function(_, player)
|
||||
DebugView.open_dubug(player)
|
||||
|
@ -107,7 +107,7 @@ function Public.show(container)
|
||||
end
|
||||
end
|
||||
|
||||
Event.add(events.on_gui_checked_state_changed, on_gui_checked_state_changed)
|
||||
Gui.on_checked_state_changed(checkbox_name, on_gui_checked_state_changed)
|
||||
|
||||
-- Event registers (TODO: turn to removable hooks.. maybe)
|
||||
for name, id in pairs(events) do
|
||||
|
@ -20,7 +20,6 @@ local focus_color = Color.dark_orange
|
||||
local unfocus_color = Color.black
|
||||
|
||||
local reward_amount = 2
|
||||
local reward_plural_indicator = reward_amount > 1 and 's' or ''
|
||||
local reward_token = PlayerRewards.get_reward()
|
||||
local info_tab_flags = {
|
||||
0x1, -- welcome
|
||||
@ -81,8 +80,7 @@ end
|
||||
local changelog_callback = Token.register(process_changelog)
|
||||
|
||||
local function prepare_title()
|
||||
local welcome_title =
|
||||
[[
|
||||
local welcome_title = [[
|
||||
111111 1111111 111111 111 111 1111111 11 11
|
||||
11 11 11 11 11 1111 1111 11 11 11
|
||||
111111 11111 11 11 11 1111 11 11111 11 1 11
|
||||
@ -182,54 +180,29 @@ local pages = {
|
||||
parent_style = parent.style
|
||||
parent_style.vertically_stretchable = false
|
||||
|
||||
header_label(parent, 'Welcome to Redmew!')
|
||||
centered_label(
|
||||
parent,
|
||||
[[
|
||||
Redmew is a community for players of all skill levels committed to pushing the limits of Factorio Multiplayer through custom scripts and crazy map designs.
|
||||
header_label(parent, {'info.welcome_header'})
|
||||
centered_label(parent, {'info.welcome_text'})
|
||||
|
||||
We are a friendly bunch, our objective is to have as much fun as possible and we hope you will too.
|
||||
]]
|
||||
)
|
||||
|
||||
header_label(parent, 'How To Chat')
|
||||
centered_label(
|
||||
parent,
|
||||
[[
|
||||
To chat with other players, press the "grave" key on your keyboard.
|
||||
It is below the ESC key on English keyboards and looks like ~ or `
|
||||
This can be changed in options -> controls -> "toggle lua console".
|
||||
]]
|
||||
)
|
||||
header_label(parent, {'info.chatting_header'})
|
||||
centered_label(parent, {'info.chatting_text', {'gui-menu.settings'}, {'gui-menu.controls'}, {'controls.toggle-console'}})
|
||||
|
||||
if config_prewards.enabled and config_prewards.info_player_reward then
|
||||
local string =
|
||||
format(
|
||||
'You have been given %s %s%s for looking at the welcome tab.\nChecking each tab will reward you %s more %s%s.\n',
|
||||
reward_amount,
|
||||
reward_token,
|
||||
reward_plural_indicator,
|
||||
reward_amount,
|
||||
reward_token,
|
||||
reward_plural_indicator
|
||||
)
|
||||
header_label(parent, 'Free Coins')
|
||||
centered_label(parent, string)
|
||||
header_label(parent, {'info.free_coin_header'})
|
||||
centered_label(parent, {'info.free_coin_text', reward_amount, reward_token, reward_amount, reward_token})
|
||||
end
|
||||
|
||||
header_label(parent, 'Useful Links')
|
||||
centered_label(parent, [[Check out our discord for new map info and to suggest new maps / ideas.]])
|
||||
header_label(parent, {'info.links_header'})
|
||||
centered_label(parent, {'info.links_discord'})
|
||||
local discord_textbox_flow = parent.add {type = 'flow'}
|
||||
local discord_textbox_flow_style = discord_textbox_flow.style
|
||||
discord_textbox_flow_style.horizontal_align = 'center'
|
||||
discord_textbox_flow_style.horizontally_stretchable = true
|
||||
discord_textbox_flow.add({type = 'label', caption = 'Discord: '}).style.font = 'default-bold'
|
||||
local discord_textbox =
|
||||
discord_textbox_flow.add {type = 'text-box', text = 'https://www.redmew.com/discord '}
|
||||
local discord_textbox = discord_textbox_flow.add {type = 'text-box', text = 'https://www.redmew.com/discord '}
|
||||
discord_textbox.read_only = true
|
||||
discord_textbox.style.width = 235
|
||||
discord_textbox.style.height = 28
|
||||
centered_label(parent, 'Contribute to our Patreon to receive special perks and help maintain our servers.')
|
||||
centered_label(parent, {'info.links_patreon'})
|
||||
local patreon_flow = parent.add {type = 'flow', direction = 'horizontal'}
|
||||
local patreon_flow_style = patreon_flow.style
|
||||
patreon_flow_style.horizontal_align = 'center'
|
||||
@ -239,7 +212,7 @@ This can be changed in options -> controls -> "toggle lua console".
|
||||
patreon_textbox.read_only = true
|
||||
patreon_textbox.style.width = 235
|
||||
patreon_textbox.style.height = 28
|
||||
centered_label(parent, 'Download our maps, start and finish state, from our website.')
|
||||
centered_label(parent, {'info.links_saves'})
|
||||
local save_textbox_flow = parent.add {type = 'flow'}
|
||||
local save_textbox_flow_style = save_textbox_flow.style
|
||||
save_textbox_flow_style.horizontal_align = 'center'
|
||||
@ -249,14 +222,13 @@ This can be changed in options -> controls -> "toggle lua console".
|
||||
save_textbox.read_only = true
|
||||
save_textbox.style.width = 235
|
||||
save_textbox.style.height = 28
|
||||
centered_label(parent, 'View our past maps as a Google Map.')
|
||||
centered_label(parent, {'info.links_factoriomaps'})
|
||||
local maps_textbox_flow = parent.add {type = 'flow'}
|
||||
local maps_textbox_flow_style = maps_textbox_flow.style
|
||||
maps_textbox_flow_style.horizontal_align = 'center'
|
||||
maps_textbox_flow_style.horizontally_stretchable = true
|
||||
maps_textbox_flow.add({type = 'label', caption = 'Maps: '}).style.font = 'default-bold'
|
||||
local maps_textbox =
|
||||
maps_textbox_flow.add {type = 'text-box', text = 'https://factoriomaps.com/browse/redmew.html '}
|
||||
local maps_textbox = maps_textbox_flow.add {type = 'text-box', text = 'https://factoriomaps.com/browse/redmew.html '}
|
||||
maps_textbox.read_only = true
|
||||
maps_textbox.style.width = 315
|
||||
maps_textbox.style.height = 28
|
||||
@ -284,23 +256,14 @@ This can be changed in options -> controls -> "toggle lua console".
|
||||
parent_style.vertically_stretchable = false
|
||||
parent_style.width = 600
|
||||
|
||||
header_label(parent, 'Rules')
|
||||
header_label(parent, {'info.rules_header'})
|
||||
|
||||
centered_label(
|
||||
parent,
|
||||
[[
|
||||
Have fun and play nice. Remember we are all just here to have fun so let’s keep it that way.
|
||||
|
||||
No hateful content or personal attacks.
|
||||
|
||||
If you suspect someone is griefing, notify the admin team by using /report or by clicking the report button next to the player in the player list.
|
||||
]]
|
||||
)
|
||||
centered_label(parent, {'info.rules_text'})
|
||||
end
|
||||
},
|
||||
{
|
||||
tab_button = function(parent)
|
||||
local button = parent.add {type = 'button', name = tab_button_name, caption = 'Map Info'}
|
||||
local button = parent.add {type = 'button', name = tab_button_name, caption = {'info.map_info_button'}}
|
||||
return button
|
||||
end,
|
||||
content = function(parent, player)
|
||||
@ -312,7 +275,7 @@ If you suspect someone is griefing, notify the admin team by using /report or by
|
||||
top_flow_style.horizontal_align = 'center'
|
||||
top_flow_style.horizontally_stretchable = true
|
||||
|
||||
local top_label = top_flow.add {type = 'label', caption = 'Map Information'}
|
||||
local top_label = top_flow.add {type = 'label', caption = {'info.map_info_header'}}
|
||||
local top_label_style = top_label.style
|
||||
top_label_style.font = 'default-dialog-button'
|
||||
|
||||
@ -320,7 +283,7 @@ If you suspect someone is griefing, notify the admin team by using /report or by
|
||||
local grid_style = grid.style
|
||||
grid_style.horizontally_stretchable = true
|
||||
|
||||
grid.add {type = 'label', caption = 'Map name: '}
|
||||
grid.add {type = 'label', caption = {'info.map_name_label'}}
|
||||
local map_name_textbox =
|
||||
grid.add({type = 'flow'}).add {
|
||||
type = 'text-box',
|
||||
@ -336,7 +299,7 @@ If you suspect someone is griefing, notify the admin team by using /report or by
|
||||
|
||||
Gui.set_data(map_name_textbox, map_name_key)
|
||||
|
||||
grid.add {type = 'label', caption = 'Map description: '}
|
||||
grid.add {type = 'label', caption = {'info.map_desc_label'}}
|
||||
local map_description_textbox =
|
||||
grid.add({type = 'flow'}).add {
|
||||
type = 'text-box',
|
||||
@ -354,7 +317,7 @@ If you suspect someone is griefing, notify the admin team by using /report or by
|
||||
|
||||
Gui.set_data(map_description_textbox, map_description_key)
|
||||
|
||||
grid.add {type = 'label', caption = 'Extra Info: '}
|
||||
grid.add {type = 'label', caption = {'info.map_extra_info_label'}}
|
||||
local map_extra_info_textbox =
|
||||
grid.add({type = 'flow'}).add {
|
||||
type = 'text-box',
|
||||
@ -373,7 +336,7 @@ If you suspect someone is griefing, notify the admin team by using /report or by
|
||||
},
|
||||
{
|
||||
tab_button = function(parent)
|
||||
local button = parent.add {type = 'button', name = tab_button_name, caption = 'Scenario Mods'}
|
||||
local button = parent.add {type = 'button', name = tab_button_name, caption = {'info.softmods_button'}}
|
||||
return button
|
||||
end,
|
||||
content = function(parent, player)
|
||||
@ -391,7 +354,7 @@ If you suspect someone is griefing, notify the admin team by using /report or by
|
||||
parent_style = parent.style
|
||||
parent_style.vertically_stretchable = true
|
||||
|
||||
header_label(parent, 'Soft Mods and Server Plugins')
|
||||
header_label(parent, {'info.softmods_header'})
|
||||
|
||||
local grid = parent.add {type = 'table', column_count = 3}
|
||||
local grid_style = grid.style
|
||||
@ -407,16 +370,12 @@ If you suspect someone is griefing, notify the admin team by using /report or by
|
||||
local ranks_label =
|
||||
ranks_flow.add {
|
||||
type = 'label',
|
||||
caption = [[
|
||||
We have a basic rank system to prevent griefing. You can't use nukes or the
|
||||
deconstruction planner if you are a guest. If you play for a couple of hours an
|
||||
admin will promote you to regular. You may also ask an admin for a promotion if
|
||||
you're working on a project which requires it.]]
|
||||
caption = {'info.softmods_rank_text'}
|
||||
}
|
||||
local ranks_label_style = ranks_label.style
|
||||
ranks_label_style.single_line = false
|
||||
local player_rank_flow = ranks_flow.add {type = 'flow', direction = 'horizontal'}
|
||||
player_rank_flow.add {type = 'label', caption = 'Your rank is:'}
|
||||
player_rank_flow.add {type = 'label', caption = {'info.softmods_rank_is'}}
|
||||
local player_name = player.name
|
||||
|
||||
local rank_label = player_rank_flow.add {type = 'label', caption = Rank.get_player_rank_name(player_name)}
|
||||
@ -428,61 +387,47 @@ you're working on a project which requires it.]]
|
||||
end
|
||||
|
||||
grid.add {type = 'sprite', sprite = 'entity/market'}
|
||||
local market = grid.add {type = 'label', caption = 'Market'}
|
||||
local market = grid.add {type = 'label', caption = {'info.softmods_market_label'}}
|
||||
market.style.font = 'default-listbox'
|
||||
local market_label =
|
||||
grid.add {
|
||||
type = 'label',
|
||||
caption = [[
|
||||
On most maps you will find a market near spawn where you can use coins to
|
||||
make purchases. Coins are acquired by chopping trees, hand crafting items and
|
||||
destroying biter nests. Most items in the market are constant but some are
|
||||
map-specific (usually landfill) and will rotate in and out from time to time.]]
|
||||
caption = {'info.softmods_market_text'}
|
||||
}
|
||||
market_label.style.single_line = false
|
||||
|
||||
grid.add {type = 'sprite', sprite = 'item/small-plane'}
|
||||
local train_savior = grid.add {type = 'label', caption = 'Train\nsavior'}
|
||||
local train_savior = grid.add {type = 'label', caption = {'info.softmods_saviour_label'}}
|
||||
local train_savior_style = train_savior.style
|
||||
train_savior_style.font = 'default-listbox'
|
||||
train_savior_style.single_line = false
|
||||
local train_savior_label =
|
||||
grid.add {
|
||||
type = 'label',
|
||||
caption = [[
|
||||
Trains are a factorio players' worst enemy. If you have at least one small plane
|
||||
in your inventory and would be killed by a train, your life will be spared
|
||||
but you will lose a small plane. You can get planes from the market.
|
||||
]]
|
||||
caption = {'info.softmods_saviour_text'}
|
||||
}
|
||||
train_savior_label.style.single_line = false
|
||||
|
||||
if config.player_list.enabled then
|
||||
grid.add {type = 'sprite', sprite = 'entity/player'}
|
||||
local player_list = grid.add {type = 'label', caption = 'Player\nlist'}
|
||||
local player_list = grid.add {type = 'label', caption = {'info.softmods_plist_label'}}
|
||||
player_list.style.font = 'default-listbox'
|
||||
player_list.style.single_line = false
|
||||
local player_list_label =
|
||||
grid.add {
|
||||
type = 'label',
|
||||
caption = [[
|
||||
Lists all players on the server and shows some stats. You can sort the list by
|
||||
clicking on the column headers. You can also poke people, which throws a random
|
||||
noun in the chat.]]
|
||||
caption = {'info.softmods_plist_text'}
|
||||
}
|
||||
player_list_label.style.single_line = false
|
||||
end
|
||||
if config.poll.enabled then
|
||||
grid.add {type = 'sprite', sprite = 'item/programmable-speaker'}
|
||||
local poll = grid.add {type = 'label', caption = 'Polls'}
|
||||
local poll = grid.add {type = 'label', caption = {'info.softmods_polls_label'}}
|
||||
poll.style.font = 'default-listbox'
|
||||
local poll_label =
|
||||
grid.add {
|
||||
type = 'label',
|
||||
caption = [[
|
||||
Polls help players get consensus for major actions. Want to improve an important
|
||||
build? Make a poll to check everyone is ok with that. You need to be a regular
|
||||
to make new polls.]]
|
||||
caption = {'info.softmods_polls_text'}
|
||||
}
|
||||
poll_label.style.single_line = false
|
||||
end
|
||||
@ -492,36 +437,31 @@ to make new polls.]]
|
||||
local tag_button_style = tag_button.style
|
||||
tag_button_style.font = 'default-listbox'
|
||||
tag_button_style.font_color = Color.black
|
||||
local tag = grid.add {type = 'label', caption = 'Tags'}
|
||||
local tag = grid.add {type = 'label', caption = {'info.softmods_tags_label'}}
|
||||
tag.style.font = 'default-listbox'
|
||||
local tag_label =
|
||||
grid.add {
|
||||
type = 'label',
|
||||
caption = [[
|
||||
You can assign yourself a role with tags to let other players know what you are
|
||||
doing. Or just use the tag as decoration. Regulars can create new custom tags,
|
||||
be sure to show off your creatively.]]
|
||||
caption = {'info.softmods_tags_text'}
|
||||
}
|
||||
tag_label.style.single_line = false
|
||||
end
|
||||
|
||||
if config.tasklist.enabled then
|
||||
grid.add {type = 'sprite', sprite = 'item/repair-pack'}
|
||||
local task = grid.add {type = 'label', caption = 'Tasks'}
|
||||
local task = grid.add {type = 'label', caption = {'info.softmods_tasks_label'}}
|
||||
task.style.font = 'default-listbox'
|
||||
local task_label =
|
||||
grid.add {
|
||||
type = 'label',
|
||||
caption = [[
|
||||
Not sure what you should be working on, why not look at the tasks and see what
|
||||
needs doing. Regulars can add new tasks.]]
|
||||
caption = {'info.softmods_tasks_text'}
|
||||
}
|
||||
task_label.style.single_line = false
|
||||
end
|
||||
|
||||
if config.blueprint_helper.enabled then
|
||||
grid.add {type = 'sprite', sprite = 'item/blueprint'}
|
||||
local blueprint = grid.add {type = 'label', caption = 'BP\nhelper'}
|
||||
local blueprint = grid.add {type = 'label', caption = {'info.softmods_bp_label'}}
|
||||
local blueprint_style = blueprint.style
|
||||
blueprint_style.font = 'default-listbox'
|
||||
blueprint_style.single_line = false
|
||||
@ -529,22 +469,19 @@ needs doing. Regulars can add new tasks.]]
|
||||
local blueprint_label =
|
||||
grid.add {
|
||||
type = 'label',
|
||||
caption = [[
|
||||
The Blueprint helper™ lets you flip blueprints horizontally or vertically and lets you
|
||||
converter the entities used in the blueprint e.g. turn yellow belts into red belts.]]
|
||||
caption = {'info.softmods_bp_text'}
|
||||
}
|
||||
blueprint_label.style.single_line = false
|
||||
end
|
||||
|
||||
if config.score.enabled then
|
||||
grid.add {type = 'sprite', sprite = 'item/rocket-silo'}
|
||||
local score = grid.add {type = 'label', caption = 'Score'}
|
||||
local score = grid.add {type = 'label', caption = {'info.softmods_score_label'}}
|
||||
score.style.font = 'default-listbox'
|
||||
local score_label =
|
||||
grid.add {
|
||||
type = 'label',
|
||||
caption = [[
|
||||
Shows number of rockets launched and biters liberated.]]
|
||||
caption = {'info.softmods_score_text'}
|
||||
}
|
||||
score_label.style.single_line = false
|
||||
end
|
||||
@ -552,7 +489,7 @@ Shows number of rockets launched and biters liberated.]]
|
||||
},
|
||||
{
|
||||
tab_button = function(parent)
|
||||
local button = parent.add {type = 'button', name = tab_button_name, caption = "What's New"}
|
||||
local button = parent.add {type = 'button', name = tab_button_name, caption = {'info.whats_new_button'}}
|
||||
return button
|
||||
end,
|
||||
content = function(parent, player)
|
||||
@ -667,7 +604,7 @@ local function draw_main_frame(center, player)
|
||||
bottom_flow_style.top_padding = 8
|
||||
bottom_flow_style.horizontally_stretchable = true
|
||||
|
||||
bottom_flow.add {type = 'button', name = main_button_name, caption = 'Close'}
|
||||
bottom_flow.add {type = 'button', name = main_button_name, caption = {'common.close_button'}}
|
||||
|
||||
player.opened = frame
|
||||
end
|
||||
@ -793,15 +730,8 @@ Gui.on_click(
|
||||
Gui.clear(content)
|
||||
|
||||
pages[index].content(content, player)
|
||||
local string =
|
||||
format(
|
||||
'%s %s%s awarded for reading a tab on the info screen.',
|
||||
reward_amount,
|
||||
reward_token,
|
||||
reward_plural_indicator
|
||||
)
|
||||
if rewarded_players[player.index] then
|
||||
reward_player(player, index, string)
|
||||
reward_player(player, index, {'info.free_coin_print', reward_amount, reward_token})
|
||||
end
|
||||
end
|
||||
)
|
||||
|
@ -1329,11 +1329,11 @@ end
|
||||
Command.add(
|
||||
'poll',
|
||||
{
|
||||
description = {'command_description.poll'},
|
||||
arguments = {'poll'},
|
||||
required_rank = Ranks.regular,
|
||||
allowed_by_server = true,
|
||||
description = 'Creates a new poll',
|
||||
custom_help_text = '<{question = "question", answers = {"answer 1", "answer 2"}, duration = 300}>',
|
||||
custom_help_text = {'command_custom_help.poll'},
|
||||
log_command = true,
|
||||
capture_excess_arguments = true
|
||||
},
|
||||
@ -1343,7 +1343,7 @@ Command.add(
|
||||
Command.add(
|
||||
'poll-result',
|
||||
{
|
||||
description = 'Prints the result for the given poll number.',
|
||||
description = {'command_description.poll_result'},
|
||||
arguments = {'poll'},
|
||||
allowed_by_server = true
|
||||
},
|
||||
|
@ -145,7 +145,7 @@ end
|
||||
Command.add(
|
||||
'popup',
|
||||
{
|
||||
description = 'Shows a popup to all connected players',
|
||||
description = {'command_description.popup'},
|
||||
arguments = {'message'},
|
||||
required_rank = Ranks.admin,
|
||||
capture_excess_arguments = true,
|
||||
@ -157,7 +157,7 @@ Command.add(
|
||||
Command.add(
|
||||
'popup-update',
|
||||
{
|
||||
description = 'Shows an update popup to all connected players',
|
||||
description = {'command_description.popup_update'},
|
||||
arguments = {'version'},
|
||||
required_rank = Ranks.admin,
|
||||
capture_excess_arguments = true,
|
||||
@ -169,7 +169,7 @@ Command.add(
|
||||
Command.add(
|
||||
'popup-player',
|
||||
{
|
||||
description = 'Shows a popup to the player.',
|
||||
description = {'command_description.popup_player'},
|
||||
arguments = {'player', 'message'},
|
||||
required_rank = Ranks.admin,
|
||||
capture_excess_arguments = true,
|
||||
|
@ -688,7 +688,7 @@ end
|
||||
Command.add(
|
||||
'tag',
|
||||
{
|
||||
description = "Sets a player's tag",
|
||||
description = {"command_description.tag"},
|
||||
arguments = {'player', 'tag'},
|
||||
required_rank = Ranks.admin,
|
||||
capture_excess_arguments = true,
|
||||
|
@ -1075,7 +1075,7 @@ Gui.allow_player_to_toggle_top_element_visibility(main_button_name)
|
||||
Command.add(
|
||||
'task',
|
||||
{
|
||||
description = 'Creates a new task.',
|
||||
description = {'command_description.task'},
|
||||
arguments = {'task'},
|
||||
required_rank = Ranks.regular,
|
||||
allowed_by_server = true,
|
||||
|
@ -11,7 +11,6 @@ local Ranks = require 'resources.ranks'
|
||||
|
||||
local pairs = pairs
|
||||
local next = next
|
||||
local format = string.format
|
||||
|
||||
local toast_volume_name = 'toast-volume'
|
||||
Settings.register(toast_volume_name, 'fraction', 1.0)
|
||||
@ -255,7 +254,7 @@ end
|
||||
Command.add(
|
||||
'toast',
|
||||
{
|
||||
description = 'Sends a toast to all players',
|
||||
description = {'command_description.toast'},
|
||||
arguments = {'msg'},
|
||||
capture_excess_arguments = true,
|
||||
required_rank = Ranks.admin,
|
||||
@ -263,14 +262,14 @@ Command.add(
|
||||
},
|
||||
function(args)
|
||||
Public.toast_all_players(15, args.msg)
|
||||
Utils.print_admins(format('%s sent a toast to all players', Utils.get_actor()))
|
||||
Utils.print_admins({'command_description.sent_all_toast', Utils.get_actor()})
|
||||
end
|
||||
)
|
||||
|
||||
Command.add(
|
||||
'toast-player',
|
||||
{
|
||||
description = 'Sends a toast to a specific player',
|
||||
description = {'command_description.toast_player'},
|
||||
arguments = {'player', 'msg'},
|
||||
capture_excess_arguments = true,
|
||||
required_rank = Ranks.admin,
|
||||
@ -281,7 +280,7 @@ Command.add(
|
||||
local target = game.players[target_name]
|
||||
if target then
|
||||
Public.toast_player(target, 15, args.msg)
|
||||
Utils.print_admins(format('%s sent a toast to %s', Utils.get_actor(), target_name))
|
||||
Utils.print_admins({'command_description.sent_player_toast', Utils.get_actor(), target_name})
|
||||
else
|
||||
Game.player_print({'common.fail_no_target', target_name}, Color.yellow)
|
||||
end
|
||||
|
@ -105,7 +105,7 @@ Event.add(defines.events.on_built_entity, function(event)
|
||||
end)
|
||||
|
||||
Command.add('lazy-bastard-bootstrap', {
|
||||
description = 'Puts down the minimum requirements to get started',
|
||||
description = {'command_description.lazy_bastard_bootstrap'},
|
||||
required_rank = Ranks.admin,
|
||||
}, function(_, player)
|
||||
local surface = player.surface
|
||||
|
@ -312,7 +312,7 @@ end
|
||||
Command.add(
|
||||
'market',
|
||||
{
|
||||
description = 'Places a market near you. Use /market removeall to remove all markets on a map',
|
||||
description = {'command_description.market'},
|
||||
arguments = {'removeall'},
|
||||
default_values = {removeall = false},
|
||||
required_rank = Ranks.admin
|
||||
|
@ -7,26 +7,29 @@ local format = string.format
|
||||
local Performance = {}
|
||||
|
||||
local mining_efficiency = {
|
||||
active_modifier = 0,
|
||||
active_modifier = 0
|
||||
}
|
||||
|
||||
local craft_bonus = {
|
||||
active_modifier = 0,
|
||||
active_modifier = 0
|
||||
}
|
||||
|
||||
local running_bonus = {
|
||||
active_modifier = 0,
|
||||
active_modifier = 0
|
||||
}
|
||||
|
||||
Global.register({
|
||||
mining_efficiency = mining_efficiency,
|
||||
craft_bonus = craft_bonus,
|
||||
running_bonus = running_bonus
|
||||
}, function(tbl)
|
||||
mining_efficiency = tbl.mining_efficiency
|
||||
craft_bonus = tbl.craft_bonus
|
||||
running_bonus = tbl.running_bonus
|
||||
end)
|
||||
Global.register(
|
||||
{
|
||||
mining_efficiency = mining_efficiency,
|
||||
craft_bonus = craft_bonus,
|
||||
running_bonus = running_bonus
|
||||
},
|
||||
function(tbl)
|
||||
mining_efficiency = tbl.mining_efficiency
|
||||
craft_bonus = tbl.craft_bonus
|
||||
running_bonus = tbl.running_bonus
|
||||
end
|
||||
)
|
||||
|
||||
---Sets the scale of performance.
|
||||
---1 means the game runs at normal game speed with normal walking speed
|
||||
@ -63,7 +66,7 @@ end
|
||||
Command.add(
|
||||
'performance-scale-set',
|
||||
{
|
||||
description = 'Sets the performance scale between 0.05 and 1. Will alter the game speed, manual mining speed, manual crafting speed and character running speed per force.',
|
||||
description = {'command_description.performance_scale_set'},
|
||||
arguments = {'scale'},
|
||||
required_rank = Ranks.admin,
|
||||
allowed_by_server = true
|
||||
@ -71,31 +74,31 @@ Command.add(
|
||||
function(arguments, player)
|
||||
local scale = tonumber(arguments.scale)
|
||||
if scale == nil or scale < 0.05 or scale > 1 then
|
||||
player.print('Scale must be a valid number ranging from 0.05 to 1')
|
||||
player.print({'performance.fail_wrong_argument'})
|
||||
return
|
||||
end
|
||||
|
||||
Performance.set_time_scale(scale)
|
||||
local p = game.print
|
||||
local stat_mod = Performance.get_player_stat_modifier()
|
||||
p('## - Game speed changed to compensate for UPS drops and players trying to catch up.')
|
||||
p(format('## - Game speed: %.2f', Performance.get_time_scale()))
|
||||
p(format('## - Running speed: %.2f', stat_mod))
|
||||
p(format('## - Manual mining speed: %.2f', stat_mod))
|
||||
p(format('## - Manual crafting speed: %.2f', stat_mod))
|
||||
p({'performance.stat_preamble'})
|
||||
p({'performance.generic_stat', {'performance.game_speed'}, format('%.2f', Performance.get_time_scale())})
|
||||
local stat_string = format('%.2f', stat_mod)
|
||||
p({'performance.output_formatter', {'performance.game_speed'}, stat_string, {'performance.manual_mining_speed'}, stat_string, {'performance.manual_crafting_speed'}, stat_string})
|
||||
end
|
||||
)
|
||||
|
||||
Command.add(
|
||||
'performance-scale-get',
|
||||
{
|
||||
description = 'Shows the current performance scale.'
|
||||
description = {'command_description.performance_scale_get'}
|
||||
},
|
||||
function(_, player)
|
||||
local p = player.print
|
||||
local stat_mod = Performance.get_player_stat_modifier()
|
||||
p(format('Game speed: %.2f', Performance.get_time_scale()))
|
||||
p(format('Running speed: %.2f -- mining speed: %.2f -- crafting speed: %.2f', stat_mod, stat_mod, stat_mod))
|
||||
p({'performance.generic_stat', {'performance.game_speed'}, format('%.2f', Performance.get_time_scale())})
|
||||
local stat_string = format('%.2f', stat_mod)
|
||||
p({'performance.output_formatter', {'performance.game_speed'}, stat_string, {'performance.manual_mining_speed'}, stat_string, {'performance.manual_crafting_speed'}, stat_string})
|
||||
end
|
||||
)
|
||||
|
||||
|
@ -43,7 +43,7 @@ end
|
||||
Command.add(
|
||||
'redmew-color',
|
||||
{
|
||||
description = 'Set will save your current color for future maps. Reset will erase your saved color. Random will give you a random color.',
|
||||
description = {'command_description.redmew_color'},
|
||||
arguments = {'set-reset-random'},
|
||||
required_rank = Ranks.regular
|
||||
},
|
||||
@ -56,16 +56,16 @@ Command.add(
|
||||
chat_color = player.chat_color
|
||||
}
|
||||
Server.set_data('colors', player_name, data)
|
||||
player.print('Your color has been saved. Any time you join a redmew server your color will automatically be set.')
|
||||
Utils.print_except(player_name .. ' has saved their color server-side for future maps. You can do the same! Check out /help redmew-color', player)
|
||||
player.print({'player_colors.color_saved'})
|
||||
Utils.print_except({'player_colors.color_saved_advert, player'})
|
||||
elseif arg == 'reset' then
|
||||
Server.set_data('colors', player_name, nil)
|
||||
player.print('Your saved color (if you had one) has been removed.')
|
||||
player.print({'player_colors.color_reset'})
|
||||
elseif arg == 'random' then
|
||||
local color_data = Public.set_random_color(player)
|
||||
player.print('Your color has been changed to: ' .. serialize(color_data))
|
||||
player.print({'player_colors.color_random', serialize(color_data)})
|
||||
else
|
||||
player.print('Only set, reset, and random are accepted arguments')
|
||||
player.print({'player_colors.fail_wrong_argument'})
|
||||
end
|
||||
end
|
||||
)
|
||||
|
113
features/player_onboarding.lua
Normal file
113
features/player_onboarding.lua
Normal file
@ -0,0 +1,113 @@
|
||||
--[[
|
||||
This module aims to gradually teach players about redmew-specific features.
|
||||
]]
|
||||
-- Dependencies
|
||||
local Event = require 'utils.event'
|
||||
local Game = require 'utils.game'
|
||||
local Global = require 'utils.global'
|
||||
local Rank = require 'features.rank_system'
|
||||
local Task = require 'utils.task'
|
||||
local Toast = require 'features.gui.toast'
|
||||
local Token = require 'utils.token'
|
||||
local Ranks = require 'resources.ranks'
|
||||
|
||||
-- Constants
|
||||
local time_to_toast = 600 -- 60s * 10 mins
|
||||
local time_to_chat = 1200 -- 60s * 20 mins
|
||||
|
||||
-- Local vars
|
||||
local Public = {}
|
||||
|
||||
-- Global-registered locals
|
||||
local player_chatted = {}
|
||||
Global.register(
|
||||
{
|
||||
player_chatted = player_chatted
|
||||
},
|
||||
function(tbl)
|
||||
player_chatted = tbl.player_chatted
|
||||
end
|
||||
)
|
||||
|
||||
-- Local functions
|
||||
local toast_token =
|
||||
Token.register(
|
||||
function(data)
|
||||
local player_index = data.player_index
|
||||
|
||||
if data.chat_teaching and player_chatted[player_index] then
|
||||
return
|
||||
end
|
||||
|
||||
local player = Game.get_player_by_index(player_index)
|
||||
if not player or not player.valid or not player.connected then
|
||||
return
|
||||
end
|
||||
|
||||
Toast.toast_player(player, 60, data.msg)
|
||||
end
|
||||
)
|
||||
|
||||
local function on_player_created(event)
|
||||
local player_index = event.player_index
|
||||
local player = Game.get_player_by_index(player_index)
|
||||
if not player or not player.valid then
|
||||
return
|
||||
end
|
||||
|
||||
local player_name = player.name
|
||||
if Rank.equal(player_name, Ranks.guest) then
|
||||
Task.set_timeout(
|
||||
time_to_toast,
|
||||
toast_token,
|
||||
{
|
||||
player_index = player_index,
|
||||
msg = {'player_onboarding.teach_toast'}
|
||||
}
|
||||
)
|
||||
Task.set_timeout(
|
||||
time_to_chat,
|
||||
toast_token,
|
||||
{
|
||||
player_index = player_index,
|
||||
chat_teaching = true,
|
||||
msg = {
|
||||
'player_onboarding.teach_chat',
|
||||
{'gui-menu.settings'},
|
||||
{'gui-menu.controls'},
|
||||
{'controls.toggle-console'}
|
||||
}
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
--- Log all players who have chatted or used commands this map.
|
||||
-- This will also gives us a measure of how many players engage in chat in a map.
|
||||
local function on_player_chat(event)
|
||||
local player_index = event.player_index
|
||||
if not player_index then
|
||||
return
|
||||
end
|
||||
|
||||
local player = Game.get_player_by_index(player_index)
|
||||
if not player or not player.valid then
|
||||
return
|
||||
end
|
||||
|
||||
player_chatted[player_index] = true
|
||||
end
|
||||
|
||||
-- Public functions
|
||||
|
||||
--- Returns the number of players who have chatted or used a command this map.
|
||||
function Public.get_num_players_chatted()
|
||||
return table_size(player_chatted)
|
||||
end
|
||||
|
||||
-- Event registers
|
||||
Event.add(defines.events.on_player_created, on_player_created)
|
||||
Event.add(defines.events.on_console_chat, on_player_chat)
|
||||
Event.add(defines.events.on_console_command, on_player_chat)
|
||||
|
||||
return Public
|
@ -7,8 +7,8 @@ local Event = require 'utils.event'
|
||||
local Game = require 'utils.game'
|
||||
local Command = require 'utils.command'
|
||||
local Global = require 'utils.global'
|
||||
|
||||
local Ranks = require 'resources.ranks'
|
||||
local Color = require 'resources.color_presets'
|
||||
|
||||
local primitives = {reactors_enabled = global.config.reactor_meltdown.on_by_default}
|
||||
local wastelands = {}
|
||||
@ -164,40 +164,48 @@ local function entity_build(event)
|
||||
end
|
||||
end
|
||||
|
||||
local function reactor_toggle()
|
||||
primitives.reactors_enabled = not primitives.reactors_enabled
|
||||
--- Prints whether meltdown is on or off
|
||||
local function get_meltdown()
|
||||
if primitives.reactors_enabled then
|
||||
game.print('Reactor meltdown activated.')
|
||||
Game.player_print({'meltdown.is_enabled'})
|
||||
else
|
||||
game.print('Reactor meltdown deactivated.')
|
||||
Game.player_print({'meltdown.is_disabled'})
|
||||
end
|
||||
end
|
||||
|
||||
local function is_meltdown()
|
||||
if primitives.reactors_enabled then
|
||||
Game.player_print('Reactor meltdown is enabled.')
|
||||
--- Toggles meltdown on or off
|
||||
local function set_meltdown(args)
|
||||
local on_off = args['on|off']
|
||||
if on_off == 'on' then
|
||||
primitives.reactors_enabled = true
|
||||
game.print({'meltdown.enable'})
|
||||
elseif on_off == 'off' then
|
||||
primitives.reactors_enabled = nil
|
||||
game.print({'meltdown.disable'})
|
||||
else
|
||||
Game.player_print('Reactor meltdown is disabled.')
|
||||
Game.player_print({'meltdown.error_not_on_off'}, Color.fail)
|
||||
end
|
||||
end
|
||||
|
||||
Command.add(
|
||||
'meltdown',
|
||||
'meltdown-get',
|
||||
{
|
||||
description = 'Toggles if reactors blow up',
|
||||
required_rank = Ranks.admin,
|
||||
allowed_by_server = true,
|
||||
log_command = true
|
||||
description = {'command_description.meltdown_get'},
|
||||
allowed_by_server = true
|
||||
},
|
||||
reactor_toggle
|
||||
get_meltdown
|
||||
)
|
||||
|
||||
Command.add(
|
||||
'is-meltdown',
|
||||
'meltdown-set',
|
||||
{
|
||||
description = 'Prints if meltdown is enabled',
|
||||
allowed_by_server = true
|
||||
description = {'command_description.meltdown_set'},
|
||||
arguments = {'on|off'},
|
||||
allowed_by_server = true,
|
||||
required_rank = Ranks.admin,
|
||||
log_command = true
|
||||
},
|
||||
is_meltdown
|
||||
set_meltdown
|
||||
)
|
||||
|
||||
Event.on_nth_tick(60, on_tick)
|
||||
|
@ -1,22 +1,23 @@
|
||||
local Game = require 'utils.game'
|
||||
local Timestamp = require 'utils.timestamp'
|
||||
local Command = require 'utils.command'
|
||||
local Settings = require 'utils.redmew_settings'
|
||||
local Utils = require 'utils.core'
|
||||
local Server = require 'features.server'
|
||||
local Walkabout = require 'features.walkabout'
|
||||
local PlayerStats = require 'features.player_stats'
|
||||
local Rank = require 'features.rank_system'
|
||||
local Donator = require 'features.donator'
|
||||
local Color = require 'resources.color_presets'
|
||||
|
||||
local format = string.format
|
||||
-- local ceil = math.ceil
|
||||
local concat = table.concat
|
||||
local pcall = pcall
|
||||
local tostring = tostring
|
||||
local tonumber = tonumber
|
||||
local pairs = pairs
|
||||
|
||||
--- Informs the actor that there is no target. Acts as a central place where this message can be changed.
|
||||
local function print_no_target(target_name)
|
||||
Game.player_print({'common.fail_no_target', target_name}, Color.fail)
|
||||
end
|
||||
|
||||
--- Kill a player with fish as the cause of death.
|
||||
local function do_fish_kill(player, suicide)
|
||||
local c = player.character
|
||||
@ -37,40 +38,30 @@ end
|
||||
|
||||
--- Kill a player: admins and the server can kill others, non-admins can only kill themselves
|
||||
local function kill(args, player)
|
||||
local target_name = args.player
|
||||
local target
|
||||
if target_name then
|
||||
target = game.players[target_name]
|
||||
local target_ident = args.player
|
||||
local target, target_name = Utils.validate_player(target_ident)
|
||||
if target_ident and not target then
|
||||
if not target then
|
||||
Game.player_print(format('Player %s was not found.', target_name))
|
||||
print_no_target(target_ident)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if (player and Walkabout.is_on_walkabout(player.index)) or (target and Walkabout.is_on_walkabout(target.index)) then
|
||||
Game.player_print("A player on walkabout cannot be killed by a mere fish, don't waste your efforts.")
|
||||
return
|
||||
end
|
||||
|
||||
if not target and player then
|
||||
if not do_fish_kill(player, true) then
|
||||
Game.player_print("Sorry, you don't have a character to kill.")
|
||||
end
|
||||
elseif player then
|
||||
if target == player then
|
||||
if player then
|
||||
if not target or target == player then -- player suicide
|
||||
if not do_fish_kill(player, true) then
|
||||
Game.player_print("Sorry, you don't have a character to kill.")
|
||||
Game.player_print({'redmew_commands.kill_fail_suicide_no_character'})
|
||||
end
|
||||
elseif target and player.admin then
|
||||
elseif target and player.admin then -- admin killing target
|
||||
if not do_fish_kill(target) then
|
||||
Game.player_print(table.concat {"'Sorry, '", target.name, "' doesn't have a character to kill."})
|
||||
Game.player_print({'redmew_commands.kill_fail_target_no_character'}, target_name)
|
||||
end
|
||||
else
|
||||
Game.player_print("Sorry you don't have permission to use the kill command on other players.")
|
||||
else -- player failing to kill target
|
||||
Game.player_print({'redmew_commands.kill_fail_no_perm'})
|
||||
end
|
||||
elseif target then
|
||||
elseif target then -- server killing target
|
||||
if not do_fish_kill(target) then
|
||||
Game.player_print(table.concat {"'Sorry, '", target.name, "' doesn't have a character to kill."})
|
||||
Game.player_print({'redmew_commands.kill_fail_target_no_character'}, target_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -93,36 +84,37 @@ local function afk()
|
||||
end
|
||||
end
|
||||
if count == 0 then
|
||||
Game.player_print('No players afk.')
|
||||
Game.player_print({'redmew_commands.afk_no_afk'})
|
||||
end
|
||||
end
|
||||
|
||||
--- Lets a player set their zoom level
|
||||
local function zoom(args, player)
|
||||
if tonumber(args.zoom) then
|
||||
player.zoom = tonumber(args.zoom)
|
||||
local zoom_val = tonumber(args.zoom)
|
||||
if zoom_val then
|
||||
player.zoom = zoom_val
|
||||
else
|
||||
Game.player_print('You must give zoom a number.')
|
||||
Game.player_print({'redmew_commands.zoom_fail'})
|
||||
end
|
||||
end
|
||||
|
||||
--- Creates an alert for the player at the location of their target
|
||||
local function find_player(args, player)
|
||||
local name = args.player
|
||||
local target_ident = args.player
|
||||
local target, target_name = Utils.validate_player(target_ident)
|
||||
|
||||
local target = game.players[name]
|
||||
if not target then
|
||||
Game.player_print('player ' .. name .. ' not found')
|
||||
print_no_target(target_ident)
|
||||
return
|
||||
end
|
||||
|
||||
target = target.character
|
||||
if not target or not target.valid then
|
||||
Game.player_print('player ' .. name .. ' does not have a character')
|
||||
Game.player_print({'redmew_commands.find_player_fail_no_character', target_name})
|
||||
return
|
||||
end
|
||||
|
||||
player.add_custom_alert(target, {type = 'virtual', name = 'signal-F'}, name, true)
|
||||
player.add_custom_alert(target, {type = 'virtual', name = 'signal-F'}, target_name, true)
|
||||
end
|
||||
|
||||
--- Turns on rail block visualization for player
|
||||
@ -131,7 +123,7 @@ local function show_rail_block(_, player)
|
||||
local show = not vs.show_rail_block_visualisation
|
||||
vs.show_rail_block_visualisation = show
|
||||
|
||||
Game.player_print('show_rail_block_visualisation set to ' .. tostring(show))
|
||||
Game.player_print({'redmew_commands.show_rail_block_success', tostring(show)})
|
||||
end
|
||||
|
||||
--- Provides the time on the server
|
||||
@ -147,65 +139,12 @@ local function server_time(_, player)
|
||||
|
||||
local secs = Server.get_current_time()
|
||||
if secs == nil then
|
||||
p('Server time is not available, is this game running on a Redmew server?')
|
||||
p({'redmew_commands.server_time_fail'})
|
||||
else
|
||||
p(Timestamp.to_string(secs))
|
||||
end
|
||||
end
|
||||
|
||||
local function search_command(arguments) -- TODO: Re-enable this when (locale) has been properly integrated
|
||||
Game.player_print('Sorry, search is temporarily out of order')
|
||||
return arguments -- return args so that we avoid a lint warning
|
||||
|
||||
--[[
|
||||
local keyword = arguments.keyword
|
||||
local p = Game.player_print
|
||||
if #keyword < 2 then
|
||||
p('Keyword should be 2 characters or more')
|
||||
return
|
||||
end
|
||||
|
||||
local per_page = 7
|
||||
local matches = Command.search(keyword)
|
||||
local count = #matches
|
||||
|
||||
if count == 0 then
|
||||
p('---- 0 Search Results ----')
|
||||
p(format('No commands found matching "%s"', keyword))
|
||||
p('-------------------------')
|
||||
return
|
||||
end
|
||||
|
||||
local page = tonumber(arguments.page)
|
||||
local pages = ceil(count / per_page)
|
||||
|
||||
if nil == page then
|
||||
p('Page should be a valid number')
|
||||
return
|
||||
end
|
||||
|
||||
-- just show the last page
|
||||
if page > pages then
|
||||
page = pages
|
||||
end
|
||||
|
||||
if page < 1 then
|
||||
page = 1
|
||||
end
|
||||
|
||||
local page_start = per_page * (page - 1) + 1
|
||||
local page_end = per_page * page
|
||||
page_end = page_end <= count and page_end or count
|
||||
|
||||
p(format('---- %d Search %s -----', count, count == 1 and 'Result' or 'Results'))
|
||||
p(format('Searching for: "%s"', keyword))
|
||||
for i = page_start, page_end do
|
||||
p(format('[%d] /%s', i, matches[i]))
|
||||
end
|
||||
p(format('-------- Page %d / %d --------', page, pages))
|
||||
--[[]]
|
||||
end
|
||||
|
||||
local function list_seeds()
|
||||
local seeds = {}
|
||||
local count_of_seeds = 0
|
||||
@ -227,27 +166,27 @@ local function print_version()
|
||||
if global.redmew_version then
|
||||
version_str = global.redmew_version
|
||||
else
|
||||
version_str = 'This map was created from source code, only releases (zips with names) and server saves have versions'
|
||||
version_str = {'redmew_commands.print_version_from_source'}
|
||||
end
|
||||
Game.player_print(version_str)
|
||||
end
|
||||
|
||||
--- Prints information about the target player
|
||||
local function print_player_info(args, player)
|
||||
local name = args.player
|
||||
local target = game.players[name]
|
||||
local target_ident = args.player
|
||||
local target, target_name, index = Utils.validate_player(target_ident)
|
||||
|
||||
if not target then
|
||||
Game.player_print('Target not found')
|
||||
print_no_target(target_ident)
|
||||
return
|
||||
end
|
||||
|
||||
local index = target.index
|
||||
local info_t = {
|
||||
'redmew_commands.whois_formatter',
|
||||
{'format.1_colon_2', 'Name', name},
|
||||
{'format.1_colon_2', 'Name', target_name},
|
||||
{'format.single_item', target.connected and 'Online: yes' or 'Online: no'},
|
||||
{'format.1_colon_2', 'Index', target.index},
|
||||
{'format.1_colon_2', 'Rank', Rank.get_player_rank_name(name)},
|
||||
{'format.1_colon_2', 'Rank', Rank.get_player_rank_name(target_name)},
|
||||
{'format.single_item', Donator.is_donator(target.name) and 'Donator: yes' or 'Donator: no'},
|
||||
{'format.1_colon_2', 'Time played', Utils.format_time(target.online_time)},
|
||||
{'format.1_colon_2', 'AFK time', Utils.format_time(target.afk_time or 0)},
|
||||
@ -276,7 +215,7 @@ end
|
||||
Command.add(
|
||||
'kill',
|
||||
{
|
||||
description = 'Will kill you.',
|
||||
description = {'command_description.kill'},
|
||||
arguments = {'player'},
|
||||
default_values = {player = false},
|
||||
allowed_by_server = true
|
||||
@ -287,7 +226,7 @@ Command.add(
|
||||
Command.add(
|
||||
'afk',
|
||||
{
|
||||
description = 'Shows how long players have been afk.',
|
||||
description = {'command_description.afk'},
|
||||
allowed_by_server = true
|
||||
},
|
||||
afk
|
||||
@ -296,7 +235,7 @@ Command.add(
|
||||
Command.add(
|
||||
'zoom',
|
||||
{
|
||||
description = 'Sets your zoom.',
|
||||
description = {'command_description.zoom'},
|
||||
arguments = {'zoom'}
|
||||
},
|
||||
zoom
|
||||
@ -305,7 +244,7 @@ Command.add(
|
||||
Command.add(
|
||||
'find',
|
||||
{
|
||||
description = 'shows an alert on the map where the player is located',
|
||||
description = {'command_description.find'},
|
||||
arguments = {'player'}
|
||||
},
|
||||
find_player
|
||||
@ -314,7 +253,7 @@ Command.add(
|
||||
Command.add(
|
||||
'show-rail-block',
|
||||
{
|
||||
description = 'Toggles rail block visualisation.'
|
||||
description = {'command_description.show_rail_block'}
|
||||
},
|
||||
show_rail_block
|
||||
)
|
||||
@ -322,27 +261,16 @@ Command.add(
|
||||
Command.add(
|
||||
'server-time',
|
||||
{
|
||||
description = "Prints the server's time.",
|
||||
description = {'command_description.server_time'},
|
||||
allowed_by_server = true
|
||||
},
|
||||
server_time
|
||||
)
|
||||
|
||||
Command.add(
|
||||
'search-command',
|
||||
{
|
||||
description = 'Search for commands matching the keyword in name or description',
|
||||
arguments = {'keyword', 'page'},
|
||||
default_values = {page = 1},
|
||||
allowed_by_server = true
|
||||
},
|
||||
search_command
|
||||
)
|
||||
|
||||
Command.add(
|
||||
'seeds',
|
||||
{
|
||||
description = 'List the seeds of all surfaces',
|
||||
description = {'command_description.seeds'},
|
||||
allowed_by_server = true
|
||||
},
|
||||
list_seeds
|
||||
@ -351,7 +279,7 @@ Command.add(
|
||||
Command.add(
|
||||
'redmew-version',
|
||||
{
|
||||
description = 'Prints the version of the RedMew scenario',
|
||||
description = {'command_description.redmew_version'},
|
||||
allowed_by_server = true
|
||||
},
|
||||
print_version
|
||||
@ -360,78 +288,10 @@ Command.add(
|
||||
Command.add(
|
||||
'whois',
|
||||
{
|
||||
description = 'provides information about a given player, admins can see the inventory of a player by adding "yes" as a second argument',
|
||||
description = {'command_description.whois'},
|
||||
arguments = {'player', 'inventory'},
|
||||
default_values = {inventory = false},
|
||||
allowed_by_server = true
|
||||
},
|
||||
print_player_info
|
||||
)
|
||||
|
||||
-- No man's land / free for all
|
||||
Command.add(
|
||||
'redmew-setting-set',
|
||||
{
|
||||
description = 'Set a setting for yourself',
|
||||
arguments = {'setting_name', 'new_value'},
|
||||
capture_excess_arguments = true
|
||||
},
|
||||
function(arguments, player)
|
||||
local value
|
||||
local setting_name = arguments.setting_name
|
||||
local success,
|
||||
data =
|
||||
pcall(
|
||||
function()
|
||||
value = Settings.set(player.index, setting_name, arguments.new_value)
|
||||
end
|
||||
)
|
||||
|
||||
if not success then
|
||||
local i = data:find('%s')
|
||||
player.print(data:sub(i + 1))
|
||||
return
|
||||
end
|
||||
|
||||
player.print(format('Changed "%s" to: "%s"', setting_name, value))
|
||||
end
|
||||
)
|
||||
|
||||
Command.add(
|
||||
'redmew-setting-get',
|
||||
{
|
||||
description = 'Display a setting value for yourself',
|
||||
arguments = {'setting_name'}
|
||||
},
|
||||
function(arguments, player)
|
||||
local value
|
||||
local setting_name = arguments.setting_name
|
||||
local success,
|
||||
data =
|
||||
pcall(
|
||||
function()
|
||||
value = Settings.get(player.index, setting_name)
|
||||
end
|
||||
)
|
||||
|
||||
if not success then
|
||||
local i = data:find('%s')
|
||||
player.print(data:sub(i + 1))
|
||||
return
|
||||
end
|
||||
|
||||
player.print(format('Setting "%s" has a value of: "%s"', setting_name, value))
|
||||
end
|
||||
)
|
||||
|
||||
Command.add(
|
||||
'redmew-setting-all',
|
||||
{
|
||||
description = 'Display all settings for yourself'
|
||||
},
|
||||
function(_, player)
|
||||
for name, value in pairs(Settings.all(player.index)) do
|
||||
player.print(format('%s=%s', name, value))
|
||||
end
|
||||
end
|
||||
)
|
||||
|
@ -139,6 +139,45 @@ local loader_check_token =
|
||||
end
|
||||
)
|
||||
|
||||
--- Sets construction robots that are not part of a roboport to unminabe
|
||||
-- if the player selecting them are not the owner of them.
|
||||
local function preserve_bot(event)
|
||||
local player = Game.get_player_by_index(event.player_index)
|
||||
local entity = player.selected
|
||||
|
||||
if entity == nil or not entity.valid then
|
||||
return
|
||||
end
|
||||
|
||||
if entity.name ~= 'construction-robot' then
|
||||
return
|
||||
end
|
||||
local logistic_network = entity.logistic_network
|
||||
|
||||
if logistic_network == nil or not logistic_network.valid then
|
||||
--prevents an orphan bot from being unremovable
|
||||
entity.minable = false
|
||||
return
|
||||
end
|
||||
|
||||
-- All valid logistic networks should have at least one cell
|
||||
local cell = logistic_network.cells[1]
|
||||
local owner = cell.owner
|
||||
|
||||
--checks if construction-robot is part of a mobile logistic network
|
||||
if owner.name ~= 'player' then
|
||||
return
|
||||
end
|
||||
|
||||
--checks if construction-robot is owned by the player that has selected it
|
||||
if owner.player.name == player.name then
|
||||
entity.minable = true
|
||||
return
|
||||
end
|
||||
|
||||
entity.minable = false
|
||||
end
|
||||
|
||||
-- Event registers
|
||||
|
||||
local function register_random_train_color()
|
||||
@ -295,4 +334,8 @@ if config.loaders then
|
||||
Event.add(defines.events.on_research_finished, enable_loaders)
|
||||
end
|
||||
|
||||
if config.save_bots then
|
||||
Event.add(defines.events.on_selected_entity_changed, preserve_bot)
|
||||
end
|
||||
|
||||
return Public
|
||||
|
@ -428,7 +428,7 @@ Gui.on_click(
|
||||
Command.add(
|
||||
'report',
|
||||
{
|
||||
description = 'Reports a user to admins',
|
||||
description = {'command_description.report'},
|
||||
arguments = {'player', 'message'},
|
||||
capture_excess_arguments = true
|
||||
},
|
||||
|
@ -74,7 +74,7 @@ Retailer.events = {
|
||||
-- player = player,
|
||||
-- group_name = group_name,
|
||||
-- }
|
||||
on_market_purchase = script.generate_event_name(),
|
||||
on_market_purchase = Event.generate_event_name('on_market_purchase'),
|
||||
}
|
||||
|
||||
Retailer.item_types = {
|
||||
|
@ -145,7 +145,7 @@ end
|
||||
Command.add(
|
||||
'dataset-copy',
|
||||
{
|
||||
description = 'Copies a dataset',
|
||||
description = {'command_description.dataset_copy'},
|
||||
arguments = {'dataset', 'destination'},
|
||||
required_rank = Ranks.admin,
|
||||
debug_only = true,
|
||||
@ -157,7 +157,7 @@ Command.add(
|
||||
Command.add(
|
||||
'dataset-move',
|
||||
{
|
||||
description = 'Moves a dataset',
|
||||
description = {'command_description.dataset_move'},
|
||||
arguments = {'dataset', 'destination'},
|
||||
required_rank = Ranks.admin,
|
||||
debug_only = true,
|
||||
@ -169,7 +169,7 @@ Command.add(
|
||||
Command.add(
|
||||
'dataset-delete',
|
||||
{
|
||||
description = 'Deletes a dataset',
|
||||
description = {'command_description.dataset_delete'},
|
||||
arguments = {'dataset'},
|
||||
required_rank = Ranks.admin,
|
||||
debug_only = true,
|
||||
@ -276,7 +276,7 @@ end
|
||||
Command.add(
|
||||
'dataset-transform',
|
||||
{
|
||||
description = 'Transforms a dataset and writes it to the target dataset. Calls global.transform_function and sends the table of entries while expecting a table to return.',
|
||||
description = {'command_description.dataset_transform'},
|
||||
arguments = {'dataset', 'destination'},
|
||||
required_rank = Ranks.admin,
|
||||
debug_only = true,
|
||||
@ -288,7 +288,7 @@ Command.add(
|
||||
Command.add(
|
||||
'dataset-transform-test',
|
||||
{
|
||||
description = 'Shows the resulting data set from a transform operation. See /help dataset-transform for more information.',
|
||||
description = {'command_description.dataset_transform_test'},
|
||||
arguments = {'dataset'},
|
||||
required_rank = Ranks.admin,
|
||||
debug_only = true,
|
||||
|
@ -66,7 +66,7 @@ local data_set_handlers = {}
|
||||
-- function()
|
||||
-- Server.try_get_all_data('regulars', callback)
|
||||
-- end)
|
||||
Public.events = {on_server_started = script.generate_event_name()}
|
||||
Public.events = {on_server_started = Event.generate_event_name('on_server_started')}
|
||||
|
||||
--- Sends a message to the linked discord channel. The message is sanitized of markdown server side.
|
||||
-- @param message<string> message to send.
|
||||
|
@ -1,186 +0,0 @@
|
||||
local Task = require 'utils.task'
|
||||
local Game = require 'utils.game'
|
||||
local Event = require 'utils.event'
|
||||
local Token = require 'utils.token'
|
||||
local Command = require 'utils.command'
|
||||
local Global = require 'utils.global'
|
||||
local Ranks = require 'resources.ranks'
|
||||
|
||||
local Public = {}
|
||||
local return_player
|
||||
|
||||
-- Register our globals
|
||||
local walkabouts = {}
|
||||
local primitives = {
|
||||
event_registered = nil
|
||||
}
|
||||
|
||||
Global.register(
|
||||
{
|
||||
walkabouts = walkabouts,
|
||||
primitives = primitives
|
||||
},
|
||||
function(tbl)
|
||||
walkabouts = tbl.walkabouts
|
||||
primitives = tbl.primitives
|
||||
end
|
||||
)
|
||||
|
||||
--- Cleans the walkabout status off players who disconnected during walkabout.
|
||||
local on_join_token =
|
||||
Token.register(
|
||||
function(event)
|
||||
local player = Game.get_player_by_index(event.player_index)
|
||||
local index = player.index
|
||||
|
||||
-- If a player joins and they're marked as being on walkabout but their timer has expired, restore them.
|
||||
if player and walkabouts[index] and walkabouts[index].timer_expired then
|
||||
return_player(index)
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
--- Returns a player from walkabout after the timeout.
|
||||
local redmew_commands_return_player =
|
||||
Token.register(
|
||||
function(player)
|
||||
if not player or not player.valid then
|
||||
log('Warning: redmew_commands_return_player received nil or invalid player')
|
||||
return
|
||||
end
|
||||
|
||||
local index = player.index
|
||||
|
||||
-- If the player is no longer connected, store that fact so we can clean them when/if they rejoin.
|
||||
if player.connected then
|
||||
return_player(index)
|
||||
else
|
||||
walkabouts[index].timer_expired = true
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
return_player = function(index)
|
||||
local data = walkabouts[index]
|
||||
if not data then
|
||||
log('Warning: return_player received nil data')
|
||||
return
|
||||
end
|
||||
|
||||
local player = Game.get_player_by_index(index)
|
||||
if not player or not player.valid then
|
||||
log('Warning: return_player received nil or invalid player')
|
||||
return
|
||||
end
|
||||
|
||||
local walkabout_character = player.character
|
||||
if walkabout_character and walkabout_character.valid then
|
||||
walkabout_character.destroy()
|
||||
end
|
||||
|
||||
local character = data.character
|
||||
if character and character.valid then
|
||||
player.character = character
|
||||
player.character.destructible = true
|
||||
else
|
||||
player.create_character()
|
||||
player.teleport(data.position)
|
||||
end
|
||||
player.force = data.force
|
||||
|
||||
game.print(data.player.name .. ' came back from walkabout.')
|
||||
walkabouts[index] = nil
|
||||
|
||||
if #walkabouts == 0 then
|
||||
--TODO unreg event
|
||||
Event.remove_removable(defines.events.on_player_joined_game, on_join_token)
|
||||
end
|
||||
end
|
||||
|
||||
--- Sends a player on a walkabout:
|
||||
-- They are teleported far away, placed on a neutral force, and are given a new character.
|
||||
-- They are returned after the timeout by redmew_commands_return_player
|
||||
local function walkabout(args)
|
||||
if not global.config.walkabout.enabled then
|
||||
Game.player_print('Walkabout is disabled via the config')
|
||||
return
|
||||
end
|
||||
local player_name = args.player
|
||||
local duration = tonumber(args.duration)
|
||||
|
||||
if not duration then
|
||||
Game.player_print('Duration should be a number, player will be sent on walkabout for the default 60 seconds.')
|
||||
duration = 60
|
||||
end
|
||||
|
||||
if duration < 15 then
|
||||
duration = 15
|
||||
end
|
||||
|
||||
local player = game.players[player_name]
|
||||
if not player or not player.character or walkabouts[player.index] then
|
||||
Game.player_print(player_name .. ' could not go on a walkabout.')
|
||||
return
|
||||
end
|
||||
|
||||
local surface = player.surface
|
||||
local chunk = surface.get_random_chunk()
|
||||
local pos = {x = chunk.x * 32, y = chunk.y * 32}
|
||||
local non_colliding_pos = surface.find_non_colliding_position('player', pos, 100, 1)
|
||||
|
||||
local character = player.character
|
||||
if character and character.valid then
|
||||
character.walking_state = {walking = false, direction = defines.direction.north}
|
||||
end
|
||||
|
||||
if non_colliding_pos then
|
||||
game.print(player_name .. ' went on a walkabout, to find himself.')
|
||||
|
||||
-- Information about the player's former state so we can restore them later
|
||||
local data = {
|
||||
player = player,
|
||||
force = player.force,
|
||||
position = {x = player.position.x, y = player.position.y},
|
||||
character = character
|
||||
}
|
||||
|
||||
Task.set_timeout(duration, redmew_commands_return_player, player)
|
||||
walkabouts[player.index] = data
|
||||
|
||||
if not primitives then
|
||||
Event.add_removable(defines.events.on_player_joined_game, on_join_token)
|
||||
end
|
||||
|
||||
player.character.destructible = false
|
||||
player.character = nil
|
||||
player.create_character()
|
||||
player.teleport(non_colliding_pos)
|
||||
player.force = 'neutral'
|
||||
else
|
||||
Game.player_print('Walkabout failed: could not find non-colliding-position')
|
||||
end
|
||||
end
|
||||
|
||||
--- Checks if a player is on walkabout
|
||||
-- @param player_index <number>
|
||||
-- @return <boolean>
|
||||
function Public.is_on_walkabout(player_index)
|
||||
if walkabouts[player_index] then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
Command.add(
|
||||
'walkabout',
|
||||
{
|
||||
description = 'Send someone on a walk. Duration is in seconds.',
|
||||
arguments = {'player', 'duration'},
|
||||
default_values = {duration = 60},
|
||||
required_rank = Ranks.admin,
|
||||
allowed_by_server = true
|
||||
},
|
||||
walkabout
|
||||
)
|
||||
|
||||
return Public
|
5
locale/de/redmew_command_text.cfg
Normal file
5
locale/de/redmew_command_text.cfg
Normal file
@ -0,0 +1,5 @@
|
||||
# This file holds all the locale strings for command help and descriptions
|
||||
|
||||
[command_description]
|
||||
|
||||
[command_custom_help]
|
18
locale/de/redmew_common.cfg
Normal file
18
locale/de/redmew_common.cfg
Normal file
@ -0,0 +1,18 @@
|
||||
# This file is to aggregate all commonly-used or shared locale strings.
|
||||
|
||||
[common]
|
||||
fail_no_target=Kein Spieler mit Name __1__ gefunden.
|
||||
warn_no_target=Warnung: Spieler __1__ konnte nicht gefunden werden, der Befehl wird trotzdem ausgeführt.
|
||||
|
||||
[ranks]
|
||||
probation=Bewährung
|
||||
guest=Gast
|
||||
auto_trusted=Automatisch vertraut
|
||||
regular=Stammgast
|
||||
admin=Admin
|
||||
donator=Unterstützer
|
||||
donator_abbreviation=U
|
||||
|
||||
[format]
|
||||
1_colon_2=__1__: __2__
|
||||
single_item=__1__
|
51
locale/de/redmew_features.cfg
Normal file
51
locale/de/redmew_features.cfg
Normal file
@ -0,0 +1,51 @@
|
||||
# This file holds all the locale strings for features
|
||||
|
||||
[donator]
|
||||
death_message=__1__ ist nicht mehr, schade eigentlich. __1__ wollte, dass euch noch diese letzte Nachricht überbracht wird:
|
||||
|
||||
[admin_commands]
|
||||
regular_add_success=__1__ beföhrderte __2__ zum Stammgast.
|
||||
regular_add_notify_target=Du wurdest zum Stammgast beföhrdert. Dieser Rang erlaubt dir ein paar neue Befehle auszuführen, so wie /redmew-colors. Wir laden dich mit /help durch alle verfügbaren Befehle zu stöbern.
|
||||
regular_add_fail=__1__ hat bereits den Rang __2__.
|
||||
regular_add_fail_probation=Eine Person auf Bewährung kann nicht zum Stammgast beföhrdert werden. Du musst ihre Bewährung erst aufgeben.
|
||||
regular_remove_success=__1__ degradierte __2__ zu __3__.
|
||||
regular_remove_notify_target=Dein Stammgast Rang wurde entfernt.
|
||||
regular_remove_fail=__1__ hat Rang __2__. __1__ Stammgast Rang kann nicht entfernt werden.
|
||||
probation_add_success=__1__ hat __2__ auf Bewährung gesetzt.
|
||||
probation_add_notify_target=Du wurdest auf Bewährung gesetzt. Du hast nur beschränkten Zugang zu normalen Funktionen.
|
||||
probation_add_fail=__1__ ist bereits auf Bewährung.
|
||||
probation_add_fail_admin=Du kannst keinen anderen Admin auf Bewährung setzten. Schande über dich!
|
||||
probation_warn_admin=__1__ hat versucht dich auf Bewährung zu setzen, kannst du's glauben?
|
||||
probation_remove_notify_target=Du bist nicht länger auf Bewährung.
|
||||
probation_remove_success=__1__ hat __2__s Bewährung aufgehoben..
|
||||
probation_remove_fail=__1__ ist nicht auf Bewährung.
|
||||
|
||||
[redmew_commands]
|
||||
whois_formatter=__1__\n__2__\n__3__\n__4__\n__5__\n__6__\n__7__\n__8__\n__9__\n__10__\n__11__\n__12__\n__13__\n__14__\n__15__\n__16__\n
|
||||
|
||||
[donator_commands]
|
||||
add_message_fail_not_string=Die Nachricht kann nicht leer sein.
|
||||
add_message_success=Nachricht hinzugefügt: __1__
|
||||
delete_message_fail_not_number=Zahl erwartet.
|
||||
delete_message_success=Nachricht gelöscht: __1__
|
||||
delete_message_fail_no_message=Es gibt keine zu löschende Nachrichten.
|
||||
list_message_no_messages=Keine Nachrichten angezeigt.
|
||||
donator_message_wrong_arg1=Verwendung: /donator-welcome-message add|delete|list
|
||||
donator_welcome_message_help=Willkommensnachrichten hinzufügen, löschen oder anzeigen.
|
||||
donator_death_message_help=Todesnachrichten hinzufügen, löschen oder anzeigen.
|
||||
|
||||
[apocalypse]
|
||||
run_twice=Das Spiel wurde gespeichert. Führe den Befehl erneut aus, um Apokalypse über die Menschheit zu bringen.
|
||||
apocalypse_begins=Der Boden beginnt sich zu bewegen. Es scheint das Ende ist nah.
|
||||
apocalypse_already_running=Die Apokalypse hat bereits begonnen. Es gibt nichts mehr zu tun. Leben ist zwecklos.
|
||||
toast_message=Die Endzeit ist nah. Die vier Beißer der Apokalypse wurden beschworen. Büße, während die Ailen sich zurückholen was ihnen zusteht.
|
||||
|
||||
[toast]
|
||||
toast_all=__1__ hat ein Pop-Up an alle Spieler gesendet.
|
||||
toast_player=__1__ hat ein Pop-Up an __2__ gesendet.
|
||||
|
||||
[nuke_control]
|
||||
train_warning=__1__ hat einen Zug zerstört und wurde gewarnt.
|
||||
train_player_warning=Du hast einen Zug zerstört. Das ist VERBOTEN!\n Wiederholte Verstöße werden zur Anzeige gebracht. Eltern haften für ihre Kinder!
|
||||
train_jailing=__1__ hat einen Zug zerstört und wurde eingesperrt.
|
||||
multiple_passengers=Achtung: In diesem Zug waren __1__ Spieler. Alle hätten ihn kontrollieren können. Spieler: __2__
|
1
locale/de/redmew_map_gen.cfg
Normal file
1
locale/de/redmew_map_gen.cfg
Normal file
@ -0,0 +1 @@
|
||||
# This file holds all the locale strings for map_gen modules excluding maps
|
1
locale/de/redmew_maps.cfg
Normal file
1
locale/de/redmew_maps.cfg
Normal file
@ -0,0 +1 @@
|
||||
# This file holds all the locale strings for specific maps
|
8
locale/de/redmew_utils.cfg
Normal file
8
locale/de/redmew_utils.cfg
Normal file
@ -0,0 +1,8 @@
|
||||
[command]
|
||||
help_text_format=__1__ __2__ __3__
|
||||
|
||||
required_rank= (Rang __1__ oder höher benötigt.)
|
||||
higher_rank_needed=Du brauchst Rang __2__ oder höher um den Befehl __1__ auszuführen.
|
||||
|
||||
[utils_core]
|
||||
print_admins=__1__(ADMIN) __2__: __3__
|
@ -1,6 +0,0 @@
|
||||
[announcements]
|
||||
msg-intro1=Welcome to our Server. You can join our Discord at: discord.gg/dtXMQq6
|
||||
msg-intro2=And remember.. Keep Calm And Spaghetti!
|
||||
msg-intro3=
|
||||
msg-announce1=
|
||||
msg-announce2=
|
@ -1,28 +0,0 @@
|
||||
msg-intro=This is the Factorio freeplay. Your task is to launch a rocket into space. Do this by constructing a Rocket Silo and launching a rocket with a satellite. You will need to research advanced technologies in order to unlock the Rocket Silo. Start small, work your way up with automation and don't forget to protect yourself from the natives.
|
||||
|
||||
[gui]
|
||||
rockets-sent=Rockets launched
|
||||
score=Score
|
||||
create-force=Create Team
|
||||
new-force=Create
|
||||
force=Team
|
||||
invite=Invite
|
||||
leave=Leave
|
||||
|
||||
[msg]
|
||||
close-position=This position is to close from another force!
|
||||
force-created=New team created!
|
||||
invalid-name=Player name not found!
|
||||
player-invated=Player __1__ has been invited to your team
|
||||
you-invated=You have been invited by __1__
|
||||
force-destroyed=Your team has been destroyed!
|
||||
force-leave="You have abandoned your team!
|
||||
force-leave-confim=Input "leave" in text field then click leave button to abandoned your team!
|
||||
info1=You can create your own team OR wait for another invitation
|
||||
info2=Select location for the base and click button "Create"
|
||||
info3=Spawn point will be installed where you stand
|
||||
info4=Bitters will run away from you
|
||||
info5=Do not click button if you are waiting for an invitation!
|
||||
info11=You can invite player: input thier name and click "Invite"
|
||||
info12=You can leave team: click "Leave"
|
||||
rocket-launched-without-satellite=You launched the rocket, but you didn't put a satellite inside.
|
@ -1,74 +0,0 @@
|
||||
[common]
|
||||
fail_no_target=No player found with name: __1__
|
||||
warn_no_target=Warning: player __1__ is not found, but the command will still be executed.
|
||||
|
||||
[ranks]
|
||||
probation=Probation
|
||||
guest=Guest
|
||||
auto_trusted=Auto Trusted
|
||||
regular=Regular
|
||||
admin=Admin
|
||||
donator=Donator
|
||||
donator_abbreviation=D
|
||||
|
||||
[format]
|
||||
1_colon_2=__1__: __2__
|
||||
single_item=__1__
|
||||
|
||||
[donator]
|
||||
death_message=__1__ has perished and will be missed by all, but wanted to share this last message:
|
||||
|
||||
[admin_commands]
|
||||
regular_add_success=__1__ promoted __2__ to regular.
|
||||
regular_add_notify_target=You have been promoted to regular. This rank opens up some commands which require regular rank such as /redmew-colors. We invite you to find more by using /help and exploring the commands.
|
||||
regular_add_fail=__1__ is already rank __2__.
|
||||
regular_add_fail_probation=Cannot promote someone on probation to regular. You must remove them from probation and then promote them.
|
||||
regular_remove_success=__1__ demoted __2__ to __3__.
|
||||
regular_remove_notify_target=Your regular rank has been removed.
|
||||
regular_remove_fail=__1__ is rank __2__ their regular status cannot be removed.
|
||||
probation_add_success=__1__ put __2__ on probation.
|
||||
probation_add_notify_target=You have been placed on probation. You have limited access to normal functions.
|
||||
probation_add_fail=__1__ already has probation rank or lower.
|
||||
probation_add_fail_admin=You failed to put your fellow admin on probation. Shame on you for trying.
|
||||
probation_warn_admin=__1__ tried to put you on probation, can you believe that shit?
|
||||
probation_remove_notify_target=Your probation status has been removed and you are once again allowed to use basic redmew commands.
|
||||
probation_remove_success=__1__ took __2__ off of probation.
|
||||
probation_remove_fail=__1__ is not on probation.
|
||||
|
||||
[redmew_commands]
|
||||
whois_formatter=__1__\n__2__\n__3__\n__4__\n__5__\n__6__\n__7__\n__8__\n__9__\n__10__\n__11__\n__12__\n__13__\n__14__\n__15__\n__16__\n
|
||||
|
||||
[donator_commands]
|
||||
add_message_fail_not_string=Must enter a value to set as message.
|
||||
add_message_success=Message added: __1__
|
||||
delete_message_fail_not_number=Must enter a number to delete.
|
||||
delete_message_success=Message deleted: __1__
|
||||
delete_message_fail_no_message=No message to delete.
|
||||
list_message_no_messages=No messages listed.
|
||||
donator_message_wrong_arg1=Correct use: /donator-welcome-message add|delete|list
|
||||
donator_welcome_message_help=Adds, deletes, or lists donator on-welcome messages.
|
||||
donator_death_message_help=Adds, deletes, or lists donator on-death messages.
|
||||
|
||||
[command]
|
||||
help_text_format=__1__ __2__ __3__
|
||||
higher_rank_needed=The command __1__ requires __2__ rank or higher to be be executed.
|
||||
required_rank= (Rank __1__ or above only)
|
||||
|
||||
[apocalypse]
|
||||
run_twice=The game has been saved, run the command again to commence the apocalypse.
|
||||
apocalypse_begins=The ground begins to rumble. It seems as if the world itself is coming to an end.
|
||||
apocalypse_already_running=The apocalypse has already begun. There is nothing more to do in this world.
|
||||
toast_message=The end times are here. The four biters of the apocalypse have been summoned. Repent as the aliens take back what is theirs.
|
||||
|
||||
[toast]
|
||||
toast_all=__1__ sent a toast to all players.
|
||||
toast_player=__1__ sent a toast to __2__.
|
||||
|
||||
[nuke_control]
|
||||
train_warning=__1__ used a train to destroy another train and has been warned.
|
||||
train_player_warning=You have destroyed another train with yours.\nRepeated infractions will be punished.
|
||||
train_jailing=__1__ used a train to destroy another train and has been jailed.
|
||||
multiple_passengers=Note: There were __1__ players in the train and any could have been controlling it: __2__
|
||||
|
||||
[utils_core]
|
||||
print_admins=__1__(ADMIN) __2__: __3__
|
67
locale/en/redmew_command_text.cfg
Normal file
67
locale/en/redmew_command_text.cfg
Normal file
@ -0,0 +1,67 @@
|
||||
# This file holds all the locale strings for command help and descriptions
|
||||
# Ideally, string keys match command names (with - turned to _)
|
||||
|
||||
[command_description]
|
||||
reward=Gives a reward to a target player (removes if quantity is negative)
|
||||
diggy_clear_void=Clears the void in a given area but still triggers all events Diggy would when clearing void.
|
||||
crash_site_restart=Restarts the crashsite scenario.
|
||||
crash_site_restart_abort=Aborts the restart of the crashsite scenario.
|
||||
dataset_copy=Copies a dataset
|
||||
dataset_move=Moves a dataset
|
||||
dataset_delete=Deletes a dataset
|
||||
dataset_transform=Transforms a dataset and writes it to the target dataset. Calls global.transform_function and sends the table of entries while expecting a table to return.
|
||||
dataset_transform_test=Shows the resulting data set from a transform operation. See /help dataset-transform for more information.
|
||||
report=Reports a user to admins
|
||||
kill=Will kill you.
|
||||
afk=Shows how long players have been afk.
|
||||
zoom=Sets your zoom.
|
||||
find=Shows an alert on the map where the player is located
|
||||
show_rail_block=Toggles rail block visualisation.
|
||||
server_time=Prints the server's time.
|
||||
seeds=List the seeds of all surfaces
|
||||
redmew_version=Prints the version of the RedMew scenario
|
||||
whois=provides information about a given player, admins can see the inventory of a player by adding "yes" as a second argument
|
||||
meltdown_get=Gets the status of meltdown.
|
||||
meltdown_set=Sets the status of meltdown.
|
||||
redmew_color=Set will save your current color for future maps. Reset will erase your saved color. Random will give you a random color.
|
||||
performance_scale_set=Sets the performance scale between 0.05 and 1. Will alter the game speed, manual mining speed, manual crafting speed and character running speed per force.
|
||||
performance_scale_get=Shows the current performance scale.
|
||||
market=Places a market near you. Use /market removeall to remove all markets on a map
|
||||
lazy_bastard_bootstrap=Puts down the minimum requirements to get started
|
||||
toast=Sends a toast to all players
|
||||
toast_player=Sends a toast to a specific player
|
||||
sent_all_toast=__1__ sent a toast to all players
|
||||
sent_player_toast=__1__ sent a toast to __2__
|
||||
task=Creates a new task.
|
||||
tag=Sets a player's tag
|
||||
popup=Shows a popup to all connected players
|
||||
popup_update=Shows an update popup to all connected players
|
||||
popup_player=Shows a popup to the player.
|
||||
poll=Creates a new poll
|
||||
poll_result=Prints the result for the given poll number.
|
||||
debug=Opens the debugger
|
||||
watch=Allows you to watch other players.
|
||||
donator_welcome_message=Adds, deletes, or lists donator welcome messages.
|
||||
donator_death_message=Adds, deletes, or lists donator death messages.
|
||||
reveal=Reveals radius around user
|
||||
particle_scale=Provide a fraction between 0 and 1 to lower or increase the amount of (max) particles. Leave empty to view the current values.
|
||||
apocalypse=This really ends the map. When you first run it, the game will save. When run a second time, the apocalypse will begin.
|
||||
a=Admin chat. Messages all other admins.
|
||||
dc=silent-command
|
||||
hax=Toggles your hax (makes recipes cost nothing)
|
||||
regular=Gives a player the regualar rank.
|
||||
regular_remove=Demotes a player from regular to the next lowest rank
|
||||
probation=Put player on probation. (They will be unable to use redmew commands and will never gain auto-trusted rank.)
|
||||
probation_remove=Remove player from probation.
|
||||
showreports=Shows user reports
|
||||
jail=Puts a player in jail
|
||||
unjail=Removes a player from jail
|
||||
pool=Spawns a pool of water
|
||||
invoke=Teleports the player to you.
|
||||
tp=If blank, teleport to selected entity. mode = toggle tp mode where you can teleport to a placed ghost. player = teleport to player.
|
||||
revive_ghosts=Revives the ghosts within the provided radius around you
|
||||
destroy=Destroys the entity under your cursor when you run this command
|
||||
|
||||
[command_custom_help]
|
||||
tp=<blank|mode|player> 3 different uses: "/tp" to tp to selected entity. "/tp mode" to toggle tp mode. "/tp Newcott" to tp to Newcott.
|
||||
poll=<{question = "question", answers = {"answer 1", "answer 2"}, duration = 300}>
|
19
locale/en/redmew_common.cfg
Normal file
19
locale/en/redmew_common.cfg
Normal file
@ -0,0 +1,19 @@
|
||||
# This file is to aggregate all commonly-used or shared locale strings.
|
||||
|
||||
[common]
|
||||
fail_no_target=No player found with name: __1__
|
||||
warn_no_target=Warning: player __1__ is not found, but the command will still be executed.
|
||||
close_button=Close
|
||||
|
||||
[ranks]
|
||||
probation=Probation
|
||||
guest=Guest
|
||||
auto_trusted=Auto Trusted
|
||||
regular=Regular
|
||||
admin=Admin
|
||||
donator=Donator
|
||||
donator_abbreviation=D
|
||||
|
||||
[format]
|
||||
1_colon_2=__1__: __2__
|
||||
single_item=__1__
|
106
locale/en/redmew_features.cfg
Normal file
106
locale/en/redmew_features.cfg
Normal file
@ -0,0 +1,106 @@
|
||||
# This file holds all the locale strings for non-gui features
|
||||
|
||||
[donator]
|
||||
death_message=__1__ has perished and will be missed by all, but wanted to share this last message:
|
||||
|
||||
[admin_commands]
|
||||
toggle_cheat_mode=Cheat mode set to __1__
|
||||
regular_add_success=__1__ promoted __2__ to regular.
|
||||
regular_add_notify_target=You have been promoted to regular. This rank opens up some commands which require regular rank such as /redmew-colors. We invite you to find more by using /help and exploring the commands.
|
||||
regular_add_fail=__1__ is already rank __2__.
|
||||
regular_add_fail_probation=Cannot promote someone on probation to regular. You must remove them from probation and then promote them.
|
||||
regular_remove_success=__1__ demoted __2__ to __3__.
|
||||
regular_remove_notify_target=Your regular rank has been removed.
|
||||
regular_remove_fail=__1__ is rank __2__ their regular status cannot be removed.
|
||||
probation_add_success=__1__ put __2__ on probation.
|
||||
probation_add_notify_target=You have been placed on probation. You have limited access to normal functions.
|
||||
probation_add_fail=__1__ already has probation rank or lower.
|
||||
probation_add_fail_admin=You failed to put your fellow admin on probation. Shame on you for trying.
|
||||
probation_warn_admin=__1__ tried to put you on probation, can you believe that shit?
|
||||
probation_remove_notify_target=Your probation status has been removed and you are once again allowed to use basic redmew commands.
|
||||
probation_remove_success=__1__ took __2__ off of probation.
|
||||
probation_remove_fail=__1__ is not on probation.
|
||||
invoke_fail_no_location=Unable to find suitable location to teleport your target to.
|
||||
invoke_announce=__1__, get your ass over here!
|
||||
tp_fail_no_location=Unable to find suitable location to teleport to.
|
||||
tp_player_announce=__1__! watcha doin'?!
|
||||
tp_player_success=You have teleported to __1__
|
||||
tp_ent_fail_no_ent=No entity under cursor.
|
||||
tp_end_success=Teleporting to your selected entity.
|
||||
tp_mode_off=tp mode is now off
|
||||
tp_mode_on=tp mode is now on - place a ghost entity to teleport there.
|
||||
destroy_success=__1__ destroyed
|
||||
destroy_fail=Nothing found to destroy. (You must have an entity under your cursor when you hit enter)
|
||||
|
||||
[redmew_commands]
|
||||
whois_formatter=__1__\n__2__\n__3__\n__4__\n__5__\n__6__\n__7__\n__8__\n__9__\n__10__\n__11__\n__12__\n__13__\n__14__\n__15__\n__16__\n
|
||||
kill_fail_suicide_no_character=Sorry, you don't have a character to kill.
|
||||
kill_fail_target_no_character=Sorry, __1__ doesn't have a character to kill.
|
||||
kill_fail_no_perm=Sorry you don't have permission to use the kill command on other players.
|
||||
afk_no_afk=No players afk.
|
||||
zoom_fail=You must give zoom a number.
|
||||
find_player_fail_no_character=Sorry, __1__ doesn't have a character to find.
|
||||
show_rail_block_success=show_rail_block_visualisation set to __1__
|
||||
server_time_fail=Server time is not available, is this game running on a Redmew server?
|
||||
print_version_from_source=This map was created from source code, only releases (zips with names) and server saves have versions
|
||||
|
||||
[donator_commands]
|
||||
add_message_fail_not_string=Must enter a value to set as message.
|
||||
add_message_success=Message added: __1__
|
||||
delete_message_fail_not_number=Must enter a number to delete.
|
||||
delete_message_success=Message deleted: __1__
|
||||
delete_message_fail_no_message=No message to delete.
|
||||
list_message_no_messages=No messages listed.
|
||||
donator_message_wrong_arg1=Correct use: /donator-welcome-message add|delete|list
|
||||
donator_welcome_message_help=Adds, deletes, or lists donator on-welcome messages.
|
||||
donator_death_message_help=Adds, deletes, or lists donator on-death messages.
|
||||
|
||||
[apocalypse]
|
||||
run_twice=The game has been saved, run the command again to commence the apocalypse.
|
||||
apocalypse_begins=The ground begins to rumble. It seems as if the world itself is coming to an end.
|
||||
apocalypse_already_running=The apocalypse has already begun. There is nothing more to do in this world.
|
||||
toast_message=The end times are here. The four biters of the apocalypse have been summoned. Repent as the aliens take back what is theirs.
|
||||
|
||||
[nuke_control]
|
||||
train_warning=__1__ used a train to destroy another train and has been warned.
|
||||
train_player_warning=You have destroyed another train with yours.\nRepeated infractions will be punished.
|
||||
train_jailing=__1__ used a train to destroy another train and has been jailed.
|
||||
multiple_passengers=Note: There were __1__ players in the train and any could have been controlling it: __2__
|
||||
|
||||
[meltdown]
|
||||
is_enabled=Reactor meltdown is enabled.
|
||||
is_disabled=Reactor meltdown is disabled.
|
||||
enable=Reactor meltdown enabled.
|
||||
disable=Reactor meltdown disabled.
|
||||
error_not_on_off=You must set meltdown to on or off.
|
||||
|
||||
[player_colors]
|
||||
color_saved=Your color has been saved. Any time you join a redmew server your color will automatically be set.
|
||||
color_saved_advert=__1__ has saved their color server-side for future maps. You can do the same! Check out /help redmew-color
|
||||
color_reset=Your saved color (if you had one) has been removed.
|
||||
color_random=Your color has been changed to: __1__
|
||||
fail_wrong_argument=Only set, reset, and random are accepted arguments
|
||||
|
||||
[performance]
|
||||
fail_wrong_argument=Scale must be a valid number ranging from 0.05 to 1
|
||||
stat_preamble=## - Game speed changed to compensate for UPS drops and players trying to catch up.
|
||||
generic_stat=## - __1__: __2__
|
||||
output_formatter=## - __1__: __2__ -- __3__: __4__ -- __5__: __6__
|
||||
game_speed=Game speed
|
||||
running_speed=Running speed
|
||||
manual_mining_speed=Manual mining speed
|
||||
manual_crafting_speed=Manual crafting speed
|
||||
|
||||
[chat_triggers]
|
||||
discord=Did you ask about our discord server?\nYou can find it here: redmew.com/discord
|
||||
patreon=Did you ask about our patreon?\nYou can find it here: patreon.com/redmew
|
||||
donate=Did you ask about donating to the server?\nYou can find our patreon here: patreon.com/redmew
|
||||
grief=To report grief please use the /report function.\nIf no admins are online use #moderation-requests on the discord and make sure the @mention the appropriate role.
|
||||
mention_success=__1__ __2__ mentioned __3__!
|
||||
mention_fail_mention_self=__1__ Can't mention yourself!
|
||||
mention_not_found_plural=__1__ Players not found: __2__
|
||||
mention_not_found_singular=__1__ Player not found: __2__
|
||||
|
||||
[player_onboarding]
|
||||
teach_toast=This is a feature in RedMew called a toast!\nThey're little pieces of information that pop up.\nYou can dismiss it by waiting or by clicking on it.
|
||||
teach_chat=To chat with other players, press the __CONTROL__toggle-console__ key on your keyboard.\nThe default key on English keyboards is the grave (`) and is below the ESC key.\nThis key can be changed in __1__ -> __2__ -> __3__.
|
47
locale/en/redmew_gui.cfg
Normal file
47
locale/en/redmew_gui.cfg
Normal file
@ -0,0 +1,47 @@
|
||||
# This file holds all the locale strings for guis
|
||||
|
||||
[info]
|
||||
welcome_header=Welcome to Redmew!
|
||||
welcome_text=Redmew is a community for players of all skill levels committed to pushing the limits of Factorio Multiplayer through custom scripts and crazy map designs.\n\nWe are a friendly bunch, our objective is to have as much fun as possible and we hope you will too.
|
||||
chatting_header=How To Chat
|
||||
chatting_text=To chat with other players, press the __CONTROL__toggle-console__ key on your keyboard.\nThe default key on English keyboards is the grave (`) and is below the ESC key.\nThis can be changed in __1__ -> __2__ -> __3__.
|
||||
free_coin_header=Free Coins
|
||||
free_coin_text=You have been given __1__ __2__ for looking at the welcome tab.\nChecking each tab will reward you __1__ more __2__.\n
|
||||
free_coin_print=__1__ __2__ awarded for reading a tab on the info screen.
|
||||
links_header=Useful Links
|
||||
links_discord=Check out our discord for new map info and to suggest new maps / ideas.
|
||||
links_patreon=Contribute to our Patreon to receive special perks and help maintain our servers.
|
||||
links_saves=Download our maps, start and finish state, from our website.
|
||||
links_factoriomaps=View our past maps as a Google Map.
|
||||
rules_header=Rules
|
||||
rules_text=Have fun and play nice. Remember we are all just here to have fun so let’s keep it that way.\n\nNo hateful content or personal attacks.\n\nIf you suspect someone is griefing, notify the admin team by using /report or by clicking the report button next to the player in the player list.
|
||||
map_info_button=Map Info
|
||||
map_info_header=Map Information
|
||||
map_name_label=Map name:
|
||||
map_desc_label=Map description:
|
||||
map_extra_info_label=Extra Info:
|
||||
softmods_button=Scenario Mods
|
||||
softmods_header=Soft Mods and Server Plugins
|
||||
softmods_rank_text=We have a basic rank system to prevent griefing. You can't use nukes or the\ndeconstruction planner if you are a guest. If you play for a couple of hours an\nadmin will promote you to regular. You may also ask an admin for a promotion if\nyou're working on a project which requires it.\n
|
||||
softmods_rank_is=Your rank is:
|
||||
softmods_market_label=Market
|
||||
softmods_market_text=On most maps you will find a market near spawn where you can use coins to\nmake purchases. Coins are acquired by chopping trees, hand crafting items and\ndestroying biter nests. Most items in the market are constant but some are\nmap-specific (usually landfill) and will rotate in and out from time to time.
|
||||
softmods_saviour_label=Train\nsavior
|
||||
softmods_saviour_text=Trains are a factorio players' worst enemy. If you have at least one small plane\nin your inventory and would be killed by a train, your life will be spared\nbut you will lose a small plane. You can get planes from the market.
|
||||
softmods_plist_label=Player\nlist
|
||||
softmods_plist_text=Lists all players on the server and shows some stats. You can sort the list by\nclicking on the column headers. You can also poke people, which throws a random\nnoun in the chat.
|
||||
softmods_polls_label=Polls
|
||||
softmods_polls_text=Polls help players get consensus for major actions. Want to improve an important\nbuild? Make a poll to check everyone is ok with that. You need to be a regular\nto make new polls.
|
||||
softmods_tags_label=Tags
|
||||
softmods_tags_text=You can assign yourself a role with tags to let other players know what you are\ndoing. Or just use the tag as decoration. Regulars can create new custom tags,\nbe sure to show off your creatively.
|
||||
softmods_tasks_label=Tasks
|
||||
softmods_tasks_text=Not sure what you should be working on, why not look at the tasks and see what\nneeds doing. Regulars can add new tasks.
|
||||
softmods_bp_label=BP\nhelper
|
||||
softmods_bp_text=The Blueprint helper™ lets you flip blueprints horizontally or vertically and lets you\nconverter the entities used in the blueprint e.g. turn yellow belts into red belts.
|
||||
softmods_score_label=Score
|
||||
softmods_score_text=Shows number of rockets launched and biters liberated.
|
||||
whats_new_button=What's New
|
||||
|
||||
[toast]
|
||||
toast_all=__1__ sent a toast to all players.
|
||||
toast_player=__1__ sent a toast to __2__.
|
1
locale/en/redmew_map_gen.cfg
Normal file
1
locale/en/redmew_map_gen.cfg
Normal file
@ -0,0 +1 @@
|
||||
# This file holds all the locale strings for map_gen modules excluding maps
|
@ -58,4 +58,3 @@ switch_desc=While in spawn, you can switch quadrant!
|
||||
switch_msg=Go ahead and pick a quadrant you'd like to help out!
|
||||
|
||||
force_sync_research=[img=item/automation-science-pack] New research complete: [technology=__1__]
|
||||
|
||||
|
30
locale/en/redmew_utils.cfg
Normal file
30
locale/en/redmew_utils.cfg
Normal file
@ -0,0 +1,30 @@
|
||||
# This file holds all the locale strings for the utils
|
||||
|
||||
[command]
|
||||
help_text_format=__1__ __2__ __3__
|
||||
log_entry=__1__(Map time: __2__) [__3__ Command] __4__, used: __5__ __6__
|
||||
|
||||
required_rank=(Rank __1__ or above only)
|
||||
donator_only=(Donator only)
|
||||
server_only=(Server only)
|
||||
undocumented_command=[Undocumented command]
|
||||
|
||||
not_allowed_by_server=The command '__1__' is not allowed to be executed by the server.
|
||||
not_allowed_by_players=The command '__1__' is not allowed to be executed by players.
|
||||
higher_rank_needed=The command '__1__' requires __2__ rank or higher to be be executed.
|
||||
not_allowed_by_non_donators=The command '__1__' is only allowed for donators.
|
||||
|
||||
fail_missing_argument=Argument "__1__" from command __2__ is missing.
|
||||
warn_player_of_error=There was an error running __1__, it has been logged.
|
||||
failed_command=Sorry there was an error running __1__
|
||||
warn_deprecated_command=Warning! Usage of the command "/__1__" is deprecated. Please use "/__2__" instead.
|
||||
error_bad_option=The following options were given to the command '__1__' but are invalid: __2__
|
||||
error_no_player_no_server=The command '__1__' is not allowed by the server nor player, please enable at least one of them.
|
||||
error_while_running_debug=__1__ triggered an error running a command and has been logged: '__2__' with arguments __3__
|
||||
error_log=Error while running '__1__' with arguments __2__: __3__
|
||||
|
||||
[utils_core]
|
||||
print_admins=__1__(ADMIN) __2__: __3__
|
||||
|
||||
[gui_util]
|
||||
button_tooltip=Shows / hides the Redmew Gui buttons.
|
@ -1,17 +0,0 @@
|
||||
[score-extended]
|
||||
score-gui-title=Score
|
||||
score-gui-tot=Total: __1__ rockets
|
||||
score-gui-nb=Count: __1__ rockets
|
||||
score-gui-delay=Delay: __1__ sec
|
||||
score-gui-delay-tt=Delay since last counter reset
|
||||
score-gui-av1h=Average: __1__ rkts/hr
|
||||
score-gui-av1m=Average: __1__ rkts/min
|
||||
score-gui-av2m=Average: __1__ min/rkt
|
||||
score-gui-av2s=Average: __1__ sec/rkt
|
||||
score-gui-reset=Reset
|
||||
score-gui-reset-tt=Reset counter to last launch time
|
||||
score-gui-prec-up-tt=Increase precision
|
||||
score-gui-prec-down-tt=Lower precision
|
||||
score-gui-count-tot=Total
|
||||
score-gui-autolaunch=Autolaunch
|
||||
score-gui-autoshow=Autoshow/hide
|
@ -207,7 +207,7 @@ local function extract4(args, player)
|
||||
end
|
||||
|
||||
Command.add(
|
||||
'extract1',
|
||||
'crash-site-extract1',
|
||||
{
|
||||
arguments = {'size'},
|
||||
default_values = {size = 6},
|
||||
@ -216,7 +216,7 @@ Command.add(
|
||||
extract1
|
||||
)
|
||||
Command.add(
|
||||
'extract4',
|
||||
'crash-site-extract4',
|
||||
{
|
||||
arguments = {'size'},
|
||||
default_values = {size = 6},
|
||||
|
@ -47,10 +47,10 @@ callback =
|
||||
)
|
||||
|
||||
Command.add(
|
||||
'restart',
|
||||
'crash-site-restart',
|
||||
{
|
||||
description = 'Restarts the crashsite scenario.',
|
||||
arguments = {'scenario_name'},
|
||||
description = {'command_description.'},
|
||||
arguments = {'scenario_name.crash_site_restart'},
|
||||
default_values = {scenario_name = 'crashsite'},
|
||||
required_rank = Ranks.admin,
|
||||
allowed_by_server = true
|
||||
@ -81,9 +81,9 @@ Command.add(
|
||||
)
|
||||
|
||||
Command.add(
|
||||
'abort',
|
||||
'crash-site-restart-abort',
|
||||
{
|
||||
description = 'Aborts the restart of the crashsite scenario.',
|
||||
description = {'command_description.crash_site_restart_abort'},
|
||||
required_rank = Ranks.admin,
|
||||
allowed_by_server = true
|
||||
},
|
||||
|
@ -947,10 +947,7 @@ local function update_market_upgrade_description(outpost_data)
|
||||
end
|
||||
end
|
||||
|
||||
str[#str + 1] = ': '
|
||||
str[#str + 1] = format('%.2f', current_rate)
|
||||
str[#str + 1] = ' -> '
|
||||
str[#str + 1] = format('%.2f / sec', next_rate)
|
||||
str[#str + 1] = concat {': ', format('%.2f', current_rate), ' -> ', format('%.2f / sec', next_rate)}
|
||||
str[#str + 1] = '\n'
|
||||
end
|
||||
str[#str] = nil
|
||||
|
@ -91,14 +91,14 @@ DiggyCaveCollapse.events = {
|
||||
- surface LuaSurface
|
||||
- player_index Number (index of player that caused the collapse)
|
||||
]]
|
||||
on_collapse_triggered = script.generate_event_name(),
|
||||
on_collapse_triggered = Event.generate_event_name('on_collapse_triggered'),
|
||||
--[[--
|
||||
After a collapse
|
||||
- position LuaPosition
|
||||
- surface LuaSurface
|
||||
- player_index Number (index of player that caused the collapse)
|
||||
]]
|
||||
on_collapse = script.generate_event_name()
|
||||
on_collapse = Event.generate_event_name('on_collapse')
|
||||
}
|
||||
|
||||
local function create_collapse_template(positions, surface)
|
||||
|
@ -127,7 +127,7 @@ local function on_mined_tile(surface, tiles)
|
||||
Template.insert(surface, new_tiles, {})
|
||||
end
|
||||
Command.add('diggy-clear-void', {
|
||||
description = 'Clears the void in a given area but still triggers all events Diggy would when clearing void.',
|
||||
description = {'command_description.diggy_clear_void'},
|
||||
arguments = {'left_top_x', 'left_top_y', 'width', 'height', 'surface_index'},
|
||||
debug_only = true,
|
||||
required_rank = Ranks.admin,
|
||||
|
@ -1,6 +1,7 @@
|
||||
-- dependencies
|
||||
local Task = require 'utils.task'
|
||||
local Token = require 'utils.token'
|
||||
local Event = require 'utils.event'
|
||||
local min = math.min
|
||||
local ceil = math.ceil
|
||||
local raise_event = script.raise_event
|
||||
@ -19,14 +20,14 @@ Template.events = {
|
||||
When an entity is placed via the template function.
|
||||
- event.entity LuaEntity
|
||||
]]
|
||||
on_placed_entity = script.generate_event_name(),
|
||||
on_placed_entity = Event.generate_event_name('on_placed_entity'),
|
||||
|
||||
--[[--
|
||||
Triggers when an 'out-of-map' tile is replaced by something else.
|
||||
|
||||
{surface, old_tile={name, position={x, y}}}
|
||||
]]
|
||||
on_void_removed = script.generate_event_name(),
|
||||
on_void_removed = Event.generate_event_name('on_void_removed'),
|
||||
}
|
||||
|
||||
local on_void_removed = Template.events.on_void_removed
|
||||
|
@ -1,137 +0,0 @@
|
||||
local b = require 'map_gen.shared.builders'
|
||||
local Event = require 'utils.event'
|
||||
global.map.terraforming.creep_retraction_tiles = {'sand-1'}
|
||||
require 'map_gen.shared.nightfall' -- forces idle biters to attack at night
|
||||
require 'map_gen.shared.terraforming' -- prevents players from building on non-terraformed tiles
|
||||
local DayNight = require 'map_gen.shared.day_night'
|
||||
local ScenarioInfo = require 'features.gui.info'
|
||||
local RS = require 'map_gen.shared.redmew_surface'
|
||||
|
||||
-- Info and world settings
|
||||
|
||||
ScenarioInfo.set_map_name('Terraform Venus')
|
||||
ScenarioInfo.set_map_description('After a long journey you have reached Venus. Your mission is simple, turn this hostile environment into one where humans can thrive')
|
||||
ScenarioInfo.add_map_extra_info(
|
||||
'- Venus is an endless desert spotted with tiny oases\n' ..
|
||||
'- The atmosphere is toxic and you are not equipped to deal with it\n' ..
|
||||
'- While unsure the exact effects the atmosphere will have, you should be cautios of it\n' ..
|
||||
'- As you spread breathable atmosphere the ground will change to show where you can breathe\n' ..
|
||||
'- The days seem endless, but when the sun begins setting night is upon us immediately.\n' ..
|
||||
'- The biters here are numerous and seem especially aggressive during the short nights'
|
||||
)
|
||||
|
||||
local MGSP = require 'resources.map_gen_settings' -- map gen settings presets
|
||||
local DSP = require 'resources.difficulty_settings' -- difficulty settings presets
|
||||
local MSP = require 'resources.map_settings' -- map settings presets
|
||||
|
||||
RS.set_map_gen_settings({MGSP.tree_none, MGSP.enemy_very_high, MGSP.water_very_low,MGSP.cliff_normal, MGSP.starting_area_very_low, MGSP.sand_only})
|
||||
RS.set_difficulty_settings({DSP.tech_x2})
|
||||
RS.set_map_settings({MSP.pollution_hard_to_spread, MSP.enemy_evolution_punishes_pollution, MSP.enemy_expansion_frequency_x4, MSP.enemy_expansion_aggressive})
|
||||
|
||||
-- 20 minute cycle, 14m of full light, 1m light to dark, 4m full dark, 1m dark to light
|
||||
DayNight.day_night_cycle = {
|
||||
['ticks_per_day'] = 72000,
|
||||
['dusk'] = 0.625,
|
||||
['evening'] = 0.775,
|
||||
['morning'] = 0.925,
|
||||
['dawn'] = 0.975
|
||||
}
|
||||
|
||||
--- Sets recipes and techs to be enabled/disabled
|
||||
local function init()
|
||||
local player_force = game.forces.player
|
||||
player_force.recipes['medium-electric-pole'].enabled = true
|
||||
player_force.recipes['steel-plate'].enabled = true
|
||||
player_force.technologies['artillery-shell-range-1'].enabled = false
|
||||
end
|
||||
|
||||
-- Map Generation
|
||||
|
||||
local function value(base, mult)
|
||||
return function(x, y)
|
||||
return mult * (math.abs(x) + math.abs(y)) + base
|
||||
end
|
||||
end
|
||||
|
||||
local function no_resources(_, _, world, tile)
|
||||
for _, e in ipairs(
|
||||
world.surface.find_entities_filtered(
|
||||
{type = 'resource', area = {{world.x, world.y}, {world.x + 1, world.y + 1}}}
|
||||
)
|
||||
) do
|
||||
e.destroy()
|
||||
end
|
||||
for _, e in ipairs(
|
||||
world.surface.find_entities_filtered(
|
||||
-- all tree types
|
||||
{type = 'tree', area = {{world.x, world.y}, {world.x + 1, world.y + 1}}}
|
||||
)
|
||||
) do
|
||||
e.destroy()
|
||||
end
|
||||
for _, e in ipairs(
|
||||
world.surface.find_entities_filtered(
|
||||
-- all rock types
|
||||
{type = 'simple-entity', area = {{world.x, world.y}, {world.x + 1, world.y + 1}}}
|
||||
)
|
||||
) do
|
||||
e.destroy()
|
||||
end
|
||||
|
||||
return tile
|
||||
end
|
||||
|
||||
-- create a square on which to place each ore
|
||||
local square = b.rectangle(12, 12)
|
||||
square = b.change_tile(square, true, 'lab-dark-2')
|
||||
|
||||
-- set the ore weights and sizes
|
||||
local iron = b.resource(b.rectangle(12, 12), 'iron-ore', value(200, 1))
|
||||
local copper = b.resource(b.rectangle(12, 12), 'copper-ore', value(150, 0.8))
|
||||
local stone = b.resource(b.rectangle(12, 12), 'stone', value(100, .5))
|
||||
local coal = b.resource(b.rectangle(12, 12), 'coal', value(100, 0.6))
|
||||
local tree = b.entity(b.throttle_world_xy(b.full_shape, 1, 2, 1, 2), 'dead-tree-desert')
|
||||
|
||||
-- place each ore on the square
|
||||
local iron_sq = b.apply_entity(square, iron)
|
||||
local copper_sq = b.apply_entity(square, copper)
|
||||
local stone_sq = b.apply_entity(square, stone)
|
||||
local coal_sq = b.apply_entity(square, coal)
|
||||
local tree_sq = b.apply_entity(square, tree)
|
||||
|
||||
-- create starting water square and change the type to water
|
||||
local water_start =
|
||||
b.any {
|
||||
b.rectangle(12, 12)
|
||||
}
|
||||
water_start = b.change_tile(water_start, true, 'water')
|
||||
|
||||
-- create the large safe square
|
||||
local safe_square = b.rectangle(80, 80)
|
||||
safe_square = b.change_tile(safe_square, true, 'lab-dark-2')
|
||||
|
||||
-- create the start area using the ore, water and safe squares
|
||||
local ore_distance = 24
|
||||
local start_area =
|
||||
b.any {
|
||||
b.translate(iron_sq, -ore_distance, -ore_distance),
|
||||
b.translate(copper_sq, -ore_distance, ore_distance),
|
||||
b.translate(stone_sq, ore_distance, -ore_distance),
|
||||
b.translate(coal_sq, ore_distance, ore_distance),
|
||||
b.translate(tree_sq, ore_distance, 0),
|
||||
b.translate(tree_sq, 0, ore_distance),
|
||||
b.translate(tree_sq, 0, -ore_distance),
|
||||
b.translate(tree_sq, -ore_distance, 0),
|
||||
water_start,
|
||||
safe_square
|
||||
}
|
||||
|
||||
start_area = b.apply_effect(start_area, no_resources)
|
||||
|
||||
local map = b.any {start_area, b.full_shape}
|
||||
map = b.change_map_gen_collision_tile(map, 'ground-tile', 'sand-1')
|
||||
map = b.translate(map, 6, -10) -- translate the whole map away, otherwise we'll spawn in the water
|
||||
|
||||
Event.on_init(init)
|
||||
|
||||
return map
|
@ -26,7 +26,7 @@ local Public = {
|
||||
surface :: LuaSurface: The surface the chunk is on
|
||||
chunk_index :: the index of the chunk in Chunklist's table
|
||||
]]
|
||||
on_chunk_registered = script.generate_event_name()
|
||||
on_chunk_registered = Event.generate_event_name('on_chunk_registered')
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ local Public = {
|
||||
ghost :: boolean indicating if the entity was a ghost
|
||||
stack :: LuaItemStack
|
||||
]]
|
||||
on_pre_restricted_entity_destroyed = script.generate_event_name(),
|
||||
on_pre_restricted_entity_destroyed = Event.generate_event_name('on_pre_restricted_entity_destroyed'),
|
||||
--[[
|
||||
on_restricted_entity_destroyed
|
||||
Called when an entity is destroyed by this script
|
||||
@ -70,7 +70,7 @@ local Public = {
|
||||
ghost :: boolean indicating if the entity was a ghost
|
||||
item_returned :: boolean indicating if a refund of the item was attempted
|
||||
]]
|
||||
on_restricted_entity_destroyed = script.generate_event_name()
|
||||
on_restricted_entity_destroyed = Event.generate_event_name('on_restricted_entity_destroyed')
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,14 +14,24 @@ local compound = defines.command.compound
|
||||
local logical_or = defines.compound_command.logical_or
|
||||
local attack = defines.command.attack
|
||||
local attack_area = defines.command.attack_area
|
||||
local hail_hydra_conf = global.config.hail_hydra
|
||||
|
||||
local spawn_table = {}
|
||||
for k, v in pairs(global.config.hail_hydra.hydras) do
|
||||
spawn_table[k] = v
|
||||
end
|
||||
|
||||
local function formula(evo)
|
||||
evo = evo * 100
|
||||
local value = (0.00003 * evo ^ 3 + 0.004 * evo ^ 2 + 0.3 * evo) * 0.01
|
||||
return value <= 1 and value or 1
|
||||
end
|
||||
|
||||
local primitives = {
|
||||
evolution_scale = global.config.hail_hydra.evolution_scale,
|
||||
evolution_scale = (hail_hydra_conf.evolution_scale ~= nil) and hail_hydra_conf.evolution_scale or 1,
|
||||
evolution_scale_formula = formula,
|
||||
online_player_scale_enabled = hail_hydra_conf.online_player_scale_enabled,
|
||||
online_player_scale = hail_hydra_conf.online_player_scale,
|
||||
enabled = nil
|
||||
}
|
||||
|
||||
@ -38,6 +48,10 @@ Global.register(
|
||||
|
||||
local Public = {}
|
||||
|
||||
local function backwards_compatibility(amount)
|
||||
return {min = amount, max = amount + primitives.evolution_scale}
|
||||
end
|
||||
|
||||
local function create_attack_command(position, target)
|
||||
local command = {type = attack_area, destination = position, radius = 10}
|
||||
if target then
|
||||
@ -67,9 +81,17 @@ local on_died =
|
||||
|
||||
local position = entity.position
|
||||
local force = entity.force
|
||||
local evolution_factor = force.evolution_factor * primitives.evolution_scale
|
||||
local cause = event.cause
|
||||
|
||||
local num_online_players = #game.connected_players
|
||||
local player_scale = 0
|
||||
if primitives.online_player_scale_enabled then
|
||||
player_scale = (num_online_players - primitives.online_player_scale) * 0.01
|
||||
end
|
||||
|
||||
local evolution_scaled = primitives.evolution_scale_formula(force.evolution_factor)
|
||||
local evolution_factor = evolution_scaled + evolution_scaled * player_scale
|
||||
|
||||
local cause = event.cause
|
||||
local surface = entity.surface
|
||||
local create_entity = surface.create_entity
|
||||
local find_non_colliding_position = surface.find_non_colliding_position
|
||||
@ -77,7 +99,26 @@ local on_died =
|
||||
local command = create_attack_command(position, cause)
|
||||
|
||||
for hydra_spawn, amount in pairs(hydra) do
|
||||
amount = amount + evolution_factor
|
||||
if (type(amount) == 'number') then
|
||||
amount = backwards_compatibility(amount)
|
||||
end
|
||||
local trigger = amount.trigger
|
||||
if trigger == nil or trigger < force.evolution_factor then
|
||||
if amount.locked then
|
||||
evolution_factor = evolution_scaled
|
||||
end
|
||||
local min = amount.min
|
||||
local max = amount.max
|
||||
max = (max ~= nil and max >= min) and max or min
|
||||
if max ~= min then
|
||||
amount = (max - min) * (evolution_factor / primitives.evolution_scale_formula(1)) + min
|
||||
else
|
||||
amount = min
|
||||
end
|
||||
else
|
||||
amount = 0
|
||||
end
|
||||
amount = (amount > 0) and amount or 0
|
||||
|
||||
local extra_chance = amount % 1
|
||||
if extra_chance > 0 then
|
||||
@ -136,6 +177,18 @@ function Public.set_evolution_scale(scale)
|
||||
primitives.evolution_scale = scale
|
||||
end
|
||||
|
||||
--- Sets the online player scale
|
||||
-- @param scale <number>
|
||||
function Public.set_evolution_scale(scale)
|
||||
primitives.online_player_scale = scale
|
||||
end
|
||||
|
||||
--- Toggles the online player scale feature
|
||||
-- @param enable <boolean>
|
||||
function Public.set_evolution_scale(enabled)
|
||||
primitives.online_player_scale_enabled = enabled
|
||||
end
|
||||
|
||||
--- Sets the hydra spawning table
|
||||
-- @param hydras <table> see config.lua's hail_hydra section for example
|
||||
function Public.set_hydras(hydras)
|
||||
|
@ -1,174 +0,0 @@
|
||||
--[[
|
||||
Softmod rewrite of https://mods.factorio.com/mod/Nightfall written by Yehn and used under the MIT license
|
||||
|
||||
Copyright 2018 Yehn
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
----
|
||||
|
||||
With Nightfall, biters in polluted areas become more aggressive at night.
|
||||
|
||||
TODO: Look into triggering existing unit groups to attack in unison with the groups we generate.
|
||||
]] --
|
||||
|
||||
-- Dependencies
|
||||
local Event = require 'utils.event'
|
||||
local Global = require 'utils.global'
|
||||
local RS = require 'map_gen.shared.redmew_surface'
|
||||
local table = require 'utils.table'
|
||||
|
||||
local random = math.random
|
||||
local insert = table.insert
|
||||
|
||||
-- config settings
|
||||
-- basic interval for checks
|
||||
local timeinterval = 2689 --2700 is ~45 seconds at 60 UPS
|
||||
-- how many chunks to process in a tick
|
||||
local processchunk = 5
|
||||
-- end of config
|
||||
|
||||
-- states
|
||||
local IDLE = 1
|
||||
local BASE_SEARCH = 2
|
||||
local ATTACKING = 3
|
||||
|
||||
-- create globals
|
||||
local chunklist = {}
|
||||
local data = {bases = {}, c_index = 1, state = 1, lastattack = 0}
|
||||
|
||||
Global.register(
|
||||
{
|
||||
chunklist = chunklist,
|
||||
data = data
|
||||
},
|
||||
function(tbl)
|
||||
chunklist = tbl.chunklist
|
||||
data = tbl.data
|
||||
end
|
||||
)
|
||||
|
||||
--- Called each tick when in ATTACKING state, scans through _processchunk_ chunks
|
||||
-- looking for biters and adding them to a group
|
||||
local function biter_attack()
|
||||
local maxindex = #data.bases
|
||||
local surface = RS.get_surface()
|
||||
for i = data.c_index, data.c_index + processchunk, 1 do
|
||||
if i > maxindex then
|
||||
-- we reached the end of the table
|
||||
data.state = IDLE
|
||||
break
|
||||
end
|
||||
if random() < surface.darkness then
|
||||
local base = data.bases
|
||||
local group = surface.create_unit_group {position = base}
|
||||
|
||||
for _, biter in pairs(surface.find_enemy_units(base, 16)) do
|
||||
group.add_member(biter)
|
||||
end
|
||||
|
||||
if #group.members == 0 then
|
||||
group.destroy()
|
||||
else
|
||||
--autonomous groups will attack polluted areas independently
|
||||
group.set_autonomous()
|
||||
if _DEBUG then
|
||||
game.print('[NIGHTFALL] sending biters to attack')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
data.c_index = data.c_index + processchunk
|
||||
--Reset if we're moving to the next state.
|
||||
if data.state == IDLE then
|
||||
data.c_index = 1
|
||||
data.lastattack = game.tick
|
||||
if _DEBUG then
|
||||
game.print('[NIGHTFALL] attack complete')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Called each tick when in BASE_SEARCH state, scans through _processchunk_ chunks
|
||||
-- looking for unit spawners and adding them to the bases table, when done iterating
|
||||
-- through chunklist it sets the state to ATTACKING
|
||||
local function find_bases()
|
||||
local get_pollution = RS.get_surface().get_pollution
|
||||
local count_entities_filtered = RS.get_surface().count_entities_filtered
|
||||
if data.c_index == 1 then
|
||||
data.bases = {}
|
||||
end
|
||||
local maxindex = #chunklist
|
||||
for i = data.c_index, data.c_index + processchunk, 1 do
|
||||
if i > maxindex then
|
||||
-- we're done with the search
|
||||
data.state = ATTACKING
|
||||
break
|
||||
end
|
||||
if get_pollution(chunklist[i]) > 0.1 then
|
||||
local chunkcoord = chunklist[i]
|
||||
if
|
||||
(count_entities_filtered {
|
||||
area = {{chunkcoord.x - 16, chunkcoord.y - 16}, {chunkcoord.x + 16, chunkcoord.y + 16}},
|
||||
type = 'unit-spawner',
|
||||
limit = 1
|
||||
}) > 0
|
||||
then
|
||||
insert(data.bases, chunkcoord)
|
||||
end
|
||||
end
|
||||
end
|
||||
data.c_index = data.c_index + processchunk
|
||||
--Reset our index and shuffle the table if we're moving to the next state.
|
||||
if data.state == ATTACKING then
|
||||
data.c_index = 1
|
||||
if #data.bases > 0 then
|
||||
table.shuffle_table(data.bases)
|
||||
end
|
||||
if _DEBUG then
|
||||
game.print('[NIGHTFALL] bases added: ' .. tostring(#data.bases))
|
||||
game.print('[NIGHTFALL] entering ATTACKING state')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- When a chunk is generated, add it to the chunklist
|
||||
local function on_chunk_generated(event)
|
||||
if event.surface == RS.get_surface() then
|
||||
local chunk = {}
|
||||
local coords = event.area.left_top
|
||||
chunk.x = coords.x + 16
|
||||
chunk.y = coords.y + 16
|
||||
insert(chunklist, chunk)
|
||||
end
|
||||
end
|
||||
|
||||
--- Every tick, choose between searching for bases, preparing an attack, or doing nothing
|
||||
-- See the definitions of the called function for further information
|
||||
local function on_tick()
|
||||
if data.state == BASE_SEARCH then
|
||||
find_bases()
|
||||
elseif data.state == ATTACKING then
|
||||
biter_attack()
|
||||
end
|
||||
end
|
||||
|
||||
--- Change us from idle to searching for bases if the conditions are met.
|
||||
local function on_interval()
|
||||
if
|
||||
RS.get_surface().darkness > 0.5 and random() > 0.5 and data.state == IDLE and
|
||||
game.tick >= data.lastattack + timeinterval
|
||||
then
|
||||
data.state = BASE_SEARCH
|
||||
if _DEBUG then
|
||||
RS.get_surface().print('[NIGHTFALL] entering BASE_SEARCH state') --for debug
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Event.add(defines.events.on_chunk_generated, on_chunk_generated)
|
||||
Event.add(defines.events.on_tick, on_tick)
|
||||
Event.on_nth_tick(timeinterval, on_interval)
|
@ -1,193 +0,0 @@
|
||||
local Event = require 'utils.event'
|
||||
local Game = require 'utils.game'
|
||||
local RS = require 'map_gen.shared.redmew_surface'
|
||||
|
||||
local function killBitters(pos)
|
||||
for k, v in pairs(RS.get_surface().find_entities_filtered({area = {{pos.x - 250, pos.y - 250}, {pos.x + 250, pos.y + 250}}, force = 'enemy'})) do
|
||||
v.destroy()
|
||||
end
|
||||
end
|
||||
|
||||
local function dist(position1, position2)
|
||||
return ((position1.x - position2.x) ^ 2 + (position1.y - position2.y) ^ 2) ^ 0.5
|
||||
end
|
||||
|
||||
local function neForceNear(pos)
|
||||
for k, v in pairs(game.forces) do
|
||||
if dist(pos, v.get_spawn_position(RS.get_surface())) <= 50 then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function validPlayer(name)
|
||||
if name ~= nil and Game.get_player_by_index(name) ~= nil and Game.get_player_by_index(name).force == game.forces.player then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function guiNewPlayer(gui)
|
||||
local frame = gui.add {type = 'frame', name = 'new_force', caption = {'gui.create-force'}, direction = 'vertical'}
|
||||
frame.add {type = 'button', name = 'new_button', caption = {'gui.new-force'}}
|
||||
end
|
||||
|
||||
local function guiForcePlayer(gui)
|
||||
local frame = gui.add {type = 'frame', name = 'own_force', caption = {'gui.force'}, direction = 'vertical'}
|
||||
frame.add {type = 'textfield', name = 'inv_name'}
|
||||
frame.add {type = 'button', name = 'inv_button', caption = {'gui.invite'}}
|
||||
frame.add {type = 'button', name = 'leave_button', caption = {'gui.leave'}}
|
||||
end
|
||||
|
||||
local function printNewPlayer(player)
|
||||
--player.print{"msg.info13"}
|
||||
--player.print{"msg.info14"}
|
||||
player.print {'msg.info1'}
|
||||
player.print {'msg.info2'}
|
||||
player.print {'msg.info3'}
|
||||
player.print {'msg.info4'}
|
||||
player.print {'msg.info5'}
|
||||
--player.print{"msg.info6"}
|
||||
--player.print{"msg.info7"}
|
||||
--player.print{"msg.info8"}
|
||||
end
|
||||
|
||||
local function printForcePlayer(player)
|
||||
player.print {'msg.info11'}
|
||||
player.print {'msg.info12'}
|
||||
end
|
||||
|
||||
Event.on_init(
|
||||
function()
|
||||
global.players = {}
|
||||
|
||||
game.forces.enemy.set_cease_fire(game.forces.player, true)
|
||||
game.forces.player.disable_research()
|
||||
game.forces.player.disable_all_prototypes()
|
||||
game.forces.player.set_ammo_damage_modifier('rocket', -3)
|
||||
end
|
||||
)
|
||||
|
||||
Event.add(
|
||||
defines.events.on_player_created,
|
||||
function(event)
|
||||
local player = Game.get_player_by_index(event.player_index)
|
||||
--player.print("Info: PVP server mod 'Bearded Snails' (c) byte");
|
||||
guiNewPlayer(player.gui.left)
|
||||
printNewPlayer(player)
|
||||
|
||||
player.insert {name = 'heavy-armor', count = 1}
|
||||
player.insert {name = 'iron-plate', count = 8}
|
||||
player.insert {name = 'pistol', count = 1}
|
||||
player.insert {name = 'firearm-magazine', count = 10}
|
||||
player.insert {name = 'burner-mining-drill', count = 1}
|
||||
player.insert {name = 'stone-furnace', count = 1}
|
||||
player.insert {name = 'shotgun', count = 1}
|
||||
player.insert {name = 'shotgun-shell', count = 10}
|
||||
player.character.character_running_speed_modifier = 0.5
|
||||
player.force.chart(player.surface, {{player.position.x - 200, player.position.y - 200}, {player.position.x + 200, player.position.y + 200}})
|
||||
end
|
||||
)
|
||||
|
||||
Event.add(
|
||||
defines.events.on_player_respawned,
|
||||
function(event)
|
||||
local player = Game.get_player_by_index(event.player_index)
|
||||
|
||||
player.insert {name = 'heavy-armor', count = 1}
|
||||
player.insert {name = 'pistol', count = 1}
|
||||
player.insert {name = 'firearm-magazine', count = 10}
|
||||
player.insert {name = 'shotgun', count = 1}
|
||||
player.insert {name = 'shotgun-shell', count = 10}
|
||||
player.character.character_running_speed_modifier = 0.5
|
||||
end
|
||||
)
|
||||
|
||||
Event.add(
|
||||
defines.events.on_rocket_launched,
|
||||
function(event)
|
||||
local force = event.rocket.force
|
||||
if event.rocket.get_item_count('satellite') > 0 then
|
||||
if global.satellite_sent == nil then
|
||||
global.satellite_sent = {}
|
||||
end
|
||||
if global.satellite_sent[force.name] == nil then
|
||||
game.set_game_state {game_finished = true, player_won = true, can_continue = true}
|
||||
global.satellite_sent[force.name] = 1
|
||||
else
|
||||
global.satellite_sent[force.name] = global.satellite_sent[force.name] + 1
|
||||
end
|
||||
for index, player in pairs(force.players) do
|
||||
if player.gui.left.rocket_score == nil then
|
||||
local frame = player.gui.left.add {name = 'rocket_score', type = 'frame', direction = 'horizontal', caption = {'gui.score'}}
|
||||
frame.add {name = 'rocket_count_label', type = 'label', caption = {'', {'gui.rockets-sent'}, ':'}}
|
||||
frame.add {name = 'rocket_count', type = 'label', caption = tostring(global.satellite_sent[force.name])}
|
||||
else
|
||||
player.gui.left.rocket_score.rocket_count.caption = tostring(global.satellite_sent[force.name])
|
||||
end
|
||||
end
|
||||
else
|
||||
for index, player in pairs(force.players) do
|
||||
player.print({'msg.gui-rocket-silo.rocket-launched-without-satellite'})
|
||||
end
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
Event.add(
|
||||
defines.events.on_gui_click,
|
||||
function(event)
|
||||
local player = Game.get_player_by_index(event.player_index)
|
||||
local gui = player.gui.left
|
||||
|
||||
if player.force == game.forces.player and event.element.name == 'new_button' then
|
||||
if neForceNear(player.position) then
|
||||
local force = game.create_force(player.name)
|
||||
force.set_spawn_position(player.position, RS.get_surface())
|
||||
player.force = force
|
||||
killBitters(player.position)
|
||||
player.force.chart(player.surface, {{player.position.x - 200, player.position.y - 200}, {player.position.x + 200, player.position.y + 200}})
|
||||
player.force.set_ammo_damage_modifier('rocket', -3)
|
||||
player.force.research_all_technologies()
|
||||
gui.new_force.destroy()
|
||||
guiForcePlayer(gui)
|
||||
player.print {'msg.force-created'}
|
||||
printForcePlayer(player)
|
||||
else
|
||||
player.print {'msg.close-position'}
|
||||
end
|
||||
elseif event.element.name == 'inv_button' then
|
||||
local name = gui.own_force.inv_name.text
|
||||
if name ~= nil and validPlayer(name) then
|
||||
local iplayer = Game.get_player_by_index(name)
|
||||
local igui = iplayer.gui.left
|
||||
|
||||
iplayer.force = player.force
|
||||
iplayer.teleport(player.force.get_spawn_position(RS.get_surface()))
|
||||
|
||||
igui.new_force.destroy()
|
||||
guiForcePlayer(igui)
|
||||
player.print {'msg.player-invated', name}
|
||||
iplayer.print {'msg.you-invated', player.name}
|
||||
else
|
||||
player.print {'msg.invalid-name'}
|
||||
end
|
||||
elseif event.element.name == 'leave_button' and gui.own_force.inv_name.text == 'leave' then
|
||||
if #player.force.players == 1 then
|
||||
game.merge_forces(player.force.name, game.forces.player.name)
|
||||
gui.own_force.destroy()
|
||||
guiNewPlayer(gui)
|
||||
player.print {'msg.force-destroyed'}
|
||||
elseif #player.force.players > 1 then
|
||||
player.force = game.forces.player
|
||||
player.character.die()
|
||||
gui.own_force.destroy()
|
||||
guiNewPlayer(gui)
|
||||
player.print {'msg.force-leave'}
|
||||
end
|
||||
elseif event.element.name == 'leave_button' and gui.own_force.inv_name.text ~= 'leave' then
|
||||
player.print {'msg.force-leave-confim'}
|
||||
end
|
||||
end
|
||||
)
|
@ -1,235 +0,0 @@
|
||||
local table = require 'utils.table'
|
||||
local Game = require 'utils.game'
|
||||
local Event = require 'utils.event'
|
||||
local naming_words = require 'resources.naming_words'
|
||||
local Utils = require 'utils.core'
|
||||
local Global = require 'utils.global'
|
||||
local Rank = require 'features.rank_system'
|
||||
local ScenarioInfo = require 'features.gui.info'
|
||||
local Command = require 'utils.command'
|
||||
local Ranks = require 'resources.ranks'
|
||||
|
||||
local format = string.format
|
||||
local random = math.random
|
||||
|
||||
ScenarioInfo.add_map_extra_info('- On this map you will be assigned a silly name.\n' .. '- If you dislike your name you can /name-restore or /name-roll for a new one')
|
||||
|
||||
global.silly_regulars = {}
|
||||
local data_silly_names = {}
|
||||
data_silly_names.silly_names = {}
|
||||
data_silly_names.silly_name_store = {}
|
||||
data_silly_names.silly_names_count = {0}
|
||||
data_silly_names.silly_name_store = {}
|
||||
data_silly_names.actual_name = {}
|
||||
|
||||
local name_combinations = #naming_words.adverbs * #naming_words.adjectives * 1
|
||||
local table_size_ceiling = math.min(name_combinations * 0.25, 10000)
|
||||
|
||||
Global.register(
|
||||
{
|
||||
data_silly_names = data_silly_names
|
||||
},
|
||||
function(tbl)
|
||||
data_silly_names = tbl.data_silly_names
|
||||
end
|
||||
)
|
||||
|
||||
--- Takes a player's real name, current silly name, and old silly name and adjusts
|
||||
-- the silly_regulars table accordingly
|
||||
local function check_regular(real_name, silly_name, old_silly_name)
|
||||
if Rank.equal(real_name, Ranks.regular) then
|
||||
global.silly_regulars[silly_name] = true
|
||||
if old_silly_name then
|
||||
global.silly_regulars[old_silly_name] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Creates name by combining elements from the passed table
|
||||
-- @param words_table including adverbs, adjectives, and nouns
|
||||
-- @param player_name string with player's name
|
||||
-- @returns string with player's silly name
|
||||
-- TODO: Config option to set the name style
|
||||
local function create_name(words_table, player_name)
|
||||
local adverb, adjective --, noun
|
||||
adverb = words_table[random(#words_table)]
|
||||
adjective = words_table[random(#words_table)]
|
||||
--noun = words_table[random(#words_table)]
|
||||
local name = format('%s_%s_%s', adverb, adjective, player_name)
|
||||
return string.gsub(name, "%s+", "_")
|
||||
end
|
||||
|
||||
--- Calls create_name until a unique name is returned
|
||||
-- @param words_table including adverbs, adjectives, and nouns
|
||||
-- @param player_name string with player's name
|
||||
-- @returns string with player's silly name
|
||||
local function create_unique_name(words_table, player_name)
|
||||
local silly_names = data_silly_names.silly_names
|
||||
local name = create_name(words_table, player_name)
|
||||
|
||||
while table.contains(silly_names, name) do
|
||||
name = create_name(words_table, player_name)
|
||||
end
|
||||
return name
|
||||
end
|
||||
|
||||
--- Assigns a player a name, stores their old and silly names
|
||||
-- @param player LuaPlayer, the player to change the name of
|
||||
local function name_player(player)
|
||||
local real_name = data_silly_names.actual_name[player.index] or player.name
|
||||
local old_silly_name
|
||||
|
||||
-- If we don't have a player's actual name yet, store it
|
||||
if data_silly_names.actual_name[player.index] then
|
||||
old_silly_name = player.name
|
||||
else
|
||||
data_silly_names.actual_name[player.index] = real_name
|
||||
end
|
||||
|
||||
-- Because create_unique_name enters a while loop looking for a _unique_ name,
|
||||
-- we ensure the table never contains all possible combinations by having a ceiling
|
||||
if data_silly_names.silly_names_count[1] > table_size_ceiling then
|
||||
table.clear_table(data_silly_names.silly_names, true)
|
||||
data_silly_names.silly_names_count[1] = 0
|
||||
end
|
||||
|
||||
local name = create_unique_name(naming_words, real_name)
|
||||
data_silly_names.silly_names[#data_silly_names.silly_names + 1] = name
|
||||
data_silly_names.silly_names_count[1] = data_silly_names.silly_names_count[1] + 1
|
||||
|
||||
local str = format('%s will now be known as: %s', player.name, name)
|
||||
game.print(str)
|
||||
local admin_str = format('%s (ID: %s)', str, player.index)
|
||||
Utils.print_admins(admin_str, nil)
|
||||
player.name = name
|
||||
|
||||
-- After they have their name, we need to ensure compatibility with the regulars system
|
||||
check_regular(real_name, name, old_silly_name)
|
||||
end
|
||||
|
||||
--- Restores a player's actual name
|
||||
local function restore_name(data, command_player)
|
||||
local player
|
||||
if data and data.player_index then
|
||||
player = Game.get_player_by_index(data.player_index)
|
||||
else
|
||||
player = command_player
|
||||
end
|
||||
local silly_name = player.name
|
||||
data_silly_names.silly_name_store[player.index] = player.name
|
||||
player.name = data_silly_names.actual_name[player.index]
|
||||
if command_player then
|
||||
player.print('Your true name has been restored.')
|
||||
local str = silly_name .. ' will now be known as: ' .. player.name
|
||||
Utils.print_admins(str .. ' (ID: ' .. player.index .. ')', nil)
|
||||
end
|
||||
end
|
||||
|
||||
--- Passes _event_ on to name_players
|
||||
local function player_joined(event)
|
||||
local player = Game.get_player_by_index(event.player_index)
|
||||
if data_silly_names.silly_name_store[event.player_index] then
|
||||
player.name = data_silly_names.silly_name_store[event.player_index]
|
||||
else
|
||||
name_player(player)
|
||||
end
|
||||
end
|
||||
|
||||
--- Passes target or player on to name_players
|
||||
local function name_player_command(args, player)
|
||||
local target
|
||||
local target_name = args.player
|
||||
|
||||
if target_name then
|
||||
target = game.players[target_name]
|
||||
if player and not player.admin then
|
||||
-- Yes param, yes player, no admin/server = fail, non-admins, non-server cannot use command on others
|
||||
Game.player_print("Sorry you don't have permission to use the roll-name command on other players.")
|
||||
return
|
||||
else
|
||||
-- Yes param, yes admin/server = check target
|
||||
if target then
|
||||
-- Yes param, yes admin/server, yes target = change name
|
||||
name_player(target)
|
||||
return
|
||||
else
|
||||
-- Yes param, yes admin/server, no target = fail, wrong player name
|
||||
Game.player_print(table.concat {"Sorry, player '", target_name, "' was not found."})
|
||||
return
|
||||
end
|
||||
end
|
||||
else
|
||||
-- No param = change self name
|
||||
name_player(player)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
--- Prints the original name of the target
|
||||
local function check_name(args)
|
||||
local current_name = args.player
|
||||
|
||||
local target = game.players[current_name]
|
||||
if not target then
|
||||
Game.player_print('player ' .. current_name .. ' not found')
|
||||
return
|
||||
end
|
||||
|
||||
local actual_name = data_silly_names.actual_name[target.index]
|
||||
Game.player_print(target.name .. ' is actually: ' .. actual_name)
|
||||
end
|
||||
|
||||
--- Prints the index of the target
|
||||
local function get_player_id(args)
|
||||
local target_name = args.player
|
||||
|
||||
local target = game.players[target_name]
|
||||
if not target then
|
||||
Game.player_print('player ' .. target_name .. ' not found')
|
||||
return
|
||||
end
|
||||
|
||||
Game.player_print(format('name: %s -- index: %s', target_name, target.index))
|
||||
end
|
||||
|
||||
Event.add(defines.events.on_player_joined_game, player_joined)
|
||||
Event.add(defines.events.on_pre_player_left_game, restore_name)
|
||||
|
||||
Command.add(
|
||||
'name-roll',
|
||||
{
|
||||
description = 'Assigns you a random, silly name. (Admins can use this command on players)',
|
||||
arguments = {'player'},
|
||||
default_values = {player = false}
|
||||
},
|
||||
name_player_command
|
||||
)
|
||||
|
||||
Command.add(
|
||||
'name-restore',
|
||||
{
|
||||
description = 'Removes your fun/silly name and gives you back your actual name.',
|
||||
},
|
||||
restore_name
|
||||
)
|
||||
|
||||
Command.add(
|
||||
'name-check',
|
||||
{
|
||||
description = 'Check the original name of a player with a silly name',
|
||||
arguments = {'player'},
|
||||
allowed_by_server = true
|
||||
},
|
||||
check_name
|
||||
)
|
||||
|
||||
Command.add(
|
||||
'get-player-id',
|
||||
{
|
||||
description = 'Gets the index of a player',
|
||||
arguments = {'player'},
|
||||
required_rank = Ranks.admin,
|
||||
allowed_by_server = true
|
||||
},
|
||||
get_player_id
|
||||
)
|
@ -1,470 +0,0 @@
|
||||
local Game = require 'utils.game'
|
||||
local Event = require 'utils.event'
|
||||
local Task = require 'utils.task'
|
||||
local Token = require 'utils.token'
|
||||
local Popup = require 'features.gui.popup'
|
||||
local Global = require 'utils.global'
|
||||
local Command = require 'utils.command'
|
||||
local RS = require 'map_gen.shared.redmew_surface'
|
||||
|
||||
local random = math.random
|
||||
local insert = table.insert
|
||||
|
||||
if not global.map.terraforming then
|
||||
global.map.terraforming = {}
|
||||
end
|
||||
|
||||
--[[
|
||||
Some inspiration and bits of code taken from Nightfall by Yehn and dangOreus by Mylon.
|
||||
Both under their respective MIT licenses.
|
||||
|
||||
This softmod originally used the Starcraft concept of "creep" as a mechanic. This was later changed
|
||||
to a terraforming context, but most of the code and documentation will keep the creep terminology.
|
||||
Players can only build on certain creep tiles (in particular, the defined `creep_expansion_tile`s).
|
||||
Pollution will naturally expand the creep. The creep will also naturally regress if pollution
|
||||
is not sustained, affecting player structures in the process.
|
||||
|
||||
This module does not create a map/safe start area, so you will not have a guaranteed safe placed
|
||||
to build, and any creep_expansion_tiles will be overtaken by creep_retraction_tiles as there is
|
||||
no initial pollution cloud. You can use creep-exempt tiles for a safe starting area.
|
||||
|
||||
Would love to make the expansion less "blocky"/constrained to chunk borders.
|
||||
]]
|
||||
|
||||
-- lets you know when creep is spreading/contracting (it is very verbose/annoying)
|
||||
global.DEBUG_SPREAD = false
|
||||
-- lets you know when your bonuses/penalties change based on being on creep
|
||||
global.DEBUG_ON_CREEP = false
|
||||
|
||||
--how many chunks to process in a tick
|
||||
local processchunk = 5
|
||||
-- the amount of damage taken when too far from creep
|
||||
local off_creep_damage = 15
|
||||
-- how often to check for players' positions
|
||||
local player_pos_check_time = 180 -- 3 secs
|
||||
-- the amount of extra damage to deal if a player has shields (because they will regen health)
|
||||
local regen_factor = 0.194 * player_pos_check_time
|
||||
-- how often to recap the deaths from lack of creep (in ticks)
|
||||
local death_recap_timer = 1200 -- 20 secs
|
||||
-- force that is restricted to the creep
|
||||
local creep_force = 'player'
|
||||
-- the threshold above which creep expands
|
||||
local pollution_upper_threshold = 200
|
||||
-- the threshold below which creep retracts
|
||||
local pollution_lower_threshold = 100
|
||||
-- the number of tiles that change to/from creep at once
|
||||
local random_factor = 0.1
|
||||
|
||||
-- the message to pop up when players build on the wrong tiles
|
||||
local popup_message = 'You may only build on terraformed land! Terraform by spreading pollution.'
|
||||
-- the message attached to the number of entities destroyed from not being on creep tiles
|
||||
local death_recap_message = ' buildings have died to the toxic atmosphere recently.'
|
||||
-- message printed to player when taking damage from being away from the creep
|
||||
local player_damage_message = 'You are taking damage from the toxic atmosphere.'
|
||||
-- message printed to player when they are ejected from a vehicle from being away from the creep
|
||||
local vehicle_ejecte_message = 'The toxic atmosphere wreaks havoc on your controls and you find yourself ejected from the vehicle.'
|
||||
-- message printed to game when a player dies to the atmosphere
|
||||
local player_death_message = 'The toxic atmosphere has claimed a victim.'
|
||||
-- message printed to the game when a bot is destroyed placing a tile
|
||||
local dead_robot_recap_message = ' robots died trying to place tiles, it seemed as though the ground swelled up swallowed them whole.'
|
||||
-- message printed to the game when a player tries placing a tile
|
||||
local player_built_tile_message = 'The ground rejects the artificial tiles you have tried to place'
|
||||
|
||||
-- boosts while on creep
|
||||
local boosts = {
|
||||
['character_running_speed_modifier'] = 1.1,
|
||||
['character_mining_speed_modifier'] = 1.3,
|
||||
['character_crafting_speed_modifier'] = 1,
|
||||
['character_health_bonus'] = 200,
|
||||
}
|
||||
|
||||
-- which tiles to use for creep expansion
|
||||
local creep_expansion_tiles = global.map.terraforming.creep_expansion_tiles or {
|
||||
'grass-1',
|
||||
'grass-2',
|
||||
}
|
||||
-- which tiles to use when creep retracts
|
||||
local creep_retraction_tiles = global.map.terraforming.creep_retraction_tiles or {
|
||||
'dirt-1',
|
||||
'dirt-2',
|
||||
'dry-dirt',
|
||||
'sand-1',
|
||||
'sand-2',
|
||||
'sand-3',
|
||||
}
|
||||
-- which tiles players can build on/count as creep
|
||||
local creep_tiles = global.map.terraforming.creep_tiles or {
|
||||
'grass-1',
|
||||
'grass-2',
|
||||
'concrete',
|
||||
'hazard-concrete-left',
|
||||
'hazard-concrete-right',
|
||||
'refined-concrete',
|
||||
'refined-hazard-concrete-left',
|
||||
'refined-hazard-concrete-right',
|
||||
'stone-path',
|
||||
}
|
||||
-- tiles which creep can expand into
|
||||
local non_creep_tiles = global.map.terraforming.non_creep_tiles or {
|
||||
'dirt-1',
|
||||
'dirt-2',
|
||||
'dirt-3',
|
||||
'dirt-4',
|
||||
'dirt-5',
|
||||
'dirt-6',
|
||||
'dirt-7',
|
||||
'dry-dirt',
|
||||
'grass-3',
|
||||
'grass-4',
|
||||
'red-desert-0',
|
||||
'red-desert-1',
|
||||
'red-desert-2',
|
||||
'red-desert-3',
|
||||
'sand-1',
|
||||
'sand-2',
|
||||
'sand-3',
|
||||
}
|
||||
|
||||
-- the 5 states a chunk can be in
|
||||
local NOT_CREEP = 1 -- Chunk is 0% creep tiles and unpolluted
|
||||
local FULL_CREEP = 2 -- Chunk is 100% creep tile and polluted
|
||||
local CREEP_RETRACTION = 3 -- Chunk has >0% creep tiles but is unpolluted
|
||||
local CREEP_EXPANDING = 4 -- Chunk has <100% creep tiles but is polluted
|
||||
local CREEP_UNKNOWN = 5 -- a special case for newly-generated chunks where we need to check their state
|
||||
|
||||
-- Register our globals
|
||||
local chunklist = {}
|
||||
local popup_timeout = {}
|
||||
local death_count = {0}
|
||||
local dead_robot_count = {0}
|
||||
local c_index = {1}
|
||||
|
||||
Global.register(
|
||||
{
|
||||
chunklist = chunklist,
|
||||
death_count = death_count,
|
||||
c_index = c_index,
|
||||
dead_robot_count = dead_robot_count,
|
||||
popup_timeout = popup_timeout,
|
||||
},
|
||||
function(tbl)
|
||||
chunklist = tbl.chunklist
|
||||
death_count = tbl.death_count
|
||||
c_index = tbl.c_index
|
||||
dead_robot_count = tbl.dead_robot_count
|
||||
popup_timeout = tbl.popup_timeout
|
||||
end
|
||||
)
|
||||
|
||||
--- Converts tiles
|
||||
-- @param tile_table table of tiles to convert
|
||||
-- @param tiles table of potential tiles to convert to
|
||||
local function convert_tiles(tile_table, tiles)
|
||||
local set_tiles = RS.get_surface().set_tiles
|
||||
local tile_set = {}
|
||||
local target_tile = tile_table[random(1, #tile_table)]
|
||||
-- convert the LuaTiles table into a new one we can edit
|
||||
for _, tiledata in pairs(tiles) do
|
||||
if random() < random_factor then
|
||||
tile_set[#tile_set + 1] = {name = target_tile, position = tiledata.position}
|
||||
end
|
||||
end
|
||||
-- change the tiles to the target_tile
|
||||
set_tiles(tile_set)
|
||||
end
|
||||
|
||||
local on_popup_timeout_complete =
|
||||
Token.register(
|
||||
function(name)
|
||||
popup_timeout[name] = nil
|
||||
end
|
||||
)
|
||||
|
||||
--- Kills buildings that are not on creep tiles
|
||||
-- @param entity LuaEntity to kill
|
||||
-- @param event or false - whether the entity is coming from a build event
|
||||
local function kill_invalid_builds(event)
|
||||
local entity = event.created_entity
|
||||
if not (entity and entity.valid) then
|
||||
return
|
||||
end
|
||||
-- don't kill players
|
||||
if entity.type == 'player' then
|
||||
return
|
||||
end
|
||||
-- don't kill vehicles
|
||||
if entity.type == 'car' or entity.type == 'tank' or not entity.health then
|
||||
return
|
||||
end
|
||||
-- Some entities have no bounding box area. Not sure which.
|
||||
if entity.bounding_box.left_top.x == entity.bounding_box.right_bottom.x or entity.bounding_box.left_top.y == entity.bounding_box.right_bottom.y then
|
||||
return
|
||||
end
|
||||
-- don't kill trains
|
||||
if entity.type == 'locomotive' or entity.type == 'fluid-wagon' or entity.type == 'cargo-wagon' or entity.type == 'artillery-wagon ' then
|
||||
return
|
||||
end
|
||||
|
||||
local last_user = entity.last_user
|
||||
local ceil = math.ceil
|
||||
local floor = math.floor
|
||||
|
||||
-- expand the bounding box to enclose full tiles to be scanned (if your area is less than the full size of the tile, the tile is not included)
|
||||
local bounding_box = {
|
||||
{floor(entity.bounding_box.left_top.x), floor(entity.bounding_box.left_top.y)},
|
||||
{ceil(entity.bounding_box.right_bottom.x), ceil(entity.bounding_box.right_bottom.y)}
|
||||
}
|
||||
local tiles = entity.surface.count_tiles_filtered {name = non_creep_tiles, area = bounding_box, limit = 1}
|
||||
if tiles > 0 then
|
||||
--Need to turn off ghosts left by dead buildings so construction bots won't keep placing buildings and having them blow up.
|
||||
local force = entity.force
|
||||
local ttl = force.ghost_time_to_live
|
||||
entity.force.ghost_time_to_live = 0
|
||||
entity.die()
|
||||
force.ghost_time_to_live = ttl
|
||||
death_count[1] = death_count[1] + 1
|
||||
-- checking for event.tick is a cheap way to see if it's an actual event or if the event data came from check_chunk_for_entities
|
||||
if event.tick and last_user and last_user.connected and not popup_timeout[last_user.name] then
|
||||
Popup.player(last_user, popup_message)
|
||||
popup_timeout[last_user.name] = true
|
||||
Task.set_timeout(60, on_popup_timeout_complete, last_user.name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Scans the provided chunk for entities on force _creep_force_.
|
||||
--@param chunk table with position and status of a map chunk
|
||||
local function check_chunk_for_entities(chunk)
|
||||
local find_entities_filtered = RS.get_surface().find_entities_filtered
|
||||
local entities_found
|
||||
entities_found =
|
||||
find_entities_filtered {
|
||||
area = {{chunk.x - 16, chunk.y - 16}, {chunk.x + 16, chunk.y + 16}},
|
||||
force = creep_force
|
||||
}
|
||||
for _, entity in pairs(entities_found) do
|
||||
kill_invalid_builds({['created_entity'] = entity})
|
||||
end
|
||||
end
|
||||
|
||||
--- Changes the state and tiles of chunks when they meet the creep expansion/retraction criteria
|
||||
--@param state number representing whether we want to expand or contract the chunk (expand = 1, retract = 2)
|
||||
--@param i number of the chunk's key in the chunklist table
|
||||
local function change_creep_state(state, i)
|
||||
local find_tiles_filtered = RS.get_surface().find_tiles_filtered
|
||||
local tiles_to_set = {}
|
||||
local debug_message
|
||||
local chunk_end_state
|
||||
local chunk_transition_state
|
||||
local tiles_to_find
|
||||
|
||||
-- states: expand = 1, retract = 2
|
||||
if state == 1 then
|
||||
tiles_to_find = non_creep_tiles
|
||||
tiles_to_set = creep_expansion_tiles
|
||||
debug_message = 'Creep expanding'
|
||||
chunk_end_state = FULL_CREEP
|
||||
chunk_transition_state = CREEP_EXPANDING
|
||||
elseif state == 2 then
|
||||
tiles_to_find = creep_tiles
|
||||
tiles_to_set = creep_retraction_tiles
|
||||
debug_message = 'Creep retracting'
|
||||
chunk_end_state = NOT_CREEP
|
||||
chunk_transition_state = CREEP_RETRACTION
|
||||
end
|
||||
|
||||
chunklist[i].is_creep = chunk_transition_state
|
||||
local chunkcoord = chunklist[i]
|
||||
local tiles =
|
||||
find_tiles_filtered(
|
||||
{
|
||||
area = {{chunkcoord.x - 16, chunkcoord.y - 16}, {chunkcoord.x + 16, chunkcoord.y + 16}},
|
||||
name = tiles_to_find
|
||||
}
|
||||
)
|
||||
if (#tiles > 0) then
|
||||
convert_tiles(tiles_to_set, tiles)
|
||||
if global.DEBUG_SPREAD then
|
||||
game.print(debug_message)
|
||||
end
|
||||
else
|
||||
-- if there are 0 tiles to convert, they're either fully creep or fully non-creep
|
||||
chunklist[i].is_creep = chunk_end_state
|
||||
-- if a chunk has lost all creep, do a final check to see if there are any buildings to kill and regen the decoratives
|
||||
if state == 2 then
|
||||
check_chunk_for_entities(chunklist[i])
|
||||
RS.get_surface().regenerate_decorative(nil, {{chunklist[i].x, chunklist[i].y}})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Every tick scan _processchunk_ number of chunks for their pollution state and if needed, change their state
|
||||
local function on_tick()
|
||||
local get_pollution = RS.get_surface().get_pollution
|
||||
local maxindex = #chunklist
|
||||
for i = c_index[1], c_index[1] + processchunk, 1 do
|
||||
if i > maxindex then
|
||||
-- we've iterated through all chunks
|
||||
c_index[1] = 1
|
||||
break
|
||||
end
|
||||
if get_pollution(chunklist[i]) > pollution_upper_threshold and chunklist[i].is_creep ~= FULL_CREEP then
|
||||
change_creep_state(1, i) -- expand = 1, retract = 2
|
||||
elseif get_pollution(chunklist[i]) < pollution_lower_threshold and chunklist[i].is_creep ~= NOT_CREEP then
|
||||
change_creep_state(2, i) -- expand = 1, retract = 2
|
||||
end
|
||||
if chunklist[i].is_creep == CREEP_RETRACTION then
|
||||
-- if a chunk's creep is retracting, we need to check if there are entities to kill
|
||||
check_chunk_for_entities(chunklist[i])
|
||||
end
|
||||
end
|
||||
c_index[1] = c_index[1] + processchunk
|
||||
end
|
||||
|
||||
--- Takes newly generated chunks and places them inside the chunklist table
|
||||
local function on_chunk_generated(event)
|
||||
if event.surface == RS.get_surface() then
|
||||
local chunk = {}
|
||||
local coords = event.area.left_top
|
||||
chunk.x = coords.x + 16
|
||||
chunk.y = coords.y + 16
|
||||
chunk.is_creep = CREEP_UNKNOWN
|
||||
insert(chunklist, chunk)
|
||||
end
|
||||
end
|
||||
|
||||
--- Prints the number of deaths from buildings outside of creep. Resets every _death_recap_timer_ ticks.
|
||||
local function print_death_recap()
|
||||
if death_count[1] > 1 then
|
||||
game.print(death_count[1] .. death_recap_message)
|
||||
death_count[1] = 0
|
||||
end
|
||||
if dead_robot_count[1] > 1 then
|
||||
game.print(dead_robot_count[1] .. dead_robot_recap_message)
|
||||
dead_robot_count[1] = 0
|
||||
end
|
||||
end
|
||||
|
||||
--- Apply penalties for being away from creep
|
||||
local function apply_penalties(p, c)
|
||||
for boost in pairs(boosts) do
|
||||
p[boost] = 0
|
||||
end
|
||||
c.disable_flashlight()
|
||||
end
|
||||
|
||||
--- Gives movement speed buffs when on creep, slows when only near creep, damages when far from creep.
|
||||
local function apply_creep_effects_on_players()
|
||||
local radius = 10 --distance to check around player for creep (nb. not actually a radius)
|
||||
for _, p in pairs(game.connected_players) do
|
||||
local c = p.character
|
||||
if c then
|
||||
-- count all non_creep_tiles around the player
|
||||
local count = p.surface.count_tiles_filtered {name = non_creep_tiles, area = {{p.position.x - radius, p.position.y - radius}, {p.position.x + radius, p.position.y + radius}}}
|
||||
if count == (radius * 2) ^ 2 then
|
||||
-- kick player from vehicle
|
||||
if p.vehicle then
|
||||
p.driving = false
|
||||
p.print(vehicle_ejecte_message)
|
||||
end
|
||||
-- calculate damage based on whether player has shields and is not in combat and check to see if we would deal lethal damage
|
||||
-- (shields prevent us putting the character into combat, so we need to compensate for health regen)
|
||||
local message = player_damage_message
|
||||
local damage
|
||||
if c.grid and c.grid.shield and not c.in_combat then
|
||||
damage = off_creep_damage + regen_factor
|
||||
message = message .. ' Your shields do nothing to help.'
|
||||
else
|
||||
damage = off_creep_damage
|
||||
end
|
||||
if (damage + 10) >= c.health then -- add 10 for the acid projectile damage
|
||||
c.die('enemy')
|
||||
game.print(player_death_message)
|
||||
return
|
||||
end
|
||||
-- create acid splash and deal damage
|
||||
p.surface.create_entity {name = 'acid-projectile-purple', target = p.character, position = p.character.position, speed = 10}
|
||||
c.health = c.health - damage
|
||||
p.print(message)
|
||||
-- apply penalties for being away from creep
|
||||
apply_penalties(p, c)
|
||||
if global.DEBUG_ON_CREEP then
|
||||
game.print('Far from creep and taking damage')
|
||||
end
|
||||
elseif count > (radius * 2) ^ 2 * 0.8 then
|
||||
-- apply penalties for being away from creep
|
||||
apply_penalties(p, c)
|
||||
if global.DEBUG_ON_CREEP then
|
||||
game.print('Near but not on creep')
|
||||
end
|
||||
else
|
||||
-- apply boosts for being on or near creep
|
||||
for boost, boost_value in pairs(boosts) do
|
||||
p[boost] = boost_value
|
||||
end
|
||||
c.enable_flashlight()
|
||||
if global.DEBUG_ON_CREEP then
|
||||
game.print('On creep and getting full benefits')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Revert built tiles
|
||||
local function check_on_tile_built(event)
|
||||
local surface
|
||||
if event.robot then
|
||||
surface = event.robot.surface
|
||||
event.robot.die('enemy')
|
||||
dead_robot_count[1] = dead_robot_count[1] + 1
|
||||
else
|
||||
local player = Game.get_player_by_index(event.player_index)
|
||||
surface = player.surface
|
||||
player.print(player_built_tile_message)
|
||||
end
|
||||
global.temp = event.tiles
|
||||
local tile_set = {}
|
||||
insert = table.insert
|
||||
for k, v in pairs(event.tiles) do
|
||||
tile_set[#tile_set + 1] = {name = v.old_tile.name, position = v.position}
|
||||
end
|
||||
surface.set_tiles(tile_set)
|
||||
end
|
||||
|
||||
Event.add(defines.events.on_tick, on_tick)
|
||||
Event.add(defines.events.on_chunk_generated, on_chunk_generated)
|
||||
Event.add(defines.events.on_built_entity, kill_invalid_builds)
|
||||
Event.add(defines.events.on_robot_built_entity, kill_invalid_builds)
|
||||
Event.add(defines.events.on_player_built_tile, check_on_tile_built)
|
||||
Event.add(defines.events.on_robot_built_tile, check_on_tile_built)
|
||||
Event.on_nth_tick(death_recap_timer, print_death_recap)
|
||||
Event.on_nth_tick(player_pos_check_time, apply_creep_effects_on_players)
|
||||
|
||||
--- Debug commands which will generate or clear pollution
|
||||
Command.add(
|
||||
'cloud',
|
||||
{
|
||||
description = 'Create a lot of pollution',
|
||||
debug_only = true,
|
||||
cheat_only = true
|
||||
},
|
||||
function()
|
||||
if game.player then
|
||||
game.player.surface.pollute(game.player.position, 10000)
|
||||
end
|
||||
end
|
||||
)
|
||||
Command.add(
|
||||
'clean',
|
||||
{
|
||||
description = 'Eliminate all pollution on the surface',
|
||||
debug_only = true,
|
||||
cheat_only = true
|
||||
},
|
||||
function()
|
||||
if game.player then
|
||||
game.player.surface.clear_pollution()
|
||||
end
|
||||
end
|
||||
)
|
@ -12,7 +12,6 @@ local insert = table.insert
|
||||
local format = string.format
|
||||
local next = next
|
||||
local serialize = serpent.line
|
||||
local match = string.match
|
||||
local gmatch = string.gmatch
|
||||
local get_rank_name = Rank.get_rank_name
|
||||
|
||||
@ -45,7 +44,7 @@ local option_names = {
|
||||
['allowed_by_player'] = 'Set to false to disable players from executing this command',
|
||||
['log_command'] = 'Set to true to log commands. Always true when admin is required',
|
||||
['capture_excess_arguments'] = 'Allows the last argument to be the remaining text in the command',
|
||||
['custom_help_text'] = 'Sets a custom help text to override the auto-generated help',
|
||||
['custom_help_text'] = 'Sets a custom help text to override the auto-generated help'
|
||||
}
|
||||
|
||||
---Validates if there aren't any wrong fields in the options.
|
||||
@ -60,7 +59,7 @@ local function assert_existing_options(command_name, options)
|
||||
end
|
||||
|
||||
if next(invalid) then
|
||||
error(format("The following options were given to the command '%s' but are invalid: %s", command_name, serialize(invalid)))
|
||||
error(format("The following options were given to the command '%s' but are invalid: %s", command_name, serialize(invalid))) -- command.error_bad_option when bug fixed
|
||||
end
|
||||
end
|
||||
|
||||
@ -89,7 +88,7 @@ end
|
||||
---@param options table
|
||||
---@param callback function
|
||||
function Command.add(command_name, options, callback)
|
||||
local description = options.description or '[Undocumented command]'
|
||||
local description = options.description or {'command.undocumented_command'}
|
||||
local arguments = options.arguments or {}
|
||||
local default_values = options.default_values or {}
|
||||
local required_rank = options.required_rank or Ranks.guest
|
||||
@ -113,9 +112,8 @@ function Command.add(command_name, options, callback)
|
||||
if (not _DEBUG and debug_only) and (not _CHEATS and cheat_only) then
|
||||
return
|
||||
end
|
||||
|
||||
if not allowed_by_player and not allowed_by_server then
|
||||
error(format("The command '%s' is not allowed by the server nor player, please enable at least one of them.", command_name))
|
||||
error(format("The command %s is not allowed by the server nor player, please enable at least one of them.", command_name)) -- command.error_no_player_no_server when bug fixed
|
||||
end
|
||||
|
||||
for index, argument_name in pairs(arguments) do
|
||||
@ -134,154 +132,136 @@ function Command.add(command_name, options, callback)
|
||||
argument_list = format('%s<%s> ', argument_list, argument_display)
|
||||
end
|
||||
|
||||
local extra = ''
|
||||
local extra = {''}
|
||||
|
||||
if allowed_by_server and not allowed_by_player then
|
||||
extra = ' (Server only)'
|
||||
extra = {'command.server_only'}
|
||||
elseif allowed_by_player and (required_rank > Ranks.guest) then
|
||||
extra = {'command.required_rank', get_rank_name(required_rank)}
|
||||
elseif allowed_by_player and donator_only then
|
||||
extra = ' (Donator only)'
|
||||
extra = {'command.donator_only'}
|
||||
end
|
||||
|
||||
local help_text = {'command.help_text_format',(custom_help_text or argument_list), description, extra}
|
||||
local help_text = {'command.help_text_format', (custom_help_text or argument_list), description, extra}
|
||||
|
||||
commands.add_command(command_name, help_text, function (command)
|
||||
local print -- custom print reference in case no player is present
|
||||
local player = game.player
|
||||
local player_name = player and player.valid and player.name or '<server>'
|
||||
if not player or not player.valid then
|
||||
print = log
|
||||
commands.add_command(
|
||||
command_name,
|
||||
help_text,
|
||||
function(command)
|
||||
local print -- custom print reference in case no player is present
|
||||
local player = game.player
|
||||
local player_name = player and player.valid and player.name or '<server>'
|
||||
if not player or not player.valid then
|
||||
print = log
|
||||
|
||||
if not allowed_by_server then
|
||||
print(format("The command '%s' is not allowed to be executed by the server.", command_name))
|
||||
return
|
||||
end
|
||||
else
|
||||
print = player.print
|
||||
|
||||
if not allowed_by_player then
|
||||
print(format("The command '%s' is not allowed to be executed by players.", command_name))
|
||||
return
|
||||
end
|
||||
|
||||
if Rank.less_than(player_name, required_rank) then
|
||||
print({'command.higher_rank_needed', command_name, get_rank_name(required_rank)})
|
||||
return
|
||||
end
|
||||
|
||||
if donator_only and not Donator.is_donator(player_name) then
|
||||
print(format("The command '%s' is only allowed for donators.", command_name))
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local named_arguments = {}
|
||||
local from_command = {}
|
||||
local raw_parameter_index = 1
|
||||
for param in gmatch(command.parameter or '', '%S+') do
|
||||
if capture_excess_arguments and raw_parameter_index == argument_list_size then
|
||||
if not from_command[raw_parameter_index] then
|
||||
from_command[raw_parameter_index] = param
|
||||
else
|
||||
from_command[raw_parameter_index] = from_command[raw_parameter_index] .. ' ' .. param
|
||||
if not allowed_by_server then
|
||||
print({'command.not_allowed_by_server', command_name})
|
||||
return
|
||||
end
|
||||
else
|
||||
from_command[raw_parameter_index] = param
|
||||
raw_parameter_index = raw_parameter_index + 1
|
||||
print = player.print
|
||||
|
||||
if not allowed_by_player then
|
||||
print({'command.not_allowed_by_players', command_name})
|
||||
return
|
||||
end
|
||||
|
||||
if Rank.less_than(player_name, required_rank) then
|
||||
print({'command.higher_rank_needed', command_name, get_rank_name(required_rank)})
|
||||
return
|
||||
end
|
||||
|
||||
if donator_only and not Donator.is_donator(player_name) then
|
||||
print({'command.not_allowed_by_non_donators', command_name})
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local errors = {}
|
||||
local named_arguments = {}
|
||||
local from_command = {}
|
||||
local raw_parameter_index = 1
|
||||
for param in gmatch(command.parameter or '', '%S+') do
|
||||
if capture_excess_arguments and raw_parameter_index == argument_list_size then
|
||||
if not from_command[raw_parameter_index] then
|
||||
from_command[raw_parameter_index] = param
|
||||
else
|
||||
from_command[raw_parameter_index] = from_command[raw_parameter_index] .. ' ' .. param
|
||||
end
|
||||
else
|
||||
from_command[raw_parameter_index] = param
|
||||
raw_parameter_index = raw_parameter_index + 1
|
||||
end
|
||||
end
|
||||
|
||||
for index, argument in pairs(arguments) do
|
||||
local parameter = from_command[index]
|
||||
local errors = {}
|
||||
|
||||
if not parameter then
|
||||
for default_value_name, default_value in pairs(default_values) do
|
||||
if default_value_name == argument then
|
||||
parameter = default_value
|
||||
break
|
||||
for index, argument in pairs(arguments) do
|
||||
local parameter = from_command[index]
|
||||
|
||||
if not parameter then
|
||||
for default_value_name, default_value in pairs(default_values) do
|
||||
if default_value_name == argument then
|
||||
parameter = default_value
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if parameter == nil then
|
||||
insert(errors, {'command.fail_missing_argument', argument, command_name})
|
||||
else
|
||||
named_arguments[argument] = parameter
|
||||
end
|
||||
end
|
||||
|
||||
if parameter == nil then
|
||||
insert(errors, format('Argument "%s" from command %s is missing.', argument, command_name))
|
||||
else
|
||||
named_arguments[argument] = parameter
|
||||
end
|
||||
end
|
||||
local return_early = false
|
||||
|
||||
local return_early = false
|
||||
|
||||
for _, error in pairs(errors) do
|
||||
return_early = true
|
||||
print(error)
|
||||
end
|
||||
|
||||
if return_early then
|
||||
return
|
||||
end
|
||||
|
||||
if log_command then
|
||||
local tick = 'pre-game'
|
||||
if game then
|
||||
tick = Utils.format_time(game.tick)
|
||||
end
|
||||
local server_time = Server.get_current_time()
|
||||
if server_time then
|
||||
server_time = format('(Server time: %s)', Timestamp.to_string(server_time))
|
||||
else
|
||||
server_time = ''
|
||||
end
|
||||
|
||||
log(format('%s(Map time: %s) [%s Command] %s, used: %s %s', server_time, tick, (options.required_rank >= Ranks.admin) and 'Admin' or 'Player', player_name, command_name, serialize(named_arguments)))
|
||||
end
|
||||
|
||||
local success, error = pcall(function ()
|
||||
callback(named_arguments, player, command.tick)
|
||||
end)
|
||||
|
||||
if not success then
|
||||
local serialized_arguments = serialize(named_arguments)
|
||||
if _DEBUG then
|
||||
print(format("%s triggered an error running a command and has been logged: '%s' with arguments %s", player_name, command_name, serialized_arguments))
|
||||
for _, error in pairs(errors) do
|
||||
return_early = true
|
||||
print(error)
|
||||
ErrorLogging.generate_error_report(error)
|
||||
end
|
||||
|
||||
if return_early then
|
||||
return
|
||||
end
|
||||
|
||||
print(format('There was an error running %s, it has been logged.', command_name))
|
||||
local err = format("Error while running '%s' with arguments %s: %s", command_name, serialized_arguments, error)
|
||||
log(err)
|
||||
ErrorLogging.generate_error_report(err)
|
||||
end
|
||||
end)
|
||||
end
|
||||
if log_command then
|
||||
local tick = 'pre-game'
|
||||
if game then
|
||||
tick = Utils.format_time(game.tick)
|
||||
end
|
||||
local server_time = Server.get_current_time()
|
||||
if server_time then
|
||||
server_time = format('(Server time: %s)', Timestamp.to_string(server_time))
|
||||
else
|
||||
server_time = ''
|
||||
end
|
||||
log({'command.log_entry', server_time, tick, (required_rank >= Ranks.admin) and 'Admin' or 'Player', player_name, command_name, serialize(named_arguments)})
|
||||
end
|
||||
|
||||
function Command.search(keyword)
|
||||
local matches = {}
|
||||
local count = 0
|
||||
keyword = keyword:lower()
|
||||
for name, description in pairs(commands.commands) do
|
||||
local command = format('%s %s', name, description)
|
||||
if match(command:lower(), keyword) then
|
||||
count = count + 1
|
||||
matches[count] = command
|
||||
end
|
||||
end
|
||||
local success, error =
|
||||
pcall(
|
||||
function()
|
||||
callback(named_arguments, player, command.tick)
|
||||
end
|
||||
)
|
||||
|
||||
-- built-in commands use LocalisedString, which cannot be translated until player.print is called
|
||||
for name in pairs(commands.game_commands) do
|
||||
name = name
|
||||
if match(name:lower(), keyword) then
|
||||
count = count + 1
|
||||
matches[count] = name
|
||||
end
|
||||
end
|
||||
if not success then
|
||||
local serialized_arguments = serialize(named_arguments)
|
||||
if _DEBUG then
|
||||
print({'command.error_while_running_debug', player_name, command_name, serialized_arguments})
|
||||
print(error)
|
||||
ErrorLogging.generate_error_report(error)
|
||||
return
|
||||
end
|
||||
|
||||
return matches
|
||||
print({'command.warn_player_of_error', command_name})
|
||||
local err = {'command.error_log', command_name, serialized_arguments, error}
|
||||
log(err)
|
||||
ErrorLogging.generate_error_report(err)
|
||||
end
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
--- Trigger messages on deprecated or defined commands, ignores the server
|
||||
@ -294,7 +274,7 @@ local function on_command(event)
|
||||
if alternative then
|
||||
local player = Game.get_player_by_index(event.player_index)
|
||||
if player then
|
||||
player.print(format('Warning! Usage of the command "/%s" is deprecated. Please use "/%s" instead.', event.command, alternative))
|
||||
player.print({'command.warn_deprecated_command', event.command, alternative})
|
||||
end
|
||||
end
|
||||
|
||||
@ -310,8 +290,7 @@ end
|
||||
--- Traps command errors if not in DEBUG.
|
||||
if not _DEBUG then
|
||||
local old_add_command = commands.add_command
|
||||
commands.add_command = -- luacheck: ignore 122
|
||||
function(name, desc, func)
|
||||
commands.add_command = function(name, desc, func) -- luacheck: ignore 122
|
||||
old_add_command(
|
||||
name,
|
||||
desc,
|
||||
@ -319,7 +298,7 @@ if not _DEBUG then
|
||||
local success, error = pcall(func, cmd)
|
||||
if not success then
|
||||
log(error)
|
||||
Game.player_print('Sorry there was an error running ' .. cmd.name)
|
||||
Game.player_print({'command.failed_command', cmd.name})
|
||||
end
|
||||
end
|
||||
)
|
||||
|
@ -65,7 +65,7 @@ function Module.print_admins(msg, source)
|
||||
source_name = 'Server'
|
||||
chat_color = Color.yellow
|
||||
end
|
||||
local formatted_msg = {'utils_core.print_admins',prefix, source_name, msg}
|
||||
local formatted_msg = {'utils_core.print_admins', prefix, source_name, msg}
|
||||
log(formatted_msg)
|
||||
for _, p in pairs(game.connected_players) do
|
||||
if p.admin then
|
||||
@ -222,6 +222,34 @@ function Module.silent_action_warning(warning_prefix, msg, player)
|
||||
Server.to_discord_bold(msg)
|
||||
end
|
||||
|
||||
--- Takes a string, number, or LuaPlayer and returns a valid LuaPlayer or nil.
|
||||
-- Intended for commands as there are extra checks in place.
|
||||
-- @param <string|number|LuaPlayer>
|
||||
-- @return <LuaPlayer|nil> <string|nil> <number|nil> the LuaPlayer, their name, and their index
|
||||
function Module.validate_player(player_ident)
|
||||
local data_type = type(player_ident)
|
||||
local player
|
||||
|
||||
if data_type == 'table' and player_ident.valid then
|
||||
local is_player = player_ident.is_player()
|
||||
if is_player then
|
||||
player = player_ident
|
||||
end
|
||||
elseif data_type == 'number' then
|
||||
player = Game.get_player_by_index(player_ident)
|
||||
elseif data_type == 'string' then
|
||||
player = game.players[player_ident]
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
if not player.valid then
|
||||
return
|
||||
end
|
||||
|
||||
return player, player.name, player.index
|
||||
end
|
||||
|
||||
-- add utility functions that exist in base factorio/util
|
||||
require 'util'
|
||||
|
||||
|
@ -107,6 +107,7 @@ local core_on_nth_tick = EventCore.on_nth_tick
|
||||
local stage_load = _STAGE.load
|
||||
local script_on_event = script.on_event
|
||||
local script_on_nth_tick = script.on_nth_tick
|
||||
local generate_event_name = script.generate_event_name
|
||||
|
||||
local Event = {}
|
||||
|
||||
@ -266,10 +267,7 @@ function Event.add_removable_function(event_name, func)
|
||||
end
|
||||
|
||||
if Debug.is_closure(func) then
|
||||
error(
|
||||
'func cannot be a closure as that is a desync risk. Consider using Event.add_removable(event_name, token) instead.',
|
||||
2
|
||||
)
|
||||
error('func cannot be a closure as that is a desync risk. Consider using Event.add_removable(event_name, token) instead.', 2)
|
||||
end
|
||||
|
||||
local funcs = function_handlers[event_name]
|
||||
@ -376,10 +374,7 @@ function Event.add_removable_nth_tick_function(tick, func)
|
||||
end
|
||||
|
||||
if Debug.is_closure(func) then
|
||||
error(
|
||||
'func cannot be a closure as that is a desync risk. Consider using Event.add_removable_nth_tick(tick, token) instead.',
|
||||
2
|
||||
)
|
||||
error('func cannot be a closure as that is a desync risk. Consider using Event.add_removable_nth_tick(tick, token) instead.', 2)
|
||||
end
|
||||
|
||||
local funcs = function_nth_tick_handlers[tick]
|
||||
@ -419,6 +414,19 @@ function Event.remove_removable_nth_tick_function(tick, func)
|
||||
end
|
||||
end
|
||||
|
||||
--- Generate a new, unique event ID.
|
||||
-- @param <string> name of the event/variable that is exposed
|
||||
function Event.generate_event_name(name)
|
||||
local event_id = generate_event_name()
|
||||
|
||||
-- If we're not in debug, we just turn the above function into an alias of script.generate_event_name
|
||||
if _DEBUG then
|
||||
defines.events[name] = event_id -- luacheck: ignore 122
|
||||
end
|
||||
|
||||
return event_id
|
||||
end
|
||||
|
||||
local function add_handlers()
|
||||
for event_name, tokens in pairs(token_handlers) do
|
||||
for i = 1, #tokens do
|
||||
|
@ -64,20 +64,20 @@ function Game.get_player_from_any(obj)
|
||||
end
|
||||
|
||||
--- Prints to player or console.
|
||||
-- @param str <string|table> table if locale is used
|
||||
-- @param msg <string|table> table if locale is used
|
||||
-- @param color <table> defaults to white
|
||||
function Game.player_print(str, color)
|
||||
function Game.player_print(msg, color)
|
||||
color = color or Color.white
|
||||
if game.player then
|
||||
game.player.print(str, color)
|
||||
game.player.print(msg, color)
|
||||
else
|
||||
print(str)
|
||||
print(msg)
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
@param Position String to display at
|
||||
@param text String to display
|
||||
@param text <string|table> table if locale is used
|
||||
@param color table in {r = 0~1, g = 0~1, b = 0~1}, defaults to white.
|
||||
@param surface LuaSurface
|
||||
|
||||
|
@ -205,7 +205,7 @@ Event.add(
|
||||
type = 'button',
|
||||
name = toggle_button_name,
|
||||
caption = '<',
|
||||
tooltip = 'Shows / hides the Redmew Gui buttons.'
|
||||
tooltip = {'gui_util.button_tooltip'}
|
||||
}
|
||||
local style = b.style
|
||||
style.width = 18
|
||||
|
@ -108,7 +108,7 @@ end
|
||||
Command.add(
|
||||
'reward',
|
||||
{
|
||||
description = 'Gives a reward to a target player (removes if quantity is negative)',
|
||||
description = {'command_description.reward'},
|
||||
arguments = {'target', 'quantity', 'reason'},
|
||||
default_values = {reason = false},
|
||||
required_rank = Ranks.admin,
|
||||
|
Loading…
x
Reference in New Issue
Block a user