1
0
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:
Simon 2019-03-05 15:11:27 +01:00 committed by GitHub
commit 7b0156b1c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
70 changed files with 1134 additions and 2231 deletions

View File

@ -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
View 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

View File

@ -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
}
}

View File

@ -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.

View File

@ -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

View File

@ -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
)

View File

@ -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

View File

@ -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
View 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
)

View File

@ -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,

View File

@ -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

View File

@ -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}
},

View File

@ -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)

View File

@ -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

View File

@ -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 lets 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
)

View File

@ -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
},

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
)

View File

@ -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
)

View 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

View File

@ -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)

View File

@ -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
)

View File

@ -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

View File

@ -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
},

View File

@ -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 = {

View File

@ -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,

View File

@ -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.

View File

@ -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

View File

@ -0,0 +1,5 @@
# This file holds all the locale strings for command help and descriptions
[command_description]
[command_custom_help]

View 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__

View 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__

View File

@ -0,0 +1 @@
# This file holds all the locale strings for map_gen modules excluding maps

View File

@ -0,0 +1 @@
# This file holds all the locale strings for specific maps

View 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__

View File

@ -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=

View File

@ -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.

View File

@ -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__

View 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}>

View 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__

View 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
View 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__.

View File

@ -0,0 +1 @@
# This file holds all the locale strings for map_gen modules excluding maps

View File

@ -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__]

View 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.

View File

@ -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

View File

@ -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},

View File

@ -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
},

View File

@ -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

View File

@ -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)

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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')
}
}

View File

@ -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')
}
}

View File

@ -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)

View File

@ -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)

View File

@ -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
)

View File

@ -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
)

View File

@ -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
)

View File

@ -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
)

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,