Battle-Royale-GAME / index.html
openfree's picture
Update index.html
612b3da verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ethereal Workshop Battle Royale</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #0a0a1a;
color: #fff;
overflow-x: hidden;
}
.game-container {
width: 100%;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
h1 {
text-align: center;
margin-bottom: 20px;
font-size: 2.5rem;
color: #c9a0ff;
text-shadow: 0 0 10px rgba(201, 160, 255, 0.6);
}
.subtitle {
text-align: center;
margin-bottom: 30px;
font-size: 1.2rem;
color: #8a7aa9;
}
.battle-arena {
position: relative;
width: 100%;
height: 600px;
background-image: url('https://static.wikia.nocookie.net/mysingingmonsters/images/4/4b/Ethereal_Workshop_Empty.png');
background-size: cover;
background-position: center;
border-radius: 12px;
margin-bottom: 30px;
box-shadow: 0 5px 25px rgba(201, 160, 255, 0.3);
overflow: hidden;
}
.monster {
position: absolute;
width: 100px;
height: 100px;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
transition: all 0.3s ease;
filter: drop-shadow(0 0 8px rgba(201, 160, 255, 0.7));
z-index: 5;
cursor: pointer;
}
.monster.attacking {
filter: drop-shadow(0 0 15px rgba(255, 86, 86, 0.9));
transform: scale(1.2);
}
.monster.damaged {
filter: drop-shadow(0 0 15px rgba(255, 0, 0, 0.9));
opacity: 0.7;
}
.monster.eliminated {
opacity: 0.3;
filter: grayscale(100%);
pointer-events: none;
}
.sword {
position: absolute;
width: 40px;
height: 40px;
background-size: contain;
background-repeat: no-repeat;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23c9a0ff'%3E%3Cpath d='M14.5,15.88L19.64,21L21,19.64L15.89,14.5L16.24,14.16L21.7,9.5L19.84,7.64L14.28,13.19L13.93,13.54L13.59,13.19L8.7,8.3L11.24,5.76L7.45,2L2,7.45L5.82,11.27L8.3,8.79L13.54,14.04L13.19,14.39L7.64,19.93L9.5,21.8L14.16,17.13L14.5,16.79V15.88Z'/%3E%3C/svg%3E");
transform: rotate(45deg);
opacity: 0;
z-index: 4;
transition: opacity 0.2s;
}
.health-bar-container {
position: absolute;
bottom: -15px;
left: 50%;
transform: translateX(-50%);
width: 80px;
height: 10px;
background-color: rgba(0, 0, 0, 0.5);
border-radius: 5px;
overflow: hidden;
}
.health-bar {
height: 100%;
width: 100%;
background-color: #2ecc71;
transition: width 0.3s ease;
}
.battle-log {
background-color: rgba(20, 20, 40, 0.8);
border-radius: 8px;
padding: 15px;
max-height: 200px;
overflow-y: auto;
border: 1px solid rgba(201, 160, 255, 0.3);
}
.log-entry {
margin-bottom: 8px;
padding-bottom: 8px;
border-bottom: 1px solid rgba(201, 160, 255, 0.2);
font-size: 14px;
}
.controls {
display: flex;
justify-content: center;
margin-top: 20px;
gap: 15px;
}
button {
background-color: #7851a9;
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
transition: all 0.3s ease;
}
button:hover {
background-color: #9d71cf;
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(157, 113, 207, 0.4);
}
button:disabled {
background-color: #4a3863;
cursor: not-allowed;
transform: none;
box-shadow: none;
}
.winner-display {
display: none;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: rgba(20, 20, 40, 0.9);
padding: 20px;
border-radius: 10px;
text-align: center;
z-index: 100;
box-shadow: 0 0 30px rgba(201, 160, 255, 0.8);
animation: pulse 2s infinite;
}
.winner-display h2 {
color: #c9a0ff;
margin-bottom: 10px;
}
.winner-display .winner-img {
width: 150px;
height: 150px;
margin: 0 auto;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
filter: drop-shadow(0 0 15px rgba(201, 160, 255, 0.9));
}
@keyframes pulse {
0% { box-shadow: 0 0 30px rgba(201, 160, 255, 0.6); }
50% { box-shadow: 0 0 30px rgba(201, 160, 255, 1); }
100% { box-shadow: 0 0 30px rgba(201, 160, 255, 0.6); }
}
.sparks {
position: absolute;
width: 5px;
height: 5px;
background-color: #ffeb3b;
border-radius: 50%;
z-index: 10;
box-shadow: 0 0 10px #ff9800;
opacity: 0;
}
.immunity-badge {
position: absolute;
top: -25px;
left: 50%;
transform: translateX(-50%);
background-color: gold;
color: #333;
font-size: 10px;
font-weight: bold;
padding: 3px 6px;
border-radius: 10px;
display: none;
}
@media (max-width: 768px) {
.battle-arena {
height: 400px;
}
.monster {
width: 80px;
height: 80px;
}
}
@media (max-width: 480px) {
h1 {
font-size: 1.8rem;
}
.battle-arena {
height: 300px;
}
.monster {
width: 60px;
height: 60px;
}
}
</style>
</head>
<body>
<div class="game-container">
<h1>Ethereal Workshop Battle Royale</h1>
<p class="subtitle">Last ethereal standing wins immunity! Click Start Battle to begin.</p>
<div class="battle-arena" id="arena">
<!-- Monsters will be added here by JavaScript -->
<div class="winner-display" id="winnerDisplay">
<h2>WINNER!</h2>
<div class="winner-img" id="winnerImg"></div>
<p>has won immunity!</p>
</div>
</div>
<div class="battle-log" id="battleLog">
<div class="log-entry">Welcome to the Ethereal Workshop Battle Royale! Click the Start Battle button to begin.</div>
</div>
<div class="controls">
<button id="startButton">Start Battle</button>
<button id="resetButton" disabled>Reset Battle</button>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Define monsters
const monsters = [
{
name: "Yooreek",
image: "https://static.wikia.nocookie.net/mysingingmonsters/images/1/13/Yooreek.png",
health: 100,
power: 25,
speed: 4,
eliminated: false,
position: { x: 10, y: 50 }
},
{
name: "Meebkin",
image: "https://static.wikia.nocookie.net/mysingingmonsters/images/f/f1/Meebkin.png",
health: 100,
power: 20,
speed: 5,
eliminated: false,
position: { x: 30, y: 60 }
},
{
name: "Blarret",
image: "https://static.wikia.nocookie.net/mysingingmonsters/images/9/93/Blarret.png",
health: 100,
power: 30,
speed: 3,
eliminated: false,
position: { x: 50, y: 30 }
},
{
name: "Gaddzooks",
image: "https://static.wikia.nocookie.net/mysingingmonsters/images/f/f3/Gaddzooks.png",
health: 100,
power: 15,
speed: 6,
eliminated: false,
position: { x: 70, y: 40 }
},
{
name: "Auglur",
image: "https://static.wikia.nocookie.net/mysingingmonsters/images/d/db/Auglur.png",
health: 100,
power: 35,
speed: 2,
eliminated: false,
position: { x: 85, y: 70 }
}
];
const arena = document.getElementById('arena');
const battleLog = document.getElementById('battleLog');
const startButton = document.getElementById('startButton');
const resetButton = document.getElementById('resetButton');
const winnerDisplay = document.getElementById('winnerDisplay');
const winnerImg = document.getElementById('winnerImg');
let battleInProgress = false;
let monsterElements = [];
let battleInterval;
let animationFrameId;
// Initialize the battle arena
function initializeBattle() {
// Reset monsters
monsters.forEach(monster => {
monster.health = 100;
monster.eliminated = false;
});
// Clear arena
arena.innerHTML = '';
monsterElements = [];
// Hide winner display
winnerDisplay.style.display = 'none';
// Add monster elements to arena
monsters.forEach((monster, index) => {
const monsterElement = document.createElement('div');
monsterElement.className = 'monster';
monsterElement.id = `monster-${index}`;
monsterElement.style.backgroundImage = `url(${monster.image})`;
monsterElement.style.left = `${monster.position.x}%`;
monsterElement.style.top = `${monster.position.y}%`;
// Add health bar
const healthBarContainer = document.createElement('div');
healthBarContainer.className = 'health-bar-container';
const healthBar = document.createElement('div');
healthBar.className = 'health-bar';
healthBarContainer.appendChild(healthBar);
// Add immunity badge
const immunityBadge = document.createElement('div');
immunityBadge.className = 'immunity-badge';
immunityBadge.textContent = 'IMMUNE';
monsterElement.appendChild(healthBarContainer);
monsterElement.appendChild(immunityBadge);
arena.appendChild(monsterElement);
monsterElements.push(monsterElement);
});
// Add winner display back to arena
arena.appendChild(winnerDisplay);
// Reset battle log
battleLog.innerHTML = '<div class="log-entry">The battle is about to begin! Ethereal monsters take their positions.</div>';
}
// Update monster health bars
function updateHealthBars() {
monsters.forEach((monster, index) => {
const healthBar = monsterElements[index].querySelector('.health-bar');
healthBar.style.width = `${monster.health}%`;
// Change color based on health
if (monster.health > 60) {
healthBar.style.backgroundColor = '#2ecc71';
} else if (monster.health > 30) {
healthBar.style.backgroundColor = '#f39c12';
} else {
healthBar.style.backgroundColor = '#e74c3c';
}
});
}
// Add log entry
function addLogEntry(text) {
const entry = document.createElement('div');
entry.className = 'log-entry';
entry.textContent = text;
battleLog.appendChild(entry);
battleLog.scrollTop = battleLog.scrollHeight;
}
// Create sword attack animation
function swordAttack(attackerIndex, targetIndex) {
const attacker = monsterElements[attackerIndex];
const target = monsterElements[targetIndex];
// Get positions
const attackerRect = attacker.getBoundingClientRect();
const targetRect = target.getBoundingClientRect();
const arenaRect = arena.getBoundingClientRect();
// Create sword
const sword = document.createElement('div');
sword.className = 'sword';
sword.style.left = `${(attackerRect.left + attackerRect.width/2) - arenaRect.left}px`;
sword.style.top = `${(attackerRect.top + attackerRect.height/2) - arenaRect.top}px`;
arena.appendChild(sword);
// Show sword
setTimeout(() => { sword.style.opacity = '1'; }, 10);
// Animate sword to target
const targetX = (targetRect.left + targetRect.width/2) - arenaRect.left;
const targetY = (targetRect.top + targetRect.height/2) - arenaRect.top;
let progress = 0;
const startX = parseFloat(sword.style.left);
const startY = parseFloat(sword.style.top);
function animateSword() {
progress += 0.05;
if (progress >= 1) {
sword.style.opacity = '0';
// Create sparks at impact
createSparks(targetX, targetY);
// Add damaged class to target
target.classList.add('damaged');
setTimeout(() => {
target.classList.remove('damaged');
}, 300);
// Remove sword after animation
setTimeout(() => {
sword.remove();
}, 200);
return;
}
const currentX = startX + (targetX - startX) * progress;
const currentY = startY + (targetY - startY) * progress;
sword.style.left = `${currentX}px`;
sword.style.top = `${currentY}px`;
requestAnimationFrame(animateSword);
}
requestAnimationFrame(animateSword);
}
// Create spark effects
function createSparks(x, y) {
for (let i = 0; i < 15; i++) {
const spark = document.createElement('div');
spark.className = 'sparks';
spark.style.left = `${x}px`;
spark.style.top = `${y}px`;
arena.appendChild(spark);
// Random direction and speed
const angle = Math.random() * Math.PI * 2;
const speed = 2 + Math.random() * 3;
const distance = 30 + Math.random() * 40;
// Set initial properties
spark.style.opacity = '1';
// Animate the spark
let progress = 0;
const startX = x;
const startY = y;
function animateSpark() {
progress += 0.03;
if (progress >= 1) {
spark.remove();
return;
}
const currentX = startX + Math.cos(angle) * distance * progress;
const currentY = startY + Math.sin(angle) * distance * progress;
spark.style.left = `${currentX}px`;
spark.style.top = `${currentY}px`;
spark.style.opacity = 1 - progress;
requestAnimationFrame(animateSpark);
}
requestAnimationFrame(animateSpark);
}
}
// Find nearest target
function findNearestTarget(attacker) {
let nearestTarget = -1;
let minDistance = Infinity;
for (let i = 0; i < monsters.length; i++) {
if (i !== attacker && !monsters[i].eliminated) {
const distance = Math.sqrt(
Math.pow(monsters[attacker].position.x - monsters[i].position.x, 2) +
Math.pow(monsters[attacker].position.y - monsters[i].position.y, 2)
);
if (distance < minDistance) {
minDistance = distance;
nearestTarget = i;
}
}
}
return nearestTarget;
}
// Move towards target
function moveTowardsTarget(attackerIndex, targetIndex) {
const attacker = monsters[attackerIndex];
const target = monsters[targetIndex];
// Calculate direction
const dx = target.position.x - attacker.position.x;
const dy = target.position.y - attacker.position.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 10) { // Only move if not close enough
// Normalize direction and scale by speed
const moveX = (dx / distance) * (attacker.speed * 0.5);
const moveY = (dy / distance) * (attacker.speed * 0.5);
// Update position
attacker.position.x += moveX;
attacker.position.y += moveY;
// Keep within bounds
attacker.position.x = Math.max(0, Math.min(90, attacker.position.x));
attacker.position.y = Math.max(0, Math.min(85, attacker.position.y));
// Update element position
monsterElements[attackerIndex].style.left = `${attacker.position.x}%`;
monsterElements[attackerIndex].style.top = `${attacker.position.y}%`;
}
return distance <= 15; // Return true if close enough to attack
}
// Perform battle round
function battleRound() {
// Check for battle end
let activeMonstersCount = 0;
let lastStanding = -1;
monsters.forEach((monster, index) => {
if (!monster.eliminated) {
activeMonstersCount++;
lastStanding = index;
}
});
if (activeMonstersCount <= 1) {
endBattle(lastStanding);
return;
}
// Process each monster's turn
monsters.forEach((monster, attackerIndex) => {
if (monster.eliminated) return;
// Find target
const targetIndex = findNearestTarget(attackerIndex);
if (targetIndex === -1) return;
// Try to move closer to target
const canAttack = moveTowardsTarget(attackerIndex, targetIndex);
if (canAttack) {
// Chance to attack based on speed
if (Math.random() < monster.speed / 10) {
// Add attacking class
monsterElements[attackerIndex].classList.add('attacking');
// Calculate damage with some randomness
const baseDamage = monster.power;
const randomFactor = 0.8 + Math.random() * 0.4; // 0.8 to 1.2
const damage = Math.round(baseDamage * randomFactor);
// Apply damage
monsters[targetIndex].health -= damage;
monsters[targetIndex].health = Math.max(0, monsters[targetIndex].health);
// Update health bars
updateHealthBars();
// Create sword attack animation
swordAttack(attackerIndex, targetIndex);
// Log the attack
addLogEntry(`${monster.name} attacks ${monsters[targetIndex].name} for ${damage} damage!`);
// Check if target is eliminated
if (monsters[targetIndex].health <= 0 && !monsters[targetIndex].eliminated) {
monsters[targetIndex].eliminated = true;
monsterElements[targetIndex].classList.add('eliminated');
addLogEntry(`${monsters[targetIndex].name} has been eliminated from the battle!`);
}
// Remove attacking class after a delay
setTimeout(() => {
monsterElements[attackerIndex].classList.remove('attacking');
}, 300);
}
}
});
}
// Start the battle
function startBattle() {
if (battleInProgress) return;
battleInProgress = true;
startButton.disabled = true;
resetButton.disabled = false;
addLogEntry("The battle has begun! Ethereal monsters are fighting for immunity!");
// Run battle rounds at intervals
battleInterval = setInterval(() => {
battleRound();
}, 1000);
// Start animation loop
function animationLoop() {
if (!battleInProgress) return;
// Any continuous animations can go here
animationFrameId = requestAnimationFrame(animationLoop);
}
animationLoop();
}
// End the battle
function endBattle(winnerIndex) {
battleInProgress = false;
clearInterval(battleInterval);
cancelAnimationFrame(animationFrameId);
// Display winner
if (winnerIndex >= 0) {
const winner = monsters[winnerIndex];
addLogEntry(`${winner.name} is the last ethereal standing and has won immunity!`);
// Show winner banner
winnerImg.style.backgroundImage = `url(${winner.image})`;
winnerDisplay.style.display = 'block';
// Show immunity badge
const immunityBadge = monsterElements[winnerIndex].querySelector('.immunity-badge');
immunityBadge.style.display = 'block';
} else {
addLogEntry("The battle has ended in a draw!");
}
resetButton.disabled = false;
}
// Reset the battle
function resetBattle() {
battleInProgress = false;
clearInterval(battleInterval);
cancelAnimationFrame(animationFrameId);
startButton.disabled = false;
resetButton.disabled = true;
initializeBattle();
}
// Event listeners
startButton.addEventListener('click', startBattle);
resetButton.addEventListener('click', resetBattle);
// Initialize the battle arena on load
initializeBattle();
});
</script>
</body>
</html>