Initial commit

This commit is contained in:
Jamon committed 2024-08-09 17:00:28 +12:00
commit d8c301215b
81 files changed
+133278

No files matched your search

+38
View File
@@ -0,0 +1,38 @@
// Add this to your game.js file or create a new cursor.js file
document.addEventListener('DOMContentLoaded', () => {
const cursor = document.createElement('div');
cursor.classList.add('custom-cursor');
cursor.innerHTML = '<div class="cursor-dot"></div><div class="cursor-outline"></div>';
document.body.appendChild(cursor);
document.addEventListener('mousemove', (e) => {
cursor.style.left = e.clientX + 'px';
cursor.style.top = e.clientY + 'px';
});
document.addEventListener('mousedown', () => {
cursor.classList.add('clicking');
});
document.addEventListener('mouseup', () => {
cursor.classList.remove('clicking');
});
// Optional: Add a subtle trailing effect
let trailDot = null;
setInterval(() => {
if (trailDot) {
trailDot.remove();
}
trailDot = cursor.querySelector('.cursor-dot').cloneNode(true);
trailDot.style.transition = 'all 0.15s linear';
trailDot.style.opacity = '0.5';
cursor.appendChild(trailDot);
setTimeout(() => {
if (trailDot) {
trailDot.style.opacity = '0';
}
}, 50);
}, 100);
});
+108
View File
@@ -0,0 +1,108 @@
function makeDraggable(element) {
let isDragging = false;
let startX, startY, initialLeft, initialTop;
// Check if the device is mobile
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
if (!isMobile) {
element.addEventListener("mousedown", dragStart, { passive: false });
document.addEventListener("mousemove", drag, { passive: false });
document.addEventListener("mouseup", dragEnd);
}
// For mobile devices, we'll only add touch events if we want to allow dragging
// If you want to completely disable dragging on mobile, you can remove these lines
element.addEventListener("touchstart", dragStart, { passive: true });
document.addEventListener("touchmove", drag, { passive: true });
document.addEventListener("touchend", dragEnd);
function dragStart(e) {
if (e.target.closest('.close-notification')) return;
if (isMobile) {
// On mobile, only start dragging if it's not a scrollable element
const isScrollable = e.target.closest('.widget-content') !== null;
if (isScrollable) return;
}
isDragging = true;
if (e.type === "touchstart") {
startX = e.touches[0].clientX;
startY = e.touches[0].clientY;
} else {
startX = e.clientX;
startY = e.clientY;
}
initialLeft = element.offsetLeft;
initialTop = element.offsetTop;
element.style.position = 'absolute';
element.style.zIndex = 1000;
}
function drag(e) {
if (!isDragging) return;
if (isMobile) {
// Prevent default only if we're actually dragging
e.preventDefault();
}
let clientX, clientY;
if (e.type === "touchmove") {
clientX = e.touches[0].clientX;
clientY = e.touches[0].clientY;
} else {
clientX = e.clientX;
clientY = e.clientY;
}
const deltaX = clientX - startX;
const deltaY = clientY - startY;
element.style.left = initialLeft + deltaX + 'px';
element.style.top = initialTop + deltaY + 'px';
}
function dragEnd(e) {
isDragging = false;
element.style.zIndex = '';
}
}
// Function to apply draggable functionality to an element
function applyDraggable(elementId) {
const element = document.getElementById(elementId);
if (element) {
element.classList.add('draggable');
makeDraggable(element);
}
}
// Apply draggable functionality to widgets and notification popups
function initDraggableElements() {
applyDraggable('uiWidget');
applyDraggable('infoWidget');
applyDraggable('classWidget');
applyDraggable('shopWidget');
// For notifications, we need to apply it dynamically when they're created
const originalShowNotification = notificationSystem.showNotification;
notificationSystem.showNotification = function(message) {
originalShowNotification.call(this, message);
const notifications = document.querySelectorAll('.custom-notification');
notifications.forEach(notification => {
notification.classList.add('draggable');
makeDraggable(notification);
});
};
}
// Call this function after your DOM is loaded
document.addEventListener('DOMContentLoaded', initDraggableElements);
+3576
View File
File diff suppressed because it is too large. Load diff
+30
View File
@@ -0,0 +1,30 @@
// Add this to your game.js file or create a new security.js file
// Disable context menu (right-click menu)
document.addEventListener('contextmenu', function(e) {
e.preventDefault();
}, false);
// Disable image dragging
document.addEventListener('dragstart', function(e) {
if (e.target.tagName.toLowerCase() === 'img') {
e.preventDefault();
}
}, false);
// Prevent text selection
document.body.style.userSelect = 'none';
document.body.style.webkitUserSelect = 'none';
document.body.style.msUserSelect = 'none';
document.body.style.mozUserSelect = 'none';
// Disable touch callout on mobile devices
document.body.style.webkitTouchCallout = 'none';
// Optional: Disable saving images on mobile
document.body.style.webkitTapHighlightColor = 'rgba(0,0,0,0)';
// Prevent copying text
document.body.oncopy = function(e) {
e.preventDefault();
};
+267
View File
@@ -0,0 +1,267 @@
const SKIN_CACHE_KEY = 'cachedSkins';
const SELECTED_SKINS_CACHE_KEY = 'cachedSelectedSkins';
const SKIN_CACHE_TIMESTAMP_KEY = 'skinCacheTimestamp';
const CACHE_DURATION = 24 * 60 * 60 * 1000; // 24 hours in milliseconds
let loadSkinsDebounceTimer;
function loadSkinOptions() {
if (!currentUser) {
displayNoSkinsMessage("Please sign in to view and select skins.");
return;
}
clearTimeout(loadSkinsDebounceTimer);
loadSkinsDebounceTimer = setTimeout(() => {
const cachedSkins = localStorage.getItem(SKIN_CACHE_KEY);
const cachedSelectedSkins = localStorage.getItem(SELECTED_SKINS_CACHE_KEY);
const cacheTimestamp = localStorage.getItem(SKIN_CACHE_TIMESTAMP_KEY);
const currentTime = Date.now();
if (cachedSkins && cachedSelectedSkins && cacheTimestamp && (currentTime - parseInt(cacheTimestamp) < CACHE_DURATION)) {
console.log('Using cached skins and selected skins');
displayUnlockedSkins(JSON.parse(cachedSkins), JSON.parse(cachedSelectedSkins));
} else {
fetchAndCacheSkins();
}
}, 300);
}
function fetchAndCacheSkins() {
const skinCustomization = document.getElementById('skinCustomization');
if (skinCustomization) {
skinCustomization.innerHTML = '<div class="loading-spinner">Loading skins...</div>';
}
const cachedEtag = localStorage.getItem('skinCacheEtag');
const headers = {
'Content-Type': 'application/json',
};
if (cachedEtag) {
headers['If-None-Match'] = cachedEtag;
}
Promise.all([
fetch('/get-unlocked-skins', {
method: 'POST',
headers: headers,
body: JSON.stringify({ username: currentUser }),
}),
fetch('/get-player-skin', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username: currentUser }),
})
])
.then(([unlockedResponse, selectedResponse]) => {
return Promise.all([
handleUnlockedSkinsResponse(unlockedResponse),
handleSelectedSkinsResponse(selectedResponse)
]);
})
.then(([unlockedSkins, selectedSkins]) => {
displayUnlockedSkins(unlockedSkins, selectedSkins);
})
.catch(error => {
console.error('Error loading skin options:', error);
displayNoSkinsMessage("An error occurred while loading skins. Please try again later.");
});
}
function handleUnlockedSkinsResponse(response) {
if (response.status === 304) {
console.log('Server returned 304 for unlocked skins, using cached data');
return JSON.parse(localStorage.getItem(SKIN_CACHE_KEY));
}
if (!response.ok) {
throw new Error('Network response was not ok for unlocked skins');
}
const newEtag = response.headers.get('ETag');
if (newEtag) {
localStorage.setItem('skinCacheEtag', newEtag);
}
return response.json().then(data => {
localStorage.setItem(SKIN_CACHE_KEY, JSON.stringify(data.skins));
localStorage.setItem(SKIN_CACHE_TIMESTAMP_KEY, Date.now().toString());
return data.skins;
});
}
function handleSelectedSkinsResponse(response) {
if (!response.ok) {
throw new Error('Network response was not ok for selected skins');
}
return response.json().then(data => {
localStorage.setItem(SELECTED_SKINS_CACHE_KEY, JSON.stringify(data));
return data;
});
}
function selectSkin(skinType, skinId, element) {
if (!currentUser) {
console.log('No user logged in');
return;
}
fetch(`/select-skin`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ username: currentUser, skin_type: skinType, skin_id: skinId }),
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
if (data.success) {
console.log('Skin selected successfully');
// Remove 'selected' class from all skin options of the same type
const options = document.querySelectorAll(`#${skinType}Options .skin-option`);
options.forEach(option => option.classList.remove('selected'));
// Add 'selected' class to the clicked element
element.classList.add('selected');
// Update the local cache
updateLocalSelectedSkinCache(skinType, {
name: element.getAttribute('title').split(' (')[0],
value: skinType === 'color' ? element.style.backgroundColor : element.style.backgroundImage,
effect: element.classList.contains('glow-effect') ? 'glow' : null
});
loadPlayerSkin(currentUser);
} else {
console.error('Failed to select skin:', data.error);
}
})
.catch(error => {
console.error('Error selecting skin:', error);
});
}
function updateLocalSelectedSkinCache(skinType, skinData) {
const cachedSelectedSkins = JSON.parse(localStorage.getItem(SELECTED_SKINS_CACHE_KEY) || '{}');
cachedSelectedSkins[skinType] = skinData;
localStorage.setItem(SELECTED_SKINS_CACHE_KEY, JSON.stringify(cachedSelectedSkins));
}
function updateSkinCache(skinType, skinId) {
const cachedSkins = JSON.parse(localStorage.getItem(SKIN_CACHE_KEY) || '[]');
const updatedSkins = cachedSkins.map(skin => {
if (skin.type === skinType) {
return { ...skin, id: skinId };
}
return skin;
});
localStorage.setItem(SKIN_CACHE_KEY, JSON.stringify(updatedSkins));
}
function displayUnlockedSkins(skins, selectedSkins) {
const skinCustomization = document.getElementById('skinCustomization');
if (!skinCustomization) {
console.error('skinCustomization element not found');
return;
}
// Create a document fragment to build the new content
const fragment = document.createDocumentFragment();
const colorSelector = document.createElement('div');
colorSelector.id = 'colorSelector';
colorSelector.className = 'skin-section';
colorSelector.innerHTML = '<h4>Colors</h4><div id="colorOptions"></div>';
fragment.appendChild(colorSelector);
const hatSelector = document.createElement('div');
hatSelector.id = 'hatSelector';
hatSelector.className = 'skin-section';
hatSelector.innerHTML = '<h4>Hats</h4><div id="hatOptions"></div>';
fragment.appendChild(hatSelector);
// Append the fragment to skinCustomization
skinCustomization.innerHTML = '';
skinCustomization.appendChild(fragment);
const colorOptions = document.getElementById('colorOptions');
const hatOptions = document.getElementById('hatOptions');
let hasColors = false;
let hasHats = false;
skins.forEach(skin => {
const optionElement = document.createElement('div');
optionElement.classList.add('skin-option');
optionElement.setAttribute('data-skin-id', skin.id);
optionElement.setAttribute('title', `${skin.name} (${skin.rarity})`);
if (selectedSkins[skin.type] && selectedSkins[skin.type].name === skin.name) {
optionElement.classList.add('selected');
}
switch (skin.type) {
case 'color':
optionElement.style.backgroundColor = skin.value;
if (skin.effect === 'glow') {
optionElement.classList.add('glow-effect');
}
colorOptions.appendChild(optionElement);
hasColors = true;
break;
case 'hat':
optionElement.style.backgroundImage = `url(${skin.value})`;
hatOptions.appendChild(optionElement);
hasHats = true;
break;
}
optionElement.addEventListener('click', () => selectSkin(skin.type, skin.id, optionElement));
});
if (selectedSkins.color && !hasColors) {
const defaultColorElement = document.createElement('div');
defaultColorElement.classList.add('skin-option', 'selected');
defaultColorElement.style.backgroundColor = selectedSkins.color.value;
defaultColorElement.setAttribute('title', selectedSkins.color.name);
colorOptions.appendChild(defaultColorElement);
hasColors = true;
}
if (!hasColors) colorOptions.innerHTML = '<p>No colors unlocked yet</p>';
if (!hasHats) hatOptions.innerHTML = '<p>No hats unlocked yet</p>';
// Fade in the skin sections
setTimeout(() => {
document.getElementById('colorSelector').classList.add('loaded');
document.getElementById('hatSelector').classList.add('loaded');
}, 50);
if (!hasColors && !hasHats) {
displayNoSkinsMessage("You haven't unlocked any skins yet. Keep playing to earn skins!");
}
}
function displayNoSkinsMessage(message) {
const skinCustomization = document.getElementById('skinCustomization');
if (skinCustomization) {
skinCustomization.innerHTML = `<p class="no-skins-message">${message}</p>`;
} else {
console.error('skinCustomization element not found');
}
}
// Call this function when the customization tab is opened
function onCustomizationTabOpen() {
loadSkinOptions();
}