class Movement(DirectObject.DirectObject): def __init__(self, parent): self.parent = parent self.hovered_unit_id = None self.hovered_tile = None self.hovered_compass_tile = None self.mouse_node = aspect2d.attachNewNode('mouse_node') self.move_node = aspect2d.attachNewNode('move_node') self.move_outline_node = NodePath('') self.move_np_list = [] self.target_info_node = None self.accept("mouse1", self.mouseLeftClick) self.accept("mouse1-up", self.mouseLeftClickUp) #taskMgr.add(self.rayupdate, 'rayupdate_task') taskMgr.add(self.pickerTask, 'picker_task') taskMgr.add(self.positionTask, 'position_task', sort=2) self.color_scale_parallel = None # Create movement compass nodes self.turn_node = NodePath('turn_node') self.turn_node.setTag('show', '0') self.turn_np_list = [] for i in xrange(9): text = TextNode('node name') text.setAlign(TextNode.ACenter) if i == 0: text.setText('NW') key = utils.HEADING_NW elif i == 1: text.setText('N') key = utils.HEADING_N elif i == 2: text.setText('NE') key = utils.HEADING_NE elif i == 3: text.setText('W') key = utils.HEADING_W elif i == 4: text.setText('E') key = utils.HEADING_E elif i == 5: text.setText('SW') key = utils.HEADING_SW elif i == 6: text.setText('S') key = utils.HEADING_S elif i == 7: text.setText('SE') key = utils.HEADING_SE elif i == 8: text.setText('X') key = utils.HEADING_NONE textNodePath = self.turn_node.attachNewNode(text) textNodePath.setColor(1, 1, 1) textNodePath.setScale(0.06) textNodePath.setTag('key', str(key)) self.turn_np_list.append(textNodePath) def calcUnitAvailMove(self, unit_id): """Displays visual indicator of tiles which are in movement range of the selected unit.""" # First delete old movement list for c in self.move_np_list: c.removeNode() self.move_np_list = [] # Start calculation of new list unit = self.parent.local_engine.units[unit_id] if self.parent.turn_player != self.parent.player_id: return if unit: unit['move_dict'] = getMoveDict(unit, self.parent.local_engine.level, self.parent.local_engine.units) self.parent.local_engine.units[unit_id]['move_dict'] = unit[ 'move_dict'] move_dict = unit['move_dict'] for tile in move_dict: text = TextNode('node name') text.setText("%s" % move_dict[tile]) text.setAlign(TextNode.ACenter) textNodePath = self.move_node.attachNewNode(text) textNodePath.setColor(1, 1, 1) textNodePath.setScale(0.06) textNodePath.setPythonTag('pos', tile) pos2d = utils.pointCoordIn2d( Point3(utils.TILE_SIZE * (tile[0] + 0.5), utils.TILE_SIZE * (tile[1] + 0.5), utils.GROUND_LEVEL)) textNodePath.setPos(pos2d) self.move_np_list.append(textNodePath) def showUnitAvailMove(self): self.move_node.reparentTo(aspect2d) self.hovered_tile = None #self.drawMoveOutline(self.calcMoveOutline(move_dict, self.parent.local_engine.units[unit_id]['pos'])) def hideUnitAvailMove(self): self.move_node.detachNode() """ def calcMoveOutline(self, move_dict, pos): outline = {} for tile in move_dict: dir = [] if not (tile[0]-1, tile[1]) in move_dict and (tile[0]-1, tile[1]) != pos: dir.append('W') if not (tile[0], tile[1]-1) in move_dict and (tile[0], tile[1]-1) != pos: dir.append('S') if not (tile[0]+1, tile[1]) in move_dict and (tile[0]+1, tile[1]) != pos: dir.append('E') if not (tile[0], tile[1]+1) in move_dict and (tile[0], tile[1]+1) != pos: dir.append('N') if dir != []: outline[tile] = dir return outline def drawMoveOutline(self, outline): self.move_outline_node.removeNode() zpos = utils.GROUND_LEVEL + 0.01 off = 0.1 segs = LineSegs() segs.setThickness(3) segs.setColor(Vec4(0.686,1,0.992,1)) for tile in outline: for dir in outline[tile]: if dir == 'N': d1 = 0 d2 = 0 if (tile[0]+1, tile[1]) in outline and 'N' in outline[(tile[0]+1, tile[1])]: d2 = off elif (tile[0]+1, tile[1]+1) in outline: d2 = 2*off if (tile[0]-1, tile[1]) in outline and 'N' in outline[(tile[0]-1, tile[1])]: d1 = off elif (tile[0]-1, tile[1]+1) in outline: d1 = 2*off segs.moveTo(tile[0]+off-d1, tile[1]+1-off, zpos) segs.drawTo(tile[0]+1-off+d2, tile[1]+1-off, zpos) elif dir == 'S': d1 = 0 d2 = 0 if (tile[0]+1, tile[1]) in outline and 'S' in outline[(tile[0]+1, tile[1])]: d2 = off elif (tile[0]+1, tile[1]-1) in outline: d2 = 2*off if (tile[0]-1, tile[1]) in outline and 'S' in outline[(tile[0]-1, tile[1])]: d1 = off elif (tile[0]-1, tile[1]-1) in outline: d1 = 2*off segs.moveTo(tile[0]+off-d1, tile[1]+off, zpos) segs.drawTo(tile[0]+1-off+d2, tile[1]+off, zpos) elif dir == 'W': d1 = 0 d2 = 0 if (tile[0], tile[1]+1) in outline and 'W' in outline[(tile[0], tile[1]+1)]: d2 = off elif (tile[0]-1, tile[1]+1) in outline: d2 = 2*off if (tile[0], tile[1]-1) in outline and 'W' in outline[(tile[0], tile[1]-1)]: d1 = off elif (tile[0]-1, tile[1]-1) in outline: d1 = 2*off segs.moveTo(tile[0]+off, tile[1]+off-d1, zpos) segs.drawTo(tile[0]+off, tile[1]+1-off+d2, zpos) elif dir == 'E': d1 = 0 d2 = 0 if (tile[0], tile[1]+1) in outline and 'E' in outline[(tile[0], tile[1]+1)]: d2 = off elif (tile[0]+1, tile[1]+1) in outline: d2 = 2*off if (tile[0], tile[1]-1) in outline and 'E' in outline[(tile[0], tile[1]-1)]: d1 = off elif (tile[0]+1, tile[1]-1) in outline: d1 = 2*off segs.moveTo(tile[0]+1-off, tile[1]+off-d1, zpos) segs.drawTo(tile[0]+1-off, tile[1]+1-off+d2, zpos) self.move_outline_node = render.attachNewNode(segs.create()) self.move_outline_node.setBin("fixed", 40) #self.move_outline_node.setDepthTest(False) #self.move_outline_node.setDepthWrite(False) self.move_outline_node.setLightOff() """ def showMoveCompass(self, dest): # Calculate postion of compass nodes based on destination tile for i in self.turn_np_list: i.setPythonTag('pos', utils.getHeadingTile(i.getTag('key'), dest)) # Show compass nodes self.turn_node.reparentTo(aspect2d) self.turn_node.setPythonTag('pos', dest) self.turn_node.setTag('show', '1') # Hide move nodes self.move_node.detachNode() def hideMoveCompass(self): # Hide compass nodes self.turn_node.detachNode() self.turn_node.setTag('show', '0') if self.hovered_compass_tile != None: self.hovered_compass_tile.setColor(1, 1, 1) self.hovered_compass_tile.setScale(0.05) self.color_scale_parallel.pause() self.hovered_compass_tile = None def mouseLeftClick(self): if self.parent.interface.hovered_gui != None: return if self.hovered_unit_id != None: unit_id = int(self.hovered_unit_id) pickedCoord = self.parent.local_engine.getCoordsByUnit(unit_id) # Player can only select his own units if self.parent.local_engine.isThisMyUnit(unit_id): if unit_id != self.parent.sel_unit_id: self.parent.selectUnit(unit_id) else: # Remember movement tile so we can send orientation message when mouse is depressed # Do this only if it is our turn if self.parent.player_id == self.parent.turn_player: self.unit_move_destination = pickedCoord self.showMoveCompass(self.unit_move_destination) elif self.parent.local_engine.isThisEnemyUnit(unit_id): if self.parent.sel_unit_id != None and self.parent.player_id == self.parent.turn_player: self.parent.render_manager.unit_renderer_dict[ self.parent. sel_unit_id].target_unit = self.parent.render_manager.unit_renderer_dict[ unit_id] if self.parent._anim_in_process == False: ClientMsg.shoot(self.parent.sel_unit_id, unit_id) elif self.hovered_tile != None: if self.parent.sel_unit_id != None and self.parent.player_id == self.parent.turn_player: # Remember movement tile so we can send movement message when mouse is depressed # Do this only if it is our turn move_coord = self.hovered_tile.getPythonTag('pos') if self.parent.local_engine.units[self.parent.sel_unit_id][ 'move_dict'].has_key(move_coord): self.unit_move_destination = move_coord self.showMoveCompass(self.unit_move_destination) def mouseLeftClickUp(self): """Handles left mouse click actions when mouse button is depressed. Used for unit movement. """ o = None if self.hovered_compass_tile != None: x = self.turn_node.getPythonTag('pos')[0] y = self.turn_node.getPythonTag('pos')[1] orientation = int(self.hovered_compass_tile.getTag('key')) if orientation == utils.HEADING_NW: o = Point2(x - 1, y + 1) elif orientation == utils.HEADING_N: o = Point2(x, y + 1) elif orientation == utils.HEADING_NE: o = Point2(x + 1, y + 1) elif orientation == utils.HEADING_W: o = Point2(x - 1, y) elif orientation == utils.HEADING_E: o = Point2(x + 1, y) elif orientation == utils.HEADING_SW: o = Point2(x - 1, y - 1) elif orientation == utils.HEADING_S: o = Point2(x, y - 1) elif orientation == utils.HEADING_SE: o = Point2(x + 1, y - 1) else: o = None self.hideMoveCompass() if o != None: ClientMsg.move(self.parent.sel_unit_id, (x, y), (o.x, o.y)) def positionTask(self, task): # If turn node is displayed, you have to cancel turning or turn to be able to pick another unit or another tile to move to if self.turn_node.getTag('show') == '1': for tile in self.turn_np_list: pos = Point3( utils.TILE_SIZE * (tile.getPythonTag('pos')[0] + 0.5), utils.TILE_SIZE * (tile.getPythonTag('pos')[1]) + 0.5, utils.GROUND_LEVEL) pos2d = utils.pointCoordIn2d(pos) tile.setPos(pos2d) else: for unit in self.parent.render_manager.unit_renderer_dict.itervalues( ): p = utils.nodeCoordIn2d(unit.model) unit.node_2d.setPos(p) for tile in self.move_np_list: pos = Point3( utils.TILE_SIZE * (tile.getPythonTag('pos')[0] + 0.5), utils.TILE_SIZE * (tile.getPythonTag('pos')[1] + 0.5), utils.GROUND_LEVEL) pos2d = utils.pointCoordIn2d(pos) tile.setPos(pos2d) return task.cont def pickerTask(self, task): if self.parent._anim_in_process: self.hovered_unit_id = None self.hovered_tile = None self.hovered_compass_tile = None return task.cont if self.parent.interface.hovered_gui != None: if self.hovered_unit_id != None: self.parent.render_manager.unit_marker_renderer.unmarkHovered( self.hovered_unit_id) self.hovered_unit_id = None if self.hovered_tile != None and not self.hovered_tile.isEmpty(): self.hovered_tile.setColor(1, 1, 1) self.hovered_tile.setScale(0.05) self.color_scale_parallel.pause() if self.hovered_compass_tile != None and not self.hovered_compass_tile.isEmpty( ): self.hovered_compass_tile.setColor(1, 1, 1) self.hovered_compass_tile.setScale(0.05) self.color_scale_parallel.pause() return task.cont min_distance = 0.5 min_unit_id = None min_tile = None min_compass_tile = None if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() r2d = Point3(mpos.getX(), 0, mpos.getY()) a2d = aspect2d.getRelativePoint(render2d, r2d) self.mouse_node.setPos(a2d) # At the end of all this we have: # - min_distance to a unit or a movement node, IF this distance is lower than 0.5 which is set at the beginning # - min_unit_id - ID of unit which is closest to the mouse, or None if there is a movement tile closer, or if everything is further than 0.5 # - min_tile - nodepath of the movement tile closest to the mouse, or None if there is a unit closer, or if evertythin is further than 0.5 if self.turn_node.getTag('show') == '1': # Get 2d coordinates for every compass node for tile in self.turn_np_list: # We cannot do nodepath.getDistance() because tiles are reparented to self.turn_node and are in different coord space than mouse node # So we do simple vector math to get distance d = Vec3(self.mouse_node.getPos() - tile.getPos()).length() if d < min_distance: min_distance = d min_unit_id = None min_tile = None min_compass_tile = tile else: # Get 2d coordinates of all units for unit_id in self.parent.render_manager.unit_renderer_dict: unit = self.parent.render_manager.unit_renderer_dict[ unit_id] if self.parent.local_engine.isThisMyUnit(unit_id): # Calculate distance between every friendly unit and mouse cursor and remember closest unit d = self.mouse_node.getDistance(unit.node_2d) if d < min_distance: min_distance = d min_unit_id = unit_id else: # Calculate distance between every enemy unit and mouse cursor and remember closest unit d = self.mouse_node.getDistance(unit.node_2d) # To target enemy unit, distance has to be even smaller than needed for regular selection/movement if d < min_distance and d < 0.1: min_distance = d min_unit_id = unit_id # Get 2d coordinates for every movement node of the selected unit for tile in self.move_np_list: # We cannot do nodepath.getDistance() because tiles are reparented to self.move_node and are in different coord space than mouse node # So we do simple vector math to get distance d = Vec3(self.mouse_node.getPos() - tile.getPos()).length() if d < min_distance: min_distance = d min_unit_id = None min_tile = tile # If a unit is the closest to the mouse: # - hide movement nodes (Incubation style!) # - unmark last hovered unit # - unmark last hovered tile # - mark new hovered unit # TODO: ogs: potencijalna optimizacija da se provjeri da li je self.hovered_unit_id = min_unit_id, tada ne treba unmark+mark if min_compass_tile != None: if self.hovered_tile != None and not self.hovered_tile.isEmpty(): self.hovered_tile.setColor(1, 1, 1) self.hovered_tile.setScale(0.05) self.color_scale_parallel.pause() self.hovered_tile = None if min_compass_tile != self.hovered_compass_tile: if self.hovered_compass_tile != None and not self.hovered_compass_tile.isEmpty( ): self.hovered_compass_tile.setColor(1, 1, 1) self.hovered_compass_tile.setScale(0.05) self.color_scale_parallel.pause() min_compass_tile.setColor(1, 0, 0) s1 = Sequence( LerpColorInterval(min_compass_tile, 0.5, (1, 1, 0, 1)), LerpColorInterval(min_compass_tile, 0.5, (1, 0, 0, 1))) s2 = Sequence(LerpScaleInterval(min_compass_tile, 0.5, (0.1)), LerpScaleInterval(min_compass_tile, 0.5, (0.05))) self.color_scale_parallel = Parallel(s1, s2) self.color_scale_parallel.loop() self.hovered_compass_tile = min_compass_tile elif min_unit_id != None: self.move_node.detachNode() if min_unit_id != self.hovered_unit_id and self.hovered_unit_id != None: if self.parent.render_manager.unit_renderer_dict.has_key( int(self.hovered_unit_id)): self.parent.render_manager.unit_marker_renderer.unmarkHovered( self.hovered_unit_id) self.parent.render_manager.unit_marker_renderer.markHovered( min_unit_id) if self.hovered_tile != None and not self.hovered_tile.isEmpty(): self.hovered_tile.setColor(1, 1, 1) self.hovered_tile.setScale(0.05) self.color_scale_parallel.pause() self.hovered_tile = None self.hovered_unit_id = min_unit_id # If a movement tile is closest to the mouse: # - unmark last hovered unit # - unmark last marked tile # - show movement nodes (Incubation style!) # - mark new hovered tile elif min_tile != None: if self.hovered_unit_id != None: if self.parent.render_manager.unit_renderer_dict.has_key( int(self.hovered_unit_id)): self.parent.render_manager.unit_marker_renderer.unmarkHovered( self.hovered_unit_id) self.hovered_unit_id = None if min_tile != self.hovered_tile: self.move_node.reparentTo(aspect2d) if self.hovered_tile != None and not self.hovered_tile.isEmpty( ): self.hovered_tile.setColor(1, 1, 1) self.hovered_tile.setScale(0.05) self.color_scale_parallel.pause() min_tile.setColor(1, 0, 0) s1 = Sequence(LerpColorInterval(min_tile, 0.5, (1, 1, 0, 1)), LerpColorInterval(min_tile, 0.5, (1, 0, 0, 1))) s2 = Sequence(LerpScaleInterval(min_tile, 0.5, (0.1)), LerpScaleInterval(min_tile, 0.5, (0.05))) self.color_scale_parallel = Parallel(s1, s2) self.color_scale_parallel.loop() self.hovered_tile = min_tile # If neither any of the units nor any of the movement tiles is closer than 0.5: # - unmark last hovered unit # - unmark last hovered tile else: if self.hovered_unit_id != None: if self.parent.render_manager.unit_renderer_dict.has_key( int(self.hovered_unit_id)): self.parent.render_manager.unit_marker_renderer.unmarkHovered( self.hovered_unit_id) self.hovered_unit_id = None if self.hovered_tile != None and not self.hovered_tile.isEmpty(): self.hovered_tile.setColor(1, 1, 1) self.hovered_tile.setScale(0.05) self.color_scale_parallel.pause() self.hovered_tile = None if self.hovered_compass_tile != None and not self.hovered_compass_tile.isEmpty( ): self.hovered_compass_tile.setColor(1, 1, 1) self.hovered_compass_tile.setScale(0.05) self.color_scale_parallel.pause() self.hovered_compass_tile = None return task.cont