10func attempt_inventory_reaction(alchemy_manager, inventory:Dictionary, inputs:Array, catalysts:Array = [], rng:RandomNumberGenerator = null) -> Dictionary:
11 var normalized_inputs = _normalized_inputs(inputs)
12 if normalized_inputs.size() != 2:
16 "message":
"Choose two materials before starting research.",
17 "inputs": normalized_inputs
19 if not _has_distinct_inputs(normalized_inputs):
23 "message":
"Choose two different materials for research.",
24 "inputs": normalized_inputs
26 if not _has_required_inventory(inventory, normalized_inputs):
30 "message":
"Not enough materials for that research attempt.",
31 "inputs": normalized_inputs
33 var reaction = alchemy_manager.attempt_reaction(normalized_inputs, catalysts)
34 if bool(reaction.get(
"success", false)):
35 var result_id = str(reaction.get(
"result",
""))
42 "inputs": normalized_inputs,
43 "consume": _counts_for(normalized_inputs),
46 "message":
"Research succeeded."
49 rng = RandomNumberGenerator.new()
51 var destroyed_index = rng.randi_range(0, normalized_inputs.size() - 1)
52 var destroyed = str(normalized_inputs[destroyed_index])
53 var returned = str(normalized_inputs[1 - destroyed_index])
54 reaction[
"destroyed"] = destroyed
55 reaction[
"returned"] = returned
59 "inputs": normalized_inputs,
60 "consume": {destroyed: 1},
62 "destroyed": destroyed,
65 "message":
"Research failed."
70func preview_inventory_reaction(alchemy_manager, inventory:Dictionary, inputs:Array, known_result_ids:Array = [], catalysts:Array = []) -> Dictionary:
71 var normalized_inputs = _normalized_inputs(inputs)
72 if normalized_inputs.size() != 2:
78 "message":
"Choose two materials."
80 if not _has_distinct_inputs(normalized_inputs):
84 "inputs": normalized_inputs,
87 "message":
"Choose two different materials."
89 if not _has_required_inventory(inventory, normalized_inputs):
93 "inputs": normalized_inputs,
96 "message":
"Not enough materials."
98 var reaction = alchemy_manager.attempt_reaction(normalized_inputs, catalysts)
99 var result_id = str(reaction.get(
"result",
""))
100 var success = bool(reaction.get(
"success", false))
and result_id !=
""
101 var known = success
and known_result_ids.has(result_id)
106 "inputs": normalized_inputs,
107 "result": result_id
if known
else "",
108 "hidden_result": result_id,
109 "label": result_id.capitalize()
if known
else "Unknown",
110 "reaction": reaction,
111 "message":
"Known recipe." if known
else "Unknown recipe."
116func craft_known_reaction(alchemy_manager, inventory:Dictionary, inputs:Array, known_result_ids:Array, catalysts:Array = []) -> Dictionary:
117 var preview = preview_inventory_reaction(alchemy_manager, inventory, inputs, known_result_ids, catalysts)
118 if not bool(preview.get(
"known", false)):
119 preview[
"valid"] = false
120 preview[
"message"] =
"Research this recipe before crafting it."
122 var result_id = str(preview.get(
"result",
""))
127 "inputs": preview.get(
"inputs", []).duplicate(true),
128 "consume": _counts_for(preview.get(
"inputs", [])),
129 "gain": {result_id: 1},
130 "reaction": preview.get(
"reaction", {}),
131 "message":
"Crafted known recipe."
136func apply_inventory_delta(inventory:Dictionary, result:Dictionary) -> Dictionary:
137 var next_inventory = inventory.duplicate(true)
138 for id
in result.get(
"consume", {}).keys():
139 var remaining = int(next_inventory.get(id, 0)) - int(result.get(
"consume", {}).get(id, 0))
141 next_inventory[id] = remaining
143 next_inventory.erase(id)
144 for id
in result.get(
"gain", {}).keys():
145 next_inventory[id] = int(next_inventory.get(id, 0)) + int(result.get(
"gain", {}).get(id, 0))
146 return next_inventory
149func get_available_inputs(inventory:Dictionary) -> Array:
151 for id
in inventory.keys():
152 if int(inventory.get(id, 0)) > 0:
153 available.append(str(id))
158func _normalized_inputs(inputs:Array) -> Array:
161 var id = str(input).strip_edges().to_lower()
163 normalized.append(id)
168func _has_distinct_inputs(inputs:Array) -> bool:
169 if inputs.size() < 2:
171 return str(inputs[0]) != str(inputs[1])
174func _has_required_inventory(inventory:Dictionary, inputs:Array) -> bool:
175 var required = _counts_for(inputs)
176 for id
in required.keys():
177 if int(inventory.get(id, 0)) < int(required[id]):
182func _counts_for(inputs:Array) -> Dictionary:
186 counts[id] = int(counts.get(id, 0)) + 1