From af65e226ded02ee7c66f2954efd0c450bac86a41 Mon Sep 17 00:00:00 2001 From: notV4l Date: Fri, 12 Apr 2024 00:48:28 +0200 Subject: [PATCH] new encounters wip --- Scarb.toml | 8 +- scripts/default_auth.sh | 8 +- src/config/config.cairo | 21 +- src/config/encounters.cairo | 334 ++++++++++------- src/config/game.cairo | 26 +- src/config/hustlers.cairo | 8 +- src/models/game.cairo | 4 +- src/systems/game.cairo | 9 +- src/systems/ryo.cairo | 4 +- src/systems/traveling.cairo | 285 ++++++--------- src/utils/bits.cairo | 5 +- web/manifest.json | 139 +++---- web/package.json | 2 +- .../pages/admin/GameConfigTable.tsx | 2 + .../pages/profile/HustlerProfile.tsx | 13 - web/src/dojo/abis/configAbi.ts | 33 +- web/src/dojo/class/Game.ts | 4 - web/src/dojo/events.ts | 14 +- web/src/dojo/generated/contractEvents.ts | 20 +- web/src/dojo/hooks/useSystems.ts | 16 +- web/src/dojo/types.ts | 8 +- web/src/generated/graphql.ts | 81 ++--- web/src/pages/[gameId]/event/consequence.tsx | 12 +- web/src/pages/[gameId]/event/decision.tsx | 344 ++++++++---------- web/src/pages/[gameId]/logs.tsx | 13 +- web/src/pages/create/new.tsx | 15 +- 26 files changed, 645 insertions(+), 783 deletions(-) diff --git a/Scarb.toml b/Scarb.toml index 1d2b06b5..bb93f0c4 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -15,7 +15,7 @@ token = { git = "https://github.com/notV4l/origami", branch = "erc_without_event [scripts] # dope_mock = "./scripts/dope_mock.sh" -katana = "katana --disable-fee --invoke-max-steps 999999999" +katana = "katana --disable-fee --invoke-max-steps 2000000" build = "sozo build && scarb run gendojo" gendojo = "./scripts/gen.sh" @@ -26,17 +26,17 @@ auth_ryo421 = "./scripts/default_auth.sh ryo421" auth_prod = "./scripts/default_auth.sh prod" # migrate -migrate = "sozo migrate apply && scarb run gendojo && scarb run auth" +migrate = "sozo migrate apply && scarb run auth && scarb run gendojo" migrate_ryo420 = "sozo -P ryo420 build && sozo -P ryo420 migrate apply && scarb run auth_ryo420" migrate_ryo421 = "sozo -P ryo421 build && sozo -P ryo421 migrate apply && scarb run auth_ryo421" migrate_prod = "sozo -P prod migrate" # slot ryo420 -slot_ryo420_katana="slot d create ryo420 katana --seed 420 --version v0.6.0 --chain-id KATANA_SLOT_420 --disable-fee true" +slot_ryo420_katana="slot d create ryo420 katana --seed 420 --version v0.6.0 --chain-id KATANA_SLOT_420 --disable-fee true --invoke-max-steps 2000000" slot_ryo420_torii="slot d create ryo420 torii --rpc https://api.cartridge.gg/x/ryo420/katana -s 0 --version v0.6.0 --world 0x3bf84ccc82282acd4c8afbb843c9e864bf1e0770fba607595104202b938b7a4" # slot ryo421 -slot_ryo421_katana="slot d create ryo421 katana --seed 421 --version v0.6.0 --chain-id KATANA_SLOT_421 --disable-fee true" +slot_ryo421_katana="slot d create ryo421 katana --seed 421 --version v0.6.0 --chain-id KATANA_SLOT_421 --disable-fee true --invoke-max-steps 2000000" slot_ryo421_torii="slot d create ryo421 torii --rpc https://api.cartridge.gg/x/ryo421/katana -s 0 --version v0.6.0 --world 0x3bf84ccc82282acd4c8afbb843c9e864bf1e0770fba607595104202b938b7a4" diff --git a/scripts/default_auth.sh b/scripts/default_auth.sh index 844ae793..5a4837cf 100755 --- a/scripts/default_auth.sh +++ b/scripts/default_auth.sh @@ -65,8 +65,12 @@ sozo -P $PROFILE execute --world $WORLD_ADDRESS $RYO_ADDRESS initialize --calld echo "Initialized RYO!" sleep $TX_SLEEP -sozo -P $PROFILE execute --world $WORLD_ADDRESS $CONFIG_ADDRESS initialize --wait -echo "Initialized CONFIG!" +sozo -P $PROFILE execute --world $WORLD_ADDRESS $CONFIG_ADDRESS initialize_1 --wait +echo "Initialized CONFIG 1!" +sleep $TX_SLEEP + +sozo -P $PROFILE execute --world $WORLD_ADDRESS $CONFIG_ADDRESS initialize_2 --wait +echo "Initialized CONFIG 2!" sleep $TX_SLEEP # remove later diff --git a/src/config/config.cairo b/src/config/config.cairo index e6125715..712a5f77 100644 --- a/src/config/config.cairo +++ b/src/config/config.cairo @@ -6,7 +6,8 @@ use rollyourown::config::{ #[starknet::interface] trait IConfig { - fn initialize(self: @T); + fn initialize_1(self: @T); + fn initialize_2(self: @T); fn get_config(self: @T) -> Config; fn update_game_config(self: @T, game_config: GameConfig); fn update_drug_config(self: @T, drug_config: DrugConfig); @@ -69,16 +70,17 @@ mod config { #[abi(embed_v0)] impl ConfigImpl of super::IConfig { - fn initialize(self: @ContractState) { + fn initialize_1(self: @ContractState) { // TODO checks self.assert_caller_is_owner(); let world = self.world(); // common + initialize_game_config(world); // must be set before encounters + initialize_drug_config(world); initialize_location_config(world); - //initialize_item_config(world); // hustlers items initialize_weapons_config(world); @@ -91,12 +93,17 @@ mod config { initialize_clothes_tiers_config(world); initialize_feet_tiers_config(world); initialize_transport_tiers_config(world); + + } + + fn initialize_2(self: @ContractState) { + // TODO checks + self.assert_caller_is_owner(); + let world = self.world(); + // encounters initialize_encounter_config(world); - - // game - initialize_game_config(world); } fn get_config(self: @ContractState) -> Config { @@ -150,7 +157,7 @@ mod config { }; // - + // TODO: remove & use torii let game_config = GameConfigImpl::get(world); // diff --git a/src/config/encounters.cairo b/src/config/encounters.cairo index e8b96d50..059f60c7 100644 --- a/src/config/encounters.cairo +++ b/src/config/encounters.cairo @@ -1,13 +1,45 @@ use starknet::ContractAddress; use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait}; use rollyourown::{ + config::game::{GameConfig, GameConfigImpl}, utils::{ random::{Random, RandomImpl}, math::{MathTrait, MathImplU8}, bits::{Bits, BitsImpl, BitsTrait, BitsMathImpl}, bytes16::{Bytes16, Bytes16Impl, Bytes16Trait} - } + }, + packing::{ + game_store::{GameStore}, + }, }; +// +// +// + +#[derive(Copy, Drop, Serde, PartialEq, Introspect)] +enum Encounters { + Cops, + Gang, +} + +impl EncountersIntoFelt252 of Into { + fn into(self: Encounters) -> felt252 { + match self { + Encounters::Cops => 'Cops', + Encounters::Gang => 'Gang', + } + } +} + +impl EncountersIntoU8 of Into { + fn into(self: Encounters) -> u8 { + match self { + Encounters::Cops => 0, + Encounters::Gang => 1, + } + } +} + // // @@ -23,17 +55,18 @@ struct EncounterConfig { // level: u8, health: u8, - attack: u8, - defense: u8, + attack: u8, // * + defense: u8, // * speed: u8, - // 32 + // payout: u32, - // 32 + // demand_pct: u8, + // rep_pay: u8, // reputation modifier for paying NEGATIVE - rep_run: u8, // reputation modifier for running + rep_run: u8, // reputation modifier for running POSITIVE(success) or NEGATIVE(fail) rep_fight: u8, // reputation modifier for fighting - // 16 + // min_rep: u8, max_rep: u8, // @@ -53,52 +86,155 @@ impl EncounterConfigImpl of EncounterConfigTrait { fn get(world: IWorldDispatcher, id: u8) -> EncounterConfig { get!(world, (id), EncounterConfig) } + + fn add_encounter(world: IWorldDispatcher,ref encounter: EncounterConfig, ref game_config: GameConfig) { + // override id + encounter.id = game_config.encounter_count; + + // create encounter + set!(world, (encounter)); + + // update total encounter count + game_config.encounter_count += 1; + } } // // // -#[derive(Copy, Drop, Serde, PartialEq, Introspect)] -enum Encounters { - Cops, - Gang, -} +#[generate_trait] +impl EncounterImpl of EncounterTrait { + fn get_encounters_ids_by_rep(world: IWorldDispatcher, rep: u8) -> Span { + let mut game_config = GameConfigImpl::get(world); + let mut encounters_ids = array![]; -impl EncountersIntoFelt252 of Into { - fn into(self: Encounters) -> felt252 { - match self { - Encounters::Cops => 'Cops', - Encounters::Gang => 'Gang', - } + let mut id = 0; + + loop { + if id == game_config.encounter_count { + break; + } + + let encounter = get!(world, (id), (EncounterConfig)); + + if rep >= encounter.min_rep && rep < encounter.max_rep { + encounters_ids.append(encounter.id); + }; + + id += 1; + }; + + encounters_ids.span() } -} -impl EncountersIntoU8 of Into { - fn into(self: Encounters) -> u8 { - match self { - Encounters::Cops => 0, - Encounters::Gang => 1, - } + fn get_encounter(ref game_store: GameStore) -> EncounterConfig { + let rep = game_store.player.reputation; + + let encounters_ids = EncounterImpl::get_encounters_ids_by_rep(game_store.world, rep); + + let rand_from_game_store: u256 = pedersen::pedersen( + game_store.markets.packed, game_store.markets.packed + ).into(); + + let rand_index = rand_from_game_store % encounters_ids.len().into(); + let rand_id = *encounters_ids.at(rand_index.try_into().unwrap()); + + get!(game_store.world, (rand_id), (EncounterConfig)) } } - // // // +fn initialize_encounter_config(world: IWorldDispatcher) { + + let mut game_config = GameConfigImpl::get(world); + // COPS -fn initialize_encounter_config(world: IWorldDispatcher) { + let mut i = 0; + loop { + if i == 6 { + break; + } + + let lvl = i+1; + let mut encounter = EncounterConfig { + id:0, // overrided + encounter: Encounters::Cops, + // + level: lvl, + health: lvl * 9, + attack: lvl * 11, + defense: lvl * 7, + speed : lvl * 8, + // + payout: 2500_u32 * lvl.into(), + demand_pct: 20, + // + rep_pay: lvl + 5, + rep_run: lvl, + rep_fight: lvl + 2, + // + min_rep: i * 15, + max_rep: (i * 15) + 25, + }; + + EncounterConfigImpl::add_encounter(world,ref encounter, ref game_config); + i += 1; + }; + + + // GANG + + let mut i = 0; + loop { + if i == 6 { + break; + } + + let lvl = i+1; + let mut encounter = EncounterConfig { + id:0, // overrided + encounter: Encounters::Gang, + // + level: lvl, + health: lvl * 11, + attack: lvl * 10, + defense: lvl * 6, + speed : lvl * 6, + // + payout: 2000_u32 * lvl.into(), + demand_pct: 20, + // + rep_pay: lvl + 5, + rep_run: lvl, + rep_fight: lvl + 2, + // + min_rep: i * 15, + max_rep: (i * 15) + 25, + }; + + EncounterConfigImpl::add_encounter(world,ref encounter, ref game_config); + i += 1; + }; + + // save encounter_count + GameConfigImpl::set(world, game_config); + + initialize_encounter_config_extra(world); +} + +fn initialize_encounter_config_extra(world: IWorldDispatcher) { + + let mut game_config = GameConfigImpl::get(world); //////// COPS //////// - set!( - world, - EncounterConfig { - // name: Bytes16Impl::from('Cops LVL 1'), - id:0, + let mut cops1 = EncounterConfig { + id:0, // overrided encounter: Encounters::Cops, // level: 1, @@ -107,7 +243,7 @@ fn initialize_encounter_config(world: IWorldDispatcher) { defense: 5, speed : 2, // - payout: 420, + payout: 4200, demand_pct: 20, // rep_pay: 10, @@ -116,77 +252,50 @@ fn initialize_encounter_config(world: IWorldDispatcher) { // min_rep: 0, max_rep: 40, - } - ); + }; + - set!( - world, - EncounterConfig { - // name: Bytes16Impl::from('Cops LVL 2'), - id:1, + let mut cops2 = EncounterConfig { + id:0, encounter: Encounters::Cops, // - level: 2, + level: 3, health: 26, attack: 16, defense: 11, - speed : 5, + speed : 14, // - payout: 2500, + payout: 42000, demand_pct: 30, // rep_pay: 6, rep_run: 2, rep_fight: 4, // - min_rep: 20, - max_rep: 60, - } - ); - - set!( - world, - EncounterConfig { - // name: Bytes16Impl::from('Cops LVL 3'), - id:2, - encounter: Encounters::Cops, - // - level: 3, - health: 42, - attack: 25, - defense: 15, - speed : 15, - // - payout: 20000, - demand_pct: 30, - // - rep_pay: 5, - rep_run: 3, - rep_fight: 6, - // min_rep: 40, max_rep: 100, - } - ); + }; + + + + EncounterConfigImpl::add_encounter(world,ref cops1, ref game_config ); + EncounterConfigImpl::add_encounter(world,ref cops2, ref game_config ); //////// GANGS //////// - set!( - world, - EncounterConfig { - // name: Bytes16Impl::from('GANG LVL 1'), - id:7, + let mut gang1 = EncounterConfig { + id:0, encounter: Encounters::Gang, // - level: 1, - health: 16, - attack: 8, - defense: 5, - speed : 2, + level: 2, + health: 40, + attack: 25, + defense: 15, + speed : 20, // - payout: 420, - demand_pct: 20, + payout: 20000, + demand_pct: 50, // rep_pay: 10, rep_run: 0, @@ -194,57 +303,34 @@ fn initialize_encounter_config(world: IWorldDispatcher) { // min_rep: 0, max_rep: 40, - } - ); + }; - set!( - world, - EncounterConfig { - // name: Bytes16Impl::from('GANG LVL 2'), - id:8, + let mut gang2 = EncounterConfig { + id:0, encounter: Encounters::Gang, // - level: 2, - health: 26, - attack: 16, - defense: 11, - speed : 5, + level: 4, + health: 60, + attack: 45, + defense: 25, + speed : 35, // - payout: 2500, - demand_pct: 30, + payout: 50000, + demand_pct: 60, // rep_pay: 6, rep_run: 2, rep_fight: 4, // - min_rep: 20, - max_rep: 60, - } - ); - - set!( - world, - EncounterConfig { - // name: Bytes16Impl::from('GANG LVL 3'), - id:9, - encounter: Encounters::Gang, - // - level: 3, - health: 42, - attack: 25, - defense: 15, - speed : 15, - // - payout: 20000, - demand_pct: 30, - // - rep_pay: 5, - rep_run: 3, - rep_fight: 6, - // min_rep: 40, max_rep: 100, - } - ); + }; -} \ No newline at end of file + + EncounterConfigImpl::add_encounter(world,ref gang1, ref game_config ); + EncounterConfigImpl::add_encounter(world,ref gang2, ref game_config ); + + // save encounter_count + GameConfigImpl::set(world, game_config); + +} diff --git a/src/config/game.cairo b/src/config/game.cairo index c69c76e2..72038f30 100644 --- a/src/config/game.cairo +++ b/src/config/game.cairo @@ -8,19 +8,18 @@ struct GameConfig { key: u8, cash: u32, // initial cash health: u8, // initial health 0-100 + // max_turns: u8, // max game turn u6 : max 63 max_wanted_shopping: u8, // limit to enter pawnshop max_rounds: u8, // max loop when running + // + encounter_count: u8, // total nb of encounters + // rep_drug_step: u8, // reputation requiered to level up drug rep_buy_item: u8, // reputation earn when buying item rep_carry_drugs: u8, // reputation earn when traveling with >5 drug.quantity - rep_pay_cops: u8, // reputation modifier for paying NEGATIVE - rep_pay_gang: u8, // reputation modifier for paying NEGATIVE - rep_run_cops: u8, // reputation modifier for running - rep_run_gang: u8, // reputation modifier for running - rep_fight_cops: u8, // reputation modifier for fighting - rep_fight_gang: u8, // reputation modifier for fighting - + rep_hospitalized: u8, // reputation earn when Hospitalized + rep_jailed: u8, // reputation earn when Jailed } #[generate_trait] @@ -46,19 +45,18 @@ fn initialize_game_config(world: IWorldDispatcher) { key: GAME_CONFIG_KEY, cash: 1000, health: 100, + // max_turns: 30, max_wanted_shopping: 5, max_rounds: 3, + // + encounter_count: 0, + // rep_drug_step: 20, rep_buy_item: 1, rep_carry_drugs: 2, - rep_pay_cops: 6, // NEGATIVE - rep_pay_gang: 3, // NEGATIVE - rep_run_cops: 3, - rep_run_gang: 1, - rep_fight_cops: 4, - rep_fight_gang: 3, - + rep_hospitalized: 3, + rep_jailed: 4, } ); } diff --git a/src/config/hustlers.cairo b/src/config/hustlers.cairo index 58cdc5a7..74001af7 100644 --- a/src/config/hustlers.cairo +++ b/src/config/hustlers.cairo @@ -447,25 +447,25 @@ fn initialize_feet_tiers_config(world: IWorldDispatcher) { set!( world, HustlerItemTiersConfig { - slot: ItemSlot::Feet, slot_id: ItemSlot::Feet.into(), tier: 3, stat: 18, cost: 1_600, + slot: ItemSlot::Feet, slot_id: ItemSlot::Feet.into(), tier: 3, stat: 25, cost: 1_600, } ); set!( world, HustlerItemTiersConfig { - slot: ItemSlot::Feet, slot_id: ItemSlot::Feet.into(), tier: 4, stat: 27, cost: 9_600, + slot: ItemSlot::Feet, slot_id: ItemSlot::Feet.into(), tier: 4, stat: 40, cost: 9_600, } ); set!( world, HustlerItemTiersConfig { - slot: ItemSlot::Feet, slot_id: ItemSlot::Feet.into(), tier: 5, stat: 36, cost: 58_000, + slot: ItemSlot::Feet, slot_id: ItemSlot::Feet.into(), tier: 5, stat: 55, cost: 58_000, } ); set!( world, HustlerItemTiersConfig { - slot: ItemSlot::Feet, slot_id: ItemSlot::Feet.into(), tier: 6, stat: 45, cost: 345_000, + slot: ItemSlot::Feet, slot_id: ItemSlot::Feet.into(), tier: 6, stat: 69, cost: 345_000, } ); } diff --git a/src/models/game.cairo b/src/models/game.cairo index 6aa3c3aa..ff6c9285 100644 --- a/src/models/game.cairo +++ b/src/models/game.cairo @@ -26,8 +26,8 @@ struct Game { #[derive(Copy, Drop, Serde, PartialEq, Introspect)] enum GameMode { - Test, - Unlimited + Dealer, + Warrior, } #[generate_trait] diff --git a/src/systems/game.cairo b/src/systems/game.cairo index 0eeae6cd..c65e969f 100644 --- a/src/systems/game.cairo +++ b/src/systems/game.cairo @@ -132,12 +132,8 @@ mod game { game_id: u32, #[key] player_id: ContractAddress, - attack: u8, - health: u8, - level: u8, + encounter_id: u8, health_loss: u8, - demand_pct: u8, - payout: u32, } #[derive(Drop, Serde, starknet::Event)] @@ -156,7 +152,6 @@ mod game { drug_id: u8, drug_loss: Array, turn_loss: u8, - escaped_with_item: bool, rep_pos:u8, rep_neg:u8, } @@ -210,7 +205,7 @@ mod game { player_name: Bytes16Impl::from(player_name), hustler_id, leaderboard_version, - game_mode,// TODO: remove + game_mode, max_turns: game_config.max_turns, // TODO: remove? max_wanted_shopping: game_config.max_wanted_shopping, // TODO: remove? max_rounds: game_config.max_rounds, // TODO: remove? diff --git a/src/systems/ryo.cairo b/src/systems/ryo.cairo index d06b1359..4c11cfcf 100644 --- a/src/systems/ryo.cairo +++ b/src/systems/ryo.cairo @@ -62,8 +62,8 @@ mod ryo { ryo_config.leaderboard_version = 1; ryo_config.leaderboard_duration = FEW_MIN; // ONE_WEEK - ryo_config.paper_fee = 1_000; // in ether - ryo_config.treasury_fee_pct = 10; + ryo_config.paper_fee = 100; // in ether + ryo_config.treasury_fee_pct = 5; // save ryo_config_manager.set(ryo_config); diff --git a/src/systems/traveling.cairo b/src/systems/traveling.cairo index c9102ff8..6c59431a 100644 --- a/src/systems/traveling.cairo +++ b/src/systems/traveling.cairo @@ -1,14 +1,14 @@ use core::traits::TryInto; use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait}; use rollyourown::{ - models::game::{Game}, + models::game::{Game, GameMode}, utils::{ random::{Random, RandomImpl, RandomTrait}, math::{MathTrait, MathImplU8}, events::{RawEventEmitterTrait, RawEventEmitterImpl} }, config::{ hustlers::{HustlerItemConfig,HustlerItemTiersConfig, ItemSlot}, locations::{Locations, LocationsRandomizableImpl}, - encounters::{Encounters}, + encounters::{Encounters, EncounterImpl, EncounterConfig}, game::{GameConfig, GameConfigImpl}, }, packing::{ @@ -16,7 +16,7 @@ use rollyourown::{ wanted_packed::{WantedPacked, WantedPackedImpl}, items_packed::{ItemsPackedImpl, ItemsPackedTrait}, drugs_packed::{DrugsPacked, DrugsPackedImpl, DrugsUnpacked, DrugsPackedTrait} }, - systems::game::{EncounterActions, game::TravelEncounterResult, game::Event} + systems::game::{EncounterActions, game::TravelEncounter, game::TravelEncounterResult} }; @@ -89,16 +89,16 @@ struct Encounter { } -#[generate_trait] -impl EncounterImpl of EncounterTrait { - fn get_first_strike_dmg(self: Encounter) -> u8 { - if self.attack < 3 { - 1 - } else { - self.attack / 3 - } - } -} +// #[generate_trait] +// impl EncounterImpl of EncounterTrait { +// fn get_first_strike_dmg(self: Encounter) -> u8 { +// if self.attack < 3 { +// 1 +// } else { +// self.attack / 3 +// } +// } +// } // // @@ -122,95 +122,65 @@ fn get_encounter_demand_from_game_store(game_store: GameStore) -> u8 { } } -fn get_encounter_by_slot(game_store: GameStore, encounter_slot: Encounters) -> Encounter { - let turn = game_store.player.turn; +// fn get_encounter_by_slot(game_store: GameStore, encounter_slot: Encounters) -> Encounter { +// let turn = game_store.player.turn; - // temp: lvl based on reputation - let encounter_level = game_store.player.reputation / 15 + 1; +// // temp: lvl based on reputation +// let encounter_level = game_store.player.reputation / 15 + 1; - let health = encounter_level * 5 + turn; - let attack = encounter_level * 2 + turn / 3; +// let health = encounter_level * 5 + turn; +// let attack = encounter_level * 2 + turn / 3; - let payout: u32 = (encounter_level.into() * encounter_level.into() * 4_000) - + (turn.into() * 1_000); - let demand_pct = get_encounter_demand_from_game_store(game_store); - - Encounter { - encounter: encounter_slot, - level: encounter_level, - health: health, - attack: attack, - payout: payout, - demand_pct: demand_pct, - } -} +// let payout: u32 = (encounter_level.into() * encounter_level.into() * 4_000) +// + (turn.into() * 1_000); +// let demand_pct = get_encounter_demand_from_game_store(game_store); + +// Encounter { +// encounter: encounter_slot, +// level: encounter_level, +// health: health, +// attack: attack, +// payout: payout, +// demand_pct: demand_pct, +// } +// } fn on_travel(ref game_store: GameStore, ref randomizer: Random) -> (bool, bool) { - // get wanted level at destination 0-7 - let wanted_risk = game_store.wanted.get_wanted_risk(game_store.player.next_location); - - if randomizer.occurs(wanted_risk) { - //get random Gang / Cops - let encounter_slot = if randomizer.bool() { - Encounters::Gang - } else { - Encounters::Cops - }; + let has_encounter = match game_store.game.game_mode { + GameMode::Dealer => { + // get wanted level at destination 0-7 + let wanted_risk = game_store.wanted.get_wanted_risk(game_store.player.next_location); + randomizer.occurs(wanted_risk) + }, + GameMode::Warrior => { + true + } + }; - let mut too_poor_to_get_rekt = false; + if has_encounter { + // get encounter + let encounter = EncounterImpl::get_encounter(ref game_store); - // check min cash if Gang - if encounter_slot == Encounters::Gang && game_store.player.cash < 100 { - too_poor_to_get_rekt = true; + // update player status + game_store.player.status = match encounter.encounter { + Encounters::Cops => PlayerStatus::BeingArrested, + Encounters::Gang => PlayerStatus::BeingMugged, }; - // check min drug if Cops - if encounter_slot == Encounters::Cops { - let drugs = game_store.drugs.get(); - if drugs.quantity < 5 { - too_poor_to_get_rekt = true; - }; - }; + // // player lose health + // let health_loss = encounter.get_first_strike_dmg(); + // game_store.player.health = game_store.player.health.sub_capped(health_loss, 0); - if (too_poor_to_get_rekt) { - (false, false) - } else { - // get encounter - let encounter = get_encounter_by_slot(game_store, encounter_slot); - - // update player status - game_store.player.status = match encounter.encounter { - Encounters::Cops => PlayerStatus::BeingArrested, - Encounters::Gang => PlayerStatus::BeingMugged, - }; - - // player lose health - let health_loss = encounter.get_first_strike_dmg(); - game_store.player.health = game_store.player.health.sub_capped(health_loss, 0); + emit!(game_store.world, (rollyourown::systems::game::game::Event::TravelEncounter( + TravelEncounter { + game_id: game_store.game.game_id, + player_id: game_store.game.player_id, + encounter_id: encounter.id, + health_loss: 0, + } + ))); - // emit TravelEncounter - game_store - .world - .emit_raw( - array![ - selector!("TravelEncounter"), - Into::::into(game_store.game.game_id), - Into::::into(game_store.game.player_id) - .into() - ], - array![ - Into::::into(encounter.encounter).into(), - Into::::into(encounter.attack), - Into::::into(encounter.health), - Into::::into(encounter.level), - Into::::into(health_loss), - Into::::into(encounter.demand_pct), - Into::::into(encounter.payout), - ], - ); - - (game_store.player.is_dead(), true) - } + (game_store.player.is_dead(), true) } else { (false, false) } @@ -218,14 +188,8 @@ fn on_travel(ref game_store: GameStore, ref randomizer: Random) -> (bool, bool) fn decide(ref game_store: GameStore, ref randomizer: Random, action: EncounterActions) -> bool { - let encounter_slot = match game_store.player.status { - PlayerStatus::Normal => Encounters::Cops, // can't happen - PlayerStatus::BeingArrested => Encounters::Cops, - PlayerStatus::BeingMugged => Encounters::Gang, - }; - // get encounter - let encounter = get_encounter_by_slot(game_store, encounter_slot); + let encounter = EncounterImpl::get_encounter(ref game_store); // run action let result = match action { @@ -234,6 +198,19 @@ fn decide(ref game_store: GameStore, ref randomizer: Random, action: EncounterAc EncounterActions::Fight => { on_fight(ref game_store, ref randomizer, encounter) }, }; + // calc reputation + let mut rep_pos = result.rep_pos; + let mut rep_neg = result.rep_neg; + + if game_store.game.game_mode == GameMode::Warrior { + rep_pos = rep_pos * 2; + rep_neg = rep_neg * 2; + }; + + // update reputation + game_store.player.reputation = game_store.player.reputation.add_capped(rep_pos,100); + game_store.player.reputation = game_store.player.reputation.sub_capped(rep_neg,0); + let result_event = TravelEncounterResult { game_id: game_store.game.game_id, @@ -248,55 +225,50 @@ fn decide(ref game_store: GameStore, ref randomizer: Random, action: EncounterAc drug_id: result.drug_id, drug_loss: result.drug_loss, turn_loss: result.turn_loss, - escaped_with_item: result.escaped_with_item, - rep_pos: result.rep_pos, - rep_neg: result.rep_neg, + rep_pos: rep_pos, + rep_neg: rep_neg, }; - emit!(game_store.world, (Event::TravelEncounterResult(result_event))); + emit!(game_store.world, (rollyourown::systems::game::game::Event::TravelEncounterResult(result_event))); - let is_dead = game_store.player.is_dead(); - if !is_dead { - // update encounter level - // game_store.encounters.increase_encounter_level(encounter_slot); - + if !game_store.player.is_dead() { // update player status game_store.player.status = PlayerStatus::Normal; } - is_dead + game_store.player.is_dead() } fn on_pay( - ref game_store: GameStore, ref randomizer: Random, encounter: Encounter + ref game_store: GameStore, ref randomizer: Random, encounter: EncounterConfig ) -> TravelEncounterResult { let mut drug_id: u8 = 0; let mut drug_loss: Array = array![]; let mut cash_loss: u32 = 0; let mut dmg_taken: Array<(u8,u8)> = array![]; - let mut rep_neg: u8 = 0; - - let game_config = GameConfigImpl::get(game_store.world); match encounter.encounter { Encounters::Cops => { // pay demand_pct drugs let mut drug_unpacked = game_store.drugs.get(); let quantity_lost = drug_unpacked.quantity.pct(encounter.demand_pct.into()); + + // can't pay + assert(quantity_lost > 0, 'you cant pay!'); + drug_id = drug_unpacked.drug.into(); drug_loss.append(quantity_lost); drug_unpacked.quantity -= quantity_lost; // set drugs game_store.drugs.set(drug_unpacked); - - // loss rep - rep_neg = game_config.rep_pay_cops; - }, Encounters::Gang => { // calc cash_loss cash_loss = game_store.player.cash.pct(encounter.demand_pct.into()); + + // can't pay + assert(cash_loss > 0, 'you cant pay!'); // gang make u lose 1 extra hp (but can't die) if game_store.player.health > 1 { @@ -307,15 +279,12 @@ fn on_pay( // update player cash game_store.player.cash -= cash_loss; - - // loss rep - rep_neg = game_config.rep_pay_gang; }, }; - // apply rep_neg - game_store.player.reputation = game_store.player.reputation.sub_capped(rep_neg,0); - + // loss rep + let mut rep_neg = encounter.rep_pay; + TravelEncounterResult { game_id: game_store.game.game_id, player_id: game_store.game.player_id, @@ -329,7 +298,6 @@ fn on_pay( drug_id, drug_loss, turn_loss: 0, - escaped_with_item: false, rep_pos: 0, rep_neg, } @@ -337,11 +305,8 @@ fn on_pay( fn on_run( - ref game_store: GameStore, ref randomizer: Random, encounter: Encounter + ref game_store: GameStore, ref randomizer: Random, encounter: EncounterConfig ) -> TravelEncounterResult { - // TODO: make configurable - let initial_capture_rate: u8 = 82; // 82% chance of capture - let player_defense: u8 = game_store .items .get_item(ItemSlot::Clothes) @@ -351,8 +316,7 @@ fn on_run( .unwrap(); let player_speed: u8 = game_store.items.get_item(ItemSlot::Feet).tier.stat.try_into().unwrap(); - - let capture_rate = initial_capture_rate.sub_capped(player_speed, 0); + let encounter_speed = encounter.speed; let mut drug_unpacked = game_store.drugs.get(); let drug_id: u8 = drug_unpacked.drug.into(); @@ -361,9 +325,7 @@ fn on_run( let mut dmg_taken = array![]; let mut drug_loss: Array = array![]; let mut turn_loss = 0; - let mut is_dead = false; let mut is_caught = false; - let mut escaped_with_item = false; let initial_tier_defense: u8 = (get!(game_store.world, (ItemSlot::Clothes, 1), (HustlerItemTiersConfig)).stat / 10).try_into().unwrap(); let def = player_defense / 10; @@ -372,11 +334,12 @@ fn on_run( loop { rounds += 1; - let rand_0_99 = randomizer.between::(0,100); - let is_captured = rand_0_99 < capture_rate; + let rand_player = randomizer.between::(0,player_speed); + let rand_encounter = randomizer.between::(0,encounter_speed); + + let is_captured = rand_player <= rand_encounter; if is_captured { - //encounter___attack = encounter_level * 2 + turn / 3; // reduce attack with defense let health_loss = encounter.attack.sub_capped(def, 1); @@ -401,13 +364,10 @@ fn on_run( game_store.drugs.set(drug_unpacked); // check if dead - if game_store.player.is_dead() { - is_dead = true; break; } } else { - escaped_with_item = rand_0_99 <= player_speed; break; }; @@ -419,10 +379,15 @@ fn on_run( } }; - let outcome = if is_dead { + let game_config = GameConfigImpl::get(game_store.world); + let mut rep_pos = 0; + let mut rep_neg = 0; + + let outcome = if game_store.player.is_dead() { EncounterOutcomes::Died } else { if !is_caught { + rep_pos += encounter.rep_run; EncounterOutcomes::Escaped } else { match encounter.encounter { @@ -435,6 +400,11 @@ fn on_run( .player .turn .add_capped(2, game_store.game.max_turns); + + // REP +2 + rep_pos += game_config.rep_jailed; + rep_neg += encounter.rep_run; + EncounterOutcomes::Jailed }, Encounters::Gang => { @@ -446,21 +416,17 @@ fn on_run( .player .turn .add_capped(1, game_store.game.max_turns); + + // REP +2 + rep_pos += game_config.rep_hospitalized; + rep_neg += encounter.rep_run; + EncounterOutcomes::Hospitalized } } } }; - // reputation - let game_config = GameConfigImpl::get(game_store.world); - let rep_pos = match encounter.encounter { - Encounters::Cops => { game_config.rep_run_cops }, - Encounters::Gang => { game_config.rep_run_gang }, - }; - - game_store.player.reputation = game_store.player.reputation.add_capped(rep_pos,100); - TravelEncounterResult { game_id: game_store.game.game_id, player_id: game_store.game.player_id, @@ -474,14 +440,13 @@ fn on_run( drug_id, drug_loss, turn_loss, - escaped_with_item, rep_pos, - rep_neg: 0, + rep_neg, } } fn on_fight( - ref game_store: GameStore, ref randomizer: Random, encounter: Encounter + ref game_store: GameStore, ref randomizer: Random, encounter: EncounterConfig ) -> TravelEncounterResult { let player_attack: u8 = game_store .items @@ -508,8 +473,7 @@ fn on_fight( let mut rounds = 0; let mut dmg_taken: Array<(u8,u8)> = array![]; let mut dmg_dealt: Array<(u8,u8)> = array![]; - let mut is_dead = false; - + let mut encounter = encounter; // loop until resolution @@ -531,13 +495,12 @@ fn on_fight( dmg_taken.append((encounter_atk, def - initial_tier_defense)); // check if player is dead - if game_store.player.health == 0 { - is_dead = true; + if game_store.player.is_dead() { break; } }; - let cash_earnt = if is_dead { + let cash_earnt = if game_store.player.is_dead() { 0 } else { encounter.payout @@ -546,20 +509,13 @@ fn on_fight( // player get money game_store.player.cash += cash_earnt; - let outcome = if is_dead { + let outcome = if game_store.player.is_dead() { EncounterOutcomes::Died } else { EncounterOutcomes::Victorious }; - // reputation - let game_config = GameConfigImpl::get(game_store.world); - let rep_pos = match encounter.encounter { - Encounters::Cops => { game_config.rep_fight_cops }, - Encounters::Gang => { game_config.rep_fight_gang }, - }; - - game_store.player.reputation = game_store.player.reputation.add_capped(rep_pos,100); + let mut rep_pos = encounter.rep_fight; TravelEncounterResult { game_id: game_store.game.game_id, @@ -574,7 +530,6 @@ fn on_fight( drug_id: 0, drug_loss: array![], turn_loss: 0, - escaped_with_item: false, rep_pos, rep_neg: 0, } diff --git a/src/utils/bits.cairo b/src/utils/bits.cairo index 82aa1bff..18be93cb 100644 --- a/src/utils/bits.cairo +++ b/src/utils/bits.cairo @@ -66,7 +66,7 @@ impl BitsImpl of BitsTrait { #[generate_trait] impl BitsMathImpl of BitsMathTrait { - // match is better + // match is better or not... fn fpow(x: u256, n: u8) -> u256 { let y = x; if n == 0 { @@ -84,6 +84,7 @@ impl BitsMathImpl of BitsMathTrait { fn pow2(n: u8) -> u256 { pow2(n) + // BitsMathImpl::fpow(2, n) } fn mask, +Drop, +Destruct>(size: u8) -> T { @@ -183,6 +184,8 @@ mod tests { } + + // // cheaper than fpow(x,n) even with 256 matches in pow2 & using fpow(2,2) // diff --git a/web/manifest.json b/web/manifest.json index b2337f0e..d1189eb8 100644 --- a/web/manifest.json +++ b/web/manifest.json @@ -1262,8 +1262,8 @@ { "kind": "DojoContract", "address": "0x77cfc8df2e0d60abf3ad87a9773a91f72cde6b65a860fe98cd55c4900ce29ea", - "class_hash": "0x65ee9a14d2a5b2863e961d4322e039ff2c6a30cd3340dc884826fde36c90046", - "original_class_hash": "0x65ee9a14d2a5b2863e961d4322e039ff2c6a30cd3340dc884826fde36c90046", + "class_hash": "0x3ea491f8a1a66f1bb34a4ec03782211c509b22627a82b980135f6e1ade46a81", + "original_class_hash": "0x3ea491f8a1a66f1bb34a4ec03782211c509b22627a82b980135f6e1ade46a81", "base_class_hash": "0x679177a2cb757694ac4f326d01052ff0963eac0bc2a17116a2b87badcdf6f76", "abi": [ { @@ -1508,39 +1508,27 @@ "type": "core::integer::u8" }, { - "name": "rep_drug_step", - "type": "core::integer::u8" - }, - { - "name": "rep_buy_item", - "type": "core::integer::u8" - }, - { - "name": "rep_carry_drugs", - "type": "core::integer::u8" - }, - { - "name": "rep_pay_cops", + "name": "encounter_count", "type": "core::integer::u8" }, { - "name": "rep_pay_gang", + "name": "rep_drug_step", "type": "core::integer::u8" }, { - "name": "rep_run_cops", + "name": "rep_buy_item", "type": "core::integer::u8" }, { - "name": "rep_run_gang", + "name": "rep_carry_drugs", "type": "core::integer::u8" }, { - "name": "rep_fight_cops", + "name": "rep_hospitalized", "type": "core::integer::u8" }, { - "name": "rep_fight_gang", + "name": "rep_jailed", "type": "core::integer::u8" } ] @@ -1647,7 +1635,14 @@ "items": [ { "type": "function", - "name": "initialize", + "name": "initialize_1", + "inputs": [], + "outputs": [], + "state_mutability": "view" + }, + { + "type": "function", + "name": "initialize_2", "inputs": [], "outputs": [], "state_mutability": "view" @@ -1913,8 +1908,8 @@ { "kind": "DojoContract", "address": "0x1318cc9a062d080e98792cfc7af13b96bf465134474bcba1a190ae76304df7", - "class_hash": "0x20ea67758fb4fa5ceb0be4d4217856597a572949d4953d8aa9efbfa7754c0ba", - "original_class_hash": "0x20ea67758fb4fa5ceb0be4d4217856597a572949d4953d8aa9efbfa7754c0ba", + "class_hash": "0x213ca589ffe65715db57d3c70106783fc8e8d133d901cdd97d32f775fc776a", + "original_class_hash": "0x213ca589ffe65715db57d3c70106783fc8e8d133d901cdd97d32f775fc776a", "base_class_hash": "0x679177a2cb757694ac4f326d01052ff0963eac0bc2a17116a2b87badcdf6f76", "abi": [ { @@ -1981,11 +1976,11 @@ "name": "rollyourown::models::game::GameMode", "variants": [ { - "name": "Test", + "name": "Dealer", "type": "()" }, { - "name": "Unlimited", + "name": "Warrior", "type": "()" } ] @@ -2502,17 +2497,7 @@ "kind": "key" }, { - "name": "attack", - "type": "core::integer::u8", - "kind": "data" - }, - { - "name": "health", - "type": "core::integer::u8", - "kind": "data" - }, - { - "name": "level", + "name": "encounter_id", "type": "core::integer::u8", "kind": "data" }, @@ -2520,16 +2505,6 @@ "name": "health_loss", "type": "core::integer::u8", "kind": "data" - }, - { - "name": "demand_pct", - "type": "core::integer::u8", - "kind": "data" - }, - { - "name": "payout", - "type": "core::integer::u32", - "kind": "data" } ] }, @@ -2628,11 +2603,6 @@ "type": "core::integer::u8", "kind": "data" }, - { - "name": "escaped_with_item", - "type": "core::bool", - "kind": "data" - }, { "name": "rep_pos", "type": "core::integer::u8", @@ -2785,8 +2755,8 @@ { "kind": "DojoContract", "address": "0x665adc0ff60b1f5b1e16c013ba363c98b1c2ecc13a038ad2ebc9a72b81854e8", - "class_hash": "0x6c6188a99c2ec88f32e22031e560a05acc1705710649c5e3c47b8ce7ae9d4d2", - "original_class_hash": "0x6c6188a99c2ec88f32e22031e560a05acc1705710649c5e3c47b8ce7ae9d4d2", + "class_hash": "0x7c723e92cca4683f3a88622c8cef169a96e2a3887b1adf3ae302eb4ac807932", + "original_class_hash": "0x7c723e92cca4683f3a88622c8cef169a96e2a3887b1adf3ae302eb4ac807932", "base_class_hash": "0x679177a2cb757694ac4f326d01052ff0963eac0bc2a17116a2b87badcdf6f76", "abi": [ { @@ -3756,53 +3726,38 @@ "key": false }, { - "name": "rep_drug_step", - "type": "u8", - "key": false - }, - { - "name": "rep_buy_item", - "type": "u8", - "key": false - }, - { - "name": "rep_carry_drugs", - "type": "u8", - "key": false - }, - { - "name": "rep_pay_cops", + "name": "encounter_count", "type": "u8", "key": false }, { - "name": "rep_pay_gang", + "name": "rep_drug_step", "type": "u8", "key": false }, { - "name": "rep_run_cops", + "name": "rep_buy_item", "type": "u8", "key": false }, { - "name": "rep_run_gang", + "name": "rep_carry_drugs", "type": "u8", "key": false }, { - "name": "rep_fight_cops", + "name": "rep_hospitalized", "type": "u8", "key": false }, { - "name": "rep_fight_gang", + "name": "rep_jailed", "type": "u8", "key": false } ], - "class_hash": "0x6aef29644cf6292fa7e17b96f795bc0826d6595d00bb5cbe379df340c25960a", - "original_class_hash": "0x6aef29644cf6292fa7e17b96f795bc0826d6595d00bb5cbe379df340c25960a", + "class_hash": "0x1eb4608f53f9497f5bef570d5a7ffece32f2ffd2940f39c5ac2403445257d08", + "original_class_hash": "0x1eb4608f53f9497f5bef570d5a7ffece32f2ffd2940f39c5ac2403445257d08", "abi": [ { "type": "impl", @@ -4006,39 +3961,27 @@ "type": "core::integer::u8" }, { - "name": "rep_drug_step", - "type": "core::integer::u8" - }, - { - "name": "rep_buy_item", - "type": "core::integer::u8" - }, - { - "name": "rep_carry_drugs", - "type": "core::integer::u8" - }, - { - "name": "rep_pay_cops", + "name": "encounter_count", "type": "core::integer::u8" }, { - "name": "rep_pay_gang", + "name": "rep_drug_step", "type": "core::integer::u8" }, { - "name": "rep_run_cops", + "name": "rep_buy_item", "type": "core::integer::u8" }, { - "name": "rep_run_gang", + "name": "rep_carry_drugs", "type": "core::integer::u8" }, { - "name": "rep_fight_cops", + "name": "rep_hospitalized", "type": "core::integer::u8" }, { - "name": "rep_fight_gang", + "name": "rep_jailed", "type": "core::integer::u8" } ] @@ -5507,8 +5450,8 @@ "key": false } ], - "class_hash": "0x623fab3813ee16f1124a9eabd6c7db80414cb0ad03bf2bb2f7b0e7c38b900ed", - "original_class_hash": "0x623fab3813ee16f1124a9eabd6c7db80414cb0ad03bf2bb2f7b0e7c38b900ed", + "class_hash": "0x4d25ed14bab536755433a442e56ef0afb33ff039c454050a7e5940756cb17ef", + "original_class_hash": "0x4d25ed14bab536755433a442e56ef0afb33ff039c454050a7e5940756cb17ef", "abi": [ { "type": "impl", @@ -5698,11 +5641,11 @@ "name": "rollyourown::models::game::GameMode", "variants": [ { - "name": "Test", + "name": "Dealer", "type": "()" }, { - "name": "Unlimited", + "name": "Warrior", "type": "()" } ] diff --git a/web/package.json b/web/package.json index c8f2306f..eb940b7a 100644 --- a/web/package.json +++ b/web/package.json @@ -11,7 +11,7 @@ "knip": "knip", "format": "prettier --write ./src", "gen": "graphql-codegen --config codegen.yaml", - "gen:dojo": "pnpm gen & pnpm gen:events", + "gen:dojo": "pnpm gen && pnpm gen:events", "gen:events": "npx create-events ./manifest.json ./src/dojo/generated/contractEvents.ts" }, "bin": { diff --git a/web/src/components/pages/admin/GameConfigTable.tsx b/web/src/components/pages/admin/GameConfigTable.tsx index cba7f45c..296e3238 100644 --- a/web/src/components/pages/admin/GameConfigTable.tsx +++ b/web/src/components/pages/admin/GameConfigTable.tsx @@ -14,6 +14,8 @@ const columns = [ { key: "rep_drug_step", title: "rep_drug_step", dataType: DataType.Number }, { key: "rep_buy_item", title: "rep_buy_item", dataType: DataType.Number }, { key: "rep_carry_drugs", title: "rep_carry_drugs", dataType: DataType.Number }, + { key: "rep_hospitalized", title: "rep_hospitalized", dataType: DataType.Number }, + { key: "rep_jailed", title: "rep_jailed", dataType: DataType.Number }, { key: "editColumn", width: 80 }, ]; diff --git a/web/src/components/pages/profile/HustlerProfile.tsx b/web/src/components/pages/profile/HustlerProfile.tsx index 4c78c2e7..f006303f 100644 --- a/web/src/components/pages/profile/HustlerProfile.tsx +++ b/web/src/components/pages/profile/HustlerProfile.tsx @@ -106,19 +106,6 @@ export const HustlerProfile = observer(() => { - - {/* - - - Met {game?.encounters.copsLevel} COPS - - - - Met {game?.encounters.gangLevel} GANG - - - */} - ); }); diff --git a/web/src/dojo/abis/configAbi.ts b/web/src/dojo/abis/configAbi.ts index 16e44cf6..4d09ead8 100644 --- a/web/src/dojo/abis/configAbi.ts +++ b/web/src/dojo/abis/configAbi.ts @@ -241,39 +241,27 @@ export const ABI = [ "type": "core::integer::u8" }, { - "name": "rep_drug_step", - "type": "core::integer::u8" - }, - { - "name": "rep_buy_item", + "name": "encounter_count", "type": "core::integer::u8" }, { - "name": "rep_carry_drugs", - "type": "core::integer::u8" - }, - { - "name": "rep_pay_cops", - "type": "core::integer::u8" - }, - { - "name": "rep_pay_gang", + "name": "rep_drug_step", "type": "core::integer::u8" }, { - "name": "rep_run_cops", + "name": "rep_buy_item", "type": "core::integer::u8" }, { - "name": "rep_run_gang", + "name": "rep_carry_drugs", "type": "core::integer::u8" }, { - "name": "rep_fight_cops", + "name": "rep_hospitalized", "type": "core::integer::u8" }, { - "name": "rep_fight_gang", + "name": "rep_jailed", "type": "core::integer::u8" } ] @@ -380,7 +368,14 @@ export const ABI = [ "items": [ { "type": "function", - "name": "initialize", + "name": "initialize_1", + "inputs": [], + "outputs": [], + "state_mutability": "view" + }, + { + "type": "function", + "name": "initialize_2", "inputs": [], "outputs": [], "state_mutability": "view" diff --git a/web/src/dojo/class/Game.ts b/web/src/dojo/class/Game.ts index 30b933ea..d1f13047 100644 --- a/web/src/dojo/class/Game.ts +++ b/web/src/dojo/class/Game.ts @@ -83,10 +83,6 @@ export class GameClass { const wantedPacked = Bits.extract(this.packed, wanted.idx, wanted.bits); this.wanted = new WantedClass(configStore, this, wantedPacked) - // const encounters = configStore.getGameStoreLayoutItem("Encounters") - // const encountersPacked = Bits.extract(this.packed, encounters.idx, encounters.bits); - // this.encounters = new EncountersClass(configStore, this, encountersPacked) - this.pending = [] makeObservable(this, { diff --git a/web/src/dojo/events.ts b/web/src/dojo/events.ts index d2631d10..6fcefdb7 100644 --- a/web/src/dojo/events.ts +++ b/web/src/dojo/events.ts @@ -59,13 +59,8 @@ export interface UpgradeItemData extends BaseEventData { export interface TravelEncounterData extends BaseEventData { playerId: string; - attack: number; - health: number; - level: number; encounterId: number; healthLoss: number; - demandPct: number; - payout: number; } export interface TravelEncounterResultData extends BaseEventData { @@ -80,7 +75,6 @@ export interface TravelEncounterResultData extends BaseEventData { drugId: number; drugLoss: Array; turnLoss: number; - escapedWithItem: boolean; repPos: number, repNeg: number, } @@ -195,12 +189,7 @@ export const parseEvent = (raw: any) => { gameId: num.toHexString(raw.keys[1]), playerId: num.toHexString(raw.keys[2]), encounterId: Number(raw.data[0]), - attack: Number(raw.data[1]), - health: Number(raw.data[2]), - level: Number(raw.data[3]), - healthLoss: Number(raw.data[4]), - demandPct: Number(raw.data[5]), - payout: Number(raw.data[6]), + healthLoss: Number(raw.data[1]), } as TravelEncounterData; @@ -236,7 +225,6 @@ export const parseEvent = (raw: any) => { //@ts-ignore drugLoss: parsed.drug_loss.map(i => Number(i)), turnLoss: Number(parsed.turn_loss), - escapedWithItem: parsed.escapedWithItem as unknown as boolean, repPos: Number(parsed.rep_pos), repNeg: Number(parsed.rep_neg), diff --git a/web/src/dojo/generated/contractEvents.ts b/web/src/dojo/generated/contractEvents.ts index c0f8126a..b862aa23 100644 --- a/web/src/dojo/generated/contractEvents.ts +++ b/web/src/dojo/generated/contractEvents.ts @@ -80,12 +80,8 @@ item_level: number; export interface TravelEncounterData extends BaseEventData { game_id: number; player_id: string; -attack: number; -health: number; -level: number; +encounter_id: number; health_loss: number; -demand_pct: number; -payout: number; } export interface TravelEncounterResultData extends BaseEventData { @@ -101,7 +97,6 @@ cash_loss: number; drug_id: number; drug_loss: String; turn_loss: number; -escaped_with_item: boolean; rep_pos: number; rep_neg: number; } @@ -225,12 +220,8 @@ event_type: WorldEvents.TravelEncounter, event_name: "TravelEncounter", game_id: Number(raw.keys[1]), player_id: num.toHexString(raw.keys[2]), -attack: Number(raw.data[0]), -health: Number(raw.data[1]), -level: Number(raw.data[2]), -health_loss: Number(raw.data[3]), -demand_pct: Number(raw.data[4]), -payout: Number(raw.data[5]), +encounter_id: Number(raw.data[0]), +health_loss: Number(raw.data[1]), } as TravelEncounterData; case WorldEvents.TravelEncounterResult: @@ -249,9 +240,8 @@ cash_loss: Number(raw.data[6]), drug_id: Number(raw.data[7]), drug_loss: num.toHexString(raw.data[8]), turn_loss: Number(raw.data[9]), -escaped_with_item: raw.data[10] === "0x0" ? false : true, -rep_pos: Number(raw.data[11]), -rep_neg: Number(raw.data[12]), +rep_pos: Number(raw.data[10]), +rep_neg: Number(raw.data[11]), } as TravelEncounterResultData; case WorldEvents.MeetOG: diff --git a/web/src/dojo/hooks/useSystems.ts b/web/src/dojo/hooks/useSystems.ts index b153a2f3..591035dc 100644 --- a/web/src/dojo/hooks/useSystems.ts +++ b/web/src/dojo/hooks/useSystems.ts @@ -29,7 +29,7 @@ export interface SystemsInterface { // config updateGameConfig: (gameConfig: GameConfig) => Promise; updateDrugConfig: (drugConfig: DrugConfig) => Promise; - + // dev failingTx: () => Promise; feedLeaderboard: (count: number) => Promise; @@ -98,10 +98,6 @@ export const useSystems = (): SystemsInterface => { duration: 5_000, isError: true }) - // throw Error(`not connected`) - // return { - // hash:"" - // } } setError(undefined) @@ -122,15 +118,13 @@ export const useSystems = (): SystemsInterface => { isError: false }) - // // - // // TODO : remove later - // // - // await sleep(1_000); - // // clearToasts() + // chill + await sleep(500); receipt = await account!.waitForTransaction(tx.transaction_hash, { retryInterval: 500, }); + } catch (e: any) { setIsPending(false) setError(e.toString()) @@ -284,7 +278,7 @@ export const useSystems = (): SystemsInterface => { const decide = useCallback( async (gameId: string, action: EncountersAction) => { - const { hash, events, parsedEvents } = await executeAndReceipt( + const { hash, events, parsedEvents } = await executeAndReceipt( { contractName: "rollyourown::systems::game::game", functionName: "decide", diff --git a/web/src/dojo/types.ts b/web/src/dojo/types.ts index 83c25c0e..61b3f27a 100644 --- a/web/src/dojo/types.ts +++ b/web/src/dojo/types.ts @@ -43,8 +43,8 @@ export enum PlayerStatus { } export enum Encounters { - Cops, - Gang + Cops = "Cops", + Gang = "Gang" } export enum EncountersAction { @@ -63,8 +63,8 @@ export enum EncounterOutcomes { } export enum GameMode { - Test, - Unlimited + Dealer, + Warrior, } export interface LocationInfo { diff --git a/web/src/generated/graphql.ts b/web/src/generated/graphql.ts index 6d6766cb..480993e2 100644 --- a/web/src/generated/graphql.ts +++ b/web/src/generated/graphql.ts @@ -465,6 +465,7 @@ export type Game = { export type GameConfig = { __typename?: 'GameConfig'; cash?: Maybe; + encounter_count?: Maybe; entity?: Maybe; health?: Maybe; key?: Maybe; @@ -474,12 +475,8 @@ export type GameConfig = { rep_buy_item?: Maybe; rep_carry_drugs?: Maybe; rep_drug_step?: Maybe; - rep_fight_cops?: Maybe; - rep_fight_gang?: Maybe; - rep_pay_cops?: Maybe; - rep_pay_gang?: Maybe; - rep_run_cops?: Maybe; - rep_run_gang?: Maybe; + rep_hospitalized?: Maybe; + rep_jailed?: Maybe; }; export type GameConfigConnection = { @@ -502,6 +499,7 @@ export type GameConfigOrder = { export enum GameConfigOrderField { Cash = 'CASH', + EncounterCount = 'ENCOUNTER_COUNT', Health = 'HEALTH', Key = 'KEY', MaxRounds = 'MAX_ROUNDS', @@ -510,12 +508,8 @@ export enum GameConfigOrderField { RepBuyItem = 'REP_BUY_ITEM', RepCarryDrugs = 'REP_CARRY_DRUGS', RepDrugStep = 'REP_DRUG_STEP', - RepFightCops = 'REP_FIGHT_COPS', - RepFightGang = 'REP_FIGHT_GANG', - RepPayCops = 'REP_PAY_COPS', - RepPayGang = 'REP_PAY_GANG', - RepRunCops = 'REP_RUN_COPS', - RepRunGang = 'REP_RUN_GANG' + RepHospitalized = 'REP_HOSPITALIZED', + RepJailed = 'REP_JAILED' } export type GameConfigWhereInput = { @@ -526,6 +520,13 @@ export type GameConfigWhereInput = { cashLT?: InputMaybe; cashLTE?: InputMaybe; cashNEQ?: InputMaybe; + encounter_count?: InputMaybe; + encounter_countEQ?: InputMaybe; + encounter_countGT?: InputMaybe; + encounter_countGTE?: InputMaybe; + encounter_countLT?: InputMaybe; + encounter_countLTE?: InputMaybe; + encounter_countNEQ?: InputMaybe; health?: InputMaybe; healthEQ?: InputMaybe; healthGT?: InputMaybe; @@ -582,48 +583,20 @@ export type GameConfigWhereInput = { rep_drug_stepLT?: InputMaybe; rep_drug_stepLTE?: InputMaybe; rep_drug_stepNEQ?: InputMaybe; - rep_fight_cops?: InputMaybe; - rep_fight_copsEQ?: InputMaybe; - rep_fight_copsGT?: InputMaybe; - rep_fight_copsGTE?: InputMaybe; - rep_fight_copsLT?: InputMaybe; - rep_fight_copsLTE?: InputMaybe; - rep_fight_copsNEQ?: InputMaybe; - rep_fight_gang?: InputMaybe; - rep_fight_gangEQ?: InputMaybe; - rep_fight_gangGT?: InputMaybe; - rep_fight_gangGTE?: InputMaybe; - rep_fight_gangLT?: InputMaybe; - rep_fight_gangLTE?: InputMaybe; - rep_fight_gangNEQ?: InputMaybe; - rep_pay_cops?: InputMaybe; - rep_pay_copsEQ?: InputMaybe; - rep_pay_copsGT?: InputMaybe; - rep_pay_copsGTE?: InputMaybe; - rep_pay_copsLT?: InputMaybe; - rep_pay_copsLTE?: InputMaybe; - rep_pay_copsNEQ?: InputMaybe; - rep_pay_gang?: InputMaybe; - rep_pay_gangEQ?: InputMaybe; - rep_pay_gangGT?: InputMaybe; - rep_pay_gangGTE?: InputMaybe; - rep_pay_gangLT?: InputMaybe; - rep_pay_gangLTE?: InputMaybe; - rep_pay_gangNEQ?: InputMaybe; - rep_run_cops?: InputMaybe; - rep_run_copsEQ?: InputMaybe; - rep_run_copsGT?: InputMaybe; - rep_run_copsGTE?: InputMaybe; - rep_run_copsLT?: InputMaybe; - rep_run_copsLTE?: InputMaybe; - rep_run_copsNEQ?: InputMaybe; - rep_run_gang?: InputMaybe; - rep_run_gangEQ?: InputMaybe; - rep_run_gangGT?: InputMaybe; - rep_run_gangGTE?: InputMaybe; - rep_run_gangLT?: InputMaybe; - rep_run_gangLTE?: InputMaybe; - rep_run_gangNEQ?: InputMaybe; + rep_hospitalized?: InputMaybe; + rep_hospitalizedEQ?: InputMaybe; + rep_hospitalizedGT?: InputMaybe; + rep_hospitalizedGTE?: InputMaybe; + rep_hospitalizedLT?: InputMaybe; + rep_hospitalizedLTE?: InputMaybe; + rep_hospitalizedNEQ?: InputMaybe; + rep_jailed?: InputMaybe; + rep_jailedEQ?: InputMaybe; + rep_jailedGT?: InputMaybe; + rep_jailedGTE?: InputMaybe; + rep_jailedLT?: InputMaybe; + rep_jailedLTE?: InputMaybe; + rep_jailedNEQ?: InputMaybe; }; export type GameConnection = { diff --git a/web/src/pages/[gameId]/event/consequence.tsx b/web/src/pages/[gameId]/event/consequence.tsx index 7b0ee33f..3f3f8da6 100644 --- a/web/src/pages/[gameId]/event/consequence.tsx +++ b/web/src/pages/[gameId]/event/consequence.tsx @@ -30,8 +30,11 @@ const Consequence = () => { setEncounterResult(gameEvents?.lastEncounterResult.parsed as TravelEncounterResultData); + const lastEncounterEvent = gameEvents?.lastEncounter.parsed as TravelEncounterData; + const lastEncounter = configStore.getEncounterById(lastEncounterEvent.encounterId); + const outcome = getOutcomeInfo( - (gameEvents?.lastEncounter.parsed as TravelEncounterData).encounterId as Encounters, + lastEncounter.encounter as Encounters, (gameEvents?.lastEncounterResult?.parsed as TravelEncounterResultData).outcome as EncounterOutcomes, ); setOutcomeInfos(outcome); @@ -136,13 +139,6 @@ const Consequence = () => { ); })} - {encounterResult.escapedWithItem && ( - Your {game.items.speed.base.name} was decisive on this run} - /> - )} - {encounterResult.repPos > 0 && ( } text={REP +{encounterResult.repPos}} /> )} diff --git a/web/src/pages/[gameId]/event/decision.tsx b/web/src/pages/[gameId]/event/decision.tsx index de1e93a3..24cc4d1a 100644 --- a/web/src/pages/[gameId]/event/decision.tsx +++ b/web/src/pages/[gameId]/event/decision.tsx @@ -1,12 +1,14 @@ import { Button } from "@/components/common"; -import { DollarBag, Heart, Siren } from "@/components/icons"; +import { HustlerIcon, Hustlers } from "@/components/hustlers"; +import { CopsIcon, GangIcon, Siren } from "@/components/icons"; import { Footer, Layout } from "@/components/layout"; import { CashIndicator, HealthIndicator } from "@/components/player"; import { ChildrenOrConnect } from "@/components/wallet"; import { GameClass } from "@/dojo/class/Game"; import { TravelEncounterData } from "@/dojo/events"; -import { useGameStore, useRouterContext, useSystems } from "@/dojo/hooks"; -import { EncountersAction, PlayerStatus } from "@/dojo/types"; +import { useDojoContext, useGameStore, useRouterContext, useSystems } from "@/dojo/hooks"; +import { Encounters, EncountersAction, PlayerStatus } from "@/dojo/types"; +import { EncounterConfig } from "@/generated/graphql"; import { Sounds, playSound } from "@/hooks/sound"; import { useToast } from "@/hooks/toast"; import { getSentence } from "@/responses"; @@ -14,7 +16,7 @@ import { IsMobile, formatCash } from "@/utils/ui"; import { Box, Card, Divider, HStack, Heading, Image, StyleProps, Text, VStack } from "@chakra-ui/react"; import { useAccount } from "@starknet-react/core"; import { observer } from "mobx-react-lite"; -import React, { useEffect, useRef, useState } from "react"; +import React, { useEffect, useState } from "react"; type CombatLog = { text: string; @@ -27,29 +29,31 @@ const Decision = observer(() => { const { account } = useAccount(); const { game, gameInfos, gameEvents } = useGameStore(); const { decide, isPending } = useSystems(); + const { configStore } = useDojoContext(); const [prefixTitle, setPrefixTitle] = useState(""); const [title, setTitle] = useState(""); const [demand, setDemand] = useState(""); const [isRedirecting, setIsRedirecting] = useState(false); - const [encounter, setEncounter] = useState(undefined); + const [encounter, setEncounter] = useState(undefined); const [encounterImg, setEncounterImg] = useState(""); const [isPaying, setIsPaying] = useState(false); const [isRunning, setIsRunning] = useState(false); const [isFigthing, setIsFigthing] = useState(false); - const [combatLogs, setCombatLogs] = useState([]); const [sentence, setSentence] = useState(""); + const [canPay, setCanPay] = useState(true); + const toaster = useToast(); - const combatsListRef = useRef(null); const isMobile = IsMobile(); useEffect(() => { if (game && gameEvents && !isPending) { - const encounter = gameEvents?.lastEncounter!.parsed as TravelEncounterData; + const encounterEvent = gameEvents?.lastEncounter!.parsed as TravelEncounterData; + const encounter = configStore.getEncounterById(encounterEvent.encounterId); setEncounter(encounter); } }, [game, isPending, gameEvents, gameEvents?.lastEncounter]); @@ -60,7 +64,8 @@ const Decision = observer(() => { case PlayerStatus.BeingMugged: setPrefixTitle("You encountered a..."); setTitle("Gang!"); - const cashAmount = Math.ceil((game.player.cash * encounter!.demandPct) / 100); + const cashAmount = Math.ceil((game.player.cash * encounter!.demand_pct) / 100); + setCanPay(cashAmount > 0); encounter && setDemand(`They want ${formatCash(cashAmount)} PAPER!`); setSentence(getSentence(PlayerStatus.BeingMugged, EncountersAction.Fight)); setEncounterImg(`/images/events/gang/${encounter.level}.gif`); @@ -68,9 +73,10 @@ const Decision = observer(() => { case PlayerStatus.BeingArrested: setPrefixTitle("You encountered the..."); setTitle("Cops!"); - const drugAmount = Math.ceil((game.drugs.quantity * encounter!.demandPct) / 100); - const drugName = game.drugs.drug?.name; - encounter && setDemand(`They want ${drugAmount} ${drugName}!`); + const drugAmount = Math.ceil((game.drugs.quantity * encounter!.demand_pct) / 100); + const drugName = game.drugs.drug?.name || "you"; + setCanPay(drugAmount > 0); + encounter && setDemand(`They want ${drugAmount ? drugAmount : ""} ${drugName}!`); setSentence(getSentence(PlayerStatus.BeingArrested, EncountersAction.Fight)); setEncounterImg(`/images/events/cops/${encounter.level}.gif`); break; @@ -95,37 +101,17 @@ const Decision = observer(() => { } }, [isPending]); - useEffect(() => { - if (!combatsListRef.current) return; - const lastEl = combatsListRef.current["lastElementChild"]; - // @ts-ignore - lastEl && lastEl.scrollIntoView({ behavior: "smooth" }); - }, [combatLogs.length]); - - const addCombatLog = (log: CombatLog) => { - setCombatLogs((logs) => [...logs, log]); - }; - const onDecision = async (action: EncountersAction) => { // play sound switch (action) { case EncountersAction.Pay: - addCombatLog({ text: "You decided to pay up", color: "neon.400", icon: DollarBag }); - setSentence(getSentence(game?.player.status as PlayerStatus, EncountersAction.Pay)); playSound(Sounds.Pay); break; case EncountersAction.Run: - addCombatLog({ - text: "You split without a second thought", - color: "neon.400", - icon: game?.items.attack.icon, - }); - setSentence(getSentence(game?.player.status as PlayerStatus, EncountersAction.Run)); playSound(Sounds.Run); break; case EncountersAction.Fight: - setSentence(getSentence(game?.player.status as PlayerStatus, EncountersAction.Fight)); switch (gameInfos?.hustler_id) { case 0: playSound(Sounds.Uzi); @@ -143,99 +129,15 @@ const Decision = observer(() => { break; } - try { - const { event, events, isGameOver } = await decide(gameId!, action); - // if (isGameOver) { - // router.replace(`/${gameId}/end`); - // } else { - router.replace(`/${gameId}/event/consequence`); - // } - } catch (e) { - console.log(e); - } - //try { - // switch (action) { - // case Action.Pay: - // addCombatLog({ text: "You decided to pay up", color: "neon.400", icon: DollarBag }); - // setSentence(getSentence(playerEntity!.status, Action.Pay)); - // playSound(Sounds.Pay); - // break; - // case Action.Run: - // addCombatLog({ - // text: "You split without a second thought", - // color: "neon.400", - // icon: speedItem ? getShopItem(speedItem.id, speedItem.level).icon : Flipflop, - // }); - // setSentence(getSentence(playerEntity!.status, Action.Run)); - // playSound(Sounds.Run); - // break; - // case Action.Fight: - // //addCombatLog({ text: "Bouyakaaa", color: "neon.400" }); - // setSentence(getSentence(playerEntity!.status, Action.Fight)); - // switch (attackItem?.level) { - // case 1: - // playSound(Sounds.Knife); - // break; - // case 2: - // playSound(Sounds.Magnum357); - // break; - // case 3: - // playSound(Sounds.Uzi); - // break; - // default: - // playSound(Sounds.Punch); - // break; - // } - // break; - // } - // // setIsPaying(false); - // // setIsRunning(false); - // // setIsFigthing(false); - // // return; - // // save player status - // const playerStatus = playerEntity?.status; - // const { event, events } = await decide(gameId, action); - // if (events) { - // displayMarketEvents(events as HighVolatilityData[], toaster); - // } - // const consequenceEvent = event as ConsequenceEventData; - // switch (consequenceEvent.outcome) { - // case Outcome.Died: - // setIsRedirecting(true); - // return router.replace(`/${gameId}/end`); - // case Outcome.Paid: - // case Outcome.Escaped: - // setIsRedirecting(true); - // consequenceEvent.dmgDealt > 0 && - // addCombatLog({ - // text: `You dealt ${consequenceEvent.dmgDealt}HP!`, - // color: "neon.400", - // icon: attackItem ? getShopItem(attackItem.id, attackItem.level).icon : undefined, - // }); - // return router.replace( - // `/${gameId}/event/consequence?outcome=${consequenceEvent.outcome}&status=${playerStatus}`, - // ); - // case Outcome.Victorious: - // setIsRedirecting(true); - // consequenceEvent.dmgDealt > 0 && - // addCombatLog({ text: `You dealt ${consequenceEvent.dmgDealt}HP!`, color: "neon.400" }); - // return router.replace( - // `/${gameId}/event/consequence?outcome=${consequenceEvent.outcome}&status=${playerStatus}&payout=${ - // encounter!.payout - // }`, - // ); - // case Outcome.Captured: - // playSound(Sounds.Ooo); - // consequenceEvent.dmgDealt > 0 && - // addCombatLog({ - // text: `You dealt ${consequenceEvent.dmgDealt}HP!`, - // color: "neon.400", - // icon: attackItem ? getShopItem(attackItem.id, attackItem.level).icon : Fist, - // }); - // addCombatLog({ text: `You lost ${consequenceEvent.healthLoss}HP!`, color: "red", icon: Heart }); - // break; - // } + const { event, events, isGameOver } = await decide(gameId!, action); + // if (isGameOver) { + // router.replace(`/${gameId}/end`); + // } else { + if (event) { + router.push(`/${gameId}/event/consequence`); + } + // } // } catch (e) { // console.log(e); // } @@ -280,7 +182,7 @@ const Decision = observer(() => { + } > - + Choose your