hytopia 0.3.27 → 0.3.29
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/docs/server.audio.cutoffdistance.md +13 -0
- package/docs/server.audio.md +35 -0
- package/docs/server.audio.setcutoffdistance.md +57 -0
- package/docs/server.audio.setreferencedistance.md +4 -0
- package/docs/server.audioevent.md +14 -0
- package/docs/server.audioeventpayloads._audio.set_cutoff_distance_.md +16 -0
- package/docs/server.audioeventpayloads.md +19 -0
- package/docs/server.audiooptions.cutoffdistance.md +13 -0
- package/docs/server.audiooptions.md +20 -1
- package/docs/server.audiooptions.referencedistance.md +1 -1
- package/examples/hygrounds/assets/icons/ranks/bronze-1.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/bronze-2.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/bronze-3.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/bronze-4.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/bronze-5.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/diamond-1.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/diamond-2.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/diamond-3.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/diamond-4.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/diamond-5.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/elite-1.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/elite-2.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/elite-3.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/elite-4.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/elite-5.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/gold-1.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/gold-2.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/gold-3.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/gold-4.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/gold-5.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/platinum-1.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/platinum-2.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/platinum-3.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/platinum-4.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/platinum-5.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/silver-1.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/silver-2.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/silver-3.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/silver-4.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/silver-5.png +0 -0
- package/examples/hygrounds/assets/icons/ranks/unranked.png +0 -0
- package/examples/hygrounds/assets/ui/index.html +305 -44
- package/examples/hygrounds/classes/ChestEntity.ts +1 -0
- package/examples/hygrounds/classes/GameManager.ts +17 -7
- package/examples/hygrounds/classes/GamePlayerEntity.ts +103 -3
- package/examples/hygrounds/classes/GunEntity.ts +3 -0
- package/examples/hygrounds/classes/ItemEntity.ts +1 -0
- package/examples/hygrounds/classes/MeleeWeaponEntity.ts +2 -0
- package/examples/hygrounds/classes/weapons/PistolEntity.ts +1 -1
- package/examples/hygrounds/classes/weapons/RocketLauncherEntity.ts +2 -1
- package/examples/hygrounds/dev/persistence/player-player-1.json +3 -0
- package/examples/hygrounds/dev/persistence/player-player-2.json +3 -0
- package/examples/hygrounds/dev/persistence/player-player-3.json +3 -0
- package/examples/hygrounds/gameConfig.ts +281 -21
- package/package.json +1 -1
- package/server.api.json +173 -2
- package/server.d.ts +33 -1
- package/server.js +114 -114
@@ -23,6 +23,13 @@
|
|
23
23
|
<!-- Winner Announcement -->
|
24
24
|
<div class="winner-announcement"></div>
|
25
25
|
|
26
|
+
<!-- Rank Up Announcement -->
|
27
|
+
<div class="rank-up-announcement">
|
28
|
+
<div class="rank-up-title">Rank Up!</div>
|
29
|
+
<img src="" alt="Rank Icon" class="rank-up-icon">
|
30
|
+
<div class="rank-up-name"></div>
|
31
|
+
</div>
|
32
|
+
|
26
33
|
<!-- Leaderboard -->
|
27
34
|
<div class="leaderboard">
|
28
35
|
<div class="leaderboard-title">Deathmatch</div>
|
@@ -40,7 +47,7 @@
|
|
40
47
|
</div>
|
41
48
|
</div>
|
42
49
|
|
43
|
-
<div class="hud">
|
50
|
+
<div class="hud">
|
44
51
|
<div class="info-container">
|
45
52
|
<div class="ammo-indicator" style="display: none;">
|
46
53
|
<img src="{{CDN_ASSETS_URL}}/icons/ammo.png" alt="Ammo Icon" class="ammo-icon">
|
@@ -48,6 +55,13 @@
|
|
48
55
|
<span class="ammo-divider">/</span>
|
49
56
|
<span class="total-ammo">30</span>
|
50
57
|
</div>
|
58
|
+
|
59
|
+
<div class="exp-bar">
|
60
|
+
<div class="exp-bar-fill"></div>
|
61
|
+
<img src="{{CDN_ASSETS_URL}}/icons/ranks/unranked.png" alt="Exp Rank Icon" class="exp-icon">
|
62
|
+
<div class="exp-text">Unranked</div>
|
63
|
+
</div>
|
64
|
+
|
51
65
|
<div class="shield-bar">
|
52
66
|
<div class="shield-bar-fill"></div>
|
53
67
|
<img src="{{CDN_ASSETS_URL}}/icons/shield.png" alt="Shield Icon" class="shield-icon">
|
@@ -64,18 +78,18 @@
|
|
64
78
|
<div class="mobile-buttons-container">
|
65
79
|
<div id="mobile-reload-button" class="mobile-button">
|
66
80
|
<img src="{{CDN_ASSETS_URL}}/icons/mobile-reload.png" />
|
67
|
-
</div>
|
68
|
-
|
81
|
+
</div>
|
82
|
+
|
69
83
|
<div id="mobile-interact-button" class="mobile-button">E</div>
|
70
|
-
|
84
|
+
|
71
85
|
<div id="mobile-jump-button" class="mobile-button">
|
72
86
|
<img src="{{CDN_ASSETS_URL}}/icons/mobile-jump.png" />
|
73
87
|
</div>
|
74
|
-
|
88
|
+
|
75
89
|
<div id="mobile-attack-button" class="mobile-button">
|
76
90
|
<img src="{{CDN_ASSETS_URL}}/icons/mobile-shoot.png" />
|
77
91
|
</div>
|
78
|
-
|
92
|
+
|
79
93
|
<div id="mobile-place-block-button" class="mobile-button">
|
80
94
|
<img src="{{CDN_ASSETS_URL}}/icons/mobile-place-block.png" />
|
81
95
|
</div>
|
@@ -100,21 +114,21 @@
|
|
100
114
|
<div class="slot-quantity" style="display: none;"></div>
|
101
115
|
<div class="slot-name" style="display: none;"></div>
|
102
116
|
</div>
|
103
|
-
|
117
|
+
|
104
118
|
<div class="inventory-slot" data-slot="2">
|
105
119
|
<div class="slot-number">2</div>
|
106
120
|
<img class="slot-icon" style="display: none;">
|
107
121
|
<div class="slot-quantity" style="display: none;"></div>
|
108
122
|
<div class="slot-name" style="display: none;"></div>
|
109
123
|
</div>
|
110
|
-
|
124
|
+
|
111
125
|
<div class="inventory-slot" data-slot="3">
|
112
126
|
<div class="slot-number">3</div>
|
113
127
|
<img class="slot-icon" style="display: none;">
|
114
128
|
<div class="slot-quantity" style="display: none;"></div>
|
115
129
|
<div class="slot-name" style="display: none;"></div>
|
116
130
|
</div>
|
117
|
-
|
131
|
+
|
118
132
|
<div class="inventory-slot" data-slot="4">
|
119
133
|
<div class="slot-number">4</div>
|
120
134
|
<img class="slot-icon" style="display: none;">
|
@@ -131,6 +145,10 @@
|
|
131
145
|
</div>
|
132
146
|
|
133
147
|
<!-- Scene UI Templates -->
|
148
|
+
<template id="player-rank-template">
|
149
|
+
<img src="" alt="Rank Icon" class="player-rank-icon">
|
150
|
+
</template>
|
151
|
+
|
134
152
|
<template id="item-label-template">
|
135
153
|
<div class="item-label">
|
136
154
|
<div class="label-quantity"></div>
|
@@ -151,9 +169,13 @@
|
|
151
169
|
<!-- UI Scripts-->
|
152
170
|
<script>
|
153
171
|
const CDN_ASSETS_URL = '{{CDN_ASSETS_URL}}';
|
172
|
+
let ranks = [];
|
173
|
+
let lastExp = 0;
|
174
|
+
let lastRank;
|
154
175
|
let leaderboardKillCounts = {};
|
155
176
|
let gameEndTime = 0;
|
156
177
|
let timerInterval;
|
178
|
+
let isLoadExpUpdate = true; // Flag to track the first EXP update
|
157
179
|
|
158
180
|
function updateLeaderboard() {
|
159
181
|
const leaderboardPlayers = document.querySelector('.leaderboard-players');
|
@@ -191,13 +213,13 @@
|
|
191
213
|
// Create player elements for the leaderboard
|
192
214
|
sortedPlayers.forEach((player, index) => {
|
193
215
|
const [username, killCount] = player;
|
194
|
-
|
216
|
+
|
195
217
|
// Skip players with 0 kills
|
196
218
|
if (killCount === 0) return;
|
197
|
-
|
219
|
+
|
198
220
|
const playerElement = document.createElement('div');
|
199
221
|
playerElement.className = 'leaderboard-player';
|
200
|
-
|
222
|
+
|
201
223
|
let rankIcon = '';
|
202
224
|
if (index === 0) {
|
203
225
|
rankIcon = `<img src="${CDN_ASSETS_URL}/icons/crown-gold.png" class="rank-icon">`;
|
@@ -214,7 +236,7 @@
|
|
214
236
|
</div>
|
215
237
|
<div class="player-kills">${killCount}</div>
|
216
238
|
`;
|
217
|
-
|
239
|
+
|
218
240
|
leaderboardPlayers.appendChild(playerElement);
|
219
241
|
});
|
220
242
|
}
|
@@ -222,15 +244,15 @@
|
|
222
244
|
function updateTimer() {
|
223
245
|
const now = Date.now();
|
224
246
|
const timeRemaining = Math.max(0, gameEndTime - now);
|
225
|
-
|
247
|
+
|
226
248
|
// Format time as mm:ss
|
227
249
|
const minutes = Math.floor(timeRemaining / 60000);
|
228
250
|
const seconds = Math.floor((timeRemaining % 60000) / 1000);
|
229
251
|
const formattedTime = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
|
230
|
-
|
252
|
+
|
231
253
|
const timerElement = document.querySelector('.leaderboard-timer');
|
232
254
|
timerElement.textContent = formattedTime;
|
233
|
-
|
255
|
+
|
234
256
|
// Stop the timer when it reaches zero
|
235
257
|
if (timeRemaining <= 0) {
|
236
258
|
clearInterval(timerInterval);
|
@@ -240,7 +262,7 @@
|
|
240
262
|
function showGameStartAnnouncement() {
|
241
263
|
const announcement = document.querySelector('.game-start-announcement');
|
242
264
|
announcement.classList.add('active');
|
243
|
-
|
265
|
+
|
244
266
|
// Remove the active class after animation completes
|
245
267
|
setTimeout(() => {
|
246
268
|
announcement.classList.remove('active');
|
@@ -251,13 +273,45 @@
|
|
251
273
|
const announcement = document.querySelector('.winner-announcement');
|
252
274
|
announcement.textContent = `${username} wins!`;
|
253
275
|
announcement.classList.add('active');
|
254
|
-
|
276
|
+
|
255
277
|
// Remove the active class after animation completes
|
256
278
|
setTimeout(() => {
|
257
279
|
announcement.classList.remove('active');
|
258
280
|
}, 5000);
|
259
281
|
}
|
260
282
|
|
283
|
+
function showRankUpAnnouncement(rank) {
|
284
|
+
const announcement = document.querySelector('.rank-up-announcement');
|
285
|
+
const rankIcon = announcement.querySelector('.rank-up-icon');
|
286
|
+
const rankName = announcement.querySelector('.rank-up-name');
|
287
|
+
|
288
|
+
rankIcon.src = `${CDN_ASSETS_URL}/${rank.iconUri}`;
|
289
|
+
rankName.textContent = rank.name;
|
290
|
+
|
291
|
+
announcement.classList.add('active');
|
292
|
+
|
293
|
+
// Remove the active class after animation completes (e.g., 5 seconds)
|
294
|
+
setTimeout(() => {
|
295
|
+
announcement.classList.remove('active');
|
296
|
+
}, 5000);
|
297
|
+
}
|
298
|
+
|
299
|
+
function showExpGainIndicator(amount) {
|
300
|
+
const expBar = document.querySelector('.exp-bar');
|
301
|
+
if (!expBar) return;
|
302
|
+
|
303
|
+
const indicator = document.createElement('div');
|
304
|
+
indicator.className = 'exp-gain-indicator';
|
305
|
+
indicator.textContent = `+${amount} Exp`;
|
306
|
+
|
307
|
+
expBar.appendChild(indicator);
|
308
|
+
|
309
|
+
// Remove after animation completes
|
310
|
+
setTimeout(() => {
|
311
|
+
indicator.remove();
|
312
|
+
}, 1500); // Match animation duration
|
313
|
+
}
|
314
|
+
|
261
315
|
hytopia.registerSceneUITemplate('item-label', (id, onState) => {
|
262
316
|
const template = document.getElementById('item-label-template');
|
263
317
|
const clone = template.content.cloneNode(true);
|
@@ -291,6 +345,20 @@
|
|
291
345
|
return clone;
|
292
346
|
});
|
293
347
|
|
348
|
+
hytopia.registerSceneUITemplate('player-rank', (id, onState) => {
|
349
|
+
const template = document.getElementById('player-rank-template');
|
350
|
+
const clone = template.content.cloneNode(true);
|
351
|
+
const playerRankIcon = clone.querySelector('.player-rank-icon');
|
352
|
+
|
353
|
+
onState(state => {
|
354
|
+
if (state.iconUri) {
|
355
|
+
playerRankIcon.src = `${CDN_ASSETS_URL}/${state.iconUri}`;
|
356
|
+
}
|
357
|
+
});
|
358
|
+
|
359
|
+
return clone;
|
360
|
+
});
|
361
|
+
|
294
362
|
hytopia.onData(data => {
|
295
363
|
const { type } = data;
|
296
364
|
|
@@ -333,29 +401,29 @@
|
|
333
401
|
|
334
402
|
if (type === 'damage-indicator') {
|
335
403
|
const { direction } = data;
|
336
|
-
|
404
|
+
|
337
405
|
// Make sure we have a valid direction object
|
338
406
|
if (!direction || typeof direction.x === 'undefined' || typeof direction.z === 'undefined') {
|
339
407
|
console.error('Invalid direction object:', direction);
|
340
408
|
return;
|
341
409
|
}
|
342
|
-
|
410
|
+
|
343
411
|
// Hide all indicators first
|
344
412
|
document.querySelectorAll('.damage-indicator').forEach(el => {
|
345
413
|
el.classList.remove('active');
|
346
414
|
});
|
347
|
-
|
415
|
+
|
348
416
|
// Determine which indicator to show based on the dominant direction
|
349
417
|
const absX = Math.abs(direction.x);
|
350
418
|
const absZ = Math.abs(direction.z);
|
351
|
-
|
419
|
+
|
352
420
|
let indicatorClass;
|
353
421
|
if (absX > absZ) {
|
354
422
|
indicatorClass = direction.x > 0 ? '.damage-indicator.right' : '.damage-indicator.left';
|
355
423
|
} else {
|
356
424
|
indicatorClass = direction.z > 0 ? '.damage-indicator.top' : '.damage-indicator.bottom';
|
357
425
|
}
|
358
|
-
|
426
|
+
|
359
427
|
// Show and animate the indicator
|
360
428
|
const indicator = document.querySelector(indicatorClass);
|
361
429
|
if (indicator) {
|
@@ -366,24 +434,58 @@
|
|
366
434
|
}
|
367
435
|
}
|
368
436
|
|
437
|
+
if (type === 'exp-update') {
|
438
|
+
const { totalExp, rankIndex } = data;
|
439
|
+
const currentRank = ranks[rankIndex];
|
440
|
+
const nextRank = ranks[rankIndex + 1];
|
441
|
+
let gainedExp = 0;
|
442
|
+
|
443
|
+
// Calculate gained exp only after the first update, which is for loading existing exp
|
444
|
+
if (!isLoadExpUpdate) {
|
445
|
+
gainedExp = totalExp - lastExp;
|
446
|
+
} else {
|
447
|
+
isLoadExpUpdate = false; // Mark load update as done
|
448
|
+
}
|
449
|
+
|
450
|
+
if (lastRank && lastRank.name !== currentRank.name && totalExp > 0) {
|
451
|
+
showRankUpAnnouncement(currentRank);
|
452
|
+
}
|
453
|
+
|
454
|
+
// Show the gained exp number if positive
|
455
|
+
if (gainedExp > 0) {
|
456
|
+
showExpGainIndicator(gainedExp);
|
457
|
+
}
|
458
|
+
|
459
|
+
const expBarFill = document.querySelector('.exp-bar-fill');
|
460
|
+
const expBarText = document.querySelector('.exp-text');
|
461
|
+
const expRankIcon = document.querySelector('.exp-icon');
|
462
|
+
|
463
|
+
expBarFill.style.width = `${((totalExp - currentRank.totalExp) / (nextRank.totalExp - currentRank.totalExp)) * 100}%`;
|
464
|
+
expBarText.textContent = currentRank.name;
|
465
|
+
expRankIcon.src = `${CDN_ASSETS_URL}/${currentRank.iconUri}`;
|
466
|
+
|
467
|
+
lastExp = totalExp;
|
468
|
+
lastRank = currentRank;
|
469
|
+
}
|
470
|
+
|
369
471
|
if (type === 'show-damage') {
|
370
472
|
const { damage } = data;
|
371
|
-
|
473
|
+
|
372
474
|
// Create a new damage number element
|
373
475
|
const damageNumber = document.createElement('div');
|
374
476
|
damageNumber.className = 'hit-damage-number';
|
375
477
|
damageNumber.textContent = damage;
|
376
|
-
|
478
|
+
|
377
479
|
// Add some randomness to position
|
378
480
|
const randomX = Math.random() * 60 - 30; // -30 to 30px
|
379
481
|
const randomY = Math.random() * 40 - 20; // -20 to 20px
|
380
|
-
|
482
|
+
|
381
483
|
damageNumber.style.transform = `translate(${randomX}px, ${randomY}px)`;
|
382
|
-
|
484
|
+
|
383
485
|
// Add to container
|
384
486
|
const container = document.querySelector('.hit-damage-container');
|
385
487
|
container.appendChild(damageNumber);
|
386
|
-
|
488
|
+
|
387
489
|
// Remove after animation completes
|
388
490
|
setTimeout(() => {
|
389
491
|
damageNumber.remove();
|
@@ -394,20 +496,20 @@
|
|
394
496
|
const { health, maxHealth } = data;
|
395
497
|
const healthText = document.querySelector('.health-text');
|
396
498
|
const healthBarFill = document.querySelector('.health-bar-fill');
|
397
|
-
|
499
|
+
|
398
500
|
healthText.textContent = health;
|
399
501
|
healthBarFill.style.width = `${(health / maxHealth) * 100}%`;
|
400
502
|
}
|
401
503
|
|
402
504
|
if (type === 'inventory') {
|
403
505
|
const { inventory } = data;
|
404
|
-
|
506
|
+
|
405
507
|
inventory.forEach((item, i) => {
|
406
508
|
const slot = document.querySelector(`.inventory-slot[data-slot="${i}"]`);
|
407
509
|
const icon = slot.querySelector('.slot-icon');
|
408
510
|
const name = slot.querySelector('.slot-name');
|
409
511
|
const quantity = slot.querySelector('.slot-quantity');
|
410
|
-
|
512
|
+
|
411
513
|
icon.style.display = item ? 'block' : 'none';
|
412
514
|
name.style.display = item ? 'block' : 'none';
|
413
515
|
quantity.style.display = item ? 'block' : 'none';
|
@@ -424,7 +526,7 @@
|
|
424
526
|
|
425
527
|
if (type === 'inventory-active-slot') {
|
426
528
|
const { index } = data;
|
427
|
-
|
529
|
+
|
428
530
|
// Remove active slot class from all slots
|
429
531
|
document.querySelectorAll('.inventory-slot').forEach(slot => {
|
430
532
|
slot.classList.remove('inventory-active-slot');
|
@@ -469,7 +571,7 @@
|
|
469
571
|
const materialsAmount = document.querySelector('.materials-amount');
|
470
572
|
const currentMaterials = parseInt(materialsAmount.textContent);
|
471
573
|
const difference = materials - currentMaterials;
|
472
|
-
|
574
|
+
|
473
575
|
if (difference !== 0) {
|
474
576
|
const materialsCounter = document.querySelector('.materials-counter');
|
475
577
|
const floatingNumber = document.createElement('div');
|
@@ -482,15 +584,19 @@
|
|
482
584
|
floatingNumber.remove();
|
483
585
|
}, 1000);
|
484
586
|
}
|
485
|
-
|
587
|
+
|
486
588
|
materialsAmount.textContent = materials;
|
487
589
|
}
|
488
590
|
|
591
|
+
if (type === 'ranks') {
|
592
|
+
ranks = data.ranks;
|
593
|
+
}
|
594
|
+
|
489
595
|
if (type === 'shield') {
|
490
596
|
const { shield, maxShield } = data;
|
491
597
|
const shieldText = document.querySelector('.shield-text');
|
492
598
|
const shieldBarFill = document.querySelector('.shield-bar-fill');
|
493
|
-
|
599
|
+
|
494
600
|
shieldText.textContent = shield;
|
495
601
|
shieldBarFill.style.width = `${(shield / maxShield) * 100}%`;
|
496
602
|
}
|
@@ -498,7 +604,7 @@
|
|
498
604
|
if (type === 'scope-zoom') {
|
499
605
|
const { zoom } = data;
|
500
606
|
const scopeOverlay = document.querySelector('.scope-overlay');
|
501
|
-
|
607
|
+
|
502
608
|
if (zoom === 1) {
|
503
609
|
scopeOverlay.classList.remove('active');
|
504
610
|
} else {
|
@@ -508,18 +614,18 @@
|
|
508
614
|
|
509
615
|
if (type === 'timer-sync') {
|
510
616
|
const { startedAt, endsAt } = data;
|
511
|
-
|
617
|
+
|
512
618
|
// Clear any existing timer interval
|
513
619
|
if (timerInterval) {
|
514
620
|
clearInterval(timerInterval);
|
515
621
|
}
|
516
|
-
|
622
|
+
|
517
623
|
// Set the end time
|
518
624
|
gameEndTime = endsAt;
|
519
|
-
|
625
|
+
|
520
626
|
// Update timer immediately
|
521
627
|
updateTimer();
|
522
|
-
|
628
|
+
|
523
629
|
// Set up interval to update timer every second
|
524
630
|
timerInterval = setInterval(updateTimer, 1000);
|
525
631
|
}
|
@@ -671,6 +777,53 @@
|
|
671
777
|
animation: winnerFade 5s ease-in-out forwards;
|
672
778
|
}
|
673
779
|
|
780
|
+
.rank-up-announcement {
|
781
|
+
position: fixed;
|
782
|
+
top: 0;
|
783
|
+
left: 0;
|
784
|
+
width: 100%;
|
785
|
+
height: 100%;
|
786
|
+
display: flex;
|
787
|
+
flex-direction: column;
|
788
|
+
align-items: center;
|
789
|
+
justify-content: center;
|
790
|
+
opacity: 0;
|
791
|
+
pointer-events: none;
|
792
|
+
z-index: 1001;
|
793
|
+
font-family: 'Inter', sans-serif;
|
794
|
+
color: white;
|
795
|
+
text-align: center;
|
796
|
+
text-shadow: 0 0 10px rgba(0, 0, 0, 0.7), 0 0 20px rgba(0, 0, 0, 0.5);
|
797
|
+
}
|
798
|
+
|
799
|
+
.rank-up-announcement.active {
|
800
|
+
animation: rankUpFade 5s ease-in-out forwards;
|
801
|
+
}
|
802
|
+
|
803
|
+
.rank-up-title {
|
804
|
+
font-size: 60px;
|
805
|
+
font-weight: bold;
|
806
|
+
color: #4CAF50; /* Green color for rank up */
|
807
|
+
text-transform: uppercase;
|
808
|
+
letter-spacing: 2px;
|
809
|
+
margin-bottom: 20px;
|
810
|
+
}
|
811
|
+
|
812
|
+
.rank-up-icon {
|
813
|
+
width: 150px;
|
814
|
+
height: 150px;
|
815
|
+
margin-bottom: 20px;
|
816
|
+
filter: drop-shadow(0 0 15px rgba(255, 255, 255, 0.5));
|
817
|
+
}
|
818
|
+
|
819
|
+
.rank-up-name {
|
820
|
+
font-size: 40px;
|
821
|
+
font-weight: bold;
|
822
|
+
color: #FFEB3B; /* Yellow color for rank name */
|
823
|
+
text-transform: uppercase;
|
824
|
+
letter-spacing: 1px;
|
825
|
+
}
|
826
|
+
|
674
827
|
@keyframes announcementFade {
|
675
828
|
0% { opacity: 0; transform: translate(-50%, -50%) scale(0.5); }
|
676
829
|
20% { opacity: 1; transform: translate(-50%, -50%) scale(1.2); }
|
@@ -687,6 +840,13 @@
|
|
687
840
|
100% { opacity: 0; transform: translate(-50%, -50%) scale(0.8); }
|
688
841
|
}
|
689
842
|
|
843
|
+
@keyframes rankUpFade {
|
844
|
+
0% { opacity: 0; transform: scale(0.7); }
|
845
|
+
20% { opacity: 1; transform: scale(1.1); }
|
846
|
+
80% { opacity: 1; transform: scale(1); }
|
847
|
+
100% { opacity: 0; transform: scale(0.9); }
|
848
|
+
}
|
849
|
+
|
690
850
|
.hit-damage-container {
|
691
851
|
position: fixed;
|
692
852
|
top: 50%;
|
@@ -855,7 +1015,7 @@
|
|
855
1015
|
color: rgba(255, 255, 255, 0.8);
|
856
1016
|
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8);
|
857
1017
|
}
|
858
|
-
|
1018
|
+
|
859
1019
|
.slot-icon {
|
860
1020
|
max-width: 70%;
|
861
1021
|
max-height: 70%;
|
@@ -875,7 +1035,7 @@
|
|
875
1035
|
padding: 1px 4px;
|
876
1036
|
border-radius: 3px;
|
877
1037
|
}
|
878
|
-
|
1038
|
+
|
879
1039
|
.slot-name {
|
880
1040
|
position: absolute;
|
881
1041
|
bottom: -18px;
|
@@ -910,6 +1070,7 @@
|
|
910
1070
|
width: 0%;
|
911
1071
|
height: 100%;
|
912
1072
|
background: linear-gradient(to right, #0000ff, #3333ff);
|
1073
|
+
border-radius: 3px;
|
913
1074
|
transition: width 0.3s ease;
|
914
1075
|
}
|
915
1076
|
|
@@ -947,6 +1108,7 @@
|
|
947
1108
|
.health-bar-fill {
|
948
1109
|
width: 100%;
|
949
1110
|
height: 100%;
|
1111
|
+
border-radius: 3px;
|
950
1112
|
background: linear-gradient(to right, #ff0000, #ff3333);
|
951
1113
|
transition: width 0.3s ease;
|
952
1114
|
}
|
@@ -972,6 +1134,74 @@
|
|
972
1134
|
z-index: 1;
|
973
1135
|
}
|
974
1136
|
|
1137
|
+
.exp-bar {
|
1138
|
+
width: 250px;
|
1139
|
+
height: 20px;
|
1140
|
+
background: rgba(0, 0, 0, 0.5);
|
1141
|
+
border-radius: 3px;
|
1142
|
+
box-shadow: 0 0 10px rgba(230, 190, 40, 0.3);
|
1143
|
+
position: relative; /* Needed for absolute positioning of children */
|
1144
|
+
}
|
1145
|
+
|
1146
|
+
.exp-bar-fill {
|
1147
|
+
width: 0%;
|
1148
|
+
height: 100%;
|
1149
|
+
border-radius: 3px;
|
1150
|
+
background: linear-gradient(to right, #e6be28, #f0cc40);
|
1151
|
+
transition: width 0.3s ease;
|
1152
|
+
}
|
1153
|
+
|
1154
|
+
.exp-icon {
|
1155
|
+
position: absolute;
|
1156
|
+
left: -5px;
|
1157
|
+
top: 80%;
|
1158
|
+
transform: translateY(-80%);
|
1159
|
+
height: 60px;
|
1160
|
+
width: 60px;
|
1161
|
+
z-index: 1;
|
1162
|
+
}
|
1163
|
+
|
1164
|
+
.exp-text {
|
1165
|
+
position: absolute;
|
1166
|
+
left: 50%;
|
1167
|
+
top: 50%;
|
1168
|
+
transform: translate(-50%, -50%);
|
1169
|
+
font-size: 0.8em;
|
1170
|
+
font-weight: bold;
|
1171
|
+
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8);
|
1172
|
+
z-index: 1;
|
1173
|
+
}
|
1174
|
+
|
1175
|
+
.exp-gain-indicator {
|
1176
|
+
position: absolute;
|
1177
|
+
z-index: 9999;
|
1178
|
+
bottom: 100%; /* Start just above the bar */
|
1179
|
+
left: 50%;
|
1180
|
+
transform: translateX(-50%);
|
1181
|
+
color: #e6be28; /* Match EXP bar color */
|
1182
|
+
font-family: 'Inter', sans-serif;
|
1183
|
+
font-size: 14px;
|
1184
|
+
font-weight: bold;
|
1185
|
+
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8);
|
1186
|
+
pointer-events: none;
|
1187
|
+
white-space: nowrap;
|
1188
|
+
animation: expGainFadeUp 1.5s ease-out forwards;
|
1189
|
+
}
|
1190
|
+
|
1191
|
+
@keyframes expGainFadeUp {
|
1192
|
+
0% {
|
1193
|
+
opacity: 0;
|
1194
|
+
transform: translate(-50%, 10px); /* Start slightly lower and faded out */
|
1195
|
+
}
|
1196
|
+
20% {
|
1197
|
+
opacity: 1;
|
1198
|
+
}
|
1199
|
+
100% {
|
1200
|
+
opacity: 0;
|
1201
|
+
transform: translate(-50%, -30px); /* Move up and fade out */
|
1202
|
+
}
|
1203
|
+
}
|
1204
|
+
|
975
1205
|
.item-label {
|
976
1206
|
background-color: rgba(0, 0, 0, 0.6);
|
977
1207
|
padding: 12px 20px;
|
@@ -1025,6 +1255,11 @@
|
|
1025
1255
|
border-top: 8px solid rgba(0, 0, 0, 0.6);
|
1026
1256
|
}
|
1027
1257
|
|
1258
|
+
.player-rank-icon {
|
1259
|
+
width: 48px;
|
1260
|
+
height: 48px;
|
1261
|
+
}
|
1262
|
+
|
1028
1263
|
.scope-overlay {
|
1029
1264
|
position: fixed;
|
1030
1265
|
top: 0;
|
@@ -1164,6 +1399,7 @@
|
|
1164
1399
|
display: flex;
|
1165
1400
|
flex-direction: column;
|
1166
1401
|
gap: 5px;
|
1402
|
+
overflow-y: scroll;
|
1167
1403
|
}
|
1168
1404
|
|
1169
1405
|
.leaderboard-player {
|
@@ -1245,13 +1481,15 @@
|
|
1245
1481
|
}
|
1246
1482
|
|
1247
1483
|
body.mobile .shield-bar,
|
1248
|
-
body.mobile .health-bar
|
1484
|
+
body.mobile .health-bar,
|
1485
|
+
body.mobile .exp-bar {
|
1249
1486
|
width: 120px;
|
1250
1487
|
height: 16px;
|
1251
1488
|
}
|
1252
1489
|
|
1253
1490
|
body.mobile .shield-text,
|
1254
|
-
body.mobile .health-text
|
1491
|
+
body.mobile .health-text,
|
1492
|
+
body.mobile .exp-text {
|
1255
1493
|
font-size: 0.7em;
|
1256
1494
|
}
|
1257
1495
|
|
@@ -1261,6 +1499,11 @@
|
|
1261
1499
|
height: 10px;
|
1262
1500
|
}
|
1263
1501
|
|
1502
|
+
body.mobile .exp-icon {
|
1503
|
+
width: 35px;
|
1504
|
+
height: 35px;
|
1505
|
+
}
|
1506
|
+
|
1264
1507
|
body.mobile .leaderboard-title {
|
1265
1508
|
font-size: 14px;
|
1266
1509
|
}
|
@@ -1270,6 +1513,7 @@
|
|
1270
1513
|
}
|
1271
1514
|
|
1272
1515
|
body.mobile .leaderboard-players-count {
|
1516
|
+
display: none;
|
1273
1517
|
font-size: 12px;
|
1274
1518
|
}
|
1275
1519
|
|
@@ -1291,6 +1535,10 @@
|
|
1291
1535
|
font-size: 14px;
|
1292
1536
|
}
|
1293
1537
|
|
1538
|
+
body.mobile .exp-gain-indicator {
|
1539
|
+
font-size: 12px;
|
1540
|
+
}
|
1541
|
+
|
1294
1542
|
body.mobile div > canvas { /* hide three debugger panels */
|
1295
1543
|
display: none !important;
|
1296
1544
|
}
|
@@ -1335,4 +1583,17 @@
|
|
1335
1583
|
width: 25px;
|
1336
1584
|
height: 25px;
|
1337
1585
|
}
|
1586
|
+
|
1587
|
+
body.mobile .rank-up-title {
|
1588
|
+
font-size: 40px;
|
1589
|
+
}
|
1590
|
+
|
1591
|
+
body.mobile .rank-up-icon {
|
1592
|
+
width: 100px;
|
1593
|
+
height: 100px;
|
1594
|
+
}
|
1595
|
+
|
1596
|
+
body.mobile .rank-up-name {
|
1597
|
+
font-size: 30px;
|
1598
|
+
}
|
1338
1599
|
</style>
|