from math import sqrt
from pyspades.server import *
from pyspades.constants import *
from commands import get_player, name, add, admin, alias
import commands
from twisted.internet import reactor
from twisted.internet.task import LoopingCall

def set_claws1(player, value):             # no i am not going
    player.claws1 = player.get_location()  # to make the whole 

def set_claws2(player, value):             # thing shorter i am
    player.claws2 = player.get_location()  # untidy as fuck

def set_loc(player):         # once you have been assigned a velocity you switch 
    c, a, t = player.claws1  # constantly between your location and the one you
    f, e, g = player.claws2  # should be according to trajectory
    if abs(c) + abs(a) + abs(t)  >  abs(f) + abs(e) + abs(g): player.set_location(player.claws1) # therefore i have to filter the wrong
    else: player.set_location(player.claws2)                                                     # locations out via these functions

def reset_intel(protocol, team):
    team.set_flag()
    team.flag.update()
    protocol.send_chat("The %s intel has been reset." % team.name)

@alias('kbv')                                                         # command for setting the knockback strength
@admin                                                                # i would suggest setting it between 5 and 15
@name('knockbackvalue')                                               # the lower the amount, the stronger the attack
def knockback_strength(self, value):
    if int(value) <= 0: return 'Great choice, now use your brain'     # for the sake of stability
    else:
        self.protocol.knockback_value = int(value)
        return 'Set to %f uhuhuhu.' % (self.protocol.knockback_value) # uhuhuhu
commands.add(knockback_strength)


def apply_script(protocol, connection, config):

    class KnockbackConnection(connection):

        cat = None    # Nyaaaaaaaaaa~
        paws = None   # <3 fluffy cats
        claws1 = None # i wanna cuddle with my cat right now Y_Y
        claws2 = None # meeow
        exist = True

        def on_hit(self, hit_amount, hit_player, type, grenade):

            if  self.team != hit_player.team: # prevents you from exterminating your comrades wich would probably suck if you do not wish for a free for all

                hit_player.cat = self.name # saves the killer's name oh yeah cats are cute btw
                hit_player.paws = type         # of course these little tigers have claws to save

                xp, yp, zp = self.get_location()       # locations 
                xv, yv, zv = hit_player.get_location() # and shit

                vec_push_x = xv - xp # i never learned in school how to do taxes
                vec_push_y = yv - yp # or how to apply for university or a job
                vec_push_z = zv - zp # but thank god i can calculate vectors now

                vec_value = sqrt( (xv - xp)**2 + (yv - yp)**2 ) # i always predicted i am going to need this one
                if vec_value == 0: vec_value = 1 # just in case, it might rip time and space apart otherwise

                hit_player.world_object.velocity.x = (vec_push_x / vec_value) * (hit_amount / hit_player.protocol.knockback_value)      # fucking hell this is something even a
                hit_player.world_object.velocity.y = (vec_push_y / vec_value) * (hit_amount / hit_player.protocol.knockback_value)      # 10th grader would be able to calculate
                hit_player.world_object.velocity.z = (vec_push_z / vec_value) * (hit_amount / (hit_player.protocol.knockback_value * 30)) # how did it end up being so difficult for me?!'''

                
                for tomato in range(30): # okay this is important BECAUSE IT TOOK ME WEEKS TO FIND IT OUT 

                    if hit_player is not None: # in case of disconnects

                        reactor.callLater(0.01*tomato, set_claws1, hit_player, 1) # first collected location data
                        reactor.callLater(0.02*tomato, set_claws2, hit_player, 2) # third (obviously not - kiddie rofl lol trole XDXD) collected location data
                        reactor.callLater(0.03*tomato, set_loc, hit_player) # the actual process where your location will be set

                    else: break

                return False

        def on_fall(self, damage): # the actual function for detecting kills, i hate it for being such a dick

            if self.exist != True: return False

            if damage >= self.hp and self.cat != None and self.paws != None: # for those who are actualy smart enough to die from their own stupidity
                try:
                    last_cat = get_player(self.protocol, self.cat) # get the bitch who attacked you last  

                    kill_action.player_id = self.player_id                      # so many lines because pyspades
                    kill_action.killer_id = last_cat.player_id                  # (in other words me) is too dumb
                    kill_action.kill_type = self.paws                           # to understand what self.kill()
                    kill_action.respawn_time = config.get("respawn_time")       # means here, pyspades is so rude
                
                    for players in self.protocol.players.values():    # to be honest i have no fucking idea anymore why
                        players.send_contained(kill_action)           # i sent this information to everybody
            
                    return connection.on_fall(self, 0)
                except: return False
            return connection.on_fall(self, damage)

        def on_spawn(self, pos):                    # yeah prevents you from giving points
            self.cat = None                         # too lazy to check out if it is realy
            self.paws = None                        # necessary to reset these variables
            return connection.on_spawn(self, pos)

        def on_disconnect(self):                                      # to make sure your murderer 
            for potatoes in self.protocol.players.values():           # does not disconnect so the
                if potatoes.cat == self.name: potatoes.cat = None     # server will not err
            self.exist = False
            return connection.on_disconnect(self)

    class KnockbackProtocol(protocol):
        
        knockback_value = 9    # just to give the admins something to screw around
        game_mode = CTF_MODE   # why not
        check_loop = None

        def check_intel_locations(self):
            if self.blue_team.flag is not None:
                if self.blue_team.flag.get()[2] >= 63:
                    reset_intel(self, self.blue_team)
            if self.green_team.flag is not None:
                if self.green_team.flag.get()[2] >= 63:
                    reset_intel(self, self.green_team)

        def on_map_change(self, map):
            if self.check_loop is not None:
                self.check_loop.stop()
            self.check_loop = LoopingCall(self.check_intel_locations)
            self.check_loop.start(1)
            return protocol.on_map_change(self, map)

    return KnockbackProtocol, KnockbackConnection