class TenTower(Tower): """ Add extra range to each surrounding tower """ def __init__(self, x, y): super().__init__(x, y) self.range = 60 self.effect = [0.1, 0.2, 0.3] self.menu = Menu(self, self.x, self.y, menu_bg, self.price) self.menu.add_btn(upgrade_btn, "Upgrade") self.menu.add_btn(sell_btn, "Sell") self.base_imgs = base_imgs4[:] self.width = 40 self.height = 44 self.name = "ten" self.sell_price = [80, 120, 240] self.price = [160, 300, 9999] def get_upgrade_cost(self): """ gets the upgrade cost :return: int """ return self.menu.get_item_cost() def draw(self, win): # super().draw_radius(win) super().draw_rectangle(win) super().draw(win) def support(self, towers): """ will modify towers according to abillity :param towers: list :return: None """ effected = [] for tower in towers: x = tower.x y = tower.y dis = math.sqrt((self.x - x)**2 + (self.y - y)**2) if dis <= self.range + tower.width / 2: effected.append(tower) for tower in effected: tower.range = tower.original_range + round( tower.range * self.effect[self.level - 1])
class ArcherTowerLong(Tower): def __init__(self, x,y): super().__init__(x, y) self.tower_imgs = tower_imgs1[:] self.archer_imgs = archer_imgs1[:] self.archer_count = 0 self.range = 200 self.original_range = self.range self.inRange = False self.left = True self.damage = 1 self.original_damage = self.damage self.width = self.height = 90 self.moving = False self.name = "archer" self.menu = Menu(self, self.x, self.y, menu_bg, [2000, 5000,"MAX"]) self.menu.add_btn(upgrade_btn, "Upgrade") def get_upgrade_cost(self): """ gets the upgrade cost :return: int """ return self.menu.get_item_cost() def draw(self, win): """ draw the arhcer tower and animated archer :param win: surface :return: int """ super().draw_radius(win) super().draw(win) if self.inRange and not self.moving: self.archer_count += 1 if self.archer_count >= len(self.archer_imgs) * 10: self.archer_count = 0 else: self.archer_count = 0 archer = self.archer_imgs[self.archer_count // 10] if self.left == True: add = -25 else: add = -archer.get_width() + 10 win.blit(archer, ((self.x + add), (self.y - archer.get_height() - 25))) def change_range(self, r): """ change range of archer tower :param r: int :return: None """ self.range = r def attack(self, enemies): """ attacks an enemy in the enemy list, modifies the list :param enemies: list of enemies :return: None """ money = 0 self.inRange = False enemy_closest = [] for enemy in enemies: x = enemy.x y = enemy.y dis = math.sqrt((self.x - 86/2 - x)**2 + (self.y - 86/2 - y)**2) if dis < self.range: self.inRange = True enemy_closest.append(enemy) enemy_closest.sort(key=lambda x: x.path_pos) enemy_closest = enemy_closest[::-1] if len(enemy_closest) > 0: first_enemy = enemy_closest[0] if self.archer_count == 50: if first_enemy.hit(self.damage) == True: money = first_enemy.money * 2 enemies.remove(first_enemy) if first_enemy.x > self.x and not(self.left): self.left = True for x, img in enumerate(self.archer_imgs): self.archer_imgs[x] = pygame.transform.flip(img, True, False) elif self.left and first_enemy.x < self.x: self.left = False for x, img in enumerate(self.archer_imgs): self.archer_imgs[x] = pygame.transform.flip(img, True, False) return money
class Tower: """ Abstract class for towers """ def __init__(self, x, y): self.x = x self.y = y self.width = self.height = 96 self.sell_price = [0,0,0] self.price = [0,0,0] self.level = 1 self.range = 200 self.original_range = self.range # Not sure if this should be in here self.selected = False # define menu and buttons self.menu = Menu(self.x, self.y, self, menu_bg, [2000, 5000, 9000, 12000, "MAX"]) self.menu.add_button(upgrade_button, "Upgrade") self.moving = False self.tower_imgs = [] self.damage = 1 self.place_color = (0,0,255, 100) def draw(self, win): """ draws the tower :param win: surface :return: None """ img = self.tower_imgs[self.level - 1] win.blit(img, (self.x-img.get_width()//2, self.y-img.get_height()//2)) # draw menu if self.selected: self.menu.draw(win) def draw_radius(self, win): # draw range circle if selected if self.selected: surface = pygame.Surface((self.range*2, self.range*2), pygame.SRCALPHA, 32) pygame.draw.circle(surface, (128, 128, 128, 100), (self.range, self.range), self.range, 0) win.blit(surface, (self.x - self.range, self.y - self.range)) def draw_placement(self, win): # draw range circle surface = pygame.Surface((self.range*2, self.range*2), pygame.SRCALPHA, 32) pygame.draw.circle(surface, self.place_color, (58, 58), 58, 0) # 58 = 96/2 + 10 win.blit(surface, (self.x - 58, self.y - 58)) def click(self, X, Y): """ returns if tower has been clicked on and select tower if it was clicked :param X: int :param Y: int :return: bool """ img = self.tower_imgs[self.level - 1] if X <= self.x - img.get_width()//2 + self.width and X >= self.x - img.get_width()//2: if Y <= self.y + self.height - img.get_height()//2 and Y >= self.y - img.get_height()//2: return True return False def sell(self): """ call to sell the tower, returns sel price :retutn: int """ return self.sell_price[self.level - 1] def upgrade(self): """ upgrades the tower for a given cost :return: None """ if self.level < len(self.tower_imgs): self.level += 1 self.damage += 1 def get_upgrade_cost(self): """ gets the upgrade cost :return: int """ return self.menu.get_item_cost() def move(self, x, y): """ moves tower to given x and y :param x: int :param y: int :return: None """ self.x = x self.y = y self.menu.x = x self.menu.y = y self.menu.update() def collide(self, otherTower): x2 = otherTower.x y2 = otherTower.y dis = math.sqrt((x2 - self.x)**2 + (y2 - self.y)**2) return True if dis <= 116 else False # width and height of the towers are equals to 96 and adding 10 from both sides = 116
class Fortress(Tower): """ Add extra range to each surrounding tower """ def __init__(self, x, y): super().__init__(x,y) self.range = 60 self.effect = [100, 200, 400] self.price = [400, 750, 9999] self.menu = Menu(self, self.x, self.y, menu_bg, self.price) self.menu.add_btn(upgrade_btn, "Upgrade") self.menu.add_btn(sell_btn, "Sell") self.base_imgs = base_imgs6[:] self.animation_imgs = animation_imgs6[:] self.width = 40 self.height = 44 self.name = "fortress" self.max_health = 500 self.health = self.max_health self.collapse = False self.price = [0, 0, 0] self.collided = [] def get_upgrade_cost(self): """ gets the upgrade cost :return: int """ return self.menu.get_item_cost() def resist(self, enemy): """ will resist according to health and nearby enemies :param towers: list :return: None """ if enemy.name == "wei_catapult": coef = 2 elif enemy.name == "wei_balista": coef = 2 elif enemy.name == "zao_riboku": coef = 10 else: coef = 1 self.health -= 1*coef if self.health <= 0: return False return True def draw(self, win): """ draw the fortress base and fortress :param win: surface :return: int """ super().draw_radius(win) super().draw(win) fortress = self.animation_imgs[self.level-1] add_x = 2 add_y = 5 win.blit(fortress, ((self.x - fortress.get_width()/2 + add_x), (self.y - fortress.get_height()/2 - add_y))) self.draw_health_bar(win) def draw_health_bar(self, win): """ draw health bar above enemy :param win: surface :return: None """ length = 30 health_bar = length*(1-((self.max_health-self.health)/self.max_health)) add_y = 15 pygame.draw.rect(win, (255, 26, 26), (self.x - 13, self.y - 55 + add_y, length, 5), 0) # red rectangle pygame.draw.rect(win, (102, 255, 51), (self.x - 13, self.y - 55 + add_y, health_bar, 5), 0) # green rectangle pygame.draw.rect(win, (77, 77, 77), (self.x - 13, self.y - 55 + add_y, health_bar, 5), 1) # grey rectangle border
class ShinTower(Tower): def __init__(self, x, y): super().__init__(x, y) self.base_imgs = base_imgs1[:] self.animation_imgs = animation_imgs1[:] self.animation_count = 0 self.range = 85 self.original_range = self.range self.inRange = False self.left = True self.timer = time.time() self.damage = 1 self.original_damage = self.damage self.width = 40 self.height = 44 self.menu = Menu(self, self.x, self.y, menu_bg, self.price) self.menu.add_btn(upgrade_btn, "Upgrade") self.menu.add_btn(sell_btn, "Sell") self.moving = False self.sound = "sword.wav" self.name = "shin" self.sell_price = [30, 80, 200] self.price = [100, 300, 9999] self.distribution = [0.89, 0.1, 0.01] self.original_distribution = self.distribution[:] self.gold_drop = 0 self.coord = (0, 0) self.speed = 4 self.attacked_enemy = None def get_upgrade_cost(self): """ gets the upgrade cost :return: int """ return self.menu.get_item_cost() def draw(self, win): """ draw the shin tower base and animated shin :param win: surface :return: int """ super().draw_radius(win) super().draw(win) if self.inRange and not self.moving: self.animation_count += 1 if self.animation_count >= len( self.animation_imgs) * (5 - self.speed): self.animation_count = len(self.animation_imgs) else: self.animation_count = 0 shin = self.animation_imgs[self.animation_count // (5 - self.speed)] add_x = 2 add_y = 5 win.blit(shin, ((self.x - shin.get_width() / 2 + add_x), (self.y - shin.get_height() / 2 - add_y))) def change_range(self, r): """ change range of shin tower :param r: int :return: None """ self.range = r def attack(self, enemies): """ attacks an enemy in the enemy list, modifies the list :param enemies: list of enemies :return: None """ money = 0 self.attacked_enemy = None self.gold_drop = 0 self.inRange = False enemy_closest = [] for enemy in enemies: x = enemy.x y = enemy.y - 36 dis = math.sqrt((self.x - x)**2 + (self.y - y)**2) if dis < self.range: self.inRange = True enemy_closest.append(enemy) enemy_closest.sort(key=lambda x: x.path_pos) enemy_closest = enemy_closest[::-1] if len(enemy_closest) > 0: first_enemy = enemy_closest[0] if self.animation_count == len(self.animation_imgs): if self.name == "ouhon": if not first_enemy.frozen: pygame.mixer.Channel(1).play(pygame.mixer.Sound( os.path.join("game_assets/sounds/", self.sound)), maxtime=600) first_enemy.frozen = True first_enemy.vel = first_enemy.vel / self.freeze_power else: pygame.mixer.Channel(1).play(pygame.mixer.Sound( os.path.join("game_assets/sounds/", self.sound)), maxtime=600) if first_enemy.hit(self.damage, self.name) == True: pygame.mixer.Channel(1).play(pygame.mixer.Sound( os.path.join("game_assets/sounds/", first_enemy.sound)), maxtime=600) # give money, drop reward (low probability), remove died enemy self.attacked_enemy = first_enemy money = first_enemy.money * 2 self.random_reward(first_enemy) if self.gold_drop > 0: self.coord = (first_enemy.x, first_enemy.y) enemies.remove(first_enemy) return money def random_reward(self, enemy): """ Return an amount of reward, with low probability :return: 1-sized list """ gold_list = [0, enemy.money, enemy.money * 3] drop = random.choices(gold_list, self.distribution) self.gold_drop = drop[0] return self.gold_drop
class ArcherTowerLong(Tower): is_game_pause = True def __init__(self, x, y): super().__init__(x, y) self.tower_imgs = tower_imgs.images[:] self.archer_imgs = archer_imgs.images[:] self.archer_count = 0 self.price = 500 self.range = 150 self.original_range = self.range self.in_range = False self.left = False self.damage = 2 self.original_damage = self.damage self.width = self.height = 90 self.moving = False self.paused = False self.name = "archer_long" # define menu and buttons self.menu = Menu(self, self.x, self.y, menu_bg, [2000, 5000, "Max"]) self.menu.add_btn(upgrade_btn, "Upgrade") def get_upgrade_cost(self): """ Gets the upgrade cost :return: int """ return self.menu.get_item_cost() def draw(self, win): """ Draw the archer tower and animated archer :param win: surface :return: int """ super().draw_radius(win) super().draw(win) if self.in_range and not self.moving and not ArcherTowerLong.is_game_pause: self.archer_count += 1 if self.archer_count >= len(self.archer_imgs) * 10: self.archer_count = 0 else: self.archer_count = 0 archer = self.archer_imgs[self.archer_count // 10] win.blit(archer, (self.x - 22, self.y - archer.get_height() - 18)) def change_range(self, r): """ Change range for archer tower :param r: int :return: None """ self.range -= r def attack(self, enemies): """ Attacks an enemy in the enemy list, modifies the list :param enemies: list of enemies :return: None """ money = 0 self.in_range = False enemy_closest = [] for enemy in enemies: enemy_x, enemy_y = enemy.x, enemy.y dis = math.sqrt((self.x - enemy_x)**2 + (self.y - enemy_y)**2) if dis < self.range: self.in_range = True enemy_closest.append(enemy) enemy_closest.sort(key=lambda x: x.health) # enemy_closest = enemy_closest[::-1] if len(enemy_closest) > 0: first_enemy = enemy_closest[0] if self.archer_count == 50: if first_enemy.hit(self.damage): money = first_enemy.money * 2 # enemies.remove(first_enemy) first_enemy.to_dying() if first_enemy.x < self.x and not self.left: self.left = True for index, img in enumerate(self.archer_imgs): self.archer_imgs[index] = pygame.transform.flip( img, True, False) elif self.left and first_enemy.x > self.x: self.left = False for index, img in enumerate(self.archer_imgs): self.archer_imgs[index] = pygame.transform.flip( img, True, False) return money
class ArcherTowerLong(Tower): def __init__(self, x, y): super().__init__(x, y) self.tower_imgs = tower_imgs1[:] self.archer_imgs = archer_imgs1[:] self.archer_count = 0 self.range = 200 self.original_range = self.range self.inRange = False self.left = True self.damage = 1 self.original_damage = self.damage self.width = self.height = 90 self.moving = False self.name = "archer" self.menu = Menu(self, self.x, self.y, menu_bg, [2000, 5000, "MAX"]) self.menu.add_btn(upgrade_btn, "Upgrade") def get_upgrade_cost(self): """ Pobierz koszt ulepszenia :return: int """ return self.menu.get_item_cost() def draw(self, win): """ narysuj wieżę łuczników i animacje łucznika :param win: surface :return: int """ super().draw_radius(win) super().draw(win) if self.inRange and not self.moving: self.archer_count += 1 if self.archer_count >= len(self.archer_imgs) * 10: self.archer_count = 0 else: self.archer_count = 0 archer = self.archer_imgs[self.archer_count // 10] if self.left == True: add = -25 else: add = -archer.get_width() + 10 win.blit(archer, ((self.x + add), (self.y - archer.get_height() - 25))) def change_range(self, r): """ Zmiana zasięgu wiezy luczniczej :param r: int :return: None """ self.range = r def attack(self, enemies): """ atakuje wroga z listy wrogów, modyfikuje listę :param enemies: lista wrogów :return: None """ money = 0 self.inRange = False enemy_closest = [] for enemy in enemies: x = enemy.x y = enemy.y dis = math.sqrt((self.x - x)**2 + (self.y - y)**2) if dis < self.range: self.inRange = True enemy_closest.append(enemy) enemy_closest.sort(key=lambda x: x.x) if len(enemy_closest) > 0: first_enemy = enemy_closest[0] if self.archer_count == 6: if first_enemy.hit(self.damage) == True: money = first_enemy.money enemies.remove(first_enemy) if first_enemy.x > self.x and not (self.left): self.left = True for x, img in enumerate(self.archer_imgs): self.archer_imgs[x] = pygame.transform.flip( img, True, False) elif self.left and first_enemy.x < self.x: self.left = False for x, img in enumerate(self.archer_imgs): self.archer_imgs[x] = pygame.transform.flip( img, True, False) return money