wip: reworking cards to use sprites and fixing up some stuff related to them

This commit is contained in:
ShyProton 2025-04-27 20:05:28 -04:00
parent d1ef1d6f4f
commit 7cddb502b4
10 changed files with 148 additions and 76 deletions

View File

@ -9,37 +9,40 @@ var _emitted_done = 0
signal fetch_start signal fetch_start
var _emitted_start = 0 var _emitted_start = 0
var _consts = preload("res://data/consts.gd") var _consts = preload("res://data/consts.gd")
func _all_downloads_done() -> bool: func _all_downloads_done() -> bool:
return _emitted_done == _emitted_start return _emitted_done == _emitted_start
func _setup_cache_in_mem(): func _setup_cache_in_mem():
var file = FileAccess.open("user://bulk.json", FileAccess.READ) var file = FileAccess.open("user://bulk.json", FileAccess.READ)
_bulk_data = JSON.parse_string(file.get_as_text()) _bulk_data = JSON.parse_string(file.get_as_text())
file.close() file.close()
func setup() -> Error: func setup() -> Error:
if !FileAccess.file_exists("user://bulk.json"): if !FileAccess.file_exists("user://bulk.json"):
get_bulk_data(false) get_bulk_data(false)
push_error("Bulk Data was not downloaded! Downloading now!") push_error("Bulk Data was not downloaded! Downloading now!")
return FAILED return FAILED
if !_all_downloads_done(): if !_all_downloads_done():
push_error("Not done downloading Bulk Data.") push_error("Not done downloading Bulk Data.")
return FAILED return FAILED
_setup_cache_in_mem() _setup_cache_in_mem()
return OK return OK
func _init() -> void: func _init() -> void:
_req_headers = PackedStringArray(["User-Agent: " + _consts.APP_NAME + "/" + _consts.APP_VERSION, "Accept: */*"]) _req_headers = PackedStringArray(
["User-Agent: " + _consts.APP_NAME + "/" + _consts.APP_VERSION, "Accept: */*"]
)
fetch_done.connect(_on_end_emit) fetch_done.connect(_on_end_emit)
fetch_start.connect(_on_start_emit) fetch_start.connect(_on_start_emit)
func _on_start_emit() -> void: func _on_start_emit() -> void:
@ -49,20 +52,22 @@ func _on_start_emit() -> void:
func _on_end_emit() -> void: func _on_end_emit() -> void:
_emitted_done += 1 _emitted_done += 1
func has_emitted_all() -> bool: func has_emitted_all() -> bool:
return _emitted_start == _emitted_done return _emitted_start == _emitted_done
func _cache_error(err: String) -> String: func _cache_error(err: String) -> String:
return "CACHE::ERROR::" + err + "\n" return "CACHE::ERROR::" + err + "\n"
func _get_dict_from_file(filepath: String) -> Dictionary: func _get_dict_from_file(filepath: String) -> Dictionary:
var file = FileAccess.open(filepath, FileAccess.READ) var file = FileAccess.open(filepath, FileAccess.READ)
var data = JSON.parse_string(file.get_as_text()) var data = JSON.parse_string(file.get_as_text())
return data return data
## get_card_data_from_name ## get_card_data_from_name
## ##
## _name: String [br] ## _name: String [br]
@ -88,108 +93,114 @@ func _get_card_data_from_bulk(field: String, search_query: String) -> Dictionary
selected_entry = entry selected_entry = entry
break break
continue continue
if selected_entry == null: if selected_entry == null:
return {} return {}
if selected_entry["image_status"] != "missing": if selected_entry["image_status"] != "missing":
_fetch_card_img(selected_entry) _fetch_card_img(selected_entry)
var dir = DirAccess.open("user://") var dir = DirAccess.open("user://")
dir.make_dir_recursive("user://card_cache/" + selected_entry["id"] + "/") dir.make_dir_recursive("user://card_cache/" + selected_entry["id"] + "/")
dir = null dir = null
var file = FileAccess.open("user://card_cache/" + selected_entry["id"] + "/card.json", FileAccess.WRITE) var file = FileAccess.open(
"user://card_cache/" + selected_entry["id"] + "/card.json", FileAccess.WRITE
)
file.store_line(JSON.stringify(selected_entry, "\t")) file.store_line(JSON.stringify(selected_entry, "\t"))
file.close() file.close()
print("Card: " + selected_entry["name"] + "(" + selected_entry["id"] + ") found, and cached.") print("Card: " + selected_entry["name"] + "(" + selected_entry["id"] + ") found, and cached.")
return selected_entry return selected_entry
func _fetch_card_img(data: Dictionary) -> Error: func _fetch_card_img(data: Dictionary) -> Error:
fetch_start.emit() fetch_start.emit()
if FileAccess.file_exists("user://card_cache/" + data["id"] + "card.png"): if FileAccess.file_exists("user://card_cache/" + data["id"] + "card.png"):
return OK return OK
var httpr = HTTPRequest.new() var httpr = HTTPRequest.new()
add_child(httpr) add_child(httpr)
var err = httpr.request((data["image_uris"])["png"], _req_headers) var err = httpr.request((data["image_uris"])["png"], _req_headers)
if err != OK: if err != OK:
push_error(_cache_error("GET_REQUEST") + "An error occured in the Scryfall request.") push_error(_cache_error("GET_REQUEST") + "An error occured in the Scryfall request.")
return FAILED return FAILED
var resp = await httpr.request_completed var resp = await httpr.request_completed
var img = Image.new() var img = Image.new()
err = img.load_png_from_buffer(resp[3]) err = img.load_png_from_buffer(resp[3])
if err != OK: if err != OK:
push_error(_cache_error("IMG_LOADING") + "Couldn't load the image.") push_error(_cache_error("IMG_LOADING") + "Couldn't load the image.")
return FAILED return FAILED
var dir = DirAccess.open("user://") var dir = DirAccess.open("user://")
dir.make_dir_recursive("user://card_cache/" + data["id"] + "/") dir.make_dir_recursive("user://card_cache/" + data["id"] + "/")
dir = null dir = null
img.save_png("user://card_cache/" + data["id"] + "/card.png") img.save_png("user://card_cache/" + data["id"] + "/card.png")
img = null img = null
fetch_done.emit() fetch_done.emit()
return OK return OK
func get_bulk_data(force: bool) -> Error: func get_bulk_data(force: bool) -> Error:
if FileAccess.file_exists("user://bulk.json"): if FileAccess.file_exists("user://bulk.json"):
if force: if force:
DirAccess.remove_absolute("user://bulk.json") DirAccess.remove_absolute("user://bulk.json")
else: else:
return OK return OK
var httpr = HTTPRequest.new() var httpr = HTTPRequest.new()
add_child(httpr) add_child(httpr)
var error = httpr.request("https://api.scryfall.com/bulk-data/unique-artwork", _req_headers) var error = httpr.request("https://api.scryfall.com/bulk-data/unique-artwork", _req_headers)
if error != OK: if error != OK:
push_error(_cache_error("GET_REQUEST") + "An error occurred in the Scryfall request.") push_error(_cache_error("GET_REQUEST") + "An error occurred in the Scryfall request.")
return FAILED return FAILED
var response = await httpr.request_completed var response = await httpr.request_completed
if response[0] != HTTPRequest.RESULT_SUCCESS: if response[0] != HTTPRequest.RESULT_SUCCESS:
push_error(_cache_error("GET_REQUEST") + "Failed to fetch card data from Scryfall") push_error(_cache_error("GET_REQUEST") + "Failed to fetch card data from Scryfall")
return FAILED return FAILED
var unprocessed_body = response[3].get_string_from_utf8() var unprocessed_body = response[3].get_string_from_utf8()
var card_content = JSON.parse_string(unprocessed_body) var card_content = JSON.parse_string(unprocessed_body)
if card_content == null: if card_content == null:
push_error(_cache_error("PARSING") + "Failed to parse the Scryfall card results.") push_error(_cache_error("PARSING") + "Failed to parse the Scryfall card results.")
return FAILED return FAILED
error = httpr.request(card_content["download_uri"], _req_headers) error = httpr.request(card_content["download_uri"], _req_headers)
if error != OK: if error != OK:
push_error(_cache_error("GET_REQUEST") + "An error occurred in the Scryfall request.") push_error(_cache_error("GET_REQUEST") + "An error occurred in the Scryfall request.")
return FAILED return FAILED
response = await httpr.request_completed response = await httpr.request_completed
if response[0] != HTTPRequest.RESULT_SUCCESS: if response[0] != HTTPRequest.RESULT_SUCCESS:
push_error(_cache_error("GET_REQUEST") + "Failed to fetch card data from Scryfall") push_error(_cache_error("GET_REQUEST") + "Failed to fetch card data from Scryfall")
return FAILED return FAILED
unprocessed_body = response[3].get_string_from_utf8() unprocessed_body = response[3].get_string_from_utf8()
card_content = JSON.parse_string(unprocessed_body) card_content = JSON.parse_string(unprocessed_body)
if card_content == null: if card_content == null:
push_error(_cache_error("PARSING") + "Failed to parse the Scryfall card results.") push_error(_cache_error("PARSING") + "Failed to parse the Scryfall card results.")
return FAILED return FAILED
var data_cache = FileAccess.open("user://bulk.json", FileAccess.WRITE) var data_cache = FileAccess.open("user://bulk.json", FileAccess.WRITE)
data_cache.store_string(unprocessed_body) data_cache.store_string(unprocessed_body)
data_cache.close() data_cache.close()
fetch_done.emit() fetch_done.emit()
return OK return OK
func _notification(what): func _notification(what):
if what == NOTIFICATION_PREDELETE: if what == NOTIFICATION_PREDELETE:
if !_all_downloads_done(): if !_all_downloads_done():
push_error("ERR::MEM::CACHE\nCache being deleted before all threads have finished processing!") push_error(
"ERR::MEM::CACHE\nCache being deleted before all threads have finished processing!"
)

71
card.gd
View File

@ -5,12 +5,7 @@ extends TextureRect
## Represents an instance of a card to be displayed on the tabletop. ## Represents an instance of a card to be displayed on the tabletop.
## Contains helper text for the text, the cards ID, and the image path. ## Contains helper text for the text, the cards ID, and the image path.
enum pivot { enum pivot { ROTATE_0, ROTATE_90, ROTATE_180, ROTATE_270 }
ROTATE_0,
ROTATE_90,
ROTATE_180,
ROTATE_270
}
var current_pivot = pivot.ROTATE_0 var current_pivot = pivot.ROTATE_0
@ -19,14 +14,16 @@ var card_name: String
var card_type: String var card_type: String
var oracle_text: String var oracle_text: String
var is_dragging = false # Tween trackers for distinguishing which state the card is in.
var is_pivot = false var is_focused = false # Is the card a focus?
var is_dragging = false # Is the card currently being dragged?
var is_travelling = false # Is the card moving to a location?
var is_pivot = false # Is the card currently waiting to be tapped/untapped?
var delay = 5.0 var delay = 5.0
var mouse_offset: Vector2 var mouse_offset: Vector2
func _pivot() -> int: func _pivot() -> int:
var deg: int var deg: int
match current_pivot: match current_pivot:
@ -39,17 +36,29 @@ func _pivot() -> int:
pivot.ROTATE_270: pivot.ROTATE_270:
deg = 270 deg = 270
return deg return deg
func _physics_process(delta: float) -> void: func _physics_process(delta: float) -> void:
if is_dragging == true: _tweening(delta)
var tween = get_tree().create_tween()
tween.tween_property(self, "position", get_global_mouse_position() - mouse_offset, delay * delta)
if is_pivot == true: func _tweening(delta: float) -> void:
var tween = get_tree().create_tween() var tween = get_tree().create_tween()
if is_focused:
tween.tween_property(self, "scale", Vector2(1.05, 1.05), delta * delay)
else:
tween.tween_property(self, "scale", Vector2(1.0, 1.0), delta * delay)
if is_dragging:
tween.tween_property(
self, "position", get_global_mouse_position() - mouse_offset, delay * delta
)
if is_pivot:
tween.tween_property(self, "rotation_degrees", _pivot(), delta * delay) tween.tween_property(self, "rotation_degrees", _pivot(), delta * delay)
is_pivot = false is_pivot = false
func _gui_input(event: InputEvent) -> void: func _gui_input(event: InputEvent) -> void:
if event is not InputEventMouseButton: if event is not InputEventMouseButton:
@ -57,14 +66,30 @@ func _gui_input(event: InputEvent) -> void:
match event.button_index: match event.button_index:
MOUSE_BUTTON_LEFT: MOUSE_BUTTON_LEFT:
if event.pressed: if event.pressed:
is_dragging = true is_dragging = true
mouse_offset = get_global_mouse_position() - global_position mouse_offset = get_global_mouse_position() - global_position
else: else:
is_dragging = false is_dragging = false
MOUSE_BUTTON_RIGHT: MOUSE_BUTTON_RIGHT:
# TODO: Tooltip menu for right-button clicking on cards.
pass pass
func _on_mouse_entered() -> void:
is_focused = true
func _on_mouse_exited() -> void:
if not is_dragging:
is_focused = false
func travel_to(position: Vector2) -> Error:
# TODO: Check whether position to travel to is within the confines of where this card can go.
return OK
func _unhandled_key_input(event: InputEvent) -> void: func _unhandled_key_input(event: InputEvent) -> void:
if not event.is_action_pressed("default_action"): if not event.is_action_pressed("default_action"):
return return
@ -76,13 +101,14 @@ func _unhandled_key_input(event: InputEvent) -> void:
is_pivot = true is_pivot = true
set_pivot_offset(size / 2) set_pivot_offset(size / 2)
func _card_error(error_type: String) -> String: func _card_error(error_type: String) -> String:
return "ERROR::CARD::%s::%s::%s::\n" % [card_id, card_name, error_type] return "ERROR::CARD::%s::%s::%s::\n" % [card_id, card_name, error_type]
func init(id: String) -> void: func init(id: String) -> void:
card_id = id card_id = id
func _ready() -> void: func _ready() -> void:
var load_status = _load_card() var load_status = _load_card()
@ -91,7 +117,7 @@ func _ready() -> void:
# if the card is not cached, perhaps a placeholder blank card can be used instead? # if the card is not cached, perhaps a placeholder blank card can be used instead?
# Setting that up can be put here later... # Setting that up can be put here later...
push_error("Failed to load card.") push_error("Failed to load card.")
set_pivot_offset(size / 2) set_pivot_offset(size / 2)
@ -140,16 +166,11 @@ func _load_image() -> Error:
push_error("%sCard on-board image failed to load correctly" % _card_error("IMAGE")) push_error("%sCard on-board image failed to load correctly" % _card_error("IMAGE"))
return FAILED return FAILED
# TODO: Get the size from the node or some constant variable.
image.resize(int(size.x), int(size.y), Image.INTERPOLATE_LANCZOS) image.resize(int(size.x), int(size.y), Image.INTERPOLATE_LANCZOS)
var image_texture = ImageTexture.new() var image_texture = ImageTexture.new()
image_texture.set_image(image) image_texture.set_image(image)
#expand_mode = TextureRect.EXPAND_FIT_WIDTH
texture = image_texture texture = image_texture
return OK return OK

View File

@ -1,7 +1,9 @@
[gd_scene load_steps=2 format=3 uid="uid://cah3mvdnom1xg"] [gd_scene load_steps=3 format=3 uid="uid://cah3mvdnom1xg"]
[ext_resource type="Script" uid="uid://b3yqd1qu7dyq" path="res://card.gd" id="1_kikvd"] [ext_resource type="Script" uid="uid://b3yqd1qu7dyq" path="res://card.gd" id="1_kikvd"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_kikvd"]
[node name="Card" type="TextureRect"] [node name="Card" type="TextureRect"]
offset_left = 794.0 offset_left = 794.0
offset_top = 79.0 offset_top = 79.0
@ -9,3 +11,11 @@ offset_right = 919.0
offset_bottom = 254.0 offset_bottom = 254.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
script = ExtResource("1_kikvd") script = ExtResource("1_kikvd")
[node name="Area2D" type="Area2D" parent="."]
[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"]
shape = SubResource("RectangleShape2D_kikvd")
[connection signal="mouse_entered" from="." to="." method="_on_mouse_entered"]
[connection signal="mouse_exited" from="." to="." method="_on_mouse_exited"]

View File

@ -6,6 +6,7 @@ var _decklist
var cards: String var cards: String
func _init(_cards: String) -> void: func _init(_cards: String) -> void:
cards = _cards cards = _cards
_decklist = Dictionary() _decklist = Dictionary()
@ -18,7 +19,7 @@ func _convert_mtgo_to_cache_lookup(decklist: String) -> Dictionary:
var words = line.split(" ", false, 1) var words = line.split(" ", false, 1)
if words.size() != 2: if words.size() != 2:
continue continue
_cards[words[1]] = words[0] _cards[words[1]] = words[0]
return _cards return _cards
@ -37,7 +38,7 @@ func do_decklist_grab(decklist: String) -> void:
for query in queries: for query in queries:
var entry = cache.get_card_data_from_name(query) var entry = cache.get_card_data_from_name(query)
_decklist[entry["id"]] = queries[query] _decklist[entry["id"]] = queries[query]
cache.fetch_done.connect(_do_free.bind(cache)) cache.fetch_done.connect(_do_free.bind(cache))

15
hand.gd Normal file
View File

@ -0,0 +1,15 @@
extends StaticBody2D
var cards: Array[Node] = []
var _card_class = preload("res://card.tscn")
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
pass

1
hand.gd.uid Normal file
View File

@ -0,0 +1 @@
uid://dvu4gdhqjejeo

View File

@ -19,6 +19,7 @@ func _init(_decklist: Dictionary) -> void:
for i in _num: for i in _num:
lib_cards.push_back(card) lib_cards.push_back(card)
func add_cards(cards: Array, top: bool) -> void: func add_cards(cards: Array, top: bool) -> void:
for card in cards: for card in cards:
add_card(card, top) add_card(card, top)

View File

@ -7,18 +7,21 @@ var fields: Array[Node] = []
var decks: Array[Dictionary] var decks: Array[Dictionary]
func _load_decks(): func _load_decks():
if !FileAccess.file_exists("user://decks.json"): if !FileAccess.file_exists("user://decks.json"):
return # no loaded decks return # no loaded decks
var file = FileAccess.open("user://decks.json", FileAccess.READ) var file = FileAccess.open("user://decks.json", FileAccess.READ)
decks = JSON.parse_string(file.get_as_text()) decks = JSON.parse_string(file.get_as_text())
file.close() file.close()
# Called when the node enters the scene tree for the first time. # Called when the node enters the scene tree for the first time.
func _ready() -> void: func _ready() -> void:
# The first field in the array will be the player's own field. # The first field in the array will be the player's own field.
# Might be a better idea to have that in a seperate variable? idk # Might be a better idea to have that in a seperate variable? idk
var card = _card_class.instantiate() var card = _card_class.instantiate()
# TODO: Currently working with an already-cached card with a known ID to load this. # TODO: Currently working with an already-cached card with a known ID to load this.
@ -26,7 +29,7 @@ func _ready() -> void:
card.init("d3f10f07-7cfe-4a6f-8de6-373e367a731b") card.init("d3f10f07-7cfe-4a6f-8de6-373e367a731b")
add_child(card) add_child(card)
#fields.append(field_scene.instantiate()) #fields.append(field_scene.instantiate())
#var colors: Array[Color] = [Color(1, 0, 1)] #var colors: Array[Color] = [Color(1, 0, 1)]
#fields[0].set_colors(colors) #fields[0].set_colors(colors)

View File

@ -1,12 +1,21 @@
[gd_scene load_steps=3 format=3 uid="uid://cx0vga81xwckh"] [gd_scene load_steps=5 format=3 uid="uid://cx0vga81xwckh"]
[ext_resource type="Script" uid="uid://w2rqm1u7p7im" path="res://player.gd" id="1_4flbx"] [ext_resource type="Script" uid="uid://w2rqm1u7p7im" path="res://player.gd" id="1_4flbx"]
[ext_resource type="Script" uid="uid://dvu4gdhqjejeo" path="res://hand.gd" id="2_i3pqv"]
[ext_resource type="Script" uid="uid://bc51go8t8uvts" path="res://library.gd" id="2_onrkg"] [ext_resource type="Script" uid="uid://bc51go8t8uvts" path="res://library.gd" id="2_onrkg"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_onrkg"]
size = Vector2(1920, 200)
[node name="Player" type="Node2D"] [node name="Player" type="Node2D"]
script = ExtResource("1_4flbx") script = ExtResource("1_4flbx")
[node name="Hand" type="Node2D" parent="."] [node name="Hand" type="StaticBody2D" parent="."]
script = ExtResource("2_i3pqv")
[node name="CollisionArea" type="CollisionShape2D" parent="Hand"]
position = Vector2(960, 980)
shape = SubResource("RectangleShape2D_onrkg")
[node name="Library" type="Node2D" parent="."] [node name="Library" type="Node2D" parent="."]
script = ExtResource("2_onrkg") script = ExtResource("2_onrkg")

View File

@ -4,17 +4,18 @@ var player_class = preload("res://player.gd")
var deck_input = preload("res://deck_input.gd") var deck_input = preload("res://deck_input.gd")
var _caching = preload("res://caching.gd") var _caching = preload("res://caching.gd")
var cards = "1 All That Glitters\n1 Ancestral Mask\n1 Angelic Destiny\n1 Arcane Signet\n1 Archon of Sun's Grace\n1 Austere Command\n1 Banishing Light\n1 Bear Umbra\n1 Blossoming Sands\n1 Canopy Vista\n1 Celestial Mantle\n1 Collective Resistance\n1 Command Tower\n1 Danitha Capashen, Paragon\n1 Danitha, New Benalia's Light\n1 Darksteel Mutation\n1 Daybreak Coronet\n1 Destiny Spinner\n1 Eidolon of Blossoms\n1 Eidolon of Countless Battles\n1 Ellivere of the Wild Court\n1 Enchantress's Presence\n1 Envoy of the Ancestors\n1 Ethereal Armor\n1 Fertile Ground\n13 Forest\n1 Frantic Strength\n1 Generous Gift\n1 Gilded Lotus\n1 Glittering Frost\n1 Grasp of Fate\n1 Gylwain, Casting Director\n1 Hall of Heliod's Generosity\n1 Heliod's Pilgrim\n1 Hidden Grotto\n1 Horrid Vigor\n1 Idyllic Tutor\n1 Jukai Naturalist\n1 Kenrith's Transformation\n1 Kor Spiritdancer\n1 Krosan Verge\n1 Light-Paws, Emperor's Voice\n1 Luminous Broodmoth\n1 Mantle of the Ancients\n1 Overgrowth\n1 Overprotect\n1 Pacifism\n14 Plains\n1 Rancor\n1 Retether\n1 Rogue's Passage\n1 Sage's Reverie\n1 Sanctum Weaver\n1 Selesnya Guildgate\n1 Setessan Champion\n1 Shalai, Voice of Plenty\n1 Snake Umbra\n1 Sol Ring\n1 Solemnity\n1 Songbirds' Blessing\n1 Starfield Mystic\n1 Swords to Plowshares\n1 Tanglespan Lookout\n1 Timber Paladin\n1 Timely Ward\n1 Tithe Takern1 Transcendent Envoy\n1 Twinblade Blessing\n1 Umbra Mystic\n1 Unfinished Business\n1 Utopia Sprawl\n1 Wild Growth\n1 Winds of Rath\n1 Yenna, Redtooth Regent\n1 Sythis, Harvest's Hand" var cards = "1 All That Glitters\n1 Ancestral Mask\n1 Angelic Destiny\n1 Arcane Signet\n1 Archon of Sun's Grace\n1 Austere Command\n1 Banishing Light\n1 Bear Umbra\n1 Blossoming Sands\n1 Canopy Vista\n1 Celestial Mantle\n1 Collective Resistance\n1 Command Tower\n1 Danitha Capashen, Paragon\n1 Danitha, New Benalia's Light\n1 Darksteel Mutation\n1 Daybreak Coronet\n1 Destiny Spinner\n1 Eidolon of Blossoms\n1 Eidolon of Countless Battles\n1 Ellivere of the Wild Court\n1 Enchantress's Presence\n1 Envoy of the Ancestors\n1 Ethereal Armor\n1 Fertile Ground\n13 Forest\n1 Frantic Strength\n1 Generous Gift\n1 Gilded Lotus\n1 Glittering Frost\n1 Grasp of Fate\n1 Gylwain, Casting Director\n1 Hall of Heliod's Generosity\n1 Heliod's Pilgrim\n1 Hidden Grotto\n1 Horrid Vigor\n1 Idyllic Tutor\n1 Jukai Naturalist\n1 Kenrith's Transformation\n1 Kor Spiritdancer\n1 Krosan Verge\n1 Light-Paws, Emperor's Voice\n1 Luminous Broodmoth\n1 Mantle of the Ancients\n1 Overgrowth\n1 Overprotect\n1 Pacifism\n14 Plains\n1 Rancor\n1 Retether\n1 Rogue's Passage\n1 Sage's Reverie\n1 Sanctum Weaver\n1 Selesnya Guildgate\n1 Setessan Champion\n1 Shalai, Voice of Plenty\n1 Snake Umbra\n1 Sol Ring\n1 Solemnity\n1 Songbirds' Blessing\n1 Starfield Mystic\n1 Swords to Plowshares\n1 Tanglespan Lookout\n1 Timber Paladin\n1 Timely Ward\n1 Tithe Takern1 Transcendent Envoy\n1 Twinblade Blessing\n1 Umbra Mystic\n1 Unfinished Business\n1 Utopia Sprawl\n1 Wild Growth\n1 Winds of Rath\n1 Yenna, Redtooth Regent\n1 Sythis, Harvest's Hand"
func _bulk_callback(cache) -> void: func _bulk_callback(cache) -> void:
cache.setup() cache.setup()
# Called when the node enters the scene tree for the first time. # Called when the node enters the scene tree for the first time.
func _ready() -> void: func _ready() -> void:
var cache = _caching.new() var cache = _caching.new()
add_child(cache) add_child(cache)
if cache.setup() != OK: if cache.setup() != OK:
cache.fetch_done.connect(_bulk_callback.bind(cache)) cache.fetch_done.connect(_bulk_callback.bind(cache))
# TODO: Create 2-4 player instances as children of this tabletop node. # TODO: Create 2-4 player instances as children of this tabletop node.
@ -22,12 +23,11 @@ func _ready() -> void:
var player = player_class.new() var player = player_class.new()
add_child(player) add_child(player)
move_child(player, 0) move_child(player, 0)
cache.get_card_data_from_name("1996 World Champion") cache.get_card_data_from_name("1996 World Champion")
var deck = deck_input.new(cards) # var deck = deck_input.new(cards)
add_child(deck) # add_child(deck)
pass # Replace with function body. pass # Replace with function body.