--- scripts/restaurant/restaurant.gd +++ scripts/restaurant/restaurant.gd @@ -1,6 +1,7 @@ extends Node2D const DISH_SCENE := preload("res://scenes/restaurant/dish.tscn") +const QuestDishPrompt := preload("res://scripts/core/confirm_prompt.gd") const CUSTOMER_SCENE := preload("res://scenes/restaurant/customer.tscn") const MONEY_POPUP_SCENE := preload("res://scenes/ui/damage_number.tscn") const TIP_SCENE := preload("res://scenes/items/tip_pickup.tscn") @@ -458,6 +459,9 @@ # Employés au travail, et le cuisinier affecté à chaque poste. var employees: Array[Employee] = [] var station_cooks: Dictionary = {} +# Keep each finished portion separate and discard consumed portions safely. +var _quest_dishes_to_offer: Array[WeakRef] = [] +var _quest_dish_prompt: CanvasLayer var takeout_cook: Employee var takeout_server: Employee var _layout_reflowed := false @@ -610,6 +614,9 @@ func _process(delta: float) -> void: if hud == null or not is_instance_valid(hud): return + _offer_next_quest_dish() + if get_tree().paused: + return cancel_guard = maxf(0.0, cancel_guard - delta) if _rearrange_pending: _try_rearrange() @@ -1997,6 +2004,9 @@ Registry.run_hook("recipes", recipe_id, "on_cooked", dish) _persist_room() GameState.toast_from(self, Loc.ui("ui.restaurant.dish_ready") % DataCatalog.recipe_name(recipe_id)) + if not _quest_dish_to_offer(dish).is_empty(): + _quest_dishes_to_offer.append(weakref(dish)) + _offer_next_quest_dish.call_deferred() func serve_customer(current_customer: Customer, dish: Dish) -> void: if current_customer.state != Customer.State.WAITING or dish.recipe_id != current_customer.requested_recipe: @@ -2508,8 +2518,11 @@ # sa fiche nomme, et l'assiette se libère. C'est ce qu'on rapportera au # personnage. func _set_aside_held_dish() -> void: - var dish := player.held_dish as Dish - if dish == null or dish.state != Dish.State.FILLED: + _set_aside_dish(player.held_dish as Dish) + +# The console and the cooking question share the same conversion. +func _set_aside_dish(dish: Dish) -> void: + if not is_instance_valid(dish) or dish.is_queued_for_deletion() or dish.state != Dish.State.FILLED: return var quest := GameState.quest_wanting_dish(dish.recipe_id) if quest.is_empty(): @@ -2518,6 +2531,50 @@ GameState.toast_from(self, Loc.ui("ui.quest.set_aside") % DataCatalog.recipe_name(dish.recipe_id)) dish.consume() _persist_room() + +func _quest_dish_to_offer(dish: Dish) -> String: + if not is_instance_valid(dish) or dish.is_queued_for_deletion() or dish.state != Dish.State.FILLED: + return "" + var quest := GameState.quest_wanting_dish(dish.recipe_id) + if quest.is_empty() or _quest_giver_is_present(quest): + return "" + return quest + +func _quest_giver_is_present(quest: String) -> bool: + var giver := str(DataCatalog.QUESTS[quest].get("giver", "")) + if giver.is_empty(): + return false + for profile_id: String in DataCatalog.CUSTOMER_PROFILES: + if str(DataCatalog.CUSTOMER_PROFILES[profile_id].get("character", "")) == giver \ + and customers_present_of(profile_id) > 0: + return true + return false + +func _offer_next_quest_dish() -> void: + if _quest_dishes_to_offer.is_empty() or is_instance_valid(_quest_dish_prompt) \ + or not is_inside_tree() or is_queued_for_deletion() or transitioning \ + or GameState.is_offstage(self) or get_tree().paused or recipe_menu.visible: + return + while not _quest_dishes_to_offer.is_empty(): + var portion: WeakRef = _quest_dishes_to_offer.pop_front() + var dish := portion.get_ref() as Dish + var quest := _quest_dish_to_offer(dish) + if quest.is_empty(): + continue + var giver := str(DataCatalog.QUESTS[quest].get("giver", "")) + var recipient := Loc.entity("characters", giver, "display_name") if not giver.is_empty() \ + else Loc.entity("quests", quest, "display_name") + var prompt := QuestDishPrompt.new() + prompt.question = Loc.ui("ui.prompt.set_aside") % recipient + prompt.confirm_text = Loc.ui("ui.common.confirm") + prompt.cancel_text = Loc.ui("ui.common.cancel") + _quest_dish_prompt = prompt + prompt.answered.connect(func(confirmed: bool) -> void: + _quest_dish_prompt = null + if confirmed and _quest_dish_to_offer(dish) == quest: + _set_aside_dish(dish)) + add_child(prompt) + return func _wash_held_plate() -> void: var dish := player.held_dish as Dish