Match.py

8 posts Page 1 of 1
danhezee
Former Admin / Co-founder
Former Admin / Co-founder
Posts: 1709
Joined: Wed Oct 03, 2012 12:09 am


Code: Select all

"""
Rewrite of match.py.
Intended to be used for tournaments and clan matches.
"""
from pyspades.common import coordinates, to_coordinates, prettify_timespan
from commands import add, admin, name
from twisted.internet import reactor
from twisted.internet.task import LoopingCall
    
S_MATCH_START = 'The match has started!'
S_MATCH_TIMELEFT = '{time} remaining.'
S_MATCH_CANCELLED = 'The match has been stopped by {who}!'
S_MATCH_OVER = 'The match is over! {team} wins {score1} to {score2}!'
S_MATCH_TIE = 'The match is over! It\'s a tie!'
S_MATCH_TIE_EXTEND = 'Tie! Extending match by {time}. {sd}'
S_MATCH_SUDDEN_DEATH = 'Sudden death!'
    
S_MATCH_KILL = '{killer} killed {victim}!'
S_MATCH_FLAG_TAKE = '{who} took the {team} flag in {coord}!'
S_MATCH_FLAG_DROP = '{who} dropped the {team} flag in {coord}!'
S_MATCH_FLAG_CAP = '{who} captured the {team} flag!'
    
# In minutes.
MATCH_OVERTIME_LENGTH = 15
MATCH_ALLOW_TIES = True # set MATCH_EXTEND_ON_TIE if you want a "one-time only" extension in the event of a tie
MATCH_DISABLE_CHAT = True
MATCH_FEED_IN_CHAT = False
MATCH_RESET_FLAG_IN_WATER = True
MATCH_EXTEND_ON_TIE = True # only extends once
MATCH_SUDDEN_DEATH_ON_TIE = True
   
   
@admin
@name('timer')
def begin_timer(connection, time=60):
    if connection.protocol.match_in_progress:
        return 'A match is already running!'
    time = int(time) * 60
    connection.protocol.begin_match(time)
    
add(begin_timer)
    
@admin
@name('stoptimer')
def stop_timer(connection):
    if not connection.protocol.match_in_progress:
        return 'There\'s no match to stop!'
    connection.protocol.end_match(cancelled=True, cancelled_by=connection.printable_name)
    
add(stop_timer)
    
@admin
@name('toggleovertime')
def toggle_overtime(connection):
    global MATCH_EXTEND_ON_TIE
    MATCH_EXTEND_ON_TIE = not MATCH_EXTEND_ON_TIE
    return 'Overtime is now %s!' % ['disabled', 'enabled'][int(MATCH_EXTEND_ON_TIE)]
    
add(toggle_overtime)
   
def apply_script(protocol, connection, config):
    class MatchProtocol(protocol):
        match_in_progress = False
        match_timer_ends = 0
        match_intel_caps = {}
        match_sudden_death = False
        match_timer_call = None
        match_messages = []
        match_message_loop = None
        match_overtime = False
        blue_kill_count = 0
        green_kill_count = 0
        blue_death_count = 0
        green_death_count = 0
    
        def msg(self, message, override=False):
            if MATCH_FEED_IN_CHAT or override:
                self.send_chat(message, irc=True)
            else:
                self.irc_say(message)
    
        def begin_match(self, time):
            self.match_in_progress = True
            self.match_timer_ends = reactor.seconds() + time
            self.match_message_loop = LoopingCall(self.show_match_messages)
            self.match_message_loop.start(3)
                
            self.msg(S_MATCH_START, override=True)
    
            for p in self.players:
                player = self.players[p]
                player.spawn(player.team.get_random_location(force_land=True))
    
            # This will start a loop of callLater()s.
            self.show_match_timer()
            
        def end_match(self, cancelled=False, cancelled_by=None):
            if self.green_team.score > self.blue_team.score:
                result = S_MATCH_OVER.format(team=self.green_team.name, score1=self.green_team.score, score2=self.blue_team.score)
            elif self.blue_team.score > self.green_team.score:
                result = S_MATCH_OVER.format(team=self.blue_team.name, score1=self.blue_team.score, score2=self.green_team.score)
            elif not cancelled:
                if (not MATCH_ALLOW_TIES) or (MATCH_EXTEND_ON_TIE and not self.match_overtime):
                    self.match_sudden_death = MATCH_SUDDEN_DEATH_ON_TIE
                    self.match_overtime = True
                    self.extend_match(MATCH_OVERTIME_LENGTH * 60)
                    self.show_match_timer()
                    return
                else:
                    result = S_MATCH_TIE
            greenkills = self.green_kill_count
            greendeaths = float(max(1,self.green_death_count))
            bluekills = self.blue_kill_count
            bluedeaths = float(max(1,self.blue_death_count))
            self.match_messages.append("Green team had %s kill(s) and %s death(s) (%.2f). Blue team had %s kill(s) and %s death(s) (%.2f)." % (self.green_kill_count, self.green_death_count, greenkills/greendeaths, self.blue_kill_count, self.blue_death_count, bluekills/bluedeaths))
            for player in self.players.values():
                player.drop_flag()
                if player.kill_count > 0 or player.death_count > 0:
                    self.match_messages.append("%s has %s kill(s) and %s death(s) (%.2f) and (%s Caps, %s Grabs)." % (player.name, player.kill_count, player.death_count, player.kill_count/float(max(1,player.death_count)), player.cap_count, player.grab_count))
            self.match_in_progress = False
            self.match_sudden_death = False
            self.match_timer_ends = 0
            self.green_kill_count = 0
            self.blue_kill_count = 0
            self.green_death_count = 0
            self.blue_death_count = 0
            for player in self.players.values():
                player.kill_count = 0
                player.death_count = 0
                player.cap_count = 0
                player.grab_count = 0
                
            if cancelled:
                self.match_timer_call.cancel()
                msg = S_MATCH_CANCELLED.format(who=cancelled_by)
                self.msg(msg, override=True)
            else:
                self.msg(result, override=True)
    
        def extend_match(self, time):
            self.match_timer_ends += time
            sd = S_MATCH_SUDDEN_DEATH if self.match_sudden_death else ''
            self.msg(S_MATCH_TIE_EXTEND.format(time=prettify_timespan(time, get_seconds=True), sd=sd), override=True)
    
        def show_match_timer(self):
            from math import floor
            time_left = self.match_timer_ends - reactor.seconds()
            if time_left > 60:
                next_call = 60
            else:
                next_call = max(1, floor(time_left / 2.0))
                
            if time_left <= 0:
                if self.match_in_progress:
                    self.end_match()
                return
    
            self.msg(S_MATCH_TIMELEFT.format(time=prettify_timespan(time_left, get_seconds=True)), override=True)
            self.match_timer_call = reactor.callLater(next_call, self.show_match_timer)
    
        def show_match_messages(self):
            if len(self.match_messages) == 0:
                if not self.match_in_progress:
                    self.match_message_loop.stop()
                return
            message = self.match_messages.pop(0)
            self.msg(message)
    
    
    class MatchConnection(connection):
        connection.kill_count = 0
        connection.death_count = 0
        connection.cap_count = 0
        connection.grab_count = 0
        def on_block_build_attempt(self, x, y, z):
            if not self.protocol.match_in_progress:
                return False
            return connection.on_block_build_attempt(self, x, y, z)
    
        def on_block_destroy(self, x, y, z, value):
            if not self.protocol.match_in_progress:
                return False
            return connection.on_block_destroy(self, x, y, z, value)
    
        def on_chat(self, message, global_message):
            if MATCH_DISABLE_CHAT and global_message and self.protocol.match_in_progress and not any(
                    t in self.user_types for t in ('admin', 'moderator', 'guard', 'trusted')):
                self.send_chat("Global messages are disabled for the duration of this match.")
                return False
            return connection.on_chat(self, message, global_message)
    
        def on_command(self, command, arguments):
            if self.protocol.match_in_progress and command == 'time':
                time_left = self.protocol.match_timer_ends - reactor.seconds()
                msg = S_MATCH_TIMELEFT.format(time=prettify_timespan(time_left, get_seconds=True))
                self.send_chat(msg)
                return False
            if command == 'kill':
                self.kill()
            return connection.on_command(self, command, arguments)
    
        def on_flag_drop(self):
            x, y, z = self.get_location()
            if self.team.other.flag.z >= 63:
                x_offset = 3
                y_offset = 5
                z = self.protocol.map.get_z(x, y)
                if y > 256:
                    self.team.other.flag.set(x - x_offset, y - y_offset, z - 1)
                if y < 256:
                    self.team.other.flag.set(x - x_offset, y + y_offset, z - 1)
                self.team.other.flag.update()
            self.protocol.match_messages.append(S_MATCH_FLAG_DROP.format(
                who=self.printable_name, team=self.team.other.name, coord=to_coordinates(x,y)))
            return connection.on_flag_drop(self)
    
        def on_flag_take(self):
            if not self.protocol.match_in_progress:
                return False
            x, y, z = self.get_location()
            self.grab_count += 1
            self.protocol.match_messages.append(S_MATCH_FLAG_TAKE.format(
                who=self.printable_name, team=self.team.other.name, coord=to_coordinates(x,y)))
            return connection.on_flag_take(self)
    
        def on_flag_capture(self):
            if not self.protocol.match_in_progress:
                return False
            self.cap_count += 1
            result = connection.on_flag_capture(self)
            message = S_MATCH_FLAG_CAP.format(
                    who=self.printable_name, team=self.team.other.name)
    
            if self.protocol.match_sudden_death:
                self.protocol.msg(message, override=True)
                self.protocol.end_match()
            else:
                self.protocol.match_messages.append(S_MATCH_FLAG_CAP.format(
                    who=self.printable_name, team=self.team.other.name))
    
            return result
    
        def on_kill(self, killer, type, grenade):
            if not self.protocol.match_in_progress:
                return False
            if self.team == self.protocol.green_team:
                if killer is not None and self.team is not killer.team:
                    if self != killer:
                        killer.kill_count += 1
                        self.protocol.blue_kill_count += 1
                self.death_count += 1
                self.protocol.green_death_count += 1
            if self.team == self.protocol.blue_team:
                if killer is not None and self.team is not killer.team:
                    if self != killer:
                        killer.kill_count += 1
                        self.protocol.green_kill_count += 1
                self.death_count += 1
                self.protocol.blue_death_count += 1
            self.protocol.match_messages.append(S_MATCH_KILL.format(
                killer=killer.name if killer else self.name, victim=self.name))
            return connection.on_kill(self, killer, type, grenade)
               
        def on_line_build_attempt(self, points):
            if not self.protocol.match_in_progress:
                return False
            return connection.on_line_build_attempt(self, points)
              
    return MatchProtocol, MatchConnection
This is the current match.py script used for the league. Sharing it incase anyone wants to use it for their own purposes and I have a few requests to be added to the script. Below are two list the first one is the primary requests and the second is secondary requests.

PRIMARY:
  • /PAUSE - pauses the timer toggles killing and building, can no longer pick up the flag.
    • There are two ways to handle pause. We could freeze players in there current positions, or we could let them run around and when we unpause they respawn on their side of the map.
    /RESUME - unpauses the game toggles everything back

    This isnt a command but after x number of players have joined either team no one else can join. So for example if the max number of players is 5 it will be impossible for a sixth player to join. Well i guess it would need a command to toggle it off or increase its size.

    The intel can only spawn on a 20 block radius away from the command post, it wouldnt spawn in water either.
SECONDARY:
  • after the match was over and there is a tie it will print out the distance the flag moved from the center
Feel free to include other match.py suggestion if you have any.
thepolm3
Scripter
Scripter
Posts: 424
Joined: Sat Feb 16, 2013 10:49 pm


Pause/unpause
Code: Select all
"""
Rewrite of match.py.
Intended to be used for tournaments and clan matches.
"""
from pyspades.common import coordinates, to_coordinates, prettify_timespan
from commands import add, admin, name
from twisted.internet import reactor
from twisted.internet.task import LoopingCall
    
S_MATCH_START = 'The match has started!'
S_MATCH_TIMELEFT = '{time} remaining.'
S_MATCH_CANCELLED = 'The match has been stopped by {who}!'
S_MATCH_OVER = 'The match is over! {team} wins {score1} to {score2}!'
S_MATCH_TIE = 'The match is over! It\'s a tie!'
S_MATCH_TIE_EXTEND = 'Tie! Extending match by {time}. {sd}'
S_MATCH_SUDDEN_DEATH = 'Sudden death!'
S_MATCH_PAUSED = "The match is paused"
S_MATCH_RESUMED = "Match unpaused"
    
S_MATCH_KILL = '{killer} killed {victim}!'
S_MATCH_FLAG_TAKE = '{who} took the {team} flag in {coord}!'
S_MATCH_FLAG_DROP = '{who} dropped the {team} flag in {coord}!'
S_MATCH_FLAG_CAP = '{who} captured the {team} flag!'
    
# In minutes.
MATCH_OVERTIME_LENGTH = 15
MATCH_ALLOW_TIES = True # set MATCH_EXTEND_ON_TIE if you want a "one-time only" extension in the event of a tie
MATCH_DISABLE_CHAT = True
MATCH_FEED_IN_CHAT = False
MATCH_RESET_FLAG_IN_WATER = True
MATCH_EXTEND_ON_TIE = True # only extends once
MATCH_SUDDEN_DEATH_ON_TIE = True
   
   
@admin
@name('timer')
def begin_timer(connection, time=60):
    if connection.protocol.match_in_progress:
        return 'A match is already running!'
    time = int(time) * 60
    connection.protocol.begin_match(time)
    
add(begin_timer)
    
@admin
@name('stoptimer')
def stop_timer(connection):
    if not connection.protocol.match_in_progress:
        return 'There\'s no match to stop!'
    connection.protocol.end_match(cancelled=True, cancelled_by=connection.printable_name)
    
add(stop_timer)
    
@admin
@name('toggleovertime')
def toggle_overtime(connection):
    global MATCH_EXTEND_ON_TIE
    MATCH_EXTEND_ON_TIE = not MATCH_EXTEND_ON_TIE
    return 'Overtime is now %s!' % ['disabled', 'enabled'][int(MATCH_EXTEND_ON_TIE)]
    
add(toggle_overtime)

@admin
def pause(connection):
    if connection.protocol.paused_since:
        return "Game already paused"
    if not connection.protocol.match_in_progress:
        return "No match in progress"
    connection.protocol.pause_match()

add(pause)

@admin
def resume(connection):
    if not connection.protocol.match_timer_ends:
        return "No game in progress"
    if not connection.protocol.paused_since:
        return "Game not paused"
    connection.protocol.resume_match()

add(resume)
   
def apply_script(protocol, connection, config):
    class MatchProtocol(protocol):
        match_in_progress = False
        match_timer_ends = 0
        match_intel_caps = {}
        match_sudden_death = False
        match_timer_call = None
        match_messages = []
        match_message_loop = None
        match_overtime = False
        blue_kill_count = 0
        green_kill_count = 0
        blue_death_count = 0
        green_death_count = 0
        paused_since = False
    
        def msg(self, message, override=False):
            if MATCH_FEED_IN_CHAT or override:
                self.send_chat(message, irc=True)
            else:
                self.irc_say(message)
    
        def begin_match(self, time):
            self.match_in_progress = True
            self.match_timer_ends = reactor.seconds() + time
            self.match_message_loop = LoopingCall(self.show_match_messages)
            self.match_message_loop.start(3)
                
            self.msg(S_MATCH_START, override=True)
    
            for p in self.players:
                player = self.players[p]
                player.spawn(player.team.get_random_location(force_land=True))
    
            # This will start a loop of callLater()s.
            self.show_match_timer()
        
        def pause_match(self):
            self.match_in_progress = False
            self.paused_since = reactor.seconds()
            self.msg(S_MATCH_PAUSED)
        
        def resume_match(self):
            self.match_timer_ends+=reactor.seconds-self.paused_since
            self.match_in_progress=True
            self.paused_since=False
            self.msg(S_MATCH_RESUMED)
            self.show_match_timer()

        def end_match(self, cancelled=False, cancelled_by=None):
            if self.green_team.score > self.blue_team.score:
                result = S_MATCH_OVER.format(team=self.green_team.name, score1=self.green_team.score, score2=self.blue_team.score)
            elif self.blue_team.score > self.green_team.score:
                result = S_MATCH_OVER.format(team=self.blue_team.name, score1=self.blue_team.score, score2=self.green_team.score)
            elif not cancelled:
                if (not MATCH_ALLOW_TIES) or (MATCH_EXTEND_ON_TIE and not self.match_overtime):
                    self.match_sudden_death = MATCH_SUDDEN_DEATH_ON_TIE
                    self.match_overtime = True
                    self.extend_match(MATCH_OVERTIME_LENGTH * 60)
                    self.show_match_timer()
                    return
                else:
                    result = S_MATCH_TIE
            greenkills = self.green_kill_count
            greendeaths = float(max(1,self.green_death_count))
            bluekills = self.blue_kill_count
            bluedeaths = float(max(1,self.blue_death_count))
            self.match_messages.append("Green team had %s kill(s) and %s death(s) (%.2f). Blue team had %s kill(s) and %s death(s) (%.2f)." % (self.green_kill_count, self.green_death_count, greenkills/greendeaths, self.blue_kill_count, self.blue_death_count, bluekills/bluedeaths))
            for player in self.players.values():
                player.drop_flag()
                if player.kill_count > 0 or player.death_count > 0:
                    self.match_messages.append("%s has %s kill(s) and %s death(s) (%.2f) and (%s Caps, %s Grabs)." % (player.name, player.kill_count, player.death_count, player.kill_count/float(max(1,player.death_count)), player.cap_count, player.grab_count))
            self.match_in_progress = False
            self.match_sudden_death = False
            self.match_timer_ends = 0
            self.green_kill_count = 0
            self.blue_kill_count = 0
            self.green_death_count = 0
            self.blue_death_count = 0
            for player in self.players.values():
                player.kill_count = 0
                player.death_count = 0
                player.cap_count = 0
                player.grab_count = 0
                
            if cancelled:
                self.match_timer_call.cancel()
                msg = S_MATCH_CANCELLED.format(who=cancelled_by)
                self.msg(msg, override=True)
            else:
                self.msg(result, override=True)
    
        def extend_match(self, time):
            self.match_timer_ends += time
            sd = S_MATCH_SUDDEN_DEATH if self.match_sudden_death else ''
            self.msg(S_MATCH_TIE_EXTEND.format(time=prettify_timespan(time, get_seconds=True), sd=sd), override=True)
    
        def show_match_timer(self):
            
            time_left = [self.match_timer_ends - reactor.seconds(),self.match_timer_ends-self.paused_since][self.paused_since]
            if time_left > 60:
                next_call = 60
            else:
                next_call = max(1, int(time_left / 2.0))
                
            if time_left <= 0:
                if self.match_in_progress:
                    self.end_match()
                return
            if self.paused_since:
                self.msg(S_MATCH_PAUSED)
            else:
                self.msg(S_MATCH_TIMELEFT.format(time=prettify_timespan(time_left, get_seconds=True)), override=True)
            self.match_timer_call = reactor.callLater(next_call, self.show_match_timer)
        
        def show_match_messages(self):
            if len(self.match_messages) == 0:
                if not self.match_in_progress:
                    self.match_message_loop.stop()
                return
            message = self.match_messages.pop(0)
            self.msg(message)
    
    
    class MatchConnection(connection):
        connection.kill_count = 0
        connection.death_count = 0
        connection.cap_count = 0
        connection.grab_count = 0
        def on_block_build_attempt(self, x, y, z):
            if not self.protocol.match_in_progress:
                return False
            return connection.on_block_build_attempt(self, x, y, z)
    
        def on_block_destroy(self, x, y, z, value):
            if not self.protocol.match_in_progress:
                return False
            return connection.on_block_destroy(self, x, y, z, value)
    
        def on_chat(self, message, global_message):
            if MATCH_DISABLE_CHAT and global_message and self.protocol.match_in_progress and not any(
                    t in self.user_types for t in ('admin', 'moderator', 'guard', 'trusted')):
                self.send_chat("Global messages are disabled for the duration of this match.")
                return False
            return connection.on_chat(self, message, global_message)
    
        def on_command(self, command, arguments):
            if self.protocol.match_in_progress and command == 'time':
                time_left = self.protocol.match_timer_ends - reactor.seconds()
                msg = S_MATCH_TIMELEFT.format(time=prettify_timespan(time_left, get_seconds=True))
                self.send_chat(msg)
                return False
            if command == 'kill':
                self.kill()
            return connection.on_command(self, command, arguments)
    
        def on_flag_drop(self):
            x, y, z = self.get_location()
            if self.team.other.flag.z >= 63:
                x_offset = 3
                y_offset = 5
                z = self.protocol.map.get_z(x, y)
                if y > 256:
                    self.team.other.flag.set(x - x_offset, y - y_offset, z - 1)
                if y < 256:
                    self.team.other.flag.set(x - x_offset, y + y_offset, z - 1)
                self.team.other.flag.update()
            self.protocol.match_messages.append(S_MATCH_FLAG_DROP.format(
                who=self.printable_name, team=self.team.other.name, coord=to_coordinates(x,y)))
            return connection.on_flag_drop(self)
    
        def on_flag_take(self):
            if not self.protocol.match_in_progress:
                return False
            x, y, z = self.get_location()
            self.grab_count += 1
            self.protocol.match_messages.append(S_MATCH_FLAG_TAKE.format(
                who=self.printable_name, team=self.team.other.name, coord=to_coordinates(x,y)))
            return connection.on_flag_take(self)
    
        def on_flag_capture(self):
            if not self.protocol.match_in_progress:
                return False
            self.cap_count += 1
            result = connection.on_flag_capture(self)
            message = S_MATCH_FLAG_CAP.format(
                    who=self.printable_name, team=self.team.other.name)
    
            if self.protocol.match_sudden_death:
                self.protocol.msg(message, override=True)
                self.protocol.end_match()
            else:
                self.protocol.match_messages.append(S_MATCH_FLAG_CAP.format(
                    who=self.printable_name, team=self.team.other.name))
    
            return result
    
        def on_kill(self, killer, type, grenade):
            if not self.protocol.match_in_progress:
                return False
            if self.team == self.protocol.green_team:
                if killer is not None and self.team is not killer.team:
                    if self != killer:
                        killer.kill_count += 1
                        self.protocol.blue_kill_count += 1
                self.death_count += 1
                self.protocol.green_death_count += 1
            if self.team == self.protocol.blue_team:
                if killer is not None and self.team is not killer.team:
                    if self != killer:
                        killer.kill_count += 1
                        self.protocol.green_kill_count += 1
                self.death_count += 1
                self.protocol.blue_death_count += 1
            self.protocol.match_messages.append(S_MATCH_KILL.format(
                killer=killer.name if killer else self.name, victim=self.name))
            return connection.on_kill(self, killer, type, grenade)
               
        def on_line_build_attempt(self, points):
            if not self.protocol.match_in_progress:
                return False
            return connection.on_line_build_attempt(self, points)
              
    return MatchProtocol, MatchConnection
Last edited by thepolm3 on Wed Feb 12, 2014 4:00 pm, edited 1 time in total.
learn_more
Coder
Coder
Posts: 890
Joined: Sun Mar 24, 2013 9:59 pm


lol either make all strings globals or keep em all inline,
don't do half one and half another :p
thepolm3
Scripter
Scripter
Posts: 424
Joined: Sat Feb 16, 2013 10:49 pm


Ah the inconsistencies
Fixed
MrFritz
League Operator
League Operator
Posts: 484
Joined: Sat Nov 10, 2012 1:57 am


Admining the League servers for a couple of months and most of the admins and players have realized something that could be a huge benefit to the game. Fixed intel to CP positions would make the initial starting of the match faster and easier for the Admins control the outcome and fairness of the intel resets. Also an idea came to me, being able to toggle the distance away from the intel to the CP is so the intel resets are always the same for the teams.

Example:
/intelpos 5 -Moves the intel 5 blocks away from the CP is either direction

It would be easier for the teams to agree on a distance away from the CP their intels are than a completely random /resetgame
Could this be available in Season 5 please? It would make running the server slightly better and we can ensure the 100% fairness between both teams intels

Cheers!
scrawl
Veterans
Veterans
Posts: 974
Joined: Mon Dec 16, 2013 12:09 pm


MrFritz wrote:
Admining the League servers for a couple of months and most of the admins and players have realized something that could be a huge benefit to the game. Fixed intel to CP positions would make the initial starting of the match faster and easier for the Admins control the outcome and fairness of the intel resets. Also an idea came to me, being able to toggle the distance away from the intel to the CP is so the intel resets are always the same for the teams.

Example:
/intelpos 5 -Moves the intel 5 blocks away from the CP is either direction

It would be easier for the teams to agree on a distance away from the CP their intels are than a completely random /resetgame
Could this be available in Season 5 please? It would make running the server slightly better and we can ensure the 100% fairness between both teams intels

Cheers!
I think this would be a great idea,it would save alot of time, and make the games fairer. This should be done for Season 5 is possible.
thepolm3
Scripter
Scripter
Posts: 424
Joined: Sat Feb 16, 2013 10:49 pm


Unfourtunately I cannot test this code at the moment, but I think It should work
/intelpos [distance] {radius}
Code: Select all
"""
Rewrite of match.py.
Intended to be used for tournaments and clan matches.
"""
from pyspades.common import coordinates, to_coordinates, prettify_timespan
from commands import add, admin, name
from twisted.internet import reactor
from twisted.internet.task import LoopingCall
from math import degrees,atan,sin,cos
from random import randint

S_MATCH_START = 'The match has started!'
S_MATCH_TIMELEFT = '{time} remaining.'
S_MATCH_CANCELLED = 'The match has been stopped by {who}!'
S_MATCH_OVER = 'The match is over! {team} wins {score1} to {score2}!'
S_MATCH_TIE = 'The match is over! It\'s a tie!'
S_MATCH_TIE_EXTEND = 'Tie! Extending match by {time}. {sd}'
S_MATCH_SUDDEN_DEATH = 'Sudden death!'
S_MATCH_PAUSED = "The match is paused"
S_MATCH_RESUMED = "Match unpaused"
    
S_MATCH_KILL = '{killer} killed {victim}!'
S_MATCH_FLAG_TAKE = '{who} took the {team} flag in {coord}!'
S_MATCH_FLAG_DROP = '{who} dropped the {team} flag in {coord}!'
S_MATCH_FLAG_CAP = '{who} captured the {team} flag!'
    
# In minutes.
MATCH_OVERTIME_LENGTH = 15
MATCH_ALLOW_TIES = True # set MATCH_EXTEND_ON_TIE if you want a "one-time only" extension in the event of a tie
MATCH_DISABLE_CHAT = True
MATCH_FEED_IN_CHAT = False
MATCH_RESET_FLAG_IN_WATER = True
MATCH_EXTEND_ON_TIE = True # only extends once
MATCH_SUDDEN_DEATH_ON_TIE = True

@admin
def intelpos(connection,distance,radius=90):
    distance,radius=int(distance),int(radius)
    protocol = connection.protocol
    blue,green = protocol.blue_team,protocol.green_team
    bx,by,bz = blue.base.x,blue.base.y,blue.base.z
    gx,gy,gz = green.base.x,green.base.y,green.base.z
    xd,yd = bx-gx,by-gy
    angle = degrees(atan(xd/yd)) + randint(radius/-2,radius/2)
    x,y = distance*degrees(sin(angle)) + gx,distance*degrees(cos(angle))*-1 + gy
    green.flag.set(x,y,protocol.map.get_z(x,y))
    green.flag.update()
    angle = degrees(atan(xd/yd)) + randint(radius/-2,radius/2)
    x,y = distance*degrees(sin(angle))*-1 + bx,distance*degrees(cos(angle)) + by
    blue.flag.set(x,y,protocol.map.get_z(x,y))
    blue.flag.update()
    return "Flags repositioned successfully"

@admin
@name('timer')
def begin_timer(connection, time=60):
    if connection.protocol.match_in_progress:
        return 'A match is already running!'
    time = int(time) * 60
    connection.protocol.begin_match(time)
    
add(begin_timer)
    
@admin
@name('stoptimer')
def stop_timer(connection):
    if not connection.protocol.match_in_progress:
        return 'There\'s no match to stop!'
    connection.protocol.end_match(cancelled=True, cancelled_by=connection.printable_name)
    
add(stop_timer)
    
@admin
@name('toggleovertime')
def toggle_overtime(connection):
    global MATCH_EXTEND_ON_TIE
    MATCH_EXTEND_ON_TIE = not MATCH_EXTEND_ON_TIE
    return 'Overtime is now %s!' % ['disabled', 'enabled'][int(MATCH_EXTEND_ON_TIE)]
    
add(toggle_overtime)

@admin
def pause(connection):
    if connection.protocol.paused_since:
        return "Game already paused"
    if not connection.protocol.match_in_progress:
        return "No match in progress"
    connection.protocol.pause_match()

add(pause)

@admin
def resume(connection):
    if not connection.protocol.match_timer_ends:
        return "No game in progress"
    if not connection.protocol.paused_since:
        return "Game not paused"
    connection.protocol.resume_match()

add(resume)
   
def apply_script(protocol, connection, config):
    class MatchProtocol(protocol):
        match_in_progress = False
        match_timer_ends = 0
        match_intel_caps = {}
        match_sudden_death = False
        match_timer_call = None
        match_messages = []
        match_message_loop = None
        match_overtime = False
        blue_kill_count = 0
        green_kill_count = 0
        blue_death_count = 0
        green_death_count = 0
        paused_since = False
    
        def msg(self, message, override=False):
            if MATCH_FEED_IN_CHAT or override:
                self.send_chat(message, irc=True)
            else:
                self.irc_say(message)
    
        def begin_match(self, time):
            self.match_in_progress = True
            self.match_timer_ends = reactor.seconds() + time
            self.match_message_loop = LoopingCall(self.show_match_messages)
            self.match_message_loop.start(3)
                
            self.msg(S_MATCH_START, override=True)
    
            for p in self.players:
                player = self.players[p]
                player.spawn(player.team.get_random_location(force_land=True))
    
            # This will start a loop of callLater()s.
            self.show_match_timer()
        
        def pause_match(self):
            self.match_in_progress = False
            self.paused_since = reactor.seconds()
            self.msg(S_MATCH_PAUSED)
        
        def resume_match(self):
            self.match_timer_ends+=reactor.seconds-self.paused_since
            self.match_in_progress=True
            self.paused_since=False
            self.msg(S_MATCH_RESUMED)
            self.show_match_timer()

        def end_match(self, cancelled=False, cancelled_by=None):
            if self.green_team.score > self.blue_team.score:
                result = S_MATCH_OVER.format(team=self.green_team.name, score1=self.green_team.score, score2=self.blue_team.score)
            elif self.blue_team.score > self.green_team.score:
                result = S_MATCH_OVER.format(team=self.blue_team.name, score1=self.blue_team.score, score2=self.green_team.score)
            elif not cancelled:
                if (not MATCH_ALLOW_TIES) or (MATCH_EXTEND_ON_TIE and not self.match_overtime):
                    self.match_sudden_death = MATCH_SUDDEN_DEATH_ON_TIE
                    self.match_overtime = True
                    self.extend_match(MATCH_OVERTIME_LENGTH * 60)
                    self.show_match_timer()
                    return
                else:
                    result = S_MATCH_TIE
            greenkills = self.green_kill_count
            greendeaths = float(max(1,self.green_death_count))
            bluekills = self.blue_kill_count
            bluedeaths = float(max(1,self.blue_death_count))
            self.match_messages.append("Green team had %s kill(s) and %s death(s) (%.2f). Blue team had %s kill(s) and %s death(s) (%.2f)." % (self.green_kill_count, self.green_death_count, greenkills/greendeaths, self.blue_kill_count, self.blue_death_count, bluekills/bluedeaths))
            for player in self.players.values():
                player.drop_flag()
                if player.kill_count > 0 or player.death_count > 0:
                    self.match_messages.append("%s has %s kill(s) and %s death(s) (%.2f) and (%s Caps, %s Grabs)." % (player.name, player.kill_count, player.death_count, player.kill_count/float(max(1,player.death_count)), player.cap_count, player.grab_count))
            self.match_in_progress = False
            self.match_sudden_death = False
            self.match_timer_ends = 0
            self.green_kill_count = 0
            self.blue_kill_count = 0
            self.green_death_count = 0
            self.blue_death_count = 0
            for player in self.players.values():
                player.kill_count = 0
                player.death_count = 0
                player.cap_count = 0
                player.grab_count = 0
                
            if cancelled:
                self.match_timer_call.cancel()
                msg = S_MATCH_CANCELLED.format(who=cancelled_by)
                self.msg(msg, override=True)
            else:
                self.msg(result, override=True)
    
        def extend_match(self, time):
            self.match_timer_ends += time
            sd = S_MATCH_SUDDEN_DEATH if self.match_sudden_death else ''
            self.msg(S_MATCH_TIE_EXTEND.format(time=prettify_timespan(time, get_seconds=True), sd=sd), override=True)
    
        def show_match_timer(self):
            
            time_left = [self.match_timer_ends - reactor.seconds(),self.match_timer_ends-self.paused_since][self.paused_since]
            if time_left > 60:
                next_call = 60
            else:
                next_call = max(1, int(time_left / 2.0))
                
            if time_left <= 0:
                if self.match_in_progress:
                    self.end_match()
                return
            if self.paused_since:
                self.msg(S_MATCH_PAUSED)
            else:
                self.msg(S_MATCH_TIMELEFT.format(time=prettify_timespan(time_left, get_seconds=True)), override=True)
            self.match_timer_call = reactor.callLater(next_call, self.show_match_timer)
        
        def show_match_messages(self):
            if len(self.match_messages) == 0:
                if not self.match_in_progress:
                    self.match_message_loop.stop()
                return
            message = self.match_messages.pop(0)
            self.msg(message)
    
    
    class MatchConnection(connection):
        connection.kill_count = 0
        connection.death_count = 0
        connection.cap_count = 0
        connection.grab_count = 0
        def on_block_build_attempt(self, x, y, z):
            if not self.protocol.match_in_progress:
                return False
            return connection.on_block_build_attempt(self, x, y, z)
    
        def on_block_destroy(self, x, y, z, value):
            if not self.protocol.match_in_progress:
                return False
            return connection.on_block_destroy(self, x, y, z, value)
    
        def on_chat(self, message, global_message):
            if MATCH_DISABLE_CHAT and global_message and self.protocol.match_in_progress and not any(
                    t in self.user_types for t in ('admin', 'moderator', 'guard', 'trusted')):
                self.send_chat("Global messages are disabled for the duration of this match.")
                return False
            return connection.on_chat(self, message, global_message)
    
        def on_command(self, command, arguments):
            if self.protocol.match_in_progress and command == 'time':
                time_left = self.protocol.match_timer_ends - reactor.seconds()
                msg = S_MATCH_TIMELEFT.format(time=prettify_timespan(time_left, get_seconds=True))
                self.send_chat(msg)
                return False
            if command == 'kill':
                self.kill()
            return connection.on_command(self, command, arguments)
    
        def on_flag_drop(self):
            x, y, z = self.get_location()
            if self.team.other.flag.z >= 63:
                x_offset = 3
                y_offset = 5
                z = self.protocol.map.get_z(x, y)
                if y > 256:
                    self.team.other.flag.set(x - x_offset, y - y_offset, z - 1)
                if y < 256:
                    self.team.other.flag.set(x - x_offset, y + y_offset, z - 1)
                self.team.other.flag.update()
            self.protocol.match_messages.append(S_MATCH_FLAG_DROP.format(
                who=self.printable_name, team=self.team.other.name, coord=to_coordinates(x,y)))
            return connection.on_flag_drop(self)
    
        def on_flag_take(self):
            if not self.protocol.match_in_progress:
                return False
            x, y, z = self.get_location()
            self.grab_count += 1
            self.protocol.match_messages.append(S_MATCH_FLAG_TAKE.format(
                who=self.printable_name, team=self.team.other.name, coord=to_coordinates(x,y)))
            return connection.on_flag_take(self)
    
        def on_flag_capture(self):
            if not self.protocol.match_in_progress:
                return False
            self.cap_count += 1
            result = connection.on_flag_capture(self)
            message = S_MATCH_FLAG_CAP.format(
                    who=self.printable_name, team=self.team.other.name)
    
            if self.protocol.match_sudden_death:
                self.protocol.msg(message, override=True)
                self.protocol.end_match()
            else:
                self.protocol.match_messages.append(S_MATCH_FLAG_CAP.format(
                    who=self.printable_name, team=self.team.other.name))
    
            return result
    
        def on_kill(self, killer, type, grenade):
            if not self.protocol.match_in_progress:
                return False
            if self.team == self.protocol.green_team:
                if killer is not None and self.team is not killer.team:
                    if self != killer:
                        killer.kill_count += 1
                        self.protocol.blue_kill_count += 1
                self.death_count += 1
                self.protocol.green_death_count += 1
            if self.team == self.protocol.blue_team:
                if killer is not None and self.team is not killer.team:
                    if self != killer:
                        killer.kill_count += 1
                        self.protocol.green_kill_count += 1
                self.death_count += 1
                self.protocol.blue_death_count += 1
            self.protocol.match_messages.append(S_MATCH_KILL.format(
                killer=killer.name if killer else self.name, victim=self.name))
            return connection.on_kill(self, killer, type, grenade)
               
        def on_line_build_attempt(self, points):
            if not self.protocol.match_in_progress:
                return False
            return connection.on_line_build_attempt(self, points)
              
    return MatchProtocol, MatchConnection
Attachments
match.py
(13.66 KiB) Downloaded 88 times
Jigsaw
3 Years of Ace of Spades
3 Years of Ace of Spades
Posts: 502
Joined: Fri Sep 27, 2013 11:41 am


scrawl wrote:
MrFritz wrote:
Admining the League servers for a couple of months and most of the admins and players have realized something that could be a huge benefit to the game. Fixed intel to CP positions would make the initial starting of the match faster and easier for the Admins control the outcome and fairness of the intel resets. Also an idea came to me, being able to toggle the distance away from the intel to the CP is so the intel resets are always the same for the teams.

Example:
/intelpos 5 -Moves the intel 5 blocks away from the CP is either direction

It would be easier for the teams to agree on a distance away from the CP their intels are than a completely random /resetgame
Could this be available in Season 5 please? It would make running the server slightly better and we can ensure the 100% fairness between both teams intels

Cheers!
I think this would be a great idea,it would save alot of time, and make the games fairer. This should be done for Season 5 is possible.
8 posts Page 1 of 1
Return to “Game Modes”

Who is online

Users browsing this forum: No registered users and 1 guest