class_name HardcodedCards extends Control @onready var card_prefab : PackedScene = preload("res://logic-scenes/board/card.tscn") @onready var note_prefab : PackedScene = preload("res://logic-scenes/board/sticky-note.tscn") var source_dicts: Array[Dictionary] = [ { "c_out_of_world": ["p_unique", "p_few_friends", []], "c_rejection": ["p_finding_friends", "p_laughed_at", []], "c_confusion": ["p_inner_conflict", "p_outer_conflict", []] }, { "c_homework": ["p_good_grades", "p_worried_mother", []], "c_teachers": ["p_volunteering", "p_becoming_teacher", []], "c_gifted": ["p_upset_peers", "p_joy", []] }, { "c_comic_heroes": ["p_effort", "p_agent_q", []], "c_boy_stuff": ["p_pretending", "p_girls", []], "c_teasing": ["p_my_own_good", "p_good_intended", ["p_thomas_gifted"]] }, { "c_jui_jutsu": ["p_body", "p_girly", []], "c_void": ["p_wet", "p_stop", []], "c_hit": ["p_confidence", "p_vent", ["p_becoming_teacher"]] }, { "c_seen": ["p_understanding_self", "p_starting_change", []], "c_autistic": ["p_always_afraid", "p_in_hindsight", []], "c_support": ["p_pride", "p_not_mutual", []] }, { "c_being_girl": ["p_other_way", "p_always_known", []], "c_not_girl": ["p_xavier", "p_fuck_that", []], "c_find_out": ["p_rad", "p_consequences", []] }, { "c_lukas_fault": ["p_aaa", "p_bbb", []], "c_ran_away": ["p_lovable", "p_my_trauma", []], "c_difficult_teachers": ["p_nightmare_children", "p_failing_forward", []] }, { "c_mom": ["p_good_intensions", "p_helplessness", []], "c_no_eating": ["p_coping", "p_too_everythig", []], "c_adoption": ["p_flawed_help", "p_bodily_needs", []] }, { "c_mental_health": ["p_early_recognition", "p_unhelpful_lectures", []], "c_adhd_life": ["p_upset_thoughts", "p_me_weird", []], "c_auti_brother": ["p_cruel_kindness", "p_time_and_faith", []] }, { "c_doing_right": ["p_getting_right", "p_self_lying", []], "c_work_piling": ["p_push_myself", "p_improve_myself", []], "c_best_version": ["p_kids_deserve", "p_whoami", []] }, { "c_right_choice": ["p_not_belonging", "p_stubborn", []], "c_creating_support": ["p_self_taught", "p_peer_review", []], "c_peer_therapy": ["p_real_help", "p_great_therapy", []] }, { "c_trauma_regrets": ["p_toxic_thoughts", "p_diganose_benefits", []], "c_cravings": ["p_therapy_talk", "p_procastinate", []], "c_ex_hurt": ["p_lessons_learned", "p_thought_spiral", []] }, ] var id_reference: Dictionary[StringName, StringName] = generate_id_reference(true, true) var card_id_reference: Dictionary[StringName, StringName] = generate_id_reference(true, false) var sticky_id_reference: Dictionary[StringName, StringName] = generate_id_reference(false, true) var obscure_reference: Dictionary[StringName, StringName] = generate_obscure_reference() func generate_id_reference(include_cards: bool, include_sticky: bool) -> Dictionary[StringName, StringName]: var out:Dictionary[StringName, StringName] = {} for id in range(source_dicts.size()): for card_name:String in source_dicts[id].keys(): if include_cards: out[card_name] = "%d.%s" % [id, card_name] if include_sticky: for sticky_name in source_dicts[id][card_name]: if sticky_name is String: out[sticky_name] = "%d.%s.%s" % [id, card_name, sticky_name] return out func generate_obscure_reference(): var out:Dictionary[StringName, StringName] = {} randomize() var salt = randi_range(1111, 9999) for id in range(source_dicts.size()): for card_name:String in source_dicts[id].keys(): out[card_name] = StringName("%d.%d" % [id, card_name.hash() % salt ]) for sticky_name in source_dicts[id][card_name]: if sticky_name is String: out[sticky_name] = StringName("%d.%s.%s" % [id, card_name.hash() % salt, sticky_name.hash() % salt]) return out func get_child_names_of(parent_id: StringName) -> Array[StringName]: var out: Array[StringName] for child_name: StringName in id_reference.keys(): if id_reference[child_name].contains(parent_id): if child_name != parent_id: out.append(child_name) return out #FIXME: enhance typing! func get_children_of(parent_id: StringName) -> Array: return get_cards_by_name_array(get_child_names_of(parent_id))["sticky_notes"] func get_obscure_name(card_name: StringName): if State.obscure_logs and not OS.is_debug_build(): return obscure_reference[card_name] else: return card_name func arrange(cards: Array[Card], rect: Rect2, _obstacles: Array[Area2D]) -> Array[Card]: #var total_cards := cards.size() var x:int = 0 var y:int = 0 var i:int = 0 var maximum:int = cards.size() var grid: int = ceil(sqrt(maximum)) var diameter:float = cards[0].diameter var r_cards: Array[Card] = cards.duplicate() r_cards.shuffle() while i < maximum: while x < grid and i < maximum: while y < ceil(sqrt(maximum)) and i < maximum: r_cards[i].position = rect.size / Vector2(y, x) * (1.0 / (rect.size.x * diameter) ) + rect.position + Vector2(randf_range(diameter/2+5, diameter-5), randf_range(diameter/2+5, diameter-5)) i += 1 y += 1 x += 1 for card: Card in r_cards: for _i in range(20): if is_out_of_bounds(card, rect): card.position = rect.get_center() - card.position * 0.8 continue var colliders: Array[Card] = [] for collision:Card in r_cards: if card != collision: if card.collider.collide(card.transform.rotated(PI/2), collision.collider, collision.transform.rotated(PI/2)): colliders.append(collision) if colliders != []: var nearest: Card = colliders[0] for colliding in colliders: if (colliding.position - card.position).length() > (nearest.position - card.position).length(): nearest = colliding card.position += min(nearest.position - card.position.normalized() * (card.diameter + 1), nearest.position - card.position) continue break return r_cards func is_out_of_bounds(card: Card, rect: Rect2): var world_boundaries: Array[Transform2D] = [ Transform2D(PI, rect.position), Transform2D(PI/2, rect.position), Transform2D(-PI/2, rect.position+rect.size), Transform2D(0, rect.position+rect.size) ] var shape: = WorldBoundaryShape2D.new() for boundary:Transform2D in world_boundaries: if card.collider.collide(card.transform, shape, boundary): return true return false func get_cards_by_scene_id(id: int) -> Array: var output:Array for card_name in source_dicts[id].keys(): var card := card_prefab.instantiate() as Card card.init(card_name, id_reference[card_name]); output.append(card) return output # used to put cards on the dev board func get_cards_by_name_array(names: Array[StringName]) -> Dictionary: var output:Dictionary = { "cards": [], "sticky_notes": [] } for card_name:StringName in names: if card_id_reference.has(card_name): output["cards"].append(create_from_id(id_reference[card_name])) else: output["sticky_notes"].append(create_from_id(id_reference[card_name])) return output func create_from_id(id:StringName) -> Area2D: var parsed: PackedStringArray = id.rsplit(".") if card_id_reference.values().has(id): var card := card_prefab.instantiate() as Card card.init(parsed[1], id); return card elif sticky_id_reference.values().has(id): var note := note_prefab.instantiate() as StickyNote note.init(parsed[2], id) return note else: push_error("Attempted to create Card or Sticky from non-existent ID!") return null func create_dev_board(parent: Control, _rect: Rect2) -> void: var scroll_container := ScrollContainer.new() var panel := Panel.new() parent.add_child(scroll_container) scroll_container.add_child(panel) for x in range(source_dicts.size()): var sub_parent := Panel.new() sub_parent.position = Vector2( 128 + 256*x , 0) panel.add_child(sub_parent, false, Node.INTERNAL_MODE_BACK) var y := 1 for card_name in source_dicts[x].keys(): var card:Card = create_from_id(card_id_reference[card_name]) sub_parent.add_child(card, false, Node.INTERNAL_MODE_BACK) card.position = Vector2(0, card.diameter * y - card.diameter/2) var z := 0 for sticky_name in get_child_names_of(card_name): var sticky: StickyNote = create_from_id(sticky_id_reference[sticky_name]) card.add_child(sticky, false, Node.INTERNAL_MODE_BACK) sticky.position = card.sticky_note_position + Vector2(0, 80) * z z += 1 y += 1 panel.custom_minimum_size.x = source_dicts.size() * 256 func _ready() -> void: create_dev_board(self, get_viewport().get_visible_rect()) TranslationServer.set_locale("en")