Example #1
0
File: a3.py Project: mj221/CSSE1001
class CoinTower(SimpleTower):
    """Tower that supplies coin for use. 1 tower gains 3 coins each interval (it makes use of the in game steps).
       2 towers = 4, 3 towers = 5 coins, etc.
    """
    name = "Coin Supply"

    colour = 'gold'

    cool_down_steps = 45
    base_cost = 40
    level_cost = 60

    range = DonutRange(0,0) # Give a range of 0 to prevent targeting of enemies

    rotation_threshold = (1 / 3) * math.pi

    def __init__(self, cell_size: int, grid_size=(.9, .9), rotation=math.pi * .25, base_damage=150, level: int = 1):
        super().__init__(cell_size, grid_size=grid_size, rotation=rotation, base_damage=base_damage, level=level)
        self._earning_rate = 1  # However due to the step interval in-game, the player earns 3 coins for first tower
        EarntCoins._counter += 1    # Counter allows the player to stack up coin earning rates when two or more coin supply is placed
    def step(self, units):
        self.cool_down.step()
        if not self.cool_down.is_done():
            # Stop the tower from earning coins during the cooldown process.
            EarntCoins._earnings = 0
            return None
        else:
            EarntCoins._earnings = self._earning_rate
            self.cool_down.start()
Example #2
0
class MissileTower(SimpleTower):
    """A tower that fires missiles that track a target"""
    name = 'Missile Tower'
    colour = 'snow'

    cool_down_steps = 10

    base_cost = 80
    level_cost = 60

    range = DonutRange(1.5, 4.5)

    rotation_threshold = (1 / 3) * math.pi

    def __init__(self,
                 cell_size: int,
                 grid_size=(.9, .9),
                 rotation=math.pi * .25,
                 base_damage=150,
                 level: int = 1):
        super().__init__(cell_size,
                         grid_size=grid_size,
                         rotation=rotation,
                         base_damage=base_damage,
                         level=level)

        self._target: AbstractEnemy = None

    def _get_target(self, units) -> Union[AbstractEnemy, None]:
        """Returns previous target, else selects new one if previous is invalid
        
        Invalid target is one of:
            - dead
            - out-of-range
        
        Return:
            AbstractEnemy: Returns previous target, unless it is non-existent or invalid (see above),
                           Otherwise, selects & returns new target if a valid one can be found,
                           Otherwise, returns None
        """
        if self._target is None \
                or self._target.is_dead() \
                or not self.is_position_in_range(self._target.position):
            self._target = self.get_unit_in_range(units)

        return self._target

    def step(self, units):
        """Rotates toward 'target' and fires missile if possible"""
        self.cool_down.step()

        target = self._get_target(units.enemies)

        if target is None:
            return None

        # Rotate toward target
        angle = angle_between(self.position, target.position)
        partial_angle = rotate_toward(self.rotation, angle,
                                      self.rotation_threshold)

        self.rotation = partial_angle

        if angle != partial_angle or not self.cool_down.is_done():
            return None

        self.cool_down.start()

        # Spawn missile on tower
        missile = Missile(self.position,
                          self.cell_size,
                          target,
                          rotation=self.rotation,
                          damage=self.get_damage(),
                          grid_speed=.3)

        # Move missile to outer edge of tower
        radius = self.grid_size[0] / 2
        delta = polar_to_rectangular(self.cell_size * radius, partial_angle)
        missile.move_by(delta)

        return [missile]
Example #3
0
class TurretTower(SimpleTower):
    """A tower that has turrets to attack a target"""
    name = 'Turret Tower'
    colour = 'dark grey'

    cool_down_steps = 1

    base_cost = 250
    level_cost = 98

    range = DonutRange(0, 1.1)

    rotation_threshold = (1 / 3) * math.pi

    def __init__(self,
                 cell_size: int,
                 grid_size=(.9, .9),
                 rotation=math.pi * .25,
                 base_damage=25,
                 level: int = 1):
        super().__init__(cell_size,
                         grid_size=grid_size,
                         rotation=rotation,
                         base_damage=base_damage,
                         level=level)

        self._target: AbstractEnemy = None

    def _get_target(self, units) -> Union[AbstractEnemy, None]:
        if self._target is None \
                or self._target.is_dead() \
                or not self.is_position_in_range(self._target.position):
            self._target = self.get_unit_in_range(units)

        return self._target

    def step(self, units):
        """Rotates toward 'target' and fires if possible"""
        self.cool_down.step()

        target = self._get_target(units.enemies)

        if target is None:
            return None

        # Rotate toward target
        angle = angle_between(self.position, target.position)
        partial_angle = rotate_toward(self.rotation, angle,
                                      self.rotation_threshold)

        self.rotation = partial_angle

        if angle != partial_angle or not self.cool_down.is_done():
            return None

        self.cool_down.start()

        # Spawn missile on tower
        turret = Turret(self.position,
                        self.cell_size,
                        target,
                        rotation=self.rotation,
                        damage=self.get_damage(),
                        grid_speed=.5)

        # Move missile to outer edge of tower
        radius = self.grid_size[0] / 2
        delta = polar_to_rectangular(self.cell_size * radius, partial_angle)
        turret.move_by(delta)

        return [turret]