""" Gives a specified amount of medkits on spawn Author: Booboorocks998 Maintainer: mat^2 """ from piccolo.commands import command from piccolo.config import config from pyspades.constants import FALL_KILL medkit_config = config.section("medkit") default_medkits = medkit_config.option("medkits", 1) medkit_heal_amount = medkit_config.option("medkit_heal_amount", 40) @command('medkit', 'm') def medkit(connection): if connection.medkits and connection.hp < 100: connection.set_hp(connection.hp + connection.protocol.heal_amount, kill_type=FALL_KILL) connection.medkits -= 1 connection.send_chat('You have been healed') else: connection.send_chat("You don't have any medkits or have full health!") def apply_script(protocol, connection, config): class MedkitConnection(connection): medkits = 0 def on_spawn(self, pos):
""" Changes the damage values depending on distance. Maintainer: ? """ from pyspades.constants import (SHOTGUN_WEAPON, SMG_WEAPON, RIFLE_WEAPON) from pyspades.collision import distance_3d_vector from math import sqrt from piccolo.config import config range_damage_config = config.section("rangedamange") rifle_config = range_damage_config.section("rifle") smg_config = range_damage_config.section("smg") shotgun_config = range_damage_config.section("shotgun") rifle_pct_per_block = rifle_config.option("pct_per_block", 0) rifle_multiplier = rifle_config.option("multiplier", 1) shotgun_pct_per_block = shotgun_config.option("pct_per_block", 2.5) shotgun_multiplier = shotgun_config.option("multiplier", 2) smg_pct_per_block = smg_config.option("pct_per_block", 1.5) smg_multiplier = smg_config.option("multiplier", 1.2) def apply_script(protocol, connection, config): class RangeDamageConnection(connection): def __init__(self, *arg, **kw): connection.__init__(self, *arg, **kw)
""" Kicks jerks for 'PRESS ALT-F4 FOR AIRSTRIKES' and so on. Maintainer: ? """ import re from piccolo.config import config chat_pattern = re.compile(".*(airstrike).*(esc|escape|alt-f4|alt f4)", re.IGNORECASE) chat_pattern_2 = re.compile(".*(esc|escape|alt-f4|alt f4).*(airstrike)", re.IGNORECASE) admin_pattern = re.compile(".*(admin)", re.IGNORECASE) antijerk_config = config.section("antijerk") ban_duration = antijerk_config.option("ban_duration", 15.0) def antijerk_match(player, msg): if not (player.user_types.trusted or player.admin): return chat_pattern.match(msg) or chat_pattern_2.match(msg) or\ admin_pattern.match(player.name) def apply_script(protocol, connection, config): def jerk_kick(connection): connection.ban('Autoban: anti-jerk', ban_duration.get()) class AntiJerkConnection(connection):
# positions can add the right "specpower" to the group rights in commands.py # to have the guards/minimods be immune to the spectator kick and chat # restrictions. # # # Oh, and admins are also automatically immune to spectator kick and chat # restrictions. # # Hope you enjoy! # Tocksman from math import ceil, floor from twisted.internet import reactor from piccolo.config import config spectator_ctrl_config = config.section("spectator_control") no_chat = spectator_ctrl_config.option("no_chat", False) kick = spectator_ctrl_config.option("kick", False) kick_time = spectator_ctrl_config.option("kick_time", 300) # in seconds def apply_script(protocol, connection, config): class SpectatorControlConnection(connection): spec_check = None def on_chat(self, value, global_message): # if no chat is set and they're a spectator and not an admin # also, check for the right "specpower" for owners who add additional # rights such as guards, mini-mods, etc. if self.team.spectator and no_chat.get(): if not self.admin and not self.rights.specpower: # not an admin self.send_chat('Spectators cannot speak on this server.')
""" Protects spawned players for a specified amount of seconds. Maintainer: ? Fixed error by kmsi([email protected]) : replaced player to hit_player """ from pyspades.common import prettify_timespan from piccolo.config import config from twisted.internet import reactor spawn_protect_config = config.section("spawn_protect") protection_time = spawn_protect_config.option("protection_time", 3.0) def apply_script(protocol, connection, config): spawn_protect_time = protection_time.get() class SpawnProtectConnection(connection): spawn_timestamp = None def on_spawn(self, pos): self.spawn_timestamp = reactor.seconds() return connection.on_spawn(self, pos) def on_hit(self, hit_amount, hit_player, type, grenade): cur_timestamp = reactor.seconds() - spawn_protect_time if cur_timestamp < hit_player.spawn_timestamp: timespan = -(cur_timestamp - hit_player.spawn_timestamp) self.send_chat( "%s is spawn-protected for %s." %
Maintainer: Triplefox """ import random from piccolo.commands import command, get_player from piccolo import commands from piccolo.config import config from piccolo.server import respawn_time_option SQUAD_NAMES = set([ 'Alpha', 'Bravo', 'Charlie', 'Delta', 'Epsilon', 'Foxtrot', 'Gamma', 'Golf', 'Hotel', 'India', 'Juliet', 'Kilo', 'Lima', 'Mike', 'November', 'Oscar', 'Papa', 'Quebec', 'Romero', 'Sierra', 'Tango', 'Uniform', 'Victor', 'Whiskey', 'X-ray', 'Yankee', 'Zulu']) squad_config = config.section('squad') RESPAWN_TIME_OPTION = squad_config.option('respawn_time', default=respawn_time_option.get()) SIZE_OPTION = squad_config.option('size', 0) AUTO_SQUAD_OPTION = squad_config.option('auto_squad', True) @command() def follow(self, playerkey=None): if playerkey is None: squad_pref = None squad = self.squad else: squad_pref = get_player(self.protocol, playerkey) squad = squad_pref.squad if squad_pref.team is not self.team:
""" Zones of control: Dropped intel and tents exert influence over nearby area, restricting player ability to destroy. Maintainer: ? """ from collections import deque from twisted.internet.task import LoopingCall from pyspades.constants import GRENADE_DESTROY, SPADE_DESTROY, CTF_MODE, TC_MODE from piccolo.config import config BK_FREE, BK_FRIENDLY, BK_ENEMY_FAR, BK_ENEMY_NEAR, BK_UNDO = range(5) zoc_config = config.section("zoc") zoc_radius = zoc_config.option("radius", 32) zoc_attack_distance = zoc_config.option("attack_distance", 64) zoc_block_undo = zoc_config.option("block_undo", 10) zoc_block_cost = zoc_config.option("block_cost", 5) zoc_points_per_tick = zoc_config.option("points_per_tick", 1) zoc_point_cap = zoc_config.option("point_cap", 6 * zoc_block_cost.get()) zoc_grenade_cost = zoc_config.option("grenade_cost", zoc_point_cap.get()) def apply_script(protocol, connection, config): class ZOCConnection(connection): def on_connect(self): self.block_undo = deque() self.zoc_destruction_points = 0 return connection.on_connect(self)
""" Greets specified people entering with messages Maintainer: mat^2 """ from piccolo.config import config welcome_config = config.section("welcome") welcomes_option = welcome_config.option("welcomes", {}) def apply_script(protocol, connection, config): welcomes = welcomes_option.get() class EnterConnection(connection): def on_login(self, name): if name in welcomes: self.protocol.send_chat(welcomes[name]) connection.on_login(self, name) return protocol, EnterConnection
SHOTGUN_DAMAGE = (16, 27, 37) # Approximate size of player's heads in blocks HEAD_RADIUS = 0.7 # 128 is the approximate fog distance, but bump it up a little # just in case FOG_DISTANCE = 135.0 # Don't touch any of this stuff FOG_DISTANCE2 = FOG_DISTANCE**2 NEAR_MISS_COS = cos(NEAR_MISS_ANGLE * (pi / 180.0)) HEADSHOT_SNAP_ANGLE_COS = cos(HEADSHOT_SNAP_ANGLE * (pi / 180.0)) aimbot_pattern = re.compile(".*(aim|bot|ha(ck|x)|cheat).*", re.IGNORECASE) aimbot_config = config.section("aimbot") collect_data = aimbot_config.option("collect_data", False) config_dir = config.config_dir def point_distance2(c1, c2): if c1.world_object is not None and c2.world_object is not None: p1 = c1.world_object.position p2 = c2.world_object.position return (p1.x - p2.x)**2 + (p1.y - p2.y)**2 + (p1.z - p2.z)**2 def dot3d(v1, v2): return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]
''' seen = set() dups = [] for script in scripts: if script in seen: dups.append(script) else: seen.add(script) if dups: print("Scripts included multiple times: {}".format(dups)) return False return True # declare configuration options bans_config = config.section('bans') logging_config = config.section('logging') team1_config = config.section('team1') team2_config = config.section('team2') bans_file = bans_config.option('file', default='bans.txt') respawn_time_option = config.option('respawn_time', default=8) respawn_waves = config.option('respawn_waves', default=False) game_mode = config.option('game_mode', default='ctf') random_rotation = config.option('random_rotation', default=False) passwords = config.option('passwords', default={}) logfile = logging_config.option('logfile', default='./logs/log.txt') map_rotation = config.option('rotation', default=['classicgen', 'random'], validate=lambda x: isinstance(x, list)) default_time_limit = config.option( 'default_time_limit', default=20,
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with pyspades. If not, see <http://www.gnu.org/licenses/>. import random from twisted.internet import reactor from twisted.internet.task import LoopingCall from pyspades.common import prettify_timespan from piccolo.map import check_rotation from piccolo.scheduler import Scheduler from piccolo.commands import command from piccolo.config import config votemap_config = config.section('votemap') VOTEMAP_AUTOSCHEDULE_OPTION = votemap_config.option('autoschedule', 180) VOTEMAP_PUBLIC_VOTES_OPTION = votemap_config.option( 'public_votes', True) VOTEMAP_TIME_OPTION = votemap_config.option('time', 120) VOTEMAP_EXTENSION_TIME_OPTION = votemap_config.option('extension_time', 15) VOTEMAP_PLAYER_DRIVEN_OPTION = votemap_config.option('player_driven', False) VOTEMAP_PERCENTAGE_OPTION = votemap_config.option('percentage', 80) def cancel_verify(connection, instigator): return (connection.admin or connection is instigator or connection.rights.cancel) class VoteMap(object):
# You should have received a copy of the GNU General Public License # along with pyspades. If not, see <http://www.gnu.org/licenses/>. import json from io import BytesIO from PIL import Image from jinja2 import Environment, PackageLoader from twisted.internet import reactor from twisted.web import server from twisted.web.resource import Resource from piccolo.config import config OVERVIEW_UPDATE_INTERVAL = 1 * 60 # 1 minute status_server_config = config.section("status_server") port_option = status_server_config.option("port", 32886) logging_option = status_server_config.option("logging", False) scripts_option = config.option("scripts", []) class CommonResource(Resource): protocol = None isLeaf = True def __init__(self, parent): self.protocol = parent.protocol self.env = parent.env self.parent = parent Resource.__init__(self)
Maintainer: hompy """ from operator import attrgetter from twisted.internet import reactor from pyspades.common import prettify_timespan from piccolo.commands import command, get_player, admin from piccolo.config import config S_AFK_CHECK = '{player} has been inactive for {time}' S_NO_PLAYERS_INACTIVE = 'No players or connections inactive for {time}' S_AFK_KICKED = ('{num_players} players kicked, {num_connections} connections ' 'terminated for {time} inactivity') S_AFK_KICK_REASON = 'Inactive for {time}' afk_config = config.section('afk') time_limit_option = afk_config.option('time_limit', default=None, cast=lambda n: None if n is None else n * 60.0) def afk(connection, player): player = get_player(connection.protocol, player) elapsed = prettify_timespan(reactor.seconds() - player.last_activity, True) return S_AFK_CHECK.format(player=player.name, time=elapsed) @command('kickafk', admin_only=True) def kick_afk(connection, minutes, amount=None): protocol = connection.protocol
S_RESULT_BANNED = 'Banned by admin' S_RESULT_KICKED = 'Kicked by admin' S_RESULT_INSTIGATOR_KICKED = 'Instigator kicked by admin' S_RESULT_LEFT = '{victim} left during votekick' S_RESULT_INSTIGATOR_LEFT = 'Instigator {instigator} left' S_RESULT_PASSED = 'Player kicked' S_ANNOUNCE_IRC = '* {instigator} started a votekick against player {victim}. ' \ 'Reason: {reason}' S_ANNOUNCE = '{instigator} started a VOTEKICK against {victim}. Say /Y to agree' S_ANNOUNCE_SELF = 'You started a votekick against {victim}. Say /CANCEL to ' \ 'stop it' S_UPDATE = '{instigator} is votekicking {victim}. /Y to vote ({needed} left)' S_REASON = 'Reason: {reason}' # register options VOTEKICK_CONFIG = config.section('votekick') REQUIRED_PERCENTAGE_OPTION = VOTEKICK_CONFIG.option('percentage', 25.0) BAN_DURATION_OPTION = VOTEKICK_CONFIG.option('ban_duration', 15.0) PUBLIC_VOTES_OPTION = VOTEKICK_CONFIG.option('public_votes', True) class VotekickFailure(Exception): pass @command('votekick') def start_votekick(connection, *args): protocol = connection.protocol if connection not in protocol.players: raise KeyError() player = connection
""" Saves current map on shutdown (and optionally loads it again on startup) Maintainer: mat^2 """ import os from twisted.internet import reactor from pyspades.vxl import VXLData from piccolo.config import config savemap_config = config.section('savemap') LOAD_SAVED_MAP_OPTION = savemap_config.option('load_saved_map', False) def get_name(map): return '%s/%s.saved.vxl' % (os.path.join(config.config_dir, 'maps'), map.rot_info.name) def apply_script(protocol, connection, config): class MapSaveProtocol(protocol): def __init__(self, *arg, **kw): protocol.__init__(self, *arg, **kw) reactor.addSystemEventTrigger('before', 'shutdown', self.save_map) def get_map(self, name): map = protocol.get_map(self, name) if LOAD_SAVED_MAP_OPTION.get(): cached_path = get_name(map) print("Loading saved map for {} from {}".format(name, cached_path)) if os.path.isfile(cached_path):
""" A tool for identifying griefers. Maintainer: hompy Note: "blockinfo" must be AFTER "votekick" in the config.txt script list """ from twisted.internet.reactor import seconds from pyspades.collision import distance_3d_vector from pyspades.common import prettify_timespan from piccolo.commands import command, admin, get_player from piccolo.config import config blockinfo_config = config.section("blockinfo") GRIEFCHECK_ON_VOTEKICK = blockinfo_config.option("griefcheck_on_votekick", True) IRC_ONLY = blockinfo_config.option("irc_only", False) @command('griefcheck', 'gc') def grief_check(connection, player, minutes=2): player = get_player(connection.protocol, player) protocol = connection.protocol color = connection not in protocol.players and connection.colors minutes = float(minutes) if minutes <= 0.0: raise ValueError('minutes must be number greater than 0') time = seconds() - minutes * 60.0 blocks_removed = player.blocks_removed or [] blocks = [b[1] for b in blocks_removed if b[0] >= time]
p.registerChecker( checkers.InMemoryUsernamePasswordDatabaseDontUse(**users)) f = manhole_ssh.ConchFactory(p) ssh_key_base_path = path.join(config.config_dir, "ssh-keys") ssh_pubkey_path = path.join(ssh_key_base_path, "ssh_host_rsa_key.pub") ssh_privkey_path = path.join(ssh_key_base_path, "ssh_host_rsa_key") try: f.publicKeys[b"ssh-rsa"] = keys.Key.fromFile(ssh_pubkey_path) f.privateKeys[b"ssh-rsa"] = keys.Key.fromFile(ssh_privkey_path) except FileNotFoundError: print("ERROR: You don't have any keys in the host key location") print("Generate one with:") print(" mkdir {}".format(ssh_key_base_path)) print(" ssh-keygen -f {} -t rsa".format(ssh_privkey_path)) print("make sure to specify no password") sys.exit(1) return f ssh_config = config.section("ssh") class RemoteConsole(object): def __init__(self, server): users = ssh_config.option("users", {}) port = ssh_config.option("port", 38827) factory = create_remote_factory(locals(), users.get()) server.listenTCP(port.get(), factory)