From 4a93e9a5b310887587436e520429a9df1bf959dc Mon Sep 17 00:00:00 2001 From: notV4l Date: Fri, 24 Nov 2023 21:57:00 +0100 Subject: [PATCH] allow death on travel/encounter meeting --- scripts/default_auth.sh | 2 +- src/models/player.cairo | 14 ++++++++++ src/systems/decide.cairo | 39 +++++--------------------- src/systems/ryo.cairo | 45 ++++++++++++++++++++++++++++++ src/systems/travel.cairo | 19 ++++++++----- src/utils/settings.cairo | 2 +- web/manifest.json | 12 ++++---- web/src/components/Leaderboard.tsx | 12 ++++---- web/src/dojo/hooks/useSystems.ts | 12 ++++++-- web/src/generated/graphql.ts | 5 ++-- web/src/graphql/components.graphql | 3 +- web/src/pages/[gameId]/logs.tsx | 8 +++--- web/src/pages/[gameId]/travel.tsx | 6 +++- web/src/pages/index.tsx | 24 ++++++++++++---- 14 files changed, 133 insertions(+), 70 deletions(-) diff --git a/scripts/default_auth.sh b/scripts/default_auth.sh index 12c4709c4..be39ef76c 100755 --- a/scripts/default_auth.sh +++ b/scripts/default_auth.sh @@ -31,7 +31,7 @@ echo "-------------------------------------------------------------------------- # enable system -> component authorizations LOBBY_COMPONENTS=("Game" "Market" "Player" "Leaderboard" "RyoMeta") -TRAVEL_COMPONENTS=("Player" "Market" "Encounter") +TRAVEL_COMPONENTS=("Player" "Market" "Encounter" "Leaderboard" "RyoMeta") DECIDE_COMPONENTS=("Player" "Drug" "Market" "Encounter" "Leaderboard" "RyoMeta") TRADE_COMPONENTS=("Drug" "Market" "Player") SHOP_COMPONENTS=("Player" "Item" "Market") diff --git a/src/models/player.cairo b/src/models/player.cairo index 3aada2099..d1b23efb3 100644 --- a/src/models/player.cairo +++ b/src/models/player.cairo @@ -38,6 +38,9 @@ struct Player { impl PlayerImpl of PlayerTrait { #[inline(always)] fn can_continue(self: Player) -> bool { + if self.game_over { + return false; + } if self.health == 0 { return false; } @@ -136,3 +139,14 @@ impl PlayerStatusIntrospectionImpl of SchemaIntrospection { } } + +impl PlayerStatusIntoFelt252 of Into { + fn into(self: PlayerStatus) -> felt252 { + match self { + PlayerStatus::Normal => 'Normal', + PlayerStatus::BeingMugged => 'BeingMugged', + PlayerStatus::BeingArrested => 'BeingArrested', + PlayerStatus::AtPawnshop => 'AtPawnshop', + } + } +} diff --git a/src/systems/decide.cairo b/src/systems/decide.cairo index 70405d26d..1f0463739 100644 --- a/src/systems/decide.cairo +++ b/src/systems/decide.cairo @@ -36,7 +36,7 @@ mod decide { use rollyourown::models::item::{Item, ItemEnum}; use rollyourown::models::encounter::{Encounter, EncounterType, EncounterImpl}; use rollyourown::models::leaderboard::{Leaderboard}; - + use rollyourown::utils::random::{Random, RandomTrait, RandomImpl}; use rollyourown::utils::settings::{ DecideSettings, DecideSettingsImpl, RiskSettings, RiskSettingsImpl, EncounterSettings, @@ -47,6 +47,9 @@ mod decide { use rollyourown::utils::leaderboard::{LeaderboardManager, LeaderboardManagerTrait}; use rollyourown::systems::travel::on_turn_end; + use rollyourown::systems::ryo; + + use rollyourown::systems::ryo::GameOver; use super::IDecide; @@ -83,19 +86,6 @@ mod decide { cash_earnt: u128, } - #[derive(Drop, starknet::Event)] - struct GameOver { - #[key] - game_id: u32, - #[key] - player_id: ContractAddress, - player_name: felt252, - player_status: PlayerStatus, - turn: u32, - cash: u128, - } - - #[external(v0)] impl DecideImpl of IDecide { fn decide(self: @ContractState, game_id: u32, action: Action) { @@ -175,7 +165,7 @@ mod decide { // using same name cash_loss makes LS crash let cash_loss_ = player.cash.pct(encounter.demand_pct.into()); - (Outcome::Paid, cash_loss_, 0, 1, 0, 0) + (Outcome::Paid, cash_loss_, 0, 0, 0, 0) }, PlayerStatus::BeingArrested => { // paying cops divide wanted by 3 @@ -189,7 +179,7 @@ mod decide { let drug_loss_ = self .take_drugs(game_id, player_id, encounter.demand_pct.into()); - (Outcome::Paid, 0, drug_loss_, 1, 0, 0) + (Outcome::Paid, 0, drug_loss_, 0, 0, 0) }, PlayerStatus::AtPawnshop => (Outcome::Unsupported, 0, 0, 0, 0, 0), } @@ -219,24 +209,9 @@ mod decide { if health_loss >= player.health { player.health = 0; - player.game_over = true; outcome = Outcome::Died; - let leaderboard_manager = LeaderboardManagerTrait::new(self.world()); - leaderboard_manager.on_game_end(player.cash); - - // in case player starts game in version v & end game in version v+1 - player.leaderboard_version = leaderboard_manager.get_current_version(); - - let game_over = GameOver { - game_id, - player_id, - player_name: player.name, - player_status: player.status, - turn: player.turn, - cash: player.cash / SCALING_FACTOR, - }; - emit!(world, game_over); + ryo::game_over(self.world(), ref player); } else { player.health -= health_loss } diff --git a/src/systems/ryo.cairo b/src/systems/ryo.cairo index e24a8a7e9..4d42fc9da 100644 --- a/src/systems/ryo.cairo +++ b/src/systems/ryo.cairo @@ -1,3 +1,12 @@ +use starknet::ContractAddress; +use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait}; + +use rollyourown::constants::SCALING_FACTOR; +use rollyourown::models::player::{Player, PlayerStatus}; +use rollyourown::utils::leaderboard::{LeaderboardManager, LeaderboardManagerTrait}; +use rollyourown::utils::events::{RawEventEmitterTrait, RawEventEmitterImpl}; + + #[starknet::interface] trait IRyo { fn initialize(self: @TContractState); @@ -17,6 +26,7 @@ mod ryo { use rollyourown::utils::random::{RandomImpl}; use rollyourown::utils::leaderboard::{LeaderboardManager, LeaderboardManagerTrait}; + use super::IRyo; #[external(v0)] @@ -48,3 +58,38 @@ mod ryo { impl RyoInternalImpl of RyoInternalTrait {} } + +#[derive(Drop, starknet::Event)] +struct GameOver { + #[key] + game_id: u32, + #[key] + player_id: ContractAddress, + player_name: felt252, + player_status: PlayerStatus, + turn: u32, + cash: u128, +} + + +fn game_over(world: IWorldDispatcher, ref player: Player) { + player.game_over = true; + + let leaderboard_manager = LeaderboardManagerTrait::new(world); + // reset leaderboard timer if new highscore + leaderboard_manager.on_game_end(player.cash); + + // in case player starts game in version v & end game in version v+1 + player.leaderboard_version = leaderboard_manager.get_current_version(); + + world + .emit_raw( + array![selector!("GameOver"), player.game_id.into(), player.player_id.into()], + array![ + player.name.into(), + player.status.into(), + player.turn.into(), + (player.cash / SCALING_FACTOR).into(), + ] + ); +} diff --git a/src/systems/travel.cairo b/src/systems/travel.cairo index 5e97ac81d..0265c6cd0 100644 --- a/src/systems/travel.cairo +++ b/src/systems/travel.cairo @@ -31,6 +31,8 @@ mod travel { use rollyourown::utils::random::{Random, RandomImpl}; use rollyourown::utils::leaderboard::{LeaderboardManager, LeaderboardManagerTrait}; + use rollyourown::systems::ryo; + use super::ITravel; use super::on_turn_end; @@ -122,17 +124,16 @@ mod travel { game.game_mode, @player, encounter.level ); - // player lose max(encounter_settings.dmg / 3,1) HP, but can't die + // player lose max(encounter_settings.dmg / 3,1) HP let mut encounter_dmg = if encounter_settings.dmg < 3 { 1 } else { encounter_settings.dmg / 3 }; - let new_health = player.health.sub_capped(encounter_dmg, 1); + let new_health = player.health.sub_capped(encounter_dmg, 0); let health_loss = player.health - new_health; player.health = new_health; - set!(world, (player)); emit!( world, AdverseEvent { @@ -144,6 +145,12 @@ mod travel { } ); + if player.health == 0 { + ryo::game_over(world, ref player); + } + + set!(world, (player)); + return true; }, Option::None => {} @@ -162,11 +169,9 @@ mod travel { let mut player: Player = get!(world, (game_id, player_id).into(), Player); assert(player.game_over == false, 'already game_over'); - player.game_over = true; - set!(world, (player)); + ryo::game_over(self.world(), ref player); - let leaderboard_manager = LeaderboardManagerTrait::new(self.world()); - leaderboard_manager.on_game_end(player.cash); + set!(world, (player)); } } diff --git a/src/utils/settings.cairo b/src/utils/settings.cairo index 913a20e2b..45ace9b5a 100644 --- a/src/utils/settings.cairo +++ b/src/utils/settings.cairo @@ -141,7 +141,7 @@ impl PlayerSettingsImpl of SettingsTrait { if game_mode == GameMode::Test { player_settings.wanted = 100; - player_settings.health = 9; + player_settings.health = 10; } player_settings diff --git a/web/manifest.json b/web/manifest.json index 5fc77aa47..9fe0fff9e 100644 --- a/web/manifest.json +++ b/web/manifest.json @@ -909,7 +909,7 @@ { "name": "decide", "address": "0x59fed3332e583eb4ff6c0ff52a45c08b823025f2bc2d1b148e14a3e089ce271", - "class_hash": "0x4f0237ac51e1fbf4e312ad9034fc7f2efe9d100233894cf336b8e62f8f86025", + "class_hash": "0xa3dffb167731889584bc4b47b626ef2fd860891ca10037a29425060f1041df", "abi": [ { "type": "impl", @@ -1169,7 +1169,7 @@ }, { "type": "event", - "name": "rollyourown::systems::decide::decide::GameOver", + "name": "rollyourown::systems::ryo::GameOver", "kind": "struct", "members": [ { @@ -1226,7 +1226,7 @@ }, { "name": "GameOver", - "type": "rollyourown::systems::decide::decide::GameOver", + "type": "rollyourown::systems::ryo::GameOver", "kind": "nested" } ] @@ -1389,7 +1389,7 @@ { "name": "lobby", "address": "0x4c03b718b8cda385d9ba4cf9eedec6588fffe053fbc9a5de3840226c981f00d", - "class_hash": "0x4225ba28a49bf788d2eba0757c1a12dacefd2b0ea1c3e4ac26e8e9e634f205b", + "class_hash": "0x62c7117972c98834e4456a8d0df9aad20944b80bdcf27c72981c179079257d1", "abi": [ { "type": "impl", @@ -2099,7 +2099,7 @@ { "name": "trade", "address": "0x5decbe746e8199f7162d9cfbf3cb84fff20712e4fec76c729a4e0a8725fbc4", - "class_hash": "0x26e9a1222efc369cf91f0026c81f39fb2b2ad80f72a3eaf8728d0f9efd4a7bb", + "class_hash": "0x49ca3563e448da5e40dcfb3853f606d03e788cb9f76a3ed251e487e7604dbfa", "abi": [ { "type": "impl", @@ -2417,7 +2417,7 @@ { "name": "travel", "address": "0x2ec3dd5ae820ac90b7a95af30b9d62c2b13d3f26c948750d9d3f38a1a7a9fbd", - "class_hash": "0x6518aa200bbb25603ef9e047fb131f2fde40411e379c10f34ab501f5e8bca41", + "class_hash": "0x4502811bcc9b6ba03b4260f6f4ac460b3b52d53237557d2cf1cb43c53e78555", "abi": [ { "type": "impl", diff --git a/web/src/components/Leaderboard.tsx b/web/src/components/Leaderboard.tsx index ded8c2e73..d1ba5afe7 100644 --- a/web/src/components/Leaderboard.tsx +++ b/web/src/components/Leaderboard.tsx @@ -48,7 +48,7 @@ const renderer = ({ return RESETS NEXT GAME; } else { return ( - + RESETS IN: {days > 0 ? `${days}D` : ""} {hours.toString().padStart(2, "0")}H{" "} {minutes.toString().padStart(2, "0")}m {seconds.toString().padStart(2, "0")}s @@ -63,7 +63,7 @@ const Leaderboard = ({ nameEntry, ...props }: { nameEntry?: boolean } & StylePro const gameId = router.query.gameId as string; const { account } = useDojoContext(); const { ryoMetas } = useRyoMetas(); - const { leaderboardMetas } = useLeaderboardMetas(ryoMetas?.leaderboard_version); + const { leaderboardMetas } = useLeaderboardMetas(ryoMetas?.leaderboard_version); const { scores, refetch, hasNextPage, fetchNextPage } = useGlobalScoresIninite(ryoMetas?.leaderboard_version, 10); const [targetGameId, setTargetGameId] = useState(""); @@ -89,10 +89,10 @@ const Leaderboard = ({ nameEntry, ...props }: { nameEntry?: boolean } & StylePro return ( - - - (v{leaderboardMetas?.version}) - + + HALL OF FAME (v{leaderboardMetas?.version}) + + { [gameId, locationId], ); + const isGameOver = parsedEvents + .find((e) => e.eventType === WorldEvents.GameOver) + const adverseEvent = parsedEvents.find( (e) => e.eventType === WorldEvents.AdverseEvent, ) as AdverseEventData @@ -192,9 +196,9 @@ export const useSystems = (): SystemsInterface => { (e) => e.eventType === WorldEvents.AtPawnshop, ) as AtPawnshopEventData - return { hash, + isGameOver, event: adverseEvent || atPawnshopEvent, events: parsedEvents .filter((e) => e.eventType === WorldEvents.MarketEvent) @@ -214,8 +218,6 @@ export const useSystems = (): SystemsInterface => { return { hash, - event: [], - events: [], }; }, [executeAndReceipt], @@ -272,12 +274,16 @@ export const useSystems = (): SystemsInterface => { [gameId, action], ); + const isGameOver = parsedEvents + .find((e) => e.eventType === WorldEvents.GameOver) + const consequenceEvent = parsedEvents.find( (e) => e.eventType === WorldEvents.Consequence, ) as ConsequenceEventData return { hash, + isGameOver, event: parsedEvents.find( (e) => e.eventType === WorldEvents.Consequence, ) as ConsequenceEventData, diff --git a/web/src/generated/graphql.ts b/web/src/generated/graphql.ts index 468f01923..94de4b427 100644 --- a/web/src/generated/graphql.ts +++ b/web/src/generated/graphql.ts @@ -1058,7 +1058,7 @@ export type GlobalScoresQueryVariables = Exact<{ }>; -export type GlobalScoresQuery = { __typename?: 'World__Query', playerModels?: { __typename?: 'PlayerConnection', total_count: number, edges?: Array<{ __typename?: 'PlayerEdge', cursor?: any | null, node?: { __typename?: 'Player', game_id?: any | null, player_id?: any | null, name?: any | null, avatar_id?: any | null, cash?: any | null, health?: any | null, turn?: any | null } | null } | null> | null } | null }; +export type GlobalScoresQuery = { __typename?: 'World__Query', playerModels?: { __typename?: 'PlayerConnection', total_count: number, edges?: Array<{ __typename?: 'PlayerEdge', cursor?: any | null, node?: { __typename?: 'Player', game_id?: any | null, player_id?: any | null, name?: any | null, avatar_id?: any | null, cash?: any | null, health?: any | null, turn?: any | null, game_over?: any | null } | null } | null> | null } | null }; export type MarketPricesQueryVariables = Exact<{ gameId?: InputMaybe; @@ -1142,7 +1142,7 @@ export const PlayerPropsFragmentDoc = ` export const GlobalScoresDocument = ` query GlobalScores($version: u32, $limit: Int, $cursor: Cursor) { playerModels( - where: {game_over: true, leaderboard_version: $version} + where: {game_over: 1, leaderboard_version: $version} order: {direction: DESC, field: CASH} first: $limit after: $cursor @@ -1157,6 +1157,7 @@ export const GlobalScoresDocument = ` cash health turn + game_over } cursor } diff --git a/web/src/graphql/components.graphql b/web/src/graphql/components.graphql index 2bb95cc39..5c49d8961 100644 --- a/web/src/graphql/components.graphql +++ b/web/src/graphql/components.graphql @@ -1,6 +1,6 @@ query GlobalScores($version: u32, $limit: Int, $cursor: Cursor) { playerModels( - where: { game_over: true, leaderboard_version: $version } + where: { game_over: 1, leaderboard_version: $version } order: { direction: DESC, field: CASH } first: $limit after: $cursor @@ -15,6 +15,7 @@ query GlobalScores($version: u32, $limit: Int, $cursor: Cursor) { cash health turn + game_over } cursor } diff --git a/web/src/pages/[gameId]/logs.tsx b/web/src/pages/[gameId]/logs.tsx index 84484df9a..c81f37287 100644 --- a/web/src/pages/[gameId]/logs.tsx +++ b/web/src/pages/[gameId]/logs.tsx @@ -56,7 +56,7 @@ export default function Logs() { const { playerLogs, isFetched } = usePlayerLogs({ gameId, playerId: playerId || account?.address }); - const [ playerName, setPlayerName] = useState(""); + const [playerName, setPlayerName] = useState(""); const [logs, setLogs] = useState([]); const listRef = useRef(null); @@ -75,8 +75,8 @@ export default function Logs() { for (let log of playerLogs?.parsedLogs) { //console.log(`${log.log.node?.id} - ${log.parsed.eventName}`) - if (log.parsed.eventType === WorldEvents.PlayerJoined){ - setPlayerName((log.parsed as JoinedEventData).playerName) + if (log.parsed.eventType === WorldEvents.PlayerJoined) { + setPlayerName((log.parsed as JoinedEventData).playerName); } if (log.parsed.eventType === WorldEvents.Traveled) { // create new day @@ -136,7 +136,7 @@ export default function Logs() {