Skip to content

Commit

Permalink
feat(contracts): hustler actions and consequences
Browse files Browse the repository at this point in the history
  • Loading branch information
broody committed Sep 7, 2023
1 parent 2a0d9c4 commit fb6657c
Show file tree
Hide file tree
Showing 14 changed files with 233 additions and 119 deletions.
5 changes: 5 additions & 0 deletions src/components/player.cairo
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use starknet::ContractAddress;
use rollyourown::PlayerState;

#[derive(Component, Copy, Drop, Serde)]
struct Player {
Expand All @@ -10,6 +11,7 @@ struct Player {
cash: u128,
health: u8,
turns_remaining: usize,
state: PlayerState,
}

#[generate_trait]
Expand All @@ -22,6 +24,9 @@ impl PlayerImpl of PlayerTrait {
if self.turns_remaining == 0 {
return false;
}
if self.state != PlayerState::Normal {
return false;
}

true
}
Expand Down
46 changes: 17 additions & 29 deletions src/components/risks.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -18,62 +18,50 @@ struct Risks {
#[key]
location_id: felt252,
travel: u8,
hurt: u8,
mugged: u8,
arrested: u8,
run: u8,
}

#[generate_trait]
impl RisksImpl of RisksTrait {
#[inline(always)]
fn travel(ref self: Risks, seed: felt252) -> (bool, TravelResult) {
let mut seed = seed;
let mut health_loss = 0;
let mut arrested = false;
let mut mugged = false;
let mut event_occured = false;

if occurs(seed, self.travel) {
seed = pedersen::pedersen(seed, seed);
event_occured = true;

// TEMP: for testing, mugging is only risk
mugged = true;
}
fn travel(ref self: Risks, seed: felt252) -> bool {
occurs(seed, self.travel)
}

(event_occured, TravelResult { arrested, mugged, health_loss })
fn run(ref self: Risks, seed: felt252) -> bool {
occurs(seed, self.run)
}
}

fn occurs(seed: felt252, likelihood: u8) -> bool {
if likelihood == 0 {
return false;
}

let seed: u256 = seed.into();
let result: u128 = seed.low % 100;

(result <= likelihood.into())
}

#[test]
#[available_gas(1000000)]
fn test_never_occurs() {
let seed = pedersen::pedersen(1, 1);
let mut risks = Risks { game_id: 0, location_id: 0, travel: 0, hurt: 0, mugged: 0, arrested: 0, };
let (event_occured, result) = risks.travel(seed);
let mut risks = Risks { game_id: 0, location_id: 0, travel: 0, run: 0 };
let event = risks.travel(seed);

assert(!event_occured, 'event occured');
assert(result.health_loss == 0, 'health_loss occured');
assert(!result.mugged, 'was mugged');
assert(!result.arrested, 'was arrested');
assert(event == bool::False, 'event occured');
}

#[test]
#[available_gas(1000000)]
fn test_always_occurs() {
let seed = pedersen::pedersen(1, 1);
let mut risks = Risks {
game_id: 0, location_id: 0, travel: 100, hurt: 100, mugged: 100, arrested: 100,
};
let (event_occured, result) = risks.travel(seed);
let mut risks = Risks { game_id: 0, location_id: 0, travel: 100, run: 0 };
let event = risks.travel(seed);

assert(event_occured, 'event did not occur');
assert(event == bool::True, 'event did not occur');
}

#[test]
Expand Down
9 changes: 5 additions & 4 deletions src/constants.cairo
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
const SCALING_FACTOR: u128 = 10_000;

const TRAVEL_RISK: u8 = 30;
const HURT_RISK: u8 = 0;
const MUGGED_RISK: u8 = 0;
const ARRESTED_RISK: u8 = 50;
const TRAVEL_RISK: u8 = 30; // 30% chance of mugged
const RUN_CHANCE: u8 = 30; // 30% chance of successfully getting away

const RUN_PENALTY: u8 = 30; // 30% of cash lost
const PAY_PENALTY: u8 = 10; // 10% of cash lost

// max drug price is $300
// min drug price is $2
Expand Down
28 changes: 28 additions & 0 deletions src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,31 @@ mod utils;
#[cfg(test)]
mod tests;

#[derive(Copy, Drop, Serde, PartialEq)]
enum PlayerState {
Normal: (),
BeingMugged: (),
BeingArrested: (),
}

impl StorageSizePlayerState of dojo::StorageSize<PlayerState> {
#[inline(always)]
fn unpacked_size() -> usize {
1
}

#[inline(always)]
fn packed_size() -> usize {
2
}
}

impl PlayerStatePrintImpl of core::debug::PrintTrait<PlayerState> {
fn print(self: PlayerState) {
match self {
PlayerState::Normal(()) => 0.print(),
PlayerState::BeingMugged(()) => 1.print(),
PlayerState::BeingArrested(()) => 2.print(),
}
}
}
3 changes: 2 additions & 1 deletion src/systems.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ mod create;
mod join;
mod trade;
mod travel;
mod player;
mod set_name;
mod decide;
35 changes: 16 additions & 19 deletions src/systems/create.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ mod create_game {

use dojo::world::Context;

use rollyourown::PlayerState;
use rollyourown::components::name::Name;
use rollyourown::components::game::Game;
use rollyourown::components::player::Player;
Expand All @@ -17,8 +18,8 @@ mod create_game {
use rollyourown::components::drug::{Drug, DrugTrait};
use rollyourown::components::location::{Location, LocationTrait};
use rollyourown::constants::{
SCALING_FACTOR, TRAVEL_RISK, HURT_RISK, MUGGED_RISK, ARRESTED_RISK, MIN_CASH, MAX_CASH,
MIN_QUANITTY, MAX_QUANTITY, STARTING_CASH
SCALING_FACTOR, TRAVEL_RISK, RUN_CHANCE, MIN_CASH, MAX_CASH, MIN_QUANITTY, MAX_QUANTITY,
STARTING_CASH
};
use rollyourown::utils::random;

Expand Down Expand Up @@ -52,7 +53,7 @@ mod create_game {
let game_id = ctx.world.uuid();

// game entity
set!(
set !(
ctx.world,
(Game {
game_id,
Expand All @@ -68,7 +69,7 @@ mod create_game {
let seed = starknet::get_tx_info().unbox().transaction_hash;
let location_id = LocationTrait::random(seed);
// player entity
set!(
set !(
ctx.world,
(
Player {
Expand All @@ -77,7 +78,8 @@ mod create_game {
location_id,
cash: STARTING_CASH,
health: 100,
turns_remaining: max_turns
turns_remaining: max_turns,
state: PlayerState::Normal(()),
},
)
);
Expand All @@ -89,15 +91,10 @@ mod create_game {
match locations.pop_front() {
Option::Some(location_id) => {
//set location entity
set!(
set !(
ctx.world,
(Risks {
game_id,
location_id: *location_id,
travel: TRAVEL_RISK,
hurt: HURT_RISK,
mugged: MUGGED_RISK,
arrested: ARRESTED_RISK
game_id, location_id: *location_id, travel: TRAVEL_RISK, run: RUN_CHANCE
})
);

Expand All @@ -108,14 +105,13 @@ mod create_game {
loop {
match drugs.pop_front() {
Option::Some(drug_id) => {
// HACK: temp hack to get some randomness
seed = pedersen::pedersen(seed, *drug_id);
let market_cash = random(seed, MIN_CASH, MAX_CASH);
let rand = random(seed, MIN_QUANITTY.into(), MAX_QUANTITY.into());
let market_quantity: usize = rand.try_into().unwrap();

//set market entity
set!(
set !(
ctx.world,
(Market {
game_id,
Expand All @@ -139,13 +135,14 @@ mod create_game {
};

// emit player joined
emit!(ctx.world, PlayerJoined { game_id, player_id: ctx.origin, location_id: location_id });
emit !(
ctx.world, PlayerJoined { game_id, player_id: ctx.origin, location_id: location_id }
);

// emit game created
emit!(
ctx.world, GameCreated {
game_id, creator: ctx.origin, start_time, max_players, max_turns
}
emit !(
ctx.world,
GameCreated { game_id, creator: ctx.origin, start_time, max_players, max_turns }
);

(game_id, ctx.origin)
Expand Down
90 changes: 90 additions & 0 deletions src/systems/decide.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#[system]
mod decide {
use array::ArrayTrait;
use box::BoxTrait;
use traits::Into;
use starknet::ContractAddress;

use dojo::world::Context;
use rollyourown::PlayerState;
use rollyourown::constants::{RUN_PENALTY, PAY_PENALTY};
use rollyourown::components::game::{Game, GameTrait};
use rollyourown::components::risks::{Risks, RisksTrait};
use rollyourown::components::player::{Player, PlayerTrait};

#[derive(Copy, Drop, Serde, PartialEq)]
enum Action {
Pay: (),
Run: (),
}

#[derive(Copy, Drop, Serde, PartialEq)]
enum Result {
Paid: (),
GotAway: (),
Mugged: (),
}

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
Decision: Decision,
Consequence: Consequence,
}

#[derive(Drop, starknet::Event)]
struct Decision {
game_id: u32,
player_id: ContractAddress,
action: Action,
}

#[derive(Drop, starknet::Event)]
struct Consequence {
game_id: u32,
player_id: ContractAddress,
result: Result
}

fn execute(ctx: Context, game_id: u32, action: Action, next_location_id: felt252) {
let game = get !(ctx.world, game_id, Game);
assert(game.tick(), 'game cannot progress');

let player_id = ctx.origin;
let mut player = get !(ctx.world, (game_id, player_id).into(), Player);
assert(player.state != PlayerState::Normal(()), 'player response not needed');

let result = match action {
Action::Pay => {
emit !(ctx.world, Decision { game_id, player_id, action: Action::Pay });

player.cash -= 1;
Result::Paid(())
},
Action::Run => {
emit !(ctx.world, Decision { game_id, player_id, action: Action::Run });

let mut risks = get !(ctx.world, (game_id, player.location_id).into(), Risks);
let seed = starknet::get_tx_info().unbox().transaction_hash;
let got_away = risks.run(seed);

match got_away {
bool::False => {
player.cash -= 1;
Result::Mugged(())
},
bool::True => {
Result::GotAway(())
}
}
},
};

player.state = PlayerState::Normal(());
player.location_id = next_location_id;
player.turns_remaining -= 1;
set !(ctx.world, (player));

emit !(ctx.world, Consequence { game_id, player_id, result });
}
}
Loading

0 comments on commit fb6657c

Please sign in to comment.