238 lines
7.6 KiB
GDScript
238 lines
7.6 KiB
GDScript
class_name LandGridView
|
|
extends RefCounted
|
|
|
|
var _owner: Control
|
|
var _game_view: Control
|
|
var _game_config
|
|
var _crop_phase_rules
|
|
var _get_land_node: Callable
|
|
var _render_add_land_indicator: Callable
|
|
var _land_count := 12
|
|
var _land_texture_size := Vector2(172.0, 102.0)
|
|
var _textures: Dictionary = {}
|
|
var _plant_layer: Control
|
|
var _plant_state_layer: Control
|
|
|
|
|
|
func setup(options: Dictionary) -> void:
|
|
_owner = options.get("owner") as Control
|
|
_game_view = options.get("game_view") as Control
|
|
_game_config = options.get("game_config")
|
|
_crop_phase_rules = options.get("crop_phase_rules")
|
|
_get_land_node = options.get("get_land_node", Callable())
|
|
_render_add_land_indicator = options.get("render_add_land_indicator", Callable())
|
|
_land_count = int(options.get("land_count", _land_count))
|
|
_land_texture_size = options.get("land_texture_size", _land_texture_size)
|
|
_textures = options.get("textures", {})
|
|
_create_layers()
|
|
|
|
|
|
func plant_layer() -> Control:
|
|
return _plant_layer
|
|
|
|
|
|
func plant_state_layer() -> Control:
|
|
return _plant_state_layer
|
|
|
|
|
|
func render(lands_by_position: Dictionary) -> void:
|
|
_clear_children(_plant_layer)
|
|
_clear_children(_plant_state_layer)
|
|
for position in range(_land_count):
|
|
var land_node := _get_land_node_for(position)
|
|
if land_node == null:
|
|
continue
|
|
var land_data: Dictionary = lands_by_position.get(position, {})
|
|
land_node.texture = _get_land_texture(land_data)
|
|
if not land_data.is_empty() and int(land_data.get("crop_id", 0)) > 0:
|
|
_render_plant_on_land(position, land_data)
|
|
_render_disease_state(position, land_data)
|
|
if _render_add_land_indicator.is_valid():
|
|
_render_add_land_indicator.call()
|
|
|
|
|
|
func build_signature(lands_by_position: Dictionary) -> String:
|
|
var parts := PackedStringArray()
|
|
for position in range(_land_count):
|
|
var land_data: Dictionary = lands_by_position.get(position, {})
|
|
if land_data.is_empty():
|
|
parts.append("%s:locked" % position)
|
|
continue
|
|
var crop_id := int(land_data.get("crop_id", 0))
|
|
if crop_id <= 0:
|
|
parts.append("%s:empty:%s" % [position, _land_level(land_data)])
|
|
continue
|
|
parts.append("%s:%s:%s:%s:%s:%s:%s:%s:%s:%s" % [
|
|
position,
|
|
crop_id,
|
|
_get_plant_phase(land_data),
|
|
int(land_data.get("crop_num", 0)),
|
|
int(land_data.get("has_gather", 0)),
|
|
int(land_data.get("has_bug", 0)),
|
|
int(land_data.get("has_grass", 0)),
|
|
int(land_data.get("has_dry", 0)),
|
|
int(land_data.get("crop_min_num", 0)),
|
|
",".join(_friend_interaction_types(land_data)),
|
|
])
|
|
return "|".join(parts)
|
|
|
|
|
|
func get_plant_phase(land_data: Dictionary) -> int:
|
|
return _get_plant_phase(land_data)
|
|
|
|
|
|
func get_crop_phase_times(crop_id: int) -> Array[int]:
|
|
if _crop_phase_rules == null:
|
|
return [1, 1, 1]
|
|
return _crop_phase_rules.get_crop_phase_times(crop_id)
|
|
|
|
|
|
func _create_layers() -> void:
|
|
if _game_view == null:
|
|
return
|
|
_plant_layer = Control.new()
|
|
_plant_layer.name = "PlantLayer"
|
|
_plant_layer.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
_plant_layer.set_anchors_preset(Control.PRESET_FULL_RECT)
|
|
_game_view.add_child(_plant_layer)
|
|
|
|
_plant_state_layer = Control.new()
|
|
_plant_state_layer.name = "PlantStateLayer"
|
|
_plant_state_layer.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
_plant_state_layer.set_anchors_preset(Control.PRESET_FULL_RECT)
|
|
_game_view.add_child(_plant_state_layer)
|
|
|
|
|
|
func _get_land_node_for(position: int) -> TextureRect:
|
|
if not _get_land_node.is_valid():
|
|
return null
|
|
return _get_land_node.call(position) as TextureRect
|
|
|
|
|
|
func _get_land_texture(land_data: Dictionary) -> Texture2D:
|
|
if land_data.is_empty():
|
|
return _textures.get("locked")
|
|
match _land_level(land_data):
|
|
1:
|
|
return _textures.get("level_1")
|
|
2:
|
|
return _textures.get("level_2")
|
|
3:
|
|
return _textures.get("level_3")
|
|
_:
|
|
return _textures.get("level_0")
|
|
|
|
|
|
func _render_plant_on_land(position: int, land_data: Dictionary) -> void:
|
|
var land_node := _get_land_node_for(position)
|
|
if land_node == null or _plant_layer == null:
|
|
return
|
|
var phase := _get_plant_phase(land_data)
|
|
var texture := _get_plant_texture(int(land_data.get("crop_id", 0)), phase)
|
|
if texture == null:
|
|
return
|
|
|
|
var plant := TextureRect.new()
|
|
plant.name = "Plant%s" % position
|
|
plant.texture = texture
|
|
plant.size = texture.get_size()
|
|
plant.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
plant.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
|
plant.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
|
|
|
var land_center := land_node.position + land_node.size * 0.5
|
|
var offset_y := -plant.size.y if phase == 0 else -plant.size.y + 10.0
|
|
plant.position = land_center + Vector2(-plant.size.x * 0.5 - 10.0, offset_y)
|
|
_plant_layer.add_child(plant)
|
|
|
|
|
|
func _render_disease_state(position: int, land_data: Dictionary) -> void:
|
|
if _plant_state_layer == null:
|
|
return
|
|
var phase := _get_plant_phase(land_data)
|
|
if phase < 0 or phase > 2:
|
|
return
|
|
|
|
var disease_textures: Array[Texture2D] = []
|
|
if int(land_data.get("has_grass", 0)) == 1:
|
|
disease_textures.append(_textures.get("state_grass"))
|
|
if int(land_data.get("has_bug", 0)) == 1:
|
|
disease_textures.append(_textures.get("state_bug"))
|
|
if int(land_data.get("has_dry", 0)) == 1:
|
|
disease_textures.append(_textures.get("state_dry"))
|
|
if disease_textures.is_empty():
|
|
return
|
|
|
|
var land_node := _get_land_node_for(position)
|
|
if land_node == null:
|
|
return
|
|
|
|
var state_group := Control.new()
|
|
state_group.name = "PlantState%s" % position
|
|
state_group.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
state_group.size = Vector2(33.0 * disease_textures.size(), 40.0)
|
|
var land_center := land_node.position + land_node.size * 0.5
|
|
state_group.position = Vector2(
|
|
land_center.x - state_group.size.x * 0.5 - 13.0,
|
|
land_center.y + (-100.0 if phase == 2 else -70.0)
|
|
)
|
|
|
|
for index in range(disease_textures.size()):
|
|
var texture := disease_textures[index]
|
|
if texture == null:
|
|
continue
|
|
var icon := TextureRect.new()
|
|
icon.name = "StateIcon%s" % index
|
|
icon.texture = texture
|
|
icon.position = Vector2(33.0 * index, -10.0 if disease_textures.size() == 3 and index == 1 else 0.0)
|
|
icon.size = texture.get_size()
|
|
icon.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
state_group.add_child(icon)
|
|
|
|
_plant_state_layer.add_child(state_group)
|
|
if _owner == null:
|
|
return
|
|
var tween := _owner.create_tween().bind_node(state_group).set_loops()
|
|
tween.tween_property(state_group, "position:y", state_group.position.y - 4.0, 0.5).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)
|
|
tween.tween_property(state_group, "position:y", state_group.position.y, 0.5).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)
|
|
|
|
|
|
func _friend_interaction_types(land_data: Dictionary) -> PackedStringArray:
|
|
var result := PackedStringArray()
|
|
var raw_types = land_data.get("interaction_type_list", [])
|
|
if not raw_types is Array:
|
|
return result
|
|
for raw_type in raw_types:
|
|
result.append(str(int(raw_type)))
|
|
return result
|
|
|
|
|
|
func _get_plant_phase(land_data: Dictionary) -> int:
|
|
if _crop_phase_rules == null:
|
|
return int(land_data.get("crop_phase", -1))
|
|
return _crop_phase_rules.get_phase(land_data)
|
|
|
|
|
|
func _get_plant_texture(crop_id: int, phase: int) -> Texture2D:
|
|
var path := "res://assets/egret/plant/plant_p0.png"
|
|
if phase == 4:
|
|
path = "res://assets/egret/plant/plant_p4.png"
|
|
elif phase > 0 and _game_config != null:
|
|
var plant_graphic_id := int(_game_config.get_crop_graphic_id(crop_id, phase))
|
|
path = "res://assets/egret/plant/%s.png" % plant_graphic_id
|
|
if not ResourceLoader.exists(path):
|
|
path = "res://assets/egret/plant/plant_p0.png"
|
|
return load(path)
|
|
|
|
|
|
func _land_level(land_data: Dictionary) -> int:
|
|
return clampi(int(land_data.get("level", land_data.get("landLv", 0))), 0, 3)
|
|
|
|
|
|
func _clear_children(parent: Node) -> void:
|
|
if parent == null:
|
|
return
|
|
for child in parent.get_children():
|
|
parent.remove_child(child)
|
|
child.queue_free()
|