示例#1
0
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)
示例#2
0
        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)
示例#3
0
文件: badmin.py 项目: yvt/piqueserver
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)

示例#4
0

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
示例#5
0
    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
示例#6
0
        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):
示例#7
0
    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
示例#8
0
@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
示例#9
0
"""
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
示例#10
0
# 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
示例#11
0
    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
示例#12
0
文件: rapid.py 项目: yvt/piqueserver
    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()
示例#13
0
文件: stats.py 项目: yvt/piqueserver
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):
示例#14
0
@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):
示例#15
0
        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
示例#16
0
    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
示例#17
0
            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):
示例#18
0
文件: afk.py 项目: yvt/piqueserver
    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
示例#19
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):
示例#20
0
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)
示例#21
0
    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)
示例#22
0
        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 = []
示例#23
0
        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)
示例#24
0

@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)
示例#25
0
        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:
示例#26
0
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
示例#27
0
@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):
示例#28
0
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
示例#29
0
文件: ratio.py 项目: yvt/piqueserver
    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()