Zombie game?

I need a base code for this, but I know it might be a bit of work, because it needs ai’s

There is no base code, to my knowledge, and if there was, it would be quite complex

Good point

I have collected one in my iPad, but it is really complex, maybe you can learn it and improve it.

--# Fire
Fire = class()
-- Towers versus Zombies by @juaxix
-- LGPL - 11/2011 
-- http://www.xixgames.com
-- it is a pleasure to gift this to the world 
-- thanks from heart to all the 2lifesleft team
function Fire:init(attackpower,position,model)
    self.attackpower = attackpower
    self.position    = position
    self.parent      = model
    self.angle       = 0
    self.sizex       = 33
    self.sizey       = 33
    self.tint        = color(255, 255, 255, 255)
    if model == TOWER_LINEAR then
        self.velocity = vec2(3.66,0)
        self.image    = "Small World:Rock"
        self.angle    = -90
    elseif model == TOWER_PARABOLIC then
        self.velocity = vec2(3,0)--math.sin(position.x)/333)
        self.image    = "Small World:Grass Patch"
    elseif model == TOWER_ICE then
        self.angle = 90
        self.velocity = vec2(3.33,0)
        self.image    = "Small World:Raindrop Soft"
        self.tint.a   = 199
    end
end

function Fire:update()
    if self.parent == TOWER_LINEAR then
        self.position = self.position + self.velocity
       -- self.angle = self.angle - math.random(3,6)
       -- if self.angle<0 then self.angle=360 end
    elseif self.parent == TOWER_PARABOLIC then
        self.position   = self.position + self.velocity
        self.position.y = self.position.y + math.sin(self.position.x/33)
        --self.velocity.y = math.sin(self.position.x)
    elseif self.parent == TOWER_ICE then
        self.position = self.position + self.velocity
        self.sizex    = 30
        self.sizey    = 41
    end
end
function Fire:draw()
    self:update()
    pushMatrix()
    translate(self.position.x,self.position.y)
    rotate(self.angle)
    tint(self.tint)
    sprite(self.image,0,0,self.sizex,self.sizey)
    noTint()
    popMatrix()
end
--# Font
Font = class()

-- - The Hershey Fonts were originally created by Dr.
-- A. V. Hershey while working at the
-- U. S. National Bureau of Standards.

-- Useful Links:
-- http://emergent.unpythonic.net/software/hershey
-- http://paulbourke.net/dataformats/hershey/

-- Re-encoding of font information and other shenanigans
-- by Tom Bortels bortels@gmail.com November 2011
-- all rights reversed (Hail Eris!)

-- "If I have seen a little further it is by standing
--  on the shoulders of Giants."
-- Isaac Newton

function Font:init()
   -- font data - 2 decimal character # of points,
   -- followed by 2*points of point data
   -- 9->-9, 8-<-8, ... 1->-1, 0->0, A->1, B->2, ... Z->26
   self.code = "9876543210ABCDEFGHIJKLMNOPQRSTUVWXYZ"
   -- this is the Hershey Roman Simplex font for ascii 32-127
   self.fontdata =
      "00160810EUEG11EBDAE0FAEB0516DUDN11LULN1121KYD711QYJ711DLRL11"
   .. "CFQF2620HYH411LYL411QROTLUHUETCRCPDNEMGLMJOIPHQFQCOAL0H0EACC"
   .. "3124UUC011HUJSJQIOGNENCPCRDTFUHUJTMSPSSTUU11QGOFNDNBP0R0TAUC"
   .. "UESGQG3426WLWMVNUNTMSKQFOCMAK0G0EADBCDCFDHEILMMNNPNRMTKUITHR"
   .. "HPIMKJPCRAT0V0WAWB0710ESDTEUFTFREPDO1014KYIWGTEPDKDGEBG2I5K7"
   .. "1014CYEWGTIPJKJGIBG2E5C70816HUHI11CRML11MRCL0526MRM011DIVI08"
   .. "10FAE0DAEBFAF1E3D40226DIVI0510EBDAE0FAEB0222TYB71720IUFTDQCL"
   .. "CIDDFAI0K0NAPDQIQLPQNTKUIU0420FQHRKUK01420DPDQESFTHULUNTOSPQ"
   .. "POOMMJC0Q01520EUPUJMMMOLPKQHQFPCNAK0H0EADBCD0620MUCGRG11MUM0"
   .. "1720OUEUDLEMHNKNNMPKQHQFPCNAK0H0EADBCD2320PROTLUJUGTEQDLDGEC"
   .. "GAJ0K0NAPCQFQGPJNLKMJMGLEJDG0520QUG011CUQU2920HUETDRDPENGMKL"
   .. "NKPIQGQDPBOAL0H0EADBCDCGDIFKILMMONPPPROTLUHU2320PNOKMIJHIHFI"
   .. "DKCNCODRFTIUJUMTORPNPIODMAJ0H0EADC1110ENDMELFMEN11EBDAE0FAEB"
   .. "1410ENDMELFMEN11FAE0DAEBFAF1E3D40324TRDIT00526DLVL11DFVF0324"
   .. "DRTID02018CPCQDSETGUKUMTNSOQOONMMLIJIG11IBHAI0JAIB5527RMQOOP"
   .. "LPJOINHKHHIFKENEPFQH11LPJNIKIHJFKE11RPQHQFSEUEWGXJXLWOVQTSRT"
   .. "OULUITGSEQDOCLCIDFEDGBIAL0O0RATBUC11SPRHRFSE0818IUA011IUQ011"
   .. "DGNG2321DUD011DUMUPTQSRQROQMPLMK11DKMKPJQIRGRDQBPAM0D01821RP"
   .. "QROTMUIUGTERDPCMCHDEECGAI0M0OAQCRE1521DUD011DUKUNTPRQPRMRHQE"
   .. "PCNAK0D01119DUD011DUQU11DKLK11D0Q00818DUD011DUQU11DKLK2221RP"
   .. "QROTMUIUGTERDPCMCHDEECGAI0M0OAQCRERH11MHRH0822DUD011RUR011DK"
   .. "RK0208DUD01016LULEKBJAH0F0DACBBEBG0821DUD011RUDG11ILR00517DU"
   .. "D011D0P01124DUD011DUL011TUL011TUT00822DUD011DUR011RUR02122IU"
   .. "GTERDPCMCHDEECGAI0M0OAQCRESHSMRPQROTMUIU1321DUD011DUMUPTQSRQ"
   .. "RNQLPKMJDJ2422IUGTERDPCMCHDEECGAI0M0OAQCRESHSMRPQROTMUIU11LD"
   .. "R21621DUD011DUMUPTQSRQROQMPLMKDK11KKR02020QROTLUHUETCRCPDNEM"
   .. "GLMJOIPHQFQCOAL0H0EACC0516HUH011AUOU1022DUDFECGAJ0L0OAQCRFRU"
   .. "0518AUI011QUI01124BUG011LUG011LUQ011VUQ00520CUQ011QUC00618AU"
   .. "IKI011QUIK0820QUC011CUQU11C0Q01114DYD711EYE711DYKY11D7K70214"
   .. "0UN31114IYI711JYJ711CYJY11C7J71016FOHRJO11CLHQML11HQH0021602"
   .. "P20710FUETDRDPEOFPEQ1719ONO011OKMMKNHNFMDKCHCFDCFAH0K0MAOC17"
   .. "19DUD011DKFMHNKNMMOKPHPFOCMAK0H0FADC1418OKMMKNHNFMDKCHCFDCFA"
   .. "H0K0MAOC1719OUO011OKMMKNHNFMDKCHCFDCFAH0K0MAOC1718CHOHOJNLMM"
   .. "KNHNFMDKCHCFDCFAH0K0MAOC0812JUHUFTEQE011BNIN2219ONO2N5M6K7H7"
   .. "F611OKMMKNHNFMDKCHCFDCFAH0K0MAOC1019DUD011DJGMINLNNMOJO00808"
   .. "CUDTEUDVCU11DND01110EUFTGUFVEU11FNF3E6C7A70817DUD011NNDD11HH"
   .. "O00208DUD01830DND011DJGMINLNNMOJO011OJRMTNWNYMZJZ01019DND011"
   .. "DJGMINLNNMOJO01719HNFMDKCHCFDCFAH0K0MAOCPFPHOKMMKNHN1719DND7"
   .. "11DKFMHNKNMMOKPHPFOCMAK0H0FADC1719ONO711OKMMKNHNFMDKCHCFDCFA"
   .. "H0K0MAOC0813DND011DHEKGMINLN1717NKMMJNGNDMCKDIFHKGMFNDNCMAJ0"
   .. "G0DACC0812EUEDFAH0J011BNIN1019DNDDEAG0J0LAOD11ONO00516BNH011"
   .. "NNH01122CNG011KNG011KNO011SNO00517CNN011NNC00916BNH011NNH0F4"
   .. "D6B7A70817NNC011CNNN11C0N03914IYGXFWEUESFQGPHNHLFJ11GXFVFTGR"
   .. "HQIOIMHKDIHGIEICHAG0F2F4G611FHHFHDGBFAE1E3F5G6I70208DYD73914"
   .. "EYGXHWIUISHQGPFNFLHJ11GXHVHTGRFQEOEMFKJIFGEEECFAG0H2H4G611HH"
   .. "FFFDGBHAI1I3H5G6E72324CFCHDKFLHLJKNHPGRGTHUJ11CHDJFKHKJJNGPF"
   .. "RFTGUJUL"

   local i=1
   local c=32
   self.font = {}
   while (i < string.len(self.fontdata)) do
      local cs = string.char(c)
      self.font[cs] = {}
      local points = string.sub(self.fontdata, i, i+1)
      self.font[cs].points = points
      self.font[cs].char = cs
      self.font[cs].ascii = c
      self.font[cs].width = string.sub(self.fontdata, i+2, i+3)
      i = i + 4
      self.font[cs].data = string.sub(self.fontdata, i, i+points*2)
      i = i + points*2
      c = c + 1
   end
   i=-9
   self.decode = {}
   for c in self.code:gmatch"." do
      self.decode[c]=i
      i=i+1
   end
end

-- returns width in pixels of unscaled, strokeWidth(1) string
function Font:stringwidth(s)
   local x, l, i = 0, string.len(s)
   for i = 1, l do
      x = x + self.font[s:sub(i, i)].width
   end
   return x
end

-- draw a string at x,y (skipping offscreen draws)
function Font:drawstring(s, x, y)
   local l, i
   l = string.len(s)
   for i = 1, l do
      local c = s:sub(i, i)
      local w = self.font[c].width
      if ((x + w) >= 0) then
         x = x + (self:drawchar(c, x, y))
      else
         x = x + w -- skip offscreen left (but track position)
      end
      if (x > WIDTH) then break end -- skip offscreen right
   end
end


-- optimized draw string at x,y (old version for reference)
function Font:olddrawstring(s, x, y)
   local l, i
   l = string.len(s)
   for i = 1, l do
      x = x + (self:drawchar(string.sub(s, i, i), x, y))
   end
end

function Font:drawchar(c, x, y)
   local ax, ay, bx, by, minx, maxx = -1, -1, -1, -1, -1, -1
   local p, plot
   local ch = self.font[c]
   for p=1, ch.points do
      ax=bx
      ay=by
      bx=self.decode[ch.data:sub(p*2-1, p*2-1)]
      by=self.decode[ch.data:sub(p*2, p*2)]
      plot=true
      if ((ax==-1) and (ay==-1)) then plot=false end
      if ((bx==-1) and (by==-1)) then plot=false end
      if (plot) then
         line(x+ax, y+ay, x+bx, y+by)
      end
   end
   return ch.width -- for drawstring
end
--# GameLogic
GameLogic = class()
-- Towers versus Zombies by @juaxix
-- LGPL - 11/2011 
-- http://www.xixgames.com
-- it is a pleasure to gift this to the world 
-- thanks from heart to all the 2lifesleft team
GAME_RUNNING = 1
GAME_ENDED   = 2
function GameLogic:init(x)
    self.stars          = {}
    self.starCoolDown   = 0.015
    self.zombieCoolDown = 0.011
    self.timeNextStar   = 0
    self.timeNextZombie = 1
    self.zombies        = {}
    self.state          = GAME_INIT
    self.frame          = 0
    -- memory alloc for zombies
    -- foreach row a line of zombies,easy
    for i=0, maxRowCells-1 do
        self.zombies[i] = {}
    end
    --math.randomseed(math.random (1000000000 ))
end

function GameLogic:update()
    if (level*7*3)<score then
        level = level + 1
    end
    self.timeNextStar = self.timeNextStar - self.starCoolDown
    if self.timeNextStar<=0 then
        table.insert(self.stars,Star(nil))
        self.timeNextStar = 6
    end
    
    self.timeNextZombie = self.timeNextZombie - self.zombieCoolDown
    if self.timeNextZombie <= 0 then
        local k = math.random(0,maxRowCells-2)
        --print("Zombie in row "..k)
        table.insert(self.zombies[k], Zombie(
         vec2(WIDTH - 6,(HEIGHT - 190 - (94*k) ))
        ))
        self.timeNextZombie = 2.3
    end
end

function GameLogic:drawGround()
    for i=0,maxRowCells do -- little trick to draw more grass tiles
        for j=0,maxColCells-1 do
            if math.fmod(i+j,2)==0 then tint(164, 163, 163, 255) end
            sprite("Planet Cute:Grass Block",66+(i*101),HEIGHT - 205 - (95*j))
            noTint()
        end
    end
end

function GameLogic:draw()
    pushMatrix()
        background(0)
        scale(3.500,3.800)
        sprite("SpaceCute:Background",0,0)
    popMatrix()
    if self.state == GAME_RUNNING then
        
        self:drawGround()
        menu:draw()
        towersLogic:draw()
        self:drawGame()
    elseif self.state ==  GAME_ENDED then
        sprite("Small World:House White", WIDTH/2,HEIGHT/2,230,230)
        tint(255, 255, 255, 119)
        sprite("Small World:Bunny Skull", 0,HEIGHT,WIDTH*2,HEIGHT*2)
        noTint()
        
        drawText("Zombies eat your brain",2,1,23,66,color(0,244,0,255))
        drawText("Press reset", 1,1,23,33,color(255,255,255,255))
    elseif self.state == GAME_INIT then
        
        self.frame = self.frame + 1
        if self.frame < 444 then
            sprite("Small World:House White", WIDTH/2,HEIGHT/2,230,230)
            drawText("Protect your house from zombie waves", 2,1,23,66,color(255,255,255,255))
            drawText("They are coming, to the garden", 1,1,23,33,color(255,255,255,255))
        else
            self.state = GAME_RUNNING
        end
    end
end

function GameLogic:drawGame()
    self:update()
    for i=0, maxRowCells-1 do
        for j,z in ipairs(self.zombies[i]) do
            if z.state == ZOMBIE_WALKING and z.position.x < 0 then
                gameLogic.state = GAME_ENDED
                return
            end
            z:draw()
            self:checkZombieAttack(z)
            z = self:checkCollisionWithZombie(z)
            if z.health<= 0 then
                table.remove(self.zombies[i],j)
            end
            
        end
    end
    for i,s in ipairs(self.stars) do
        if s.position.y>HEIGHT or s.position.y<0 then
            table.remove(self.stars,i)
        else
            s:draw()
        end
    end
end

function GameLogic:touchStar(x,y)
    for i,star in ipairs(self.stars) do
        if star:touched(x,y) then
            --sound(SOUND_PICKUP)
            stars = stars + 25
            table.remove(self.stars,i)
            return true
        end
    end
    return false
end

function GameLogic:checkCollisionWithZombie(z)
    -- with missiles
    for i,f in ipairs(towersLogic.fires) do
            if z.position:dist(f.position)<44 then
                -- missile hit a zombie
                z:hit(f.attackpower,f.parent)
                table.remove(towersLogic.fires,i)
                if z.health <= 0 then
                   -- sound(SOUND_EXPLODE)
                    score = score + 6
                    return z
                else
                   -- sound(SOUND_HIT)
                end
                
            end
    end
    return z
end

function GameLogic:checkZombieAttack(z)
    for i=0,maxRowCells-1 do
        for j=0,maxColCells-1 do
         local t = towersLogic.towers[i][j]
         if t.model ~= TOWER_EMPTY then
            if z.position:dist(t.position)<79 then
                if z.state == ZOMBIE_ATTACKING then
                    --sound(SOUND_HIT)
                    t.health = t.health - z.attackpower
                    if t.health <= 0 then
                        t.model = TOWER_EMPTY
                        z.state = ZOMBIE_WALKING
                    else
                        z.state = ZOMBIE_THINKING
                        z.timeNextAtck = z.coolDown
                    end
                elseif z.state == ZOMBIE_WALKING then
                    z.state = ZOMBIE_ATTACKING
                end
                return
            end
          end -- if empty
       end -- for j
    end -- for i
    if z.state == ZOMBIE_ATTACKING then z.state = ZOMBIE_WALKING end
end

function GameLogic:getNumZombiesInRow(numRow)
    local count = 0
    for i,z in ipairs(self.zombies[numRow]) do
        count = count + 1
    end
    return count
end

--# Main
-- Main
-- Towers versus Zombies by @juaxix
-- LGPL - 11/2011 
-- http://www.xixgames.com
-- it is a pleasure to gift this to the world 
-- thanks from heart to all the 2lifesleft team

function setup()
    print("Towers vs Zombies!")
    font  = Font()
    menu  = Menu()
    stars = 550
    maxRowCells = 7
    maxColCells = 6
    towersLogic = TowersLogic()
    gameLogic   = GameLogic()
    score       = 0
    parameter.watch("score")
    level       = 1
    parameter.watch("level")
end

function drawText(text,sw,sc,x,y,color)
    stroke(color)
    noSmooth()
    strokeWidth(sw)
    lineCapMode(ROUND)
    scale(sc)
    font:drawstring(text, x, y)
end


function draw()
    gameLogic:draw()
end

function touched(touch)
    if touch.state == BEGAN or touch.state == MOVING then return end
    --print("x:"..touch.x..",y:"..touch.y)
    local x,y = touch.x,touch.y
    if gameLogic:touchStar(x,y) then return end
    if x>=21 and y<=744 and y>=600 then
        menu:touched(touch)
    elseif x>=21 and y<=566 and y>=23 then
        if menu.towerSelected ~= nil then
            towersLogic:touched(touch)
        end
    end
end
--# Menu
Menu = class()
-- Towers versus Zombies by @juaxix
-- LGPL - 11/2011 
-- http://www.xixgames.com
-- it is a pleasure to gift this to the world 
-- thanks from heart to all the 2lifesleft team
function Menu:init()
    self.towerSelected = nil
    self.positions     = {}
    self.positions[TOWER_STAR]     = vec2(66+202, HEIGHT - 66)
    self.positions[TOWER_ROCK]     = vec2(66+303, HEIGHT - 66)
    self.positions[TOWER_LINEAR]   = vec2(66+404, HEIGHT - 66)
    self.positions[TOWER_PARABOLIC]= vec2(66+505, HEIGHT - 66)
    self.positions[TOWER_ICE]      = vec2(66+606, HEIGHT - 66)
    
    self.availableTowers = 5 -- max number of constant named TOWER_ for towers not empty
end

function Menu:draw()
    for i=0, 6 do
        sprite("Planet Cute:Wood Block",66+(101*i), HEIGHT - 66)
    end
    if stars > 0 then  
        sprite("Planet Cute:Chest Open",66, HEIGHT - 26)
        sprite("Planet Cute:Star", 66, HEIGHT -23,55,85)
    else
        sprite("Planet Cute:Chest Closed", 66, HEIGHT -26)
    end
    --sprite("Planet Cute:Chest Closed",672, HEIGHT - 26)
    if self.towerSelected ~= nil then
        sprite("Planet Cute:Selector", self.positions[self.towerSelected].x,HEIGHT - 26)
    end
    drawText(""..stars, 2,1, 50, HEIGHT - 141,color(255,255,0,255))
    sprite(towersLogic.images[TOWER_STAR], self.positions[TOWER_STAR].x,
        self.positions[TOWER_STAR].y, 101,101)
    drawText(""..towersLogic.towersCosts[TOWER_STAR], 2,1, 244,
        HEIGHT - 141,color(255,255,255,255))
    sprite(towersLogic.images[TOWER_ROCK], self.positions[TOWER_ROCK].x,
        self.positions[TOWER_ROCK].y
        , 101,101)
    drawText(""..towersLogic.towersCosts[TOWER_ROCK], 2,1, 344,
        HEIGHT - 141,color(255,255,255,255))
    sprite(towersLogic.images[TOWER_LINEAR], self.positions[TOWER_LINEAR].x,
        self.positions[TOWER_LINEAR].y, 101,101)
    drawText(""..towersLogic.towersCosts[TOWER_LINEAR], 2,1, 444,
        HEIGHT - 141,color(255,255,255,255))
    sprite(towersLogic.images[TOWER_PARABOLIC], self.positions[TOWER_PARABOLIC].x,
        self.positions[TOWER_PARABOLIC].y
        , 101,101)
    drawText(""..towersLogic.towersCosts[TOWER_PARABOLIC], 2,1, 544,
        HEIGHT - 141,color(255,255,255,255))
    sprite(towersLogic.images[TOWER_ICE], self.positions[TOWER_ICE].x,
        self.positions[TOWER_ICE].y
        , 101,101)
    drawText(""..towersLogic.towersCosts[TOWER_ICE], 2,1, 644,
        HEIGHT - 141,color(255,255,255,255))
    
end

function Menu:touched(touch)
    if stars==0 then return end
    local p = vec2(touch.x,touch.y)
    for i=0,self.availableTowers - 1 do
        if p:dist(self.positions[i])<33 then
           -- print("selected:"..i)
            if towersLogic.towersCosts[i]<=stars then
                if i == self.towerSelected then
                    self.towerSelected = nil
                    return
                end
                self.towerSelected = i 
                --sound(SOUND_HIT)
            else
                --sound(SOUND_BLIT)
            end
            return
        else
            --print("i:"..i..",d:"..p:dist(self.positions[i]))
        end
    end
end

--# Star
Star = class()
-- Towers versus Zombies by @juaxix
-- LGPL - 11/2011 
-- http://www.xixgames.com
-- it is a pleasure to gift this to the world 
-- thanks from heart to all the 2lifesleft team
function Star:init(position)
    if position == nil then
        self.position = vec2(math.random(33,666),HEIGHT)
        self.velocity = vec2(0,-1)
    else
        self.position = position
        self.velocity = vec2(0,0.33)
    end
    self.picked = false
end

function Star:draw()
    self.position = self.position + self.velocity
    sprite("Planet Cute:Star",self.position.x,self.position.y,50,80)
end

function Star:touched(x,y)
    if self.position:dist(vec2(x,y))<= 21 then 
        return true
    else 
        return false
    end
end
--# Tower
Tower = class()
-- Towers versus Zombies by @juaxix
-- LGPL - 11/2011 
-- http://www.xixgames.com
-- it is a pleasure to gift this to the world 
-- thanks from heart to all the 2lifesleft team
-- Tower models
TOWER_EMPTY     = -1
TOWER_STAR      = 0
TOWER_ROCK      = 1
TOWER_LINEAR    = 2
TOWER_PARABOLIC = 3
TOWER_ICE       = 4

-- Tower states
TOWER_ACTIVATED   = 1
TOWER_DEACTIVATED = 2
function Tower:init(model,position)
    self.model    = model
    self.position = position
    self.time     = 0.3
    self.ySmoke   = 0
    self.tintSmoke= color(144, 148, 154, 0)
    self.state= TOWER_ACTIVATED
    if model == TOWER_STAR then
        self.attackpower = 0
        self.health      = 70
        self.coolDown    = 1/66
        self.state       = TOWER_ACTIVATED
    elseif model == TOWER_LINEAR then
        self.attackpower = 1.66
        self.health      = 60
        self.coolDown    = 1/6
    elseif model == TOWER_PARABOLIC then
        self.attackpower = 3
        self.health      = 66
        self.coolDown    = 1/11
    elseif model == TOWER_ROCK then
        self.attackpower = 0
        self.health      = 133
        self.coolDown    = 1/66
    elseif model == TOWER_ICE then
        self.attackpower = 0.66
        self.health      = 33
        self.coolDown    = 1/11
    end
end

function Tower:update()
    if self.model == TOWER_EMPTY or self.model == TOWER_ROCK then return end
    if self.state == TOWER_ACTIVATED then
        self.time = self.time - self.coolDown
    end
    if self.time<= 0 then
        self.time = 7
        if self.model == TOWER_STAR then
            table.insert(gameLogic.stars, Star(self.position))
        elseif self.model == TOWER_LINEAR then
            self.ySmoke = self.position.y 
            self.tintSmoke.a = 255
            --sound(SOUND_SHOOT)
            table.insert(towersLogic.fires,
                Fire(self.attackpower,self.position+vec2(1,0),
                TOWER_LINEAR)
            )
        elseif self.model == TOWER_PARABOLIC then
            self.ySmoke = self.position.y 
            self.tintSmoke.a = 223
            --sound(SOUND_SHOOT)
            table.insert(towersLogic.fires,
                Fire(self.attackpower,self.position+vec2(1,0),
                TOWER_PARABOLIC)
            )
        elseif self.model == TOWER_ICE then
            self.ySmoke = self.position.y 
            self.tintSmoke.a = 223
            --sound(SOUND_SHOOT)
            table.insert(towersLogic.fires,
                Fire(self.attackpower,self.position+vec2(1,0),
                TOWER_ICE)
            )
        end
    end
end

function Tower:draw()
    if self.model == TOWER_EMPTY then return end --deactivated cell
    self:update()
    sprite(towersLogic.images[self.model],self.position.x,self.position.y,101,101)
    pushMatrix()
    local l = 0 -- longitude of the tower health bar
    if self.health < 21 then
        stroke(255, 28, 0, 255)
        l = 6
    elseif self.health < 33 then
        stroke(255, 170, 0, 255)
        l = 11
    else
        stroke(95, 255, 0, 255)
        l = 23
    end
    
    strokeWidth(11)
    smooth()
    lineCapMode(0)
    line(self.position.x-l,self.position.y-33,self.position.x+l,self.position.y-33)
    popMatrix()
    if self.tintSmoke.a>128 then
        self.tintSmoke.a = self.tintSmoke.a - 1
        self.ySmoke      = self.ySmoke + 0.333
        pushMatrix()
        translate(self.position.x,self.ySmoke)
        tint(self.tintSmoke)
        sprite("Small World:Dirt Patch",0,0,101,101)
        noTint()
        popMatrix()
    end
end
--# TowerLogic
TowersLogic = class()
-- Towers versus Zombies by @juaxix
-- LGPL - 11/2011 
-- http://www.xixgames.com
-- it is a pleasure to gift this to the world 
-- thanks from heart to all the 2lifesleft team
function TowersLogic:init()
    self.images = {}
    self.images[TOWER_STAR]     = "Small World:Tower"
    self.images[TOWER_ROCK]     = "Planet Cute:Rock"
    self.images[TOWER_LINEAR]   = "Small World:Watch Tower"
    self.images[TOWER_PARABOLIC]= "Small World:Observatory"
    self.images[TOWER_ICE]      = "Small World:Monster Den"
    
    
    self.towersCosts = {}
    self.towersCosts[TOWER_STAR]      = 50
    self.towersCosts[TOWER_ROCK]      = 60
    self.towersCosts[TOWER_LINEAR]    = 100
    self.towersCosts[TOWER_PARABOLIC] = 150
    self.towersCosts[TOWER_ICE]       = 175
    
    -- allocate memory
    self.towers = {}
    for i=0,maxRowCells-1 do
        self.towers[i] = {}
        for j=0,maxColCells-1 do
            self.towers[i][j] = Tower(TOWER_EMPTY,vec2(66+ (101*i),(HEIGHT - 205 - 94*j)))
        end
    end
    self.fires = {}
end

function TowersLogic:draw()
    zombiesC = 0
    for i=0,maxRowCells-1 do
        --local zcount = gameLogic:getNumZombiesInRow(i)
       -- zombiesC =  zcount
       -- if showZ == 1 then
     --      print("Row "..i..", "..zcount.." zombies")
      --  end
        for j=0,maxColCells-1 do
            if self.towers[i][j].model ~= TOWER_EMPTY then
                if self.towers[i][j].health <= 0 then
                    self.towers[i][j].model = TOWER_EMPTY
                else
                    if self.towers[i][j].model > TOWER_ROCK then
                        if gameLogic:getNumZombiesInRow(j) > 0 then
                            self.towers[i][j].state = TOWER_ACTIVATED
                        else
                            self.towers[i][j].state = TOWER_DEACTIVATED
                        end
                    end
                    self.towers[i][j]:draw()
                end
            end
        end
    end
    for i,f in ipairs(self.fires) do
        if f.position.x > WIDTH then
            table.remove(self.fires,i)
        else
            f:draw()
        end
    end
end

function TowersLogic:touched(touch)
    local d = vec2(touch.x,touch.y)
    for i=0,maxRowCells-1 do
        for j=0,maxColCells-1 do
            if self.towers[i][j].position:dist(d)<21 then
                if self.towers[i][j].model == TOWER_EMPTY then
                    self.towers[i][j]:init(menu.towerSelected,self.towers[i][j].position)
                    stars = stars - self.towersCosts[menu.towerSelected]
                    menu.towerSelected = nil
                    --sound(SOUND_PICKUP)
                else
                    --sound(SOUND_BLIT)
                end
                return
            end
        end
    end
end

--# Zombie
Zombie = class()

-- Towers versus Zombies by @juaxix
-- LGPL - 11/2011 
-- http://www.xixgames.com
-- it is a pleasure to gift this to the world 
-- thanks from heart to all the 2lifesleft team

ZOMBIE_WALKING   = 1
ZOMBIE_ATTACKING = 2
ZOMBIE_THINKING  = 3

function Zombie:init(position)
    self.position     = position
    self.state        = ZOMBIE_WALKING
    self.timeNextAtck = 0
    self.level        = math.random(1,level)
    self.attackpower  = 3.3*self.level
    self.health       = 8 + 3*self.level
    self.coolDown     = 6
    self.tintBlood    = color(255, 0, 16, 0)
    self.yBlood       = 0
    self.timeFrozen   = 0
end

function Zombie:hit(dmg,tower)
    self.health = self.health - (dmg/self.level)
    self.yBlood = self.position.y - 11
    self.tintBlood.a = 200
    --sound(SOUND_HIT)
    if tower == TOWER_ICE then
        self.timeFrozen = 6
    end 
end

function Zombie:draw()
    if self.state == ZOMBIE_WALKING or self.state == ZOMBIE_ATTACKING or 
        self.state == ZOMBIE_THINKING 
    then
        if self.timeFrozen>0 then
            self.timeFrozen = self.timeFrozen - 1/33
            tint(93, 132, 230, 255)
        else
            tint(177, 199, 174, 255)
        end
        pushMatrix()
        translate(self.position.x ,self.position.y)
        if self.level == 1 then
            sprite("Planet Cute:Character Pink Girl")
        elseif self.level == 2 then
            sprite("Planet Cute:Character Boy")
        elseif self.level == 3 then
            sprite("Planet Cute:Character Cat Girl")
        elseif self.level == 4 then
            sprite("Planet Cute:Character Horn Girl")
        elseif self.level == 5 then
            sprite("Planet Cute:Character Princess Girl")
        elseif self.level == 6 then  
            sprite("Planet Cute:Enemy Bug",0,0,-101,171)
        else
            sprite("SpaceCute:Beetle Ship",0,0,-101,171)
        end
        popMatrix()
        noTint()
        if self.tintBlood.a > 123 then
            self.tintBlood.a = self.tintBlood.a - 1
            self.yBlood      = self.yBlood + 0.1
            if self.timeFrozen > 0 then
                tint(46, 66, 236, self.tintBlood.a)
            else
                tint(self.tintBlood)
            end
            sprite("Small World:Dirt Patch",self.position.x,self.yBlood)
            noTint()
        end
        if self.state == ZOMBIE_WALKING then
            if self.timeFrozen > 0 then
                self.position.x = self.position.x  - 0.09
            else
                self.position.x = self.position.x  - 3
            end
        elseif self.state == ZOMBIE_THINKING then
            self.timeNextAtck = self.timeNextAtck - 1/33
            if self.timeNextAtck <= 0 then
                self.timeNextAtck = 6
                self.state = ZOMBIE_ATTACKING
            end
        end
        if self.state == ZOMBIE_ATTACKING or self.state == ZOMBIE_THINKING then
            pushMatrix()
                translate(self.position.x-6,self.position.y+16)
                sprite("Small World:Dialog Thought")
                rotate(90)
                sprite("Small World:Sword")
            popMatrix()
        end
    end
    
    local l = 0 -- longitude of the tower health bar
    if self.health < 3 then
        stroke(255, 28, 0, 255)
        l = 6
    elseif self.health < 6 then
        stroke(255, 170, 0, 255)
        l = 11
    else
        stroke(95, 255, 0, 255)
        l = 23
    end
    strokeWidth(3)
    smooth()
    lineCapMode(1)
    line(self.position.x-l,self.position.y-66,self.position.x+l,self.position.y-66) 
end