def update(self, pings): ''' Update the plane status according to the elapsed time. Pings = number of radar pings from last update. ''' burning_speed = 1 if self.pilot.status['haste'] == 'normal' else 2 initial = self.position.copy() for i in range(pings): # Pilot's updates self.pilot.update() # Compute waiting time score if not airborne # FIXME: distinguish between just landed and waiting to takeoff if self.flags.on_ground: mult = pings * S.PING_IN_SECONDS self.aerospace.gamelogic.score_event(S.PLANE_WAITS_ONE_SECOND, multiplier=mult) # Decrease fuel amount if airborne elif self.fuel > 0: dist = U.ground_distance(initial, self.position) burnt = burning_speed * dist * self.fuel_efficiency self.fuel -= burnt self.aerospace.gamelogic.score_event(S.PLANE_BURNS_FUEL_UNIT, multiplier=burnt) # Check if a fuel emergency has to be triggered. # FIXME: this is goo reason to use objects intstead of IATA/NAME try: dest_point = self.aerospace.airports[self.destination].location except KeyError: tmp = self.aerospace.gates[self.destination].location dest_point = Vector3(tmp[0], tmp[1], self.altitude) dist = U.ground_distance(dest_point, self.position) self.fuel_delta = self.fuel - (2 * dist * self.fuel_efficiency) self.dist_to_target = dist if not self.flags.fuel_emergency and self.fuel_delta < 0: log.info('%s is declaring fuel emergency' % self.icao) msg = 'Pan-Pan, Pan-Pan, Pan-Pan... We are low on fuel, ' \ 'requesting priority landing!' self.pilot.say(msg, S.KO_COLOUR) self.aerospace.gamelogic.score_event(S.EMERGENCY_FUEL) self.flags.fuel_emergency = True # Fuel has ran out if self.fuel < 0: msg = 'Mayday! Mayday! Mayday! All engines have flamed out, we ' \ 'are going down!' self.pilot.say(msg, S.KO_COLOUR) log.info('%s has ran out of fuel' % self.icao) self.fuel = 0 self.max_speed = self.min_speed * 2 max_down = self.climb_rate_limits[0] self.climb_rate_limits = [max_down, max_down / 2.0] # Update sprite self.rect = U.sc(self.position.xy) self.trail.appendleft(U.sc(self.position.xy))
def __generate_flight_plan(self): ''' Return intial position and velocity 3D vectors plus the origin and destination identifiers (airport or gate) for a plane. It also returns the initial amount of onboard fuel and the fuel_efficiency values. ''' #TODO: foresee port to port and gate to gate #TODO: foresee a configurable ratio between ports and air #FIXME: consider passing gate and airport objects directly as orig/dest # Establish type of origin if self.__check_grounded_is_ok(): options = ['gates', 'airports'] random.shuffle(options) type_ = options.pop() else: type_ = 'gates' if type_ == 'gates': entry_data_gates = self.__entry_data['gates'][:] random.shuffle(entry_data_gates) # Attempt to make planes enter the aerospace without making them # collide with each other while entry_data_gates: orig, pos, vel, levels = entry_data_gates.pop() levels = levels[:] while levels: # Prevent in-place modification on __entry_data pos = pos.copy() pos.z = levels.pop() if not self.gamelogic.aerospace.check_proximity(pos): vel = vel.copy() tmp = random.choice(self.scenario.airports) dest = tmp.iata fuel = U.rint(U.ground_distance(pos, tmp.location)* 4*self.fuel_per_metre) return dict(origin=orig, position=pos, velocity=vel, destination=dest, fuel=fuel, fuel_efficiency=self.fuel_per_metre) elif type_ == 'airports': random.shuffle(self.__entry_data['airports']) orig, pos, vel = self.__entry_data['airports'][0] pos = pos.copy() vel = vel.copy() tmp = random.choice(self.scenario.gates) dest = tmp.name fuel = U.rint(U.ground_distance(pos, Vector3(*tmp.location))* 4*self.fuel_per_metre) return dict(origin=orig, position=pos, velocity=vel, destination=dest, fuel=fuel, fuel_efficiency=self.fuel_per_metre) return False
def testGroundDistance(self): ''' ground_distance - ground distance between points ''' TO_TEST = [((0,0,0), (0,0,10), 0), ((0,0,0), (0,10,0), 10), ((0,0,0), (10,0,0), 10), ((0,0,0), (1,1,1), 2**0.5), ((0,0,0), (-1,-1,-1), 2**0.5)] for v1, v2, r in TO_TEST: back = U.ground_distance(Vector3(*v1), Vector3(*v2)) self.assertAlmostEqual(back, r, 5)