def kill_escaped(self): ''' Kill all sprites related to a plane that left the aerospace. ''' for plane in self.__planes.values(): s = self.surface.get_rect() x, y = plane['sprites'][0].position if x < 0 or x > s.width or y < 0 or y > s.height: # This is the worst scenario msg = 'Tower? ... Tower? ... Aaaaahhhh!' event = S.PLANE_LEAVES_RANDOM colour = S.KO_COLOUR crossed = self.__get_crossed_gates(plane['plane']) # This might be better for gate in crossed: msg = 'Tower? It doesn\'t seem we are where we should...' event = S.PLANE_LEAVES_WRONG_GATE #little better! if gate.name == plane['plane'].destination and \ plane['plane'].altitude % 1000 == 0: msg = 'Thank you tower, and good bye!' colour = S.OK_COLOUR event = S.PLANE_LEAVES_CORRECT_GATE #yay! :) plane['plane'].pilot.say(msg, colour) self.gamelogic.remove_plane(plane['plane'], event) log.info('%s left aerospace under event %s' % (plane['plane'].icao, event)) log.debug('Data at exit was: %s' % plane['plane'].get_current_configuration())
def msg_append(self, colour, text): ''' Append a message to the console. ''' log.debug(text) wrapped = textwrap.wrap(text, width=self.max_small_line_length, subsequent_indent=' ' * S.CONSOLE_INDENTATION) for line in wrapped: self.console_lines.append((colour, line))
def process_commands(self, commands): ''' Process commands. This is a "subroutine" of ``execute`` which is also called by some of the procedures. This is such that is possible to process commands without triggering score events and setting flags (as it happens with ``execute()``). This method will silently pass if the command name has not been recognised. This is to allow the method to process set of commands that also contains *procedures* (such LAND, TAKEOFF, etc...). ''' pi = self.pilot pl = self.plane tc = self.pilot.target_conf for cname, (args, flags) in commands.items(): log.info('%s executes: %s' % (pl.icao, ' '.join((cname, repr(args), repr(flags))))) # PROCESS COMMANDS # Since flags are "universal" across commands (they all do the same # thing if they are called the same), it is possible to process # them separately. if cname == 'HEADING': assert len(args) == 1 tc.heading = args[0] pi.status['veer_dir'] = \ pi.navigator.get_shortest_veering_direction() elif cname == 'ALTITUDE': tc.altitude = args[0] elif cname == 'SPEED': tc.speed = args[0] elif cname == 'ABORT': self.abort() elif cname == 'SQUAWK': if pl.flags.on_ground: pi.say('Currently at airport %s, our destination is %s' % (pl.origin, pl.destination), S.OK_COLOUR) else: pi.say('Currently heading %s, our destination is %s' % (U.rint(pl.heading), pl.destination), S.OK_COLOUR) else: log.debug('process_commands() ignored: %s' % cname) # PROCESS FLAGS # Flags with the same name have the same meaning and therefore # can be processed independently from the command they are # associated with. Since they can modify the value set by their # command, they must follow the command processing if 'EXPEDITE' in flags: pi.status['haste'] = 'expedite' if 'LONG' in flags: pi.status['veer_dir'] *= -1 #invert direction
def _toggle_paused(self): ''' Toggle the paused machine state. ''' gl = self.gamelogic gl.machine_state = \ [S.MS_RUN, S.MS_PAUSED][gl.machine_state == S.MS_RUN] if gl.machine_state == S.MS_PAUSED: self.__blur_radar() log.debug('### GAME PAUSED ###') else: self.__restore_radar() log.debug('### GAME RESUMED ###')
def __add_plane(self): ''' Add an aeroplane to the game. ''' kwargs = {} # Aeroplane model and specifications kwargs.update(self.model_generator()) # Flight number and callsign kwargs.update(self.flightnum_generator()) # Origin and destionation. If for some reason the challenge engine # hasn't find a viable entry point for the challenge logic, it will # return False, and no aeroplane will be added to the game result = self.__generate_flight_plan() if not result: return kwargs.update(result) # Set the module of the velocity (until here a normalized vector) kwargs['velocity'] *= kwargs['max_speed'] log.debug('About to add plane: %s' % kwargs) self.gamelogic.add_plane(Aeroplane(self.gamelogic.aerospace, **kwargs)) self.plane_counter += 1
def make_decision(self): ''' Make a decision if trying to land or not depending on whether the target runway is free or not. If free, return True and mark runway busy, otherwise return False. ''' rman = self.plane.aerospace.runways_manager if rman.check_runway_free(self.port, self.rnwy): rman.use_runway(self.port, self.rnwy, self.plane) full_length_speed = float(self.rnwy['length'])/S.RUNWAY_BUSY_TIME self.taxiing_data = dict( speed = min(self.plane.landing_speed, full_length_speed), timer = S.RUNWAY_BUSY_TIME) log.debug('%s *positive* landing decision on %s %s' % (self.plane.icao, self.port.iata, self.rnwy['name'])) self.plane.flags.locked = True return True log.debug('%s *negative* landing decision on %s %s' % (self.plane.icao, self.port.iata, self.rnwy['name'])) msg = 'Somebody is using our landing runway!!!' self.plane.pilot._abort_landing(msg) return False
def do(self, commands): ''' Perform an order issued by the player. Input is a list of triplets each of them in the format: [command, [arg1, arg2, ...], [flag1, flag2, ...]]. Return boolean. ''' radio_last = self.last_radio_hash # Transform the commands in a more suitable dictionary form.. commands = dict([(a, (b, c)) for a, b, c in commands]) # ...perform validity checks... check = self.checker.check(commands) if check != True: log.debug('%s failed to execute %s. Message: %s' % (self.plane.icao, commands, check)) self.say(check, S.KO_COLOUR) return False # ..and eventually execute the commands! self.executer.execute(commands) # If no radio feedback has been provided yet by any of the commands, # provide a generic affirmative answer. if radio_last == self.last_radio_hash: self.say(choice(self.AFFIRMATIVE_ANSWERS), S.OK_COLOUR) return True
def update(self): ''' Guide a plane towards the ILS descent path and then makes it land. Return the phase of the landing sequence. ''' pl = self.plane pi = self.pilot l = self.lander assert self.phase in (self.ABORTED, self.INTERCEPTING, self.MERGING, self.MATCHING, self.GLIDING, self.TAXIING) if self.phase == self.INTERCEPTING: #BUG: if command is given too late the plane won't manage to # turn into the vector log.debug('%s INTERCEPTING: md=%s fd=%s' % (pl.icao, l.md, l.fd)) if pi.navigator.check_overshot(l.mp) == True: pi.target_conf.heading = l.foot self.phase = self.MERGING if self.phase == self.MERGING: log.debug('%s MERGING: head=%s t_head= %s fd=%s' % (pl.icao, pl.heading, pi.target_conf.heading, l.fd)) if pl.heading == pi.target_conf.heading: self.phase = self.MATCHING if self.phase == self.MATCHING: path_alt = l.path_alt alt_diff = path_alt - pl.altitude #negative -> descend! log.debug('%s MATCHING: alt=%s path_alt=%s delta=%s fd=%s' % (pl.icao, pl.altitude, path_alt, alt_diff, l.fd)) secs_to_foot = l.fd / pl.speed # Abort if the plane is too fast to descend if abs(secs_to_foot * pl.climb_rate_limits[0]) < l.above_foot: msg = 'Plane is flying too fast to lose enough altitude' return self._abort_landing(msg) # If the delta to the path is less than the climbing/descending # capabilities of the aeroplane, consider it on slope... if alt_diff < 0 and alt_diff > pl.climb_rate_limits[0] or \ alt_diff > 0 and alt_diff < pl.climb_rate_limits[1]: pl.position.z = path_alt self.phase = self.GLIDING l.set_breaking_point() if pi.navigator.check_overshot(l.bp): msg = 'Plane too fast to slow down to landing speed' self._abort_landing(msg) # ...otherwise tell it to climb/descend!! else: pi.target_conf.altitude = path_alt elif self.phase == self.GLIDING: log.debug('%s GLIDING: footalt=%s speed=%s t_speed=%s bd=%s fd=%s' % (pl.icao, l.above_foot, pl.speed, pi.target_conf.speed, l.bd, l.fd)) # Abort if the plane is too fast to slow to landing speed if pi.navigator.check_overshot(l.bp): pi.target_conf.speed = pl.landing_speed # Make decision if below minimum altitude if not l.taxiing_data and l.above_foot <= S.DECISION_ALTITUDE: l.make_decision() ticks = 1.0 * l.fd / pi.target_conf.speed / S.PING_IN_SECONDS z_step = 1.0 * l.above_foot / ticks pi.target_conf.altitude -= z_step if pl.position.z <= l.foot.z \ or pi.navigator.check_overshot(l.foot): pl.flags.on_ground = True self.phase = self.TAXIING pi.target_conf.speed = l.taxiing_data['speed'] if pl.destination == l.port.iata: msg = 'Thank you tower, we\'ve hit home. Over and out!' pi.say(msg, S.OK_COLOUR) else: msg = 'Well, well... we just landed at the WRONG airport!' pi.say(msg, S.KO_COLOUR) elif self.phase == self.TAXIING: log.debug('%s TAXIING: speed=%s fd=%s' % (pl.icao, pl.speed, l.fd)) l.taxiing_data['timer'] -= S.PING_IN_SECONDS if l.taxiing_data['timer'] <= 0: if pl.destination == l.port.iata: pl.terminate(S.PLANE_LANDS_CORRECT_PORT) else: pl.terminate(S.PLANE_LANDS_WRONG_PORT) return self.phase