diff --git a/resources/graphics/Items/Background/Background_4.jpg b/resources/graphics/Items/Background/Background_4.jpg new file mode 100644 index 0000000..d4743ad Binary files /dev/null and b/resources/graphics/Items/Background/Background_4.jpg differ diff --git a/resources/graphics/Plants/WallNut/RedWallNutBowling/RedWallNutBowling_0.png b/resources/graphics/Plants/WallNut/RedWallNutBowling/RedWallNutBowling_0.png new file mode 100644 index 0000000..f9f5a27 Binary files /dev/null and b/resources/graphics/Plants/WallNut/RedWallNutBowling/RedWallNutBowling_0.png differ diff --git a/resources/graphics/Plants/WallNut/RedWallNutBowlingExplode/RedWallNutBowlingExplode_0.png b/resources/graphics/Plants/WallNut/RedWallNutBowlingExplode/RedWallNutBowlingExplode_0.png new file mode 100644 index 0000000..0286674 Binary files /dev/null and b/resources/graphics/Plants/WallNut/RedWallNutBowlingExplode/RedWallNutBowlingExplode_0.png differ diff --git a/source/component/menubar.py b/source/component/menubar.py index a8f40e0..56054a5 100644 --- a/source/component/menubar.py +++ b/source/component/menubar.py @@ -15,15 +15,15 @@ card_name_list = [c.CARD_SUNFLOWER, c.CARD_PEASHOOTER, c.CARD_SNOWPEASHOOTER, c. 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_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] -plant_sun_list = [50, 100, 175, 50, 150, 325, 200, 150, 0, 25, 50, 100, 125, 25, 25, 75, 75] + 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] + 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): @@ -323,16 +323,16 @@ class Panel(): surface.blit(self.button_image, self.button_rect) class MoveCard(): - def __init__(self, x, y, name_index, scale=0.78): - name = card_name_list[name_index] + '_move' - self.loadFrame(name, scale) + 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.name_index = name_index + self.card_name = card_name + self.plant_name = plant_name self.move_timer = 0 self.select = True @@ -400,7 +400,10 @@ class MoveBar(): x = self.card_end_x y = 6 index = random.randint(0, len(self.card_pool) - 1) - self.card_list.append(MoveCard(x, y, self.card_pool[index])) + 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): @@ -418,7 +421,7 @@ class MoveBar(): result = None for index, card in enumerate(self.card_list): if card.checkMouseClick(mouse_pos): - result = (plant_name_list[card.name_index], card) + result = (card.plant_name, card) break return result diff --git a/source/component/plant.py b/source/component/plant.py index ce4c4e6..684065b 100644 --- a/source/component/plant.py +++ b/source/component/plant.py @@ -1,5 +1,6 @@ __author__ = 'marble_xu' +import random import pygame as pg from .. import tool from .. import constants as c @@ -822,4 +823,149 @@ class HypnoShroom(Plant): for i, name in enumerate(name_list): self.loadFrames(frame_list[i], name, 1, c.WHITE) - self.frames = self.idle_frames \ No newline at end of file + 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/constants.py b/source/constants.py index 066d9f1..0c4e2b6 100644 --- a/source/constants.py +++ b/source/constants.py @@ -59,6 +59,7 @@ MAP_OFFSET_Y = 100 CHOOSEBAR_TYPE = 'choosebar_type' CHOOSEBAR_STATIC = 0 CHOOSEBAR_MOVE = 1 +CHOSSEBAR_BOWLING = 2 MENUBAR_BACKGROUND = 'ChooserBackground' MOVEBAR_BACKGROUND = 'MoveBackground' PANEL_BACKGROUND = 'PanelBackground' @@ -90,11 +91,14 @@ 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 @@ -124,6 +128,7 @@ 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' 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 diff --git a/source/state/level.py b/source/state/level.py index 7106fd4..133cc28 100644 --- a/source/state/level.py +++ b/source/state/level.py @@ -78,6 +78,12 @@ class Level(tool.State): self.draw(surface) + def initBowlingMap(self): + print('initBowlingMap') + for x in range(3, self.map.width): + for y in range(self.map.height): + self.map.setMapGridType(x, y, c.MAP_EXIST) + def initState(self): if c.CHOOSEBAR_TYPE in self.map_data: self.bar_type = self.map_data[c.CHOOSEBAR_TYPE] @@ -89,6 +95,8 @@ class Level(tool.State): else: card_pool = menubar.getCardPool(self.map_data[c.CARD_POOL]) self.initPlay(card_pool) + if self.bar_type == c.CHOSSEBAR_BOWLING: + self.initBowlingMap() def initChoose(self): self.state = c.CHOOSE @@ -238,6 +246,10 @@ class Level(tool.State): new_plant = plant.IceShroom(x, y) elif self.plant_name == c.HYPNOSHROOM: new_plant = plant.HypnoShroom(x, y) + elif self.plant_name == c.WALLNUTBOWLING: + new_plant = plant.WallNutBowling(x, y, map_y, self) + elif self.plant_name == c.REDWALLNUTBOWLING: + new_plant = plant.RedWallNutBowling(x, y) if new_plant.can_sleep and self.background_type == c.BACKGROUND_DAY: new_plant.setSleep() @@ -248,7 +260,8 @@ class Level(tool.State): else: self.menubar.deleateCard(self.select_plant) - self.map.setMapGridType(map_x, map_y, c.MAP_EXIST) + if self.bar_type != c.CHOSSEBAR_BOWLING: + self.map.setMapGridType(map_x, map_y, c.MAP_EXIST) self.removeMouseImage() #print('addPlant map[%d,%d], grid pos[%d, %d] pos[%d, %d]' % (map_x, map_y, x, y, pos[0], pos[1])) @@ -284,7 +297,8 @@ class Level(tool.State): if (plant_name == c.POTATOMINE or plant_name == c.SQUASH or plant_name == c.SPIKEWEED or plant_name == c.JALAPENO or plant_name == c.SCAREDYSHROOM or plant_name == c.SUNSHROOM or - plant_name == c.ICESHROOM or plant_name == c.HYPNOSHROOM): + plant_name == c.ICESHROOM or plant_name == c.HYPNOSHROOM or + plant_name == c.WALLNUTBOWLING or plant_name == c.REDWALLNUTBOWLING): color = c.WHITE else: color = c.BLACK @@ -313,15 +327,27 @@ class Level(tool.State): bullet.setExplode() def checkZombieCollisions(self): - collided_func = pg.sprite.collide_circle_ratio(0.7) + if self.bar_type == c.CHOSSEBAR_BOWLING: + ratio = 0.6 + else: + ratio = 0.7 + collided_func = pg.sprite.collide_circle_ratio(ratio) for i in range(self.map_y_len): hypo_zombies = [] for zombie in self.zombie_groups[i]: if zombie.state != c.WALK: continue plant = pg.sprite.spritecollideany(zombie, self.plant_groups[i], collided_func) - if plant and plant.name != c.SPIKEWEED: - zombie.setAttack(plant) + if plant: + if plant.name == c.WALLNUTBOWLING: + if plant.canHit(i): + zombie.setDamage(c.WALLNUT_BOWLING_DAMAGE) + plant.changeDirection(i) + elif plant.name == c.REDWALLNUTBOWLING: + if plant.state == c.IDLE: + plant.setAttack() + elif plant.name != c.SPIKEWEED: + zombie.setAttack(plant) for hypno_zombie in self.hypno_zombie_groups[i]: if hypno_zombie.health <= 0: @@ -352,7 +378,7 @@ class Level(tool.State): if abs(i - map_y) > y_range: continue for zombie in self.zombie_groups[i]: - if abs(zombie.rect.x - x) <= x_range: + if abs(zombie.rect.centerx - x) <= x_range: zombie.setBoomDie() def freezeZombies(self, plant): @@ -364,9 +390,11 @@ class Level(tool.State): def killPlant(self, plant): x, y = plant.getPosition() map_x, map_y = self.map.getMapIndex(x, y) - self.map.setMapGridType(map_x, map_y, c.MAP_EMPTY) + if self.bar_type != c.CHOSSEBAR_BOWLING: + self.map.setMapGridType(map_x, map_y, c.MAP_EMPTY) if (plant.name == c.CHERRYBOMB or plant.name == c.JALAPENO or - (plant.name == c.POTATOMINE and not plant.is_init)): + (plant.name == c.POTATOMINE and not plant.is_init) or + plant.name == c.REDWALLNUTBOWLING): self.boomZombies(plant.rect.centerx, map_y, plant.explode_y_range, plant.explode_x_range) elif plant.name == c.ICESHROOM and plant.state != c.SLEEP: @@ -440,6 +468,9 @@ class Level(tool.State): plant.setAttack() elif plant.state != c.IDLE: plant.setIdle() + elif(plant.name == c.WALLNUTBOWLING or + plant.name == c.REDWALLNUTBOWLING): + pass else: can_attack = False if (plant.state == c.IDLE and zombie_len > 0):