P23-03: 生活の観察
This commit is contained in:
+252
-24
@@ -79,6 +79,8 @@ var _queue_hidden: Dictionary = {}
|
||||
var _landing_badges: Array[Dictionary] = []
|
||||
var _transport_report: Dictionary = {}
|
||||
var _life_observation: Dictionary = {}
|
||||
var _life_overlay: Node2D
|
||||
var _life_observation_serial := 0
|
||||
var _dragging := false
|
||||
var _drag_button := MOUSE_BUTTON_NONE
|
||||
|
||||
@@ -104,6 +106,10 @@ func _ready() -> void:
|
||||
_inactive_layer_art = InactiveLayerRooms.new()
|
||||
_inactive_layer_art.name = "InactiveLayerRooms"
|
||||
add_child(_inactive_layer_art)
|
||||
_life_overlay = Node2D.new()
|
||||
_life_overlay.name = "LifeOverlay"
|
||||
_life_overlay.draw.connect(_draw_life_overlay)
|
||||
add_child(_life_overlay)
|
||||
_layer_lens = ColorRect.new()
|
||||
_layer_lens.name = "LayerLens"
|
||||
_layer_lens.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
@@ -513,6 +519,8 @@ func _draw() -> void:
|
||||
|
||||
func _draw_contents() -> void:
|
||||
_life_observation = {}
|
||||
if _life_overlay != null:
|
||||
_life_overlay.queue_redraw()
|
||||
if _inactive_layer_art != null:
|
||||
_inactive_layer_art.visible = false
|
||||
_draw_background()
|
||||
@@ -524,6 +532,9 @@ func _draw_contents() -> void:
|
||||
if map_rect.size == Vector2.ZERO:
|
||||
return
|
||||
_life_observation = _build_life_observation()
|
||||
_life_observation_serial += 1
|
||||
_life_observation[&"observation_serial"] = _life_observation_serial
|
||||
_life_observation[&"overlay_consumed_serial"] = -1
|
||||
_room_presentations = _life_observation[&"rooms"]
|
||||
_carried_patients = _life_observation[&"carried_patients"]
|
||||
_treated_patients = _life_observation[&"treated_patients"]
|
||||
@@ -540,11 +551,9 @@ func _draw_contents() -> void:
|
||||
_draw_legacy_stairs()
|
||||
_draw_elevators()
|
||||
_draw_other_layer()
|
||||
_draw_congestion_overlay(bounds)
|
||||
_draw_life_badges()
|
||||
_draw_construction_labels()
|
||||
_draw_facility_labels()
|
||||
_draw_actors()
|
||||
_draw_excavation_jobs()
|
||||
_draw_build_preview()
|
||||
_draw_excavation_preview()
|
||||
@@ -599,6 +608,7 @@ func _build_life_observation() -> Dictionary:
|
||||
model[&"guests"] = guests
|
||||
model[&"staff"] = staff
|
||||
model[&"tasks"] = tasks
|
||||
_fit_life_actors(model)
|
||||
var bridge: Variant = _service(&"supply_logistics")
|
||||
var goods: Dictionary = bridge.get_report() if bridge != null else {&"requests": [], &"deliveries": []}
|
||||
model[&"goods"] = goods
|
||||
@@ -638,7 +648,14 @@ func _build_life_observation() -> Dictionary:
|
||||
var cell := Vector3i(x, y, layer_mode)
|
||||
var row: Dictionary = path.get_cell_traffic(cell)
|
||||
if not row.is_empty():
|
||||
traffic.append({&"cell": cell, &"traffic": row, &"rect": get_cell_rect(cell).grow(-2.0)})
|
||||
var cell_rect := get_cell_rect(cell)
|
||||
var rect := cell_rect.grow(-2.0)
|
||||
var world_pixel := _cell_dimensions().x / 16.0
|
||||
var thickness := clampf(rect.size.y * 0.16, 2.0, 5.0)
|
||||
var band := Rect2(Vector2(rect.position.x + rect.size.x * 0.12,
|
||||
cell_rect.end.y - 2 * world_pixel - thickness * 0.5),
|
||||
Vector2(rect.size.x * 0.76, thickness))
|
||||
traffic.append({&"cell": cell, &"traffic": row, &"rect": rect, &"band_rect": band})
|
||||
model[&"traffic"] = traffic
|
||||
return model
|
||||
|
||||
@@ -758,9 +775,27 @@ func _draw_leaf_cluster(center: Vector2, p: float, variation: int) -> void:
|
||||
draw_rect(Rect2(c+offset,Vector2(3+i%2,2)*p),Color("95ad69") if i%3==0 else Color("648957"))
|
||||
|
||||
|
||||
func _draw_congestion_overlay(_bounds: Dictionary) -> void:
|
||||
func _draw_life_overlay() -> void:
|
||||
if _life_observation.is_empty():
|
||||
return
|
||||
# These are actual child indices and the passes executed by this callback.
|
||||
_life_observation[&"overlay_child_indices"] = [_inactive_layer_art.get_index(), _life_overlay.get_index(), _layer_lens.get_index()]
|
||||
_life_observation[&"overlay_passes"] = []
|
||||
_life_observation[&"overlay_passes"].append(&"traffic")
|
||||
_draw_congestion_overlay(_life_overlay)
|
||||
_life_observation[&"overlay_passes"].append(&"actors")
|
||||
for cabin: Dictionary in _life_observation.get(&"cabins", []):
|
||||
for actor: Dictionary in cabin[&"passengers"]:
|
||||
_draw_observed_actor(actor, _life_overlay)
|
||||
_draw_actors(_life_overlay)
|
||||
for badge: Dictionary in _life_observation.get(&"actor_aggregations", []):
|
||||
_draw_readable_badge(badge[&"at"], badge[&"text"], _life_overlay)
|
||||
_life_observation[&"overlay_consumed_serial"] = _life_observation[&"observation_serial"]
|
||||
|
||||
|
||||
func _draw_congestion_overlay(canvas: CanvasItem) -> void:
|
||||
for row: Dictionary in _life_observation.get(&"traffic", []):
|
||||
var rect: Rect2 = row[&"rect"]
|
||||
var band: Rect2 = row[&"band_rect"]
|
||||
var traffic: Dictionary = row[&"traffic"]
|
||||
var density := int(traffic[&"current_density"])
|
||||
var blocked := bool(traffic[&"temporary_block"])
|
||||
@@ -768,13 +803,11 @@ func _draw_congestion_overlay(_bounds: Dictionary) -> void:
|
||||
continue
|
||||
var ratio := float(density) / maxi(int(traffic[&"base_capacity"]), 1)
|
||||
var color := Color("e34332") if blocked or ratio > 1.0 else Color("e3a62f") if ratio >= 0.65 else Color("55c96b")
|
||||
var center := rect.get_center()
|
||||
draw_line(Vector2(rect.position.x + rect.size.x * 0.12, center.y),
|
||||
Vector2(rect.end.x - rect.size.x * 0.12, center.y),
|
||||
Color(color, 0.90 if show_grid else 0.28), clampf(rect.size.y * 0.16, 2.0, 5.0))
|
||||
canvas.draw_rect(band, Color(color, 0.90))
|
||||
if blocked:
|
||||
draw_line(rect.position, rect.end, Color(color, 0.90 if show_grid else 0.28), 2.0)
|
||||
draw_line(Vector2(rect.end.x, rect.position.y), Vector2(rect.position.x, rect.end.y), Color(color, 0.90 if show_grid else 0.28), 2.0)
|
||||
var cross := band.grow(-1.0)
|
||||
canvas.draw_line(cross.position, cross.end, Color(color, 0.90), 2.0)
|
||||
canvas.draw_line(Vector2(cross.end.x, cross.position.y), Vector2(cross.position.x, cross.end.y), Color(color, 0.90), 2.0)
|
||||
|
||||
|
||||
## Visual-only level comes from the existing live FacilityInstance, not the
|
||||
@@ -887,13 +920,15 @@ func _draw_world_entity_icons() -> void:
|
||||
draw_rect(rect.grow(-p),Color("f5d582"),false,2*p)
|
||||
|
||||
|
||||
func _draw_readable_badge(at: Vector2, text: String) -> void:
|
||||
func _draw_readable_badge(at: Vector2, text: String, canvas: CanvasItem = null) -> void:
|
||||
if canvas == null:
|
||||
canvas = self
|
||||
var width := ThemeDB.fallback_font.get_string_size(text, HORIZONTAL_ALIGNMENT_LEFT, -1, 10).x+6
|
||||
var rect := Rect2(at, Vector2(width, 14))
|
||||
if not rect.intersects(Rect2(Vector2.ZERO, size)):
|
||||
return
|
||||
draw_rect(rect, Color("34413b", 0.94))
|
||||
draw_string(ThemeDB.fallback_font, at+Vector2(3, 11), text, HORIZONTAL_ALIGNMENT_LEFT, -1, 10, Color("fff2ce"))
|
||||
canvas.draw_rect(rect, Color("34413b", 0.94))
|
||||
canvas.draw_string(ThemeDB.fallback_font, at+Vector2(3, 11), text, HORIZONTAL_ALIGNMENT_LEFT, -1, 10, Color("fff2ce"))
|
||||
|
||||
|
||||
func _prepare_room_presentations() -> void:
|
||||
@@ -1146,8 +1181,6 @@ func _draw_facility_labels() -> void:
|
||||
func _draw_elevators() -> void:
|
||||
for row: Dictionary in _life_observation.get(&"cabins", []):
|
||||
PixelArt.elevator_cabin(self, row[&"rect"], row[&"pixel"], layer_mode == LayerMode.BACK, row[&"operational"])
|
||||
for actor: Dictionary in row[&"passengers"]:
|
||||
_draw_observed_actor(actor)
|
||||
PixelArt.elevator_gate(self, row[&"rect"], row[&"pixel"], row[&"doors_open"])
|
||||
_draw_readable_badge(row[&"badge_at"], row[&"badge"])
|
||||
for badge: Dictionary in _life_observation.get(&"landing_badges", []):
|
||||
@@ -1188,8 +1221,7 @@ func _observe_elevators(observation: Dictionary) -> Array[Dictionary]:
|
||||
var doors_open := operational and phase in [&"IDLE", &"BOARDING", &"ALIGHTING"]
|
||||
var passengers_drawn: Array[Dictionary] = []
|
||||
var seat_columns := maxi(int((cabin.size.x / p - 4.0) / 8.0), 1)
|
||||
var visible_count := mini(passengers.size(), seat_columns*2)
|
||||
for index: int in range(visible_count):
|
||||
for index: int in range(passengers.size()):
|
||||
var actor_key := _elevator_actor_key(String(passengers[index]))
|
||||
var is_staff := actor_key.begins_with("staff/")
|
||||
var person: Variant = null
|
||||
@@ -1200,7 +1232,7 @@ func _observe_elevators(observation: Dictionary) -> Array[Dictionary]:
|
||||
var carrying := is_staff and person != null and not String(person.carried_inventory_id).is_empty()
|
||||
var state := int(person.state) if person != null else 0
|
||||
var x := cabin.position.x + (2.0 + (index % seat_columns + 0.5)*8.0)*p
|
||||
var feet := cabin.end.y - (2.0 + int(index / seat_columns)*9.0)*p
|
||||
var feet := cabin.end.y - (2.0 + (int(index / seat_columns) % 2)*9.0)*p
|
||||
var center := Vector2(x, feet+3*p-_cell_dimensions().y*0.5)
|
||||
passengers_drawn.append(_actor_drawing(center,actor_key,is_staff,state,false,carrying,&"",true,observation))
|
||||
cabins.append({&"shaft_id": shaft_id, &"rect": cabin, &"pixel": p,
|
||||
@@ -1240,9 +1272,9 @@ func _tracked_elevator_floor(shaft_id: StringName, current_floor: float, observa
|
||||
return lerpf(float(track[&"from"]),current_floor,t)
|
||||
|
||||
|
||||
func _draw_actors() -> void:
|
||||
func _draw_actors(canvas: CanvasItem = null) -> void:
|
||||
for row: Dictionary in _life_observation.get(&"actor_drawings", []):
|
||||
_draw_observed_actor(row)
|
||||
_draw_observed_actor(row, canvas)
|
||||
|
||||
|
||||
func _observe_actors(observation: Dictionary) -> Array[Dictionary]:
|
||||
@@ -1291,6 +1323,9 @@ func _observe_actors(observation: Dictionary) -> Array[Dictionary]:
|
||||
continue
|
||||
var position := _tracked_actor_position(key,staff.current_cell,observation)
|
||||
if staff.current_cell.z==layer_mode:
|
||||
if _queue_positions.has(key):
|
||||
rows.append(_actor_drawing(_queue_positions[key],key,true,int(staff.state),false,not String(staff.carried_inventory_id).is_empty(),_staff_work_animation(staff),false,observation))
|
||||
continue
|
||||
if _carried_patients.has(staff.staff_id):
|
||||
var carrier: Variant = staff_service.get_staff(_carried_patients[staff.staff_id])
|
||||
if carrier != null:
|
||||
@@ -1412,11 +1447,13 @@ func _draw_pixel_actor(center: Vector2, key: String, staff: bool, state: int, re
|
||||
_draw_observed_actor(_actor_drawing(center, key, staff, state, receiving, carrying, activity, riding))
|
||||
|
||||
|
||||
func _draw_observed_actor(row: Dictionary) -> void:
|
||||
func _draw_observed_actor(row: Dictionary, canvas: CanvasItem = null) -> void:
|
||||
if canvas == null:
|
||||
canvas = self
|
||||
var at: Vector2 = row[&"at"]
|
||||
var p: float = row[&"scale"]
|
||||
draw_rect(Rect2(at + Vector2(5, 17) * p, Vector2(8, 1) * p), Color("303c40", 0.2))
|
||||
People.draw(self, at, p, row[&"mode"], row[&"frame"], row[&"variant"], row[&"staff"], row[&"flip"])
|
||||
canvas.draw_rect(Rect2(at + Vector2(5, 17) * p, Vector2(8, 1) * p), Color("303c40", 0.2))
|
||||
People.draw(canvas, at, p, row[&"mode"], row[&"frame"], row[&"variant"], row[&"staff"], row[&"flip"])
|
||||
|
||||
|
||||
func _actor_drawing(center: Vector2, key: String, staff: bool, state: int, receiving: bool, carrying: bool, activity: StringName = &"", riding := false, observation: Dictionary = {}) -> Dictionary:
|
||||
@@ -1454,6 +1491,197 @@ func _actor_drawing(center: Vector2, key: String, staff: bool, state: int, recei
|
||||
&"riding": riding, &"flip": float(track.get(&"direction", 1.0)) < 0.0}
|
||||
|
||||
|
||||
## Identity cores are tied to the unchanged PixelPeople poses, not sprite boxes.
|
||||
func _life_core(row: Dictionary) -> Rect2:
|
||||
var phase := int(row[&"frame"]) % 8
|
||||
var core := Rect2(6, 1, 6, 12)
|
||||
if row[&"mode"] in [&"sleep", &"collapsed", &"standard_room_sleep"]:
|
||||
core = Rect2(2, 11, 13, 5)
|
||||
if row[&"mode"] == &"standard_room_sleep" and phase in [2, 3, 4]:
|
||||
core.position.y -= 1
|
||||
core.size.y += 1
|
||||
elif row[&"mode"] in [&"walk", &"carry_walk"] and phase in [2, 6]:
|
||||
core.position.y -= 1
|
||||
if row[&"flip"]:
|
||||
core.position.x = 16-core.end.x
|
||||
return Rect2(row[&"at"]+core.position*row[&"scale"], core.size*row[&"scale"])
|
||||
|
||||
|
||||
func _life_track_region(key: String, cell: Vector3i, model: Dictionary) -> Dictionary:
|
||||
var track: Dictionary = model[&"actor_tracks"].get(key, {})
|
||||
var transit: bool = not model[&"paused"] and track.get(&"from", cell) != cell and _animation_time-float(track.get(&"at", 0.0)) < 0.42
|
||||
var rect := get_cell_rect(cell)
|
||||
if transit:
|
||||
rect = rect.merge(get_cell_rect(track[&"from"]))
|
||||
return {&"bounds": rect, &"transit": transit}
|
||||
|
||||
|
||||
func _life_actor_region(row: Dictionary, person: Dictionary, model: Dictionary) -> Dictionary:
|
||||
var key: String = row[&"key"]
|
||||
var cell: Vector3i = person[&"cell"]
|
||||
var result := _life_track_region(key, cell, model)
|
||||
var p := _cell_dimensions().x/16.0
|
||||
var world: Variant = _service(&"world_service")
|
||||
var facility_id: StringName = &""
|
||||
if model[&"queue_positions"].has(key):
|
||||
result = {&"bounds": Rect2(model[&"queue_positions"][key]-_cell_dimensions()*0.5, _cell_dimensions()), &"transit": false}
|
||||
elif not row[&"staff"]:
|
||||
if not String(person[&"service"]).is_empty():
|
||||
var room: Dictionary = model[&"rooms"].get(person[&"target"], {})
|
||||
if (room.get(&"people", []) as Array).has(person[&"id"]):
|
||||
facility_id = person[&"target"]
|
||||
else:
|
||||
var id: StringName = person[&"id"]
|
||||
if model[&"carried_patients"].has(id):
|
||||
for carrier: Dictionary in model[&"staff"]:
|
||||
if carrier[&"id"] == model[&"carried_patients"][id]:
|
||||
result = _life_track_region("staff/"+String(carrier[&"id"]), carrier[&"cell"], model)
|
||||
var rect: Rect2 = result[&"bounds"]
|
||||
rect.position.y -= 12*p
|
||||
result[&"bounds"] = rect
|
||||
elif model[&"resting_staff"].has(id):
|
||||
facility_id = model[&"resting_staff"][id]
|
||||
elif model[&"treated_patients"].has(id):
|
||||
facility_id = model[&"treated_patients"][id]
|
||||
elif person[&"state"] in ["WORKING", "AVAILABLE"] and world != null:
|
||||
var cells: Array[Vector3i] = world.get_entity_cells(person[&"facility"])
|
||||
var room: Dictionary = model[&"rooms"].get(person[&"facility"], {})
|
||||
var slot := (room.get(&"staff", []) as Array).find(id)
|
||||
var rect := _cell_bounds_rect(cells)
|
||||
var columns := maxi(int(rect.size.x/(16*p)), 1)
|
||||
if cells.has(cell) and slot >= 0 and slot < columns and rect.size.y >= 40*p:
|
||||
result = {&"bounds": Rect2(rect.position+Vector2(slot*rect.size.x/columns, 0), Vector2(rect.size.x/columns, rect.size.y)), &"transit": false}
|
||||
if not facility_id.is_empty() and world != null:
|
||||
var cells: Array[Vector3i] = world.get_entity_cells(facility_id)
|
||||
if not cells.is_empty():
|
||||
result = {&"bounds": _cell_bounds_rect(cells), &"transit": false}
|
||||
result[&"bounds"] = (result[&"bounds"] as Rect2).grow(-p)
|
||||
return result
|
||||
|
||||
|
||||
func _life_scaled(row: Dictionary, scale: float) -> Dictionary:
|
||||
var result := row.duplicate(true)
|
||||
result[&"scale"] = scale
|
||||
result[&"at"] = (row[&"center"]+Vector2(-8*scale, _cell_dimensions().y*0.5-3*_cell_dimensions().x/16.0-17*scale)).round()
|
||||
return result
|
||||
|
||||
|
||||
## Forward/backward packing keeps each member's own interval. No relocation.
|
||||
func _life_pack(group: Array, scale: float) -> Array:
|
||||
var trial: Array = []
|
||||
var right := -INF
|
||||
for member: Dictionary in group:
|
||||
var row := _life_scaled(member[&"row"], minf(scale, member[&"row"][&"scale"]))
|
||||
var core := _life_core(row)
|
||||
var bounds: Rect2 = member[&"bounds"]
|
||||
var x := maxf(maxf(core.position.x, bounds.position.x), right)
|
||||
row[&"at"].x += x-core.position.x
|
||||
right = x+core.size.x
|
||||
trial.append(row)
|
||||
var left := INF
|
||||
for i: int in range(trial.size()-1, -1, -1):
|
||||
var row: Dictionary = trial[i]
|
||||
var core := _life_core(row)
|
||||
var bounds: Rect2 = group[i][&"bounds"]
|
||||
var x := minf(core.position.x, minf(bounds.end.x, left)-core.size.x)
|
||||
row[&"at"].x += x-core.position.x
|
||||
left = x
|
||||
if x < bounds.position.x or core.position.y < bounds.position.y or core.end.y > bounds.end.y:
|
||||
return []
|
||||
return trial
|
||||
|
||||
|
||||
## Rebuild vertical components at every fitted scale. Ceilings only decrease;
|
||||
## once none decreases, the feet/cores and therefore the partition are fixed.
|
||||
func _life_fitted_groups(members: Array) -> Array:
|
||||
var groups: Array = []
|
||||
while true:
|
||||
for member: Dictionary in members:
|
||||
member[&"row"].merge(_life_scaled(member[&"row"], member[&"row"][&"scale"]), true)
|
||||
members.sort_custom(func(a: Dictionary, b: Dictionary) -> bool:
|
||||
var ay := _life_core(a[&"row"]).position.y
|
||||
var by := _life_core(b[&"row"]).position.y
|
||||
return ay < by or (ay == by and a[&"row"][&"key"] < b[&"row"][&"key"]))
|
||||
groups = []
|
||||
var bottom := -INF
|
||||
for member: Dictionary in members:
|
||||
var core := _life_core(member[&"row"])
|
||||
if groups.is_empty() or core.position.y >= bottom:
|
||||
groups.append([])
|
||||
bottom = core.end.y
|
||||
else:
|
||||
bottom = maxf(bottom, core.end.y)
|
||||
groups.back().append(member)
|
||||
var reduced := false
|
||||
for group: Array in groups:
|
||||
group.sort_custom(func(a: Dictionary, b: Dictionary) -> bool: return a[&"row"][&"center"].x < b[&"row"][&"center"].x or (a[&"row"][&"center"].x == b[&"row"][&"center"].x and a[&"row"][&"key"] < b[&"row"][&"key"]))
|
||||
var ceiling := 1.0
|
||||
for member: Dictionary in group:
|
||||
ceiling = maxf(ceiling, member[&"row"][&"scale"])
|
||||
if _life_pack(group, ceiling).is_empty() and ceiling > 1:
|
||||
for member: Dictionary in group:
|
||||
var scale := minf(member[&"row"][&"scale"], maxf(1, int(ceiling)-1))
|
||||
member[&"row"].merge(_life_scaled(member[&"row"], scale), true)
|
||||
reduced = true
|
||||
if not reduced:
|
||||
return groups
|
||||
return groups
|
||||
|
||||
|
||||
func _fit_life_actors(model: Dictionary) -> void:
|
||||
var people: Dictionary = {}
|
||||
for person: Dictionary in model[&"guests"]:
|
||||
people["guest/"+String(person[&"id"])] = person
|
||||
for person: Dictionary in model[&"staff"]:
|
||||
people["staff/"+String(person[&"id"])] = person
|
||||
var members: Array = []
|
||||
var all_rows: Array = model[&"actor_drawings"].duplicate()
|
||||
var passenger_bounds: Dictionary = {}
|
||||
for cabin: Dictionary in model[&"cabins"]:
|
||||
for row: Dictionary in cabin[&"passengers"]:
|
||||
all_rows.append(row)
|
||||
passenger_bounds[row[&"key"]] = (cabin[&"rect"] as Rect2).grow(-_cell_dimensions().x/16.0)
|
||||
for row: Dictionary in all_rows:
|
||||
var person: Dictionary = people[row[&"key"]]
|
||||
row[&"cell"] = person[&"cell"]
|
||||
var region := _life_actor_region(row, person, model) if not row[&"riding"] else {&"bounds": passenger_bounds[row[&"key"]], &"transit": false}
|
||||
region[&"row"] = row
|
||||
if not region[&"transit"]:
|
||||
members.append(region)
|
||||
var groups := _life_fitted_groups(members)
|
||||
model[&"actor_aggregations"] = []
|
||||
var hidden: Dictionary = {}
|
||||
for group: Array in groups:
|
||||
group.sort_custom(func(a: Dictionary, b: Dictionary) -> bool: return a[&"row"][&"center"].x < b[&"row"][&"center"].x or (a[&"row"][&"center"].x == b[&"row"][&"center"].x and a[&"row"][&"key"] < b[&"row"][&"key"]))
|
||||
var base := 1.0
|
||||
for member: Dictionary in group:
|
||||
base = maxf(base, member[&"row"][&"scale"])
|
||||
var fitted := _life_pack(group, base)
|
||||
var retained: Array = group
|
||||
if fitted.is_empty():
|
||||
retained = []
|
||||
var identities: Array = []
|
||||
var drawn: Array = []
|
||||
for member: Dictionary in group:
|
||||
var row: Dictionary = member[&"row"]
|
||||
identities.append({&"key": row[&"key"], &"id": people[row[&"key"]][&"id"], &"state": row[&"state"], &"cell": row[&"cell"], &"mode": row[&"mode"]})
|
||||
var attempt := retained.duplicate()
|
||||
attempt.append(member)
|
||||
var packed := _life_pack(attempt, 1)
|
||||
if not packed.is_empty():
|
||||
retained = attempt
|
||||
fitted = packed
|
||||
drawn.append(row[&"key"])
|
||||
else:
|
||||
hidden[row[&"key"]] = true
|
||||
model[&"actor_aggregations"].append({&"members": identities, &"drawn_keys": drawn, &"at": (group[0][&"bounds"] as Rect2).position, &"text": "+%d" % (group.size()-retained.size())})
|
||||
for i: int in fitted.size():
|
||||
retained[i][&"row"].merge(fitted[i], true)
|
||||
model[&"actor_drawings"] = model[&"actor_drawings"].filter(func(row: Dictionary) -> bool: return not hidden.has(row[&"key"]))
|
||||
for cabin: Dictionary in model[&"cabins"]:
|
||||
cabin[&"passengers"] = cabin[&"passengers"].filter(func(row: Dictionary) -> bool: return not hidden.has(row[&"key"]))
|
||||
|
||||
|
||||
func _draw_excavation_jobs() -> void:
|
||||
var excavation: Variant = _service(&"excavation_service")
|
||||
if excavation == null or not excavation.has_method(&"get_jobs"):
|
||||
|
||||
Reference in New Issue
Block a user