# Tower of Babel game mode by Yourself
# Anti-griefized by izzy
# Made better by thepolm3
# like, alot better
from pyspades.constants import *
from random import randint
from twisted.internet.reactor import callLater

TRANSPARENT,FOG_COLOR,MULTI_TEAM=range(3)

PLATFORM_WIDTH = 50
PLATFORM_LENGTH = 100
PLATFORM_HEIGHT = 10 #below max spawn height
PLATFORM_COLOR = TRANSPARENT
BLUE_BASE_COORDS = (256-138, 256)
GREEN_BASE_COORDS = (256+138, 256)
SPAWN_SIZE = 40

PLATFORM_WIDTH /= 2
PLATFORM_LENGTH /= 2
PLATFORM_HEIGHT /= 2

def below_platform(x, y, z):
    h,w,l=PLATFORM_HEIGHT,PLATFORM_WIDTH,PLATFORM_LENGTH
    return (z >= h and 256+w>=y>=256-w and 256+l>=x>=256-l)

def above_platform(x, y, z):
    h,w,l=PLATFORM_HEIGHT,PLATFORM_WIDTH,PLATFORM_LENGTH
    return (z <= h and 256+w>=y>=256-w and 256+l>=x>=256-l)

def touching_platform(x,y,z):
    h,w,l=PLATFORM_HEIGHT,PLATFORM_WIDTH,PLATFORM_LENGTH
    return (h+1>=z>=h-1 and 256+w+1>=y>=256-w-1 and 256+l+1>=x>=256-l-1)

def apply_script(protocol, connection, config):
    
    class TowerOfBabelConnection(connection):
        block_list = []

        def on_spawn_location(self,pos):
            x,y,z = self.team.base.x,self.team.base.y,63
            while z==63 and not above_platform(x,y,z):
                x += randint(-SPAWN_SIZE, SPAWN_SIZE)
                y += randint(-SPAWN_SIZE, SPAWN_SIZE)
                z = self.protocol.map.get_z(x, y)
            return (x+0.5, y+0.5, z-0.5)

        def on_block_destroy(self, x, y, z, value):
            if not self.is_valid_destroy(x,y,z): return False
            if value==GRENADE_DESTROY:
                for xa in range(-1,2):
                    for ya in range(-1,2):
                        for za in range(-1,2):
                            if not self.is_valid_destroy(x+xa,y+ya,z+za): return False
            return connection.on_block_destroy(self, x, y, z, value)

        def is_valid_destroy(self,x,y,z):
            if touching_platform(x, y, z): return False
            try:
                for player in self.protocol.players.values():
                    if player.block_list!=self.block_list:
                        if player.team==self.team and (x, y, z) in player.block_list:
                            self.send_chat("You can't destroy your team's blocks")
                            return False
            except Exception:
                pass
            return True

        def on_block_build_attempt(self, x, y, z):
            if touching_platform(x, y, z): return False
            if 5>x-self.team.base.x>-5 and 5>y-self.team.base.y>-5:
                self.send_chat("You can't build so close to your base")
                return False
            self.block_list.append((x,y,z))
            return connection.on_block_build_attempt(self, x, y, z)

        def on_line_build_attempt(self, points):
            for point in points:
                if self.on_block_build_attempt(*point)==False: return False
            return connection.on_line_build_attempt(self, points)

        def on_flag_take(self):
            # flash team color in sky
            callLater(0.25, self.protocol.set_fog_color,self.protocol.fog_color)
            self.protocol.set_fog_color(self.team.color)
            return connection.on_flag_take(self)

        def on_disconnect(self):
            self.block_list=[] #he won't care after he's gone ;)
            connection.on_disconnect(self)

        # return intel to platform if dropped
        def on_flag_drop(self):
            if not above_platform(*self.get_location()):
                self.protocol.reset_flags()
                self.protocol.send_chat('The intel has returned to the heavens')
            return connection.on_flag_drop(self)

    class TowerOfBabelProtocol(protocol):
        game_mode = CTF_MODE

        def reset_flags(self):
            for flag in self.blue_team.flag,self.green_team.flag:
                flag.x,flag.y,flag.z=self.on_flag_spawn(0,0,0,flag,flag.id)
                flag.update()

        def build_platform(self):
            map=self.map
            for y in xrange(256 - PLATFORM_WIDTH, 256 + PLATFORM_WIDTH):
                for x in xrange(256 - PLATFORM_LENGTH, 256 + PLATFORM_LENGTH):
                    if PLATFORM_COLOR==TRANSPARENT: map.set_point(x, y, PLATFORM_HEIGHT, map.get_color(x,y,map.get_z(x,y)))
                    elif PLATFORM_COLOR==FOG_COLOR: map.set_point(x, y, PLATFORM_HEIGHT, getattr(self.map_info.info, 'fog', (128, 232, 255)))
                    elif PLATFORM_COLOR==MULTI_TEAM:
                        if x<256: map.set_point(x, y, PLATFORM_HEIGHT, self.blue_team.color)
                        elif x>256: map.set_point(x, y, PLATFORM_HEIGHT, self.green_team.color)
                        else: map.set_point(x, y, PLATFORM_HEIGHT, (0,0,0))
                    else: map.set_point(x, y, PLATFORM_HEIGHT, PLATFORM_COLOR)

        def on_flag_spawn(self,x,y,z,flag,id):
            x = randint(256 - PLATFORM_LENGTH, 256 + PLATFORM_LENGTH)
            y = randint(256 - PLATFORM_WIDTH, 256 + PLATFORM_WIDTH)
            z = PLATFORM_HEIGHT
            return (x,y,z)

        def on_base_spawn(self,x,y,z,base,id):
            if base.team==self.blue_team: x,y = BLUE_BASE_COORDS
            if base.team==self.green_team: x,y = GREEN_BASE_COORDS
            return x,y,self.map.get_z(x,y)

        def on_map_change(self, map):
            self.build_platform()
            return protocol.on_map_change(self, map)

    return TowerOfBabelProtocol, TowerOfBabelConnection
