"""
MOBApowers by thepolm3
Powers! Idea by blockpower
Use this script with the "MOBA" as your gamemode for epic win
#jdrew
"""

from pyspades.server import weapon_reload,set_tool
from pyspades.constants import *
from twisted.internet.reactor import callLater
from commands import invisible,add,admin,get_player
from random import randint

GREY,RED,ORANGE,YELLOW,GREEN,TOURQUOISE,BLUE,PINK=range(8)
ARMOR,DAMAGE,TELEPORT,FLY,INVISIBLE,AMMO,HEAL,CRITICAL=range(8)
MAX_LEVEL=5
LEVEL_UP_THRESHOLD=10 #kills-deaths
COOLDOWN=20

@admin
def super(connection,*args):
    if args:
        player=get_player(connection.protocol,args[0])
    else:
        player=connection
    player.level=100
    player.pickingPower=False
    player.on_refill()
    connection.send_chat("Superfied!")
add(super)

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","Critical hit"][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 b==r and r>g: return PINK #critical hit 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
    return 0

def multiplier(powerid,level):
    if powerid==ARMOR: return (1.0/(level+1))+0.25
    if powerid==DAMAGE: return 1.0/((1.0/(level+1))+0.25)
    if powerid==TELEPORT: return (level-1)
    if powerid==FLY: return 2*level+3
    if powerid==INVISIBLE: return 1.5*level+3.5
    if powerid==AMMO: return (float(level)/2)+1
    if powerid==HEAL: return level
    if powerid==CRITICAL: return float(level)/100

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==CRITICAL: return "You have a %s chance to deal critical damage" %(percentage(n))

def apply_script(protocol,connection,config):
    class PowConnection(connection):
        PickingPower=True
        power=POWdeaths=POWkills=teleports=on_cooldown=0
        level=1
        flop=True

        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 and not self.PickingPower:
                self.teleports=multiplier(TELEPORT,self.level)
                print(self.teleports)
            if self.power==AMMO and not self.PickingPower:
                callLater(0.01,self.set_ammo,self.weapon_object.current_ammo,self.weapon_object.current_stock*multiplier(AMMO,self.level))
            return connection.on_refill(self)

        def on_spawn_location(self,pos):
            if self.PickingPower:
                self.send_chat("You are picking your power, use blocks to change power and /power to finish")
            else:
                self.on_refill()
            connection.on_spawn_location(self,pos)

        def on_hit(self,amount,victim,type,weapon):
            print(amount)
            if self.power==CRITICAL and not self.PickingPower:
                if not self==victim:
                    rand=randint(0,100)
                    if rand<(multiplier(CRITICAL,self.level)*100):
                        amount=200
                        self.send_chat("Critical strike!")
            if victim.power==ARMOR and not victim.PickingPower:
                amount*=multiplier(ARMOR,victim.level)
            if self.power==DAMAGE and not self.PickingPower:
                if not self==victim:
                    amount*=multiplier(DAMAGE,self.level)
            temp=connection.on_hit(self,amount,victim,type,weapon)
            if temp:
                amount=temp
            print(amount)
            return amount

        def on_kill(self,killer,type,weapon):
            if killer and killer!=self:
                self.POWdeaths+=1
                killer.POWkills+=1
                killer.level_up()
                self.send_chat("Your killer had the power; "+power_name(killer.power))
            return connection.on_kill(self,killer,type,weapon)

        def on_position_update(self):
            if self.power==HEAL and not self.PickingPower:
                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,type=FALL_KILL)
            return connection.on_position_update(self)

        def on_block_destroy(self,x,y,z,type):
            if self.power==TELEPORT and self.teleports>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.teleports-=1
                self.send_chat("You have %d gun teleports remaining"%(self.teleports))
            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)
                self.send_chat("Type /power to choose this")
                self.send_chat(power_name(power)+" : "+power_description(power,self.level))
            return connection.on_color_set(self,colour)

        def end_pow(self):
            self.fly=False
            if self.invisible:
                invisible(self)
            self.on_cooldown=True
            self.send_chat("Your power has timed out")
            callLater(COOLDOWN,self.reset_pow,"You can now use fly and invisible again")

        def reset_pow(self,prompt):
            self.send_chat(prompt)
            self.on_cooldown=False

        def on_command(self,command,parameters):
            if command=="power":
                if self.PickingPower:
                    self.remind_power()
                    self.fly=False
                    if self.invisible:
                        invisible(self)
                    callLater(COOLDOWN,self.reset_pow,"")
                    self.send_chat("Your power has been set")
                    self.PickingPower=False
                else:
                    self.send_chat("You are now picking your power, use block colours to change power")
                    self.PickingPower=True
            if self.power==FLY:
                if command=="f" and not self.PickingPower:
                    if self.on_cooldown:
                        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" and not self.PickingPower:
                    if self.on_cooldown:
                        self.send_chat("You can't hide so soon after your last fly!")
                    else:
                        invisible(self)
                        callLater(multiplier(FLY,self.level),self.end_pow)
                    
            return connection.on_command(self,command,parameters)

        def on_grenade_thrown(self, grenade):
            if self.power==TELEPORT and not self.PickingPower:
                callLater(grenade.fuse+0.5,self.on_grenade_splode,grenade)
            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):
        pass
            
            
    return PowProtocol, PowConnection
