menu.py 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. from puzzle import Puzzle
  2. class Menu:
  3. def __init__(self, menu_options, game_state, parent_menu = None, parent_screen = None, cursor_index = 0):
  4. # menu_options is a list of dictionaries with keys "option_name" and "on_select"
  5. self.menu_options = menu_options
  6. self.game_state = game_state
  7. self.parent_menu = parent_menu
  8. self.parent_screen = parent_screen
  9. self.selected_option = cursor_index
  10. def navigate(self, direction):
  11. self.selected_option = (self.selected_option + direction) % len(self.menu_options)
  12. def cancel(self):
  13. if self.parent_menu is None and self.parent_screen is None:
  14. return
  15. self.game_state.menu = self.parent_menu
  16. if self.parent_menu is None and self.game_state.screen == 'menu':
  17. self.game_state.screen = self.parent_screen
  18. def force_screen(self, screen_name):
  19. if self.game_state.screen == 'menu' and self.game_state.menu == self:
  20. self.game_state.menu = None
  21. self.game_state.screen = screen_name
  22. def select(self):
  23. option = self.menu_options[self.selected_option]
  24. if 'on_select' in option:
  25. option['on_select'](option, self, self.game_state)
  26. def open_sub_menu(self, new_options, cursor_index = 0):
  27. sub_menu = Menu(new_options, self.game_state, self, cursor_index = cursor_index)
  28. self.game_state.menu = sub_menu
  29. def save_and_exit(option, menu, game_state):
  30. menu.force_screen('exit_to_os')
  31. def quit_to_main_menu(option, menu, game_state):
  32. game_state.open_main_menu()
  33. def new_main_menu(game_state_parent):
  34. def on_select_resume_story(option, menu, game_state):
  35. game_state.mode = 'story'
  36. game_state.level = None
  37. story_info = option['meta_info']
  38. story = story_info['story']
  39. current_level = story_info['level']
  40. level_history = story_info['level_history']
  41. game_state.load_level_history(level_history)
  42. if 'current_game' in story_info:
  43. current_game = story_info['current_game']
  44. saved_puzzle = Puzzle(current_game['quote'], current_game['key'], current_game['letter_mappings'])
  45. game_state.load_story_level(story, current_level, True)
  46. game_state.load_puzzle(saved_puzzle)
  47. else:
  48. game_state.load_story_level(story, current_level, False)
  49. def on_select_new_game_story(option, menu, game_state):
  50. game_state.mode = 'story'
  51. game_state.level = None
  52. story = option['meta_info']
  53. init_level_id = story['init_level']
  54. game_state.load_level_history({"unlocked_levels": [], "completed_levels": []})
  55. game_state.load_story_level(story, init_level_id, False)
  56. def on_select_level(option, menu, game_state):
  57. game_state.mode = 'story'
  58. game_state.level = None
  59. story_info = option["meta_info"]
  60. story = story_info["story"]
  61. level = option["option_value"]
  62. level_history = story_info["level_history"]
  63. game_state.load_level_history(level_history)
  64. game_state.load_story_level(story, level["id"], False)
  65. def on_open_level_select_sub_menu(option, menu, game_state):
  66. story_info = option['meta_info']
  67. story = story_info['story']
  68. levels = story['levels']
  69. level_history = story_info['level_history']
  70. unlocked_levels = level_history['unlocked_levels']
  71. # Convert the list of levels into a dictionary for quick lookup
  72. level_dict = { level["id"]: level for level in levels}
  73. menu_options = []
  74. for level_id in unlocked_levels:
  75. level = level_dict[level_id]
  76. menu_options.append({ "option_name": level['name'], "on_select": on_select_level, "option_value": level, "meta_info": story_info })
  77. menu_options.sort(key=lambda x: x["option_value"]["index"])
  78. menu.open_sub_menu(menu_options)
  79. def on_select_story(option, menu, game_state):
  80. story = option['option_value']
  81. saved_game_data = game_state.data_manager.try_load_game()
  82. if 'story_mode' in saved_game_data and story['id'] in saved_game_data['story_mode']:
  83. saved_story_progress = saved_game_data['story_mode'][story['id']]
  84. current_level = saved_story_progress['level']
  85. level_history = saved_story_progress['level_history']
  86. story_info = {
  87. "story": story,
  88. "saved_story_progress": saved_story_progress,
  89. "current_level": current_level,
  90. "level_history": level_history,
  91. "level": current_level
  92. }
  93. if 'current_game' in saved_story_progress:
  94. story_info['current_game'] = saved_story_progress['current_game']
  95. menu_options = [
  96. { "option_name": "Resume Game", "on_select": on_select_resume_story, "meta_info": story_info },
  97. { "option_name": "Level Select", "on_select": on_open_level_select_sub_menu, "meta_info": story_info }
  98. ]
  99. else:
  100. menu_options = [{ "option_name": "New Game", "on_select": on_select_new_game_story, "meta_info": story}]
  101. menu.open_sub_menu(menu_options)
  102. def story_mode(option, menu, game_state):
  103. story_list = [story for story in game_state.data_manager.list_stories()]
  104. story_options = [{ "option_name": story['name'], "option_value": story, "on_select": on_select_story } for story in story_list]
  105. menu.open_sub_menu(story_options)
  106. def endless_mode(option, menu, game_state):
  107. game_state.mode = 'endless'
  108. saved_game_data = game_state.data_manager.try_load_game()
  109. if 'game' in saved_game_data:
  110. saved_puzzle = Puzzle(saved_game_data['game']['quote'], saved_game_data['game']['key'], saved_game_data['game']['letter_mappings'])
  111. game_state.load_puzzle(saved_puzzle)
  112. game_state.screen = 'puzzle'
  113. else:
  114. game_state.start_new_puzzle()
  115. game_state.screen = 'puzzle'
  116. menu_options = [
  117. { "option_name": "Story Mode", "on_select": story_mode },
  118. { "option_name": "Endless Mode", "on_select": endless_mode },
  119. { "option_name": "Save & Exit", "on_select": save_and_exit }
  120. ]
  121. return Menu(menu_options, game_state_parent)
  122. def new_pause_menu(game_state_parent):
  123. def start_over(option, menu, game_state):
  124. menu.force_screen('puzzle')
  125. game_state.start_over()
  126. def hint(option, menu, game_state):
  127. menu.force_screen('puzzle')
  128. game_state.show_hint()
  129. def give_up(option, menu, game_state):
  130. menu.force_screen('puzzle')
  131. game_state.open_game_over_dialog()
  132. def how_to_play(option, menu, game_state):
  133. game_state.open_how_to_play_dialog()
  134. def settings(option, menu, game_state):
  135. settings_menu_options = [
  136. { "option_name": "Visual Themes", "on_select": visual_themes },
  137. { "option_name": "Quote File", "on_select": quote_file },
  138. { "option_name": "Sound Settings" }
  139. ]
  140. menu.open_sub_menu(settings_menu_options)
  141. def about(option, menu, game_state):
  142. game_state.open_about_dialog()
  143. def set_visual_theme(option, menu, game_state):
  144. game_state.user_preferences.visual_theme = option["option_name"]
  145. def set_quote_db(option, menu, game_state):
  146. game_state.user_preferences.quote_db = option["option_name"]
  147. menu.cancel()
  148. def visual_themes(option, menu, game_state):
  149. current_theme = game_state.user_preferences.visual_theme
  150. theme_list = [theme["id"] for theme in game_state.data_manager.read_theme_file()]
  151. theme_options = [{ "option_name": theme, "on_select": set_visual_theme } for theme in theme_list]
  152. current_theme_index = theme_list.index(current_theme) if current_theme in theme_list else 0
  153. menu.open_sub_menu(theme_options, cursor_index = current_theme_index)
  154. def quote_file(option, menu, game_state):
  155. current_quote_db = game_state.user_preferences.quote_db
  156. quote_db_list = [quote_db_name for quote_db_name in game_state.data_manager.list_quote_dbs()]
  157. quote_db_options = [{ "option_name": quote_db_name, "on_select": set_quote_db } for quote_db_name in quote_db_list]
  158. current_quote_db_index = quote_db_list.index(current_quote_db) if current_quote_db in quote_db_list else 0
  159. menu.open_sub_menu(quote_db_options, cursor_index = current_quote_db_index)
  160. if game_state_parent.mode == 'story':
  161. menu_options = [
  162. { "option_name": "Start Over", "on_select": start_over },
  163. { "option_name": "How To Play", "on_select": how_to_play },
  164. { "option_name": "Settings", "on_select": settings },
  165. { "option_name": "About", "on_select": about },
  166. { "option_name": "Quit to Main Menu", "on_select": quit_to_main_menu },
  167. { "option_name": "Save & Exit", "on_select": save_and_exit }
  168. ]
  169. else:
  170. menu_options = [
  171. { "option_name": "Start Over", "on_select": start_over },
  172. { "option_name": "Hint", "on_select": hint },
  173. { "option_name": "Give Up", "on_select": give_up },
  174. { "option_name": "How To Play", "on_select": how_to_play },
  175. { "option_name": "Settings", "on_select": settings },
  176. { "option_name": "About", "on_select": about },
  177. { "option_name": "Quit to Main Menu", "on_select": quit_to_main_menu },
  178. { "option_name": "Save & Exit", "on_select": save_and_exit }
  179. ]
  180. parent_screen = game_state_parent.screen
  181. return Menu(menu_options, game_state_parent, parent_screen = parent_screen)
  182. def new_story_branch_menu(game_state_parent, choices):
  183. def select_story_branch(option, menu, game_state):
  184. game_state.load_story_level(game_state.story, option["option_value"], False)
  185. menu_options = [{ "option_name": i["name"], "on_select": select_story_branch, "option_value": i["next_level"] } for i in choices]
  186. return Menu(menu_options, game_state_parent)