Skip to content

Commit de510a2

Browse files
authored
Merge pull request #151 from db0/selection_window
Selection Window / Nested Script
2 parents f86090f + ac8ab96 commit de510a2

19 files changed

+469
-24
lines changed

CHANGELOG.md

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,25 @@
11
# Changelog
22

3-
## 1.13 (Ongoing)
3+
## 1.13
44

5-
## Tweaks
5+
### Tweaks
66

77
* Right click in the Card Viewer filter buttons, will not press that button and unpress all the others
8-
* Can now filter also on properties not mention in CardConfig
9-
* Added button which presses all filter buttons.
8+
* Can now filter also on properties not defined in CardConfig
109
* Improved performance when showing/hiding the viewport focus
1110
* Improved performance when loading the card viewer in grid mode.
1211

12+
### New Features
13+
14+
* In Cardviewer, added button which presses all filter buttons.
15+
16+
17+
#### ScriptingEngine
18+
19+
* Added new `nested_script` task allows to execute more tasks recursively. It allows for infinite amount of nests, which can create pretty complex combinations of scripts.
20+
* Added new selection window functionality which creates an dialogue window to the player to select an amount of cards from those selected as subjects. Typically should be combined with boardseek, tutor or index subjects.
21+
Controlled by the following new keys: `KEY_NEEDS_SELECTION`, `KEY_SELECTION_COUNT`, `KEY_SELECTION_TYPE`, `KEY_SELECTION_OPTIONAL`, `KEY_SELECTION_IGNORE_SELF`
22+
1323
## 1.12
1424

1525
### Important for Upgrades

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
# Godot Card Game Framework [1.12](CHANGELOG.md)
2+
# Godot Card Game Framework [1.13](CHANGELOG.md)
33

44
![Godot Card Game Framework preview image](preview.png "Godot Card Game Framework preview image")
55

project.godot

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,11 @@ _global_script_classes=[ {
269269
"language": "GDScript",
270270
"path": "res://src/core/ScriptingEngine.gd"
271271
}, {
272+
"base": "AcceptDialog",
273+
"class": "SelectionWindow",
274+
"language": "GDScript",
275+
"path": "res://src/core/SelectionWindow.gd"
276+
}, {
272277
"base": "Line2D",
273278
"class": "TargetingArrow",
274279
"language": "GDScript",
@@ -352,6 +357,7 @@ _global_script_class_icons={
352357
"ScriptProperties": "",
353358
"ScriptTask": "",
354359
"ScriptingEngine": "",
360+
"SelectionWindow": "",
355361
"TargetingArrow": "",
356362
"Token": "",
357363
"TokenDrawer": "",

src/core/CardTemplate.gd

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1576,10 +1576,10 @@ func get_focus() -> bool:
15761576

15771577
# Returns the Card's index position among other card objects
15781578
func get_my_card_index() -> int:
1579-
if "CardPopUpSlot" in get_parent().name:
1580-
return(0)
1579+
if get_parent().has_method('get_card_index'):
1580+
return(get_parent().get_card_index(self))
15811581
else:
1582-
return get_parent().get_card_index(self)
1582+
return(0)
15831583

15841584

15851585
# Changes the hosted Control nodes filters

src/core/CardViewer/CVGridCardObject.gd

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,13 @@ func _ready() -> void:
1212
rect_min_size = CFConst.CARD_SIZE
1313

1414

15-
func setup(card_name) -> Card:
16-
display_card = cfc.instance_card(card_name)
15+
func setup(card) -> Card:
16+
if typeof(card) == TYPE_STRING:
17+
display_card = cfc.instance_card(card)
18+
else:
19+
display_card = card
20+
display_card.position = Vector2(0,0)
21+
display_card.scale = Vector2(1,1)
1722
add_child(display_card)
1823
display_card.resize_recursively(display_card._control, CFConst.THUMBNAIL_SCALE)
1924
display_card.card_front.scale_to(CFConst.THUMBNAIL_SCALE)

src/core/MousePointer.gd

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ var current_focused_card : Card = null
2323
# Instead we populate according to signals,which are more immediate
2424
var overlaps := []
2525
# When set to false, prevents the player from disable interacting with the game.
26-
var is_disabled := false
26+
var is_disabled := false setget set_disabled
2727

2828

2929
# Called when the node enters the scene tree for the first time.
@@ -122,6 +122,11 @@ func enable() -> void:
122122
func forget_focus() -> void:
123123
current_focused_card = null
124124

125+
func set_disabled(value) -> void:
126+
forget_focus()
127+
overlaps.clear()
128+
is_disabled = value
129+
125130
# Parses all collided objects and figures out which card, if any, to focus on and
126131
# also while a card is being dragged, figures out which potential area to highlight
127132
# for the drop effect.

src/core/OverridableUtils.gd

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
class_name OVUtils
77
extends Reference
88

9+
const _CARD_SELECT_SCENE_FILE = CFConst.PATH_CORE + "SelectionWindow.tscn"
10+
const _CARD_SELECT_SCENE = preload(_CARD_SELECT_SCENE_FILE)
911

1012
# Populates the info panels under the card, when it is shown in the
1113
# viewport focus or deckbuilder
@@ -27,3 +29,24 @@ func populate_info_panels(card: Card, focus_info: DetailPanels) -> void:
2729

2830
func get_subjects(_subject_request, _stored_integer : int = 0) -> Array:
2931
return([])
32+
33+
func select_card(
34+
card_list: Array,
35+
selection_count: int,
36+
selection_type: String,
37+
selection_optional: bool):
38+
cfc.game_paused = true
39+
var selected_cards
40+
var selection = _CARD_SELECT_SCENE.instance()
41+
cfc.NMAP.board.add_child(selection)
42+
selection.initiate_selection(card_list,selection_count,selection_type,selection_optional)
43+
# We have to wait until the player has finished selecting their cards
44+
yield(selection,"confirmed")
45+
if selection.is_cancelled:
46+
selected_cards = false
47+
else:
48+
selected_cards = selection.selected_cards
49+
# Garbage cleanup
50+
selection.queue_free()
51+
cfc.game_paused = false
52+
return(selected_cards)

src/core/ScriptObject.gd

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,35 @@ func _find_subjects(prev_subjects := [], stored_integer := 0) -> Array:
101101
_:
102102
subjects_array = cfc.ov_utils.get_subjects(
103103
get_property(SP.KEY_SUBJECT), stored_integer)
104+
if get_property(SP.KEY_NEEDS_SELECTION):
105+
var selection_count = get_property(SP.KEY_SELECTION_COUNT)
106+
var selection_type = get_property(SP.KEY_SELECTION_TYPE)
107+
var selection_optional = get_property(SP.KEY_SELECTION_OPTIONAL)
108+
if get_property(SP.KEY_SELECTION_IGNORE_SELF):
109+
subjects_array.erase(owner)
110+
var select_return = cfc.ov_utils.select_card(
111+
subjects_array, selection_count, selection_type, selection_optional)
112+
# In case the owner card is still focused (say because script was triggered
113+
# on double-click and card was not moved
114+
# Then we need to ensure it's unfocused
115+
# Otherwise its z-index will make it draw on top of the popup.
116+
if owner as Card:
117+
if owner.state in [Card.CardState.FOCUSED_IN_HAND]:
118+
# We also reorganize the whole hand to avoid it getting
119+
# stuck like this.
120+
for c in owner.get_parent().get_all_cards():
121+
c.interruptTweening()
122+
c.reorganize_self()
123+
if select_return is GDScriptFunctionState: # Still working.
124+
select_return = yield(select_return, "completed")
125+
# If the return is not an array, it means that the selection
126+
# was cancelled (either because there were not enough cards
127+
# or because the player pressed cancel
128+
# in which case we consider the task invalid
129+
if typeof(select_return) == TYPE_ARRAY:
130+
subjects_array = select_return
131+
else:
132+
is_valid = false
104133
subjects = subjects_array
105134
return(subjects_array)
106135

src/core/ScriptProperties.gd

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,15 @@ const KEY_SUBJECT_COUNT_V_ALL := "all"
109109
const KEY_IS_COST := "is_cost"
110110
# Value Type: bool (Default = false).
111111
#
112+
# This key is used on a task marked with KEY_IS_COST
113+
# It means that its cost effects will not evn be evaluated if previous costs
114+
# have already failed.
115+
# This is useful when there's more than 1 interactive cost,
116+
# such as targeting or selection boxes
117+
# To prevnent them from popping up even when previous costs have already failed.
118+
const KEY_ABORT_ON_COST_FAILURE := "abort_on_cost_failure"
119+
# Value Type: bool (Default = false).
120+
#
112121
# This key is used to mark a task to be executed only if the card costs
113122
# cannot be paid. As such, they will never fire,unless the card also has
114123
# an "is_cost" task.
@@ -440,6 +449,12 @@ const KEY_ALTERATION := "alteration"
440449
# Note using a minus-sign '-' in place of a plus-sign will not work as expected.
441450
# Use [KEY_IS_INVERTED](#KEY_IS_INVERTED) instead
442451
const VALUE_PER := "per_"
452+
# Value Type: Float/Int
453+
#
454+
# Used to multiply per results.
455+
# This allows us to craft scripts like
456+
# "Gain 2 Health per card on the table" or "Gain 1 Health per two cards on the table"
457+
const KEY_MULTIPLIER := "multiplier"
443458
# Value Type: String
444459
#
445460
# This key is typically needed in combination with
@@ -674,6 +689,44 @@ const VALUE_COMPARE_WITH_TRIGGER := "compare_with_trigger"
674689
#
675690
# At the script level, the whole script if cancelled.
676691
const KEY_IS_OPTIONAL := "is_optional_"
692+
# Value Type: Bool (default: False)
693+
#
694+
# If true, the script will popup a card selection window, among all the
695+
# valid subjects detected for this script.
696+
const KEY_NEEDS_SELECTION := "needs_selection"
697+
# Value Type: Int (default: 0)
698+
#
699+
# How many cards need to be selected from the selection window
700+
const KEY_SELECTION_COUNT := "selection_count"
701+
# Value Type: String (default: 'min')
702+
# How to evaluate [SELECTION_COUNT](#SELECTION_COUNT)
703+
# before the player is allowed to proceed
704+
#
705+
# * 'min': The minimum amount of cards that need to be selected
706+
# * 'equal': The exact amount of cards that need to be selected
707+
# * 'max': The maximum amount of cards that need to be selected
708+
const KEY_SELECTION_TYPE := "selection_type"
709+
# Value Type: Bool (default: False)
710+
#
711+
# Marks a selection window as optional. This means the player can opt to
712+
# select none of the possible choices.
713+
# In which case, the underlying task will be considered invalid
714+
# and if it is a cost, it will also abort further execution.
715+
const KEY_SELECTION_OPTIONAL := "selection_optional"
716+
# Value Type: Bool (default: False)
717+
#
718+
# Ignores the card executing the script from the selection window
719+
# This is necessary in some instances where the selection encompases the
720+
# scripting card, but this is unwanted. For example because the card
721+
# is supposed to already be in a different pile but this will only
722+
# technically happen as the last task.
723+
const KEY_SELECTION_IGNORE_SELF := "selection_ignore_self"
724+
# Value Type: Array
725+
#
726+
# Initiates a new instance of the scripting engine
727+
# Which runs through the specified task list
728+
# using its own cost calculations
729+
const KEY_NESTED_TASKS := "nested_tasks"
677730
#---------------------------------------------------------------------
678731
# Filter Definition Keys
679732
#
@@ -1051,7 +1104,8 @@ const TRIGGER_V_COUNT_INCREASED := "increased"
10511104
const TRIGGER_V_COUNT_DECREASED := "decreased"
10521105

10531106

1054-
# Returns the default value any script definition key should have
1107+
# For any script key defined in this reference,
1108+
# returns the default it should have
10551109
static func get_default(property: String):
10561110
var default
10571111
# for property details, see const definitionts
@@ -1061,13 +1115,18 @@ static func get_default(property: String):
10611115
KEY_IS_INVERTED,\
10621116
KEY_SET_TO_MOD,\
10631117
KEY_IS_OPTIONAL,\
1118+
KEY_NEEDS_SELECTION,\
1119+
KEY_SELECTION_OPTIONAL,\
10641120
KEY_SORT_DESCENDING,\
1121+
KEY_ABORT_ON_COST_FAILURE,\
10651122
KEY_STORE_INTEGER:
10661123
default = false
10671124
KEY_TRIGGER:
10681125
default = "any"
1069-
KEY_SUBJECT_INDEX:
1126+
KEY_SUBJECT_INDEX,KEY_SELECTION_COUNT:
10701127
default = 0
1128+
KEY_SELECTION_TYPE:
1129+
default = "min"
10711130
KEY_DEST_INDEX:
10721131
default = -1
10731132
KEY_BOARD_POSITION:
@@ -1078,7 +1137,8 @@ static func get_default(property: String):
10781137
default = {}
10791138
KEY_SUBJECT_COUNT,\
10801139
KEY_OBJECT_COUNT,\
1081-
KEY_MODIFICATION:
1140+
KEY_MODIFICATION,\
1141+
KEY_MULTIPLIER:
10821142
default = 1
10831143
KEY_GRID_NAME, KEY_SUBJECT:
10841144
default = ""

src/core/ScriptTask.gd

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class_name ScriptTask
77
extends ScriptObject
88

99
# Stores the details arg passed the signal to use for filtering
10-
var signal_details : Dictionary
10+
var trigger_details : Dictionary
1111
# If true if this task has been confirmed to run by the player
1212
# Only relevant for optional tasks (see [SP].KEY_IS_OPTIONAL)
1313
var is_accepted := true
@@ -20,9 +20,10 @@ var is_else := false
2020
func _init(owner,
2121
script: Dictionary,
2222
_trigger_object,
23-
trigger_details).(owner, script, _trigger_object) -> void:
23+
_trigger_details).(owner, script, _trigger_object) -> void:
2424
# The function name to be called gets its own var
2525
script_name = get_property("name")
26+
trigger_details = _trigger_details
2627
is_cost = get_property(SP.KEY_IS_COST)
2728
is_else = get_property(SP.KEY_IS_ELSE)
2829
if not SP.filter_trigger(

0 commit comments

Comments
 (0)