def handle_mouseup(self, event, drag=False): # It's simply a timing error if self.screen.selected_actors == []: return relative_pos = (event.pos[0] - self.position.left, event.pos[1] - self.position.top) col = math.floor(relative_pos[0] / self.grid_size[0]) row = math.floor(relative_pos[1] / self.grid_size[1]) col_count = int(math.floor(self.size[0] / self.grid_size[0])) index = int((col_count * row) + col) # No button there? Ignore the click but they clicked the menu # so we don't want to pass this back to the screen if index >= len(self.buttons): return True # Get the information for the button item_name, item_image, queue_length = self.buttons[index] # What are we looking at? if item_name in self.screen.actor_types: actor_type = self.screen.actor_types[item_name] if "placement_image" in actor_type: # It has a placement image, it's placed by the player self.screen.place_actor_mode(item_name) else: # No placement image, the actor is added to the build queue # and placed later # TODO: Make this game-specific rule go in a game-specific file # When starting Downstream this errored choice = (None, 999999) for a in self.screen.selected_actors: if actor_lib.can_build( self.screen.actor_types[a.actor_type], actor_type, self.screen.build_lists): if len(a.build_queue) < choice[1]: choice = (a, len(a.build_queue)) if choice[0] != None: choice[0].build_queue.append(item_name) self.update_queue_sizes() else: raise Exception( """Cannot build that unit using current selection: item_name = %s Selection: %s""" % (item_name, [a.actor_type for a in self.screen.selected_actors])) else: raise Exception("Not found in actor types") return True
def handle_mouseup(self, event, drag=False): # It's simply a timing error if self.screen.selected_actors == []: return relative_pos = (event.pos[0] - self.position.left, event.pos[1] - self.position.top) col = math.floor(relative_pos[0]/self.grid_size[0]) row = math.floor(relative_pos[1]/self.grid_size[1]) col_count = int(math.floor(self.size[0]/self.grid_size[0])) index = int((col_count * row) + col) # No button there? Ignore the click but they clicked the menu # so we don't want to pass this back to the screen if index >= len(self.buttons): return True # Get the information for the button item_name, item_image, queue_length = self.buttons[index] # What are we looking at? if item_name in self.screen.actor_types: actor_type = self.screen.actor_types[item_name] if "placement_image" in actor_type: # It has a placement image, it's placed by the player self.screen.place_actor_mode(item_name) else: # No placement image, the actor is added to the build queue # and placed later # TODO: Make this game-specific rule go in a game-specific file # When starting Downstream this errored choice = (None, 999999) for a in self.screen.selected_actors: if actor_lib.can_build(self.screen.actor_types[a.actor_type], actor_type, self.screen.build_lists): if len(a.build_queue) < choice[1]: choice = (a, len(a.build_queue)) if choice[0] != None: choice[0].build_queue.append(item_name) self.update_queue_sizes() else: raise Exception("""Cannot build that unit using current selection: item_name = %s Selection: %s""" % (item_name, [a.actor_type for a in self.screen.selected_actors])) else: raise Exception("Not found in actor types") return True
def construct_attack(self, base_name): the_base = self.bases[base_name] attacker_list = the_base['attacks'][the_base['current_attack']] missing = {} found = [] for a in attacker_list: if a not in missing: missing[a] = 0 missing[a] += 1 # Find out what we've got in the base that fits into # the list of units we plan to attack with for a in the_base['current_buildings']: the_actor = self.own_actors[a] if the_actor.actor_type in missing: if missing[the_actor.actor_type] > 0: missing[the_actor.actor_type] -= 1 found.append(a) # We now have a list of what we're missing total_missing = sum([v for k, v in missing.items()]) if total_missing == 0: # Do stuff self.commence_attack(base_name, found) else: builders = {} for a_type, amount in missing.items(): if a_type not in builders: builders[a_type] = [] for b in the_base['current_buildings']: the_builder = self.own_actors[b].actor_type if actor_lib.can_build( builder_type=self.actor_types[the_builder], item_type=self.actor_types[a_type], build_lists=self.build_lists, ): builders[a_type].append(b) # Now we find out if any of them have a slot in their queue free for b in builders[a_type]: the_builder = self.own_actors[b] if the_builder.build_queue == []: self.issue_orders(b, "build", pos=None, target=a_type)
def construct_attack(self, base_name): the_base = self.bases[base_name] attacker_list = the_base['attacks'][the_base['current_attack']] missing = {} found = [] for a in attacker_list: if a not in missing: missing[a] = 0 missing[a] += 1 # Find out what we've got in the base that fits into # the list of units we plan to attack with for a in the_base['current_buildings']: the_actor = self.own_actors[a] if the_actor.actor_type in missing: if missing[the_actor.actor_type] > 0: missing[the_actor.actor_type] -= 1 found.append(a) # We now have a list of what we're missing total_missing = sum([v for k,v in missing.items()]) if total_missing == 0: # Do stuff self.commence_attack(base_name, found) else: builders = {} for a_type, amount in missing.items(): if a_type not in builders: builders[a_type] = [] for b in the_base['current_buildings']: the_builder = self.own_actors[b].actor_type if actor_lib.can_build( builder_type = self.actor_types[the_builder], item_type = self.actor_types[a_type], build_lists = self.build_lists, ): builders[a_type].append(b) # Now we find out if any of them have a slot in their queue free for b in builders[a_type]: the_builder = self.own_actors[b] if the_builder.build_queue == []: self.issue_orders(b, "build", pos=None, target=a_type)
def plan_attacks(self): for base_name, base_data in self.bases.items(): # Has it already selected an attack? if base_data['current_attack'] != None: # TODO check to see if attack has been constructed self.construct_attack(base_name) continue # Find out which of the attacks it can make buildable_attacks = set() buildable_units = set() unbuildable_units = set() for attack_id, attacker_list in base_data['attacks'].items(): cannot_build_attack = False for a in attacker_list: if a in buildable_units: continue if a in unbuildable_units: cannot_build_attack = True continue is_buildable = False for b in base_data['current_buildings']: the_builder = self.own_actors[b].actor_type if actor_lib.can_build( builder_type = self.actor_types[the_builder], item_type = self.actor_types[a], build_lists = self.build_lists, ): is_buildable = True if is_buildable: buildable_units.add(a) else: unbuildable_units.add(a) cannot_build_attack = True if cannot_build_attack == True: continue buildable_attacks.add(attack_id) # Pick an attack to build, it'll get sorted in the next logic cycle if len(buildable_attacks) > 0: a = random.choice(list(buildable_attacks)) base_data['current_attack'] = a
def plan_attacks(self): for base_name, base_data in self.bases.items(): # Has it already selected an attack? if base_data['current_attack'] != None: # TODO check to see if attack has been constructed self.construct_attack(base_name) continue # Find out which of the attacks it can make buildable_attacks = set() buildable_units = set() unbuildable_units = set() for attack_id, attacker_list in base_data['attacks'].items(): cannot_build_attack = False for a in attacker_list: if a in buildable_units: continue if a in unbuildable_units: cannot_build_attack = True continue is_buildable = False for b in base_data['current_buildings']: the_builder = self.own_actors[b].actor_type if actor_lib.can_build( builder_type=self.actor_types[the_builder], item_type=self.actor_types[a], build_lists=self.build_lists, ): is_buildable = True if is_buildable: buildable_units.add(a) else: unbuildable_units.add(a) cannot_build_attack = True if cannot_build_attack == True: continue buildable_attacks.add(attack_id) # Pick an attack to build, it'll get sorted in the next logic cycle if len(buildable_attacks) > 0: a = random.choice(list(buildable_attacks)) base_data['current_attack'] = a
def place_actor_from_click(self, event, drag, actor_data): self.place_image = None actor_data['pos'] = [event.pos[0] - self.draw_margin[0], event.pos[1] - self.draw_margin[1], 0] actor_data['team'] = self.player_team # If holding the shift key, allow them to continue placing mods = pygame.key.get_mods() if KMOD_SHIFT & mods: self.place_actor_mode(actor_data['type']) builders = [] for a in self.selected_actors: if actor_lib.can_build(self.actor_types[a.actor_type], self.actor_types[actor_data['type']], self.build_lists): builders.append(a) return self.place_actor(actor_data, builders=builders)
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])