Ruby-Cogs/unbelievaboat/business.py

367 lines
No EOL
16 KiB
Python

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(f"Invalid business type! Use `{ctx.clean_prefix}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 = int(business_types[business_type]["cost"]) # Ensure cost is an integer
current_balance = await bank.get_balance(ctx.author)
max_balance = await bank.get_max_balance(ctx.guild)
# Debug information
debug_msg = (
f"Debug Info:\n"
f"- Your current balance: ${current_balance:,}\n"
f"- Business cost: ${cost:,}\n"
f"- Max possible balance: ${max_balance:,}\n"
f"- Can spend: {await bank.can_spend(ctx.author, cost)}"
)
await ctx.send(debug_msg)
if not await bank.can_spend(ctx.author, cost):
return await ctx.send(
f"You need ${cost:,} to start this business! "
f"(You have ${current_balance:,})"
)
try:
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}!")
except ValueError as e:
await ctx.send(f"Error occurred while trying to withdraw credits: {str(e)}")
except Exception as e:
await ctx.send(f"An unexpected error occurred: {str(e)}")
@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(f"Invalid upgrade! Available upgrades: {', '.join(upgrades.keys())}\nUse `{ctx.clean_prefix}business upgrades` to see details.")
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)