from __future__ import generators
import plus
import Arenas
import AI
import random
import Hazards
import HazardsBlueRay
import math

class BoxArena(Arenas.SuperArena):
    "The Second Chance Arena - despite its name, allows for your robot to be flipped out three times before being eliminated. Make the most of your chances!"
    name = "The Second Chance Arena"
    preview = "secondchance/secondchance_preview.bmp"
    game_types = ['DEATHMATCH', 'BATTLE ROYAL', 'TEAM MATCH']

    def __init__(self):
        Arenas.SuperArena.__init__(self, "Arenas/secondchance/secondchance.gmf")
        plus.setBackColor(0,0,0)
        degrad = 0.01745
        self.AddStaticCamera("                Overview", (0, 7.8, -17.5), (35*degrad,0), 68*degrad)
        self.AddStaticCamera("                Corner Cam 1", (4, 0, 4), (10*degrad,45*degrad),72*degrad)
        self.AddStaticCamera("                Corner Cam 2", (4, 0, -4), (10*degrad,135*degrad), 72*degrad)
        self.AddStaticCamera("                Corner Cam 3", (-4, 0, -4), (10*degrad,225*degrad), 72*degrad)
        self.AddStaticCamera("                Corner Cam 4", (-4, 0, 4), (10*degrad,315*degrad), 72*degrad)
        self.AddWatchCamera("                Watch Cam 1", (15, 7.8, -15), (6, 37, 40*degrad, 15*degrad))
        self.AddWatchCamera("                Watch Cam 2", (-15, 7.8, 15), (6, 37, 40*degrad, 15*degrad))
        self.AddWatchCamera("                Blade Cam", (0, 2, 0), (5, 25, 65*degrad, 45*degrad))
        self.AddWatchCamera("                Overhead Cam", (0, 7.8, 0), (10, 15, 68*degrad, 58*degrad))
        self.AddWatchCamera("                Audience Cam", (0, 3, -30), (19, 41, 30*degrad, 20*degrad))
        self.players = ()

        self.OutStatus = {}
        ############
        self.MaxRescues = 3 #Max number of times that a bot can return into the arena after it has been thrown out
        self.BreakAwayDistance = 3 #How far the AI needs to move if being counted out...
        ############
        self.LocationSnapshot = {}
        self.NewEnd = (0,0,0)
        self.N_Status = 0 #For Wall Sounds
        self.S_Status = 0
        self.E_Status = 0
        self.W_Status = 0

    def Activate(self, on):
        if on: self.players = plus.getPlayers()
        Arenas.SuperArena.Activate(self, on)

    def HazardsOn(self, on):
        if on:
            N_Wallset = self.AddPrismatic("floor", "glass_wall_North", 0, -150, 0,    2, 0,    0)
                # Above parentheses explained: ("stationary/fixed gmf geoobject",    "moving gmf geoobject",     X,Y,Z =movement direction[number size determines power],    -13,13 =movement parameters,   0=?).   Note: The + or - number in X, Y, or Z, should match the + or - of the first movement parameter.
            self.WALL_MOVER_N = HazardsBlueRay.Mover_1(N_Wallset,  10,  (0, 0, 0))
                # Above parentheses explained: (Prismatic Object's Variable[already assigned above 'Wallset'],   12=Speed+ some power,    (x,y,z = start location[this should equal moving gmf's geoobject's x,y,z]))
            self.AddHazard(self.WALL_MOVER_N)

            S_Wallset = self.AddPrismatic("floor", "glass_wall_South", 0, -150, 0,    2, 0,    0)
                # Above parentheses explained: ("stationary/fixed gmf geoobject",    "moving gmf geoobject",     X,Y,Z =movement direction[number size determines power],    -13,13 =movement parameters,   0=?).   Note: The + or - number in X, Y, or Z, should match the + or - of the first movement parameter.
            self.WALL_MOVER_S = HazardsBlueRay.Mover_1(S_Wallset,  10,  (0, 0, 0))
                # Above parentheses explained: (Prismatic Object's Variable[already assigned above 'Wallset'],   12=Speed+ some power,    (x,y,z = start location[this should equal moving gmf's geoobject's x,y,z]))
            self.AddHazard(self.WALL_MOVER_S)

            E_Wallset = self.AddPrismatic("floor", "glass_wall_East", 0, -150, 0,    2, 0,    0)
                # Above parentheses explained: ("stationary/fixed gmf geoobject",    "moving gmf geoobject",     X,Y,Z =movement direction[number size determines power],    -13,13 =movement parameters,   0=?).   Note: The + or - number in X, Y, or Z, should match the + or - of the first movement parameter.
            self.WALL_MOVER_E = HazardsBlueRay.Mover_1(E_Wallset,  10,  (0, 0, 0))
                # Above parentheses explained: (Prismatic Object's Variable[already assigned above 'Wallset'],   12=Speed+ some power,    (x,y,z = start location[this should equal moving gmf's geoobject's x,y,z]))
            self.AddHazard(self.WALL_MOVER_E)

            W_Wallset = self.AddPrismatic("floor", "glass_wall_West", 0, -150, 0,    2, 0,     0)
                # Above parentheses explained: ("stationary/fixed gmf geoobject",    "moving gmf geoobject",     X,Y,Z =movement direction[number size determines power],    -13,13 =movement parameters,   0=?).   Note: The + or - number in X, Y, or Z, should match the + or - of the first movement parameter.
            self.WALL_MOVER_W = HazardsBlueRay.Mover_1(W_Wallset,  10,  (0, 0, 0))
                # Above parentheses explained: (Prismatic Object's Variable[already assigned above 'Wallset'],   12=Speed+ some power,    (x,y,z = start location[this should equal moving gmf's geoobject's x,y,z]))
            self.AddHazard(self.WALL_MOVER_W)


            self.Wall_Sound = plus.createSound("Sounds/motorloop3.wav", False, (0, 0, 0))
            #plus.playSound(Sound File)
        return Arenas.SuperArena.HazardsOn(self, on)

    def Tick(self):
        self.WALL_MOVER_N.Tick()
        self.WALL_MOVER_S.Tick()
        self.WALL_MOVER_E.Tick()
        self.WALL_MOVER_W.Tick()

        for each in self.players:
            self.Where = plus.getLocation(each)
            if each not in self.OutStatus or not self.OutStatus[each][:4].count(1):
                self.Rescues = 0
                if each in self.OutStatus: self.Rescues = self.OutStatus[each][4]
                #Item format in self.OutStatus dictionary -> BotID: [True/False, True/False, True/False, True/False, Rescues, LastReportedRescue, Timer] Values represent whether the bot is in or out of the four walls, how many times it has been saved after leaving the arena, last recorded number of Rescues, and time before walls close)
                self.OutStatus[each] = [self.Where[0] > 11.3, -11.3 > self.Where[0], self.Where[2] > 11.3, -11.3 > self.Where[2], self.Rescues, self.Rescues, 10]
                if plus.isEliminated(each) or plus.isDefeated(each):
                    self.players = list(self.players) #tuples don't have any way of deleting things
                    self.players.remove(each)
                    del self.OutStatus[each]
            else: # OOTA stuff. #######################################################################
                if self.OutStatus[each][4] == self.OutStatus[each][5]: self.OutStatus[each][4] += 1
                if not plus.isMatchPaused(): self.OutStatus[each][6] -= self.tickInterval
                if self.OutStatus[each][2]: #If outside of NORTH wall
                    if (self.OutStatus[each][4] <= self.MaxRescues):
                        if (self.Where[2] < 10.7) or (self.OutStatus[each][6] <= 0): #If back in or out of time
                            if self.N_Status:
                                self.WALL_MOVER_N.MoveON(True) # Wall Move Up.
                                plus.playSound(self.Wall_Sound)
                                self.N_Status = 0
                            self.OutStatus[each] = [self.Where[0] > 11.3, -11.3 > self.Where[0], self.Where[2] > 11.3, -11.3 > self.Where[2], self.OutStatus[each][4], self.OutStatus[each][5], self.OutStatus[each][6]]
                            if (self.OutStatus[each][6] <= 0) or plus.isDefeated(each):
                                if (not plus.isDefeated(each)) or (not plus.isEliminated(each)): plus.eliminatePlayer(each)
                                self.players = list(self.players) #tuples don't have any way of deleting things
                                self.players.remove(each)
                                del self.OutStatus[each]
                        else: #If still out
                            plus.force(each, 0, 50*plus.getWeight(each), -50*plus.getWeight(each))
                            if not self.N_Status:
                                self.WALL_MOVER_N.MoveREV(True) # Wall Move Down.
                                plus.playSound(self.Wall_Sound)
                                self.N_Status = 1
                    else: plus.eliminatePlayer(each)
                elif self.OutStatus[each][3]: #If outside of SOUTH wall
                    if (self.OutStatus[each][4] <= self.MaxRescues):
                        if (-10.7 < self.Where[2]) or (self.OutStatus[each][6] <= 0): #If back in or out of time
                            if self.S_Status:
                                self.WALL_MOVER_S.MoveON(True) # Wall Move Up.
                                plus.playSound(self.Wall_Sound)
                                self.S_Status = 0
                            self.OutStatus[each] = [self.Where[0] > 11.3, -11.3 > self.Where[0], self.Where[2] > 11.3, -11.3 > self.Where[2], self.OutStatus[each][4], self.OutStatus[each][5], self.OutStatus[each][6]]
                            if (self.OutStatus[each][6] <= 0) or plus.isDefeated(each):
                                if (not plus.isDefeated(each)) or (not plus.isEliminated(each)): plus.eliminatePlayer(each)
                                self.players = list(self.players) #tuples don't have any way of deleting things
                                self.players.remove(each)
                                del self.OutStatus[each]
                        else: #If still out
                            plus.force(each, 0, 50*plus.getWeight(each), 50*plus.getWeight(each))
                            if not self.S_Status:
                                self.WALL_MOVER_S.MoveREV(True) # Wall Move Down.
                                plus.playSound(self.Wall_Sound)
                                self.S_Status = 1
                    else: plus.eliminatePlayer(each)
                if not plus.isEliminated(each):
                    if self.OutStatus[each][0]: #If outside of WEST wall
                        if (self.OutStatus[each][4] <= self.MaxRescues):
                            if (self.Where[0] < 10.7) or (self.OutStatus[each][6] <= 0): #If back in or out of time
                                if self.W_Status:
                                    self.WALL_MOVER_W.MoveON(True) # Wall Move Up.
                                    plus.playSound(self.Wall_Sound)
                                    self.W_Status = 0
                                self.OutStatus[each] = [self.Where[0] > 11.3, -11.3 > self.Where[0], self.Where[2] > 11.3, -11.3 > self.Where[2], self.OutStatus[each][4], self.OutStatus[each][5], self.OutStatus[each][6]]
                                if (self.OutStatus[each][6] <= 0) or plus.isDefeated(each):
                                    if (not plus.isDefeated(each)) or (not plus.isEliminated(each)): plus.eliminatePlayer(each)
                                    self.players = list(self.players) #tuples don't have any way of deleting things
                                    self.players.remove(each)
                                    del self.OutStatus[each]
                            else: #If still out
                                plus.force(each, -50*plus.getWeight(each), 50*plus.getWeight(each), 0)
                                if not self.W_Status:
                                    self.WALL_MOVER_W.MoveREV(True) # Wall Move Down.
                                    plus.playSound(self.Wall_Sound)
                                    self.W_Status = 1
                        else: plus.eliminatePlayer(each)
                    elif self.OutStatus[each][1]: #If outside of EAST wall
                        if (self.OutStatus[each][4] <= self.MaxRescues):
                            if (-10.7 < self.Where[0]) or (self.OutStatus[each][6] <= 0): #If back in or out of time
                                if self.E_Status:
                                    self.WALL_MOVER_E.MoveON(True) # Wall Move Up.
                                    plus.playSound(self.Wall_Sound)
                                    self.E_Status = 0
                                self.OutStatus[each] = [self.Where[0] > 11.3, -11.3 > self.Where[0], self.Where[2] > 11.3, -11.3 > self.Where[2], self.OutStatus[each][4], self.OutStatus[each][5], self.OutStatus[each][6]]
                                if (self.OutStatus[each][6] <= 0) or plus.isDefeated(each):
                                    if (not plus.isDefeated(each)) or (not plus.isEliminated(each)): plus.eliminatePlayer(each)
                                    self.players = list(self.players) #tuples don't have any way of deleting things
                                    self.players.remove(each)
                                    del self.OutStatus[each]
                            else: #If still out
                                plus.force(each, 50*plus.getWeight(each), 50*plus.getWeight(each), 0)
                                if not self.E_Status:
                                    self.WALL_MOVER_E.MoveREV(True) # Wall Move Down.
                                    plus.playSound(self.Wall_Sound)
                                    self.E_Status = 1
                        else: plus.eliminatePlayer(each)
        return Arenas.SuperArena.Tick(self)

    def GetPath(self, start, end, ignore_hazards):
        # overridden to stay in bounds
        
        if ignore_hazards:
            return Arenas.SuperArena.GetPath(self, start, end, ignore_hazards)
        
        if (abs(end[0]) < 11) and (abs(end[2]) < 11):
            return Arenas.SuperArena.GetPath(self, start, end, ignore_hazards)
                
        self.TargetingSystem = [(math.sqrt((start[0]-plus.getLocation(x)[0])**2+(start[1]-plus.getLocation(x)[1])**2+(start[2]-plus.getLocation(x)[2])**2), self.OutStatus[x][:4].count(1), x) for x in self.OutStatus]
        #[(DistanceFromStart, Out, BotID)] #After sorting, the first bot is the AI loading this and the second bot is its target
        if self.TargetingSystem != []: 
            self.TargetingSystem.sort()
            self.TargetingSystem.reverse()
            self.StatusOfAI = self.TargetingSystem.pop() #Don't target self unless you want to hold still (I'm not using the variable 'start' because future AI might use GetPath for other things besides driving right away)
            
            self.AI_Index = 0
            self.NewTargetID = -1
            
            for bot in xrange(0, len(self.TargetingSystem)):
                if bot < self.StatusOfAI[2]:
                    if not plus.isHuman(bot):
                        self.AI_Index += 1
            for bot in xrange(0, len(self.TargetingSystem)):
                if not self.TargetingSystem[bot][1] and AI.running_ai[self.AI_Index].IsEnemy(bot):
                    self.NewTargetID = self.TargetingSystem[bot][2] #Keeps replacing the ID as it gets closer to the bot (because I reversed the order after having it from smallest to biggest distances between the bot)
                    
            
            if AI.running_ai[self.AI_Index].bImmobile:
                if not self.AI_Index in self.LocationSnapshot: #Supports more than one bot getting counted out
                    self.LocationSnapshot[self.AI_Index] = plus.getLocation(self.StatusOfAI[2])
                self.currentLocation = plus.getLocation(self.StatusOfAI[2])
                if math.sqrt((self.LocationSnapshot[self.AI_Index][0]-self.currentLocation[0])**2+(self.LocationSnapshot[self.AI_Index][1]-self.currentLocation[1])**2+(self.LocationSnapshot[self.AI_Index][2]-self.currentLocation[2])**2) >= self.BreakAwayDistance:
                    AI.running_ai[self.AI_Index].bImmobile = 0
                    del self.LocationSnapshot[self.AI_Index]
                else: 
                    return Arenas.SuperArena.GetPath(self, start, end, ignore_hazards)
                    
            if self.NewTargetID == -1:
                if (abs(start[0]) < 1) and (abs(start[2]) < 1):
                    self.HeadingToTarget = AI.running_ai[self.AI_Index].GetHeadingTo(end, plus.isUpsideDown(self.StatusOfAI[2]))
                    if self.HeadingToTarget > math.pi: self.HeadingToTarget -= 2 * math.pi
                    elif self.HeadingToTarget < -math.pi: self.HeadingToTarget += 2 * math.pi
                    
                    if self.HeadingToTarget > .25: self.NewEnd = end
                    else: self.NewEnd = plus.getLocation(self.StatusOfAI[2])
                else: self.NewEnd = (0,0,0)
                
            else: self.NewEnd = plus.getLocation(self.NewTargetID)
            
        return Arenas.SuperArena.GetPath(self, start, self.NewEnd, ignore_hazards)

    def __del__(self):
        plus.removeSound(self.Wall_Sound)
        Arenas.SuperArena.__del__(self)

Arenas.register(BoxArena)
