Skip to content

Commit

Permalink
simplify cop/gang events
Browse files Browse the repository at this point in the history
  • Loading branch information
broody committed Sep 16, 2023
1 parent cb4cb48 commit c8551ff
Show file tree
Hide file tree
Showing 17 changed files with 993 additions and 842 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,13 @@ flowchart TD
C --> |Buys / Sells drugs on local markets|D[Select next location to travel to]
D --> |Player travels without incident|END[Turn ends]
D --> F[Player is Mugged]
F --> F1[Fight]
F --> F1[Pay]
F --> F2[Run]
F2 --> F12[Win] --> END
F2 --> L[Lose]
L --> |Player loses their stash|END
D --> G[Chased by Cops]
G --> F1[Fight]
G --> F1[Pay]
G --> F2[Run]
F1 --> F12
F1 --> L
Expand Down
4 changes: 2 additions & 2 deletions Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ dojo = { git = "https://github.com/dojoengine/dojo.git" }


# Katana
rpc_url = "https://api.cartridge.gg/x/rollyourown/katana"
#rpc_url = "http://localhost:5050"
#rpc_url = "https://api.cartridge.gg/x/rollyourown/katana"
rpc_url = "http://localhost:5050"
account_address = "0x517ececd29116499f4a1b64b094da79ba08dfd54a3edaa316134c41f8160973"
private_key = "0x1800000000300000180000000000030000000000003006001800006600"

Expand Down
4 changes: 2 additions & 2 deletions src/components/market.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ impl MarketImpl of MarketTrait {
}
} else {
panic(array!['invalid drug_id']);
PricingInfos { min_price: 0, max_price: 0, min_qty: 0, max_qty: 0, }
PricingInfos { min_price: 0, max_price: 0, min_qty: 0, max_qty: 0, }
}
}
}
Expand All @@ -102,7 +102,7 @@ fn normalize(amount: usize, market: Market) -> (u128, u128, u128) {


#[test]
#[should_panic(expected: ('not enough liquidity', ))]
#[should_panic(expected: ('not enough liquidity',))]
fn test_not_enough_quantity() {
let mut market = Market {
game_id: 0, location_id: 0, drug_id: 0, cash: SCALING_FACTOR * 1, quantity: 1
Expand Down
14 changes: 8 additions & 6 deletions src/components/risks.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use traits::{Into, TryInto};
use option::OptionTrait;
use debug::PrintTrait;

use rollyourown::constants::SCALING_FACTOR;
use rollyourown::constants::{SCALING_FACTOR, COPS_DRUG_THRESHOLD, ENCOUNTER_BIAS_GANGS};
use rollyourown::PlayerStatus;

#[derive(Component, Copy, Drop, Serde)]
Expand All @@ -25,15 +25,17 @@ impl RisksImpl of RisksTrait {
let result: u128 = entropy.low % 100;

// more bias towards gang encounter
return match result <= 30 {
bool::False => PlayerStatus::BeingMugged,
bool::True => {
// don't trigger if no drugs
if drug_count == 0 {
return match result <= ENCOUNTER_BIAS_GANGS {
bool::False => {
if drug_count < COPS_DRUG_THRESHOLD {
return PlayerStatus::Normal;
}

PlayerStatus::BeingArrested
},
bool::True => {
PlayerStatus::BeingMugged
}
};
}

Expand Down
7 changes: 5 additions & 2 deletions src/constants.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ const SCALING_FACTOR: u128 = 10_000;
const TRAVEL_RISK: u8 = 30; // 30% chance of travel encounter
const CAPTURE_RISK: u8 = 50; // 50% chance of capture

const HEALTH_IMPACT: u8 = 10;
const ENCOUNTER_BIAS_GANGS: u128 = 60;
const COPS_DRUG_THRESHOLD: usize = 5; // cops encounter threshold

const BASE_PAYMENT: u128 = 500_0000; // base payment is $500
const HEALTH_IMPACT: u8 = 10;
const COPS_PAYMENT: usize = 20;
const GANGS_PAYMENT: usize = 10;

// starting stats
const STARTING_CASH: u128 = 2000_0000; // $2000
Expand Down
13 changes: 8 additions & 5 deletions src/systems/create.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ mod create_game {
use rollyourown::components::location::{Location, LocationTrait};
use rollyourown::components::market::{MarketTrait};
use rollyourown::constants::{
SCALING_FACTOR, TRAVEL_RISK, CAPTURE_RISK, STARTING_CASH, STARTING_HEALTH, STARTING_BAG_LIMIT
SCALING_FACTOR, TRAVEL_RISK, CAPTURE_RISK, STARTING_CASH, STARTING_HEALTH,
STARTING_BAG_LIMIT
};
use rollyourown::utils::random;
use debug::PrintTrait;
Expand Down Expand Up @@ -86,7 +87,10 @@ mod create_game {
set!(
ctx.world,
(Risks {
game_id, location_id: *location_id, travel: TRAVEL_RISK, capture: CAPTURE_RISK
game_id,
location_id: *location_id,
travel: TRAVEL_RISK,
capture: CAPTURE_RISK
})
);

Expand Down Expand Up @@ -139,9 +143,8 @@ mod create_game {

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

(game_id, ctx.origin)
Expand Down
167 changes: 53 additions & 114 deletions src/systems/decide.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ mod decide {
use dojo::world::Context;

use rollyourown::PlayerStatus;
use rollyourown::constants::{BASE_PAYMENT, HEALTH_IMPACT};
use rollyourown::constants::{
GANGS_PAYMENT, COPS_PAYMENT, HEALTH_IMPACT, COPS_DRUG_THRESHOLD
};
use rollyourown::components::game::{Game, GameTrait};
use rollyourown::components::risks::{Risks, RisksTrait};
use rollyourown::components::player::{Player, PlayerTrait};
Expand All @@ -18,14 +20,12 @@ mod decide {
enum Action {
Run: (),
Pay: (),
Fight: (),
}

#[derive(Copy, Drop, Serde, PartialEq)]
enum Outcome {
Died: (),
Paid: (),
Fought: (),
Escaped: (),
Captured: (),
Unsupported: (),
Expand All @@ -36,28 +36,20 @@ mod decide {
enum Event {
Decision: Decision,
Consequence: Consequence,
Losses: Losses
}

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

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

#[derive(Drop, starknet::Event)]
struct Losses {
game_id: u32,
player_id: ContractAddress,
health_loss: u8,
drug_loss: usize,
cash_loss: u128
Expand All @@ -68,41 +60,32 @@ mod decide {
let mut player = get!(ctx.world, (game_id, player_id).into(), Player);
assert(player.status != PlayerStatus::Normal, 'player response not needed');

let (mut outcome, cash_loss, drug_loss, health_loss) = match player.status {
PlayerStatus::Normal => (Outcome::Unsupported, 0, 0, 0),
PlayerStatus::BeingMugged => match action {
Action::Run => run(
ctx,
game_id,
player_id,
player.status,
player.cash,
player.location_id,
player.run_attempts
),
Action::Pay => (Outcome::Unsupported, 0, 0, 0), // can't pay muggers
Action::Fight => fight(ctx, game_id, player_id),
let (mut outcome, cash_loss, drug_loss, health_loss) = match 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;
match risks.run(seed) {
bool::False => (Outcome::Captured, 0, 0, HEALTH_IMPACT),
bool::True => (Outcome::Escaped, 0, 0, 0)
}
},
PlayerStatus::BeingArrested => match action {
Action::Run => run(
ctx,
game_id,
player_id,
player.status,
player.cash,
player.location_id,
player.run_attempts
),
Action::Pay => pay(ctx, game_id, player_id, player.cash),
Action::Fight => (Outcome::Unsupported, 0, 0, 0), // can't fight officers
Action::Pay => {
match player.status {
PlayerStatus::Normal => (Outcome::Unsupported, 0, 0, 0),
PlayerStatus::BeingMugged => {
let drug_loss = take_drugs(ctx, game_id, player_id, GANGS_PAYMENT);
let cash_loss = (player.cash * GANGS_PAYMENT.into()) / 100;
(Outcome::Paid, cash_loss, drug_loss, 0)
},
PlayerStatus::BeingArrested => {
let cash_loss = cops_payment(player.drug_count);
assert(cash_loss <= player.cash, 'not enough cash to pay cops');
(Outcome::Paid, cash_loss, 0, 0)
}
}
},
};

// you can only bribe cops and fight muggers, not the other way around
assert(outcome != Outcome::Unsupported, 'unsupported action');

// if captured, stay in captured state and faces the same decision again, can choose to run
// again but consequences increase each tinme (-health, +risk)
if outcome == Outcome::Captured {
player.run_attempts += 1;
} else {
Expand All @@ -112,99 +95,55 @@ mod decide {
player.run_attempts = 0;
}

player.cash -= cash_loss;
player.drug_count -= drug_loss;
if health_loss >= player.health {
player.health = 0;
player.turns_remaining = 0;
outcome = Outcome::Died;
} else {
player.health -= health_loss;
player.health -= health_loss
}

player.cash -= cash_loss;
player.drug_count -= drug_loss;

set!(ctx.world, (player));
emit!(ctx.world, Consequence { game_id, player_id, outcome });

if health_loss > 0 || cash_loss > 0 || drug_loss > 0 {
emit!(ctx.world, Losses { game_id, player_id, health_loss, drug_loss, cash_loss});
}
}

// Player will fight muggers, but it kinda hurts, taking 20hp of your health. You
// might also die if not enough health
fn fight(ctx: Context, game_id: u32, player_id: ContractAddress) -> (Outcome, u128, u32, u8) {
emit!(ctx.world, Decision { game_id, player_id, action: Action::Fight, run_attempts: 0 });
(Outcome::Fought, 0, 0, 20)
emit!(ctx.world, Decision { game_id, player_id, action });
emit!(
ctx.world,
Consequence { game_id, player_id, outcome, health_loss, drug_loss, cash_loss }
);
}

// Player will hand over either 20% of their cash or $400, which ever is more
fn pay(
ctx: Context, game_id: u32, player_id: ContractAddress, player_cash: u128
) -> (Outcome, u128, u32, u8) {
assert(player_cash >= BASE_PAYMENT, 'not enough cash kid');
let cash_loss = cmp::max(player_cash / 5, BASE_PAYMENT);

emit!(ctx.world, Decision { game_id, player_id, action: Action::Pay, run_attempts: 0 });
(Outcome::Paid, cash_loss, 0, 0)
}

// Player will try to run and can escape without consequence. However, if you
// are caught be ready to face the consequences:
// - caught escaping an officer - 10hp and 20% of your drugs
// - caught escaping muggers - 10hp and 20% of your cash
//
// In this captured state, players can choose to continue to run, the stash percentage
// you lose increments by +10% each time. (ie 20%, 30%, 40%, etc) and health continues
// to decrease by 10hp
fn run(
ctx: Context,
game_id: u32,
player_id: ContractAddress,
player_status: PlayerStatus,
player_cash: u128,
location_id: felt252,
run_attempts: u8,
) -> (Outcome, u128, u32, u8) {
let mut risks = get!(ctx.world, (game_id, location_id).into(), Risks);
let seed = starknet::get_tx_info().unbox().transaction_hash;
let got_away = risks.run(seed);

emit!(ctx.world, Decision { game_id, player_id, action: Action::Run, run_attempts });
match got_away {
bool::False => match player_status {
PlayerStatus::Normal => {
(Outcome::Unsupported, 0, 0, 0)
},
PlayerStatus::BeingMugged => {
let additional_penalty: u128 = run_attempts.into() * 10;
let cash_loss = (player_cash * (20 + additional_penalty)) / 100;

(Outcome::Captured, cash_loss, 0, HEALTH_IMPACT)
},
PlayerStatus::BeingArrested => {
let drug_count_loss = take_drugs(ctx, game_id, player_id, run_attempts);
(Outcome::Captured, 0, drug_count_loss, HEALTH_IMPACT)
}
},
bool::True => {
(Outcome::Escaped, 0, 0, 0)
}
fn cops_payment(drug_count: u32) -> u128 {
if drug_count < COPS_DRUG_THRESHOLD + 20 {
1000_0000 // $1000
} else if drug_count < COPS_DRUG_THRESHOLD + 50 {
5000_0000 // $5000
} else if drug_count < COPS_DRUG_THRESHOLD + 80 {
10000_0000 // $10000
} else {
20000_0000 // $20000
}
}

fn take_drugs(ctx: Context, game_id: u32, player_id: ContractAddress, run_attempts: u8) -> usize {
fn take_drugs(
ctx: Context, game_id: u32, player_id: ContractAddress, percentage: usize
) -> usize {
let mut drugs = DrugTrait::all();
let mut total_drug_loss = 0;
loop {
match drugs.pop_front() {
Option::Some(drug_id) => {
let mut drug = get!(ctx.world, (game_id, player_id, *drug_id), Drug);
if (drug.quantity != 0) {
let additional_penalty: u32 = run_attempts.into() * 10;
let drug_loss = (drug.quantity * (20 + additional_penalty)) / 100;
let mut drug_loss = (drug.quantity * percentage) / 100;
drug_loss = if drug_loss == 0 {
1
} else {
drug_loss
};
drug.quantity -= drug_loss;
total_drug_loss += drug.quantity;
total_drug_loss += drug_loss;

set!(ctx.world, (drug));
}
Expand Down
2 changes: 1 addition & 1 deletion src/systems/set_name.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ mod set_name {
use rollyourown::components::name::Name;

fn execute(ctx: Context, game_id: u32, player_name: felt252) {
set!(ctx.world, (Name { game_id, player_id: ctx.origin, short_string: player_name, }))
set!(ctx.world, (Name { game_id, player_id: ctx.origin, short_string: player_name, }))
}
}
3 changes: 2 additions & 1 deletion src/systems/travel.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ mod travel {
set!(ctx.world, (player));

emit!(
ctx.world, Traveled {
ctx.world,
Traveled {
game_id, player_id, from_location: player.location_id, to_location: next_location_id
}
);
Expand Down
Loading

0 comments on commit c8551ff

Please sign in to comment.