reaper-arcade-hub 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.html CHANGED
@@ -94,6 +94,11 @@
94
94
  <!-- Starfield Space Canvas -->
95
95
  <canvas id="bg-canvas"></canvas>
96
96
 
97
+ <!-- Global Live Broadcast Alert Banner -->
98
+ <div id="global-broadcast-banner" style="display: none; background: linear-gradient(90deg, #ff0055, #ff8800); color: #fff; padding: 0.55rem 1rem; text-align: center; font-weight: 800; font-size: 0.85rem; letter-spacing: 0.05em; z-index: 99990; position: sticky; top: 0; box-shadow: 0 4px 15px rgba(255, 0, 85, 0.5);">
99
+ <span id="global-broadcast-text">🚨 SYSTEM ALERT</span>
100
+ </div>
101
+
97
102
  <!-- App Header -->
98
103
  <header class="app-header">
99
104
  <div class="nav-container">
@@ -106,7 +111,6 @@
106
111
  <button class="nav-tab-btn active" data-tab="home" onclick="app.switchTab('home')">Home</button>
107
112
  <button class="nav-tab-btn" data-tab="games" onclick="app.switchTab('games')">Games (788)</button>
108
113
  <button class="nav-tab-btn" data-tab="leaderboard" onclick="app.switchTab('leaderboard')">Leaderboard</button>
109
- <button class="nav-tab-btn" data-tab="shield" style="color: #00d2ff;" onclick="app.switchTab('shield')">🛡️ Shield</button>
110
114
  <button class="nav-tab-btn" id="nav-tab-mod" style="display: none; color: #00ffaa;" data-tab="mod" onclick="app.switchTab('mod')">Mod</button>
111
115
  <button class="nav-tab-btn" id="nav-tab-admin" style="display: none; color: #ffd700;" data-tab="admin" onclick="app.switchTab('admin')">Admin</button>
112
116
  </nav>
@@ -132,6 +136,10 @@
132
136
  <span class="bind-username" id="header-username-display">Reaper</span>
133
137
  <span class="bind-rank rank-pill rank-member" id="header-rank-badge">MEMBER</span>
134
138
  </div>
139
+
140
+ <button class="btn-stealth" id="btn-settings-toggle" onclick="app.openSettingsModal()" style="border-color: var(--blue-bright); color: #00d2ff; font-weight: 800;" title="Settings & Security Shield">
141
+ ⚙️ Settings
142
+ </button>
135
143
  </div>
136
144
  </div>
137
145
  </header>
@@ -237,62 +245,6 @@
237
245
  </div>
238
246
  </section>
239
247
 
240
- <!-- ========================================== -->
241
- <!-- TAB: BROWSER EXTENSION SHIELD & FIREWALL -->
242
- <!-- ========================================== -->
243
- <section id="section-shield" class="tab-section" style="display: none;">
244
- <div class="leaderboard-container">
245
- <div class="leaderboard-header" style="border-color: #00d2ff;">
246
- <div>
247
- <h2 style="font-size: 1.6rem; color: #00d2ff; margin-bottom: 0.25rem; font-family: var(--font-heading);">
248
- 🛡️ BROWSER EXTENSION FIREWALL &amp; SPY DEFENDER
249
- </h2>
250
- <p style="color: var(--text-sub); font-size: 0.85rem;">
251
- Live extension detection engine. Scans, cuts, and isolates all school surveillance hooks and DOM sniffers.
252
- </p>
253
- </div>
254
- <div style="text-align: right;">
255
- <button class="btn-primary" onclick="app.purgeAllExtensionHooks()" style="background: #ff0055; border-color: #ff3377; padding: 0.6rem 1.2rem; font-size: 0.82rem;">
256
- ⚡ DISABLE &amp; PURGE ALL HOOKS
257
- </button>
258
- </div>
259
- </div>
260
-
261
- <!-- Controls & Status Strip -->
262
- <div style="display: flex; justify-content: space-between; align-items: center; background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px; margin-bottom: 1.5rem; flex-wrap: wrap; gap: 1rem;">
263
- <div style="display: flex; gap: 1.5rem; align-items: center;">
264
- <div>
265
- <span style="font-size: 0.72rem; color: #88aacc; text-transform: uppercase; display: block;">SHIELD STATUS</span>
266
- <strong style="color: #00ffaa; font-size: 0.95rem;">ACTIVE &amp; ENFORCING</strong>
267
- </div>
268
- <div>
269
- <span style="font-size: 0.72rem; color: #88aacc; text-transform: uppercase; display: block;">ISOLATION INTEGRITY</span>
270
- <strong style="color: #00d2ff; font-size: 0.95rem;">100% SECURE</strong>
271
- </div>
272
- </div>
273
-
274
- <div style="display: flex; gap: 1rem; align-items: center;">
275
- <label style="display: flex; align-items: center; gap: 0.5rem; cursor: pointer; color: #fff; font-size: 0.82rem; font-weight: 700;">
276
- <input type="checkbox" id="auto-shield-toggle" style="width: 20px; height: 20px; accent-color: #0088ff;" onchange="app.toggleAutoShield(this.checked)" checked>
277
- AUTO-PURGE ON EVERY VISIT
278
- </label>
279
- <button class="btn-stealth" onclick="app.refreshExtensionScan()" style="padding: 0.4rem 0.85rem; font-size: 0.78rem;">
280
- 🔄 RESCAN BROWSER
281
- </button>
282
- </div>
283
- </div>
284
-
285
- <!-- Detected Extensions Matrix -->
286
- <div style="font-size: 0.82rem; color: #88aacc; font-weight: 800; margin-bottom: 0.75rem; letter-spacing: 0.05em; text-transform: uppercase;">
287
- DETECTED EXTENSIONS &amp; SPY PROBES:
288
- </div>
289
-
290
- <div id="shield-extensions-list" style="display: flex; flex-direction: column; gap: 0.6rem;">
291
- <!-- Extensions rendered dynamically -->
292
- </div>
293
- </div>
294
- </section>
295
-
296
248
  <!-- ========================================== -->
297
249
  <!-- TAB 4: CHAT MOD TAB (MOD ONLY) -->
298
250
  <!-- ========================================== -->
@@ -304,6 +256,15 @@
304
256
  <span class="rank-pill rank-mod">CHAT MOD ACCESS</span>
305
257
  </div>
306
258
 
259
+ <!-- Slow Mode Toggle for Mods -->
260
+ <div class="mod-section" style="display: flex; justify-content: space-between; align-items: center;">
261
+ <div>
262
+ <strong style="color: #fff; font-size: 0.92rem;">CHAT SLOW-MODE (5 SECONDS)</strong>
263
+ <p style="color: #88aacc; font-size: 0.78rem;">Enforces a 5-second cooldown between messages to prevent spamming.</p>
264
+ </div>
265
+ <input type="checkbox" id="mod-slowmode-toggle" style="width: 22px; height: 22px; cursor: pointer; accent-color: #00ffaa;" onchange="app.toggleSlowMode(this.checked)">
266
+ </div>
267
+
307
268
  <!-- Timeout User Box -->
308
269
  <div class="mod-section">
309
270
  <h3 style="font-size: 0.95rem; color: #fff; margin-bottom: 0.35rem;">TIMEOUT / MUTE USER</h3>
@@ -319,7 +280,7 @@
319
280
  <!-- Live Chat Logs with Quick Actions -->
320
281
  <div class="mod-section">
321
282
  <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem;">
322
- <h3 style="font-size: 0.95rem; color: #fff;">LIVE CHAT LOGS & MESSAGE PURGE</h3>
283
+ <h3 style="font-size: 0.95rem; color: #fff;">LIVE CHAT LOGS &amp; MESSAGE PURGE</h3>
323
284
  </div>
324
285
  <p style="color: #88aacc; font-size: 0.8rem; margin-bottom: 0.75rem;">Click DEL to remove rulebreaking messages or TIMEOUT to mute the user.</p>
325
286
  <div id="mod-chat-logs" style="max-height: 280px; overflow-y: auto; background: #040912; border: 1px solid var(--blue-border); border-radius: 4px;"></div>
@@ -341,26 +302,47 @@
341
302
  </div>
342
303
  </div>
343
304
 
344
- <!-- User Roles & Directory (Promote / Demote) -->
305
+ <!-- Superpower: Global Live Broadcast Alert -->
306
+ <div class="admin-section" style="border-color: #ff0055; background: #18030c;">
307
+ <h3 style="font-size: 0.95rem; color: #ff3377; margin-bottom: 0.4rem;">👑 GLOBAL LIVE BROADCAST BANNER</h3>
308
+ <p style="color: #ff99bb; font-size: 0.8rem; margin-bottom: 0.75rem;">Display an instant sticky banner across all players' screens in real time.</p>
309
+ <div style="display: flex; gap: 0.5rem; flex-wrap: wrap;">
310
+ <input type="text" id="admin-broadcast-msg" class="red-chat-input" placeholder="Type global announcement message..." autocomplete="off" style="flex: 1; min-width: 250px;">
311
+ <button class="btn-primary" style="background: #ff0055; border-color: #ff3377;" onclick="app.sendGlobalAlert()">BROADCAST TO ALL PLAYERS</button>
312
+ <button class="btn-stealth" onclick="app.clearGlobalAlert()" style="color: #ff8888;">CLEAR BANNER</button>
313
+ </div>
314
+ </div>
315
+
316
+ <!-- Superpower: Chat Slow-Mode Switch -->
317
+ <div class="admin-section" style="display: flex; justify-content: space-between; align-items: center;">
318
+ <div>
319
+ <strong style="color: #fff; font-size: 0.95rem;">CHAT SLOW-MODE (5-SECOND COOLDOWN)</strong>
320
+ <p style="color: #88aacc; font-size: 0.8rem;">Enforces a 5-second interval between chat messages for non-owner players.</p>
321
+ </div>
322
+ <input type="checkbox" id="admin-slowmode-toggle" style="width: 22px; height: 22px; cursor: pointer; accent-color: #00d2ff;" onchange="app.toggleSlowMode(this.checked)">
323
+ </div>
324
+
325
+ <!-- Connected Players Directory (With Promote/Demote/Kick/Ban) -->
345
326
  <div class="admin-section">
346
- <h3 style="font-size: 0.95rem; color: #fff; margin-bottom: 0.35rem;">USER ROLES & PROMOTION</h3>
347
- <p style="color: #88aacc; font-size: 0.8rem; margin-bottom: 0.85rem;">Promote members to Chat Mod, de-rank mods back to Member, or ban offenders.</p>
348
- <div id="admin-users-directory" style="display: flex; flex-direction: column; gap: 0.4rem; max-height: 220px; overflow-y: auto;">
349
- <!-- Users rendered dynamically -->
327
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem;">
328
+ <h3 style="font-size: 0.95rem; color: #fff;">LIVE PLAYERS DIRECTORY &amp; ROLES</h3>
329
+ <button onclick="app.renderAdminUsersDirectory()" class="btn-stealth" style="font-size: 0.75rem;">REFRESH LIST</button>
350
330
  </div>
331
+ <p style="color: #88aacc; font-size: 0.8rem; margin-bottom: 0.65rem;">Manage connected users, promote to Chat Mod, de-rank, kick, or permanently ban.</p>
332
+ <div id="admin-users-directory" style="max-height: 200px; overflow-y: auto; display: flex; flex-direction: column; gap: 0.4rem;"></div>
351
333
  </div>
352
334
 
353
- <!-- Key Generator (Duration, Max Uses, & Auto-Expiration) -->
335
+ <!-- Custom Access Key Generator -->
354
336
  <div class="admin-section">
355
337
  <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem;">
356
- <h3 style="font-size: 0.95rem; color: #fff;">KEY GENERATOR & USAGE CONTROLS</h3>
357
- <button onclick="app.clearAllKeys()" class="btn-stealth" style="color: #ff5555; border-color: #771111; font-size: 0.72rem;">CLEAR ALL KEYS</button>
338
+ <h3 style="font-size: 0.95rem; color: #fff;">CUSTOM ACCESS KEY GENERATOR</h3>
339
+ <button onclick="app.clearAllKeys()" class="btn-stealth" style="color: #ff5555; border-color: #771111; font-size: 0.75rem;">PURGE ALL KEYS</button>
358
340
  </div>
359
- <p style="color: #88aacc; font-size: 0.8rem; margin-bottom: 0.85rem;">Set key name, duration, and max uses. Keys auto-expire once all uses are exhausted.</p>
341
+ <p style="color: #88aacc; font-size: 0.8rem; margin-bottom: 0.65rem;">Generate keys with custom durations (e.g. 3 Days, 5 Days, Lifetime) and usage limits.</p>
360
342
 
361
343
  <!-- Custom Key Creation Input -->
362
344
  <div style="display: flex; gap: 0.5rem; margin-bottom: 0.85rem; flex-wrap: wrap; align-items: center;">
363
- <input type="text" id="admin-custom-key-input" class="red-chat-input" placeholder="Blank for REAPER-$$$ (or type name)" autocomplete="off" style="max-width: 250px;">
345
+ <input type="text" id="admin-custom-key-input" class="red-chat-input" placeholder="Blank for REAPER-$$$ (or custom name)" autocomplete="off" style="max-width: 250px;">
364
346
 
365
347
  <select id="admin-custom-key-rank" style="background: #040912; color: #fff; border: 1px solid var(--blue-border); border-radius: 6px; padding: 0.45rem 0.65rem; font-size: 0.8rem; font-weight: 700;">
366
348
  <option value="member">Rank: Member</option>
@@ -389,7 +371,7 @@
389
371
  <button class="btn-primary" style="padding: 0.5rem 1.15rem;" onclick="app.createCustomKey()">GENERATE KEY</button>
390
372
  </div>
391
373
 
392
- <div style="font-size: 0.78rem; color: #88aacc; margin-bottom: 0.3rem;">ACTIVE KEYS & REMAINING USES:</div>
374
+ <div style="font-size: 0.78rem; color: #88aacc; margin-bottom: 0.3rem;">ACTIVE KEYS &amp; REMAINING USES:</div>
393
375
  <div id="admin-keys-list" style="max-height: 180px; overflow-y: auto;"></div>
394
376
  </div>
395
377
 
@@ -431,7 +413,7 @@
431
413
  <div style="display: flex; justify-content: space-between; align-items: center;">
432
414
  <div>
433
415
  <strong style="color: #ffbb33; font-size: 0.95rem;">PAUSE / FREEZE ALL ACCESS KEYS</strong>
434
- <p style="color: #ffe099; font-size: 0.8rem;">When paused, no new key logins can occur on the gateway. Key durations & remaining uses are frozen and preserved.</p>
416
+ <p style="color: #ffe099; font-size: 0.8rem;">When paused, no new key logins can occur on the gateway. Key durations &amp; remaining uses are frozen and preserved.</p>
435
417
  </div>
436
418
  <input type="checkbox" id="admin-keys-locked-toggle" style="width: 24px; height: 24px; cursor: pointer; accent-color: #ffaa00;" onchange="app.toggleKeysLocked(this.checked)">
437
419
  </div>
@@ -605,6 +587,136 @@
605
587
  </div>
606
588
  </div>
607
589
 
590
+ <!-- Settings & Security Suite Modal -->
591
+ <div id="settings-modal" style="position: fixed; inset: 0; background: rgba(0, 4, 10, 0.85); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); z-index: 99995; display: none; align-items: center; justify-content: center; padding: 1.5rem;">
592
+ <div style="background: linear-gradient(145deg, #061124 0%, #030814 100%); border: 1.5px solid var(--blue-border); border-radius: 14px; width: 100%; max-width: 850px; max-height: 90vh; display: flex; flex-direction: column; overflow: hidden; box-shadow: 0 0 45px rgba(0, 136, 255, 0.35);">
593
+
594
+ <!-- Settings Header -->
595
+ <div style="padding: 1rem 1.4rem; border-bottom: 1px solid var(--blue-border); display: flex; justify-content: space-between; align-items: center; background: #020712;">
596
+ <div style="display: flex; align-items: center; gap: 0.6rem;">
597
+ <span style="font-size: 1.2rem;">⚙️</span>
598
+ <span style="font-family: var(--font-heading); font-weight: 800; font-size: 1.1rem; color: #fff;">SETTINGS &amp; SECURITY SUITE</span>
599
+ </div>
600
+ <button onclick="app.closeSettingsModal()" class="btn-stealth" style="padding: 0.3rem 0.65rem; font-size: 0.9rem; font-weight: bold;">✕</button>
601
+ </div>
602
+
603
+ <!-- Settings Sub-Tabs -->
604
+ <div style="display: flex; border-bottom: 1px solid var(--blue-border); background: #030a18; padding: 0.5rem 1.4rem; gap: 0.5rem; overflow-x: auto;">
605
+ <button class="nav-tab-btn active" id="st-tab-btn-shield" onclick="app.switchSettingsTab('shield')" style="padding: 0.45rem 1rem; font-size: 0.82rem;">🛡️ Security Shield</button>
606
+ <button class="nav-tab-btn" id="st-tab-btn-prefs" onclick="app.switchSettingsTab('prefs')" style="padding: 0.45rem 1rem; font-size: 0.82rem;">⚡ Preferences &amp; Audio</button>
607
+ <button class="nav-tab-btn" id="st-tab-btn-saves" onclick="app.switchSettingsTab('saves')" style="padding: 0.45rem 1rem; font-size: 0.82rem;">💾 Game Saves</button>
608
+ <button class="nav-tab-btn" id="st-tab-btn-identity" onclick="app.switchSettingsTab('identity')" style="padding: 0.45rem 1rem; font-size: 0.82rem;">🔑 Device &amp; Rank</button>
609
+ </div>
610
+
611
+ <!-- Settings Content Body -->
612
+ <div style="padding: 1.4rem; overflow-y: auto; flex: 1;">
613
+
614
+ <!-- SUBTAB 1: SECURITY SHIELD -->
615
+ <div id="st-content-shield">
616
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.25rem; flex-wrap: wrap; gap: 1rem;">
617
+ <div>
618
+ <h3 style="font-size: 1.15rem; color: #00d2ff; font-family: var(--font-heading); margin-bottom: 0.2rem;">
619
+ 🛡️ BROWSER EXTENSION FIREWALL &amp; SPY DEFENDER
620
+ </h3>
621
+ <p style="color: var(--text-sub); font-size: 0.82rem;">
622
+ Scans, isolates, and terminates school surveillance hooks, screen snipers, and keyloggers.
623
+ </p>
624
+ </div>
625
+ <button class="btn-primary" onclick="app.purgeAllExtensionHooks()" style="background: #ff0055; border-color: #ff3377; padding: 0.6rem 1.2rem; font-size: 0.82rem;">
626
+ ⚡ DISABLE &amp; PURGE ALL HOOKS
627
+ </button>
628
+ </div>
629
+
630
+ <div style="display: flex; justify-content: space-between; align-items: center; background: #040e1e; border: 1px solid var(--blue-border); padding: 0.85rem 1.15rem; border-radius: 8px; margin-bottom: 1.25rem; flex-wrap: wrap; gap: 1rem;">
631
+ <div style="display: flex; gap: 1.5rem; align-items: center;">
632
+ <div>
633
+ <span style="font-size: 0.7rem; color: #88aacc; text-transform: uppercase; display: block;">SHIELD STATUS</span>
634
+ <strong style="color: #00ffaa; font-size: 0.92rem;">ACTIVE &amp; ENFORCING</strong>
635
+ </div>
636
+ <div>
637
+ <span style="font-size: 0.7rem; color: #88aacc; text-transform: uppercase; display: block;">ISOLATION INTEGRITY</span>
638
+ <strong style="color: #00d2ff; font-size: 0.92rem;">100% SECURE</strong>
639
+ </div>
640
+ </div>
641
+
642
+ <div style="display: flex; gap: 1rem; align-items: center;">
643
+ <label style="display: flex; align-items: center; gap: 0.5rem; cursor: pointer; color: #fff; font-size: 0.8rem; font-weight: 700;">
644
+ <input type="checkbox" id="auto-shield-toggle" style="width: 18px; height: 18px; accent-color: #0088ff;" onchange="app.toggleAutoShield(this.checked)" checked>
645
+ AUTO-PURGE ON VISIT
646
+ </label>
647
+ <button class="btn-stealth" onclick="app.refreshExtensionScan()" style="padding: 0.35rem 0.75rem; font-size: 0.75rem;">
648
+ 🔄 RESCAN BROWSER
649
+ </button>
650
+ </div>
651
+ </div>
652
+
653
+ <div style="font-size: 0.78rem; color: #88aacc; font-weight: 800; margin-bottom: 0.6rem; letter-spacing: 0.05em; text-transform: uppercase;">
654
+ DETECTED EXTENSIONS &amp; SPY PROBES:
655
+ </div>
656
+ <div id="shield-extensions-list" style="display: flex; flex-direction: column; gap: 0.55rem;"></div>
657
+ </div>
658
+
659
+ <!-- SUBTAB 2: PREFERENCES & AUDIO -->
660
+ <div id="st-content-prefs" style="display: none;">
661
+ <div style="display: flex; flex-direction: column; gap: 1.2rem;">
662
+ <div style="background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px; display: flex; justify-content: space-between; align-items: center;">
663
+ <div>
664
+ <strong style="color: #fff; font-size: 0.95rem;">🔊 Sci-Fi Synthesizer Sound FX</strong>
665
+ <p style="color: #88aacc; font-size: 0.8rem;">Play high-tech audio blips on card hover, tab clicks, and game launch.</p>
666
+ </div>
667
+ <button class="btn-primary" onclick="app.toggleSoundFX()" style="font-size: 0.82rem; padding: 0.5rem 1.2rem;">TOGGLE SFX</button>
668
+ </div>
669
+
670
+ <div style="background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px;">
671
+ <strong style="color: #00d2ff; font-size: 0.95rem;">🚨 Emergency Panic Cloak Hotkey</strong>
672
+ <p style="color: #88aacc; font-size: 0.8rem; margin-top: 0.35rem; line-height: 1.4;">
673
+ Press the <kbd style="background: #000; border: 1px solid var(--blue-bright); color: #00d2ff; padding: 0.15rem 0.45rem; border-radius: 4px; font-weight: bold;">~</kbd> (Tilde / Backquote) key at any moment to instantly disguise the site as <strong>Google Classroom</strong> with authentic assignments. Press <kbd style="background: #000; border: 1px solid var(--blue-bright); color: #00d2ff; padding: 0.15rem 0.45rem; border-radius: 4px; font-weight: bold;">~</kbd> again to exit disguise.
674
+ </p>
675
+ </div>
676
+ </div>
677
+ </div>
678
+
679
+ <!-- SUBTAB 3: GAME SAVES -->
680
+ <div id="st-content-saves" style="display: none;">
681
+ <div style="display: flex; flex-direction: column; gap: 1.2rem;">
682
+ <div style="background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px;">
683
+ <strong style="color: #00ffaa; font-size: 0.95rem;">💾 Export &amp; Backup Game Save Data</strong>
684
+ <p style="color: #88aacc; font-size: 0.8rem; margin: 0.4rem 0 0.85rem 0;">Download a single backup file containing all your local progress for Slope, Subway Surfers, BitLife, Retro Bowl, 1v1.LOL, and more.</p>
685
+ <button class="btn-primary" onclick="app.exportSaveData()" style="background: #00ffaa; color: #000; border-color: #00ffaa; font-size: 0.82rem;">💾 DOWNLOAD SAVE BACKUP</button>
686
+ </div>
687
+
688
+ <div style="background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px;">
689
+ <strong style="color: #ffd700; font-size: 0.95rem;">📥 Import &amp; Restore Game Save Data</strong>
690
+ <p style="color: #88aacc; font-size: 0.8rem; margin: 0.4rem 0 0.85rem 0;">Upload a previously downloaded JSON save backup file to restore all your game saves instantly.</p>
691
+ <button class="btn-primary" onclick="app.importSaveData()" style="background: #ffd700; color: #000; border-color: #ffd700; font-size: 0.82rem;">📥 RESTORE SAVE BACKUP</button>
692
+ </div>
693
+ </div>
694
+ </div>
695
+
696
+ <!-- SUBTAB 4: IDENTITY & HWID -->
697
+ <div id="st-content-identity" style="display: none;">
698
+ <div style="display: flex; flex-direction: column; gap: 1rem;">
699
+ <div style="background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px;">
700
+ <div style="font-size: 0.72rem; color: #88aacc; text-transform: uppercase; margin-bottom: 0.25rem;">CURRENT USERNAME</div>
701
+ <div id="st-display-username" style="font-size: 1.1rem; font-weight: 800; color: #fff;">-</div>
702
+ </div>
703
+
704
+ <div style="background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px;">
705
+ <div style="font-size: 0.72rem; color: #88aacc; text-transform: uppercase; margin-bottom: 0.25rem;">SECURITY ROLE / RANK</div>
706
+ <div id="st-display-rank" style="font-size: 1rem; font-weight: 800; color: #00d2ff;">MEMBER</div>
707
+ </div>
708
+
709
+ <div style="background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px;">
710
+ <div style="font-size: 0.72rem; color: #88aacc; text-transform: uppercase; margin-bottom: 0.25rem;">DEVICE HARDWARE ID (HWID HASH)</div>
711
+ <div id="st-display-hwid" style="font-family: var(--font-mono); font-size: 0.85rem; color: #88aacc;">-</div>
712
+ </div>
713
+ </div>
714
+ </div>
715
+
716
+ </div>
717
+ </div>
718
+ </div>
719
+
608
720
  <!-- Toast -->
609
721
  <div id="toast-box" class="toast-box"></div>
610
722
 
package/js/app.js CHANGED
@@ -139,6 +139,31 @@ class ReaperHubApp {
139
139
  window.location.replace("https://www.google.com");
140
140
  }
141
141
  });
142
+ window.reaperFirebase.listenGlobalAlert((alertMsg) => {
143
+ const banner = document.getElementById('global-broadcast-banner');
144
+ const textEl = document.getElementById('global-broadcast-text');
145
+ if (banner && textEl) {
146
+ if (alertMsg && alertMsg.trim().length > 0) {
147
+ textEl.textContent = `🚨 ${alertMsg}`;
148
+ banner.style.display = 'block';
149
+ } else {
150
+ banner.style.display = 'none';
151
+ }
152
+ }
153
+ });
154
+ window.reaperFirebase.listenSlowMode((isSlow) => {
155
+ this.isSlowModeActive = isSlow;
156
+ const adminToggle = document.getElementById('admin-slowmode-toggle');
157
+ const modToggle = document.getElementById('mod-slowmode-toggle');
158
+ if (adminToggle) adminToggle.checked = isSlow;
159
+ if (modToggle) modToggle.checked = isSlow;
160
+ });
161
+ window.reaperFirebase.listenKicked(this.currentUser.username, (kickData) => {
162
+ if (this.currentUser.rank !== 'owner') {
163
+ alert(`[KICKED FROM SERVER]\nReason: ${kickData.reason || 'Kicked by Administrator'}`);
164
+ window.location.replace('about:blank');
165
+ }
166
+ });
142
167
  }
143
168
 
144
169
  // 9. Render UI, Games, Leaderboard
@@ -716,6 +741,7 @@ class ReaperHubApp {
716
741
  ` : currentRank === 'chat_mod' || currentRank === 'mod' ? `
717
742
  <button onclick="app.setUserRank('${u.username}', 'member')" class="btn-stealth" style="color: #ffaa00; padding: 0.2rem 0.5rem; font-size: 0.72rem;">- DE-RANK MEMBER</button>
718
743
  ` : ''}
744
+ <button onclick="app.kickUser('${u.username}')" class="btn-stealth" style="color: #ffaa00; padding: 0.2rem 0.5rem; font-size: 0.72rem;">KICK</button>
719
745
  <button onclick="app.banUser('${u.username}')" class="btn-stealth" style="color: #ff5555; padding: 0.2rem 0.5rem; font-size: 0.72rem;">BAN</button>
720
746
  ` : '<span style="color: #ffd700; font-weight: 800;">YOU</span>'}
721
747
  </div>
@@ -724,6 +750,54 @@ class ReaperHubApp {
724
750
  }).join('');
725
751
  }
726
752
 
753
+ async sendGlobalAlert() {
754
+ if (this.currentUser.rank !== 'owner') return;
755
+ const input = document.getElementById('admin-broadcast-msg');
756
+ if (!input || !input.value.trim()) {
757
+ this.showToast("Enter a broadcast message.");
758
+ return;
759
+ }
760
+ const msg = input.value.trim();
761
+ if (window.reaperFirebase) {
762
+ await window.reaperFirebase.setGlobalAlert(msg);
763
+ this.showToast("Broadcast alert sent to all connected players! 🚨");
764
+ }
765
+ }
766
+
767
+ async clearGlobalAlert() {
768
+ if (this.currentUser.rank !== 'owner') return;
769
+ const input = document.getElementById('admin-broadcast-msg');
770
+ if (input) input.value = '';
771
+ if (window.reaperFirebase) {
772
+ await window.reaperFirebase.setGlobalAlert('');
773
+ this.showToast("Broadcast alert cleared.");
774
+ }
775
+ }
776
+
777
+ async toggleSlowMode(isSlow) {
778
+ if (this.currentUser.rank !== 'owner' && this.currentUser.rank !== 'chat_mod' && this.currentUser.rank !== 'mod') return;
779
+ this.isSlowModeActive = isSlow;
780
+ if (window.reaperFirebase) {
781
+ await window.reaperFirebase.setSlowMode(isSlow);
782
+ this.showToast(isSlow ? "Chat Slow-Mode Enabled (5s Cooldown)" : "Chat Slow-Mode Disabled");
783
+ }
784
+ }
785
+
786
+ async kickUser(username) {
787
+ if (this.currentUser.rank !== 'owner') return;
788
+ if (username === this.currentUser.username || username === 'owner') {
789
+ this.showToast("Cannot kick Owner.");
790
+ return;
791
+ }
792
+ const reason = prompt(`Enter reason for kicking ${username}:`, "Kicked by Administrator");
793
+ if (reason !== null) {
794
+ if (window.reaperFirebase) {
795
+ await window.reaperFirebase.kickUser(username, reason);
796
+ this.showToast(`Kicked user ${username}!`);
797
+ }
798
+ }
799
+ }
800
+
727
801
  // ==========================================
728
802
  // CHAT MOD DESK ACTIONS
729
803
  // ==========================================
@@ -1039,6 +1113,16 @@ class ReaperHubApp {
1039
1113
  return;
1040
1114
  }
1041
1115
 
1116
+ if (this.isSlowModeActive && !isPrivileged) {
1117
+ const now = Date.now();
1118
+ if (this.lastChatMessageTime && (now - this.lastChatMessageTime < 5000)) {
1119
+ const waitSec = Math.ceil((5000 - (now - this.lastChatMessageTime)) / 1000);
1120
+ this.showToast(`Slow-mode active: please wait ${waitSec}s.`);
1121
+ return;
1122
+ }
1123
+ this.lastChatMessageTime = now;
1124
+ }
1125
+
1042
1126
  const secondsLeft = window.aiModerator ? window.aiModerator.getTimeoutRemaining() : 0;
1043
1127
  if (secondsLeft > 0 && !isPrivileged) {
1044
1128
  this.showToast("You are currently timed out.");
@@ -1872,6 +1956,40 @@ class ReaperHubApp {
1872
1956
  }
1873
1957
  }
1874
1958
 
1959
+ openSettingsModal() {
1960
+ const modal = document.getElementById('settings-modal');
1961
+ if (modal) {
1962
+ modal.style.display = 'flex';
1963
+ this.switchSettingsTab('shield');
1964
+ const nameEl = document.getElementById('st-display-username');
1965
+ const rankEl = document.getElementById('st-display-rank');
1966
+ const hwidEl = document.getElementById('st-display-hwid');
1967
+ if (nameEl) nameEl.textContent = this.currentUser.username || 'Reaper';
1968
+ if (rankEl) rankEl.textContent = (this.currentUser.rank || 'member').toUpperCase();
1969
+ if (hwidEl) hwidEl.textContent = this.getDeviceHWID();
1970
+ if (window.reaperSFX) window.reaperSFX.playClick();
1971
+ }
1972
+ }
1973
+
1974
+ closeSettingsModal() {
1975
+ const modal = document.getElementById('settings-modal');
1976
+ if (modal) modal.style.display = 'none';
1977
+ }
1978
+
1979
+ switchSettingsTab(tabName) {
1980
+ ['shield', 'prefs', 'saves', 'identity'].forEach(t => {
1981
+ const btn = document.getElementById(`st-tab-btn-${t}`);
1982
+ const content = document.getElementById(`st-content-${t}`);
1983
+ if (btn) btn.classList.toggle('active', t === tabName);
1984
+ if (content) content.style.display = (t === tabName) ? 'block' : 'none';
1985
+ });
1986
+
1987
+ if (tabName === 'shield') {
1988
+ this.renderShieldUI();
1989
+ }
1990
+ if (window.reaperSFX) window.reaperSFX.playClick();
1991
+ }
1992
+
1875
1993
  escapeHtml(str) {
1876
1994
  const div = document.createElement('div');
1877
1995
  div.textContent = str;
@@ -280,7 +280,77 @@ class FirebaseService {
280
280
  }
281
281
  }
282
282
 
283
- // Permanent Shutdown Mode ("WE ARE SHUTTING DOWN FOR GOOD")
283
+ // Global Owner Broadcast Alert Banner
284
+ listenGlobalAlert(callback) {
285
+ if (this.db) {
286
+ try {
287
+ this.db.ref("reaperGlobalAlert").on("value", (snap) => {
288
+ callback(snap.val() || '');
289
+ });
290
+ } catch (e) {
291
+ callback('');
292
+ }
293
+ }
294
+ }
295
+
296
+ async setGlobalAlert(message) {
297
+ if (this.db) {
298
+ try {
299
+ if (!message) {
300
+ await this.db.ref("reaperGlobalAlert").remove();
301
+ } else {
302
+ await this.db.ref("reaperGlobalAlert").set(message);
303
+ }
304
+ } catch (e) {}
305
+ }
306
+ }
307
+
308
+ // Chat Slow-Mode
309
+ listenSlowMode(callback) {
310
+ if (this.db) {
311
+ try {
312
+ this.db.ref("reaperSlowMode").on("value", (snap) => {
313
+ callback(Boolean(snap.val()));
314
+ });
315
+ } catch (e) {
316
+ callback(false);
317
+ }
318
+ }
319
+ }
320
+
321
+ async setSlowMode(isSlow) {
322
+ if (this.db) {
323
+ try {
324
+ await this.db.ref("reaperSlowMode").set(isSlow);
325
+ } catch (e) {}
326
+ }
327
+ }
328
+
329
+ // Realtime User Kick System
330
+ listenKicked(myUsername, callback) {
331
+ if (this.db && myUsername) {
332
+ try {
333
+ this.db.ref(`reaperKicked/${myUsername}`).on("value", (snap) => {
334
+ if (snap.exists() && snap.val()) {
335
+ callback(snap.val());
336
+ }
337
+ });
338
+ } catch (e) {}
339
+ }
340
+ }
341
+
342
+ async kickUser(username, reason) {
343
+ if (this.db && username) {
344
+ try {
345
+ await this.db.ref(`reaperKicked/${username}`).set({
346
+ reason: reason || 'Kicked by Administrator',
347
+ timestamp: Date.now()
348
+ });
349
+ } catch (e) {}
350
+ }
351
+ }
352
+
353
+ // Realtime Perm Shutdown Mode
284
354
  listenShutdownMode(callback) {
285
355
  if (this.db) {
286
356
  try {
@@ -289,7 +359,11 @@ class FirebaseService {
289
359
  localStorage.setItem('reaper_shutdown_mode', isShutdown ? 'true' : 'false');
290
360
  callback(isShutdown);
291
361
  });
292
- } catch (e) {}
362
+ } catch (e) {
363
+ callback(localStorage.getItem('reaper_shutdown_mode') === 'true');
364
+ }
365
+ } else {
366
+ callback(localStorage.getItem('reaper_shutdown_mode') === 'true');
293
367
  }
294
368
  }
295
369
 
package/main/index.html CHANGED
@@ -94,6 +94,11 @@
94
94
  <!-- Starfield Space Canvas -->
95
95
  <canvas id="bg-canvas"></canvas>
96
96
 
97
+ <!-- Global Live Broadcast Alert Banner -->
98
+ <div id="global-broadcast-banner" style="display: none; background: linear-gradient(90deg, #ff0055, #ff8800); color: #fff; padding: 0.55rem 1rem; text-align: center; font-weight: 800; font-size: 0.85rem; letter-spacing: 0.05em; z-index: 99990; position: sticky; top: 0; box-shadow: 0 4px 15px rgba(255, 0, 85, 0.5);">
99
+ <span id="global-broadcast-text">🚨 SYSTEM ALERT</span>
100
+ </div>
101
+
97
102
  <!-- App Header -->
98
103
  <header class="app-header">
99
104
  <div class="nav-container">
@@ -106,7 +111,6 @@
106
111
  <button class="nav-tab-btn active" data-tab="home" onclick="app.switchTab('home')">Home</button>
107
112
  <button class="nav-tab-btn" data-tab="games" onclick="app.switchTab('games')">Games (788)</button>
108
113
  <button class="nav-tab-btn" data-tab="leaderboard" onclick="app.switchTab('leaderboard')">Leaderboard</button>
109
- <button class="nav-tab-btn" data-tab="shield" style="color: #00d2ff;" onclick="app.switchTab('shield')">🛡️ Shield</button>
110
114
  <button class="nav-tab-btn" id="nav-tab-mod" style="display: none; color: #00ffaa;" data-tab="mod" onclick="app.switchTab('mod')">Mod</button>
111
115
  <button class="nav-tab-btn" id="nav-tab-admin" style="display: none; color: #ffd700;" data-tab="admin" onclick="app.switchTab('admin')">Admin</button>
112
116
  </nav>
@@ -132,6 +136,10 @@
132
136
  <span class="bind-username" id="header-username-display">Reaper</span>
133
137
  <span class="bind-rank rank-pill rank-member" id="header-rank-badge">MEMBER</span>
134
138
  </div>
139
+
140
+ <button class="btn-stealth" id="btn-settings-toggle" onclick="app.openSettingsModal()" style="border-color: var(--blue-bright); color: #00d2ff; font-weight: 800;" title="Settings & Security Shield">
141
+ ⚙️ Settings
142
+ </button>
135
143
  </div>
136
144
  </div>
137
145
  </header>
@@ -237,62 +245,6 @@
237
245
  </div>
238
246
  </section>
239
247
 
240
- <!-- ========================================== -->
241
- <!-- TAB: BROWSER EXTENSION SHIELD & FIREWALL -->
242
- <!-- ========================================== -->
243
- <section id="section-shield" class="tab-section" style="display: none;">
244
- <div class="leaderboard-container">
245
- <div class="leaderboard-header" style="border-color: #00d2ff;">
246
- <div>
247
- <h2 style="font-size: 1.6rem; color: #00d2ff; margin-bottom: 0.25rem; font-family: var(--font-heading);">
248
- 🛡️ BROWSER EXTENSION FIREWALL &amp; SPY DEFENDER
249
- </h2>
250
- <p style="color: var(--text-sub); font-size: 0.85rem;">
251
- Live extension detection engine. Scans, cuts, and isolates all school surveillance hooks and DOM sniffers.
252
- </p>
253
- </div>
254
- <div style="text-align: right;">
255
- <button class="btn-primary" onclick="app.purgeAllExtensionHooks()" style="background: #ff0055; border-color: #ff3377; padding: 0.6rem 1.2rem; font-size: 0.82rem;">
256
- ⚡ DISABLE &amp; PURGE ALL HOOKS
257
- </button>
258
- </div>
259
- </div>
260
-
261
- <!-- Controls & Status Strip -->
262
- <div style="display: flex; justify-content: space-between; align-items: center; background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px; margin-bottom: 1.5rem; flex-wrap: wrap; gap: 1rem;">
263
- <div style="display: flex; gap: 1.5rem; align-items: center;">
264
- <div>
265
- <span style="font-size: 0.72rem; color: #88aacc; text-transform: uppercase; display: block;">SHIELD STATUS</span>
266
- <strong style="color: #00ffaa; font-size: 0.95rem;">ACTIVE &amp; ENFORCING</strong>
267
- </div>
268
- <div>
269
- <span style="font-size: 0.72rem; color: #88aacc; text-transform: uppercase; display: block;">ISOLATION INTEGRITY</span>
270
- <strong style="color: #00d2ff; font-size: 0.95rem;">100% SECURE</strong>
271
- </div>
272
- </div>
273
-
274
- <div style="display: flex; gap: 1rem; align-items: center;">
275
- <label style="display: flex; align-items: center; gap: 0.5rem; cursor: pointer; color: #fff; font-size: 0.82rem; font-weight: 700;">
276
- <input type="checkbox" id="auto-shield-toggle" style="width: 20px; height: 20px; accent-color: #0088ff;" onchange="app.toggleAutoShield(this.checked)" checked>
277
- AUTO-PURGE ON EVERY VISIT
278
- </label>
279
- <button class="btn-stealth" onclick="app.refreshExtensionScan()" style="padding: 0.4rem 0.85rem; font-size: 0.78rem;">
280
- 🔄 RESCAN BROWSER
281
- </button>
282
- </div>
283
- </div>
284
-
285
- <!-- Detected Extensions Matrix -->
286
- <div style="font-size: 0.82rem; color: #88aacc; font-weight: 800; margin-bottom: 0.75rem; letter-spacing: 0.05em; text-transform: uppercase;">
287
- DETECTED EXTENSIONS &amp; SPY PROBES:
288
- </div>
289
-
290
- <div id="shield-extensions-list" style="display: flex; flex-direction: column; gap: 0.6rem;">
291
- <!-- Extensions rendered dynamically -->
292
- </div>
293
- </div>
294
- </section>
295
-
296
248
  <!-- ========================================== -->
297
249
  <!-- TAB 4: CHAT MOD TAB (MOD ONLY) -->
298
250
  <!-- ========================================== -->
@@ -304,6 +256,15 @@
304
256
  <span class="rank-pill rank-mod">CHAT MOD ACCESS</span>
305
257
  </div>
306
258
 
259
+ <!-- Slow Mode Toggle for Mods -->
260
+ <div class="mod-section" style="display: flex; justify-content: space-between; align-items: center;">
261
+ <div>
262
+ <strong style="color: #fff; font-size: 0.92rem;">CHAT SLOW-MODE (5 SECONDS)</strong>
263
+ <p style="color: #88aacc; font-size: 0.78rem;">Enforces a 5-second cooldown between messages to prevent spamming.</p>
264
+ </div>
265
+ <input type="checkbox" id="mod-slowmode-toggle" style="width: 22px; height: 22px; cursor: pointer; accent-color: #00ffaa;" onchange="app.toggleSlowMode(this.checked)">
266
+ </div>
267
+
307
268
  <!-- Timeout User Box -->
308
269
  <div class="mod-section">
309
270
  <h3 style="font-size: 0.95rem; color: #fff; margin-bottom: 0.35rem;">TIMEOUT / MUTE USER</h3>
@@ -319,7 +280,7 @@
319
280
  <!-- Live Chat Logs with Quick Actions -->
320
281
  <div class="mod-section">
321
282
  <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem;">
322
- <h3 style="font-size: 0.95rem; color: #fff;">LIVE CHAT LOGS & MESSAGE PURGE</h3>
283
+ <h3 style="font-size: 0.95rem; color: #fff;">LIVE CHAT LOGS &amp; MESSAGE PURGE</h3>
323
284
  </div>
324
285
  <p style="color: #88aacc; font-size: 0.8rem; margin-bottom: 0.75rem;">Click DEL to remove rulebreaking messages or TIMEOUT to mute the user.</p>
325
286
  <div id="mod-chat-logs" style="max-height: 280px; overflow-y: auto; background: #040912; border: 1px solid var(--blue-border); border-radius: 4px;"></div>
@@ -341,26 +302,47 @@
341
302
  </div>
342
303
  </div>
343
304
 
344
- <!-- User Roles & Directory (Promote / Demote) -->
305
+ <!-- Superpower: Global Live Broadcast Alert -->
306
+ <div class="admin-section" style="border-color: #ff0055; background: #18030c;">
307
+ <h3 style="font-size: 0.95rem; color: #ff3377; margin-bottom: 0.4rem;">👑 GLOBAL LIVE BROADCAST BANNER</h3>
308
+ <p style="color: #ff99bb; font-size: 0.8rem; margin-bottom: 0.75rem;">Display an instant sticky banner across all players' screens in real time.</p>
309
+ <div style="display: flex; gap: 0.5rem; flex-wrap: wrap;">
310
+ <input type="text" id="admin-broadcast-msg" class="red-chat-input" placeholder="Type global announcement message..." autocomplete="off" style="flex: 1; min-width: 250px;">
311
+ <button class="btn-primary" style="background: #ff0055; border-color: #ff3377;" onclick="app.sendGlobalAlert()">BROADCAST TO ALL PLAYERS</button>
312
+ <button class="btn-stealth" onclick="app.clearGlobalAlert()" style="color: #ff8888;">CLEAR BANNER</button>
313
+ </div>
314
+ </div>
315
+
316
+ <!-- Superpower: Chat Slow-Mode Switch -->
317
+ <div class="admin-section" style="display: flex; justify-content: space-between; align-items: center;">
318
+ <div>
319
+ <strong style="color: #fff; font-size: 0.95rem;">CHAT SLOW-MODE (5-SECOND COOLDOWN)</strong>
320
+ <p style="color: #88aacc; font-size: 0.8rem;">Enforces a 5-second interval between chat messages for non-owner players.</p>
321
+ </div>
322
+ <input type="checkbox" id="admin-slowmode-toggle" style="width: 22px; height: 22px; cursor: pointer; accent-color: #00d2ff;" onchange="app.toggleSlowMode(this.checked)">
323
+ </div>
324
+
325
+ <!-- Connected Players Directory (With Promote/Demote/Kick/Ban) -->
345
326
  <div class="admin-section">
346
- <h3 style="font-size: 0.95rem; color: #fff; margin-bottom: 0.35rem;">USER ROLES & PROMOTION</h3>
347
- <p style="color: #88aacc; font-size: 0.8rem; margin-bottom: 0.85rem;">Promote members to Chat Mod, de-rank mods back to Member, or ban offenders.</p>
348
- <div id="admin-users-directory" style="display: flex; flex-direction: column; gap: 0.4rem; max-height: 220px; overflow-y: auto;">
349
- <!-- Users rendered dynamically -->
327
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem;">
328
+ <h3 style="font-size: 0.95rem; color: #fff;">LIVE PLAYERS DIRECTORY &amp; ROLES</h3>
329
+ <button onclick="app.renderAdminUsersDirectory()" class="btn-stealth" style="font-size: 0.75rem;">REFRESH LIST</button>
350
330
  </div>
331
+ <p style="color: #88aacc; font-size: 0.8rem; margin-bottom: 0.65rem;">Manage connected users, promote to Chat Mod, de-rank, kick, or permanently ban.</p>
332
+ <div id="admin-users-directory" style="max-height: 200px; overflow-y: auto; display: flex; flex-direction: column; gap: 0.4rem;"></div>
351
333
  </div>
352
334
 
353
- <!-- Key Generator (Duration, Max Uses, & Auto-Expiration) -->
335
+ <!-- Custom Access Key Generator -->
354
336
  <div class="admin-section">
355
337
  <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem;">
356
- <h3 style="font-size: 0.95rem; color: #fff;">KEY GENERATOR & USAGE CONTROLS</h3>
357
- <button onclick="app.clearAllKeys()" class="btn-stealth" style="color: #ff5555; border-color: #771111; font-size: 0.72rem;">CLEAR ALL KEYS</button>
338
+ <h3 style="font-size: 0.95rem; color: #fff;">CUSTOM ACCESS KEY GENERATOR</h3>
339
+ <button onclick="app.clearAllKeys()" class="btn-stealth" style="color: #ff5555; border-color: #771111; font-size: 0.75rem;">PURGE ALL KEYS</button>
358
340
  </div>
359
- <p style="color: #88aacc; font-size: 0.8rem; margin-bottom: 0.85rem;">Set key name, duration, and max uses. Keys auto-expire once all uses are exhausted.</p>
341
+ <p style="color: #88aacc; font-size: 0.8rem; margin-bottom: 0.65rem;">Generate keys with custom durations (e.g. 3 Days, 5 Days, Lifetime) and usage limits.</p>
360
342
 
361
343
  <!-- Custom Key Creation Input -->
362
344
  <div style="display: flex; gap: 0.5rem; margin-bottom: 0.85rem; flex-wrap: wrap; align-items: center;">
363
- <input type="text" id="admin-custom-key-input" class="red-chat-input" placeholder="Blank for REAPER-$$$ (or type name)" autocomplete="off" style="max-width: 250px;">
345
+ <input type="text" id="admin-custom-key-input" class="red-chat-input" placeholder="Blank for REAPER-$$$ (or custom name)" autocomplete="off" style="max-width: 250px;">
364
346
 
365
347
  <select id="admin-custom-key-rank" style="background: #040912; color: #fff; border: 1px solid var(--blue-border); border-radius: 6px; padding: 0.45rem 0.65rem; font-size: 0.8rem; font-weight: 700;">
366
348
  <option value="member">Rank: Member</option>
@@ -389,7 +371,7 @@
389
371
  <button class="btn-primary" style="padding: 0.5rem 1.15rem;" onclick="app.createCustomKey()">GENERATE KEY</button>
390
372
  </div>
391
373
 
392
- <div style="font-size: 0.78rem; color: #88aacc; margin-bottom: 0.3rem;">ACTIVE KEYS & REMAINING USES:</div>
374
+ <div style="font-size: 0.78rem; color: #88aacc; margin-bottom: 0.3rem;">ACTIVE KEYS &amp; REMAINING USES:</div>
393
375
  <div id="admin-keys-list" style="max-height: 180px; overflow-y: auto;"></div>
394
376
  </div>
395
377
 
@@ -431,7 +413,7 @@
431
413
  <div style="display: flex; justify-content: space-between; align-items: center;">
432
414
  <div>
433
415
  <strong style="color: #ffbb33; font-size: 0.95rem;">PAUSE / FREEZE ALL ACCESS KEYS</strong>
434
- <p style="color: #ffe099; font-size: 0.8rem;">When paused, no new key logins can occur on the gateway. Key durations & remaining uses are frozen and preserved.</p>
416
+ <p style="color: #ffe099; font-size: 0.8rem;">When paused, no new key logins can occur on the gateway. Key durations &amp; remaining uses are frozen and preserved.</p>
435
417
  </div>
436
418
  <input type="checkbox" id="admin-keys-locked-toggle" style="width: 24px; height: 24px; cursor: pointer; accent-color: #ffaa00;" onchange="app.toggleKeysLocked(this.checked)">
437
419
  </div>
@@ -605,6 +587,136 @@
605
587
  </div>
606
588
  </div>
607
589
 
590
+ <!-- Settings & Security Suite Modal -->
591
+ <div id="settings-modal" style="position: fixed; inset: 0; background: rgba(0, 4, 10, 0.85); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); z-index: 99995; display: none; align-items: center; justify-content: center; padding: 1.5rem;">
592
+ <div style="background: linear-gradient(145deg, #061124 0%, #030814 100%); border: 1.5px solid var(--blue-border); border-radius: 14px; width: 100%; max-width: 850px; max-height: 90vh; display: flex; flex-direction: column; overflow: hidden; box-shadow: 0 0 45px rgba(0, 136, 255, 0.35);">
593
+
594
+ <!-- Settings Header -->
595
+ <div style="padding: 1rem 1.4rem; border-bottom: 1px solid var(--blue-border); display: flex; justify-content: space-between; align-items: center; background: #020712;">
596
+ <div style="display: flex; align-items: center; gap: 0.6rem;">
597
+ <span style="font-size: 1.2rem;">⚙️</span>
598
+ <span style="font-family: var(--font-heading); font-weight: 800; font-size: 1.1rem; color: #fff;">SETTINGS &amp; SECURITY SUITE</span>
599
+ </div>
600
+ <button onclick="app.closeSettingsModal()" class="btn-stealth" style="padding: 0.3rem 0.65rem; font-size: 0.9rem; font-weight: bold;">✕</button>
601
+ </div>
602
+
603
+ <!-- Settings Sub-Tabs -->
604
+ <div style="display: flex; border-bottom: 1px solid var(--blue-border); background: #030a18; padding: 0.5rem 1.4rem; gap: 0.5rem; overflow-x: auto;">
605
+ <button class="nav-tab-btn active" id="st-tab-btn-shield" onclick="app.switchSettingsTab('shield')" style="padding: 0.45rem 1rem; font-size: 0.82rem;">🛡️ Security Shield</button>
606
+ <button class="nav-tab-btn" id="st-tab-btn-prefs" onclick="app.switchSettingsTab('prefs')" style="padding: 0.45rem 1rem; font-size: 0.82rem;">⚡ Preferences &amp; Audio</button>
607
+ <button class="nav-tab-btn" id="st-tab-btn-saves" onclick="app.switchSettingsTab('saves')" style="padding: 0.45rem 1rem; font-size: 0.82rem;">💾 Game Saves</button>
608
+ <button class="nav-tab-btn" id="st-tab-btn-identity" onclick="app.switchSettingsTab('identity')" style="padding: 0.45rem 1rem; font-size: 0.82rem;">🔑 Device &amp; Rank</button>
609
+ </div>
610
+
611
+ <!-- Settings Content Body -->
612
+ <div style="padding: 1.4rem; overflow-y: auto; flex: 1;">
613
+
614
+ <!-- SUBTAB 1: SECURITY SHIELD -->
615
+ <div id="st-content-shield">
616
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.25rem; flex-wrap: wrap; gap: 1rem;">
617
+ <div>
618
+ <h3 style="font-size: 1.15rem; color: #00d2ff; font-family: var(--font-heading); margin-bottom: 0.2rem;">
619
+ 🛡️ BROWSER EXTENSION FIREWALL &amp; SPY DEFENDER
620
+ </h3>
621
+ <p style="color: var(--text-sub); font-size: 0.82rem;">
622
+ Scans, isolates, and terminates school surveillance hooks, screen snipers, and keyloggers.
623
+ </p>
624
+ </div>
625
+ <button class="btn-primary" onclick="app.purgeAllExtensionHooks()" style="background: #ff0055; border-color: #ff3377; padding: 0.6rem 1.2rem; font-size: 0.82rem;">
626
+ ⚡ DISABLE &amp; PURGE ALL HOOKS
627
+ </button>
628
+ </div>
629
+
630
+ <div style="display: flex; justify-content: space-between; align-items: center; background: #040e1e; border: 1px solid var(--blue-border); padding: 0.85rem 1.15rem; border-radius: 8px; margin-bottom: 1.25rem; flex-wrap: wrap; gap: 1rem;">
631
+ <div style="display: flex; gap: 1.5rem; align-items: center;">
632
+ <div>
633
+ <span style="font-size: 0.7rem; color: #88aacc; text-transform: uppercase; display: block;">SHIELD STATUS</span>
634
+ <strong style="color: #00ffaa; font-size: 0.92rem;">ACTIVE &amp; ENFORCING</strong>
635
+ </div>
636
+ <div>
637
+ <span style="font-size: 0.7rem; color: #88aacc; text-transform: uppercase; display: block;">ISOLATION INTEGRITY</span>
638
+ <strong style="color: #00d2ff; font-size: 0.92rem;">100% SECURE</strong>
639
+ </div>
640
+ </div>
641
+
642
+ <div style="display: flex; gap: 1rem; align-items: center;">
643
+ <label style="display: flex; align-items: center; gap: 0.5rem; cursor: pointer; color: #fff; font-size: 0.8rem; font-weight: 700;">
644
+ <input type="checkbox" id="auto-shield-toggle" style="width: 18px; height: 18px; accent-color: #0088ff;" onchange="app.toggleAutoShield(this.checked)" checked>
645
+ AUTO-PURGE ON VISIT
646
+ </label>
647
+ <button class="btn-stealth" onclick="app.refreshExtensionScan()" style="padding: 0.35rem 0.75rem; font-size: 0.75rem;">
648
+ 🔄 RESCAN BROWSER
649
+ </button>
650
+ </div>
651
+ </div>
652
+
653
+ <div style="font-size: 0.78rem; color: #88aacc; font-weight: 800; margin-bottom: 0.6rem; letter-spacing: 0.05em; text-transform: uppercase;">
654
+ DETECTED EXTENSIONS &amp; SPY PROBES:
655
+ </div>
656
+ <div id="shield-extensions-list" style="display: flex; flex-direction: column; gap: 0.55rem;"></div>
657
+ </div>
658
+
659
+ <!-- SUBTAB 2: PREFERENCES & AUDIO -->
660
+ <div id="st-content-prefs" style="display: none;">
661
+ <div style="display: flex; flex-direction: column; gap: 1.2rem;">
662
+ <div style="background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px; display: flex; justify-content: space-between; align-items: center;">
663
+ <div>
664
+ <strong style="color: #fff; font-size: 0.95rem;">🔊 Sci-Fi Synthesizer Sound FX</strong>
665
+ <p style="color: #88aacc; font-size: 0.8rem;">Play high-tech audio blips on card hover, tab clicks, and game launch.</p>
666
+ </div>
667
+ <button class="btn-primary" onclick="app.toggleSoundFX()" style="font-size: 0.82rem; padding: 0.5rem 1.2rem;">TOGGLE SFX</button>
668
+ </div>
669
+
670
+ <div style="background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px;">
671
+ <strong style="color: #00d2ff; font-size: 0.95rem;">🚨 Emergency Panic Cloak Hotkey</strong>
672
+ <p style="color: #88aacc; font-size: 0.8rem; margin-top: 0.35rem; line-height: 1.4;">
673
+ Press the <kbd style="background: #000; border: 1px solid var(--blue-bright); color: #00d2ff; padding: 0.15rem 0.45rem; border-radius: 4px; font-weight: bold;">~</kbd> (Tilde / Backquote) key at any moment to instantly disguise the site as <strong>Google Classroom</strong> with authentic assignments. Press <kbd style="background: #000; border: 1px solid var(--blue-bright); color: #00d2ff; padding: 0.15rem 0.45rem; border-radius: 4px; font-weight: bold;">~</kbd> again to exit disguise.
674
+ </p>
675
+ </div>
676
+ </div>
677
+ </div>
678
+
679
+ <!-- SUBTAB 3: GAME SAVES -->
680
+ <div id="st-content-saves" style="display: none;">
681
+ <div style="display: flex; flex-direction: column; gap: 1.2rem;">
682
+ <div style="background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px;">
683
+ <strong style="color: #00ffaa; font-size: 0.95rem;">💾 Export &amp; Backup Game Save Data</strong>
684
+ <p style="color: #88aacc; font-size: 0.8rem; margin: 0.4rem 0 0.85rem 0;">Download a single backup file containing all your local progress for Slope, Subway Surfers, BitLife, Retro Bowl, 1v1.LOL, and more.</p>
685
+ <button class="btn-primary" onclick="app.exportSaveData()" style="background: #00ffaa; color: #000; border-color: #00ffaa; font-size: 0.82rem;">💾 DOWNLOAD SAVE BACKUP</button>
686
+ </div>
687
+
688
+ <div style="background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px;">
689
+ <strong style="color: #ffd700; font-size: 0.95rem;">📥 Import &amp; Restore Game Save Data</strong>
690
+ <p style="color: #88aacc; font-size: 0.8rem; margin: 0.4rem 0 0.85rem 0;">Upload a previously downloaded JSON save backup file to restore all your game saves instantly.</p>
691
+ <button class="btn-primary" onclick="app.importSaveData()" style="background: #ffd700; color: #000; border-color: #ffd700; font-size: 0.82rem;">📥 RESTORE SAVE BACKUP</button>
692
+ </div>
693
+ </div>
694
+ </div>
695
+
696
+ <!-- SUBTAB 4: IDENTITY & HWID -->
697
+ <div id="st-content-identity" style="display: none;">
698
+ <div style="display: flex; flex-direction: column; gap: 1rem;">
699
+ <div style="background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px;">
700
+ <div style="font-size: 0.72rem; color: #88aacc; text-transform: uppercase; margin-bottom: 0.25rem;">CURRENT USERNAME</div>
701
+ <div id="st-display-username" style="font-size: 1.1rem; font-weight: 800; color: #fff;">-</div>
702
+ </div>
703
+
704
+ <div style="background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px;">
705
+ <div style="font-size: 0.72rem; color: #88aacc; text-transform: uppercase; margin-bottom: 0.25rem;">SECURITY ROLE / RANK</div>
706
+ <div id="st-display-rank" style="font-size: 1rem; font-weight: 800; color: #00d2ff;">MEMBER</div>
707
+ </div>
708
+
709
+ <div style="background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px;">
710
+ <div style="font-size: 0.72rem; color: #88aacc; text-transform: uppercase; margin-bottom: 0.25rem;">DEVICE HARDWARE ID (HWID HASH)</div>
711
+ <div id="st-display-hwid" style="font-family: var(--font-mono); font-size: 0.85rem; color: #88aacc;">-</div>
712
+ </div>
713
+ </div>
714
+ </div>
715
+
716
+ </div>
717
+ </div>
718
+ </div>
719
+
608
720
  <!-- Toast -->
609
721
  <div id="toast-box" class="toast-box"></div>
610
722
 
package/main/js/app.js CHANGED
@@ -139,6 +139,31 @@ class ReaperHubApp {
139
139
  window.location.replace("https://www.google.com");
140
140
  }
141
141
  });
142
+ window.reaperFirebase.listenGlobalAlert((alertMsg) => {
143
+ const banner = document.getElementById('global-broadcast-banner');
144
+ const textEl = document.getElementById('global-broadcast-text');
145
+ if (banner && textEl) {
146
+ if (alertMsg && alertMsg.trim().length > 0) {
147
+ textEl.textContent = `🚨 ${alertMsg}`;
148
+ banner.style.display = 'block';
149
+ } else {
150
+ banner.style.display = 'none';
151
+ }
152
+ }
153
+ });
154
+ window.reaperFirebase.listenSlowMode((isSlow) => {
155
+ this.isSlowModeActive = isSlow;
156
+ const adminToggle = document.getElementById('admin-slowmode-toggle');
157
+ const modToggle = document.getElementById('mod-slowmode-toggle');
158
+ if (adminToggle) adminToggle.checked = isSlow;
159
+ if (modToggle) modToggle.checked = isSlow;
160
+ });
161
+ window.reaperFirebase.listenKicked(this.currentUser.username, (kickData) => {
162
+ if (this.currentUser.rank !== 'owner') {
163
+ alert(`[KICKED FROM SERVER]\nReason: ${kickData.reason || 'Kicked by Administrator'}`);
164
+ window.location.replace('about:blank');
165
+ }
166
+ });
142
167
  }
143
168
 
144
169
  // 9. Render UI, Games, Leaderboard
@@ -716,6 +741,7 @@ class ReaperHubApp {
716
741
  ` : currentRank === 'chat_mod' || currentRank === 'mod' ? `
717
742
  <button onclick="app.setUserRank('${u.username}', 'member')" class="btn-stealth" style="color: #ffaa00; padding: 0.2rem 0.5rem; font-size: 0.72rem;">- DE-RANK MEMBER</button>
718
743
  ` : ''}
744
+ <button onclick="app.kickUser('${u.username}')" class="btn-stealth" style="color: #ffaa00; padding: 0.2rem 0.5rem; font-size: 0.72rem;">KICK</button>
719
745
  <button onclick="app.banUser('${u.username}')" class="btn-stealth" style="color: #ff5555; padding: 0.2rem 0.5rem; font-size: 0.72rem;">BAN</button>
720
746
  ` : '<span style="color: #ffd700; font-weight: 800;">YOU</span>'}
721
747
  </div>
@@ -724,6 +750,54 @@ class ReaperHubApp {
724
750
  }).join('');
725
751
  }
726
752
 
753
+ async sendGlobalAlert() {
754
+ if (this.currentUser.rank !== 'owner') return;
755
+ const input = document.getElementById('admin-broadcast-msg');
756
+ if (!input || !input.value.trim()) {
757
+ this.showToast("Enter a broadcast message.");
758
+ return;
759
+ }
760
+ const msg = input.value.trim();
761
+ if (window.reaperFirebase) {
762
+ await window.reaperFirebase.setGlobalAlert(msg);
763
+ this.showToast("Broadcast alert sent to all connected players! 🚨");
764
+ }
765
+ }
766
+
767
+ async clearGlobalAlert() {
768
+ if (this.currentUser.rank !== 'owner') return;
769
+ const input = document.getElementById('admin-broadcast-msg');
770
+ if (input) input.value = '';
771
+ if (window.reaperFirebase) {
772
+ await window.reaperFirebase.setGlobalAlert('');
773
+ this.showToast("Broadcast alert cleared.");
774
+ }
775
+ }
776
+
777
+ async toggleSlowMode(isSlow) {
778
+ if (this.currentUser.rank !== 'owner' && this.currentUser.rank !== 'chat_mod' && this.currentUser.rank !== 'mod') return;
779
+ this.isSlowModeActive = isSlow;
780
+ if (window.reaperFirebase) {
781
+ await window.reaperFirebase.setSlowMode(isSlow);
782
+ this.showToast(isSlow ? "Chat Slow-Mode Enabled (5s Cooldown)" : "Chat Slow-Mode Disabled");
783
+ }
784
+ }
785
+
786
+ async kickUser(username) {
787
+ if (this.currentUser.rank !== 'owner') return;
788
+ if (username === this.currentUser.username || username === 'owner') {
789
+ this.showToast("Cannot kick Owner.");
790
+ return;
791
+ }
792
+ const reason = prompt(`Enter reason for kicking ${username}:`, "Kicked by Administrator");
793
+ if (reason !== null) {
794
+ if (window.reaperFirebase) {
795
+ await window.reaperFirebase.kickUser(username, reason);
796
+ this.showToast(`Kicked user ${username}!`);
797
+ }
798
+ }
799
+ }
800
+
727
801
  // ==========================================
728
802
  // CHAT MOD DESK ACTIONS
729
803
  // ==========================================
@@ -1039,6 +1113,16 @@ class ReaperHubApp {
1039
1113
  return;
1040
1114
  }
1041
1115
 
1116
+ if (this.isSlowModeActive && !isPrivileged) {
1117
+ const now = Date.now();
1118
+ if (this.lastChatMessageTime && (now - this.lastChatMessageTime < 5000)) {
1119
+ const waitSec = Math.ceil((5000 - (now - this.lastChatMessageTime)) / 1000);
1120
+ this.showToast(`Slow-mode active: please wait ${waitSec}s.`);
1121
+ return;
1122
+ }
1123
+ this.lastChatMessageTime = now;
1124
+ }
1125
+
1042
1126
  const secondsLeft = window.aiModerator ? window.aiModerator.getTimeoutRemaining() : 0;
1043
1127
  if (secondsLeft > 0 && !isPrivileged) {
1044
1128
  this.showToast("You are currently timed out.");
@@ -1872,6 +1956,40 @@ class ReaperHubApp {
1872
1956
  }
1873
1957
  }
1874
1958
 
1959
+ openSettingsModal() {
1960
+ const modal = document.getElementById('settings-modal');
1961
+ if (modal) {
1962
+ modal.style.display = 'flex';
1963
+ this.switchSettingsTab('shield');
1964
+ const nameEl = document.getElementById('st-display-username');
1965
+ const rankEl = document.getElementById('st-display-rank');
1966
+ const hwidEl = document.getElementById('st-display-hwid');
1967
+ if (nameEl) nameEl.textContent = this.currentUser.username || 'Reaper';
1968
+ if (rankEl) rankEl.textContent = (this.currentUser.rank || 'member').toUpperCase();
1969
+ if (hwidEl) hwidEl.textContent = this.getDeviceHWID();
1970
+ if (window.reaperSFX) window.reaperSFX.playClick();
1971
+ }
1972
+ }
1973
+
1974
+ closeSettingsModal() {
1975
+ const modal = document.getElementById('settings-modal');
1976
+ if (modal) modal.style.display = 'none';
1977
+ }
1978
+
1979
+ switchSettingsTab(tabName) {
1980
+ ['shield', 'prefs', 'saves', 'identity'].forEach(t => {
1981
+ const btn = document.getElementById(`st-tab-btn-${t}`);
1982
+ const content = document.getElementById(`st-content-${t}`);
1983
+ if (btn) btn.classList.toggle('active', t === tabName);
1984
+ if (content) content.style.display = (t === tabName) ? 'block' : 'none';
1985
+ });
1986
+
1987
+ if (tabName === 'shield') {
1988
+ this.renderShieldUI();
1989
+ }
1990
+ if (window.reaperSFX) window.reaperSFX.playClick();
1991
+ }
1992
+
1875
1993
  escapeHtml(str) {
1876
1994
  const div = document.createElement('div');
1877
1995
  div.textContent = str;
@@ -280,7 +280,77 @@ class FirebaseService {
280
280
  }
281
281
  }
282
282
 
283
- // Permanent Shutdown Mode ("WE ARE SHUTTING DOWN FOR GOOD")
283
+ // Global Owner Broadcast Alert Banner
284
+ listenGlobalAlert(callback) {
285
+ if (this.db) {
286
+ try {
287
+ this.db.ref("reaperGlobalAlert").on("value", (snap) => {
288
+ callback(snap.val() || '');
289
+ });
290
+ } catch (e) {
291
+ callback('');
292
+ }
293
+ }
294
+ }
295
+
296
+ async setGlobalAlert(message) {
297
+ if (this.db) {
298
+ try {
299
+ if (!message) {
300
+ await this.db.ref("reaperGlobalAlert").remove();
301
+ } else {
302
+ await this.db.ref("reaperGlobalAlert").set(message);
303
+ }
304
+ } catch (e) {}
305
+ }
306
+ }
307
+
308
+ // Chat Slow-Mode
309
+ listenSlowMode(callback) {
310
+ if (this.db) {
311
+ try {
312
+ this.db.ref("reaperSlowMode").on("value", (snap) => {
313
+ callback(Boolean(snap.val()));
314
+ });
315
+ } catch (e) {
316
+ callback(false);
317
+ }
318
+ }
319
+ }
320
+
321
+ async setSlowMode(isSlow) {
322
+ if (this.db) {
323
+ try {
324
+ await this.db.ref("reaperSlowMode").set(isSlow);
325
+ } catch (e) {}
326
+ }
327
+ }
328
+
329
+ // Realtime User Kick System
330
+ listenKicked(myUsername, callback) {
331
+ if (this.db && myUsername) {
332
+ try {
333
+ this.db.ref(`reaperKicked/${myUsername}`).on("value", (snap) => {
334
+ if (snap.exists() && snap.val()) {
335
+ callback(snap.val());
336
+ }
337
+ });
338
+ } catch (e) {}
339
+ }
340
+ }
341
+
342
+ async kickUser(username, reason) {
343
+ if (this.db && username) {
344
+ try {
345
+ await this.db.ref(`reaperKicked/${username}`).set({
346
+ reason: reason || 'Kicked by Administrator',
347
+ timestamp: Date.now()
348
+ });
349
+ } catch (e) {}
350
+ }
351
+ }
352
+
353
+ // Realtime Perm Shutdown Mode
284
354
  listenShutdownMode(callback) {
285
355
  if (this.db) {
286
356
  try {
@@ -289,7 +359,11 @@ class FirebaseService {
289
359
  localStorage.setItem('reaper_shutdown_mode', isShutdown ? 'true' : 'false');
290
360
  callback(isShutdown);
291
361
  });
292
- } catch (e) {}
362
+ } catch (e) {
363
+ callback(localStorage.getItem('reaper_shutdown_mode') === 'true');
364
+ }
365
+ } else {
366
+ callback(localStorage.getItem('reaper_shutdown_mode') === 'true');
293
367
  }
294
368
  }
295
369
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reaper-arcade-hub",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Reaper Hub - 788 High-Speed HTML5 Games, Realtime Chat, Playtime Leaderboard & Verification Gateway",
5
5
  "main": "main/index.html",
6
6
  "unpkg": "main/index.html",
@@ -280,7 +280,77 @@ class FirebaseService {
280
280
  }
281
281
  }
282
282
 
283
- // Permanent Shutdown Mode ("WE ARE SHUTTING DOWN FOR GOOD")
283
+ // Global Owner Broadcast Alert Banner
284
+ listenGlobalAlert(callback) {
285
+ if (this.db) {
286
+ try {
287
+ this.db.ref("reaperGlobalAlert").on("value", (snap) => {
288
+ callback(snap.val() || '');
289
+ });
290
+ } catch (e) {
291
+ callback('');
292
+ }
293
+ }
294
+ }
295
+
296
+ async setGlobalAlert(message) {
297
+ if (this.db) {
298
+ try {
299
+ if (!message) {
300
+ await this.db.ref("reaperGlobalAlert").remove();
301
+ } else {
302
+ await this.db.ref("reaperGlobalAlert").set(message);
303
+ }
304
+ } catch (e) {}
305
+ }
306
+ }
307
+
308
+ // Chat Slow-Mode
309
+ listenSlowMode(callback) {
310
+ if (this.db) {
311
+ try {
312
+ this.db.ref("reaperSlowMode").on("value", (snap) => {
313
+ callback(Boolean(snap.val()));
314
+ });
315
+ } catch (e) {
316
+ callback(false);
317
+ }
318
+ }
319
+ }
320
+
321
+ async setSlowMode(isSlow) {
322
+ if (this.db) {
323
+ try {
324
+ await this.db.ref("reaperSlowMode").set(isSlow);
325
+ } catch (e) {}
326
+ }
327
+ }
328
+
329
+ // Realtime User Kick System
330
+ listenKicked(myUsername, callback) {
331
+ if (this.db && myUsername) {
332
+ try {
333
+ this.db.ref(`reaperKicked/${myUsername}`).on("value", (snap) => {
334
+ if (snap.exists() && snap.val()) {
335
+ callback(snap.val());
336
+ }
337
+ });
338
+ } catch (e) {}
339
+ }
340
+ }
341
+
342
+ async kickUser(username, reason) {
343
+ if (this.db && username) {
344
+ try {
345
+ await this.db.ref(`reaperKicked/${username}`).set({
346
+ reason: reason || 'Kicked by Administrator',
347
+ timestamp: Date.now()
348
+ });
349
+ } catch (e) {}
350
+ }
351
+ }
352
+
353
+ // Realtime Perm Shutdown Mode
284
354
  listenShutdownMode(callback) {
285
355
  if (this.db) {
286
356
  try {
@@ -289,7 +359,11 @@ class FirebaseService {
289
359
  localStorage.setItem('reaper_shutdown_mode', isShutdown ? 'true' : 'false');
290
360
  callback(isShutdown);
291
361
  });
292
- } catch (e) {}
362
+ } catch (e) {
363
+ callback(localStorage.getItem('reaper_shutdown_mode') === 'true');
364
+ }
365
+ } else {
366
+ callback(localStorage.getItem('reaper_shutdown_mode') === 'true');
293
367
  }
294
368
  }
295
369