Plants Vs. Zombies recreated in Code Combat!

For my Game Dev 3 final project, I recreated Plants Vs. Zombies. It’s very laggy, and I don’t think non-pvz players will understand how to play, but it works. I’m pretty proud of it. It took about a week and 550 lines of code.

Here’s the link:
https://codecombat.com/play/game-dev-level/game-dev-3-final-project/6239ce6202b488004498f7b8?course=5a0df02b8f2391437740f74f

And here’s the code:

# Welcome to Heros vs. Ogres! (It's just a bad PVZ clone)
#By Jeremy

#Game Values
isDebug = 0
    #Player
playerHealth = 999999999
playerSpeed = 999999999
    #Rows & Columns
rowOne = 14
rowTwo = 22
rowThree = 30
rowFour = 38
rowFive = 46
rowSix = 54
rowForestOne = 6
rowForestTwo = 62
columnOne = 20
columnTwo = 28
columnThree = 36
columnFour = 44
columnFive = 52
columnSix = 60
columnSeven = 68
columnEight = 76
columnDead = 0
columnPlayer = 4
columnLawnmower = 12
columnZombie = 84
    #General
plantHealth = 10
gridOffset = 4
winWave = 2
randomSeed = 0
borderObject = "forest"
gridOneObject = "silver-coin"
gridTwoObject = "bronze-coin"
selectorObject = "gold-coin"
sunObject = "gem"
winObject = "mushroom"
gridOneDecor = "x-mark-wood"
gridTwoDecor = "x-mark-stone"
selectorDecor = "x-mark-bones"
lawnMowerEntity = "skeleton"
sunflowerEntity = "soldier"
peashooterEntity = "archer"
zombieEntity = "munchkin"
coneheadEntity = "scout"
polevaulterEntity = "thrower"
bucketheadEntity = "ogre"
gargantuarEntity = "ogre-f"
    #Sun & Sunflowers
sunMinX = columnPlayer - gridOffset
sunMaxX = columnPlayer + gridOffset
sunMinY = rowThree - gridOffset
sunMaxY = rowFive + gridOffset
sunMinTime = 8
sunMaxTime = 10
sunNextDespawn = 8
sunflowerMinTime = 8
sunflowerMaxTime = 10
sunScore = 25
gems = 0
    #LawnMowers & Peashooters
lawnMowerSpeed = 20
peashooterDamage = 1
    #Zombies
zombieMinSpeed = 15
zombieMaxSpeed = 25
zombieDamage = 2
zombieHealth = 10
coneheadHealth = zombieHealth * 2
bucketheadHealth = zombieHealth * 3
zombiePercent = 74
coneheadPercent = 98
zombieMinTime = 15
zombieMaxTime = 27
zombieMinY = rowOne - gridOffset
zombieMaxY = rowSix + gridOffset
    #Initial Spawn Time
sunSpawnTime = 4
zombieSpawnTime = 40
hordeSpawnTime = 120
hordeNextTime = 120
hordeLength = 5
hordeZombieSpawnTime = 0
hordeNextZombieSpawnTime = 1

# "Homeower"
player = game.spawnHeroXY(columnPlayer, rowThree)
player.attackDamage = 0
player.maxSpeed = playerSpeed
player.maxHealth = playerHealth
player.health = player.maxHealth

# Hud
ui.track(game, "gems")
ui.track(game, "selected")
ui.track(game, "level")
ui.track(game, "ogres")

# Goals
fakegoal1 = game.addManualGoal("Welcome to Heros vs. Ogres!")
fakegoal2 = game.addManualGoal("Collect coins and gems to build your army!")
fakegoal3 = game.addManualGoal("(This isn't going to make much sense if you've never played PVZ)")
game.setGoalState(fakegoal1, True)
game.setGoalState(fakegoal2, True)
game.setGoalState(fakegoal3, True)
goal = game.addManualGoal("Survive " + winWave + " huge waves of ogres!")
game.addSurviveGoal()

# "Lawn"
game.spawnXY(borderObject, columnPlayer, rowForestOne)
game.spawnXY(borderObject, columnLawnmower, rowForestOne)
game.spawnXY(borderObject, columnOne, rowForestOne)
game.spawnXY(borderObject, columnTwo, rowForestOne)
game.spawnXY(borderObject, columnThree, rowForestOne)
game.spawnXY(borderObject, columnFour, rowForestOne)
game.spawnXY(borderObject, columnFive, rowForestOne)
game.spawnXY(borderObject, columnSix, rowForestOne)
game.spawnXY(borderObject, columnSeven, rowForestOne)
game.spawnXY(borderObject, columnEight, rowForestOne)
game.spawnXY(borderObject, columnPlayer, rowForestTwo)
game.spawnXY(borderObject, columnLawnmower, rowForestTwo)
game.spawnXY(borderObject, columnOne, rowForestTwo)
game.spawnXY(borderObject, columnTwo, rowForestTwo)
game.spawnXY(borderObject, columnThree, rowForestTwo)
game.spawnXY(borderObject, columnFour, rowForestTwo)
game.spawnXY(borderObject, columnFive, rowForestTwo)
game.spawnXY(borderObject, columnSix, rowForestTwo)
game.spawnXY(borderObject, columnSeven, rowForestTwo)
game.spawnXY(borderObject, columnEight, rowForestTwo)
game.spawnXY(selectorObject, columnPlayer, rowSix)
game.spawnXY(lawnMowerEntity, columnLawnmower, rowOne)
game.spawnXY(lawnMowerEntity, columnLawnmower, rowTwo)
game.spawnXY(lawnMowerEntity, columnLawnmower, rowThree)
game.spawnXY(lawnMowerEntity, columnLawnmower, rowFour)
game.spawnXY(lawnMowerEntity, columnLawnmower, rowFive)
game.spawnXY(lawnMowerEntity, columnLawnmower, rowSix)
game.spawnXY(gridOneObject, columnOne, rowOne)
game.spawnXY(gridTwoObject, columnOne, rowTwo)
game.spawnXY(gridOneObject, columnOne, rowThree)
game.spawnXY(gridTwoObject, columnOne, rowFour)
game.spawnXY(gridOneObject, columnOne, rowFive)
game.spawnXY(gridTwoObject, columnOne, rowSix)
game.spawnXY(gridTwoObject, columnTwo, rowOne)
game.spawnXY(gridOneObject, columnTwo, rowTwo)
game.spawnXY(gridTwoObject, columnTwo, rowThree)
game.spawnXY(gridOneObject, columnTwo, rowFour)
game.spawnXY(gridTwoObject, columnTwo, rowFive)
game.spawnXY(gridOneObject, columnTwo, rowSix)
game.spawnXY(gridOneObject, columnThree, rowOne)
game.spawnXY(gridTwoObject, columnThree, rowTwo)
game.spawnXY(gridOneObject, columnThree, rowThree)
game.spawnXY(gridTwoObject, columnThree, rowFour)
game.spawnXY(gridOneObject, columnThree, rowFive)
game.spawnXY(gridTwoObject, columnThree, rowSix)
game.spawnXY(gridTwoObject, columnFour, rowOne)
game.spawnXY(gridOneObject, columnFour, rowTwo)
game.spawnXY(gridTwoObject, columnFour, rowThree)
game.spawnXY(gridOneObject, columnFour, rowFour)
game.spawnXY(gridTwoObject, columnFour, rowFive)
game.spawnXY(gridOneObject, columnFour, rowSix)
game.spawnXY(gridOneObject, columnFive, rowOne)
game.spawnXY(gridTwoObject, columnFive, rowTwo)
game.spawnXY(gridOneObject, columnFive, rowThree)
game.spawnXY(gridTwoObject, columnFive, rowFour)
game.spawnXY(gridOneObject, columnFive, rowFive)
game.spawnXY(gridTwoObject, columnFive, rowSix)
game.spawnXY(gridTwoObject, columnSix, rowOne)
game.spawnXY(gridOneObject, columnSix, rowTwo)
game.spawnXY(gridTwoObject, columnSix, rowThree)
game.spawnXY(gridOneObject, columnSix, rowFour)
game.spawnXY(gridTwoObject, columnSix, rowFive)
game.spawnXY(gridOneObject, columnSix, rowSix)
game.spawnXY(gridOneObject, columnSeven, rowOne)
game.spawnXY(gridTwoObject, columnSeven, rowTwo)
game.spawnXY(gridOneObject, columnSeven, rowThree)
game.spawnXY(gridTwoObject, columnSeven, rowFour)
game.spawnXY(gridOneObject, columnSeven, rowFive)
game.spawnXY(gridTwoObject, columnSeven, rowSix)
game.spawnXY(gridTwoObject, columnEight, rowOne)
game.spawnXY(gridOneObject, columnEight, rowTwo)
game.spawnXY(gridTwoObject, columnEight, rowThree)
game.spawnXY(gridOneObject, columnEight, rowFour)
game.spawnXY(gridTwoObject, columnEight, rowFive)
game.spawnXY(gridOneObject, columnEight, rowSix)
# Lawn Decor
game.spawnXY(selectorDecor, columnPlayer, rowOne)
game.spawnXY(selectorDecor, columnPlayer, rowSix)
game.spawnXY(gridOneDecor, columnOne, rowOne)
game.spawnXY(gridTwoDecor, columnOne, rowTwo)
game.spawnXY(gridOneDecor, columnOne, rowThree)
game.spawnXY(gridTwoDecor, columnOne, rowFour)
game.spawnXY(gridOneDecor, columnOne, rowFive)
game.spawnXY(gridTwoDecor, columnOne, rowSix)
game.spawnXY(gridTwoDecor, columnTwo, rowOne)
game.spawnXY(gridOneDecor, columnTwo, rowTwo)
game.spawnXY(gridTwoDecor, columnTwo, rowThree)
game.spawnXY(gridOneDecor, columnTwo, rowFour)
game.spawnXY(gridTwoDecor, columnTwo, rowFive)
game.spawnXY(gridOneDecor, columnTwo, rowSix)
game.spawnXY(gridOneDecor, columnThree, rowOne)
game.spawnXY(gridTwoDecor, columnThree, rowTwo)
game.spawnXY(gridOneDecor, columnThree, rowThree)
game.spawnXY(gridTwoDecor, columnThree, rowFour)
game.spawnXY(gridOneDecor, columnThree, rowFive)
game.spawnXY(gridTwoDecor, columnThree, rowSix)
game.spawnXY(gridTwoDecor, columnFour, rowOne)
game.spawnXY(gridOneDecor, columnFour, rowTwo)
game.spawnXY(gridTwoDecor, columnFour, rowThree)
game.spawnXY(gridOneDecor, columnFour, rowFour)
game.spawnXY(gridTwoDecor, columnFour, rowFive)
game.spawnXY(gridOneDecor, columnFour, rowSix)
game.spawnXY(gridOneDecor, columnFive, rowOne)
game.spawnXY(gridTwoDecor, columnFive, rowTwo)
game.spawnXY(gridOneDecor, columnFive, rowThree)
game.spawnXY(gridTwoDecor, columnFive, rowFour)
game.spawnXY(gridOneDecor, columnFive, rowFive)
game.spawnXY(gridTwoDecor, columnFive, rowSix)
game.spawnXY(gridTwoDecor, columnSix, rowOne)
game.spawnXY(gridOneDecor, columnSix, rowTwo)
game.spawnXY(gridTwoDecor, columnSix, rowThree)
game.spawnXY(gridOneDecor, columnSix, rowFour)
game.spawnXY(gridTwoDecor, columnSix, rowFive)
game.spawnXY(gridOneDecor, columnSix, rowSix)
game.spawnXY(gridOneDecor, columnSeven, rowOne)
game.spawnXY(gridTwoDecor, columnSeven, rowTwo)
game.spawnXY(gridOneDecor, columnSeven, rowThree)
game.spawnXY(gridTwoDecor, columnSeven, rowFour)
game.spawnXY(gridOneDecor, columnSeven, rowFive)
game.spawnXY(gridTwoDecor, columnSeven, rowSix)
game.spawnXY(gridTwoDecor, columnEight, rowOne)
game.spawnXY(gridOneDecor, columnEight, rowTwo)
game.spawnXY(gridTwoDecor, columnEight, rowThree)
game.spawnXY(gridOneDecor, columnEight, rowFour)
game.spawnXY(gridTwoDecor, columnEight, rowFive)
game.spawnXY(gridOneDecor, columnEight, rowSix)


# Position Updates
def onUpdatePositionX(event):
    target = event.target
    if target.pos.x >= columnOne - gridOffset and target.pos.x <= columnOne + gridOffset:
        target.pos.x = columnOne
    elif target.pos.x >= columnTwo - gridOffset and target.pos.x <= columnTwo + gridOffset:
        target.pos.x = columnTwo
    elif target.pos.x >= columnThree - gridOffset and target.pos.x <= columnThree + gridOffset:
        target.pos.x = columnThree
    elif target.pos.x >= columnFour - gridOffset and target.pos.x <= columnFour + gridOffset:
        target.pos.x = columnFour
    elif target.pos.x >= columnFive - gridOffset and target.pos.x <= columnFive + gridOffset:
        target.pos.x = columnFive
    elif target.pos.x >= columnSix - gridOffset and target.pos.x <= columnSix + gridOffset:
        target.pos.x = columnSix
    elif target.pos.x >= columnSeven - gridOffset and target.pos.x <= columnSeven + gridOffset:
        target.pos.x = columnSeven
    elif target.pos.x >= columnEight - gridOffset and target.pos.x <= columnEight + gridOffset:
        target.pos.x = columnEight
    else:
        target.pos.x = columnOne
def onUpdatePositionY(event):
    target = event.target
    if target.pos.y >= rowOne - gridOffset and target.pos.y <= rowOne + gridOffset:
        target.pos.y = rowOne
    elif target.pos.y >= rowTwo - gridOffset and target.pos.y <= rowTwo + gridOffset:
        target.pos.y = rowTwo
    elif target.pos.y >= rowThree - gridOffset and target.pos.y <= rowThree + gridOffset:
        target.pos.y = rowThree
    elif target.pos.y >= rowFour - gridOffset and target.pos.y <= rowFour + gridOffset:
        target.pos.y = rowFour
    elif target.pos.y >= rowFive - gridOffset and target.pos.y <= rowFive + gridOffset:
        target.pos.y = rowFive
    elif target.pos.y >= rowSix - gridOffset and target.pos.y <= rowSix + gridOffset:
        target.pos.y = rowSix
    else:
        target.pos.y = rowOne

# "Lawn Mowers"
lawnMowerGo = 0
def lawnMowerCollide(event):
    lawnMower = event.target
    lawnMower.maxSpeed = lawnMowerSpeed
    other = event.other
    if other.type == zombieEntity or other.type == coneheadEntity or other.type == polevaulterEntity or other.type == bucketheadEntity or other.type == gargantuarEntity:
        other.defeat()
        lawnMower.moveXY(columnZombie, lawnMower.pos.y)
        lawnMower.destroy
game.setActionFor(lawnMowerEntity, "collide", lawnMowerCollide)
game.setActionFor(lawnMowerEntity, "update", onUpdatePositionY)

# Collectables and Spawners
plantSelector = 0
def onCollect(event):
    item = event.other
    if item.type == sunObject:
        gems += sunScore
    elif item.type == winObject:
        game.setGoalState(goal, True)
    if item.type == selectorObject:
        if plantSelector == 0:
            plantSelector += 1
            player.say("Archer selected")
            game.spawnXY(selectorObject, columnPlayer, rowOne)
        elif plantSelector == 1:
            plantSelector -= 1
            player.say("Gemcutter selected")
            game.spawnXY(selectorObject, columnPlayer, rowSix)
    if item.type == gridOneObject or item.type == gridTwoObject:
        if plantSelector == 0 and gems >= 50:
            gems -= 50
            game.spawnXY(sunflowerEntity, item.pos.x, item.pos.y)
            player.say("Gemcutter deployed!")
        elif plantSelector == 1 and gems >= 100:
            gems -= 100
            game.spawnXY(peashooterEntity, item.pos.x, item.pos.y)
            player.say("Archer deployed!")
        else:
            randomMarkX = game.randomInteger(0, 1)
            if randomMarkX == 0:
                game.spawnXY(gridOneObject, item.pos.x, item.pos.y)
            else:
                game.spawnXY(gridTwoObject, item.pos.x, item.pos.y)
player.on("collect", onCollect)
sunDespawn = 4
def spawnRandomSun():
    sunRandX = game.randomInteger(sunMinX, sunMaxX)
    sunRandY = game.randomInteger(sunMinY, sunMaxY)
    game.spawnXY(sunObject, sunRandX, sunRandY)
def onSunSpawn(event):
    sun = event.target
    sunDespawn -= sunDespawn
    sunDespawn += game.time
    game.setActionFor(sun, "update", onSunUpdate)
def onSunUpdate(event):
    sun = event.target
    if game.time >= sunDespawn + sunNextDespawn:
        sun.pos.y += rowForestTwo - sun.pos.y
        sun.destroy()
game.setActionFor(sunObject, "spawn", onSunSpawn)

# "Plants"
sunflowerCount = 0
sunflowerTime = sunflowerMinTime
def onSpawnSunflower(event):
    sunflower = event.target
    sunflower.maxSpeed = 0
    sunflower.maxHealth = plantHealth
    sunflower.health == plantHealth
    sunflowerCount += 1
    sunflowerTime -= sunflowerTime
    sunflowerTime += game.time + sunflowerMinTime
    game.setActionFor(sunflower, "update", onUpdateSunflower)
    game.setActionFor(sunflower, "update", onUpdatePositionX)
    game.setActionFor(sunflower, "update", onUpdatePositionY)
def onUpdateSunflower(event):
    sunflowerRandomTime = game.randomInteger(sunflowerMinTime, sunflowerMaxTime)
    if game.time >= sunflowerTime:
        spawnRandomSun()
        sunflowerTime += (sunflowerRandomTime / sunflowerCount)
game.setActionFor(sunflowerEntity, "spawn", onSpawnSunflower)

peashooterCount = 0
def onSpawnPeashooter(event):
    peashooter = event.target
    peashooter.maxSpeed = 0
    peashooter.attackDamage = peashooterDamage
    peashooter.maxHealth = plantHealth
    peashooter.health == plantHealth
    peashooterCount += 1
    game.setActionFor(peashooter, "update", onUpdatePeashooter)
    game.setActionFor(peashooter, "update", onUpdatePositionX)
    game.setActionFor(peashooter, "update", onUpdatePositionY)
def onUpdatePeashooter(event):
    peashooter = event.target
    enemy = peashooter.findNearestEnemy()
    if enemy and (enemy.type == zombieEntity or enemy.type == coneheadEntity or enemy.type == polevaulterEntity or enemy.type == bucketheadEntity or enemy.type == gargantuarEntity) and (enemy.pos.y <= peashooter.pos.y + gridOffset and enemy.pos.y >= peashooter.pos.y - gridOffset and enemy.pos.x >= peashooter.pos.x):
        peashooter.attack(enemy)
game.setActionFor(peashooterEntity, "spawn", onSpawnPeashooter)

def plantDie(event):
    plant = event.target
    randomMarkX = game.randomInteger(0, 1)
    if randomMarkX == 0:
        game.spawnXY(gridOneObject, plant.pos.x, plant.pos.y)
    else:
        game.spawnXY(gridTwoObject, plant.pos.x, plant.pos.y)
    if plant.type == sunflowerEntity:
        sunflowerCount -= 1
    elif plant.type == peashooterEntity:
        peashooterCount -= 1
    plant.destroy()
game.setActionFor(peashooterEntity, "defeat", plantDie)
game.setActionFor(sunflowerEntity, "defeat", plantDie)

# "Zombies"
zombieCount = 0
def onSpawnZombie(event):
    zombie = event.target
    zombieCount += 1
    if zombie.type == zombieEntity:
        zombie.attackDamage = zombieDamage
        zombie.maxSpeed = (game.randomInteger(zombieMinSpeed, zombieMaxSpeed) / 10)
        zombie.maxHealth = zombieHealth
        zombie.health == zombieHealth
    if zombie.type == coneheadEntity:
        zombie.attackDamage = zombieDamage
        zombie.maxSpeed = (game.randomInteger(zombieMinSpeed, zombieMaxSpeed) / 10)
        zombie.maxHealth = coneheadHealth
        zombie.health == coneheadHealth
    if zombie.type == bucketheadEntity:
        zombie.attackDamage = zombieDamage
        zombie.maxSpeed = (game.randomInteger(zombieMinSpeed, zombieMaxSpeed) / 10)
        zombie.maxHealth = bucketheadHealth
        zombie.health == bucketheadHealth
    game.setActionFor(zombie, "update", onUpdateZombie)
    game.setActionFor(zombie, "update", onUpdatePositionY)
def onUpdateZombie(event):
    zombie = event.target
    hero = zombie.findNearestEnemy()
    if hero:
        distance = zombie.distanceTo(hero)
        if (hero.type == sunflowerEntity or hero.type == peashooterEntity) and (distance <= 2 and hero.pos.x <= zombie.pos.x):
            zombie.attack(hero)
        else:
            zombie.moveXY(columnDead, zombie.pos.y)
    else:
        zombie.moveXY(columnDead, zombie.pos.y)
    if zombie.pos.x <= columnDead and isDebug != 25:
        player.defeat()
        player.say("The Ogres Took Our Land!")
    elif zombie.pos.x <= columnDead and isDebug == 25:
        zombie.defeat()
        player.say("lol")
def zombieDie(event):
    zombie = event.target
    zombieCount -= 1
    zombie.destroy()
game.setActionFor(zombieEntity, "spawn", onSpawnZombie)
game.setActionFor(coneheadEntity, "spawn", onSpawnZombie)
game.setActionFor(bucketheadEntity, "spawn", onSpawnZombie)
game.setActionFor("munchkin", "defeat", zombieDie)
game.setActionFor("scout", "defeat", zombieDie)
game.setActionFor("ogre", "defeat", zombieDie)

def spawnRandomZombie():
    zombieY = game.randomInteger(zombieMinY, zombieMaxY)
    zombieNumber = game.randomInteger(0, 99)
    if zombieNumber <= zombiePercent:
        game.spawnXY("munchkin", columnZombie, zombieY)
    elif zombieNumber <= coneheadPercent:
        game.spawnXY("scout", columnZombie, zombieY)
    else:
        game.spawnXY("ogre", columnZombie, zombieY)

#Spawns
winCount = 0
def spawns():
    if game.time >= sunSpawnTime:
        spawnRandomSun()
        sunRandomTime = game.randomInteger(sunMinTime, sunMaxTime)
        sunSpawnTime += sunRandomTime
    if game.time <= (hordeNextTime * winWave) + zombieMinTime:
        if game.time >= zombieSpawnTime:
            spawnRandomZombie()
            zombieRandomTime = game.randomInteger(zombieMinTime, zombieMaxTime)
            zombieSpawnTime += zombieRandomTime
        if game.time >= hordeSpawnTime:
            if game.time >= (hordeSpawnTime + hordeZombieSpawnTime):
                spawnRandomZombie()
                spawnRandomZombie()
                hordeZombieSpawnTime += hordeNextZombieSpawnTime
                if hordeZombieSpawnTime > hordeLength:
                    hordeZombieSpawnTime -= hordeZombieSpawnTime
            if game.time >= (hordeSpawnTime + hordeLength):
                hordeSpawnTime += hordeNextTime
    elif (game.time >= (hordeNextTime * winWave) + zombieMinTime) and zombieCount == 0 and winCount == 0:
        player.say("We did it!")
        winCount += 1
        game.spawnXY(winObject, columnPlayer, rowThree)

# Game Update
def gameUpdate():
    spawns()
    game.gems = gems
    game.selected = plantSelector
    game.ogres = zombieCount
    plusOrMinus = game.randomInteger(1, 2)
    if game.time == 3:
        randomSeed += (player.pos.y / 20)
        if plusOrMinus == 1:
            zombiePercent += randomSeed
            coneheadPercent = 98
            zombieMinTime += randomSeed
            zombieMinY += randomSeed
            zombieSpawnTime += randomSeed
        elif plusOrMinus == 2:
            zombiePercent -= randomSeed
            coneheadPercent = 98
            zombieMinTime -= randomSeed
            zombieMinY -= randomSeed
            zombieSpawnTime -= randomSeed
    if game.time == 4:
        randomSeed += ((player.pos.y / 20) - randomSeed)
        if plusOrMinus == 1:
            zombieMaxTime += randomSeed
            zombieMaxY += randomSeed
            hordeSpawnTime += randomSeed
            hordeNextTime += randomSeed
        elif plusOrMinus == 2:
            zombieMaxTime -= randomSeed
            zombieMaxY -= randomSeed
            hordeNextTime -= randomSeed
            hordeSpawnTime -= randomSeed
    if game.time == hordeNextTime + zombieMinTime:
        zombieMinTime -= (zombieMinTime / 3) * 2
        zombieMaxTime -= (zombieMaxTime / 3) * 2
    if (game.time * 100) / ((hordeNextTime * winWave) + zombieMinTime) <= 100:
        game.level = (game.time * 100) / ((hordeNextTime * winWave) + zombieMinTime)
    else:
        game.level = 100
    if game.time == 1:
        player.say("3")
    if game.time == 2:
        player.say("2")
    if game.time == 3:
        player.say("1")
    if game.time == 4:
        player.say("Charge!")
        gems += 50
    if game.time == 38:
        player.say("The Ogres are Coming!")
    if game.time == zombieSpawnTime and peashooterCount == 0:
        player.say("We need an archer!")
    if game.time == (hordeSpawnTime - 2):
        player.say("A Huge Wave of Ogres is Approaching!")
    if isDebug == 25:
        game.seed = randomSeed
        game.zombiemintime = zombieMinTime
        game.zombiemaxtime = zombieMaxTime
        game.zombiespawntime = zombieSpawnTime
        game.hordespawntime = hordeSpawnTime
        game.hordenexttime = hordeNextTime
        game.hordelength = hordeLength
        game.hordezombiespawntime = hordeZombieSpawnTime
        game.hordenextzombiespawntime = hordeNextZombieSpawnTime
        ui.track(game, "time")
        ui.track(game, "seed")
        ui.track(game, "zombiemintime")
        ui.track(game, "zombiemaxtime")
        ui.track(game, "zombiespawntime")
        ui.track(game, "hordespawntime")
        ui.track(game, "hordenexttime")
        ui.track(game, "hordelength")
        ui.track(game, "hordezombiespawntime")
        ui.track(game, "hordenextzombiespawntime")
game.on("update", gameUpdate)

Let me know if there are any improvements I could make!

4 Likes

That’s amazing! Awesome job.
If you want to develop it further though, I suggest you add some more types of heroes, e.g. ones that run at an enemy instead of standing.
Also, the mechanics of heroes attacking the ogres are pretty weird.I mean they stand until the ogre comes very close, and then they attack, but they die because of the ogre

Yeah, it’s mostly because I wanted it to be as close to PVZ without getting too complicated. The hero’s range is shorter than I wanted it to be, but I’m not sure how to control that yet. Thanks for the feedback!

Edit: Wait, were you talking about the gemcutters or the archers? The gemcutters don’t attack, they only increase gem spawn rates.

Yes, I am talking about archers

Range solution:

hero.attackRange = float('inf') # infinity, but you can put any other number you want :3

I noticed that you can stop the zombies from moving if you just put your character in the path; you can also make zombies go in between paths if you “ram” your character into them.

That’s the problem with having a character with collision instead of a mouse. I looked for a solution for that, but I couldn’t find one.

Sadly, it does not seem that this fixed anything. I think it’s because the archers are attempting to move closer before attacking, which fails. Making the value infinity also makes their range even worse somehow, giving them the range of bonk choy.

Then try hero.attackRange = 9001

Sadly, it doesn’t matter the range I put on them. It still doesn’t increase their range.

well you have to do unit.attackRange

That is what I am currently doing.

hmmm, it works for me

Can you post your code? :slight_smile:

Current code (Sorry for how long it is, the range value is on line 67 and the range is on 369)

# Welcome to Heros vs. Ogres! (It's just a bad PVZ clone)
#By Jeremy

#Game Values
isDebug = 0
    #Player
playerHealth = 999999999
playerSpeed = 999999999
    #Rows & Columns
rowOne = 14
rowTwo = 22
rowThree = 30
rowFour = 38
rowFive = 46
rowSix = 54
rowForestOne = 6
rowForestTwo = 62
columnOne = 20
columnTwo = 28
columnThree = 36
columnFour = 44
columnFive = 52
columnSix = 60
columnSeven = 68
columnEight = 76
columnDead = 0
columnPlayer = 4
columnLawnmower = 12
columnZombie = 84
    #General
plantHealth = 10
gridOffset = 4
winWave = 2
randomSeed = 0
borderObject = "forest"
gridOneObject = "silver-coin"
gridTwoObject = "bronze-coin"
selectorObject = "gold-coin"
sunObject = "gem"
winObject = "mushroom"
gridOneDecor = "x-mark-wood"
gridTwoDecor = "x-mark-stone"
selectorDecor = "x-mark-bones"
lawnMowerEntity = "skeleton"
sunflowerEntity = "soldier"
peashooterEntity = "archer"
zombieEntity = "munchkin"
coneheadEntity = "scout"
polevaulterEntity = "thrower"
bucketheadEntity = "ogre"
gargantuarEntity = "ogre-f"
    #Sun & Sunflowers
sunMinX = columnPlayer - gridOffset
sunMaxX = columnPlayer + gridOffset
sunMinY = rowThree - gridOffset
sunMaxY = rowFive + gridOffset
sunMinTime = 8
sunMaxTime = 10
sunNextDespawn = 8
sunflowerMinTime = 8
sunflowerMaxTime = 10
sunScore = 25
gems = 0
    #LawnMowers & Peashooters
lawnMowerSpeed = 20
peashooterDamage = 1
peashooterRange = 999999999
    #Zombies
zombieMinSpeed = 15
zombieMaxSpeed = 25
zombieDamage = 2
zombieHealth = 10
coneheadHealth = zombieHealth * 2
bucketheadHealth = zombieHealth * 3
zombiePercent = 74
coneheadPercent = 98
zombieMinTime = 15
zombieMaxTime = 27
zombieMinY = rowOne - gridOffset
zombieMaxY = rowSix + gridOffset
    #Initial Spawn Time
sunSpawnTime = 4
zombieSpawnTime = 40
hordeSpawnTime = 120
hordeNextTime = 120
hordeLength = 5
hordeZombieSpawnTime = 0
hordeNextZombieSpawnTime = 1

# "Homeower"
player = game.spawnHeroXY(columnPlayer, rowThree)
player.attackDamage = 0
player.maxSpeed = playerSpeed
player.maxHealth = playerHealth
player.health = player.maxHealth

# Hud
ui.track(game, "gems")
ui.track(game, "selected")
ui.track(game, "level")
ui.track(game, "ogres")

# Goals
fakegoal1 = game.addManualGoal("Welcome to Heros vs. Ogres!")
fakegoal2 = game.addManualGoal("Collect coins and gems to build your army!")
fakegoal3 = game.addManualGoal("(This isn't going to make much sense if you've never played PVZ)")
game.setGoalState(fakegoal1, True)
game.setGoalState(fakegoal2, True)
game.setGoalState(fakegoal3, True)
goal = game.addManualGoal("Survive " + winWave + " huge waves of ogres!")
game.addSurviveGoal()

# "Lawn"
game.spawnXY(borderObject, columnPlayer, rowForestOne)
game.spawnXY(borderObject, columnLawnmower, rowForestOne)
game.spawnXY(borderObject, columnOne, rowForestOne)
game.spawnXY(borderObject, columnTwo, rowForestOne)
game.spawnXY(borderObject, columnThree, rowForestOne)
game.spawnXY(borderObject, columnFour, rowForestOne)
game.spawnXY(borderObject, columnFive, rowForestOne)
game.spawnXY(borderObject, columnSix, rowForestOne)
game.spawnXY(borderObject, columnSeven, rowForestOne)
game.spawnXY(borderObject, columnEight, rowForestOne)
game.spawnXY(borderObject, columnPlayer, rowForestTwo)
game.spawnXY(borderObject, columnLawnmower, rowForestTwo)
game.spawnXY(borderObject, columnOne, rowForestTwo)
game.spawnXY(borderObject, columnTwo, rowForestTwo)
game.spawnXY(borderObject, columnThree, rowForestTwo)
game.spawnXY(borderObject, columnFour, rowForestTwo)
game.spawnXY(borderObject, columnFive, rowForestTwo)
game.spawnXY(borderObject, columnSix, rowForestTwo)
game.spawnXY(borderObject, columnSeven, rowForestTwo)
game.spawnXY(borderObject, columnEight, rowForestTwo)
game.spawnXY(selectorObject, columnPlayer, rowSix)
game.spawnXY(lawnMowerEntity, columnLawnmower, rowOne)
game.spawnXY(lawnMowerEntity, columnLawnmower, rowTwo)
game.spawnXY(lawnMowerEntity, columnLawnmower, rowThree)
game.spawnXY(lawnMowerEntity, columnLawnmower, rowFour)
game.spawnXY(lawnMowerEntity, columnLawnmower, rowFive)
game.spawnXY(lawnMowerEntity, columnLawnmower, rowSix)
game.spawnXY(gridOneObject, columnOne, rowOne)
game.spawnXY(gridTwoObject, columnOne, rowTwo)
game.spawnXY(gridOneObject, columnOne, rowThree)
game.spawnXY(gridTwoObject, columnOne, rowFour)
game.spawnXY(gridOneObject, columnOne, rowFive)
game.spawnXY(gridTwoObject, columnOne, rowSix)
game.spawnXY(gridTwoObject, columnTwo, rowOne)
game.spawnXY(gridOneObject, columnTwo, rowTwo)
game.spawnXY(gridTwoObject, columnTwo, rowThree)
game.spawnXY(gridOneObject, columnTwo, rowFour)
game.spawnXY(gridTwoObject, columnTwo, rowFive)
game.spawnXY(gridOneObject, columnTwo, rowSix)
game.spawnXY(gridOneObject, columnThree, rowOne)
game.spawnXY(gridTwoObject, columnThree, rowTwo)
game.spawnXY(gridOneObject, columnThree, rowThree)
game.spawnXY(gridTwoObject, columnThree, rowFour)
game.spawnXY(gridOneObject, columnThree, rowFive)
game.spawnXY(gridTwoObject, columnThree, rowSix)
game.spawnXY(gridTwoObject, columnFour, rowOne)
game.spawnXY(gridOneObject, columnFour, rowTwo)
game.spawnXY(gridTwoObject, columnFour, rowThree)
game.spawnXY(gridOneObject, columnFour, rowFour)
game.spawnXY(gridTwoObject, columnFour, rowFive)
game.spawnXY(gridOneObject, columnFour, rowSix)
game.spawnXY(gridOneObject, columnFive, rowOne)
game.spawnXY(gridTwoObject, columnFive, rowTwo)
game.spawnXY(gridOneObject, columnFive, rowThree)
game.spawnXY(gridTwoObject, columnFive, rowFour)
game.spawnXY(gridOneObject, columnFive, rowFive)
game.spawnXY(gridTwoObject, columnFive, rowSix)
game.spawnXY(gridTwoObject, columnSix, rowOne)
game.spawnXY(gridOneObject, columnSix, rowTwo)
game.spawnXY(gridTwoObject, columnSix, rowThree)
game.spawnXY(gridOneObject, columnSix, rowFour)
game.spawnXY(gridTwoObject, columnSix, rowFive)
game.spawnXY(gridOneObject, columnSix, rowSix)
game.spawnXY(gridOneObject, columnSeven, rowOne)
game.spawnXY(gridTwoObject, columnSeven, rowTwo)
game.spawnXY(gridOneObject, columnSeven, rowThree)
game.spawnXY(gridTwoObject, columnSeven, rowFour)
game.spawnXY(gridOneObject, columnSeven, rowFive)
game.spawnXY(gridTwoObject, columnSeven, rowSix)
game.spawnXY(gridTwoObject, columnEight, rowOne)
game.spawnXY(gridOneObject, columnEight, rowTwo)
game.spawnXY(gridTwoObject, columnEight, rowThree)
game.spawnXY(gridOneObject, columnEight, rowFour)
game.spawnXY(gridTwoObject, columnEight, rowFive)
game.spawnXY(gridOneObject, columnEight, rowSix)
# Lawn Decor
game.spawnXY(selectorDecor, columnPlayer, rowOne)
game.spawnXY(selectorDecor, columnPlayer, rowSix)
game.spawnXY(gridOneDecor, columnOne, rowOne)
game.spawnXY(gridTwoDecor, columnOne, rowTwo)
game.spawnXY(gridOneDecor, columnOne, rowThree)
game.spawnXY(gridTwoDecor, columnOne, rowFour)
game.spawnXY(gridOneDecor, columnOne, rowFive)
game.spawnXY(gridTwoDecor, columnOne, rowSix)
game.spawnXY(gridTwoDecor, columnTwo, rowOne)
game.spawnXY(gridOneDecor, columnTwo, rowTwo)
game.spawnXY(gridTwoDecor, columnTwo, rowThree)
game.spawnXY(gridOneDecor, columnTwo, rowFour)
game.spawnXY(gridTwoDecor, columnTwo, rowFive)
game.spawnXY(gridOneDecor, columnTwo, rowSix)
game.spawnXY(gridOneDecor, columnThree, rowOne)
game.spawnXY(gridTwoDecor, columnThree, rowTwo)
game.spawnXY(gridOneDecor, columnThree, rowThree)
game.spawnXY(gridTwoDecor, columnThree, rowFour)
game.spawnXY(gridOneDecor, columnThree, rowFive)
game.spawnXY(gridTwoDecor, columnThree, rowSix)
game.spawnXY(gridTwoDecor, columnFour, rowOne)
game.spawnXY(gridOneDecor, columnFour, rowTwo)
game.spawnXY(gridTwoDecor, columnFour, rowThree)
game.spawnXY(gridOneDecor, columnFour, rowFour)
game.spawnXY(gridTwoDecor, columnFour, rowFive)
game.spawnXY(gridOneDecor, columnFour, rowSix)
game.spawnXY(gridOneDecor, columnFive, rowOne)
game.spawnXY(gridTwoDecor, columnFive, rowTwo)
game.spawnXY(gridOneDecor, columnFive, rowThree)
game.spawnXY(gridTwoDecor, columnFive, rowFour)
game.spawnXY(gridOneDecor, columnFive, rowFive)
game.spawnXY(gridTwoDecor, columnFive, rowSix)
game.spawnXY(gridTwoDecor, columnSix, rowOne)
game.spawnXY(gridOneDecor, columnSix, rowTwo)
game.spawnXY(gridTwoDecor, columnSix, rowThree)
game.spawnXY(gridOneDecor, columnSix, rowFour)
game.spawnXY(gridTwoDecor, columnSix, rowFive)
game.spawnXY(gridOneDecor, columnSix, rowSix)
game.spawnXY(gridOneDecor, columnSeven, rowOne)
game.spawnXY(gridTwoDecor, columnSeven, rowTwo)
game.spawnXY(gridOneDecor, columnSeven, rowThree)
game.spawnXY(gridTwoDecor, columnSeven, rowFour)
game.spawnXY(gridOneDecor, columnSeven, rowFive)
game.spawnXY(gridTwoDecor, columnSeven, rowSix)
game.spawnXY(gridTwoDecor, columnEight, rowOne)
game.spawnXY(gridOneDecor, columnEight, rowTwo)
game.spawnXY(gridTwoDecor, columnEight, rowThree)
game.spawnXY(gridOneDecor, columnEight, rowFour)
game.spawnXY(gridTwoDecor, columnEight, rowFive)
game.spawnXY(gridOneDecor, columnEight, rowSix)


# Position Updates
def onUpdatePositionX(event):
    target = event.target
    if target.pos.x >= columnOne - gridOffset and target.pos.x <= columnOne + gridOffset:
        target.pos.x = columnOne
    elif target.pos.x >= columnTwo - gridOffset and target.pos.x <= columnTwo + gridOffset:
        target.pos.x = columnTwo
    elif target.pos.x >= columnThree - gridOffset and target.pos.x <= columnThree + gridOffset:
        target.pos.x = columnThree
    elif target.pos.x >= columnFour - gridOffset and target.pos.x <= columnFour + gridOffset:
        target.pos.x = columnFour
    elif target.pos.x >= columnFive - gridOffset and target.pos.x <= columnFive + gridOffset:
        target.pos.x = columnFive
    elif target.pos.x >= columnSix - gridOffset and target.pos.x <= columnSix + gridOffset:
        target.pos.x = columnSix
    elif target.pos.x >= columnSeven - gridOffset and target.pos.x <= columnSeven + gridOffset:
        target.pos.x = columnSeven
    elif target.pos.x >= columnEight - gridOffset and target.pos.x <= columnEight + gridOffset:
        target.pos.x = columnEight
    else:
        target.pos.x = columnOne
def onUpdatePositionY(event):
    target = event.target
    if target.pos.y >= rowOne - gridOffset and target.pos.y <= rowOne + gridOffset:
        target.pos.y = rowOne
    elif target.pos.y >= rowTwo - gridOffset and target.pos.y <= rowTwo + gridOffset:
        target.pos.y = rowTwo
    elif target.pos.y >= rowThree - gridOffset and target.pos.y <= rowThree + gridOffset:
        target.pos.y = rowThree
    elif target.pos.y >= rowFour - gridOffset and target.pos.y <= rowFour + gridOffset:
        target.pos.y = rowFour
    elif target.pos.y >= rowFive - gridOffset and target.pos.y <= rowFive + gridOffset:
        target.pos.y = rowFive
    elif target.pos.y >= rowSix - gridOffset and target.pos.y <= rowSix + gridOffset:
        target.pos.y = rowSix
    else:
        target.pos.y = rowOne

# "Lawn Mowers"
lawnMowerGo = 0
def lawnMowerCollide(event):
    lawnMower = event.target
    lawnMower.maxSpeed = lawnMowerSpeed
    other = event.other
    if other.type == zombieEntity or other.type == coneheadEntity or other.type == polevaulterEntity or other.type == bucketheadEntity or other.type == gargantuarEntity:
        other.defeat()
        lawnMower.moveXY(columnZombie, lawnMower.pos.y)
        lawnMower.destroy
game.setActionFor(lawnMowerEntity, "collide", lawnMowerCollide)
game.setActionFor(lawnMowerEntity, "update", onUpdatePositionY)

# Collectables and Spawners
plantSelector = 0
def onCollect(event):
    item = event.other
    if item.type == sunObject:
        gems += sunScore
    elif item.type == winObject:
        game.setGoalState(goal, True)
    if item.type == selectorObject:
        if plantSelector == 0:
            plantSelector += 1
            player.say("Archer selected")
            game.spawnXY(selectorObject, columnPlayer, rowOne)
        elif plantSelector == 1:
            plantSelector -= 1
            player.say("Gemcutter selected")
            game.spawnXY(selectorObject, columnPlayer, rowSix)
    if item.type == gridOneObject or item.type == gridTwoObject:
        if plantSelector == 0 and gems >= 50:
            gems -= 50
            game.spawnXY(sunflowerEntity, item.pos.x, item.pos.y)
            player.say("Gemcutter deployed!")
        elif plantSelector == 1 and gems >= 100:
            gems -= 100
            game.spawnXY(peashooterEntity, item.pos.x, item.pos.y)
            player.say("Archer deployed!")
        else:
            randomMarkX = game.randomInteger(0, 1)
            if randomMarkX == 0:
                game.spawnXY(gridOneObject, item.pos.x, item.pos.y)
            else:
                game.spawnXY(gridTwoObject, item.pos.x, item.pos.y)
player.on("collect", onCollect)
sunDespawn = 4
def spawnRandomSun():
    sunRandX = game.randomInteger(sunMinX, sunMaxX)
    sunRandY = game.randomInteger(sunMinY, sunMaxY)
    game.spawnXY(sunObject, sunRandX, sunRandY)
def onSunSpawn(event):
    sun = event.target
    sunDespawn -= sunDespawn
    sunDespawn += game.time
    game.setActionFor(sun, "update", onSunUpdate)
def onSunUpdate(event):
    sun = event.target
    if game.time >= sunDespawn + sunNextDespawn:
        sun.pos.y += rowForestTwo - sun.pos.y
        sun.destroy()
game.setActionFor(sunObject, "spawn", onSunSpawn)

# "Plants"
sunflowerCount = 0
sunflowerTime = sunflowerMinTime
def onSpawnSunflower(event):
    sunflower = event.target
    sunflower.maxSpeed = 0
    sunflower.maxHealth = plantHealth
    sunflower.health == plantHealth
    sunflowerCount += 1
    sunflowerTime -= sunflowerTime
    sunflowerTime += game.time + sunflowerMinTime
    game.setActionFor(sunflower, "update", onUpdateSunflower)
    game.setActionFor(sunflower, "update", onUpdatePositionX)
    game.setActionFor(sunflower, "update", onUpdatePositionY)
def onUpdateSunflower(event):
    sunflowerRandomTime = game.randomInteger(sunflowerMinTime, sunflowerMaxTime)
    if game.time >= sunflowerTime:
        spawnRandomSun()
        sunflowerTime += (sunflowerRandomTime / sunflowerCount)
game.setActionFor(sunflowerEntity, "spawn", onSpawnSunflower)

peashooterCount = 0
def onSpawnPeashooter(event):
    peashooter = event.target
    peashooter.maxSpeed = 0
    peashooter.attackDamage = peashooterDamage
    peashooter.range = peashooterRange
    peashooter.maxHealth = plantHealth
    peashooter.health == plantHealth
    peashooterCount += 1
    game.setActionFor(peashooter, "update", onUpdatePeashooter)
    game.setActionFor(peashooter, "update", onUpdatePositionX)
    game.setActionFor(peashooter, "update", onUpdatePositionY)
def onUpdatePeashooter(event):
    peashooter = event.target
    enemy = peashooter.findNearestEnemy()
    if enemy and (enemy.type == zombieEntity or enemy.type == coneheadEntity or enemy.type == polevaulterEntity or enemy.type == bucketheadEntity or enemy.type == gargantuarEntity) and (enemy.pos.y <= peashooter.pos.y + gridOffset and enemy.pos.y >= peashooter.pos.y - gridOffset and enemy.pos.x >= peashooter.pos.x):
        peashooter.attack(enemy)
game.setActionFor(peashooterEntity, "spawn", onSpawnPeashooter)

def plantDie(event):
    plant = event.target
    randomMarkX = game.randomInteger(0, 1)
    if randomMarkX == 0:
        game.spawnXY(gridOneObject, plant.pos.x, plant.pos.y)
    else:
        game.spawnXY(gridTwoObject, plant.pos.x, plant.pos.y)
    if plant.type == sunflowerEntity:
        sunflowerCount -= 1
    elif plant.type == peashooterEntity:
        peashooterCount -= 1
    plant.destroy()
game.setActionFor(peashooterEntity, "defeat", plantDie)
game.setActionFor(sunflowerEntity, "defeat", plantDie)

# "Zombies"
zombieCount = 0
def onSpawnZombie(event):
    zombie = event.target
    zombieCount += 1
    if zombie.type == zombieEntity:
        zombie.attackDamage = zombieDamage
        zombie.maxSpeed = (game.randomInteger(zombieMinSpeed, zombieMaxSpeed) / 10)
        zombie.maxHealth = zombieHealth
        zombie.health == zombieHealth
    if zombie.type == coneheadEntity:
        zombie.attackDamage = zombieDamage
        zombie.maxSpeed = (game.randomInteger(zombieMinSpeed, zombieMaxSpeed) / 10)
        zombie.maxHealth = coneheadHealth
        zombie.health == coneheadHealth
    if zombie.type == bucketheadEntity:
        zombie.attackDamage = zombieDamage
        zombie.maxSpeed = (game.randomInteger(zombieMinSpeed, zombieMaxSpeed) / 10)
        zombie.maxHealth = bucketheadHealth
        zombie.health == bucketheadHealth
    game.setActionFor(zombie, "update", onUpdateZombie)
    game.setActionFor(zombie, "update", onUpdatePositionY)
def onUpdateZombie(event):
    zombie = event.target
    hero = zombie.findNearestEnemy()
    if hero:
        distance = zombie.distanceTo(hero)
        if (hero.type == sunflowerEntity or hero.type == peashooterEntity) and (distance <= 2 and hero.pos.x <= zombie.pos.x):
            zombie.attack(hero)
        else:
            zombie.moveXY(columnDead, zombie.pos.y)
    else:
        zombie.moveXY(columnDead, zombie.pos.y)
    if zombie.pos.x <= columnDead and isDebug != 25:
        player.defeat()
        player.say("The Ogres Took Our Land!")
    elif zombie.pos.x <= columnDead and isDebug == 25:
        zombie.defeat()
        player.say("lol")
def zombieDie(event):
    zombie = event.target
    zombieCount -= 1
    zombie.destroy()
game.setActionFor(zombieEntity, "spawn", onSpawnZombie)
game.setActionFor(coneheadEntity, "spawn", onSpawnZombie)
game.setActionFor(bucketheadEntity, "spawn", onSpawnZombie)
game.setActionFor("munchkin", "defeat", zombieDie)
game.setActionFor("scout", "defeat", zombieDie)
game.setActionFor("ogre", "defeat", zombieDie)

def spawnRandomZombie():
    zombieY = game.randomInteger(zombieMinY, zombieMaxY)
    zombieNumber = game.randomInteger(0, 99)
    if zombieNumber <= zombiePercent:
        game.spawnXY("munchkin", columnZombie, zombieY)
    elif zombieNumber <= coneheadPercent:
        game.spawnXY("scout", columnZombie, zombieY)
    else:
        game.spawnXY("ogre", columnZombie, zombieY)

#Spawns
winCount = 0
def spawns():
    if game.time >= sunSpawnTime:
        spawnRandomSun()
        sunRandomTime = game.randomInteger(sunMinTime, sunMaxTime)
        sunSpawnTime += sunRandomTime
    if game.time <= (hordeNextTime * winWave) + zombieMinTime:
        if game.time >= zombieSpawnTime:
            spawnRandomZombie()
            zombieRandomTime = game.randomInteger(zombieMinTime, zombieMaxTime)
            zombieSpawnTime += zombieRandomTime
        if game.time >= hordeSpawnTime:
            if game.time >= (hordeSpawnTime + hordeZombieSpawnTime):
                spawnRandomZombie()
                spawnRandomZombie()
                hordeZombieSpawnTime += hordeNextZombieSpawnTime
                if hordeZombieSpawnTime > hordeLength:
                    hordeZombieSpawnTime -= hordeZombieSpawnTime
            if game.time >= (hordeSpawnTime + hordeLength):
                hordeSpawnTime += hordeNextTime
    elif (game.time >= (hordeNextTime * winWave) + zombieMinTime) and zombieCount == 0 and winCount == 0:
        player.say("We did it!")
        winCount += 1
        game.spawnXY(winObject, columnPlayer, rowThree)

# Game Update
def gameUpdate():
    spawns()
    game.gems = gems
    game.selected = plantSelector
    game.ogres = zombieCount
    plusOrMinus = game.randomInteger(1, 2)
    if game.time == 3:
        randomSeed += (player.pos.y / 20)
        if plusOrMinus == 1:
            zombiePercent += randomSeed
            coneheadPercent = 98
            zombieMinTime += randomSeed
            zombieMinY += randomSeed
            zombieSpawnTime += randomSeed
        elif plusOrMinus == 2:
            zombiePercent -= randomSeed
            coneheadPercent = 98
            zombieMinTime -= randomSeed
            zombieMinY -= randomSeed
            zombieSpawnTime -= randomSeed
    if game.time == 4:
        randomSeed += ((player.pos.y / 20) - randomSeed)
        if plusOrMinus == 1:
            zombieMaxTime += randomSeed
            zombieMaxY += randomSeed
            hordeSpawnTime += randomSeed
            hordeNextTime += randomSeed
        elif plusOrMinus == 2:
            zombieMaxTime -= randomSeed
            zombieMaxY -= randomSeed
            hordeNextTime -= randomSeed
            hordeSpawnTime -= randomSeed
    if game.time == hordeNextTime + zombieMinTime:
        zombieMinTime -= (zombieMinTime / 3) * 2
        zombieMaxTime -= (zombieMaxTime / 3) * 2
    if (game.time * 100) / ((hordeNextTime * winWave) + zombieMinTime) <= 100:
        game.level = (game.time * 100) / ((hordeNextTime * winWave) + zombieMinTime)
    else:
        game.level = 100
    if game.time == 1:
        player.say("3")
    if game.time == 2:
        player.say("2")
    if game.time == 3:
        player.say("1")
    if game.time == 4:
        player.say("Charge!")
        gems += 50
    if game.time == 38:
        player.say("The Ogres are Coming!")
    if game.time == zombieSpawnTime and peashooterCount == 0:
        player.say("We need an archer!")
    if game.time == (hordeSpawnTime - 2):
        player.say("A Huge Wave of Ogres is Approaching!")
    if isDebug == 25:
        game.seed = randomSeed
        game.zombiemintime = zombieMinTime
        game.zombiemaxtime = zombieMaxTime
        game.zombiespawntime = zombieSpawnTime
        game.hordespawntime = hordeSpawnTime
        game.hordenexttime = hordeNextTime
        game.hordelength = hordeLength
        game.hordezombiespawntime = hordeZombieSpawnTime
        game.hordenextzombiespawntime = hordeNextZombieSpawnTime
        ui.track(game, "time")
        ui.track(game, "seed")
        ui.track(game, "zombiemintime")
        ui.track(game, "zombiemaxtime")
        ui.track(game, "zombiespawntime")
        ui.track(game, "hordespawntime")
        ui.track(game, "hordenexttime")
        ui.track(game, "hordelength")
        ui.track(game, "hordezombiespawntime")
        ui.track(game, "hordenextzombiespawntime")
game.on("update", gameUpdate)

not .range it’s .attackRange -_-

Oh shoot, sorry about that. Using float('inf') seems to increase their range greatly. It’s not completely infinite, but it works.