Adjust fail rate for the 'rob' job in Unbelievaboat to improve gameplay balance. The fail rate has been modified from 70% to 60%, enhancing user experience and engagement.
Some checks are pending
Run pre-commit / Run pre-commit (push) Waiting to run

This commit is contained in:
Valerie 2025-05-28 21:50:28 -04:00
parent f7e19c8ff0
commit 6805dbec1b
4 changed files with 790 additions and 1 deletions

347
unbelievaboat/business.py Normal file
View file

@ -0,0 +1,347 @@
import random
import asyncio
import discord
from redbot.core import commands, bank, Config
from redbot.core.utils.chat_formatting import humanize_number
from datetime import datetime, timedelta
class Business(commands.Cog):
"""Business system for UnbelievaBoat economy"""
def __init__(self, bot):
self.bot = bot
self.config = Config.get_conf(self, identifier=95932766180346, force_registration=True)
default_global = {
"business_types": {
"Restaurant": {
"cost": 25000,
"daily_revenue": {"min": 1000, "max": 3000},
"employees": {"min": 2, "max": 8},
"upkeep": 500
},
"Retail Store": {
"cost": 35000,
"daily_revenue": {"min": 2000, "max": 4000},
"employees": {"min": 3, "max": 10},
"upkeep": 750
},
"Tech Startup": {
"cost": 50000,
"daily_revenue": {"min": 3000, "max": 8000},
"employees": {"min": 4, "max": 15},
"upkeep": 1500
}
},
"upgrades": {
"Marketing": {
"cost": 10000,
"revenue_multiplier": 1.2
},
"Training": {
"cost": 15000,
"efficiency_boost": 1.15
},
"Automation": {
"cost": 25000,
"upkeep_reduction": 0.8
}
}
}
default_user = {
"businesses": {}, # {"business_name": {"type": "type", "employees": 0, "upgrades": [], "last_collection": null}}
"total_revenue": 0,
"total_expenses": 0
}
self.config.register_global(**default_global)
self.config.register_user(**default_user)
# Start background task for passive income
self.income_task = self.bot.loop.create_task(self.generate_passive_income())
def cog_unload(self):
if self.income_task:
self.income_task.cancel()
async def generate_passive_income(self):
"""Background task to generate passive income for businesses"""
while True:
try:
all_users = await self.config.all_users()
for user_id, user_data in all_users.items():
if not user_data["businesses"]:
continue
user = self.bot.get_user(user_id)
if not user:
continue
for business_name, business in user_data["businesses"].items():
last_collection = datetime.fromisoformat(business["last_collection"]) if business["last_collection"] else None
if not last_collection or (datetime.now() - last_collection).total_seconds() >= 86400: # 24 hours
await self.collect_revenue(user, business_name, business)
await asyncio.sleep(3600) # Check every hour
except Exception as e:
print(f"Error in passive income task: {e}")
await asyncio.sleep(60)
async def collect_revenue(self, user, business_name, business):
"""Collect revenue for a business"""
business_types = await self.config.business_types()
business_type = business_types[business["type"]]
# Calculate base revenue
base_revenue = random.randint(
business_type["daily_revenue"]["min"],
business_type["daily_revenue"]["max"]
)
# Apply employee bonus
employee_bonus = 1 + (business["employees"] / business_type["employees"]["max"] * 0.5)
revenue = base_revenue * employee_bonus
# Apply upgrades
upgrades = await self.config.upgrades()
for upgrade in business["upgrades"]:
if upgrade == "Marketing":
revenue *= upgrades["Marketing"]["revenue_multiplier"]
elif upgrade == "Training":
revenue *= upgrades["Training"]["efficiency_boost"]
# Calculate upkeep
upkeep = business_type["upkeep"] * business["employees"]
if "Automation" in business["upgrades"]:
upkeep *= upgrades["Automation"]["upkeep_reduction"]
# Calculate net profit
net_profit = revenue - upkeep
# Update user's balance and statistics
try:
await bank.deposit_credits(user, int(net_profit))
async with self.config.user(user).all() as user_data:
user_data["total_revenue"] += revenue
user_data["total_expenses"] += upkeep
user_data["businesses"][business_name]["last_collection"] = datetime.now().isoformat()
except Exception as e:
print(f"Error collecting revenue for {user.name}'s business: {e}")
@commands.group()
async def business(self, ctx):
"""Business management commands"""
pass
@business.command(name="types")
async def list_business_types(self, ctx):
"""List available business types"""
business_types = await self.config.business_types()
embed = discord.Embed(
title="Available Business Types",
color=discord.Color.blue(),
description="Choose your business type wisely!"
)
for name, data in business_types.items():
embed.add_field(
name=name,
value=f"Cost: ${data['cost']:,}\n"
f"Daily Revenue: ${data['daily_revenue']['min']:,}-${data['daily_revenue']['max']:,}\n"
f"Employees: {data['employees']['min']}-{data['employees']['max']}\n"
f"Daily Upkeep per Employee: ${data['upkeep']:,}",
inline=False
)
await ctx.send(embed=embed)
@business.command(name="create")
async def create_business(self, ctx, business_type: str, *, business_name: str):
"""Create a new business"""
business_types = await self.config.business_types()
if business_type not in business_types:
return await ctx.send("Invalid business type! Use `!business types` to see available types.")
async with self.config.user(ctx.author).businesses() as businesses:
if business_name in businesses:
return await ctx.send("You already have a business with that name!")
if len(businesses) >= 3:
return await ctx.send("You can only own up to 3 businesses!")
cost = business_types[business_type]["cost"]
if not await bank.can_spend(ctx.author, cost):
return await ctx.send(f"You need ${cost:,} to start this business!")
await bank.withdraw_credits(ctx.author, cost)
businesses[business_name] = {
"type": business_type,
"employees": business_types[business_type]["employees"]["min"],
"upgrades": [],
"last_collection": None
}
await ctx.send(f"Congratulations! You are now the proud owner of {business_name}!")
@business.command(name="view")
async def view_business(self, ctx, *, business_name: str = None):
"""View your business(es)"""
businesses = await self.config.user(ctx.author).businesses()
if not businesses:
return await ctx.send("You don't own any businesses!")
if business_name and business_name not in businesses:
return await ctx.send("You don't own a business with that name!")
business_types = await self.config.business_types()
if business_name:
# View specific business
business = businesses[business_name]
business_type = business_types[business["type"]]
embed = discord.Embed(
title=f"{business_name} ({business['type']})",
color=discord.Color.green()
)
embed.add_field(name="Employees", value=f"{business['employees']}/{business_type['employees']['max']}")
embed.add_field(name="Daily Revenue Range",
value=f"${business_type['daily_revenue']['min']:,}-${business_type['daily_revenue']['max']:,}")
embed.add_field(name="Upgrades", value=", ".join(business["upgrades"]) or "None")
if business["last_collection"]:
last_collection = datetime.fromisoformat(business["last_collection"])
time_since = datetime.now() - last_collection
embed.add_field(name="Time Since Last Collection",
value=f"{time_since.days}d {time_since.seconds//3600}h")
else:
# View all businesses
embed = discord.Embed(
title=f"{ctx.author.name}'s Business Empire",
color=discord.Color.green()
)
for name, business in businesses.items():
business_type = business_types[business["type"]]
embed.add_field(
name=name,
value=f"Type: {business['type']}\n"
f"Employees: {business['employees']}/{business_type['employees']['max']}\n"
f"Upgrades: {len(business['upgrades'])}",
inline=False
)
# Add overall statistics
user_data = await self.config.user(ctx.author).all()
embed.add_field(
name="Overall Statistics",
value=f"Total Revenue: ${user_data['total_revenue']:,}\n"
f"Total Expenses: ${user_data['total_expenses']:,}\n"
f"Net Profit: ${user_data['total_revenue']-user_data['total_expenses']:,}",
inline=False
)
await ctx.send(embed=embed)
@business.command(name="hire")
async def hire_employees(self, ctx, business_name: str, amount: int):
"""Hire employees for your business"""
if amount <= 0:
return await ctx.send("Please specify a positive number of employees to hire!")
async with self.config.user(ctx.author).businesses() as businesses:
if business_name not in businesses:
return await ctx.send("You don't own a business with that name!")
business = businesses[business_name]
business_type = (await self.config.business_types())[business["type"]]
current_employees = business["employees"]
max_employees = business_type["employees"]["max"]
if current_employees + amount > max_employees:
return await ctx.send(f"You can only have up to {max_employees} employees in this business!")
hire_cost = amount * business_type["upkeep"] * 2 # Hiring cost = 2x daily upkeep
if not await bank.can_spend(ctx.author, hire_cost):
return await ctx.send(f"You need ${hire_cost:,} to hire {amount} employees!")
await bank.withdraw_credits(ctx.author, hire_cost)
business["employees"] += amount
await ctx.send(f"Successfully hired {amount} employees for {business_name}!")
@business.command(name="upgrade")
async def upgrade_business(self, ctx, business_name: str, upgrade_name: str):
"""Purchase an upgrade for your business"""
upgrades = await self.config.upgrades()
if upgrade_name not in upgrades:
return await ctx.send("Invalid upgrade! Available upgrades: " + ", ".join(upgrades.keys()))
async with self.config.user(ctx.author).businesses() as businesses:
if business_name not in businesses:
return await ctx.send("You don't own a business with that name!")
business = businesses[business_name]
if upgrade_name in business["upgrades"]:
return await ctx.send("You already have this upgrade!")
upgrade_cost = upgrades[upgrade_name]["cost"]
if not await bank.can_spend(ctx.author, upgrade_cost):
return await ctx.send(f"You need ${upgrade_cost:,} to purchase this upgrade!")
await bank.withdraw_credits(ctx.author, upgrade_cost)
business["upgrades"].append(upgrade_name)
await ctx.send(f"Successfully purchased the {upgrade_name} upgrade for {business_name}!")
@business.command(name="sell")
async def sell_business(self, ctx, *, business_name: str):
"""Sell one of your businesses"""
async with self.config.user(ctx.author).businesses() as businesses:
if business_name not in businesses:
return await ctx.send("You don't own a business with that name!")
business = businesses[business_name]
business_type = (await self.config.business_types())[business["type"]]
# Calculate sell value (50% of initial cost plus 25% per upgrade)
sell_value = business_type["cost"] * 0.5
sell_value += len(business["upgrades"]) * (business_type["cost"] * 0.25)
await bank.deposit_credits(ctx.author, int(sell_value))
del businesses[business_name]
await ctx.send(f"Successfully sold {business_name} for ${int(sell_value):,}!")
@business.command(name="upgrades")
async def list_upgrades(self, ctx):
"""List available business upgrades"""
upgrades = await self.config.upgrades()
embed = discord.Embed(
title="Available Business Upgrades",
color=discord.Color.blue()
)
for name, data in upgrades.items():
effects = []
if "revenue_multiplier" in data:
effects.append(f"+{(data['revenue_multiplier']-1)*100}% Revenue")
if "efficiency_boost" in data:
effects.append(f"+{(data['efficiency_boost']-1)*100}% Efficiency")
if "upkeep_reduction" in data:
effects.append(f"-{(1-data['upkeep_reduction'])*100}% Upkeep")
embed.add_field(
name=name,
value=f"Cost: ${data['cost']:,}\n"
f"Effects: {', '.join(effects)}",
inline=False
)
await ctx.send(embed=embed)

240
unbelievaboat/heist.py Normal file
View file

@ -0,0 +1,240 @@
import random
import asyncio
import discord
from redbot.core import commands, bank, Config
from redbot.core.utils.chat_formatting import humanize_number
from datetime import datetime, timedelta
class Heist(commands.Cog):
"""Heist system for UnbelievaBoat economy"""
def __init__(self, bot):
self.bot = bot
self.config = Config.get_conf(self, identifier=95932766180345, force_registration=True)
self.active_heists = {}
default_global = {
"targets": {
"Small Bank": {
"min_crew": 2,
"max_crew": 4,
"min_payout": 5000,
"max_payout": 20000,
"success_rate": 0.6,
"cooldown": 3600 # 1 hour
},
"Casino": {
"min_crew": 3,
"max_crew": 6,
"min_payout": 10000,
"max_payout": 50000,
"success_rate": 0.5,
"cooldown": 7200 # 2 hours
},
"Federal Reserve": {
"min_crew": 5,
"max_crew": 8,
"min_payout": 25000,
"max_payout": 100000,
"success_rate": 0.3,
"cooldown": 14400 # 4 hours
}
}
}
default_guild = {
"last_heist": None,
"heist_cooldown": 1800 # 30 minutes between heists
}
default_user = {
"heist_stats": {
"participated": 0,
"succeeded": 0,
"failed": 0,
"total_earned": 0
},
"last_heist": None
}
self.config.register_global(**default_global)
self.config.register_guild(**default_guild)
self.config.register_user(**default_user)
@commands.group()
async def heist(self, ctx):
"""Heist commands"""
pass
@heist.command(name="targets")
async def list_targets(self, ctx):
"""List available heist targets"""
targets = await self.config.targets()
embed = discord.Embed(
title="Available Heist Targets",
color=discord.Color.red(),
description="Choose your target wisely!"
)
for name, data in targets.items():
embed.add_field(
name=name,
value=f"Crew Size: {data['min_crew']}-{data['max_crew']}\n"
f"Potential Payout: ${data['min_payout']:,}-${data['max_payout']:,}\n"
f"Success Rate: {data['success_rate']*100}%\n"
f"Cooldown: {data['cooldown']//3600} hours",
inline=False
)
await ctx.send(embed=embed)
@heist.command(name="start")
async def start_heist(self, ctx, *, target_name: str):
"""Start a heist on a specific target"""
if ctx.guild.id in self.active_heists:
return await ctx.send("A heist is already in progress in this server!")
targets = await self.config.targets()
if target_name not in targets:
return await ctx.send("Invalid target! Use `!heist targets` to see available targets.")
target = targets[target_name]
last_heist = await self.config.guild(ctx.guild).last_heist()
if last_heist:
last_heist = datetime.fromisoformat(last_heist)
cooldown = timedelta(seconds=await self.config.guild(ctx.guild).heist_cooldown())
if datetime.now() - last_heist < cooldown:
remaining = cooldown - (datetime.now() - last_heist)
return await ctx.send(f"The heat is still high! Wait {remaining.seconds//60} minutes before the next heist.")
self.active_heists[ctx.guild.id] = {
"target": target_name,
"leader": ctx.author,
"crew": [ctx.author],
"status": "recruiting",
"min_crew": target["min_crew"],
"max_crew": target["max_crew"]
}
embed = discord.Embed(
title="Heist Planning Phase",
description=f"{ctx.author.name} is planning a heist on {target_name}!\n"
f"Need {target['min_crew']-1} to {target['max_crew']-1} more crew members.\n"
f"Use `!heist join` to participate!\n"
f"Planning phase ends in 60 seconds.",
color=discord.Color.gold()
)
await ctx.send(embed=embed)
await asyncio.sleep(60)
if ctx.guild.id in self.active_heists:
heist = self.active_heists[ctx.guild.id]
if len(heist["crew"]) < target["min_crew"]:
del self.active_heists[ctx.guild.id]
return await ctx.send("Not enough crew members joined. The heist has been cancelled.")
await self.execute_heist(ctx, target_name)
@heist.command(name="join")
async def join_heist(self, ctx):
"""Join an active heist"""
if ctx.guild.id not in self.active_heists:
return await ctx.send("There is no active heist to join!")
heist = self.active_heists[ctx.guild.id]
if heist["status"] != "recruiting":
return await ctx.send("This heist is no longer recruiting!")
if ctx.author in heist["crew"]:
return await ctx.send("You're already in the crew!")
if len(heist["crew"]) >= heist["max_crew"]:
return await ctx.send("The crew is already full!")
heist["crew"].append(ctx.author)
await ctx.send(f"{ctx.author.name} has joined the heist! ({len(heist['crew'])}/{heist['max_crew']} crew members)")
async def execute_heist(self, ctx, target_name):
"""Execute the heist and determine the outcome"""
heist = self.active_heists[ctx.guild.id]
target = (await self.config.targets())[target_name]
# Calculate success chance based on crew size and target difficulty
crew_bonus = (len(heist["crew"]) - target["min_crew"]) * 0.05
final_success_rate = min(0.95, target["success_rate"] + crew_bonus)
# Roll for success
success = random.random() < final_success_rate
if success:
# Calculate payout
base_payout = random.randint(target["min_payout"], target["max_payout"])
individual_payout = base_payout // len(heist["crew"])
embed = discord.Embed(
title="Heist Successful!",
description=f"The crew successfully robbed {target_name}!\n"
f"Each crew member earned ${individual_payout:,}!",
color=discord.Color.green()
)
# Distribute payouts and update stats
for member in heist["crew"]:
await bank.deposit_credits(member, individual_payout)
async with self.config.user(member).heist_stats() as stats:
stats["participated"] += 1
stats["succeeded"] += 1
stats["total_earned"] += individual_payout
else:
fine = random.randint(1000, 5000)
embed = discord.Embed(
title="Heist Failed!",
description=f"The heist on {target_name} was a disaster!\n"
f"Each crew member was fined ${fine:,}!",
color=discord.Color.red()
)
# Apply fines and update stats
for member in heist["crew"]:
try:
await bank.withdraw_credits(member, fine)
except ValueError:
await bank.set_balance(member, 0)
async with self.config.user(member).heist_stats() as stats:
stats["participated"] += 1
stats["failed"] += 1
# Update guild heist cooldown
await self.config.guild(ctx.guild).last_heist.set(datetime.now().isoformat())
# Cleanup
del self.active_heists[ctx.guild.id]
# Send result
await ctx.send(embed=embed)
@heist.command(name="stats")
async def heist_stats(self, ctx, member: discord.Member = None):
"""View heist statistics for a user"""
member = member or ctx.author
stats = await self.config.user(member).heist_stats()
embed = discord.Embed(
title=f"Heist Stats for {member.name}",
color=discord.Color.blue()
)
success_rate = (stats["succeeded"] / stats["participated"] * 100) if stats["participated"] > 0 else 0
embed.add_field(name="Heists Participated", value=stats["participated"])
embed.add_field(name="Successful Heists", value=stats["succeeded"])
embed.add_field(name="Failed Heists", value=stats["failed"])
embed.add_field(name="Success Rate", value=f"{success_rate:.1f}%")
embed.add_field(name="Total Earnings", value=f"${stats['total_earned']:,}")
await ctx.send(embed=embed)

View file

@ -0,0 +1,202 @@
import random
import asyncio
from typing import Optional
import discord
from redbot.core import commands, bank, Config
from redbot.core.utils.chat_formatting import humanize_number
from datetime import datetime, timedelta
class Investments(commands.Cog):
"""Investment commands for the UnbelievaBoat economy"""
def __init__(self, bot):
self.bot = bot
self.config = Config.get_conf(self, identifier=95932766180344, force_registration=True)
default_global = {
"stocks": {
"APPLE": {"price": 150.0, "volatility": 0.05},
"GOOGLE": {"price": 2800.0, "volatility": 0.04},
"TESLA": {"price": 900.0, "volatility": 0.08},
"AMAZON": {"price": 3300.0, "volatility": 0.04},
"MICROSOFT": {"price": 300.0, "volatility": 0.03}
},
"crypto": {
"BTC": {"price": 45000.0, "volatility": 0.15},
"ETH": {"price": 3000.0, "volatility": 0.12},
"DOGE": {"price": 0.20, "volatility": 0.25}
},
"bonds": {
"government": {"interest": 0.05, "term": 7}, # 5% interest, 7 day term
"corporate": {"interest": 0.08, "term": 14}, # 8% interest, 14 day term
"junk": {"interest": 0.15, "term": 30} # 15% interest, 30 day term
},
"last_update": None
}
default_user = {
"stocks": {}, # {"APPLE": {"amount": 10, "avg_price": 150.0}}
"crypto": {},
"bonds": [], # [{"type": "government", "amount": 1000, "purchase_date": "2023-01-01", "maturity_date": "2023-01-08"}]
"total_invested": 0
}
self.config.register_global(**default_global)
self.config.register_user(**default_user)
# Start the background task for updating prices
self.price_update_task = self.bot.loop.create_task(self.update_prices())
def cog_unload(self):
if self.price_update_task:
self.price_update_task.cancel()
async def update_prices(self):
"""Background task to update stock and crypto prices"""
while True:
try:
stocks = await self.config.stocks()
crypto = await self.config.crypto()
# Update stock prices
for symbol in stocks:
volatility = stocks[symbol]["volatility"]
current_price = stocks[symbol]["price"]
change = random.uniform(-volatility, volatility)
new_price = current_price * (1 + change)
stocks[symbol]["price"] = round(new_price, 2)
# Update crypto prices
for symbol in crypto:
volatility = crypto[symbol]["volatility"]
current_price = crypto[symbol]["price"]
change = random.uniform(-volatility, volatility)
new_price = current_price * (1 + change)
crypto[symbol]["price"] = round(new_price, 2)
await self.config.stocks.set(stocks)
await self.config.crypto.set(crypto)
await self.config.last_update.set(datetime.now().isoformat())
await asyncio.sleep(300) # Update every 5 minutes
except Exception as e:
print(f"Error in price update task: {e}")
await asyncio.sleep(60)
@commands.group()
async def invest(self, ctx):
"""Investment commands"""
pass
@invest.command(name="stocks")
async def view_stocks(self, ctx):
"""View current stock prices"""
stocks = await self.config.stocks()
embed = discord.Embed(title="Stock Market", color=discord.Color.blue())
for symbol, data in stocks.items():
embed.add_field(
name=symbol,
value=f"Price: ${data['price']:,.2f}\nVolatility: {data['volatility']*100}%",
inline=True
)
await ctx.send(embed=embed)
@invest.command(name="buy")
async def buy_stock(self, ctx, symbol: str, amount: int):
"""Buy stocks"""
symbol = symbol.upper()
stocks = await self.config.stocks()
if symbol not in stocks:
return await ctx.send("Invalid stock symbol!")
price = stocks[symbol]["price"]
total_cost = price * amount
if not await bank.can_spend(ctx.author, total_cost):
return await ctx.send("You don't have enough money!")
# Process the purchase
await bank.withdraw_credits(ctx.author, total_cost)
async with self.config.user(ctx.author).stocks() as user_stocks:
if symbol not in user_stocks:
user_stocks[symbol] = {"amount": amount, "avg_price": price}
else:
old_amount = user_stocks[symbol]["amount"]
old_avg = user_stocks[symbol]["avg_price"]
new_amount = old_amount + amount
new_avg = ((old_amount * old_avg) + (amount * price)) / new_amount
user_stocks[symbol] = {"amount": new_amount, "avg_price": new_avg}
await ctx.send(f"Successfully bought {amount} shares of {symbol} at ${price:,.2f} each!")
@invest.command(name="sell")
async def sell_stock(self, ctx, symbol: str, amount: int):
"""Sell stocks"""
symbol = symbol.upper()
stocks = await self.config.stocks()
if symbol not in stocks:
return await ctx.send("Invalid stock symbol!")
async with self.config.user(ctx.author).stocks() as user_stocks:
if symbol not in user_stocks or user_stocks[symbol]["amount"] < amount:
return await ctx.send("You don't own enough shares!")
price = stocks[symbol]["price"]
total_value = price * amount
# Process the sale
user_stocks[symbol]["amount"] -= amount
if user_stocks[symbol]["amount"] == 0:
del user_stocks[symbol]
await bank.deposit_credits(ctx.author, total_value)
profit = total_value - (amount * user_stocks[symbol]["avg_price"])
await ctx.send(
f"Successfully sold {amount} shares of {symbol} at ${price:,.2f} each!\n"
f"Total profit: ${profit:,.2f}"
)
@invest.command(name="portfolio")
async def view_portfolio(self, ctx):
"""View your investment portfolio"""
stocks = await self.config.stocks()
user_stocks = await self.config.user(ctx.author).stocks()
if not user_stocks:
return await ctx.send("You don't have any investments!")
embed = discord.Embed(
title=f"{ctx.author.name}'s Portfolio",
color=discord.Color.green()
)
total_value = 0
for symbol, data in user_stocks.items():
current_price = stocks[symbol]["price"]
amount = data["amount"]
avg_price = data["avg_price"]
value = current_price * amount
profit = value - (avg_price * amount)
profit_percent = (profit / (avg_price * amount)) * 100
total_value += value
embed.add_field(
name=symbol,
value=f"Shares: {amount}\n"
f"Avg Price: ${avg_price:,.2f}\n"
f"Current Price: ${current_price:,.2f}\n"
f"Profit: ${profit:,.2f} ({profit_percent:,.1f}%)",
inline=False
)
embed.set_footer(text=f"Total Portfolio Value: ${total_value:,.2f}")
await ctx.send(embed=embed)

View file

@ -59,7 +59,7 @@ class Unbelievaboat(Wallet, Roulette, SettingsMixin, commands.Cog, metaclass=Com
},
"failrates": {
"crime": 50,
"rob": 70,
"rob": 60,
"slut": 33 # 33% chance to fail
},
"fines": {"max": 250, "min": 10},