feature updates

This commit is contained in:
2026-02-02 16:28:53 -05:00
parent bf9aa3fa23
commit 44c06530ac
83 changed files with 282641 additions and 11251 deletions

View File

@@ -0,0 +1,363 @@
extends GutTest
## Tests for the Modal Choice System (CHOOSE_MODE effects)
## Tests parser output, ChoiceModal UI, and AbilitySystem integration
# =============================================================================
# PARSER OUTPUT TESTS
# =============================================================================
func test_modal_effect_has_correct_structure() -> void:
# Simulate a parsed CHOOSE_MODE effect
var effect = {
"type": "CHOOSE_MODE",
"select_count": 1,
"select_up_to": false,
"mode_count": 3,
"modes": [
{
"index": 0,
"description": "Choose 1 Forward. Deal it 7000 damage.",
"effects": [{"type": "DAMAGE", "amount": 7000}]
},
{
"index": 1,
"description": "Choose 1 Monster. Break it.",
"effects": [{"type": "BREAK"}]
},
{
"index": 2,
"description": "Deal 3000 damage to all Forwards.",
"effects": [{"type": "DAMAGE", "amount": 3000}]
}
]
}
assert_eq(effect.type, "CHOOSE_MODE", "Effect type should be CHOOSE_MODE")
assert_eq(effect.select_count, 1, "Should select 1 mode")
assert_eq(effect.mode_count, 3, "Should have 3 modes")
assert_eq(effect.modes.size(), 3, "Modes array should have 3 entries")
assert_false(effect.select_up_to, "Should not be 'up to' selection")
func test_modal_effect_with_enhanced_condition() -> void:
var effect = {
"type": "CHOOSE_MODE",
"select_count": 1,
"select_up_to": false,
"mode_count": 3,
"modes": [],
"enhanced_condition": {
"description": "if you have 5 or more ifrit in your break zone",
"select_count": 3,
"select_up_to": true
}
}
assert_true(effect.has("enhanced_condition"), "Should have enhanced condition")
assert_eq(effect.enhanced_condition.select_count, 3, "Enhanced should allow 3 selections")
assert_true(effect.enhanced_condition.select_up_to, "Enhanced should be 'up to'")
func test_modal_mode_has_description_and_effects() -> void:
var mode = {
"index": 0,
"description": "Draw 2 cards.",
"effects": [{"type": "DRAW", "amount": 2}]
}
assert_true(mode.has("description"), "Mode should have description")
assert_true(mode.has("effects"), "Mode should have effects array")
assert_eq(mode.effects.size(), 1, "Mode should have 1 effect")
assert_eq(mode.effects[0].type, "DRAW", "Effect should be DRAW")
# =============================================================================
# CHOICE MODAL TESTS
# =============================================================================
func test_choice_modal_instantiates() -> void:
var modal = ChoiceModal.new()
assert_not_null(modal, "ChoiceModal should instantiate")
modal.free()
func test_choice_modal_starts_invisible() -> void:
var modal = ChoiceModal.new()
add_child_autofree(modal)
# Need to wait for _ready to complete
await get_tree().process_frame
assert_false(modal.visible, "ChoiceModal should start invisible")
func test_choice_modal_has_correct_layer() -> void:
var modal = ChoiceModal.new()
add_child_autofree(modal)
await get_tree().process_frame
assert_eq(modal.layer, 200, "ChoiceModal should be at layer 200")
func test_choice_modal_signals_exist() -> void:
var modal = ChoiceModal.new()
assert_true(modal.has_signal("choice_made"), "Should have choice_made signal")
assert_true(modal.has_signal("choice_cancelled"), "Should have choice_cancelled signal")
modal.free()
# =============================================================================
# EFFECT RESOLVER TESTS
# =============================================================================
func test_effect_resolver_has_choice_required_signal() -> void:
var resolver = EffectResolver.new()
assert_true(resolver.has_signal("choice_required"), "Should have choice_required signal")
func test_effect_resolver_emits_choice_required_for_choose_mode() -> void:
var resolver = EffectResolver.new()
var signal_received = false
var received_effect = {}
var received_modes = []
resolver.choice_required.connect(func(effect, modes):
signal_received = true
received_effect = effect
received_modes = modes
)
var effect = {
"type": "CHOOSE_MODE",
"modes": [
{"index": 0, "description": "Option 1", "effects": []},
{"index": 1, "description": "Option 2", "effects": []}
]
}
# Resolve the effect
resolver.resolve(effect, null, [], null)
assert_true(signal_received, "Should emit choice_required signal")
assert_eq(received_modes.size(), 2, "Should pass modes to signal")
# =============================================================================
# FIELD EFFECT MANAGER TESTS
# =============================================================================
func test_field_effect_manager_block_immunity_empty() -> void:
var manager = FieldEffectManager.new()
# With no abilities registered, should return false
var result = manager.has_block_immunity(null, null, null)
assert_false(result, "Should return false with no abilities")
func test_field_effect_manager_attack_restriction_empty() -> void:
var manager = FieldEffectManager.new()
var result = manager.has_attack_restriction(null, null)
assert_false(result, "Should return false with no abilities")
func test_field_effect_manager_block_restriction_empty() -> void:
var manager = FieldEffectManager.new()
var result = manager.has_block_restriction(null, null)
assert_false(result, "Should return false with no abilities")
func test_field_effect_manager_taunt_targets_empty() -> void:
var manager = FieldEffectManager.new()
var result = manager.get_taunt_targets(0, null)
assert_eq(result.size(), 0, "Should return empty array with no abilities")
func test_field_effect_manager_cost_modifier_empty() -> void:
var manager = FieldEffectManager.new()
var result = manager.get_cost_modifier(null, 0, null)
assert_eq(result, 0, "Should return 0 with no abilities")
func test_field_effect_manager_max_attacks_default() -> void:
var manager = FieldEffectManager.new()
var result = manager.get_max_attacks(null, null)
assert_eq(result, 1, "Default max attacks should be 1")
# =============================================================================
# BLOCKER IMMUNITY CONDITION TESTS
# =============================================================================
func test_blocker_immunity_condition_empty() -> void:
var manager = FieldEffectManager.new()
# Empty condition means unconditional immunity
var result = manager._blocker_matches_immunity_condition(null, {}, null)
assert_true(result, "Empty condition should return true (unconditional)")
func test_blocker_immunity_condition_cost_gte() -> void:
var manager = FieldEffectManager.new()
# Create mock card data
var blocker = _create_mock_card(3, 5000) # cost 3, power 5000
var condition = {
"comparison": "GTE",
"attribute": "cost",
"value": 4
}
var result = manager._blocker_matches_immunity_condition(blocker, condition, null)
assert_false(result, "Cost 3 is not >= 4")
blocker.card_data.cost = 4
result = manager._blocker_matches_immunity_condition(blocker, condition, null)
assert_true(result, "Cost 4 is >= 4")
blocker.free()
func test_blocker_immunity_condition_power_lt_self() -> void:
var manager = FieldEffectManager.new()
var blocker = _create_mock_card(3, 5000)
var attacker = _create_mock_card(4, 8000)
var condition = {
"comparison": "LT",
"attribute": "power",
"compare_to": "SELF_POWER"
}
# Blocker power 5000 < attacker power 8000
var result = manager._blocker_matches_immunity_condition(blocker, condition, attacker)
assert_true(result, "5000 < 8000 should be true")
# Change blocker power to be higher
blocker.current_power = 9000
result = manager._blocker_matches_immunity_condition(blocker, condition, attacker)
assert_false(result, "9000 < 8000 should be false")
blocker.free()
attacker.free()
# =============================================================================
# ABILITY SYSTEM INTEGRATION TESTS
# =============================================================================
func test_ability_system_has_choice_modal_reference() -> void:
# Check that AbilitySystem has the choice_modal variable
var ability_system_script = load("res://scripts/game/abilities/AbilitySystem.gd")
assert_not_null(ability_system_script, "AbilitySystem script should exist")
func test_modes_selected_queues_effects() -> void:
# This tests the logic of _on_modes_selected indirectly
var effect = {
"type": "CHOOSE_MODE",
"modes": [
{"index": 0, "description": "Deal damage", "effects": [{"type": "DAMAGE", "amount": 5000}]},
{"index": 1, "description": "Draw cards", "effects": [{"type": "DRAW", "amount": 2}]}
]
}
var modes = effect.modes
var selected_indices = [1] # Player selected option 2 (draw)
# Verify mode selection logic
var queued_effects = []
for index in selected_indices:
if index >= 0 and index < modes.size():
var mode = modes[index]
for mode_effect in mode.get("effects", []):
queued_effects.append(mode_effect)
assert_eq(queued_effects.size(), 1, "Should queue 1 effect")
assert_eq(queued_effects[0].type, "DRAW", "Queued effect should be DRAW")
assert_eq(queued_effects[0].amount, 2, "Draw amount should be 2")
func test_multi_select_queues_multiple_effects() -> void:
var effect = {
"type": "CHOOSE_MODE",
"select_count": 2,
"modes": [
{"index": 0, "effects": [{"type": "DAMAGE", "amount": 5000}]},
{"index": 1, "effects": [{"type": "DRAW", "amount": 2}]},
{"index": 2, "effects": [{"type": "BREAK"}]}
]
}
var modes = effect.modes
var selected_indices = [0, 2] # Player selected damage and break
var queued_effects = []
for index in selected_indices:
if index >= 0 and index < modes.size():
var mode = modes[index]
for mode_effect in mode.get("effects", []):
queued_effects.append(mode_effect)
assert_eq(queued_effects.size(), 2, "Should queue 2 effects")
assert_eq(queued_effects[0].type, "DAMAGE", "First effect should be DAMAGE")
assert_eq(queued_effects[1].type, "BREAK", "Second effect should be BREAK")
# =============================================================================
# ENHANCED CONDITION TESTS
# =============================================================================
func test_enhanced_condition_parsing() -> void:
var condition = {
"description": "if you have a total of 5 or more card name ifrita and/or card name ifrit in your break zone",
"select_count": 3,
"select_up_to": true
}
# Test that description contains expected keywords
assert_true("break zone" in condition.description, "Should mention break zone")
assert_true("5 or more" in condition.description, "Should mention count requirement")
func test_regex_count_extraction() -> void:
var description = "if you have 5 or more ifrit in your break zone"
var regex = RegEx.new()
regex.compile(r"(\d+) or more")
var match_result = regex.search(description)
assert_not_null(match_result, "Should find count pattern")
assert_eq(match_result.get_string(1), "5", "Should extract '5'")
assert_eq(int(match_result.get_string(1)), 5, "Should convert to int 5")
# =============================================================================
# HELPER FUNCTIONS
# =============================================================================
func _create_mock_card(cost: int, power: int) -> CardInstance:
var card = CardInstance.new()
# Create minimal card data
var data = CardDatabase.CardData.new()
data.cost = cost
data.power = power
data.type = Enums.CardType.FORWARD
card.card_data = data
card.current_power = power
return card