"""
thepolm3
Powers! Idea by blockpower
"""
from pyspades.server import weapon_reload,set_tool
from pyspades.constants import *
from twisted.internet.reactor import callLater
from commands import invisible

GREY,RED,ORANGE,YELLOW,GREEN,TOURQUOISE,BLUE,PINK=range(8)
ARMOR,DAMAGE,TELEPORT,FLY,INVISIBLE,AMMO,HEAL,SPEED=range(8)
CAGE=[(0,0,58),(1,0,61),(1,0,60),(1,0,59),(0,1,61),(0,1,60),(0,1,59),(0,0,62)]

MAX_LEVEL=5
LEVEL_UP_THRESHOLD=10 #kills-deaths
COOLDOWN=20

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)

def power_name(powerid):
    if powerid==None: return "No power"
    return ["Armor","Damage","Teleportation","Fly","Invisibility","Ammo","Healing","Speed"][powerid]

def get_colour_id(colour):
    r,g,b=colour
    if r==g==b: return GREY #armor row
    if r>g and g==b: return RED #damage row
    if r>g>b: return ORANGE #teleport row
    if r==g and r>b: return YELLOW #fly row
    if g>b and b==r: return GREEN #invisible row
    if g==b and b>r: return TOURQUOISE #ammo row
    if b>r and r==g: return BLUE #heal row
    if b==r and r>g: return PINK #speed row
    return 0

def multiplier(powerid,level):
    if powerid==ARMOR: return (1.0/(level+1))+0.25
    if powerid==DAMAGE: return (float(level)/2)+0.75
    if powerid==TELEPORT: return (level-1)
    if powerid==FLY: return 2*level
    if powerid==INVISIBLE: return 2*level
    if powerid==AMMO: return (float(level)/2)+1
    if powerid==HEAL: return level
    if powerid==SPEED: return 1/float(level)

def percentage(number):
    return str(int(number*100))+"%"

def power_description(powerid,level):
    n=multiplier(powerid,level)
    if powerid==ARMOR: return "You take %s damage from hits" %(percentage(n))
    if powerid==DAMAGE: return "You deal %s damage with hits" %(percentage(n))
    if powerid==TELEPORT and level==1: return "You can teleport with grenades"
    if powerid==TELEPORT: return "You can teleport using grenades and (%d) bullets" %(n)
    if powerid==FLY: return "You can fly for %d seconds using /f" %(n)
    if powerid==INVISIBLE: return "You can stealth for %d seconds using /i" %(n)
    if powerid==AMMO: return "You start off with %s more ammo" %(percentage(n-1))
    if powerid==HEAL: return "You heal those around you for %d hp" %(n)
    if powerid==SPEED: return "Your mining lag becomes %s WORK IN PROGRESS" %(percentage(n))

def apply_script(protocol,connection,config):
    class PowConnection(connection):
        PickingPower=True
        power=POWdeaths=POWkills=parameter=0
        """looping=False"""
        level=1

        def tell_trapped(self):
            self.send_chat("----------------------------------------------")
            self.send_chat("------------Do /done when finished------------")
            self.send_chat("----------------------------------------------")
            self.send_chat("----------------------------------------------")
            self.send_chat("Please pick a power by using the block colours")
            self.send_chat("----------------------------------------------")
            
        def remind_power(self):
            self.send_chat(power_description(self.power,self.level))
            self.send_chat("You are a level %d %s" %(self.level, power_name(self.power)))

        def level_up(self):
            if self.POWkills-self.POWdeaths>LEVEL_UP_THRESHOLD:
                if self.level<MAX_LEVEL:
                    self.POWkills=0
                    self.POWdeaths=0
                    self.level+=1
                    self.remind_power()
                    self.send_chat("Congratulations! You leveled up!")
                    self.refill()

        def on_refill(self):
            self.remind_power()
            if self.power==TELEPORT:
                self.parameter==multiplier(TELEPORT,self.level)
            if self.power==AMMO:
                callLater(0.01,self.set_ammo,self.weapon_object.current_ammo,self.weapon_object.current_stock*multiplier(AMMO,self.level))
            """if self.power==SPEED and not self.looping:
                self.reset_tool()"""
            return connection.on_refill(self)

        def on_spawn_location(self,pos):
            if self.PickingPower:
                self.tell_trapped()
                return (0.5,0.5,62)
            else:
                self.remind_power()
                self.on_refill()
            return connection.on_spawn_location(self,pos)

        def on_hit(self,amount,hitter,type,weapon):
            if self.PickingPower:
                self.tell_trapped()
                return False
            if self.power==ARMOR:
                amount*=multiplier(ARMOR,self.level)
            if hitter.power==DAMAGE:
                amount*=multiplier(DAMAGE,hitter.level)
            temp=connection.on_hit(self,amount,hitter,type,weapon)
            if temp:
                amount=temp
            return amount

        def on_kill(self,killer,type,weapon):
            if self.PickingPower:
                self.tell_trapped()
                return False
            if killer and killer!=self:
                self.POWdeaths+=1
                killer.POWkills+=1
                killer.level_up()
            return connection.on_kill(self,killer,type,weapon)

        def on_position_update(self):
            if self.power==HEAL:
                x,y,z=self.get_location()
                for player in self.protocol.players.values():
                    xa,ya,za = player.get_location()
                    if 5>xa-x>-5 and 5>ya-y>-5 and 5>za-z>-5 and self.team==player.team:
                        if player.hp!=100:
                            player.set_hp(player.hp+multiplier(HEAL,self.level),self)
            return connection.on_position_update(self)

        """def reset_tool(self):
            if self.tool==SPADE_TOOL or BLOCK_TOOL and self.world_object:
                resend_tool(self)
            if self.power==SPEED:
                self.looping=True
                self.rapid_hack_detect=False
                callLater(multiplier(SPEED,self.level),self.reset_tool)
            else:
                self.rapid_hack_detect=True
                self.looping=False"""

        def on_block_destroy(self,x,y,z,type):
            if (x,y,z) in CAGE:
                self.tell_trapped()
                return False
            if self.power==TELEPORT and self.parameter>0 and self.tool==WEAPON_TOOL: #lost of ands XD
                #from my script, worldedit
                for zt in range(z,0,-1):
                    solid,colour=self.protocol.map.get_point(x,y,zt)
                    if solid:
                        z=zt-3
                if zt!=0:
                    self.set_location((x,y,z))
                else:
                    self.set_location((x,y,-1))
                self.parameter-=1
                self.send_chat("You have %d gun teleports remaining"%(self.parameter))
            return connection.on_block_destroy(self,x,y,z,type)

        def on_color_set(self,colour):
            if self.PickingPower:
                self.power=power=get_colour_id(colour)
                for i in range(5):
                    self.send_chat("")
                self.send_chat(power_name(power)+" : "+power_description(power,1))
            return connection.on_color_set(self,colour)

        def on_chat(self,chat,is_global):
            if self.PickingPower:
                self.tell_trapped
                return False
            return connection.send_chat(self,chat,is_global)

        def end_pow(self):
            self.fly=False
            if self.invisible:
                invisible(self)
            self.parameter=COOLDOWN
            self.send_chat("Your power has timed out")
            callLater(COOLDOWN,self.reset_pow)

        def reset_pow(self):
            self.send_chat("You can now use your power again")
            self.parameter=0

        def on_command(self,command,parameters):
            if self.PickingPower:
                if command=="done":
                    self.PickingPower=False
                    self.spawn()
            if self.power==FLY:
                if command=="f":
                    if self.parameter:
                        self.send_chat("You can't fly so soon after your last fly!")
                    else:
                        self.fly=True
                        callLater(multiplier(FLY,self.level),self.end_pow)
                        self.send_chat("spam ctrl to fly!")
            if self.power==INVISIBLE:
                if command=="i":
                    if self.parameter:
                        self.send_chat("You can't hide so soon after your last fly!")
                    else:
                        invisible(self)
                        callLater(multiplier(FLY,self.level),self.end_pow)
                        self.send_chat("You are now invisible!")
                    
            return connection.on_command(self,command,parameters)

        def on_grenade_thrown(self, grenade):
            if self.power==TELEPORT:
                grenade.callback = self.on_grenade_splode
            return connection.on_grenade_thrown(self,grenade)

        def on_grenade_splode(self, grenade):
            x, y, z = (int(n) for n in grenade.position.get())
            self.set_location((x,y,z))

        def set_ammo(self, new_ammo, new_stock=None):
            #from my ammo.py ^^
            if new_ammo>255:
                new_ammo=255
            if new_stock>255:
                new_stock=255
            weapon=self.weapon_object
            weapon.set_shoot(False)
            weapon_reload.player_id = self.player_id
            weapon_reload.clip_ammo = weapon.current_ammo
            weapon.current_ammo = new_ammo
            if new_stock:
                weapon.current_stock = new_stock
            weapon_reload.reserve_ammo = weapon.current_stock
            self.send_contained(weapon_reload)
            self.ammo=(new_ammo,new_stock)
            
    class PowProtocol(protocol):
        
        def on_map_change(self,map):
            map.remove_point(0,0,61)
            map.remove_point(0,0,60)
            map.remove_point(0,0,59)
            for i in CAGE:
                map.set_point(*i, color=(255,255,255))
            
            return protocol.on_map_change(self, map)
            
            
    return PowProtocol, PowConnection
