diff --git a/source/__init__.py b/source/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/component/__init__.py b/source/component/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/component/map.py b/source/component/map.py new file mode 100644 index 0000000..0de0eda --- /dev/null +++ b/source/component/map.py @@ -0,0 +1,45 @@ +__author__ = 'marble_xu' + +import random +import pygame as pg +from .. import tool +from .. import constants as c + +class Map(): + def __init__(self, width, height): + self.width = width + self.height = height + self.map = [[0 for x in range(self.width)] for y in range(self.height)] + + def isValid(self, map_x, map_y): + if (map_x < 0 or map_x >= self.width or + map_y < 0 or map_y >= self.height): + return False + return True + + def isMovable(self, map_x, map_y): + return (self.map[map_y][map_x] == c.MAP_EMPTY) + + def getMapIndex(self, x, y): + x -= c.MAP_OFFSET_X + y -= c.MAP_OFFSET_Y + return (x // c.GRID_X_SIZE, y // c.GRID_Y_SIZE) + + def getMapGridPos(self, map_x, map_y): + return (map_x * c.GRID_X_SIZE + c.GRID_X_SIZE//2 + c.MAP_OFFSET_X, + map_y * c.GRID_Y_SIZE + c.GRID_Y_SIZE//5 * 3 + c.MAP_OFFSET_Y) + + def setMapGridType(self, map_x, map_y, type): + self.map[map_y][map_x] = type + + def getRandomMapIndex(self): + map_x = random.randint(0, self.width-1) + map_y = random.randint(0, self.height-1) + return (map_x, map_y) + + def showPlant(self, x, y): + pos = None + map_x, map_y = self.getMapIndex(x, y) + if self.isValid(map_x, map_y) and self.isMovable(map_x, map_y): + pos = self.getMapGridPos(map_x, map_y) + return pos diff --git a/source/component/menubar.py b/source/component/menubar.py new file mode 100644 index 0000000..56054a5 --- /dev/null +++ b/source/component/menubar.py @@ -0,0 +1,441 @@ +__author__ = 'marble_xu' + +import random +import pygame as pg +from .. import tool +from .. import constants as c + +PANEL_Y_START = 87 +PANEL_X_START = 22 +PANEL_Y_INTERNAL = 74 +PANEL_X_INTERNAL = 53 +CARD_LIST_NUM = 8 + +card_name_list = [c.CARD_SUNFLOWER, c.CARD_PEASHOOTER, c.CARD_SNOWPEASHOOTER, c.CARD_WALLNUT, + c.CARD_CHERRYBOMB, c.CARD_THREEPEASHOOTER, c.CARD_REPEATERPEA, c.CARD_CHOMPER, + c.CARD_PUFFSHROOM, c.CARD_POTATOMINE, c.CARD_SQUASH, c.CARD_SPIKEWEED, + c.CARD_JALAPENO, c.CARD_SCAREDYSHROOM, c.CARD_SUNSHROOM, c.CARD_ICESHROOM, + c.CARD_HYPNOSHROOM, c.CARD_WALLNUT, c.CARD_REDWALLNUT] +plant_name_list = [c.SUNFLOWER, c.PEASHOOTER, c.SNOWPEASHOOTER, c.WALLNUT, + c.CHERRYBOMB, c.THREEPEASHOOTER, c.REPEATERPEA, c.CHOMPER, + c.PUFFSHROOM, c.POTATOMINE, c.SQUASH, c.SPIKEWEED, + c.JALAPENO, c.SCAREDYSHROOM, c.SUNSHROOM, c.ICESHROOM, + c.HYPNOSHROOM, c.WALLNUTBOWLING, c.REDWALLNUTBOWLING] +plant_sun_list = [50, 100, 175, 50, 150, 325, 200, 150, 0, 25, 50, 100, 125, 25, 25, 75, 75, 0, 0] +plant_frozen_time_list = [7500, 7500, 7500, 30000, 50000, 7500, 7500, 7500, 7500, 30000, + 30000, 7500, 50000, 7500, 7500, 50000, 30000, 0, 0] +all_card_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] + +def getSunValueImage(sun_value): + font = pg.font.SysFont(None, 22) + width = 32 + msg_image = font.render(str(sun_value), True, c.NAVYBLUE, c.LIGHTYELLOW) + msg_rect = msg_image.get_rect() + msg_w = msg_rect.width + + image = pg.Surface([width, 17]) + x = width - msg_w + + image.fill(c.LIGHTYELLOW) + image.blit(msg_image, (x, 0), (0, 0, msg_rect.w, msg_rect.h)) + image.set_colorkey(c.BLACK) + return image + +def getCardPool(data): + card_pool = [] + for card in data: + tmp = card['name'] + for i,name in enumerate(plant_name_list): + if name == tmp: + card_pool.append(i) + break + return card_pool + +class Card(): + def __init__(self, x, y, name_index, scale=0.78): + self.loadFrame(card_name_list[name_index], scale) + self.rect = self.orig_image.get_rect() + self.rect.x = x + self.rect.y = y + + self.name_index = name_index + self.sun_cost = plant_sun_list[name_index] + self.frozen_time = plant_frozen_time_list[name_index] + self.frozen_timer = -self.frozen_time + self.refresh_timer = 0 + self.select = True + + def loadFrame(self, name, scale): + frame = tool.GFX[name] + rect = frame.get_rect() + width, height = rect.w, rect.h + + self.orig_image = tool.get_image(frame, 0, 0, width, height, c.BLACK, scale) + self.image = self.orig_image + + def checkMouseClick(self, mouse_pos): + x, y = mouse_pos + if(x >= self.rect.x and x <= self.rect.right and + y >= self.rect.y and y <= self.rect.bottom): + return True + return False + + def canClick(self, sun_value, current_time): + if self.sun_cost <= sun_value and (current_time - self.frozen_timer) > self.frozen_time: + return True + return False + + def canSelect(self): + return self.select + + def setSelect(self, can_select): + self.select = can_select + if can_select: + self.image.set_alpha(255) + else: + self.image.set_alpha(128) + + def setFrozenTime(self, current_time): + self.frozen_timer = current_time + + def createShowImage(self, sun_value, current_time): + '''create a card image to show cool down status + or disable status when have not enough sun value''' + time = current_time - self.frozen_timer + if time < self.frozen_time: #cool down status + image = pg.Surface([self.rect.w, self.rect.h]) + frozen_image = self.orig_image.copy() + frozen_image.set_alpha(128) + frozen_height = (self.frozen_time - time)/self.frozen_time * self.rect.h + + image.blit(frozen_image, (0,0), (0, 0, self.rect.w, frozen_height)) + image.blit(self.orig_image, (0,frozen_height), + (0, frozen_height, self.rect.w, self.rect.h - frozen_height)) + elif self.sun_cost > sun_value: #disable status + image = self.orig_image.copy() + image.set_alpha(192) + else: + image = self.orig_image + return image + + def update(self, sun_value, current_time): + if (current_time - self.refresh_timer) >= 250: + self.image = self.createShowImage(sun_value, current_time) + self.refresh_timer = current_time + + def draw(self, surface): + surface.blit(self.image, self.rect) + +class MenuBar(): + def __init__(self, card_list, sun_value): + self.loadFrame(c.MENUBAR_BACKGROUND) + self.rect = self.image.get_rect() + self.rect.x = 10 + self.rect.y = 0 + + self.sun_value = sun_value + self.card_offset_x = 32 + self.setupCards(card_list) + + def loadFrame(self, name): + frame = tool.GFX[name] + rect = frame.get_rect() + frame_rect = (rect.x, rect.y, rect.w, rect.h) + + self.image = tool.get_image(tool.GFX[name], *frame_rect, c.WHITE, 1) + + def update(self, current_time): + self.current_time = current_time + for card in self.card_list: + card.update(self.sun_value, self.current_time) + + def createImage(self, x, y, num): + if num == 1: + return + img = self.image + rect = self.image.get_rect() + width = rect.w + height = rect.h + self.image = pg.Surface((width * num, height)).convert() + self.rect = self.image.get_rect() + self.rect.x = x + self.rect.y = y + for i in range(num): + x = i * width + self.image.blit(img, (x,0)) + self.image.set_colorkey(c.BLACK) + + def setupCards(self, card_list): + self.card_list = [] + x = self.card_offset_x + y = 8 + for index in card_list: + x += 55 + self.card_list.append(Card(x, y, index)) + + def checkCardClick(self, mouse_pos): + result = None + for card in self.card_list: + if card.checkMouseClick(mouse_pos): + if card.canClick(self.sun_value, self.current_time): + result = (plant_name_list[card.name_index], card) + break + return result + + def checkMenuBarClick(self, mouse_pos): + x, y = mouse_pos + if(x >= self.rect.x and x <= self.rect.right and + y >= self.rect.y and y <= self.rect.bottom): + return True + return False + + def decreaseSunValue(self, value): + self.sun_value -= value + + def increaseSunValue(self, value): + self.sun_value += value + + def setCardFrozenTime(self, plant_name): + for card in self.card_list: + if plant_name_list[card.name_index] == plant_name: + card.setFrozenTime(self.current_time) + break + + def drawSunValue(self): + self.value_image = getSunValueImage(self.sun_value) + self.value_rect = self.value_image.get_rect() + self.value_rect.x = 21 + self.value_rect.y = self.rect.bottom - 21 + + self.image.blit(self.value_image, self.value_rect) + + def draw(self, surface): + self.drawSunValue() + surface.blit(self.image, self.rect) + for card in self.card_list: + card.draw(surface) + +class Panel(): + def __init__(self, card_list, sun_value): + self.loadImages(sun_value) + self.selected_cards = [] + self.selected_num = 0 + self.setupCards(card_list) + + def loadFrame(self, name): + frame = tool.GFX[name] + rect = frame.get_rect() + frame_rect = (rect.x, rect.y, rect.w, rect.h) + + return tool.get_image(tool.GFX[name], *frame_rect, c.WHITE, 1) + + def loadImages(self, sun_value): + self.menu_image = self.loadFrame(c.MENUBAR_BACKGROUND) + self.menu_rect = self.menu_image.get_rect() + self.menu_rect.x = 0 + self.menu_rect.y = 0 + + self.panel_image = self.loadFrame(c.PANEL_BACKGROUND) + self.panel_rect = self.panel_image.get_rect() + self.panel_rect.x = 0 + self.panel_rect.y = PANEL_Y_START + + + self.value_image = getSunValueImage(sun_value) + self.value_rect = self.value_image.get_rect() + self.value_rect.x = 21 + self.value_rect.y = self.menu_rect.bottom - 21 + + self.button_image = self.loadFrame(c.START_BUTTON) + self.button_rect = self.button_image.get_rect() + self.button_rect.x = 155 + self.button_rect.y = 547 + + def setupCards(self, card_list): + self.card_list = [] + x = PANEL_X_START - PANEL_X_INTERNAL + y = PANEL_Y_START + 43 - PANEL_Y_INTERNAL + for i, index in enumerate(card_list): + if i % 8 == 0: + x = PANEL_X_START - PANEL_X_INTERNAL + y += PANEL_Y_INTERNAL + x += PANEL_X_INTERNAL + self.card_list.append(Card(x, y, index, 0.75)) + + def checkCardClick(self, mouse_pos): + delete_card = None + for card in self.selected_cards: + if delete_card: # when delete a card, move right cards to left + card.rect.x -= 55 + elif card.checkMouseClick(mouse_pos): + self.deleteCard(card.name_index) + delete_card = card + + if delete_card: + self.selected_cards.remove(delete_card) + self.selected_num -= 1 + + if self.selected_num == CARD_LIST_NUM: + return + + for card in self.card_list: + if card.checkMouseClick(mouse_pos): + if card.canSelect(): + self.addCard(card) + break + + def addCard(self, card): + card.setSelect(False) + y = 8 + x = 78 + self.selected_num * 55 + self.selected_cards.append(Card(x, y, card.name_index)) + self.selected_num += 1 + + def deleteCard(self, index): + self.card_list[index].setSelect(True) + + def checkStartButtonClick(self, mouse_pos): + if self.selected_num < CARD_LIST_NUM: + return False + + x, y = mouse_pos + if (x >= self.button_rect.x and x <= self.button_rect.right and + y >= self.button_rect.y and y <= self.button_rect.bottom): + return True + return False + + def getSelectedCards(self): + card_index_list = [] + for card in self.selected_cards: + card_index_list.append(card.name_index) + return card_index_list + + def draw(self, surface): + self.menu_image.blit(self.value_image, self.value_rect) + surface.blit(self.menu_image, self.menu_rect) + surface.blit(self.panel_image, self.panel_rect) + for card in self.card_list: + card.draw(surface) + for card in self.selected_cards: + card.draw(surface) + + if self.selected_num == CARD_LIST_NUM: + surface.blit(self.button_image, self.button_rect) + +class MoveCard(): + def __init__(self, x, y, card_name, plant_name, scale=0.78): + self.loadFrame(card_name, scale) + self.rect = self.orig_image.get_rect() + self.rect.x = x + self.rect.y = y + self.rect.w = 1 + self.image = self.createShowImage() + + self.card_name = card_name + self.plant_name = plant_name + self.move_timer = 0 + self.select = True + + def loadFrame(self, name, scale): + frame = tool.GFX[name] + rect = frame.get_rect() + width, height = rect.w, rect.h + + self.orig_image = tool.get_image(frame, 0, 0, width, height, c.BLACK, scale) + self.orig_rect = self.orig_image.get_rect() + self.image = self.orig_image + + def checkMouseClick(self, mouse_pos): + x, y = mouse_pos + if(x >= self.rect.x and x <= self.rect.right and + y >= self.rect.y and y <= self.rect.bottom): + return True + return False + + def createShowImage(self): + '''create a part card image when card appears from left''' + if self.rect.w < self.orig_rect.w: #create a part card image + image = pg.Surface([self.rect.w, self.rect.h]) + image.blit(self.orig_image, (0, 0), (0, 0, self.rect.w, self.rect.h)) + self.rect.w += 1 + else: + image = self.orig_image + return image + + def update(self, left_x, current_time): + if self.move_timer == 0: + self.move_timer = current_time + elif (current_time - self.move_timer) >= c.CARD_MOVE_TIME: + if self.rect.x > left_x: + self.rect.x -= 1 + self.image = self.createShowImage() + self.move_timer += c.CARD_MOVE_TIME + + def draw(self, surface): + surface.blit(self.image, self.rect) + +class MoveBar(): + def __init__(self, card_pool): + self.loadFrame(c.MOVEBAR_BACKGROUND) + self.rect = self.image.get_rect() + self.rect.x = 90 + self.rect.y = 0 + + self.card_start_x = self.rect.x + 8 + self.card_end_x = self.rect.right - 5 + self.card_pool = card_pool + self.card_list = [] + self.create_timer = -c.MOVEBAR_CARD_FRESH_TIME + + def loadFrame(self, name): + frame = tool.GFX[name] + rect = frame.get_rect() + frame_rect = (rect.x, rect.y, rect.w, rect.h) + + self.image = tool.get_image(tool.GFX[name], *frame_rect, c.WHITE, 1) + + def createCard(self): + if len(self.card_list) > 0 and self.card_list[-1].rect.right > self.card_end_x: + return False + x = self.card_end_x + y = 6 + index = random.randint(0, len(self.card_pool) - 1) + card_index = self.card_pool[index] + card_name = card_name_list[card_index] + '_move' + plant_name = plant_name_list[card_index] + self.card_list.append(MoveCard(x, y, card_name, plant_name)) + return True + + def update(self, current_time): + self.current_time = current_time + left_x = self.card_start_x + for card in self.card_list: + card.update(left_x, self.current_time) + left_x = card.rect.right + 1 + + if(self.current_time - self.create_timer) > c.MOVEBAR_CARD_FRESH_TIME: + if self.createCard(): + self.create_timer = self.current_time + + def checkCardClick(self, mouse_pos): + result = None + for index, card in enumerate(self.card_list): + if card.checkMouseClick(mouse_pos): + result = (card.plant_name, card) + break + return result + + def checkMenuBarClick(self, mouse_pos): + x, y = mouse_pos + if(x >= self.rect.x and x <= self.rect.right and + y >= self.rect.y and y <= self.rect.bottom): + return True + return False + + def deleateCard(self, card): + self.card_list.remove(card) + + def draw(self, surface): + surface.blit(self.image, self.rect) + for card in self.card_list: + card.draw(surface) \ No newline at end of file diff --git a/source/component/plant.py b/source/component/plant.py new file mode 100644 index 0000000..684065b --- /dev/null +++ b/source/component/plant.py @@ -0,0 +1,971 @@ +__author__ = 'marble_xu' + +import random +import pygame as pg +from .. import tool +from .. import constants as c + +class Car(pg.sprite.Sprite): + def __init__(self, x, y, map_y): + pg.sprite.Sprite.__init__(self) + + rect = tool.GFX[c.CAR].get_rect() + width, height = rect.w, rect.h + self.image = tool.get_image(tool.GFX[c.CAR], 0, 0, width, height) + self.rect = self.image.get_rect() + self.rect.x = x + self.rect.bottom = y + self.map_y = map_y + self.state = c.IDLE + self.dead = False + + def update(self, game_info): + self.current_time = game_info[c.CURRENT_TIME] + if self.state == c.IDLE: + pass + elif self.state == c.WALK: + self.rect.x += 4 + if self.rect.x > c.SCREEN_WIDTH: + self.dead = True + + def setWalk(self): + if self.state == c.IDLE: + self.state = c.WALK + + def draw(self, surface): + surface.blit(self.image, self.rect) + +class Bullet(pg.sprite.Sprite): + def __init__(self, x, start_y, dest_y, name, damage, ice): + pg.sprite.Sprite.__init__(self) + + self.name = name + self.frames = [] + self.frame_index = 0 + self.load_images() + self.image = self.frames[self.frame_index] + self.rect = self.image.get_rect() + self.rect.x = x + self.rect.y = start_y + self.dest_y = dest_y + self.y_vel = 4 if (dest_y > start_y) else -4 + self.x_vel = 4 + self.damage = damage + self.ice = ice + self.state = c.FLY + self.current_time = 0 + + def loadFrames(self, frames, name): + frame_list = tool.GFX[name] + if name in tool.PLANT_RECT: + data = tool.PLANT_RECT[name] + x, y, width, height = data['x'], data['y'], data['width'], data['height'] + else: + x, y = 0, 0 + rect = frame_list[0].get_rect() + width, height = rect.w, rect.h + + for frame in frame_list: + frames.append(tool.get_image(frame, x, y, width, height)) + + def load_images(self): + self.fly_frames = [] + self.explode_frames = [] + + fly_name = self.name + if self.name == c.BULLET_MUSHROOM: + explode_name = 'BulletMushRoomExplode' + else: + explode_name = 'PeaNormalExplode' + + self.loadFrames(self.fly_frames, fly_name) + self.loadFrames(self.explode_frames, explode_name) + + self.frames = self.fly_frames + + def update(self, game_info): + self.current_time = game_info[c.CURRENT_TIME] + if self.state == c.FLY: + if self.rect.y != self.dest_y: + self.rect.y += self.y_vel + if self.y_vel * (self.dest_y - self.rect.y) < 0: + self.rect.y = self.dest_y + self.rect.x += self.x_vel + if self.rect.x > c.SCREEN_WIDTH: + self.kill() + elif self.state == c.EXPLODE: + if(self.current_time - self.explode_timer) > 500: + self.kill() + + def setExplode(self): + self.state = c.EXPLODE + self.explode_timer = self.current_time + self.frames = self.explode_frames + self.image = self.frames[self.frame_index] + + def draw(self, surface): + surface.blit(self.image, self.rect) + +class Plant(pg.sprite.Sprite): + def __init__(self, x, y, name, health, bullet_group, scale=1): + pg.sprite.Sprite.__init__(self) + + self.frames = [] + self.frame_index = 0 + self.loadImages(name, scale) + self.frame_num = len(self.frames) + self.image = self.frames[self.frame_index] + self.rect = self.image.get_rect() + self.rect.centerx = x + self.rect.bottom = y + + self.name = name + self.health = health + self.state = c.IDLE + self.bullet_group = bullet_group + self.can_sleep = False + self.animate_timer = 0 + self.animate_interval = 100 + self.hit_timer = 0 + + def loadFrames(self, frames, name, scale, color=c.BLACK): + frame_list = tool.GFX[name] + if name in tool.PLANT_RECT: + data = tool.PLANT_RECT[name] + x, y, width, height = data['x'], data['y'], data['width'], data['height'] + else: + x, y = 0, 0 + rect = frame_list[0].get_rect() + width, height = rect.w, rect.h + + for frame in frame_list: + frames.append(tool.get_image(frame, x, y, width, height, color, scale)) + + def loadImages(self, name, scale): + self.loadFrames(self.frames, name, scale) + + def changeFrames(self, frames): + '''change image frames and modify rect position''' + self.frames = frames + self.frame_num = len(self.frames) + self.frame_index = 0 + + bottom = self.rect.bottom + x = self.rect.x + self.image = self.frames[self.frame_index] + self.rect = self.image.get_rect() + self.rect.bottom = bottom + self.rect.x = x + + def update(self, game_info): + self.current_time = game_info[c.CURRENT_TIME] + self.handleState() + self.animation() + + def handleState(self): + if self.state == c.IDLE: + self.idling() + elif self.state == c.ATTACK: + self.attacking() + elif self.state == c.DIGEST: + self.digest() + + def idling(self): + pass + + def attacking(self): + pass + + def digest(self): + pass + + def animation(self): + if (self.current_time - self.animate_timer) > self.animate_interval: + self.frame_index += 1 + if self.frame_index >= self.frame_num: + self.frame_index = 0 + self.animate_timer = self.current_time + + self.image = self.frames[self.frame_index] + if(self.current_time - self.hit_timer) >= 200: + self.image.set_alpha(255) + else: + self.image.set_alpha(192) + + def canAttack(self, zombie): + if (self.state != c.SLEEP and zombie.state != c.DIE and + self.rect.x <= zombie.rect.right): + return True + return False + + def setAttack(self): + self.state = c.ATTACK + + def setIdle(self): + self.state = c.IDLE + self.is_attacked = False + + def setSleep(self): + self.state = c.SLEEP + self.changeFrames(self.sleep_frames) + + def setDamage(self, damage, zombie): + self.health -= damage + self.hit_timer = self.current_time + if self.health == 0: + self.kill_zombie = zombie + + def getPosition(self): + return self.rect.centerx, self.rect.bottom + +class Sun(Plant): + def __init__(self, x, y, dest_x, dest_y, is_big=True): + if is_big: + scale = 0.9 + self.sun_value = c.SUN_VALUE + else: + scale = 0.6 + self.sun_value = 12 + Plant.__init__(self, x, y, c.SUN, 0, None, scale) + self.move_speed = 1 + self.dest_x = dest_x + self.dest_y = dest_y + self.die_timer = 0 + + def handleState(self): + if self.rect.centerx != self.dest_x: + self.rect.centerx += self.move_speed if self.rect.centerx < self.dest_x else -self.move_speed + if self.rect.bottom != self.dest_y: + self.rect.bottom += self.move_speed if self.rect.bottom < self.dest_y else -self.move_speed + + if self.rect.centerx == self.dest_x and self.rect.bottom == self.dest_y: + if self.die_timer == 0: + self.die_timer = self.current_time + elif(self.current_time - self.die_timer) > c.SUN_LIVE_TIME: + self.state = c.DIE + self.kill() + + def checkCollision(self, x, y): + if self.state == c.DIE: + return False + if(x >= self.rect.x and x <= self.rect.right and + y >= self.rect.y and y <= self.rect.bottom): + self.state = c.DIE + self.kill() + return True + return False + +class SunFlower(Plant): + def __init__(self, x, y, sun_group): + Plant.__init__(self, x, y, c.SUNFLOWER, c.PLANT_HEALTH, None) + self.sun_timer = 0 + self.sun_group = sun_group + + def idling(self): + if self.sun_timer == 0: + self.sun_timer = self.current_time - (c.FLOWER_SUN_INTERVAL - 6000) + elif (self.current_time - self.sun_timer) > c.FLOWER_SUN_INTERVAL: + self.sun_group.add(Sun(self.rect.centerx, self.rect.bottom, self.rect.right, self.rect.bottom + self.rect.h // 2)) + self.sun_timer = self.current_time + +class PeaShooter(Plant): + def __init__(self, x, y, bullet_group): + Plant.__init__(self, x, y, c.PEASHOOTER, c.PLANT_HEALTH, bullet_group) + self.shoot_timer = 0 + + def attacking(self): + if (self.current_time - self.shoot_timer) > 2000: + self.bullet_group.add(Bullet(self.rect.right, self.rect.y, self.rect.y, + c.BULLET_PEA, c.BULLET_DAMAGE_NORMAL, False)) + self.shoot_timer = self.current_time + +class RepeaterPea(Plant): + def __init__(self, x, y, bullet_group): + Plant.__init__(self, x, y, c.REPEATERPEA, c.PLANT_HEALTH, bullet_group) + self.shoot_timer = 0 + + def attacking(self): + if (self.current_time - self.shoot_timer) > 2000: + self.bullet_group.add(Bullet(self.rect.right, self.rect.y, self.rect.y, + c.BULLET_PEA, c.BULLET_DAMAGE_NORMAL, False)) + self.bullet_group.add(Bullet(self.rect.right + 40, self.rect.y, self.rect.y, + c.BULLET_PEA, c.BULLET_DAMAGE_NORMAL, False)) + self.shoot_timer = self.current_time + +class ThreePeaShooter(Plant): + def __init__(self, x, y, bullet_groups, map_y): + Plant.__init__(self, x, y, c.THREEPEASHOOTER, c.PLANT_HEALTH, None) + self.shoot_timer = 0 + self.map_y = map_y + self.bullet_groups = bullet_groups + + def attacking(self): + if (self.current_time - self.shoot_timer) > 2000: + offset_y = 9 # modify bullet in the same y position with bullets of other plants + for i in range(3): + tmp_y = self.map_y + (i - 1) + if tmp_y < 0 or tmp_y >= c.GRID_Y_LEN: + continue + dest_y = self.rect.y + (i - 1) * c.GRID_Y_SIZE + offset_y + self.bullet_groups[tmp_y].add(Bullet(self.rect.right, self.rect.y, dest_y, + c.BULLET_PEA, c.BULLET_DAMAGE_NORMAL, False)) + self.shoot_timer = self.current_time + +class SnowPeaShooter(Plant): + def __init__(self, x, y, bullet_group): + Plant.__init__(self, x, y, c.SNOWPEASHOOTER, c.PLANT_HEALTH, bullet_group) + self.shoot_timer = 0 + + def attacking(self): + if (self.current_time - self.shoot_timer) > 2000: + self.bullet_group.add(Bullet(self.rect.right, self.rect.y, self.rect.y, + c.BULLET_PEA_ICE, c.BULLET_DAMAGE_NORMAL, True)) + self.shoot_timer = self.current_time + +class WallNut(Plant): + def __init__(self, x, y): + Plant.__init__(self, x, y, c.WALLNUT, c.WALLNUT_HEALTH, None) + self.load_images() + self.cracked1 = False + self.cracked2 = False + + def load_images(self): + self.cracked1_frames = [] + self.cracked2_frames = [] + + cracked1_frames_name = self.name + '_cracked1' + cracked2_frames_name = self.name + '_cracked2' + + self.loadFrames(self.cracked1_frames, cracked1_frames_name, 1) + self.loadFrames(self.cracked2_frames, cracked2_frames_name, 1) + + def idling(self): + if not self.cracked1 and self.health <= c.WALLNUT_CRACKED1_HEALTH: + self.changeFrames(self.cracked1_frames) + self.cracked1 = True + elif not self.cracked2 and self.health <= c.WALLNUT_CRACKED2_HEALTH: + self.changeFrames(self.cracked2_frames) + self.cracked2 = True + +class CherryBomb(Plant): + def __init__(self, x, y): + Plant.__init__(self, x, y, c.CHERRYBOMB, c.WALLNUT_HEALTH, None) + self.state = c.ATTACK + self.start_boom = False + self.bomb_timer = 0 + self.explode_y_range = 1 + self.explode_x_range = c.GRID_X_SIZE + + def setBoom(self): + frame = tool.GFX[c.CHERRY_BOOM_IMAGE] + rect = frame.get_rect() + width, height = rect.w, rect.h + + old_rect = self.rect + image = tool.get_image(frame, 0, 0, width, height, c.BLACK, 1) + self.image = image + self.rect = image.get_rect() + self.rect.centerx = old_rect.centerx + self.rect.centery = old_rect.centery + self.start_boom = True + + def animation(self): + if self.start_boom: + if self.bomb_timer == 0: + self.bomb_timer = self.current_time + elif(self.current_time - self.bomb_timer) > 500: + self.health = 0 + else: + if (self.current_time - self.animate_timer) > 100: + self.frame_index += 1 + if self.frame_index >= self.frame_num: + self.setBoom() + return + self.animate_timer = self.current_time + + self.image = self.frames[self.frame_index] + +class Chomper(Plant): + def __init__(self, x, y): + Plant.__init__(self, x, y, c.CHOMPER, c.PLANT_HEALTH, None) + self.animate_interval = 250 + self.digest_timer = 0 + self.digest_interval = 15000 + self.attack_zombie = None + self.zombie_group = None + + def loadImages(self, name, scale): + self.idle_frames = [] + self.attack_frames = [] + self.digest_frames = [] + + idle_name = name + attack_name = name + 'Attack' + digest_name = name + 'Digest' + + frame_list = [self.idle_frames, self.attack_frames, self.digest_frames] + name_list = [idle_name, attack_name, digest_name] + scale_list = [1, 1, 1] + rect_list = [(0, 0, 100, 114), None, None] + + for i, name in enumerate(name_list): + self.loadFrames(frame_list[i], name, scale_list[i]) + + self.frames = self.idle_frames + + def canAttack(self, zombie): + if (self.state == c.IDLE and zombie.state != c.DIGEST and + self.rect.x <= zombie.rect.right and + (self.rect.right + c.GRID_X_SIZE//3 >= zombie.rect.x)): + return True + return False + + def setIdle(self): + self.state = c.IDLE + self.changeFrames(self.idle_frames) + + def setAttack(self, zombie, zombie_group): + self.attack_zombie = zombie + self.zombie_group = zombie_group + self.state = c.ATTACK + self.changeFrames(self.attack_frames) + + def setDigest(self): + self.state = c.DIGEST + self.changeFrames(self.digest_frames) + + def attacking(self): + if self.frame_index == (self.frame_num - 3): + self.zombie_group.remove(self.attack_zombie) + if (self.frame_index + 1) == self.frame_num: + self.setDigest() + + def digest(self): + if self.digest_timer == 0: + self.digest_timer = self.current_time + elif (self.current_time - self.digest_timer) > self.digest_interval: + self.digest_timer = 0 + self.attack_zombie.kill() + self.setIdle() + +class PuffShroom(Plant): + def __init__(self, x, y, bullet_group): + Plant.__init__(self, x, y, c.PUFFSHROOM, c.PLANT_HEALTH, bullet_group) + self.can_sleep = True + self.shoot_timer = 0 + + def loadImages(self, name, scale): + self.idle_frames = [] + self.sleep_frames = [] + + idle_name = name + sleep_name = name + 'Sleep' + + frame_list = [self.idle_frames, self.sleep_frames] + name_list = [idle_name, sleep_name] + + for i, name in enumerate(name_list): + self.loadFrames(frame_list[i], name, 1) + + self.frames = self.idle_frames + + def attacking(self): + if (self.current_time - self.shoot_timer) > 3000: + self.bullet_group.add(Bullet(self.rect.right, self.rect.y + 10, self.rect.y + 10, + c.BULLET_MUSHROOM, c.BULLET_DAMAGE_NORMAL, True)) + self.shoot_timer = self.current_time + + def canAttack(self, zombie): + if (self.rect.x <= zombie.rect.right and + (self.rect.right + c.GRID_X_SIZE * 4 >= zombie.rect.x)): + return True + return False + +class PotatoMine(Plant): + def __init__(self, x, y): + Plant.__init__(self, x, y, c.POTATOMINE, c.PLANT_HEALTH, None) + self.animate_interval = 300 + self.is_init = True + self.init_timer = 0 + self.bomb_timer = 0 + self.explode_y_range = 0 + self.explode_x_range = c.GRID_X_SIZE//3 * 2 + + def loadImages(self, name, scale): + self.init_frames = [] + self.idle_frames = [] + self.explode_frames = [] + + init_name = name + 'Init' + idle_name = name + explode_name = name + 'Explode' + + frame_list = [self.init_frames, self.idle_frames, self.explode_frames] + name_list = [init_name, idle_name, explode_name] + + for i, name in enumerate(name_list): + self.loadFrames(frame_list[i], name, 1, c.WHITE) + + self.frames = self.init_frames + + def idling(self): + if self.is_init: + if self.init_timer == 0: + self.init_timer = self.current_time + elif (self.current_time - self.init_timer) > 15000: + self.changeFrames(self.idle_frames) + self.is_init = False + + def canAttack(self, zombie): + if (not self.is_init and zombie.rect.right >= self.rect.x and + (zombie.rect.x - self.rect.x) <= self.explode_x_range): + return True + return False + + def attacking(self): + if self.bomb_timer == 0: + self.bomb_timer = self.current_time + self.changeFrames(self.explode_frames) + elif (self.current_time - self.bomb_timer) > 500: + self.health = 0 + +class Squash(Plant): + def __init__(self, x, y): + Plant.__init__(self, x, y, c.SQUASH, c.PLANT_HEALTH, None) + self.orig_pos = (x, y) + self.aim_timer = 0 + self.squashing = False + + def loadImages(self, name, scale): + self.idle_frames = [] + self.aim_frames = [] + self.attack_frames = [] + + idle_name = name + aim_name = name + 'Aim' + attack_name = name + 'Attack' + + frame_list = [self.idle_frames, self.aim_frames, self.attack_frames] + name_list = [idle_name, aim_name, attack_name] + + for i, name in enumerate(name_list): + self.loadFrames(frame_list[i], name, 1, c.WHITE) + + self.frames = self.idle_frames + + def canAttack(self, zombie): + if (self.state == c.IDLE and self.rect.x <= zombie.rect.right and + (self.rect.right + c.GRID_X_SIZE >= zombie.rect.x)): + return True + return False + + def setAttack(self, zombie, zombie_group): + self.attack_zombie = zombie + self.zombie_group = zombie_group + self.state = c.ATTACK + + def attacking(self): + if self.squashing: + if self.frame_index == 2: + self.zombie_group.remove(self.attack_zombie) + if (self.frame_index + 1) == self.frame_num: + self.attack_zombie.kill() + self.health = 0 + elif self.aim_timer == 0: + self.aim_timer = self.current_time + self.changeFrames(self.aim_frames) + elif (self.current_time - self.aim_timer) > 1000: + self.changeFrames(self.attack_frames) + self.rect.centerx = self.attack_zombie.rect.centerx + self.squashing = True + self.animate_interval = 300 + + def getPosition(self): + return self.orig_pos + +class Spikeweed(Plant): + def __init__(self, x, y): + Plant.__init__(self, x, y, c.SPIKEWEED, c.PLANT_HEALTH, None) + self.animate_interval = 200 + self.attack_timer = 0 + + def loadImages(self, name, scale): + self.loadFrames(self.frames, name, 0.9, c.WHITE) + + def setIdle(self): + print('spikeweed idle') + self.animate_interval = 200 + self.state = c.IDLE + + def canAttack(self, zombie): + if (self.rect.x <= zombie.rect.right and + (self.rect.right >= zombie.rect.x)): + return True + return False + + def setAttack(self, zombie_group): + self.zombie_group = zombie_group + self.animate_interval = 50 + self.state = c.ATTACK + + def attacking(self): + if (self.current_time - self.attack_timer) > 2000: + self.attack_timer = self.current_time + for zombie in self.zombie_group: + if self.canAttack(zombie): + zombie.setDamage(1, False) + +class Jalapeno(Plant): + def __init__(self, x, y): + Plant.__init__(self, x, y, c.JALAPENO, c.PLANT_HEALTH, None) + self.orig_pos = (x, y) + self.state = c.ATTACK + self.start_explode = False + self.explode_y_range = 0 + self.explode_x_range = 377 + + def loadImages(self, name, scale): + self.explode_frames = [] + explode_name = name + 'Explode' + self.loadFrames(self.explode_frames, explode_name, 1, c.WHITE) + + self.loadFrames(self.frames, name, 1, c.WHITE) + + def setExplode(self): + self.changeFrames(self.explode_frames) + self.animate_timer = self.current_time + self.rect.x = c.MAP_OFFSET_X + self.start_explode = True + + def animation(self): + if self.start_explode: + if(self.current_time - self.animate_timer) > 100: + self.frame_index += 1 + if self.frame_index >= self.frame_num: + self.health = 0 + return + self.animate_timer = self.current_time + else: + if (self.current_time - self.animate_timer) > 100: + self.frame_index += 1 + if self.frame_index >= self.frame_num: + self.setExplode() + return + self.animate_timer = self.current_time + self.image = self.frames[self.frame_index] + + def getPosition(self): + return self.orig_pos + +class ScaredyShroom(Plant): + def __init__(self, x, y, bullet_group): + Plant.__init__(self, x, y, c.SCAREDYSHROOM, c.PLANT_HEALTH, bullet_group) + self.can_sleep = True + self.shoot_timer = 0 + self.cry_x_range = c.GRID_X_SIZE * 2 + + def loadImages(self, name, scale): + self.idle_frames = [] + self.cry_frames = [] + self.sleep_frames = [] + + idle_name = name + cry_name = name + 'Cry' + sleep_name = name + 'Sleep' + + frame_list = [self.idle_frames, self.cry_frames, self.sleep_frames] + name_list = [idle_name, cry_name, sleep_name] + + for i, name in enumerate(name_list): + self.loadFrames(frame_list[i], name, 1, c.WHITE) + + self.frames = self.idle_frames + + def needCry(self, zombie): + if (zombie.state != c.DIE and self.rect.x <= zombie.rect.right and + self.rect.x + self.cry_x_range > zombie.rect.x): + return True + return False + + def setCry(self): + self.state = c.CRY + self.changeFrames(self.cry_frames) + + def setAttack(self): + self.state = c.ATTACK + self.changeFrames(self.idle_frames) + + def setIdle(self): + self.state = c.IDLE + self.changeFrames(self.idle_frames) + + def attacking(self): + if (self.current_time - self.shoot_timer) > 2000: + self.bullet_group.add(Bullet(self.rect.right, self.rect.y + 40, self.rect.y + 40, + c.BULLET_MUSHROOM, c.BULLET_DAMAGE_NORMAL, True)) + self.shoot_timer = self.current_time + +class SunShroom(Plant): + def __init__(self, x, y, sun_group): + Plant.__init__(self, x, y, c.SUNSHROOM, c.PLANT_HEALTH, None) + self.can_sleep = True + self.animate_interval = 200 + self.sun_timer = 0 + self.sun_group = sun_group + self.is_big = False + self.change_timer = 0 + + def loadImages(self, name, scale): + self.idle_frames = [] + self.big_frames = [] + self.sleep_frames = [] + + idle_name = name + big_name = name + 'Big' + sleep_name = name + 'Sleep' + + frame_list = [self.idle_frames, self.big_frames, self.sleep_frames] + name_list = [idle_name, big_name, sleep_name] + + for i, name in enumerate(name_list): + self.loadFrames(frame_list[i], name, 1, c.WHITE) + + self.frames = self.idle_frames + + def idling(self): + if not self.is_big: + if self.change_timer == 0: + self.change_timer = self.current_time + elif (self.current_time - self.change_timer) > 25000: + self.changeFrames(self.big_frames) + self.is_big = True + + if self.sun_timer == 0: + self.sun_timer = self.current_time - (c.FLOWER_SUN_INTERVAL - 6000) + elif (self.current_time - self.sun_timer) > c.FLOWER_SUN_INTERVAL: + self.sun_group.add(Sun(self.rect.centerx, self.rect.bottom, self.rect.right, + self.rect.bottom + self.rect.h // 2, self.is_big)) + self.sun_timer = self.current_time + +class IceShroom(Plant): + def __init__(self, x, y): + Plant.__init__(self, x, y, c.ICESHROOM, c.PLANT_HEALTH, None) + self.can_sleep = True + self.orig_pos = (x, y) + self.start_freeze = False + + def loadImages(self, name, scale): + self.idle_frames = [] + self.snow_frames = [] + self.sleep_frames = [] + self.trap_frames = [] + + idle_name = name + snow_name = name + 'Snow' + sleep_name = name + 'Sleep' + trap_name = name + 'Trap' + + frame_list = [self.idle_frames, self.snow_frames, self.sleep_frames, self.trap_frames] + name_list = [idle_name, snow_name, sleep_name, trap_name] + scale_list = [1, 1.5, 1, 1] + + for i, name in enumerate(name_list): + self.loadFrames(frame_list[i], name, scale_list[i], c.WHITE) + + self.frames = self.idle_frames + + def setFreeze(self): + self.changeFrames(self.snow_frames) + self.animate_timer = self.current_time + self.rect.x = c.MAP_OFFSET_X + self.rect.y = c.MAP_OFFSET_Y + self.start_freeze = True + + def animation(self): + if self.start_freeze: + if(self.current_time - self.animate_timer) > 500: + self.frame_index += 1 + if self.frame_index >= self.frame_num: + self.health = 0 + return + self.animate_timer = self.current_time + else: + if (self.current_time - self.animate_timer) > 100: + self.frame_index += 1 + if self.frame_index >= self.frame_num: + if self.state == c.SLEEP: + self.frame_index = 0 + else: + self.setFreeze() + return + self.animate_timer = self.current_time + self.image = self.frames[self.frame_index] + + def getPosition(self): + return self.orig_pos + +class HypnoShroom(Plant): + def __init__(self, x, y): + Plant.__init__(self, x, y, c.HYPNOSHROOM, 1, None) + self.can_sleep = True + self.animate_interval = 200 + + def loadImages(self, name, scale): + self.idle_frames = [] + self.sleep_frames = [] + + idle_name = name + sleep_name = name + 'Sleep' + + frame_list = [self.idle_frames, self.sleep_frames] + name_list = [idle_name, sleep_name] + + for i, name in enumerate(name_list): + self.loadFrames(frame_list[i], name, 1, c.WHITE) + + self.frames = self.idle_frames + +class WallNutBowling(Plant): + def __init__(self, x, y, map_y, level): + Plant.__init__(self, x, y, c.WALLNUTBOWLING, 1, None) + self.map_y = map_y + self.level = level + self.init_rect = self.rect.copy() + self.rotate_degree = 0 + self.animate_interval = 200 + self.move_timer = 0 + self.move_interval = 70 + self.vel_x = random.randint(12, 15) + self.vel_y = 0 + self.disable_hit_y = -1 + + def loadImages(self, name, scale): + self.loadFrames(self.frames, name, 1, c.WHITE) + + def idling(self): + if self.move_timer == 0: + self.move_timer = self.current_time + elif (self.current_time - self.move_timer) >= self.move_interval: + self.rotate_degree = (self.rotate_degree - 30) % 360 + self.init_rect.x += self.vel_x + self.init_rect.y += self.vel_y + self.handleMapYPosition() + if self.shouldChangeDirection(): + self.changeDirection(-1) + if self.init_rect.x > c.SCREEN_WIDTH: + self.health = 0 + self.move_timer += self.move_interval + + def canHit(self, map_y): + if self.disable_hit_y == map_y: + return False + return True + + def handleMapYPosition(self): + _, map_y1 = self.level.map.getMapIndex(self.init_rect.x, self.init_rect.centery) + _, map_y2 = self.level.map.getMapIndex(self.init_rect.x, self.init_rect.bottom) + if self.map_y != map_y1 and map_y1 == map_y2: + # wallnut bowls to another row, should modify which plant group it belongs to + self.level.plant_groups[self.map_y].remove(self) + self.level.plant_groups[map_y1].add(self) + self.map_y = map_y1 + + def shouldChangeDirection(self): + if self.init_rect.centery <= c.MAP_OFFSET_Y: + return True + elif self.init_rect.bottom + 20 >= c.SCREEN_HEIGHT: + return True + return False + + def changeDirection(self, map_y): + if self.vel_y == 0: + if self.map_y == 0: + direc = 1 + elif self.map_y == (c.GRID_Y_LEN-1): + direc = -1 + else: + if random.randint(0, 1) == 0: + direc = 1 + else: + direc = -1 + self.vel_y = self.vel_x * direc + else: + self.vel_y = - self.vel_y + + self.disable_hit_y = map_y + + def animation(self): + if (self.current_time - self.animate_timer) > self.animate_interval: + self.frame_index += 1 + if self.frame_index >= self.frame_num: + self.frame_index = 0 + self.animate_timer = self.current_time + + image = self.frames[self.frame_index] + self.image = pg.transform.rotate(image, self.rotate_degree) + # must keep the center postion of image when rotate + self.rect = self.image.get_rect(center=self.init_rect.center) + +class RedWallNutBowling(Plant): + def __init__(self, x, y): + Plant.__init__(self, x, y, c.REDWALLNUTBOWLING, 1, None) + self.orig_y = y + self.explode_timer = 0 + self.explode_y_range = 1 + self.explode_x_range = c.GRID_X_SIZE + self.init_rect = self.rect.copy() + self.rotate_degree = 0 + self.animate_interval = 200 + self.move_timer = 0 + self.move_interval = 70 + self.vel_x = random.randint(12, 15) + + def loadImages(self, name, scale): + self.idle_frames = [] + self.explode_frames = [] + + idle_name = name + explode_name = name + 'Explode' + + frame_list = [self.idle_frames, self.explode_frames] + name_list = [idle_name, explode_name] + + for i, name in enumerate(name_list): + self.loadFrames(frame_list[i], name, 1, c.WHITE) + + self.frames = self.idle_frames + + def idling(self): + if self.move_timer == 0: + self.move_timer = self.current_time + elif (self.current_time - self.move_timer) >= self.move_interval: + self.rotate_degree = (self.rotate_degree - 30) % 360 + self.init_rect.x += self.vel_x + if self.init_rect.x > c.SCREEN_WIDTH: + self.health = 0 + self.move_timer += self.move_interval + + def attacking(self): + if self.explode_timer == 0: + self.explode_timer = self.current_time + self.changeFrames(self.explode_frames) + elif (self.current_time - self.explode_timer) > 500: + self.health = 0 + + def animation(self): + if (self.current_time - self.animate_timer) > self.animate_interval: + self.frame_index += 1 + if self.frame_index >= self.frame_num: + self.frame_index = 0 + self.animate_timer = self.current_time + + image = self.frames[self.frame_index] + if self.state == c.IDLE: + self.image = pg.transform.rotate(image, self.rotate_degree) + else: + self.image = image + # must keep the center postion of image when rotate + self.rect = self.image.get_rect(center=self.init_rect.center) + + def getPosition(self): + return (self.rect.centerx, self.orig_y) \ No newline at end of file diff --git a/source/component/zombie.py b/source/component/zombie.py new file mode 100644 index 0000000..73780f1 --- /dev/null +++ b/source/component/zombie.py @@ -0,0 +1,414 @@ +__author__ = 'marble_xu' + +import pygame as pg +from .. import tool +from .. import constants as c + +class Zombie(pg.sprite.Sprite): + def __init__(self, x, y, name, health, head_group=None, damage=1): + pg.sprite.Sprite.__init__(self) + + self.name = name + self.frames = [] + self.frame_index = 0 + self.loadImages() + self.frame_num = len(self.frames) + + self.image = self.frames[self.frame_index] + self.rect = self.image.get_rect() + self.rect.centerx = x + self.rect.bottom = y + + self.health = health + self.damage = damage + self.dead = False + self.losHead = False + self.helmet = False + self.head_group = head_group + + self.walk_timer = 0 + self.animate_timer = 0 + self.attack_timer = 0 + self.state = c.WALK + self.animate_interval = 150 + self.ice_slow_ratio = 1 + self.ice_slow_timer = 0 + self.hit_timer = 0 + self.speed = 1 + self.freeze_timer = 0 + self.is_hypno = False # the zombie is hypo and attack other zombies when it ate a HypnoShroom + + def loadFrames(self, frames, name, image_x, colorkey=c.BLACK): + frame_list = tool.GFX[name] + rect = frame_list[0].get_rect() + width, height = rect.w, rect.h + width -= image_x + + for frame in frame_list: + frames.append(tool.get_image(frame, image_x, 0, width, height, colorkey)) + + def update(self, game_info): + self.current_time = game_info[c.CURRENT_TIME] + self.handleState() + self.updateIceSlow() + self.animation() + + def handleState(self): + if self.state == c.WALK: + self.walking() + elif self.state == c.ATTACK: + self.attacking() + elif self.state == c.DIE: + self.dying() + elif self.state == c.FREEZE: + self.freezing() + + def walking(self): + if self.health <= 0: + self.setDie() + elif self.health <= c.LOSTHEAD_HEALTH and not self.losHead: + self.changeFrames(self.losthead_walk_frames) + self.setLostHead() + elif self.health <= c.NORMAL_HEALTH and self.helmet: + self.changeFrames(self.walk_frames) + self.helmet = False + if self.name == c.NEWSPAPER_ZOMBIE: + self.speed = 2 + + if (self.current_time - self.walk_timer) > (c.ZOMBIE_WALK_INTERVAL * self.getTimeRatio()): + self.walk_timer = self.current_time + if self.is_hypno: + self.rect.x += self.speed + else: + self.rect.x -= self.speed + + def attacking(self): + if self.health <= 0: + self.setDie() + elif self.health <= c.LOSTHEAD_HEALTH and not self.losHead: + self.changeFrames(self.losthead_attack_frames) + self.setLostHead() + elif self.health <= c.NORMAL_HEALTH and self.helmet: + self.changeFrames(self.attack_frames) + self.helmet = False + if (self.current_time - self.attack_timer) > (c.ATTACK_INTERVAL * self.getTimeRatio()): + if self.prey.health > 0: + if self.prey_is_plant: + self.prey.setDamage(self.damage, self) + else: + self.prey.setDamage(self.damage) + self.attack_timer = self.current_time + + if self.prey.health <= 0: + self.prey = None + self.setWalk() + + def dying(self): + pass + + def freezing(self): + if self.health <= 0: + self.setDie() + elif self.health <= c.LOSTHEAD_HEALTH and not self.losHead: + if self.old_state == c.WALK: + self.changeFrames(self.losthead_walk_frames) + else: + self.changeFrames(self.losthead_attack_frames) + self.setLostHead() + if (self.current_time - self.freeze_timer) > c.FREEZE_TIME: + self.setWalk() + + def setLostHead(self): + self.losHead = True + if self.head_group is not None: + self.head_group.add(ZombieHead(self.rect.centerx, self.rect.bottom)) + + def changeFrames(self, frames): + '''change image frames and modify rect position''' + self.frames = frames + self.frame_num = len(self.frames) + self.frame_index = 0 + + bottom = self.rect.bottom + centerx = self.rect.centerx + self.image = self.frames[self.frame_index] + self.rect = self.image.get_rect() + self.rect.bottom = bottom + self.rect.centerx = centerx + + def animation(self): + if self.state == c.FREEZE: + self.image.set_alpha(192) + return + + if (self.current_time - self.animate_timer) > (self.animate_interval * self.getTimeRatio()): + self.frame_index += 1 + if self.frame_index >= self.frame_num: + if self.state == c.DIE: + self.kill() + return + self.frame_index = 0 + self.animate_timer = self.current_time + + self.image = self.frames[self.frame_index] + if self.is_hypno: + self.image = pg.transform.flip(self.image, True, False) + if(self.current_time - self.hit_timer) >= 200: + self.image.set_alpha(255) + else: + self.image.set_alpha(192) + + def getTimeRatio(self): + return self.ice_slow_ratio + + def setIceSlow(self): + '''when get a ice bullet damage, slow the attack or walk speed of the zombie''' + self.ice_slow_timer = self.current_time + self.ice_slow_ratio = 2 + + def updateIceSlow(self): + if self.ice_slow_ratio > 1: + if (self.current_time - self.ice_slow_timer) > c.ICE_SLOW_TIME: + self.ice_slow_ratio = 1 + + def setDamage(self, damage, ice=False): + self.health -= damage + self.hit_timer = self.current_time + if ice: + self.setIceSlow() + + def setWalk(self): + self.state = c.WALK + self.animate_interval = 150 + + if self.helmet: + self.changeFrames(self.helmet_walk_frames) + elif self.losHead: + self.changeFrames(self.losthead_walk_frames) + else: + self.changeFrames(self.walk_frames) + + def setAttack(self, prey, is_plant=True): + self.prey = prey # prey can be plant or other zombies + self.prey_is_plant = is_plant + self.state = c.ATTACK + self.attack_timer = self.current_time + self.animate_interval = 100 + + if self.helmet: + self.changeFrames(self.helmet_attack_frames) + elif self.losHead: + self.changeFrames(self.losthead_attack_frames) + else: + self.changeFrames(self.attack_frames) + + def setDie(self): + self.state = c.DIE + self.animate_interval = 200 + self.changeFrames(self.die_frames) + + def setBoomDie(self): + self.state = c.DIE + self.animate_interval = 200 + self.changeFrames(self.boomdie_frames) + + def setFreeze(self, ice_trap_image): + self.old_state = self.state + self.state = c.FREEZE + self.freeze_timer = self.current_time + self.ice_trap_image = ice_trap_image + self.ice_trap_rect = ice_trap_image.get_rect() + self.ice_trap_rect.centerx = self.rect.centerx + self.ice_trap_rect.bottom = self.rect.bottom + + def drawFreezeTrap(self, surface): + if self.state == c.FREEZE: + surface.blit(self.ice_trap_image, self.ice_trap_rect) + + def setHypno(self): + self.is_hypno = True + self.setWalk() + +class ZombieHead(Zombie): + def __init__(self, x, y): + Zombie.__init__(self, x, y, c.ZOMBIE_HEAD, 0) + self.state = c.DIE + + def loadImages(self): + self.die_frames = [] + die_name = self.name + self.loadFrames(self.die_frames, die_name, 0) + self.frames = self.die_frames + + def setWalk(self): + self.animate_interval = 100 + +class NormalZombie(Zombie): + def __init__(self, x, y, head_group): + Zombie.__init__(self, x, y, c.NORMAL_ZOMBIE, c.NORMAL_HEALTH, head_group) + + def loadImages(self): + self.walk_frames = [] + self.attack_frames = [] + self.losthead_walk_frames = [] + self.losthead_attack_frames = [] + self.die_frames = [] + self.boomdie_frames = [] + + walk_name = self.name + attack_name = self.name + 'Attack' + losthead_walk_name = self.name + 'LostHead' + losthead_attack_name = self.name + 'LostHeadAttack' + die_name = self.name + 'Die' + boomdie_name = c.BOOMDIE + + frame_list = [self.walk_frames, self.attack_frames, self.losthead_walk_frames, + self.losthead_attack_frames, self.die_frames, self.boomdie_frames] + name_list = [walk_name, attack_name, losthead_walk_name, + losthead_attack_name, die_name, boomdie_name] + + for i, name in enumerate(name_list): + self.loadFrames(frame_list[i], name, tool.ZOMBIE_RECT[name]['x']) + + self.frames = self.walk_frames + +class ConeHeadZombie(Zombie): + def __init__(self, x, y, head_group): + Zombie.__init__(self, x, y, c.CONEHEAD_ZOMBIE, c.CONEHEAD_HEALTH, head_group) + self.helmet = True + + def loadImages(self): + self.helmet_walk_frames = [] + self.helmet_attack_frames = [] + self.walk_frames = [] + self.attack_frames = [] + self.losthead_walk_frames = [] + self.losthead_attack_frames = [] + self.die_frames = [] + self.boomdie_frames = [] + + helmet_walk_name = self.name + helmet_attack_name = self.name + 'Attack' + walk_name = c.NORMAL_ZOMBIE + attack_name = c.NORMAL_ZOMBIE + 'Attack' + losthead_walk_name = c.NORMAL_ZOMBIE + 'LostHead' + losthead_attack_name = c.NORMAL_ZOMBIE + 'LostHeadAttack' + die_name = c.NORMAL_ZOMBIE + 'Die' + boomdie_name = c.BOOMDIE + + frame_list = [self.helmet_walk_frames, self.helmet_attack_frames, + self.walk_frames, self.attack_frames, self.losthead_walk_frames, + self.losthead_attack_frames, self.die_frames, self.boomdie_frames] + name_list = [helmet_walk_name, helmet_attack_name, + walk_name, attack_name, losthead_walk_name, + losthead_attack_name, die_name, boomdie_name] + + for i, name in enumerate(name_list): + self.loadFrames(frame_list[i], name, tool.ZOMBIE_RECT[name]['x']) + + self.frames = self.helmet_walk_frames + +class BucketHeadZombie(Zombie): + def __init__(self, x, y, head_group): + Zombie.__init__(self, x, y, c.BUCKETHEAD_ZOMBIE, c.BUCKETHEAD_HEALTH, head_group) + self.helmet = True + + def loadImages(self): + self.helmet_walk_frames = [] + self.helmet_attack_frames = [] + self.walk_frames = [] + self.attack_frames = [] + self.losthead_walk_frames = [] + self.losthead_attack_frames = [] + self.die_frames = [] + self.boomdie_frames = [] + + helmet_walk_name = self.name + helmet_attack_name = self.name + 'Attack' + walk_name = c.NORMAL_ZOMBIE + attack_name = c.NORMAL_ZOMBIE + 'Attack' + losthead_walk_name = c.NORMAL_ZOMBIE + 'LostHead' + losthead_attack_name = c.NORMAL_ZOMBIE + 'LostHeadAttack' + die_name = c.NORMAL_ZOMBIE + 'Die' + boomdie_name = c.BOOMDIE + + frame_list = [self.helmet_walk_frames, self.helmet_attack_frames, + self.walk_frames, self.attack_frames, self.losthead_walk_frames, + self.losthead_attack_frames, self.die_frames, self.boomdie_frames] + name_list = [helmet_walk_name, helmet_attack_name, + walk_name, attack_name, losthead_walk_name, + losthead_attack_name, die_name, boomdie_name] + + for i, name in enumerate(name_list): + self.loadFrames(frame_list[i], name, tool.ZOMBIE_RECT[name]['x']) + + self.frames = self.helmet_walk_frames + +class FlagZombie(Zombie): + def __init__(self, x, y, head_group): + Zombie.__init__(self, x, y, c.FLAG_ZOMBIE, c.FLAG_HEALTH, head_group) + + def loadImages(self): + self.walk_frames = [] + self.attack_frames = [] + self.losthead_walk_frames = [] + self.losthead_attack_frames = [] + self.die_frames = [] + self.boomdie_frames = [] + + walk_name = self.name + attack_name = self.name + 'Attack' + losthead_walk_name = self.name + 'LostHead' + losthead_attack_name = self.name + 'LostHeadAttack' + die_name = c.NORMAL_ZOMBIE + 'Die' + boomdie_name = c.BOOMDIE + + frame_list = [self.walk_frames, self.attack_frames, self.losthead_walk_frames, + self.losthead_attack_frames, self.die_frames, self.boomdie_frames] + name_list = [walk_name, attack_name, losthead_walk_name, + losthead_attack_name, die_name, boomdie_name] + + for i, name in enumerate(name_list): + self.loadFrames(frame_list[i], name, tool.ZOMBIE_RECT[name]['x']) + + self.frames = self.walk_frames + +class NewspaperZombie(Zombie): + def __init__(self, x, y, head_group): + Zombie.__init__(self, x, y, c.NEWSPAPER_ZOMBIE, c.NEWSPAPER_HEALTH, head_group) + self.helmet = True + + def loadImages(self): + self.helmet_walk_frames = [] + self.helmet_attack_frames = [] + self.walk_frames = [] + self.attack_frames = [] + self.losthead_walk_frames = [] + self.losthead_attack_frames = [] + self.die_frames = [] + self.boomdie_frames = [] + + helmet_walk_name = self.name + helmet_attack_name = self.name + 'Attack' + walk_name = self.name + 'NoPaper' + attack_name = self.name + 'NoPaperAttack' + losthead_walk_name = self.name + 'LostHead' + losthead_attack_name = self.name + 'LostHeadAttack' + die_name = self.name + 'Die' + boomdie_name = c.BOOMDIE + + frame_list = [self.helmet_walk_frames, self.helmet_attack_frames, + self.walk_frames, self.attack_frames, self.losthead_walk_frames, + self.losthead_attack_frames, self.die_frames, self.boomdie_frames] + name_list = [helmet_walk_name, helmet_attack_name, + walk_name, attack_name, losthead_walk_name, + losthead_attack_name, die_name, boomdie_name] + + for i, name in enumerate(name_list): + if name == c.BOOMDIE: + color = c.BLACK + else: + color = c.WHITE + self.loadFrames(frame_list[i], name, tool.ZOMBIE_RECT[name]['x'], color) + + self.frames = self.helmet_walk_frames \ No newline at end of file diff --git a/source/constants.py b/source/constants.py new file mode 100644 index 0000000..0c4e2b6 --- /dev/null +++ b/source/constants.py @@ -0,0 +1,180 @@ +__author__ = 'marble_xu' + +START_LEVEL_NUM = 1 + +ORIGINAL_CAPTION = 'Plant VS Zombies Game' + +SCREEN_WIDTH = 800 +SCREEN_HEIGHT = 600 +SCREEN_SIZE = (SCREEN_WIDTH, SCREEN_HEIGHT) + +GRID_X_LEN = 9 +GRID_Y_LEN = 5 +GRID_X_SIZE = 80 +GRID_Y_SIZE = 100 + + +WHITE = (255, 255, 255) +NAVYBLUE = ( 60, 60, 100) +SKY_BLUE = ( 39, 145, 251) +BLACK = ( 0, 0, 0) +LIGHTYELLOW = (234, 233, 171) +RED = (255, 0, 0) +PURPLE = (255, 0, 255) +GOLD = (255, 215, 0) +GREEN = ( 0, 255, 0) + +SIZE_MULTIPLIER = 1.3 + +#GAME INFO DICTIONARY KEYS +CURRENT_TIME = 'current time' +LEVEL_NUM = 'level num' + +#STATES FOR ENTIRE GAME +MAIN_MENU = 'main menu' +LOAD_SCREEN = 'load screen' +GAME_LOSE = 'game los' +GAME_VICTORY = 'game victory' +LEVEL = 'level' + +MAIN_MENU_IMAGE = 'MainMenu' +OPTION_ADVENTURE = 'Adventure' +GAME_LOOSE_IMAGE = 'GameLoose' +GAME_VICTORY_IMAGE = 'GameVictory' + +#MAP COMPONENTS +BACKGROUND_NAME = 'Background' +BACKGROUND_TYPE = 'background_type' +INIT_SUN_NAME = 'init_sun_value' +ZOMBIE_LIST = 'zombie_list' + +MAP_EMPTY = 0 +MAP_EXIST = 1 + +BACKGROUND_OFFSET_X = 220 +MAP_OFFSET_X = 35 +MAP_OFFSET_Y = 100 + +#MENUBAR +CHOOSEBAR_TYPE = 'choosebar_type' +CHOOSEBAR_STATIC = 0 +CHOOSEBAR_MOVE = 1 +CHOSSEBAR_BOWLING = 2 +MENUBAR_BACKGROUND = 'ChooserBackground' +MOVEBAR_BACKGROUND = 'MoveBackground' +PANEL_BACKGROUND = 'PanelBackground' +START_BUTTON = 'StartButton' +CARD_POOL = 'card_pool' + +MOVEBAR_CARD_FRESH_TIME = 6000 +CARD_MOVE_TIME = 60 + +#PLANT INFO +PLANT_IMAGE_RECT = 'plant_image_rect' +CAR = 'car' +SUN = 'Sun' +SUNFLOWER = 'SunFlower' +PEASHOOTER = 'Peashooter' +SNOWPEASHOOTER = 'SnowPea' +WALLNUT = 'WallNut' +CHERRYBOMB = 'CherryBomb' +THREEPEASHOOTER = 'Threepeater' +REPEATERPEA = 'RepeaterPea' +CHOMPER = 'Chomper' +CHERRY_BOOM_IMAGE = 'Boom' +PUFFSHROOM = 'PuffShroom' +POTATOMINE = 'PotatoMine' +SQUASH = 'Squash' +SPIKEWEED = 'Spikeweed' +JALAPENO = 'Jalapeno' +SCAREDYSHROOM = 'ScaredyShroom' +SUNSHROOM = 'SunShroom' +ICESHROOM = 'IceShroom' +HYPNOSHROOM = 'HypnoShroom' +WALLNUTBOWLING = 'WallNutBowling' +REDWALLNUTBOWLING = 'RedWallNutBowling' + +PLANT_HEALTH = 5 +WALLNUT_HEALTH = 30 +WALLNUT_CRACKED1_HEALTH = 20 +WALLNUT_CRACKED2_HEALTH = 10 +WALLNUT_BOWLING_DAMAGE = 10 + +PRODUCE_SUN_INTERVAL = 7000 +FLOWER_SUN_INTERVAL = 22000 +SUN_LIVE_TIME = 7000 +SUN_VALUE = 25 + +ICE_SLOW_TIME = 2000 + +FREEZE_TIME = 7500 +ICETRAP = 'IceTrap' + +#PLANT CARD INFO +CARD_SUNFLOWER = 'card_sunflower' +CARD_PEASHOOTER = 'card_peashooter' +CARD_SNOWPEASHOOTER = 'card_snowpea' +CARD_WALLNUT = 'card_wallnut' +CARD_CHERRYBOMB = 'card_cherrybomb' +CARD_THREEPEASHOOTER = 'card_threepeashooter' +CARD_REPEATERPEA = 'card_repeaterpea' +CARD_CHOMPER = 'card_chomper' +CARD_PUFFSHROOM = 'card_puffshroom' +CARD_POTATOMINE = 'card_potatomine' +CARD_SQUASH = 'card_squash' +CARD_SPIKEWEED = 'card_spikeweed' +CARD_JALAPENO = 'card_jalapeno' +CARD_SCAREDYSHROOM = 'card_scaredyshroom' +CARD_SUNSHROOM = 'card_sunshroom' +CARD_ICESHROOM = 'card_iceshroom' +CARD_HYPNOSHROOM = 'card_hypnoshroom' +CARD_REDWALLNUT = 'card_redwallnut' + +#BULLET INFO +BULLET_PEA = 'PeaNormal' +BULLET_PEA_ICE = 'PeaIce' +BULLET_MUSHROOM = 'BulletMushRoom' +BULLET_DAMAGE_NORMAL = 1 + +#ZOMBIE INFO +ZOMBIE_IMAGE_RECT = 'zombie_image_rect' +ZOMBIE_HEAD = 'ZombieHead' +NORMAL_ZOMBIE = 'Zombie' +CONEHEAD_ZOMBIE = 'ConeheadZombie' +BUCKETHEAD_ZOMBIE = 'BucketheadZombie' +FLAG_ZOMBIE = 'FlagZombie' +NEWSPAPER_ZOMBIE = 'NewspaperZombie' +BOOMDIE = 'BoomDie' + +LOSTHEAD_HEALTH = 5 +NORMAL_HEALTH = 10 +FLAG_HEALTH = 15 +CONEHEAD_HEALTH = 20 +BUCKETHEAD_HEALTH = 30 +NEWSPAPER_HEALTH = 15 + +ATTACK_INTERVAL = 1000 +ZOMBIE_WALK_INTERVAL = 70 + +ZOMBIE_START_X = SCREEN_WIDTH + 50 + +#STATE +IDLE = 'idle' +FLY = 'fly' +EXPLODE = 'explode' +ATTACK = 'attack' +ATTACKED = 'attacked' +DIGEST = 'digest' +WALK = 'walk' +DIE = 'die' +CRY = 'cry' +FREEZE = 'freeze' +SLEEP = 'sleep' + +#LEVEL STATE +CHOOSE = 'choose' +PLAY = 'play' + +#BACKGROUND +BACKGROUND_DAY = 0 +BACKGROUND_NIGHT = 1 \ No newline at end of file diff --git a/source/data/entity/plant.json b/source/data/entity/plant.json new file mode 100644 index 0000000..a790f7c --- /dev/null +++ b/source/data/entity/plant.json @@ -0,0 +1,14 @@ +{ + "plant_image_rect":{ + "PeaNormal":{"x":28, "y":0, "width":28, "height":34}, + "PeaIce":{"x":26, "y":0, "width":30, "height":34}, + "Chomper":{"x":0, "y":0, "width":100, "height":114}, + "PuffShroom":{"x":0, "y":28, "width":35, "height":38}, + "PuffShroomSleep":{"x":1, "y":0, "width":39, "height":65}, + "BulletMushRoom":{"x":0, "y":1, "width":55, "height":21}, + "PotatoMine":{"x":0, "y":0, "width":75, "height":55}, + "Squash":{"x":10, "y":140, "width":80, "height":86}, + "SquashAim":{"x":10, "y":140, "width":80, "height":86}, + "Spikeweed":{"x":3, "y":0, "width":80, "height":35} + } +} \ No newline at end of file diff --git a/source/data/entity/zombie.json b/source/data/entity/zombie.json new file mode 100644 index 0000000..bbc81fb --- /dev/null +++ b/source/data/entity/zombie.json @@ -0,0 +1,25 @@ +{ + "zombie_image_rect":{ + "Zombie":{"x":62, "width":90}, + "ZombieAttack":{"x":62, "width":90}, + "ZombieLostHead":{"x":62, "width":90}, + "ZombieLostHeadAttack":{"x":62, "width":90}, + "ZombieDie":{"x":0, "width":164}, + "BoomDie":{"x":68, "width":80}, + "ConeheadZombie":{"x":80, "width":80}, + "ConeheadZombieAttack":{"x":79, "width":87}, + "BucketheadZombie":{"x":54, "width":90}, + "BucketheadZombieAttack":{"x":46, "width":90}, + "FlagZombie":{"x":56, "width":110}, + "FlagZombieAttack":{"x":60, "width":100}, + "FlagZombieLostHead":{"x":55, "width":110}, + "FlagZombieLostHeadAttack":{"x":55, "width":110}, + "NewspaperZombie":{"x":48, "width":92}, + "NewspaperZombieAttack":{"x":48, "width":92}, + "NewspaperZombieNoPaper":{"x":40, "width":98}, + "NewspaperZombieNoPaperAttack":{"x":48, "width":92}, + "NewspaperZombieLostHead":{"x":44, "width":96}, + "NewspaperZombieLostHeadAttack":{"x":48, "width":92}, + "NewspaperZombieDie":{"x":0, "width":100} + } +} \ No newline at end of file diff --git a/source/data/map/level_0.json b/source/data/map/level_0.json new file mode 100644 index 0000000..c22fd75 --- /dev/null +++ b/source/data/map/level_0.json @@ -0,0 +1,7 @@ +{ + "background_type":0, + "init_sun_value":500, + "zombie_list":[ + {"time":1000, "map_y":2, "name":"Zombie"} + ] +} \ No newline at end of file diff --git a/source/data/map/level_1.json b/source/data/map/level_1.json new file mode 100644 index 0000000..59801a4 --- /dev/null +++ b/source/data/map/level_1.json @@ -0,0 +1,19 @@ +{ + "background_type":0, + "init_sun_value":50, + "zombie_list":[ + {"time":20000, "map_y":0, "name":"Zombie"}, + {"time":40000, "map_y":2, "name":"FlagZombie"}, + {"time":50000, "map_y":4, "name":"Zombie"}, + {"time":70000, "map_y":3, "name":"Zombie"}, + {"time":72000, "map_y":1, "name":"FlagZombie"}, + {"time":74000, "map_y":2, "name":"Zombie"}, + {"time":90000, "map_y":0, "name":"Zombie"}, + {"time":91000, "map_y":1, "name":"FlagZombie"}, + {"time":92000, "map_y":2, "name":"Zombie"}, + {"time":93000, "map_y":3, "name":"FlagZombie"}, + {"time":94000, "map_y":0, "name":"Zombie"}, + {"time":95000, "map_y":4, "name":"FlagZombie"}, + {"time":96000, "map_y":1, "name":"Zombie"} + ] +} \ No newline at end of file diff --git a/source/data/map/level_2.json b/source/data/map/level_2.json new file mode 100644 index 0000000..b3d9170 --- /dev/null +++ b/source/data/map/level_2.json @@ -0,0 +1,19 @@ +{ + "background_type":0, + "init_sun_value":50, + "zombie_list":[ + {"time":20000, "map_y":0, "name":"Zombie"}, + {"time":40000, "map_y":2, "name":"FlagZombie"}, + {"time":50000, "map_y":4, "name":"ConeheadZombie"}, + {"time":70000, "map_y":3, "name":"ConeheadZombie"}, + {"time":72000, "map_y":1, "name":"FlagZombie"}, + {"time":74000, "map_y":2, "name":"ConeheadZombie"}, + {"time":90000, "map_y":0, "name":"FlagZombie"}, + {"time":91000, "map_y":1, "name":"ConeheadZombie"}, + {"time":92000, "map_y":2, "name":"Zombie"}, + {"time":93000, "map_y":3, "name":"ConeheadZombie"}, + {"time":94000, "map_y":0, "name":"Zombie"}, + {"time":95000, "map_y":4, "name":"FlagZombie"}, + {"time":96000, "map_y":1, "name":"ConeheadZombie"} + ] +} \ No newline at end of file diff --git a/source/data/map/level_3.json b/source/data/map/level_3.json new file mode 100644 index 0000000..04ad595 --- /dev/null +++ b/source/data/map/level_3.json @@ -0,0 +1,20 @@ +{ + "background_type":1, + "init_sun_value":50, + "zombie_list":[ + {"time":20000, "map_y":0, "name":"Zombie"}, + {"time":40000, "map_y":2, "name":"ConeheadZombie"}, + {"time":50000, "map_y":4, "name":"BucketheadZombie"}, + {"time":70000, "map_y":3, "name":"BucketheadZombie"}, + {"time":72000, "map_y":1, "name":"FlagZombie"}, + {"time":74000, "map_y":2, "name":"ConeheadZombie"}, + {"time":90000, "map_y":0, "name":"BucketheadZombie"}, + {"time":91000, "map_y":1, "name":"ConeheadZombie"}, + {"time":92000, "map_y":2, "name":"Zombie"}, + {"time":93000, "map_y":3, "name":"BucketheadZombie"}, + {"time":94000, "map_y":0, "name":"Zombie"}, + {"time":95000, "map_y":4, "name":"FlagZombie"}, + {"time":96000, "map_y":1, "name":"BucketheadZombie"}, + {"time":97000, "map_y":1, "name":"FlagZombie"} + ] +} diff --git a/source/data/map/level_4.json b/source/data/map/level_4.json new file mode 100644 index 0000000..aaa525b --- /dev/null +++ b/source/data/map/level_4.json @@ -0,0 +1,41 @@ +{ + "background_type":0, + "choosebar_type":1, + "card_pool":[ + {"name":"Peashooter"}, + {"name":"SnowPea"}, + {"name":"WallNut"}, + {"name":"CherryBomb"}, + {"name":"RepeaterPea"}, + {"name":"Chomper"}, + {"name":"PotatoMine"} + ], + "zombie_list":[ + {"time": 1000, "map_y":1, "name":"Zombie"}, + {"time": 6000, "map_y":3, "name":"FlagZombie"}, + {"time":10000, "map_y":0, "name":"ConeheadZombie"}, + {"time":14000, "map_y":2, "name":"NewspaperZombie"}, + {"time":18000, "map_y":4, "name":"BucketheadZombie"}, + {"time":22000, "map_y":0, "name":"Zombie"}, + {"time":26000, "map_y":3, "name":"BucketheadZombie"}, + {"time":30000, "map_y":4, "name":"Zombie"}, + {"time":32000, "map_y":3, "name":"NewspaperZombie"}, + {"time":34000, "map_y":1, "name":"FlagZombie"}, + {"time":36000, "map_y":2, "name":"ConeheadZombie"}, + {"time":38000, "map_y":0, "name":"BucketheadZombie"}, + {"time":40000, "map_y":1, "name":"ConeheadZombie"}, + {"time":42000, "map_y":1, "name":"NewspaperZombie"}, + {"time":60000, "map_y":4, "name":"Zombie"}, + {"time":61000, "map_y":3, "name":"NewspaperZombie"}, + {"time":62000, "map_y":1, "name":"FlagZombie"}, + {"time":63000, "map_y":2, "name":"Zombie"}, + {"time":64000, "map_y":0, "name":"BucketheadZombie"}, + {"time":65000, "map_y":1, "name":"ConeheadZombie"}, + {"time":66000, "map_y":2, "name":"Zombie"}, + {"time":67000, "map_y":4, "name":"BucketheadZombie"}, + {"time":68000, "map_y":3, "name":"NewspaperZombie"}, + {"time":69000, "map_y":1, "name":"FlagZombie"}, + {"time":70000, "map_y":4, "name":"BucketheadZombie"}, + {"time":71000, "map_y":0, "name":"FlagZombie"} + ] +} \ No newline at end of file diff --git a/source/data/map/level_5.json b/source/data/map/level_5.json new file mode 100644 index 0000000..343c68b --- /dev/null +++ b/source/data/map/level_5.json @@ -0,0 +1,33 @@ +{ + "background_type":4, + "choosebar_type":2, + "card_pool":[ + {"name":"WallNutBowling"}, + {"name":"RedWallNutBowling"} + ], + "zombie_list":[ + {"time": 1000, "map_y":1, "name":"Zombie"}, + {"time":10000, "map_y":3, "name":"FlagZombie"}, + {"time":12000, "map_y":0, "name":"ConeheadZombie"}, + {"time":14000, "map_y":2, "name":"NewspaperZombie"}, + {"time":18000, "map_y":4, "name":"BucketheadZombie"}, + {"time":22000, "map_y":3, "name":"Zombie"}, + {"time":26000, "map_y":1, "name":"BucketheadZombie"}, + {"time":30000, "map_y":4, "name":"Zombie"}, + {"time":32000, "map_y":3, "name":"NewspaperZombie"}, + {"time":34000, "map_y":1, "name":"FlagZombie"}, + {"time":36000, "map_y":2, "name":"ConeheadZombie"}, + {"time":40000, "map_y":1, "name":"ConeheadZombie"}, + {"time":42000, "map_y":1, "name":"NewspaperZombie"}, + {"time":50000, "map_y":4, "name":"Zombie"}, + {"time":54000, "map_y":3, "name":"NewspaperZombie"}, + {"time":58000, "map_y":1, "name":"FlagZombie"}, + {"time":62000, "map_y":2, "name":"Zombie"}, + {"time":64000, "map_y":1, "name":"ConeheadZombie"}, + {"time":66000, "map_y":2, "name":"Zombie"}, + {"time":68000, "map_y":3, "name":"NewspaperZombie"}, + {"time":70000, "map_y":1, "name":"FlagZombie"}, + {"time":72000, "map_y":4, "name":"BucketheadZombie"}, + {"time":74000, "map_y":0, "name":"FlagZombie"} + ] +} \ No newline at end of file