Skip to content

Instantly share code, notes, and snippets.

Created December 1, 2011 17:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/1418508 to your computer and use it in GitHub Desktop.
Save anonymous/1418508 to your computer and use it in GitHub Desktop.
Wizard's Fire for Codea 0.20
House = class()
-- this class contains info for both houses and towers. It's pretty
-- sparse at the moment, but I expect to expand the game with the
-- ability to upgrade and rebuild houses 
HOUSE_DESTROYED = 0
HOUSE_STANDARD = 1
HOUSE_TOWER = 5
function House:init(x)
    self.x = x
    self.type = HOUSE_STANDARD
end
function House:distance(x)
    return math.abs(self.x - x)
end
function House:draw()
    if self.type == HOUSE_DESTROYED then
        sprite("Small World:Dirt Patch", self.x, 60)
    elseif self.type == HOUSE_STANDARD then
        sprite("Small World:House", self.x, 80)
    elseif self.type == HOUSE_TOWER then
        sprite("Small World:Watch Tower", self.x, 110)
    end
end
Level = class()
-- This class is mostly a grab bag of variables associated with the
-- current round of play, but is also reonsible for drawing level 
-- and game over messages along with background items.
function Level:init(x)
    self.number = x
    -- maxMissilies is the number of incoming on screen at one time
    self.maxMissiles = x * 4
    if self.maxMissiles > 12 then 
        self.maxMissiles = 12
    end
    self.missileCount = 0
    -- total is the number of missiles in the level
    self.total = x * 4 + 12
    -- launched is how many have already been launched
    self.launched = 0
    self.destroyed = 0
    -- endTime marks elapsedTime when final missile is destroyed
    self.endTime = 0
    self.stars = {}
    self.clouds = {}
    for i=1, 25 do
        self.stars[i] = vec2(WIDTH * math.random(), 
        HEIGHT * math.random() + 150)
    end
    for i=1, 10 do
        self.clouds[i] = vec2(WIDTH * math.random() - 100, 
        HEIGHT * math.random() + 250)
    end
    self.sun = vec2(WIDTH -110, HEIGHT - 50)
end 
function drawChar(c, x, y, w)
    -- some letters for level / game over
    h = w * 2
    if c == 'L' then
        line(x, y, x, y - h)
        line(x, y - h, x + w, y - h)
    elseif c == 'E' then
        line(x, y, x, y - h)
        line(x, y, x + w, y)
        line(x, y - h / 2, x + w, y - h / 2)
        line(x, y - h, x + w, y - h)
    elseif c == 'V' then
        line(x, y, x + w / 2, y - h)
        line(x + w / 2, y - h, x + w, y)
    elseif c == 'O' then
        line(x, y, x, y - h)
        line(x, y - h, x + w, y - h)
        line(x + w, y - h, x + w, y)
        line(x, y, x + w, y)
    elseif c == 'R' then
        line(x, y, x, y - h)
        line(x, y, x + w, y - h / 4)
        line(x + w, y - h / 4, x, y - h / 2)
        line(x, y - h / 2, x + w, y - h)
    elseif c == 'G' then
        line(x, y, x, y - h)
        line(x, y, x + w, y)
        line(x, y - h, x + w, y - h)
        line(x + w, y - h, x + w, y - h / 2)
        line(x + w / 2, y - h / 2, x + w, y - h / 2)
    elseif c == 'M' then
        line(x, y, x, y - h)
        line(x + w, y, x + w, y - h)
        line(x, y, x + w / 2, y - h)
        line(x + w / 2, y - h, x + w, y)
    elseif c == 'A' then
        line(x + w / 2, y, x, y - h)
        line(x + w / 2, y, x + w, y - h)
        line(x + w / 4, y - h / 2, x + w * 0.75, y - h / 2)
    end
end
    
function Level:drawOver()
    stroke(255, 153, 0, 255)
    strokeWidth(8)
    drawChar('L', 130, 400, 40)
    drawChar('E', 180, 400, 40)
    drawChar('V', 230, 400, 40)
    drawChar('E', 280, 400, 40)
    drawChar('L', 330, 400, 40)
    
    drawChar('O', 430, 400, 40)
    drawChar('V', 480, 400, 40)
    drawChar('E', 530, 400, 40)
    drawChar('R', 580, 400, 40)
end
function Level:gameOver()
    stroke(255, 0, 11, 255)
    strokeWidth(8)
    drawChar('G', 100, 400, 50)
    drawChar('A', 160, 400, 50)
    drawChar('M', 220, 400, 50)
    drawChar('E', 280, 400, 50)
    
    drawChar('O', 420, 400, 50)
    drawChar('V', 480, 400, 50)
    drawChar('E', 540, 400, 50)
    drawChar('R', 600, 400, 50)
end
function Level:hit()
    -- a missile is taken out
    self.destroyed = self.destroyed + 1
    if self.destroyed >= self.total then
        self.endTime = ElapsedTime
    end
end
function Level:active()
    -- check to see if there are more missiles to launch
    if self.launched < self.total then
        return true
    end
    return false
end
function Level:over()
    -- check to see that everything has been destroyed
    if self.destroyed >= self.total then
        return true
    end
    return false
end
function Level:draw()
    -- background
    if math.modf(self.number / 2) == self.number / 2 then
        fill(0, 0, 0, 255)
        rect(0, 190, WIDTH, HEIGHT)
        fill(13, 13, 13, 255)
        rect(0, 132, WIDTH, 64) 
        fill(33, 24, 21, 255)
        rect(0, 100, WIDTH, 32)
        fill(31, 116, 51, 255)
        rect(0,0,WIDTH,100)
        stroke(255, 255, 255, 255)
        strokeWidth(3)
        for i = 1, 25 do
            line(self.stars[i].x, self.stars[i].y, 
            self.stars[i].x, self.stars[i].y)
        end
    else
        fill(152, 158, 221, 255)
        rect(0, 190, WIDTH, HEIGHT)
        fill(153, 159, 200, 255)
        rect(0, 132, WIDTH, 64) 
        fill(162, 169, 184, 255)
        rect(0, 100, WIDTH, 32)
        for i=1, 5 do
            fill(251, 251, 1, i * 50)
            ellipse(self.sun.x, self.sun.y, 100 - i * 10)
            self.sun.y = self.sun.y - 0.02
        end
        fill(45, 152, 59, 255)
        rect(0,0,WIDTH,100)
        strokeWidth(0)
        for i=1, 5 do
            fill(251, 251, 1, i * 50)
            ellipse(self.sun.x, self.sun.y, 100 - i * 10)
            self.sun.y = self.sun.y - 0.02
        end
        if self.number > 1 then
            for i = 1, 10 do
                sprite("Small World:Dialog Thought", 
                self.clouds[i].x, self.clouds[i].y, 100, 35)
                self.clouds[i].x = self.clouds[i].x + 0.1
            end
        end
    end
end
-- Wizard's Fire 0.2
-- Mark Sumner 
-- devilstower@gmail.com
function setup()
    local i
    -- the missiles array holds the incoming fire
    missiles = {}
    -- the houses array holds buildings, including towers
    houses = {}
    -- the shots array holds shots
    shots = {}
    -- level has most of the info on diificulty
    level = Level(1)
    -- layout buildings
    for i=1, 7 do
        houses[i] = House(i * 100 - 98 + 70)
    end
    houses[1].type = HOUSE_TOWER
    houses[7].type = HOUSE_TOWER
    -- init shots
    for i= 1, 5 do
        shots[i] = Shot(0,0,0,0, SHOT_READY)
    end
    -- track changes in touch
    oldTouch = nil
    score = Score()
    day = true
    endTimer = 0
    startLevel()
end
function startLevel()
    -- reset the missiles
    local i
    for i=1, level.maxMissiles do
        missiles[i] = Missile(WIDTH * math.random(), 
        HEIGHT + 200 * math.random(), 1 + level.number/3)
        level.launched = level.launched + 1
    end
end
function launchShot(x, y)
    -- return fire
    local house
    local shot
    local tower
    -- find nearest tower
    distance = 1000
    tower = 0
    for house = 1, 7 do
        if houses[house].type == HOUSE_TOWER then
            if houses[house]:distance(x) < distance then
                distance = houses[house]:distance(x)
                tower = house
            end
        end
    end
    if tower == 0 then
        sound(SOUND_BLIT,111)
        return nil
    end
    for shot = 1, 5 do
        if shots[shot].status == SHOT_READY then
            -- launch a shot 
            sound(SOUND_HIT,111)
            shots[shot]:launch(houses[tower].x, 145, x, y)
            return nil
        end
    end
    return nil
end
function houseCount()
    -- check to see how many houses remain
    local i
    local count = 0
    for i=1, 7 do
        if houses[i].type == HOUSE_STANDARD then
            count = count + 1
        end
    end
    return count
end
function drawLandscape()
    -- houses, towers, & background
    level:draw()
    local house
    for house=1, 7 do
        houses[house]:draw()
    end
    return nil
end
function draw()
    -- main loop
    if math.modf(level.number / 2) == level.number / 2 then
        day = true
    else
        day = false
    end
    drawLandscape()
    score:draw()
    -- check on launching a shot
    if CurrentTouch.state == BEGAN and 
        CurrentTouch.state < oldTouch then
        launchShot(CurrentTouch.x, CurrentTouch.y)
    end
    oldTouch = CurrentTouch.state
    -- update missiles
    for i=1, level.maxMissiles do
        tempX = WIDTH * math.random()
        tempY = 555 * math.random() + HEIGHT
        tempT = math.floor(7 * math.random() + 1)
        if missiles[i].status == MISSILE_IN_FLIGHT then
            missiles[i]:draw(day)
        end
        -- check to see if missiles have hit ground
        if missiles[i].status == MISSILE_DONE then
            houses[missiles[i].target].type = HOUSE_DESTROYED
            sound(SOUND_EXPLODE, 111)
            level:hit()
            missiles[i].status = MISSILE_DESTROYED
        elseif missiles[i].status == MISSILE_IN_FLIGHT then
            -- check to see if missiles are destroyed
            for s = 1, 5 do 
                if shots[s].status == SHOT_DONE then
                    if shots[s]:collision(missiles[i].x, 
                        missiles[i].y) then
                        sound(SOUND_EXPLODE, 111)
                        fill(255, 220, 0, 255)
                        stroke(255, 224, 0, 255)
                        ellipse(missiles[i].x, missiles[i].y, 22,33)
                        missiles[i].status = MISSILE_DESTROYED
                        score:add(100)
                        level:hit()
                    end
                end
            end
        end
        if missiles[i].status == MISSILE_DESTROYED then
            if level:over() then
                if houseCount() == 0 then
                    level:gameOver()
                else
                    level:drawOver()
                    if ElapsedTime > level.endTime + 3 then
                        sound(SOUND_PICKUP)
                        level = Level(level.number + 1)
                        startLevel()
                    end
                end
            elseif level:active() then
                missiles[i]:reset(tempX, tempY, tempT)
                level.launched = level.launched + 1
            end
        end
    end
    -- draw the shots
    for s = 1, 5 do
        shots[s]:draw()
    end
end
Missile = class()
--constants
MISSILE_READY = -1
MISSILE_IN_FLIGHT = 0
MISSILE_DONE = 1
MISSILE_DESTROED = 2
function Missile:init(x, y, speed)
    self.speed = speed
    local t = math.floor(math.random() *7 + 1)
    self:reset(x, y, t)
end
function Missile:reset(x, y, t)
    self.x = x
    self.y = y
    -- origin position
    self.ox = self.x
    self.oy = self.y
    --pick a target
    self.target = t
    -- set change in x per cycle
    self.dx = (self.x - (self.target * 100 - 30)) / 
    ((self.y - 100) / self.speed)
    self.status= MISSILE_IN_FLIGHT
end
function Missile:clear()
    -- provides an outline that makes it easier to see
    if day == 0 then
        stroke(0, 0, 0, 255)
    else
        stroke(255, 159, 0, 255)
    end
    strokeWidth(5)
    line(self.ox, self.oy, self.x, self.y)
end
function Missile:draw(day)
    --self:clear(day)
    if self.status == MISSILE_IN_FLIGHT then
        if self.y < 120 then
            self.status = MISSILE_DONE
            sprite("Small World:Explosion", self.x, self.y)
        else
            -- update position
            self.x = self.x - self.dx
            self.y = self.y - self.speed
            if day then 
                stroke(232, 222, 6, 105)
            else
                stroke(0, 0, 0, 120)
            end
            strokeWidth(5)
            line(self.ox, self.oy, self.x, self.y)
            ellipse(self.x, self.y, 10)
        end
    end
end
Score = class()
-- this class does little but, surprise, display the score
function Score:init()
    -- you can accept and set parameters here
    self.val = 0
end
function Score:add(x)
    self.val = self.val + x
end
-- Draw a number
function drawNumber(x, y, n)
    w = 15
    h = 20
    stroke(236, 72, 62, 255)
    fill(234, 82, 70, 255)
    strokeWidth(4)
    if string.match(n, "1") then
        line(x + (w / 2), y, x + (w / 2), y - h)
    elseif string.match(n, "2") then
        line(x, y, x + w, y)
        line(x + w, y, x + w, y - (h / 2))
        line(x + w, y - (h / 2), x, y - (h / 2))
        line(x, y - (h / 2), x, y - h)
        line(x, y - h, x + w, y - h)
    elseif string.match(n, "3") then
        line(x, y, x + w, y)
        line(x + w, y, x + w, y - h)
        line(x + w, y - h, x, y - h)
        line(x, y - (h / 2), x + w, y - (h / 2))
    elseif string.match(n, "4") then
        line(x, y, x, y - (h / 2))
        line(x, y - (h / 2), x + w, y - (h / 2))
        line(x + w, y, x + w, y - h)
    elseif string.match(n, "5") then
        line(x + w, y, x, y)
        line(x, y, x, y - (h / 2))
        line(x, y - (h / 2), x + w, y - (h / 2))
        line(x + w, y - (h / 2), x + w, y - h)
        line(x + w, y - h, x, y - h)
    elseif string.match(n, "6") then
        line(x + w, y, x, y)
        line(x, y, x, y - h)
        line(x, y - h, x + w, y - h)
        line(x + w, y - h, x + w, y - (h / 2))
        line(x + w, y - (h / 2), x, y - (h / 2))
    elseif string.match(n, "7") then
        line(x, y, x + w, y)
        line(x + w, y, x + w, y - h)
    elseif string.match(n, "8") then
        line(x, y, x + w, y)
        line(x + w, y, x + w, y - h)
        line(x + w, y - h, x, y - h)
        line(x, y - h, x, y)
        line(x, y - (h / 2), x + w, y - (h / 2))
    elseif string.match(n, "9") then
        line(x + w, y - (h / 2), x, y - (h / 2))
        line(x, y - (h / 2), x, y)
        line(x, y, x + w, y)
        line(x + w, y, x + w, y - h)
        line(x + w, y - h, x, y - h)
    elseif string.match(n, "0") then
        line(x, y, x + w, y)
        line(x + w, y, x + w, y - h)
        line(x + w, y - h, x, y - h)
        line(x, y - h, x, y)
    elseif string.match(n, "x") then
        line(x, y - (w / 3), x + w, y - (h + 1))
        line(x + w, y - (w / 3), x, y - (h + 1))
    end
end
function Score:draw()
    l = string.len(self.val)
    for i = 1, l do
        drawNumber(10 + (i * 30), HEIGHT - 10, 
        string.sub(self.val, i, i))
    end
end
Shot = class()
-- this class tracks your return fire
-- constants
SHOT_READY = -1
SHOT_IN_FLIGHT = 0
SHOT_DONE = 1
function Shot:init(sx, sy, tx, ty, stat)
    self.x = sx
    self.y = sy
    self.tx = tx
    self.ty = ty
    self.status = stat
    self.size = 1
    self.speed = 10
end
function Shot:load(sx, sy, tx, ty)
    self.x = x
    self.y = y
    self.tx = tx
    self.ty = ty
    self.status = SHOT_READY
end
function Shot:launch(sx, sy, tx, ty)
    self.status = SHOT_IN_FLIGHT
    self.size=0
    self.x = sx
    self.y = sy
    self.tx = tx
    self.ty = ty
end
function Shot:update()
    if self.status == SHOT_IN_FLIGHT then
        if self.x < self.tx then
            self.x = self.x + self.speed
        elseif self.x > self.tx then
            self.x = self.x - self.speed
        end
        if self.y < self.ty then
            self.y = self.y + self.speed
        elseif self.y > self.tx then
            self.y = self.y - self.speed
        end
        -- check if done
        if math.abs(self.x - self.tx) < self.speed * 2 and 
           math.abs(self.y - self.ty) < self.speed * 2 then
            self.status = SHOT_DONE
            sound(SOUND_SHOOT,222)
        end
    end
    return nil
end
function Shot:collision(x, y)
    if math.abs(self.tx - x) < self.size * 3 and
       math.abs(self.ty - y) < self.size * 2 and 
        self.size < 21 then
        return true
    end
    return false
end
function Shot:draw()
    self:update()
    if self.status == SHOT_IN_FLIGHT then
        
        fill(247, 255, 0, 255)
        stroke(182, 179, 99, 255)
        ellipse(self.x, self.y, 11, 11)
        stroke(128, 130, 153, 255)
        ellipse(self.tx, self.ty, 11, 11)
        return nil
    end
    if self.status == SHOT_DONE then
        -- do the explosion
        self.size = self.size + 0.5
        strokeWidth(0)
        fill(255, 177, 0, 255 - self.size * 11)
        stroke(255, 179, 0, 255)
        ellipse(self.tx, self.ty, self.size * 3, self.size * 2)
        if self.size > 30 then
            self:load(0,0,0,0)
        end
    end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment