115 lines
4.8 KiB
Python
115 lines
4.8 KiB
Python
import pygame
|
|
import math
|
|
from game.config import TOWER_DATA, COLOR_BLACK, COLOR_WHITE
|
|
from game.utils import distance
|
|
from game.projectile import Projectile
|
|
|
|
|
|
class Tower:
|
|
def __init__(self, tower_type, grid_col, grid_row, px, py):
|
|
data = TOWER_DATA[tower_type]
|
|
self.type = tower_type
|
|
self.col = grid_col
|
|
self.row = grid_row
|
|
self.x = px
|
|
self.y = py
|
|
self.damage = data["damage"]
|
|
self.range = data["range"]
|
|
self.fire_rate = data["fire_rate"]
|
|
self.price = data["price"]
|
|
self.color = data["color"]
|
|
self.name = data["name"]
|
|
self.splash = data.get("splash", 0)
|
|
self.slow_factor = data.get("slow_factor", 0)
|
|
self.slow_duration = data.get("slow_duration", 0)
|
|
self.poison_dps = data.get("poison_dps", 0)
|
|
self.poison_duration = data.get("poison_duration", 0)
|
|
self.chain_count = data.get("chain_count", 0)
|
|
self.chain_range = data.get("chain_range", 0)
|
|
self.chain_decay = data.get("chain_decay", 0)
|
|
self.cooldown = 0
|
|
self.target = None
|
|
|
|
def find_target(self, enemies):
|
|
self.target = None
|
|
best = None
|
|
best_progress = -1
|
|
for e in enemies:
|
|
if not e.alive:
|
|
continue
|
|
d = distance(self.x, self.y, e.x, e.y)
|
|
if d <= self.range:
|
|
wp_idx = min(e.waypoint_index, len(e.waypoints) - 1)
|
|
progress = e.waypoint_index + (1 - distance(e.x, e.y, *e.waypoints[wp_idx]) / 100)
|
|
if progress > best_progress:
|
|
best_progress = progress
|
|
best = e
|
|
self.target = best
|
|
|
|
def _wp(self, idx):
|
|
if self.target and idx < len(self.target.waypoints):
|
|
return self.target.waypoints[idx]
|
|
if self.target:
|
|
return self.target.waypoints[-1]
|
|
from game.config import PATH_WAYPOINTS
|
|
return PATH_WAYPOINTS[-1]
|
|
|
|
def update(self, dt, enemies, projectiles):
|
|
if self.cooldown > 0:
|
|
self.cooldown -= dt
|
|
|
|
self.find_target(enemies)
|
|
|
|
if self.target and self.cooldown <= 0:
|
|
self.cooldown = self.fire_rate
|
|
proj_type = {
|
|
"arrow": "arrow", "cannon": "cannon", "slow": "slow",
|
|
"sniper": "sniper", "poison": "poison", "lightning": "lightning",
|
|
}[self.type]
|
|
projectiles.append(Projectile(
|
|
self.x, self.y, self.target, self.damage,
|
|
proj_type=proj_type, splash=self.splash,
|
|
slow_factor=self.slow_factor, slow_duration=self.slow_duration,
|
|
poison_dps=self.poison_dps, poison_duration=self.poison_duration,
|
|
chain_count=self.chain_count, chain_range=self.chain_range, chain_decay=self.chain_decay,
|
|
))
|
|
|
|
def draw(self, surface):
|
|
ix, iy = int(self.x), int(self.y)
|
|
if self.type == "arrow":
|
|
pygame.draw.rect(surface, self.color, (ix - 12, iy - 12, 24, 24))
|
|
pygame.draw.rect(surface, COLOR_BLACK, (ix - 12, iy - 12, 24, 24), 2)
|
|
elif self.type == "cannon":
|
|
pygame.draw.circle(surface, self.color, (ix, iy), 14)
|
|
pygame.draw.circle(surface, COLOR_BLACK, (ix, iy), 14, 2)
|
|
pygame.draw.circle(surface, (180, 100, 30), (ix, iy), 8)
|
|
elif self.type == "slow":
|
|
points = [(ix, iy - 14), (ix + 14, iy), (ix, iy + 14), (ix - 14, iy)]
|
|
pygame.draw.polygon(surface, self.color, points)
|
|
pygame.draw.polygon(surface, COLOR_BLACK, points, 2)
|
|
elif self.type == "sniper":
|
|
pts = [(ix, iy - 16), (ix + 14, iy + 12), (ix - 14, iy + 12)]
|
|
pygame.draw.polygon(surface, self.color, pts)
|
|
pygame.draw.polygon(surface, COLOR_BLACK, pts, 2)
|
|
pygame.draw.line(surface, (200, 200, 255), (ix, iy - 10), (ix, iy + 6), 2)
|
|
elif self.type == "poison":
|
|
pts = []
|
|
for i in range(6):
|
|
angle = math.pi / 3 * i - math.pi / 6
|
|
pts.append((ix + int(14 * math.cos(angle)), iy + int(14 * math.sin(angle))))
|
|
pygame.draw.polygon(surface, self.color, pts)
|
|
pygame.draw.polygon(surface, COLOR_BLACK, pts, 2)
|
|
elif self.type == "lightning":
|
|
pts = [
|
|
(ix - 2, iy - 14), (ix + 6, iy - 4), (ix, iy - 4),
|
|
(ix + 4, iy + 14), (ix - 4, iy + 2), (ix + 1, iy + 2),
|
|
]
|
|
pygame.draw.polygon(surface, self.color, pts)
|
|
pygame.draw.polygon(surface, COLOR_BLACK, pts, 2)
|
|
|
|
if self.target and self.target.alive:
|
|
pygame.draw.line(surface, (*self.color, ), (ix, iy), (int(self.target.x), int(self.target.y)), 1)
|
|
|
|
def draw_range(self, surface):
|
|
pygame.draw.circle(surface, COLOR_WHITE, (int(self.x), int(self.y)), self.range, 1)
|