def __handle_hull_destroyed(hull_destroyed): if hull_destroyed.player: return PlainResponse("The hull has been destroyed, all is lost.") else: return PlainResponse( "The enemy ship bursts apart, the crew lets out a " + "sigh of relief, then a cheer. On to the next challenge.")
def __handle_combat(self, slots, game_state): unassigned = [ c for (c, s) in game_state.ship.crew.iteritems() if s.station is None ] if len(unassigned) > 0: return (build_speechlet_response_enahnced( QPContent.unassigned_crew( [CREW_MEMBERS[c]["name"] for c in unassigned], [ STATIONS[station].name for station in game_state.ship.stations.keys() if station not in game_state.ship.crew.values() ]), reprompt=PlainResponse("Move your crew to stations or " + "say engage to continue.")), game_state) (game_state, qp_results) = \ self.__runner.advance_combat(game_state) is_end_game = len( filter(lambda r: issubclass(type(r), EndGameState), qp_results)) > 0 return (build_speechlet_response_enahnced( QPContent.handle_qp_results_respone(qp_results), should_end_session=is_end_game, reprompt=PlainResponse("Move your crew to stations or " + "say engage to continue.")), game_state)
def __handle_station_fire_state_change(station_fire): station_name = STATIONS.get(station_fire.station).name if station_fire.extinguished_by is not None: crew_name = CREW_MEMBERS.get(station_fire.extinguished_by)["name"] if station_fire.start_by is not None: return PlainResponse("Enemy fire expanded the fire " + crew_name + " put out in the " + station_name) else: return PlainResponse(crew_name + " has extinguished the fire in the " + station_name) elif station_fire.start_by == StationStateActor.ATTACK: return PlainResponse("The " + station_name + " has started on fire.")
def new_game_response(crew_members, stations, opponent_name): return PlainResponse(" ".join([ QPContent.NEW_GAME_INTRO, QPContent.describe_stage(opponent_name), "As a remminder, ", QPContent.list_crew(crew_members), QPContent.STATION_DESCRIPTION, QPContent.list_stations(stations), QPContent.MOVE_SUGGESTION_TEXT ]))
def __get_crew_state_response(self, crew_id, crew): if crew_id in CREW_MEMBERS: crew_name = CREW_MEMBERS[crew_id]["name"] if crew_id in crew: crew_state = crew[crew_id] if crew_state.station is not None: return PlainResponse( QPContent.cs_crew_crew_manning_station( crew_name, STATIONS[crew_state.station].name)) else: return PlainResponse( QPContent.cs_crew_not_assigned(crew_name)) else: return QPContent.cs_crew_member_invalid_response(crew_name) else: return QPContent.cs_crew_member_invalid_response(crew_id)
def __handle_station_damage_state_change(station_damage): station_name = STATIONS.get(station_damage.station).name if station_damage.repaired_by is not None: crew_name = CREW_MEMBERS.get(station_damage.repaired_by)["name"] if station_damage.damaged_by is not None: return PlainResponse( crew_name + " is repairing the " + station_name + ", but it was futher damaged by enemy fire.") else: return PlainResponse(crew_name + " has repaired the " + station_name) elif station_damage.damaged_by == StationStateActor.ATTACK: return PlainResponse("The " + station_name + " has been damaged by enemy fire.") elif station_damage.damaged_by == StationStateActor.FIRE: return PlainResponse("The fire in the " + station_name + " has damaged it.")
def unassigned_crew(unassigned_names, empty_stations): multiple_c = len(unassigned_names) > 1 multiple_s = len(empty_stations) > 1 return PlainResponse( handle_text_list(unassigned_names) + " " + ("have" if multiple_c else "has") + " not been assigned to a station." + " I suggest you assign them before we engage." + " You can say move crew member name to station name." + " The empty stations " + ("are" if multiple_s else "is") + " " + handle_text_list(empty_stations))
def report_post_advance_state_response(hull, ls, warp, ehull, stations, end_game): """Ship state, station state, and end_game states.""" return PlainResponse(" ".join([ s for s in [ "The hull has " + str(hull) + " points remaining. ", "The life support is charged to " + str(ls) + ". ", "The warp is charged to " + str(warp) + ". ", "The enemy hull has " + str(ehull) + " points left." ] + [ QPContent.__adv_station_state(STATIONS.get(id).name, state) for (id, state) in stations.iteritems() ] + [QPContent.__report_end_game(end_game)] if s is not None ]))
def __handle_instruct_crew(self, slots, game_state): crew_id = self.__extract_id_from_slot(slots.get("crewSlot")) station_id = self.__extract_id_from_slot(slots.get("stationSlot")) try: (state, crew, station) = \ self.__runner.instruct_crew(game_state, crew_id, station_id) response = build_speechlet_response_enahnced( QPContent.instruct_crew_response(crew["name"], station.name), reprompt=QPContent.INSTRUCT_CREW_REPROMPT, card=QPContent.INSTRUCT_CREW_CARD) return (response, state) except (CrewMemberInvalidException, StationInvalidException), e: response = build_speechlet_response_enahnced( PlainResponse(str(e)), QPContent.INSTRUCT_CREW_REPROMPT, card=QPContent.INVALID_INSTRUCTION_CARD) return (response, game_state)
def __handle_life_support_threshold_breach(ls_breach): if not ls_breach.up: if ls_breach.threshold == "HIGH": return PlainResponse("We are losing life support charge!") elif ls_breach.threshold == "MID": return PlainResponse( "Life Support state continues to worsen, " + "consider repairing the Life Support station.") elif ls_breach.threshold == "LOW": return PlainResponse("Life support is critical, " + "repair or we will die, captain!") else: if ls_breach.threshold == "FULL": return PlainResponse("Life support is full restored.") elif ls_breach.threshold == "HIGH": return PlainResponse("Life Support is improving.") elif ls_breach.threshold == "MID": return PlainResponse("Life Support out of a critical state.")
def __handle_health_threshold_breach(health_breach): if not health_breach.up: if health_breach.player: if health_breach.threshold == ResultThresholds["HIGH"]: return PlainResponse("The hull is holding, captain.") elif health_breach.threshold == ResultThresholds["MID"]: return PlainResponse("The hull is weakening, captain.") elif health_breach.threshold == ResultThresholds["LOW"]: return PlainResponse( "The hull is critically damaged, captain.") else: if health_breach.threshold == ResultThresholds["HIGH"]: return PlainResponse( "The enemy hull is withstnding our impacts, captain.") elif health_breach.threshold == ResultThresholds["MID"]: return PlainResponse( "The enemy hull is showing weakness, captain.") elif health_breach.threshold == ResultThresholds["LOW"]: return PlainResponse( "The enemy is critically damaged, let's finish them!") else: pass # TODO handle up phrases
def cs_station_unmanned_response(station_name): return PlainResponse(station_name + " is unmanned.")
def instruct_crew_response(crew_name, station_name): return PlainResponse(crew_name + " has been moved to " + station_name)
def __handle_life_support_depleted(life_support_depleted): return PlainResponse("Life support reserves is empty. " + "The crew breaths its last breath " + "as cold overtakes the ship.")
def cs_crew_stations_reponse(crew_station_names_tuples): return PlainResponse(" ".join([ QPContent.cs_crew_crew_manning_station(c, s) if s is not None else QPContent.cs_crew_not_assigned(c) for (c, s) in crew_station_names_tuples ]))
class QPContent(object): """Common Strings and Text output functions.""" QUICK_PARTICLE_STRING = "Quick Particle" DEFAULT_OUTPUT = "Captain, I am not sure what you meant by that. " +\ "Try asking the crew to move to stations " + \ "or say engage to continue the battle." DEFAULT_RESPONSE = \ PlainResponse(DEFAULT_OUTPUT) DEFAULT_CARD = SimpleCard(QUICK_PARTICLE_STRING, DEFAULT_OUTPUT) """ New Game """ NEW_GAME_INTRO = \ "Captain, are you ok? Our core is damaged, our " + \ "shields and warp drive are unusable. " + \ "We should find another ship to scrap a core from, then we " + \ "could get moving again." NEW_GAME_CARD_TITLE = "Quick Particle Ship Acquisition" STATION_DESCRIPTION = "You can assign crew members to our stations. " + \ "Manned stations will operate more effectively. " + \ "A crew member can also repair damaged stations or put out fires." MOVE_SUGGESTION_TEXT = \ "You can assign your crew to stations by saying move " \ + "crew name to station name. Say engage once you are ready " \ + "to fight the enemy ship." @staticmethod def list_crew(crew_names): return "Our small crew is " + handle_text_list(crew_names) + "." @staticmethod def list_stations(station_names): return "Our functioning stations are " + \ handle_text_list(station_names) + "." @staticmethod def describe_stage(opponent_name): # TODO Note, this is temporarily specific return "Luckily, There is an enemy ship called " + \ opponent_name + \ " off the port. It has begun firing on us." # TODO separate new game, stage, and instructions @staticmethod def new_game_response(crew_members, stations, opponent_name): return PlainResponse(" ".join([ QPContent.NEW_GAME_INTRO, QPContent.describe_stage(opponent_name), "As a remminder, ", QPContent.list_crew(crew_members), QPContent.STATION_DESCRIPTION, QPContent.list_stations(stations), QPContent.MOVE_SUGGESTION_TEXT ])) """ Instruct Crew """ INSTRUCT_CREW_CARD = SimpleCard("Instruct crew member", "") INSTRUCT_CREW_REPROMPT = \ PlainResponse("anymore to move? otherwise say GO when ready.") INVALID_INSTRUCTION_CARD = SimpleCard("Invalid Instruction", "") @staticmethod def instruct_crew_response(crew_name, station_name): return PlainResponse(crew_name + " has been moved to " + station_name) """ Crew State """ CREW_STATE_CARD = SimpleCard("Crew State", "") @staticmethod def cs_station_unmanned_response(station_name): return PlainResponse(station_name + " is unmanned.") @staticmethod def cs_station_not_avaliable_response(station_name): return PlainResponse("your ship does not have the " + station_name + " station yet") @staticmethod def cs_station_is_invalid_response(station_name): return PlainResponse(station_name + " is not a valid station") @staticmethod def cs_crew_not_assigned(crew_name): return crew_name + " has not been assigned." @staticmethod def cs_crew_crew_manning_station(crew_name, station_name): return crew_name + " is manning the " + station_name + ". " @staticmethod def cs_crew_stations_reponse(crew_station_names_tuples): return PlainResponse(" ".join([ QPContent.cs_crew_crew_manning_station(c, s) if s is not None else QPContent.cs_crew_not_assigned(c) for (c, s) in crew_station_names_tuples ])) @staticmethod def cs_crew_member_invalid_response(crew_name): return PlainResponse(crew_name + " is not in the crew") """ Advance """ @staticmethod def unassigned_crew(unassigned_names, empty_stations): multiple_c = len(unassigned_names) > 1 multiple_s = len(empty_stations) > 1 return PlainResponse( handle_text_list(unassigned_names) + " " + ("have" if multiple_c else "has") + " not been assigned to a station." + " I suggest you assign them before we engage." + " You can say move crew member name to station name." + " The empty stations " + ("are" if multiple_s else "is") + " " + handle_text_list(empty_stations)) @staticmethod def report_post_advance_state_response(hull, ls, warp, ehull, stations, end_game): """Ship state, station state, and end_game states.""" return PlainResponse(" ".join([ s for s in [ "The hull has " + str(hull) + " points remaining. ", "The life support is charged to " + str(ls) + ". ", "The warp is charged to " + str(warp) + ". ", "The enemy hull has " + str(ehull) + " points left." ] + [ QPContent.__adv_station_state(STATIONS.get(id).name, state) for (id, state) in stations.iteritems() ] + [QPContent.__report_end_game(end_game)] if s is not None ])) @staticmethod def __adv_station_state(station_name, station): if station.fire > 0: if station.damaged: return "Our " + station_name + " is damaged and on fire. " else: return "Our " + station_name + " is on fire. " if station.damaged: return "Our " + station_name + " is damaged." return None """QP Results""" @staticmethod def handle_qp_results_respone(qp_results): return [ resp for resp in [QPContent.handle_qp_result(r) for r in qp_results] if resp is not None ] @staticmethod def handle_qp_result(result): if isinstance(result, AttackMissed): return QPContent.__handle_attack_miss(result) elif isinstance(result, AttackHit): return QPContent.__handle_attack_hit(result) elif isinstance(result, StationDamageStateChange): return QPContent.__handle_station_damage_state_change(result) elif isinstance(result, StationFireStateChange): return QPContent.__handle_station_fire_state_change(result) elif isinstance(result, HealthThresholdBreached): return QPContent.__handle_health_threshold_breach(result) elif isinstance(result, LifeSupportThresholdBreached): return QPContent.__handle_life_support_threshold_breach(result) elif isinstance(result, LifeSupportDepleted): return QPContent.__handle_life_support_depleted(result) elif isinstance(result, HullDestroyed): return QPContent.__handle_hull_destroyed(result) @staticmethod def __handle_attack_miss(attack_miss): if attack_miss.player: return SSMLResponse( "<say-as interpret-as=\"interjection\">bah!</say-as> " + "we missed their ship.") else: return SSMLResponse( "<say-as interpret-as=\"interjection\">hooray</say-as> " + "they missed us.") @staticmethod def __handle_attack_hit(attack_hit): # TODO base result on damage done if attack_hit.player: return SSMLResponse( "<say-as interpret-as=\"interjection\">bam!</say-as> " + "we hit them!") else: return SSMLResponse( "<say-as interpret-as=\"interjection\">wham!</say-as> " + "they hit us captain.") @staticmethod def __handle_station_damage_state_change(station_damage): station_name = STATIONS.get(station_damage.station).name if station_damage.repaired_by is not None: crew_name = CREW_MEMBERS.get(station_damage.repaired_by)["name"] if station_damage.damaged_by is not None: return PlainResponse( crew_name + " is repairing the " + station_name + ", but it was futher damaged by enemy fire.") else: return PlainResponse(crew_name + " has repaired the " + station_name) elif station_damage.damaged_by == StationStateActor.ATTACK: return PlainResponse("The " + station_name + " has been damaged by enemy fire.") elif station_damage.damaged_by == StationStateActor.FIRE: return PlainResponse("The fire in the " + station_name + " has damaged it.") @staticmethod def __handle_station_fire_state_change(station_fire): station_name = STATIONS.get(station_fire.station).name if station_fire.extinguished_by is not None: crew_name = CREW_MEMBERS.get(station_fire.extinguished_by)["name"] if station_fire.start_by is not None: return PlainResponse("Enemy fire expanded the fire " + crew_name + " put out in the " + station_name) else: return PlainResponse(crew_name + " has extinguished the fire in the " + station_name) elif station_fire.start_by == StationStateActor.ATTACK: return PlainResponse("The " + station_name + " has started on fire.") @staticmethod def __handle_health_threshold_breach(health_breach): if not health_breach.up: if health_breach.player: if health_breach.threshold == ResultThresholds["HIGH"]: return PlainResponse("The hull is holding, captain.") elif health_breach.threshold == ResultThresholds["MID"]: return PlainResponse("The hull is weakening, captain.") elif health_breach.threshold == ResultThresholds["LOW"]: return PlainResponse( "The hull is critically damaged, captain.") else: if health_breach.threshold == ResultThresholds["HIGH"]: return PlainResponse( "The enemy hull is withstnding our impacts, captain.") elif health_breach.threshold == ResultThresholds["MID"]: return PlainResponse( "The enemy hull is showing weakness, captain.") elif health_breach.threshold == ResultThresholds["LOW"]: return PlainResponse( "The enemy is critically damaged, let's finish them!") else: pass # TODO handle up phrases @staticmethod def __handle_life_support_threshold_breach(ls_breach): if not ls_breach.up: if ls_breach.threshold == "HIGH": return PlainResponse("We are losing life support charge!") elif ls_breach.threshold == "MID": return PlainResponse( "Life Support state continues to worsen, " + "consider repairing the Life Support station.") elif ls_breach.threshold == "LOW": return PlainResponse("Life support is critical, " + "repair or we will die, captain!") else: if ls_breach.threshold == "FULL": return PlainResponse("Life support is full restored.") elif ls_breach.threshold == "HIGH": return PlainResponse("Life Support is improving.") elif ls_breach.threshold == "MID": return PlainResponse("Life Support out of a critical state.") @staticmethod def __handle_hull_destroyed(hull_destroyed): if hull_destroyed.player: return PlainResponse("The hull has been destroyed, all is lost.") else: return PlainResponse( "The enemy ship bursts apart, the crew lets out a " + "sigh of relief, then a cheer. On to the next challenge.") @staticmethod def __handle_life_support_depleted(life_support_depleted): return PlainResponse("Life support reserves is empty. " + "The crew breaths its last breath " + "as cold overtakes the ship.")
def cs_station_not_avaliable_response(station_name): return PlainResponse("your ship does not have the " + station_name + " station yet")
def cs_crew_member_invalid_response(crew_name): return PlainResponse(crew_name + " is not in the crew")
def cs_station_is_invalid_response(station_name): return PlainResponse(station_name + " is not a valid station")
class QPSkillAdaptor(object): """Translates skill logic into QP game logic.""" def __init__(self): """Build QP Skill Adaptor.""" self.__runner = QPRunner() def on_intent(self, intent_data, session): """Route intents within qp.""" meta = session.get("meta", {}) if session is not None else {} game_state = meta.get("game_state", {}) new_game_state = game_state response = build_speechlet_response_enahnced( QPContent.DEFAULT_RESPONSE, card=QPContent.DEFAULT_CARD, should_end_session=False) intent_name = intent_data.get("name") # New Game if game_state is None or game_state == {}: (response, new_game_state) = self.__handle_new_game() else: state = self.__runner.transform_game_state(game_state) slots = intent_data.get("slots") if intent_name == "instructCrewIntent": # Instruct Crew (response, new_game_state) = \ self.__handle_instruct_crew(slots, state) if intent_name == "crewStateIntent": response = self.__handle_crew_state(slots, state) elif intent_name == "goIntent": # Advance Combat (response, new_game_state) = \ self.__handle_combat(slots, state) # TODO this is gross, use immutable objects meta["game_state"] = self.__runner.to_json_friendly(new_game_state) session["meta"] = meta # TODO do more with game end # TODO keep session alive when not lost return build_response(session, response) def __handle_new_game(self): """Create a new game. NOTE: In the future, creating and priming a stage will be separate from creating a new ship. Create new ship Create the a new stage Prime the ship's stage persistent status. """ game_state = self.__runner.new_game(CONSTANTS.STARTING_CREW_MEMBERS, STARTING_STATIONS) # Create a new stage/opponent new_stage = self.__runner.start_stage( "Destroyer", { STATS.HULL_HEALTH: 50, STATS.ATTACK_POWER: 5, STATS.DODGE: 2, STATS.SHIELD: 0, STATS.ACCURACY: 4, STATS.MAX_HULL_HEALTH: 50 }) # Set the stage game_state.stage = new_stage # TODO Prime based on ship calculated ship stats, # for now MH and MLS canonot be upgraded game_state.ship.stats = \ self.__runner.prime_ship_for_combat(BASE_STATS) # Welcome message, introduce the crew, introduce the stations crew = [ CREW_MEMBERS.get(c).get("name") for c in game_state.ship.crew.keys() ] stations = [ STATIONS.get(s).name for s in game_state.ship.stations.keys() ] text = QPContent.new_game_response(crew, stations, new_stage.opponent.name) response = build_speechlet_response_enahnced(text) return (response, game_state) def __handle_instruct_crew(self, slots, game_state): crew_id = self.__extract_id_from_slot(slots.get("crewSlot")) station_id = self.__extract_id_from_slot(slots.get("stationSlot")) try: (state, crew, station) = \ self.__runner.instruct_crew(game_state, crew_id, station_id) response = build_speechlet_response_enahnced( QPContent.instruct_crew_response(crew["name"], station.name), reprompt=QPContent.INSTRUCT_CREW_REPROMPT, card=QPContent.INSTRUCT_CREW_CARD) return (response, state) except (CrewMemberInvalidException, StationInvalidException), e: response = build_speechlet_response_enahnced( PlainResponse(str(e)), QPContent.INSTRUCT_CREW_REPROMPT, card=QPContent.INVALID_INSTRUCTION_CARD) return (response, game_state) except MemberAlreadyInStationException, e: response = build_speechlet_response_enahnced( PlainResponse(str(e)), QPContent.INSTRUCT_CREW_REPROMPT, card=QPContent.INVALID_INSTRUCTION_CARD) return (response, game_state)