From ec6d6f3ab369d480c69648c88544c364ed6d8365 Mon Sep 17 00:00:00 2001 From: Ajidokwu Sabo Date: Wed, 16 Jul 2025 19:33:04 +0100 Subject: [PATCH] chore fixed trading --- src/interfaces/IActions.cairo | 28 +- src/model/property_model.cairo | 72 +++ src/systems/actions.cairo | 864 +++++++++++++++++++++++++++++++-- src/tests/test_world.cairo | 827 +++++++++++++++++++++++++++++++ 4 files changed, 1755 insertions(+), 36 deletions(-) diff --git a/src/interfaces/IActions.cairo b/src/interfaces/IActions.cairo index 701e057..74c3cd3 100644 --- a/src/interfaces/IActions.cairo +++ b/src/interfaces/IActions.cairo @@ -1,7 +1,7 @@ use dojo_starter::model::game_model::{GameType, Game}; use dojo_starter::model::game_player_model::{PlayerSymbol, GamePlayer}; use dojo_starter::model::player_model::Player; -use dojo_starter::model::property_model::Property; +use dojo_starter::model::property_model::{Property, TradeOffer}; use dojo_starter::model::utility_model::Utility; use dojo_starter::model::rail_road_model::RailRoad; use dojo_starter::model::community_chest_model::CommunityChest; @@ -45,6 +45,32 @@ pub trait IActions { fn use_getout_of_jail_chance(ref self: T, game_id: u256) -> bool; fn use_getout_of_jail_community_chest(ref self: T, game_id: u256) -> bool; + fn offer_trade( + ref self: T, + game_id: u256, + to: ContractAddress, + offered_property_ids: Array, + requested_property_ids: Array, + cash_offer: u256, + cash_request: u256, + trade_type: TradeOffer, + ) -> u256; + + fn accept_trade(ref self: T, trade_id: u256, game_id: u256) -> bool; + + fn reject_trade(ref self: T, trade_id: u256, game_id: u256) -> bool; + + fn counter_trade( + ref self: T, + game_id: u256, + original_offer_id: u256, + offered_property_ids: Array, + requested_property_ids: Array, + cash_offer: u256, + cash_request: u256, + trade_type: TradeOffer, + ) -> u256; + // Dice & player movement fn roll_dice(ref self: T) -> (u8, u8); fn move_player(ref self: T, game_id: u256, steps: u8) -> u8; diff --git a/src/model/property_model.cairo b/src/model/property_model.cairo index 44bd328..a2a7845 100644 --- a/src/model/property_model.cairo +++ b/src/model/property_model.cairo @@ -1,5 +1,28 @@ use starknet::{ContractAddress, contract_address_const}; +#[derive(Serde, Copy, Drop, Introspect, PartialEq)] +#[dojo::model] +pub struct TradeCounter { + #[key] + pub id: felt252, + pub current_val: u256, +} + +#[derive(Clone, Drop, Serde)] +#[dojo::model] +pub struct TradeOfferDetails { + #[key] + pub id: u256, + pub from: ContractAddress, + pub to: ContractAddress, + pub game_id: u256, + pub offered_property_ids: Array, + pub requested_property_ids: Array, + pub cash_offer: u256, + pub cash_request: u256, + pub trade_type: TradeOffer, + pub status: TradeStatus, +} #[derive(Copy, Drop, Serde)] #[dojo::model] pub struct Property { @@ -38,6 +61,26 @@ pub enum PropertyType { VisitingJail, } +#[derive(Serde, Copy, Drop, Introspect, PartialEq, Debug)] +pub enum TradeOffer { + PropertyForProperty, + PropertyForCash, + CashForProperty, + CashPlusPropertyForProperty, + PropertyForCashPlusProperty, + CashForChanceJailCard, + CashForCommunityJailCard, + CommunityJailCardForCash, + ChanceJailCardForCash, +} + +#[derive(Serde, Copy, Drop, Introspect, PartialEq, Debug)] +pub enum TradeStatus { + Accepted, + Rejected, + Pending, +} + #[derive(Drop, Copy, Serde)] #[dojo::model] @@ -84,10 +127,39 @@ pub trait PropertyTrait { fn change_game_property_ownership( ref self: Property, new_owner: ContractAddress, owner: ContractAddress, ) -> bool; + // fn property_transfer( +// initiator_property: Property, initiator: GamePlayer, receiver: GamePlayer, +// ) -> (GamePlayer, GamePlayer, Property); } impl PropertyImpl of PropertyTrait { + // fn property_transfer( + // mut initiator_property: Property, mut initiator: GamePlayer, mut receiver: GamePlayer, + // ) -> (GamePlayer, GamePlayer, Property) { + // assert(initiator_property.game_id == receiver.game_id, 'Not in the same Game'); + + // // Update the property owner + // initiator_property.owner = receiver.address; + + // // Build a new properties array for initiator excluding the transferred property + // let mut new_properties = array![]; + // let mut i = 0; + // while (i < initiator.properties_owned.len()) { + // let prop = initiator.properties_owned[i]; + // if prop.property_id != initiator_property.property_id { + // new_properties.append(prop); + // } + // i += 1; + // }; + // initiator.properties_owned = new_properties; + + // // Add the property to receiver's properties + // receiver.properties_owned.append(initiator_property); + + // (initiator, receiver, initiator_property) + // } + fn new( id: u8, game_id: u256, diff --git a/src/systems/actions.cairo b/src/systems/actions.cairo index 34f2ee4..7c717e5 100644 --- a/src/systems/actions.cairo +++ b/src/systems/actions.cairo @@ -3,7 +3,8 @@ pub mod actions { use dojo_starter::interfaces::IActions::IActions; use dojo_starter::model::property_model::{ - Property, PropertyType, PropertyTrait, PropertyToId, IdToProperty, + Property, PropertyType, PropertyTrait, PropertyToId, IdToProperty, TradeOffer, + TradeOfferDetails, TradeCounter, TradeStatus, }; use dojo_starter::model::utility_model::{Utility, UtilityTrait, UtilityToId, IdToUtility}; use dojo_starter::model::rail_road_model::{RailRoad, RailRoadTrait, RailRoadToId, IdToRailRoad}; @@ -697,40 +698,788 @@ pub mod actions { } - // fn offer_trade( - // ref self: ContractState, - // game_id: u256, - // to: ContractAddress, - // offered_property_ids: Array, - // requested_property_ids: Array, - // cash_offer: u256, - // cash_request: u256, - // ) { - // let mut world = self.world_default(); - // let caller = get_caller_address(); - - // // Validate trade parameters - // assert(offered_property_ids.len() > 0 || cash_offer > 0, 'No properties or cash - // offered'); - // assert(requested_property_ids.len() > 0 || cash_request > 0, 'No properties or cash - // requested'); - - // // Ensure the recipient is a valid player in the game - // let recipient_username = self.get_username_from_address(to); - // assert(recipient_username != 0, 'Recipient not registered'); - - // // Create and store the trade offer - // let trade_id = world.get_next_trade_id(); - // let trade_offer = TradeOffer { - // trade_id, - // from: caller, - // to, - // offered_property_ids, - // requested_property_ids, - // cash_offer, - // cash_request, - // status: TradeStatus::Pending, - // }; + fn offer_trade( + ref self: ContractState, + game_id: u256, + to: ContractAddress, + offered_property_ids: Array, + requested_property_ids: Array, + cash_offer: u256, + cash_request: u256, + trade_type: TradeOffer, + ) -> u256 { + let caller = get_caller_address(); + + let mut world = self.world_default(); + let mut game: Game = world.read_model(game_id); + + assert!(game.next_player == caller, "Not your turn"); + assert!(game.status == GameStatus::Ongoing, "Game is not ongoing"); + + let id = self.create_trade_id(); + + // Validate inputs here (as you do) + let mut offer: TradeOfferDetails = world.read_model(id); + // Create the offer struct + + offer.id = id; + offer.from = caller; + offer.to = to; + offer.game_id = game_id; + offer.offered_property_ids = offered_property_ids; + offer.requested_property_ids = requested_property_ids; + offer.cash_offer = cash_offer; + offer.cash_request = cash_request; + offer.trade_type = trade_type; + offer.status = TradeStatus::Pending; + + world.write_model(@offer); + + id + } + + fn accept_trade(ref self: ContractState, trade_id: u256, game_id: u256) -> bool { + let mut world = self.world_default(); + let caller = get_caller_address(); + + let mut offer: TradeOfferDetails = world.read_model(trade_id); + assert!(caller == offer.to, "Only recipient can accept trade"); + + // Load offer + + let mut initiator: GamePlayer = world.read_model((offer.from, offer.game_id)); + let mut receiver: GamePlayer = world.read_model((offer.to, offer.game_id)); + + if offer.trade_type == TradeOffer::PropertyForCash { + // Transfer properties from initiator to receiver + let mut i = 0; + while i < offer.offered_property_ids.len() { + let prop_id = *offer.offered_property_ids[i]; + let mut property: Property = world.read_model((prop_id, game_id)); + + // Manual transfer of ownership + assert!( + property.owner == initiator.address, "Initiator does not own this property", + ); + property.owner = receiver.address; + + // Create a new array excluding the property being traded + let mut new_properties_owned: Array = ArrayTrait::new(); + let mut j = 0; + + while j < initiator.properties_owned.len() { + let owned_prop_id = *initiator.properties_owned[j]; + if owned_prop_id != prop_id { + new_properties_owned.append(owned_prop_id); + } + j += 1; + }; + + // Assign back the new array + initiator.properties_owned = new_properties_owned; + + // Now add the property to the receiver + receiver.properties_owned.append(prop_id); + match property.group_id { + 0 => {}, + 1 => receiver.no_section1 += 1, + 2 => receiver.no_section2 += 1, + 3 => receiver.no_section3 += 1, + 4 => receiver.no_section4 += 1, + 5 => receiver.no_section5 += 1, + 6 => receiver.no_section6 += 1, + 7 => receiver.no_section7 += 1, + 8 => receiver.no_section8 += 1, + _ => {}, + } + match property.group_id { + 0 => {}, + 1 => initiator.no_section1 -= 1, + 2 => initiator.no_section2 -= 1, + 3 => initiator.no_section3 -= 1, + 4 => initiator.no_section4 -= 1, + 5 => initiator.no_section5 -= 1, + 6 => initiator.no_section6 -= 1, + 7 => initiator.no_section7 -= 1, + 8 => initiator.no_section8 -= 1, + _ => {}, + } + + // Save updated property + world.write_model(@property); + + i += 1; + }; + + // Transfer cash from receiver to initiator + assert!(receiver.balance >= offer.cash_request, "Receiver has insufficient cash"); + receiver.balance -= offer.cash_request; + initiator.balance += offer.cash_request; + + // Persist updated players + world.write_model(@initiator); + world.write_model(@receiver); + } else if offer.trade_type == TradeOffer::PropertyForProperty { + // Transfer offered properties from initiator to receiver + let mut i = 0; + while i < offer.offered_property_ids.len() { + let prop_id = *offer.offered_property_ids[i]; + let mut property: Property = world.read_model((prop_id, game_id)); + + // Ensure the initiator owns it + assert!( + property.owner == initiator.address, "Initiator does not own this property", + ); + property.owner = receiver.address; + + // Remove from initiator properties_owned + let mut new_properties_owned: Array = ArrayTrait::new(); + let mut k = 0; + while k < initiator.properties_owned.len() { + let owned_prop_id = *initiator.properties_owned[k]; + if owned_prop_id != prop_id { + new_properties_owned.append(owned_prop_id); + } + k += 1; + }; + initiator.properties_owned = new_properties_owned; + + // Add to receiver properties_owned + receiver.properties_owned.append(prop_id); + + // Update section counters + match property.group_id { + 0 => {}, + 1 => { + receiver.no_section1 += 1; + initiator.no_section1 -= 1; + }, + 2 => { + receiver.no_section2 += 1; + initiator.no_section2 -= 1; + }, + 3 => { + receiver.no_section3 += 1; + initiator.no_section3 -= 1; + }, + 4 => { + receiver.no_section4 += 1; + initiator.no_section4 -= 1; + }, + 5 => { + receiver.no_section5 += 1; + initiator.no_section5 -= 1; + }, + 6 => { + receiver.no_section6 += 1; + initiator.no_section6 -= 1; + }, + 7 => { + receiver.no_section7 += 1; + initiator.no_section7 -= 1; + }, + 8 => { + receiver.no_section8 += 1; + initiator.no_section8 -= 1; + }, + _ => {}, + } + + // Write updated property + world.write_model(@property); + + i += 1; + }; + + // Transfer requested properties from receiver to initiator + let mut j = 0; + while j < offer.requested_property_ids.len() { + let prop_id = *offer.requested_property_ids[j]; + let mut property: Property = world.read_model((prop_id, game_id)); + + // Ensure the receiver owns it + assert!( + property.owner == receiver.address, "Receiver does not own this property", + ); + property.owner = initiator.address; + + // Remove from receiver properties_owned + let mut new_properties_owned: Array = ArrayTrait::new(); + let mut l = 0; + while l < receiver.properties_owned.len() { + let owned_prop_id = *receiver.properties_owned[l]; + if owned_prop_id != prop_id { + new_properties_owned.append(owned_prop_id); + } + l += 1; + }; + receiver.properties_owned = new_properties_owned; + + // Add to initiator properties_owned + initiator.properties_owned.append(prop_id); + + // Update section counters + match property.group_id { + 0 => {}, + 1 => { + initiator.no_section1 += 1; + receiver.no_section1 -= 1; + }, + 2 => { + initiator.no_section2 += 1; + receiver.no_section2 -= 1; + }, + 3 => { + initiator.no_section3 += 1; + receiver.no_section3 -= 1; + }, + 4 => { + initiator.no_section4 += 1; + receiver.no_section4 -= 1; + }, + 5 => { + initiator.no_section5 += 1; + receiver.no_section5 -= 1; + }, + 6 => { + initiator.no_section6 += 1; + receiver.no_section6 -= 1; + }, + 7 => { + initiator.no_section7 += 1; + receiver.no_section7 -= 1; + }, + 8 => { + initiator.no_section8 += 1; + receiver.no_section8 -= 1; + }, + _ => {}, + } + + // Write updated property + world.write_model(@property); + + j += 1; + }; + + // Write updated players + world.write_model(@initiator); + world.write_model(@receiver); + } else if offer.trade_type == TradeOffer::CashForProperty { + // Transfer cash from initiator to receiver + assert!(initiator.balance >= offer.cash_offer, "Initiator has insufficient cash"); + initiator.balance -= offer.cash_offer; + receiver.balance += offer.cash_offer; + + // Transfer requested properties from receiver to initiator + let mut j = 0; + while j < offer.requested_property_ids.len() { + let prop_id = *offer.requested_property_ids[j]; + let mut property: Property = world.read_model((prop_id, game_id)); + + // Ensure the receiver owns it + assert!( + property.owner == receiver.address, "Receiver does not own this property", + ); + property.owner = initiator.address; + + // Remove from receiver properties_owned + let mut new_properties_owned: Array = ArrayTrait::new(); + let mut l = 0; + while l < receiver.properties_owned.len() { + let owned_prop_id = *receiver.properties_owned[l]; + if owned_prop_id != prop_id { + new_properties_owned.append(owned_prop_id); + } + l += 1; + }; + receiver.properties_owned = new_properties_owned; + + // Add to initiator properties_owned + initiator.properties_owned.append(prop_id); + + // Update section counters + match property.group_id { + 0 => {}, + 1 => { + initiator.no_section1 += 1; + receiver.no_section1 -= 1; + }, + 2 => { + initiator.no_section2 += 1; + receiver.no_section2 -= 1; + }, + 3 => { + initiator.no_section3 += 1; + receiver.no_section3 -= 1; + }, + 4 => { + initiator.no_section4 += 1; + receiver.no_section4 -= 1; + }, + 5 => { + initiator.no_section5 += 1; + receiver.no_section5 -= 1; + }, + 6 => { + initiator.no_section6 += 1; + receiver.no_section6 -= 1; + }, + 7 => { + initiator.no_section7 += 1; + receiver.no_section7 -= 1; + }, + 8 => { + initiator.no_section8 += 1; + receiver.no_section8 -= 1; + }, + _ => {}, + } + + // Write updated property + world.write_model(@property); + + j += 1; + }; + + // Write updated players + world.write_model(@initiator); + world.write_model(@receiver); + } else if offer.trade_type == TradeOffer::CashPlusPropertyForProperty { + // Transfer offered properties from initiator to receiver + let mut i = 0; + while i < offer.offered_property_ids.len() { + let prop_id = *offer.offered_property_ids[i]; + let mut property: Property = world.read_model((prop_id, game_id)); + + // Ensure the initiator owns it + assert!( + property.owner == initiator.address, "Initiator does not own this property", + ); + property.owner = receiver.address; + + // Remove from initiator properties_owned + let mut new_properties_owned: Array = ArrayTrait::new(); + let mut k = 0; + while k < initiator.properties_owned.len() { + let owned_prop_id = *initiator.properties_owned[k]; + if owned_prop_id != prop_id { + new_properties_owned.append(owned_prop_id); + } + k += 1; + }; + initiator.properties_owned = new_properties_owned; + + // Add to receiver properties_owned + receiver.properties_owned.append(prop_id); + + // Update section counters + match property.group_id { + 0 => {}, + 1 => { + receiver.no_section1 += 1; + initiator.no_section1 -= 1; + }, + 2 => { + receiver.no_section2 += 1; + initiator.no_section2 -= 1; + }, + 3 => { + receiver.no_section3 += 1; + initiator.no_section3 -= 1; + }, + 4 => { + receiver.no_section4 += 1; + initiator.no_section4 -= 1; + }, + 5 => { + receiver.no_section5 += 1; + initiator.no_section5 -= 1; + }, + 6 => { + receiver.no_section6 += 1; + initiator.no_section6 -= 1; + }, + 7 => { + receiver.no_section7 += 1; + initiator.no_section7 -= 1; + }, + 8 => { + receiver.no_section8 += 1; + initiator.no_section8 -= 1; + }, + _ => {}, + } + + // Write updated property + world.write_model(@property); + + i += 1; + }; + + // Transfer cash from initiator to receiver + assert!(initiator.balance >= offer.cash_offer, "Initiator has insufficient cash"); + initiator.balance -= offer.cash_offer; + receiver.balance += offer.cash_offer; + + // Transfer requested properties from receiver to initiator + let mut j = 0; + while j < offer.requested_property_ids.len() { + let prop_id = *offer.requested_property_ids[j]; + let mut property: Property = world.read_model((prop_id, game_id)); + + // Ensure the receiver owns it + assert!( + property.owner == receiver.address, "Receiver does not own this property", + ); + property.owner = initiator.address; + + // Remove from receiver properties_owned + let mut new_properties_owned: Array = ArrayTrait::new(); + let mut l = 0; + while l < receiver.properties_owned.len() { + let owned_prop_id = *receiver.properties_owned[l]; + if owned_prop_id != prop_id { + new_properties_owned.append(owned_prop_id); + } + l += 1; + }; + receiver.properties_owned = new_properties_owned; + + // Add to initiator properties_owned + initiator.properties_owned.append(prop_id); + + // Update section counters + match property.group_id { + 0 => {}, + 1 => { + initiator.no_section1 += 1; + receiver.no_section1 -= 1; + }, + 2 => { + initiator.no_section2 += 1; + receiver.no_section2 -= 1; + }, + 3 => { + initiator.no_section3 += 1; + receiver.no_section3 -= 1; + }, + 4 => { + initiator.no_section4 += 1; + receiver.no_section4 -= 1; + }, + 5 => { + initiator.no_section5 += 1; + receiver.no_section5 -= 1; + }, + 6 => { + initiator.no_section6 += 1; + receiver.no_section6 -= 1; + }, + 7 => { + initiator.no_section7 += 1; + receiver.no_section7 -= 1; + }, + 8 => { + initiator.no_section8 += 1; + receiver.no_section8 -= 1; + }, + _ => {}, + } + + // Write updated property + world.write_model(@property); + + j += 1; + }; + + // Write updated players + world.write_model(@initiator); + world.write_model(@receiver); + } else if offer.trade_type == TradeOffer::PropertyForCashPlusProperty { + // Transfer offered properties from initiator to receiver + let mut i = 0; + while i < offer.offered_property_ids.len() { + let prop_id = *offer.offered_property_ids[i]; + let mut property: Property = world.read_model((prop_id, game_id)); + + // Ensure the initiator owns it + assert!( + property.owner == initiator.address, "Initiator does not own this property", + ); + property.owner = receiver.address; + + // Remove from initiator properties_owned + let mut new_properties_owned: Array = ArrayTrait::new(); + let mut k = 0; + while k < initiator.properties_owned.len() { + let owned_prop_id = *initiator.properties_owned[k]; + if owned_prop_id != prop_id { + new_properties_owned.append(owned_prop_id); + } + k += 1; + }; + initiator.properties_owned = new_properties_owned; + + // Add to receiver properties_owned + receiver.properties_owned.append(prop_id); + + // Update section counters + match property.group_id { + 0 => {}, + 1 => { + receiver.no_section1 += 1; + initiator.no_section1 -= 1; + }, + 2 => { + receiver.no_section2 += 1; + initiator.no_section2 -= 1; + }, + 3 => { + receiver.no_section3 += 1; + initiator.no_section3 -= 1; + }, + 4 => { + receiver.no_section4 += 1; + initiator.no_section4 -= 1; + }, + 5 => { + receiver.no_section5 += 1; + initiator.no_section5 -= 1; + }, + 6 => { + receiver.no_section6 += 1; + initiator.no_section6 -= 1; + }, + 7 => { + receiver.no_section7 += 1; + initiator.no_section7 -= 1; + }, + 8 => { + receiver.no_section8 += 1; + initiator.no_section8 -= 1; + }, + _ => {}, + } + + // Write updated property + world.write_model(@property); + + i += 1; + }; + + // Transfer cash from receiver to initiator + assert!(receiver.balance >= offer.cash_request, "Receiver has insufficient cash"); + receiver.balance -= offer.cash_request; + initiator.balance += offer.cash_request; + + // Transfer requested properties from receiver to initiator + let mut j = 0; + while j < offer.requested_property_ids.len() { + let prop_id = *offer.requested_property_ids[j]; + let mut property: Property = world.read_model((prop_id, game_id)); + + // Ensure the receiver owns it + assert!( + property.owner == receiver.address, "Receiver does not own this property", + ); + property.owner = initiator.address; + + // Remove from receiver properties_owned + let mut new_properties_owned: Array = ArrayTrait::new(); + let mut l = 0; + while l < receiver.properties_owned.len() { + let owned_prop_id = *receiver.properties_owned[l]; + if owned_prop_id != prop_id { + new_properties_owned.append(owned_prop_id); + } + l += 1; + }; + receiver.properties_owned = new_properties_owned; + + // Add to initiator properties_owned + initiator.properties_owned.append(prop_id); + + // Update section counters + match property.group_id { + 0 => {}, + 1 => { + initiator.no_section1 += 1; + receiver.no_section1 -= 1; + }, + 2 => { + initiator.no_section2 += 1; + receiver.no_section2 -= 1; + }, + 3 => { + initiator.no_section3 += 1; + receiver.no_section3 -= 1; + }, + 4 => { + initiator.no_section4 += 1; + receiver.no_section4 -= 1; + }, + 5 => { + initiator.no_section5 += 1; + receiver.no_section5 -= 1; + }, + 6 => { + initiator.no_section6 += 1; + receiver.no_section6 -= 1; + }, + 7 => { + initiator.no_section7 += 1; + receiver.no_section7 -= 1; + }, + 8 => { + initiator.no_section8 += 1; + receiver.no_section8 -= 1; + }, + _ => {}, + } + + // Write updated property + world.write_model(@property); + + j += 1; + }; + + // Write updated players + world.write_model(@initiator); + world.write_model(@receiver); + } else if offer.trade_type == TradeOffer::CashForChanceJailCard { + // Initiator pays cash to receiver for receiver's chance jail card + assert!(initiator.balance >= offer.cash_offer, "Initiator has insufficient cash"); + assert!(receiver.chance_jail_card, "Receiver does not have a chance jail card"); + assert!(!initiator.chance_jail_card, "Initiator already owns a chance jail card"); + + // Transfer cash + initiator.balance -= offer.cash_offer; + receiver.balance += offer.cash_offer; + + // Transfer the card + receiver.chance_jail_card = false; + initiator.chance_jail_card = true; + + // Write back players + world.write_model(@initiator); + world.write_model(@receiver); + } else if offer.trade_type == TradeOffer::CommunityJailCardForCash { + // Initiator pays cash to receiver for receiver's community jail card + assert!(initiator.balance >= offer.cash_offer, "Initiator has insufficient cash"); + assert!(receiver.comm_free_card, "Receiver does not have a community jail card"); + assert!(!initiator.comm_free_card, "Initiator already owns a community jail card"); + + // Transfer cash + initiator.balance -= offer.cash_offer; + receiver.balance += offer.cash_offer; + + // Transfer the card + receiver.comm_free_card = false; + initiator.comm_free_card = true; + + // Write back players + world.write_model(@initiator); + world.write_model(@receiver); + } else if offer.trade_type == TradeOffer::CashForCommunityJailCard { + // Receiver pays cash to initiator for initiator's community jail card + assert!(receiver.balance >= offer.cash_request, "Receiver has insufficient cash"); + assert!(initiator.comm_free_card, "Initiator does not have a community jail card"); + assert!(!receiver.comm_free_card, "Receiver already owns a community jail card"); + + // Transfer cash + receiver.balance -= offer.cash_request; + initiator.balance += offer.cash_request; + + // Transfer the card + initiator.comm_free_card = false; + receiver.comm_free_card = true; + + // Write back players + world.write_model(@initiator); + world.write_model(@receiver); + } else if offer.trade_type == TradeOffer::ChanceJailCardForCash { + // Receiver pays cash to initiator for initiator's chance jail card + assert!(receiver.balance >= offer.cash_request, "Receiver has insufficient cash"); + assert!(initiator.chance_jail_card, "Initiator does not have a chance jail card"); + assert!(!receiver.chance_jail_card, "Receiver already owns a chance jail card"); + + // Transfer cash + receiver.balance -= offer.cash_request; + initiator.balance += offer.cash_request; + + // Transfer the card + initiator.chance_jail_card = false; + receiver.chance_jail_card = true; + + // Write back players + world.write_model(@initiator); + world.write_model(@receiver); + } + + offer.status = TradeStatus::Accepted; + + // Save updated player and property data + world.write_model(@initiator); + world.write_model(@receiver); + world.write_model(@offer); + + true + } + + fn reject_trade(ref self: ContractState, trade_id: u256, game_id: u256) -> bool { + let mut world = self.world_default(); + let caller = get_caller_address(); + + let mut offer: TradeOfferDetails = world.read_model(trade_id); + assert!(caller == offer.to, "Only recipient can reject trade"); + offer.status = TradeStatus::Rejected; + + world.write_model(@offer); + + true + } + + fn counter_trade( + ref self: ContractState, + game_id: u256, + original_offer_id: u256, + offered_property_ids: Array, + requested_property_ids: Array, + cash_offer: u256, + cash_request: u256, + trade_type: TradeOffer, + ) -> u256 { + let caller = get_caller_address(); + + let mut world = self.world_default(); + let mut game: Game = world.read_model(game_id); + + assert!(game.status == GameStatus::Ongoing, "Game is not ongoing"); + + let mut original_offer: TradeOfferDetails = world.read_model(original_offer_id); + + // Ensure the caller is the recipient of the original offer + assert!( + original_offer.to == caller, "Only the receiver of the original trade can counter", + ); + + original_offer.id = original_offer.id; + original_offer.from = caller; // now the original receiver is offering + original_offer.to = original_offer.from; // the original initiator is now the receiver + original_offer.game_id = game_id; + original_offer.offered_property_ids = offered_property_ids; + original_offer.requested_property_ids = requested_property_ids; + original_offer.cash_offer = cash_offer; + original_offer.cash_request = cash_request; + original_offer.trade_type = trade_type; + original_offer.status = TradeStatus::Pending; + + world.write_model(@original_offer); + + original_offer.id + } + fn sell_house_or_hotel(ref self: ContractState, property_id: u8, game_id: u256) -> bool { let mut world = self.world_default(); @@ -2238,6 +2987,51 @@ pub mod actions { world.write_model(@game_counter); new_val } + + fn create_trade_id(ref self: ContractState) -> u256 { + let mut world = self.world_default(); + let mut trade_counter: TradeCounter = world.read_model('v0'); + let new_val = trade_counter.current_val + 1; + trade_counter.current_val = new_val; + world.write_model(@trade_counter); + new_val + } + + + fn property_transfer( + ref self: ContractState, + mut initiator_property: Property, + mut initiator: GamePlayer, + mut receiver: GamePlayer, + ) -> (GamePlayer, GamePlayer, Property) { + let mut world = self.world_default(); + assert(initiator_property.game_id == receiver.game_id, 'Not in the same Game'); + + // Update property owner + initiator_property.owner = receiver.address; + + // Build new properties array excluding the transferred property + let mut new_properties = array![]; + let mut i = 0; + while (i < initiator.properties_owned.len()) { + let prop_id = *initiator.properties_owned[i]; + let prop = self.get_property(prop_id, initiator.game_id); + if prop.id != initiator_property.id { + new_properties.append(prop.id); + } + i += 1; + }; + initiator.properties_owned = new_properties; + + // Add property to receiver's properties + receiver.properties_owned.append(initiator_property.id); + + world.write_model(@initiator); + world.write_model(@receiver); + world.write_model(@initiator_property); + + (initiator, receiver, initiator_property) + } } } diff --git a/src/tests/test_world.cairo b/src/tests/test_world.cairo index 1d4bb8a..a1cbef6 100644 --- a/src/tests/test_world.cairo +++ b/src/tests/test_world.cairo @@ -25,6 +25,8 @@ mod tests { use dojo_starter::model::property_model::{ Property, m_Property, IdToProperty, m_IdToProperty, PropertyToId, m_PropertyToId, + TradeCounter, m_TradeCounter, TradeOfferDetails, m_TradeOfferDetails, TradeOffer, + TradeStatus, }; use dojo_starter::model::utility_model::{ Utility, m_Utility, IdToUtility, m_IdToUtility, UtilityToId, m_UtilityToId, @@ -65,6 +67,8 @@ mod tests { TestResource::Model(m_Go::TEST_CLASS_HASH), TestResource::Model(m_Tax::TEST_CLASS_HASH), TestResource::Model(m_GamePlayer::TEST_CLASS_HASH), + TestResource::Model(m_TradeCounter::TEST_CLASS_HASH), + TestResource::Model(m_TradeOfferDetails::TEST_CLASS_HASH), TestResource::Event(actions::e_PlayerCreated::TEST_CLASS_HASH), TestResource::Event(actions::e_GameCreated::TEST_CLASS_HASH), TestResource::Event(actions::e_PlayerJoined::TEST_CLASS_HASH), @@ -2663,5 +2667,828 @@ mod tests { assert!(!pl.comm_free_card, "pl still has community jail card"); assert!(pl.position == 15, "pl.position not 15"); } + + #[test] + fn test_offer_trade_property_for_cash() { + let caller_1 = contract_address_const::<'aji'>(); + let caller_2 = contract_address_const::<'collins'>(); + let username = 'Ajidokwu'; + let username_1 = 'Collins'; + + let ndef = namespace_def(); + let mut world = spawn_test_world([ndef].span()); + world.sync_perms_and_inits(contract_defs()); + + let (contract_address, _) = world.dns(@"actions").unwrap(); + let actions_system = IActionsDispatcher { contract_address }; + + testing::set_contract_address(caller_2); + actions_system.register_new_player(username_1); + + testing::set_contract_address(caller_1); + actions_system.register_new_player(username); + + testing::set_contract_address(caller_1); + actions_system.create_new_game(GameType::PublicGame, PlayerSymbol::Hat, 4); + + testing::set_contract_address(caller_2); + actions_system.join_game(PlayerSymbol::Dog, 1); + + testing::set_contract_address(caller_1); + let started = actions_system.start_game(1); + assert(started, 'Game start fail'); + + let game_p = actions_system.retrieve_game(1); + + testing::set_contract_address(caller_1); + actions_system.move_player(1, 5); + let ppt = actions_system.get_property(5, 1); + + let buyppt = actions_system.buy_property(ppt); + + testing::set_contract_address(caller_2); + actions_system.move_player(1, 1); + let mut property = actions_system.get_property(1, 1); + + actions_system.buy_property(property); + + assert(buyppt, 'Buy property failed'); + + testing::set_contract_address(caller_1); + // let ppt = actions_system.get_property(5, 1); + + let mut offered_property_ids: Array = array![]; + let mut requested_property_ids: Array = array![]; + offered_property_ids.append(5); + requested_property_ids.append(1); + let mut trade_id = actions_system + .offer_trade( + 1, + caller_2, + offered_property_ids, + requested_property_ids, + 0, + 250, + TradeOffer::PropertyForCash, + ); + + println!("trade id : {} ", trade_id); + + actions_system.move_player(1, 5); + let g = actions_system.retrieve_game(1); + actions_system.finish_turn(g); + + testing::set_contract_address(caller_2); + let s = actions_system.accept_trade(1, 1); + assert(s, 'accept failed'); + + // requested_property_ids, cash_offer, cash_request, trade_type ); + + let aji = actions_system.retrieve_game_player(caller_1, 1); + let mut collins = actions_system.retrieve_game_player(caller_2, 1); + + actions_system.move_player(1, 5); + let ppt = actions_system.get_property(5, 1); + + let pptfelt: felt252 = ppt.owner.into(); + + assert(ppt.owner == caller_2, 'property tf failed'); + assert(aji.balance == 1550, 'debit failed'); + assert(aji.properties_owned.len() == 0, 'aji .len failed'); + assert(*collins.properties_owned[1] == ppt.id, 'ownership transfer failed'); + assert(aji.no_section1 == 0, 'Section update'); + assert(collins.no_section1 == 1, 'Section update'); + } + + #[test] + fn test_offer_trade_property_for_property() { + let caller_1 = contract_address_const::<'aji'>(); + let caller_2 = contract_address_const::<'collins'>(); + let username = 'Ajidokwu'; + let username_1 = 'Collins'; + + let ndef = namespace_def(); + let mut world = spawn_test_world([ndef].span()); + world.sync_perms_and_inits(contract_defs()); + + let (contract_address, _) = world.dns(@"actions").unwrap(); + let actions_system = IActionsDispatcher { contract_address }; + + testing::set_contract_address(caller_2); + actions_system.register_new_player(username_1); + + testing::set_contract_address(caller_1); + actions_system.register_new_player(username); + + testing::set_contract_address(caller_1); + actions_system.create_new_game(GameType::PublicGame, PlayerSymbol::Hat, 4); + + testing::set_contract_address(caller_2); + actions_system.join_game(PlayerSymbol::Dog, 1); + + testing::set_contract_address(caller_1); + let started = actions_system.start_game(1); + assert(started, 'Game start fail'); + + let game_p = actions_system.retrieve_game(1); + + testing::set_contract_address(caller_1); + actions_system.move_player(1, 6); + let ppt = actions_system.get_property(6, 1); + + let buyppt = actions_system.buy_property(ppt); + + testing::set_contract_address(caller_2); + actions_system.move_player(1, 1); + let mut property = actions_system.get_property(1, 1); + + actions_system.buy_property(property); + + assert(buyppt, 'Buy property failed'); + + testing::set_contract_address(caller_1); + // let ppt = actions_system.get_property(5, 1); + + let mut offered_property_ids: Array = array![]; + let mut requested_property_ids: Array = array![]; + offered_property_ids.append(6); + requested_property_ids.append(1); + let mut trade_id = actions_system + .offer_trade( + 1, + caller_2, + offered_property_ids, + requested_property_ids, + 0, + 0, + TradeOffer::PropertyForProperty, + ); + + println!("trade id : {} ", trade_id); + + actions_system.move_player(1, 5); + let g = actions_system.retrieve_game(1); + actions_system.finish_turn(g); + + testing::set_contract_address(caller_2); + let s = actions_system.accept_trade(1, 1); + assert(s, 'accept failed'); + + // requested_property_ids, cash_offer, cash_request, trade_type ); + + let aji = actions_system.retrieve_game_player(caller_1, 1); + let mut collins = actions_system.retrieve_game_player(caller_2, 1); + + actions_system.move_player(1, 5); + let ppt = actions_system.get_property(6, 1); + let ppp = actions_system.get_property(1, 1); + + let ppt_felt: felt252 = ppt.owner.into(); + let ppp_felt: felt252 = ppp.owner.into(); + + println!("ppt_felt : {}", ppt_felt); + println!("ppp_felt : {}", ppp_felt); + + assert(ppt.owner == caller_2, 'trade failed'); + assert(ppp.owner == caller_1, 'trade failed'); + assert(aji.no_section1 == 1, 'Section update'); + assert(collins.no_section1 == 0, 'Section update'); + assert(aji.no_section2 == 0, 'Section update'); + assert(collins.no_section2 == 1, 'Section update'); + } + + #[test] + fn test_offer_trade_cash_for_property() { + let caller_1 = contract_address_const::<'aji'>(); + let caller_2 = contract_address_const::<'collins'>(); + let username = 'Ajidokwu'; + let username_1 = 'Collins'; + + let ndef = namespace_def(); + let mut world = spawn_test_world([ndef].span()); + world.sync_perms_and_inits(contract_defs()); + + let (contract_address, _) = world.dns(@"actions").unwrap(); + let actions_system = IActionsDispatcher { contract_address }; + + testing::set_contract_address(caller_2); + actions_system.register_new_player(username_1); + + testing::set_contract_address(caller_1); + actions_system.register_new_player(username); + + testing::set_contract_address(caller_1); + actions_system.create_new_game(GameType::PublicGame, PlayerSymbol::Hat, 4); + + testing::set_contract_address(caller_2); + actions_system.join_game(PlayerSymbol::Dog, 1); + + testing::set_contract_address(caller_1); + let started = actions_system.start_game(1); + assert(started, 'Game start fail'); + + let game_p = actions_system.retrieve_game(1); + + testing::set_contract_address(caller_1); + actions_system.move_player(1, 6); + let ppt = actions_system.get_property(6, 1); + + let buyppt = actions_system.buy_property(ppt); + + testing::set_contract_address(caller_2); + actions_system.move_player(1, 1); + let mut property = actions_system.get_property(1, 1); + + actions_system.buy_property(property); + + assert(buyppt, 'Buy property failed'); + + testing::set_contract_address(caller_1); + // let ppt = actions_system.get_property(5, 1); + + let mut offered_property_ids: Array = array![]; + let mut requested_property_ids: Array = array![]; + offered_property_ids.append(6); + requested_property_ids.append(1); + let mut trade_id = actions_system + .offer_trade( + 1, + caller_2, + offered_property_ids, + requested_property_ids, + 250, + 0, + TradeOffer::CashForProperty, + ); + + println!("trade id : {} ", trade_id); + + actions_system.move_player(1, 5); + let g = actions_system.retrieve_game(1); + actions_system.finish_turn(g); + + testing::set_contract_address(caller_2); + let s = actions_system.accept_trade(1, 1); + assert(s, 'accept failed'); + + // requested_property_ids, cash_offer, cash_request, trade_type ); + + let aji = actions_system.retrieve_game_player(caller_1, 1); + let mut collins = actions_system.retrieve_game_player(caller_2, 1); + + actions_system.move_player(1, 5); + let ppt = actions_system.get_property(6, 1); + let ppp = actions_system.get_property(1, 1); + + let ppt_felt: felt252 = ppt.owner.into(); + let ppp_felt: felt252 = ppp.owner.into(); + + println!("aji balance : {} ", aji.balance); + println!("collins balance : {} ", collins.balance); + + assert(ppt.owner == caller_1, 'trade failed'); + assert(ppp.owner == caller_1, 'trade failed'); + assert(aji.no_section1 == 1, 'Section update'); + assert(collins.no_section1 == 0, 'Section update'); + assert(aji.no_section2 == 1, 'Section update'); + assert(collins.no_section2 == 0, 'Section update'); + } + #[test] + // fn test_offer_trade_property_for_cash_and_property() { + fn test_offer_cash_plus_property_for_property() { + let caller_1 = contract_address_const::<'aji'>(); + let caller_2 = contract_address_const::<'collins'>(); + let username = 'Ajidokwu'; + let username_1 = 'Collins'; + + let ndef = namespace_def(); + let mut world = spawn_test_world([ndef].span()); + world.sync_perms_and_inits(contract_defs()); + + let (contract_address, _) = world.dns(@"actions").unwrap(); + let actions_system = IActionsDispatcher { contract_address }; + + testing::set_contract_address(caller_2); + actions_system.register_new_player(username_1); + + testing::set_contract_address(caller_1); + actions_system.register_new_player(username); + + testing::set_contract_address(caller_1); + actions_system.create_new_game(GameType::PublicGame, PlayerSymbol::Hat, 4); + + testing::set_contract_address(caller_2); + actions_system.join_game(PlayerSymbol::Dog, 1); + + testing::set_contract_address(caller_1); + let started = actions_system.start_game(1); + assert(started, 'Game start fail'); + + let game_p = actions_system.retrieve_game(1); + + testing::set_contract_address(caller_1); + actions_system.move_player(1, 6); + let ppt = actions_system.get_property(6, 1); + + let buyppt = actions_system.buy_property(ppt); + + testing::set_contract_address(caller_2); + actions_system.move_player(1, 1); + let mut property = actions_system.get_property(1, 1); + + actions_system.buy_property(property); + + assert(buyppt, 'Buy property failed'); + + testing::set_contract_address(caller_1); + // let ppt = actions_system.get_property(5, 1); + + let mut offered_property_ids: Array = array![]; + let mut requested_property_ids: Array = array![]; + offered_property_ids.append(6); + requested_property_ids.append(1); + let mut trade_id = actions_system + .offer_trade( + 1, + caller_2, + offered_property_ids, + requested_property_ids, + 250, + 0, + TradeOffer::CashPlusPropertyForProperty, + ); + + println!("trade id : {} ", trade_id); + + actions_system.move_player(1, 5); + let g = actions_system.retrieve_game(1); + actions_system.finish_turn(g); + + testing::set_contract_address(caller_2); + let s = actions_system.accept_trade(1, 1); + assert(s, 'accept failed'); + + // requested_property_ids, cash_offer, cash_request, trade_type ); + + let aji = actions_system.retrieve_game_player(caller_1, 1); + let mut collins = actions_system.retrieve_game_player(caller_2, 1); + + actions_system.move_player(1, 5); + let ppt = actions_system.get_property(6, 1); + let ppp = actions_system.get_property(1, 1); + + let ppt_felt: felt252 = ppt.owner.into(); + let ppp_felt: felt252 = ppp.owner.into(); + + println!("ppt_felt : {}", ppt_felt); + println!("ppp_felt : {}", ppp_felt); + println!("aji balance : {} ", aji.balance); + println!("collins balance : {} ", collins.balance); + + assert(ppt.owner == caller_2, 'trade failed'); + assert(ppp.owner == caller_1, 'trade failed'); + assert(aji.no_section1 == 1, 'Section update'); + assert(collins.no_section1 == 0, 'Section update'); + assert(aji.no_section2 == 0, 'Section update'); + assert(collins.no_section2 == 1, 'Section update'); + } + #[test] + fn test_offer_trade_property_for_cash_and_property() { + let caller_1 = contract_address_const::<'aji'>(); + let caller_2 = contract_address_const::<'collins'>(); + let username = 'Ajidokwu'; + let username_1 = 'Collins'; + + let ndef = namespace_def(); + let mut world = spawn_test_world([ndef].span()); + world.sync_perms_and_inits(contract_defs()); + + let (contract_address, _) = world.dns(@"actions").unwrap(); + let actions_system = IActionsDispatcher { contract_address }; + + testing::set_contract_address(caller_2); + actions_system.register_new_player(username_1); + + testing::set_contract_address(caller_1); + actions_system.register_new_player(username); + + testing::set_contract_address(caller_1); + actions_system.create_new_game(GameType::PublicGame, PlayerSymbol::Hat, 4); + + testing::set_contract_address(caller_2); + actions_system.join_game(PlayerSymbol::Dog, 1); + + testing::set_contract_address(caller_1); + let started = actions_system.start_game(1); + assert(started, 'Game start fail'); + + let game_p = actions_system.retrieve_game(1); + + testing::set_contract_address(caller_1); + actions_system.move_player(1, 6); + let ppt = actions_system.get_property(6, 1); + + let buyppt = actions_system.buy_property(ppt); + + testing::set_contract_address(caller_2); + actions_system.move_player(1, 1); + let mut property = actions_system.get_property(1, 1); + + actions_system.buy_property(property); + + assert(buyppt, 'Buy property failed'); + + testing::set_contract_address(caller_1); + // let ppt = actions_system.get_property(5, 1); + + let mut offered_property_ids: Array = array![]; + let mut requested_property_ids: Array = array![]; + offered_property_ids.append(6); + requested_property_ids.append(1); + let mut trade_id = actions_system + .offer_trade( + 1, + caller_2, + offered_property_ids, + requested_property_ids, + 0, + 250, + TradeOffer::PropertyForCashPlusProperty, + ); + + println!("trade id : {} ", trade_id); + + actions_system.move_player(1, 5); + let g = actions_system.retrieve_game(1); + actions_system.finish_turn(g); + + testing::set_contract_address(caller_2); + let s = actions_system.accept_trade(1, 1); + assert(s, 'accept failed'); + + // requested_property_ids, cash_offer, cash_request, trade_type ); + + let aji = actions_system.retrieve_game_player(caller_1, 1); + let mut collins = actions_system.retrieve_game_player(caller_2, 1); + + actions_system.move_player(1, 5); + let ppt = actions_system.get_property(6, 1); + let ppp = actions_system.get_property(1, 1); + + let ppt_felt: felt252 = ppt.owner.into(); + let ppp_felt: felt252 = ppp.owner.into(); + + println!("ppt_felt : {}", ppt_felt); + println!("ppp_felt : {}", ppp_felt); + println!("aji balance : {} ", aji.balance); + println!("collins balance : {} ", collins.balance); + + assert(ppt.owner == caller_2, 'trade failed'); + assert(ppp.owner == caller_1, 'trade failed'); + assert(aji.no_section1 == 1, 'Section update'); + assert(collins.no_section1 == 0, 'Section update'); + assert(aji.no_section2 == 0, 'Section update'); + assert(collins.no_section2 == 1, 'Section update'); + } + + #[test] + fn test_offer_trade_cash_for_chaance_jail_card() { + let caller_1 = contract_address_const::<'aji'>(); + let caller_2 = contract_address_const::<'collins'>(); + let username = 'Ajidokwu'; + let username_1 = 'Collins'; + + let ndef = namespace_def(); + let mut world = spawn_test_world([ndef].span()); + world.sync_perms_and_inits(contract_defs()); + + let (contract_address, _) = world.dns(@"actions").unwrap(); + let actions_system = IActionsDispatcher { contract_address }; + + testing::set_contract_address(caller_2); + actions_system.register_new_player(username_1); + + testing::set_contract_address(caller_1); + actions_system.register_new_player(username); + + testing::set_contract_address(caller_1); + actions_system.create_new_game(GameType::PublicGame, PlayerSymbol::Hat, 4); + + testing::set_contract_address(caller_2); + actions_system.join_game(PlayerSymbol::Dog, 1); + + testing::set_contract_address(caller_1); + let started = actions_system.start_game(1); + assert(started, 'Game start fail'); + + let game_p = actions_system.retrieve_game(1); + + testing::set_contract_address(caller_1); + actions_system.move_player(1, 7); + let chance = "Get out of Jail Free"; + + let mut g = actions_system.retrieve_game(1); + let mut p = actions_system.retrieve_game_player(caller_1, 1); + + let (g, ply) = actions_system.process_chance_card(g.clone(), p, chance); + actions_system.finish_turn(g); + + testing::set_contract_address(caller_2); + actions_system.move_player(1, 1); + let mut property = actions_system.get_property(1, 1); + actions_system.buy_property(property); + + testing::set_contract_address(caller_1); + let mut ga = actions_system.retrieve_game(1); + actions_system.move_player(1, 1); + actions_system.finish_turn(ga); + + testing::set_contract_address(caller_2); + let mut offered_property_ids: Array = array![]; + let mut requested_property_ids: Array = array![]; + offered_property_ids.append(6); + requested_property_ids.append(1); + let mut trade_id = actions_system + .offer_trade( + 1, + caller_1, + offered_property_ids, + requested_property_ids, + 50, + 0, + TradeOffer::CashForChanceJailCard, + ); + + println!("trade id : {} ", trade_id); + + actions_system.move_player(1, 5); + let g = actions_system.retrieve_game(1); + actions_system.finish_turn(g); + + testing::set_contract_address(caller_1); + let s = actions_system.accept_trade(1, 1); + assert(s, 'accept failed'); + + let aji = actions_system.retrieve_game_player(caller_1, 1); + let mut collins = actions_system.retrieve_game_player(caller_2, 1); + + actions_system.move_player(1, 5); + + println!("aji balance : {} ", aji.balance); + println!("collins balance : {} ", collins.balance); + + assert(!aji.chance_jail_card, 'Section update'); + assert(collins.chance_jail_card, 'Section update'); + } + + #[test] + fn test_offer_trade_chance_jail_card_for_cash() { + let caller_1 = contract_address_const::<'aji'>(); + let caller_2 = contract_address_const::<'collins'>(); + let username = 'Ajidokwu'; + let username_1 = 'Collins'; + + let ndef = namespace_def(); + let mut world = spawn_test_world([ndef].span()); + world.sync_perms_and_inits(contract_defs()); + + let (contract_address, _) = world.dns(@"actions").unwrap(); + let actions_system = IActionsDispatcher { contract_address }; + + testing::set_contract_address(caller_2); + actions_system.register_new_player(username_1); + + testing::set_contract_address(caller_1); + actions_system.register_new_player(username); + + testing::set_contract_address(caller_1); + actions_system.create_new_game(GameType::PublicGame, PlayerSymbol::Hat, 4); + + testing::set_contract_address(caller_2); + actions_system.join_game(PlayerSymbol::Dog, 1); + + testing::set_contract_address(caller_1); + let started = actions_system.start_game(1); + assert(started, 'Game start fail'); + + let game_p = actions_system.retrieve_game(1); + + testing::set_contract_address(caller_1); + actions_system.move_player(1, 7); + let chance = "Get out of Jail Free"; + + let mut g = actions_system.retrieve_game(1); + let mut p = actions_system.retrieve_game_player(caller_1, 1); + + let (g, ply) = actions_system.process_chance_card(g.clone(), p, chance); + actions_system.finish_turn(g.clone()); + + testing::set_contract_address(caller_2); + actions_system.move_player(1, 1); + actions_system.finish_turn(g); + + testing::set_contract_address(caller_1); + let mut offered_property_ids: Array = array![]; + let mut requested_property_ids: Array = array![]; + offered_property_ids.append(6); + requested_property_ids.append(1); + let mut trade_id = actions_system + .offer_trade( + 1, + caller_2, + offered_property_ids, + requested_property_ids, + 0, + 50, + TradeOffer::ChanceJailCardForCash, + ); + + println!("trade id : {} ", trade_id); + + actions_system.move_player(1, 5); + let g = actions_system.retrieve_game(1); + actions_system.finish_turn(g); + + testing::set_contract_address(caller_2); + let s = actions_system.accept_trade(1, 1); + assert(s, 'accept failed'); + + let aji = actions_system.retrieve_game_player(caller_1, 1); + let mut collins = actions_system.retrieve_game_player(caller_2, 1); + + actions_system.move_player(1, 5); + + println!("aji balance : {} ", aji.balance); + println!("collins balance : {} ", collins.balance); + + assert(!aji.chance_jail_card, 'Section update'); + assert(collins.chance_jail_card, 'Section update'); + } + + #[test] + fn test_offer_trade_cash_for_community_jail_card() { + let caller_1 = contract_address_const::<'aji'>(); + let caller_2 = contract_address_const::<'collins'>(); + let username = 'Ajidokwu'; + let username_1 = 'Collins'; + + let ndef = namespace_def(); + let mut world = spawn_test_world([ndef].span()); + world.sync_perms_and_inits(contract_defs()); + + let (contract_address, _) = world.dns(@"actions").unwrap(); + let actions_system = IActionsDispatcher { contract_address }; + + testing::set_contract_address(caller_2); + actions_system.register_new_player(username_1); + + testing::set_contract_address(caller_1); + actions_system.register_new_player(username); + + testing::set_contract_address(caller_1); + actions_system.create_new_game(GameType::PublicGame, PlayerSymbol::Hat, 4); + + testing::set_contract_address(caller_2); + actions_system.join_game(PlayerSymbol::Dog, 1); + + testing::set_contract_address(caller_1); + let started = actions_system.start_game(1); + assert(started, 'Game start fail'); + + let game_p = actions_system.retrieve_game(1); + + testing::set_contract_address(caller_1); + actions_system.move_player(1, 2); + let chance = "Get Out of Jail Free"; + + let mut g = actions_system.retrieve_game(1); + let mut p = actions_system.retrieve_game_player(caller_1, 1); + + let (g, ply) = actions_system.process_community_chest_card(g.clone(), p, chance); + actions_system.finish_turn(g); + + p = actions_system.retrieve_game_player(caller_1, 1); + assert!(p.comm_free_card, "p does not have community jail card"); + + testing::set_contract_address(caller_2); + actions_system.move_player(1, 1); + let mut property = actions_system.get_property(1, 1); + actions_system.buy_property(property); + + testing::set_contract_address(caller_1); + let mut offered_property_ids: Array = array![]; + let mut requested_property_ids: Array = array![]; + offered_property_ids.append(6); + requested_property_ids.append(1); + let mut trade_id = actions_system + .offer_trade( + 1, + caller_2, + offered_property_ids, + requested_property_ids, + 0, + 50, + TradeOffer::CashForCommunityJailCard, + ); + + println!("trade id : {} ", trade_id); + + actions_system.move_player(1, 2); + let g = actions_system.retrieve_game(1); + actions_system.finish_turn(g); + + testing::set_contract_address(caller_2); + let s = actions_system.accept_trade(1, 1); + assert(s, 'accept failed'); + + let aji = actions_system.retrieve_game_player(caller_1, 1); + let mut collins = actions_system.retrieve_game_player(caller_2, 1); + + actions_system.move_player(1, 5); + + println!("aji balance : {} ", aji.balance); + println!("collins balance : {} ", collins.balance); + + assert(!aji.comm_free_card, 'Section update'); + assert(collins.comm_free_card, 'Section update'); + } + + #[test] + fn test_offer_trade_community_jail_card_for_cash() { + let caller_1 = contract_address_const::<'aji'>(); + let caller_2 = contract_address_const::<'collins'>(); + let username = 'Ajidokwu'; + let username_1 = 'Collins'; + + let ndef = namespace_def(); + let mut world = spawn_test_world([ndef].span()); + world.sync_perms_and_inits(contract_defs()); + + let (contract_address, _) = world.dns(@"actions").unwrap(); + let actions_system = IActionsDispatcher { contract_address }; + + testing::set_contract_address(caller_2); + actions_system.register_new_player(username_1); + + testing::set_contract_address(caller_1); + actions_system.register_new_player(username); + + testing::set_contract_address(caller_1); + actions_system.create_new_game(GameType::PublicGame, PlayerSymbol::Hat, 4); + + testing::set_contract_address(caller_2); + actions_system.join_game(PlayerSymbol::Dog, 1); + + testing::set_contract_address(caller_1); + let started = actions_system.start_game(1); + assert(started, 'Game start fail'); + + let game_p = actions_system.retrieve_game(1); + + testing::set_contract_address(caller_1); + actions_system.move_player(1, 2); + let chance = "Get Out of Jail Free"; + + let mut g = actions_system.retrieve_game(1); + let mut p = actions_system.retrieve_game_player(caller_1, 1); + + let (g, ply) = actions_system.process_community_chest_card(g.clone(), p, chance); + actions_system.finish_turn(g); + + p = actions_system.retrieve_game_player(caller_1, 1); + assert!(p.comm_free_card, "p does not have community jail card"); + + testing::set_contract_address(caller_2); + let mut offered_property_ids: Array = array![]; + let mut requested_property_ids: Array = array![]; + offered_property_ids.append(6); + requested_property_ids.append(1); + let mut trade_id = actions_system + .offer_trade( + 1, + caller_1, + offered_property_ids, + requested_property_ids, + 50, + 0, + TradeOffer::CommunityJailCardForCash, + ); + + println!("trade id : {} ", trade_id); + + actions_system.move_player(1, 5); + let g = actions_system.retrieve_game(1); + actions_system.finish_turn(g); + + testing::set_contract_address(caller_1); + let s = actions_system.accept_trade(1, 1); + assert(s, 'accept failed'); + + let aji = actions_system.retrieve_game_player(caller_1, 1); + let mut collins = actions_system.retrieve_game_player(caller_2, 1); + + assert(!aji.comm_free_card, 'Section update'); + assert(collins.comm_free_card, 'Section update'); + } }