12func configure(config:Dictionary, next_tile_size := 40.0) -> void:
13 world_config = config.duplicate(true)
14 tile_size = max(1.0, float(next_tile_size))
17func get_grid_size() -> Vector2i:
18 return _cell_from_value(world_config.get(
"grid_size", [12, 12]))
21func get_bounds() -> Rect2:
22 return Rect2(Vector2.ZERO, Vector2(get_grid_size()) * tile_size)
25func get_blocked_cells() -> Array:
27 for obstacle
in world_config.get(
"obstacles", []):
28 if not obstacle
is Dictionary:
30 for cell
in cells_from_obstacle(obstacle):
35func get_movement_blocked_cells(occupied_cells:Array) -> Array:
36 var cells = get_blocked_cells()
37 for cell
in occupied_cells:
38 cells.append(_cell_from_value(cell))
42func cells_from_obstacle(obstacle:Dictionary) -> Array:
44 if obstacle.has(
"cells"):
45 for cell
in obstacle.get(
"cells", []):
46 cells.append(_cell_from_value(cell))
47 elif obstacle.has(
"rect"):
48 cells = rect_to_cells(_rect_from_value(obstacle.get(
"rect", [])))
52func rect_to_cells(rect:Rect2) -> Array:
53 var min_cell = Vector2i(int(floor(rect.position.x / tile_size)), int(floor(rect.position.y / tile_size)))
54 var max_cell = Vector2i(
55 int(floor((rect.position.x + max(0.0, rect.size.x - 0.01)) / tile_size)),
56 int(floor((rect.position.y + max(0.0, rect.size.y - 0.01)) / tile_size))
59 for y
in range(min_cell.y, max_cell.y + 1):
60 for x
in range(min_cell.x, max_cell.x + 1):
61 cells.append(Vector2i(x, y))
66func collect_material_at(cell:Vector2i, collected_nodes:Dictionary) -> Dictionary:
67 for node
in world_config.get(
"material_nodes", []):
68 if not node
is Dictionary:
70 var node_id = str(node.get(
"id",
""))
71 if node_id ==
"" or collected_nodes.has(node_id):
73 if _cell_from_value(node.get(
"cell", [0, 0])) != cell:
78 "element": str(node.get(
"element",
"")),
79 "amount": int(node.get(
"amount", 1))
81 return {
"collected": false}
85func resolve_spell_interactions(card:Dictionary, affected_cells:Array, activated_interactions:Dictionary) -> Array:
87 for interaction
in world_config.get(
"spell_interactions", []):
88 if not interaction
is Dictionary:
90 var id = str(interaction.get(
"id",
""))
91 if id ==
"" or activated_interactions.has(id):
93 var cell = _cell_from_value(interaction.get(
"cell", [0, 0]))
94 if not affected_cells.has(cell):
96 if not _card_matches_interaction(card, interaction):
98 var entry = interaction.duplicate(true)
99 entry[
"activated"] = true
100 activated.append(entry)
104func _rect_from_value(value) -> Rect2:
107 if value
is Array
and value.size() >= 4:
108 return Rect2(Vector2(float(value[0]), float(value[1])), Vector2(float(value[2]), float(value[3])))
112func _cell_from_value(value) -> Vector2i:
113 if value
is Vector2i:
116 return Vector2i(int(value.x), int(value.y))
117 if value
is Array
and value.size() >= 2:
118 return Vector2i(int(value[0]), int(value[1]))
119 if value
is Dictionary
and value.has(
"cell"):
120 return _cell_from_value(value.get(
"cell"))
124func _card_matches_interaction(card:Dictionary, interaction:Dictionary) -> bool:
125 var requires = interaction.get(
"requires", {})
126 if not requires
is Dictionary
or requires.is_empty():
128 for key
in requires.keys():
129 var expected = requires[key]
130 if key ==
"compound" and str(card.get(
"compound",
"")) != str(expected):
132 if key ==
"manifestation" and str(card.get(
"manifestation",
"")) != str(expected):
134 if key ==
"card_id" and str(card.get(
"id",
"")) != str(expected):
136 if key ==
"modifier" and not card.get(
"modifiers", []).has(str(expected)):