/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { persistLanguage: true, language: "en" }); /**** * Classes ****/ var MusicNameOverlay = Container.expand(function () { var self = Container.call(this); // Text for displaying music name var musicText = new Text2("", { size: 110, fill: 0x000000, align: "center", dropShadow: true, dropShadowColor: 0x000000, dropShadowDistance: 3, dropShadowAlpha: 0.5 }); musicText.anchor.set(0.5, 0.5); musicText.x = 2048 / 2; musicText.y = 150; musicText.alpha = 0; self.addChild(musicText); // Random fake music names in different languages var musicNames = { en: ["Slime Symphony No. 5", "Bouncy Beats", "Gelatinous Groove", "Blob Bop", "Jiggle Jam", "Slimy Sonata", "Elasticity Etude", "Viscous Vibes", "Gooey Grooves", "Jiggly Jazz", "Will anyone read this?"], es: ["Sinfonía de Slime No. 5", "Ritmos Rebotantes", "Ritmo Gelatinoso", "Bop de Burbuja", "Mermelada Temblorosa", "Sonata Viscosa", "Estudio Elastico", "Vibraciones Viscosas", "Ritmos Pegajosos", "Jazz Tembloroso", "¿Alguien leerá esto?"] }; // Show a random music name self.showRandomName = function (language) { var names = musicNames[language] || musicNames.en; var randomName = names[Math.floor(Math.random() * names.length)]; // Stop any running animations tween.stop(musicText); // Set the text musicText.setText(randomName); // Fade in and move up animation sequence musicText.alpha = 0; musicText.y = 180; // First animation: fade in and move to position tween(musicText, { alpha: 1, y: 150 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { // Wait a bit then fade out and move up LK.setTimeout(function () { tween(musicText, { alpha: 0, y: 100 }, { duration: 1200, easing: tween.easeIn }); }, 3000); } }); }; return self; }); var Slime = Container.expand(function () { var self = Container.call(this); // Create and attach the slime asset with consistent scaling // We won't set width/height here because we'll set a consistent scale instead self.slimeAsset = self.attachAsset('ClasicSlime', { anchorX: 0.5, anchorY: 0.5 }); // Set consistent scale factor for all slimes self.baseScale = 3.5; // Reduced base scaling factor self.lastX = self.lastY = 0; self.baseX = 0; self.baseY = 0; self.setBasePosition = function (x, y) { self.baseX = x; self.baseY = y; self.x = x; self.y = y; }; self.update = function () { self.lastX = self.x; self.lastY = self.y; }; return self; }); var Star = Container.expand(function () { var self = Container.call(this); var starGraphics = self.attachAsset('Star', { anchorX: 0.5, anchorY: 0.5, width: 100, height: 100 }); self.setColorByRarity = function (rarityLevel) { // Create a smooth gradient from gray (common) to dark purple (highest rarity) // Use a gradient color scheme for better visual differentiation var colors = [0xaaaaaa, // 1: Gray (Common) 0x8ab4f8, // 2: Light blue 0x52cca3, // 3: Teal 0x1e88e5, // 4: Blue 0x7e57c2, // 5: Light purple 0xab47bc, // 6: Purple 0x8e24aa, // 7: Dark purple 0x6a1b9a, // 8: Deeper purple 0x4a148c, // 9: Very dark purple 0x38006b // 10: Darkest purple (Supreme) ]; starGraphics.tint = rarityLevel >= 1 && rarityLevel <= 10 ? colors[rarityLevel - 1] : colors[0]; // Create glow effect with subtle pulsation self.glowIntensity = 0.2 + rarityLevel / 10; LK.setTimeout(function () { tween(starGraphics, { scaleX: 1 + self.glowIntensity * 0.1, scaleY: 1 + self.glowIntensity * 0.1 }, { duration: 1000 + rarityLevel * 100, easing: tween.easeInOut, repeat: -1, yoyo: true }); }, Math.random() * 500); }; return self; }); var StartScreen = Container.expand(function () { var self = Container.call(this); // Create background for start screen var startBg = self.attachAsset('BGInitial', { anchorX: 0, anchorY: 0, width: 2048, height: 2732 }); // Add title screen image using TittleAsset var titleImage = self.attachAsset('TittleAsset', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 - 300, scaleX: 1.2, scaleY: 1.2 }); // Title is now included in the TittleAsset // No tap to start text - removed as requested // Make the start screen interactive self.interactive = true; // When screen is tapped, trigger the transition self.down = function () { if (self.onStart) { // Clear the auto-start timer if it exists if (autoStartTimer) { LK.clearTimeout(autoStartTimer); } LK.getSound('InterfazSound').play(); // Create a darkening overlay var darkOverlay = new Container(); var darkRect = LK.getAsset('transition', { anchorX: 0, anchorY: 0, width: 2048, height: 2732, alpha: 0 }); darkOverlay.addChild(darkRect); self.addChild(darkOverlay); // Start darkening animation tween(darkRect, { alpha: 1.0 }, { duration: 3000, easing: tween.easeInOut }); // Add rotation and falling animation to title image if (titleImage) { tween(titleImage, { rotation: 0.2, y: titleImage.y + 100 }, { duration: 600, easing: tween.easeIn, onFinish: function onFinish() { // Add pause before falling LK.setTimeout(function () { // Accelerate falling tween(titleImage, { y: 2732 + 500, rotation: 0.5 }, { duration: 1200, easing: tween.easeIn, onFinish: function onFinish() { // Add delay before transitioning to give more time for cube to disappear LK.setTimeout(function () { // Call the actual transition self.onStart(); }, 800); } }); }, 1000); // 1 second pause between rotation and falling } }); } // Close the if (titleImage) block } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Day/Night detection variables var isDayTime = true; var darkTint = 0x404060; // Dark blue-gray tint for night mode // Function to check if it's day or night function checkDayTime() { var now = new Date(); var hours = now.getHours(); // Day is from 6 AM to 6 PM return hours >= 6 && hours < 18; } // Create a container for game content that will appear from center var gameContent = new Container(); gameContent.y = 0; // Position at normal position gameContent.alpha = 0; // Start invisible gameContent.scale.set(0.5); // Start small for zoom effect // Create BGMenu for bottom half of screen var bgMenu = LK.getAsset('BGMenu', { anchorX: 0, anchorY: 0, x: 0, y: 2032 / 2, width: 2048, height: 3532 / 2 }); // Create BG for top half of screen var bg = LK.getAsset('BG', { anchorX: 0, anchorY: 0, x: 0, y: 0, width: 2048, height: 2032 / 2 }); // Create and add start screen var startScreen = new StartScreen(); game.addChild(startScreen); // Set up auto-start timer for 10 seconds var autoStartTimer = LK.setTimeout(function () { // Only trigger if startScreen still exists and has a parent if (startScreen && startScreen.parent) { startScreen.down(); // Simulate tap to start } }, 10000); // Set up the transition function startScreen.onStart = function () { // Keep the darkening overlay visible until menu animation completes // First animate the game content appearing from center tween(gameContent, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 0, easing: tween.easeOut, onFinish: function onFinish() { // Only after game content is positioned, fade out the start screen // Add null check before tweening to prevent TypeError if (startScreen) { tween(startScreen, { alpha: 0 // Fade out }, { duration: 5000, easing: tween.easeInOut, onFinish: function onFinish() { // Remove start screen when animation completes if (startScreen && startScreen.parent) { game.removeChild(startScreen); startScreen = null; } } }); } } }); }; // Create interface element at the top of BGMenu var interfaz = LK.getAsset('Interfaz', { anchorX: 0.5, anchorY: 0, width: 2048, height: 400 }); // Create sort button at the top right of interface var sortButton = LK.getAsset('BotonExtras', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8, x: 800, y: -700 }); // Add event handler for sort button sortButton.interactive = true; sortButton.down = function () { // Play interface sound LK.getSound('InterfazSound').play(); changeSortOrder(); }; // Create sort text to show current sort order var sortText = new Text2("★↑", { size: 90, fill: 0x000000 }); sortText.anchor.set(0.5, 0.5); sortText.x = sortButton.x; sortText.y = sortButton.y + 35; // Position the interface at the top of BGMenu interfaz.x = bgMenu.width / 2; interfaz.y = bgMenu.y; // Create left button var leftButton = LK.getAsset('BotonChange', { anchorX: 0.5, anchorY: 0.5, scaleX: -1, // Flip horizontally to point left x: -800, y: interfaz.height / 2 }); // Add event handlers for left button leftButton.interactive = true; // Create right button var rightButton = LK.getAsset('BotonChange', { anchorX: 0.5, anchorY: 0.5, x: 800, y: interfaz.height / 2 }); // Add event handlers for right button rightButton.interactive = true; var currentSlimeIndex = 0; var currentSortOrder = 0; // 0: Ascending by rarity, 1: Descending by rarity, 2: A-Z by name, 3: Z-A by name // Get language from storage with fallback to browser language or English var currentLanguage = storage.language; if (!currentLanguage || currentLanguage !== 'en' && currentLanguage !== 'es') { // Try to detect browser language, defaulting to English if not supported var browserLang = navigator && navigator.language ? navigator.language.substring(0, 2) : null; currentLanguage = browserLang === 'es' ? 'es' : 'en'; storage.language = currentLanguage; // Save initial language to storage } // Language selector button var languageButton = LK.getAsset('BotonExtras', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8, x: 800, y: -900 }); languageButton.interactive = true; languageButton.down = function () { // Play interface sound LK.getSound('InterfazSound').play(); toggleLanguage(); }; // Language text display var languageText = new Text2(currentLanguage.toUpperCase(), { size: 70, fill: 0x000000 }); languageText.anchor.set(0.5, 0.5); languageText.x = languageButton.x; languageText.y = languageButton.y + 35; // Language translations var translations = { en: { sortLabels: ["★↑", "★↓", "A→Z", "Z→A", "⚖↑", "⚖↓"], categoryTitles: { "Rarity": "Rarity", "Size": "Size", "History": "History", "Location": "Location", "Favorite Food": "Favorite Food", "Ability": "Ability", "Stats": "Stats", "Lifespan": "Lifespan" }, rarityNames: { 1: "Common", 2: "Uncommon", 3: "Infrequent", 4: "Rare", 5: "Epic", 6: "Exceptional", 7: "Legendary", 8: "Mythic", 9: "Arcane", 10: "Supreme" }, sizeDescriptions: { tiny: "Tiny", small: "Small", medium: "Medium", large: "Large", veryLarge: "Very Large", enormous: "Enormous" }, statNames: { strength: "Strength", agility: "Agility", defense: "Defense", magic: "Magic", luck: "Luck", mysticism: "Mysticism" } }, es: { sortLabels: ["★↑", "★↓", "A→Z", "Z→A", "⚖↑", "⚖↓"], categoryTitles: { "Rarity": "Rareza", "Size": "Tamaño", "History": "Historia", "Location": "Ubicación", "Favorite Food": "Comida Favorita", "Ability": "Habilidad", "Stats": "Estadísticas", "Lifespan": "Esperanza de vida" }, rarityNames: { 1: "Común", 2: "Poco Común", 3: "Infrecuente", 4: "Raro", 5: "Épico", 6: "Excepcional", 7: "Legendario", 8: "Mtico", 9: "Arcano", 10: "Supremo" }, sizeDescriptions: { tiny: "Diminuto", small: "Pequeño", medium: "Mediano", large: "Grande", veryLarge: "Muy Grande", enormous: "Enorme" }, statNames: { strength: "Fuerza", agility: "Agilidad", defense: "Defensa", magic: "Magia", luck: "Suerte", mysticism: "Misticismo" } } }; // Function to update all language-dependent UI elements function updateLanguageUI() { // Update language display languageText.setText(currentLanguage.toUpperCase()); // Update sort labels var sortLabels = translations[currentLanguage].sortLabels; sortText.setText(sortLabels[currentSortOrder]); // Update slime name display var displayName = currentLanguage === 'en' ? slimeNames[currentSlimeIndex] : SlimeInfo[currentSlimeIndex].SlimeNameEs || slimeNames[currentSlimeIndex]; slimeNameText.setText(displayName); // Update info panel with new language content updateInfoPanel(); // Update music name overlay if visible if (musicNameOverlay && musicNameOverlay.parent) { musicNameOverlay.showRandomName(currentLanguage); } } // Function to toggle between languages function toggleLanguage() { currentLanguage = currentLanguage === 'en' ? 'es' : 'en'; // Save language preference to storage storage.language = currentLanguage; // Update all UI elements with new language updateLanguageUI(); } // Function to sort slimes based on current sort order function changeSortOrder() { // Change sort order currentSortOrder = (currentSortOrder + 1) % 6; // Update sort text with current language var sortLabels = translations[currentLanguage].sortLabels; sortText.setText(sortLabels[currentSortOrder]); // Sort SlimeInfo based on the selected order if (currentSortOrder === 0) { // Sort by rarity (ascending) SlimeInfo.sort(function (a, b) { return a.Rarity - b.Rarity; }); } else if (currentSortOrder === 1) { // Sort by rarity (descending) SlimeInfo.sort(function (a, b) { return b.Rarity - a.Rarity; }); } else if (currentSortOrder === 2) { // Sort alphabetically (A to Z) SlimeInfo.sort(function (a, b) { return a.SlimeName.localeCompare(b.SlimeName); }); } else if (currentSortOrder === 3) { // Sort alphabetically (Z to A) SlimeInfo.sort(function (a, b) { return b.SlimeName.localeCompare(a.SlimeName); }); } else if (currentSortOrder === 4) { // Sort by size (ascending) SlimeInfo.sort(function (a, b) { return (a.Size || 1.0) - (b.Size || 1.0); }); } else { // Sort by size (descending) SlimeInfo.sort(function (a, b) { return (b.Size || 1.0) - (a.Size || 1.0); }); } // Update arrays based on the new sorted SlimeInfo slimes = SlimeInfo.map(function (slime) { var slimeName = slime.SlimeName.replace(/\s+/g, ''); return slimeName; }); slimeNames = SlimeInfo.map(function (slime) { return slime.SlimeName; }); rarityValues = SlimeInfo.map(function (slime) { return slime.Rarity; }); // Reset to first slime currentSlimeIndex = 0; updateSlimeAndInfo(); } // Function to wrap text that exceeds screen width function wrapText(text, maxWidth, textSize) { if (!text) { return ""; } var words = text.split(' '); var wrappedText = '', line = ''; var charsPerLine = Math.floor(maxWidth / (textSize * 0.5)); for (var i = 0; i < words.length; i++) { var testLine = line + words[i] + ' '; if (testLine.length > charsPerLine) { wrappedText += line.trim() + '\n'; line = words[i] + ' '; } else { line = testLine; } } return wrappedText + line.trim(); } // Create structured slime information var rarityNamesByValue = { 1: "Common", 2: "Unusual", 3: "Uncommon", 4: "Remarkable", 5: "Rare", 6: "Exceptional", 7: "Mythical", 8: "Legendary", 9: "Ancient", 10: "Divine" }; // Function to sort slimes by rarity from highest to lowest function sortSlimesByRarity(slimes) { return slimes.slice().sort(function (a, b) { return b.Rarity - a.Rarity; // Sort in descending order (highest to lowest) }); } // Structured SlimeInfo array with all properties in a single place var SlimeInfo = [{ SlimeName: 'Clasic Slime', SlimeNameEs: 'Slime Clásico', Rarity: 1, Size: 1.0, // Medium size (baseline) History: 'The most common and friendly of all slimes, Clasic Slimes are believed to be the original form from which all other slimes evolved.', HistoryEs: 'El más común y amigable de todos los slimes, los Slimes Clásicos son considerados la forma original de la que evolucionaron todos los demás slimes.', Location: 'Meadows, gardens, and anywhere with fresh dew', LocationEs: 'Praderas, jardines y cualquier lugar con rocío fresco', FavoriteFood: 'Fresh grass and morning dew', FavoriteFoodEs: 'Hierba fresca y rocío de la mañana', Ability: 'Can split into two smaller slimes when threatened', AbilityEs: 'Puede dividirse en dos slimes más pequeños cuando se siente amenazado', Stats: { strength: 3, agility: 5, defense: 2, magic: 1, luck: 2, mysticism: 1 }, Lifespan: '5-8 years', LifespanEs: '5-8 años' }, { SlimeName: 'Snowy Slime', SlimeNameEs: 'Slime Nevado', Rarity: 2, Size: 0.9, // Slightly smaller History: 'Snowy Slimes are born from snowdrifts touched by moonlight. They are gentle and love cold climates.', HistoryEs: 'Los Slimes Nevados nacen de ventisqueros tocados por la luz de la luna. Son gentiles y aman los climas fríos.', Location: 'Snowfields, icy caves, and mountaintops', LocationEs: 'Campos nevados, cuevas heladas y cimas de montañas', FavoriteFood: 'Icicles and frozen berries', FavoriteFoodEs: 'Carámbanos y bayas congeladas', Ability: 'Can lower the temperature around them, freezing small puddles instantly', AbilityEs: 'Puede bajar la temperatura a su alrededor, congelando pequeños charcos instantáneamente', Stats: { strength: 3, agility: 2, defense: 8, magic: 6, luck: 4, mysticism: 5 }, Lifespan: '12-15 years', LifespanEs: '12-15 años' }, { SlimeName: 'Water Slime', SlimeNameEs: 'Slime Acuático', Rarity: 3, Size: 0.8, // Small and fluid History: 'Formed from enchanted raindrops, Water Slimes are playful and quick, often found near rivers.', HistoryEs: 'Formados a partir de gotas de lluvia encantadas, los Slimes Acuáticos son juguetones y rápidos, a menudo encontrados cerca de ríos.', Location: 'Lakes, rivers, and rainy forests', LocationEs: 'Lagos, ríos y bosques lluviosos', FavoriteFood: 'Pure spring water and water lilies', FavoriteFoodEs: 'Agua pura de manantial y nenúfares', Ability: 'Can merge with water to become invisible and move swiftly', AbilityEs: 'Puede fusionarse con el agua para volverse invisible y moverse rápidamente', Stats: { strength: 2, agility: 7, defense: 1, magic: 5, luck: 4, mysticism: 3 }, Lifespan: '8-12 years', LifespanEs: '8-12 años' }, { SlimeName: 'Rock Slime', SlimeNameEs: 'Slime Rocoso', Rarity: 4, Size: 1.3, // Bulky and dense History: 'Rock Slimes are the result of slimes living near mineral-rich caves, slowly absorbing stone and earth.', HistoryEs: 'Los Slimes Rocosos son el resultado de slimes que viven cerca de cuevas ricas en minerales, absorbiendo lentamente piedra y tierra.', Location: 'Caves, rocky hills, and mountain bases', LocationEs: 'Cuevas, colinas rocosas y bases de montañas', FavoriteFood: 'Pebbles and mineral-rich soil', FavoriteFoodEs: 'Guijarros y tierra rica en minerales', Ability: 'Can harden their bodies to become nearly unbreakable for short periods', AbilityEs: 'Puede endurecer su cuerpo para volverse casi irrompible por cortos períodos', Stats: { strength: 8, agility: 1, defense: 9, magic: 2, luck: 3, mysticism: 1 }, Lifespan: '20-30 years', LifespanEs: '20-30 años' }, { SlimeName: 'Fire Slime', SlimeNameEs: 'Slime de Fuego', Rarity: 5, Size: 1.1, // Slightly larger due to heat expansion History: 'Fire Slimes are born from the embers of ancient volcanoes, carrying a spark of elemental fire within.', HistoryEs: 'Los Slimes de Fuego nacen de las brasas de antiguos volcanes, llevando una chispa de fuego elemental en su interior.', Location: 'Volcanoes, hot springs, and scorched plains', LocationEs: 'Volcanes, aguas termales y llanuras calcinadas', FavoriteFood: 'Charcoal and spicy peppers', FavoriteFoodEs: 'Carbón y pimientos picantes', Ability: 'Can ignite themselves to ward off predators and light dark places', AbilityEs: 'Puede encenderse para ahuyentar a los depredadores e iluminar lugares oscuros', Stats: { strength: 6, agility: 3, defense: 4, magic: 7, luck: 2, mysticism: 6 }, Lifespan: '10-15 years' }, { SlimeName: 'Shadow Slime', SlimeNameEs: 'Slime de Sombra', Rarity: 6, Size: 1.2, // Larger and imposing History: 'Shadow Slimes are born in places untouched by light, absorbing the darkness around them.', HistoryEs: 'Los Slimes de Sombra nacen en lugares donde la luz nunca llega, absorbiendo la oscuridad a su alrededor.', Location: 'Caverns, abandoned ruins, and deep forests at night', LocationEs: 'Cavernas, ruinas abandonadas y bosques profundos durante la noche', FavoriteFood: 'Shadows and nocturnal insects', FavoriteFoodEs: 'Sombras e insectos nocturnos', Ability: 'Can blend into shadows and become nearly invisible', AbilityEs: 'Puede fundirse con las sombras y volverse casi invisible', Stats: { strength: 5, agility: 8, defense: 3, magic: 9, luck: 6, mysticism: 8 }, Lifespan: '30-40 years', LifespanEs: '30-40 años' }, { SlimeName: 'Forest Slime', SlimeNameEs: 'Slime de Bosque', Rarity: 7, Size: 1.15, // Healthy and lush History: 'Forest Slimes are the guardians of ancient woods, formed from moss and enchanted leaves.', HistoryEs: 'Los Slimes de Bosque son guardianes de los bosques antiguos, formados de musgo y hojas encantadas.', Location: 'Dense forests, groves, and magical thickets', LocationEs: 'Bosques densos, arboledas y matorrales mágicos', FavoriteFood: 'Moss, leaves, and wildflowers', FavoriteFoodEs: 'Musgo, hojas y flores silvestres', Ability: 'Can heal plants and accelerate their growth', AbilityEs: 'Puede curar plantas y acelerar su crecimiento', Stats: { strength: 4, agility: 6, defense: 5, magic: 8, luck: 5, mysticism: 7 }, Lifespan: '25-35 years', LifespanEs: '25-35 años' }, { SlimeName: 'Beast Slime', SlimeNameEs: 'Slime Bestia', Rarity: 8, Size: 1.4, // Large and intimidating History: 'Beast Slimes are fierce and wild, believed to have evolved by mimicking the strongest animals in their environment.', HistoryEs: 'Los Slimes Bestia son feroces y salvajes, se cree que evolucionaron imitando a los animales más fuertes de su entorno.', Location: 'Savannahs, jungles, and wild plains', LocationEs: 'Sabanas, selvas y llanuras salvajes', FavoriteFood: 'Raw meat and wild fruits', FavoriteFoodEs: 'Carne cruda y frutas silvestres', Ability: 'Can roar to intimidate foes and temporarily boost their own strength', AbilityEs: 'Puede rugir para intimidar enemigos y aumentar temporalmente su fuerza', Stats: { strength: 9, agility: 7, defense: 7, magic: 3, luck: 8, mysticism: 2 }, Lifespan: '18-25 years', LifespanEs: '18-25 años' }, { SlimeName: 'Lucky Slime', SlimeNameEs: 'Slime de la Suerte', Rarity: 8, Size: 0.95, // Medium-small for good luck History: 'Lucky Slimes are said to be born during rare celestial events, bringing fortune to those who find them.', HistoryEs: 'Se dice que los Slimes de la Suerte nacen durante eventos celestiales raros, trayendo fortuna a quienes los encuentran.', Location: 'Rainbow fields, clover patches, and near waterfalls', LocationEs: 'Campos de arcoíris, parches de tréboles y cerca de cascadas', FavoriteFood: 'Four-leaf clovers and golden apples', FavoriteFoodEs: 'Tréboles de cuatro hojas y manzanas doradas', Ability: 'Can increase the luck of nearby creatures and find hidden treasures', AbilityEs: 'Puede aumentar la suerte de criaturas cercanas y encontrar tesoros ocultos', Stats: { strength: 3, agility: 5, defense: 2, magic: 6, luck: 10, mysticism: 4 }, Lifespan: '10-20 years', LifespanEs: '10-20 años' }, { SlimeName: 'Runic Slime', SlimeNameEs: 'Slime Rúnico', Rarity: 9, Size: 1.25, // Large with ornate runes History: 'Runic Slimes are ancient beings, their bodies inscribed with glowing runes of power.', HistoryEs: 'Los Slimes Rúnicos son seres antiguos, sus cuerpos están inscritos con runas brillantes de poder.', Location: 'Ancient temples, rune circles, and magical libraries', LocationEs: 'Templos antiguos, círculos de runas y bibliotecas mágicas', FavoriteFood: 'Enchanted stones and magical scrolls', FavoriteFoodEs: 'Piedras encantadas y pergaminos mágicos', Ability: 'Can cast simple spells and decipher ancient languages', AbilityEs: 'Puede lanzar hechizos simples y descifrar lenguas antiguas', Stats: { strength: 5, agility: 4, defense: 3, magic: 9, luck: 7, mysticism: 10 }, Lifespan: '50-100 years', LifespanEs: '50-100 años' }, { SlimeName: 'Divine Slime', SlimeNameEs: 'Slime Divino', Rarity: 10, Size: 1.5, // Majestic and grand History: 'Divine Slimes are legendary, said to descend from the heavens during times of great need.', HistoryEs: 'Los Slimes Divinos son legendarios, se dice que descienden de los cielos en tiempos de gran necesidad.', Location: 'Sacred groves, mountaintops, and places of worship', LocationEs: 'Arboledas sagradas, cimas de montañas y lugares de culto', FavoriteFood: 'Nectar from sacred flowers and pure spring water', FavoriteFoodEs: 'Néctar de flores sagradas y agua de manantial pura', Ability: 'Can heal wounds and purify water with a touch', AbilityEs: 'Puede curar heridas y purificar agua con solo tocarla', Stats: { strength: 7, agility: 4, defense: 6, magic: 10, luck: 10, mysticism: 9 }, Lifespan: 'Unknown, possibly eternal', LifespanEs: 'Desconocida, posiblemente eterna' }, { SlimeName: 'Fruit Slime', SlimeNameEs: 'Slime Fruta', Rarity: 5, Size: 1.05, // Plump and juicy History: 'Born from the essence of vibrant orchards, Fruit Slimes emerged when magical runoff seeped into ancient fruit groves.', HistoryEs: 'Nacidos de la esencia de huertos vibrantes, los Slimes Fruta surgieron cuando la magia se filtró en antiguos huertos de frutas.', Location: 'Orchards, fruit markets, and gardens with sweet-smelling blossoms', LocationEs: 'Huertos, mercados de frutas y jardines con flores fragantes', FavoriteFood: 'Overripe fruits and berry preserves', FavoriteFoodEs: 'Frutas demasiado maduras y conservas de bayas', Ability: 'Can change color based on the last fruit consumed, and releases a sweet aroma that calms nearby creatures', AbilityEs: 'Puede cambiar de color según la última fruta consumida y libera un aroma dulce que calma a las criaturas cercanas', Stats: { strength: 4, agility: 6, defense: 3, magic: 7, luck: 6, mysticism: 5 }, Lifespan: '15-20 years, longer if fed a varied diet of exotic fruits', LifespanEs: '15-20 años, más si se alimenta con una dieta variada de frutas exóticas' }, { SlimeName: 'Ghost Slime', SlimeNameEs: 'Slime Fantasma', Rarity: 7, Size: 1.1, // Ethereal and wispy History: 'Ghost Slimes formed when regular slimes wandered into haunted areas and absorbed spectral essence, gaining ethereal properties.', HistoryEs: 'Los Slimes Fantasma se formaron cuando slimes comunes vagaron por zonas embrujadas y absorbieron esencia espectral, obteniendo propiedades etéreas.', Location: 'Abandoned buildings, ancient ruins, and places with strong spiritual energy', LocationEs: 'Edificios abandonados, ruinas antiguas y lugares con fuerte energía espiritual', FavoriteFood: 'Emotions, particularly nostalgia and melancholy', FavoriteFoodEs: 'Emociones, especialmente nostalgia y melancolía', Ability: 'Can phase through solid objects and temporarily become invisible when threatened', AbilityEs: 'Puede atravesar objetos sólidos y volverse invisible temporalmente cuando se siente amenazado', Stats: { strength: 2, agility: 7, defense: 3, magic: 9, luck: 6, mysticism: 8 }, Lifespan: 'Potentially immortal, though they can fade away if they lose their spectral essence', LifespanEs: 'Potencialmente inmortal, aunque pueden desvanecerse si pierden su esencia espectral' }, { SlimeName: 'King Slime', SlimeNameEs: 'Rey Slime', Rarity: 9, Size: 1.6, // Royal and massive History: 'The legendary King Slime is said to be born once a century when a slime absorbs royal essence from an ancient crown.', HistoryEs: 'Se dice que el legendario Rey Slime nace una vez cada siglo cuando un slime absorbe la esencia real de una corona antigua.', Location: 'Hidden chambers in royal castles and within the deepest parts of enchanted forests', LocationEs: 'Cámaras ocultas en castillos reales y en las partes más profundas de bosques encantados', FavoriteFood: 'Precious metals and gems, particularly gold and rubies', FavoriteFoodEs: 'Metales preciosos y gemas, especialmente oro y rubíes', Ability: 'Can command lesser slimes and temporarily grow to massive size, becoming nearly invulnerable', AbilityEs: 'Puede comandar slimes menores y crecer temporalmente a un tamaño masivo, volviéndose casi invulnerable', Stats: { strength: 8, agility: 4, defense: 8, magic: 7, luck: 7, mysticism: 9 }, Lifespan: 'Over 200 years, with some specimens reported to live for millennia', LifespanEs: 'Más de 200 años, con algunos ejemplares reportados viviendo milenios' }, { SlimeName: 'Golden Slime', SlimeNameEs: 'Slime Dorado', Rarity: 10, Size: 1.35, // Substantial and solid History: 'Golden Slimes are incredibly rare mutations that occur when a slime is exposed to concentrated alchemical gold for generations.', HistoryEs: 'Los Slimes Dorados son mutaciones increíblemente raras que ocurren cuando un slime es expuesto a oro alquímico concentrado durante generaciones.', Location: 'Ancient treasure vaults, alchemist laboratories, and the hearts of mountains rich with gold deposits', LocationEs: 'Antiguas bóvedas de tesoros, laboratorios de alquimistas y el corazón de montañas ricas en oro', FavoriteFood: 'Gold dust and magical essences', FavoriteFoodEs: 'Polvo de oro y esencias mágicas', Ability: 'Turns objects it consumes partially to gold and can detect precious metals at great distances', AbilityEs: 'Convierte parcialmente en oro los objetos que consume y puede detectar metales preciosos a grandes distancias', Stats: { strength: 6, agility: 3, defense: 9, magic: 8, luck: 10, mysticism: 8 }, Lifespan: 'Virtually immortal as long as they consume small amounts of gold regularly', LifespanEs: 'Prácticamente inmortal mientras consuma pequeñas cantidades de oro regularmente' }]; // Sort SlimeInfo by rarity (highest to lowest) SlimeInfo = sortSlimesByRarity(SlimeInfo); // Update slimes array based on the new sorted SlimeInfo slimes = SlimeInfo.map(function (slime, index) { // Get the appropriate slime asset name based on the SlimeName var slimeName = slime.SlimeName.replace(/\s+/g, ''); return slimeName; }); // Extract arrays for backward compatibility and easier access var slimeNames = SlimeInfo.map(function (slime) { return slime.SlimeName; }); // Array for Spanish slime names var slimeNamesEs = SlimeInfo.map(function (slime) { return slime.SlimeNameEs || slime.SlimeName; }); var rarityValues = SlimeInfo.map(function (slime) { return slime.Rarity; }); var histories = SlimeInfo.map(function (slime) { return slime.History; }); var locations = SlimeInfo.map(function (slime) { return slime.Location; }); var favoriteFoods = SlimeInfo.map(function (slime) { return slime.FavoriteFood; }); var abilities = SlimeInfo.map(function (slime) { return slime.Ability; }); var stats = SlimeInfo.map(function (slime) { return slime.Stats; }); var lifespans = SlimeInfo.map(function (slime) { return slime.Lifespan; }); // Create text display for slime name var slimeNameText = new Text2(slimeNames[currentSlimeIndex], { size: 100, fill: 0xFFFFFF }); slimeNameText.anchor.set(0.5, 0.5); slimeNameText.x = 0; slimeNameText.y = interfaz.height / 2; // Create a slime and add it to the scene var slime = new Slime(); // Position slime at the center of BG but lower down and set base position var centerX = bg.width / 2; var centerY = bg.height / 2 + 220; // Lower position slime.setBasePosition(centerX, centerY); // Set initial properties for animations slime.alpha = 1; slime.scaleX = 1; slime.scaleY = 1; // Music array for random background music selection var musicTracks = ['BGSong', 'BGSong2', 'BGSong3', 'BGSong4', 'BGSong5']; var currentMusicIndex = -1; // Music name overlay to display song names var musicNameOverlay = new MusicNameOverlay(); // Function to play a random music track function playRandomMusic() { var newIndex; // Make sure we don't play the same track twice in a row do { newIndex = Math.floor(Math.random() * musicTracks.length); } while (newIndex === currentMusicIndex && musicTracks.length > 1); currentMusicIndex = newIndex; LK.playMusic(musicTracks[currentMusicIndex]); // Show random music name with current language // Make a safe call to ensure language is correctly set if (musicNameOverlay) { musicNameOverlay.showRandomName(currentLanguage); } } // Play initial random music playRandomMusic(); // Set up music change timer (1:40 minutes = 100,000 milliseconds) LK.setInterval(playRandomMusic, 100000); // --- Info Panel for BGMenu --- var infoPanelHeight = bgMenu.height - interfaz.height - 40; var infoPanelWidth = bgMenu.width; var infoPanelY = bgMenu.y + interfaz.height + 20; var infoPanelX = bgMenu.x + (bgMenu.width - infoPanelWidth) / 2; // Center horizontally // Create a container for the info panel var infoPanel = new Container(); infoPanel.x = infoPanelX; infoPanel.y = infoPanelY; // No background for the info panel // Prepare info categories and data var infoCategories = [{ title: "Rarity", get: function get(i) { var rarityValue = SlimeInfo[i].Rarity; this.currentRarityValue = rarityValue; // Return translated rarity name return translations[currentLanguage].rarityNames[rarityValue]; } }, { title: "Size", get: function get(i) { var sizeValue = SlimeInfo[i].Size || 1.0; var sizeKey; if (sizeValue <= 0.8) { sizeKey = "tiny"; } else if (sizeValue <= 0.95) { sizeKey = "small"; } else if (sizeValue <= 1.1) { sizeKey = "medium"; } else if (sizeValue <= 1.3) { sizeKey = "large"; } else if (sizeValue <= 1.5) { sizeKey = "veryLarge"; } else { sizeKey = "enormous"; } var sizeDescription = translations[currentLanguage].sizeDescriptions[sizeKey]; return sizeDescription + " (" + sizeValue.toFixed(2) + "x scale)"; } }, { title: "History", get: function get(i) { return currentLanguage === 'en' ? SlimeInfo[i].History : SlimeInfo[i].HistoryEs || SlimeInfo[i].History; } }, { title: "Location", get: function get(i) { return currentLanguage === 'en' ? SlimeInfo[i].Location : SlimeInfo[i].LocationEs || SlimeInfo[i].Location; } }, { title: "Favorite Food", get: function get(i) { return currentLanguage === 'en' ? SlimeInfo[i].FavoriteFood : SlimeInfo[i].FavoriteFoodEs || SlimeInfo[i].FavoriteFood; } }, { title: "Ability", get: function get(i) { return currentLanguage === 'en' ? SlimeInfo[i].Ability : SlimeInfo[i].AbilityEs || SlimeInfo[i].Ability; } }, { title: "Stats", get: function get(i) { var s = SlimeInfo[i].Stats; // Create visual stat bars with colored values using actual colors instead of tags function formatStat(name, value) { var barChars = "■".repeat(value); var emptyChars = "□".repeat(10 - value); // Translate stat name based on current language var translatedName = translations[currentLanguage].statNames[name.toLowerCase()] || name; return translatedName + ": " + value + " [" + barChars + emptyChars + "]"; } // Create a single column with all 6 stats var statText = ""; statText += formatStat("strength", s.strength) + "\n"; statText += formatStat("agility", s.agility) + "\n"; statText += formatStat("defense", s.defense) + "\n"; statText += formatStat("magic", s.magic) + "\n"; statText += formatStat("luck", s.luck) + "\n"; statText += formatStat("mysticism", s.mysticism); return statText; } }, { title: "Lifespan", get: function get(i) { return currentLanguage === 'en' ? SlimeInfo[i].Lifespan : SlimeInfo[i].LifespanEs || SlimeInfo[i].Lifespan; } }]; // Create a container for the scrollable text var infoTextContainer = new Container(); infoTextContainer.x = 30; infoTextContainer.y = 30; // Add top margin // Function to update info text for current slime function updateInfoPanel() { // Remove old children infoTextContainer.removeChildren(); var y = 0; for (var c = 0; c < infoCategories.length; c++) { // Add extra spacing between sections if not the first section if (c > 0) { y += 80; // Add extra spacing between sections } // Title with gradient effect based on category var titleColors = { "Rarity": 0xFFD700, "History": 0xCF9FFF, "Location": 0x98FB98, "Favorite Food": 0xFF7F50, "Ability": 0x00BFFF, "Stats": 0xFF1493, "Lifespan": 0x00FA9A }; var titleColor = titleColors[infoCategories[c].title] || 0xFFF7B2; // Get translated title var translatedTitle = translations[currentLanguage].categoryTitles[infoCategories[c].title] || infoCategories[c].title; var titleText = new Text2(translatedTitle, { size: 110, fill: titleColor, font: "GillSans-Bold", align: "center", dropShadow: true, dropShadowColor: 0x000000, dropShadowDistance: 3, dropShadowAlpha: 0.5 }); titleText.anchor.set(0.5, 0); titleText.x = infoPanelWidth / 2 - 30; titleText.y = y; infoTextContainer.addChild(titleText); y += titleText.height + 6; // Info - wrap text to fit screen width var infoContent = infoCategories[c].get(currentSlimeIndex); var wrappedText = infoContent; // Only apply text wrapping if not the stats category (which already has formatting) if (infoCategories[c].title !== "Stats") { wrappedText = wrapText(infoContent, infoPanelWidth - 60, 85); // Wrap text with some padding } // Choose text color based on category var textColors = { "Rarity": 0xFFFACD, "History": 0xE6E6FA, "Location": 0xF0FFF0, "Favorite Food": 0xFFE4E1, "Ability": 0xE0FFFF, "Stats": 0xFFE4E1, "Lifespan": 0xF0FFFF }; var textColor = textColors[infoCategories[c].title] || 0xFFFFFF; var infoText = new Text2(wrappedText, { size: 85, fill: textColor, font: "GillSans", align: infoCategories[c].title === "Stats" ? "left" : "center", dropShadow: true, dropShadowColor: 0x333333, dropShadowDistance: 2, dropShadowAlpha: 0.3 }); // Set anchor based on content type if (infoCategories[c].title === "Stats") { infoText.anchor.set(0.5, 0); // Center align stats too infoText.x = infoPanelWidth / 2 - 30; } else { infoText.anchor.set(0.5, 0); // Center align for other content infoText.x = infoPanelWidth / 2 - 30; } infoText.y = y + 20; infoTextContainer.addChild(infoText); // If this is the rarity category, add colored stars if (infoCategories[c].title === "Rarity" && infoCategories[c].currentRarityValue) { var starContainer = new Container(); starContainer.x = infoPanelWidth / 2 - 30; starContainer.y = y + infoText.height + 40; var rarityValue = infoCategories[c].currentRarityValue; var starSpacing = 110, totalWidth = (rarityValue - 1) * starSpacing; var startX = -totalWidth / 2; for (var s = 0; s < rarityValue; s++) { var star = new Star(); star.x = startX + s * starSpacing; star.y = 20; star.alpha = 0; star.scale.x = star.scale.y = 0.5; star.setColorByRarity(rarityValue); starContainer.addChild(star); (function (targetStar, delay) { LK.setTimeout(function () { tween(targetStar, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 400, easing: tween.easeOut }); }, delay); })(star, s * 200); } infoTextContainer.addChild(starContainer); y += 80; } y += infoText.height + 24; } infoTextContainer.totalHeight = y; } updateInfoPanel(); // --- Scrolling logic for info panel with visual enhancements --- var scrollOffset = 0; var maxScroll = 0; function updateScrollLimits() { maxScroll = Math.max(0, infoTextContainer.totalHeight - infoPanelHeight + 40 + 60); // Add 60px to account for top and bottom margins // Clamp scrollOffset to valid range, no bounce, no tween if (scrollOffset < 0) { scrollOffset = 0; } if (scrollOffset > maxScroll) { scrollOffset = maxScroll; } // Set position directly, no tween infoTextContainer.y = 30 - scrollOffset; } updateScrollLimits(); // Touch/mouse drag to scroll with inertia and visual feedback var isScrolling = false, lastScrollY = 0, scrollVelocity = 0, lastScrollTime = 0, scrollTweenActive = false, scrollTracker = []; infoPanel.interactive = true; infoPanel.down = function (x, y, obj) { isScrolling = true; lastScrollY = y; lastScrollTime = Date.now(); scrollTracker = []; }; infoPanel.move = function (x, y, obj) { if (isScrolling) { var dy = y - lastScrollY; scrollOffset -= dy; updateScrollLimits(); lastScrollY = y; } }; infoPanel.up = function (x, y, obj) { if (isScrolling) { isScrolling = false; // No inertia, no tween, just clamp and update position updateScrollLimits(); } }; // Unified handler for both navigation buttons function createButtonHandler(direction) { return function (x, y, obj) { changeSlime(direction); updateInfoPanel(); updateScrollLimits(); }; } leftButton.down = createButtonHandler('prev'); rightButton.down = createButtonHandler('next'); // When changing slime, update info panel and scroll position function updateSlimeAndInfo() { // Update slime name text first to fix the name display bug var displayName = currentLanguage === 'en' ? slimeNames[currentSlimeIndex] : SlimeInfo[currentSlimeIndex].SlimeNameEs || slimeNames[currentSlimeIndex]; slimeNameText.setText(displayName); // Stop existing tweens before starting new ones to prevent animation conflicts tween.stop(slime); // Enhanced slime transition effects with color flash and particle-like animation tween(slime, { alpha: 0, scaleX: 0.8, scaleY: 0.8, rotation: -0.1 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { // Get the current slime asset name var currentSlimeName = slimes[currentSlimeIndex]; // Remove old slime asset if (slime.slimeAsset) { slime.removeChild(slime.slimeAsset); } // Get new slime asset slime.slimeAsset = slime.attachAsset(currentSlimeName, { anchorX: 0.5, anchorY: 0.5 }); // Apply day/night effect immediately after creating the new slime if (!isDayTime && slime.slimeAsset) { slime.slimeAsset.tint = darkTint; } // Get the size multiplier from SlimeInfo and apply it to the base scale var sizeMultiplier = SlimeInfo[currentSlimeIndex].Size || 1.0; // Apply the consistent scale to maintain proper sizing, adjusted by slime-specific size slime.slimeAsset.scale.set(slime.baseScale * sizeMultiplier); // Reset to base position to prevent drift, but adjust Y position based on size // This ensures all slimes appear to be on the same baseline regardless of size slime.x = slime.baseX; // Calculate Y offset based on size to keep bottom of slime at same level // Larger slimes need to be positioned higher to maintain same baseline var yOffset = (sizeMultiplier - 1.0) * slime.slimeAsset.height * slime.baseScale * 0.5; slime.y = slime.baseY - yOffset; slime.alpha = 0; slime.scaleX = 0.3; slime.scaleY = 0.3; slime.rotation = 0.1; // More dynamic entrance animation tween(slime, { alpha: 1, scaleX: 1, scaleY: 1, rotation: 0 }, { duration: 400, easing: tween.easeOut, onFinish: function onFinish() { tween(slime, { scaleX: 0.8, scaleY: 0.8 }, { duration: 500, easing: tween.elasticOut, onFinish: function onFinish() { // Day/night effect already applied before animation } }); } }); } }); // Update content and scroll position updateInfoPanel(); scrollOffset = 0; updateScrollLimits(); // Fade in info container infoTextContainer.alpha = 0; tween(infoTextContainer, { alpha: 1 }, { duration: 400, easing: tween.easeOut }); } function changeSlime(direction) { currentSlimeIndex = direction === 'next' ? (currentSlimeIndex + 1) % slimes.length : (currentSlimeIndex - 1 + slimes.length) % slimes.length; updateSlimeAndInfo(); // Day/night effect now applied in updateSlimeAndInfo before animation } /* * Asset initialization */ // Add elements to game content container instead of directly to game gameContent.addChild(bgMenu); gameContent.addChild(infoPanel); infoPanel.addChild(infoTextContainer); gameContent.addChild(bg); gameContent.addChild(interfaz); interfaz.addChild(leftButton); interfaz.addChild(rightButton); interfaz.addChild(slimeNameText); interfaz.addChild(sortButton); interfaz.addChild(sortText); interfaz.addChild(languageButton); interfaz.addChild(languageText); gameContent.addChild(slime); gameContent.addChild(musicNameOverlay); // Add the game content container to the game game.addChild(gameContent); // Initialize with ascending order (1->10) as default sort currentSortOrder = 0; SlimeInfo.sort(function (a, b) { return a.Rarity - b.Rarity; }); // Update arrays based on the sorted SlimeInfo slimes = SlimeInfo.map(function (slime) { var slimeName = slime.SlimeName.replace(/\s+/g, ''); return slimeName; }); slimeNames = SlimeInfo.map(function (slime) { return slime.SlimeName; }); rarityValues = SlimeInfo.map(function (slime) { return slime.Rarity; }); // Reset to first slime and update display with proper language currentSlimeIndex = 0; updateSlimeAndInfo(); // Initialize all UI elements with correct language updateLanguageUI(); // Initial day/night check isDayTime = checkDayTime(); applyDayNightEffect(); // Set up timer to check day/night status every minute LK.setInterval(function () { var newIsDayTime = checkDayTime(); if (newIsDayTime !== isDayTime) { isDayTime = newIsDayTime; applyDayNightEffect(); } }, 60000); // Check every minute // Function to apply day/night effect to background and slimes function applyDayNightEffect() { if (isDayTime) { // Day time - normal colors bg.tint = 0xFFFFFF; if (slime && slime.slimeAsset) { slime.slimeAsset.tint = 0xFFFFFF; } } else { // Night time - darken everything bg.tint = darkTint; if (slime && slime.slimeAsset) { slime.slimeAsset.tint = darkTint; } } }
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
persistLanguage: true,
language: "en"
});
/****
* Classes
****/
var MusicNameOverlay = Container.expand(function () {
var self = Container.call(this);
// Text for displaying music name
var musicText = new Text2("", {
size: 110,
fill: 0x000000,
align: "center",
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowDistance: 3,
dropShadowAlpha: 0.5
});
musicText.anchor.set(0.5, 0.5);
musicText.x = 2048 / 2;
musicText.y = 150;
musicText.alpha = 0;
self.addChild(musicText);
// Random fake music names in different languages
var musicNames = {
en: ["Slime Symphony No. 5", "Bouncy Beats", "Gelatinous Groove", "Blob Bop", "Jiggle Jam", "Slimy Sonata", "Elasticity Etude", "Viscous Vibes", "Gooey Grooves", "Jiggly Jazz", "Will anyone read this?"],
es: ["Sinfonía de Slime No. 5", "Ritmos Rebotantes", "Ritmo Gelatinoso", "Bop de Burbuja", "Mermelada Temblorosa", "Sonata Viscosa", "Estudio Elastico", "Vibraciones Viscosas", "Ritmos Pegajosos", "Jazz Tembloroso", "¿Alguien leerá esto?"]
};
// Show a random music name
self.showRandomName = function (language) {
var names = musicNames[language] || musicNames.en;
var randomName = names[Math.floor(Math.random() * names.length)];
// Stop any running animations
tween.stop(musicText);
// Set the text
musicText.setText(randomName);
// Fade in and move up animation sequence
musicText.alpha = 0;
musicText.y = 180;
// First animation: fade in and move to position
tween(musicText, {
alpha: 1,
y: 150
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// Wait a bit then fade out and move up
LK.setTimeout(function () {
tween(musicText, {
alpha: 0,
y: 100
}, {
duration: 1200,
easing: tween.easeIn
});
}, 3000);
}
});
};
return self;
});
var Slime = Container.expand(function () {
var self = Container.call(this);
// Create and attach the slime asset with consistent scaling
// We won't set width/height here because we'll set a consistent scale instead
self.slimeAsset = self.attachAsset('ClasicSlime', {
anchorX: 0.5,
anchorY: 0.5
});
// Set consistent scale factor for all slimes
self.baseScale = 3.5; // Reduced base scaling factor
self.lastX = self.lastY = 0;
self.baseX = 0;
self.baseY = 0;
self.setBasePosition = function (x, y) {
self.baseX = x;
self.baseY = y;
self.x = x;
self.y = y;
};
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
var Star = Container.expand(function () {
var self = Container.call(this);
var starGraphics = self.attachAsset('Star', {
anchorX: 0.5,
anchorY: 0.5,
width: 100,
height: 100
});
self.setColorByRarity = function (rarityLevel) {
// Create a smooth gradient from gray (common) to dark purple (highest rarity)
// Use a gradient color scheme for better visual differentiation
var colors = [0xaaaaaa,
// 1: Gray (Common)
0x8ab4f8,
// 2: Light blue
0x52cca3,
// 3: Teal
0x1e88e5,
// 4: Blue
0x7e57c2,
// 5: Light purple
0xab47bc,
// 6: Purple
0x8e24aa,
// 7: Dark purple
0x6a1b9a,
// 8: Deeper purple
0x4a148c,
// 9: Very dark purple
0x38006b // 10: Darkest purple (Supreme)
];
starGraphics.tint = rarityLevel >= 1 && rarityLevel <= 10 ? colors[rarityLevel - 1] : colors[0];
// Create glow effect with subtle pulsation
self.glowIntensity = 0.2 + rarityLevel / 10;
LK.setTimeout(function () {
tween(starGraphics, {
scaleX: 1 + self.glowIntensity * 0.1,
scaleY: 1 + self.glowIntensity * 0.1
}, {
duration: 1000 + rarityLevel * 100,
easing: tween.easeInOut,
repeat: -1,
yoyo: true
});
}, Math.random() * 500);
};
return self;
});
var StartScreen = Container.expand(function () {
var self = Container.call(this);
// Create background for start screen
var startBg = self.attachAsset('BGInitial', {
anchorX: 0,
anchorY: 0,
width: 2048,
height: 2732
});
// Add title screen image using TittleAsset
var titleImage = self.attachAsset('TittleAsset', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2 - 300,
scaleX: 1.2,
scaleY: 1.2
});
// Title is now included in the TittleAsset
// No tap to start text - removed as requested
// Make the start screen interactive
self.interactive = true;
// When screen is tapped, trigger the transition
self.down = function () {
if (self.onStart) {
// Clear the auto-start timer if it exists
if (autoStartTimer) {
LK.clearTimeout(autoStartTimer);
}
LK.getSound('InterfazSound').play();
// Create a darkening overlay
var darkOverlay = new Container();
var darkRect = LK.getAsset('transition', {
anchorX: 0,
anchorY: 0,
width: 2048,
height: 2732,
alpha: 0
});
darkOverlay.addChild(darkRect);
self.addChild(darkOverlay);
// Start darkening animation
tween(darkRect, {
alpha: 1.0
}, {
duration: 3000,
easing: tween.easeInOut
});
// Add rotation and falling animation to title image
if (titleImage) {
tween(titleImage, {
rotation: 0.2,
y: titleImage.y + 100
}, {
duration: 600,
easing: tween.easeIn,
onFinish: function onFinish() {
// Add pause before falling
LK.setTimeout(function () {
// Accelerate falling
tween(titleImage, {
y: 2732 + 500,
rotation: 0.5
}, {
duration: 1200,
easing: tween.easeIn,
onFinish: function onFinish() {
// Add delay before transitioning to give more time for cube to disappear
LK.setTimeout(function () {
// Call the actual transition
self.onStart();
}, 800);
}
});
}, 1000); // 1 second pause between rotation and falling
}
});
} // Close the if (titleImage) block
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Day/Night detection variables
var isDayTime = true;
var darkTint = 0x404060; // Dark blue-gray tint for night mode
// Function to check if it's day or night
function checkDayTime() {
var now = new Date();
var hours = now.getHours();
// Day is from 6 AM to 6 PM
return hours >= 6 && hours < 18;
}
// Create a container for game content that will appear from center
var gameContent = new Container();
gameContent.y = 0; // Position at normal position
gameContent.alpha = 0; // Start invisible
gameContent.scale.set(0.5); // Start small for zoom effect
// Create BGMenu for bottom half of screen
var bgMenu = LK.getAsset('BGMenu', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 2032 / 2,
width: 2048,
height: 3532 / 2
});
// Create BG for top half of screen
var bg = LK.getAsset('BG', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
width: 2048,
height: 2032 / 2
});
// Create and add start screen
var startScreen = new StartScreen();
game.addChild(startScreen);
// Set up auto-start timer for 10 seconds
var autoStartTimer = LK.setTimeout(function () {
// Only trigger if startScreen still exists and has a parent
if (startScreen && startScreen.parent) {
startScreen.down(); // Simulate tap to start
}
}, 10000);
// Set up the transition function
startScreen.onStart = function () {
// Keep the darkening overlay visible until menu animation completes
// First animate the game content appearing from center
tween(gameContent, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 0,
easing: tween.easeOut,
onFinish: function onFinish() {
// Only after game content is positioned, fade out the start screen
// Add null check before tweening to prevent TypeError
if (startScreen) {
tween(startScreen, {
alpha: 0 // Fade out
}, {
duration: 5000,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Remove start screen when animation completes
if (startScreen && startScreen.parent) {
game.removeChild(startScreen);
startScreen = null;
}
}
});
}
}
});
};
// Create interface element at the top of BGMenu
var interfaz = LK.getAsset('Interfaz', {
anchorX: 0.5,
anchorY: 0,
width: 2048,
height: 400
});
// Create sort button at the top right of interface
var sortButton = LK.getAsset('BotonExtras', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8,
x: 800,
y: -700
});
// Add event handler for sort button
sortButton.interactive = true;
sortButton.down = function () {
// Play interface sound
LK.getSound('InterfazSound').play();
changeSortOrder();
};
// Create sort text to show current sort order
var sortText = new Text2("★↑", {
size: 90,
fill: 0x000000
});
sortText.anchor.set(0.5, 0.5);
sortText.x = sortButton.x;
sortText.y = sortButton.y + 35;
// Position the interface at the top of BGMenu
interfaz.x = bgMenu.width / 2;
interfaz.y = bgMenu.y;
// Create left button
var leftButton = LK.getAsset('BotonChange', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: -1,
// Flip horizontally to point left
x: -800,
y: interfaz.height / 2
});
// Add event handlers for left button
leftButton.interactive = true;
// Create right button
var rightButton = LK.getAsset('BotonChange', {
anchorX: 0.5,
anchorY: 0.5,
x: 800,
y: interfaz.height / 2
});
// Add event handlers for right button
rightButton.interactive = true;
var currentSlimeIndex = 0;
var currentSortOrder = 0; // 0: Ascending by rarity, 1: Descending by rarity, 2: A-Z by name, 3: Z-A by name
// Get language from storage with fallback to browser language or English
var currentLanguage = storage.language;
if (!currentLanguage || currentLanguage !== 'en' && currentLanguage !== 'es') {
// Try to detect browser language, defaulting to English if not supported
var browserLang = navigator && navigator.language ? navigator.language.substring(0, 2) : null;
currentLanguage = browserLang === 'es' ? 'es' : 'en';
storage.language = currentLanguage; // Save initial language to storage
}
// Language selector button
var languageButton = LK.getAsset('BotonExtras', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8,
x: 800,
y: -900
});
languageButton.interactive = true;
languageButton.down = function () {
// Play interface sound
LK.getSound('InterfazSound').play();
toggleLanguage();
};
// Language text display
var languageText = new Text2(currentLanguage.toUpperCase(), {
size: 70,
fill: 0x000000
});
languageText.anchor.set(0.5, 0.5);
languageText.x = languageButton.x;
languageText.y = languageButton.y + 35;
// Language translations
var translations = {
en: {
sortLabels: ["★↑", "★↓", "A→Z", "Z→A", "⚖↑", "⚖↓"],
categoryTitles: {
"Rarity": "Rarity",
"Size": "Size",
"History": "History",
"Location": "Location",
"Favorite Food": "Favorite Food",
"Ability": "Ability",
"Stats": "Stats",
"Lifespan": "Lifespan"
},
rarityNames: {
1: "Common",
2: "Uncommon",
3: "Infrequent",
4: "Rare",
5: "Epic",
6: "Exceptional",
7: "Legendary",
8: "Mythic",
9: "Arcane",
10: "Supreme"
},
sizeDescriptions: {
tiny: "Tiny",
small: "Small",
medium: "Medium",
large: "Large",
veryLarge: "Very Large",
enormous: "Enormous"
},
statNames: {
strength: "Strength",
agility: "Agility",
defense: "Defense",
magic: "Magic",
luck: "Luck",
mysticism: "Mysticism"
}
},
es: {
sortLabels: ["★↑", "★↓", "A→Z", "Z→A", "⚖↑", "⚖↓"],
categoryTitles: {
"Rarity": "Rareza",
"Size": "Tamaño",
"History": "Historia",
"Location": "Ubicación",
"Favorite Food": "Comida Favorita",
"Ability": "Habilidad",
"Stats": "Estadísticas",
"Lifespan": "Esperanza de vida"
},
rarityNames: {
1: "Común",
2: "Poco Común",
3: "Infrecuente",
4: "Raro",
5: "Épico",
6: "Excepcional",
7: "Legendario",
8: "Mtico",
9: "Arcano",
10: "Supremo"
},
sizeDescriptions: {
tiny: "Diminuto",
small: "Pequeño",
medium: "Mediano",
large: "Grande",
veryLarge: "Muy Grande",
enormous: "Enorme"
},
statNames: {
strength: "Fuerza",
agility: "Agilidad",
defense: "Defensa",
magic: "Magia",
luck: "Suerte",
mysticism: "Misticismo"
}
}
};
// Function to update all language-dependent UI elements
function updateLanguageUI() {
// Update language display
languageText.setText(currentLanguage.toUpperCase());
// Update sort labels
var sortLabels = translations[currentLanguage].sortLabels;
sortText.setText(sortLabels[currentSortOrder]);
// Update slime name display
var displayName = currentLanguage === 'en' ? slimeNames[currentSlimeIndex] : SlimeInfo[currentSlimeIndex].SlimeNameEs || slimeNames[currentSlimeIndex];
slimeNameText.setText(displayName);
// Update info panel with new language content
updateInfoPanel();
// Update music name overlay if visible
if (musicNameOverlay && musicNameOverlay.parent) {
musicNameOverlay.showRandomName(currentLanguage);
}
}
// Function to toggle between languages
function toggleLanguage() {
currentLanguage = currentLanguage === 'en' ? 'es' : 'en';
// Save language preference to storage
storage.language = currentLanguage;
// Update all UI elements with new language
updateLanguageUI();
}
// Function to sort slimes based on current sort order
function changeSortOrder() {
// Change sort order
currentSortOrder = (currentSortOrder + 1) % 6;
// Update sort text with current language
var sortLabels = translations[currentLanguage].sortLabels;
sortText.setText(sortLabels[currentSortOrder]);
// Sort SlimeInfo based on the selected order
if (currentSortOrder === 0) {
// Sort by rarity (ascending)
SlimeInfo.sort(function (a, b) {
return a.Rarity - b.Rarity;
});
} else if (currentSortOrder === 1) {
// Sort by rarity (descending)
SlimeInfo.sort(function (a, b) {
return b.Rarity - a.Rarity;
});
} else if (currentSortOrder === 2) {
// Sort alphabetically (A to Z)
SlimeInfo.sort(function (a, b) {
return a.SlimeName.localeCompare(b.SlimeName);
});
} else if (currentSortOrder === 3) {
// Sort alphabetically (Z to A)
SlimeInfo.sort(function (a, b) {
return b.SlimeName.localeCompare(a.SlimeName);
});
} else if (currentSortOrder === 4) {
// Sort by size (ascending)
SlimeInfo.sort(function (a, b) {
return (a.Size || 1.0) - (b.Size || 1.0);
});
} else {
// Sort by size (descending)
SlimeInfo.sort(function (a, b) {
return (b.Size || 1.0) - (a.Size || 1.0);
});
}
// Update arrays based on the new sorted SlimeInfo
slimes = SlimeInfo.map(function (slime) {
var slimeName = slime.SlimeName.replace(/\s+/g, '');
return slimeName;
});
slimeNames = SlimeInfo.map(function (slime) {
return slime.SlimeName;
});
rarityValues = SlimeInfo.map(function (slime) {
return slime.Rarity;
});
// Reset to first slime
currentSlimeIndex = 0;
updateSlimeAndInfo();
}
// Function to wrap text that exceeds screen width
function wrapText(text, maxWidth, textSize) {
if (!text) {
return "";
}
var words = text.split(' ');
var wrappedText = '',
line = '';
var charsPerLine = Math.floor(maxWidth / (textSize * 0.5));
for (var i = 0; i < words.length; i++) {
var testLine = line + words[i] + ' ';
if (testLine.length > charsPerLine) {
wrappedText += line.trim() + '\n';
line = words[i] + ' ';
} else {
line = testLine;
}
}
return wrappedText + line.trim();
}
// Create structured slime information
var rarityNamesByValue = {
1: "Common",
2: "Unusual",
3: "Uncommon",
4: "Remarkable",
5: "Rare",
6: "Exceptional",
7: "Mythical",
8: "Legendary",
9: "Ancient",
10: "Divine"
};
// Function to sort slimes by rarity from highest to lowest
function sortSlimesByRarity(slimes) {
return slimes.slice().sort(function (a, b) {
return b.Rarity - a.Rarity; // Sort in descending order (highest to lowest)
});
}
// Structured SlimeInfo array with all properties in a single place
var SlimeInfo = [{
SlimeName: 'Clasic Slime',
SlimeNameEs: 'Slime Clásico',
Rarity: 1,
Size: 1.0,
// Medium size (baseline)
History: 'The most common and friendly of all slimes, Clasic Slimes are believed to be the original form from which all other slimes evolved.',
HistoryEs: 'El más común y amigable de todos los slimes, los Slimes Clásicos son considerados la forma original de la que evolucionaron todos los demás slimes.',
Location: 'Meadows, gardens, and anywhere with fresh dew',
LocationEs: 'Praderas, jardines y cualquier lugar con rocío fresco',
FavoriteFood: 'Fresh grass and morning dew',
FavoriteFoodEs: 'Hierba fresca y rocío de la mañana',
Ability: 'Can split into two smaller slimes when threatened',
AbilityEs: 'Puede dividirse en dos slimes más pequeños cuando se siente amenazado',
Stats: {
strength: 3,
agility: 5,
defense: 2,
magic: 1,
luck: 2,
mysticism: 1
},
Lifespan: '5-8 years',
LifespanEs: '5-8 años'
}, {
SlimeName: 'Snowy Slime',
SlimeNameEs: 'Slime Nevado',
Rarity: 2,
Size: 0.9,
// Slightly smaller
History: 'Snowy Slimes are born from snowdrifts touched by moonlight. They are gentle and love cold climates.',
HistoryEs: 'Los Slimes Nevados nacen de ventisqueros tocados por la luz de la luna. Son gentiles y aman los climas fríos.',
Location: 'Snowfields, icy caves, and mountaintops',
LocationEs: 'Campos nevados, cuevas heladas y cimas de montañas',
FavoriteFood: 'Icicles and frozen berries',
FavoriteFoodEs: 'Carámbanos y bayas congeladas',
Ability: 'Can lower the temperature around them, freezing small puddles instantly',
AbilityEs: 'Puede bajar la temperatura a su alrededor, congelando pequeños charcos instantáneamente',
Stats: {
strength: 3,
agility: 2,
defense: 8,
magic: 6,
luck: 4,
mysticism: 5
},
Lifespan: '12-15 years',
LifespanEs: '12-15 años'
}, {
SlimeName: 'Water Slime',
SlimeNameEs: 'Slime Acuático',
Rarity: 3,
Size: 0.8,
// Small and fluid
History: 'Formed from enchanted raindrops, Water Slimes are playful and quick, often found near rivers.',
HistoryEs: 'Formados a partir de gotas de lluvia encantadas, los Slimes Acuáticos son juguetones y rápidos, a menudo encontrados cerca de ríos.',
Location: 'Lakes, rivers, and rainy forests',
LocationEs: 'Lagos, ríos y bosques lluviosos',
FavoriteFood: 'Pure spring water and water lilies',
FavoriteFoodEs: 'Agua pura de manantial y nenúfares',
Ability: 'Can merge with water to become invisible and move swiftly',
AbilityEs: 'Puede fusionarse con el agua para volverse invisible y moverse rápidamente',
Stats: {
strength: 2,
agility: 7,
defense: 1,
magic: 5,
luck: 4,
mysticism: 3
},
Lifespan: '8-12 years',
LifespanEs: '8-12 años'
}, {
SlimeName: 'Rock Slime',
SlimeNameEs: 'Slime Rocoso',
Rarity: 4,
Size: 1.3,
// Bulky and dense
History: 'Rock Slimes are the result of slimes living near mineral-rich caves, slowly absorbing stone and earth.',
HistoryEs: 'Los Slimes Rocosos son el resultado de slimes que viven cerca de cuevas ricas en minerales, absorbiendo lentamente piedra y tierra.',
Location: 'Caves, rocky hills, and mountain bases',
LocationEs: 'Cuevas, colinas rocosas y bases de montañas',
FavoriteFood: 'Pebbles and mineral-rich soil',
FavoriteFoodEs: 'Guijarros y tierra rica en minerales',
Ability: 'Can harden their bodies to become nearly unbreakable for short periods',
AbilityEs: 'Puede endurecer su cuerpo para volverse casi irrompible por cortos períodos',
Stats: {
strength: 8,
agility: 1,
defense: 9,
magic: 2,
luck: 3,
mysticism: 1
},
Lifespan: '20-30 years',
LifespanEs: '20-30 años'
}, {
SlimeName: 'Fire Slime',
SlimeNameEs: 'Slime de Fuego',
Rarity: 5,
Size: 1.1,
// Slightly larger due to heat expansion
History: 'Fire Slimes are born from the embers of ancient volcanoes, carrying a spark of elemental fire within.',
HistoryEs: 'Los Slimes de Fuego nacen de las brasas de antiguos volcanes, llevando una chispa de fuego elemental en su interior.',
Location: 'Volcanoes, hot springs, and scorched plains',
LocationEs: 'Volcanes, aguas termales y llanuras calcinadas',
FavoriteFood: 'Charcoal and spicy peppers',
FavoriteFoodEs: 'Carbón y pimientos picantes',
Ability: 'Can ignite themselves to ward off predators and light dark places',
AbilityEs: 'Puede encenderse para ahuyentar a los depredadores e iluminar lugares oscuros',
Stats: {
strength: 6,
agility: 3,
defense: 4,
magic: 7,
luck: 2,
mysticism: 6
},
Lifespan: '10-15 years'
}, {
SlimeName: 'Shadow Slime',
SlimeNameEs: 'Slime de Sombra',
Rarity: 6,
Size: 1.2,
// Larger and imposing
History: 'Shadow Slimes are born in places untouched by light, absorbing the darkness around them.',
HistoryEs: 'Los Slimes de Sombra nacen en lugares donde la luz nunca llega, absorbiendo la oscuridad a su alrededor.',
Location: 'Caverns, abandoned ruins, and deep forests at night',
LocationEs: 'Cavernas, ruinas abandonadas y bosques profundos durante la noche',
FavoriteFood: 'Shadows and nocturnal insects',
FavoriteFoodEs: 'Sombras e insectos nocturnos',
Ability: 'Can blend into shadows and become nearly invisible',
AbilityEs: 'Puede fundirse con las sombras y volverse casi invisible',
Stats: {
strength: 5,
agility: 8,
defense: 3,
magic: 9,
luck: 6,
mysticism: 8
},
Lifespan: '30-40 years',
LifespanEs: '30-40 años'
}, {
SlimeName: 'Forest Slime',
SlimeNameEs: 'Slime de Bosque',
Rarity: 7,
Size: 1.15,
// Healthy and lush
History: 'Forest Slimes are the guardians of ancient woods, formed from moss and enchanted leaves.',
HistoryEs: 'Los Slimes de Bosque son guardianes de los bosques antiguos, formados de musgo y hojas encantadas.',
Location: 'Dense forests, groves, and magical thickets',
LocationEs: 'Bosques densos, arboledas y matorrales mágicos',
FavoriteFood: 'Moss, leaves, and wildflowers',
FavoriteFoodEs: 'Musgo, hojas y flores silvestres',
Ability: 'Can heal plants and accelerate their growth',
AbilityEs: 'Puede curar plantas y acelerar su crecimiento',
Stats: {
strength: 4,
agility: 6,
defense: 5,
magic: 8,
luck: 5,
mysticism: 7
},
Lifespan: '25-35 years',
LifespanEs: '25-35 años'
}, {
SlimeName: 'Beast Slime',
SlimeNameEs: 'Slime Bestia',
Rarity: 8,
Size: 1.4,
// Large and intimidating
History: 'Beast Slimes are fierce and wild, believed to have evolved by mimicking the strongest animals in their environment.',
HistoryEs: 'Los Slimes Bestia son feroces y salvajes, se cree que evolucionaron imitando a los animales más fuertes de su entorno.',
Location: 'Savannahs, jungles, and wild plains',
LocationEs: 'Sabanas, selvas y llanuras salvajes',
FavoriteFood: 'Raw meat and wild fruits',
FavoriteFoodEs: 'Carne cruda y frutas silvestres',
Ability: 'Can roar to intimidate foes and temporarily boost their own strength',
AbilityEs: 'Puede rugir para intimidar enemigos y aumentar temporalmente su fuerza',
Stats: {
strength: 9,
agility: 7,
defense: 7,
magic: 3,
luck: 8,
mysticism: 2
},
Lifespan: '18-25 years',
LifespanEs: '18-25 años'
}, {
SlimeName: 'Lucky Slime',
SlimeNameEs: 'Slime de la Suerte',
Rarity: 8,
Size: 0.95,
// Medium-small for good luck
History: 'Lucky Slimes are said to be born during rare celestial events, bringing fortune to those who find them.',
HistoryEs: 'Se dice que los Slimes de la Suerte nacen durante eventos celestiales raros, trayendo fortuna a quienes los encuentran.',
Location: 'Rainbow fields, clover patches, and near waterfalls',
LocationEs: 'Campos de arcoíris, parches de tréboles y cerca de cascadas',
FavoriteFood: 'Four-leaf clovers and golden apples',
FavoriteFoodEs: 'Tréboles de cuatro hojas y manzanas doradas',
Ability: 'Can increase the luck of nearby creatures and find hidden treasures',
AbilityEs: 'Puede aumentar la suerte de criaturas cercanas y encontrar tesoros ocultos',
Stats: {
strength: 3,
agility: 5,
defense: 2,
magic: 6,
luck: 10,
mysticism: 4
},
Lifespan: '10-20 years',
LifespanEs: '10-20 años'
}, {
SlimeName: 'Runic Slime',
SlimeNameEs: 'Slime Rúnico',
Rarity: 9,
Size: 1.25,
// Large with ornate runes
History: 'Runic Slimes are ancient beings, their bodies inscribed with glowing runes of power.',
HistoryEs: 'Los Slimes Rúnicos son seres antiguos, sus cuerpos están inscritos con runas brillantes de poder.',
Location: 'Ancient temples, rune circles, and magical libraries',
LocationEs: 'Templos antiguos, círculos de runas y bibliotecas mágicas',
FavoriteFood: 'Enchanted stones and magical scrolls',
FavoriteFoodEs: 'Piedras encantadas y pergaminos mágicos',
Ability: 'Can cast simple spells and decipher ancient languages',
AbilityEs: 'Puede lanzar hechizos simples y descifrar lenguas antiguas',
Stats: {
strength: 5,
agility: 4,
defense: 3,
magic: 9,
luck: 7,
mysticism: 10
},
Lifespan: '50-100 years',
LifespanEs: '50-100 años'
}, {
SlimeName: 'Divine Slime',
SlimeNameEs: 'Slime Divino',
Rarity: 10,
Size: 1.5,
// Majestic and grand
History: 'Divine Slimes are legendary, said to descend from the heavens during times of great need.',
HistoryEs: 'Los Slimes Divinos son legendarios, se dice que descienden de los cielos en tiempos de gran necesidad.',
Location: 'Sacred groves, mountaintops, and places of worship',
LocationEs: 'Arboledas sagradas, cimas de montañas y lugares de culto',
FavoriteFood: 'Nectar from sacred flowers and pure spring water',
FavoriteFoodEs: 'Néctar de flores sagradas y agua de manantial pura',
Ability: 'Can heal wounds and purify water with a touch',
AbilityEs: 'Puede curar heridas y purificar agua con solo tocarla',
Stats: {
strength: 7,
agility: 4,
defense: 6,
magic: 10,
luck: 10,
mysticism: 9
},
Lifespan: 'Unknown, possibly eternal',
LifespanEs: 'Desconocida, posiblemente eterna'
}, {
SlimeName: 'Fruit Slime',
SlimeNameEs: 'Slime Fruta',
Rarity: 5,
Size: 1.05,
// Plump and juicy
History: 'Born from the essence of vibrant orchards, Fruit Slimes emerged when magical runoff seeped into ancient fruit groves.',
HistoryEs: 'Nacidos de la esencia de huertos vibrantes, los Slimes Fruta surgieron cuando la magia se filtró en antiguos huertos de frutas.',
Location: 'Orchards, fruit markets, and gardens with sweet-smelling blossoms',
LocationEs: 'Huertos, mercados de frutas y jardines con flores fragantes',
FavoriteFood: 'Overripe fruits and berry preserves',
FavoriteFoodEs: 'Frutas demasiado maduras y conservas de bayas',
Ability: 'Can change color based on the last fruit consumed, and releases a sweet aroma that calms nearby creatures',
AbilityEs: 'Puede cambiar de color según la última fruta consumida y libera un aroma dulce que calma a las criaturas cercanas',
Stats: {
strength: 4,
agility: 6,
defense: 3,
magic: 7,
luck: 6,
mysticism: 5
},
Lifespan: '15-20 years, longer if fed a varied diet of exotic fruits',
LifespanEs: '15-20 años, más si se alimenta con una dieta variada de frutas exóticas'
}, {
SlimeName: 'Ghost Slime',
SlimeNameEs: 'Slime Fantasma',
Rarity: 7,
Size: 1.1,
// Ethereal and wispy
History: 'Ghost Slimes formed when regular slimes wandered into haunted areas and absorbed spectral essence, gaining ethereal properties.',
HistoryEs: 'Los Slimes Fantasma se formaron cuando slimes comunes vagaron por zonas embrujadas y absorbieron esencia espectral, obteniendo propiedades etéreas.',
Location: 'Abandoned buildings, ancient ruins, and places with strong spiritual energy',
LocationEs: 'Edificios abandonados, ruinas antiguas y lugares con fuerte energía espiritual',
FavoriteFood: 'Emotions, particularly nostalgia and melancholy',
FavoriteFoodEs: 'Emociones, especialmente nostalgia y melancolía',
Ability: 'Can phase through solid objects and temporarily become invisible when threatened',
AbilityEs: 'Puede atravesar objetos sólidos y volverse invisible temporalmente cuando se siente amenazado',
Stats: {
strength: 2,
agility: 7,
defense: 3,
magic: 9,
luck: 6,
mysticism: 8
},
Lifespan: 'Potentially immortal, though they can fade away if they lose their spectral essence',
LifespanEs: 'Potencialmente inmortal, aunque pueden desvanecerse si pierden su esencia espectral'
}, {
SlimeName: 'King Slime',
SlimeNameEs: 'Rey Slime',
Rarity: 9,
Size: 1.6,
// Royal and massive
History: 'The legendary King Slime is said to be born once a century when a slime absorbs royal essence from an ancient crown.',
HistoryEs: 'Se dice que el legendario Rey Slime nace una vez cada siglo cuando un slime absorbe la esencia real de una corona antigua.',
Location: 'Hidden chambers in royal castles and within the deepest parts of enchanted forests',
LocationEs: 'Cámaras ocultas en castillos reales y en las partes más profundas de bosques encantados',
FavoriteFood: 'Precious metals and gems, particularly gold and rubies',
FavoriteFoodEs: 'Metales preciosos y gemas, especialmente oro y rubíes',
Ability: 'Can command lesser slimes and temporarily grow to massive size, becoming nearly invulnerable',
AbilityEs: 'Puede comandar slimes menores y crecer temporalmente a un tamaño masivo, volviéndose casi invulnerable',
Stats: {
strength: 8,
agility: 4,
defense: 8,
magic: 7,
luck: 7,
mysticism: 9
},
Lifespan: 'Over 200 years, with some specimens reported to live for millennia',
LifespanEs: 'Más de 200 años, con algunos ejemplares reportados viviendo milenios'
}, {
SlimeName: 'Golden Slime',
SlimeNameEs: 'Slime Dorado',
Rarity: 10,
Size: 1.35,
// Substantial and solid
History: 'Golden Slimes are incredibly rare mutations that occur when a slime is exposed to concentrated alchemical gold for generations.',
HistoryEs: 'Los Slimes Dorados son mutaciones increíblemente raras que ocurren cuando un slime es expuesto a oro alquímico concentrado durante generaciones.',
Location: 'Ancient treasure vaults, alchemist laboratories, and the hearts of mountains rich with gold deposits',
LocationEs: 'Antiguas bóvedas de tesoros, laboratorios de alquimistas y el corazón de montañas ricas en oro',
FavoriteFood: 'Gold dust and magical essences',
FavoriteFoodEs: 'Polvo de oro y esencias mágicas',
Ability: 'Turns objects it consumes partially to gold and can detect precious metals at great distances',
AbilityEs: 'Convierte parcialmente en oro los objetos que consume y puede detectar metales preciosos a grandes distancias',
Stats: {
strength: 6,
agility: 3,
defense: 9,
magic: 8,
luck: 10,
mysticism: 8
},
Lifespan: 'Virtually immortal as long as they consume small amounts of gold regularly',
LifespanEs: 'Prácticamente inmortal mientras consuma pequeñas cantidades de oro regularmente'
}];
// Sort SlimeInfo by rarity (highest to lowest)
SlimeInfo = sortSlimesByRarity(SlimeInfo);
// Update slimes array based on the new sorted SlimeInfo
slimes = SlimeInfo.map(function (slime, index) {
// Get the appropriate slime asset name based on the SlimeName
var slimeName = slime.SlimeName.replace(/\s+/g, '');
return slimeName;
});
// Extract arrays for backward compatibility and easier access
var slimeNames = SlimeInfo.map(function (slime) {
return slime.SlimeName;
});
// Array for Spanish slime names
var slimeNamesEs = SlimeInfo.map(function (slime) {
return slime.SlimeNameEs || slime.SlimeName;
});
var rarityValues = SlimeInfo.map(function (slime) {
return slime.Rarity;
});
var histories = SlimeInfo.map(function (slime) {
return slime.History;
});
var locations = SlimeInfo.map(function (slime) {
return slime.Location;
});
var favoriteFoods = SlimeInfo.map(function (slime) {
return slime.FavoriteFood;
});
var abilities = SlimeInfo.map(function (slime) {
return slime.Ability;
});
var stats = SlimeInfo.map(function (slime) {
return slime.Stats;
});
var lifespans = SlimeInfo.map(function (slime) {
return slime.Lifespan;
});
// Create text display for slime name
var slimeNameText = new Text2(slimeNames[currentSlimeIndex], {
size: 100,
fill: 0xFFFFFF
});
slimeNameText.anchor.set(0.5, 0.5);
slimeNameText.x = 0;
slimeNameText.y = interfaz.height / 2;
// Create a slime and add it to the scene
var slime = new Slime();
// Position slime at the center of BG but lower down and set base position
var centerX = bg.width / 2;
var centerY = bg.height / 2 + 220; // Lower position
slime.setBasePosition(centerX, centerY);
// Set initial properties for animations
slime.alpha = 1;
slime.scaleX = 1;
slime.scaleY = 1;
// Music array for random background music selection
var musicTracks = ['BGSong', 'BGSong2', 'BGSong3', 'BGSong4', 'BGSong5'];
var currentMusicIndex = -1;
// Music name overlay to display song names
var musicNameOverlay = new MusicNameOverlay();
// Function to play a random music track
function playRandomMusic() {
var newIndex;
// Make sure we don't play the same track twice in a row
do {
newIndex = Math.floor(Math.random() * musicTracks.length);
} while (newIndex === currentMusicIndex && musicTracks.length > 1);
currentMusicIndex = newIndex;
LK.playMusic(musicTracks[currentMusicIndex]);
// Show random music name with current language
// Make a safe call to ensure language is correctly set
if (musicNameOverlay) {
musicNameOverlay.showRandomName(currentLanguage);
}
}
// Play initial random music
playRandomMusic();
// Set up music change timer (1:40 minutes = 100,000 milliseconds)
LK.setInterval(playRandomMusic, 100000);
// --- Info Panel for BGMenu ---
var infoPanelHeight = bgMenu.height - interfaz.height - 40;
var infoPanelWidth = bgMenu.width;
var infoPanelY = bgMenu.y + interfaz.height + 20;
var infoPanelX = bgMenu.x + (bgMenu.width - infoPanelWidth) / 2; // Center horizontally
// Create a container for the info panel
var infoPanel = new Container();
infoPanel.x = infoPanelX;
infoPanel.y = infoPanelY;
// No background for the info panel
// Prepare info categories and data
var infoCategories = [{
title: "Rarity",
get: function get(i) {
var rarityValue = SlimeInfo[i].Rarity;
this.currentRarityValue = rarityValue;
// Return translated rarity name
return translations[currentLanguage].rarityNames[rarityValue];
}
}, {
title: "Size",
get: function get(i) {
var sizeValue = SlimeInfo[i].Size || 1.0;
var sizeKey;
if (sizeValue <= 0.8) {
sizeKey = "tiny";
} else if (sizeValue <= 0.95) {
sizeKey = "small";
} else if (sizeValue <= 1.1) {
sizeKey = "medium";
} else if (sizeValue <= 1.3) {
sizeKey = "large";
} else if (sizeValue <= 1.5) {
sizeKey = "veryLarge";
} else {
sizeKey = "enormous";
}
var sizeDescription = translations[currentLanguage].sizeDescriptions[sizeKey];
return sizeDescription + " (" + sizeValue.toFixed(2) + "x scale)";
}
}, {
title: "History",
get: function get(i) {
return currentLanguage === 'en' ? SlimeInfo[i].History : SlimeInfo[i].HistoryEs || SlimeInfo[i].History;
}
}, {
title: "Location",
get: function get(i) {
return currentLanguage === 'en' ? SlimeInfo[i].Location : SlimeInfo[i].LocationEs || SlimeInfo[i].Location;
}
}, {
title: "Favorite Food",
get: function get(i) {
return currentLanguage === 'en' ? SlimeInfo[i].FavoriteFood : SlimeInfo[i].FavoriteFoodEs || SlimeInfo[i].FavoriteFood;
}
}, {
title: "Ability",
get: function get(i) {
return currentLanguage === 'en' ? SlimeInfo[i].Ability : SlimeInfo[i].AbilityEs || SlimeInfo[i].Ability;
}
}, {
title: "Stats",
get: function get(i) {
var s = SlimeInfo[i].Stats;
// Create visual stat bars with colored values using actual colors instead of tags
function formatStat(name, value) {
var barChars = "■".repeat(value);
var emptyChars = "□".repeat(10 - value);
// Translate stat name based on current language
var translatedName = translations[currentLanguage].statNames[name.toLowerCase()] || name;
return translatedName + ": " + value + " [" + barChars + emptyChars + "]";
}
// Create a single column with all 6 stats
var statText = "";
statText += formatStat("strength", s.strength) + "\n";
statText += formatStat("agility", s.agility) + "\n";
statText += formatStat("defense", s.defense) + "\n";
statText += formatStat("magic", s.magic) + "\n";
statText += formatStat("luck", s.luck) + "\n";
statText += formatStat("mysticism", s.mysticism);
return statText;
}
}, {
title: "Lifespan",
get: function get(i) {
return currentLanguage === 'en' ? SlimeInfo[i].Lifespan : SlimeInfo[i].LifespanEs || SlimeInfo[i].Lifespan;
}
}];
// Create a container for the scrollable text
var infoTextContainer = new Container();
infoTextContainer.x = 30;
infoTextContainer.y = 30; // Add top margin
// Function to update info text for current slime
function updateInfoPanel() {
// Remove old children
infoTextContainer.removeChildren();
var y = 0;
for (var c = 0; c < infoCategories.length; c++) {
// Add extra spacing between sections if not the first section
if (c > 0) {
y += 80; // Add extra spacing between sections
}
// Title with gradient effect based on category
var titleColors = {
"Rarity": 0xFFD700,
"History": 0xCF9FFF,
"Location": 0x98FB98,
"Favorite Food": 0xFF7F50,
"Ability": 0x00BFFF,
"Stats": 0xFF1493,
"Lifespan": 0x00FA9A
};
var titleColor = titleColors[infoCategories[c].title] || 0xFFF7B2;
// Get translated title
var translatedTitle = translations[currentLanguage].categoryTitles[infoCategories[c].title] || infoCategories[c].title;
var titleText = new Text2(translatedTitle, {
size: 110,
fill: titleColor,
font: "GillSans-Bold",
align: "center",
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowDistance: 3,
dropShadowAlpha: 0.5
});
titleText.anchor.set(0.5, 0);
titleText.x = infoPanelWidth / 2 - 30;
titleText.y = y;
infoTextContainer.addChild(titleText);
y += titleText.height + 6;
// Info - wrap text to fit screen width
var infoContent = infoCategories[c].get(currentSlimeIndex);
var wrappedText = infoContent;
// Only apply text wrapping if not the stats category (which already has formatting)
if (infoCategories[c].title !== "Stats") {
wrappedText = wrapText(infoContent, infoPanelWidth - 60, 85); // Wrap text with some padding
}
// Choose text color based on category
var textColors = {
"Rarity": 0xFFFACD,
"History": 0xE6E6FA,
"Location": 0xF0FFF0,
"Favorite Food": 0xFFE4E1,
"Ability": 0xE0FFFF,
"Stats": 0xFFE4E1,
"Lifespan": 0xF0FFFF
};
var textColor = textColors[infoCategories[c].title] || 0xFFFFFF;
var infoText = new Text2(wrappedText, {
size: 85,
fill: textColor,
font: "GillSans",
align: infoCategories[c].title === "Stats" ? "left" : "center",
dropShadow: true,
dropShadowColor: 0x333333,
dropShadowDistance: 2,
dropShadowAlpha: 0.3
});
// Set anchor based on content type
if (infoCategories[c].title === "Stats") {
infoText.anchor.set(0.5, 0); // Center align stats too
infoText.x = infoPanelWidth / 2 - 30;
} else {
infoText.anchor.set(0.5, 0); // Center align for other content
infoText.x = infoPanelWidth / 2 - 30;
}
infoText.y = y + 20;
infoTextContainer.addChild(infoText);
// If this is the rarity category, add colored stars
if (infoCategories[c].title === "Rarity" && infoCategories[c].currentRarityValue) {
var starContainer = new Container();
starContainer.x = infoPanelWidth / 2 - 30;
starContainer.y = y + infoText.height + 40;
var rarityValue = infoCategories[c].currentRarityValue;
var starSpacing = 110,
totalWidth = (rarityValue - 1) * starSpacing;
var startX = -totalWidth / 2;
for (var s = 0; s < rarityValue; s++) {
var star = new Star();
star.x = startX + s * starSpacing;
star.y = 20;
star.alpha = 0;
star.scale.x = star.scale.y = 0.5;
star.setColorByRarity(rarityValue);
starContainer.addChild(star);
(function (targetStar, delay) {
LK.setTimeout(function () {
tween(targetStar, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 400,
easing: tween.easeOut
});
}, delay);
})(star, s * 200);
}
infoTextContainer.addChild(starContainer);
y += 80;
}
y += infoText.height + 24;
}
infoTextContainer.totalHeight = y;
}
updateInfoPanel();
// --- Scrolling logic for info panel with visual enhancements ---
var scrollOffset = 0;
var maxScroll = 0;
function updateScrollLimits() {
maxScroll = Math.max(0, infoTextContainer.totalHeight - infoPanelHeight + 40 + 60); // Add 60px to account for top and bottom margins
// Clamp scrollOffset to valid range, no bounce, no tween
if (scrollOffset < 0) {
scrollOffset = 0;
}
if (scrollOffset > maxScroll) {
scrollOffset = maxScroll;
}
// Set position directly, no tween
infoTextContainer.y = 30 - scrollOffset;
}
updateScrollLimits();
// Touch/mouse drag to scroll with inertia and visual feedback
var isScrolling = false,
lastScrollY = 0,
scrollVelocity = 0,
lastScrollTime = 0,
scrollTweenActive = false,
scrollTracker = [];
infoPanel.interactive = true;
infoPanel.down = function (x, y, obj) {
isScrolling = true;
lastScrollY = y;
lastScrollTime = Date.now();
scrollTracker = [];
};
infoPanel.move = function (x, y, obj) {
if (isScrolling) {
var dy = y - lastScrollY;
scrollOffset -= dy;
updateScrollLimits();
lastScrollY = y;
}
};
infoPanel.up = function (x, y, obj) {
if (isScrolling) {
isScrolling = false;
// No inertia, no tween, just clamp and update position
updateScrollLimits();
}
};
// Unified handler for both navigation buttons
function createButtonHandler(direction) {
return function (x, y, obj) {
changeSlime(direction);
updateInfoPanel();
updateScrollLimits();
};
}
leftButton.down = createButtonHandler('prev');
rightButton.down = createButtonHandler('next');
// When changing slime, update info panel and scroll position
function updateSlimeAndInfo() {
// Update slime name text first to fix the name display bug
var displayName = currentLanguage === 'en' ? slimeNames[currentSlimeIndex] : SlimeInfo[currentSlimeIndex].SlimeNameEs || slimeNames[currentSlimeIndex];
slimeNameText.setText(displayName);
// Stop existing tweens before starting new ones to prevent animation conflicts
tween.stop(slime);
// Enhanced slime transition effects with color flash and particle-like animation
tween(slime, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8,
rotation: -0.1
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
// Get the current slime asset name
var currentSlimeName = slimes[currentSlimeIndex];
// Remove old slime asset
if (slime.slimeAsset) {
slime.removeChild(slime.slimeAsset);
}
// Get new slime asset
slime.slimeAsset = slime.attachAsset(currentSlimeName, {
anchorX: 0.5,
anchorY: 0.5
});
// Apply day/night effect immediately after creating the new slime
if (!isDayTime && slime.slimeAsset) {
slime.slimeAsset.tint = darkTint;
}
// Get the size multiplier from SlimeInfo and apply it to the base scale
var sizeMultiplier = SlimeInfo[currentSlimeIndex].Size || 1.0;
// Apply the consistent scale to maintain proper sizing, adjusted by slime-specific size
slime.slimeAsset.scale.set(slime.baseScale * sizeMultiplier);
// Reset to base position to prevent drift, but adjust Y position based on size
// This ensures all slimes appear to be on the same baseline regardless of size
slime.x = slime.baseX;
// Calculate Y offset based on size to keep bottom of slime at same level
// Larger slimes need to be positioned higher to maintain same baseline
var yOffset = (sizeMultiplier - 1.0) * slime.slimeAsset.height * slime.baseScale * 0.5;
slime.y = slime.baseY - yOffset;
slime.alpha = 0;
slime.scaleX = 0.3;
slime.scaleY = 0.3;
slime.rotation = 0.1;
// More dynamic entrance animation
tween(slime, {
alpha: 1,
scaleX: 1,
scaleY: 1,
rotation: 0
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(slime, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 500,
easing: tween.elasticOut,
onFinish: function onFinish() {
// Day/night effect already applied before animation
}
});
}
});
}
});
// Update content and scroll position
updateInfoPanel();
scrollOffset = 0;
updateScrollLimits();
// Fade in info container
infoTextContainer.alpha = 0;
tween(infoTextContainer, {
alpha: 1
}, {
duration: 400,
easing: tween.easeOut
});
}
function changeSlime(direction) {
currentSlimeIndex = direction === 'next' ? (currentSlimeIndex + 1) % slimes.length : (currentSlimeIndex - 1 + slimes.length) % slimes.length;
updateSlimeAndInfo();
// Day/night effect now applied in updateSlimeAndInfo before animation
}
/*
* Asset initialization
*/
// Add elements to game content container instead of directly to game
gameContent.addChild(bgMenu);
gameContent.addChild(infoPanel);
infoPanel.addChild(infoTextContainer);
gameContent.addChild(bg);
gameContent.addChild(interfaz);
interfaz.addChild(leftButton);
interfaz.addChild(rightButton);
interfaz.addChild(slimeNameText);
interfaz.addChild(sortButton);
interfaz.addChild(sortText);
interfaz.addChild(languageButton);
interfaz.addChild(languageText);
gameContent.addChild(slime);
gameContent.addChild(musicNameOverlay);
// Add the game content container to the game
game.addChild(gameContent);
// Initialize with ascending order (1->10) as default sort
currentSortOrder = 0;
SlimeInfo.sort(function (a, b) {
return a.Rarity - b.Rarity;
});
// Update arrays based on the sorted SlimeInfo
slimes = SlimeInfo.map(function (slime) {
var slimeName = slime.SlimeName.replace(/\s+/g, '');
return slimeName;
});
slimeNames = SlimeInfo.map(function (slime) {
return slime.SlimeName;
});
rarityValues = SlimeInfo.map(function (slime) {
return slime.Rarity;
});
// Reset to first slime and update display with proper language
currentSlimeIndex = 0;
updateSlimeAndInfo();
// Initialize all UI elements with correct language
updateLanguageUI();
// Initial day/night check
isDayTime = checkDayTime();
applyDayNightEffect();
// Set up timer to check day/night status every minute
LK.setInterval(function () {
var newIsDayTime = checkDayTime();
if (newIsDayTime !== isDayTime) {
isDayTime = newIsDayTime;
applyDayNightEffect();
}
}, 60000); // Check every minute
// Function to apply day/night effect to background and slimes
function applyDayNightEffect() {
if (isDayTime) {
// Day time - normal colors
bg.tint = 0xFFFFFF;
if (slime && slime.slimeAsset) {
slime.slimeAsset.tint = 0xFFFFFF;
}
} else {
// Night time - darken everything
bg.tint = darkTint;
if (slime && slime.slimeAsset) {
slime.slimeAsset.tint = darkTint;
}
}
}
Star cartoon. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Un slime verde RPG con estilo suave y simple. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Un slime rojo prendido fuego RPG con estilo suave y simple. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Un slime RPG amarillo y divino con estilo suave y simple. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Un slime fantasmal RPG con estilo suave y simple. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Un slime blanco con una moneda brillante en la frente RPG con estilo suave y simple. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Un slime gris RPG con rocas en su espalda. Estilo suave y simple. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Un slime RPG nevado con estilo suave y simple. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Un slime de agua RPG con estilo suave y simple. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Un slime bestia peludo RPG con estilo suave y simple. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Un slime morado con runas magicas RPG. Estilo suave y simple. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Un slime angelical RPG con estilo suave y simple. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Fullscreen medieval landscape banner, 16:9, high definition, for a game titled "Slime Bestiary". Medieval forest with multiple colored slimes. No text on banner!