def can_use(self, target=None, **kwargs): if not super(RepairAbility, self).can_use(target, **kwargs): return False if vectors.distance(self.actor.pos, target.pos) > self.max_range: return False if self.min_range > 0: if vectors.distance(self.actor.pos, target.pos) < self.min_range: return False if self.actor.team != target.team: return False # Is the ally still under construction? if target.completion < 100: return False # Is the ally hurt? if target.hp >= target.max_hp: return False # Finally, can we afford it? cost = teams.multiply_cost(target._part_repair_cost, self.repair_rate) if not self.actor.team_obj.can_afford(cost): return False return True
def run_ai(self): if self.micro_orders == []: cmd, pos, target = self.current_order else: cmd, pos, target = self.micro_orders[0] self._passive_ai() self._attack_ai() self._help_ai() if cmd == "stop" or cmd == "hold position": self.velocity = [0, 0, 0] if target == 0: self.next_order() elif cmd == "move": self._move_ai(pos) if vectors.distance(self.pos, pos) <= vectors.total_velocity(self.velocity): self.pos = pos self.velocity = [0, 0, 0] self.next_order() elif cmd == "attack": target = self.get_first_target() # If we have a target, lets move closer to it if target != None: # First, are we within optimum range of our target? # If not then we need to get closer target_distance = vectors.distance(self.pos, target.pos) if target_distance > self.optimum_attack_range: attack_pos = vectors.get_midpoint(self.pos, target.pos, self.optimum_attack_range) self._move_ai(attack_pos) else: # If we are close enough then we can slow down self._decelerate_ai() elif cmd == "aid": if target == None: target = self.get_first_ally() # If we have a target, lets move closer to it if target != None: dist = vectors.distance(self.pos, target.pos) if dist > self.optimum_heal_range: target_pos = vectors.get_midpoint(self.pos, target.pos, self.optimum_heal_range) self._move_ai(target_pos) else: self._decelerate_ai() else: raise Exception("No handler for cmd %s (pos: %s, target: %s)" % (cmd, pos, target)) # Do we have something to build? if self.build_queue != []: pass
def explode(self, actors): for a in actors: if vectors.distance(self.pos, a.pos) <= self.blast_radius: actor_lib.apply_damage(a, dissipate( self.damage, vectors.distance(self.pos, a.pos), self.blast_radius, self.dissipation_func) ) return self.generate_effect()
def __init__(self, actor, ability_data={}): super(Ability, self).__init__() self.actor = actor self.facing = [0,0] self.set_stats(ability_data) self.charge = self.required_charge self._effect_offset_distance = vectors.distance(self.effect_offset) self._effect_offset_angle = vectors.angle(self.effect_offset) self._img_offset_distance = vectors.distance(self.image_offset) self._img_offset_angle = vectors.angle(self.image_offset)
def __init__(self, actor, ability_data={}): super(Ability, self).__init__() self.actor = actor self.facing = [0, 0] self.set_stats(ability_data) self.charge = self.required_charge self._effect_offset_distance = vectors.distance(self.effect_offset) self._effect_offset_angle = vectors.angle(self.effect_offset) self._img_offset_distance = vectors.distance(self.image_offset) self._img_offset_angle = vectors.angle(self.image_offset)
def can_use(self, target=None, **kwargs): """Called to see if the ability can be used""" if self.charge < self.required_charge: return False if vectors.distance(self.actor.pos, target.pos) > self.max_range: return False if self.min_range > 0: if vectors.distance(self.actor.pos, target.pos) < self.min_range: return False return True
def can_use(self, target=None, **kwargs): if not super(WeaponAbility, self).can_use(target, **kwargs): return False if vectors.distance(self.actor.pos, target.pos) > self.max_range: return False if self.min_range > 0: if vectors.distance(self.actor.pos, target.pos) < self.min_range: return False if self.actor.team == target.team: return False return True
def _accelerate_ai(self, target): dist = vectors.distance(self.pos, target) if dist > self.max_velocity: self.velocity = vectors.move_to_vector(vectors.angle(self.pos, target), self.max_velocity) else: self.velocity = vectors.move_to_vector(vectors.angle(self.pos, target), dist)
def generate_bullet(self, target): # Set correct origin offset_angle = vectors.bound_angle( vectors.add_vectors(self._effect_offset_angle, self.facing) ) origin_pos = vectors.add_vectors(self.get_offset_pos(use_effect_offset=True), self.actor.pos) # Get actual velocity we'll be using if type(target) == list or type(target) == tuple: direction = vectors.angle(origin_pos, target) target_pos = target else: direction = vectors.angle(origin_pos, target.pos) target_pos = target.pos velocity = vectors.move_to_vector(direction, self.bullet['velocity']) velocity[2] = math_lib.calc_trajectory(0.1, vectors.distance(origin_pos, target_pos), self.bullet['velocity']) the_bullet = bullets.Shell( pos=origin_pos, velocity=velocity, image = self.bullet['image'], size = self.bullet['size'], blast_radius = self.bullet['blast_radius'], damage = self.bullet['damage'], dissipation_func = self.bullet.get('dissipation_func', "linear"), ) self.actor.bullets.append(the_bullet)
def generate_bullet(self, target): # Set correct origin offset_angle = vectors.bound_angle( vectors.add_vectors(self._effect_offset_angle, self.facing)) origin_pos = vectors.add_vectors( self.get_offset_pos(use_effect_offset=True), self.actor.pos) # Get actual velocity we'll be using if type(target) == list or type(target) == tuple: direction = vectors.angle(origin_pos, target) target_pos = target else: direction = vectors.angle(origin_pos, target.pos) target_pos = target.pos velocity = vectors.move_to_vector(direction, self.bullet['velocity']) velocity[2] = math_lib.calc_trajectory( 0.1, vectors.distance(origin_pos, target_pos), self.bullet['velocity']) the_bullet = bullets.Shell( pos=origin_pos, velocity=velocity, image=self.bullet['image'], size=self.bullet['size'], blast_radius=self.bullet['blast_radius'], damage=self.bullet['damage'], dissipation_func=self.bullet.get('dissipation_func', "linear"), ) self.actor.bullets.append(the_bullet)
def run_ai(self): if self.micro_orders == []: cmd, pos, target = self.current_order else: cmd, pos, target = self.micro_orders[0] self._attack_ai() if cmd == "stop" or cmd == "hold position": self.velocity = [0,0,0] if target == 0: self.next_order() elif cmd == "move" or cmd == "reverse": dist = vectors.distance(self.pos, pos) self.velocity = vectors.move_to_vector(vectors.angle(self.pos, pos), self.max_velocity) if dist <= vectors.total_velocity(self.velocity): self.pos = pos self.velocity = [0,0,0] self.next_order() else: raise Exception("No handler for cmd %s (pos: %s, target: %s)" % (cmd, pos, target))
def __init__(self, filepath, columns=1, rows=1, animation_rate = 0.5, rotate_about=None): super(Animation, self).__init__() if columns < 1: raise Exception("Cannot have fewer than 1 column in an animation") if rows < 1: raise Exception("Cannot have fewer than 1 row in an animation") self.images = [] self.animation_rate = animation_rate img = pygame.image.load(filepath) r = img.get_rect() # Break it down into tiles, save the tiles tile_width = r.width / columns tile_height = r.height / rows for y in range(rows): for x in range(columns): tile = pygame.Surface((tile_width, tile_height), SRCALPHA) tile.blit(img, (0,0), (x * tile_width, y * tile_height, tile_width, tile_height)) self.images.append(tile) # Default the rotate about point if rotate_about == None: rotate_about = 0, 0, 0 # centre_offset is a distance and angle self.centre_offset = ( vectors.distance(rotate_about), vectors.angle(rotate_about), )
def update_actor(self, the_actor): the_actor.enemy_targets = [] for a in self.enemy_actors: dist = vectors.distance(a.pos, the_actor.pos) if dist <= the_actor.max_attack_range: the_actor.enemy_targets.append(a)
def _accelerate_ai(self, target): dist = vectors.distance(self.pos, target) if dist > self.max_velocity: self.velocity = vectors.move_to_vector( vectors.angle(self.pos, target), self.max_velocity) else: self.velocity = vectors.move_to_vector( vectors.angle(self.pos, target), dist)
def test_distance(self): vals = ( # 2D ([0, 0], [0, 0], 0), ([1, 1], [0, 0], 1.41), ([3, 4], [0, 0], 5), ([3, 0], [0, 0], 3), # 3D ([0, 0, 0], [0, 0, 0], 0), ([1, 1, 1], [0, 0, 0], 1.73), ([3, 4, 0], [0, 0, 0], 5), ([3, 0, 4], [0, 0, 0], 5), ) for a, b, expected in vals: self.assertAlmostEqual(vectors.distance(a, b), expected, places=2)
def test_distance(self): vals = ( # 2D ([0,0], [0,0], 0), ([1,1], [0,0], 1.41), ([3,4], [0,0], 5), ([3,0], [0,0], 3), # 3D ([0,0,0], [0,0,0], 0), ([1,1,1], [0,0,0], 1.73), ([3,4,0], [0,0,0], 5), ([3,0,4], [0,0,0], 5), ) for a, b, expected in vals: self.assertAlmostEqual(vectors.distance(a, b), expected, places=2)
def __init__(self, filepath, columns=1, rows=1, animation_rate=0.5, rotate_about=None): super(Animation, self).__init__() if columns < 1: raise Exception("Cannot have fewer than 1 column in an animation") if rows < 1: raise Exception("Cannot have fewer than 1 row in an animation") self.images = [] self.animation_rate = animation_rate img = pygame.image.load(filepath) r = img.get_rect() # Break it down into tiles, save the tiles tile_width = r.width / columns tile_height = r.height / rows for y in range(rows): for x in range(columns): tile = pygame.Surface((tile_width, tile_height), SRCALPHA) tile.blit( img, (0, 0), (x * tile_width, y * tile_height, tile_width, tile_height)) self.images.append(tile) # Default the rotate about point if rotate_about == None: rotate_about = 0, 0, 0 # centre_offset is a distance and angle self.centre_offset = ( vectors.distance(rotate_about), vectors.angle(rotate_about), )
def generate_bullet(self, target): if type(target) == list or type(target) == tuple: direction = vectors.angle(self.actor.pos, target) target_pos = target else: direction = vectors.angle(self.actor.pos, target.pos) target_pos = target.pos velocity = vectors.move_to_vector(direction, self.bullet['velocity']) velocity[2] = math_lib.calc_trajectory(0.1, vectors.distance(self.actor.pos, target_pos), self.bullet['velocity']) the_bullet = bullets.Shell( pos=self.actor.pos, velocity=velocity, image = self.bullet['image'], size = self.bullet['size'], blast_radius = self.bullet['blast_radius'], damage = self.bullet['damage'], dissipation_func = self.bullet.get('dissipation_func', "linear"), ) self.actor.bullets.append(the_bullet)
def inspect_bases(self): # First find out which buildings we are missing for base_name, base_data in self.bases.items(): base_area = ( base_data['location'][0] - base_data['size'][0], base_data['location'][1] - base_data['size'][1], base_data['location'][0] + base_data['size'][0], base_data['location'][1] + base_data['size'][1], ) buildings_needed = set(base_data['buildings']) # Reset this now base_data['current_buildings'] = [] # Get all buildings within this base found_buildings = {} total_needed = {} for b in buildings_needed: found_buildings[b] = 0 total_needed[b] = 0 for b in base_data['buildings']: total_needed[b] += 1 # Loop through all actors and see what we've got for i, a in self.own_actors.items(): if actor_lib.is_inside(a, base_area): if a.actor_type in buildings_needed: found_buildings[a.actor_type] += 1 if a.completion >= 100: base_data['current_buildings'].append(a.oid) # Now also loop through all the buildings_in_progress # Use a range loop so we can update the list as we go for i in range(len(base_data['buildings_in_progress'])-1, -1, -1): b, ttl = base_data['buildings_in_progress'][i] if ttl <= 0: del(base_data['buildings_in_progress'][i]) continue base_data['buildings_in_progress'][i][1] -= 1 if b in found_buildings: found_buildings[b] += 1 # Now find out what we are missing missing = {} for b in buildings_needed: m = total_needed[b] - found_buildings[b] if m > 0: missing[b] = m # None missing? We can stop looking around now if missing == {}: continue # Now find out which builders we can use # Narrow down our list of builders so we don't later iterate over # non-builders more than once builders = [] builders_used = [] for aid, a in self.own_actors.items(): if self.actor_types[a.actor_type]['can_construct']: if a.current_order[0] == "stop": builders.append(a) # Now we work out which buildings we can build and who is closest to it for building_type, amount in missing.items(): for i in range(amount): target_pos = base_data['location'] closest_builder = None, 9999999 for b in builders: if b in builders_used: continue if actor_lib.can_build( builder_type = self.actor_types[b.actor_type], item_type = self.actor_types[building_type], build_lists = self.build_lists, ): # If they are closest we want them to go build it dist = vectors.distance(target_pos, b.pos) if dist < closest_builder[1]: closest_builder = b, dist # Now remove them from the pool and issue the build order if closest_builder[0] != None: builders_used.append(closest_builder[0]) self.issue_orders(closest_builder[0].oid, cmd="build", pos=target_pos, target=building_type) base_data['buildings_in_progress'].append([building_type, buildings_in_progress_ttl])
def inspect_bases(self): # First find out which buildings we are missing for base_name, base_data in self.bases.items(): base_area = ( base_data['location'][0] - base_data['size'][0], base_data['location'][1] - base_data['size'][1], base_data['location'][0] + base_data['size'][0], base_data['location'][1] + base_data['size'][1], ) buildings_needed = set(base_data['buildings']) # Reset this now base_data['current_buildings'] = [] # Get all buildings within this base found_buildings = {} total_needed = {} for b in buildings_needed: found_buildings[b] = 0 total_needed[b] = 0 for b in base_data['buildings']: total_needed[b] += 1 # Loop through all actors and see what we've got for i, a in self.own_actors.items(): if actor_lib.is_inside(a, base_area): if a.actor_type in buildings_needed: found_buildings[a.actor_type] += 1 if a.completion >= 100: base_data['current_buildings'].append(a.oid) # Now also loop through all the buildings_in_progress # Use a range loop so we can update the list as we go for i in range( len(base_data['buildings_in_progress']) - 1, -1, -1): b, ttl = base_data['buildings_in_progress'][i] if ttl <= 0: del (base_data['buildings_in_progress'][i]) continue base_data['buildings_in_progress'][i][1] -= 1 if b in found_buildings: found_buildings[b] += 1 # Now find out what we are missing missing = {} for b in buildings_needed: m = total_needed[b] - found_buildings[b] if m > 0: missing[b] = m # None missing? We can stop looking around now if missing == {}: continue # Now find out which builders we can use # Narrow down our list of builders so we don't later iterate over # non-builders more than once builders = [] builders_used = [] for aid, a in self.own_actors.items(): if self.actor_types[a.actor_type]['can_construct']: if a.current_order[0] == "stop": builders.append(a) # Now we work out which buildings we can build and who is closest to it for building_type, amount in missing.items(): for i in range(amount): target_pos = base_data['location'] closest_builder = None, 9999999 for b in builders: if b in builders_used: continue if actor_lib.can_build( builder_type=self.actor_types[b.actor_type], item_type=self.actor_types[building_type], build_lists=self.build_lists, ): # If they are closest we want them to go build it dist = vectors.distance(target_pos, b.pos) if dist < closest_builder[1]: closest_builder = b, dist # Now remove them from the pool and issue the build order if closest_builder[0] != None: builders_used.append(closest_builder[0]) self.issue_orders(closest_builder[0].oid, cmd="build", pos=target_pos, target=building_type) base_data['buildings_in_progress'].append( [building_type, buildings_in_progress_ttl])
def run_ai(self): if self.micro_orders == []: cmd, pos, target = self.current_order else: cmd, pos, target = self.micro_orders[0] self._passive_ai() self._attack_ai() self._help_ai() if cmd == "stop" or cmd == "hold position": self.velocity = [0, 0, 0] if target == 0: self.next_order() elif cmd == "move": self._move_ai(pos) if vectors.distance(self.pos, pos) <= vectors.total_velocity( self.velocity): self.pos = pos self.velocity = [0, 0, 0] self.next_order() elif cmd == "attack": target = self.get_first_target() # If we have a target, lets move closer to it if target != None: # First, are we within optimum range of our target? # If not then we need to get closer target_distance = vectors.distance(self.pos, target.pos) if target_distance > self.optimum_attack_range: attack_pos = vectors.get_midpoint( self.pos, target.pos, self.optimum_attack_range) self._move_ai(attack_pos) else: # If we are close enough then we can slow down self._decelerate_ai() elif cmd == "aid": if target == None: target = self.get_first_ally() # If we have a target, lets move closer to it if target != None: dist = vectors.distance(self.pos, target.pos) if dist > self.optimum_heal_range: target_pos = vectors.get_midpoint(self.pos, target.pos, self.optimum_heal_range) self._move_ai(target_pos) else: self._decelerate_ai() else: raise Exception("No handler for cmd %s (pos: %s, target: %s)" % (cmd, pos, target)) # Do we have something to build? if self.build_queue != []: pass