240 lines
No EOL
9.2 KiB
Python
240 lines
No EOL
9.2 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 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) |