class Qi_base(Kingdom): def __init__(self): super().__init__() self.img = img self.name = "qi_base" self.x = 980 self.y = 318 self.tile = [[1100, 176], [1020, 210], [1060, 210], [1100, 210], [860, 244], [900, 244], [940, 244], [980, 244], [1020, 244], [1060, 244], [1100, 244], [860, 279], [900, 279], [940, 279], [980, 279], [1020, 279], [1060, 279], [1100, 279], [860, 313], [900, 313], [940, 313], [980, 313], [1020, 313], [1060, 313], [1100, 313], [860, 349], [900, 349], [940, 349], [980, 349], [1020, 349], [1060, 349], [1100, 349]] self.rgb = rgb(254, 234, 178) self.menu = Menu(self, self.x, self.y, menu_bg, self.price) self.menu.add_btn(warrior, "kingdom") self.menu.add_btn(boat, "kingdom") def draw(self, win): super().draw(win) if self.selected: self.menu.x = self.x self.menu.y = self.y self.menu.update() self.menu.draw(win)
class Wei_base(Kingdom): def __init__(self): super().__init__() self.img = img self.name = "wei_base" self.x = 660 self.y = 318 self.tile = [[460, 244], [500, 244], [540, 244], [580, 244], [620, 244], [660, 244], [700, 244], [460, 279], [500, 279], [540, 279], [580, 279], [620, 279], [660, 279], [700, 279], [500, 313], [540, 313], [580, 313], [620, 313], [660, 313], [700, 313], [500, 349], [540, 349], [580, 349], [620, 349], [660, 349], [700, 349], [500, 383], [540, 383], [580, 383], [620, 383], [660, 383], [500, 417], [540, 417], [580, 417], [620, 417], [660, 417]] self.rgb = rgb(254, 245, 134) self.menu = Menu(self, self.x, self.y, menu_bg, self.price) self.menu.add_btn(catapult, "kingdom") self.menu.add_btn(balista, "kingdom") def draw(self, win): super().draw(win) if self.selected: self.menu.x = self.x self.menu.y = self.y self.menu.update() self.menu.draw(win)
class DamageTower(Tower): def __init__(self, x, y): super().__init__(x, y) self.range = 150 self.effect = [2, 4] self.imgs = damage_imgs[:] self.width = self.height = 128 self.price = [1300, 0] temp = [] for x in range(len(self.price) - 1): temp.append(str(self.price[x])) temp.append("MAX") self.menu = Menu(self, self.x, self.y, menu_bg, temp) self.menu.add_btn(upgrade_btn, "Upgrade") self.name = "damageTower" def get_upgrade_cost(self): return self.price[self.level - 1] def draw(self, win): super().draw_radius(win) super().draw(win) def support(self, towers): 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.damage = tower.oryginal_damage * self.effect[self.level - 1]
class KyoukaiTower(TenTower): """ add damage to surrounding towers """ def __init__(self, x, y): super().__init__(x, y) self.range = 60 self.base_imgs = base_imgs5[:] self.effect = [1, 2, 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.name = "kyoukai" self.sell_price = [80, 120, 240] self.price = [160, 300, 9999] def support(self, towers): """ will modify towers according to ability :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.damage = tower.original_damage + round( tower.original_damage * self.effect[self.level - 1])
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 ArcherTowerShort(ArcherTowerLong): def __init__(self, x,y): super().__init__(x, y) self.tower_imgs = tower_imgs[:] self.archer_imgs = archer_imgs[:] self.archer_count = 0 self.range = 120 self.original_range = self.range self.inRange = False self.left = True self.damage = 2 self.original_damage = self.damage self.menu = Menu(self, self.x, self.y, menu_bg, [2500, 5500, "MAX"]) self.menu.add_btn(upgrade_btn, "Upgrade") self.name = "archer2"
class Zao_base(Kingdom): def __init__(self): super().__init__() self.img = img self.name = "zao_base" self.x = 700 self.y = 145 self.tile = [[20, 40], [60, 40], [100, 40], [140, 40], [180, 40], [220, 40], [260, 40], [300, 40], [340, 40], [380, 40], [420, 40], [460, 40], [500, 40], [540, 40], [580, 40], [620, 40], [660, 40], [700, 40], [740, 40], [20, 74], [60, 74], [100, 74], [140, 74], [180, 74], [220, 74], [260, 74], [300, 74], [340, 74], [380, 74], [420, 74], [460, 74], [500, 74], [540, 74], [580, 74], [620, 74], [660, 74], [700, 74], [740, 74], [20, 108], [60, 108], [100, 108], [140, 108], [180, 108], [220, 108], [260, 108], [300, 108], [340, 108], [540, 108], [580, 108], [620, 108], [660, 108], [700, 108], [740, 108], [540, 142], [580, 142], [620, 142], [660, 142], [700, 142], [740, 142], [540, 176], [580, 176], [620, 176], [660, 176], [700, 176], [740, 176], [540, 210], [580, 210], [620, 210], [660, 210], [700, 210], [740, 210], [780, 210], [820, 210], [740, 244], [780, 244], [820, 244], [740, 279], [780, 279], [820, 279], [740, 313], [780, 313], [820, 313], [740, 349], [780, 349], [820, 349], [820, 383]] self.rgb = rgb(250, 160, 150) self.menu = Menu(self, self.x, self.y, menu_bg, self.price) self.menu.add_btn(warrior, "kingdom") self.menu.add_btn(riboku, "kingdom") def draw(self, win): super().draw(win) if self.selected: self.menu.x = self.x self.menu.y = self.y self.menu.update() self.menu.draw(win)
class ArcherTowerShort(ArcherTowerLong): def __init__(self, x, y): super().__init__(x, y) self.tower_imgs = tower_imgs_sibling.images[:] self.archer_imgs = archer_imgs_sibling.images[:] self.archer_count = 0 self.range = 120 self.price = 750 self.original_range = self.range self.in_range = False self.left = False self.damage = 4 self.original_damage = self.damage self.width = self.height = 100 self.name = "archer_short" # define menu and buttons self.menu = Menu(self, self.x, self.y, menu_bg, [2500, 5500, "Max"]) self.menu.add_btn(upgrade_btn, "Upgrade")
class KankiTower(ShinTower): def __init__(self, x, y): super().__init__(x, y) self.base_imgs = base_imgs3[:] self.animation_imgs = animation_imgs3[:] self.animation_count = 0 self.range = 65 self.original_range = self.range self.inRange = False self.left = True self.damage = 1 self.original_damage = self.damage 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.sound = "sword2.wav" self.name = "kanki" self.sell_price = [60, 100, 200] self.price = [120, 250, 9999] self.distribution = [0.89, 0.1, 0.01]
class Han_base(Kingdom): def __init__(self): super().__init__() self.img = img self.name = "han_base" self.x = 740 self.y = 388 self.tile = [[700,383],[740,383],[780,383],[700,417],[740,417],[780,417],[700,453],[740,453],[780,453],[700,489],[740,489],[780,489],[700,523],[740,523]] self.rgb = rgb(253, 143, 66) self.menu = Menu(self, self.x, self.y, menu_bg, self.price) self.menu.add_btn(warrior, "kingdom2") def draw(self, win): super().draw(win) if self.selected: self.menu.x = self.x self.menu.y = self.y self.menu.update() self.menu.draw(win)
class Chu3_base(Kingdom): def __init__(self): super().__init__() self.img = img self.name = "chu3_base" self.x = 820 self.y = 564 self.tile = [[860,383],[900,383],[940,383],[980,383],[1020,383],[1060,383],[1100,383],[820,417],[860,417],[900,417],[940,417],[980,417],[1020,417],[1060,417],[1100,417],[500,453],[540,453],[580,453],[620,453],[660,453],[820,453],[860,453],[900,453],[940,453],[980,453],[1020,453],[1060,453],[1100,453],[500,489],[540,489],[580,489],[620,489],[660,489],[820,489],[860,489],[900,489],[940,489],[980,489],[1020,489],[1060,489],[1100,489],[140,523],[180,523],[220,523],[260,523],[300,523],[340,523],[380,523],[420,523],[460,523],[500,523],[540,523],[580,523],[620,523],[660,523],[780,523],[820,523],[860,523],[900,523],[940,523],[980,523],[1020,523],[1060,523],[1100,523],[20,559],[60,559],[100,559],[140,559],[180,559],[220,559],[260,559],[300,559],[340,559],[380,559],[420,559],[460,559],[500,559],[540,559],[580,559],[620,559],[660,559],[700,559],[740,559],[780,559],[820,559],[860,559],[900,559],[940,559],[980,559],[1020,559],[1060,559],[1100,559],[20,593],[60,593],[100,593],[140,593],[180,593],[220,593],[260,593],[300,593],[340,593],[380,593],[420,593],[460,593],[500,593],[540,593],[580,593],[620,593],[660,593],[700,593],[740,593],[780,593],[820,593],[860,593],[900,593],[940,593],[980,593],[1020,593],[1060,593],[1100,593],[20,627],[60,627],[100,627],[140,627],[180,627],[220,627],[260,627],[300,627],[340,627],[380,627],[420,627],[460,627],[500,627],[540,627],[580,627],[620,627],[660,627],[700,627],[740,627],[780,627],[820,627],[860,627],[900,627],[940,627],[980,627],[1020,627],[1060,627],[1100,627],[20,661],[60,661],[100,661],[140,661],[180,661],[220,661],[260,661],[300,661],[340,661],[380,661],[420,661],[460,661],[500,661],[540,661],[580,661],[620,661],[660,661],[700,661],[740,661],[780,661],[820,661],[860,661],[900,661],[940,661],[980,661],[1020,661],[1060,661],[1100,661]] self.rgb = rgb(176, 134, 105) self.menu = Menu(self, self.x, self.y, menu_bg, self.price) self.menu.add_btn(boat, "kingdom2") def draw(self, win): super().draw(win) if self.selected: self.menu.x = self.x self.menu.y = self.y self.menu.update() self.menu.draw(win)
class MoubuTower(ShinTower): def __init__(self, x, y): super().__init__(x, y) self.base_imgs = base_imgs2[:] self.animation_imgs = animation_imgs2[:] self.animation_count = 0 self.range = 65 self.original_range = self.range self.inRange = False self.left = True self.damage = 2 self.original_damage = self.damage 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.sound = "club.wav" self.name = "moubu" self.sell_price = [90, 150, 200] self.price = [180, 300, 9999] self.distribution = [0.89, 0.1, 0.01] self.original_distribution = self.distribution[:]
class RyoTower(TenTower): """ enhance rewards surrounding towers """ def __init__(self, x, y): super().__init__(x, y) self.range = 100 self.base_imgs = base_imgs6[:] self.effect = [1, 2, 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.name = "ryo" self.sell_price = [80, 120, 240] self.price = [160, 300, 9999] def support(self, towers): """ will modify towers according to ability :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: for i in range(1, 3): tower.distribution[i] = tower.original_distribution[i] + round( tower.original_distribution[i] * self.effect[self.level - 1], 3) tower.distribution[0] = 1 - (tower.distribution[1] + tower.distribution[2])
class Yan_base(Kingdom): def __init__(self): super().__init__() self.img = img self.name = "yan_base" self.x = 940 self.y = 111 self.tile = [[780,40],[820,40],[860,40],[900,40],[940,40],[980,40],[1020,40],[1060,40],[1100,40],[780,74],[820,74],[860,74],[900,74],[940,74],[980,74],[1020,74],[1060,74],[1100,74],[780,108],[820,108],[860,108],[900,108],[940,108],[980,108],[1020,108],[1060,108],[1100,108],[780,142],[820,142],[860,142],[900,142],[940,142],[980,142],[1020,142],[1060,142],[1100,142],[780,176],[820,176],[860,176],[900,176],[940,176],[980,176],[1020,176],[1060,176],[860,210],[900,210],[940,210],[980,210]] self.rgb = rgb(170, 250, 140) self.menu = Menu(self, self.x, self.y, menu_bg, self.price) self.menu.add_btn(warrior, "kingdom") self.menu.add_btn(boat, "kingdom") def draw(self, win): super().draw(win) if self.selected: self.menu.x = self.x self.menu.y = self.y self.menu.update() self.menu.draw(win)
class Tower: """ Klasa abstrakcyjna dla wież """ def __init__(self,x,y): self.x = x self.y = y self.width = 0 self.height = 0 self.sell_price = [0,0,0] self.price = [0,0,0] self.level = 1 self.selected = False #definiuje menu i przyciski self.menu = Menu(self, self.x, self.y, menu_bg, [2000, "MAX"]) self.menu.add_btn(upgrade_btn, "Upgrade") self.tower_imgs = [] self.damage = 1 def draw(self, win): """ Rysowanie wieży :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)) #rysowanie menu if self.selected: self.menu.draw(win) def draw_radius(self, win): if self.selected: # rysowanie okręgu zasięgu surface = pygame.Surface((self.range*4, self.range*4), 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 click(self, X, Y): """ Zwraca gdy kliknięto na wieżę i zaznacza wieżę gdy jest kliknięta :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): """ wezwanie do sprzedazy wiezy, zwraca koszt sprzedaży :return:int """ return self.sell_price[self.level-1] def upgrade(self): """ ulepsza wieżę za określony koszt :return: None """ if self.level + 1 < len(self.tower_imgs): self.level += 1 self.damage += 1 def get_upgrade_cost(self): """ zwraca koszt ulepszenia, jeśli 0, to nie może ulepszać :return: int """ return self.price[self.level-1] def move(self, x, y): """ Przesuwa wieze do podanego x i 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()
class Tower(PositionalObject, ILocation, IUpgradable): """ Abstract class for towers """ def __init__(self, x, y): super().__init__() self.x = x self.y = y self.width = 0 self.height = 0 self.price = 0 self.level = 1 self.range = 0 self.selected = False self.is_collide = False # define menu and buttons self.menu = Menu(self, self.x, self.y, menu_background, [2000, "Max"]) self.menu.add_btn(button_background, "Upgrade") self.tower_imgs = [] self.damage = 1 self.sell_price = [] self.place_color = (0, 255, 0, 100) def get_position(self): return self.x, self.y 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): if self.selected: # Draw range circle 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): surface = pygame.Surface((self.range * 2, self.range * 2), pygame.SRCALPHA, 32) pygame.draw.circle(surface, self.place_color, (45, 45), 45, 0) win.blit(surface, (self.x - 45, self.y - 45)) def click(self, x, y): """ Returns if tower has been clicked on and selects tower if it was clicked :param x: int :param y: int :return: bool """ img = self.tower_imgs[self.level - 1] if self.x - img.get_width( ) // 2 <= x <= self.x + self.width - img.get_width() // 2: if self.y - img.get_height( ) // 2 <= y <= self.y + self.height - img.get_height() // 2: return True return False def sell(self): """ Call to sell the tower, returns sell cost :return: int """ return self.sell_price[self.level - 1] def get_upgrade_cost(self): """ Return the upgrade cost, if 0 then can't upgrade anymore :return: """ return self.price def upgrade(self): """ Upgrades the tower for given cost :return: None """ if self.level < len(self.tower_imgs): self.level += 1 self.damage += 1 def move(self, x, y): """ Moves tower to given x and y position :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, other_tower): x2 = other_tower.x y2 = other_tower.y dis = math.sqrt((x2 - self.x)**2 + (y2 - self.y)**2) if dis >= 90: return False else: return True
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 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 Tower: """ Abstract class for towers """ def __init__(self, x, y): self.x = x self.y = y self.width = 0 self.height = 0 self.sell_price = [0, 0, 0] self.price = [0, 0, 0] self.level = 1 self.selected = False # define menu and buttons self.menu = Menu(self, self.x, self.y, menu_bg, [2000, "MAX"]) self.menu.add_btn(upgrade_btn, "Upgrade") 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): if self.selected: # draw range circle surface = pygame.Surface((self.range * 4, self.range * 4), 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 * 4, self.range * 4), pygame.SRCALPHA, 32) pygame.draw.circle(surface, self.place_color, (50, 50), 50, 0) win.blit(surface, (self.x - 50, self.y - 50)) def click(self, X, Y): """ returns if tower has been clicked on and selects 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 sell price :return: 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): """ returns the upgrade cost, if 0 then can't upgrade anymore :return: int """ return self.price[self.level - 1] 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) if dis >= 100: return False else: return True
class Tower: """ Abstract class for towers """ def __init__(self, x, y): self.x = x self.y = y self.width = 0 self.height = 0 self.sell_price = [0, 0, 0] self.price = [100, 300, 9999] self.level = 1 self.selected = False 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 = [] self.animation_imgs = [] self.damage = 1 self.speed = 4 def draw(self, win): """ draws the tower :param win: surface :return: None """ img = self.base_imgs[self.level - 1] # find the closest tile self.x = min(tile_x, key=lambda x: abs(x - self.x)) self.y = min(tile_y, key=lambda y: abs(y - self.y)) tile_key = (self.x, self.y) if self.name == "fortress": if dict_tile_fortress[tile_key] == 0: win.blit(img, (self.x - img.get_width() // 2, self.y - img.get_height() // 2)) else: if dict_tile[tile_key] == 0: 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): if self.selected: # draw range circle size = (self.range * 2, self.range * 2) radius = self.range surface = pygame.Surface(size, pygame.SRCALPHA, 32) pygame.draw.circle(surface, rgb(204, 255, 255), (radius, radius), radius, 0) win.blit(surface, (self.x - radius, self.y - radius)) def draw_rectangle(self, win): if self.selected: # draw range rectangle surface = pygame.Surface((self.range * 4, self.range * 4), pygame.SRCALPHA, 32) pygame.draw.rect(surface, rgb(204, 255, 255), (self.range * 2, self.range * 2, self.range * 2, self.range * 1.8), 0) win.blit(surface, (self.x - 3 * self.range, self.y - 2.6 * self.range)) def click(self, X, Y): """ returns if tower has been clicked on and selects tower if it was clicked :param X: int :param Y: int :return: bool """ img = self.base_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 sell price :return: int """ return self.sell_price[self.level - 1] def upgrade(self): """ upgrades the tower for a given cost :return: None """ if self.name == "fortress": if self.level < len(self.animation_imgs): self.level += 1 self.max_health += self.max_health self.health += self.health elif self.name == "ouhon": if self.level < len(self.base_imgs): self.level += 1 self.freeze_power += 0.5 else: if self.level < len(self.base_imgs): self.level += 1 self.damage += 1 def get_upgrade_cost(self): """ returns the upgrade cost, if 0 then can't upgrade anymore :return: int """ return self.price[self.level - 1] 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 # find closest tile x2 = min( tile_x, key=lambda x: abs(x - x2) ) # set x2 at the x coordinate of tyle_x which has the minimum distance from x2 y2 = min( tile_y, key=lambda y: abs(y - y2) ) # set y2 the y coordinate of tyle_y which has the minimum distance from y2 tile_key = (x2, y2) # distance between the object and the closest tile dis = math.sqrt((x2 - self.x)**2 + (y2 - self.y)**2) # check if first tower of the game collides with forbidden tile if self == otherTower: if self.name == "fortress": # tile is available if dict_tile_fortress[tile_key] == 0: return False # collide == False # tile is not available (collision with outside path) else: return True # collide == True else: # tile is available if dict_tile[tile_key] == 0: return False # collide == False # tile is not available (collision with path) else: return True # collide == True # check if moving object collides with towers, fortress or forbidden tile else: if self.name == "fortress": # tile is possibly available if dict_tile_fortress[tile_key] == 0: # when not already occupied by another fortress if dis >= 10: return False # collide == False # tile is already occupied by another fortress else: return True # collide == True # tile is not available (collision with outside path) else: return True # collide == True else: # tile is possibly available if dict_tile[tile_key] == 0: # when not already occupied by another object if dis >= 10: return False # collide == False # tile is already occupied by another object else: return True # collide == True # tile is not available (collision with path) else: return True # collide == True
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 LongRangeTower(Tower): def __init__(self, x, y): super().__init__(x, y) self.imgs = [] self.oryginal_range = 150 self.range = self.oryginal_range self.inRange = False self.left = True self.timer = time.time() self.oryginal_damage = 1 self.damage = self.oryginal_damage self.width = self.height = 128 self.price = [2000, 4000, 0] temp = [] for x in range(len(self.price) - 1): temp.append(str(self.price[x])) temp.append("MAX") self.menu = Menu(self, self.x, self.y, menu_bg, temp) self.menu.add_btn(upgrade_btn, "Upgrade") self.name = "longRangeTower" self.moving = False self.imgs.append( pygame.transform.scale( pygame.image.load( os.path.join("game_assets/towers/", "base1.png")), (50, 100))) def get_upgrade_cost(self): return self.price[self.level - 1] def draw(self, win): super().draw_radius(win) super().draw(win) base = self.imgs[0] def change_range(self, r): self.range = r def attack(self, enemies): """""" self.inRange = False enemy_closest = [] for enemy in enemies: en_x = enemy.x en_y = enemy.y dis = math.sqrt((self.x - en_x)**2 + (self.y - en_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] # to bedzie przydatne w lucznikach. # flipowanie obrazka w zaleznosci czy przeciwnik jest z lewej lub prawej strony # """ if len(enemy_closest) > 0: first_enemy = enemy_closest[0] if time.time() - self.timer > 0.5: self.timer = time.time() if first_enemy.hit(self.damage) == True: income = first_enemy.worth enemies.remove(first_enemy) return income if first_enemy.x > self.x and not (self.left): self.left = True for x, img in enumerate(self.imgs): self.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.imgs): self.imgs[x] = pygame.transform.flip(img, True, False) return 0
class Tower: def __init__(self, x, y): self.x = x self.y = y self.width = 0 self.height = 0 self.range = 0 self.price = [0, 0, 0] self.level = 1 self.selected = False # define menu and buttons self.menu = Menu(self, self.x, self.y, menu_bg, [2000, "MAX"]) self.menu.add_btn(upgrade_btn, "Upgrade") self.imgs = [] self.damage = 1 self.place_color = (0, 0, 255, 100) def draw(self, win): # TODO: dodaj wiecej spritow zeby pokazac ulepszanie wiez, ustawione normalnie na self.level - 1 img = self.imgs[0] 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): if self.selected: # draw range circle circle_surface = pygame.Surface((self.range * 2, self.range * 2), pygame.SRCALPHA, 32) pygame.draw.circle(circle_surface, (128, 128, 128, 100), (self.range, self.range), self.range, 0) win.blit(circle_surface, (self.x - self.range, self.y - self.range)) def draw_placement(self, win): # draw range circle surface = pygame.Surface((self.range * 4, self.range * 4), pygame.SRCALPHA, 32) pygame.draw.circle(surface, self.place_color, (50, 50), 50, 0) win.blit(surface, (self.x - 50, self.y - 50)) def click(self, X, Y): """Returns if tower has been clicked on and selects tower if it was clicked""" # tu zmienione również z self.level - 1 na 0 z powodu brakow spritow img = self.imgs[0] 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 upgrade(self): """Upgrades towers to higher tier at given cost""" # instead of next sprites is only block by number if self.level < len(self.price): self.level += 1 self.damage += 1 return True else: return False def get_upgrade_cost(self): return self.price[self.level - 1] 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) if dis >= 100: return False else: return True
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 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