Update ccc.py
Browse files
ccc.py
CHANGED
@@ -2,25 +2,61 @@ import requests
|
|
2 |
import discord
|
3 |
from discord.ext import commands
|
4 |
import asyncio
|
|
|
5 |
import re
|
|
|
6 |
from collections import deque
|
7 |
from datetime import datetime, timedelta
|
|
|
8 |
import os
|
9 |
|
10 |
TOKEN = os.environ['TOKEN']
|
11 |
CHANNEL_ID = 1298830206387228682
|
|
|
|
|
12 |
|
13 |
PETS_API = 'https://petsapi.deno.dev/'
|
14 |
EXISTS_API = 'https://existsapi.deno.dev/'
|
15 |
RAP_API = 'https://rapapi.deno.dev/'
|
16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
intents = discord.Intents.default()
|
|
|
18 |
bot = commands.Bot(command_prefix='!', intents=intents)
|
19 |
|
20 |
pet_images = {}
|
21 |
pet_difficulties = {}
|
22 |
pet_raps = {}
|
23 |
pet_changes = {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
|
25 |
def format_number(number):
|
26 |
if not isinstance(number, (int, float)):
|
@@ -30,13 +66,387 @@ def format_number(number):
|
|
30 |
if abs_number < 1000:
|
31 |
return str(number)
|
32 |
elif abs_number < 1000000:
|
33 |
-
return f"{number/1000:.1f}
|
34 |
elif abs_number < 1000000000:
|
35 |
-
return f"{number/1000000:.1f}
|
36 |
elif abs_number < 1000000000000:
|
37 |
-
return f"{number/1000000000:.1f}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
else:
|
39 |
-
|
|
|
|
|
|
|
40 |
|
41 |
async def update_rap_values():
|
42 |
try:
|
@@ -45,16 +455,32 @@ async def update_rap_values():
|
|
45 |
data = response.json()
|
46 |
if data['status'] == 'ok':
|
47 |
pet_raps.clear()
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
58 |
except Exception as e:
|
59 |
print(f"Error fetching RAP values: {e}")
|
60 |
|
@@ -116,56 +542,85 @@ async def get_huge_secret_pets():
|
|
116 |
return []
|
117 |
|
118 |
async def send_embed_message(channel, pet_name, previous_value, current_value, is_change=False):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
119 |
pet_image_url = pet_images.get(pet_name, None)
|
120 |
difficulty = pet_difficulties.get(pet_name, "Unknown")
|
121 |
rap_value = pet_raps.get(pet_name, "No RAP")
|
122 |
hourly_rate = calculate_hourly_rate(pet_name)
|
123 |
-
|
124 |
-
# Format values with abbreviations
|
125 |
difficulty_display = format_number(difficulty) if isinstance(difficulty, (int, float)) else difficulty
|
126 |
rap_display = format_number(rap_value) if isinstance(rap_value, (int, float)) else rap_value
|
127 |
-
current_display =
|
128 |
previous_display = format_number(previous_value) if isinstance(previous_value, (int, float)) else previous_value
|
129 |
hourly_rate_display = format_number(hourly_rate) if isinstance(hourly_rate, (int, float)) else hourly_rate
|
130 |
-
|
131 |
-
# Check if the pet is shiny
|
132 |
is_shiny = pet_name.startswith("Shiny ")
|
133 |
-
|
134 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
135 |
if is_shiny:
|
136 |
-
|
137 |
-
|
138 |
-
title = f"✨ ***SHINY*** {base_name} was rolled! ✨"
|
139 |
-
embed_color = discord.Color.from_rgb(255, 255, 255) # White color for shiny pets
|
140 |
else:
|
141 |
-
|
142 |
-
title = f"🎲 A {pet_name} was rolled! 🎲"
|
143 |
embed_color = discord.Color.blue() if not is_change else discord.Color.orange()
|
144 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
145 |
embed = discord.Embed(
|
146 |
title=title,
|
147 |
-
description=
|
148 |
-
f"Difficulty: **1 in {difficulty_display}**\n"
|
149 |
-
f"RAP Value: **{rap_display}**\n"
|
150 |
-
f"Hourly Rate: **{hourly_rate_display}** per hour",
|
151 |
color=embed_color
|
152 |
)
|
153 |
-
|
154 |
if pet_image_url:
|
155 |
if isinstance(pet_image_url, str):
|
156 |
if pet_image_url.startswith('rbxassetid://'):
|
157 |
-
asset_id = pet_image_url.replace('rbxassetid://', '')
|
158 |
-
asset_id = re.search(r'^\d+', asset_id).group(0)
|
159 |
pet_image_url = f"https://rbxgleaks.pythonanywhere.com/asset/{asset_id}"
|
160 |
|
161 |
print(f"Using image URL for {pet_name}: {pet_image_url}")
|
162 |
embed.set_thumbnail(url=pet_image_url)
|
163 |
-
|
164 |
try:
|
165 |
await channel.send(embed=embed)
|
166 |
except discord.HTTPException as e:
|
167 |
print(f"Failed to send embed for {pet_name}: {e}")
|
168 |
-
await channel.send(f"🎲 A {pet_name} was rolled! Exists: {current_display} (Previous: {previous_display})")
|
169 |
|
170 |
async def petdata(tracked_pets):
|
171 |
try:
|
@@ -208,6 +663,7 @@ async def main_loop():
|
|
208 |
|
209 |
while True:
|
210 |
try:
|
|
|
211 |
if not tracked_pets:
|
212 |
tracked_pets = await get_huge_secret_pets() or []
|
213 |
lastknown.update({pet: None for pet in tracked_pets if pet not in lastknown})
|
@@ -246,5 +702,4 @@ async def main_loop():
|
|
246 |
async def on_ready():
|
247 |
print(f'Logged in as {bot.user.name}')
|
248 |
bot.loop.create_task(main_loop())
|
249 |
-
|
250 |
bot.run(TOKEN)
|
|
|
2 |
import discord
|
3 |
from discord.ext import commands
|
4 |
import asyncio
|
5 |
+
import json
|
6 |
import re
|
7 |
+
from collections import defaultdict
|
8 |
from collections import deque
|
9 |
from datetime import datetime, timedelta
|
10 |
+
import pytz
|
11 |
import os
|
12 |
|
13 |
TOKEN = os.environ['TOKEN']
|
14 |
CHANNEL_ID = 1298830206387228682
|
15 |
+
MONITORED_ITEMS_CHANNEL_ID = 1307752080139878500
|
16 |
+
AUTHORIZED_USER_ID = 1219416244806094883
|
17 |
|
18 |
PETS_API = 'https://petsapi.deno.dev/'
|
19 |
EXISTS_API = 'https://existsapi.deno.dev/'
|
20 |
RAP_API = 'https://rapapi.deno.dev/'
|
21 |
|
22 |
+
last_rap_values = {
|
23 |
+
"Crystal Key": None,
|
24 |
+
"Huge Shiba": None,
|
25 |
+
"Huge Dragon": None,
|
26 |
+
"Huge Inferno Cat": None,
|
27 |
+
"Autumn God Potion": None
|
28 |
+
}
|
29 |
+
|
30 |
+
LIMITED_PETS = {
|
31 |
+
"Huge Shiba": 15000,
|
32 |
+
"Huge Dragon": 7500,
|
33 |
+
"Huge Nightmare Corgi": 15000,
|
34 |
+
"Huge Jelly Axolotl": 5000
|
35 |
+
}
|
36 |
+
|
37 |
+
JELLY_LEAVE_TIMES = {
|
38 |
+
"Huge Pilgrim Turkey": datetime.strptime('2024-12-06 12:00:00', '%Y-%m-%d %H:%M:%S').replace(tzinfo=pytz.timezone('US/Eastern')),
|
39 |
+
"Acorn": datetime.strptime('2024-12-06 12:00:00', '%Y-%m-%d %H:%M:%S').replace(tzinfo=pytz.timezone('US/Eastern'))
|
40 |
+
}
|
41 |
+
|
42 |
intents = discord.Intents.default()
|
43 |
+
intents.message_content = True
|
44 |
bot = commands.Bot(command_prefix='!', intents=intents)
|
45 |
|
46 |
pet_images = {}
|
47 |
pet_difficulties = {}
|
48 |
pet_raps = {}
|
49 |
pet_changes = {}
|
50 |
+
recent_notifications = defaultdict(lambda: deque(maxlen=5))
|
51 |
+
|
52 |
+
async def fetch_exists_data():
|
53 |
+
try:
|
54 |
+
response = requests.get('https://biggamesapi.io/api/exists')
|
55 |
+
if response.status_code == 200:
|
56 |
+
return response.json().get('data', [])
|
57 |
+
except Exception as e:
|
58 |
+
print(f"Error fetching exists data: {e}")
|
59 |
+
return []
|
60 |
|
61 |
def format_number(number):
|
62 |
if not isinstance(number, (int, float)):
|
|
|
66 |
if abs_number < 1000:
|
67 |
return str(number)
|
68 |
elif abs_number < 1000000:
|
69 |
+
return f"{number/1000:.1f}k"
|
70 |
elif abs_number < 1000000000:
|
71 |
+
return f"{number/1000000:.1f}m"
|
72 |
elif abs_number < 1000000000000:
|
73 |
+
return f"{number/1000000000:.1f}b"
|
74 |
+
else:
|
75 |
+
return f"{number/1000000000000:.1f}t"
|
76 |
+
|
77 |
+
async def fetch_pet_collection_data(pet_name):
|
78 |
+
try:
|
79 |
+
response = requests.get('https://ps99.biggamesapi.io/api/collection/Pets')
|
80 |
+
if response.status_code == 200:
|
81 |
+
data = response.json().get('data', [])
|
82 |
+
for pet in data:
|
83 |
+
if pet.get('configName', '').lower() == pet_name.lower():
|
84 |
+
return pet
|
85 |
+
except Exception as e:
|
86 |
+
print(f"Error fetching pet collection data: {e}")
|
87 |
+
return None
|
88 |
+
|
89 |
+
async def fetch_pet_exists_data(pet_name):
|
90 |
+
try:
|
91 |
+
response = requests.get('https://biggamesapi.io/api/exists')
|
92 |
+
if response.status_code == 200:
|
93 |
+
data = response.json().get('data', [])
|
94 |
+
variants = {
|
95 |
+
'Normal': 0,
|
96 |
+
'Golden': 0,
|
97 |
+
'Rainbow': 0,
|
98 |
+
'Shiny': 0,
|
99 |
+
'Shiny Golden': 0,
|
100 |
+
'Shiny Rainbow': 0
|
101 |
+
}
|
102 |
+
|
103 |
+
for pet_data in data:
|
104 |
+
config_data = pet_data.get('configData', {})
|
105 |
+
value = pet_data.get('value', 0)
|
106 |
+
|
107 |
+
pet_id = config_data.get('id', '')
|
108 |
+
is_shiny = config_data.get('sh', False)
|
109 |
+
pt_value = config_data.get('pt', 0)
|
110 |
+
|
111 |
+
if pet_id.lower() == pet_name.lower():
|
112 |
+
if is_shiny and pt_value == 1:
|
113 |
+
variants['Shiny Golden'] = max(variants['Shiny Golden'], value)
|
114 |
+
elif is_shiny and pt_value == 2:
|
115 |
+
variants['Shiny Rainbow'] = max(variants['Shiny Rainbow'], value)
|
116 |
+
elif is_shiny:
|
117 |
+
variants['Shiny'] = max(variants['Shiny'], value)
|
118 |
+
elif pt_value == 1:
|
119 |
+
variants['Golden'] = max(variants['Golden'], value)
|
120 |
+
elif pt_value == 2:
|
121 |
+
variants['Rainbow'] = max(variants['Rainbow'], value)
|
122 |
+
else:
|
123 |
+
variants['Normal'] = max(variants['Normal'], value)
|
124 |
+
|
125 |
+
return variants
|
126 |
+
except Exception as e:
|
127 |
+
print(f"Error fetching exists data: {e}")
|
128 |
+
return None
|
129 |
+
|
130 |
+
@bot.command(name='petdata')
|
131 |
+
async def pet_data(ctx, *, pet_name):
|
132 |
+
collection_data = await fetch_pet_collection_data(pet_name)
|
133 |
+
|
134 |
+
exists_data = await fetch_pet_exists_data(pet_name)
|
135 |
+
|
136 |
+
if not collection_data or not exists_data:
|
137 |
+
await ctx.send("Pet does not exist!")
|
138 |
+
return
|
139 |
+
|
140 |
+
embed = discord.Embed(
|
141 |
+
title=collection_data.get('configName', 'Unknown Pet'),
|
142 |
+
color=int('11ff00', 16)
|
143 |
+
)
|
144 |
+
|
145 |
+
config_data = collection_data.get('configData', {})
|
146 |
+
|
147 |
+
description = f"**Index Description:** {config_data.get('indexDesc', 'N/A')}\n"
|
148 |
+
description += f"**Obtainable in Index:** {config_data.get('indexObtainable', 'N/A')}"
|
149 |
+
embed.description = description
|
150 |
+
|
151 |
+
total_exists = sum(exists_data.values())
|
152 |
+
|
153 |
+
exists_text = "\n".join([
|
154 |
+
f"{variant}: **{count:,}**"
|
155 |
+
for variant, count in exists_data.items() if count > 0
|
156 |
+
])
|
157 |
+
exists_text += f"\n\n**Total Exist: {total_exists:,}**"
|
158 |
+
|
159 |
+
embed.add_field(name="**Pet Exists:**", value=exists_text, inline=False)
|
160 |
+
|
161 |
+
thumbnail_url = config_data.get('thumbnail')
|
162 |
+
if thumbnail_url:
|
163 |
+
if thumbnail_url.startswith('rbxassetid://'):
|
164 |
+
asset_id = re.search(r'\d+', thumbnail_url.replace('rbxassetid://', '')).group(0)
|
165 |
+
thumbnail_url = f"https://rbxgleaks.pythonanywhere.com/asset/{asset_id}"
|
166 |
+
|
167 |
+
embed.set_image(url=thumbnail_url)
|
168 |
+
|
169 |
+
await ctx.send(embed=embed)
|
170 |
+
|
171 |
+
@bot.command(name='commonhuges')
|
172 |
+
async def common_huge_pets(ctx, count: int = 10):
|
173 |
+
if ctx.author.id != AUTHORIZED_USER_ID:
|
174 |
+
await ctx.send("You are not authorized to use this command.")
|
175 |
+
return
|
176 |
+
|
177 |
+
count = max(1, min(count, 25))
|
178 |
+
|
179 |
+
exists_data = await fetch_exists_data()
|
180 |
+
if not exists_data:
|
181 |
+
await ctx.send("Could not retrieve pet data. Please try again later.")
|
182 |
+
return
|
183 |
+
|
184 |
+
huge_pet_counts = defaultdict(int)
|
185 |
+
|
186 |
+
for pet in exists_data:
|
187 |
+
config_data = pet.get('configData', {})
|
188 |
+
value = pet.get('value', 0)
|
189 |
+
|
190 |
+
if config_data.get('id', '').startswith('Huge'):
|
191 |
+
pet_name = config_data.get('id', 'Unknown')
|
192 |
+
|
193 |
+
is_shiny = config_data.get('sh', False)
|
194 |
+
pt_value = config_data.get('pt', 0)
|
195 |
+
|
196 |
+
if is_shiny and pt_value == 1:
|
197 |
+
variant_key = f"Shiny Golden {pet_name}"
|
198 |
+
elif is_shiny and pt_value == 2:
|
199 |
+
variant_key = f"Shiny Rainbow {pet_name}"
|
200 |
+
elif is_shiny:
|
201 |
+
variant_key = f"Shiny {pet_name}"
|
202 |
+
elif pt_value == 1:
|
203 |
+
variant_key = f"Golden {pet_name}"
|
204 |
+
elif pt_value == 2:
|
205 |
+
variant_key = f"Rainbow {pet_name}"
|
206 |
+
else:
|
207 |
+
variant_key = f"Normal {pet_name}"
|
208 |
+
|
209 |
+
huge_pet_counts[variant_key] = max(huge_pet_counts[variant_key], value)
|
210 |
+
|
211 |
+
sorted_huge_pets = sorted(huge_pet_counts.items(), key=lambda x: x[1], reverse=True)
|
212 |
+
|
213 |
+
embed = discord.Embed(title=f"Top {count} Most Common Huge Pets", color=discord.Color.blue())
|
214 |
+
|
215 |
+
if sorted_huge_pets:
|
216 |
+
for i, (pet_name, count_value) in enumerate(sorted_huge_pets[:count], 1):
|
217 |
+
embed.add_field(
|
218 |
+
name=f"{i}. {pet_name}",
|
219 |
+
value=f"Exists: **{format_number(count_value)}**",
|
220 |
+
inline=False
|
221 |
+
)
|
222 |
+
else:
|
223 |
+
embed.description = "No huge pets found in the data."
|
224 |
+
|
225 |
+
await ctx.send(embed=embed)
|
226 |
+
|
227 |
+
@bot.command(name='commontitanics')
|
228 |
+
async def common_titanic_pets(ctx, count: int = 10):
|
229 |
+
if ctx.author.id != AUTHORIZED_USER_ID:
|
230 |
+
await ctx.send("You are not authorized to use this command.")
|
231 |
+
return
|
232 |
+
|
233 |
+
count = max(1, min(count, 25))
|
234 |
+
|
235 |
+
exists_data = await fetch_exists_data()
|
236 |
+
if not exists_data:
|
237 |
+
await ctx.send("Could not retrieve pet data. Please try again later.")
|
238 |
+
return
|
239 |
+
|
240 |
+
huge_pet_counts = defaultdict(int)
|
241 |
+
|
242 |
+
for pet in exists_data:
|
243 |
+
config_data = pet.get('configData', {})
|
244 |
+
value = pet.get('value', 0)
|
245 |
+
|
246 |
+
if config_data.get('id', '').startswith('Titanic'):
|
247 |
+
pet_name = config_data.get('id', 'Unknown')
|
248 |
+
|
249 |
+
is_shiny = config_data.get('sh', False)
|
250 |
+
pt_value = config_data.get('pt', 0)
|
251 |
+
|
252 |
+
if is_shiny and pt_value == 1:
|
253 |
+
variant_key = f"Shiny Golden {pet_name}"
|
254 |
+
elif is_shiny and pt_value == 2:
|
255 |
+
variant_key = f"Shiny Rainbow {pet_name}"
|
256 |
+
elif is_shiny:
|
257 |
+
variant_key = f"Shiny {pet_name}"
|
258 |
+
elif pt_value == 1:
|
259 |
+
variant_key = f"Golden {pet_name}"
|
260 |
+
elif pt_value == 2:
|
261 |
+
variant_key = f"Rainbow {pet_name}"
|
262 |
+
else:
|
263 |
+
variant_key = f"Normal {pet_name}"
|
264 |
+
|
265 |
+
huge_pet_counts[variant_key] = max(huge_pet_counts[variant_key], value)
|
266 |
+
|
267 |
+
sorted_huge_pets = sorted(huge_pet_counts.items(), key=lambda x: x[1], reverse=True)
|
268 |
+
|
269 |
+
embed = discord.Embed(title=f"Top {count} Most Common Titanic Pets", color=discord.Color.blue())
|
270 |
+
|
271 |
+
if sorted_huge_pets:
|
272 |
+
for i, (pet_name, count_value) in enumerate(sorted_huge_pets[:count], 1):
|
273 |
+
embed.add_field(
|
274 |
+
name=f"{i}. {pet_name}",
|
275 |
+
value=f"Exists: **{format_number(count_value)}**",
|
276 |
+
inline=False
|
277 |
+
)
|
278 |
+
else:
|
279 |
+
embed.description = "No titanic pets found in the data."
|
280 |
+
|
281 |
+
await ctx.send(embed=embed)
|
282 |
+
|
283 |
+
@bot.command(name='leastcommonhuges')
|
284 |
+
async def least_common_huge_pets(ctx, count: int = 10):
|
285 |
+
if ctx.author.id != AUTHORIZED_USER_ID:
|
286 |
+
await ctx.send("You are not authorized to use this command.")
|
287 |
+
return
|
288 |
+
|
289 |
+
count = max(1, min(count, 25))
|
290 |
+
|
291 |
+
exists_data = await fetch_exists_data()
|
292 |
+
if not exists_data:
|
293 |
+
await ctx.send("Could not retrieve pet data. Please try again later.")
|
294 |
+
return
|
295 |
+
|
296 |
+
huge_pet_counts = defaultdict(int)
|
297 |
+
|
298 |
+
for pet in exists_data:
|
299 |
+
config_data = pet.get('configData', {})
|
300 |
+
value = pet.get('value', 0)
|
301 |
+
|
302 |
+
if config_data.get('id', '').startswith('Huge'):
|
303 |
+
pet_name = config_data.get('id', 'Unknown')
|
304 |
+
|
305 |
+
is_shiny = config_data.get('sh', False)
|
306 |
+
pt_value = config_data.get('pt', 0)
|
307 |
+
|
308 |
+
if is_shiny and pt_value == 1:
|
309 |
+
variant_key = f"Shiny Golden {pet_name}"
|
310 |
+
elif is_shiny and pt_value == 2:
|
311 |
+
variant_key = f"Shiny Rainbow {pet_name}"
|
312 |
+
elif is_shiny:
|
313 |
+
variant_key = f"Shiny {pet_name}"
|
314 |
+
elif pt_value == 1:
|
315 |
+
variant_key = f"Golden {pet_name}"
|
316 |
+
elif pt_value == 2:
|
317 |
+
variant_key = f"Rainbow {pet_name}"
|
318 |
+
else:
|
319 |
+
variant_key = f"Normal {pet_name}"
|
320 |
+
|
321 |
+
huge_pet_counts[variant_key] = max(huge_pet_counts[variant_key], value)
|
322 |
+
|
323 |
+
sorted_huge_pets = sorted(huge_pet_counts.items(), key=lambda x: x[1])
|
324 |
+
|
325 |
+
embed = discord.Embed(title=f"Top {count} Least Common Huge Pets", color=discord.Color.dark_red())
|
326 |
+
|
327 |
+
if sorted_huge_pets:
|
328 |
+
for i, (pet_name, count_value) in enumerate(sorted_huge_pets[:count], 1):
|
329 |
+
embed.add_field(
|
330 |
+
name=f"{i}. {pet_name}",
|
331 |
+
value=f"Exists: **{format_number(count_value)}**",
|
332 |
+
inline=False
|
333 |
+
)
|
334 |
+
else:
|
335 |
+
embed.description = "No huge pets found in the data."
|
336 |
+
|
337 |
+
await ctx.send(embed=embed)
|
338 |
+
|
339 |
+
@bot.command(name='leastcommontitanics')
|
340 |
+
async def least_common_titanic_pets(ctx, count: int = 10):
|
341 |
+
if ctx.author.id != AUTHORIZED_USER_ID:
|
342 |
+
await ctx.send("You are not authorized to use this command.")
|
343 |
+
return
|
344 |
+
|
345 |
+
count = max(1, min(count, 25))
|
346 |
+
|
347 |
+
exists_data = await fetch_exists_data()
|
348 |
+
if not exists_data:
|
349 |
+
await ctx.send("Could not retrieve pet data. Please try again later.")
|
350 |
+
return
|
351 |
+
|
352 |
+
titanic_pet_counts = defaultdict(int)
|
353 |
+
|
354 |
+
for pet in exists_data:
|
355 |
+
config_data = pet.get('configData', {})
|
356 |
+
value = pet.get('value', 0)
|
357 |
+
|
358 |
+
if config_data.get('id', '').startswith('Titanic'):
|
359 |
+
pet_name = config_data.get('id', 'Unknown')
|
360 |
+
|
361 |
+
is_shiny = config_data.get('sh', False)
|
362 |
+
pt_value = config_data.get('pt', 0)
|
363 |
+
|
364 |
+
if is_shiny and pt_value == 1:
|
365 |
+
variant_key = f"Shiny Golden {pet_name}"
|
366 |
+
elif is_shiny and pt_value == 2:
|
367 |
+
variant_key = f"Shiny Rainbow {pet_name}"
|
368 |
+
elif is_shiny:
|
369 |
+
variant_key = f"Shiny {pet_name}"
|
370 |
+
elif pt_value == 1:
|
371 |
+
variant_key = f"Golden {pet_name}"
|
372 |
+
elif pt_value == 2:
|
373 |
+
variant_key = f"Rainbow {pet_name}"
|
374 |
+
else:
|
375 |
+
variant_key = f"Normal {pet_name}"
|
376 |
+
|
377 |
+
titanic_pet_counts[variant_key] = max(titanic_pet_counts[variant_key], value)
|
378 |
+
|
379 |
+
sorted_titanic_pets = sorted(titanic_pet_counts.items(), key=lambda x: x[1])
|
380 |
+
|
381 |
+
embed = discord.Embed(title=f"Top {count} Least Common Titanic Pets", color=discord.Color.dark_red())
|
382 |
+
|
383 |
+
if sorted_titanic_pets:
|
384 |
+
for i, (pet_name, count_value) in enumerate(sorted_titanic_pets[:count], 1):
|
385 |
+
embed.add_field(
|
386 |
+
name=f"{i}. {pet_name}",
|
387 |
+
value=f"Exists: **{format_number(count_value)}**",
|
388 |
+
inline=False
|
389 |
+
)
|
390 |
+
else:
|
391 |
+
embed.description = "No titanic pets found in the data."
|
392 |
+
|
393 |
+
await ctx.send(embed=embed)
|
394 |
+
|
395 |
+
def calculate_jelly_prediction(pet_name, current_value, hourly_rate):
|
396 |
+
if pet_name not in JELLY_LEAVE_TIMES:
|
397 |
+
return None
|
398 |
+
|
399 |
+
current_time = datetime.now(pytz.timezone('US/Eastern'))
|
400 |
+
leave_time = JELLY_LEAVE_TIMES[pet_name]
|
401 |
+
|
402 |
+
if current_time >= leave_time:
|
403 |
+
return None
|
404 |
+
|
405 |
+
time_diff = leave_time - current_time
|
406 |
+
hours_remaining = time_diff.total_seconds() / 3600
|
407 |
+
predicted_increase = hourly_rate * hours_remaining
|
408 |
+
predicted_final = current_value + predicted_increase
|
409 |
+
|
410 |
+
return {
|
411 |
+
'predicted_value': int(predicted_final),
|
412 |
+
'hours_remaining': round(hours_remaining, 1)
|
413 |
+
}
|
414 |
+
|
415 |
+
def calculate_time_until_limited(pet_name, current_value, hourly_rate):
|
416 |
+
if pet_name not in LIMITED_PETS or hourly_rate <= 0:
|
417 |
+
return None
|
418 |
+
|
419 |
+
limit = LIMITED_PETS[pet_name]
|
420 |
+
remaining = limit - current_value
|
421 |
+
|
422 |
+
if remaining <= 0:
|
423 |
+
return "Already Limited!"
|
424 |
+
|
425 |
+
hours = remaining / hourly_rate
|
426 |
+
if hours < 0:
|
427 |
+
return "Error calculating time"
|
428 |
+
|
429 |
+
days = hours // 24
|
430 |
+
remaining_hours = hours % 24
|
431 |
+
|
432 |
+
if days > 0:
|
433 |
+
return f"~{int(days)}d {int(remaining_hours)}h"
|
434 |
+
else:
|
435 |
+
return f"~{int(remaining_hours)}h"
|
436 |
+
|
437 |
+
async def send_rap_change_notification(channel, item_name, previous_rap, current_rap):
|
438 |
+
percent_change = ((current_rap - previous_rap) / previous_rap) * 100
|
439 |
+
|
440 |
+
if current_rap > previous_rap:
|
441 |
+
message = f"🚀 {item_name} RAP ROSE BY {percent_change:.2f}%!\n" + \
|
442 |
+
f"Previous RAP: {previous_rap:,}\n" + \
|
443 |
+
f"Current RAP: {current_rap:,}"
|
444 |
+
await channel.send(message)
|
445 |
else:
|
446 |
+
message = f"📉 {item_name} RAP DROPPED BY {abs(percent_change):.2f}%!\n" + \
|
447 |
+
f"Previous RAP: {previous_rap:,}\n" + \
|
448 |
+
f"Current RAP: {current_rap:,}"
|
449 |
+
await channel.send(message)
|
450 |
|
451 |
async def update_rap_values():
|
452 |
try:
|
|
|
455 |
data = response.json()
|
456 |
if data['status'] == 'ok':
|
457 |
pet_raps.clear()
|
458 |
+
|
459 |
+
monitored_channel = bot.get_channel(MONITORED_ITEMS_CHANNEL_ID)
|
460 |
+
if monitored_channel:
|
461 |
+
for pet_data in data['data']:
|
462 |
+
config_data = pet_data['configData']
|
463 |
+
pet_id = config_data['id']
|
464 |
+
value = pet_data['value']
|
465 |
+
is_shiny = config_data.get('sh', False)
|
466 |
+
|
467 |
+
monitored_key = f"Shiny {pet_id}" if is_shiny else pet_id
|
468 |
+
|
469 |
+
if monitored_key in last_rap_values:
|
470 |
+
current_rap = value
|
471 |
+
previous_rap = last_rap_values[monitored_key]
|
472 |
+
|
473 |
+
if previous_rap is not None and current_rap != previous_rap:
|
474 |
+
await send_rap_change_notification(monitored_channel, monitored_key, previous_rap, current_rap)
|
475 |
+
|
476 |
+
last_rap_values[monitored_key] = current_rap
|
477 |
+
|
478 |
+
if is_shiny:
|
479 |
+
pet_raps[f"Shiny {pet_id}"] = value
|
480 |
+
else:
|
481 |
+
pet_raps[pet_id] = value
|
482 |
+
|
483 |
+
print(f"Updated RAP values for {len(data['data'])} pets and items")
|
484 |
except Exception as e:
|
485 |
print(f"Error fetching RAP values: {e}")
|
486 |
|
|
|
542 |
return []
|
543 |
|
544 |
async def send_embed_message(channel, pet_name, previous_value, current_value, is_change=False):
|
545 |
+
notification_key = f"{pet_name}_{previous_value}_{current_value}"
|
546 |
+
|
547 |
+
if notification_key in recent_notifications.get(pet_name, []):
|
548 |
+
print(f"Skipping duplicate notification for {pet_name}")
|
549 |
+
return
|
550 |
+
|
551 |
+
if pet_name not in recent_notifications:
|
552 |
+
recent_notifications[pet_name] = []
|
553 |
+
recent_notifications[pet_name].append(notification_key)
|
554 |
+
|
555 |
pet_image_url = pet_images.get(pet_name, None)
|
556 |
difficulty = pet_difficulties.get(pet_name, "Unknown")
|
557 |
rap_value = pet_raps.get(pet_name, "No RAP")
|
558 |
hourly_rate = calculate_hourly_rate(pet_name)
|
559 |
+
|
|
|
560 |
difficulty_display = format_number(difficulty) if isinstance(difficulty, (int, float)) else difficulty
|
561 |
rap_display = format_number(rap_value) if isinstance(rap_value, (int, float)) else rap_value
|
562 |
+
current_display = f"{current_value:,}" if isinstance(current_value, (int, float)) else current_value
|
563 |
previous_display = format_number(previous_value) if isinstance(previous_value, (int, float)) else previous_value
|
564 |
hourly_rate_display = format_number(hourly_rate) if isinstance(hourly_rate, (int, float)) else hourly_rate
|
565 |
+
|
|
|
566 |
is_shiny = pet_name.startswith("Shiny ")
|
567 |
+
base_name = pet_name.replace("Shiny ", "") if is_shiny else pet_name
|
568 |
+
|
569 |
+
time_until_limited = None
|
570 |
+
if base_name in LIMITED_PETS:
|
571 |
+
time_until_limited = calculate_time_until_limited(base_name, current_value, hourly_rate)
|
572 |
+
|
573 |
+
jelly_prediction = None
|
574 |
+
if base_name in JELLY_LEAVE_TIMES:
|
575 |
+
jelly_prediction = calculate_jelly_prediction(base_name, current_value, hourly_rate)
|
576 |
+
|
577 |
+
value_change = current_value - previous_value if previous_value is not None else current_value
|
578 |
+
|
579 |
if is_shiny:
|
580 |
+
title = f"✨ {f'A **SHINY** {base_name} was' if value_change == 1 else f'{value_change} **SHINY** {base_name}s were'} rolled! ✨"
|
581 |
+
embed_color = discord.Color.from_rgb(255, 255, 255)
|
|
|
|
|
582 |
else:
|
583 |
+
title = f"🎲 {f'A {pet_name}' if value_change == 1 else f'{value_change} {pet_name}s'} were rolled! 🎲"
|
|
|
584 |
embed_color = discord.Color.blue() if not is_change else discord.Color.orange()
|
585 |
+
|
586 |
+
description = f"{pet_name} exists: **{current_display}**\n" \
|
587 |
+
f"Difficulty: **1 in {difficulty_display}**\n" \
|
588 |
+
f"RAP Value: **{rap_display}**\n" \
|
589 |
+
f"Hourly Rate: **{hourly_rate_display}/h**"
|
590 |
+
|
591 |
+
if time_until_limited is not None:
|
592 |
+
description += f"\nTime Remaining Until Limited: **{time_until_limited}**"
|
593 |
+
|
594 |
+
if base_name in LIMITED_PETS:
|
595 |
+
limit = LIMITED_PETS[base_name]
|
596 |
+
remaining = limit - current_value
|
597 |
+
if remaining > 0:
|
598 |
+
description += f"\nQuantity Remaining: **{remaining:,}**"
|
599 |
+
|
600 |
+
if jelly_prediction is not None:
|
601 |
+
description += f"\nEstimated Final Count: **{jelly_prediction['predicted_value']:,}**"
|
602 |
+
description += f"\nGoing Limited In: **{jelly_prediction['hours_remaining']}h**"
|
603 |
+
|
604 |
embed = discord.Embed(
|
605 |
title=title,
|
606 |
+
description=description,
|
|
|
|
|
|
|
607 |
color=embed_color
|
608 |
)
|
609 |
+
|
610 |
if pet_image_url:
|
611 |
if isinstance(pet_image_url, str):
|
612 |
if pet_image_url.startswith('rbxassetid://'):
|
613 |
+
asset_id = re.search(r'^\d+', pet_image_url.replace('rbxassetid://', '')).group(0)
|
|
|
614 |
pet_image_url = f"https://rbxgleaks.pythonanywhere.com/asset/{asset_id}"
|
615 |
|
616 |
print(f"Using image URL for {pet_name}: {pet_image_url}")
|
617 |
embed.set_thumbnail(url=pet_image_url)
|
618 |
+
|
619 |
try:
|
620 |
await channel.send(embed=embed)
|
621 |
except discord.HTTPException as e:
|
622 |
print(f"Failed to send embed for {pet_name}: {e}")
|
623 |
+
await channel.send(f"🎲 {'A' if value_change == 1 else value_change} {pet_name} was rolled! Exists: {current_display} (Previous: {previous_display})")
|
624 |
|
625 |
async def petdata(tracked_pets):
|
626 |
try:
|
|
|
663 |
|
664 |
while True:
|
665 |
try:
|
666 |
+
|
667 |
if not tracked_pets:
|
668 |
tracked_pets = await get_huge_secret_pets() or []
|
669 |
lastknown.update({pet: None for pet in tracked_pets if pet not in lastknown})
|
|
|
702 |
async def on_ready():
|
703 |
print(f'Logged in as {bot.user.name}')
|
704 |
bot.loop.create_task(main_loop())
|
|
|
705 |
bot.run(TOKEN)
|