coollsd commited on
Commit
cdfa259
·
verified ·
1 Parent(s): 7cd896c

Update ccc.py

Browse files
Files changed (1) hide show
  1. ccc.py +493 -38
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}K"
34
  elif abs_number < 1000000000:
35
- return f"{number/1000000:.1f}M"
36
  elif abs_number < 1000000000000:
37
- return f"{number/1000000000:.1f}B"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  else:
39
- return f"{number/1000000000000:.1f}T"
 
 
 
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
- for pet_data in data['data']:
49
- config_data = pet_data['configData']
50
- pet_id = config_data['id']
51
- value = pet_data['value']
52
- is_shiny = config_data.get('sh', False)
53
- if is_shiny:
54
- pet_raps[f"Shiny {pet_id}"] = value
55
- else:
56
- pet_raps[pet_id] = value
57
- print(f"Updated RAP values for {len(data['data'])} pets")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 = format_number(current_value) if isinstance(current_value, (int, float)) else current_value
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
- # Format the title based on whether the pet is shiny
 
 
 
 
 
 
 
 
 
 
135
  if is_shiny:
136
- # For shiny pets: use sparkles and format "SHINY" in bold and italic
137
- base_name = pet_name.replace("Shiny ", "")
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
- # For regular pets: use dice emoji
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=f"{pet_name} exists: **{current_display}**\n"
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)