"""
Rush by thepolm3.
Based totaly on this (as I can't use TC that well)
 | | | |
 V V V V
Tug of War game mode, where you must progressively capture the enemy CPs in a 
straight line to win.

Maintainer: mat^2
"""

from pyspades.constants import *
from pyspades.server import Territory
import random
import math
from math import pi
from commands import get_team

#touch!
CP_COUNT = 4
MAX_SPAWNS = 10
ALWAYS_BLUE = False

#don't touch :)
CP_COUNT*=2 #easiest fix for bug
CP_EXTRA_COUNT = CP_COUNT + 2 # PLUS last 'spawn'
ANGLE = 65
START_ANGLE = math.radians(-ANGLE)
END_ANGLE = math.radians(ANGLE)
DELTA_ANGLE = math.radians(30)
FIX_ANGLE = math.radians(4)

class TugTerritory(Territory):
    disabled = True
    
    def add_player(self, player):
        if self.disabled:
            return
        Territory.add_player(self, player)
    
    def enable(self):
        self.disabled = False
    
    def disable(self):
        for player in self.players.copy():
            self.remove_player(player)
        self.disabled = True
        self.progress = float(self.team.id)

def get_index(value):
    if value < 0:
        raise IndexError()
    return value

def random_up_down(value):
    value /= 2
    return random.uniform(-value, value)

def limit_angle(value):
    return min(END_ANGLE, max(START_ANGLE, value))

def limit_dimension(value):
    return min(511, max(0, value))

def get_point(x, y, magnitude, angle):
    return (limit_dimension(x + math.cos(angle) * magnitude),
            limit_dimension(y + math.sin(angle) * magnitude))

def apply_script(protocol, connection, config):
    class TugConnection(connection):
        spawns=0

        def get_spawn_location(self):
            if self.team.spawn_cp is None:
                base = self.team.last_spawn
            else:
                base = self.team.spawn_cp
            return base.get_spawn_location()

        def on_team_switch_attempt(self):
            if self.team==get_team(self,"blue"):
                if self.spawns>=MAX_SPAWNS:
                    self.send_chat("You are dead! You can't do that!")
                    return False
            return connection.on_team_switchattempt(self)

        def on_spawn(self,pos):
            returned = connection.on_spawn(self,pos)
            if self.name in self.protocol.playersMaxed:
                self.spawns=self.protocol.playersMaxed[self.name]
                if self.spawns>=MAX_SPAWNS: #if reconnecting
                    self.kill()
            return returned

        def respawn(self):
            if self.team==get_team(self,"blue"):
                self.spawns+=1
                self.protocol.playersMaxed[self.name] = self.spawns
                if self.spawns>=MAX_SPAWNS:
                    return False
                else:
                    self.send_chat("Phew, that was a close one. You have %d spawns left" %(MAX_SPAWNS-self.spawns))
            return connection.respawn(self)
            
    class TugProtocol(protocol):
        game_mode = TC_MODE
        playersMaxed={}

        def get_cp_entities(self):
            # generate positions

            map = self.map
            blue_cp = []
            green_cp = [(0,0)]

            magnitude = 10
            angle = random.uniform(START_ANGLE, END_ANGLE)
            x, y = (0, random.randrange(64, 512 - 64))
            
            points = []
            
            square_1 = xrange(128)
            square_2 = xrange(512 - 128, 512)
            
            while 1:
                top = int(y) in square_1
                bottom = int(y) in square_2
                if top:
                    angle = limit_angle(angle + FIX_ANGLE)
                elif bottom:
                    angle = limit_angle(angle - FIX_ANGLE)
                else:
                    angle = limit_angle(angle + random_up_down(DELTA_ANGLE))
                magnitude += random_up_down(2)
                magnitude = min(15, max(5, magnitude))
                x2, y2 = get_point(x, y, magnitude, angle)
                if x2 >= 511:
                    break
                x, y = x2, y2
                points.append((int(x), int(y)))
            
            move = 512 / CP_EXTRA_COUNT
            offset = move / 2
            
            for i in xrange(CP_EXTRA_COUNT):
                index = 0
                while 1:
                    p_x, p_y = points[index]
                    index += 1
                    if p_x >= offset:
                        break
                if i*2 < CP_EXTRA_COUNT:
                    blue_cp.append((p_x, p_y))
                offset += move
            
            # make entities
            
            index = 0
            entities = []
            
            for i, (x, y) in enumerate(blue_cp):
                entity = TugTerritory(index, self, *(x, y, map.get_z(x, y)))
                entity.team = self.blue_team
                if i == 0:
                    self.blue_team.last_spawn = entity
                    entity.id = -1
                else:
                    entities.append(entity)
                    index += 1
            
            self.blue_team.cp = entities[-1]
            self.blue_team.cp.disabled = False
            self.blue_team.spawn_cp = entities[-2]

            for i, (x, y) in enumerate(green_cp):
                entity = TugTerritory(index, self, *(x, y, map.get_z(x, y)))
                entity.team = self.green_team
                if i == len(green_cp) - 1:
                    self.green_team.last_spawn = entity
                    entity.id = index
                else:
                    entities.append(entity)
                    index += 1

            self.green_team.cp = entities[-CP_COUNT/2]
            self.green_team.cp.disabled = False
            self.green_team.spawn_cp = entities[-CP_COUNT/2 + 1]
            
            return entities
    
        def on_cp_capture(self, territory):
            team = territory.team
            if team==get_team(self.players[0],"blue"):
                return False
            if team.id:
                move = -1
            else:
                move = 1
            for team in [self.blue_team, self.green_team]:
                try:
                    team.cp = self.entities[get_index(team.cp.id + move)]
                    team.cp.enable()
                except IndexError:
                    pass
                try:
                    team.spawn_cp = self.entities[get_index(
                        team.spawn_cp.id + move)]
                except IndexError:
                    team.spawn_cp = team.last_spawn
            cp = (self.blue_team.cp, self.green_team.cp)
            for entity in self.entities:
                if not entity.disabled and entity not in cp:
                    entity.disable()

        def on_map_change(self,map):
            for player in self.players:
                self.players[player].spawns=0
            playersMaxed=[]
            return protocol.on_map_change(self,map)

    return TugProtocol, TugConnection
