from piqueserver.commands import add, admin DEMOLITION_ENABLED_AT_ROUND_START = False @admin def toggledemo(connection): connection.protocol.demolitionEnabled = not connection.protocol.demolitionEnabled message = 'Demolition is now disabled' if connection.protocol.demolitionEnabled: message = 'Demolition is now enabled' connection.protocol.send_chat(message, irc=True) return 'ok :)' add(toggledemo) def apply_script(protocol, connection, config): class DemolitionProtocol(protocol): demolitionEnabled = DEMOLITION_ENABLED_AT_ROUND_START def on_map_change(self, map): self.demolitionEnabled = DEMOLITION_ENABLED_AT_ROUND_START return protocol.on_map_change(self, map) class DemolitionConnection(connection): def _on_reload(self): if self.protocol.demolitionEnabled: self.refill() return connection._on_reload(self)
else: message = "doesn't have an alias for %s" % unaliased_name else: aliases[unaliased_name] = value message = 'will alias %s to %s' % (unaliased_name, value) connection.me(message) @restrict_irc def unalias(connection): aliases = connection.factory.aliases unaliased_name = connection.unaliased_name if unaliased_name in aliases: aliases.pop(unaliased_name) message = 'will no longer alias %s' % unaliased_name else: message = "doesn't have an alias for %s" % unaliased_name connection.me(message) @restrict_irc def colors(connection): connection.colors = not connection.colors if connection.colors: return '\x0312c\x0304o\x0309l\x0308o\x0306r\x0313s \x0f\x16ON!' else: return 'colors off' for function in (who, score, alias, unalias, colors): commands.add(function)
def aimbot_match(player, msg): return (not aimbot_pattern.match(msg) is None) @admin def badmin(connection, var=None): if var == None: return ( "@Badmin (r%s): Language Filter(LF) [%s], Blank Votekick Blocker(BV) " "[%s], Grief Votekick Protection(GV) [%s], Aimbot Votekick Protection(AV) [%s]" % (BADMIN_VERSION, LANGUAGE_FILTER_ENABLED, BLANK_VOTEKICK_ENABLED, SCORE_GRIEF_ENABLED, SCORE_AIMBOT_ENABLED)) add(badmin) @admin def investigate(connection, player): player = get_player(connection.protocol, player) score = score_grief(connection, player) kdr = round(player.ratio_kills / float(max(1, player.ratio_deaths))) percent = round(check_percent(player)) message = "Results for %s: Grief Score - %s / KDR - %s / Hit Acc. - %s" % ( player.name, score, kdr, percent) add(investigate)
def commands(connection, value=None): names = [] for command in cmdlist: command_func = cmdlist[command] if (hasattr(command_func, 'user_types') and command not in connection.rights): continue include = False if (value is None or fnmatch.fnmatch(command, value)): include = True aliases = [] for a in aliaslist: if aliaslist[a] == command: if (value is None or fnmatch.fnmatch(a, value)): include = True aliases.append(a) cmd = command if len(aliases) == 0 else ('%s (%s)' % (command, ', '.join(aliases))) if include: names.append(cmd) return 'Commands: %s' % (', '.join(names)) add(commands) def apply_script(protocol, connection, config): return protocol, connection
protocol = connection.protocol if len(args) == 0: protocol.votekick_enabled = not protocol.votekick_enabled return S_VOTEKICKING_SET.format( set=('enabled' if protocol.votekick_enabled else 'disabled')) try: player = get_player(protocol, '#' + args[0]) except InvalidPlayer: player = get_player(protocol, args[0]) player.votekick_enabled = not player.votekick_enabled return S_VOTEKICK_USER_SET.format( user=player.name, set=('enabled' if player.votekick_enabled else 'disabled')) add(start_votekick) add(cancel_votekick) add(vote_yes) add(togglevotekick) class Votekick(object): duration = 120.0 # 2 minutes interval = 2 * 60.0 # 3 minutes ban_duration = 15.0 public_votes = True schedule = None def _get_votes_remaining(self): return self.protocol.get_required_votes() - len(self.votes) + 1
message += '.' votekick = getattr(protocol, 'votekick', None) if (votekick and votekick.victim is player and votekick.victim.world_object and votekick.instigator.world_object): instigator = votekick.instigator tiles = int( distance_3d_vector(player.world_object.position, instigator.world_object.position)) instigator_name = (('\x0303' if instigator.team.id else '\x0302') + instigator.name + '\x0f') message += (' %s is %d tiles away from %s, who started the votekick.' % (player_name, tiles, instigator_name)) return message add(grief_check) def apply_script(protocol, connection, config): has_votekick = 'votekick' in config.get('scripts', []) class BlockInfoConnection(connection): blocks_removed = None teamkill_times = None def on_reset(self): self.blocks_removed = None self.teamkill_times = None connection.on_reset(self) def on_block_build(self, x, y, z):
m = Minefield(ext) if m.isValid(): return m return None @admin def minedebug(connection): proto = connection.protocol proto.minefield_debug = not proto.minefield_debug message = 'Minefield is now in debug' if proto.minefield_debug else 'Minefield is no longer in debug' proto.send_chat(message, global_message=True) return 'You toggled minefield debug' add(minedebug) def apply_script(protocol, connection, config): class MineConnection(connection): def on_position_update(self): ret = connection.on_position_update(self) if self.protocol.minefield_debug: return ret pos = self.world_object.position x, y, z = int(pos.x), int(pos.y), int(pos.z) + 3 if self.world_object.crouch: z -= 1 self.protocol.check_mine(self, x, y, z, spawnUp=True) return ret
@admin def reloadconfig(connection): new_config = {} try: new_config = json.load(open('config.txt', 'r')) if not isinstance(new_config, dict): raise ValueError('config.txt is not a mapping type') except ValueError, v: print 'Error reloading config:', v return 'Error reloading config. Check pyspades log for details.' connection.protocol.config.update(new_config) connection.protocol.reload_passes() return 'Config reloaded!' add(reloadconfig) def apply_script(protocol, connection, config): class PassreloadProtocol(protocol): def reload_passes(self): self.passwords = config.get('passwords', {}) for password in self.passwords.get('admin', []): if password == 'replaceme': print 'REMEMBER TO CHANGE THE DEFAULT ADMINISTRATOR PASSWORD!' elif not password: self.everyone_is_admin = True commands.rights.update(config.get('rights', {})) return PassreloadProtocol, connection
""" Team Deathmatch game mode. Maintainer: Triplefox """ from pyspades.constants import * from piqueserver import commands def score(connection): return connection.protocol.get_kill_count() commands.add(score) def apply_script(protocol, connection, config): class TDMConnection(connection): def on_spawn(self, pos): self.send_chat(self.explain_game_mode()) self.send_chat(self.protocol.get_kill_count()) return connection.on_spawn(self, pos) def on_flag_capture(self): result = connection.on_flag_capture(self) self.team.kills += self.protocol.intel_points self.protocol.check_end_game(self) return result
# disable if you don't want to kick people who jerk conviniently backwards onto their targets # -- NOT IMPLEMENTED! AIMBLOCK_KICK_SNAP = False def aimbotcheck(connection, user, minutes): connection = commands.get_player(connection.protocol, user) if connection not in connection.protocol.players: raise KeyError() kills = connection.tally_kill_log(reactor.seconds() - int(minutes) * 60) return ('Player %s did %s kills in the last %s minutes.' % (connection.name, kills, minutes)) commands.add(aimbotcheck) def apply_script(protocol, connection, config): def aimblock(f): def _f1(self, *args, **kwargs): if self.aimbot_detect: return f(self, *args, **kwargs) return _f1 class AImBlockConnection(connection): aimbot_detect = True aimbot_heur_max = 0.92 aimbot_heur_jerk = 0.33 aimbot_heur_leeway = 0.9
team.flag.set(*pos) # If spawn not set, it would throw error. team.flag.update() protocol.send_chat("The %s intel has been reset." % team.name) @admin def resetblueintel(connection): reset_intel(connection.protocol, connection.protocol.blue_team) @admin def resetgreenintel(connection): reset_intel(connection.protocol, connection.protocol.green_team) add(resetblueintel) add(resetgreenintel) def get_entity_location(self, entity_id): if entity_id == BLUE_BASE: return self.protocol.blue_team.cp elif entity_id == GREEN_BASE: return self.protocol.green_team.cp # this next part might seem counter intuitive but you need the blue intel # to spawn near the greens and vice versa elif entity_id == BLUE_FLAG: return self.protocol.green_team.spawn elif entity_id == GREEN_FLAG: return self.protocol.blue_team.spawn
player.send_chat("You're %s" % message) if connection is not player and connection in protocol.players: connection.send_chat('%s is %s' % (player.name, message)) protocol.irc_say('* %s is %s' % (player.name, message)) def resend_tool(player): set_tool.player_id = player.player_id set_tool.value = player.tool if player.weapon_object.shoot: player.protocol.send_contained(set_tool) else: player.send_contained(set_tool) add(toggle_rapid) def apply_script(protocol, connection, config): class RapidConnection(connection): rapid = False rapid_loop = None def on_login(self, name): self.rapid = ALWAYS_RAPID self.rapid_hack_detect = not self.rapid connection.on_login(self, name) def on_reset(self): if self.rapid_loop and self.rapid_loop.running: self.rapid_loop.stop()
Maintainer: mat^2 """ from statistics import DEFAULT_PORT, connect_statistics from piqueserver import commands def sitelogin(connection, name, password): value = connection.site_login(name, password) connection.send_chat(value) # so it doesn't appear in the log return False commands.add(sitelogin) def apply_script(protocol, connection, config): stats_config = config.get('statistics', {}) host = stats_config.get('host', 'localhost') port = stats_config.get('port', DEFAULT_PORT) server_name = stats_config.get('server_name', 'stats server') password = stats_config.get('password', '') class StatisticsConnection(connection): login_defer = None stats_name = None def on_kill(self, killer, type, grenade): if killer not in (self, None):
@name('daytime') def day_time(connection, value=None): if value is not None: if not connection.admin: return S_NO_RIGHTS value = float(value) if value < 0.0: raise ValueError() connection.protocol.current_time = value connection.protocol.update_day_color() f, i = modf(connection.protocol.current_time) return S_TIME_OF_DAY.format(hours=int(i), minutes=int(f * 60)) add(day_speed) add(day_time) from pyspades.color import * def apply_script(protocol, connection, config): class DayCycleProtocol(protocol): current_color = None current_time = None daycycle_loop = None day_duration = None day_update_frequency = None time_multiplier = None def __init__(self, *arg, **kw):
return "Player-initiated mapvotes are disabled on this server." return connection.protocol.start_votemap( VoteMap(connection, connection.protocol, connection.protocol.maps)) @commands.name('vote') def votemap_vote(connection, value): if connection not in connection.protocol.players: raise KeyError() if connection.protocol.votemap is not None: return connection.protocol.votemap.vote(connection, value) else: return 'No map vote in progress.' commands.add(votemap) commands.add(votemap_vote) def apply_script(protocol, connection, config): class VoteProtocol(protocol): # voting votemap_time = 120 votemap_interval = 3 * 60 votemap_percentage = 80.0 votemap = None planned_map = None autoschedule_call = None # voting
nick = args[0] time = int(args[1]) reason = join_arguments(args[2:]) player = get_player(protocol, nick) if time < 0: raise ValueError() if not player.mute: TimedMute(player, time, reason) else: return '%s is already muted!' % nick add(timed_mute) class TimedMute(object): player = None time = None def __init__(self, player, time=300, reason='None'): if time == 0: player.mute = True player.protocol.send_chat( '%s was muted indefinitely (Reason: %s)' % (player.name, reason), irc=True) return
block_action.value = DESTROY_BLOCK block_action.x = x block_action.y = y block_action.z = z prt.map.remove_point(x, y, z) prt.send_contained(block_action) return True return False def mirror(connection, mirror_x, mirror_y): connection.mirror_x = bool(mirror_x) connection.mirror_y = bool(mirror_y) add(mirror) def tunnel(*arguments): connection = arguments[0] connection.reset_build() connection.callback = tunnel_r connection.arguments = arguments connection.select = True connection.points = 1 add(tunnel) def tunnel_r(connection, radius, length, zoffset=0):
kicks = 0 for conn in to_kick[:amount]: if conn.name: conn.afk_kick() kicks += 1 else: conn.disconnect() message = S_AFK_KICKED.format(num_players=kicks, num_connections=amount - kicks, time=minutes_s) protocol.irc_say('* ' + message) if connection in protocol.players: return message add(afk) add(kick_afk) def apply_script(protocol, connection, config): time_limit = config.get('afk_time_limit', None) time_limit = time_limit and time_limit * 60.0 class AFKConnection(connection): afk_kick_call = None last_activity = None def afk_kick(self): if self.name: time_inactive = reactor.seconds() - self.last_activity time_inactive = max(1.0, round(time_inactive / 60.0)) * 60.0
from piqueserver.commands import add, admin, get_player S_GRANTED = '{player} is now trusted' S_GRANTED_SELF = "You've been granted trust, and can't be votekicked" S_CANT_VOTEKICK = "{player} is trusted and can't be votekicked" S_RESULT_TRUSTED = 'Trusted user' @admin def trust(connection, player): player = get_player(connection.protocol, player) player.on_user_login('trusted', False) player.send_chat(S_GRANTED_SELF) return S_GRANTED.format(player=player.name) add(trust) def apply_script(protocol, connection, config): class TrustedConnection(connection): def on_user_login(self, user_type, verbose=True): if user_type == 'trusted': self.speedhack_detect = False votekick = getattr(self.protocol, 'votekick', None) if votekick and votekick.victim is self: votekick.end(S_RESULT_TRUSTED) self.protocol.votekick = None return connection.on_user_login(self, user_type, verbose) class TrustedProtocol(protocol):
import random from piqueserver import commands DISCO_ON_GAME_END = True # Time is in seconds DISCO_ON_GAME_END_DURATION = 10.0 @commands.name('disco') @commands.admin def toggle_disco(connection): connection.protocol.toggle_disco(True) commands.add(toggle_disco) DISCO_COLORS = set([(235, 64, 0), (128, 232, 121), (220, 223, 12), (43, 72, 228), (216, 94, 231), (255, 255, 255)]) def apply_script(protocol, connection, config): class DiscoProtocol(protocol): current_colors = None disco = False old_fog_color = None def __init__(self, *arg, **kw): protocol.__init__(self, *arg, **kw) self.disco_loop = LoopingCall(self.update_color)
elif not player.airstrike: kills_left = STREAK_REQUIREMENT - (player.streak % STREAK_REQUIREMENT) return S_NO_STREAK.format(streak=STREAK_REQUIREMENT, remaining=kills_left) try: coord_x, coord_y = coordinates(coords) except (ValueError): return S_BAD_COORDS last_airstrike = getattr(player.team, 'last_airstrike', None) if last_airstrike and seconds() - last_airstrike < TEAM_COOLDOWN: remaining = TEAM_COOLDOWN - (seconds() - last_airstrike) return S_COOLDOWN.format(seconds=int(ceil(remaining))) player.start_airstrike(coord_x, coord_y) add(airstrike) def apply_script(protocol, connection, config): class AirstrikeConnection(connection): airstrike = False airstrike_grenade_calls = None last_streak = None def start_airstrike(self, coord_x, coord_y): coords = to_coordinates(coord_x, coord_y) message = S_ALLIED.format(player=self.name, coords=coords) self.protocol.send_chat(message, global_message=False, team=self.team) message = S_ENEMY.format(coords=coords)
message = S_PLAYER_ENABLED if player.allow_markers else S_PLAYER_DISABLED message = message.format(player=player.name) protocol.send_chat(message, irc=True) else: protocol.allow_markers = not protocol.allow_markers message = S_ENABLED if protocol.allow_markers else S_DISABLED connection.protocol.send_chat(message, irc=True) def markers(connection): if connection not in connection.protocol.players: raise ValueError() connection.send_lines(S_HELP) add(clear) add(toggle_markers) add(markers) class BaseMarker(): name = 'Marker' triggers = [] background = None background_class = None duration = None color = None random_colors = None team_color = False lines = [] points = []
smg_percent = 'None' if player.shotgun_count != 0: shotgun_percent = str( int(100.0 * (float(player.shotgun_hits) / float(player.shotgun_count)))) + '%' else: shotgun_percent = 'None' s = '' if name_info: s += player.name + ' has an accuracy of: ' s += 'Rifle: %s SMG: %s Shotgun: %s.' % (rifle_percent, smg_percent, shotgun_percent) return s add(accuracy) @admin def hackinfo(connection, name): player = get_player(connection.protocol, name) return hackinfo_player(player) def hackinfo_player(player): info = "%s #%s (%s) has an accuracy of: " % (player.name, player.player_id, player.address[0]) info += accuracy_player(player, False) ratio = player.ratio_kills / float(max(1, player.ratio_deaths)) info += " Kill-death ratio of %.2f (%s kills, %s deaths)." % ( ratio, player.ratio_kills, player.ratio_deaths)
@alias('a') def airstrike(connection, *args): if connection not in connection.protocol.players: raise ValueError() player = connection if player.airstrike: return S_READY kills_left = STREAK_REQUIREMENT - player.airstrike_streak return S_NO_STREAK.format(streak=STREAK_REQUIREMENT, remaining=kills_left) add(airstrike) # debug @admin @name('givestrike') def give_strike(connection, player=None): protocol = connection.protocol if player is not None: player = get_player(protocol, player) elif connection in protocol.players: player = connection else: raise ValueError() player.airstrike = True player.send_chat(S_READY)
player = get_player(protocol, player) elif connection in protocol.players: player = connection else: raise ValueError() player.drop_link() player.linkable = not player.linkable player.send_chat(S_LINKABLE_SELF if player.linkable else S_UNLINKABLE_SELF) message = S_LINKABLE if player.linkable else S_UNLINKABLE message.format(player=player.name) if connection is not player: return message for func in (running_man, relink, unlink): add(func) def apply_script(protocol, connection, config): class RunningManConnection(connection): link = None linkable = True last_warning = None link_deaths = None def on_position_update(self): if self.protocol.running_man: if self.link is not None and self.link.hp > 0: dist = distance_3d_vector(self.world_object.position, self.link.world_object.position) if dist > LINK_DISTANCE:
MAX_SPAWN_DISTANCE = 15.0 BUILDING_ENABLED = False if MAX_ROUND_TIME >= 60: MAX_ROUND_TIME_TEXT = '%.2f minutes' % (float(MAX_ROUND_TIME) / 60.0) else: MAX_ROUND_TIME_TEXT = str(MAX_ROUND_TIME) + ' seconds' @admin def coord(connection): connection.get_coord = True return 'Spade a block to get its coordinate.' add(coord) def make_color(r, g, b, a=255): r = int(r) g = int(g) b = int(b) a = float(a) return b | (g << 8) | (r << 16) | (int((a / 255.0) * 128.0) << 24) # Algorithm for minimizing the number of blocks sent for the gates using # a block line. Probably won't find the optimal solution for shapes that are not # rectangular prisms but it's better than nothing. # d = changing indice # c1 = first constant indice # c2 = second constant indice
@commands.admin @commands.name('stoprecord') def stop_record(connection): connection.protocol.stop_record() return 'Recording stopped.' @commands.admin @commands.name('saverecord') def save_record(connection, value): if not connection.protocol.save_record(value): return 'No record file available.' return 'Record saved.' commands.add(start_timer) commands.add(stop_timer) commands.add(start_record) commands.add(stop_record) commands.add(save_record) def apply_script(protocol, connection, config): class MatchConnection(connection): def on_flag_take(self): self.add_message("%s took %s's flag!" % (self.printable_name, self.team.other.name.lower())) return connection.on_flag_take(self) def on_flag_drop(self):
from pyspades.server import * from piqueserver import commands @commands.alias('tws') @commands.admin @commands.name('togglewallspading') def togglewallspading(self): self.protocol.is_fluffy = not self.protocol.is_fluffy if not self.protocol.is_fluffy: return 'Spading someone behind a wall is possible again now!' else: return 'You canot spade people through walls anymore. (killjoy)' commands.add(togglewallspading) def apply_script(protocol, connection, config): class nowallspadingprotocol(protocol): is_fluffy = True class nowallspadingconnection(connection): def on_hit(self, hit_amount, hit_player, hit_type, grenade): if hit_player.protocol.is_fluffy: pos = hit_player.world_object.position if not self.world_object.can_see(pos.x, pos.y, pos.z) and self.tool == SPADE_TOOL and not grenade and self.team != hit_player.team: return False
has_msg = "You have" if user != None: connection = get_player(connection.protocol, user) has_msg = "%s has" if connection not in connection.protocol.players: raise KeyError() has_msg %= connection.name if connection not in connection.protocol.players: raise KeyError() ratio = connection.ratio_kills / float(max(1, connection.ratio_deaths)) ratio_msg = has_msg + (" a kill-death ratio of %.2f" % (ratio)) return ('%s (%s kills, %s deaths).' % (ratio_msg, connection.ratio_kills, connection.ratio_deaths)) add(ratio) def apply_script(protocol, connection, config): class RatioConnection(connection): ratio_kills = 0 ratio_deaths = 0 def on_kill(self, killer, type, grenade): if killer is not None and self.team is not killer.team: if self != killer: killer.ratio_kills += 1 self.ratio_deaths += 1 return connection.on_kill(self, killer, type, grenade) class RatioProtocol(protocol):
r1, g1, b1 = a r2, g2, b2 = b r = blend_color_single(r1, r2, p) g = blend_color_single(g1, g2, p) b = blend_color_single(b1, b2, p) return r, g, b @name('stat') def show_stat(connection): protocol = connection.protocol msg = protocol.get_stat_message() connection.send_chat(msg) add(show_stat) def apply_script(protocol, connection, config): class BuildAndSplatConnection(connection): def get_spawn_location(self): # don't want spawn location decided using territory location self.protocol.game_mode = CTF_MODE p = connection.get_spawn_location(self) self.protocol.game_mode = TC_MODE return p def set_weapon(self, weapon, local=False, no_kill=False): self.weapon = weapon if self.weapon_object is not None: self.weapon_object.reset()