diff --git a/Makefile b/Makefile index 1c551b7..36c979b 100644 --- a/Makefile +++ b/Makefile @@ -13,8 +13,11 @@ deploy-sepolia: generate-event-keys: @./scripts/generateEventKeys.sh +enviroment: + @./scripts/enviroment.sh + # Define tasks that are not real files -.PHONY: deploy-slot deploy-sepolia katana setup torii generate-event-keys +.PHONY: deploy-slot deploy-sepolia katana setup torii generate-event-keys enviroment # Catch-all rule for undefined commands %: diff --git a/manifests/dev/deployment/manifest.json b/manifests/dev/deployment/manifest.json index e7eec3c..539a9ae 100644 --- a/manifests/dev/deployment/manifest.json +++ b/manifests/dev/deployment/manifest.json @@ -1256,8 +1256,8 @@ { "kind": "DojoContract", "address": "0x6a41badee85305fa1aac33488860360c66b60d7f3b204d6e2cd84071dc3c394", - "class_hash": "0x5f74e789806e15032b0e17a3d05f4f70f03b1bba1f6522bdf755235ac6286af", - "original_class_hash": "0x5f74e789806e15032b0e17a3d05f4f70f03b1bba1f6522bdf755235ac6286af", + "class_hash": "0x42e0a9b814ff24e92f45d9dd6e764ec9fc948c70b49242249b2cb7d97d62071", + "original_class_hash": "0x42e0a9b814ff24e92f45d9dd6e764ec9fc948c70b49242249b2cb7d97d62071", "base_class_hash": "0x2427dd10a58850ac9a5ca6ce04b7771b05330fd18f2e481831ad903b969e6b2", "abi": [ { @@ -1392,60 +1392,6 @@ "name": "ActionsImpl", "interface_name": "jokers_of_neon::systems::game_system::IGameSystem" }, - { - "type": "enum", - "name": "jokers_of_neon::models::data::poker_hand::PokerHand", - "variants": [ - { - "name": "None", - "type": "()" - }, - { - "name": "RoyalFlush", - "type": "()" - }, - { - "name": "StraightFlush", - "type": "()" - }, - { - "name": "FiveOfAKind", - "type": "()" - }, - { - "name": "FourOfAKind", - "type": "()" - }, - { - "name": "FullHouse", - "type": "()" - }, - { - "name": "Straight", - "type": "()" - }, - { - "name": "Flush", - "type": "()" - }, - { - "name": "ThreeOfAKind", - "type": "()" - }, - { - "name": "TwoPair", - "type": "()" - }, - { - "name": "OnePair", - "type": "()" - }, - { - "name": "HighCard", - "type": "()" - } - ] - }, { "type": "interface", "name": "jokers_of_neon::systems::game_system::IGameSystem", @@ -1556,26 +1502,14 @@ }, { "type": "function", - "name": "check_hand", + "name": "end_turn", "inputs": [ { "name": "game_id", "type": "core::integer::u32" - }, - { - "name": "cards_index", - "type": "core::array::Array::" - }, - { - "name": "modifiers_index", - "type": "core::array::Array::" - } - ], - "outputs": [ - { - "type": "jokers_of_neon::models::data::poker_hand::PokerHand" } ], + "outputs": [], "state_mutability": "external" }, { @@ -1702,6 +1636,7 @@ "select_modifier_cards", "play", "discard", + "end_turn", "discard_effect_card", "discard_special_card" ], @@ -2034,8 +1969,8 @@ { "kind": "DojoContract", "address": "0x75602558fd679c49be1a6ccb73e3d6d842f0558e1f41c4013ce109d05a5790f", - "class_hash": "0xe1327a50fe39d93f025e0a84e7ce9ccd46c1acd1f575c50acd881e3d4e23b7", - "original_class_hash": "0xe1327a50fe39d93f025e0a84e7ce9ccd46c1acd1f575c50acd881e3d4e23b7", + "class_hash": "0x4d335ac492b01d48fc5431dc87810c59111033fb62eaefd438ab41b6cdb3c06", + "original_class_hash": "0x4d335ac492b01d48fc5431dc87810c59111033fb62eaefd438ab41b6cdb3c06", "base_class_hash": "0x2427dd10a58850ac9a5ca6ce04b7771b05330fd18f2e481831ad903b969e6b2", "abi": [ { @@ -2288,28 +2223,28 @@ "key": true }, { - "name": "idx", - "type": "u32", - "key": true + "name": "tier", + "type": "u8", + "key": false }, { - "name": "blister_pack_id", - "type": "u32", + "name": "level", + "type": "u8", "key": false }, { - "name": "cost", + "name": "health", "type": "u32", "key": false }, { - "name": "purchased", - "type": "bool", + "name": "attack", + "type": "u32", "key": false } ], - "class_hash": "0x5c83fb072bedb835ecfd14432d82495c086e5f2089f390dcf8613da319d7f8e", - "original_class_hash": "0x5c83fb072bedb835ecfd14432d82495c086e5f2089f390dcf8613da319d7f8e", + "class_hash": "0x5a1c6141a6afc7ffaff55d76c948b77992e8cd89ca6c50b21ac617a9889dcd0", + "original_class_hash": "0x5a1c6141a6afc7ffaff55d76c948b77992e8cd89ca6c50b21ac617a9889dcd0", "abi": [ { "type": "impl", @@ -2675,52 +2610,38 @@ }, { "type": "impl", - "name": "blister_pack_itemImpl", - "interface_name": "jokers_of_neon::models::status::shop::shop::Iblister_pack_item" - }, - { - "type": "enum", - "name": "core::bool", - "variants": [ - { - "name": "False", - "type": "()" - }, - { - "name": "True", - "type": "()" - } - ] + "name": "beastImpl", + "interface_name": "jokers_of_neon::models::data::beast::Ibeast" }, { "type": "struct", - "name": "jokers_of_neon::models::status::shop::shop::BlisterPackItem", + "name": "jokers_of_neon::models::data::beast::Beast", "members": [ { "name": "game_id", "type": "core::integer::u32" }, { - "name": "idx", - "type": "core::integer::u32" + "name": "tier", + "type": "core::integer::u8" }, { - "name": "blister_pack_id", - "type": "core::integer::u32" + "name": "level", + "type": "core::integer::u8" }, { - "name": "cost", + "name": "health", "type": "core::integer::u32" }, { - "name": "purchased", - "type": "core::bool" + "name": "attack", + "type": "core::integer::u32" } ] }, { "type": "interface", - "name": "jokers_of_neon::models::status::shop::shop::Iblister_pack_item", + "name": "jokers_of_neon::models::data::beast::Ibeast", "items": [ { "type": "function", @@ -2728,7 +2649,7 @@ "inputs": [ { "name": "model", - "type": "jokers_of_neon::models::status::shop::shop::BlisterPackItem" + "type": "jokers_of_neon::models::data::beast::Beast" } ], "outputs": [], @@ -2738,14 +2659,14 @@ }, { "type": "event", - "name": "jokers_of_neon::models::status::shop::shop::blister_pack_item::Event", + "name": "jokers_of_neon::models::data::beast::beast::Event", "kind": "enum", "variants": [] } ], - "tag": "jokers_of_neon-BlisterPackItem", - "qualified_path": "jokers_of_neon::models::status::shop::shop::blister_pack_item", - "manifest_name": "jokers_of_neon-BlisterPackItem-57733b8c" + "tag": "jokers_of_neon-Beast", + "qualified_path": "jokers_of_neon::models::data::beast::beast", + "manifest_name": "jokers_of_neon-Beast-35a29cda" }, { "kind": "DojoModel", @@ -2756,18 +2677,28 @@ "key": true }, { - "name": "cards_picked", - "type": "bool", + "name": "idx", + "type": "u32", + "key": true + }, + { + "name": "blister_pack_id", + "type": "u32", "key": false }, { - "name": "cards", - "type": "Span", + "name": "cost", + "type": "u32", + "key": false + }, + { + "name": "purchased", + "type": "bool", "key": false } ], - "class_hash": "0x23d3777b1da18fb7a80a94e5960d6a8cfce27155a0f1d96f579c165524d1e70", - "original_class_hash": "0x23d3777b1da18fb7a80a94e5960d6a8cfce27155a0f1d96f579c165524d1e70", + "class_hash": "0x5c83fb072bedb835ecfd14432d82495c086e5f2089f390dcf8613da319d7f8e", + "original_class_hash": "0x5c83fb072bedb835ecfd14432d82495c086e5f2089f390dcf8613da319d7f8e", "abi": [ { "type": "impl", @@ -3133,8 +3064,8 @@ }, { "type": "impl", - "name": "blister_pack_resultImpl", - "interface_name": "jokers_of_neon::models::status::shop::shop::Iblister_pack_result" + "name": "blister_pack_itemImpl", + "interface_name": "jokers_of_neon::models::status::shop::shop::Iblister_pack_item" }, { "type": "enum", @@ -3152,35 +3083,33 @@ }, { "type": "struct", - "name": "core::array::Span::", - "members": [ - { - "name": "snapshot", - "type": "@core::array::Array::" - } - ] - }, - { - "type": "struct", - "name": "jokers_of_neon::models::status::shop::shop::BlisterPackResult", + "name": "jokers_of_neon::models::status::shop::shop::BlisterPackItem", "members": [ { "name": "game_id", "type": "core::integer::u32" }, { - "name": "cards_picked", - "type": "core::bool" + "name": "idx", + "type": "core::integer::u32" }, { - "name": "cards", - "type": "core::array::Span::" + "name": "blister_pack_id", + "type": "core::integer::u32" + }, + { + "name": "cost", + "type": "core::integer::u32" + }, + { + "name": "purchased", + "type": "core::bool" } ] }, { "type": "interface", - "name": "jokers_of_neon::models::status::shop::shop::Iblister_pack_result", + "name": "jokers_of_neon::models::status::shop::shop::Iblister_pack_item", "items": [ { "type": "function", @@ -3188,7 +3117,7 @@ "inputs": [ { "name": "model", - "type": "jokers_of_neon::models::status::shop::shop::BlisterPackResult" + "type": "jokers_of_neon::models::status::shop::shop::BlisterPackItem" } ], "outputs": [], @@ -3198,14 +3127,14 @@ }, { "type": "event", - "name": "jokers_of_neon::models::status::shop::shop::blister_pack_result::Event", + "name": "jokers_of_neon::models::status::shop::shop::blister_pack_item::Event", "kind": "enum", "variants": [] } ], - "tag": "jokers_of_neon-BlisterPackResult", - "qualified_path": "jokers_of_neon::models::status::shop::shop::blister_pack_result", - "manifest_name": "jokers_of_neon-BlisterPackResult-2fcefd2c" + "tag": "jokers_of_neon-BlisterPackItem", + "qualified_path": "jokers_of_neon::models::status::shop::shop::blister_pack_item", + "manifest_name": "jokers_of_neon-BlisterPackItem-57733b8c" }, { "kind": "DojoModel", @@ -3216,23 +3145,18 @@ "key": true }, { - "name": "level", - "type": "u32", - "key": true - }, - { - "name": "idx", - "type": "u32", - "key": true + "name": "cards_picked", + "type": "bool", + "key": false }, { - "name": "blister_pack_id", - "type": "u32", + "name": "cards", + "type": "Span", "key": false } ], - "class_hash": "0x7adba2677583267bfddbb599ea6dfbd67c8e62437e8db6696d61c59c34548a0", - "original_class_hash": "0x7adba2677583267bfddbb599ea6dfbd67c8e62437e8db6696d61c59c34548a0", + "class_hash": "0x23d3777b1da18fb7a80a94e5960d6a8cfce27155a0f1d96f579c165524d1e70", + "original_class_hash": "0x23d3777b1da18fb7a80a94e5960d6a8cfce27155a0f1d96f579c165524d1e70", "abi": [ { "type": "impl", @@ -3598,34 +3522,54 @@ }, { "type": "impl", - "name": "buy_blister_pack_eventImpl", - "interface_name": "jokers_of_neon::models::data::events::Ibuy_blister_pack_event" + "name": "blister_pack_resultImpl", + "interface_name": "jokers_of_neon::models::status::shop::shop::Iblister_pack_result" + }, + { + "type": "enum", + "name": "core::bool", + "variants": [ + { + "name": "False", + "type": "()" + }, + { + "name": "True", + "type": "()" + } + ] }, { "type": "struct", - "name": "jokers_of_neon::models::data::events::BuyBlisterPackEvent", + "name": "core::array::Span::", "members": [ { - "name": "game_id", - "type": "core::integer::u32" - }, + "name": "snapshot", + "type": "@core::array::Array::" + } + ] + }, + { + "type": "struct", + "name": "jokers_of_neon::models::status::shop::shop::BlisterPackResult", + "members": [ { - "name": "level", + "name": "game_id", "type": "core::integer::u32" }, { - "name": "idx", - "type": "core::integer::u32" + "name": "cards_picked", + "type": "core::bool" }, { - "name": "blister_pack_id", - "type": "core::integer::u32" + "name": "cards", + "type": "core::array::Span::" } ] }, { "type": "interface", - "name": "jokers_of_neon::models::data::events::Ibuy_blister_pack_event", + "name": "jokers_of_neon::models::status::shop::shop::Iblister_pack_result", "items": [ { "type": "function", @@ -3633,7 +3577,7 @@ "inputs": [ { "name": "model", - "type": "jokers_of_neon::models::data::events::BuyBlisterPackEvent" + "type": "jokers_of_neon::models::status::shop::shop::BlisterPackResult" } ], "outputs": [], @@ -3643,14 +3587,14 @@ }, { "type": "event", - "name": "jokers_of_neon::models::data::events::buy_blister_pack_event::Event", + "name": "jokers_of_neon::models::status::shop::shop::blister_pack_result::Event", "kind": "enum", "variants": [] } ], - "tag": "jokers_of_neon-BuyBlisterPackEvent", - "qualified_path": "jokers_of_neon::models::data::events::buy_blister_pack_event", - "manifest_name": "jokers_of_neon-BuyBlisterPackEvent-4b403c73" + "tag": "jokers_of_neon-BlisterPackResult", + "qualified_path": "jokers_of_neon::models::status::shop::shop::blister_pack_result", + "manifest_name": "jokers_of_neon-BlisterPackResult-2fcefd2c" }, { "kind": "DojoModel", @@ -3671,23 +3615,13 @@ "key": true }, { - "name": "item_type", - "type": "CardItemType", - "key": true - }, - { - "name": "card_id", + "name": "blister_pack_id", "type": "u32", "key": false - }, - { - "name": "temporary", - "type": "bool", - "key": false } ], - "class_hash": "0x538c2d365f659f08347a9366549a66e77bd8a892e963997ac5f1819221c1f08", - "original_class_hash": "0x538c2d365f659f08347a9366549a66e77bd8a892e963997ac5f1819221c1f08", + "class_hash": "0x7adba2677583267bfddbb599ea6dfbd67c8e62437e8db6696d61c59c34548a0", + "original_class_hash": "0x7adba2677583267bfddbb599ea6dfbd67c8e62437e8db6696d61c59c34548a0", "abi": [ { "type": "impl", @@ -4053,48 +3987,12 @@ }, { "type": "impl", - "name": "buy_card_eventImpl", - "interface_name": "jokers_of_neon::models::data::events::Ibuy_card_event" - }, - { - "type": "enum", - "name": "jokers_of_neon::models::status::shop::shop::CardItemType", - "variants": [ - { - "name": "None", - "type": "()" - }, - { - "name": "Common", - "type": "()" - }, - { - "name": "Modifier", - "type": "()" - }, - { - "name": "Special", - "type": "()" - } - ] - }, - { - "type": "enum", - "name": "core::bool", - "variants": [ - { - "name": "False", - "type": "()" - }, - { - "name": "True", - "type": "()" - } - ] + "name": "buy_blister_pack_eventImpl", + "interface_name": "jokers_of_neon::models::data::events::Ibuy_blister_pack_event" }, { "type": "struct", - "name": "jokers_of_neon::models::data::events::BuyCardEvent", + "name": "jokers_of_neon::models::data::events::BuyBlisterPackEvent", "members": [ { "name": "game_id", @@ -4109,22 +4007,14 @@ "type": "core::integer::u32" }, { - "name": "item_type", - "type": "jokers_of_neon::models::status::shop::shop::CardItemType" - }, - { - "name": "card_id", + "name": "blister_pack_id", "type": "core::integer::u32" - }, - { - "name": "temporary", - "type": "core::bool" } ] }, { "type": "interface", - "name": "jokers_of_neon::models::data::events::Ibuy_card_event", + "name": "jokers_of_neon::models::data::events::Ibuy_blister_pack_event", "items": [ { "type": "function", @@ -4132,7 +4022,7 @@ "inputs": [ { "name": "model", - "type": "jokers_of_neon::models::data::events::BuyCardEvent" + "type": "jokers_of_neon::models::data::events::BuyBlisterPackEvent" } ], "outputs": [], @@ -4142,14 +4032,14 @@ }, { "type": "event", - "name": "jokers_of_neon::models::data::events::buy_card_event::Event", + "name": "jokers_of_neon::models::data::events::buy_blister_pack_event::Event", "kind": "enum", "variants": [] } ], - "tag": "jokers_of_neon-BuyCardEvent", - "qualified_path": "jokers_of_neon::models::data::events::buy_card_event", - "manifest_name": "jokers_of_neon-BuyCardEvent-2f7801e2" + "tag": "jokers_of_neon-BuyBlisterPackEvent", + "qualified_path": "jokers_of_neon::models::data::events::buy_blister_pack_event", + "manifest_name": "jokers_of_neon-BuyBlisterPackEvent-4b403c73" }, { "kind": "DojoModel", @@ -4170,18 +4060,23 @@ "key": true }, { - "name": "poker_hand", - "type": "PokerHand", + "name": "item_type", + "type": "CardItemType", + "key": true + }, + { + "name": "card_id", + "type": "u32", "key": false }, { - "name": "level_hand", - "type": "u8", + "name": "temporary", + "type": "bool", "key": false } ], - "class_hash": "0x2ef016c9f8776fc5004cf0b7ae709d6ad9c5dbda8903d4fea6cdd6d92d9b1e5", - "original_class_hash": "0x2ef016c9f8776fc5004cf0b7ae709d6ad9c5dbda8903d4fea6cdd6d92d9b1e5", + "class_hash": "0x538c2d365f659f08347a9366549a66e77bd8a892e963997ac5f1819221c1f08", + "original_class_hash": "0x538c2d365f659f08347a9366549a66e77bd8a892e963997ac5f1819221c1f08", "abi": [ { "type": "impl", @@ -4547,66 +4442,48 @@ }, { "type": "impl", - "name": "buy_poker_hand_eventImpl", - "interface_name": "jokers_of_neon::models::data::events::Ibuy_poker_hand_event" + "name": "buy_card_eventImpl", + "interface_name": "jokers_of_neon::models::data::events::Ibuy_card_event" }, { "type": "enum", - "name": "jokers_of_neon::models::data::poker_hand::PokerHand", + "name": "jokers_of_neon::models::status::shop::shop::CardItemType", "variants": [ { "name": "None", "type": "()" }, { - "name": "RoyalFlush", - "type": "()" - }, - { - "name": "StraightFlush", - "type": "()" - }, - { - "name": "FiveOfAKind", - "type": "()" - }, - { - "name": "FourOfAKind", - "type": "()" - }, - { - "name": "FullHouse", - "type": "()" - }, - { - "name": "Straight", - "type": "()" - }, - { - "name": "Flush", + "name": "Common", "type": "()" }, { - "name": "ThreeOfAKind", + "name": "Modifier", "type": "()" }, { - "name": "TwoPair", + "name": "Special", "type": "()" - }, + } + ] + }, + { + "type": "enum", + "name": "core::bool", + "variants": [ { - "name": "OnePair", + "name": "False", "type": "()" }, { - "name": "HighCard", + "name": "True", "type": "()" } ] }, { "type": "struct", - "name": "jokers_of_neon::models::data::events::BuyPokerHandEvent", + "name": "jokers_of_neon::models::data::events::BuyCardEvent", "members": [ { "name": "game_id", @@ -4621,18 +4498,22 @@ "type": "core::integer::u32" }, { - "name": "poker_hand", - "type": "jokers_of_neon::models::data::poker_hand::PokerHand" + "name": "item_type", + "type": "jokers_of_neon::models::status::shop::shop::CardItemType" }, { - "name": "level_hand", - "type": "core::integer::u8" + "name": "card_id", + "type": "core::integer::u32" + }, + { + "name": "temporary", + "type": "core::bool" } ] }, { "type": "interface", - "name": "jokers_of_neon::models::data::events::Ibuy_poker_hand_event", + "name": "jokers_of_neon::models::data::events::Ibuy_card_event", "items": [ { "type": "function", @@ -4640,7 +4521,7 @@ "inputs": [ { "name": "model", - "type": "jokers_of_neon::models::data::events::BuyPokerHandEvent" + "type": "jokers_of_neon::models::data::events::BuyCardEvent" } ], "outputs": [], @@ -4650,14 +4531,14 @@ }, { "type": "event", - "name": "jokers_of_neon::models::data::events::buy_poker_hand_event::Event", + "name": "jokers_of_neon::models::data::events::buy_card_event::Event", "kind": "enum", "variants": [] } ], - "tag": "jokers_of_neon-BuyPokerHandEvent", - "qualified_path": "jokers_of_neon::models::data::events::buy_poker_hand_event", - "manifest_name": "jokers_of_neon-BuyPokerHandEvent-271c3d94" + "tag": "jokers_of_neon-BuyCardEvent", + "qualified_path": "jokers_of_neon::models::data::events::buy_card_event", + "manifest_name": "jokers_of_neon-BuyCardEvent-2f7801e2" }, { "kind": "DojoModel", @@ -4673,18 +4554,23 @@ "key": true }, { - "name": "reroll_cost", + "name": "idx", "type": "u32", + "key": true + }, + { + "name": "poker_hand", + "type": "PokerHand", "key": false }, { - "name": "reroll_executed", - "type": "bool", + "name": "level_hand", + "type": "u8", "key": false } ], - "class_hash": "0x48551f3cb2ee84945746d10494f3b28eb0ef23121f09861f07e234a1e257ef9", - "original_class_hash": "0x48551f3cb2ee84945746d10494f3b28eb0ef23121f09861f07e234a1e257ef9", + "class_hash": "0x2ef016c9f8776fc5004cf0b7ae709d6ad9c5dbda8903d4fea6cdd6d92d9b1e5", + "original_class_hash": "0x2ef016c9f8776fc5004cf0b7ae709d6ad9c5dbda8903d4fea6cdd6d92d9b1e5", "abi": [ { "type": "impl", @@ -5050,26 +4936,66 @@ }, { "type": "impl", - "name": "buy_reroll_eventImpl", - "interface_name": "jokers_of_neon::models::data::events::Ibuy_reroll_event" + "name": "buy_poker_hand_eventImpl", + "interface_name": "jokers_of_neon::models::data::events::Ibuy_poker_hand_event" }, { "type": "enum", - "name": "core::bool", + "name": "jokers_of_neon::models::data::poker_hand::PokerHand", "variants": [ { - "name": "False", + "name": "None", "type": "()" }, { - "name": "True", + "name": "RoyalFlush", + "type": "()" + }, + { + "name": "StraightFlush", + "type": "()" + }, + { + "name": "FiveOfAKind", + "type": "()" + }, + { + "name": "FourOfAKind", + "type": "()" + }, + { + "name": "FullHouse", + "type": "()" + }, + { + "name": "Straight", + "type": "()" + }, + { + "name": "Flush", + "type": "()" + }, + { + "name": "ThreeOfAKind", + "type": "()" + }, + { + "name": "TwoPair", + "type": "()" + }, + { + "name": "OnePair", + "type": "()" + }, + { + "name": "HighCard", "type": "()" } ] }, { "type": "struct", - "name": "jokers_of_neon::models::data::events::BuyRerollEvent", + "name": "jokers_of_neon::models::data::events::BuyPokerHandEvent", "members": [ { "name": "game_id", @@ -5080,18 +5006,22 @@ "type": "core::integer::u32" }, { - "name": "reroll_cost", + "name": "idx", "type": "core::integer::u32" }, { - "name": "reroll_executed", - "type": "core::bool" + "name": "poker_hand", + "type": "jokers_of_neon::models::data::poker_hand::PokerHand" + }, + { + "name": "level_hand", + "type": "core::integer::u8" } ] }, { "type": "interface", - "name": "jokers_of_neon::models::data::events::Ibuy_reroll_event", + "name": "jokers_of_neon::models::data::events::Ibuy_poker_hand_event", "items": [ { "type": "function", @@ -5099,7 +5029,7 @@ "inputs": [ { "name": "model", - "type": "jokers_of_neon::models::data::events::BuyRerollEvent" + "type": "jokers_of_neon::models::data::events::BuyPokerHandEvent" } ], "outputs": [], @@ -5109,14 +5039,14 @@ }, { "type": "event", - "name": "jokers_of_neon::models::data::events::buy_reroll_event::Event", + "name": "jokers_of_neon::models::data::events::buy_poker_hand_event::Event", "kind": "enum", "variants": [] } ], - "tag": "jokers_of_neon-BuyRerollEvent", - "qualified_path": "jokers_of_neon::models::data::events::buy_reroll_event", - "manifest_name": "jokers_of_neon-BuyRerollEvent-5231a152" + "tag": "jokers_of_neon-BuyPokerHandEvent", + "qualified_path": "jokers_of_neon::models::data::events::buy_poker_hand_event", + "manifest_name": "jokers_of_neon-BuyPokerHandEvent-271c3d94" }, { "kind": "DojoModel", @@ -5127,38 +5057,23 @@ "key": true }, { - "name": "idx", + "name": "level", "type": "u32", "key": true }, { - "name": "item_type", - "type": "CardItemType", - "key": true - }, - { - "name": "card_id", - "type": "u32", - "key": false - }, - { - "name": "cost", + "name": "reroll_cost", "type": "u32", "key": false }, { - "name": "purchased", - "type": "bool", - "key": false - }, - { - "name": "temporary", + "name": "reroll_executed", "type": "bool", "key": false } ], - "class_hash": "0x70dd3b72cb71dae628531a5f9634320e7800766f1018852b373281ad9f381bd", - "original_class_hash": "0x70dd3b72cb71dae628531a5f9634320e7800766f1018852b373281ad9f381bd", + "class_hash": "0x48551f3cb2ee84945746d10494f3b28eb0ef23121f09861f07e234a1e257ef9", + "original_class_hash": "0x48551f3cb2ee84945746d10494f3b28eb0ef23121f09861f07e234a1e257ef9", "abi": [ { "type": "impl", @@ -5524,30 +5439,8 @@ }, { "type": "impl", - "name": "card_itemImpl", - "interface_name": "jokers_of_neon::models::status::shop::shop::Icard_item" - }, - { - "type": "enum", - "name": "jokers_of_neon::models::status::shop::shop::CardItemType", - "variants": [ - { - "name": "None", - "type": "()" - }, - { - "name": "Common", - "type": "()" - }, - { - "name": "Modifier", - "type": "()" - }, - { - "name": "Special", - "type": "()" - } - ] + "name": "buy_reroll_eventImpl", + "interface_name": "jokers_of_neon::models::data::events::Ibuy_reroll_event" }, { "type": "enum", @@ -5565,41 +5458,29 @@ }, { "type": "struct", - "name": "jokers_of_neon::models::status::shop::shop::CardItem", + "name": "jokers_of_neon::models::data::events::BuyRerollEvent", "members": [ { "name": "game_id", "type": "core::integer::u32" }, { - "name": "idx", - "type": "core::integer::u32" - }, - { - "name": "item_type", - "type": "jokers_of_neon::models::status::shop::shop::CardItemType" - }, - { - "name": "card_id", + "name": "level", "type": "core::integer::u32" }, { - "name": "cost", + "name": "reroll_cost", "type": "core::integer::u32" }, { - "name": "purchased", - "type": "core::bool" - }, - { - "name": "temporary", + "name": "reroll_executed", "type": "core::bool" } ] }, { "type": "interface", - "name": "jokers_of_neon::models::status::shop::shop::Icard_item", + "name": "jokers_of_neon::models::data::events::Ibuy_reroll_event", "items": [ { "type": "function", @@ -5607,7 +5488,7 @@ "inputs": [ { "name": "model", - "type": "jokers_of_neon::models::status::shop::shop::CardItem" + "type": "jokers_of_neon::models::data::events::BuyRerollEvent" } ], "outputs": [], @@ -5617,41 +5498,56 @@ }, { "type": "event", - "name": "jokers_of_neon::models::status::shop::shop::card_item::Event", + "name": "jokers_of_neon::models::data::events::buy_reroll_event::Event", "kind": "enum", "variants": [] } ], - "tag": "jokers_of_neon-CardItem", - "qualified_path": "jokers_of_neon::models::status::shop::shop::card_item", - "manifest_name": "jokers_of_neon-CardItem-1a854299" + "tag": "jokers_of_neon-BuyRerollEvent", + "qualified_path": "jokers_of_neon::models::data::events::buy_reroll_event", + "manifest_name": "jokers_of_neon-BuyRerollEvent-5231a152" }, { "kind": "DojoModel", "members": [ { - "name": "player", - "type": "ContractAddress", + "name": "game_id", + "type": "u32", "key": true }, { - "name": "index", + "name": "idx", "type": "u32", - "key": false + "key": true }, { - "name": "multi", + "name": "item_type", + "type": "CardItemType", + "key": true + }, + { + "name": "card_id", "type": "u32", "key": false }, { - "name": "points", + "name": "cost", "type": "u32", "key": false + }, + { + "name": "purchased", + "type": "bool", + "key": false + }, + { + "name": "temporary", + "type": "bool", + "key": false } ], - "class_hash": "0x25edae79ec31b503664c1ad9da2104d3b0dc4b4611bc3cd7bd613a438ce80b3", - "original_class_hash": "0x25edae79ec31b503664c1ad9da2104d3b0dc4b4611bc3cd7bd613a438ce80b3", + "class_hash": "0x70dd3b72cb71dae628531a5f9634320e7800766f1018852b373281ad9f381bd", + "original_class_hash": "0x70dd3b72cb71dae628531a5f9634320e7800766f1018852b373281ad9f381bd", "abi": [ { "type": "impl", @@ -6017,34 +5913,82 @@ }, { "type": "impl", - "name": "card_score_eventImpl", - "interface_name": "jokers_of_neon::models::data::events::Icard_score_event" + "name": "card_itemImpl", + "interface_name": "jokers_of_neon::models::status::shop::shop::Icard_item" + }, + { + "type": "enum", + "name": "jokers_of_neon::models::status::shop::shop::CardItemType", + "variants": [ + { + "name": "None", + "type": "()" + }, + { + "name": "Common", + "type": "()" + }, + { + "name": "Modifier", + "type": "()" + }, + { + "name": "Special", + "type": "()" + } + ] + }, + { + "type": "enum", + "name": "core::bool", + "variants": [ + { + "name": "False", + "type": "()" + }, + { + "name": "True", + "type": "()" + } + ] }, { "type": "struct", - "name": "jokers_of_neon::models::data::events::CardScoreEvent", + "name": "jokers_of_neon::models::status::shop::shop::CardItem", "members": [ { - "name": "player", - "type": "core::starknet::contract_address::ContractAddress" + "name": "game_id", + "type": "core::integer::u32" }, { - "name": "index", + "name": "idx", "type": "core::integer::u32" }, { - "name": "multi", + "name": "item_type", + "type": "jokers_of_neon::models::status::shop::shop::CardItemType" + }, + { + "name": "card_id", "type": "core::integer::u32" }, { - "name": "points", + "name": "cost", "type": "core::integer::u32" + }, + { + "name": "purchased", + "type": "core::bool" + }, + { + "name": "temporary", + "type": "core::bool" } ] }, { "type": "interface", - "name": "jokers_of_neon::models::data::events::Icard_score_event", + "name": "jokers_of_neon::models::status::shop::shop::Icard_item", "items": [ { "type": "function", @@ -6052,7 +5996,7 @@ "inputs": [ { "name": "model", - "type": "jokers_of_neon::models::data::events::CardScoreEvent" + "type": "jokers_of_neon::models::status::shop::shop::CardItem" } ], "outputs": [], @@ -6062,14 +6006,14 @@ }, { "type": "event", - "name": "jokers_of_neon::models::data::events::card_score_event::Event", + "name": "jokers_of_neon::models::status::shop::shop::card_item::Event", "kind": "enum", "variants": [] } ], - "tag": "jokers_of_neon-CardScoreEvent", - "qualified_path": "jokers_of_neon::models::data::events::card_score_event", - "manifest_name": "jokers_of_neon-CardScoreEvent-5e073648" + "tag": "jokers_of_neon-CardItem", + "qualified_path": "jokers_of_neon::models::status::shop::shop::card_item", + "manifest_name": "jokers_of_neon-CardItem-1a854299" }, { "kind": "DojoModel", @@ -6080,13 +6024,23 @@ "key": true }, { - "name": "game_id", + "name": "index", + "type": "u32", + "key": false + }, + { + "name": "multi", + "type": "u32", + "key": false + }, + { + "name": "points", "type": "u32", "key": false } ], - "class_hash": "0x101deece771f5cbf115831a78e13c3e68fcf8a6220ea0f86b9177799a610dd1", - "original_class_hash": "0x101deece771f5cbf115831a78e13c3e68fcf8a6220ea0f86b9177799a610dd1", + "class_hash": "0x25edae79ec31b503664c1ad9da2104d3b0dc4b4611bc3cd7bd613a438ce80b3", + "original_class_hash": "0x25edae79ec31b503664c1ad9da2104d3b0dc4b4611bc3cd7bd613a438ce80b3", "abi": [ { "type": "impl", @@ -6452,26 +6406,34 @@ }, { "type": "impl", - "name": "create_game_eventImpl", - "interface_name": "jokers_of_neon::models::data::events::Icreate_game_event" + "name": "card_score_eventImpl", + "interface_name": "jokers_of_neon::models::data::events::Icard_score_event" }, { "type": "struct", - "name": "jokers_of_neon::models::data::events::CreateGameEvent", + "name": "jokers_of_neon::models::data::events::CardScoreEvent", "members": [ { "name": "player", "type": "core::starknet::contract_address::ContractAddress" }, { - "name": "game_id", + "name": "index", + "type": "core::integer::u32" + }, + { + "name": "multi", + "type": "core::integer::u32" + }, + { + "name": "points", "type": "core::integer::u32" } ] }, { "type": "interface", - "name": "jokers_of_neon::models::data::events::Icreate_game_event", + "name": "jokers_of_neon::models::data::events::Icard_score_event", "items": [ { "type": "function", @@ -6479,7 +6441,7 @@ "inputs": [ { "name": "model", - "type": "jokers_of_neon::models::data::events::CreateGameEvent" + "type": "jokers_of_neon::models::data::events::CardScoreEvent" } ], "outputs": [], @@ -6489,36 +6451,31 @@ }, { "type": "event", - "name": "jokers_of_neon::models::data::events::create_game_event::Event", + "name": "jokers_of_neon::models::data::events::card_score_event::Event", "kind": "enum", "variants": [] } ], - "tag": "jokers_of_neon-CreateGameEvent", - "qualified_path": "jokers_of_neon::models::data::events::create_game_event", - "manifest_name": "jokers_of_neon-CreateGameEvent-17f86ee2" + "tag": "jokers_of_neon-CardScoreEvent", + "qualified_path": "jokers_of_neon::models::data::events::card_score_event", + "manifest_name": "jokers_of_neon-CardScoreEvent-5e073648" }, { "kind": "DojoModel", "members": [ { - "name": "game_id", - "type": "u32", - "key": true - }, - { - "name": "idx", - "type": "u32", + "name": "player", + "type": "ContractAddress", "key": true }, { - "name": "card_id", + "name": "game_id", "type": "u32", "key": false } ], - "class_hash": "0x6214acf8fa0a427d8d2712413c586866a023b5d256e7c5acd3ccfaade2db633", - "original_class_hash": "0x6214acf8fa0a427d8d2712413c586866a023b5d256e7c5acd3ccfaade2db633", + "class_hash": "0x101deece771f5cbf115831a78e13c3e68fcf8a6220ea0f86b9177799a610dd1", + "original_class_hash": "0x101deece771f5cbf115831a78e13c3e68fcf8a6220ea0f86b9177799a610dd1", "abi": [ { "type": "impl", @@ -6884,30 +6841,26 @@ }, { "type": "impl", - "name": "current_hand_cardImpl", - "interface_name": "jokers_of_neon::models::status::round::current_hand_card::Icurrent_hand_card" + "name": "create_game_eventImpl", + "interface_name": "jokers_of_neon::models::data::events::Icreate_game_event" }, { "type": "struct", - "name": "jokers_of_neon::models::status::round::current_hand_card::CurrentHandCard", + "name": "jokers_of_neon::models::data::events::CreateGameEvent", "members": [ { - "name": "game_id", - "type": "core::integer::u32" - }, - { - "name": "idx", - "type": "core::integer::u32" + "name": "player", + "type": "core::starknet::contract_address::ContractAddress" }, { - "name": "card_id", + "name": "game_id", "type": "core::integer::u32" } ] }, { "type": "interface", - "name": "jokers_of_neon::models::status::round::current_hand_card::Icurrent_hand_card", + "name": "jokers_of_neon::models::data::events::Icreate_game_event", "items": [ { "type": "function", @@ -6915,7 +6868,7 @@ "inputs": [ { "name": "model", - "type": "jokers_of_neon::models::status::round::current_hand_card::CurrentHandCard" + "type": "jokers_of_neon::models::data::events::CreateGameEvent" } ], "outputs": [], @@ -6925,14 +6878,14 @@ }, { "type": "event", - "name": "jokers_of_neon::models::status::round::current_hand_card::current_hand_card::Event", + "name": "jokers_of_neon::models::data::events::create_game_event::Event", "kind": "enum", "variants": [] } ], - "tag": "jokers_of_neon-CurrentHandCard", - "qualified_path": "jokers_of_neon::models::status::round::current_hand_card::current_hand_card", - "manifest_name": "jokers_of_neon-CurrentHandCard-29753f22" + "tag": "jokers_of_neon-CreateGameEvent", + "qualified_path": "jokers_of_neon::models::data::events::create_game_event", + "manifest_name": "jokers_of_neon-CreateGameEvent-17f86ee2" }, { "kind": "DojoModel", @@ -6948,23 +6901,13 @@ "key": true }, { - "name": "effect_card_id", - "type": "u32", - "key": false - }, - { - "name": "is_temporary", - "type": "bool", - "key": false - }, - { - "name": "remaining", + "name": "card_id", "type": "u32", "key": false } ], - "class_hash": "0x3888b285bfb37fed4b852e2056f5fc8cce5d379014cbcf81ea4496a9269c7fd", - "original_class_hash": "0x3888b285bfb37fed4b852e2056f5fc8cce5d379014cbcf81ea4496a9269c7fd", + "class_hash": "0x6214acf8fa0a427d8d2712413c586866a023b5d256e7c5acd3ccfaade2db633", + "original_class_hash": "0x6214acf8fa0a427d8d2712413c586866a023b5d256e7c5acd3ccfaade2db633", "abi": [ { "type": "impl", @@ -7330,26 +7273,12 @@ }, { "type": "impl", - "name": "current_special_cardsImpl", - "interface_name": "jokers_of_neon::models::status::game::game::Icurrent_special_cards" - }, - { - "type": "enum", - "name": "core::bool", - "variants": [ - { - "name": "False", - "type": "()" - }, - { - "name": "True", - "type": "()" - } - ] + "name": "current_hand_cardImpl", + "interface_name": "jokers_of_neon::models::status::round::current_hand_card::Icurrent_hand_card" }, { "type": "struct", - "name": "jokers_of_neon::models::status::game::game::CurrentSpecialCards", + "name": "jokers_of_neon::models::status::round::current_hand_card::CurrentHandCard", "members": [ { "name": "game_id", @@ -7360,22 +7289,14 @@ "type": "core::integer::u32" }, { - "name": "effect_card_id", - "type": "core::integer::u32" - }, - { - "name": "is_temporary", - "type": "core::bool" - }, - { - "name": "remaining", + "name": "card_id", "type": "core::integer::u32" } ] }, { "type": "interface", - "name": "jokers_of_neon::models::status::game::game::Icurrent_special_cards", + "name": "jokers_of_neon::models::status::round::current_hand_card::Icurrent_hand_card", "items": [ { "type": "function", @@ -7383,7 +7304,7 @@ "inputs": [ { "name": "model", - "type": "jokers_of_neon::models::status::game::game::CurrentSpecialCards" + "type": "jokers_of_neon::models::status::round::current_hand_card::CurrentHandCard" } ], "outputs": [], @@ -7393,14 +7314,14 @@ }, { "type": "event", - "name": "jokers_of_neon::models::status::game::game::current_special_cards::Event", + "name": "jokers_of_neon::models::status::round::current_hand_card::current_hand_card::Event", "kind": "enum", "variants": [] } ], - "tag": "jokers_of_neon-CurrentSpecialCards", - "qualified_path": "jokers_of_neon::models::status::game::game::current_special_cards", - "manifest_name": "jokers_of_neon-CurrentSpecialCards-11ae0174" + "tag": "jokers_of_neon-CurrentHandCard", + "qualified_path": "jokers_of_neon::models::status::round::current_hand_card::current_hand_card", + "manifest_name": "jokers_of_neon-CurrentHandCard-29753f22" }, { "kind": "DojoModel", @@ -7411,18 +7332,28 @@ "key": true }, { - "name": "index", + "name": "idx", "type": "u32", "key": true }, { - "name": "card_id", + "name": "effect_card_id", + "type": "u32", + "key": false + }, + { + "name": "is_temporary", + "type": "bool", + "key": false + }, + { + "name": "remaining", "type": "u32", "key": false } ], - "class_hash": "0x5e1f44f133a6951fe33a0c0084ce584ee4fd4e5498a3208e6f561096f751ea8", - "original_class_hash": "0x5e1f44f133a6951fe33a0c0084ce584ee4fd4e5498a3208e6f561096f751ea8", + "class_hash": "0x3888b285bfb37fed4b852e2056f5fc8cce5d379014cbcf81ea4496a9269c7fd", + "original_class_hash": "0x3888b285bfb37fed4b852e2056f5fc8cce5d379014cbcf81ea4496a9269c7fd", "abi": [ { "type": "impl", @@ -7788,30 +7719,52 @@ }, { "type": "impl", - "name": "deck_cardImpl", - "interface_name": "jokers_of_neon::models::data::game_deck::Ideck_card" + "name": "current_special_cardsImpl", + "interface_name": "jokers_of_neon::models::status::game::game::Icurrent_special_cards" + }, + { + "type": "enum", + "name": "core::bool", + "variants": [ + { + "name": "False", + "type": "()" + }, + { + "name": "True", + "type": "()" + } + ] }, { "type": "struct", - "name": "jokers_of_neon::models::data::game_deck::DeckCard", + "name": "jokers_of_neon::models::status::game::game::CurrentSpecialCards", "members": [ { "name": "game_id", "type": "core::integer::u32" }, { - "name": "index", + "name": "idx", "type": "core::integer::u32" }, { - "name": "card_id", + "name": "effect_card_id", + "type": "core::integer::u32" + }, + { + "name": "is_temporary", + "type": "core::bool" + }, + { + "name": "remaining", "type": "core::integer::u32" } ] }, { "type": "interface", - "name": "jokers_of_neon::models::data::game_deck::Ideck_card", + "name": "jokers_of_neon::models::status::game::game::Icurrent_special_cards", "items": [ { "type": "function", @@ -7819,7 +7772,7 @@ "inputs": [ { "name": "model", - "type": "jokers_of_neon::models::data::game_deck::DeckCard" + "type": "jokers_of_neon::models::status::game::game::CurrentSpecialCards" } ], "outputs": [], @@ -7829,76 +7782,36 @@ }, { "type": "event", - "name": "jokers_of_neon::models::data::game_deck::deck_card::Event", + "name": "jokers_of_neon::models::status::game::game::current_special_cards::Event", "kind": "enum", "variants": [] } ], - "tag": "jokers_of_neon-DeckCard", - "qualified_path": "jokers_of_neon::models::data::game_deck::deck_card", - "manifest_name": "jokers_of_neon-DeckCard-4e65fb96" + "tag": "jokers_of_neon-CurrentSpecialCards", + "qualified_path": "jokers_of_neon::models::status::game::game::current_special_cards", + "manifest_name": "jokers_of_neon-CurrentSpecialCards-11ae0174" }, { "kind": "DojoModel", "members": [ - { - "name": "player", - "type": "ContractAddress", - "key": true - }, { "name": "game_id", "type": "u32", - "key": false - }, - { - "name": "round_defeat", - "type": "u32", - "key": false - }, - { - "name": "level_bonus", - "type": "u32", - "key": false - }, - { - "name": "hands_left", - "type": "u32", - "key": false - }, - { - "name": "hands_left_cash", - "type": "u32", - "key": false - }, - { - "name": "discard_left", - "type": "u32", - "key": false - }, - { - "name": "discard_left_cash", - "type": "u32", - "key": false - }, - { - "name": "rage_card_defeated", - "type": "u32", - "key": false + "key": true }, { - "name": "rage_card_defeated_cash", + "name": "index", "type": "u32", - "key": false + "key": true }, { - "name": "total", + "name": "card_id", "type": "u32", "key": false } ], - "class_hash": "0x5a8e5e18e43d39e182e079e0bcc67056e5a2a4bae237350d15e51fee36a5355", - "original_class_hash": "0x5a8e5e18e43d39e182e079e0bcc67056e5a2a4bae237350d15e51fee36a5355", + "class_hash": "0x5e1f44f133a6951fe33a0c0084ce584ee4fd4e5498a3208e6f561096f751ea8", + "original_class_hash": "0x5e1f44f133a6951fe33a0c0084ce584ee4fd4e5498a3208e6f561096f751ea8", "abi": [ { "type": "impl", @@ -8264,62 +8177,30 @@ }, { "type": "impl", - "name": "detail_earned_eventImpl", - "interface_name": "jokers_of_neon::models::data::events::Idetail_earned_event" + "name": "deck_cardImpl", + "interface_name": "jokers_of_neon::models::data::game_deck::Ideck_card" }, { "type": "struct", - "name": "jokers_of_neon::models::data::events::DetailEarnedEvent", + "name": "jokers_of_neon::models::data::game_deck::DeckCard", "members": [ - { - "name": "player", - "type": "core::starknet::contract_address::ContractAddress" - }, { "name": "game_id", "type": "core::integer::u32" }, { - "name": "round_defeat", - "type": "core::integer::u32" - }, - { - "name": "level_bonus", - "type": "core::integer::u32" - }, - { - "name": "hands_left", - "type": "core::integer::u32" - }, - { - "name": "hands_left_cash", - "type": "core::integer::u32" - }, - { - "name": "discard_left", - "type": "core::integer::u32" - }, - { - "name": "discard_left_cash", - "type": "core::integer::u32" - }, - { - "name": "rage_card_defeated", - "type": "core::integer::u32" - }, - { - "name": "rage_card_defeated_cash", + "name": "index", "type": "core::integer::u32" }, { - "name": "total", + "name": "card_id", "type": "core::integer::u32" } ] }, { "type": "interface", - "name": "jokers_of_neon::models::data::events::Idetail_earned_event", + "name": "jokers_of_neon::models::data::game_deck::Ideck_card", "items": [ { "type": "function", @@ -8327,7 +8208,7 @@ "inputs": [ { "name": "model", - "type": "jokers_of_neon::models::data::events::DetailEarnedEvent" + "type": "jokers_of_neon::models::data::game_deck::DeckCard" } ], "outputs": [], @@ -8337,96 +8218,76 @@ }, { "type": "event", - "name": "jokers_of_neon::models::data::events::detail_earned_event::Event", + "name": "jokers_of_neon::models::data::game_deck::deck_card::Event", "kind": "enum", "variants": [] } ], - "tag": "jokers_of_neon-DetailEarnedEvent", - "qualified_path": "jokers_of_neon::models::data::events::detail_earned_event", - "manifest_name": "jokers_of_neon-DetailEarnedEvent-40f670e5" + "tag": "jokers_of_neon-DeckCard", + "qualified_path": "jokers_of_neon::models::data::game_deck::deck_card", + "manifest_name": "jokers_of_neon-DeckCard-4e65fb96" }, { "kind": "DojoModel", "members": [ { - "name": "id", - "type": "u32", + "name": "player", + "type": "ContractAddress", "key": true }, { - "name": "owner", - "type": "ContractAddress", - "key": false - }, - { - "name": "player_name", - "type": "felt252", - "key": false - }, - { - "name": "max_hands", - "type": "u8", - "key": false - }, - { - "name": "max_discard", - "type": "u8", - "key": false - }, - { - "name": "max_jokers", - "type": "u8", + "name": "game_id", + "type": "u32", "key": false }, { - "name": "round", - "type": "u8", + "name": "round_defeat", + "type": "u32", "key": false }, { - "name": "player_score", + "name": "level_bonus", "type": "u32", "key": false }, { - "name": "level", + "name": "hands_left", "type": "u32", "key": false }, { - "name": "len_hand", + "name": "hands_left_cash", "type": "u32", "key": false }, { - "name": "len_max_current_special_cards", + "name": "discard_left", "type": "u32", "key": false }, { - "name": "len_current_special_cards", + "name": "discard_left_cash", "type": "u32", "key": false }, { - "name": "current_jokers", - "type": "u8", + "name": "rage_card_defeated", + "type": "u32", "key": false }, { - "name": "state", - "type": "GameState", + "name": "rage_card_defeated_cash", + "type": "u32", "key": false }, { - "name": "cash", + "name": "total", "type": "u32", "key": false } ], - "class_hash": "0xd231a89d484f9ce343542808702a69ff45ecd316470ea746e8de8e889d6f8", - "original_class_hash": "0xd231a89d484f9ce343542808702a69ff45ecd316470ea746e8de8e889d6f8", + "class_hash": "0x5a8e5e18e43d39e182e079e0bcc67056e5a2a4bae237350d15e51fee36a5355", + "original_class_hash": "0x5a8e5e18e43d39e182e079e0bcc67056e5a2a4bae237350d15e51fee36a5355", "abi": [ { "type": "impl", @@ -8792,112 +8653,1094 @@ }, { "type": "impl", - "name": "gameImpl", - "interface_name": "jokers_of_neon::models::status::game::game::Igame" + "name": "detail_earned_eventImpl", + "interface_name": "jokers_of_neon::models::data::events::Idetail_earned_event" }, { - "type": "enum", - "name": "jokers_of_neon::models::status::game::game::GameState", - "variants": [ + "type": "struct", + "name": "jokers_of_neon::models::data::events::DetailEarnedEvent", + "members": [ { - "name": "SELECT_DECK", - "type": "()" + "name": "player", + "type": "core::starknet::contract_address::ContractAddress" }, { - "name": "SELECT_SPECIAL_CARDS", - "type": "()" + "name": "game_id", + "type": "core::integer::u32" }, { - "name": "SELECT_MODIFIER_CARDS", - "type": "()" + "name": "round_defeat", + "type": "core::integer::u32" }, { - "name": "AT_SHOP", - "type": "()" + "name": "level_bonus", + "type": "core::integer::u32" }, { - "name": "IN_GAME", - "type": "()" + "name": "hands_left", + "type": "core::integer::u32" }, { - "name": "FINISHED", - "type": "()" + "name": "hands_left_cash", + "type": "core::integer::u32" }, { - "name": "OPEN_BLISTER_PACK", - "type": "()" - } - ] - }, - { - "type": "struct", - "name": "jokers_of_neon::models::status::game::game::Game", - "members": [ - { - "name": "id", + "name": "discard_left", "type": "core::integer::u32" }, { - "name": "owner", - "type": "core::starknet::contract_address::ContractAddress" + "name": "discard_left_cash", + "type": "core::integer::u32" }, { - "name": "player_name", - "type": "core::felt252" + "name": "rage_card_defeated", + "type": "core::integer::u32" }, { - "name": "max_hands", - "type": "core::integer::u8" + "name": "rage_card_defeated_cash", + "type": "core::integer::u32" }, { - "name": "max_discard", - "type": "core::integer::u8" - }, + "name": "total", + "type": "core::integer::u32" + } + ] + }, + { + "type": "interface", + "name": "jokers_of_neon::models::data::events::Idetail_earned_event", + "items": [ { - "name": "max_jokers", - "type": "core::integer::u8" - }, + "type": "function", + "name": "ensure_abi", + "inputs": [ + { + "name": "model", + "type": "jokers_of_neon::models::data::events::DetailEarnedEvent" + } + ], + "outputs": [], + "state_mutability": "view" + } + ] + }, + { + "type": "event", + "name": "jokers_of_neon::models::data::events::detail_earned_event::Event", + "kind": "enum", + "variants": [] + } + ], + "tag": "jokers_of_neon-DetailEarnedEvent", + "qualified_path": "jokers_of_neon::models::data::events::detail_earned_event", + "manifest_name": "jokers_of_neon-DetailEarnedEvent-40f670e5" + }, + { + "kind": "DojoModel", + "members": [ + { + "name": "id", + "type": "u32", + "key": true + }, + { + "name": "owner", + "type": "ContractAddress", + "key": false + }, + { + "name": "player_name", + "type": "felt252", + "key": false + }, + { + "name": "max_hands", + "type": "u8", + "key": false + }, + { + "name": "max_discard", + "type": "u8", + "key": false + }, + { + "name": "max_jokers", + "type": "u8", + "key": false + }, + { + "name": "player_score", + "type": "u32", + "key": false + }, + { + "name": "level", + "type": "u32", + "key": false + }, + { + "name": "len_hand", + "type": "u32", + "key": false + }, + { + "name": "len_max_current_special_cards", + "type": "u32", + "key": false + }, + { + "name": "len_current_special_cards", + "type": "u32", + "key": false + }, + { + "name": "current_jokers", + "type": "u8", + "key": false + }, + { + "name": "state", + "type": "GameState", + "key": false + }, + { + "name": "substate", + "type": "GameSubState", + "key": false + }, + { + "name": "cash", + "type": "u32", + "key": false + } + ], + "class_hash": "0x55a1aee842d76a253cb36c4989bc5ef74d3cd7d2d8dd4c464c64295986afa10", + "original_class_hash": "0x55a1aee842d76a253cb36c4989bc5ef74d3cd7d2d8dd4c464c64295986afa10", + "abi": [ + { + "type": "impl", + "name": "DojoModelImpl", + "interface_name": "dojo::model::model::IModel" + }, + { + "type": "struct", + "name": "core::byte_array::ByteArray", + "members": [ { - "name": "round", - "type": "core::integer::u8" + "name": "data", + "type": "core::array::Array::" }, { - "name": "player_score", - "type": "core::integer::u32" + "name": "pending_word", + "type": "core::felt252" }, { - "name": "level", + "name": "pending_word_len", "type": "core::integer::u32" - }, + } + ] + }, + { + "type": "enum", + "name": "core::option::Option::", + "variants": [ { - "name": "len_hand", + "name": "Some", "type": "core::integer::u32" }, { - "name": "len_max_current_special_cards", + "name": "None", + "type": "()" + } + ] + }, + { + "type": "struct", + "name": "core::array::Span::", + "members": [ + { + "name": "snapshot", + "type": "@core::array::Array::" + } + ] + }, + { + "type": "struct", + "name": "dojo::model::layout::FieldLayout", + "members": [ + { + "name": "selector", + "type": "core::felt252" + }, + { + "name": "layout", + "type": "dojo::model::layout::Layout" + } + ] + }, + { + "type": "struct", + "name": "core::array::Span::", + "members": [ + { + "name": "snapshot", + "type": "@core::array::Array::" + } + ] + }, + { + "type": "struct", + "name": "core::array::Span::", + "members": [ + { + "name": "snapshot", + "type": "@core::array::Array::" + } + ] + }, + { + "type": "enum", + "name": "dojo::model::layout::Layout", + "variants": [ + { + "name": "Fixed", + "type": "core::array::Span::" + }, + { + "name": "Struct", + "type": "core::array::Span::" + }, + { + "name": "Tuple", + "type": "core::array::Span::" + }, + { + "name": "Array", + "type": "core::array::Span::" + }, + { + "name": "ByteArray", + "type": "()" + }, + { + "name": "Enum", + "type": "core::array::Span::" + } + ] + }, + { + "type": "struct", + "name": "core::array::Span::", + "members": [ + { + "name": "snapshot", + "type": "@core::array::Array::" + } + ] + }, + { + "type": "struct", + "name": "dojo::model::introspect::Member", + "members": [ + { + "name": "name", + "type": "core::felt252" + }, + { + "name": "attrs", + "type": "core::array::Span::" + }, + { + "name": "ty", + "type": "dojo::model::introspect::Ty" + } + ] + }, + { + "type": "struct", + "name": "core::array::Span::", + "members": [ + { + "name": "snapshot", + "type": "@core::array::Array::" + } + ] + }, + { + "type": "struct", + "name": "dojo::model::introspect::Struct", + "members": [ + { + "name": "name", + "type": "core::felt252" + }, + { + "name": "attrs", + "type": "core::array::Span::" + }, + { + "name": "children", + "type": "core::array::Span::" + } + ] + }, + { + "type": "struct", + "name": "core::array::Span::<(core::felt252, dojo::model::introspect::Ty)>", + "members": [ + { + "name": "snapshot", + "type": "@core::array::Array::<(core::felt252, dojo::model::introspect::Ty)>" + } + ] + }, + { + "type": "struct", + "name": "dojo::model::introspect::Enum", + "members": [ + { + "name": "name", + "type": "core::felt252" + }, + { + "name": "attrs", + "type": "core::array::Span::" + }, + { + "name": "children", + "type": "core::array::Span::<(core::felt252, dojo::model::introspect::Ty)>" + } + ] + }, + { + "type": "struct", + "name": "core::array::Span::", + "members": [ + { + "name": "snapshot", + "type": "@core::array::Array::" + } + ] + }, + { + "type": "enum", + "name": "dojo::model::introspect::Ty", + "variants": [ + { + "name": "Primitive", + "type": "core::felt252" + }, + { + "name": "Struct", + "type": "dojo::model::introspect::Struct" + }, + { + "name": "Enum", + "type": "dojo::model::introspect::Enum" + }, + { + "name": "Tuple", + "type": "core::array::Span::" + }, + { + "name": "Array", + "type": "core::array::Span::" + }, + { + "name": "ByteArray", + "type": "()" + } + ] + }, + { + "type": "interface", + "name": "dojo::model::model::IModel", + "items": [ + { + "type": "function", + "name": "name", + "inputs": [], + "outputs": [ + { + "type": "core::byte_array::ByteArray" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "namespace", + "inputs": [], + "outputs": [ + { + "type": "core::byte_array::ByteArray" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "tag", + "inputs": [], + "outputs": [ + { + "type": "core::byte_array::ByteArray" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "version", + "inputs": [], + "outputs": [ + { + "type": "core::integer::u8" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "selector", + "inputs": [], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "name_hash", + "inputs": [], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "namespace_hash", + "inputs": [], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "unpacked_size", + "inputs": [], + "outputs": [ + { + "type": "core::option::Option::" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "packed_size", + "inputs": [], + "outputs": [ + { + "type": "core::option::Option::" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "layout", + "inputs": [], + "outputs": [ + { + "type": "dojo::model::layout::Layout" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "schema", + "inputs": [], + "outputs": [ + { + "type": "dojo::model::introspect::Ty" + } + ], + "state_mutability": "view" + } + ] + }, + { + "type": "impl", + "name": "gameImpl", + "interface_name": "jokers_of_neon::models::status::game::game::Igame" + }, + { + "type": "enum", + "name": "jokers_of_neon::models::status::game::game::GameState", + "variants": [ + { + "name": "SELECT_DECK", + "type": "()" + }, + { + "name": "SELECT_SPECIAL_CARDS", + "type": "()" + }, + { + "name": "SELECT_MODIFIER_CARDS", + "type": "()" + }, + { + "name": "AT_SHOP", + "type": "()" + }, + { + "name": "IN_GAME", + "type": "()" + }, + { + "name": "FINISHED", + "type": "()" + }, + { + "name": "OPEN_BLISTER_PACK", + "type": "()" + } + ] + }, + { + "type": "enum", + "name": "jokers_of_neon::models::status::game::game::GameSubState", + "variants": [ + { + "name": "NONE", + "type": "()" + }, + { + "name": "OBSTACLE", + "type": "()" + }, + { + "name": "BEAST", + "type": "()" + } + ] + }, + { + "type": "struct", + "name": "jokers_of_neon::models::status::game::game::Game", + "members": [ + { + "name": "id", + "type": "core::integer::u32" + }, + { + "name": "owner", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "player_name", + "type": "core::felt252" + }, + { + "name": "max_hands", + "type": "core::integer::u8" + }, + { + "name": "max_discard", + "type": "core::integer::u8" + }, + { + "name": "max_jokers", + "type": "core::integer::u8" + }, + { + "name": "player_score", + "type": "core::integer::u32" + }, + { + "name": "level", + "type": "core::integer::u32" + }, + { + "name": "len_hand", + "type": "core::integer::u32" + }, + { + "name": "len_max_current_special_cards", + "type": "core::integer::u32" + }, + { + "name": "len_current_special_cards", + "type": "core::integer::u32" + }, + { + "name": "current_jokers", + "type": "core::integer::u8" + }, + { + "name": "state", + "type": "jokers_of_neon::models::status::game::game::GameState" + }, + { + "name": "substate", + "type": "jokers_of_neon::models::status::game::game::GameSubState" + }, + { + "name": "cash", + "type": "core::integer::u32" + } + ] + }, + { + "type": "interface", + "name": "jokers_of_neon::models::status::game::game::Igame", + "items": [ + { + "type": "function", + "name": "ensure_abi", + "inputs": [ + { + "name": "model", + "type": "jokers_of_neon::models::status::game::game::Game" + } + ], + "outputs": [], + "state_mutability": "view" + } + ] + }, + { + "type": "event", + "name": "jokers_of_neon::models::status::game::game::game::Event", + "kind": "enum", + "variants": [] + } + ], + "tag": "jokers_of_neon-Game", + "qualified_path": "jokers_of_neon::models::status::game::game::game", + "manifest_name": "jokers_of_neon-Game-162de85b" + }, + { + "kind": "DojoModel", + "members": [ + { + "name": "game_id", + "type": "u32", + "key": true + }, + { + "name": "len", + "type": "u32", + "key": false + }, + { + "name": "round_len", + "type": "u32", + "key": false + } + ], + "class_hash": "0x165c5bd99b1100a2e1a2faaf9a2443d6ca12bc310e2ec39d1ac64eac3555f31", + "original_class_hash": "0x165c5bd99b1100a2e1a2faaf9a2443d6ca12bc310e2ec39d1ac64eac3555f31", + "abi": [ + { + "type": "impl", + "name": "DojoModelImpl", + "interface_name": "dojo::model::model::IModel" + }, + { + "type": "struct", + "name": "core::byte_array::ByteArray", + "members": [ + { + "name": "data", + "type": "core::array::Array::" + }, + { + "name": "pending_word", + "type": "core::felt252" + }, + { + "name": "pending_word_len", + "type": "core::integer::u32" + } + ] + }, + { + "type": "enum", + "name": "core::option::Option::", + "variants": [ + { + "name": "Some", + "type": "core::integer::u32" + }, + { + "name": "None", + "type": "()" + } + ] + }, + { + "type": "struct", + "name": "core::array::Span::", + "members": [ + { + "name": "snapshot", + "type": "@core::array::Array::" + } + ] + }, + { + "type": "struct", + "name": "dojo::model::layout::FieldLayout", + "members": [ + { + "name": "selector", + "type": "core::felt252" + }, + { + "name": "layout", + "type": "dojo::model::layout::Layout" + } + ] + }, + { + "type": "struct", + "name": "core::array::Span::", + "members": [ + { + "name": "snapshot", + "type": "@core::array::Array::" + } + ] + }, + { + "type": "struct", + "name": "core::array::Span::", + "members": [ + { + "name": "snapshot", + "type": "@core::array::Array::" + } + ] + }, + { + "type": "enum", + "name": "dojo::model::layout::Layout", + "variants": [ + { + "name": "Fixed", + "type": "core::array::Span::" + }, + { + "name": "Struct", + "type": "core::array::Span::" + }, + { + "name": "Tuple", + "type": "core::array::Span::" + }, + { + "name": "Array", + "type": "core::array::Span::" + }, + { + "name": "ByteArray", + "type": "()" + }, + { + "name": "Enum", + "type": "core::array::Span::" + } + ] + }, + { + "type": "struct", + "name": "core::array::Span::", + "members": [ + { + "name": "snapshot", + "type": "@core::array::Array::" + } + ] + }, + { + "type": "struct", + "name": "dojo::model::introspect::Member", + "members": [ + { + "name": "name", + "type": "core::felt252" + }, + { + "name": "attrs", + "type": "core::array::Span::" + }, + { + "name": "ty", + "type": "dojo::model::introspect::Ty" + } + ] + }, + { + "type": "struct", + "name": "core::array::Span::", + "members": [ + { + "name": "snapshot", + "type": "@core::array::Array::" + } + ] + }, + { + "type": "struct", + "name": "dojo::model::introspect::Struct", + "members": [ + { + "name": "name", + "type": "core::felt252" + }, + { + "name": "attrs", + "type": "core::array::Span::" + }, + { + "name": "children", + "type": "core::array::Span::" + } + ] + }, + { + "type": "struct", + "name": "core::array::Span::<(core::felt252, dojo::model::introspect::Ty)>", + "members": [ + { + "name": "snapshot", + "type": "@core::array::Array::<(core::felt252, dojo::model::introspect::Ty)>" + } + ] + }, + { + "type": "struct", + "name": "dojo::model::introspect::Enum", + "members": [ + { + "name": "name", + "type": "core::felt252" + }, + { + "name": "attrs", + "type": "core::array::Span::" + }, + { + "name": "children", + "type": "core::array::Span::<(core::felt252, dojo::model::introspect::Ty)>" + } + ] + }, + { + "type": "struct", + "name": "core::array::Span::", + "members": [ + { + "name": "snapshot", + "type": "@core::array::Array::" + } + ] + }, + { + "type": "enum", + "name": "dojo::model::introspect::Ty", + "variants": [ + { + "name": "Primitive", + "type": "core::felt252" + }, + { + "name": "Struct", + "type": "dojo::model::introspect::Struct" + }, + { + "name": "Enum", + "type": "dojo::model::introspect::Enum" + }, + { + "name": "Tuple", + "type": "core::array::Span::" + }, + { + "name": "Array", + "type": "core::array::Span::" + }, + { + "name": "ByteArray", + "type": "()" + } + ] + }, + { + "type": "interface", + "name": "dojo::model::model::IModel", + "items": [ + { + "type": "function", + "name": "name", + "inputs": [], + "outputs": [ + { + "type": "core::byte_array::ByteArray" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "namespace", + "inputs": [], + "outputs": [ + { + "type": "core::byte_array::ByteArray" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "tag", + "inputs": [], + "outputs": [ + { + "type": "core::byte_array::ByteArray" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "version", + "inputs": [], + "outputs": [ + { + "type": "core::integer::u8" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "selector", + "inputs": [], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "name_hash", + "inputs": [], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "namespace_hash", + "inputs": [], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "unpacked_size", + "inputs": [], + "outputs": [ + { + "type": "core::option::Option::" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "packed_size", + "inputs": [], + "outputs": [ + { + "type": "core::option::Option::" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "layout", + "inputs": [], + "outputs": [ + { + "type": "dojo::model::layout::Layout" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "schema", + "inputs": [], + "outputs": [ + { + "type": "dojo::model::introspect::Ty" + } + ], + "state_mutability": "view" + } + ] + }, + { + "type": "impl", + "name": "game_deckImpl", + "interface_name": "jokers_of_neon::models::data::game_deck::Igame_deck" + }, + { + "type": "struct", + "name": "jokers_of_neon::models::data::game_deck::GameDeck", + "members": [ + { + "name": "game_id", "type": "core::integer::u32" }, { - "name": "len_current_special_cards", + "name": "len", "type": "core::integer::u32" }, { - "name": "current_jokers", - "type": "core::integer::u8" - }, - { - "name": "state", - "type": "jokers_of_neon::models::status::game::game::GameState" - }, - { - "name": "cash", + "name": "round_len", "type": "core::integer::u32" } ] }, { "type": "interface", - "name": "jokers_of_neon::models::status::game::game::Igame", + "name": "jokers_of_neon::models::data::game_deck::Igame_deck", "items": [ { "type": "function", @@ -8905,7 +9748,7 @@ "inputs": [ { "name": "model", - "type": "jokers_of_neon::models::status::game::game::Game" + "type": "jokers_of_neon::models::data::game_deck::GameDeck" } ], "outputs": [], @@ -8915,14 +9758,14 @@ }, { "type": "event", - "name": "jokers_of_neon::models::status::game::game::game::Event", + "name": "jokers_of_neon::models::data::game_deck::game_deck::Event", "kind": "enum", "variants": [] } ], - "tag": "jokers_of_neon-Game", - "qualified_path": "jokers_of_neon::models::status::game::game::game", - "manifest_name": "jokers_of_neon-Game-162de85b" + "tag": "jokers_of_neon-GameDeck", + "qualified_path": "jokers_of_neon::models::data::game_deck::game_deck", + "manifest_name": "jokers_of_neon-GameDeck-481bbebe" }, { "kind": "DojoModel", @@ -8933,18 +9776,23 @@ "key": true }, { - "name": "len", - "type": "u32", + "name": "cost_discard", + "type": "u8", "key": false }, { - "name": "round_len", - "type": "u32", + "name": "cost_play", + "type": "u8", + "key": false + }, + { + "name": "energy_max_player", + "type": "u8", "key": false } ], - "class_hash": "0x165c5bd99b1100a2e1a2faaf9a2443d6ca12bc310e2ec39d1ac64eac3555f31", - "original_class_hash": "0x165c5bd99b1100a2e1a2faaf9a2443d6ca12bc310e2ec39d1ac64eac3555f31", + "class_hash": "0x4c5166033b50fa2dcbe8dca20d4c219aaf3b4944657affccd16cb08405bf8b5", + "original_class_hash": "0x4c5166033b50fa2dcbe8dca20d4c219aaf3b4944657affccd16cb08405bf8b5", "abi": [ { "type": "impl", @@ -9310,30 +10158,34 @@ }, { "type": "impl", - "name": "game_deckImpl", - "interface_name": "jokers_of_neon::models::data::game_deck::Igame_deck" + "name": "game_mode_beastImpl", + "interface_name": "jokers_of_neon::models::data::beast::Igame_mode_beast" }, { "type": "struct", - "name": "jokers_of_neon::models::data::game_deck::GameDeck", + "name": "jokers_of_neon::models::data::beast::GameModeBeast", "members": [ { "name": "game_id", "type": "core::integer::u32" }, { - "name": "len", - "type": "core::integer::u32" + "name": "cost_discard", + "type": "core::integer::u8" }, { - "name": "round_len", - "type": "core::integer::u32" + "name": "cost_play", + "type": "core::integer::u8" + }, + { + "name": "energy_max_player", + "type": "core::integer::u8" } ] }, { "type": "interface", - "name": "jokers_of_neon::models::data::game_deck::Igame_deck", + "name": "jokers_of_neon::models::data::beast::Igame_mode_beast", "items": [ { "type": "function", @@ -9341,7 +10193,7 @@ "inputs": [ { "name": "model", - "type": "jokers_of_neon::models::data::game_deck::GameDeck" + "type": "jokers_of_neon::models::data::beast::GameModeBeast" } ], "outputs": [], @@ -9351,14 +10203,14 @@ }, { "type": "event", - "name": "jokers_of_neon::models::data::game_deck::game_deck::Event", + "name": "jokers_of_neon::models::data::beast::game_mode_beast::Event", "kind": "enum", "variants": [] } ], - "tag": "jokers_of_neon-GameDeck", - "qualified_path": "jokers_of_neon::models::data::game_deck::game_deck", - "manifest_name": "jokers_of_neon-GameDeck-481bbebe" + "tag": "jokers_of_neon-GameModeBeast", + "qualified_path": "jokers_of_neon::models::data::beast::game_mode_beast", + "manifest_name": "jokers_of_neon-GameModeBeast-2eece866" }, { "kind": "DojoModel", @@ -11673,28 +12525,23 @@ "kind": "DojoModel", "members": [ { - "name": "player", - "type": "ContractAddress", + "name": "game_id", + "type": "u32", "key": true }, { - "name": "poker_hand", - "type": "u8", - "key": false - }, - { - "name": "multi", + "name": "health", "type": "u32", "key": false }, { - "name": "points", - "type": "u32", + "name": "energy", + "type": "u8", "key": false } ], - "class_hash": "0x34c07816aa25e5daadc2370bd4793af7dbd786de2c1e99d74e7347680ffa281", - "original_class_hash": "0x34c07816aa25e5daadc2370bd4793af7dbd786de2c1e99d74e7347680ffa281", + "class_hash": "0x72bab25593e59ba01387711eaa353d06fd59c06a93e1b5dcff3c30245d6c640", + "original_class_hash": "0x72bab25593e59ba01387711eaa353d06fd59c06a93e1b5dcff3c30245d6c640", "abi": [ { "type": "impl", @@ -12060,34 +12907,30 @@ }, { "type": "impl", - "name": "poker_hand_eventImpl", - "interface_name": "jokers_of_neon::models::data::events::Ipoker_hand_event" + "name": "player_beastImpl", + "interface_name": "jokers_of_neon::models::data::beast::Iplayer_beast" }, { "type": "struct", - "name": "jokers_of_neon::models::data::events::PokerHandEvent", + "name": "jokers_of_neon::models::data::beast::PlayerBeast", "members": [ { - "name": "player", - "type": "core::starknet::contract_address::ContractAddress" - }, - { - "name": "poker_hand", - "type": "core::integer::u8" + "name": "game_id", + "type": "core::integer::u32" }, { - "name": "multi", + "name": "health", "type": "core::integer::u32" }, { - "name": "points", - "type": "core::integer::u32" + "name": "energy", + "type": "core::integer::u8" } ] }, { "type": "interface", - "name": "jokers_of_neon::models::data::events::Ipoker_hand_event", + "name": "jokers_of_neon::models::data::beast::Iplayer_beast", "items": [ { "type": "function", @@ -12095,7 +12938,7 @@ "inputs": [ { "name": "model", - "type": "jokers_of_neon::models::data::events::PokerHandEvent" + "type": "jokers_of_neon::models::data::beast::PlayerBeast" } ], "outputs": [], @@ -12105,46 +12948,41 @@ }, { "type": "event", - "name": "jokers_of_neon::models::data::events::poker_hand_event::Event", + "name": "jokers_of_neon::models::data::beast::player_beast::Event", "kind": "enum", "variants": [] } ], - "tag": "jokers_of_neon-PokerHandEvent", - "qualified_path": "jokers_of_neon::models::data::events::poker_hand_event", - "manifest_name": "jokers_of_neon-PokerHandEvent-2ca11749" + "tag": "jokers_of_neon-PlayerBeast", + "qualified_path": "jokers_of_neon::models::data::beast::player_beast", + "manifest_name": "jokers_of_neon-PlayerBeast-22d6f7af" }, { "kind": "DojoModel", "members": [ { - "name": "game_id", - "type": "u32", + "name": "player", + "type": "ContractAddress", "key": true }, { - "name": "is_active", - "type": "bool", - "key": false - }, - { - "name": "current_probability", - "type": "u16", + "name": "poker_hand", + "type": "u8", "key": false }, { - "name": "active_rage_ids", - "type": "Span", + "name": "multi", + "type": "u32", "key": false }, { - "name": "last_active_level", - "type": "u8", + "name": "points", + "type": "u32", "key": false } ], - "class_hash": "0x7732ec110c4cfe77b29c39aa5115b1e4f5a547a42ef2e36c8b96ff5382a63fa", - "original_class_hash": "0x7732ec110c4cfe77b29c39aa5115b1e4f5a547a42ef2e36c8b96ff5382a63fa", + "class_hash": "0x34c07816aa25e5daadc2370bd4793af7dbd786de2c1e99d74e7347680ffa281", + "original_class_hash": "0x34c07816aa25e5daadc2370bd4793af7dbd786de2c1e99d74e7347680ffa281", "abi": [ { "type": "impl", @@ -12510,62 +13348,34 @@ }, { "type": "impl", - "name": "rage_roundImpl", - "interface_name": "jokers_of_neon::models::status::game::rage::Irage_round" - }, - { - "type": "enum", - "name": "core::bool", - "variants": [ - { - "name": "False", - "type": "()" - }, - { - "name": "True", - "type": "()" - } - ] - }, - { - "type": "struct", - "name": "core::array::Span::", - "members": [ - { - "name": "snapshot", - "type": "@core::array::Array::" - } - ] + "name": "poker_hand_eventImpl", + "interface_name": "jokers_of_neon::models::data::events::Ipoker_hand_event" }, { "type": "struct", - "name": "jokers_of_neon::models::status::game::rage::RageRound", + "name": "jokers_of_neon::models::data::events::PokerHandEvent", "members": [ { - "name": "game_id", - "type": "core::integer::u32" - }, - { - "name": "is_active", - "type": "core::bool" + "name": "player", + "type": "core::starknet::contract_address::ContractAddress" }, { - "name": "current_probability", - "type": "core::integer::u16" + "name": "poker_hand", + "type": "core::integer::u8" }, { - "name": "active_rage_ids", - "type": "core::array::Span::" + "name": "multi", + "type": "core::integer::u32" }, { - "name": "last_active_level", - "type": "core::integer::u8" + "name": "points", + "type": "core::integer::u32" } ] }, { "type": "interface", - "name": "jokers_of_neon::models::status::game::rage::Irage_round", + "name": "jokers_of_neon::models::data::events::Ipoker_hand_event", "items": [ { "type": "function", @@ -12573,7 +13383,7 @@ "inputs": [ { "name": "model", - "type": "jokers_of_neon::models::status::game::rage::RageRound" + "type": "jokers_of_neon::models::data::events::PokerHandEvent" } ], "outputs": [], @@ -12583,14 +13393,14 @@ }, { "type": "event", - "name": "jokers_of_neon::models::status::game::rage::rage_round::Event", + "name": "jokers_of_neon::models::data::events::poker_hand_event::Event", "kind": "enum", "variants": [] } ], - "tag": "jokers_of_neon-RageRound", - "qualified_path": "jokers_of_neon::models::status::game::rage::rage_round", - "manifest_name": "jokers_of_neon-RageRound-625525ca" + "tag": "jokers_of_neon-PokerHandEvent", + "qualified_path": "jokers_of_neon::models::data::events::poker_hand_event", + "manifest_name": "jokers_of_neon-PokerHandEvent-2ca11749" }, { "kind": "DojoModel", @@ -12601,28 +13411,28 @@ "key": true }, { - "name": "player_score", - "type": "u32", + "name": "is_active", + "type": "bool", "key": false }, { - "name": "level_score", - "type": "u32", + "name": "current_probability", + "type": "u16", "key": false }, { - "name": "hands", - "type": "u8", + "name": "active_rage_ids", + "type": "Span", "key": false }, { - "name": "discard", + "name": "last_active_level", "type": "u8", "key": false } ], - "class_hash": "0x6d9570cbe297941fe609b1c6ea2637516f1e0f426f57f8740026216958daddb", - "original_class_hash": "0x6d9570cbe297941fe609b1c6ea2637516f1e0f426f57f8740026216958daddb", + "class_hash": "0x7732ec110c4cfe77b29c39aa5115b1e4f5a547a42ef2e36c8b96ff5382a63fa", + "original_class_hash": "0x7732ec110c4cfe77b29c39aa5115b1e4f5a547a42ef2e36c8b96ff5382a63fa", "abi": [ { "type": "impl", @@ -12988,38 +13798,62 @@ }, { "type": "impl", - "name": "roundImpl", - "interface_name": "jokers_of_neon::models::status::round::round::Iround" + "name": "rage_roundImpl", + "interface_name": "jokers_of_neon::models::status::game::rage::Irage_round" + }, + { + "type": "enum", + "name": "core::bool", + "variants": [ + { + "name": "False", + "type": "()" + }, + { + "name": "True", + "type": "()" + } + ] + }, + { + "type": "struct", + "name": "core::array::Span::", + "members": [ + { + "name": "snapshot", + "type": "@core::array::Array::" + } + ] }, { "type": "struct", - "name": "jokers_of_neon::models::status::round::round::Round", + "name": "jokers_of_neon::models::status::game::rage::RageRound", "members": [ { "name": "game_id", "type": "core::integer::u32" }, { - "name": "player_score", - "type": "core::integer::u32" + "name": "is_active", + "type": "core::bool" }, { - "name": "level_score", - "type": "core::integer::u32" + "name": "current_probability", + "type": "core::integer::u16" }, { - "name": "hands", - "type": "core::integer::u8" + "name": "active_rage_ids", + "type": "core::array::Span::" }, { - "name": "discard", + "name": "last_active_level", "type": "core::integer::u8" } ] }, { "type": "interface", - "name": "jokers_of_neon::models::status::round::round::Iround", + "name": "jokers_of_neon::models::status::game::rage::Irage_round", "items": [ { "type": "function", @@ -13027,7 +13861,7 @@ "inputs": [ { "name": "model", - "type": "jokers_of_neon::models::status::round::round::Round" + "type": "jokers_of_neon::models::status::game::rage::RageRound" } ], "outputs": [], @@ -13037,14 +13871,14 @@ }, { "type": "event", - "name": "jokers_of_neon::models::status::round::round::round::Event", + "name": "jokers_of_neon::models::status::game::rage::rage_round::Event", "kind": "enum", "variants": [] } ], - "tag": "jokers_of_neon-Round", - "qualified_path": "jokers_of_neon::models::status::round::round::round", - "manifest_name": "jokers_of_neon-Round-23a2f4a8" + "tag": "jokers_of_neon-RageRound", + "qualified_path": "jokers_of_neon::models::status::game::rage::rage_round", + "manifest_name": "jokers_of_neon-RageRound-625525ca" }, { "kind": "DojoModel", diff --git a/manifests/dev/deployment/manifest.toml b/manifests/dev/deployment/manifest.toml index f90d3ba..304cef1 100644 --- a/manifests/dev/deployment/manifest.toml +++ b/manifests/dev/deployment/manifest.toml @@ -24,8 +24,8 @@ manifest_name = "dojo-base" [[contracts]] kind = "DojoContract" address = "0x6a41badee85305fa1aac33488860360c66b60d7f3b204d6e2cd84071dc3c394" -class_hash = "0x5f74e789806e15032b0e17a3d05f4f70f03b1bba1f6522bdf755235ac6286af" -original_class_hash = "0x5f74e789806e15032b0e17a3d05f4f70f03b1bba1f6522bdf755235ac6286af" +class_hash = "0x42e0a9b814ff24e92f45d9dd6e764ec9fc948c70b49242249b2cb7d97d62071" +original_class_hash = "0x42e0a9b814ff24e92f45d9dd6e764ec9fc948c70b49242249b2cb7d97d62071" base_class_hash = "0x2427dd10a58850ac9a5ca6ce04b7771b05330fd18f2e481831ad903b969e6b2" abi = "manifests/dev/deployment/abis/contracts/jokers_of_neon-game_system-7a205bbc.json" reads = [] @@ -38,6 +38,7 @@ systems = [ "select_modifier_cards", "play", "discard", + "end_turn", "discard_effect_card", "discard_special_card", ] @@ -60,8 +61,8 @@ manifest_name = "jokers_of_neon-poker_hand_system-25bae3ed" [[contracts]] kind = "DojoContract" address = "0x75602558fd679c49be1a6ccb73e3d6d842f0558e1f41c4013ce109d05a5790f" -class_hash = "0xe1327a50fe39d93f025e0a84e7ce9ccd46c1acd1f575c50acd881e3d4e23b7" -original_class_hash = "0xe1327a50fe39d93f025e0a84e7ce9ccd46c1acd1f575c50acd881e3d4e23b7" +class_hash = "0x4d335ac492b01d48fc5431dc87810c59111033fb62eaefd438ab41b6cdb3c06" +original_class_hash = "0x4d335ac492b01d48fc5431dc87810c59111033fb62eaefd438ab41b6cdb3c06" base_class_hash = "0x2427dd10a58850ac9a5ca6ce04b7771b05330fd18f2e481831ad903b969e6b2" abi = "manifests/dev/deployment/abis/contracts/jokers_of_neon-rage_system-601fc835.json" reads = [] @@ -71,6 +72,40 @@ tag = "jokers_of_neon-rage_system" systems = ["calculate"] manifest_name = "jokers_of_neon-rage_system-601fc835" +[[models]] +kind = "DojoModel" +class_hash = "0x5a1c6141a6afc7ffaff55d76c948b77992e8cd89ca6c50b21ac617a9889dcd0" +original_class_hash = "0x5a1c6141a6afc7ffaff55d76c948b77992e8cd89ca6c50b21ac617a9889dcd0" +abi = "manifests/dev/deployment/abis/models/jokers_of_neon-Beast-35a29cda.json" +tag = "jokers_of_neon-Beast" +qualified_path = "jokers_of_neon::models::data::beast::beast" +manifest_name = "jokers_of_neon-Beast-35a29cda" + +[[models.members]] +name = "game_id" +type = "u32" +key = true + +[[models.members]] +name = "tier" +type = "u8" +key = false + +[[models.members]] +name = "level" +type = "u8" +key = false + +[[models.members]] +name = "health" +type = "u32" +key = false + +[[models.members]] +name = "attack" +type = "u32" +key = false + [[models]] kind = "DojoModel" class_hash = "0x5c83fb072bedb835ecfd14432d82495c086e5f2089f390dcf8613da319d7f8e" @@ -500,8 +535,8 @@ key = false [[models]] kind = "DojoModel" -class_hash = "0xd231a89d484f9ce343542808702a69ff45ecd316470ea746e8de8e889d6f8" -original_class_hash = "0xd231a89d484f9ce343542808702a69ff45ecd316470ea746e8de8e889d6f8" +class_hash = "0x55a1aee842d76a253cb36c4989bc5ef74d3cd7d2d8dd4c464c64295986afa10" +original_class_hash = "0x55a1aee842d76a253cb36c4989bc5ef74d3cd7d2d8dd4c464c64295986afa10" abi = "manifests/dev/deployment/abis/models/jokers_of_neon-Game-162de85b.json" tag = "jokers_of_neon-Game" qualified_path = "jokers_of_neon::models::status::game::game::game" @@ -537,11 +572,6 @@ name = "max_jokers" type = "u8" key = false -[[models.members]] -name = "round" -type = "u8" -key = false - [[models.members]] name = "player_score" type = "u32" @@ -577,6 +607,11 @@ name = "state" type = "GameState" key = false +[[models.members]] +name = "substate" +type = "GameSubState" +key = false + [[models.members]] name = "cash" type = "u32" @@ -606,6 +641,35 @@ name = "round_len" type = "u32" key = false +[[models]] +kind = "DojoModel" +class_hash = "0x4c5166033b50fa2dcbe8dca20d4c219aaf3b4944657affccd16cb08405bf8b5" +original_class_hash = "0x4c5166033b50fa2dcbe8dca20d4c219aaf3b4944657affccd16cb08405bf8b5" +abi = "manifests/dev/deployment/abis/models/jokers_of_neon-GameModeBeast-2eece866.json" +tag = "jokers_of_neon-GameModeBeast" +qualified_path = "jokers_of_neon::models::data::beast::game_mode_beast" +manifest_name = "jokers_of_neon-GameModeBeast-2eece866" + +[[models.members]] +name = "game_id" +type = "u32" +key = true + +[[models.members]] +name = "cost_discard" +type = "u8" +key = false + +[[models.members]] +name = "cost_play" +type = "u8" +key = false + +[[models.members]] +name = "energy_max_player" +type = "u8" +key = false + [[models]] kind = "DojoModel" class_hash = "0x42cf1e65c45e0ef0b7c53dce92420243d76e261a51da744de4b1edb51937625" @@ -751,6 +815,30 @@ name = "player_score" type = "u32" key = false +[[models]] +kind = "DojoModel" +class_hash = "0x72bab25593e59ba01387711eaa353d06fd59c06a93e1b5dcff3c30245d6c640" +original_class_hash = "0x72bab25593e59ba01387711eaa353d06fd59c06a93e1b5dcff3c30245d6c640" +abi = "manifests/dev/deployment/abis/models/jokers_of_neon-PlayerBeast-22d6f7af.json" +tag = "jokers_of_neon-PlayerBeast" +qualified_path = "jokers_of_neon::models::data::beast::player_beast" +manifest_name = "jokers_of_neon-PlayerBeast-22d6f7af" + +[[models.members]] +name = "game_id" +type = "u32" +key = true + +[[models.members]] +name = "health" +type = "u32" +key = false + +[[models.members]] +name = "energy" +type = "u8" +key = false + [[models]] kind = "DojoModel" class_hash = "0x34c07816aa25e5daadc2370bd4793af7dbd786de2c1e99d74e7347680ffa281" @@ -814,40 +902,6 @@ name = "last_active_level" type = "u8" key = false -[[models]] -kind = "DojoModel" -class_hash = "0x6d9570cbe297941fe609b1c6ea2637516f1e0f426f57f8740026216958daddb" -original_class_hash = "0x6d9570cbe297941fe609b1c6ea2637516f1e0f426f57f8740026216958daddb" -abi = "manifests/dev/deployment/abis/models/jokers_of_neon-Round-23a2f4a8.json" -tag = "jokers_of_neon-Round" -qualified_path = "jokers_of_neon::models::status::round::round::round" -manifest_name = "jokers_of_neon-Round-23a2f4a8" - -[[models.members]] -name = "game_id" -type = "u32" -key = true - -[[models.members]] -name = "player_score" -type = "u32" -key = false - -[[models.members]] -name = "level_score" -type = "u32" -key = false - -[[models.members]] -name = "hands" -type = "u8" -key = false - -[[models.members]] -name = "discard" -type = "u8" -key = false - [[models]] kind = "DojoModel" class_hash = "0x58fe22073d9dc0c2cf86d7a19fa3d32e90e1eac8b3b057c20a9477c88565134" diff --git a/scripts/enviroment.sh b/scripts/enviroment.sh new file mode 100755 index 0000000..433bc4c --- /dev/null +++ b/scripts/enviroment.sh @@ -0,0 +1,23 @@ +echo -e "\n[INFO] Creating a new game..." +sozo execute game_system create_game -c 1 --wait --world 0x37578f01e123327fb366fc6e2224f4be4e44234d682855e1326363b57444b88 +sleep 3 +echo -e "\n[INFO] Game created successfully. Waiting 3 seconds before selecting deck..." + +echo -e "\n[INFO] Selecting deck for the game..." +sozo execute game_system select_deck -c 1,0 --wait --world 0x37578f01e123327fb366fc6e2224f4be4e44234d682855e1326363b57444b88 +sleep 3 +echo -e "\n[INFO] Deck selected successfully. Waiting 3 seconds before selecting special cards..." + +echo -e "\n[INFO] Selecting special cards for the deck..." +sozo execute game_system select_special_cards -c 1,1,1 --wait --world 0x37578f01e123327fb366fc6e2224f4be4e44234d682855e1326363b57444b88 +sleep 3 +echo -e "\n[INFO] Special cards selected successfully. Waiting 3 seconds before selecting modifier cards..." + +echo -e "\n[INFO] Selecting modifier cards for the deck..." +sozo execute game_system select_modifier_cards -c 1,1,1 --wait --world 0x37578f01e123327fb366fc6e2224f4be4e44234d682855e1326363b57444b88 +sleep 3 +echo -e "\n[INFO] Modifier cards selected successfully. Setup complete!" + + +# sozo execute game_system play -c 1,5,0,1,2,3,4,5,100,100,100,100,100 --wait --world 0x37578f01e123327fb366fc6e2224f4be4e44234d682855e1326363b57444b88 +# sozo execute game_system end_turn -c 1 --wait --world 0x37578f01e123327fb366fc6e2224f4be4e44234d682855e1326363b57444b88 diff --git a/src/configs/level.cairo b/src/configs/level.cairo new file mode 100644 index 0000000..0ea13ed --- /dev/null +++ b/src/configs/level.cairo @@ -0,0 +1,15 @@ +#[derive(Copy, Drop, Serde)] +struct LevelConfig { + initial_probability: u16, + increment_by_round: u16, + min_round_level_before_activate: u8, + level_cooldown: u8 +} + +impl LevelConfigDefault of Default { + fn default() -> LevelConfig { + LevelConfig { + initial_probability: 35, increment_by_round: 15, min_round_level_before_activate: 3, level_cooldown: 2 + } + } +} diff --git a/src/constants/challenge.cairo b/src/constants/challenge.cairo new file mode 100644 index 0000000..15bb87e --- /dev/null +++ b/src/constants/challenge.cairo @@ -0,0 +1,69 @@ +const CHALLENGE_ROYAL_FLUSH: u32 = 1; +const CHALLENGE_STRAIGHT_FLUSH: u32 = 2; +const CHALLENGE_FIVE_OF_A_KIND: u32 = 3; +const CHALLENGE_FOUR_OF_A_KIND: u32 = 4; +const CHALLENGE_FULL_HOUSE: u32 = 5; +const CHALLENGE_FLUSH: u32 = 6; +const CHALLENGE_STRAIGHT: u32 = 7; +const CHALLENGE_THREE_OF_A_KIND: u32 = 8; +const CHALLENGE_DOUBLE_PAIR: u32 = 9; +const CHALLENGE_PAIR: u32 = 10; +const CHALLENGE_HIGH_CARD: u32 = 11; + +const CHALLENGE_HEARTS: u32 = 12; +const CHALLENGE_CLUBS: u32 = 13; +const CHALLENGE_DIAMONDS: u32 = 14; +const CHALLENGE_SPADES: u32 = 15; + +const CHALLENGE_ONE: u32 = 16; +const CHALLENGE_TWO: u32 = 17; +const CHALLENGE_THREE: u32 = 18; +const CHALLENGE_FOUR: u32 = 19; +const CHALLENGE_FIVE: u32 = 20; +const CHALLENGE_SIX: u32 = 21; +const CHALLENGE_SEVEN: u32 = 22; +const CHALLENGE_EIGHT: u32 = 23; +const CHALLENGE_NINE: u32 = 24; +const CHALLENGE_TEN: u32 = 25; +const CHALLENGE_JACK: u32 = 26; +const CHALLENGE_QUEEN: u32 = 27; +const CHALLENGE_KING: u32 = 28; +const CHALLENGE_ACE: u32 = 29; + +const CHALLENGE_JOKER: u32 = 30; + + +fn challenges_all() -> Array { + array![ + CHALLENGE_ROYAL_FLUSH, + CHALLENGE_STRAIGHT_FLUSH, + CHALLENGE_FIVE_OF_A_KIND, + CHALLENGE_FOUR_OF_A_KIND, + CHALLENGE_FULL_HOUSE, + CHALLENGE_FLUSH, + CHALLENGE_STRAIGHT, + CHALLENGE_THREE_OF_A_KIND, + CHALLENGE_DOUBLE_PAIR, + CHALLENGE_PAIR, + CHALLENGE_HIGH_CARD, + CHALLENGE_HEARTS, + CHALLENGE_CLUBS, + CHALLENGE_DIAMONDS, + CHALLENGE_SPADES, + CHALLENGE_ONE, + CHALLENGE_TWO, + CHALLENGE_THREE, + CHALLENGE_FOUR, + CHALLENGE_FIVE, + CHALLENGE_SIX, + CHALLENGE_SEVEN, + CHALLENGE_EIGHT, + CHALLENGE_NINE, + CHALLENGE_TEN, + CHALLENGE_JACK, + CHALLENGE_QUEEN, + CHALLENGE_KING, + CHALLENGE_ACE, + CHALLENGE_JOKER + ] +} diff --git a/src/constants/packs.cairo b/src/constants/packs.cairo index 52e87b8..d8004af 100644 --- a/src/constants/packs.cairo +++ b/src/constants/packs.cairo @@ -241,7 +241,7 @@ fn MODIFIER_CARDS_PACK() -> BlisterPack { cost: 0, name: 'modifier_cards_pack', probability: 100, - size: 5, + size: 10, cards: array![array![].span(), modifiers_ids_all().span()].span(), probs: array![100, 100].span(), } diff --git a/src/lib.cairo b/src/lib.cairo index cb2fb8c..5b0b01c 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -4,6 +4,7 @@ mod traits; mod constants { mod card; + mod challenge; mod effect; mod modifiers; mod packs; @@ -14,11 +15,14 @@ mod constants { mod models { mod data { + mod beast; mod blister_pack; mod card; + mod challenge; mod effect_card; mod events; mod game_deck; + mod last_beast_level; mod poker_hand; } mod status { @@ -27,9 +31,11 @@ mod models { mod rage; } mod round { + mod beast; + mod challenge; mod current_hand_card; mod deck_card; - mod round; + mod level; } mod shop { mod shop; @@ -47,12 +53,11 @@ mod systems { mod tests { mod setup; mod test_calculate_hand; - mod test_calculate_level_score; - mod test_game_discard_effect_card; - mod test_game_discard_special_card; - mod test_game_play; + mod test_challenge; + // mod test_game_discard_effect_card; + // mod test_game_discard_special_card; + mod test_game_play_beast; mod test_game_select_deck; - mod test_game_select_modifier_cards; mod test_game_select_special_cards; mod utils; } @@ -60,15 +65,17 @@ mod tests { mod utils { mod calculate_hand; mod constants; + mod game; + mod level; mod packs; mod rage; mod random; - mod round; mod shop; } mod configs { mod earning_cash; + mod level; mod rage; mod slot_special_cards; } diff --git a/src/models/data/beast.cairo b/src/models/data/beast.cairo new file mode 100644 index 0000000..b0e47d7 --- /dev/null +++ b/src/models/data/beast.cairo @@ -0,0 +1,29 @@ +#[derive(Copy, Drop, IntrospectPacked, Serde)] +#[dojo::model] +struct GameModeBeast { + #[key] + game_id: u32, + cost_discard: u8, + cost_play: u8, + energy_max_player: u8 +} + +#[derive(Copy, Drop, IntrospectPacked, Serde)] +#[dojo::model] +struct Beast { + #[key] + game_id: u32, + tier: u8, + level: u8, + health: u32, + attack: u32 +} + +#[derive(Copy, Drop, IntrospectPacked, Serde)] +#[dojo::model] +struct PlayerBeast { + #[key] + game_id: u32, + health: u32, + energy: u8 +} diff --git a/src/models/data/challenge.cairo b/src/models/data/challenge.cairo new file mode 100644 index 0000000..fe7648b --- /dev/null +++ b/src/models/data/challenge.cairo @@ -0,0 +1,16 @@ +#[derive(Copy, Drop, Serde)] +#[dojo::model] +struct Challenge { + #[key] + game_id: u32, + active_ids: Span, +} + +#[derive(Copy, Drop, IntrospectPacked, Serde)] +#[dojo::model] +struct ChallengePlayer { + #[key] + game_id: u32, + discards: u8, + plays: u8 +} diff --git a/src/models/data/events.cairo b/src/models/data/events.cairo index ce2f56d..28172bc 100644 --- a/src/models/data/events.cairo +++ b/src/models/data/events.cairo @@ -244,3 +244,13 @@ struct SpecialCashEvent { card_idx: u32, special_idx: u32 } + +#[derive(Copy, Drop, Serde)] +#[dojo::event] +#[dojo::model] +struct ChallengeCompleted { + #[key] + player: ContractAddress, + player_name: felt252, + game_id: u32 +} diff --git a/src/models/data/last_beast_level.cairo b/src/models/data/last_beast_level.cairo new file mode 100644 index 0000000..af1eed7 --- /dev/null +++ b/src/models/data/last_beast_level.cairo @@ -0,0 +1,9 @@ +#[derive(Copy, Drop, Serde)] +#[dojo::model] +#[dojo::event] +struct LastBeastLevel { + #[key] + game_id: u32, + current_probability: u16, + level: u8 +} diff --git a/src/models/status/game/game.cairo b/src/models/status/game/game.cairo index e539e6d..3e82a62 100644 --- a/src/models/status/game/game.cairo +++ b/src/models/status/game/game.cairo @@ -1,5 +1,12 @@ use starknet::ContractAddress; +#[derive(Serde, Copy, Drop, IntrospectPacked, PartialEq)] +enum GameSubState { + BEAST, + CREATE_LEVEL, + OBSTACLE +} + #[derive(Serde, Copy, Drop, IntrospectPacked, PartialEq)] enum GameState { SELECT_DECK, @@ -22,7 +29,6 @@ struct Game { max_hands: u8, max_discard: u8, max_jokers: u8, - round: u8, player_score: u32, level: u32, len_hand: u32, @@ -30,6 +36,7 @@ struct Game { len_current_special_cards: u32, current_jokers: u8, state: GameState, + substate: GameSubState, cash: u32 } @@ -54,7 +61,6 @@ impl DefaultGame of Default { max_hands: 5, max_discard: 5, max_jokers: 5, - round: 1, player_score: 0, level: 1, len_hand: 8, @@ -62,6 +68,7 @@ impl DefaultGame of Default { len_current_special_cards: 0, current_jokers: 0, state: GameState::IN_GAME, + substate: GameSubState::CREATE_LEVEL, cash: 0 } } diff --git a/src/models/status/round/beast.cairo b/src/models/status/round/beast.cairo new file mode 100644 index 0000000..228fc21 --- /dev/null +++ b/src/models/status/round/beast.cairo @@ -0,0 +1,260 @@ +use core::nullable::NullableTrait; +use dojo::world::Resource::Contract; +use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait}; +use jokers_of_neon::constants::card::INVALID_CARD; +use jokers_of_neon::models::data::beast::{ + GameModeBeast, GameModeBeastStore, Beast, BeastStore, PlayerBeast, PlayerBeastStore +}; +use jokers_of_neon::models::data::events::{PlayWinGameEvent, PlayGameOverEvent}; +use jokers_of_neon::models::data::game_deck::{GameDeckImpl, GameDeck, GameDeckStore}; +use jokers_of_neon::models::status::game::game::{Game, GameState, GameSubState}; +use jokers_of_neon::models::status::game::rage::{RageRound, RageRoundStore}; +use jokers_of_neon::models::status::round::current_hand_card::{CurrentHandCard, CurrentHandCardTrait}; +use jokers_of_neon::store::{Store, StoreTrait}; +use jokers_of_neon::systems::rage_system::{IRageSystemDispatcher, IRageSystemDispatcherTrait}; +use jokers_of_neon::utils::constants::{ + RAGE_CARD_DIMINISHED_HOLD, RAGE_CARD_SILENT_JOKERS, RAGE_CARD_SILENT_HEARTS, RAGE_CARD_SILENT_CLUBS, + RAGE_CARD_SILENT_DIAMONDS, RAGE_CARD_SILENT_SPADES, RAGE_CARD_ZERO_WASTE, is_neon_card, is_modifier_card +}; +use jokers_of_neon::utils::game::play; +use jokers_of_neon::utils::level::create_level; +use jokers_of_neon::utils::rage::is_rage_card_active; +use starknet::{ContractAddress, get_caller_address, ClassHash}; + +mod errors { + const GAME_NOT_FOUND: felt252 = 'Game: game not found'; + const CALLER_NOT_OWNER: felt252 = 'Game: caller not owner'; + const INVALID_CARD_INDEX_LEN: felt252 = 'Game: invalid card index len'; + const INVALID_CARD_ELEM: felt252 = 'Game: invalid card element'; + const ARRAY_REPEATED_ELEMENTS: felt252 = 'Game: array repeated elements'; + const ONLY_EFFECT_CARD: felt252 = 'Game: only effect cards'; + const GAME_NOT_IN_GAME: felt252 = 'Game: is not IN_GAME'; + const GAME_NOT_IN_BEAST: felt252 = 'Game: is not BEAST'; + const USE_INVALID_CARD: felt252 = 'Game: use an invalid card'; +} + +#[generate_trait] +impl BeastImpl of BeastTrait { + fn create(world: IWorldDispatcher, ref store: Store, game_id: u32) { + let mut game = store.get_game(game_id); + game.substate = GameSubState::BEAST; + // Active `Rage Cards` + let rage_round = RageRoundStore::get(world, game_id); + + if is_rage_card_active(@rage_round, RAGE_CARD_DIMINISHED_HOLD) { + game.len_hand -= 2; + } + store.set_game(game); + + let game_mode_beast = GameModeBeast { game_id, cost_discard: 1, cost_play: 2, energy_max_player: 3 }; + GameModeBeastStore::set(@game_mode_beast, world); + + let beast = Beast { game_id, tier: 5, level: 5, health: 300, attack: 15 }; + BeastStore::set(@beast, world); + + let player_beast = PlayerBeast { game_id, health: 100, energy: game_mode_beast.energy_max_player }; + PlayerBeastStore::set(@player_beast, world); + + let mut game_deck = GameDeckStore::get(world, game_id); + game_deck.restore(world); + CurrentHandCardTrait::create(world, game); + } + + fn play(world: IWorldDispatcher, game_id: u32, cards_index: Array, modifiers_index: Array) { + let mut store: Store = StoreTrait::new(world); + let mut game = store.get_game(game_id); + + assert(game.owner.is_non_zero(), errors::GAME_NOT_FOUND); + assert(game.owner == get_caller_address(), errors::CALLER_NOT_OWNER); + assert(game.state == GameState::IN_GAME, errors::GAME_NOT_IN_GAME); + assert(game.substate == GameSubState::BEAST, errors::GAME_NOT_IN_BEAST); + assert(cards_index.len() > 0 && cards_index.len() <= game.len_hand, errors::INVALID_CARD_INDEX_LEN); + + let rage_round = RageRoundStore::get(world, game_id); + + let score = play(world, ref game, @cards_index, @modifiers_index); + + let player_attack = score; // TODO: + + let mut beast = BeastStore::get(world, game.id); + beast.health = if player_attack < beast.health { + beast.health - player_attack + } else { + 0 + }; + BeastStore::set(@beast, world); + + let mut game_mode_beast = GameModeBeastStore::get(world, game.id); + + let mut player_beast = PlayerBeastStore::get(world, game.id); + player_beast.energy -= game_mode_beast.cost_play; + PlayerBeastStore::set(@player_beast, world); + + if beast.health.is_zero() { + let play_win_game_event = PlayWinGameEvent { + player: get_caller_address(), game_id, level: game.level, player_score: 0 + }; + emit!(world, (play_win_game_event)); + game.state = GameState::IN_GAME; + game.substate = GameSubState::CREATE_LEVEL; + game.player_score += 1; + + if is_rage_card_active(@rage_round, RAGE_CARD_DIMINISHED_HOLD) { + // return the cards to the deck + game.len_hand += 2; + } + let (_, rage_system_address) = match world.resource(selector_from_tag!("jokers_of_neon-rage_system")) { + Contract((class_hash, contract_address)) => Option::Some((class_hash, contract_address)), + _ => Option::None + }.unwrap(); + IRageSystemDispatcher { contract_address: rage_system_address.try_into().unwrap() }.calculate(game.id); + // create_level(world, ref store, game); TODO: + } else if player_beast.energy.is_zero() { + _attack_beast(world, ref store, ref game, ref player_beast, ref beast, ref game_mode_beast); + } else { + let mut cards = array![]; + let mut idx = 0; + loop { + if idx == cards_index.len() { + break; + } + cards.append(*cards_index.at(idx)); + idx += 1; + }; + + idx = 0; + loop { + if idx == modifiers_index.len() { + break; + } + let card_index = *modifiers_index.at(idx); + if card_index != 100 { + cards.append(card_index); + } + idx += 1; + }; + + CurrentHandCardTrait::refresh(world, game_id, cards); + + // The player has no more cards in his hand and in the deck + let game_deck = GameDeckStore::get(world, game.id); + if game_deck.round_len.is_zero() && player_has_empty_hand(ref store, @game) { // TODO: GameOver + let play_game_over_event = PlayGameOverEvent { player: get_caller_address(), game_id }; + emit!(world, (play_game_over_event)); + game.state = GameState::FINISHED; + } + } + store.set_game(game); + } + + fn discard(world: IWorldDispatcher, game_id: u32, cards_index: Array, modifiers_index: Array) { + let mut store: Store = StoreTrait::new(world); + let mut game = store.get_game(game_id); + + assert(game.owner.is_non_zero(), errors::GAME_NOT_FOUND); + assert(game.owner == get_caller_address(), errors::CALLER_NOT_OWNER); + assert(game.state == GameState::IN_GAME, errors::GAME_NOT_IN_GAME); + assert(game.substate == GameSubState::BEAST, errors::GAME_NOT_IN_BEAST); + + let mut cards = array![]; + let mut idx = 0; + loop { + if idx == cards_index.len() { + break; + } + let current_hand_card = store.get_current_hand_card(game_id, *cards_index.at(idx)); + assert(current_hand_card.card_id != INVALID_CARD, errors::USE_INVALID_CARD); + + cards.append(*cards_index.at(idx)); + idx += 1; + }; + + idx = 0; + loop { + if idx == modifiers_index.len() { + break; + } + let card_index = *modifiers_index.at(idx); + if card_index != 100 { + cards.append(card_index); + } + idx += 1; + }; + + CurrentHandCardTrait::refresh(world, game.id, cards); + + let mut game_mode_beast = GameModeBeastStore::get(world, game.id); + + let mut player_beast = PlayerBeastStore::get(world, game.id); + player_beast.energy -= game_mode_beast.cost_discard; + PlayerBeastStore::set(@player_beast, world); + + let game_deck = GameDeckStore::get(world, game_id); + if game_deck.round_len.is_zero() && player_has_empty_hand(ref store, @game) { + let play_game_over_event = PlayGameOverEvent { player: get_caller_address(), game_id: game.id }; + emit!(world, (play_game_over_event)); + game.state = GameState::FINISHED; + store.set_game(game); + } + + if player_beast.energy.is_zero() { + let mut beast = BeastStore::get(world, game.id); + _attack_beast(world, ref store, ref game, ref player_beast, ref beast, ref game_mode_beast); + } + } + + fn end_turn(world: IWorldDispatcher, game_id: u32) { + let mut store: Store = StoreTrait::new(world); + let mut game = store.get_game(game_id); + + assert(game.owner.is_non_zero(), errors::GAME_NOT_FOUND); + assert(game.owner == get_caller_address(), errors::CALLER_NOT_OWNER); + assert(game.state == GameState::IN_GAME, errors::GAME_NOT_IN_GAME); + assert(game.substate == GameSubState::BEAST, errors::GAME_NOT_IN_BEAST); + + let mut beast = BeastStore::get(world, game.id); + let mut game_mode_beast = GameModeBeastStore::get(world, game.id); + let mut player_beast = PlayerBeastStore::get(world, game.id); + _attack_beast(world, ref store, ref game, ref player_beast, ref beast, ref game_mode_beast); + } +} + +fn player_has_empty_hand(ref store: Store, game: @Game) -> bool { + let mut i = 0; + loop { + if game.len_hand == @i { + break true; + } + let deck_card = store.get_current_hand_card(*game.id, i); + if deck_card.card_id != INVALID_CARD { + break false; + } + i += 1; + } +} + +fn _attack_beast( + world: IWorldDispatcher, + ref store: Store, + ref game: Game, + ref player_beast: PlayerBeast, + ref beast: Beast, + ref game_mode_beast: GameModeBeast +) { + player_beast.health = if beast.attack > player_beast.health { + 0 + } else { + player_beast.health - beast.attack + }; + + if player_beast.health.is_zero() { + let play_game_over_event = PlayGameOverEvent { player: get_caller_address(), game_id: game.id }; + emit!(world, (play_game_over_event)); + game.state = GameState::FINISHED; + store.set_game(game); + } else { + // reset energy + player_beast.energy = game_mode_beast.energy_max_player; + } + PlayerBeastStore::set(@player_beast, world); +} diff --git a/src/models/status/round/challenge.cairo b/src/models/status/round/challenge.cairo new file mode 100644 index 0000000..8ca086b --- /dev/null +++ b/src/models/status/round/challenge.cairo @@ -0,0 +1,319 @@ +use dojo::world::{IWorld, IWorldDispatcher, IWorldDispatcherTrait}; +use jokers_of_neon::constants::{ + card::INVALID_CARD, + challenge::{ + CHALLENGE_ROYAL_FLUSH, CHALLENGE_STRAIGHT_FLUSH, CHALLENGE_FIVE_OF_A_KIND, CHALLENGE_FOUR_OF_A_KIND, + CHALLENGE_FULL_HOUSE, CHALLENGE_FLUSH, CHALLENGE_STRAIGHT, CHALLENGE_THREE_OF_A_KIND, CHALLENGE_DOUBLE_PAIR, + CHALLENGE_PAIR, CHALLENGE_HIGH_CARD, CHALLENGE_HEARTS, CHALLENGE_CLUBS, CHALLENGE_DIAMONDS, CHALLENGE_SPADES, + CHALLENGE_ONE, CHALLENGE_TWO, CHALLENGE_THREE, CHALLENGE_FOUR, CHALLENGE_FIVE, CHALLENGE_SIX, CHALLENGE_SEVEN, + CHALLENGE_EIGHT, CHALLENGE_NINE, CHALLENGE_TEN, CHALLENGE_JACK, CHALLENGE_QUEEN, CHALLENGE_KING, CHALLENGE_ACE, + CHALLENGE_JOKER, challenges_all + }, + specials::SPECIAL_ALL_CARDS_TO_HEARTS_ID, +}; + +use jokers_of_neon::{ + models::{ + data::{ + challenge::{Challenge, ChallengeStore, ChallengePlayerStore}, card::{Card, Suit, Value}, + game_deck::{GameDeckStore, GameDeckImpl}, + events::{ChallengeCompleted, PlayGameOverEvent, ModifierCardSuitEvent, SpecialModifierSuitEvent}, + poker_hand::PokerHand + }, + status::{ + game::game::{Game, GameState, GameSubState, GameStore}, + round::current_hand_card::{CurrentHandCard, CurrentHandCardTrait} + }, + }, + store::{Store, StoreTrait}, utils::{shop::generate_unique_random_values, calculate_hand::calculate_hand} +}; +use starknet::get_caller_address; + +mod errors { + const STATE_NOT_IN_GAME: felt252 = 'State not IN_GAME'; + const SUBSTATE_NOT_OBSTACLE: felt252 = 'Substate not OBSTACLE'; + const USE_INVALID_CARD: felt252 = 'Use an invalid card'; + const ARRAY_REPEATED_ELEMENTS: felt252 = 'Array has repeated elements'; +} + +#[generate_trait] +impl ChallengeImpl of ChallengeTrait { + fn create(world: IWorldDispatcher, game_id: u32) { + let mut challenge = ChallengeStore::get(world, game_id); + challenge.active_ids = generate_unique_random_values(world, 3, challenges_all(), array![]).span(); + ChallengeStore::set(@challenge, world); + } + + fn play(world: IWorldDispatcher, game_id: u32, cards_index: Array, modifiers_index: Array) { + let mut game = GameStore::get(world, game_id); + assert(game.state == GameState::IN_GAME, errors::STATE_NOT_IN_GAME); + assert(game.substate == GameSubState::OBSTACLE, errors::SUBSTATE_NOT_OBSTACLE); + + let mut store = StoreTrait::new(world); + let mut current_special_cards_index = _current_special_cards(ref store, @game); + // TODO: Modifiers + let (mut cards, _, _) = _get_cards( + world, ref store, game.id, @cards_index, @modifiers_index, ref current_special_cards_index + ); + let (result_hand, mut hit_cards) = calculate_hand(@cards, ref current_special_cards_index); + + let mut challenge = ChallengeStore::get(world, game_id); + _resolve_challenges(ref challenge, result_hand, ref hit_cards, @cards); + ChallengeStore::set(@challenge, world); + + if Self::is_completed(@world, game_id) { + emit!(world, ChallengeCompleted { player: game.owner, player_name: game.player_name, game_id }) + } else { + let mut challenge_player = ChallengePlayerStore::get(world, game_id); + challenge_player.plays -= 1; + ChallengePlayerStore::set(@challenge_player, world); + } + + CurrentHandCardTrait::refresh(world, game_id, cards_index); + + let game_deck = GameDeckStore::get(world, game_id); + if game_deck.round_len.is_zero() && _player_has_empty_hand(ref store, @game) { + let play_game_over_event = PlayGameOverEvent { player: get_caller_address(), game_id: game.id }; + emit!(world, (play_game_over_event)); + game.state = GameState::FINISHED; + GameStore::set(@game, world); + } + } + + fn discard(world: IWorldDispatcher, game_id: u32, cards_index: Array, modifiers_index: Array) { + let mut game = GameStore::get(world, game_id); + assert(game.state == GameState::IN_GAME, errors::STATE_NOT_IN_GAME); + assert(game.substate == GameSubState::OBSTACLE, errors::SUBSTATE_NOT_OBSTACLE); + + let mut store = StoreTrait::new(world); + let mut cards = array![]; + let mut idx = 0; + loop { + if idx == cards_index.len() { + break; + } + let current_hand_card = store.get_current_hand_card(game_id, *cards_index.at(idx)); + assert(current_hand_card.card_id != INVALID_CARD, errors::USE_INVALID_CARD); + + cards.append(*cards_index.at(idx)); + idx += 1; + }; + + idx = 0; + loop { + if idx == modifiers_index.len() { + break; + } + let card_index = *modifiers_index.at(idx); + if card_index != 100 { + cards.append(card_index); + } + idx += 1; + }; + CurrentHandCardTrait::refresh(world, game_id, cards); + + let mut challenge_player = ChallengePlayerStore::get(world, game_id); + challenge_player.discards -= 1; + ChallengePlayerStore::set(@challenge_player, world); + + let game_deck = GameDeckStore::get(world, game_id); + if game_deck.round_len.is_zero() && _player_has_empty_hand(ref store, @game) { + let play_game_over_event = PlayGameOverEvent { player: get_caller_address(), game_id: game.id }; + emit!(world, (play_game_over_event)); + game.state = GameState::FINISHED; + store.set_game(game); + } + } + + fn is_completed(world: @IWorldDispatcher, game_id: u32) -> bool { + ChallengeStore::get(*world, game_id).active_ids.is_empty() + } +} + + +fn _resolve_challenges( + ref challenge: Challenge, result_hand: PokerHand, ref hit_cards: Felt252Dict, cards: @Array +) { + match result_hand { + PokerHand::RoyalFlush => _complete(ref challenge, CHALLENGE_ROYAL_FLUSH), + PokerHand::StraightFlush => _complete(ref challenge, CHALLENGE_STRAIGHT_FLUSH), + PokerHand::FiveOfAKind => _complete(ref challenge, CHALLENGE_FIVE_OF_A_KIND), + PokerHand::FourOfAKind => _complete(ref challenge, CHALLENGE_FOUR_OF_A_KIND), + PokerHand::FullHouse => _complete(ref challenge, CHALLENGE_FULL_HOUSE), + PokerHand::Straight => _complete(ref challenge, CHALLENGE_STRAIGHT), + PokerHand::Flush => _complete(ref challenge, CHALLENGE_FLUSH), + PokerHand::ThreeOfAKind => _complete(ref challenge, CHALLENGE_THREE_OF_A_KIND), + PokerHand::TwoPair => _complete(ref challenge, CHALLENGE_DOUBLE_PAIR), + PokerHand::OnePair => _complete(ref challenge, CHALLENGE_PAIR), + PokerHand::HighCard => _complete(ref challenge, CHALLENGE_HIGH_CARD), + PokerHand::None => (), + }; + + let mut idx = 0; + loop { + if idx == cards.len() { + break; + } + + let hit = hit_cards.get(idx.into()); + if hit { + let card = *cards.at(idx); + match card.value { + Value::Two => { _complete(ref challenge, CHALLENGE_TWO); }, + Value::Three => { _complete(ref challenge, CHALLENGE_THREE); }, + Value::Four => { _complete(ref challenge, CHALLENGE_FOUR); }, + Value::Five => { _complete(ref challenge, CHALLENGE_FIVE); }, + Value::Six => { _complete(ref challenge, CHALLENGE_SIX); }, + Value::Seven => { _complete(ref challenge, CHALLENGE_SEVEN); }, + Value::Eight => { _complete(ref challenge, CHALLENGE_EIGHT); }, + Value::Nine => { _complete(ref challenge, CHALLENGE_NINE); }, + Value::Ten => { _complete(ref challenge, CHALLENGE_TEN); }, + Value::Jack => { _complete(ref challenge, CHALLENGE_JACK); }, + Value::Queen => { _complete(ref challenge, CHALLENGE_QUEEN); }, + Value::King => { _complete(ref challenge, CHALLENGE_KING); }, + Value::Ace => { _complete(ref challenge, CHALLENGE_ACE); }, + Value::Joker => { _complete(ref challenge, CHALLENGE_JOKER); }, + Value::NeonJoker => { _complete(ref challenge, CHALLENGE_JOKER); }, + Value::None => {}, + }; + + match card.suit { + Suit::Clubs => { _complete(ref challenge, CHALLENGE_CLUBS); }, + Suit::Hearts => { _complete(ref challenge, CHALLENGE_HEARTS); }, + Suit::Spades => { _complete(ref challenge, CHALLENGE_SPADES); }, + Suit::Diamonds => { _complete(ref challenge, CHALLENGE_DIAMONDS); }, + Suit::Joker => {}, + Suit::None => {}, + }; + } + idx += 1; + }; +} + +fn _complete(ref challenge: Challenge, challenge_id: u32) { + let mut remaining_challenges = array![]; + loop { + match challenge.active_ids.pop_front() { + Option::Some(challenge) => { if *challenge != challenge_id { + remaining_challenges.append(*challenge); + } }, + Option::None => { break; }, + } + }; + challenge.active_ids = remaining_challenges.span(); +} + +fn _player_has_empty_hand(ref store: Store, game: @Game) -> bool { + let mut i = 0; + loop { + if game.len_hand == @i { + break true; + } + let deck_card = store.get_current_hand_card(*game.id, i); + if deck_card.card_id != INVALID_CARD { + break false; + } + i += 1; + } +} + +fn _current_special_cards(ref store: Store, game: @Game) -> Felt252Dict> { + let mut current_special_cards_index: Felt252Dict> = Default::default(); + let mut idx = 0; + loop { + if idx == *game.len_current_special_cards { + break; + } + let current_special_card = store.get_current_special_cards(*game.id, idx); + current_special_cards_index.insert(current_special_card.effect_card_id.into(), NullableTrait::new(idx)); + idx += 1; + }; + current_special_cards_index +} + +fn _get_cards( + world: IWorldDispatcher, + ref store: Store, + game_id: u32, + cards_index: @Array, + modifiers_index: @Array, + ref current_special_cards_index: Felt252Dict> +) -> (Array, Array, Array) { + assert(!_has_repeated(cards_index), errors::ARRAY_REPEATED_ELEMENTS); + let mut cards = array![]; + let mut effect_id_cards_1 = array![]; + let mut effect_id_cards_2 = array![]; + let mut idx = 0; + loop { + if idx == cards_index.len() { + break; + } + + let current_hand_card = store.get_current_hand_card(game_id, *cards_index.at(idx)); + assert(current_hand_card.card_id != INVALID_CARD, errors::USE_INVALID_CARD); + + let mut card = store.get_card(current_hand_card.card_id); + + let modifier_1_index = *modifiers_index.at(idx); + if modifier_1_index != 100 { // TODO: Invalid + let current_hand_modifier_card = store.get_current_hand_card(game_id, modifier_1_index); + let effect_card = store.get_effect_card(current_hand_modifier_card.card_id); + effect_id_cards_1.append(effect_card.effect_id); + let effect = store.get_effect(effect_card.effect_id); + if effect.suit != Suit::None && card.suit != Suit::Joker { + card.suit = effect.suit; + emit!( + world, + ModifierCardSuitEvent { + player: get_caller_address(), + game_id, + modifier_card_idx: *modifiers_index.at(idx), + current_hand_card_idx: *cards_index.at(idx), + suit: card.suit + } + ); + } + } else { + effect_id_cards_1.append(100); + } + + if !(current_special_cards_index.get(SPECIAL_ALL_CARDS_TO_HEARTS_ID.into()).is_null()) { + if card.suit != Suit::Joker { + card.suit = Suit::Hearts; + emit!( + world, + SpecialModifierSuitEvent { + player: get_caller_address(), + game_id, + current_special_card_idx: current_special_cards_index + .get(SPECIAL_ALL_CARDS_TO_HEARTS_ID.into()) + .deref(), + current_hand_card_idx: *cards_index.at(idx), + suit: card.suit + } + ); + } + } + + cards.append(card); + idx += 1; + }; + (cards, effect_id_cards_1, effect_id_cards_2) +} + +fn _has_repeated(array: @Array) -> bool { + let mut founded: Felt252Dict = Default::default(); + let mut span = array.span(); + loop { + match span.pop_front() { + Option::Some(e) => { + let repeated = founded.get((*e).into()); + if repeated { + break true; + } + founded.insert((*e).into(), true); + }, + Option::None => { break false; } + }; + } +} diff --git a/src/models/status/round/current_hand_card.cairo b/src/models/status/round/current_hand_card.cairo index 78275d5..000876f 100644 --- a/src/models/status/round/current_hand_card.cairo +++ b/src/models/status/round/current_hand_card.cairo @@ -1,7 +1,6 @@ use dojo::world::{IWorld, IWorldDispatcher, IWorldDispatcherTrait}; use jokers_of_neon::models::status::game::game::Game; use jokers_of_neon::models::status::round::deck_card::DeckCardTrait; -use jokers_of_neon::models::status::round::round::Round; use jokers_of_neon::store::{Store, StoreTrait}; #[derive(Copy, Drop, IntrospectPacked, Serde)] @@ -17,17 +16,17 @@ struct CurrentHandCard { #[generate_trait] impl CurrentHandCardImpl of CurrentHandCardTrait { - fn create(world: IWorldDispatcher, ref round: Round, game: Game) { + fn create(world: IWorldDispatcher, game: Game) { // TODO: upgrade this solution let cards_indexes = if game.len_hand == 10 { array![0, 1, 2, 3, 4, 5, 6, 7, 8, 9] } else { array![0, 1, 2, 3, 4, 5, 6, 7] }; - DeckCardTrait::dealing(world, ref round, cards_indexes); + DeckCardTrait::dealing(world, game.id, cards_indexes); } - fn refresh(world: IWorldDispatcher, ref round: Round, cards_indexes: Array) { - DeckCardTrait::dealing(world, ref round, cards_indexes); + fn refresh(world: IWorldDispatcher, game_id: u32, cards_indexes: Array) { + DeckCardTrait::dealing(world, game_id, cards_indexes); } } diff --git a/src/models/status/round/deck_card.cairo b/src/models/status/round/deck_card.cairo index 07048ac..3d9785f 100644 --- a/src/models/status/round/deck_card.cairo +++ b/src/models/status/round/deck_card.cairo @@ -2,7 +2,6 @@ use dojo::world::{IWorld, IWorldDispatcher, IWorldDispatcherTrait}; use jokers_of_neon::constants::card::INVALID_CARD; use jokers_of_neon::models::data::game_deck::{GameDeckImpl, GameDeck, GameDeckStore}; use jokers_of_neon::models::status::round::current_hand_card::{CurrentHandCard, CurrentHandCardStore}; -use jokers_of_neon::models::status::round::round::Round; use jokers_of_neon::utils::random::{Random, RandomImpl, RandomTrait}; const TWO_POW_160: u256 = 0x10000000000000000000000000000000000000000; @@ -10,12 +9,12 @@ const TWO_POW_255: u256 = 0x8000000000000000000000000000000000000000000000000000 #[generate_trait] impl DeckCardImpl of DeckCardTrait { - fn dealing(world: IWorldDispatcher, ref round: Round, cards_ids: Array) { + fn dealing(world: IWorldDispatcher, game_id: u32, cards_ids: Array) { let mut randomizer = RandomImpl::new(world); - let mut game_deck = GameDeckStore::get(world, round.game_id); + let mut game_deck = GameDeckStore::get(world, game_id); let mut random = randomizer.between_u256(TWO_POW_160, TWO_POW_255); - _dealing(world, ref game_deck, cards_ids.len(), random, round.game_id, cards_ids); + _dealing(world, ref game_deck, cards_ids.len(), random, game_id, cards_ids); GameDeckStore::set(@game_deck, world); } } diff --git a/src/models/status/round/level.cairo b/src/models/status/round/level.cairo new file mode 100644 index 0000000..7563d28 --- /dev/null +++ b/src/models/status/round/level.cairo @@ -0,0 +1,48 @@ +use dojo::world::{IWorld, IWorldDispatcher}; +use jokers_of_neon::models::data::last_beast_level::{LastBeastLevel, LastBeastLevelStore}; +use jokers_of_neon::models::status::game::game::GameSubState; +use jokers_of_neon::models::status::{game::{game::GameStore}}; +use jokers_of_neon::store::StoreTrait; +use jokers_of_neon::utils::constants::rage_cards_all; +use jokers_of_neon::utils::random::RandomImpl; +use jokers_of_neon::utils::shop::generate_unique_random_values; + +#[generate_trait] +impl LevelImpl of LevelTrait { + fn calculate(world: IWorldDispatcher, game_id: u32) -> GameSubState { + let mut store = StoreTrait::new(world); + let game = GameStore::get(world, game_id); + let level_config = store.get_level_config(); + let mut last_active_level = LastBeastLevelStore::get(world, game_id); + + if game.level <= level_config.min_round_level_before_activate.into() { + return GameSubState::OBSTACLE; + } + + if last_active_level.level != 0 && game.level + - last_active_level.level.into() <= level_config.level_cooldown.try_into().unwrap() { + return GameSubState::OBSTACLE; + } + + let mut randomizer = RandomImpl::new(world); + let random = randomizer.between::(0, 100); + if random <= last_active_level.current_probability { + last_active_level.level = game.level.try_into().unwrap(); + last_active_level.current_probability = level_config.initial_probability; + LastBeastLevelStore::set(@last_active_level, world); + + GameSubState::BEAST + } else { + if last_active_level.current_probability + level_config.increment_by_round <= 100 { + last_active_level.current_probability = last_active_level.current_probability + + level_config.increment_by_round; + } else { + last_active_level.current_probability = 100; + } + LastBeastLevelStore::set(@last_active_level, world); + + GameSubState::OBSTACLE + } + } +} + diff --git a/src/models/status/round/round.cairo b/src/models/status/round/round.cairo deleted file mode 100644 index 666ef35..0000000 --- a/src/models/status/round/round.cairo +++ /dev/null @@ -1,11 +0,0 @@ -#[derive(Copy, Drop, IntrospectPacked, Serde)] -#[dojo::model] -struct Round { - #[key] - game_id: u32, - player_score: u32, - level_score: u32, - hands: u8, - discard: u8 -} - diff --git a/src/store.cairo b/src/store.cairo index 9a23624..110f447 100644 --- a/src/store.cairo +++ b/src/store.cairo @@ -1,6 +1,7 @@ use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait}; use jokers_of_neon::configs::{ - rage::RageRoundConfig, slot_special_cards::SlotSpecialCardsConfig, earning_cash::EarningCashConfig + rage::RageRoundConfig, slot_special_cards::SlotSpecialCardsConfig, earning_cash::EarningCashConfig, + level::LevelConfig }; use jokers_of_neon::constants::card::{ @@ -87,7 +88,6 @@ use jokers_of_neon::models::data::poker_hand::{LevelPokerHand, PokerHand}; use jokers_of_neon::models::status::game::game::{Game, CurrentSpecialCards}; use jokers_of_neon::models::status::round::current_hand_card::{CurrentHandCard, CurrentHandCardTrait}; use jokers_of_neon::models::status::round::deck_card::{DeckCardTrait}; -use jokers_of_neon::models::status::round::round::Round; use jokers_of_neon::models::status::shop::shop::{CardItem, CardItemType, BlisterPackItem, BlisterPackResult}; use starknet::ContractAddress; @@ -266,6 +266,10 @@ impl StoreImpl of StoreTrait { } } + fn get_level_config(ref self: Store) -> LevelConfig { + Default::default() + } + fn get_level_poker_hand(ref self: Store, poker_hand: PokerHand, level: u8) -> LevelPokerHand { match poker_hand { PokerHand::RoyalFlush => ROYAL_FLUSH(level), @@ -307,14 +311,6 @@ impl StoreImpl of StoreTrait { set!(self.world, (current_hand_card)); } - fn get_round(ref self: Store, game_id: u32) -> Round { - get!(self.world, (game_id), (Round)) - } - - fn set_round(ref self: Store, round: Round) { - set!(self.world, (round)); - } - fn get_card_item(ref self: Store, game_id: u32, idx: u32, item_type: CardItemType) -> CardItem { get!(self.world, (game_id, idx, item_type), (CardItem)) } diff --git a/src/systems/game_system.cairo b/src/systems/game_system.cairo index 5cddebd..b7b3d18 100644 --- a/src/systems/game_system.cairo +++ b/src/systems/game_system.cairo @@ -5,14 +5,13 @@ use jokers_of_neon::models::data::poker_hand::PokerHand; #[dojo::interface] trait IGameSystem { fn create_game(ref world: IWorldDispatcher, player_name: felt252) -> u32; + fn create_level(ref world: IWorldDispatcher, game_id: u32); fn select_deck(ref world: IWorldDispatcher, game_id: u32, deck_id: u8); fn select_special_cards(ref world: IWorldDispatcher, game_id: u32, cards_index: Array); fn select_modifier_cards(ref world: IWorldDispatcher, game_id: u32, cards_index: Array); fn play(ref world: IWorldDispatcher, game_id: u32, cards_index: Array, modifiers_index: Array); fn discard(ref world: IWorldDispatcher, game_id: u32, cards_index: Array, modifiers_index: Array); - fn check_hand( - ref world: IWorldDispatcher, game_id: u32, cards_index: Array, modifiers_index: Array - ) -> PokerHand; + fn end_turn(ref world: IWorldDispatcher, game_id: u32); fn discard_effect_card(ref world: IWorldDispatcher, game_id: u32, card_index: u32); fn discard_special_card(ref world: IWorldDispatcher, game_id: u32, special_card_index: u32); } @@ -22,14 +21,15 @@ mod errors { const CALLER_NOT_OWNER: felt252 = 'Game: caller not owner'; const INVALID_CARD_INDEX_LEN: felt252 = 'Game: invalid card index len'; const INVALID_CARD_ELEM: felt252 = 'Game: invalid card element'; - const ARRAY_REPEATED_ELEMENTS: felt252 = 'Game: array repeated elements'; const ONLY_EFFECT_CARD: felt252 = 'Game: only effect cards'; const GAME_NOT_IN_GAME: felt252 = 'Game: is not IN_GAME'; const GAME_NOT_SELECT_SPECIAL_CARDS: felt252 = 'Game:is not SELECT_SPECIAL_CARD'; - const GAME_NOT_SELECT_DECK: felt252 = 'Game:is not SELECT_DECK'; const GAME_NOT_SELECT_MODIFIER_CARDS: felt252 = 'Game:is not SELCT_MODIFIER_CARD'; + const GAME_NOT_SELECT_DECK: felt252 = 'Game:is not SELECT_DECK'; const USE_INVALID_CARD: felt252 = 'Game: use an invalid card'; const INVALID_DECK_ID: felt252 = 'Game: use an invalid deck'; + const WRONG_SUBSTATE_BEAST: felt252 = 'Game: wrong substate BEAST'; + const WRONG_SUBSTATE_CREATE_LEVEL: felt252 = 'Wrong substate CREATE_LEVEL'; } #[dojo::contract] @@ -56,10 +56,12 @@ mod game_system { }; use jokers_of_neon::models::data::game_deck::{GameDeckStore, GameDeckImpl}; use jokers_of_neon::models::data::poker_hand::{LevelPokerHand, PokerHand}; - use jokers_of_neon::models::status::game::game::{Game, GameState}; + use jokers_of_neon::models::status::game::game::{Game, GameState, GameSubState}; use jokers_of_neon::models::status::game::rage::{RageRound, RageRoundStore}; + use jokers_of_neon::models::status::round::beast::BeastTrait; + use jokers_of_neon::models::status::round::challenge::ChallengeTrait; use jokers_of_neon::models::status::round::current_hand_card::{CurrentHandCard, CurrentHandCardTrait}; - use jokers_of_neon::models::status::round::round::Round; + use jokers_of_neon::models::status::round::level::LevelTrait; use jokers_of_neon::models::status::shop::shop::{BlisterPackResult}; use jokers_of_neon::store::{Store, StoreTrait}; @@ -69,9 +71,9 @@ mod game_system { RAGE_CARD_DIMINISHED_HOLD, RAGE_CARD_SILENT_JOKERS, RAGE_CARD_SILENT_HEARTS, RAGE_CARD_SILENT_CLUBS, RAGE_CARD_SILENT_DIAMONDS, RAGE_CARD_SILENT_SPADES, RAGE_CARD_ZERO_WASTE, is_neon_card, is_modifier_card }; + use jokers_of_neon::utils::level::create_level; use jokers_of_neon::utils::packs::{open_blister_pack, select_cards_from_blister}; use jokers_of_neon::utils::rage::is_rage_card_active; - use jokers_of_neon::utils::round::create_round; use starknet::{ContractAddress, get_caller_address, ClassHash}; use super::IGameSystem; use super::errors; @@ -91,7 +93,6 @@ mod game_system { max_hands: 5, max_discard: 5, max_jokers: 5, - round: 1, player_score: 0, level: 1, len_hand: 8, @@ -99,6 +100,7 @@ mod game_system { len_current_special_cards: 0, current_jokers: 0, state: GameState::SELECT_DECK, + substate: GameSubState::CREATE_LEVEL, cash: 0 }; store.set_game(game); @@ -109,6 +111,61 @@ mod game_system { game_id } + fn create_level(ref world: IWorldDispatcher, game_id: u32) { + let mut store = StoreTrait::new(world); + let mut game = store.get_game(game_id); + + assert(game.owner.is_non_zero(), errors::GAME_NOT_FOUND); + assert(game.state == GameState::IN_GAME, errors::GAME_NOT_IN_GAME); + assert(game.substate == GameSubState::CREATE_LEVEL, errors::WRONG_SUBSTATE_CREATE_LEVEL); + + game.substate = LevelTrait::calculate(world, game_id); + match game.substate { + GameSubState::BEAST => { BeastTrait::create(world, ref store, game_id); }, + GameSubState::OBSTACLE => { ChallengeTrait::create(world, game_id); }, + GameSubState::CREATE_LEVEL => {}, + } + store.set_game(game); + } + + fn play(ref world: IWorldDispatcher, game_id: u32, cards_index: Array, modifiers_index: Array) { + let mut store: Store = StoreTrait::new(world); + + let game = store.get_game(game_id); + assert(game.owner.is_non_zero(), errors::GAME_NOT_FOUND); + assert(game.state == GameState::IN_GAME, errors::GAME_NOT_IN_GAME); + + match game.substate { + GameSubState::BEAST => { BeastTrait::play(world, game_id, cards_index, modifiers_index); }, + GameSubState::OBSTACLE => { ChallengeTrait::play(world, game_id, cards_index, modifiers_index); }, + GameSubState::CREATE_LEVEL => {}, + } + } + + fn discard(ref world: IWorldDispatcher, game_id: u32, cards_index: Array, modifiers_index: Array) { + let mut store: Store = StoreTrait::new(world); + + let game = store.get_game(game_id); + assert(game.owner.is_non_zero(), errors::GAME_NOT_FOUND); + assert(game.state == GameState::IN_GAME, errors::GAME_NOT_IN_GAME); + + match game.substate { + GameSubState::BEAST => { BeastTrait::discard(world, game_id, cards_index, modifiers_index); }, + GameSubState::OBSTACLE => { ChallengeTrait::discard(world, game_id, cards_index, modifiers_index); }, + GameSubState::CREATE_LEVEL => {}, + } + } + + fn end_turn(ref world: IWorldDispatcher, game_id: u32) { + let mut store: Store = StoreTrait::new(world); + + let game = store.get_game(game_id); + assert(game.owner.is_non_zero(), errors::GAME_NOT_FOUND); + assert(game.substate == GameSubState::BEAST, errors::WRONG_SUBSTATE_BEAST); + + BeastTrait::end_turn(world, game_id); + } + fn select_deck(ref world: IWorldDispatcher, game_id: u32, deck_id: u8) { let mut store: Store = StoreTrait::new(world); let mut game = store.get_game(game_id); @@ -152,11 +209,11 @@ mod game_system { blister_pack_result.cards_picked = true; store.set_blister_pack_result(blister_pack_result); - let cards = open_blister_pack(world, ref store, game, MODIFIER_CARDS_PACK_ID); - store.set_blister_pack_result(BlisterPackResult { game_id, cards_picked: false, cards }); - game.state = GameState::SELECT_MODIFIER_CARDS; store.set_game(game); + + let cards = open_blister_pack(world, ref store, game, MODIFIER_CARDS_PACK_ID); + store.set_blister_pack_result(BlisterPackResult { game_id, cards_picked: false, cards }); } fn select_modifier_cards(ref world: IWorldDispatcher, game_id: u32, cards_index: Array) { @@ -180,281 +237,29 @@ mod game_system { blister_pack_result.cards_picked = true; store.set_blister_pack_result(blister_pack_result); - // game.state = GameState::; / TODO: + game.state = GameState::IN_GAME; store.set_game(game); - } - - fn play(ref world: IWorldDispatcher, game_id: u32, cards_index: Array, modifiers_index: Array) { - let mut store: Store = StoreTrait::new(world); - - let mut game = store.get_game(game_id); - // Check that the game exists (if the game has no owner means it does not exists) - assert(game.owner.is_non_zero(), errors::GAME_NOT_FOUND); - - // Check that the owner of the game is the caller - assert(game.owner == get_caller_address(), errors::CALLER_NOT_OWNER); - - // Check that the status of the game - assert(game.state == GameState::IN_GAME, errors::GAME_NOT_IN_GAME); - - // Check that the length of card_index is between 1 and game.len_hand - assert(cards_index.len() > 0 && cards_index.len() <= game.len_hand, errors::INVALID_CARD_INDEX_LEN); - let rage_round = RageRoundStore::get(world, game_id); - - let mut current_special_cards_index = self.get_current_special_cards(ref store, @game); - - let (mut cards, effect_id_cards_1, effect_id_cards_2) = self - .get_cards(world, ref store, game.id, @cards_index, @modifiers_index, ref current_special_cards_index); - - let (result_hand, mut hit_cards) = calculate_hand(@cards, ref current_special_cards_index); - - let mut points_acum = 0; - let mut multi_acum = 0; - let mut cash_acum = 0; - - self - .apply_joker( - world, - game_id, - @cards_index, - ref current_special_cards_index, - @cards, - ref hit_cards, - ref points_acum, - ref multi_acum, - @rage_round - ); - - let silent_suits = self.get_silent_suits(@rage_round); - - self - .calculate_score( - world, @cards, ref hit_cards, @cards_index, ref points_acum, ref multi_acum, @silent_suits - ); - - self - .apply_modifiers( - world, - ref store, - ref hit_cards, - @cards_index, - ref current_special_cards_index, - @modifiers_index, - effect_id_cards_1, - effect_id_cards_2, - ref points_acum, - ref multi_acum - ); - - let mut round = store.get_round(game.id); - self - .apply_special_global( - world, @game, @round, ref current_special_cards_index, ref points_acum, ref multi_acum - ); - - self - .apply_special_every_card( - world, - game_id, - @cards_index, - ref current_special_cards_index, - @cards, - ref hit_cards, - ref points_acum, - ref multi_acum, - @silent_suits - ); - - self - .apply_special_level_hand( - world, - ref store, - game_id, - @round, - ref current_special_cards_index, - result_hand, - ref hit_cards, - @cards_index, - @cards, - ref points_acum, - ref multi_acum - ); - - self - .apply_cash_special( - world, ref current_special_cards_index, @cards, @cards_index, ref hit_cards, ref cash_acum - ); - - let mut round = store.get_round(game.id); - round.hands -= 1; - round.player_score += points_acum * multi_acum; - game.cash += cash_acum; - - store.set_round(round); - let round_score_event = RoundScoreEvent { - player: get_caller_address(), game_id, player_score: round.player_score - }; - emit!(world, (round_score_event)); - if round.player_score >= round.level_score { - let play_win_game_event = PlayWinGameEvent { - player: get_caller_address(), game_id, level: game.level, player_score: round.player_score - }; - emit!(world, (play_win_game_event)); - game.cash += self.calculate_earning_cash(world, ref store, round, game); - game.state = GameState::AT_SHOP; - game.player_score += round.player_score; - self.sync_current_special_cards(ref store, ref game); - - if is_rage_card_active(@rage_round, RAGE_CARD_DIMINISHED_HOLD) { - // return the cards to the deck - game.len_hand += 2; - } - let (_, rage_system_address) = match world.resource(selector_from_tag!("jokers_of_neon-rage_system")) { - Contract((class_hash, contract_address)) => Option::Some((class_hash, contract_address)), - _ => Option::None - }.unwrap(); - IRageSystemDispatcher { contract_address: rage_system_address.try_into().unwrap() }.calculate(game_id); - } else { - // The player ran out of hands - if round.hands == 0 { - let play_game_over_event = PlayGameOverEvent { player: get_caller_address(), game_id }; - emit!(world, (play_game_over_event)); - game.state = GameState::FINISHED; - game.player_score += round.player_score; - } else { - let mut cards = array![]; - let mut idx = 0; - loop { - if idx == cards_index.len() { - break; - } - cards.append(*cards_index.at(idx)); - idx += 1; - }; - - idx = 0; - loop { - if idx == modifiers_index.len() { - break; - } - let card_index = *modifiers_index.at(idx); - if card_index != 100 { - cards.append(card_index); - } - idx += 1; - }; - CurrentHandCardTrait::refresh(world, ref round, cards); - - // The player has no more cards in his hand and in the deck - let game_deck = GameDeckStore::get(world, game_id); - if game_deck.round_len.is_zero() && self.player_has_empty_hand(ref store, @game) { - let play_game_over_event = PlayGameOverEvent { player: get_caller_address(), game_id }; - emit!(world, (play_game_over_event)); - game.state = GameState::FINISHED; - game.player_score += round.player_score; - } - } - } - store.set_game(game); - - // Track PlayPokerHand - emit!( - world, - (PlayPokerHandEvent { - game_id, level: game.level, count_hand: game.max_hands - round.hands, poker_hand: result_hand - }) - ); - } - - fn discard(ref world: IWorldDispatcher, game_id: u32, cards_index: Array, modifiers_index: Array) { - let mut store: Store = StoreTrait::new(world); - let mut game = store.get_game(game_id); - - assert(game.owner.is_non_zero(), errors::GAME_NOT_FOUND); - assert(game.owner == get_caller_address(), errors::CALLER_NOT_OWNER); - assert(game.state == GameState::IN_GAME, errors::GAME_NOT_IN_GAME); - - let mut cards = array![]; - let mut idx = 0; - loop { - if idx == cards_index.len() { - break; - } - let current_hand_card = store.get_current_hand_card(game_id, *cards_index.at(idx)); - assert(current_hand_card.card_id != INVALID_CARD, errors::USE_INVALID_CARD); - - cards.append(*cards_index.at(idx)); - idx += 1; - }; - - idx = 0; - loop { - if idx == modifiers_index.len() { - break; - } - let card_index = *modifiers_index.at(idx); - if card_index != 100 { - cards.append(card_index); - } - idx += 1; - }; - - let mut round = store.get_round(game.id); - CurrentHandCardTrait::refresh(world, ref round, cards); - - // The player has no more cards in his hand and in the deck - round.discard -= 1; - store.set_round(round); - - let game_deck = GameDeckStore::get(world, game_id); - if game_deck.round_len.is_zero() && self.player_has_empty_hand(ref store, @game) { - let play_game_over_event = PlayGameOverEvent { player: get_caller_address(), game_id: game.id }; - emit!(world, (play_game_over_event)); - game.state = GameState::FINISHED; - store.set_game(game); - } - } - - fn check_hand( - ref world: IWorldDispatcher, game_id: u32, cards_index: Array, modifiers_index: Array - ) -> PokerHand { - let mut store: Store = StoreTrait::new(world); - - let mut game = store.get_game(game_id); - let mut current_special_cards_index = self.get_current_special_cards(ref store, @game); - - let (cards, _, _) = self - .get_cards(world, ref store, game_id, @cards_index, @modifiers_index, ref current_special_cards_index,); - let (poker_hand, _) = calculate_hand(@cards, ref current_special_cards_index); - - let poker_hand_details = store.get_level_poker_hand(poker_hand, 1); - let poker_hand_event = PokerHandEvent { - player: get_caller_address(), - poker_hand: poker_hand.into(), - multi: poker_hand_details.multi, - points: poker_hand_details.points - }; - emit!(world, (poker_hand_event)); - poker_hand + create_level(world, ref store, game); } fn discard_effect_card(ref world: IWorldDispatcher, game_id: u32, card_index: u32) { let mut store: Store = StoreTrait::new(world); let game = store.get_game(game_id); + assert(game.state == GameState::IN_GAME, errors::GAME_NOT_IN_GAME); assert(game.owner.is_non_zero(), errors::GAME_NOT_FOUND); assert(game.owner == get_caller_address(), errors::CALLER_NOT_OWNER); assert(card_index >= 0 && card_index < game.len_hand, errors::INVALID_CARD_ELEM); let current_hand_card = store.get_current_hand_card(game_id, card_index); assert(is_modifier_card(current_hand_card.card_id), errors::ONLY_EFFECT_CARD); - let mut round = store.get_round(game.id); - CurrentHandCardTrait::refresh(world, ref round, array![card_index]); + CurrentHandCardTrait::refresh(world, game.id, array![card_index]); } fn discard_special_card(ref world: IWorldDispatcher, game_id: u32, special_card_index: u32) { let mut store: Store = StoreTrait::new(world); let mut game = store.get_game(game_id); + assert(game.state == GameState::IN_GAME, errors::GAME_NOT_IN_GAME); assert(game.owner.is_non_zero(), errors::GAME_NOT_FOUND); assert(game.owner == get_caller_address(), errors::CALLER_NOT_OWNER); assert(special_card_index < game.len_current_special_cards, errors::INVALID_CARD_ELEM); @@ -499,840 +304,4 @@ mod game_system { store.set_game(game); } } - - #[generate_trait] - impl InternalImpl of InternalTrait { - fn player_has_empty_hand(self: @ContractState, ref store: Store, game: @Game) -> bool { - let mut i = 0; - loop { - if game.len_hand == @i { - break true; - } - let deck_card = store.get_current_hand_card(*game.id, i); - if deck_card.card_id != INVALID_CARD { - break false; - } - i += 1; - } - } - - fn has_repeated_elements(self: @ContractState, array: @Array) -> bool { - let mut array_span = array.span(); - let mut elements = array![]; - - let repeated_elements = loop { - match array_span.pop_front() { - Option::Some(new_elem) => { - let mut elements_span = elements.span(); - let result = loop { - match elements_span.pop_front() { - Option::Some(seen_elem) => { if *seen_elem == *new_elem { - break true; - } }, - Option::None => { break false; } - }; - }; - if result { - break result; - } - elements.append(*new_elem); - }, - Option::None => { break false; } - }; - }; - repeated_elements - } - - fn get_current_special_cards( - self: @ContractState, ref store: Store, game: @Game - ) -> Felt252Dict> { - let mut current_special_cards_index: Felt252Dict> = Default::default(); - let mut idx = 0; - loop { - if idx == *game.len_current_special_cards { - break; - } - let current_special_card = store.get_current_special_cards(*game.id, idx); - current_special_cards_index.insert(current_special_card.effect_card_id.into(), NullableTrait::new(idx)); - idx += 1; - }; - current_special_cards_index - } - - fn get_cards( - self: @ContractState, - world: IWorldDispatcher, - ref store: Store, - game_id: u32, - cards_index: @Array, - modifiers_index: @Array, - ref current_special_cards_index: Felt252Dict> - ) -> (Array, Array, Array) { - assert(!self.has_repeated_elements(cards_index), errors::ARRAY_REPEATED_ELEMENTS); - let mut cards = array![]; - let mut effect_id_cards_1 = array![]; - let mut effect_id_cards_2 = array![]; - let mut idx = 0; - loop { - if idx == cards_index.len() { - break; - } - - let current_hand_card = store.get_current_hand_card(game_id, *cards_index.at(idx)); - assert(current_hand_card.card_id != INVALID_CARD, errors::USE_INVALID_CARD); - - let mut card = store.get_card(current_hand_card.card_id); - - let modifier_1_index = *modifiers_index.at(idx); - if modifier_1_index != 100 { // TODO: Invalid - let current_hand_modifier_card = store.get_current_hand_card(game_id, modifier_1_index); - let effect_card = store.get_effect_card(current_hand_modifier_card.card_id); - effect_id_cards_1.append(effect_card.effect_id); - let effect = store.get_effect(effect_card.effect_id); - if effect.suit != Suit::None && card.suit != Suit::Joker { - card.suit = effect.suit; - emit!( - world, - ModifierCardSuitEvent { - player: get_caller_address(), - game_id, - modifier_card_idx: *modifiers_index.at(idx), - current_hand_card_idx: *cards_index.at(idx), - suit: card.suit - } - ); - } - } else { - effect_id_cards_1.append(100); - } - - if !(current_special_cards_index.get(SPECIAL_ALL_CARDS_TO_HEARTS_ID.into()).is_null()) { - if card.suit != Suit::Joker { - card.suit = Suit::Hearts; - emit!( - world, - SpecialModifierSuitEvent { - player: get_caller_address(), - game_id, - current_special_card_idx: current_special_cards_index - .get(SPECIAL_ALL_CARDS_TO_HEARTS_ID.into()) - .deref(), - current_hand_card_idx: *cards_index.at(idx), - suit: card.suit - } - ); - } - } - - cards.append(card); - idx += 1; - }; - (cards, effect_id_cards_1, effect_id_cards_2) - } - - /// Checks if all the cards in the poker hand are neon cards, in which case it will return the card indexes. - /// Returns an empty array in case the hand is not a neon hand. - /// - /// # Arguments - /// hit_cards: A dictionary with the indexes of the cards that are part of the hand. - /// cards_index: The indexes of the cards that are part of the hand. - /// cards: The array of cards that were played. - /// - /// # Returns - /// An array of the cards indexes that are part of the neon hand. - fn get_neon_hand_card_index( - self: @ContractState, ref hit_cards: Felt252Dict, cards_index: @Array, cards: @Array, - ) -> Array { - let mut idx = 0; - let mut is_neon_hand = true; - let mut neon_idx = array![]; - loop { - if cards.len() == idx { - break; - } - let hit = hit_cards.get(idx.into()); - if hit { - if !is_neon_card(*cards.at(idx).id) { - is_neon_hand = false; - break; - } - neon_idx.append(*cards_index.at(idx)); - } - idx += 1; - }; - - let result = if is_neon_hand { - neon_idx - } else { - array![] - }; - result - } - - fn calculate_score( - self: @ContractState, - world: IWorldDispatcher, - cards: @Array, - ref hit_cards: Felt252Dict, - cards_index: @Array, - ref points_acum: u32, - ref multi_acum: u32, - silent_suits: @Array - ) { - let mut idx = 0; - loop { - if cards.len() == idx { - break; - } - let hit = hit_cards.get(idx.into()); - if hit { - let card = *cards.at(idx); - let suit_is_silence = self.contains_suit(silent_suits, card.suit); - if suit_is_silence { // Emitir evento de Rage Card Silent Suit - } else { - points_acum += card.points.into(); - multi_acum += card.multi_add.into(); - if card.points > 0 { - emit!( - world, - (CardScoreEvent { - player: get_caller_address(), - index: *cards_index.at(idx), - multi: 0, - points: card.points.into() - }) - ); - } - if card.multi_add > 0 { - emit!( - world, - (CardScoreEvent { - player: get_caller_address(), - index: *cards_index.at(idx), - multi: card.multi_add, - points: 0 - }) - ); - } - }; - } - idx += 1; - } - } - - fn apply_joker( - self: @ContractState, - world: IWorldDispatcher, - game_id: u32, - cards_index: @Array, - ref current_special_cards_index: Felt252Dict>, - cards: @Array, - ref hit_cards: Felt252Dict, - ref points_acum: u32, - ref multi_acum: u32, - rage_round: @RageRound - ) { - let mut idx = 0; - loop { - if cards.len() == idx { - break; - } - let card = *cards.at(idx); - if card.suit == Suit::Joker { - if is_rage_card_active(rage_round, RAGE_CARD_SILENT_JOKERS) { // Emitir evento - hit_cards.insert(idx.into(), false); - } else { - if !(current_special_cards_index.get(SPECIAL_JOKER_BOOSTER_ID.into()).is_null()) { - points_acum += card.points; - multi_acum += card.multi_add; - emit!( - world, - SpecialModifierPointsEvent { - player: get_caller_address(), - game_id, - current_special_card_idx: current_special_cards_index - .get(SPECIAL_JOKER_BOOSTER_ID.into()) - .deref(), - current_hand_card_idx: *cards_index.at(idx), - points: card.points - } - ); - emit!( - world, - SpecialModifierMultiEvent { - player: get_caller_address(), - game_id, - current_special_card_idx: current_special_cards_index - .get(SPECIAL_JOKER_BOOSTER_ID.into()) - .deref(), - current_hand_card_idx: *cards_index.at(idx), - multi: card.multi_add - } - ); - } - hit_cards.insert(idx.into(), true); - } - } - idx += 1; - }; - } - - fn calculate_earning_cash( - self: @ContractState, world: IWorldDispatcher, ref store: Store, round: Round, game: Game - ) -> u32 { - let config = store.get_config_earning_cash(); - - let hands_left: u32 = (round.hands).into(); - let mut discard_left: u32 = (round.discard).into(); - let level_bonus = 500; - - let rage_round = RageRoundStore::get(world, game.id); - let mut rage_card_defeated = 0; - if rage_round.is_active { - rage_card_defeated = rage_round.active_rage_ids.len(); - if is_rage_card_active(@rage_round, RAGE_CARD_ZERO_WASTE) { - discard_left = game.max_discard.into(); - } - } - - let total = config.base * 100 - + level_bonus - + hands_left * 150 - + discard_left * 150 - + rage_card_defeated * 500; - - let detail_earned = DetailEarnedEvent { - player: game.owner, - game_id: game.id, - round_defeat: config.base * 100, - level_bonus, - hands_left, - hands_left_cash: hands_left * 150, - discard_left, - discard_left_cash: discard_left * 150, - rage_card_defeated, - rage_card_defeated_cash: rage_card_defeated * 500, - total - }; - emit!(world, (detail_earned)); - total - } - - fn apply_modifiers( - self: @ContractState, - world: IWorldDispatcher, - ref store: Store, - ref hit_cards: Felt252Dict, - cards_index: @Array, - ref current_special_cards_index: Felt252Dict>, - modifiers_index: @Array, - effect_id_cards_1: Array, - effect_id_cards_2: Array, - ref points_acum: u32, - ref multi_acum: u32 - ) { - let mut idx = 0; - loop { - if cards_index.len() == idx { - break; - } - let hit = hit_cards.get(idx.into()); - if hit { - let effect_card_id_1 = *effect_id_cards_1.at(idx); - if effect_card_id_1 != 100 { // TODO: Invalid - let effect = store.get_effect(effect_card_id_1); - if effect.suit == Suit::None { - let (points, multi_add) = if !(current_special_cards_index - .get(SPECIAL_MODIFIER_BOOSTER_ID.into()) - .is_null()) { - (effect.points * 2, effect.multi_add * 2) - } else { - (effect.points, effect.multi_add) - }; - points_acum += points; - multi_acum += multi_add; - emit!( - world, - (CardScoreEvent { - player: get_caller_address(), - index: *modifiers_index.at(idx), - multi: multi_add, - points - }) - ); - } - } - } - idx += 1; - }; - } - - fn apply_special_global( - self: @ContractState, - world: IWorldDispatcher, - game: @Game, - round: @Round, - ref current_special_cards_index: Felt252Dict>, - ref points_acum: u32, - ref multi_acum: u32 - ) { - let mut store = StoreTrait::new(world); - if !(current_special_cards_index.get(SPECIAL_INITIAL_ADVANTAGE_ID.into()).is_null()) { - // first hand - if *game.max_hands == *round.hands { - let effect_card = store.get_effect_card(SPECIAL_INITIAL_ADVANTAGE_ID); - let effect = store.get_effect(effect_card.effect_id); - points_acum += effect.points; - multi_acum += effect.multi_add; - emit!( - world, - SpecialGlobalEvent { - player: get_caller_address(), - game_id: *game.id, - current_special_card_idx: current_special_cards_index - .get(SPECIAL_INITIAL_ADVANTAGE_ID.into()) - .deref(), - multi: effect.multi_add, - points: effect.points - } - ); - } - } - } - - fn apply_special_every_card( - self: @ContractState, - world: IWorldDispatcher, - game_id: u32, - cards_index: @Array, - ref current_special_cards_index: Felt252Dict>, - cards: @Array, - ref hit_cards: Felt252Dict, - ref points_acum: u32, - ref multi_acum: u32, - silent_suits: @Array - ) { - let mut idx = 0; - let mut store = StoreTrait::new(world); - loop { - if idx == cards.len() { - break; - } - - let hit = hit_cards.get(idx.into()); - let mut card = *cards.at(idx); - if hit { - let suit_is_silence = self.contains_suit(silent_suits, card.suit); - if !(current_special_cards_index.get(SPECIAL_MULTI_FOR_HEART_ID.into()).is_null()) { - if card.suit == Suit::Hearts && !suit_is_silence { - let effect_card = store.get_effect_card(SPECIAL_MULTI_FOR_HEART_ID); - let effect = store.get_effect(effect_card.effect_id); - multi_acum += effect.multi_add; - emit!( - world, - SpecialModifierMultiEvent { - player: get_caller_address(), - game_id, - current_special_card_idx: current_special_cards_index - .get(SPECIAL_MULTI_FOR_HEART_ID.into()) - .deref(), - current_hand_card_idx: *cards_index.at(idx), - multi: effect.multi_add - } - ); - } - } - - if !(current_special_cards_index.get(SPECIAL_MULTI_FOR_DIAMOND_ID.into()).is_null()) { - if card.suit == Suit::Diamonds && !suit_is_silence { - let effect_card = store.get_effect_card(SPECIAL_MULTI_FOR_DIAMOND_ID); - let effect = store.get_effect(effect_card.effect_id); - multi_acum += effect.multi_add; - emit!( - world, - SpecialModifierMultiEvent { - player: get_caller_address(), - game_id, - current_special_card_idx: current_special_cards_index - .get(SPECIAL_MULTI_FOR_DIAMOND_ID.into()) - .deref(), - current_hand_card_idx: *cards_index.at(idx), - multi: effect.multi_add - } - ); - } - } - - if !(current_special_cards_index.get(SPECIAL_MULTI_FOR_CLUB_ID.into()).is_null()) { - if card.suit == Suit::Clubs && !suit_is_silence { - let effect_card = store.get_effect_card(SPECIAL_MULTI_FOR_CLUB_ID); - let effect = store.get_effect(effect_card.effect_id); - multi_acum += effect.multi_add; - emit!( - world, - SpecialModifierMultiEvent { - player: get_caller_address(), - game_id, - current_special_card_idx: current_special_cards_index - .get(SPECIAL_MULTI_FOR_CLUB_ID.into()) - .deref(), - current_hand_card_idx: *cards_index.at(idx), - multi: effect.multi_add - } - ); - } - } - - if !(current_special_cards_index.get(SPECIAL_MULTI_FOR_SPADE_ID.into()).is_null()) { - if card.suit == Suit::Spades && !suit_is_silence { - let effect_card = store.get_effect_card(SPECIAL_MULTI_FOR_SPADE_ID); - let effect = store.get_effect(effect_card.effect_id); - multi_acum += effect.multi_add; - emit!( - world, - SpecialModifierMultiEvent { - player: get_caller_address(), - game_id, - current_special_card_idx: current_special_cards_index - .get(SPECIAL_MULTI_FOR_SPADE_ID.into()) - .deref(), - current_hand_card_idx: *cards_index.at(idx), - multi: effect.multi_add - } - ); - } - } - - if !(current_special_cards_index.get(SPECIAL_POINTS_FOR_FIGURES_ID.into()).is_null()) { - if (card.value == Value::Jack || card.value == Value::Queen || card.value == Value::King) - && !suit_is_silence { - points_acum += 50; - emit!( - world, - SpecialModifierPointsEvent { - player: get_caller_address(), - game_id, - current_special_card_idx: current_special_cards_index - .get(SPECIAL_POINTS_FOR_FIGURES_ID.into()) - .deref(), - current_hand_card_idx: *cards_index.at(idx), - points: 50 - } - ); - } - } - - if !(current_special_cards_index.get(SPECIAL_MULTI_ACES_ID.into()).is_null()) { - if card.value == Value::Ace && !suit_is_silence { - let effect_card = store.get_effect_card(SPECIAL_MULTI_ACES_ID); - let effect = store.get_effect(effect_card.effect_id); - multi_acum += effect.multi_add; - emit!( - world, - SpecialModifierMultiEvent { - player: get_caller_address(), - game_id, - current_special_card_idx: current_special_cards_index - .get(SPECIAL_MULTI_ACES_ID.into()) - .deref(), - current_hand_card_idx: *cards_index.at(idx), - multi: effect.multi_add - } - ); - } - } - - if !(current_special_cards_index.get(SPECIAL_LUCKY_SEVEN_ID.into()).is_null()) { - if card.value == Value::Seven && !suit_is_silence { - let effect_card = store.get_effect_card(SPECIAL_LUCKY_SEVEN_ID); - let effect = store.get_effect(effect_card.effect_id); - points_acum += effect.points; - emit!( - world, - SpecialModifierPointsEvent { - player: get_caller_address(), - game_id, - current_special_card_idx: current_special_cards_index - .get(SPECIAL_LUCKY_SEVEN_ID.into()) - .deref(), - current_hand_card_idx: *cards_index.at(idx), - points: effect.points - } - ); - } - } - - if !(current_special_cards_index.get(SPECIAL_NEON_BONUS_ID.into()).is_null()) { - if is_neon_card(card.id) && !suit_is_silence { - let effect_card = store.get_effect_card(SPECIAL_NEON_BONUS_ID); - let effect = store.get_effect(effect_card.effect_id); - points_acum += effect.points; - emit!( - world, - SpecialModifierPointsEvent { - player: get_caller_address(), - game_id, - current_special_card_idx: current_special_cards_index - .get(SPECIAL_NEON_BONUS_ID.into()) - .deref(), - current_hand_card_idx: *cards_index.at(idx), - points: effect.points - } - ); - } - } - }; - idx += 1; - } - } - - fn apply_special_level_hand( - self: @ContractState, - world: IWorldDispatcher, - ref store: Store, - game_id: u32, - round: @Round, - ref current_special_cards_index: Felt252Dict>, - poker_hand: PokerHand, - ref hit_cards: Felt252Dict, - cards_index: @Array, - cards: @Array, - ref points_acum: u32, - ref multi_acum: u32 - ) { - let mut level_acum = 1; - if !(current_special_cards_index.get(SPECIAL_INCREASE_LEVEL_PAIR_ID.into()).is_null()) { - if poker_hand == PokerHand::OnePair { - level_acum += 4; - let level_poker_hand = store.get_level_poker_hand(poker_hand, level_acum); - emit!( - world, - SpecialPokerHandEvent { - player: get_caller_address(), - game_id, - current_special_card_idx: current_special_cards_index - .get(SPECIAL_INCREASE_LEVEL_PAIR_ID.into()) - .deref(), - multi: level_poker_hand.multi, - points: level_poker_hand.points - } - ); - } - } - if !(current_special_cards_index.get(SPECIAL_INCREASE_LEVEL_DOUBLE_PAIR_ID.into()).is_null()) { - if poker_hand == PokerHand::TwoPair { - level_acum += 4; - let level_poker_hand = store.get_level_poker_hand(poker_hand, level_acum); - emit!( - world, - SpecialPokerHandEvent { - player: get_caller_address(), - game_id, - current_special_card_idx: current_special_cards_index - .get(SPECIAL_INCREASE_LEVEL_DOUBLE_PAIR_ID.into()) - .deref(), - multi: level_poker_hand.multi, - points: level_poker_hand.points - } - ); - } - } - if !(current_special_cards_index.get(SPECIAL_INCREASE_LEVEL_STRAIGHT_ID.into()).is_null()) { - if poker_hand == PokerHand::Straight { - level_acum += 4; - let level_poker_hand = store.get_level_poker_hand(poker_hand, level_acum); - emit!( - world, - SpecialPokerHandEvent { - player: get_caller_address(), - game_id, - current_special_card_idx: current_special_cards_index - .get(SPECIAL_INCREASE_LEVEL_STRAIGHT_ID.into()) - .deref(), - multi: level_poker_hand.multi, - points: level_poker_hand.points - } - ); - } - } - if !(current_special_cards_index.get(SPECIAL_INCREASE_LEVEL_FLUSH_ID.into()).is_null()) { - if poker_hand == PokerHand::Flush { - level_acum += 4; - let level_poker_hand = store.get_level_poker_hand(poker_hand, level_acum); - emit!( - world, - SpecialPokerHandEvent { - player: get_caller_address(), - game_id, - current_special_card_idx: current_special_cards_index - .get(SPECIAL_INCREASE_LEVEL_FLUSH_ID.into()) - .deref(), - multi: level_poker_hand.multi, - points: level_poker_hand.points - } - ); - } - } - if !(current_special_cards_index.get(SPECIAL_DEADLINE_ID.into()).is_null()) { - if *round.hands == 1 { - level_acum += 10; - let level_poker_hand = store.get_level_poker_hand(poker_hand, level_acum); - emit!( - world, - SpecialPokerHandEvent { - player: get_caller_address(), - game_id, - current_special_card_idx: current_special_cards_index - .get(SPECIAL_DEADLINE_ID.into()) - .deref(), - multi: level_poker_hand.multi, - points: level_poker_hand.points - } - ); - } - } - - let neon_idx = self.get_neon_hand_card_index(ref hit_cards, cards_index, cards); - if neon_idx.len() > 0 { - level_acum += 4; - let level_poker_hand = store.get_level_poker_hand(poker_hand, level_acum); - - emit!( - world, - NeonPokerHandEvent { - player: get_caller_address(), - game_id, - neon_cards_idx: neon_idx, - multi: level_poker_hand.multi, - points: level_poker_hand.points - } - ); - } - - let level_poker_hand = store.get_level_poker_hand(poker_hand, level_acum); - points_acum += level_poker_hand.points; - multi_acum += level_poker_hand.multi; - } - - fn apply_cash_special( - self: @ContractState, - world: IWorldDispatcher, - ref current_special_cards_index: Felt252Dict>, - cards: @Array, - cards_index: @Array, - ref hit_cards: Felt252Dict, - ref cash_acum: u32, - ) { - if current_special_cards_index.get(SPECIAL_LUCKY_HAND_ID.into()).is_null() { - return; - } - - let mut idx = 0; - loop { - if idx == cards.len() { - break; - } - - let hit = hit_cards.get(idx.into()); - let mut card = *cards.at(idx); - if hit { - if card.suit == Suit::Diamonds { - cash_acum += 50; - emit!( - world, - SpecialCashEvent { - player: get_caller_address(), - cash: 50, - card_idx: *cards_index.at(idx), - special_idx: current_special_cards_index.get(SPECIAL_LUCKY_HAND_ID.into()).deref() - } - ); - } - } - idx += 1; - } - } - - fn sync_current_special_cards(self: @ContractState, ref store: Store, ref game: Game) { - let mut idx = 0; - - let mut new_current_special_cards = array![]; - let mut len_current_special_cards = game.len_current_special_cards; - loop { - if idx == len_current_special_cards { - break; - } - let mut current_special_card = store.get_current_special_cards(game.id, idx); - if current_special_card.is_temporary { - current_special_card.remaining -= 1; - if current_special_card.remaining > 0 { - new_current_special_cards.append(current_special_card); - } else { - game.len_current_special_cards -= 1; - - if current_special_card.effect_card_id == SPECIAL_HAND_THIEF_ID { - game.max_hands -= 1; - game.max_discard -= 1; - } - if current_special_card.effect_card_id == SPECIAL_EXTRA_HELP_ID { - game.len_hand -= 2; - } - } - } else { - new_current_special_cards.append(current_special_card); - } - idx += 1; - }; - - idx = 0; - loop { - if idx == game.len_current_special_cards { - break; - } - let mut new_current_special_card = *new_current_special_cards.at(idx); - new_current_special_card.idx = idx; - store.set_current_special_cards(new_current_special_card); - idx += 1; - } - } - - fn get_silent_suits(self: @ContractState, rage_round: @RageRound) -> Array { - let mut silent_suits = array![]; - if *rage_round.is_active { - let mut active_rages = (*rage_round.active_rage_ids).clone(); - loop { - match active_rages.pop_front() { - Option::Some(rage_id) => { - if *rage_id == RAGE_CARD_SILENT_HEARTS { - silent_suits.append(Suit::Hearts); - } else if *rage_id == RAGE_CARD_SILENT_CLUBS { - silent_suits.append(Suit::Clubs); - } else if *rage_id == RAGE_CARD_SILENT_DIAMONDS { - silent_suits.append(Suit::Diamonds); - } else if *rage_id == RAGE_CARD_SILENT_SPADES { - silent_suits.append(Suit::Spades); - } - }, - Option::None => { break Suit::None; } - } - }; - } - silent_suits - } - - fn contains_suit(self: @ContractState, suits: @Array, suit: Suit) -> bool { - let mut idx = 0; - loop { - if suits.len() == idx { - break false; - } - - if *suits[idx] == suit { - break true; - } - - idx += 1; - } - } - } } diff --git a/src/systems/rage_system.cairo b/src/systems/rage_system.cairo index dc6d985..33dbe3d 100644 --- a/src/systems/rage_system.cairo +++ b/src/systems/rage_system.cairo @@ -26,7 +26,7 @@ trait IRageSystem { #[dojo::contract] mod rage_system { - use jokers_of_neon::models::status::{game::{game::GameStore, rage::RageRoundStore}, round::round::RoundStore}; + use jokers_of_neon::models::status::{game::{game::GameStore, rage::RageRoundStore}}; use jokers_of_neon::store::StoreTrait; use jokers_of_neon::utils::constants::rage_cards_all; use jokers_of_neon::utils::random::RandomImpl; diff --git a/src/tests/setup.cairo b/src/tests/setup.cairo index a313e6f..6161257 100644 --- a/src/tests/setup.cairo +++ b/src/tests/setup.cairo @@ -2,15 +2,14 @@ mod setup { use dojo::utils::test::{spawn_test_world, deploy_contract}; use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait}; + use jokers_of_neon::models::data::beast::{game_mode_beast, beast, player_beast}; + use jokers_of_neon::models::data::challenge::{challenge, challenge_player}; use jokers_of_neon::models::data::game_deck::{game_deck, deck_card}; - use jokers_of_neon::models::status::game::game::{game, current_special_cards}; use jokers_of_neon::models::status::game::rage::rage_round; use jokers_of_neon::models::status::round::current_hand_card::current_hand_card; - use jokers_of_neon::models::status::round::round::round; use jokers_of_neon::models::status::shop::shop::{card_item, blister_pack_item, blister_pack_result}; - use jokers_of_neon::systems::game_system::{game_system, IGameSystemDispatcher, IGameSystemDispatcherTrait}; use jokers_of_neon::systems::rage_system::{rage_system, IRageSystemDispatcher, IRageSystemDispatcherTrait}; use starknet::ContractAddress; @@ -33,9 +32,10 @@ mod setup { fn spawn_game() -> (IWorldDispatcher, Systems) { let mut models = array![ + challenge::TEST_CLASS_HASH, + challenge_player::TEST_CLASS_HASH, game::TEST_CLASS_HASH, current_special_cards::TEST_CLASS_HASH, - round::TEST_CLASS_HASH, current_hand_card::TEST_CLASS_HASH, game_deck::TEST_CLASS_HASH, deck_card::TEST_CLASS_HASH, @@ -43,6 +43,9 @@ mod setup { blister_pack_item::TEST_CLASS_HASH, blister_pack_result::TEST_CLASS_HASH, rage_round::TEST_CLASS_HASH, + game_mode_beast::TEST_CLASS_HASH, + beast::TEST_CLASS_HASH, + player_beast::TEST_CLASS_HASH, ]; let world = spawn_test_world(array!["jokers_of_neon"].span(), models.span()); let systems = Systems { diff --git a/src/tests/test_calculate_level_score.cairo b/src/tests/test_calculate_level_score.cairo deleted file mode 100644 index 50ddfa5..0000000 --- a/src/tests/test_calculate_level_score.cairo +++ /dev/null @@ -1,36 +0,0 @@ -use jokers_of_neon::utils::round::calculate_level_score; - -#[test] -#[available_gas(300000000000)] -fn test_calculate_level_score_two_level() { - let level_score = calculate_level_score(level: 2); - assert(level_score == 600, 'error level_score'); -} - -#[test] -#[available_gas(300000000000)] -fn test_calculate_level_score_ten_level() { - let level_score = calculate_level_score(level: 10); - assert(level_score == 5400, 'error level_score'); -} - -#[test] -#[available_gas(300000000000)] -fn test_calculate_level_score_twenty_level() { - let level_score = calculate_level_score(level: 20); - assert(level_score == 17400, 'error level_score'); -} - -#[test] -#[available_gas(300000000000)] -fn test_calculate_level_score_twenty_five_level() { - let level_score = calculate_level_score(level: 25); - assert(level_score == 32400, 'error level_score'); -} - -#[test] -#[available_gas(300000000000)] -fn test_calculate_level_score_thirty_level() { - let level_score = calculate_level_score(level: 30); - assert(level_score == 67400, 'error level_score'); -} diff --git a/src/tests/test_challenge.cairo b/src/tests/test_challenge.cairo new file mode 100644 index 0000000..0e4dd32 --- /dev/null +++ b/src/tests/test_challenge.cairo @@ -0,0 +1,51 @@ +mod test_challenge { + use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait}; + use jokers_of_neon::constants::{ + challenge::{CHALLENGE_STRAIGHT, CHALLENGE_CLUBS, CHALLENGE_HEARTS, CHALLENGE_TEN}, + card::{SIX_CLUBS_ID, SEVEN_CLUBS_ID, EIGHT_CLUBS_ID, NINE_HEARTS_ID, TEN_CLUBS_ID} + }; + use jokers_of_neon::models::data::challenge::{Challenge, ChallengeStore, ChallengePlayer, ChallengePlayerStore}; + + use jokers_of_neon::models::status::game::game::{Game, GameState, GameSubState, GameStore}; + use jokers_of_neon::models::status::round::challenge::ChallengeImpl; + use jokers_of_neon::store::{Store, StoreTrait}; + use jokers_of_neon::systems::game_system::{game_system, IGameSystemDispatcher, IGameSystemDispatcherTrait}; + use jokers_of_neon::tests::setup::{ + setup, setup::OWNER, setup::IDojoInitDispatcher, setup::IDojoInitDispatcherTrait + }; + use jokers_of_neon::tests::utils::{mock_current_hand_cards_ids, mock_game}; + + use starknet::testing::set_contract_address; + + fn PLAYER() -> starknet::ContractAddress { + starknet::contract_address_const::<'PLAYER'>() + } + + #[test] + #[available_gas(30000000000000000)] + fn test_complete_all_challenges() { + let (world, systems) = setup::spawn_game(); + let mut store = StoreTrait::new(world); + let mut game = mock_game(ref store, PLAYER()); + game.state = GameState::IN_GAME; + game.substate = GameSubState::OBSTACLE; + store.set_game(game); + + // Mock hand + let hand_cards_ids = array![SIX_CLUBS_ID, SEVEN_CLUBS_ID, EIGHT_CLUBS_ID, NINE_HEARTS_ID, TEN_CLUBS_ID]; + mock_current_hand_cards_ids(ref store, game.id, hand_cards_ids); + + ChallengeStore::set( + @Challenge { + game_id: game.id, + active_ids: array![CHALLENGE_STRAIGHT, CHALLENGE_CLUBS, CHALLENGE_HEARTS, CHALLENGE_TEN].span() + }, + world + ); + + ChallengePlayerStore::set(@ChallengePlayer { game_id: game.id, discards: 5, plays: 5 }, world); + + set_contract_address(PLAYER()); + systems.game_system.play(game.id, array![0, 1, 2, 3, 4], array![100, 100, 100, 100, 100]); + } +} diff --git a/src/tests/test_game_discard_beast.cairo b/src/tests/test_game_discard_beast.cairo new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/tests/test_game_discard_beast.cairo @@ -0,0 +1 @@ + diff --git a/src/tests/test_game_end_turn.cairo b/src/tests/test_game_end_turn.cairo new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/tests/test_game_end_turn.cairo @@ -0,0 +1 @@ + diff --git a/src/tests/test_game_play.cairo b/src/tests/test_game_play.cairo index 2eb2e5d..eb0e0d6 100644 --- a/src/tests/test_game_play.cairo +++ b/src/tests/test_game_play.cairo @@ -649,7 +649,7 @@ mod test_rage_cards { let round_after = store.get_round(game.id); assert(round_after.player_score == 40, 'wrong round player_score'); } - // #[test] +// #[test] // #[available_gas(30000000000000000)] // fn test_play_rage_card_diminished_hold() { // let (world, systems) = setup::spawn_game(); @@ -657,22 +657,22 @@ mod test_rage_cards { // let mut game = mock_game(ref store, PLAYER()); // mock_round(ref store, @game, 300); - // // Mock RageRound +// // Mock RageRound // let len_hand_before = game.len_hand; // mock_rage_round(world, game.id, array![RAGE_CARD_DIMINISHED_HOLD]); - // // Set game state in shop +// // Set game state in shop // game.state = GameState::AT_SHOP; // store.set_game(game); - // set_contract_address(PLAYER()); +// set_contract_address(PLAYER()); // systems.shop_system.skip_shop(game.id); - // let game_after = store.get_game(game.id); +// let game_after = store.get_game(game.id); // assert(game_after.len_hand == len_hand_before - 2, 'wrong game_after len_hand'); // } - // #[test] +// #[test] // #[available_gas(30000000000000000)] // fn test_play_rage_card_zero_waste() { // let (world, systems) = setup::spawn_game(); @@ -680,17 +680,17 @@ mod test_rage_cards { // let mut game = mock_game(ref store, PLAYER()); // mock_round(ref store, @game, 300); - // // Mock RageRound +// // Mock RageRound // mock_rage_round(world, game.id, array![RAGE_CARD_ZERO_WASTE]); - // // Set game state in shop +// // Set game state in shop // game.state = GameState::AT_SHOP; // store.set_game(game); - // set_contract_address(PLAYER()); +// set_contract_address(PLAYER()); // systems.shop_system.skip_shop(game.id); - // let round = store.get_round(game.id); +// let round = store.get_round(game.id); // assert(round.discard == 0, 'wrong round discard'); // } } diff --git a/src/tests/test_game_play_beast.cairo b/src/tests/test_game_play_beast.cairo new file mode 100644 index 0000000..e32eb1b --- /dev/null +++ b/src/tests/test_game_play_beast.cairo @@ -0,0 +1,893 @@ +mod test_play_beast_special_cards { + use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait}; + use jokers_of_neon::constants::card::{ + SIX_CLUBS_ID, ACE_CLUBS_ID, ACE_HEARTS_ID, ACE_DIAMONDS_ID, NINE_DIAMONDS_ID, EIGHT_HEARTS_ID, QUEEN_CLUBS_ID, + SEVEN_DIAMONDS_ID, FIVE_CLUBS_ID, KING_CLUBS_ID, SIX_HEARTS_ID, FOUR_CLUBS_ID, JACK_CLUBS_ID, JACK_HEARTS_ID, + KING_DIAMONDS_ID, SEVEN_CLUBS_ID, SEVEN_HEARTS_ID, ACE_SPADES_ID + }; + use jokers_of_neon::constants::modifiers::{SUIT_CLUB_MODIFIER_ID, MULTI_MODIFIER_1_ID}; + use jokers_of_neon::constants::specials::{ + SPECIAL_LUCKY_SEVEN_ID, SPECIAL_INCREASE_LEVEL_PAIR_ID, SPECIAL_MULTI_FOR_CLUB_ID, SPECIAL_MULTI_FOR_HEART_ID, + SPECIAL_POINTS_FOR_FIGURES_ID, SPECIAL_MULTI_FOR_DIAMOND_ID, SPECIAL_MULTI_FOR_SPADE_ID, SPECIAL_NEON_BONUS_ID, + SPECIAL_INITIAL_ADVANTAGE_ID, SPECIAL_MULTI_ACES_ID, SPECIAL_DEADLINE_ID, SPECIAL_ALL_CARDS_TO_HEARTS_ID, + SPECIAL_LUCKY_HAND_ID + }; + use jokers_of_neon::models::data::beast::{ + GameModeBeast, GameModeBeastStore, Beast, BeastStore, PlayerBeast, PlayerBeastStore + }; + use jokers_of_neon::models::data::card::{Card, CardTrait, Suit, Value, SuitEnumerableImpl, ValueEnumerableImpl}; + use jokers_of_neon::models::data::game_deck::{GameDeck, DeckCard}; + use jokers_of_neon::models::data::poker_hand::PokerHand; + use jokers_of_neon::models::status::game::game::{Game, CurrentSpecialCards, GameState, GameSubState}; + use jokers_of_neon::models::status::round::current_hand_card::{CurrentHandCard}; + use jokers_of_neon::store::{Store, StoreTrait}; + + use jokers_of_neon::systems::game_system::{game_system, IGameSystemDispatcher, IGameSystemDispatcherTrait}; + use jokers_of_neon::tests::setup::{ + setup, setup::OWNER, setup::IDojoInitDispatcher, setup::IDojoInitDispatcherTrait + }; + use jokers_of_neon::tests::utils::{ + mock_current_hand, mock_current_hand_cards_ids, mock_game, mock_special_cards, mock_level_best + }; + use starknet::testing::set_contract_address; + + fn PLAYER() -> starknet::ContractAddress { + starknet::contract_address_const::<'PLAYER'>() + } + + #[test] + #[available_gas(30000000000000000)] + fn test_play_special_flush() { + let (world, systems) = setup::spawn_game(); + let mut store = StoreTrait::new(world); + let mut game = mock_game(ref store, PLAYER()); + game.state = GameState::IN_GAME; + game.substate = GameSubState::BEAST; + store.set_game(game); + + mock_level_best(world, game.id); + + // Mock special card + let special_cards_ids = array![SPECIAL_ALL_CARDS_TO_HEARTS_ID]; + mock_special_cards(ref store, ref game, special_cards_ids); + + // Mock hand + let hand_cards_ids = array![SIX_CLUBS_ID, QUEEN_CLUBS_ID, FOUR_CLUBS_ID, JACK_HEARTS_ID, KING_DIAMONDS_ID]; + mock_current_hand_cards_ids(ref store, game.id, hand_cards_ids); + + let game_mode_beast = GameModeBeastStore::get(world, game.id); + let beast_before = BeastStore::get(world, game.id); + let player_beast_before = PlayerBeastStore::get(world, game.id); + + set_contract_address(PLAYER()); + systems.game_system.play(game.id, array![0, 1, 2, 3, 4], array![100, 100, 100, 100, 100]); + // Flush - points: 35, multi: 4 + // points: 6 + 10 + 4 + 10 + 10 + // multi add: 0 + // player_score = 300 + + let beast_after = BeastStore::get(world, game.id); + assert(beast_after.health == beast_before.health - 300, 'wrong beast health'); + + let player_beast_after = PlayerBeastStore::get(world, game.id); + assert( + player_beast_after.energy == player_beast_before.energy - game_mode_beast.cost_play, 'wrong player energy' + ); + } + + #[test] + #[available_gas(30000000000000000)] + fn test_play_special_extra_points_figure() { + let (world, systems) = setup::spawn_game(); + let mut store = StoreTrait::new(world); + let mut game = mock_game(ref store, PLAYER()); + game.state = GameState::IN_GAME; + game.substate = GameSubState::BEAST; + store.set_game(game); + + mock_level_best(world, game.id); + + // Mock special card + let special_cards_ids = array![SPECIAL_POINTS_FOR_FIGURES_ID]; + mock_special_cards(ref store, ref game, special_cards_ids); + + // Mock hand + let hand_cards_ids = array![ + SIX_CLUBS_ID, + QUEEN_CLUBS_ID, + FOUR_CLUBS_ID, + JACK_HEARTS_ID, + KING_DIAMONDS_ID, + SUIT_CLUB_MODIFIER_ID, + SUIT_CLUB_MODIFIER_ID, + MULTI_MODIFIER_1_ID + ]; + mock_current_hand_cards_ids(ref store, game.id, hand_cards_ids); + + let game_mode_beast = GameModeBeastStore::get(world, game.id); + let player_beast_before = PlayerBeastStore::get(world, game.id); + + set_contract_address(PLAYER()); + systems.game_system.play(game.id, array![0, 1, 2, 3, 4], array![100, 7, 100, 5, 6]); + // Flush - points: 35, multi: 4 + // points: 6 + 10 + 4 + 10 + 10 + 50 * 3 + // multi add: 1 + // player_score = 1125 + + let beast_after = BeastStore::get(world, game.id); + assert(beast_after.health.is_zero(), 'wrong beast health'); + + let player_beast_after = PlayerBeastStore::get(world, game.id); + assert( + player_beast_after.energy == player_beast_before.energy - game_mode_beast.cost_play, 'wrong player energy' + ); + } + + #[test] + #[available_gas(30000000000000000)] + fn test_play_special_multi_for_clubs() { + let (world, systems) = setup::spawn_game(); + let mut store = StoreTrait::new(world); + let mut game = mock_game(ref store, PLAYER()); + game.state = GameState::IN_GAME; + game.substate = GameSubState::BEAST; + store.set_game(game); + + mock_level_best(world, game.id); + + // Mock special card + let special_cards_ids = array![SPECIAL_MULTI_FOR_CLUB_ID]; + mock_special_cards(ref store, ref game, special_cards_ids); + + // Mock hand + let hand_cards_ids = array![SIX_CLUBS_ID, SIX_HEARTS_ID, FOUR_CLUBS_ID, JACK_HEARTS_ID, KING_DIAMONDS_ID,]; + mock_current_hand_cards_ids(ref store, game.id, hand_cards_ids); + + let game_mode_beast = GameModeBeastStore::get(world, game.id); + let beast_before = BeastStore::get(world, game.id); + let player_beast_before = PlayerBeastStore::get(world, game.id); + + set_contract_address(PLAYER()); + systems.game_system.play(game.id, array![0, 1, 2, 3, 4], array![100, 100, 100, 100, 100]); + // Pair - points: 10, multi: 2 + // points: 6 + 6 + // multi add: 2 + // player_score = 88 + + let beast_after = BeastStore::get(world, game.id); + assert(beast_after.health == beast_before.health - 88, 'wrong beast health'); + + let player_beast_after = PlayerBeastStore::get(world, game.id); + assert( + player_beast_after.energy == player_beast_before.energy - game_mode_beast.cost_play, 'wrong player energy' + ); + } + + #[test] + #[available_gas(30000000000000000)] + fn test_play_special_multi_for_all_suits() { + let (world, systems) = setup::spawn_game(); + let mut store = StoreTrait::new(world); + let mut game = mock_game(ref store, PLAYER()); + game.state = GameState::IN_GAME; + game.substate = GameSubState::BEAST; + store.set_game(game); + + mock_level_best(world, game.id); + + // Mock special card + let special_cards_ids = array![ + SPECIAL_MULTI_FOR_CLUB_ID, + SPECIAL_MULTI_FOR_HEART_ID, + SPECIAL_MULTI_FOR_DIAMOND_ID, + SPECIAL_MULTI_FOR_SPADE_ID + ]; + mock_special_cards(ref store, ref game, special_cards_ids); + + // Mock hand + let hand_cards_ids = array![ + FIVE_CLUBS_ID, SIX_HEARTS_ID, SEVEN_DIAMONDS_ID, EIGHT_HEARTS_ID, NINE_DIAMONDS_ID, + ]; + mock_current_hand_cards_ids(ref store, game.id, hand_cards_ids); + + let game_mode_beast = GameModeBeastStore::get(world, game.id); + let player_beast_before = PlayerBeastStore::get(world, game.id); + + set_contract_address(PLAYER()); + systems.game_system.play(game.id, array![0, 1, 2, 3, 4], array![100, 100, 100, 100, 100]); + // Straight - points: 40, multi: 4 + // points: 5 + 6 + 7 + 8 + 9 + // multi add: 2 + 2 + 2 + 2 + 2 + // player_score = 1050 + + let beast_after = BeastStore::get(world, game.id); + assert(beast_after.health.is_zero(), 'wrong beast health'); + + let player_beast_after = PlayerBeastStore::get(world, game.id); + assert( + player_beast_after.energy == player_beast_before.energy - game_mode_beast.cost_play, 'wrong player energy' + ); + } + + #[test] + #[available_gas(30000000000000000)] + fn test_play_special_multi_aces() { + let (world, systems) = setup::spawn_game(); + let mut store = StoreTrait::new(world); + let mut game = mock_game(ref store, PLAYER()); + game.state = GameState::IN_GAME; + game.substate = GameSubState::BEAST; + store.set_game(game); + + mock_level_best(world, game.id); + + // Mock special card + let special_cards_ids = array![SPECIAL_MULTI_ACES_ID]; + mock_special_cards(ref store, ref game, special_cards_ids); + + // Mock hand + let hand_cards_ids = array![ACE_CLUBS_ID, ACE_HEARTS_ID, ACE_DIAMONDS_ID]; + mock_current_hand_cards_ids(ref store, game.id, hand_cards_ids); + + let game_mode_beast = GameModeBeastStore::get(world, game.id); + let player_beast_before = PlayerBeastStore::get(world, game.id); + + set_contract_address(PLAYER()); + systems.game_system.play(game.id, array![0, 1, 2], array![100, 100, 100,]); + // Three of a Kind - points: 30, multi: 5 + // points: 11 + 11 + 11 + // multi add: 3 + 3 + 3 + // player_score = 1134 + + let beast_after = BeastStore::get(world, game.id); + assert(beast_after.health.is_zero(), 'wrong beast health'); + + let player_beast_after = PlayerBeastStore::get(world, game.id); + assert( + player_beast_after.energy == player_beast_before.energy - game_mode_beast.cost_play, 'wrong player energy' + ); + } + + #[test] + #[available_gas(30000000000000000)] + fn test_play_special_lucky_seven() { + let (world, systems) = setup::spawn_game(); + let mut store = StoreTrait::new(world); + let mut game = mock_game(ref store, PLAYER()); + + game.state = GameState::IN_GAME; + game.substate = GameSubState::BEAST; + store.set_game(game); + + mock_level_best(world, game.id); + + // Mock special card + let special_cards_ids = array![SPECIAL_LUCKY_SEVEN_ID]; + mock_special_cards(ref store, ref game, special_cards_ids); + + // Mock hand + let hand_cards_ids = array![SEVEN_CLUBS_ID, SEVEN_HEARTS_ID, FOUR_CLUBS_ID, JACK_HEARTS_ID, KING_DIAMONDS_ID,]; + mock_current_hand_cards_ids(ref store, game.id, hand_cards_ids); + + let game_mode_beast = GameModeBeastStore::get(world, game.id); + let player_beast_before = PlayerBeastStore::get(world, game.id); + + set_contract_address(PLAYER()); + systems.game_system.play(game.id, array![0, 1, 2, 3, 4], array![100, 100, 100, 100, 100]); + // Pair - points: 10, multi: 2 + // points: 7 + 7 + 77 + 77 + // multi add: 0 + // player_score = 356 + + let beast_after = BeastStore::get(world, game.id); + assert(beast_after.health.is_zero(), 'wrong beast health'); + + let player_beast_after = PlayerBeastStore::get(world, game.id); + assert( + player_beast_after.energy == player_beast_before.energy - game_mode_beast.cost_play, 'wrong player energy' + ); + } +// #[test] +// #[available_gas(30000000000000000)] +// fn test_play_special_initial_advantage() { +// let (world, systems) = setup::spawn_game(); +// let mut store = StoreTrait::new(world); +// let mut game = mock_game(ref store, PLAYER()); +// mock_round(ref store, @game, 300); + +// // Mock special card +// let special_cards_ids = array![SPECIAL_INITIAL_ADVANTAGE_ID]; +// mock_special_cards(ref store, ref game, special_cards_ids); + +// // Mock hand +// let hand_cards_ids = array![ACE_CLUBS_ID, ACE_HEARTS_ID, ACE_DIAMONDS_ID, ACE_SPADES_ID]; +// mock_current_hand_cards_ids(ref store, game.id, hand_cards_ids); + +// set_contract_address(PLAYER()); +// systems.game_system.play(game.id, array![0, 1, 2, 3], array![100, 100, 100, 100]); +// // Four of a Kind - points: 60, multi: 7 +// // points: 11 + 11 + 11 + 11 + 100 +// // multi add: 10 +// let round_after = store.get_round(game.id); +// assert(round_after.player_score == 3468, 'wrong round player_score'); +// } +} + +mod test_play_beast_modifier_cards { + use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait}; + use jokers_of_neon::constants::card::{ + JACK_CLUBS_ID, JACK_SPADES_ID, SIX_CLUBS_ID, QUEEN_CLUBS_ID, FOUR_CLUBS_ID, JACK_HEARTS_ID, KING_DIAMONDS_ID, + KING_SPADES_ID, TWO_SPADES_ID, TWO_DIAMONDS_ID, TWO_CLUBS_ID, FOUR_DIAMONDS_ID, FOUR_HEARTS_ID + }; + use jokers_of_neon::constants::modifiers::{ + SUIT_CLUB_MODIFIER_ID, MULTI_MODIFIER_1_ID, POINTS_MODIFIER_4_ID, MULTI_MODIFIER_4_ID, POINTS_MODIFIER_2_ID, + MULTI_MODIFIER_3_ID, + }; + use jokers_of_neon::models::data::beast::{ + GameModeBeast, GameModeBeastStore, Beast, BeastStore, PlayerBeast, PlayerBeastStore + }; + use jokers_of_neon::models::data::card::{Card, CardTrait, Suit, Value, SuitEnumerableImpl, ValueEnumerableImpl}; + use jokers_of_neon::models::data::game_deck::{GameDeck}; + use jokers_of_neon::models::data::poker_hand::{PokerHand, LevelPokerHand}; + use jokers_of_neon::models::status::game::game::{Game, CurrentSpecialCards, GameState, GameSubState}; + use jokers_of_neon::models::status::round::current_hand_card::{CurrentHandCard}; + use jokers_of_neon::store::{Store, StoreTrait}; + + use jokers_of_neon::systems::game_system::{game_system, IGameSystemDispatcher, IGameSystemDispatcherTrait}; + use jokers_of_neon::tests::setup::{ + setup, setup::OWNER, setup::IDojoInitDispatcher, setup::IDojoInitDispatcherTrait + }; + + use jokers_of_neon::tests::utils::{mock_current_hand, mock_current_hand_cards_ids, mock_game, mock_level_best}; + + use starknet::testing::set_contract_address; + + fn PLAYER() -> starknet::ContractAddress { + starknet::contract_address_const::<'PLAYER'>() + } + + #[test] + #[available_gas(30000000000000000)] + fn test_play_modifier_high_card() { + let (world, systems) = setup::spawn_game(); + + let mut store: Store = StoreTrait::new(world); + let mut game = mock_game(ref store, PLAYER()); + game.state = GameState::IN_GAME; + game.substate = GameSubState::BEAST; + store.set_game(game); + + mock_level_best(world, game.id); + + // Mock hand + let hand_cards_ids = array![KING_SPADES_ID, POINTS_MODIFIER_4_ID, MULTI_MODIFIER_4_ID]; + mock_current_hand_cards_ids(ref store, game.id, hand_cards_ids); + + let game_mode_beast = GameModeBeastStore::get(world, game.id); + let beast_before = BeastStore::get(world, game.id); + let player_beast_before = PlayerBeastStore::get(world, game.id); + + set_contract_address(PLAYER()); + systems.game_system.play(game.id, array![0], array![1]); + + let beast_after = BeastStore::get(world, game.id); + assert(beast_after.health == beast_before.health - 115, 'wrong beast health'); + + let player_beast_after = PlayerBeastStore::get(world, game.id); + assert( + player_beast_after.energy == player_beast_before.energy - game_mode_beast.cost_play, 'wrong player energy' + ); + } + + #[test] + #[available_gas(30000000000000000)] + fn test_play_modifier_one_pair() { + let (world, systems) = setup::spawn_game(); + let mut store = StoreTrait::new(world); + let mut game = mock_game(ref store, PLAYER()); + + game.state = GameState::IN_GAME; + game.substate = GameSubState::BEAST; + store.set_game(game); + + mock_level_best(world, game.id); + + // Mock hand + let hand_cards_ids = array![TWO_SPADES_ID, TWO_DIAMONDS_ID, POINTS_MODIFIER_4_ID, MULTI_MODIFIER_4_ID]; + mock_current_hand_cards_ids(ref store, game.id, hand_cards_ids); + + let game_mode_beast = GameModeBeastStore::get(world, game.id); + let player_beast_before = PlayerBeastStore::get(world, game.id); + + set_contract_address(PLAYER()); + systems.game_system.play(game.id, array![0, 1], array![2, 3]); + // Pair - points: 10, multi: 2 + // points: 2 + 2 + 100 + // multi add: 10 + // player_score = 1368 + + let beast_after = BeastStore::get(world, game.id); + assert(beast_after.health.is_zero(), 'wrong beast health'); + + let player_beast_after = PlayerBeastStore::get(world, game.id); + assert( + player_beast_after.energy == player_beast_before.energy - game_mode_beast.cost_play, 'wrong player energy' + ); + } + + #[test] + #[available_gas(30000000000000000)] + fn test_play_two_pair() { + let (world, systems) = setup::spawn_game(); + let mut store = StoreTrait::new(world); + let mut game = mock_game(ref store, PLAYER()); + + game.state = GameState::IN_GAME; + game.substate = GameSubState::BEAST; + store.set_game(game); + + mock_level_best(world, game.id); + + // Mock hand + let hand_cards_ids = array![TWO_CLUBS_ID, TWO_SPADES_ID, FOUR_DIAMONDS_ID, FOUR_HEARTS_ID]; + mock_current_hand_cards_ids(ref store, game.id, hand_cards_ids); + + let game_mode_beast = GameModeBeastStore::get(world, game.id); + let beast_before = BeastStore::get(world, game.id); + let player_beast_before = PlayerBeastStore::get(world, game.id); + + set_contract_address(PLAYER()); + systems.game_system.play(game.id, array![0, 1, 2, 3], array![100, 100, 100, 100]); + // TwoPair - points: 20, multi: 3 + // points: 2 + 2 + 4 + 4 = 12 + // multi add: 0 + // player_score = 96 + + let beast_after = BeastStore::get(world, game.id); + assert(beast_after.health == beast_before.health - 96, 'wrong beast health'); + + let player_beast_after = PlayerBeastStore::get(world, game.id); + assert( + player_beast_after.energy == player_beast_before.energy - game_mode_beast.cost_play, 'wrong player energy' + ); + } +} +// mod test_rage_cards { +// use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait}; +// use jokers_of_neon::constants::card::{ +// ACE_CLUBS_ID, ACE_HEARTS_ID, ACE_DIAMONDS_ID, ACE_SPADES_ID, SIX_CLUBS_ID, JOKER_CARD, FOUR_CLUBS_ID, +// JACK_HEARTS_ID, KING_DIAMONDS_ID +// }; +// use jokers_of_neon::constants::specials::{SPECIAL_MULTI_FOR_DIAMOND_ID, SPECIAL_JOKER_BOOSTER_ID}; +// use jokers_of_neon::models::data::card::{Card, CardTrait, Suit, Value, SuitEnumerableImpl, ValueEnumerableImpl}; +// use jokers_of_neon::models::data::game_deck::{GameDeck}; +// use jokers_of_neon::models::data::poker_hand::PokerHand; +// use jokers_of_neon::models::status::game::game::{Game, CurrentSpecialCards, GameState}; +// use jokers_of_neon::models::status::round::current_hand_card::{CurrentHandCard}; +// use jokers_of_neon::models::status::round::round::{Round}; + +// use jokers_of_neon::store::{Store, StoreTrait}; + +// use jokers_of_neon::systems::game_system::{game_system, IGameSystemDispatcher, IGameSystemDispatcherTrait}; +// use jokers_of_neon::tests::setup::{ +// setup, setup::OWNER, setup::IDojoInitDispatcher, setup::IDojoInitDispatcherTrait +// }; + +// use jokers_of_neon::tests::utils::{ +// mock_current_hand, mock_current_hand_cards_ids, mock_game, mock_round, mock_special_cards, mock_rage_round +// }; +// use jokers_of_neon::utils::constants::{ +// RAGE_CARD_SILENT_DIAMONDS, RAGE_CARD_DIMINISHED_HOLD, RAGE_CARD_ZERO_WASTE, RAGE_CARD_SILENT_JOKERS +// }; +// use starknet::testing::set_contract_address; + +// fn PLAYER() -> starknet::ContractAddress { +// starknet::contract_address_const::<'PLAYER'>() +// } + +// #[test] +// #[available_gas(30000000000000000)] +// fn test_play_rage_card_silent_diamond() { +// let (world, systems) = setup::spawn_game(); +// let mut store = StoreTrait::new(world); +// let mut game = mock_game(ref store, PLAYER()); +// mock_round(ref store, @game, 300); + +// // Mock RageRound +// mock_rage_round(world, game.id, array![RAGE_CARD_SILENT_DIAMONDS]); + +// // Mock hand +// let hand_cards_ids = array![ACE_CLUBS_ID, ACE_HEARTS_ID, ACE_DIAMONDS_ID, ACE_SPADES_ID]; +// mock_current_hand_cards_ids(ref store, game.id, hand_cards_ids); + +// set_contract_address(PLAYER()); +// systems.game_system.play(game.id, array![0, 1, 2, 3], array![100, 100, 100, 100]); +// // Four of a Kind - points: 60, multi: 7 +// // points: 11 + 11 + 0 + 11 +// let round_after = store.get_round(game.id); +// assert(round_after.player_score == 651, 'wrong round player_score'); +// } + +// #[test] +// #[available_gas(30000000000000000)] +// fn test_play_rage_card_silent_diamond_with_special() { +// let (world, systems) = setup::spawn_game(); +// let mut store = StoreTrait::new(world); +// let mut game = mock_game(ref store, PLAYER()); +// mock_round(ref store, @game, 300); + +// // Mock RageRound +// mock_rage_round(world, game.id, array![RAGE_CARD_SILENT_DIAMONDS]); + +// // Mock special card +// let special_cards_ids = array![SPECIAL_MULTI_FOR_DIAMOND_ID]; +// mock_special_cards(ref store, ref game, special_cards_ids); + +// // Mock hand +// let hand_cards_ids = array![ACE_CLUBS_ID, ACE_HEARTS_ID, ACE_DIAMONDS_ID, ACE_SPADES_ID]; +// mock_current_hand_cards_ids(ref store, game.id, hand_cards_ids); + +// set_contract_address(PLAYER()); +// systems.game_system.play(game.id, array![0, 1, 2, 3], array![100, 100, 100, 100]); +// // Four of a Kind - points: 60, multi: 7 +// // points: 11 + 11 + 0 + 11 +// let round_after = store.get_round(game.id); +// assert(round_after.player_score == 651, 'wrong round player_score'); +// } + +// #[test] +// #[available_gas(30000000000000000)] +// fn test_play_rage_card_silent_jokers_with_special() { +// let (world, systems) = setup::spawn_game(); +// let mut store = StoreTrait::new(world); +// let mut game = mock_game(ref store, PLAYER()); +// mock_round(ref store, @game, 300); + +// // Mock RageRound +// mock_rage_round(world, game.id, array![RAGE_CARD_SILENT_JOKERS]); + +// // Mock special card +// let special_cards_ids = array![SPECIAL_JOKER_BOOSTER_ID]; +// mock_special_cards(ref store, ref game, special_cards_ids); + +// // Mock hand +// let hand_cards_ids = array![SIX_CLUBS_ID, JOKER_CARD, FOUR_CLUBS_ID, JACK_HEARTS_ID, KING_DIAMONDS_ID]; +// mock_current_hand_cards_ids(ref store, game.id, hand_cards_ids); + +// set_contract_address(PLAYER()); +// systems.game_system.play(game.id, array![0, 1, 2, 3, 4], array![100, 100, 100, 100, 100]); +// // Pair - points: 10, multi: 2 +// // points: 10 +// // player_score = 40 +// let round_after = store.get_round(game.id); +// assert(round_after.player_score == 40, 'wrong round player_score'); +// } +// #[test] +// #[available_gas(30000000000000000)] +// fn test_play_rage_card_diminished_hold() { +// let (world, systems) = setup::spawn_game(); +// let mut store = StoreTrait::new(world); +// let mut game = mock_game(ref store, PLAYER()); +// mock_round(ref store, @game, 300); + +// // Mock RageRound +// let len_hand_before = game.len_hand; +// mock_rage_round(world, game.id, array![RAGE_CARD_DIMINISHED_HOLD]); + +// // Set game state in shop +// game.state = GameState::AT_SHOP; +// store.set_game(game); + +// set_contract_address(PLAYER()); +// systems.shop_system.skip_shop(game.id); + +// let game_after = store.get_game(game.id); +// assert(game_after.len_hand == len_hand_before - 2, 'wrong game_after len_hand'); +// } + +// #[test] +// #[available_gas(30000000000000000)] +// fn test_play_rage_card_zero_waste() { +// let (world, systems) = setup::spawn_game(); +// let mut store = StoreTrait::new(world); +// let mut game = mock_game(ref store, PLAYER()); +// mock_round(ref store, @game, 300); + +// // Mock RageRound +// mock_rage_round(world, game.id, array![RAGE_CARD_ZERO_WASTE]); + +// // Set game state in shop +// game.state = GameState::AT_SHOP; +// store.set_game(game); + +// set_contract_address(PLAYER()); +// systems.shop_system.skip_shop(game.id); + +// let round = store.get_round(game.id); +// assert(round.discard == 0, 'wrong round discard'); +// } +// } + +// mod test_play_validations { +// use jokers_of_neon::constants::card::INVALID_CARD; +// use jokers_of_neon::models::data::card::{Card, CardTrait, Suit, Value, SuitEnumerableImpl, ValueEnumerableImpl}; +// use jokers_of_neon::models::data::game_deck::{GameDeckImpl, GameDeck, GameDeckStore}; +// use jokers_of_neon::models::data::poker_hand::PokerHand; + +// use jokers_of_neon::models::status::game::game::{Game, GameState, DefaultGame}; +// use jokers_of_neon::models::status::round::round::Round; + +// use jokers_of_neon::store::{Store, StoreTrait}; + +// use jokers_of_neon::systems::game_system::{game_system, IGameSystemDispatcher, IGameSystemDispatcherTrait}; +// use jokers_of_neon::tests::setup::{setup, setup::IDojoInitDispatcher, setup::IDojoInitDispatcherTrait}; +// use jokers_of_neon::tests::utils::{mock_current_hand_cards_ids, mock_game, mock_game_deck}; +// use starknet::testing::set_contract_address; + +// fn PLAYER() -> starknet::ContractAddress { +// starknet::contract_address_const::<'PLAYER'>() +// } + +// #[test] +// #[available_gas(300000000000)] +// #[should_panic(expected: ('Game: game not found', 'ENTRYPOINT_FAILED'))] +// fn test_game_not_found() { +// let (_, systems) = setup::spawn_game(); +// let NON_EXISTENT_GAME_ID = 1; +// systems.game_system.play(NON_EXISTENT_GAME_ID, array![0], array![0]); +// } + +// #[test] +// #[available_gas(300000000000)] +// #[should_panic(expected: ('Game: caller not owner', 'ENTRYPOINT_FAILED'))] +// fn test_caller_not_owner() { +// let (world, systems) = setup::spawn_game(); +// let mut store = StoreTrait::new(world); +// let game = mock_game(ref store, PLAYER()); + +// let ANYONE = starknet::contract_address_const::<'ANYONE'>(); +// set_contract_address(ANYONE); + +// systems.game_system.play(game.id, array![0], array![0]); +// } + +// #[test] +// #[available_gas(300000000000)] +// #[should_panic(expected: ('Game: invalid card index len', 'ENTRYPOINT_FAILED'))] +// fn test_invalid_card_index() { +// let (world, systems) = setup::spawn_game(); +// let mut store = StoreTrait::new(world); +// let game = mock_game(ref store, PLAYER()); + +// set_contract_address(PLAYER()); +// systems.game_system.play(game.id, array![], array![]); +// } + +// #[test] +// #[available_gas(30000000000000000)] +// #[should_panic(expected: ('Game: use an invalid card', 'ENTRYPOINT_FAILED'))] +// fn test_play_invalid_card() { +// let (world, systems) = setup::spawn_game(); +// let mut store = StoreTrait::new(world); +// let game = mock_game(ref store, PLAYER()); +// mock_round(ref store, @game, 300); + +// let cards_ids = array![INVALID_CARD]; +// mock_current_hand_cards_ids(ref store, game.id, cards_ids); + +// set_contract_address(PLAYER()); +// systems.game_system.play(game.id, array![0], array![100]); +// } + +// #[test] +// #[available_gas(30000000000000000)] +// #[should_panic(expected: ('Game: use an invalid card', 'ENTRYPOINT_FAILED'))] +// fn test_discard_invalid_card() { +// let (world, systems) = setup::spawn_game(); +// let mut store = StoreTrait::new(world); +// let game = mock_game(ref store, PLAYER()); +// mock_round(ref store, @game, 300); + +// let cards_ids = array![INVALID_CARD]; +// mock_current_hand_cards_ids(ref store, game.id, cards_ids); + +// set_contract_address(PLAYER()); +// systems.game_system.discard(game.id, array![0], array![100]); +// } + +// #[test] +// #[available_gas(30000000000000000)] +// fn test_play_when_current_deck_is_empty_should_return_invalid_cards() { +// let (world, systems) = setup::spawn_game(); +// let mut store = StoreTrait::new(world); +// let game = mock_game(ref store, PLAYER()); +// mock_round(ref store, @game, 3000); + +// let mut game_deck = mock_game_deck(world, game.id); +// game_deck.round_len = 0; +// GameDeckStore::set(@game_deck, world); + +// let TWO_OF_HEARTS = CardTrait::generate_id(Value::Two, Suit::Hearts); +// let cards_ids = array![ +// TWO_OF_HEARTS, +// TWO_OF_HEARTS, +// TWO_OF_HEARTS, +// TWO_OF_HEARTS, +// TWO_OF_HEARTS, +// TWO_OF_HEARTS, +// TWO_OF_HEARTS, +// TWO_OF_HEARTS +// ]; +// mock_current_hand_cards_ids(ref store, game.id, cards_ids); + +// set_contract_address(PLAYER()); +// systems.game_system.play(game.id, array![0, 1], array![100, 100]); + +// // Validate that the quantity of invalid cards is 2 +// let mut i = 0; +// let mut invalid_cards_count = 0; +// let HAND_LEN = 8; +// loop { +// if HAND_LEN == i { +// break; +// } +// let current_hand_card = store.get_current_hand_card(game.id, i); +// if current_hand_card.card_id == INVALID_CARD { +// invalid_cards_count += 1; +// } +// i += 1; +// }; +// assert(invalid_cards_count == 2, 'wrong invalid cards quantity'); +// } + +// #[test] +// #[available_gas(30000000000000000)] +// fn test_play_when_current_deck_and_hand_are_empty_then_game_finish() { +// let (world, systems) = setup::spawn_game(); +// let mut store = StoreTrait::new(world); +// let game = mock_game(ref store, PLAYER()); +// mock_round(ref store, @game, 3000); + +// // Make sure that player doenst win with next hand +// // Set an empty current deck +// let mut game_deck = mock_game_deck(world, game.id); +// game_deck.round_len = 0; +// GameDeckStore::set(@game_deck, world); + +// let TWO_OF_HEARTS = CardTrait::generate_id(Value::Two, Suit::Hearts); +// let cards_ids = array![ +// TWO_OF_HEARTS, +// TWO_OF_HEARTS, +// TWO_OF_HEARTS, +// TWO_OF_HEARTS, +// TWO_OF_HEARTS, +// INVALID_CARD, +// INVALID_CARD, +// INVALID_CARD +// ]; +// mock_current_hand_cards_ids(ref store, game.id, cards_ids); + +// set_contract_address(PLAYER()); +// systems.game_system.play(game.id, array![0, 1, 2, 3, 4], array![100, 100, 100, 100, 100]); + +// let game = store.get_game(game.id); +// assert(game.state == GameState::FINISHED, 'game should be finished'); +// } + +// #[test] +// #[available_gas(300000000000)] +// #[should_panic(expected: ('Game: game not found', 'ENTRYPOINT_FAILED'))] +// fn test_discard_game_not_found() { +// let (_, systems) = setup::spawn_game(); +// let NON_EXISTENT_GAME_ID = 1; +// systems.game_system.discard(NON_EXISTENT_GAME_ID, array![0], array![0]); +// } + +// #[test] +// #[available_gas(300000000000)] +// #[should_panic(expected: ('Game: caller not owner', 'ENTRYPOINT_FAILED'))] +// fn test_discard_caller_not_owner() { +// let (world, systems) = setup::spawn_game(); +// let mut store = StoreTrait::new(world); +// let game = mock_game(ref store, PLAYER()); + +// let ANYONE = starknet::contract_address_const::<'ANYONE'>(); +// set_contract_address(ANYONE); + +// systems.game_system.discard(game.id, array![0], array![0]); +// } + +// #[test] +// #[available_gas(300000000000)] +// #[should_panic(expected: ('Game: is not IN_GAME', 'ENTRYPOINT_FAILED'))] +// fn test_discard_game_not_in_progress() { +// let (world, systems) = setup::spawn_game(); +// let mut store = StoreTrait::new(world); +// let mut game = mock_game(ref store, PLAYER()); +// game.state = GameState::FINISHED; +// store.set_game(game); + +// set_contract_address(PLAYER()); +// systems.game_system.discard(game.id, array![0], array![0]); +// } + +// #[test] +// #[available_gas(30000000000000000)] +// fn test_discard_when_current_deck_is_empty_and_have_invalid_cards() { +// let (world, systems) = setup::spawn_game(); +// let mut store = StoreTrait::new(world); +// let game = mock_game(ref store, PLAYER()); +// mock_round(ref store, @game, 3000); + +// let mut game_deck = mock_game_deck(world, game.id); +// game_deck.round_len = 0; +// GameDeckStore::set(@game_deck, world); + +// let TWO_OF_HEARTS = CardTrait::generate_id(Value::Two, Suit::Hearts); +// let cards_ids = array![ +// TWO_OF_HEARTS, +// TWO_OF_HEARTS, +// TWO_OF_HEARTS, +// INVALID_CARD, +// INVALID_CARD, +// INVALID_CARD, +// INVALID_CARD, +// INVALID_CARD +// ]; +// mock_current_hand_cards_ids(ref store, game.id, cards_ids); + +// set_contract_address(PLAYER()); +// systems.game_system.discard(game.id, array![0, 1], array![100, 100]); + +// // Validate that the quantity of invalid cards is 7 (5 current invalid cards + 2 invalid for +// // discard) +// let mut i = 0; +// let mut invalid_cards_count = 0; +// let HAND_LEN = 8; +// loop { +// if HAND_LEN == i { +// break; +// } +// let current_hand_card = store.get_current_hand_card(game.id, i); +// if current_hand_card.card_id == INVALID_CARD { +// invalid_cards_count += 1; +// } +// i += 1; +// }; +// assert(invalid_cards_count == 7, 'wrong invalid cards quantity'); +// } + +// #[test] +// #[available_gas(30000000000000000)] +// fn test_discard_when_current_deck_and_hand_are_empty_then_game_finish() { +// let (world, systems) = setup::spawn_game(); +// let mut store = StoreTrait::new(world); +// let game = mock_game(ref store, PLAYER()); +// mock_round(ref store, @game, 3000); + +// let mut game_deck = mock_game_deck(world, game.id); +// game_deck.round_len = 0; +// GameDeckStore::set(@game_deck, world); + +// let TWO_OF_HEARTS = CardTrait::generate_id(Value::Two, Suit::Hearts); +// let cards_ids = array![ +// TWO_OF_HEARTS, +// TWO_OF_HEARTS, +// TWO_OF_HEARTS, +// INVALID_CARD, +// INVALID_CARD, +// INVALID_CARD, +// INVALID_CARD, +// INVALID_CARD +// ]; +// mock_current_hand_cards_ids(ref store, game.id, cards_ids); + +// set_contract_address(PLAYER()); +// systems.game_system.discard(game.id, array![0, 1, 2], array![100, 100, 100]); + +// let game = store.get_game(game.id); +// assert(game.state == GameState::FINISHED, 'game should be finished'); +// } +// } + + diff --git a/src/tests/utils.cairo b/src/tests/utils.cairo index f3688c1..8a6e979 100644 --- a/src/tests/utils.cairo +++ b/src/tests/utils.cairo @@ -1,5 +1,8 @@ use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait}; use jokers_of_neon::configs::rage::RageRoundConfig; +use jokers_of_neon::models::data::beast::{ + GameModeBeast, GameModeBeastStore, Beast, BeastStore, PlayerBeast, PlayerBeastStore +}; use jokers_of_neon::models::data::blister_pack::BlisterPack; use jokers_of_neon::models::data::card::{Card, CardTrait, Suit, Value, ValueEnumerableImpl}; use jokers_of_neon::models::data::effect_card::{Effect, EffectCard, TypeEffectCard}; @@ -8,7 +11,6 @@ use jokers_of_neon::models::data::poker_hand::{LevelPokerHand, PokerHand}; use jokers_of_neon::models::status::game::game::{Game, CurrentSpecialCards}; use jokers_of_neon::models::status::game::rage::{RageRound, RageRoundStore}; use jokers_of_neon::models::status::round::current_hand_card::CurrentHandCard; -use jokers_of_neon::models::status::round::round::Round; use jokers_of_neon::models::status::shop::shop::{CardItem, CardItemType, BlisterPackItem}; use jokers_of_neon::store::{Store, StoreTrait}; use starknet::ContractAddress; @@ -87,12 +89,15 @@ fn mock_game(ref store: Store, owner: ContractAddress) -> Game { game } -fn mock_round(ref store: Store, game: @Game, level_score: u32) -> Round { - let round = Round { - game_id: *game.id, player_score: 0, level_score: level_score, hands: *game.max_hands, discard: *game.max_discard - }; - store.set_round(round); - round +fn mock_level_best(world: IWorldDispatcher, game_id: u32) { + let game_mode_beast = GameModeBeast { game_id, cost_discard: 1, cost_play: 2, energy_max_player: 3 }; + GameModeBeastStore::set(@game_mode_beast, world); + + let beast = Beast { game_id, tier: 5, level: 5, health: 300, attack: 15 }; + BeastStore::set(@beast, world); + + let player_beast = PlayerBeast { game_id, health: 100, energy: game_mode_beast.energy_max_player }; + PlayerBeastStore::set(@player_beast, world); } fn mock_game_deck(world: IWorldDispatcher, game_id: u32) -> GameDeck { diff --git a/src/utils/game.cairo b/src/utils/game.cairo new file mode 100644 index 0000000..9e98035 --- /dev/null +++ b/src/utils/game.cairo @@ -0,0 +1,730 @@ +use core::nullable::NullableTrait; +use dojo::world::Resource::Contract; +use dojo::world::{IWorld, IWorldDispatcher, IWorldDispatcherTrait}; +use jokers_of_neon::constants::card::{JOKER_CARD, NEON_JOKER_CARD, INVALID_CARD}; +use jokers_of_neon::constants::packs::SPECIAL_CARDS_PACK_ID; +use jokers_of_neon::constants::specials::{ + SPECIAL_MULTI_FOR_HEART_ID, SPECIAL_MULTI_FOR_CLUB_ID, SPECIAL_MULTI_FOR_DIAMOND_ID, SPECIAL_MULTI_FOR_SPADE_ID, + SPECIAL_INCREASE_LEVEL_PAIR_ID, SPECIAL_INCREASE_LEVEL_DOUBLE_PAIR_ID, SPECIAL_INCREASE_LEVEL_STRAIGHT_ID, + SPECIAL_INCREASE_LEVEL_FLUSH_ID, SPECIAL_STRAIGHT_WITH_FOUR_CARDS_ID, SPECIAL_FLUSH_WITH_FOUR_CARDS_ID, + SPECIAL_JOKER_BOOSTER_ID, SPECIAL_MODIFIER_BOOSTER_ID, SPECIAL_POINTS_FOR_FIGURES_ID, SPECIAL_MULTI_ACES_ID, + SPECIAL_ALL_CARDS_TO_HEARTS_ID, SPECIAL_HAND_THIEF_ID, SPECIAL_EXTRA_HELP_ID, SPECIAL_LUCKY_SEVEN_ID, + SPECIAL_NEON_BONUS_ID, SPECIAL_DEADLINE_ID, SPECIAL_INITIAL_ADVANTAGE_ID, SPECIAL_LUCKY_HAND_ID +}; +use jokers_of_neon::models::data::card::{Card, CardTrait, Suit, Value, SuitEnumerableImpl, ValueEnumerableImpl,}; +use jokers_of_neon::models::data::effect_card::Effect; +use jokers_of_neon::models::data::events::{ + PokerHandEvent, CreateGameEvent, CardScoreEvent, PlayWinGameEvent, PlayGameOverEvent, DetailEarnedEvent, + SpecialModifierPointsEvent, SpecialModifierMultiEvent, SpecialModifierSuitEvent, SpecialPokerHandEvent, + SpecialGlobalEvent, ModifierCardSuitEvent, RoundScoreEvent, NeonPokerHandEvent, PlayPokerHandEvent, SpecialCashEvent +}; +use jokers_of_neon::models::data::game_deck::{GameDeckStore, GameDeckImpl}; +use jokers_of_neon::models::data::poker_hand::{LevelPokerHand, PokerHand}; +use jokers_of_neon::models::status::game::game::{Game, GameState}; +use jokers_of_neon::models::status::game::rage::{RageRound, RageRoundStore}; +use jokers_of_neon::models::status::round::current_hand_card::{CurrentHandCard, CurrentHandCardTrait}; +use jokers_of_neon::models::status::shop::shop::{BlisterPackResult}; + +use jokers_of_neon::store::{Store, StoreTrait}; +use jokers_of_neon::systems::rage_system::{IRageSystemDispatcher, IRageSystemDispatcherTrait}; +use jokers_of_neon::utils::calculate_hand::calculate_hand; +use jokers_of_neon::utils::constants::{ + RAGE_CARD_DIMINISHED_HOLD, RAGE_CARD_SILENT_JOKERS, RAGE_CARD_SILENT_HEARTS, RAGE_CARD_SILENT_CLUBS, + RAGE_CARD_SILENT_DIAMONDS, RAGE_CARD_SILENT_SPADES, RAGE_CARD_ZERO_WASTE, is_neon_card, is_modifier_card +}; +use jokers_of_neon::utils::packs::{open_blister_pack, select_cards_from_blister}; +use jokers_of_neon::utils::rage::is_rage_card_active; +use starknet::{ContractAddress, get_caller_address, ClassHash}; + +fn play(world: IWorldDispatcher, ref game: Game, cards_index: @Array, modifiers_index: @Array) -> u32 { + let mut store: Store = StoreTrait::new(world); + + let rage_round = RageRoundStore::get(world, game.id); + + let mut current_special_cards_index = get_current_special_cards(ref store, @game); + + let (mut cards, effect_id_cards_1, effect_id_cards_2) = get_cards( + world, ref store, game.id, cards_index, modifiers_index, ref current_special_cards_index + ); + + let (result_hand, mut hit_cards) = calculate_hand(@cards, ref current_special_cards_index); + + let mut points_acum = 0; + let mut multi_acum = 0; + + apply_joker( + world, + game.id, + cards_index, + ref current_special_cards_index, + @cards, + ref hit_cards, + ref points_acum, + ref multi_acum, + @rage_round + ); + + let silent_suits = get_silent_suits(@rage_round); + + calculate_score(world, @cards, ref hit_cards, cards_index, ref points_acum, ref multi_acum, @silent_suits); + + apply_modifiers( + world, + ref store, + ref hit_cards, + cards_index, + ref current_special_cards_index, + modifiers_index, + effect_id_cards_1, + effect_id_cards_2, + ref points_acum, + ref multi_acum + ); + + apply_special_global(world, @game, ref current_special_cards_index, ref points_acum, ref multi_acum); + + apply_special_every_card( + world, + game.id, + cards_index, + ref current_special_cards_index, + @cards, + ref hit_cards, + ref points_acum, + ref multi_acum, + @silent_suits + ); + + apply_special_level_hand( + world, + ref store, + game.id, + ref current_special_cards_index, + result_hand, + ref hit_cards, + cards_index, + @cards, + ref points_acum, + ref multi_acum + ); + points_acum * multi_acum +} + +fn player_has_empty_hand(ref store: Store, game: @Game) -> bool { + let mut i = 0; + loop { + if game.len_hand == @i { + break true; + } + let deck_card = store.get_current_hand_card(*game.id, i); + if deck_card.card_id != INVALID_CARD { + break false; + } + i += 1; + } +} + +fn has_repeated_elements(array: @Array) -> bool { + let mut array_span = array.span(); + let mut elements = array![]; + + let repeated_elements = loop { + match array_span.pop_front() { + Option::Some(new_elem) => { + let mut elements_span = elements.span(); + let result = loop { + match elements_span.pop_front() { + Option::Some(seen_elem) => { if *seen_elem == *new_elem { + break true; + } }, + Option::None => { break false; } + }; + }; + if result { + break result; + } + elements.append(*new_elem); + }, + Option::None => { break false; } + }; + }; + repeated_elements +} + +fn get_cards( + world: IWorldDispatcher, + ref store: Store, + game_id: u32, + cards_index: @Array, + modifiers_index: @Array, + ref current_special_cards_index: Felt252Dict> +) -> (Array, Array, Array) { + assert(!has_repeated_elements(cards_index), 'Game: array repeated elements'); + let mut cards = array![]; + let mut effect_id_cards_1 = array![]; + let mut effect_id_cards_2 = array![]; + let mut idx = 0; + loop { + if idx == cards_index.len() { + break; + } + + let current_hand_card = store.get_current_hand_card(game_id, *cards_index.at(idx)); + assert(current_hand_card.card_id != INVALID_CARD, 'Game: use an invalid card'); + + let mut card = store.get_card(current_hand_card.card_id); + + let modifier_1_index = *modifiers_index.at(idx); + if modifier_1_index != 100 { // TODO: Invalid + let current_hand_modifier_card = store.get_current_hand_card(game_id, modifier_1_index); + let effect_card = store.get_effect_card(current_hand_modifier_card.card_id); + effect_id_cards_1.append(effect_card.effect_id); + let effect = store.get_effect(effect_card.effect_id); + if effect.suit != Suit::None && card.suit != Suit::Joker { + card.suit = effect.suit; + emit!( + world, + ModifierCardSuitEvent { + player: get_caller_address(), + game_id, + modifier_card_idx: *modifiers_index.at(idx), + current_hand_card_idx: *cards_index.at(idx), + suit: card.suit + } + ); + } + } else { + effect_id_cards_1.append(100); + } + + if !(current_special_cards_index.get(SPECIAL_ALL_CARDS_TO_HEARTS_ID.into()).is_null()) { + if card.suit != Suit::Joker { + card.suit = Suit::Hearts; + emit!( + world, + SpecialModifierSuitEvent { + player: get_caller_address(), + game_id, + current_special_card_idx: current_special_cards_index + .get(SPECIAL_ALL_CARDS_TO_HEARTS_ID.into()) + .deref(), + current_hand_card_idx: *cards_index.at(idx), + suit: card.suit + } + ); + } + } + + cards.append(card); + idx += 1; + }; + (cards, effect_id_cards_1, effect_id_cards_2) +} + +fn calculate_score( + world: IWorldDispatcher, + cards: @Array, + ref hit_cards: Felt252Dict, + cards_index: @Array, + ref points_acum: u32, + ref multi_acum: u32, + silent_suits: @Array +) { + let mut idx = 0; + loop { + if cards.len() == idx { + break; + } + let hit = hit_cards.get(idx.into()); + if hit { + let card = *cards.at(idx); + let suit_is_silence = contains_suit(silent_suits, card.suit); + if suit_is_silence { // Emitir evento de Rage Card Silent Suit + } else { + points_acum += card.points.into(); + multi_acum += card.multi_add.into(); + if card.points > 0 { + emit!( + world, + (CardScoreEvent { + player: get_caller_address(), + index: *cards_index.at(idx), + multi: 0, + points: card.points.into() + }) + ); + } + if card.multi_add > 0 { + emit!( + world, + (CardScoreEvent { + player: get_caller_address(), index: *cards_index.at(idx), multi: card.multi_add, points: 0 + }) + ); + } + }; + } + idx += 1; + } +} + +fn apply_joker( + world: IWorldDispatcher, + game_id: u32, + cards_index: @Array, + ref current_special_cards_index: Felt252Dict>, + cards: @Array, + ref hit_cards: Felt252Dict, + ref points_acum: u32, + ref multi_acum: u32, + rage_round: @RageRound +) { + let mut idx = 0; + loop { + if cards.len() == idx { + break; + } + let card = *cards.at(idx); + if card.suit == Suit::Joker { + if is_rage_card_active(rage_round, RAGE_CARD_SILENT_JOKERS) { // Emitir evento + hit_cards.insert(idx.into(), false); + } else { + if !(current_special_cards_index.get(SPECIAL_JOKER_BOOSTER_ID.into()).is_null()) { + points_acum += card.points; + multi_acum += card.multi_add; + emit!( + world, + SpecialModifierPointsEvent { + player: get_caller_address(), + game_id, + current_special_card_idx: current_special_cards_index + .get(SPECIAL_JOKER_BOOSTER_ID.into()) + .deref(), + current_hand_card_idx: *cards_index.at(idx), + points: card.points + } + ); + emit!( + world, + SpecialModifierMultiEvent { + player: get_caller_address(), + game_id, + current_special_card_idx: current_special_cards_index + .get(SPECIAL_JOKER_BOOSTER_ID.into()) + .deref(), + current_hand_card_idx: *cards_index.at(idx), + multi: card.multi_add + } + ); + } + hit_cards.insert(idx.into(), true); + } + } + idx += 1; + }; +} + +fn apply_modifiers( + world: IWorldDispatcher, + ref store: Store, + ref hit_cards: Felt252Dict, + cards_index: @Array, + ref current_special_cards_index: Felt252Dict>, + modifiers_index: @Array, + effect_id_cards_1: Array, + effect_id_cards_2: Array, + ref points_acum: u32, + ref multi_acum: u32 +) { + let mut idx = 0; + loop { + if cards_index.len() == idx { + break; + } + let hit = hit_cards.get(idx.into()); + if hit { + let effect_card_id_1 = *effect_id_cards_1.at(idx); + if effect_card_id_1 != 100 { // TODO: Invalid + let effect = store.get_effect(effect_card_id_1); + if effect.suit == Suit::None { + let (points, multi_add) = if !(current_special_cards_index + .get(SPECIAL_MODIFIER_BOOSTER_ID.into()) + .is_null()) { + (effect.points * 2, effect.multi_add * 2) + } else { + (effect.points, effect.multi_add) + }; + points_acum += points; + multi_acum += multi_add; + emit!( + world, + (CardScoreEvent { + player: get_caller_address(), index: *modifiers_index.at(idx), multi: multi_add, points + }) + ); + } + } + } + idx += 1; + }; +} + +fn apply_special_global( + world: IWorldDispatcher, + game: @Game, + ref current_special_cards_index: Felt252Dict>, + ref points_acum: u32, + ref multi_acum: u32 +) { + // let mut store = StoreTrait::new(world); + if !(current_special_cards_index.get(SPECIAL_INITIAL_ADVANTAGE_ID.into()).is_null()) { // first hand + // TODO: Pedir los puntos de energia + // if *game.max_hands == *round.hands { + // let effect_card = store.get_effect_card(SPECIAL_INITIAL_ADVANTAGE_ID); + // let effect = store.get_effect(effect_card.effect_id); + // points_acum += effect.points; + // multi_acum += effect.multi_add; + // emit!( + // world, + // SpecialGlobalEvent { + // player: get_caller_address(), + // game_id: *game.id, + // current_special_card_idx: current_special_cards_index + // .get(SPECIAL_INITIAL_ADVANTAGE_ID.into()) + // .deref(), + // multi: effect.multi_add, + // points: effect.points + // } + // ); + // } + } +} + +fn apply_special_every_card( + world: IWorldDispatcher, + game_id: u32, + cards_index: @Array, + ref current_special_cards_index: Felt252Dict>, + cards: @Array, + ref hit_cards: Felt252Dict, + ref points_acum: u32, + ref multi_acum: u32, + silent_suits: @Array +) { + let mut idx = 0; + let mut store = StoreTrait::new(world); + loop { + if idx == cards.len() { + break; + } + + let hit = hit_cards.get(idx.into()); + let mut card = *cards.at(idx); + if hit { + let suit_is_silence = contains_suit(silent_suits, card.suit); + if !(current_special_cards_index.get(SPECIAL_MULTI_FOR_HEART_ID.into()).is_null()) { + if card.suit == Suit::Hearts && !suit_is_silence { + let effect_card = store.get_effect_card(SPECIAL_MULTI_FOR_HEART_ID); + let effect = store.get_effect(effect_card.effect_id); + multi_acum += effect.multi_add; + emit!( + world, + SpecialModifierMultiEvent { + player: get_caller_address(), + game_id, + current_special_card_idx: current_special_cards_index + .get(SPECIAL_MULTI_FOR_HEART_ID.into()) + .deref(), + current_hand_card_idx: *cards_index.at(idx), + multi: effect.multi_add + } + ); + } + } + + if !(current_special_cards_index.get(SPECIAL_MULTI_FOR_DIAMOND_ID.into()).is_null()) { + if card.suit == Suit::Diamonds && !suit_is_silence { + let effect_card = store.get_effect_card(SPECIAL_MULTI_FOR_DIAMOND_ID); + let effect = store.get_effect(effect_card.effect_id); + multi_acum += effect.multi_add; + emit!( + world, + SpecialModifierMultiEvent { + player: get_caller_address(), + game_id, + current_special_card_idx: current_special_cards_index + .get(SPECIAL_MULTI_FOR_DIAMOND_ID.into()) + .deref(), + current_hand_card_idx: *cards_index.at(idx), + multi: effect.multi_add + } + ); + } + } + + if !(current_special_cards_index.get(SPECIAL_MULTI_FOR_CLUB_ID.into()).is_null()) { + if card.suit == Suit::Clubs && !suit_is_silence { + let effect_card = store.get_effect_card(SPECIAL_MULTI_FOR_CLUB_ID); + let effect = store.get_effect(effect_card.effect_id); + multi_acum += effect.multi_add; + emit!( + world, + SpecialModifierMultiEvent { + player: get_caller_address(), + game_id, + current_special_card_idx: current_special_cards_index + .get(SPECIAL_MULTI_FOR_CLUB_ID.into()) + .deref(), + current_hand_card_idx: *cards_index.at(idx), + multi: effect.multi_add + } + ); + } + } + + if !(current_special_cards_index.get(SPECIAL_MULTI_FOR_SPADE_ID.into()).is_null()) { + if card.suit == Suit::Spades && !suit_is_silence { + let effect_card = store.get_effect_card(SPECIAL_MULTI_FOR_SPADE_ID); + let effect = store.get_effect(effect_card.effect_id); + multi_acum += effect.multi_add; + emit!( + world, + SpecialModifierMultiEvent { + player: get_caller_address(), + game_id, + current_special_card_idx: current_special_cards_index + .get(SPECIAL_MULTI_FOR_SPADE_ID.into()) + .deref(), + current_hand_card_idx: *cards_index.at(idx), + multi: effect.multi_add + } + ); + } + } + + if !(current_special_cards_index.get(SPECIAL_POINTS_FOR_FIGURES_ID.into()).is_null()) { + if (card.value == Value::Jack || card.value == Value::Queen || card.value == Value::King) + && !suit_is_silence { + points_acum += 50; + emit!( + world, + SpecialModifierPointsEvent { + player: get_caller_address(), + game_id, + current_special_card_idx: current_special_cards_index + .get(SPECIAL_POINTS_FOR_FIGURES_ID.into()) + .deref(), + current_hand_card_idx: *cards_index.at(idx), + points: 50 + } + ); + } + } + + if !(current_special_cards_index.get(SPECIAL_MULTI_ACES_ID.into()).is_null()) { + if card.value == Value::Ace && !suit_is_silence { + let effect_card = store.get_effect_card(SPECIAL_MULTI_ACES_ID); + let effect = store.get_effect(effect_card.effect_id); + multi_acum += effect.multi_add; + emit!( + world, + SpecialModifierMultiEvent { + player: get_caller_address(), + game_id, + current_special_card_idx: current_special_cards_index + .get(SPECIAL_MULTI_ACES_ID.into()) + .deref(), + current_hand_card_idx: *cards_index.at(idx), + multi: effect.multi_add + } + ); + } + } + + if !(current_special_cards_index.get(SPECIAL_LUCKY_SEVEN_ID.into()).is_null()) { + if card.value == Value::Seven && !suit_is_silence { + let effect_card = store.get_effect_card(SPECIAL_LUCKY_SEVEN_ID); + let effect = store.get_effect(effect_card.effect_id); + points_acum += effect.points; + emit!( + world, + SpecialModifierPointsEvent { + player: get_caller_address(), + game_id, + current_special_card_idx: current_special_cards_index + .get(SPECIAL_LUCKY_SEVEN_ID.into()) + .deref(), + current_hand_card_idx: *cards_index.at(idx), + points: effect.points + } + ); + } + } + + if !(current_special_cards_index.get(SPECIAL_NEON_BONUS_ID.into()).is_null()) { + if is_neon_card(card.id) && !suit_is_silence { + let effect_card = store.get_effect_card(SPECIAL_NEON_BONUS_ID); + let effect = store.get_effect(effect_card.effect_id); + points_acum += effect.points; + emit!( + world, + SpecialModifierPointsEvent { + player: get_caller_address(), + game_id, + current_special_card_idx: current_special_cards_index + .get(SPECIAL_NEON_BONUS_ID.into()) + .deref(), + current_hand_card_idx: *cards_index.at(idx), + points: effect.points + } + ); + } + } + }; + idx += 1; + } +} + +fn apply_special_level_hand( + world: IWorldDispatcher, + ref store: Store, + game_id: u32, + ref current_special_cards_index: Felt252Dict>, + poker_hand: PokerHand, + ref hit_cards: Felt252Dict, + cards_index: @Array, + cards: @Array, + ref points_acum: u32, + ref multi_acum: u32 +) { + let mut level_acum = 1; + if !(current_special_cards_index.get(SPECIAL_INCREASE_LEVEL_PAIR_ID.into()).is_null()) { + if poker_hand == PokerHand::OnePair { + level_acum += 4; + let level_poker_hand = store.get_level_poker_hand(poker_hand, level_acum); + emit!( + world, + SpecialPokerHandEvent { + player: get_caller_address(), + game_id, + current_special_card_idx: current_special_cards_index + .get(SPECIAL_INCREASE_LEVEL_PAIR_ID.into()) + .deref(), + multi: level_poker_hand.multi, + points: level_poker_hand.points + } + ); + } + } + if !(current_special_cards_index.get(SPECIAL_INCREASE_LEVEL_DOUBLE_PAIR_ID.into()).is_null()) { + if poker_hand == PokerHand::TwoPair { + level_acum += 4; + let level_poker_hand = store.get_level_poker_hand(poker_hand, level_acum); + emit!( + world, + SpecialPokerHandEvent { + player: get_caller_address(), + game_id, + current_special_card_idx: current_special_cards_index + .get(SPECIAL_INCREASE_LEVEL_DOUBLE_PAIR_ID.into()) + .deref(), + multi: level_poker_hand.multi, + points: level_poker_hand.points + } + ); + } + } + if !(current_special_cards_index.get(SPECIAL_INCREASE_LEVEL_STRAIGHT_ID.into()).is_null()) { + if poker_hand == PokerHand::Straight { + level_acum += 4; + let level_poker_hand = store.get_level_poker_hand(poker_hand, level_acum); + emit!( + world, + SpecialPokerHandEvent { + player: get_caller_address(), + game_id, + current_special_card_idx: current_special_cards_index + .get(SPECIAL_INCREASE_LEVEL_STRAIGHT_ID.into()) + .deref(), + multi: level_poker_hand.multi, + points: level_poker_hand.points + } + ); + } + } + if !(current_special_cards_index.get(SPECIAL_INCREASE_LEVEL_FLUSH_ID.into()).is_null()) { + if poker_hand == PokerHand::Flush { + level_acum += 4; + let level_poker_hand = store.get_level_poker_hand(poker_hand, level_acum); + emit!( + world, + SpecialPokerHandEvent { + player: get_caller_address(), + game_id, + current_special_card_idx: current_special_cards_index + .get(SPECIAL_INCREASE_LEVEL_FLUSH_ID.into()) + .deref(), + multi: level_poker_hand.multi, + points: level_poker_hand.points + } + ); + } + } + + let level_poker_hand = store.get_level_poker_hand(poker_hand, level_acum); + points_acum += level_poker_hand.points; + multi_acum += level_poker_hand.multi; +} + +fn get_current_special_cards(ref store: Store, game: @Game) -> Felt252Dict> { + let mut current_special_cards_index: Felt252Dict> = Default::default(); + let mut idx = 0; + loop { + if idx == *game.len_current_special_cards { + break; + } + let current_special_card = store.get_current_special_cards(*game.id, idx); + current_special_cards_index.insert(current_special_card.effect_card_id.into(), NullableTrait::new(idx)); + idx += 1; + }; + current_special_cards_index +} + +fn get_silent_suits(rage_round: @RageRound) -> Array { + let mut silent_suits = array![]; + if *rage_round.is_active { + let mut active_rages = (*rage_round.active_rage_ids).clone(); + loop { + match active_rages.pop_front() { + Option::Some(rage_id) => { + if *rage_id == RAGE_CARD_SILENT_HEARTS { + silent_suits.append(Suit::Hearts); + } else if *rage_id == RAGE_CARD_SILENT_CLUBS { + silent_suits.append(Suit::Clubs); + } else if *rage_id == RAGE_CARD_SILENT_DIAMONDS { + silent_suits.append(Suit::Diamonds); + } else if *rage_id == RAGE_CARD_SILENT_SPADES { + silent_suits.append(Suit::Spades); + } + }, + Option::None => { break Suit::None; } + } + }; + } + silent_suits +} + +fn contains_suit(suits: @Array, suit: Suit) -> bool { + let mut idx = 0; + loop { + if suits.len() == idx { + break false; + } + + if *suits[idx] == suit { + break true; + } + + idx += 1; + } +} diff --git a/src/utils/level.cairo b/src/utils/level.cairo new file mode 100644 index 0000000..0556de2 --- /dev/null +++ b/src/utils/level.cairo @@ -0,0 +1,13 @@ +use dojo::world::{IWorld, IWorldDispatcher, IWorldDispatcherTrait}; + +use jokers_of_neon::models::status::game::game::{Game, GameState, GameSubState}; +use jokers_of_neon::models::status::round::beast::BeastTrait; +use jokers_of_neon::store::{Store, StoreTrait}; +use jokers_of_neon::utils::random::{Random, RandomImpl, RandomTrait}; + +fn create_level(world: IWorldDispatcher, ref store: Store, game: Game) { + if true { + BeastTrait::create(world, ref store, game.id); + } +} + diff --git a/src/utils/round.cairo b/src/utils/round.cairo deleted file mode 100644 index 3affce9..0000000 --- a/src/utils/round.cairo +++ /dev/null @@ -1,56 +0,0 @@ -use dojo::world::{IWorld, IWorldDispatcher, IWorldDispatcherTrait}; -use jokers_of_neon::models::data::game_deck::{GameDeckStore, GameDeckImpl}; -use jokers_of_neon::models::status::game::game::Game; -use jokers_of_neon::models::status::game::rage::{RageRound, RageRoundStore}; -use jokers_of_neon::models::status::round::current_hand_card::CurrentHandCardTrait; -use jokers_of_neon::models::status::round::deck_card::DeckCardTrait; -use jokers_of_neon::models::status::round::round::Round; -use jokers_of_neon::store::{Store, StoreTrait}; -use jokers_of_neon::utils::constants::{RAGE_CARD_DIMINISHED_HOLD, RAGE_CARD_ZERO_WASTE}; -use jokers_of_neon::utils::rage::is_rage_card_active; - -fn create_round(world: IWorldDispatcher, game: Game) { - let mut game = game; - let mut store: Store = StoreTrait::new(world); - - // Active `Rage Cards` - let rage_round = RageRoundStore::get(world, game.id); - - if is_rage_card_active(@rage_round, RAGE_CARD_DIMINISHED_HOLD) { - game.len_hand -= 2; - store.set_game(game); - } - - let round_discards = if is_rage_card_active(@rage_round, RAGE_CARD_ZERO_WASTE) { - Zeroable::zero() - } else { - game.max_discard - }; - - let level_score = calculate_level_score(game.level); - - let mut round = Round { - game_id: game.id, player_score: 0, level_score, hands: game.max_hands, discard: round_discards, - }; - store.set_round(round); - - let mut game_deck = GameDeckStore::get(world, game.id); - game_deck.restore(world); - CurrentHandCardTrait::create(world, ref round, game); -} - -fn calculate_level_score(level: u32) -> u32 { - if level <= 2 { - 300 * level - } else if level <= 10 { - 600 * level - 600 - } else if level <= 20 { - 1200 * level - 6600 - } else if level <= 25 { - 3000 * level - 42600 - } else if level <= 30 { - 7000 * level - 142600 - } else { - 20000 * level - 532600 - } -}