from __future__ import division

from math import hypot, sin

import pygame

from effect import *
from util import *

from random import choice, random



def miscable(j1,j2):
    mix_table = {
        "brown":Brown_Jelly,
        "red":Red_Jelly,
        "blue":Blue_Jelly,
        "yellow":Yellow_Jelly,
        
        "purple":Purple_Jelly,
        "orange":Orange_Jelly,
        "green":Green_Jelly,

        "pink":Pink_Jelly,
        "grape":Grape_Jelly,
        "lime":Lime_Jelly,
        "lemon":Lemon_Jelly,
        "ochre":Ochre_Jelly,
        "copper":Copper_Jelly,
        

        ("red","yellow"):Orange_Jelly,
        ("blue","red"):Purple_Jelly,
        ("blue","yellow"):Green_Jelly,

        
        ("purple","red"):Pink_Jelly,
        ("blue","purple"):Grape_Jelly,
        ("green","yellow"):Lime_Jelly,
        ("orange","yellow"):Lemon_Jelly,
        ("orange","red"):Ochre_Jelly,
        ("blue","green"):Copper_Jelly,
        }

    brownlist = {
        "red":["lime","green","copper"],
        "blue":["orange","ochre","lemon"],
        "yellow":["pink","purple","grape"],
        "purple":["lemon","yellow","lime"],
        "green":["ochre","red","pink"],
        "orange":["grape","blue","copper"],
        "copper":["ochre","red","orange"],
        "pink":["lime","green","yellow"],
        "grape":["orange","lemon","yellow"],
        "lime":["pink","red","purple"],
        "lemon":["grape","purple","blue"],
        "ochre":["copper","blue","green"],
        }
    
    jelly = None
    if j2 in mix_table:
        if j1.colour in mix_table:
            if j1.colour == j2:
                jelly = mix_table.get(j1.colour)
            elif j1.colour == "brown" or j2 == "brown":
                jelly = mix_table.get("brown")
            else:
                j = [j1.colour,j2]
                k = tuple(sorted(j))
                if k in mix_table:
                    jelly = mix_table[k]
                elif k[1] in brownlist[k[0]]:
                    jelly = mix_table["brown"]
    elif j1.side == j2.side == "jelly":
        if j1.colour == j2.colour:
            jelly = mix_table.get(j1.colour)
        elif j1.colour == "brown" or j2.colour == "brown":
                jelly = mix_table.get("brown")
        else:
            j = [j1.colour,j2.colour]
            k = tuple(sorted(j))
            if k in mix_table:
                jelly = mix_table[k]
            elif k[1] in brownlist[k[0]]:
                jelly = mix_table.get("brown")
    return jelly

def mix(j1,j2,floor):
    jelly = miscable(j1,j2)
    hp = j1.hp + j2.hp

    x = j1.x
    y = j1.y

    floor.data[(x,y)].remove(j1)
    floor.data[(x,y)].remove(j2)

    z = floor.data[(x,y)].height()

    unit = jelly((x,y,z))
    unit.hp = min(unit.max_hp,hp)
    floor.data[(x,y)].add(unit)
    return unit

def recolour(j1,colour,floor):
    jelly = miscable(j1,colour)
    if jelly:
        hp = j1.hp
        x = j1.x
        y = j1.y
        z = j1.z
        floor.data[(x,y)].remove(j1)
        unit = jelly((x,y,z))
        unit.hp = min(unit.max_hp,hp)
        floor.data[(x,y)].add(unit)
        return unit

class Camera:
    def __init__(self,x,y):
        self.pos = (x,y)
        self.motion = None
        self.time = 0
    def look_to(self,pos,time):
        """Looks to a point specified."""
        x,y = self.pos
        nx,ny = pos
        dx = (nx - x)/time
        dy = (ny - y)/time
        self.motion = (dx,dy)
        self.time = time
    def look_at(self,obj,time):
        """Looks at an object with a pos value."""
        self.look_to(obj.pos,time)
    def move(self,x,y):
        px,py = self.pos
        px += x
        py += y
        self.pos = (px,py)
    def offset(self):
        x,y = self.pos
        ox,oy = (-x+500,-y+260)
        return (ox,oy)
    def tick(self):
        if self.motion:
            x,y = self.pos
            mx,my = self.motion
            x += mx
            y += my
            self.time -= 1
            self.pos = (x,y)
            if self.time == 0:
                self.motion = None

class Stack:
    def __init__(self,pos):
        self.x,self.y = pos
        self.pos = (self.x*32-self.y*32,(self.x+self.y)*16)
        self.objects = []
    def draw(self,screen,offset):
        for o in self.objects:
            o.draw(screen,offset)
    def height(self):
        h = 0
        for o in self.objects:
            h += o.h
        return h
    def indicated(self,colour = None):
        for o in self.objects:
            if o.type == "indicator":
                return colour is None or colour == o.colour
        return False
    def top(self):
        for o in self.objects.__reversed__():
            if o.type in ("indicator","cursor"):
                continue
            else:
                return o
    def add(self,item,cur = False):
        if cur:
            if self.objects[-1].type not in ("floor","indicator","spawn"):
                item.z = self.height()-self.objects[-1].h
                self.objects.insert(-1,item)
            else:
                item.z = self.height()
                self.objects.append(item)                
        else:
            self.objects.append(item)
    def remove(self,item):
        self.objects.remove(item)
    def delight(self,colour = None):
        for o in self.objects:
            if colour:
                if o.type == "indicator" and o.colour == colour:
                    self.objects.remove(o)
            else:
                if o.type == "indicator":
                    self.objects.remove(o)
    def __getitem__(self,index):
        return self.objects[index]

class Cursor:
    def __init__(self,image,pos):
        self.image = load_image(image)
        self.type = "cursor"
        self.x,self.y = pos
        self.z = 0
        self.pos = (self.x*32-self.y*32,(self.x+self.y)*16-self.z)
        self.h = 0
        self.rect = self.image.get_rect()
        self.cd = 0
    def draw(self,screen,offset):
        ox,oy = offset
        px,py = self.pos
        x = px+ox
        y = py+oy
        self.rect.midbottom = (x,y)
        screen.blit(self.image,self.rect)
        self.pos = (self.x*32-self.y*32,(self.x+self.y)*16-self.z)
    def move(self,d,floor):
        if self.cd == 0:
            x,y = (self.x,self.y)
            dx,dy = d
            floor.data[(x,y)].remove(self)
            x = max(min(dx+x,floor.length-1),0)
            y = max(min(dy+y,floor.length-1),0)
            floor.data[(x,y)].add(self,cur=True)
            self.x = x
            self.y = y
            self.cd += 8
    def hide(self,floor):
        s = floor.data[(self.x,self.y)]
        if self in s.objects:
            s.remove(self)
    def show(self,floor):
        s = floor.data[(self.x,self.y)]
        if self not in s.objects:
            s.add(self,cur=True)
    def select(self,floor):
        s = floor.data[(self.x,self.y)].top()
        return s
    def tick(self):
        self.cd = max(self.cd-1,0)

class Arrow:
    def __init__(self,screen):
        self.screen = screen
        self.target = None
        self.images = {
            "jelly":load_image("arrow-ally"),
            "ooze":load_image("arrow-enemy"),
            None:load_image("arrow-object"),
            }
        self.cycle = 0
        self.rect = self.images["jelly"].get_rect()
    def draw(self,offset):
        self.cycle += 0.1
        ox,oy = offset
        if self.target:
            i = self.images[self.target.side]
            x,y = self.target.pos
            self.rect.midbottom = (ox+x,oy+y-self.target.h-10 + sin(self.cycle)*6)
            self.screen.blit(i,self.rect)

class Panel:
    def __init__(self,colour,pos):
        self.x,self.y,self.z = pos
        self.h = 6
        self.pos = (self.x*32-self.y*32,(self.x+self.y)*16-self.z)
        self.image = load_image("panel-%s"% colour)
        self.colour = colour
        self.type = "indicator"
        self.rect = self.image.get_rect()
        self.walkable = False
    def draw(self,screen,offset):
        ox,oy = offset
        px,py = self.pos
        x = px+ox
        y = py+oy
        self.rect.midbottom = (x,y)
        screen.blit(self.image,self.rect)

class Tile:
    def __init__(self,image,pos,height,walkable,colour = "white"):
        self.x,self.y,self.z = pos
        self.h = height
        self.pos = (self.x*32-self.y*32,(self.x+self.y)*16-self.z)
        self.image = load_image(image)
        self.type = "floor"
        self.colour = colour
        self.rect = self.image.get_rect()
        self.walkable = walkable
    def draw(self,screen,offset):
        ox,oy = offset
        px,py = self.pos
        x = px+ox
        y = py+oy
        self.rect.midbottom = (x,y)
        screen.blit(self.image,self.rect)

class Spawn:
    def __init__(self,colour,pos):
        self.x,self.y,self.z = pos
        self.h = 10
        self.pos = (self.x*32-self.y*32,(self.x+self.y)*16-self.z)
        self.image = load_image("spawnpoint")
        self.ball = load_image("blood-%s"%colour)
        self.colour = colour
        self.type = "spawn"
        self.rect = self.image.get_rect()
        self.walkable = True
        self.time = 0
    def draw(self,screen,offset):
        self.time += 1
        ox,oy = offset
        px,py = self.pos
        x = px+ox
        y = py+oy
        self.rect.midbottom = (x,y)
        screen.blit(self.image,self.rect)
        screen.blit(self.ball,(x-4,y-40+8*sin(self.time/3)))
    
class Unit:
    colour = "blue"
    side = "jelly"
    
    max_hp = 100
    attack = 20
    defense = 10

    attackeffect = None
    moverange = 5
    attackrange = 1
    attackmin = 0
    targetsize = 0.5
    targetmin = 0
    mode = "circle"
    shape = "circle"
    jump = 24

    worth = 10
    def __init__(self,pos,personality="lazy"):
        self.x,self.y,self.z = pos
        self.pos = (self.x*32-self.y*32,(self.x+self.y)*16-self.z)
        self.h = 24
        ipath = "%s-%s"%(self.side,self.colour)
        self.images = {
            "n":load_image("%s-n"% ipath),
            "s":load_image("%s-s"% ipath),
            "e":load_image("%s-e"% ipath),
            "w":load_image("%s-w"% ipath),
            }
        moods = {
            "lazy":self.lazy,
            }
        self.personality = moods[personality]
        self.facing = choice(self.images.keys())
        self.image = self.images[self.facing]
        self.sleepy = load_image("tired")
        self.type = "unit"
        self.rect = self.image.get_rect()
        self.walkable = False
        
        self.path = []
        self.target = None
        
        self.switchd = False
        self.v = None
        self.frames = 0

        self.hp = self.max_hp
        
        self.damage = 0
        self.hurtframes = 0
        
        self.jumping = False
        self.tired = False

    def draw(self,screen,offset):
        ox,oy = offset
        px,py = self.pos
        x = px+ox
        y = py+oy-12
        self.rect.midbottom = (x,y)
        if self.path and not self.jumping:
            s = sin(self.frames/2.55)
            i = pygame.transform.scale(self.image,(int(64+3*s),int(64-6*s)))
            screen.blit(i,self.rect)
        else:
            screen.blit(self.image,self.rect)
        if self.tired:
            u,v = (x+6,y-self.h)
            screen.blit(self.sleepy,(u,v))
        if self.hurtframes:
            self.hurtframes -= 1
            if self.damage < 0:
                c = "green"
            else:
                c = "red"
            ybuff = sin((3.14/30)*self.hurtframes)
            n = 0
            for d in str(abs(self.damage)):
                screen.blit(load_image("%s-%s"%(d,c)),(x-10+n*8,y-self.h-16-ybuff*5))
                n += 1
    def ai(self,core):
        floor = core.floor
        actions = []
        best_action = None
        brain = self.personality
        paths = self.walkable_tiles(floor)
        for p in paths:
            reach = self.attack_tiles(floor,p)
            for t in reach:
                if paths[p] and paths[p][-1] != t:
                    actions.append(brain(paths[p],t,core))
        best_action = actions[0]
        
        actions.sort()
        best_action = actions[-1]

        self.path = best_action[1][1:]
        self.target = best_action[2]
                
    def action(self,targets,victims,cursor,floor):
        return []
    def hurt(self,attacker,core,damage = None):
        colours = ["red","yellow","blue","green","orange","purple"]
        floor = core.floor
        attack = attacker.attack
        effect = attacker.attackeffect
        if attack >= 0:
            bd = (attack/self.defense)*10
        else:
            bd = attack
        d = bd*(0.9+(random()/5))
        if damage == None:
            self.damage = int(d)
        else:
            self.damage = damage
        self.hp = max(min(self.hp-self.damage,self.max_hp),0)
        self.hurtframes = 30

        if self.hp == 0:
            return True
        
        if effect in colours:
            unit = recolour(self,effect,floor)
            if unit:
                unit.tired = True
                core.allies.append(unit)
                core.allies.remove(self)
        if effect == "drain":
            attacker.hurt(self,core,damage = -self.damage)
        if effect == "slow":
            self.moverange = max(self.moverange-1,0)
    def reset(self,pos,floor):
        ux,uy,uz = pos
        floor.data[(self.x,self.y)].remove(self)
        self.x = ux
        self.y = uy
        self.z = uz
        floor.data[(self.x,self.y)].add(self)
        self.pos = (self.x*32-self.y*32,(self.x+self.y)*16-self.z)
    def column(self,ownstack,dstack):
        self.x = dstack[-1].x
        self.y = dstack[-1].y
        self.z = dstack.height()
        ownstack.remove(self)
        dstack.add(self)
    def move(self,core):
        floor = core.floor
        if self.path:
            ownstack = floor.data[(self.x,self.y)]
            dstack = floor.data[(self.path[0])]
            tx,ty = dstack[-1].pos
            ty -= (dstack[-1].h)
            x,y = self.pos
            if self.v:
                x += self.v[0]
                y += self.v[1]
                self.frames -= 1
                if self.jumping:
                    g = (1/8)-(1/64)*self.frames
                    y += g*(self.jump*2)
                self.pos = (x,y)
            else:
                self.v = ((tx-x)/16,(ty-y)/16)
                f = get_facing(self.v)
                if f:
                    self.facing = f
                    self.image = self.images[self.facing]
                self.frames = 16
                if dstack.height() != ownstack.height()-self.h:
                    self.jumping = True
                else:
                    self.jumping = False
            if self.frames == 16:
                dx,dy = self.path[0]
                if dx > self.x or dy > self.y:
                    self.column(ownstack,dstack)
                    self.switchd = True
                else:
                    self.switchd = False
            elif self.frames == 0:
                if not self.switchd:
                    self.column(ownstack,dstack)
                self.path.pop(0)
                self.v = None
                self.pos = (self.x*32-self.y*32,(self.x+self.y)*16-self.z)
            return True
        else:
            ownstack = floor.data[(self.x,self.y)]
            surf = floor.data[(self.x,self.y)][-2]
            if self.side == "jelly" and surf.type == "floor" and surf.colour != "white":
                u = recolour(self,surf.colour,floor)
                if u:
                    u.tired = True
                    core.allies.remove(self)
                    core.allies.append(u)
                    core.selected = core.arrow.target = u
            return False

    def attack_tiles(self,floor,centre):
        targets = []
        cx,cy = centre
        if self.mode in ("circle","line"):
            for y in range(int(-self.attackrange),int(self.attackrange+1)):
                for x in range(int(-self.attackrange),int(self.attackrange+1)):
                    if self.attackmin <= hypot(x,y) <= self.attackrange:
                        if floor.data.has_key((cx+x,cy+y)):
                            if self.mode == "line":
                                if self.x == (cx+x) or self.y == (cy+y):
                                    targets.append((cx+x,cy+y))
                            else:
                                targets.append((cx+x,cy+y))
        return targets
    def target_tiles(self,floor,centre):
        targets = []
        cx,cy = centre
        if self.shape in ("circle","grid"):
            for y in range(int(-self.targetsize),int(self.targetsize+1)):
                for x in range(int(-self.targetsize),int(self.targetsize+1)):
                    if self.targetmin <= hypot(x,y) <= self.targetsize:
                        if floor.data.has_key((cx+x,cy+y)):
                            if self.shape == "grid":
                                out = (x+y)%2
                                if not out:
                                    targets.append((cx+x,cy+y))
                            else:
                                targets.append((cx+x,cy+y))
        return targets
        
    def walkable_tiles(self,floor):
        stacks = floor.data
        working = [[(self.x,self.y)]]
        tiles = {}
        tiles[(self.x,self.y)] = []
        while working:
            poslist = working.pop(0)
            x,y = poslist[-1]
            adj = [poslist+[(x+i,y+j)]
                   for i,j in [(-1,0),(0,-1),(0,1),(1,0)]]
            for newlist in adj:
                ax,ay = newlist[-1]
                steps = len(newlist)
                if (ax,ay) in tiles or steps > self.moverange:
                    continue
                surf = stacks[(x,y)].top()
                dest = stacks.get((ax,ay))
                if dest:
                    if dest.top().type == "unit" and miscable(self,dest.top()):
                        working.append(newlist)
                        tiles[(ax,ay)] = newlist
                    elif dest.top().walkable:
                        if surf == self:
                            z = stacks[(x,y)].height()-self.h
                        else:
                            z = stacks[(x,y)].height()
                        tz = dest.top().z+dest.top().h
                        dz = tz-z
                        if dz <= self.jump:
                            working.append(newlist)
                            tiles[(ax,ay)] = newlist
        return tiles

    def net_damage(self,targets,floor):
        d = 0
        for t in targets:
            if t.side == self.side:
                d -= self.attack
            else:
                d += self.attack
        return d
    def nearest_units(self,pos,core):
        x,y = pos
        if core.allies:
            a_dist = min((hypot(a.x-x,a.y-y),a)
                         for a in core.allies)
        else:
            a_dist = None
        if core.enemies:
            e_dist = min((hypot(e.x-x,e.y-y),e)
                         for e in core.enemies)
        else:
            e_dist = None
        return (a_dist,e_dist)        
        
    def lazy(self,path,target,core):
        floor = core.floor
        x,y = (self.x,self.y)
        tx,ty = target
        areas = self.target_tiles(floor,target)
        victims = find_targets(areas,floor)
        d = self.net_damage(victims,floor)
        dist = hypot(tx-x,ty-y)
        nearest_a,nearest_e = self.nearest_units(path[-1],core)
        if self.attack > 0 and nearest_a:
            aim = nearest_a
        elif self.attack <= 0 and nearest_e:
            aim = nearest_e
        else:
            aim = (0,None)
        return ((d,-dist,-aim[0]),path,target)
        

class Blue_Jelly(Unit):
    name = "Blue Jelly"
    colour = "blue"
    side = "jelly"
    
    max_hp = 80
    attack = 28
    defense = 6

    moverange = 6
    attackrange = 4
    targetsize = 1
    mode = "circle"
    shape = "circle"
    jump = 24

    desc = [
        "Blue jellies take the role of",
        "the magician in the jelly army."
        ]
    def action(self,targets,victims,cursor,floor):
        cx,cy = cursor
        t = floor.data[(cx,cy)][-1]
        x,y = t.pos
        effects = [LineEffect([
                ("beam1",3),
                ("beam2",4),
                ("beam3",5),
                ("beam4",6),
                ("beam5",5),
                ("beam6",4),
                ],(x,y-500),(x,y-16),20),
                   
                    LineEffect([
                ("nova01",2),
                ("nova02",2),
                ("nova03",2),
                ("nova04",2),
                ("nova05",2),
                ("nova06",2),
                ("nova07",2),
                ("nova08",2),
                ("nova09",2),
                ("nova10",2),
                ("nova11",4),
                ("nova12",4),
                ("nova13",4),
                ("nova14",4),
                ],(x,y-t.h-28),(x,y-t.h-28),-1,delay=10),]
        return effects
    
class Red_Jelly(Unit):
    name = "Red Jelly"
    colour = "red"
    side = "jelly"
    
    max_hp = 100
    attack = 35
    defense = 12

    moverange = 5
    attackrange = 1
    targetsize = 0.5
    mode = "circle"
    shape = "circle"
    jump = 20

    desc = [
        "Red jellies are slow, but they",
        "can give and take a hit very well."
        ]
    def action(self,targets,victims,cursor,floor):
        vx,vy = targets[0]
        x,y = floor.data[(vx,vy)][-1].pos
        effects = [LineEffect([
            ("horn1",4),
            ("horn2",4),
            ("horn3",4),
            ("horn4",10),
            ],(x,y-64),(x,y-16),22),
                   LineEffect([
            ("impact-red1",6),
            ("impact-red2",6),
            ("impact-red3",4),],(x,y-26),(x,y-26),-1,delay = 12)]
        return effects

class Green_Jelly(Unit):
    name = "Green Jelly"
    colour = "green"
    side = "jelly"
    
    max_hp = 80
    attack = -45
    defense = 6

    moverange = 6
    attackrange = 2.5
    targetmin = 0.5
    targetsize = 1
    mode = "circle"
    shape = "circle"
    jump = 20

    desc = [
        "Green jellies cannot deal damage.",
        "They can only heal their allies."
        ]
    def action(self,targets,victims,cursor,floor):
        x,y = self.pos
        effects = [LineEffect([
            ("heal1",4),
            ("heal2",4),
            ("heal3",4),
            ("heal4",4),
            ("heal5",4),
            ("heal6",4),
            ("heal7",4),
            ("heal8",4),
            ("heal9",4),
            ("heal11",12),
            ("heal12",6),
            ("heal13",6),
            ("heal14",6)],(x,y-30),(x,y-130),66)]
        for v in victims:
            vx,vy = v.pos
            effect = LineEffect([
                ("sparkle1",3),
                ("sparkle2",3),
                ("sparkle3",3)],(vx,vy-200),(vx,vy-48),90,loop=True)
            effects.append(effect)
        return effects

class Yellow_Jelly(Unit):
    name = "Yellow Jelly"
    colour = "yellow"
    side = "jelly"
    
    max_hp = 80
    attack = 30
    defense = 8

    moverange = 6
    attackrange = 5
    targetsize = 0.5
    mode = "line"
    shape = "circle"
    jump = 32

    desc = [
        "Yellow jellies are agile and strong.",
        "Their ranged attack can be invaluable",
        "when fighting against powerful foes."
        ]
    def action(self,targets,victims,cursor,floor):
        x,y = self.pos
        cx,cy = cursor
        t = floor.data[(cx,cy)][-1]
        tx,ty = t.pos
        effects = [LineEffect([
            ("blood-yellow",1)],(x,y-32),(tx,ty-32),20,loop=True),
                   LineEffect([
            ("impact-yellow1",6),
            ("impact-yellow2",6),
            ("impact-yellow3",4),],(tx,ty-32),(tx,ty-32),-1,delay = 20)]
        return effects

class Orange_Jelly(Unit):
    name = "Orange Jelly"
    colour = "orange"
    side = "jelly"
    
    max_hp = 60
    attack = 30
    defense = 8

    moverange = 7
    attackrange = 2
    targetsize = 0.5
    mode = "circle"
    shape = "circle"
    jump = 64

    desc = [
        "Orange jellies have decent reach and",
        "can pack a punch. However, their major",
        "forte is just how springy they are."
        ]
    def action(self,targets,victims,cursor,floor):
        x,y = self.pos
        cx,cy = cursor
        t = floor.data[(cx,cy)][-1]
        tx,ty = t.pos
        effects = [LineEffect([
            ("borange1",4),
            ("borange2",4),
            ("borange3",4),
            ("borange4",4),
            ("borange5",4),
            ("borange6",4),],(x,y-32),(tx,ty-32),24,loop=True),
                   LineEffect([
            ("impact-orange1",6),
            ("impact-orange2",6),
            ("impact-orange3",4),],(tx,ty-32),(tx,ty-32),-1,delay = 24)]
        return effects

class Purple_Jelly(Unit):
    name = "Purple Jelly"
    colour = "purple"
    side = "jelly"
    
    max_hp = 140
    attack = 35
    defense = 10

    moverange = 4
    attackrange = 2
    attackmin = 1.3
    targetsize = 1
    mode = "circle"
    shape = "circle"
    jump = 5

    desc = [
        "Purple jellies have an incredible mass",
        "to them. Their impact can leave a group",
        "of oozes reeling, but don't try to get",
        "one up a ledge."
        ]
    def action(self,targets,victims,cursor,floor):
        cx,cy = cursor
        c = floor.data[(cx,cy)][-1]
        x,y = c.pos
        effects = [LineEffect([
            ("purpleattack",1)],(x,y-200),(x,y-32),20,loop=True)]
        for t in targets:
            tile = floor.data[t][-1]
            tx,ty = tile.pos
            effect = LineEffect([
                ("purple-pop1",4),
                ("purple-pop2",6),
                ("purple-pop3",8),
                ("purple-pop2",6),
                ("purple-pop1",4),],(tx,ty-tile.h-16),(tx,ty-tile.h-16),-1,delay=20)
            effects.append(effect)
        return effects

class Grape_Jelly(Unit):
    name = "Grape Jelly"
    colour = "grape"
    side = "jelly"
    
    max_hp = 100
    attack = 30
    defense = 15

    moverange = 6
    attackrange = 5
    attackmin = 1.5
    targetsize = 1
    mode = "line"
    shape = "circle"
    jump = 24

    desc = [
        "Something about the purple-blue combinatory",
        "process gives the Grape jelly much higher",
        "density. It can move faster and takes less",
        "damage. And of course, inherits the blue-jelly",
        "magic."
        ]
    def action(self,targets,victims,cursor,floor):
        cx,cy = cursor
        c = floor.data[(cx,cy)][-1]
        x,y = c.pos
        sx,sy = self.pos
        effects = [LineEffect([
            ("blood-grape",1)],(sx,sy),(x,y-32),20,loop=True)]
        for t in targets:
            tile = floor.data[t][-1]
            tx,ty = tile.pos
            effect = LineEffect([
                ("impact-purple1",6),
                ("impact-purple2",6),
                ("impact-purple3",4)],(tx,ty-tile.h-16),(tx,ty-tile.h-16),-1,delay=20)
            effects.append(effect)
        return effects

class Pink_Jelly(Unit):
    name = "Pink Jelly"
    colour = "pink"
    side = "jelly"
    
    max_hp = 120
    attack = 55
    defense = 5

    moverange = 5
    attackrange = 1
    targetsize = 0.5
    mode = "circle"
    shape = "circle"
    jump = 32

    desc = [
        "Look... just don't underestimate the Pink",
        "jelly. Looks can be deceiving.",
        ]
    def action(self,targets,victims,cursor,floor):
        vx,vy = targets[0]
        x,y = floor.data[(vx,vy)][-1].pos
        effects = [LineEffect([
            ("impact-red1",6),
            ("impact-purple2",6),
            ("impact-blue3",4),
            ],(x+4,y-32),(x+4,y-32),-1),
                   LineEffect([
            ("impact-blue1",6),
            ("impact-blue2",6),
            ("impact-blue3",4),
            ],(x+3,y-22),(x+3,y-22),-1,delay=4),
                   LineEffect([
            ("impact-purple1",6),
            ("impact-red2",6),
            ("impact-red3",4),
            ],(x-2,y-30),(x-2,y-30),-1,delay=14),
                   LineEffect([
            ("impact-purple1",6),
            ("impact-purple2",6),
            ("impact-purple3",4),
            ],(x-3,y-28),(x-3,y-28),-1,delay=8),
                   LineEffect([
            ("impact-red1",6),
            ("impact-red2",6),
            ("impact-red3",4),
            ],(x,y-24),(x,y-24),-1,delay=20),
                   ]
        return effects

class Copper_Jelly(Unit):
    name = "Copper Jelly"
    colour = "copper"
    side = "jelly"
    
    max_hp = 70
    attack = 30
    defense = 12

    moverange = 5
    attackrange = 4
    targetsize = 0.5
    mode = "circle"
    shape = "circle"
    attackeffect = "drain"
    jump = 32

    desc = [
        "Despite his startled appearance, the",
        "Copper jelly is most devious. His attacks",
        "can drain an enemy of their life while",
        "restoring his own."
        ]
    def action(self,targets,victims,cursor,floor):
        x,y = self.pos
        cx,cy = cursor
        t = floor.data[(cx,cy)][-1]
        tx,ty = t.pos
        effects = [LineEffect([
            ("blood-copper",1)],(tx,ty-32),(x,y-32),20,loop=True),
                   LineEffect([
            ("impact-green3",7),
            ("impact-green2",6),
            ("impact-green1",5),],(x,y-32),(x,y-32),-1,delay = 20)]
        return effects

class Lemon_Jelly(Unit):
    name = "Lemon Jelly"
    colour = "lemon"
    side = "jelly"
    
    max_hp = 111
    attack = 30
    defense = 6

    moverange = 5
    attackrange = 5
    targetsize = 1.5
    mode = "circle"
    shape = "circle"
    jump = 32

    desc = [
        "Among the most hunted of all the jellies,",
        "the Lemon jelly has to be able to defend",
        "himself from multiple foes at once. Hence",
        "the wide area-effect attack he posesses."
        ]
    def action(self,targets,victims,cursor,floor):
        cx,cy = cursor
        t = floor.data[(cx,cy)][-1]
        x,y = t.pos
        effects = [            
                    LineEffect([
                ("cloud1",8),
                ("cloud2",8),
                ("cloud3",8),
                ("cloud4",8),
                ("cloud5",8),
                ("cloud6",8),
                ("cloud7",24),
                ("cloud6",8),
                ("cloud5",8),
                ("cloud4",8),
                ("cloud3",8),
                ("cloud2",8),
                ("cloud1",8)],(x,y-130),(x,y-120),120),]
        for t in targets:
            tile = floor.data[t][-1]
            tx,ty = tile.pos
            effects.append(LineEffect([
                ("rain1",4),
                ("rain2",4),
                ("rain3",4),
                ("rain4",4),
                ("rain5",4),
                ("rain6",4),
                ("rain7",4),
                ("rain8",4),
                ("rain9",4),
                ("rain10",4),
                ("rain11",4),
                ("rain12",4),
                ("rain13",4)],(tx,ty-48),(tx,ty-48),-1,delay=20))
        return effects

class Lime_Jelly(Unit):
    name = "Lime Jelly"
    colour = "lime"
    side = "jelly"
    
    max_hp = 123
    attack = -50
    defense = 8

    moverange = 5
    attackrange = 5
    targetsize = 3
    mode = "circle"
    shape = "grid"
    jump = 32

    desc = [
        "Though as sour as his yellow counterpart,",
        "the Lime Jelly has no grudge to bear against",
        "any substance, regardless of viscosity. He exists",
        "only to help others with his great healing range."
        ]
    def action(self,targets,victims,cursor,floor):
        x,y = self.pos
        effects = []
        for t in victims:
            tx,ty = t.pos
            effect = LineEffect([
                ("blood-lime",1)],(x,y-16),(tx,ty-16),24,loop=True)
            effects.append(effect)
            effect2 = LineEffect([
                ("impact-green3",6),
                ("impact-green2",6),
                ("impact-green1",4),],(tx,ty-16),(tx,ty-16),-1,delay=24)
            effects.append(effect2)
            effect3 = LineEffect([
                ("sparkle1",5),
                ("sparkle2",5),
                ("sparkle3",5)],(tx,ty-16),(tx,ty-116),40,loop=True,delay=24)
            effects.append(effect3)
        return effects

class Ochre_Jelly(Unit):
    name = "Ochre Jelly"
    colour = "ochre"
    side = "jelly"
    
    max_hp = 100
    attack = 20
    defense = 10

    moverange = 5
    attackrange = 1
    targetsize = 0.5
    attackeffect = "slow"
    mode = "circle"
    shape = "circle"
    jump = 32

    desc = [
        "The Ochre jelly is more sticky than most of the,",
        "other jellies. This gives him the ability to slow",
        "his opponents down even to a standstill.",
        ]
    def action(self,targets,victims,cursor,floor):
        effects = []
        x,y = floor.data[targets[0]][-1].pos
        effects = [LineEffect([
            ("borange6",4),
            ("borange5",4),
            ("borange4",4),
            ("borange3",4),
            ("borange2",4),
            ("borange1",4),],(x,y-16),(x,y-16),-1),
                   LineEffect([
            ("impact-orange1",6),
            ("impact-orange2",6),
            ("impact-orange3",4),],(x,y-16),(x,y-16),-1,delay = 24),
                   LineEffect([
            ("impact-red1",6),
            ("impact-red2",6),
            ("impact-red3",4),],(x,y-18),(x,y-18),-1,delay = 28),
                   LineEffect([
            ("impact-purple1",6),
            ("impact-purple2",6),
            ("impact-purple3",4),],(x,y-20),(x,y-20),-1,delay = 32),
                   LineEffect([
            ("impact-blue1",6),
            ("impact-blue2",6),
            ("impact-blue3",4),],(x,y-22),(x,y-22),-1,delay = 36),
                   ]
        return effects

class Brown_Jelly(Unit):
    name = "Brown Jelly"
    colour = "brown"
    side = "jelly"
    
    max_hp = 50
    attack = 10
    defense = 6

    moverange = 5
    attackrange = 1
    targetsize = 0.5
    mode = "circle"
    shape = "circle"
    jump = 32

    desc = [
        "Oh how we all pity the Brown jelly.",
        "He's really not too good at anything.",
        "Try not to mix him. You'll only bring",
        "him and you unhappiness."
        ]
    def action(self,targets,victims,cursor,floor):
        effects = []
        x,y = floor.data[targets[0]][-1].pos
        effects = [LineEffect([
            ("brown-pop1",4),
            ("brown-pop2",6),
            ("brown-pop3",8),
            ("brown-pop2",6),
            ("brown-pop1",4),],(x,y-26),(x,y-26),-1),
                   LineEffect([
            ("impact-brown1",6),
            ("impact-brown2",6),
            ("impact-brown3",4)],(x,y-30),(x,y-30),-1)
                   ]
        return effects

class Grey_Ooze(Unit):
    name = "Grey Ooze"
    colour = "grey"
    side = "ooze"
    
    max_hp = 75
    attack = 30
    defense = 12

    moverange = 6
    attackrange = 1
    targetsize = 0.5
    mode = "circle"
    shape = "circle"
    jump = 20

    worth = 5

    desc = [
        "Grey oozes are the lowest of the low.",
        "Typical brute; they are easily dispatched",
        "at range."
        ]
    def action(self,targets,victims,cursor,floor):
        x,y = self.pos
        t = floor.data[targets[0]][-1]
        tx,ty = t.pos
        effects = [LineEffect([
            ("blood-grey",1)],(tx,ty),(tx,ty-32),16,loop=True),
                   LineEffect([
            ("impact-grey1",6),
            ("impact-grey2",6),
            ("impact-grey3",4),],(tx,ty-26),(tx,ty-26),-1,delay = 20)]
        return effects

class Gobber(Unit):
    name = "Gobber Ooze"
    colour = "gobber"
    side = "ooze"
    
    max_hp = 70
    attack = 25
    defense = 8

    moverange = 5
    attackrange = 5
    targetsize = 0.5
    mode = "circle"
    shape = "circle"
    jump = 20

    worth = 7

    desc = [
        "Gobbers can pose a very serious threat to you.",
        "You don't want your jellies recoloured do you?"
        ]
    def action(self,targets,victims,cursor,floor):
        x,y = self.pos
        t = targets[0]
        tile = floor.data[t][-1]
        tx,ty = tile.pos
        effects = [LineEffect([
            ("blood-grey",1)],(x,y-32),(tx,ty-32),20,loop=True),
                   LineEffect([
            ("impact-grey1",6),
            ("impact-grey2",6),
            ("impact-grey3",4),],(tx,ty-32),(tx,ty-32),-1,delay = 20)]
        return effects

class Red_Gobber(Gobber):
    name = "Redmouth Gobber"
    colour = "red"
    attackeffect = "red"
    def action(self,targets,victims,cursor,floor):
        x,y = self.pos
        t = targets[0]
        tile = floor.data[t][-1]
        tx,ty = tile.pos
        effects = [LineEffect([
            ("blood-red",1)],(x,y-32),(tx,ty-32),20,loop=True),
                   LineEffect([
            ("impact-red1",6),
            ("impact-red2",6),
            ("impact-red3",4),],(tx,ty-32),(tx,ty-32),-1,delay = 20)]
        return effects

class Blue_Gobber(Gobber):
    name = "Bluemouth Gobber"
    colour = "blue"
    attackeffect = "blue"
    def action(self,targets,victims,cursor,floor):
        x,y = self.pos
        t = targets[0]
        tile = floor.data[t][-1]
        tx,ty = tile.pos
        effects = [LineEffect([
            ("blood-blue",1)],(x,y-32),(tx,ty-32),20,loop=True),
                   LineEffect([
            ("impact-blue1",6),
            ("impact-blue2",6),
            ("impact-blue3",4),],(tx,ty-32),(tx,ty-32),-1,delay = 20)]
        return effects

class Yellow_Gobber(Gobber):
    name = "Yellowmouth Gobber"
    colour = "yellow"
    attackeffect = "yellow"
    def action(self,targets,victims,cursor,floor):
        x,y = self.pos
        t = targets[0]
        tile = floor.data[t][-1]
        tx,ty = tile.pos
        effects = [LineEffect([
            ("blood-yellow",1)],(x,y-32),(tx,ty-32),20,loop=True),
                   LineEffect([
            ("impact-yellow1",6),
            ("impact-yellow2",6),
            ("impact-yellow3",4),],(tx,ty-32),(tx,ty-32),-1,delay = 20)]
        return effects

class Green_Gobber(Gobber):
    name = "Greenmouth Gobber"
    colour = "green"
    attackeffect = "green"
    def action(self,targets,victims,cursor,floor):
        x,y = self.pos
        t = targets[0]
        tile = floor.data[t][-1]
        tx,ty = tile.pos
        effects = [LineEffect([
            ("blood-green",1)],(x,y-32),(tx,ty-32),20,loop=True),
                   LineEffect([
            ("impact-green1",6),
            ("impact-green2",6),
            ("impact-green3",4),],(tx,ty-32),(tx,ty-32),-1,delay = 20)]
        return effects

class Purple_Gobber(Gobber):
    name = "Purplemouth Gobber"
    colour = "purple"
    attackeffect = "purple"
    def action(self,targets,victims,cursor,floor):
        x,y = self.pos
        t = targets[0]
        tile = floor.data[t][-1]
        tx,ty = tile.pos
        effects = [LineEffect([
            ("blood-purple",1)],(x,y-32),(tx,ty-32),20,loop=True),
                   LineEffect([
            ("impact-purple1",6),
            ("impact-purple2",6),
            ("impact-purple3",4),],(tx,ty-32),(tx,ty-32),-1,delay = 20)]
        return effects

class Orange_Gobber(Gobber):
    name = "Orangemouth Gobber"
    colour = "orange"
    attackeffect = "orange"
    def action(self,targets,victims,cursor,floor):
        x,y = self.pos
        t = targets[0]
        tile = floor.data[t][-1]
        tx,ty = tile.pos
        effects = [LineEffect([
            ("blood-orange",1)],(x,y-32),(tx,ty-32),20,loop=True),
                   LineEffect([
            ("impact-orange1",6),
            ("impact-orange2",6),
            ("impact-orange3",4),],(tx,ty-32),(tx,ty-32),-1,delay = 20)]
        return effects

class Green_Gobber(Gobber):
    name = "Greenmouth Gobber"
    colour = "green"
    attackeffect = "green"
    def action(self,targets,victims,cursor,floor):
        x,y = self.pos
        t = targets[0]
        tile = floor.data[t][-1]
        tx,ty = tile.pos
        effects = [LineEffect([
            ("blood-green",1)],(x,y-32),(tx,ty-32),20,loop=True),
                   LineEffect([
            ("impact-green1",6),
            ("impact-green2",6),
            ("impact-green3",4),],(tx,ty-32),(tx,ty-32),-1,delay = 20)]
        return effects

class Brown_Gobber(Gobber):
    name = "Brownmouth Gobber"
    colour = "brown"
    attackeffect = "brown"
    def action(self,targets,victims,cursor,floor):
        x,y = self.pos
        t = targets[0]
        tile = floor.data[t][-1]
        tx,ty = tile.pos
        effects = [LineEffect([
            ("blood-brown",1)],(x,y-32),(tx,ty-32),20,loop=True),
                   LineEffect([
            ("impact-brown1",6),
            ("impact-brown2",6),
            ("impact-brown3",4),],(tx,ty-32),(tx,ty-32),-1,delay = 20)]
        return effects

class Black_Pudding(Unit):
    name = "Black Pudding"
    colour = "black"
    side = "ooze"
    
    max_hp = 120
    attack = 40
    defense = 6

    moverange = 4
    attackeffect = "slow"
    attackrange = 1
    targetsize = 0.5
    mode = "circle"
    shape = "circle"
    jump = 20

    worth = 5

    desc = [
        "Black Puddings are digustingly thick",
        "and very capable of immobilizing your",
        "jellies."
        ]
    def action(self,targets,victims,cursor,floor):
        x,y = self.pos
        t = floor.data[targets[0]][-1]
        tx,ty = t.pos
        effects = [LineEffect([
            ("blood-black",1)],(tx,ty),(tx,ty-32),16,loop=True),
                   LineEffect([
            ("impact-yellow1",6),
            ("impact-green2",6),
            ("impact-blue3",4),],(tx,ty-26),(tx,ty-26),-1,delay = 20)]
        return effects

