class BasicModule(): '''Basic Module: literally just a tin can''' def __init__(self, logger=None): self.id = util.register(self) print self.id if not hasattr(self,'size'): self.size = np.array([ 3 , 2 , 2 ]) self.stowage = Stowage(10) #things floating around in the module self.exterior_stowage = Stowage(0) #things strapped to the outside of the module self.sprite = None self.gravity = np.array([ 0 , 0 , 0 ]) self.max_gravity = 0.01 self.min_gravity = 0 self.orientation = np.array([ math.pi/4 , 0 ]) self.location = np.array([ 0 , 0 , 0 ]) self.composition = {'Al' : 14500} self.package_material = [] #if a list of filters, material put in this will not be removed self.station = None self.manifest=None self.logger = logging.getLogger(logger.name + '.' + self.name) if logger else util.generic_logger self.loggername = self.logger.name self.atmo = Atmosphere() self.atmo.volume= math.pi * 2*self.size[0] * pow (self.size[1], 2) self.atmo.initialize('Air') self.equipment=dict() #miscellaneous (or unremovable) non-rack equipment self.player_installable = True self.paths = nx.Graph() self.nodes=dict() self.touched = False self.refresh_image() def __getstate__(self): d = dict(self.__dict__) del d['logger'] del d['sprite'] return d def __setstate__(self, d): self.__dict__.update(d) self.logger = logging.getLogger(self.loggername) if self.loggername else util.generic_logger self.sprite=None self.refresh_image() def refresh_image(self): if not gv.config['GRAPHICS']: return if gv.config['GRAPHICS'] == 'pyglet': if self.sprite: self.sprite.delete() self.sprite = util.make_solid_sprite(int(2*self.size[0]*gv.config['ZOOM']),int(2*self.size[1]*gv.config['ZOOM']),(128,128,128,255),None,None,self.location[0],self.location[1], self.orientation[0],batch = util.station_batch) self.sprite.owner = self elif gv.config['GRAPHICS'] == 'cocos2d': self.sprite = util.make_solid_sprite(int(2*self.size[0]*gv.config['ZOOM']),int(2*self.size[1]*gv.config['ZOOM']),(128,128,128,255),None,None,self.location[0],self.location[1], self.orientation[0]) if self.station: self.station.sprite.add(self.sprite) def new_manifest(self): self.manifest = manifest.Manifest(self) def search(self, filter_, **kwargs): hits=[] if "Equipment" in filter_.comparison_type or 'All' in filter_.comparison_type: hits.extend([[self.equipment[e][3], self.node( e ), filter_.compare(self.equipment[e][3]) ] for e in self.equipment.keys() if self.equipment[e][3]]) s = self.stowage.search( filter_ ) if hasattr(s,'local_coords'): snode = self.node( self.nearest_hall_node(s.local_coords) ) else: snode = self.filterNode( self.node('Inside') ) hits.append( [ s, snode, s != None ] ) #hits.append( self.exterior_stowage.find_resource( filter_ ) ) if "Equipment Slot" in filter_.comparison_type or 'All' in filter_.comparison_type: hits.extend([[self.equipment[e][2], self.node( e ), filter_.compare(self.equipment[e][2]) ] for e in self.equipment.keys() if not self.equipment[e][3] and self.player_installable]) if "Clutter" in filter_.comparison_type: s = self.stowage.search( filter_ ) if hasattr(s,'local_coords'): snode = self.node( self.nearest_hall_node(s.local_coords) ) else: snode = self.filterNode( self.node('Inside') ) hits.append( [ s, snode, s != None ] ) random.shuffle(hits) hits.sort(key=lambda tup: tup[2], reverse=True) return hits[0] if hits and hits[0][2] else [None, None, False] def get_living_space(self): return self.stowage.free_space living_space = property(get_living_space, None, None, "Living space" ) #exterior_space = self.exterior_stowage.free_space def compute_short_id(self): return string.upper(self.id[0:6]) short_id = property(compute_short_id, None, None, "Short ID" ) def get_mass(self): return sum([self.composition.values()]) mass = property(get_mass, None, None, "Total mass" ) def node(self, to_append): return ''.join( [ self.id, '|', to_append ] ) def getXYZ(self,offset): return absolute_xyz(self.location, offset, self.orientation, self.size) def filterNode(self,node): [ module, name ] = separate_node(node) if module != self.id: return None if name == "Inside": return random.choice(self.nodes.keys()) return node def mix_neighbor(self,neighbor,amt=1.0): self.atmo.mix( neighbor.atmo, 1.0 ) def update(self, dt): for e in self.equipment: if self.equipment[e][3]: self.equipment[e][3].update( dt ) self.stowage.update(dt) self.exterior_stowage.update(dt) #if 'Equipment' not in self.package_material: # for c in self.stowage.contents: # if isinstance(c,Equipment) and not c.installed and not c.task: # c.install_task(self.station) if self.manifest: satisfaction = self.manifest.check_satisfied() #print satisfaction if random.random() < 0.05: #atmo mix with neighbors for n in self.get_neighbors(): self.mix_neighbor(n) def get_random_dock(self, side_port_allowed=True, unused = True, used = False): docks=[] if unused: docks.extend([f for f in self.equipment.keys() if self.equipment[f][2] in DOCK_EQUIPMENT and self.equipment[f][3] and not self.equipment[f][3].docked and ( side_port_allowed or not ( '2' in f or '3' in f ) ) and self.equipment[f][3].player_usable ]) if used: docks.extend([f for f in self.equipment.keys() if self.equipment[f][2] in DOCK_EQUIPMENT and self.equipment[f][3] and self.equipment[f][3].docked and ( side_port_allowed or not ( '2' in f or '3' in f ) ) and self.equipment[f][3].player_usable ]) if not docks: return None return random.choice(docks) def get_neighbors(self, equipment=False): out=[] for e in [f for f in self.equipment.keys() if self.equipment[f][2] in DOCK_EQUIPMENT and self.equipment[f][3] and self.equipment[f][3].docked ]: if not equipment: out.append(self.equipment[e][3].partner.installed) else: out.append(self.equipment[e][3]) return out def get_neighbor(self,station=None): for n in self.get_neighbors(): if station and n.station == station: return n return None def percolate(self): if self.touched: return [] out = [self] self.touched=True for n in self.get_neighbors(): out.extend(n.percolate()) return out def percolate_location(self): if self.touched: return self.touched = True for e in self.get_neighbors(equipment=True): #update e's partner's module's location n = e.partner.installed if not n.touched: n.adjust_location(e.partner.get_name(),self,e.get_name()) n.refresh_image() #call n n.percolate_location() def get_empty_slot(self,slot_type='LSS'): if not self.player_installable: return None slots = [s for s in self.equipment.keys() if ( self.equipment[s][2] == slot_type or slot_type=='ANY' ) and not self.equipment[s][3]] if not slots: return None return random.choice(slots) def get_node(self,equip): for f in self.equipment.keys(): if self.equipment[f][3] == equip: return self.node(f) return None def uninstall_equipment(self,equip): for f in self.equipment.keys(): if self.equipment[f][3] == equip: self.equipment[f][3] = None self.stowage.add( equip ) return True return False def adjust_location(self,my_node,neighbor,their_node): self.orientation = ( neighbor.orientation + neighbor.equipment[their_node][1] - self.equipment[my_node][1] ) + np.array([math.pi, 0]) self.orientation %= 2*math.pi #calculate location self.location=np.array([ 0,0,0 ]) loc_offset = self.getXYZ(self.equipment[my_node][0]) self.location = neighbor.getXYZ(neighbor.equipment[their_node][0]) - loc_offset def dock(self, my_node, neighbor, their_node): if not neighbor or not my_node or not their_node: return False, "Docking cancelled: pointers missing" if not my_node in self.equipment or not their_node in neighbor.equipment: return False, "Docking cancelled: wrong module, I guess?" if not self.equipment[my_node][2] in DOCK_EQUIPMENT or not neighbor.equipment[their_node][2] in DOCK_EQUIPMENT: return False, "Docking cancelled: requested interface(s) are not docking equipment!" if self.equipment[my_node][2] != neighbor.equipment[their_node][2]: return False, "Docking cancelled: incompatible docking mechanisms" if self.equipment[my_node][3].docked or neighbor.equipment[their_node][3].docked: return False, "Docking cancelled: at least one module already docked elsewhere" self.adjust_location(my_node,neighbor,their_node) #collision detection if neighbor.station: if not self.station: self.station = neighbor.station self.station.paths.add_nodes_from(self.paths.nodes()) self.station.paths.add_edges_from(self.paths.edges(data=True)) self.refresh_station() else: neighbor.station = self.station if self.station: self.station.paths.add_nodes_from(neighbor.paths.nodes()) self.station.paths.add_edges_from(neighbor.paths.edges(data=True)) neighbor.refresh_station() neighbor.refresh_image() self.refresh_image() return True def connect(self, my_node, neighbor, their_node, instant=False): #dock, finally self.equipment[my_node][3].dock( neighbor, neighbor.equipment[their_node][3], instant) neighbor.equipment[their_node][3].dock( self, self.equipment[my_node][3], instant ) def disconnect(self, my_node, their_node, instant=False): #dock, finally a = self.equipment[my_node][3].undock( instant ) b = their_node.undock( instant ) return a and b def add_edge(self,one,two): delta = self.nodes[two] - self.nodes[one] #numpy vector subtraction, I hope delta *= self.size mag = abs( np.sqrt( np.vdot( delta , delta ) ) ) self.paths.add_edge(one,two,weight=mag) def add_edge_list(self,edges): for e in range(1,len(edges)): self.add_edge( self.node( edges[ e - 1 ] ), self.node( edges[ e ] ) ) def nearest_hall_node(self,coords): all_nodes = [separate_node(n)[1] for n in self.nodes.keys()] hall_nodes = [n for n in all_nodes if not n in self.equipment.keys()] hall_nodes.sort(key=lambda t: util.vec_dist( self.nodes[self.node( t )] , coords ), reverse=False) return hall_nodes[0] def add_equipment(self, eq_node, eq_obj, eq_coords, hall_node=None, eq_orientation=np.array([ 0 , 0]), eq_type='MISC' ): if not hall_node: hall_node = self.nearest_hall_node(eq_coords) node_coords = self.nodes[ self.node( hall_node ) ] + ( eq_coords - self.nodes[ self.node( hall_node ) ] ) self.nodes[self.node(eq_node)] = node_coords self.add_edge( self.node(hall_node), self.node(eq_node) ) self.equipment[ eq_node ] = [ eq_coords, eq_orientation, eq_type, eq_obj] def refresh_station(self, station=None): if station and station != self.station: self.station = station if gv.config['GRAPHICS'] == 'cocos2d': self.station.sprite.add(self.sprite) if self.manifest: self.manifest.refresh_station(self.station) for e in self.equipment: if self.equipment[e][3]: self.equipment[e][3].refresh_station() def draw(self,window): zoom=gv.config['ZOOM'] #self.img.blit(zoom*self.location[0]+window.width // 2, zoom*self.location[1]+window.height // 2, 0) if hasattr(self.sprite, 'update_sprite'): l=self.location self.sprite.update_sprite(zoom*l[0], zoom*l[1],-180*(self.orientation[0])/math.pi) if self.sprite: self.sprite.draw() for e in self.equipment.keys(): if self.equipment[e][3] and self.equipment[e][3].visible: l=self.getXYZ(self.equipment[e][0]) #rotimg=self.equipment[e][3].img.get_transform self.equipment[e][3].sprite.update_sprite(zoom*l[0], zoom*l[1],-180*(self.equipment[e][1][0]+self.orientation[0])/math.pi) #self.equipment[e][3].sprite.set_position(zoom*l[0], zoom*l[1]) #self.equipment[e][3].sprite.rotation = -180*(self.equipment[e][1][0]+self.orientation[0])/math.pi self.equipment[e][3].sprite.draw()#img.blit(zoom*l[0]+window.width // 2, zoom*l[1]+window.height // 2, 0) for c in self.stowage.contents: if hasattr(c,'sprite') and hasattr(c,'local_coords') and c.sprite: loc_xyz = self.getXYZ( 1.0*c.local_coords ) c.sprite.set_position(zoom*loc_xyz[0],zoom*loc_xyz[1]) #c.sprite.rotation = (-180/math.pi)*self.orientation[0] c.sprite.visible=True c.sprite.draw()
class BasicModule(): '''Basic Module: literally just a tin can''' def __init__(self): self.id = str(uuid.uuid4()) if not hasattr(self,'size'): self.size = np.array([ 3 , 2 , 2 ]) self.stowage = Stowage(10) #things floating around in the module self.exterior_stowage = Stowage(0) #things strapped to the outside of the module self.sprite = None self.gravity = np.array([ 0 , 0 , 0 ]) self.max_gravity = 0.01 self.min_gravity = 0 self.orientation = np.array([ math.pi/4 , 0 ]) self.location = np.array([ 0 , 0 , 0 ]) self.composition = {'Al' : 14500} self.package_material = [] #if a list of filters, material put in this will not be removed self.station = None self.atmo = Atmosphere() self.atmo.volume= math.pi * 2*self.size[0] * pow (self.size[1], 2) self.atmo.initialize('Air') self.equipment=dict() #miscellaneous (or unremovable) non-rack equipment self.paths = nx.Graph() self.nodes=dict() self.refresh_image() def refresh_image(self): if not util.GRAPHICS: return if True:#not hasattr(self,'imgfile'): if util.GRAPHICS: self.img = util.make_solid_image(int(2*self.size[0]*util.ZOOM),int(2*self.size[1]*util.ZOOM),(128,128,128,255)) else: self.imgfile = "images/module_placeholder.jpg" #if hasattr(self,'imgfile'): # self.img = util.load_image(self.imgfile) '''if math.sin(self.orientation[0]) < 0: self.img = self.img.get_transform(flip_y=True) #TODO replace with different image altogether if math.cos(self.orientation[0]) < 0: self.img = self.img.get_transform(flip_x=True) ''' self.sprite = util.image_to_sprite(self.img,self.location[0],self.location[1], self.orientation[0]) def search(self, filter_): hits=[] if "Equipment" in filter_.comparison_type or 'All' in filter_.comparison_type: hits.extend([[self.equipment[e][3], self.node( e ), filter_.compare(self.equipment[e][3]) ] for e in self.equipment.keys() if self.equipment[e][3]]) hits.append( [ self.stowage.search( filter_ ), self.filterNode( self.node('Inside') ), self.stowage.search( filter_ ) != None ] ) #hits.append( self.exterior_stowage.find_resource( filter_ ) ) if "Equipment Slot" in filter_.comparison_type or 'All' in filter_.comparison_type: hits.extend([[self.equipment[e][2], self.node( e ), filter_.compare(self.equipment[e][2]) ] for e in self.equipment.keys() if not self.equipment[e][3]]) if "Clutter" in filter_.comparison_type: hits.append( [ self.stowage.search( filter_ ), self.filterNode( self.node('Inside') ), self.stowage.search( filter_ ) != None ] ) random.shuffle(hits) hits.sort(key=lambda tup: tup[2], reverse=True) #print hits return hits[0] if hits and hits[0][2] else [None, None, False] def get_living_space(self): return self.stowage.free_space living_space = property(get_living_space, None, None, "Living space" ) #exterior_space = self.exterior_stowage.free_space def compute_short_id(self): return string.upper(self.id[0:6]) short_id = property(compute_short_id, None, None, "Short ID" ) def get_mass(self): return sum([self.composition.values()]) mass = property(get_mass, None, None, "Total mass" ) def node(self, to_append): return ''.join( [ self.id, '|', to_append ] ) def getXYZ(self,offset): return absolute_xyz(self.location, offset, self.orientation, self.size) def filterNode(self,node): [ module, name ] = separate_node(node) if module != self.id: return None if name == "Inside": return random.choice(self.nodes.keys()) return node def update(self, dt): for e in self.equipment: if self.equipment[e][3]: self.equipment[e][3].update( dt ) self.stowage.update(dt) self.exterior_stowage.update(dt) if 'Equipment' not in self.package_material: for c in self.stowage.contents: if isinstance(c,Equipment) and not c.installed and not c.task: c.install_task(self.station) def get_random_dock(self, side_port_allowed=True): docks=[f for f in self.equipment.keys() if self.equipment[f][2] in DOCK_EQUIPMENT and self.equipment[f][3] and not self.equipment[f][3].docked and ( side_port_allowed or not ( '2' in f or '3' in f ) ) ] if not docks: return None return random.choice(docks) def get_empty_slot(self,slot_type='LSS'): slots = [s for s in self.equipment.keys() if ( self.equipment[s][2] == slot_type or slot_type=='ANY' ) and not self.equipment[s][3]] if not slots: return None return random.choice(slots) def uninstall_equipment(self,equip): for f in self.equipment.keys(): if self.equipment[f][3] == equip: self.equipment[f][3] = None self.stowage.add( equip ) return True return False def berth(self, my_node, neighbor, their_node, instant=False): if not neighbor or not my_node or not their_node: return False, "Docking cancelled: pointers missing" if not my_node in self.equipment or not their_node in neighbor.equipment: return False, "Docking cancelled: wrong module, I guess?" if not self.equipment[my_node][2] in DOCK_EQUIPMENT or not neighbor.equipment[their_node][2] in DOCK_EQUIPMENT: return False, "Docking cancelled: requested interface(s) are not docking equipment!" if self.equipment[my_node][2] != neighbor.equipment[their_node][2]: return False, "Docking cancelled: incompatible docking mechanisms" if self.equipment[my_node][3].docked or neighbor.equipment[their_node][3].docked: return False, "Docking cancelled: at least one module already docked elsewhere" #calculate orientation self.orientation = ( neighbor.orientation + neighbor.equipment[their_node][1] - self.equipment[my_node][1] ) + np.array([math.pi, 0]) #calculate location self.location=np.array([ 0,0,0 ]) loc_offset = self.getXYZ(self.equipment[my_node][0]) self.location = neighbor.getXYZ(neighbor.equipment[their_node][0]) - loc_offset self.orientation %= 2*math.pi #collision detection #dock, finally self.equipment[my_node][3].dock( neighbor, neighbor.equipment[their_node][3], instant) neighbor.equipment[their_node][3].dock( self, self.equipment[my_node][3], instant ) # map graphs together if neighbor.station: if self.station: print self.station, neighbor.station assert False, "Station merging not in yet" #TODO replace with station merge else: self.station = neighbor.station self.station.paths.add_nodes_from(self.paths.nodes()) self.station.paths.add_edges_from(self.paths.edges(data=True)) self.station.paths.add_edge(self.node(my_node),neighbor.node(their_node),weight=1) self.refresh_equipment() else: neighbor.station = self.station if self.station: self.station.paths.add_nodes_from(neighbor.paths.nodes()) self.station.paths.add_edges_from(neighbor.paths.edges(data=True)) self.station.paths.add_edge(self.node(my_node),neighbor.node(their_node),weight=1) neighbor.refresh_equipment() neighbor.refresh_image() self.refresh_image() return True def add_edge(self,one,two): delta = self.nodes[two] - self.nodes[one] #numpy vector subtraction, I hope delta *= self.size mag = abs( np.sqrt( np.vdot( delta , delta ) ) ) self.paths.add_edge(one,two,weight=mag) def add_edge_list(self,edges): for e in range(1,len(edges)): self.add_edge( self.node( edges[ e - 1 ] ), self.node( edges[ e ] ) ) def add_equipment(self, eq_node, eq_obj, eq_coords, hall_node=None, eq_orientation=np.array([ 0 , 0]), eq_type='MISC' ): if not hall_node: all_nodes = [separate_node(n)[1] for n in self.nodes.keys()] hall_nodes = [n for n in all_nodes if not n in self.equipment.keys()] hall_nodes.sort(key=lambda t: util.vec_dist( self.nodes[self.node( t )] , eq_coords ), reverse=False) #print [util.vec_dist( self.nodes[self.node( t )] , eq_coords ) for t in hall_nodes] hall_node = hall_nodes[0] node_coords = self.nodes[ self.node( hall_node ) ] + ( eq_coords - self.nodes[ self.node( hall_node ) ] ) self.nodes[self.node(eq_node)] = node_coords self.add_edge( self.node(hall_node), self.node(eq_node) ) self.equipment[ eq_node ] = [ eq_coords, eq_orientation, eq_type, eq_obj] def refresh_equipment(self): for e in self.equipment: if self.equipment[e][3]: self.equipment[e][3].refresh_station() def draw(self,window): zoom=util.ZOOM #self.img.blit(zoom*self.location[0]+window.width // 2, zoom*self.location[1]+window.height // 2, 0) self.sprite.draw() for c in self.stowage.contents: if hasattr(c,'sprite') and hasattr(c,'local_coords') and c.sprite: loc_xyz = self.getXYZ( 0.8*c.local_coords ) c.sprite.set_position(zoom*loc_xyz[0],zoom*loc_xyz[1]) c.sprite.rotation = (-180/math.pi)*self.orientation[0] c.sprite.draw() for e in self.equipment.keys(): if self.equipment[e][3] and self.equipment[e][3].visible: l=self.getXYZ(self.equipment[e][0]) #rotimg=self.equipment[e][3].img.get_transform self.equipment[e][3].sprite.update_sprite(zoom*l[0], zoom*l[1],-180*(self.equipment[e][1][0]+self.orientation[0])/math.pi)