User prompt
erase the cubix info ai on middile of the screen with image in catching action there has to be just 1 info of cubix
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 2407
User prompt
in catching action top middle of screen UI add a which cubix gives a chance and remove the cubix info on middle of the screen
User prompt
remove in catching action in middile of cubix info UI becuse at this action there is 2 UI and on top middle of screen is good
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 2366
User prompt
in collection menu i cannot see UI for what have i cubixion
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 2377
User prompt
make one UI in catching action for cubix
User prompt
when i no cubix make increse spawnig rate for basic cubix
User prompt
in catching action u are showing the cubix UI and add a selection on top of screen cause that remove the other UI
User prompt
make basic UI for catching actions to cubix just type of image type of name and type of image and how many they are and write it to the top middle of screen and remove the cubixion UI on this action
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 2302
User prompt
make basic UI for catching actions to cubixion just type of image type of name and type of image and how many they are and write it to the top middle of screen
User prompt
ın cubixion menu show me the cubixion dont show cubixes but in bag menu show cubix
User prompt
in catching action change the cubix UI for good looking to read info
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'self.cubixButtonNameLabels[j].style.fill = self.cubixButtons[j].rarity === type.rarity ? 0xFFD700 : type.color;' Line Number: 1967
User prompt
Please fix the bug: 'TypeError: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'self.cubixButtonNameLabels[j].style.fill = j === firstAvailableIdx ? 0xFFD700 : cubixTypes[j].color;' Line Number: 2089
User prompt
Please fix the bug: 'TypeError: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'self.cubixButtonNameLabels[i].style.fill = i === firstAvailableIdx ? 0xFFD700 : cType.color;' Line Number: 2042
User prompt
i cant see what i caught cubixion fix it make sure to show them on collection menu
User prompt
fix it when i caught a cubixion add to the collection menu and when i used for catching minus that cubix type and show them bag and catching action and i should select the which type of cubix
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 2145
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 2145
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 2145
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 2145
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 2145
/**** * Plugins ****/ var storage = LK.import("@upit/storage.v1", { discoveredCreatures: {}, playerPosition: { x: 10, y: 10 }, unlockedAreas: { starter: true } }); var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Collection class to manage discovered creatures var Collection = Container.expand(function () { var self = Container.call(this); // Collection components self.visible = false; self.background = null; self.scrollContainer = null; self.closeButton = null; // Initialize collection screen self.init = function () { // Create darkened background self.background = self.attachAsset('grassTile', { anchorX: 0, anchorY: 0, width: 2048, height: 2732 }); self.background.alpha = 0.9; self.background.tint = 0x000000; // Create scroll container for creatures and bag self.scrollContainer = new Container(); self.addChild(self.scrollContainer); self.scrollContainer.x = 50; self.scrollContainer.y = 320; // Move down to make space for bag section // Create scrollable Bag section container with mask self.bagScrollContainer = new Container(); self.bagMaskContainer = new Container(); self.addChild(self.bagMaskContainer); self.bagMaskContainer.x = 50; self.bagMaskContainer.y = 200; self.bagMaskContainer.addChild(self.bagScrollContainer); // Create a mask for the scrollable area var bagMask = LK.getAsset('grassTile', { anchorX: 0, anchorY: 0, width: 2048 - 100, height: 1000 }); bagMask.alpha = 0.0; // Invisible mask self.bagMaskContainer.addChild(bagMask); self.bagScrollContainer.mask = bagMask; // Create a background for the bag area var bagBackground = LK.getAsset('grassTile', { anchorX: 0, anchorY: 0, width: 2048 - 100, height: 1000 }); bagBackground.alpha = 0.3; bagBackground.tint = 0x000088; self.bagMaskContainer.addChild(bagBackground); self.bagMaskContainer.setChildIndex(bagBackground, 0); // Add Bag button to open Bag section self.bagButton = self.attachAsset('dpadButton', { anchorX: 0.5, anchorY: 0.5, // Move to right bottom x: 2048 - 200, y: 2732 - 200, scaleX: 1.5, scaleY: 1.5 }); self.bagButton.interactive = true; self.bagBtnText = new Text2('BAG', { size: 60, fill: 0xFFD700 }); self.bagBtnText.anchor.set(0.5, 0.5); // Move to right bottom self.bagBtnText.x = 2048 - 200; self.bagBtnText.y = 2732 - 200; self.addChild(self.bagButton); self.addChild(self.bagBtnText); // Add bag section title self.bagTitleText = new Text2('MY BAG', { size: 70, fill: 0xFFD700 }); self.bagTitleText.anchor.set(0.5, 0); self.bagTitleText.x = 1024; self.bagTitleText.y = 220; self.addChild(self.bagTitleText); self.bagTitleText.visible = true; // Scrolling variables self.bagScrollingActive = false; self.bagScrollStartY = 0; self.bagScrollStartPos = 0; self.bagMaxScroll = 0; // Add scroll indicators self.scrollUpIndicator = new Text2('▲', { size: 60, fill: 0xFFFFFF }); self.scrollUpIndicator.anchor.set(0.5, 0); self.scrollUpIndicator.x = 1024; self.scrollUpIndicator.y = 260; self.scrollUpIndicator.alpha = 0.7; self.addChild(self.scrollUpIndicator); self.scrollDownIndicator = new Text2('▼', { size: 60, fill: 0xFFFFFF }); self.scrollDownIndicator.anchor.set(0.5, 1); self.scrollDownIndicator.x = 1024; self.scrollDownIndicator.y = 1180; self.scrollDownIndicator.alpha = 0.7; self.addChild(self.scrollDownIndicator); // Bag section is visible by default, but you can toggle it with the button if desired self.bagButton.down = function () { // Toggle bagMaskContainer visibility self.bagMaskContainer.visible = !self.bagMaskContainer.visible; self.bagTitleText.visible = self.bagMaskContainer.visible; self.scrollUpIndicator.visible = self.bagMaskContainer.visible; self.scrollDownIndicator.visible = self.bagMaskContainer.visible; // Change title depending on bagContainer visibility if (self.bagMaskContainer.visible && self.titleText) { self.titleText.setText('THE BAG'); // Hide bag button when bag is visible self.bagButton.visible = false; if (self.bagBtnText) { self.bagBtnText.visible = false; } // Create/show Cubixion menu button when in bag view if (!self.cubixionMenuButton) { self.cubixionMenuButton = self.attachAsset('dpadButton', { anchorX: 0.5, anchorY: 0.5, x: 2048 - 200, y: 2732 - 200, scaleX: 1.5, scaleY: 1.5 }); self.cubixionMenuButton.interactive = true; self.cubixionMenuBtnText = new Text2('CUBIXION MENU', { size: 60, fill: 0xFFD700 }); self.cubixionMenuBtnText.anchor.set(0.5, 0.5); self.cubixionMenuBtnText.x = 2048 - 200; self.cubixionMenuBtnText.y = 2732 - 200; self.addChild(self.cubixionMenuButton); self.addChild(self.cubixionMenuBtnText); self.cubixionMenuButton.down = function () { // Hide bag view self.bagMaskContainer.visible = false; self.bagTitleText.visible = false; self.scrollUpIndicator.visible = false; self.scrollDownIndicator.visible = false; // Hide Cubixion menu button self.cubixionMenuButton.visible = false; self.cubixionMenuBtnText.visible = false; // Show bag button again self.bagButton.visible = true; if (self.bagBtnText) { self.bagBtnText.visible = true; } // Change title back to collection menu if (self.titleText) { self.titleText.setText('CUBIXION MENU'); } // Hide back button and collection button if they exist if (self.backToCollectionButton) { self.backToCollectionButton.visible = false; if (self.backToCollectionButton.backBtnText) { self.backToCollectionButton.backBtnText.visible = false; } } if (self.collectionButton) { self.collectionButton.visible = false; if (self.collectionButton.colBtnText) { self.collectionButton.colBtnText.visible = false; } } }; } self.cubixionMenuButton.visible = true; self.cubixionMenuBtnText.visible = true; } else if (self.titleText) { self.titleText.setText('CUBIXION MENU'); // Show bag button when bag is not visible self.bagButton.visible = true; if (self.bagBtnText) { self.bagBtnText.visible = true; } // Hide Cubixion menu button if it exists if (self.cubixionMenuButton) { self.cubixionMenuButton.visible = false; self.cubixionMenuBtnText.visible = false; } } // If showing bag, populate it with items if (self.bagMaskContainer.visible) { self.populateBagItems(); // Make sure back button is visible when bag is visible if (self.backToCollectionButton) { self.backToCollectionButton.visible = true; if (self.backToCollectionButton.backBtnText) { self.backToCollectionButton.backBtnText.visible = true; } } } }; // Function to populate bag with items self.populateBagItems = function () { // Remove previous cubixion images from bagScrollContainer for (var i = self.bagScrollContainer.children.length - 1; i >= 0; i--) { var child = self.bagScrollContainer.children[i]; if (child && child.isCubixionBagImage) { self.bagScrollContainer.removeChild(child); } } // Reset scroll position self.bagScrollContainer.y = 0; // Show a summary of how many cubix of each rarity the player has in the bag section, with their image on the left var cubixRarities = ['basic', 'uncommon', 'rare', 'legendary']; var cubixNames = { basic: 'Basic Cubix', uncommon: 'Uncommon Cubix', rare: 'Rare Cubix', legendary: 'Legendary Cubix' }; var cubixColors = { basic: 0xffffff, uncommon: 0x00ff00, rare: 0x0000ff, legendary: 0xffd700 }; var itemHeight = 200; // Increased height for each item var padding = 40; // Padding between items var totalHeight = 0; var containerWidth = 1900; // Width of the container // Add title for each section var headerText = new Text2('CUBIX BAG', { size: 70, fill: 0xFFFFFF }); headerText.anchor.set(0.5, 0); headerText.x = containerWidth / 2; headerText.y = 20; headerText.isCubixionBagImage = true; self.bagScrollContainer.addChild(headerText); totalHeight = 120; // Starting height after header // Store references to cubix count Text2 for live updating if (!self._cubixCountTexts) self._cubixCountTexts = {}; for (var i = 0; i < cubixRarities.length; i++) { var rarity = cubixRarities[i]; // Always access the latest playerCubix from global or storage for UI accuracy if (typeof window !== "undefined" && typeof window.playerCubix !== "undefined") { playerCubix = window.playerCubix; } if (typeof storage !== "undefined" && typeof storage.playerCubix !== "undefined") { playerCubix = storage.playerCubix; } if (typeof syncPlayerCubix === "function") { syncPlayerCubix(); } // Defensive: always show all rarities, even if 0 var count = playerCubix && typeof playerCubix[rarity] === "number" ? playerCubix[rarity] : 0; // Create a container for this item row for better organization var itemContainer = new Container(); itemContainer.y = totalHeight; itemContainer.isCubixionBagImage = true; self.bagScrollContainer.addChild(itemContainer); // Add background for this item var itemBg = LK.getAsset('grassTile', { anchorX: 0, anchorY: 0, width: containerWidth, height: itemHeight }); itemBg.alpha = 0.2; itemBg.tint = cubixColors[rarity]; itemContainer.addChild(itemBg); // Always show all rarities, even if 0 var cubixImg = LK.getAsset('cubix_' + rarity, { anchorX: 0.5, anchorY: 0.5, x: 150, y: itemHeight / 2, scaleX: 2.5, // Bigger image (increased from 2.0 to 2.5) scaleY: 2.5 // Bigger image (increased from 2.0 to 2.5) }); itemContainer.addChild(cubixImg); var cubixName = new Text2(cubixNames[rarity], { size: 80, // Bigger text (increased from 70 to 80) fill: cubixColors[rarity] }); cubixName.anchor.set(0, 0.5); cubixName.x = 300; cubixName.y = itemHeight / 2 - 30; itemContainer.addChild(cubixName); var cubixDescription = new Text2('Used for capturing creatures', { size: 55, // Bigger text (increased from 45 to 55) fill: 0xCCCCCC }); cubixDescription.anchor.set(0, 0.5); cubixDescription.x = 300; cubixDescription.y = itemHeight / 2 + 30; itemContainer.addChild(cubixDescription); // Make sure to display the correct count from playerCubix var countText = new Text2('x' + count, { size: 100, // Bigger text (increased from 90 to 100) fill: 0xFFFFFF }); countText.anchor.set(1, 0.5); countText.x = containerWidth - 80; countText.y = itemHeight / 2; itemContainer.addChild(countText); // Store reference for live updating self._cubixCountTexts[rarity] = countText; // Add a select button for this cubix type (for catching) var selectBtn = LK.getAsset('dpadButton', { anchorX: 0.5, anchorY: 0.5, x: containerWidth - 300, y: itemHeight / 2, scaleX: 1.2, scaleY: 1.2 }); selectBtn.interactive = true; itemContainer.addChild(selectBtn); var selectText = new Text2('SELECT', { size: 40, fill: 0xFFD700 }); selectText.anchor.set(0.5, 0.5); selectText.x = containerWidth - 300; selectText.y = itemHeight / 2; itemContainer.addChild(selectText); (function (rarity) { selectBtn.down = function () { // Set selected cubix type for catching if (typeof encounter !== "undefined" && encounter.active) { encounter.selectedCubix = rarity; // Optionally, show a message or highlight var msg = new Text2('Selected ' + cubixNames[rarity] + ' for catching!', { size: 40, fill: cubixColors[rarity] }); msg.anchor.set(0.5, 0.5); msg.x = 1024; msg.y = 400; game.addChild(msg); LK.setTimeout(function () { game.removeChild(msg); }, 800); } }; })(rarity); totalHeight += itemHeight + padding; } // Add a live update function for cubix counts if (!self._cubixBagLiveUpdateAdded) { self._cubixBagLiveUpdateAdded = true; // Add to game.update for live updating var oldGameUpdate = typeof game.update === "function" ? game.update : null; game.update = function () { // Live update cubix counts in bag if bag is visible if (self.bagMaskContainer && self.bagMaskContainer.visible && self._cubixCountTexts) { // Always get latest playerCubix from global or storage if (typeof window !== "undefined" && typeof window.playerCubix !== "undefined") { playerCubix = window.playerCubix; } if (typeof storage !== "undefined" && typeof storage.playerCubix !== "undefined") { playerCubix = storage.playerCubix; } if (typeof syncPlayerCubix === "function") { syncPlayerCubix(); } for (var i = 0; i < cubixRarities.length; i++) { var rarity = cubixRarities[i]; if (self._cubixCountTexts[rarity]) { var newCount = playerCubix[rarity] || 0; var txt = self._cubixCountTexts[rarity]; if (txt.text !== 'x' + newCount) { txt.setText('x' + newCount); } } } } if (oldGameUpdate) oldGameUpdate(); }; } // Add a section for other potential items (empty for now, but prepared for future items) if (totalHeight > 0) { var otherItemsHeader = new Text2('OTHER ITEMS', { size: 50, fill: 0xFFFFFF }); otherItemsHeader.anchor.set(0.5, 0); otherItemsHeader.x = containerWidth / 2; otherItemsHeader.y = totalHeight; otherItemsHeader.isCubixionBagImage = true; self.bagScrollContainer.addChild(otherItemsHeader); totalHeight += 80; // Add placeholder message for future items var placeholderText = new Text2('No other items in your bag yet', { size: 36, fill: 0xAAAAAA }); placeholderText.anchor.set(0.5, 0); placeholderText.x = containerWidth / 2; placeholderText.y = totalHeight; placeholderText.isCubixionBagImage = true; self.bagScrollContainer.addChild(placeholderText); totalHeight += 100; } // Set the max scroll value based on content height self.bagMaxScroll = Math.max(0, totalHeight - 900); // 900 is approximate visible area height // Update scroll indicators visibility self.updateScrollIndicators(); // Add scroll functionality self.bagMaskContainer.interactive = true; // Remove any existing listeners to prevent duplicates if (self.bagMaskContainer.down) { self.bagMaskContainer.down = null; } if (self.bagMaskContainer.up) { self.bagMaskContainer.up = null; } if (self.bagMaskContainer.move) { self.bagMaskContainer.move = null; } self.bagMaskContainer.down = function (x, y, obj) { self.bagScrollingActive = true; self.bagScrollStartY = y; self.bagScrollStartPos = self.bagScrollContainer.y; }; self.bagMaskContainer.move = function (x, y, obj) { if (self.bagScrollingActive) { var delta = y - self.bagScrollStartY; var newY = self.bagScrollStartPos + delta; // Clamp scrolling if (newY > 0) newY = 0; if (newY < -self.bagMaxScroll) newY = -self.bagMaxScroll; self.bagScrollContainer.y = newY; self.updateScrollIndicators(); } }; self.bagMaskContainer.up = function () { self.bagScrollingActive = false; // Only one spawn near player per update if (Math.abs(self.bagScrollContainer.y - self.bagScrollStartPos) > 5) { var velocity = (self.bagScrollContainer.y - self.bagScrollStartPos) * 0.3; var targetY = self.bagScrollContainer.y + velocity; // Clamp target if (targetY > 0) targetY = 0; if (targetY < -self.bagMaxScroll) targetY = -self.bagMaxScroll; // Animate to target position tween(self.bagScrollContainer, { y: targetY }, { duration: 300, easing: tween.easeOut, onUpdate: function onUpdate() { self.updateScrollIndicators(); } }); } // Add back button if not already added if (!self.backToCollectionButton) { self.backToCollectionButton = self.attachAsset('dpadButton', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1180, scaleX: 1.5, scaleY: 1.5 }); self.backToCollectionButton.interactive = true; var backBtnText = new Text2('BACK TO COLLECTION', { size: 50, fill: 0xFFD700 }); backBtnText.anchor.set(0.5, 0.5); backBtnText.x = 1024; backBtnText.y = 1180; self.addChild(self.backToCollectionButton); self.addChild(backBtnText); self.backToCollectionButton.backBtnText = backBtnText; self.backToCollectionButton.down = function () { // Toggle bag visibility off and show collection menu self.bagMaskContainer.visible = false; self.bagTitleText.visible = false; self.scrollUpIndicator.visible = false; self.scrollDownIndicator.visible = false; self.backToCollectionButton.visible = false; self.backToCollectionButton.backBtnText.visible = false; // Change title back to collection menu if (self.titleText) { self.titleText.setText('CUBIXION MENU'); } // Show bag button again self.bagButton.visible = true; if (self.bagBtnText) { self.bagBtnText.visible = true; } // Hide Cubixion menu button if it exists if (self.cubixionMenuButton) { self.cubixionMenuButton.visible = false; self.cubixionMenuBtnText.visible = false; } // Also hide collection button if it exists if (self.collectionButton) { self.collectionButton.visible = false; if (self.collectionButton.colBtnText) { self.collectionButton.colBtnText.visible = false; } } }; } // Make sure the back button is visible when the bag is visible if (self.backToCollectionButton) { self.backToCollectionButton.visible = self.bagMaskContainer.visible; if (self.backToCollectionButton.backBtnText) { self.backToCollectionButton.backBtnText.visible = self.bagMaskContainer.visible; } } // Make sure the back button is visible when the bag is visible if (self.backToCollectionButton) { self.backToCollectionButton.visible = self.bagMaskContainer.visible; if (self.backToCollectionButton.backBtnText) { self.backToCollectionButton.backBtnText.visible = self.bagMaskContainer.visible; } } // Add Collection button to left bottom corner in bag menu if (!self.collectionButton) { self.collectionButton = self.attachAsset('dpadButton', { anchorX: 0.5, anchorY: 0.5, x: 200, y: 1180, scaleX: 1.5, scaleY: 1.5 }); self.collectionButton.interactive = true; var colBtnText = new Text2('COLLECTION', { size: 50, fill: 0xFFD700 }); colBtnText.anchor.set(0.5, 0.5); colBtnText.x = 200; colBtnText.y = 1180; self.addChild(self.collectionButton); self.addChild(colBtnText); self.collectionButton.colBtnText = colBtnText; self.collectionButton.down = function () { // Same function as backToCollectionButton - toggle bag visibility off and show collection menu self.bagMaskContainer.visible = false; self.bagTitleText.visible = false; self.scrollUpIndicator.visible = false; self.scrollDownIndicator.visible = false; self.backToCollectionButton.visible = false; self.backToCollectionButton.backBtnText.visible = false; self.collectionButton.visible = false; self.collectionButton.colBtnText.visible = false; // Change title back to collection menu if (self.titleText) { self.titleText.setText('CUBIX MENU'); } }; } // Make collection button visible when bag is visible if (self.collectionButton) { self.collectionButton.visible = self.bagMaskContainer.visible; if (self.collectionButton.colBtnText) { self.collectionButton.colBtnText.visible = self.bagMaskContainer.visible; } } // Add Collection button to left bottom corner in bag menu if (!self.collectionButton) { self.collectionButton = self.attachAsset('dpadButton', { anchorX: 0.5, anchorY: 0.5, x: 200, y: 1180, scaleX: 1.5, scaleY: 1.5 }); self.collectionButton.interactive = true; var colBtnText = new Text2('COLLECTION', { size: 50, fill: 0xFFD700 }); colBtnText.anchor.set(0.5, 0.5); colBtnText.x = 200; colBtnText.y = 1180; self.addChild(self.collectionButton); self.addChild(colBtnText); self.collectionButton.colBtnText = colBtnText; self.collectionButton.down = function () { // Same function as backToCollectionButton - toggle bag visibility off and show collection menu self.bagMaskContainer.visible = false; self.bagTitleText.visible = false; self.scrollUpIndicator.visible = false; self.scrollDownIndicator.visible = false; self.backToCollectionButton.visible = false; self.backToCollectionButton.backBtnText.visible = false; self.collectionButton.visible = false; self.collectionButton.colBtnText.visible = false; // Change title back to collection menu if (self.titleText) { self.titleText.setText('CUBIXION MENU'); } // Show bag button again self.bagButton.visible = true; if (self.bagBtnText) { self.bagBtnText.visible = true; } // Hide Cubixion menu button if it exists if (self.cubixionMenuButton) { self.cubixionMenuButton.visible = false; self.cubixionMenuBtnText.visible = false; } }; } // Make collection button visible when bag is visible if (self.collectionButton) { self.collectionButton.visible = self.bagMaskContainer.visible; if (self.collectionButton.colBtnText) { self.collectionButton.colBtnText.visible = self.bagMaskContainer.visible; } } }; }; // Update scroll indicators based on current scroll position self.updateScrollIndicators = function () { if (self.bagMaxScroll <= 0) { // No need for indicators if content fits self.scrollUpIndicator.visible = false; self.scrollDownIndicator.visible = false; return; } // Show up indicator only if scrolled down self.scrollUpIndicator.visible = self.bagMaskContainer.visible && self.bagScrollContainer.y < 0; // Show down indicator only if can scroll further down self.scrollDownIndicator.visible = self.bagMaskContainer.visible && self.bagScrollContainer.y > -self.bagMaxScroll; // Fade indicators based on scroll position self.scrollUpIndicator.alpha = Math.min(1, Math.abs(self.bagScrollContainer.y) / 100); self.scrollDownIndicator.alpha = Math.min(1, (self.bagMaxScroll + self.bagScrollContainer.y) / 100); }; // Example: Add a placeholder for "other items" in the bag // You can add more items here as needed var bagItemY = 70; // Remove potion and revive from the bag playerBagItems = []; // No items to display in the bag // Add title self.titleText = new Text2('CUBIXION MENU', { size: 80, fill: 0xFFFFFF }); self.titleText.anchor.set(0.5, 0); self.titleText.x = 1024; self.titleText.y = 50; self.addChild(self.titleText); // Show owned Cubixion with image, rarity, and element // Remove previous Cubixion display if present if (self.cubixionDisplay && self.cubixionDisplay.length) { for (var i = 0; i < self.cubixionDisplay.length; i++) { self.removeChild(self.cubixionDisplay[i]); } } self.cubixionDisplay = []; // --- Show caught Cubixion in collection menu with image and info --- // Defensive: get playerCubixionCollection from storage or window if not present if (typeof playerCubixionCollection === "undefined" && typeof storage !== "undefined" && typeof storage.playerCubixionCollection !== "undefined") { playerCubixionCollection = storage.playerCubixionCollection; } if (typeof playerCubixionCollection === "undefined" && typeof window !== "undefined" && typeof window.playerCubixionCollection !== "undefined") { playerCubixionCollection = window.playerCubixionCollection; } if (typeof playerCubixionCollection === "undefined") playerCubixionCollection = {}; // Build ownedCubixion array from playerCubixionCollection var ownedCubixion = []; for (var key in playerCubixionCollection) { if (playerCubixionCollection.hasOwnProperty(key) && playerCubixionCollection[key].count > 0) { // Try to find matching cubixType for bag cubix var cType = null; for (var j = 0; j < cubixTypes.length; j++) { if (cubixTypes[j].rarity === key) { cType = cubixTypes[j]; break; } } // Try to find matching creature for creature cubixion if (!cType && typeof Creature !== "undefined" && Creature.prototype && Creature.prototype.creatureList) { for (var j = 0; j < Creature.prototype.creatureList.length; j++) { if (String(Creature.prototype.creatureList[j].id) === String(key)) { cType = { id: Creature.prototype.creatureList[j].id, name: Creature.prototype.creatureList[j].name, type: Creature.prototype.creatureList[j].type, image: Creature.prototype.creatureList[j].image, rarity: 'common', color: 0xffffff }; break; } } } if (cType) { ownedCubixion.push({ type: cType, count: playerCubixionCollection[key].count }); } } } // Sort by element (type) alphabetically ownedCubixion.sort(function (a, b) { if (!a.type.type) return -1; if (!b.type.type) return 1; if (a.type.type < b.type.type) return -1; if (a.type.type > b.type.type) return 1; return 0; }); var cubixionStartX = 400; var cubixionStartY = 140; var cubixionSpacing = 320; for (var i = 0; i < ownedCubixion.length; i++) { var cType = ownedCubixion[i].type; var count = ownedCubixion[i].count; // Cubixion image var cubixionImg = LK.getAsset(cType.image ? cType.image : 'cubix_' + (cType && typeof cType.rarity !== "undefined" ? cType.rarity : "basic"), { anchorX: 0.5, anchorY: 0.5, x: cubixionStartX + i * cubixionSpacing, y: cubixionStartY + 80, scaleX: 0.7, scaleY: 0.7 }); self.addChild(cubixionImg); self.cubixionDisplay.push(cubixionImg); // Cubixion name var cubixionName = new Text2(cType.name ? cType.name.replace(' Cubix', 'ion') : cType.rarity ? cType.rarity.charAt(0).toUpperCase() + cType.rarity.slice(1) + " Cubixion" : "Cubixion", { size: 38, fill: cType.color || 0xffffff }); cubixionName.anchor.set(0.5, 0); cubixionName.x = cubixionStartX + i * cubixionSpacing; cubixionName.y = cubixionStartY + 160; self.addChild(cubixionName); self.cubixionDisplay.push(cubixionName); // Cubixion rarity var rarityText = new Text2('Rarity: ' + (cType.rarity ? cType.rarity.toUpperCase() : "-"), { size: 32, fill: 0xFFD700 }); rarityText.anchor.set(0.5, 0); rarityText.x = cubixionStartX + i * cubixionSpacing; rarityText.y = cubixionStartY + 210; self.addChild(rarityText); self.cubixionDisplay.push(rarityText); // Cubixion element (type) var elementText = new Text2('Element: ' + (cType.type ? cType.type.toUpperCase() : '-'), { size: 32, fill: 0xFFFFFF }); elementText.anchor.set(0.5, 0); elementText.x = cubixionStartX + i * cubixionSpacing; elementText.y = cubixionStartY + 250; self.addChild(elementText); self.cubixionDisplay.push(elementText); // Cubixion count var countText = new Text2('x' + count, { size: 36, fill: 0xFFFFFF }); countText.anchor.set(0.5, 0); countText.x = cubixionStartX + i * cubixionSpacing; countText.y = cubixionStartY + 290; self.addChild(countText); self.cubixionDisplay.push(countText); } // Create close button self.closeButton = self.attachAsset('dpadButton', { anchorX: 0.5, anchorY: 0.5, x: 1900, y: 100 }); self.closeButton.interactive = true; // Add X to close button var closeText = new Text2('X', { size: 60, fill: 0xFFFFFF }); closeText.anchor.set(0.5, 0.5); closeText.x = 1900; closeText.y = 100; self.addChild(closeText); // Hide initially self.visible = false; return self; }; // Show collection screen and populate with discovered creatures self.show = function () { self.visible = true; // Make sure the bag container is initialized but hidden initially if (self.bagMaskContainer) { self.bagMaskContainer.visible = false; self.bagTitleText.visible = false; self.scrollUpIndicator.visible = false; self.scrollDownIndicator.visible = false; // Initialize bag items on first show self.populateBagItems(); // Make sure back button is properly hidden if (self.backToCollectionButton) { self.backToCollectionButton.visible = false; if (self.backToCollectionButton.backBtnText) { self.backToCollectionButton.backBtnText.visible = false; } } } // Remove any collection menu under the cross (close) button if present for (var i = self.children.length - 1; i >= 0; i--) { var child = self.children[i]; // Remove any Text2 or Container that is at or near the close button position (1900, 100) if ((child instanceof Text2 || typeof child.x === "number" && typeof child.y === "number") && Math.abs(child.x - 1900) < 80 && Math.abs(child.y - 100) < 80 && child !== self.closeButton) { self.removeChild(child); } } // Clear existing creatures while (self.scrollContainer.children.length > 0) { self.scrollContainer.removeChild(self.scrollContainer.children[0]); } // Get discovered creatures from storage var discoveredCreatures = storage.discoveredCreatures || {}; var creatureCount = Object.keys(discoveredCreatures).length; // Calculate total Cubixion count var totalCubixion = 0; var ownedCubixion = []; if (typeof window !== "undefined" && typeof window.playerCubix !== "undefined") { playerCubix = window.playerCubix; } if (typeof storage !== "undefined" && typeof storage.playerCubix !== "undefined") { playerCubix = storage.playerCubix; } if (typeof syncPlayerCubix === "function") { syncPlayerCubix(); } // --- Fix: Show caught Cubixion in collection menu with image --- // Use playerCubixionCollection to show all caught Cubixion if (typeof playerCubixionCollection === "undefined" && typeof storage !== "undefined" && typeof storage.playerCubixionCollection !== "undefined") { playerCubixionCollection = storage.playerCubixionCollection; } if (typeof playerCubixionCollection === "undefined" && typeof window !== "undefined" && typeof window.playerCubixionCollection !== "undefined") { playerCubixionCollection = window.playerCubixionCollection; } if (typeof playerCubixionCollection === "undefined") playerCubixionCollection = {}; // Defensive: always sync to storage and window if (typeof storage !== "undefined" && typeof storage.set === "function") { storage.set("playerCubixionCollection", playerCubixionCollection); } else if (typeof storage !== "undefined") { try { storage.playerCubixionCollection = playerCubixionCollection; } catch (e) { // Fallback: do nothing if assignment fails } } if (typeof window !== "undefined") window.playerCubixionCollection = playerCubixionCollection; // Build ownedCubixion from playerCubixionCollection ownedCubixion = []; totalCubixion = 0; // Add Cubixion from creatures if (typeof Creature !== "undefined" && Creature.prototype && Creature.prototype.creatureList) { for (var i = 0; i < Creature.prototype.creatureList.length; i++) { var c = Creature.prototype.creatureList[i]; if (playerCubixionCollection[c.id] && playerCubixionCollection[c.id].count > 0) { ownedCubixion.push({ type: { id: c.id, name: c.name, type: c.type, image: c.image, rarity: 'common', color: 0xffffff // Optionally set color, or use a color map by type }, count: playerCubixionCollection[c.id].count }); totalCubixion += playerCubixionCollection[c.id].count; } } } // Add Cubixion from cubix types (bag) as well for (var i = 0; i < cubixTypes.length; i++) { var cType = cubixTypes[i]; var cubixionId = cType.rarity; var count = 0; if (playerCubixionCollection[cubixionId] && typeof playerCubixionCollection[cubixionId].count === "number") { count = playerCubixionCollection[cubixionId].count; } else if (playerCubix && typeof playerCubix[cType.rarity] === "number") { count = playerCubix[cType.rarity]; } if (count > 0) { ownedCubixion.push({ type: cType, count: count }); totalCubixion += count; } } // If none found, fallback to old logic (by cubixTypes) if (ownedCubixion.length === 0) { for (var i = 0; i < cubixTypes.length; i++) { var cType = cubixTypes[i]; var count = playerCubix[cType.rarity] || 0; totalCubixion += count; if (count > 0) { ownedCubixion.push({ type: cType, count: count }); } } } // Show Cubixion count at the top of collection menu var cubixionCountText = new Text2('Cubixion: ' + totalCubixion, { size: 50, fill: 0xFFFFFF }); cubixionCountText.anchor.set(0.5, 0); cubixionCountText.x = 1024; cubixionCountText.y = 150; self.addChild(cubixionCountText); // Remove previous Cubixion image display if present if (self.cubixionImageDisplay && Array.isArray(self.cubixionImageDisplay) && self.cubixionImageDisplay.length) { for (var i = 0; i < self.cubixionImageDisplay.length; i++) { self.removeChild(self.cubixionImageDisplay[i]); } } self.cubixionImageDisplay = []; // Show Cubixion as images in a row var imgStartX = 400; var imgY = 220; var imgSpacing = 320; for (var i = 0; i < ownedCubixion.length; i++) { var cType = ownedCubixion[i].type; var count = ownedCubixion[i].count; var cubixionImg = LK.getAsset('cubix_' + (cType && typeof cType.rarity !== "undefined" ? cType.rarity : "basic"), { anchorX: 0.5, anchorY: 0.5, x: imgStartX + i * imgSpacing, y: imgY + 80, scaleX: 0.7, scaleY: 0.7 }); self.addChild(cubixionImg); self.cubixionImageDisplay.push(cubixionImg); // Cubixion name var cubixionName = new Text2(cType.name.replace(' Cubix', 'ion'), { size: 38, fill: cType.color }); cubixionName.anchor.set(0.5, 0); cubixionName.x = imgStartX + i * imgSpacing; cubixionName.y = imgY + 160; self.addChild(cubixionName); self.cubixionImageDisplay.push(cubixionName); // Cubixion count var countText = new Text2('x' + count, { size: 36, fill: 0xFFFFFF }); countText.anchor.set(0.5, 0); countText.x = imgStartX + i * imgSpacing; countText.y = imgY + 210; self.addChild(countText); self.cubixionImageDisplay.push(countText); // Show gems for this cubixion var cid = cType.id !== undefined ? cType.id : cType.creatureId; var creatureIdx = typeof cType.creatureId !== "undefined" ? cType.creatureId : typeof cType.id !== "undefined" ? cType.id : null; var gems = 0; if (creatureIdx !== null && _typeof2(playerCubixionCollection) === "object" && playerCubixionCollection[creatureIdx]) { gems = playerCubixionCollection[creatureIdx].gems || 0; } var gemText = new Text2('Gems: ' + gems, { size: 28, fill: 0xFFD700 }); gemText.anchor.set(0.5, 0); gemText.x = imgStartX + i * imgSpacing; gemText.y = imgY + 250; self.addChild(gemText); self.cubixionImageDisplay.push(gemText); // Add evolve button if possible if (typeof Creature !== "undefined" && Creature.prototype && Creature.prototype.creatureList) { var evoId = null; // Find the creature in the database for (var ci = 0; ci < Creature.prototype.creatureList.length; ci++) { var c = Creature.prototype.creatureList[ci]; if (c.name === cType.name.replace(' Cubix', '') && c.type === cType.type) { evoId = c.evolvesTo; break; } } if (evoId !== null && typeof Creature.prototype.creatureList[evoId] !== "undefined" && gems > 0) { // Show evolve button var evolveBtn = self.attachAsset('dpadButton', { anchorX: 0.5, anchorY: 0.5, x: imgStartX + i * imgSpacing, y: imgY + 320 }); evolveBtn.interactive = true; var evolveText = new Text2('EVOLVE', { size: 28, fill: 0x00FF00 }); evolveText.anchor.set(0.5, 0.5); evolveText.x = imgStartX + i * imgSpacing; evolveText.y = imgY + 320; self.addChild(evolveBtn); self.addChild(evolveText); self.cubixionImageDisplay.push(evolveBtn); self.cubixionImageDisplay.push(evolveText); // Evolve logic: spend 1 gem, unlock evolved form (function (creatureIdx, evoId) { evolveBtn.down = function () { if (playerCubixionCollection[creatureIdx] && playerCubixionCollection[creatureIdx].gems > 0) { playerCubixionCollection[creatureIdx].gems--; // Add evolved form to collection if (!playerCubixionCollection[evoId]) playerCubixionCollection[evoId] = { count: 0, gems: 0 }; playerCubixionCollection[evoId].count++; playerCubixionCollection[evoId].gems++; // Save updated collection to storage if (typeof storage !== "undefined" && typeof storage.set === "function") { storage.set("playerCubixionCollection", playerCubixionCollection); } else { if (typeof storage !== "undefined" && typeof storage.set === "function") { storage.set("playerCubixionCollection", playerCubixionCollection); } else { storage.playerCubixionCollection = playerCubixionCollection; } } // Show message var msg = new Text2('Evolved to ' + Creature.prototype.creatureList[evoId].name + '!', { size: 60, fill: 0x00FF00 }); msg.anchor.set(0.5, 0.5); msg.x = 1024; msg.y = 400; self.addChild(msg); LK.setTimeout(function () { self.removeChild(msg); // Refresh collection menu to show new evolution if (typeof self.show === "function") self.show(); }, 1000); } }; })(creatureIdx, evoId); } } } // Create grid of discovered creatures var gridX = 0; var gridY = 0; // Make collection menu much bigger var itemsPerRow = 7; var cellSize = 480; // Build a list of all possible creatures (by name, not by element type) var allCreatures = []; if (typeof Creature !== "undefined" && Creature.prototype && Creature.prototype.creatureList) { for (var i = 0; i < Creature.prototype.creatureList.length; i++) { var c = Creature.prototype.creatureList[i]; // For each rarity, add a possible entry var allRarities = ['common', 'uncommon', 'rare', 'epic', 'legendary']; for (var r = 0; r < allRarities.length; r++) { allCreatures.push({ name: c.name, type: c.type, image: c.image, rarity: allRarities[r] }); } } } // Sort allCreatures by name (alphabetically) allCreatures.sort(function (a, b) { if (a.name < b.name) return -1; if (a.name > b.name) return 1; return 0; }); var itemsPerRow = 7; var cellSize = 480; for (var idx = 0; idx < allCreatures.length; idx++) { var creature = allCreatures[idx]; var key = creature.type + '-' + creature.rarity; var gridX = idx % itemsPerRow; var gridY = Math.floor(idx / itemsPerRow); var cell = new Container(); cell.x = gridX * cellSize; cell.y = gridY * cellSize; self.scrollContainer.addChild(cell); if (discoveredCreatures[key]) { // Discovered creature var creatureGraphic = LK.getAsset(creature.image, { anchorX: 0.5, anchorY: 0.5, x: cellSize / 2, y: cellSize / 2 - 40 }); // Apply rarity styling var rarityColor = 0xFFFFFF; if (creature.rarity === 'uncommon') rarityColor = 0x00FF00; if (creature.rarity === 'rare') rarityColor = 0x0000FF; if (creature.rarity === 'epic') rarityColor = 0xFF00FF; if (creature.rarity === 'legendary') rarityColor = 0xFFD700; // Make rarer creatures slightly larger var scale = 1.0; if (creature.rarity === 'uncommon') scale = 1.1; if (creature.rarity === 'rare') scale = 1.2; if (creature.rarity === 'epic') scale = 1.3; if (creature.rarity === 'legendary') scale = 1.5; creatureGraphic.scale.set(scale, scale); cell.addChild(creatureGraphic); // Add info text with name, element type, and rarity under each discovered Cubixion var infoText = new Text2(creature.name + '\nElement: ' + creature.type.toUpperCase() + '\nRarity: ' + creature.rarity.toUpperCase(), { size: 40, fill: 0xFFFFFF }); infoText.anchor.set(0.5, 0); infoText.x = cellSize / 2; infoText.y = cellSize / 2 + 60; cell.addChild(infoText); } else { // Undiscovered creature (shadow) var undiscoveredGraphic = LK.getAsset(creature.type + 'Cubixion', { anchorX: 0.5, anchorY: 0.5, x: cellSize / 2, y: cellSize / 2 }); undiscoveredGraphic.alpha = 0.2; undiscoveredGraphic.tint = 0x000000; cell.addChild(undiscoveredGraphic); // Add question mark var questionText = new Text2('?', { size: 80, fill: 0x999999 }); questionText.anchor.set(0.5, 0.5); questionText.x = cellSize / 2; questionText.y = cellSize / 2; cell.addChild(questionText); } } // --- Fluent drag-to-scroll logic for scrollContainer --- self.scrollContainer.interactive = true; self.scrollContainer.hitArea = new Rectangle(0, 0, itemsPerRow * cellSize, (gridY + 1) * cellSize); var isDragging = false; var dragStartY = 0; var dragStartScrollY = 0; var minY = 0; var maxY = Math.max(0, (gridY + 1) * cellSize - 1800); // 1800px is approx. visible area // For momentum/fluent scroll var lastMoveTime = 0; var lastMoveY = 0; var velocityY = 0; var momentumTimer = null; self.scrollContainer.down = function (x, y, obj) { isDragging = true; dragStartY = y; dragStartScrollY = self.scrollContainer.y; lastMoveTime = Date.now(); lastMoveY = y; velocityY = 0; if (momentumTimer) { LK.clearInterval(momentumTimer); momentumTimer = null; } // Prevent accidental selection of creatures while dragging if (obj && obj.event && obj.event.stopPropagation) obj.event.stopPropagation(); }; self.scrollContainer.move = function (x, y, obj) { if (isDragging) { var now = Date.now(); var newY = dragStartScrollY + (y - dragStartY); // Clamp scroll if (newY > 200) newY = 200; if (newY < -maxY) newY = -maxY; self.scrollContainer.y = newY; // Calculate velocity for momentum var dt = now - lastMoveTime; if (dt > 0) { velocityY = (y - lastMoveY) / dt; lastMoveTime = now; lastMoveY = y; } } }; self.scrollContainer.up = function (x, y, obj) { isDragging = false; // Start momentum scroll if velocity is significant if (Math.abs(velocityY) > 0.1) { var decay = 0.95; momentumTimer = LK.setInterval(function () { self.scrollContainer.y += velocityY * 30; // Clamp scroll if (self.scrollContainer.y > 200) self.scrollContainer.y = 200; if (self.scrollContainer.y < -maxY) self.scrollContainer.y = -maxY; velocityY *= decay; if (Math.abs(velocityY) < 0.05) { LK.clearInterval(momentumTimer); momentumTimer = null; } }, 16); } }; }; // Hide collection screen self.hide = function () { self.visible = false; // Make sure to hide bag containers too if (self.bagMaskContainer) { self.bagMaskContainer.visible = false; } if (self.bagTitleText) { self.bagTitleText.visible = false; } if (self.scrollUpIndicator) { self.scrollUpIndicator.visible = false; } if (self.scrollDownIndicator) { self.scrollDownIndicator.visible = false; } }; return self; }); // Creature class for encounters var Creature = Container.expand(function () { var self = Container.call(this); // --- Creature Database: 100 unique creatures with names, images, and evolutions --- self.creatureList = [ // Example: {id: 0, name: "Sproutle", type: "grass", image: "grassCreature", evolvesTo: 1} // ... 100 creatures, each with unique name, type, image, and evolution chain ]; // Generate 100 unique creatures with types, images, and names (function () { var types = ['bug', 'dark', 'dragon', 'electric', 'fairy', 'fighting', 'fire', 'flying', 'ghost', 'grass', 'ground', 'ice', 'normal', 'poison', 'psychic', 'rock', 'steel', 'water']; var baseNames = ["Sproutle", "Aquapup", "Pyrokit", "Stonox", "Zephyro", "Lumina", "Frosty", "Venoma", "Spectra", "Boulder", "Voltix", "Mystwing", "Shadeon", "Petalyn", "Scorcher", "Chillfin", "Ironclad", "Pebblit", "Gustlet", "Dewdrop", "Emberly", "Thornet", "Mossy", "Duskleaf", "Blazetail", "Crystowl", "Sableye", "Toxifin", "Glimmer", "Rubble", "Cinderpaw", "Leaflet", "Mudkip", "Glacier", "Fanglet", "Wispurr", "Bramble", "Sparky", "Tidelet", "Cobalite", "Garnet", "Quartz", "Onyx", "Topaz", "Opal", "Jade", "Amber", "Ruby", "Sapphire", "Emerald", "Coral", "Shellby", "Ripple", "Torrent", "Breeze", "Nimbus", "Tempest", "Cyclone", "Blizzard", "Icicle", "Flicker", "Glowbug", "Mothra", "Scarab", "Beetle", "Antler", "Staggle", "Hornet", "Buzzly", "Flutter", "Puddle", "Splashy", "Drizzle", "Rainy", "Stormy", "Thunder", "Bolt", "Sparkle", "Shocker", "Zaplet", "Mystic", "Rune", "Oracle", "Wraith", "Shade", "Phantom", "Polter", "Ghast", "Specter", "Spirit", "Bash", "Crush", "Smash", "Pummel", "Thump", "Rumble", "Gravel", "Dusty", "Rocky", "Pebble"]; // Shuffle baseNames for uniqueness for (var i = baseNames.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var temp = baseNames[i]; baseNames[i] = baseNames[j]; baseNames[j] = temp; } // Assign types and images in a round-robin fashion for (var i = 0; i < 100; i++) { var type = types[i % types.length]; var name = baseNames[i % baseNames.length] + (i >= baseNames.length ? String(i) : ""); var image = type + "Cubixion"; var evolvesTo = i + 1 < 100 && Math.random() < 0.7 ? i + 1 : null; // 70% chance to evolve to next self.creatureList.push({ id: i, name: name, type: type, image: image, evolvesTo: evolvesTo }); } })(); // Creature properties self.creatureId = 0; // Index in creatureList self.type = 'normal'; // Default type self.rarity = 'common'; // Default rarity self.gridX = 0; self.gridY = 0; self.captured = false; self.name = ''; self.image = ''; self.evolvesTo = null; // Rarity colors self.rarityColors = { common: 0xFFFFFF, uncommon: 0x00FF00, rare: 0x0000FF, epic: 0xFF00FF, legendary: 0xFFD700 }; // Type to biome mapping self.typeBiomeMap = { bug: 'forest', dark: 'mountain', dragon: 'mountain', electric: 'grass', fairy: 'forest', fighting: 'mountain', fire: 'desert', flying: 'grass', ghost: 'mountain', grass: 'grass', ground: 'desert', ice: 'mountain', normal: 'grass', poison: 'forest', psychic: 'grass', rock: 'mountain', steel: 'urban', water: 'water' }; // Initialize creature with specific id, or type/rarity/position self.init = function (type, rarity, gridX, gridY, creatureId) { // If creatureId is provided, use it if (typeof creatureId === "number" && self.creatureList[creatureId]) { var c = self.creatureList[creatureId]; self.creatureId = c.id; self.type = c.type; self.name = c.name; self.image = c.image; self.evolvesTo = c.evolvesTo; } else { // Pick a random creature for the biome var candidates = []; for (var i = 0; i < self.creatureList.length; i++) { if (!type || self.creatureList[i].type === type) { candidates.push(self.creatureList[i]); } } var c = candidates[Math.floor(Math.random() * candidates.length)]; self.creatureId = c.id; self.type = c.type; self.name = c.name; self.image = c.image; self.evolvesTo = c.evolvesTo; } self.rarity = rarity || self.getRandomRarity(); self.gridX = gridX; self.gridY = gridY; // Create creature graphic var creatureGraphics = self.attachAsset(self.image, { anchorX: 0.5, anchorY: 0.5 }); // Apply rarity visual effect (glow or color) var rarityColor = self.rarityColors[self.rarity] || 0xFFFFFF; // Add glow effect for rare+ creatures if (self.rarity !== 'common') { // Make rarer creatures slightly larger var scale = 1.0; if (self.rarity === 'uncommon') scale = 1.1; if (self.rarity === 'rare') scale = 1.2; if (self.rarity === 'epic') scale = 1.3; if (self.rarity === 'legendary') scale = 1.5; creatureGraphics.scale.set(scale, scale); } // Position creature self.x = self.gridX * TILE_SIZE + TILE_SIZE / 2; // Center of tile self.y = self.gridY * TILE_SIZE + TILE_SIZE / 2; // Center of tile // Add name label var nameText = new Text2(self.name, { size: 36, fill: 0xFFFFFF }); nameText.anchor.set(0.5, 0); nameText.x = 0; nameText.y = 60; self.addChild(nameText); // If this creature can evolve, show evolution arrow if (self.evolvesTo !== null && typeof self.creatureList[self.evolvesTo] !== "undefined") { var evoText = new Text2("Evolves to: " + self.creatureList[self.evolvesTo].name, { size: 24, fill: 0xFFD700 }); evoText.anchor.set(0.5, 0); evoText.x = 0; evoText.y = 100; self.addChild(evoText); } return self; }; // Generate a random creature type, weighted by biome self.getRandomType = function (biome) { // Default types for each biome var biomeTypes = { grass: ['normal', 'grass', 'bug', 'flying', 'electric', 'psychic'], water: ['water', 'ice', 'flying'], desert: ['ground', 'fire', 'rock'], forest: ['bug', 'grass', 'poison', 'fairy'], mountain: ['rock', 'fighting', 'dragon', 'dark', 'ghost', 'ice'], street: ['steel', 'electric', 'poison', 'normal', 'fighting'], urban: ['steel', 'electric', 'normal', 'psychic'] }; // Get types for the provided biome, or use all types var types = biome ? biomeTypes[biome] : Object.keys(self.typeBiomeMap); // Select random type from available options return types[Math.floor(Math.random() * types.length)]; }; // Generate a random rarity based on configured probabilities self.getRandomRarity = function () { var rand = Math.random(); if (rand < 0.65) return 'common'; if (rand < 0.85) return 'uncommon'; if (rand < 0.95) return 'rare'; if (rand < 0.99) return 'epic'; return 'legendary'; }; // Animate creature during encounter self.animate = function () { // Bounce animation var originalY = self.y; // Use tween to create a bouncing effect tween(self, { y: originalY - 20 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { tween(self, { y: originalY }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { // Repeat animation self.animate(); } }); } }); }; // Stop animations self.stopAnimation = function () { tween.stop(self, { y: true }); }; // Evolve this creature to its next form, if possible self.evolve = function () { if (self.evolvesTo !== null && typeof self.creatureList[self.evolvesTo] !== "undefined") { var next = self.creatureList[self.evolvesTo]; // Remove all children (graphics, name, evo text) while (self.children.length > 0) self.removeChild(self.children[0]); self.creatureId = next.id; self.type = next.type; self.name = next.name; self.image = next.image; self.evolvesTo = next.evolvesTo; // Re-add graphics and labels var creatureGraphics = self.attachAsset(self.image, { anchorX: 0.5, anchorY: 0.5 }); creatureGraphics.scale.set(1.2, 1.2); var nameText = new Text2(self.name, { size: 36, fill: 0xFFFFFF }); nameText.anchor.set(0.5, 0); nameText.x = 0; nameText.y = 60; self.addChild(nameText); if (self.evolvesTo !== null && typeof self.creatureList[self.evolvesTo] !== "undefined") { var evoText = new Text2("Evolves to: " + self.creatureList[self.evolvesTo].name, { size: 24, fill: 0xFFD700 }); evoText.anchor.set(0.5, 0); evoText.x = 0; evoText.y = 100; self.addChild(evoText); } } }; return self; }); // Directional pad control for player movement var DPad = Container.expand(function () { var self = Container.call(this); // DPad components self.padBase = null; self.upButton = null; self.downButton = null; self.leftButton = null; self.rightButton = null; // Initialize dpad with buttons self.init = function () { // Create base of DPad self.padBase = self.attachAsset('dpad', { anchorX: 0.5, anchorY: 0.5 }); // Create directional buttons self.upButton = self.createButton(0, -65); self.downButton = self.createButton(0, 65); self.leftButton = self.createButton(-65, 0); self.rightButton = self.createButton(65, 0); // Position the entire DPad in the bottom left of the screen self.x = 200; self.y = 2500; return self; }; // Create a directional button at relative x,y from center self.createButton = function (relX, relY) { var button = self.attachAsset('dpadButton', { anchorX: 0.5, anchorY: 0.5, x: relX, y: relY }); button.interactive = true; return button; }; return self; }); // Encounter class to handle creature encounters var Encounter = Container.expand(function () { var self = Container.call(this); // Encounter state self.active = false; self.creature = null; self.captureRing = null; self.captureTarget = null; self.targetSpeed = 5; self.targetDirection = 1; self.captureAttempts = 0; self.maxAttempts = 3; // Initialize encounter screen self.init = function () { // Darkened background var bg = self.attachAsset('grassTile', { anchorX: 0, anchorY: 0, width: 2048, height: 2732 }); bg.alpha = 0.7; bg.tint = 0x000000; // Initially hidden self.visible = false; return self; }; // Start encounter with a specific creature self.startEncounter = function (creature) { self.active = true; self.visible = true; self.creature = creature; self.captureAttempts = 0; // --- Cubix selection UI --- self.selectedCubix = 'basic'; // Default // Defensive: always ensure playerCubix is defined and up to date, and always use the global reference if (typeof window !== "undefined" && typeof window.playerCubix !== "undefined") { playerCubix = window.playerCubix; } if (typeof storage !== "undefined" && typeof storage.playerCubix !== "undefined") { playerCubix = storage.playerCubix; } if (_typeof3(playerCubix) !== "object" || !playerCubix) { playerCubix = { basic: 0, uncommon: 0, rare: 0, legendary: 0 }; } if (typeof syncPlayerCubix === "function") { syncPlayerCubix(); } // Defensive: ensure all rarities are present and are numbers, and always update the global reference for (var i = 0; i < cubixTypes.length; i++) { if (!cubixTypes[i] || typeof cubixTypes[i].rarity === "undefined") continue; var rarity = cubixTypes[i].rarity; if (typeof playerCubix[rarity] !== "number" || isNaN(playerCubix[rarity])) { playerCubix[rarity] = 0; } } // Defensive: always sync playerCubix to storage and global scope if (typeof syncPlayerCubix === "function") { syncPlayerCubix(); } else { if (typeof storage !== "undefined") { if (typeof storage.set === "function") { storage.set("playerCubix", playerCubix); } else { storage.playerCubix = { basic: playerCubix.basic, uncommon: playerCubix.uncommon, rare: playerCubix.rare, legendary: playerCubix.legendary }; } } if (typeof window !== "undefined") { window.playerCubix = playerCubix; } } // Only allow selection of cubix the player has (at least one of any type) function getTotalCubixCount() { var total = 0; for (var i = 0; i < cubixTypes.length; i++) { total += playerCubix[cubixTypes[i].rarity] || 0; } return total; } // Defensive: always get the latest value from global and storage before checking var totalCubixCount = getTotalCubixCount(); var hasAnyCubix = false; for (var i = 0; i < cubixTypes.length; i++) { if ((playerCubix[cubixTypes[i].rarity] || 0) > 0) { hasAnyCubix = true; break; } } // Defensive: also check for negative or non-integer values (should never happen, but just in case) // --- FIX: Check for all possible causes of 'No Cubix' and resync inventory if needed --- var cubixError = false; var cubixErrorMsg = ''; // Defensive: check for undefined, null, negative, or non-integer values for (var i = 0; i < cubixTypes.length; i++) { if (!cubixTypes[i] || typeof cubixTypes[i].rarity === "undefined") continue; var rarity = cubixTypes[i].rarity; if (typeof playerCubix[rarity] !== "number" || isNaN(playerCubix[rarity]) || playerCubix[rarity] < 0) { playerCubix[rarity] = 0; cubixError = true; cubixErrorMsg = 'Cubix inventory error detected. Inventory was reset.'; } } // Defensive: check for missing playerCubix object if (!playerCubix || _typeof4(playerCubix) !== "object") { playerCubix = { basic: 0, uncommon: 0, rare: 0, legendary: 0 }; cubixError = true; cubixErrorMsg = 'Cubix inventory missing. Inventory was reset.'; } // Defensive: check for out-of-sync inventory (storage vs global) if (typeof storage !== "undefined" && typeof storage.playerCubix !== "undefined") { for (var i = 0; i < cubixTypes.length; i++) { if (!cubixTypes[i] || typeof cubixTypes[i].rarity === "undefined") continue; var rarity = cubixTypes[i].rarity; if (typeof storage.playerCubix[rarity] !== "number" || isNaN(storage.playerCubix[rarity]) || storage.playerCubix[rarity] < 0) { storage.playerCubix[rarity] = 0; cubixError = true; cubixErrorMsg = 'Cubix inventory in storage was invalid. Inventory was reset.'; } } } // Defensive: check for out-of-sync between window and storage if (typeof window !== "undefined" && typeof window.playerCubix !== "undefined") { for (var i = 0; i < cubixTypes.length; i++) { if (!cubixTypes[i] || typeof cubixTypes[i].rarity === "undefined") continue; var rarity = cubixTypes[i].rarity; if (typeof window.playerCubix[rarity] !== "number" || isNaN(window.playerCubix[rarity]) || window.playerCubix[rarity] < 0) { window.playerCubix[rarity] = 0; cubixError = true; cubixErrorMsg = 'Cubix inventory in window was invalid. Inventory was reset.'; } } } // Defensive: always sync after any fix if (cubixError && typeof syncPlayerCubix === "function") { syncPlayerCubix(); } // Defensive: check for totalCubixCount again after all fixes totalCubixCount = getTotalCubixCount(); hasAnyCubix = false; for (var i = 0; i < cubixTypes.length; i++) { if (!cubixTypes[i] || typeof cubixTypes[i].rarity === "undefined") continue; if ((playerCubix[cubixTypes[i].rarity] || 0) > 0) { hasAnyCubix = true; break; } } // If player has no Cubix, allow normal catching animation, but player must leave manually. // Do not show any warning or block the encounter. Just proceed as normal. // Show cubix selection UI with image and name, require player to choose for catching self.cubixButtons = []; self.cubixButtonLabels = []; self.cubixButtonNameLabels = []; var firstAvailableIdx = -1; var cubixButtonStartX = 600; var cubixButtonSpacing = 250; for (var i = 0; i < cubixTypes.length; i++) { var cType = cubixTypes[i]; if (!cType || typeof cType.rarity === "undefined") continue; // Cubix image button var btn = self.attachAsset('cubix_' + (cType && typeof cType.rarity !== "undefined" ? cType.rarity : "basic"), { anchorX: 0.5, anchorY: 0.5, x: cubixButtonStartX + i * cubixButtonSpacing, y: 1600 }); btn.scale.set(0.38, 0.38); btn.interactive = true; (function (type, idx) { btn.down = function () { if ((playerCubix[type.rarity] || 0) > 0) { self.selectedCubix = type.rarity; // Highlight selected for (var j = 0; j < self.cubixButtons.length; j++) { self.cubixButtons[j].alpha = self.cubixButtons[j].rarity === type.rarity ? 1.0 : 0.5; if (self.cubixButtonNameLabels[j]) { self.cubixButtonNameLabels[j].style.fill = self.cubixButtons[j].rarity === type.rarity ? 0xFFD700 : type.color; } } // Show info about catch chance if (self.cubixCatchInfoText) { self.removeChild(self.cubixCatchInfoText); } var bonus = typeof type.catchBonus === "number" ? type.catchBonus : 0; var baseChance = 0.5; if (self.creature && self.creature.rarity) { if (self.creature.rarity === 'common') baseChance = 0.5; if (self.creature.rarity === 'uncommon') baseChance = 0.35; if (self.creature.rarity === 'rare') baseChance = 0.2; if (self.creature.rarity === 'epic') baseChance = 0.1; if (self.creature.rarity === 'legendary') baseChance = 0.05; } var finalChance = baseChance + bonus; if (finalChance > 1) finalChance = 1; var percent = Math.round(finalChance * 100); self.cubixCatchInfoText = new Text2('Catch chance: ' + percent + '%', { size: 38, fill: 0xFFD700 }); self.cubixCatchInfoText.anchor.set(0.5, 0); self.cubixCatchInfoText.x = 1024; self.cubixCatchInfoText.y = 1750; self.addChild(self.cubixCatchInfoText); } }; })(cType, i); btn.rarity = cType.rarity; if ((playerCubix[cType.rarity] || 0) <= 0) { btn.alpha = 0.2; btn.interactive = false; } else { if (firstAvailableIdx === -1) firstAvailableIdx = i; } self.addChild(btn); self.cubixButtons.push(btn); // Add cubix name label below image var nameLabel = new Text2(cType.name, { size: 36, fill: cType.color }); nameLabel.anchor.set(0.5, 0); nameLabel.x = cubixButtonStartX + i * cubixButtonSpacing; nameLabel.y = 1670; self.addChild(nameLabel); self.cubixButtonNameLabels.push(nameLabel); // Add count label below name var label = new Text2('x' + (playerCubix[cType.rarity] || 0), { size: 28, fill: cType.color }); label.anchor.set(0.5, 0); label.x = cubixButtonStartX + i * cubixButtonSpacing; label.y = 1710; self.addChild(label); self.cubixButtonLabels.push(label); btn.alpha = i === firstAvailableIdx ? 1.0 : 0.5; if (self.cubixButtonNameLabels[i] && self.cubixButtonNameLabels[i].style) { self.cubixButtonNameLabels[i].style.fill = i === firstAvailableIdx ? 0xFFD700 : cType.color; } } // Set default selectedCubix to first available type if (firstAvailableIdx !== -1) { self.selectedCubix = cubixTypes[firstAvailableIdx].rarity; // Show info about catch chance for default if (self.cubixCatchInfoText) { self.removeChild(self.cubixCatchInfoText); } var type = cubixTypes[firstAvailableIdx]; var bonus = typeof type.catchBonus === "number" ? type.catchBonus : 0; var baseChance = 0.5; if (self.creature && self.creature.rarity) { if (self.creature.rarity === 'common') baseChance = 0.5; if (self.creature.rarity === 'uncommon') baseChance = 0.35; if (self.creature.rarity === 'rare') baseChance = 0.2; if (self.creature.rarity === 'epic') baseChance = 0.1; if (self.creature.rarity === 'legendary') baseChance = 0.05; } var finalChance = baseChance + bonus; if (finalChance > 1) finalChance = 1; var percent = Math.round(finalChance * 100); self.cubixCatchInfoText = new Text2('Catch chance: ' + percent + '%', { size: 38, fill: 0xFFD700 }); self.cubixCatchInfoText.anchor.set(0.5, 0); self.cubixCatchInfoText.x = 1024; self.cubixCatchInfoText.y = 1750; self.addChild(self.cubixCatchInfoText); // Highlight default selected for (var j = 0; j < self.cubixButtons.length; j++) { self.cubixButtons[j].alpha = j === firstAvailableIdx ? 1.0 : 0.5; if (self.cubixButtonNameLabels[j]) { self.cubixButtonNameLabels[j].style.fill = j === firstAvailableIdx ? 0xFFD700 : cubixTypes[j].color; } } } // Add creature to encounter screen self.addChild(creature); creature.x = 1024; // Center horizontally creature.y = 1000; // Position in upper portion of screen // Make creature interactive to allow clicking directly on it creature.interactive = true; creature.down = function () { self.attemptCapture(); }; // Start creature animation creature.animate(); // Create capture interface self.createCaptureInterface(); // Play encounter sound LK.getSound('encounter').play(); }; // Create the capture ring and target interface self.createCaptureInterface = function () { // Capture ring self.captureRing = self.attachAsset('captureRing', { anchorX: 0.5, anchorY: 0.5, x: 1024, // Center horizontally y: 1800 // Lower portion of screen }); // Moving target self.captureTarget = self.attachAsset('captureTarget', { anchorX: 0.5, anchorY: 0.5, x: 964, // Start position (left side of ring) y: 1800 // Same Y as ring }); // Defensive: check if player has any cubix before showing capture button/text var totalCubixCount = 0; if (typeof playerCubix !== "undefined" && typeof cubixTypes !== "undefined") { for (var i = 0; i < cubixTypes.length; i++) { totalCubixCount += playerCubix[cubixTypes[i].rarity] || 0; } } // --- Cubix counter UI: Show cubix type-by-type counter below cubix selection buttons in encounter --- // Remove previous cubixCountTexts if present if (self.cubixCountTexts) { for (var i = 0; i < self.cubixCountTexts.length; i++) { if (self.cubixCountTexts[i] && self.cubixCountTexts[i].parent === self) { self.removeChild(self.cubixCountTexts[i]); } } } self.cubixCountTexts = []; for (var i = 0; i < cubixTypes.length; i++) { var cType = cubixTypes[i]; if (!cType || typeof cType.rarity === "undefined") continue; // Show cubix image and count for each type var img = LK.getAsset('cubix_' + (cType && typeof cType.rarity !== "undefined" ? cType.rarity : "basic"), { anchorX: 0.5, anchorY: 0.5, x: 700 + i * 200, y: 1720, scaleX: 0.18, scaleY: 0.18 }); self.addChild(img); // Show count text var count = playerCubix && typeof playerCubix[cType.rarity] === "number" ? playerCubix[cType.rarity] : 0; var countText = new Text2('x' + count, { size: 32, fill: cType.color }); countText.anchor.set(0.5, 0); countText.x = 700 + i * 200; countText.y = 1745; self.addChild(countText); self.cubixCountTexts.push(countText); } // Fix: Always show capture button if player has at least 1 of any cubix (including 10 basic cubix) if (playerCubix && (playerCubix.basic > 0 || playerCubix.uncommon > 0 || playerCubix.rare > 0 || playerCubix.legendary > 0)) { // Capture button var captureButton = self.attachAsset('grassTile', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 2200, width: 300, height: 100 }); captureButton.tint = 0xFF0000; // Capture button text var captureText = new Text2('CAPTURE', { size: 60, fill: 0xFFFFFF }); captureText.anchor.set(0.5, 0.5); captureText.x = 1024; captureText.y = 2200; self.addChild(captureText); // Capture button event captureButton.interactive = true; captureButton.down = function () { self.attemptCapture(); }; } // Leave button var leaveButton = self.attachAsset('grassTile', { anchorX: 0.5, anchorY: 0.5, x: 1700, y: 2200, width: 300, height: 100 }); leaveButton.tint = 0x888888; var leaveText = new Text2('LEAVE', { size: 60, fill: 0xFFFFFF }); leaveText.anchor.set(0.5, 0.5); leaveText.x = 1700; leaveText.y = 2200; self.addChild(leaveText); leaveButton.interactive = true; leaveButton.down = function () { // End encounter immediately, treat as fail/escape self.endEncounter(); }; // Info text about the creature (removed attempts display) var infoText = new Text2('TYPE: ' + self.creature.type.toUpperCase() + '\n' + 'RARITY: ' + self.creature.rarity.toUpperCase(), { size: 50, fill: 0xFFFFFF }); infoText.anchor.set(0.5, 0); infoText.x = 1024; infoText.y = 2300; self.addChild(infoText); }; // Update function for moving the target self.update = function () { if (!self.active || !self.captureTarget) return; // Move target back and forth across the ring self.captureTarget.x += self.targetSpeed * self.targetDirection; // Reverse direction at edges if (self.captureTarget.x > 1084) { // Right edge of ring self.targetDirection = -1; } else if (self.captureTarget.x < 964) { // Left edge of ring self.targetDirection = 1; } // Make target move faster based on creature rarity var speedMultiplier = 1; if (self.creature) { if (self.creature.rarity === 'uncommon') speedMultiplier = 1.2; if (self.creature.rarity === 'rare') speedMultiplier = 1.5; if (self.creature.rarity === 'epic') speedMultiplier = 1.8; if (self.creature.rarity === 'legendary') speedMultiplier = 2.2; } self.targetSpeed = 5 * speedMultiplier; }; // Attempt to capture the creature self.attemptCapture = function () { // Play capture sound LK.getSound('capture').play(); self.captureAttempts++; // Use selected cubix, reduce inventory var selectedType = cubixTypes[0]; for (var i = 0; i < cubixTypes.length; i++) { if (cubixTypes[i].rarity === self.selectedCubix) { selectedType = cubixTypes[i]; break; } } if (selectedType && typeof selectedType.rarity === "string" && playerCubix && typeof playerCubix[selectedType.rarity] === "number" && playerCubix[selectedType.rarity] > 0) { playerCubix[selectedType.rarity]--; // Defensive: always sync playerCubix to storage and global scope after change if (typeof syncPlayerCubix === "function") { syncPlayerCubix(); } else { if (typeof storage !== "undefined") { if (typeof storage.set === "function") { storage.set("playerCubix", playerCubix); } else { storage.playerCubix = { basic: playerCubix.basic, uncommon: playerCubix.uncommon, rare: playerCubix.rare, legendary: playerCubix.legendary }; } } if (typeof window !== "undefined") { window.playerCubix = playerCubix; } // Also decrement from Cubixion bag collection if present if (typeof playerCubixionCollection !== "undefined") { var cubixionId = selectedType.rarity; if (playerCubixionCollection[cubixionId] && typeof playerCubixionCollection[cubixionId].count === "number" && playerCubixionCollection[cubixionId].count > 0) { playerCubixionCollection[cubixionId].count--; // Defensive: always sync to storage and window if (typeof storage !== "undefined" && typeof storage.set === "function") { storage.set("playerCubixionCollection", playerCubixionCollection); } else if (typeof storage !== "undefined") { try { storage.playerCubixionCollection = playerCubixionCollection; } catch (e) {} } if (typeof window !== "undefined") window.playerCubixionCollection = playerCubixionCollection; } } } // Update cubix button labels and cubix count display if (self.cubixButtons) { for (var i = 0; i < self.cubixButtons.length; i++) { if (!cubixTypes[i] || typeof cubixTypes[i].rarity === "undefined") continue; // Update label if (self.cubixButtonLabels && self.cubixButtonLabels[i]) { self.cubixButtonLabels[i].setText(cubixTypes[i].name + ' (' + (playerCubix[cubixTypes[i].rarity] || 0) + ')'); } if (playerCubix[cubixTypes[i].rarity] <= 0) self.cubixButtons[i].alpha = 0.2; } } // Update cubix count text below (by type with image) if (self.cubixCountTexts) { for (var i = 0; i < self.cubixCountTexts.length; i++) { if (!cubixTypes[i] || typeof cubixTypes[i].rarity === "undefined") continue; var rarity = cubixTypes[i].rarity; if (self.cubixCountTexts[i]) { self.cubixCountTexts[i].setText('x' + (playerCubix[rarity] || 0)); } } } } // Check if target is in center zone (successful capture) var distanceFromCenter = Math.abs(self.captureTarget.x - 1024); var successZone = 15; // Size of "perfect" zone // Adjust success zone based on rarity (harder for rarer creatures) if (self.creature.rarity === 'uncommon') successZone = 13; if (self.creature.rarity === 'rare') successZone = 10; if (self.creature.rarity === 'epic') successZone = 8; if (self.creature.rarity === 'legendary') successZone = 5; var captured = false; if (distanceFromCenter <= successZone) { // Use selected cubix type for catch bonus var baseChance = 0.5; if (self.creature.rarity === 'common') baseChance = 0.5; if (self.creature.rarity === 'uncommon') baseChance = 0.35; if (self.creature.rarity === 'rare') baseChance = 0.2; if (self.creature.rarity === 'epic') baseChance = 0.1; if (self.creature.rarity === 'legendary') baseChance = 0.05; var catchBonus = 0; var selectedType = cubixTypes[0]; for (var i = 0; i < cubixTypes.length; i++) { if (cubixTypes[i].rarity === self.selectedCubix) { selectedType = cubixTypes[i]; break; } } if (selectedType && typeof selectedType.catchBonus === "number") { catchBonus = selectedType.catchBonus; } var finalChance = baseChance + catchBonus; if (finalChance > 1) finalChance = 1; if (Math.random() < finalChance) captured = true; } if (captured) { // Success! self.captureSuccess(); } else if (self.captureAttempts >= self.maxAttempts) { // Failed after max attempts self.captureFail(); } else { // No attempts text to update (removed attempts UI) // Decrease player's cubix of used type by 1 on every failed catch attempt var selectedType = cubixTypes[0]; for (var i = 0; i < cubixTypes.length; i++) { if (cubixTypes[i].rarity === self.selectedCubix) { selectedType = cubixTypes[i]; break; } } if (selectedType && typeof selectedType.rarity === "string" && playerCubix && typeof playerCubix[selectedType.rarity] === "number" && playerCubix[selectedType.rarity] > 0) { playerCubix[selectedType.rarity]--; // Defensive: always sync playerCubix to storage and global scope after change if (typeof syncPlayerCubix === "function") { syncPlayerCubix(); } else { if (typeof storage !== "undefined") { if (typeof storage.set === "function") { storage.set("playerCubix", playerCubix); } else { storage.playerCubix = { basic: playerCubix.basic, uncommon: playerCubix.uncommon, rare: playerCubix.rare, legendary: playerCubix.legendary }; } } if (typeof window !== "undefined") { window.playerCubix = playerCubix; } } } // Update cubix button labels and cubix count display if (self.cubixButtons) { for (var i = 0; i < self.cubixButtons.length; i++) { if (!cubixTypes[i] || typeof cubixTypes[i].rarity === "undefined") continue; // Update label if (self.cubixButtonLabels && self.cubixButtonLabels[i]) { self.cubixButtonLabels[i].setText(cubixTypes[i].name + " (" + (playerCubix[cubixTypes[i].rarity] || 0) + ")"); } if (playerCubix[cubixTypes[i].rarity] <= 0) self.cubixButtons[i].alpha = 0.2; } } // Update cubix count text below (by type with image) if (self.cubixCountTexts) { for (var i = 0; i < self.cubixCountTexts.length; i++) { if (!cubixTypes[i] || typeof cubixTypes[i].rarity === "undefined") continue; var rarity = cubixTypes[i].rarity; if (self.cubixCountTexts[i]) { self.cubixCountTexts[i].setText("x" + (playerCubix[rarity] || 0)); } } } } }; // Handle successful capture self.captureSuccess = function () { // Play success sound LK.getSound('success').play(); // Add to collection if (!storage.discoveredCreatures) { storage.discoveredCreatures = {}; } var creatureKey = self.creature.type + '-' + self.creature.rarity; storage.discoveredCreatures[creatureKey] = true; // --- Cubixion collection and gem system --- if (typeof playerCubixionCollection === "undefined") playerCubixionCollection = {}; var cid = self.creature.creatureId; if (!playerCubixionCollection[cid]) { playerCubixionCollection[cid] = { count: 0, gems: 0 }; } playerCubixionCollection[cid].count++; playerCubixionCollection[cid].gems++; // 1 gem per catch // Mark the tile as caught so it cannot be encountered again until respawn if (typeof gameMap !== "undefined" && typeof player !== "undefined") { var tile = gameMap.getTileAt(player.gridX, player.gridY); if (tile) { tile._creatureCaught = true; tile.hasCreature = false; // Remove creature visual if present if (tile._creatureVisual) { tile.removeChild(tile._creatureVisual); tile._creatureVisual = null; } // Remove from mapCreatures/mapCreatureTiles/mapCreatureLabels if present if (typeof mapCreatureTiles !== "undefined" && typeof mapCreatures !== "undefined" && typeof mapCreatureLabels !== "undefined") { for (var i = mapCreatureTiles.length - 1; i >= 0; i--) { if (mapCreatureTiles[i] === tile) { // Defensive: Only remove label if it exists and index is valid if (Array.isArray(mapCreatureLabels) && i < mapCreatureLabels.length && mapCreatureLabels[i]) { tile.removeChild(mapCreatureLabels[i]); mapCreatureLabels.splice(i, 1); } // Defensive: Only remove from mapCreatures and mapCreatureTiles if index is valid if (Array.isArray(mapCreatures) && i < mapCreatures.length) { mapCreatures.splice(i, 1); } if (Array.isArray(mapCreatureTiles) && i < mapCreatureTiles.length) { mapCreatureTiles.splice(i, 1); } break; } } } // Remove encounterIndicator if present (yellow circle) } } // Show success message var successText = new Text2('CAPTURED!', { size: 100, fill: 0x00FF00 }); successText.anchor.set(0.5, 0.5); successText.x = 1024; successText.y = 1400; self.addChild(successText); // Flash screen LK.effects.flashScreen(0x00FF00, 500); // End encounter after delay LK.setTimeout(function () { // --- Refresh collection menu if open --- if (typeof collection !== "undefined" && collection.visible && typeof collection.show === "function") { collection.show(); } self.endEncounter(); }, 1500); }; // Handle failed capture self.captureFail = function () { // Show fail message var failText = new Text2('ESCAPED!', { size: 100, fill: 0xFF0000 }); failText.anchor.set(0.5, 0.5); failText.x = 1024; failText.y = 1400; self.addChild(failText); // Flash screen LK.effects.flashScreen(0xFF0000, 500); // Despawn the creature from the map if present if (typeof gameMap !== "undefined" && typeof player !== "undefined") { var tile = gameMap.getTileAt(player.gridX, player.gridY); if (tile) { tile.hasCreature = false; tile._creatureCaught = false; // Not caught, but despawned // Remove indicator if present // Remove from mapCreatures/mapCreatureTiles/mapCreatureLabels if present if (typeof mapCreatureTiles !== "undefined") { for (var k = mapCreatureTiles.length - 1; k >= 0; k--) { if (mapCreatureTiles[k] === tile) { if (mapCreatureLabels[k]) { tile.removeChild(mapCreatureLabels[k]); mapCreatureLabels.splice(k, 1); } mapCreatures.splice(k, 1); mapCreatureTiles.splice(k, 1); } } } } } // End encounter after delay LK.setTimeout(function () { self.endEncounter(); }, 1500); }; // End the current encounter self.endEncounter = function () { if (self.creature) { self.creature.stopAnimation(); } self.active = false; self.visible = false; // Remove all children while (self.children.length > 0) { self.removeChild(self.children[0]); } self.creature = null; self.captureRing = null; self.captureTarget = null; // Reinitialize for next encounter self.init(); // Also set encounterActive to false so game resumes if (typeof encounterActive !== "undefined") { encounterActive = false; } }; return self; }); // GameMap represents the entire game map with different biomes var GameMap = Container.expand(function () { var self = Container.call(this); self.mapWidth = 60; // Number of tiles horizontally (max size, increased) self.mapHeight = 60; // Number of tiles vertically (max size, increased) self.tileSize = TILE_SIZE; // Size of each tile in pixels (increased to match TILE_SIZE) self.tiles = []; // 2D array to hold all map tiles // Biome generation parameters self.biomeTypes = ['grass', 'water', 'desert', 'forest', 'mountain', 'street', 'urban']; self.biomeSeeds = []; // Points from which biomes spread // Initialize map with biomes self.initMap = function () { // Create empty 2D array for tiles for (var y = 0; y < self.mapHeight; y++) { self.tiles[y] = []; for (var x = 0; x < self.mapWidth; x++) { self.tiles[y][x] = null; } } // Place biome seeds self.placeBiomeSeeds(); // Generate biomes from seeds self.generateBiomes(); // --- Flood fill to ensure all tiles are connected (no black dots) --- var visited = []; for (var y = 0; y < self.mapHeight; y++) { visited[y] = []; for (var x = 0; x < self.mapWidth; x++) { visited[y][x] = false; } } // Start flood fill from center of map var startX = Math.floor(self.mapWidth / 2); var startY = Math.floor(self.mapHeight / 2); var startBiome = self.tiles[startY][startX]; var queue = [{ x: startX, y: startY }]; visited[startY][startX] = true; while (queue.length > 0) { var pos = queue.shift(); var dirs = [{ dx: 1, dy: 0 }, { dx: -1, dy: 0 }, { dx: 0, dy: 1 }, { dx: 0, dy: -1 }]; for (var d = 0; d < dirs.length; d++) { var nx = pos.x + dirs[d].dx; var ny = pos.y + dirs[d].dy; if (nx >= 0 && nx < self.mapWidth && ny >= 0 && ny < self.mapHeight && !visited[ny][nx]) { // Only connectable if not "dark" if (self.tiles[ny][nx] !== "dark") { visited[ny][nx] = true; queue.push({ x: nx, y: ny }); } } } } // Any tile not visited is unreachable, so set it to the most common neighbor biome for (var y = 0; y < self.mapHeight; y++) { for (var x = 0; x < self.mapWidth; x++) { if (!visited[y][x]) { // Find most common neighbor biome (not dark) var biomeCount = {}; for (var dy = -1; dy <= 1; dy++) { for (var dx = -1; dx <= 1; dx++) { var nx = x + dx; var ny = y + dy; if (nx >= 0 && nx < self.mapWidth && ny >= 0 && ny < self.mapHeight && (dx !== 0 || dy !== 0)) { var b = self.tiles[ny][nx]; if (b && b !== "dark") { if (!biomeCount[b]) biomeCount[b] = 0; biomeCount[b]++; } } } } // Pick the most common neighbor biome, fallback to "grass" var maxCount = 0; var bestBiome = "grass"; for (var b in biomeCount) { if (biomeCount[b] > maxCount) { maxCount = biomeCount[b]; bestBiome = b; } } self.tiles[y][x] = bestBiome; } } } // Create tiles based on biome map self.createTiles(); return self; }; // Place seed points for biome generation self.placeBiomeSeeds = function () { // Place multiple seeds for each biome for more, smaller biomes for (var i = 0; i < self.biomeTypes.length; i++) { var seedsPerBiome = 3; // Default for most biomes // Make mountain biomes much smaller by reducing their seed count if (self.biomeTypes[i] === 'mountain') { seedsPerBiome = 1; // Only 1 seed for mountain biome for much smaller area } for (var j = 0; j < seedsPerBiome; j++) { var seed = { x: Math.floor(Math.random() * self.mapWidth), y: Math.floor(Math.random() * self.mapHeight), biome: self.biomeTypes[i] }; self.biomeSeeds.push(seed); } } }; // Generate biomes from seed points using a simple distance-based algorithm self.generateBiomes = function () { for (var y = 0; y < self.mapHeight; y++) { for (var x = 0; x < self.mapWidth; x++) { // Find closest biome seed var closestDist = Number.MAX_VALUE; var closestBiome = 'grass'; // Default for (var i = 0; i < self.biomeSeeds.length; i++) { var seed = self.biomeSeeds[i]; // Reduce the effective radius for each seed, so biomes are smaller var dist = Math.sqrt(Math.pow(x - seed.x, 2) + Math.pow(y - seed.y, 2)) * 0.35; // Reduce multiplier for smaller biomes // Make mountain biomes even smaller by increasing the distance multiplier if (seed.biome === 'mountain') { dist *= 3.5; // Make mountain biomes much smaller } // Add more randomness to make borders less regular and biomes patchier dist += Math.random() * 6 - 3; if (dist < closestDist) { closestDist = dist; closestBiome = seed.biome; } } self.tiles[y][x] = closestBiome; } } // Add some randomness and blending between biomes self.refineBiomes(); }; // Add more natural transitions between biomes with street patterns self.refineBiomes = function () { // Create a deep copy of tiles array var tempTiles = []; for (var y = 0; y < self.mapHeight; y++) { tempTiles[y] = []; for (var x = 0; x < self.mapWidth; x++) { tempTiles[y][x] = self.tiles[y][x]; } } // Create street grid patterns // Find street biome seed var streetSeedX = -1; var streetSeedY = -1; for (var i = 0; i < self.biomeSeeds.length; i++) { if (self.biomeSeeds[i].biome === 'street') { streetSeedX = self.biomeSeeds[i].x; streetSeedY = self.biomeSeeds[i].y; break; } } // If we have a street seed, create grid pattern around it if (streetSeedX >= 0 && streetSeedY >= 0) { // Create street grid - horizontal and vertical streets var streetRadius = 8; // Size of urban area var streetGridSpacing = 3; // Distance between streets for (var y = Math.max(0, streetSeedY - streetRadius); y < Math.min(self.mapHeight, streetSeedY + streetRadius); y++) { for (var x = Math.max(0, streetSeedX - streetRadius); x < Math.min(self.mapWidth, streetSeedX + streetRadius); x++) { // Check if within street biome core radius var distToSeed = Math.sqrt(Math.pow(x - streetSeedX, 2) + Math.pow(y - streetSeedY, 2)); if (distToSeed <= streetRadius) { // Street grid pattern: create roads at regular intervals if (x % streetGridSpacing === 0 || y % streetGridSpacing === 0) { self.tiles[y][x] = 'street'; } // Building blocks between streets else if (self.tiles[y][x] === 'street') { // Determine building type based on position in grid - some variety within urban areas if ((x + y) % 2 === 0) { self.tiles[y][x] = 'street'; // Keep as urban (tall buildings) } else { // Mix with nearby biomes occasionally for parks, etc. if (Math.random() < 0.3) { var nearbyNonStreetBiome = ''; // Look for any non-street biome nearby for (var ny = y - 1; ny <= y + 1; ny++) { for (var nx = x - 1; nx <= x + 1; nx++) { if (ny >= 0 && ny < self.mapHeight && nx >= 0 && nx < self.mapWidth) { if (self.tiles[ny][nx] !== 'street' && self.tiles[ny][nx] !== undefined) { nearbyNonStreetBiome = self.tiles[ny][nx]; break; } } } if (nearbyNonStreetBiome) break; } // If found nearby non-street biome, use it, otherwise keep as street if (nearbyNonStreetBiome) { self.tiles[y][x] = nearbyNonStreetBiome; } } } } } } } } // Now apply regular biome smoothing for (var y = 1; y < self.mapHeight - 1; y++) { for (var x = 1; x < self.mapWidth - 1; x++) { // Skip street grid areas var distToStreetSeed = streetSeedX >= 0 ? Math.sqrt(Math.pow(x - streetSeedX, 2) + Math.pow(y - streetSeedY, 2)) : Number.MAX_VALUE; if (distToStreetSeed <= streetRadius && (x % streetGridSpacing === 0 || y % streetGridSpacing === 0)) { continue; // Skip street grid lines } // Count neighboring biomes var biomeCount = {}; for (var ny = y - 1; ny <= y + 1; ny++) { for (var nx = x - 1; nx <= x + 1; nx++) { // Check that neighbor coordinates are valid if (ny >= 0 && ny < self.mapHeight && nx >= 0 && nx < self.mapWidth) { var neighborBiome = tempTiles[ny][nx]; if (neighborBiome) { if (!biomeCount[neighborBiome]) { biomeCount[neighborBiome] = 0; } biomeCount[neighborBiome]++; } } } } // Random chance to convert to most common neighbor if (Math.random() < 0.4) { var mostCommon = tempTiles[y][x]; var maxCount = 0; for (var biome in biomeCount) { if (biomeCount.hasOwnProperty(biome) && biomeCount[biome] > maxCount) { maxCount = biomeCount[biome]; mostCommon = biome; } } self.tiles[y][x] = mostCommon; } } } }; // Create actual tile objects based on the biome map self.createTiles = function () { for (var y = 0; y < self.mapHeight; y++) { for (var x = 0; x < self.mapWidth; x++) { var biomeType = self.tiles[y][x]; var tile = new MapTile().initTile(biomeType, x, y); tile.tileSize = TILE_SIZE; self.addChild(tile); } } }; // Get tile at grid coordinates self.getTileAt = function (gridX, gridY) { // Ensure coordinates are within bounds if (gridX < 0 || gridX >= self.mapWidth || gridY < 0 || gridY >= self.mapHeight) { return null; } // Find the tile in the children for (var i = 0; i < self.children.length; i++) { var tile = self.children[i]; if (tile.gridX === gridX && tile.gridY === gridY) { return tile; } } return null; }; return self; }); // MapTile represents a single tile in the game grid var MapTile = Container.expand(function () { var self = Container.call(this); self.biomeType = 'grass'; // Default biome self.tileSize = TILE_SIZE; // Set to match TILE_SIZE for correct movement alignment self.hasCreature = false; self.explored = false; self.x = 0; self.y = 0; self.gridX = 0; self.gridY = 0; // Initialize the tile with a specific biome self.initTile = function (biomeType, gridX, gridY) { self.biomeType = biomeType; self.gridX = gridX; self.gridY = gridY; self.x = gridX * self.tileSize; self.y = gridY * self.tileSize; // Get the appropriate tile asset based on biome, using unique tile for each biome var biomeTileAssetMap = { grass: ['grassTile', 'grassTile2'], water: ['waterTile', 'waterTile2'], desert: ['desertTile', 'desertTile2'], forest: ['forestTile', 'forestTile2'], mountain: ['mountainTile', 'mountainTile2'], street: ['streetTile', 'streetTile2'], urban: ['urbanTile', 'urbanTile2'] }; // Special handling for out-of-world tiles removed. All tiles use biome tile assets. var assetList = biomeTileAssetMap[self.biomeType] || [self.biomeType + 'Tile']; // Randomly pick one of the two tile assets for this biome var assetId = assetList[Math.floor(Math.random() * assetList.length)]; // Use a single tile for the biome, with the new TILE_SIZE (already 3x bigger) self.tileImage = self.attachAsset(assetId, { anchorX: 0, anchorY: 0, width: TILE_SIZE, height: TILE_SIZE, x: 0, y: 0 }); self.tileImage.alpha = 0.9; // Set the logical tile size to TILE_SIZE for correct movement and centering self.tileSize = TILE_SIZE; // No fog overlay for undiscovered tiles (fog removed) self.fogOverlay = null; // Random chance to spawn a creature based on biome (further reduced for less frequent spawning) if (Math.random() < 0.02) { self.hasCreature = true; } return self; }; // Mark tile as explored self.explore = function () { if (!self.explored) { self.explored = true; // Hide fog overlay if present if (self.fogOverlay) { self.fogOverlay.visible = false; } // Add to explored areas in storage var exploredKey = self.gridX + "," + self.gridY; if (!storage.exploredTiles) storage.exploredTiles = {}; storage.exploredTiles[exploredKey] = true; } }; return self; }); // MiniMap class to show explored areas var MiniMap = Container.expand(function () { var self = Container.call(this); // MiniMap components self.mapBackground = null; self.playerMarker = null; self.tileMarkers = []; self.mapSize = 300; self.scale = 0.1; // How much of the full map to show // Initialize minimap self.init = function () { // Create background self.mapBackground = self.attachAsset('minimap', { anchorX: 0, anchorY: 0, width: self.mapSize, height: self.mapSize }); // Create player marker self.playerMarker = self.attachAsset('minimapMarker', { anchorX: 0.5, anchorY: 0.5, x: self.mapSize / 2, y: self.mapSize / 2 }); // Position minimap in top right corner self.x = 2048 - self.mapSize - 20; self.y = 20; return self; }; // Update minimap with current player position and explored tiles self.update = function (player, gameMap) { // Check if player and gameMap are defined if (!player || !gameMap) return; // Update player marker position var centerX = self.mapSize / 2; var centerY = self.mapSize / 2; // Position marker relative to center self.playerMarker.x = centerX; self.playerMarker.y = centerY; // Clear existing tile markers for (var i = 0; i < self.tileMarkers.length; i++) { self.removeChild(self.tileMarkers[i]); } self.tileMarkers = []; // Add markers for visible tiles around player var visionRadius = 1; // Match the reduced player vision radius for less lag for (var y = Math.floor(player.gridY - visionRadius); y <= Math.ceil(player.gridY + visionRadius); y++) { for (var x = Math.floor(player.gridX - visionRadius); x <= Math.ceil(player.gridX + visionRadius); x++) { var dx = x - player.gridX; var dy = y - player.gridY; if (Math.sqrt(dx * dx + dy * dy) <= visionRadius + 0.2) { var tile = gameMap.getTileAt(x, y); if (tile && tile.explored) { // Create marker with biome color var color = 0x33cc33; // Default grass if (tile.biomeType === 'water') color = 0x3399ff; if (tile.biomeType === 'desert') color = 0xe6cc99; if (tile.biomeType === 'forest') color = 0x006600; if (tile.biomeType === 'mountain') color = 0x999999; if (tile.biomeType === 'street') color = 0x666666; if (tile.biomeType === 'urban') color = 0x4444aa; var marker = new Container(); var markerGraphics = LK.getAsset('grassTile', { anchorX: 0, anchorY: 0, width: 10, height: 10 }); markerGraphics.tint = color; marker.addChild(markerGraphics); // Position marker relative to player marker.x = centerX + (x - player.gridX) * 10; marker.y = centerY + (y - player.gridY) * 10; self.addChild(marker); self.tileMarkers.push(marker); } } } } }; return self; }); // Player character with integrated vision logic var Player = Container.expand(function () { var self = Container.call(this); // Player properties self.gridX = 10; // Starting X position on grid (max map) self.gridY = 10; // Starting Y position on grid (max map) self.moveSpeed = 0.2; // Movement animation speed self.moving = false; self.lastGridX = 10; self.lastGridY = 10; self.visionRadius = 2; // Reduced vision radius in blocks // Remove sub-tile logic: always center player in tile self.subTileX = 0; self.subTileY = 0; // New: quadrant label self.quadrantLabel = null; // Initialize player with graphics self.init = function () { var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5, y: -44 // Move player image 44px higher for better visual centering }); // Make player a bit bigger for better visibility playerGraphics.scale.set(0.34, 0.34); // Store reference for orientation logic self.playerGraphics = playerGraphics; // Always reset rotation and scale.x on init self.playerGraphics.rotation = 0; self.playerGraphics.scale.x = Math.abs(self.playerGraphics.scale.x); // Add quadrant label self.quadrantLabel = new Text2('', { size: 40, fill: 0xffff00 }); self.quadrantLabel.anchor.set(0.5, 1); self.quadrantLabel.x = 0; self.quadrantLabel.y = -TILE_SIZE / 4; self.addChild(self.quadrantLabel); // Load position from storage if available if (storage.playerPosition) { self.gridX = storage.playerPosition.x; self.gridY = storage.playerPosition.y; self.lastGridX = self.gridX; self.lastGridY = self.gridY; // Always force subTileX and subTileY to 0 (center) self.subTileX = 0; self.subTileY = 0; } else { // If not in storage, spawn at center of map self.gridX = 15; self.gridY = 15; self.lastGridX = 15; self.lastGridY = 15; self.subTileX = 0; self.subTileY = 0; } // Update position based on grid coordinates self.updatePosition(); // Always visually center player on screen after spawn self.x = self.gridX * TILE_SIZE + TILE_SIZE / 2; self.y = self.gridY * TILE_SIZE + TILE_SIZE / 2; return self; }; // Move player to specific grid coordinates self.moveToGrid = function (newGridX, newGridY) { if (self.moving) return; // Don't interrupt current movement // Store last position for comparison self.lastGridX = self.gridX; self.lastGridY = self.gridY; // --- Determine facing direction and update sprite orientation --- // We'll use self.facing: 'left', 'right', 'up', 'down' if (typeof self.facing === "undefined") self.facing = "down"; if (typeof self.playerGraphics === "undefined") self.playerGraphics = self.children[0]; // Assume first child is player sprite var dx = newGridX - self.gridX; var dy = newGridY - self.gridY; if (Math.abs(dx) > Math.abs(dy)) { // Horizontal move if (dx > 0) { self.facing = "right"; // Swap to 'player' asset if not already if (self.playerGraphics && self.playerGraphics.assetId !== 'player') { self.removeChild(self.playerGraphics); self.playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5, y: -44 }); self.playerGraphics.scale.set(0.34, 0.34); } if (self.playerGraphics) { self.playerGraphics.scale.x = Math.abs(self.playerGraphics.scale.x); // Face right (default) } } else if (dx < 0) { self.facing = "left"; // Swap to 'player' asset if not already if (self.playerGraphics && self.playerGraphics.assetId !== 'player') { self.removeChild(self.playerGraphics); self.playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5, y: -44 }); self.playerGraphics.scale.set(0.34, 0.34); } if (self.playerGraphics) { self.playerGraphics.scale.x = -Math.abs(self.playerGraphics.scale.x); // Flip horizontally to face left } } } else if (Math.abs(dy) > 0) { // Vertical move if (dy < 0) { self.facing = "up"; // Swap to 'player_up' asset if not already if (self.playerGraphics && self.playerGraphics.assetId !== 'player_up') { // Remove old graphic self.removeChild(self.playerGraphics); // Attach new up-facing asset self.playerGraphics = self.attachAsset('player_up', { anchorX: 0.5, anchorY: 0.5, y: -44 }); self.playerGraphics.scale.set(0.34, 0.34); } if (self.playerGraphics) { self.playerGraphics.scale.x = Math.abs(self.playerGraphics.scale.x); // Face right (default) self.playerGraphics.rotation = Math.PI; // Show back (rotate 180deg) } } else if (dy > 0) { self.facing = "down"; // Swap to 'player' asset if not already if (self.playerGraphics && self.playerGraphics.assetId !== 'player') { self.removeChild(self.playerGraphics); self.playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5, y: -44 }); self.playerGraphics.scale.set(0.34, 0.34); } if (self.playerGraphics) { self.playerGraphics.scale.x = Math.abs(self.playerGraphics.scale.x); // Face right (default) self.playerGraphics.rotation = 0; // Face forward } } } // If not moving vertically, always reset rotation if (Math.abs(dx) > 0 && Math.abs(dy) === 0 && self.playerGraphics) { self.playerGraphics.rotation = 0; } // Prevent movement onto dark (black) blocks if (typeof gameMap !== "undefined") { var targetTile = gameMap.getTileAt(newGridX, newGridY); if (targetTile && targetTile.biomeType === "dark") { // Block movement, do not update grid position return; } // Water entry animation: if moving into water, play animation // Only animate player if actually on a water tile (not on edge) if (targetTile && targetTile.biomeType === "water") { // No shaking or swimming animation when entering water self._inWaterSwim = false; } else { // If not in water, stop swimming animation if it was running if (self._inWaterSwim) { self._inWaterSwim = false; if (typeof tween !== "undefined") { tween.stop(self, { y: true }); } } } } // Update grid position (no sub-tile logic) self.gridX = newGridX; self.gridY = newGridY; self.subTileX = 0; self.subTileY = 0; // Save position to storage storage.playerPosition = { x: self.gridX, y: self.gridY, subTileX: self.subTileX, subTileY: self.subTileY }; // Animate movement and update vision after movement finishes self.moving = true; // Move to the center of the tile var offsetX = TILE_SIZE / 2; var offsetY = TILE_SIZE / 2; var targetMapX = self.gridX * TILE_SIZE + offsetX; var targetMapY = self.gridY * TILE_SIZE + offsetY; // Animate the map and player so the player appears to move smoothly and always stays centered on screen var startPlayerX = self.x; var startPlayerY = self.y; var startMapX = typeof gameMap !== "undefined" ? gameMap.x : 0; var startMapY = typeof gameMap !== "undefined" ? gameMap.y : 0; var endPlayerX = 1024; var endPlayerY = 1366; var endMapX = 1024 - targetMapX; var endMapY = 1366 - targetMapY; var playerTweenDuration = 350; var visionTweenDuration = 200; // Animate vision update to be much faster than player movement if (typeof gameMap !== "undefined" && typeof self.updateVision === "function") { var visionObj = { progress: 0 }; tween(visionObj, { progress: 1 }, { duration: visionTweenDuration, easing: tween.easeOut, onUpdate: function onUpdate() { self.updateVision(gameMap); } }); } // Animate both player and map for smooth movement tween({ t: 0 }, { t: 1 }, { duration: playerTweenDuration, easing: tween.easeOut, onUpdate: function onUpdate(obj) { // Interpolate player position (moves on map) self.x = startPlayerX + (targetMapX - startPlayerX) * obj.t; self.y = startPlayerY + (targetMapY - startPlayerY) * obj.t; // Animate map so player is always centered if (typeof gameMap !== "undefined") { gameMap.x = startMapX + (endMapX - startMapX) * obj.t; gameMap.y = startMapY + (endMapY - startMapY) * obj.t; } }, onFinish: function onFinish() { self.moving = false; // Snap to final positions self.x = targetMapX; // If current tile is water, keep the "bobbing" offset, else restore to normal var currentTile = typeof gameMap !== "undefined" ? gameMap.getTileAt(self.gridX, self.gridY) : null; if (currentTile && currentTile.biomeType === "water") { self.y = targetMapY; // Appear lower in water } else { self.y = targetMapY - 30; // Move player image 30px above tile center for better centering // If coming from water, stop any water bobbing animation and reset Y if (typeof tween !== "undefined") { tween.stop(self, { y: true }); } } if (typeof gameMap !== "undefined") { gameMap.x = endMapX; gameMap.y = endMapY; } // Only update vision after movement is complete for optimized vision if (typeof gameMap !== "undefined") { self.updateVision(gameMap); } } }); // Always clear quadrant label since player is always at center if (self.quadrantLabel) self.quadrantLabel.setText(''); // Call onQuadrantChange with 'CENTER' label for compatibility if (typeof self.onQuadrantChange === "function") { self.onQuadrantChange(self.gridX, self.gridY, self.subTileX, self.subTileY, 'CENTER'); } }; // Update position based on current grid coordinates (no animation) self.updatePosition = function () { // Position player at the center of the tile (no sub-tile logic) var offsetX = TILE_SIZE / 2; var offsetY = TILE_SIZE / 2; self.x = self.gridX * TILE_SIZE + offsetX; // If current tile is water, show player lower (no -30 offset) var currentTile = typeof gameMap !== "undefined" ? gameMap.getTileAt(self.gridX, self.gridY) : null; if (currentTile && currentTile.biomeType === "water") { self.y = self.gridY * TILE_SIZE + offsetY; } else { self.y = self.gridY * TILE_SIZE + offsetY - 30; // Move player image 30px above tile center for better centering } // Always reset player sprite orientation if not moving if (self.facing === "up") { if (!self.playerGraphics || self.playerGraphics.assetId !== 'player_up') { if (self.playerGraphics) self.removeChild(self.playerGraphics); self.playerGraphics = self.attachAsset('player_up', { anchorX: 0.5, anchorY: 0.5, y: -44 }); self.playerGraphics.scale.set(0.34, 0.34); } self.playerGraphics.scale.x = Math.abs(self.playerGraphics.scale.x); self.playerGraphics.rotation = Math.PI; } else if (self.facing === "left") { if (!self.playerGraphics || self.playerGraphics.assetId !== 'player') { if (self.playerGraphics) self.removeChild(self.playerGraphics); self.playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5, y: -44 }); self.playerGraphics.scale.set(0.34, 0.34); } self.playerGraphics.scale.x = -Math.abs(self.playerGraphics.scale.x); self.playerGraphics.rotation = 0; } else if (self.facing === "right") { if (!self.playerGraphics || self.playerGraphics.assetId !== 'player') { if (self.playerGraphics) self.removeChild(self.playerGraphics); self.playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5, y: -44 }); self.playerGraphics.scale.set(0.34, 0.34); } self.playerGraphics.scale.x = Math.abs(self.playerGraphics.scale.x); self.playerGraphics.rotation = 0; } else { if (!self.playerGraphics || self.playerGraphics.assetId !== 'player') { if (self.playerGraphics) self.removeChild(self.playerGraphics); self.playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5, y: -44 }); self.playerGraphics.scale.set(0.34, 0.34); } self.playerGraphics.scale.x = Math.abs(self.playerGraphics.scale.x); self.playerGraphics.rotation = 0; } // Hide player sprite if on dark (black) block if (typeof gameMap !== "undefined") { var tile = gameMap.getTileAt(self.gridX, self.gridY); // Do not hide player, but do not show dark tiles self.visible = true; // Mark this tile as discovered if not already if (tile && !tile.explored) { tile.explore(); } } else { self.visible = true; } // No longer force sub-tile to 0 (center) when updating position // Only update vision if not moving, to optimize vision updates if (!self.moving && typeof gameMap !== "undefined" && typeof self.updateVision === "function") { self.updateVision(gameMap); } // Always clear quadrant label since player is always at center if (self.quadrantLabel) self.quadrantLabel.setText(''); // Call onQuadrantChange with 'CENTER' label for compatibility if (typeof self.onQuadrantChange === "function") { self.onQuadrantChange(self.gridX, self.gridY, self.subTileX, self.subTileY, 'CENTER'); } // --- Rotate player if next to world border --- if (typeof self.rotation !== "undefined") { self.rotation = 0; } var nearBorder = false; var borderDir = 0; // 0=none, 1=left, 2=right, 3=top, 4=bottom if (self.gridX <= 0.5) { nearBorder = true; borderDir = 1; } else if (self.gridX >= MAP_WIDTH - 1) { nearBorder = true; borderDir = 2; } else if (self.gridY <= 0.5) { nearBorder = true; borderDir = 3; } else if (self.gridY >= MAP_HEIGHT - 1) { nearBorder = true; borderDir = 4; } if (nearBorder) { // Rotate player to indicate border direction if (borderDir === 1) self.rotation = Math.PI / 2; // Left: face down else if (borderDir === 2) self.rotation = -Math.PI / 2; // Right: face up // Remove upside-down rotation at top border (no Math.PI) else if (borderDir === 3) self.rotation = 0; // Top: normal (no upside down) else if (borderDir === 4) self.rotation = 0; // Bottom: normal } else { self.rotation = 0; } // Ensure player is always above the tile and centered after update if (typeof game !== "undefined" && self.parent !== game) { game.addChild(self); } self.scale.set(gameMap.scale.x, gameMap.scale.y); self.visible = true; // Always visually center player on screen after updatePosition // Now: player moves on map, so set to map position self.x = self.gridX * TILE_SIZE + TILE_SIZE / 2; self.y = self.gridY * TILE_SIZE + TILE_SIZE / 2; // Always bring player to top of display list if (typeof game !== "undefined" && typeof game.children !== "undefined") { if (game.children.indexOf(self) !== -1) { game.removeChild(self); game.addChild(self); } } }; // Update vision: show/hide tiles based on a circular vision area, and save seen tiles as memory self.updateVision = function (gameMap) { // Vision area: always center player in the middle of the vision area for optimized movement var visionRadius = 1; // Reduced from 2 to 1 for even fewer visible tiles and less lag var centerX = self.gridX; var centerY = self.gridY; var minX = Math.max(0, Math.floor(centerX - visionRadius)); var maxX = Math.min(MAP_WIDTH - 1, Math.ceil(centerX + visionRadius)); var minY = Math.max(0, Math.floor(centerY - visionRadius)); var maxY = Math.min(MAP_HEIGHT - 1, Math.ceil(centerY + visionRadius)); for (var y = 0; y < MAP_HEIGHT; y++) { for (var x = 0; x < MAP_WIDTH; x++) { var tile = gameMap.getTileAt(x, y); if (tile) { // Calculate distance from player - properly centered now var dx = x - centerX; var dy = y - centerY; // Only show tiles within a circular vision area (Euclidean distance <= visionRadius + 0.2 for smoothness) if (Math.sqrt(dx * dx + dy * dy) <= visionRadius + 0.2) { // Hide dark (out-of-world) tiles so black area is never shown if (tile.biomeType === "dark") { tile.visible = false; continue; } tile.visible = true; // Mark as explored and save to memory if (!tile.explored) { tile.explored = true; var exploredKey = x + "," + y; if (!storage.exploredTiles) storage.exploredTiles = {}; storage.exploredTiles[exploredKey] = true; } // No fog overlay to hide (fog removed) // --- Show both spawned and despawned creatures in vision --- // In vision area: show both spawned and despawned creatures // Remove all faded indicators first to avoid duplicates // If a creature is currently spawned, mark that this tile has ever had a creature if (tile.hasCreature) { tile._everHadCreature = true; } // Show indicator for spawned creature if (tile.hasCreature) { // --- Show creature visually on top of tile --- if (!tile._creatureVisual) { // Find the type of the creature for this tile from mapCreatures/mapCreatureTiles var creatureType = null; if (typeof mapCreatures !== "undefined" && typeof mapCreatureTiles !== "undefined") { for (var mci = 0; mci < mapCreatureTiles.length; mci++) { if (mapCreatureTiles[mci] === tile) { creatureType = mapCreatures[mci]; break; } } } // If not found, fallback to biomeType if (!creatureType) { // Use a default type for biome if (typeof Creature !== "undefined") { creatureType = new Creature().getRandomType(tile.biomeType); } else { creatureType = "normal"; } } // If biome is urban, use urbanCreature if (tile.biomeType === "urban") { creatureType = "urban"; } // Try to find the correct image asset for the cubixion (creature) type var creatureImageAsset = null; if (typeof Creature !== "undefined" && Creature.prototype && Creature.prototype.creatureList) { // Find a matching creature in the database for this type for (var ci = 0; ci < Creature.prototype.creatureList.length; ci++) { var c = Creature.prototype.creatureList[ci]; if (c.type === creatureType) { // Prefer image asset if available if (c.image && LK.assets && LK.assets[c.image]) { creatureImageAsset = c.image; } // If there is a specific image asset for this type+name, use it if (LK.assets && LK.assets["creature_" + c.id + "_" + c.name + "_" + c.type]) { creatureImageAsset = "creature_" + c.id + "_" + c.name + "_" + c.type; } break; } } } // Fallback to typeCreature if no image found if (!creatureImageAsset) { // Try to use a generic image for this type if available if (LK.assets && LK.assets[creatureType + "Cubixion"]) { creatureImageAsset = creatureType + "Cubixion"; } else { // As a last fallback, use a generic ellipse creatureImageAsset = "grassCubixion"; } } // Show the cubixion visually using the correct image asset var creatureVisual = LK.getAsset(creatureImageAsset, { anchorX: 0.5, anchorY: 0.5, x: TILE_SIZE / 2, y: TILE_SIZE / 2 }); creatureVisual.scale.set(1.2, 1.2); creatureVisual.alpha = 1.0; tile.addChild(creatureVisual); tile._creatureVisual = creatureVisual; } // Always bring creature visual to top if (tile._creatureVisual && tile.children.indexOf(tile._creatureVisual) !== -1) { tile.removeChild(tile._creatureVisual); tile.addChild(tile._creatureVisual); } } // Remove creature visual if not hasCreature if (!tile.hasCreature && tile._creatureVisual) { tile.removeChild(tile._creatureVisual); tile._creatureVisual = null; } // Show faded indicator for despawned creature (if ever had creature, but not currently spawned) if (tile._everHadCreature && !tile.hasCreature) { // Remove creature visual if not hasCreature if (tile._creatureVisual) { tile.removeChild(tile._creatureVisual); tile._creatureVisual = null; } } // --- End show both spawned and despawned creatures in vision --- } else { // Out of vision: hide all encounter indicators (spawned and despawned) in foggy/unvision area // Hide all creatures in foggy area: do not show any indicators or creatures tile.visible = true; // No fog overlay to show (fog removed) } } } // Called whenever the player moves to a new quadrant of a tile self.onQuadrantChange = function (gridX, gridY, subTileX, subTileY, label) { // Example: you can add your own logic here to check which quadrant the player is in // For example, trigger something if in DOWN LEFT // gridX, gridY: tile coordinates // subTileX, subTileY: 0 or 1 (0=left/up, 1=right/down) // label: string label of the quadrant }; // Example: log which quadrant the player is in // console.log("Player is at tile (" + gridX + "," + gridY + ") in quadrant: " + label); // You can add more logic here, e.g.: // if (subTileX === 0 && subTileY === 1) { /* DOWN LEFT */ } // if (subTileX === 1 && subTileY === 0) { /* UP RIGHT */ } // etc. } ; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // The following assets are initialized with the creature's name and element in the asset id for clarity // For demonstration, we use placeholder image ids. Replace with real ids as needed. // Example: LK.init.image('creature_0', {width:120, height:120, id:'<image_id>'}) // --- Creature image assets for all 100 unique creatures --- // Creature type base shapes (for fallback and type-based visuals) // Unique biome tile assets for each biome (example: add one more for each) // Unique image for urban biome // Sounds // Encounter indicator // UI elements // Creatures by elemental type // Map tiles // Player character // Storage for saving game progress // Tween for animations // Game dimensions and settings // JSON helper functions for parsing and stringifying // Out-of-world tile asset (default color, can be changed in MapTile) // Cubix (pokeball) image assets // Example: use Sproutle as basic cubix // Example: use Boulder as uncommon cubix // Example: use Voltix as rare cubix // Example: use desertTile as legendary cubix function _typeof4(o) { "@babel/helpers - typeof"; return _typeof4 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof4(o); } function _typeof3(o) { "@babel/helpers - typeof"; return _typeof3 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof3(o); } function _typeof2(o) { "@babel/helpers - typeof"; return _typeof2 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof2(o); } function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function parseJSON(str) { var result = {}; if (typeof str === 'string') { try { var pairs = str.slice(1, -1).split(','); for (var i = 0; i < pairs.length; i++) { var pair = pairs[i].trim().split(':'); var key = pair[0].replace(/["']/g, '').trim(); var value = pair[1].trim(); if (value.startsWith('[') && value.endsWith(']')) { result[key] = parseJSONArray(value); } else if (value.startsWith('{') && value.endsWith('}')) { result[key] = parseJSON(value); } else if (value === 'true') { result[key] = true; } else if (value === 'false') { result[key] = false; } else if (!isNaN(value)) { result[key] = Number(value); } else { result[key] = value.replace(/["']/g, ''); } } } catch (e) { console.log('Error parsing JSON: ', e); } } return result; } function parseJSONArray(str) { var result = []; if (typeof str === 'string') { try { var items = str.slice(1, -1).split(','); for (var i = 0; i < items.length; i++) { var item = items[i].trim(); if (item.startsWith('[') && item.endsWith(']')) { result.push(parseJSONArray(item)); } else if (item.startsWith('{') && item.endsWith('}')) { result.push(parseJSON(item)); } else if (item === 'true') { result.push(true); } else if (item === 'false') { result.push(false); } else if (!isNaN(item)) { result.push(Number(item)); } else { result.push(item.replace(/["']/g, '')); } } } catch (e) { console.log('Error parsing JSON array: ', e); } } return result; } function stringifyJSON(obj) { if (Array.isArray(obj)) { var items = []; for (var i = 0; i < obj.length; i++) { items.push(stringifyJSON(obj[i])); } return '[' + items.join(',') + ']'; } else if (_typeof(obj) === 'object' && obj !== null) { var pairs = []; for (var key in obj) { if (obj.hasOwnProperty(key)) { pairs.push('"' + key + '":' + stringifyJSON(obj[key])); } } return '{' + pairs.join(',') + '}'; } else if (typeof obj === 'string') { return '"' + obj.replace(/"/g, '\\"') + '"'; } else { return String(obj); } } var TILE_SIZE = 400 * 3; // Make each tile 3 times bigger than before var MAP_WIDTH = 80; // Make the map much larger var MAP_HEIGHT = 80; // Make the map much larger // Vision radius is now set in Player.updateVision for optimized vision area // Initialize game objects var gameMap = game.addChild(new GameMap().initMap()); gameMap.scale.set(1.5, 1.5); // Zoom in the map for a closer look // Remove special case for (0,0) tile, all tiles are now the same size (TILE_SIZE * 3) for (var y = 0; y < MAP_HEIGHT; y++) { var _loop = function _loop() { t = gameMap.getTileAt(x, y); if (t) { t.tileSize = TILE_SIZE; } }, t, originalY; for (var x = 0; x < MAP_WIDTH; x++) { _loop(); } } // Spawn player at a random non-water, non-dark tile, and ensure nothing else spawns at the same place at game start function findRandomValidPlayerStart(gameMap) { var validTiles = []; for (var y = 0; y < MAP_HEIGHT; y++) { for (var x = 0; x < MAP_WIDTH; x++) { var biome = gameMap.tiles && gameMap.tiles[y] && gameMap.tiles[y][x]; if (biome && biome !== "water" && biome !== "dark") { var tileObj = gameMap.getTileAt(x, y); // Defensive: skip if tileObj is missing or already has a creature/cubix // Prevent spawning on player's current tile if (tileObj && !tileObj.hasCreature && !tileObj._cubixVisual && !tileObj._creatureVisual && !(tileObj.gridX === Math.round(playerStartX) && tileObj.gridY === Math.round(playerStartY))) { validTiles.push({ x: x, y: y }); } } } } // Pick a random valid tile, fallback to 0,0 if none found if (validTiles.length > 0) { return validTiles[Math.floor(Math.random() * validTiles.length)]; } return { x: 0, y: 0 }; } var validStart = findRandomValidPlayerStart(gameMap); var playerStartX = validStart.x; var playerStartY = validStart.y; // Ensure start tile is not water or dark for consistency if (gameMap.tiles && gameMap.tiles[playerStartY] && gameMap.tiles[playerStartY][playerStartX]) { if (gameMap.tiles[playerStartY][playerStartX] === "water" || gameMap.tiles[playerStartY][playerStartX] === "dark") { gameMap.tiles[playerStartY][playerStartX] = "grass"; var tileObj = gameMap.getTileAt(playerStartX, playerStartY); if (tileObj) { tileObj.biomeType = "grass"; tileObj.tileSize = TILE_SIZE; } } else { var tileObj = gameMap.getTileAt(playerStartX, playerStartY); if (tileObj) { tileObj.biomeType = gameMap.tiles[playerStartY][playerStartX]; tileObj.tileSize = TILE_SIZE; } } } storage.playerPosition = { x: playerStartX, y: playerStartY, subTileX: 0, subTileY: 0 }; var player = new Player().init(); player.gridX = playerStartX; player.gridY = playerStartY; player.lastGridX = playerStartX; player.lastGridY = playerStartY; player.subTileX = 0; player.subTileY = 0; player.updatePosition(); centerViewOnPlayer(); centerViewOnPlayer(); // Prevent spawning cubix/cubixion on the same tile as the player at game start var playerStartTile = gameMap.getTileAt(playerStartX, playerStartY); if (playerStartTile) { // Remove cubix visual if present if (playerStartTile._cubixVisual) { playerStartTile.removeChild(playerStartTile._cubixVisual); playerStartTile._cubixVisual = null; if (typeof mapCubixTiles !== "undefined" && typeof mapCubix !== "undefined") { for (var i = mapCubixTiles.length - 1; i >= 0; i--) { if (mapCubixTiles[i] === playerStartTile) { mapCubix.splice(i, 1); mapCubixTiles.splice(i, 1); break; } } } } // Remove cubixion (creature) visual if present if (playerStartTile._creatureVisual) { playerStartTile.removeChild(playerStartTile._creatureVisual); playerStartTile._creatureVisual = null; playerStartTile.hasCreature = false; if (typeof mapCreatureTiles !== "undefined" && typeof mapCreatures !== "undefined" && typeof mapCreatureLabels !== "undefined") { for (var i = mapCreatureTiles.length - 1; i >= 0; i--) { if (mapCreatureTiles[i] === playerStartTile) { // Defensive: Only remove label if it exists and index is valid if (Array.isArray(mapCreatureLabels) && i < mapCreatureLabels.length && mapCreatureLabels[i]) { playerStartTile.removeChild(mapCreatureLabels[i]); mapCreatureLabels.splice(i, 1); } // Defensive: Only remove from mapCreatures and mapCreatureTiles if index is valid if (Array.isArray(mapCreatures) && i < mapCreatures.length) { mapCreatures.splice(i, 1); } if (Array.isArray(mapCreatureTiles) && i < mapCreatureTiles.length) { mapCreatureTiles.splice(i, 1); } break; } } } } } // player.x and player.y are set by updatePosition and movement now // Ensure player is always above all map tiles and scaled to match map player.scale.set(gameMap.scale.x, gameMap.scale.y); // Always add player after gameMap so it is above all tiles if (player.parent !== game) { game.addChild(player); } player.visible = true; // Explicitly set player visible in case it was hidden // Mark starting tile as explored and discovered var startTile2 = gameMap.getTileAt(playerStartX, playerStartY); if (startTile2 && !startTile2.explored) { startTile2.explore(); } var dpad = game.addChild(new DPad().init()); var minimap = game.addChild(new MiniMap().init()); var encounter = game.addChild(new Encounter().init()); var collection = game.addChild(new Collection().init()); // Collection button (top right corner) var collectionButton = game.attachAsset('dpadButton', { anchorX: 0.5, anchorY: 0.5, x: 1900, y: 150, scaleX: 1.5, scaleY: 1.5 }); collectionButton.interactive = true; // Collection button icon var collectionText = new Text2('COL', { size: 48, fill: 0xFFFFFF }); collectionText.anchor.set(0.5, 0.5); collectionText.x = 1900; collectionText.y = 150; game.addChild(collectionText); // Game variables var encounterActive = false; var exploredCount = 0; var totalTiles = MAP_WIDTH * MAP_HEIGHT; // Cubix inventory UI // Removed cubixInventoryText from main UI (Cubix inventory is shown in collection menu) // Define playerCubix in global scope if not already defined // Reset playerCubix and Cubixion collection at game start var playerCubix = { basic: 10, uncommon: 0, rare: 0, legendary: 0 }; // Remove all Cubix except 10 basic Cubix from storage and window at game start if (typeof storage !== "undefined") { if (typeof storage.set === "function") { storage.set("playerCubix", { basic: 10, uncommon: 0, rare: 0, legendary: 0 }); storage.set("playerCubixionCollection", {}); // Reset Cubixion collection } else { storage.playerCubix = { basic: 10, uncommon: 0, rare: 0, legendary: 0 }; storage.playerCubixionCollection = {}; } } if (typeof window !== "undefined") { window.playerCubix = { basic: 10, uncommon: 0, rare: 0, legendary: 0 }; window.playerCubixionCollection = {}; } // Defensive: always sync playerCubix to storage and global scope after every update function syncPlayerCubix() { if (typeof storage !== "undefined") { if (typeof storage.set === "function") { storage.set("playerCubix", playerCubix); } else { // fallback for legacy: assign a shallow copy to avoid circular reference storage.playerCubix = { basic: playerCubix.basic, uncommon: playerCubix.uncommon, rare: playerCubix.rare, legendary: playerCubix.legendary }; } } if (typeof window !== "undefined") { window.playerCubix = playerCubix; } } // Cubixion collection and gem system var playerCubixionCollection = {}; // {creatureId: {count: 0, gems: 0}} // Reset Cubixion collection at game start if (typeof storage !== "undefined") { if (typeof storage.set === "function") { storage.set("playerCubixionCollection", {}); } else { storage.playerCubixionCollection = {}; } } if (typeof window !== "undefined") { window.playerCubixionCollection = {}; } // Removed updateCubixInventoryText and its calls (Cubix inventory now shown in collection menu) // Update stats display // (removed: no stats text shown) // Center the game view on player function centerViewOnPlayer() { // Always center the map so the player is visually centered on screen if (typeof gameMap !== "undefined" && typeof player !== "undefined") { // Calculate the target position for the map so player is at (1024, 1366) var offsetX = TILE_SIZE / 2; var offsetY = TILE_SIZE / 2; var targetMapX = player.gridX * TILE_SIZE + offsetX; var targetMapY = player.gridY * TILE_SIZE + offsetY; // Adjust for zoom (scale) var scaleX = gameMap.scale.x; var scaleY = gameMap.scale.y; gameMap.x = 1024 - targetMapX * scaleX; gameMap.y = 1366 - targetMapY * scaleY; // Place player at the center of the screen player.x = 1024; player.y = 1336; // Move player image 30px above tile center for better centering // Ensure player is always visually centered in the tile // (player.x, player.y are always the center of the tile in world coordinates) } // Ensure player is above tiles if (player.parent !== game) { game.addChild(player); } player.scale.set(gameMap.scale.x, gameMap.scale.y); player.visible = true; } // Handle player movement from DPad (move exactly 1 block per input) dpad.upButton.down = function () { if (!player.moving && !encounterActive && !collection.visible) { // Move exactly 0.25 tile up per press var newGridY = player.gridY - 0.25; if (newGridY < 0) newGridY = 0; // Prevent moving into black area (dark biome) var targetTile = gameMap.getTileAt(Math.round(player.gridX), Math.round(newGridY)); if (targetTile && targetTile.biomeType !== "dark") { player.moveToGrid(player.gridX, newGridY); } } }; dpad.downButton.down = function () { if (!player.moving && !encounterActive && !collection.visible) { // Move exactly 0.25 tile down per press var newGridY = player.gridY + 0.25; if (newGridY > MAP_HEIGHT - 1) newGridY = MAP_HEIGHT - 1; // Prevent moving into black area (dark biome) var targetTile = gameMap.getTileAt(Math.round(player.gridX), Math.round(newGridY)); if (targetTile && targetTile.biomeType !== "dark") { player.moveToGrid(player.gridX, newGridY); } } }; dpad.leftButton.down = function () { if (!player.moving && !encounterActive && !collection.visible) { // Move exactly 0.25 tile left per press var newGridX = player.gridX - 0.25; if (newGridX < 0) newGridX = 0; // Prevent moving into black area (dark biome) var targetTile = gameMap.getTileAt(Math.round(newGridX), Math.round(player.gridY)); if (targetTile && targetTile.biomeType !== "dark") { player.moveToGrid(newGridX, player.gridY); } } }; dpad.rightButton.down = function () { if (!player.moving && !encounterActive && !collection.visible) { // Move exactly 0.25 tile right per press var newGridX = player.gridX + 0.25; if (newGridX > MAP_WIDTH - 1) newGridX = MAP_WIDTH - 1; // Prevent moving into black area (dark biome) var targetTile = gameMap.getTileAt(Math.round(newGridX), Math.round(player.gridY)); if (targetTile && targetTile.biomeType !== "dark") { player.moveToGrid(newGridX, player.gridY); } } }; // Always start the player centered in the vision area player.gridX = playerStartX; player.gridY = playerStartY; player.lastGridX = playerStartX; player.lastGridY = playerStartY; player.updatePosition(); centerViewOnPlayer(); // Handle collection button collectionButton.down = function () { if (!encounterActive) { // Hide collection button and text when menu is open collectionButton.visible = false; collectionText.visible = false; // Always reload the bag menu for all creatures if (typeof collection.show === "function") { collection.show(); } // Show exit button in collection menu if (!collection.exitButton) { collection.exitButton = collection.attachAsset('dpadButton', { anchorX: 0.5, anchorY: 0.5, x: 1900, y: 150 }); collection.exitButton.interactive = true; var exitText = new Text2('EXIT', { size: 48, fill: 0xFFFFFF }); exitText.anchor.set(0.5, 0.5); exitText.x = 1900; exitText.y = 150; collection.addChild(exitText); collection.exitButton.exitText = exitText; collection.exitButton.down = function () { collection.hide(); // Show player and collection button again player.visible = true; collectionButton.visible = true; collectionText.visible = true; // Hide exit button and text if (collection.exitButton) { collection.exitButton.visible = false; if (collection.exitButton.exitText) { collection.exitButton.exitText.visible = false; } } }; } // Show exit button and text if (collection.exitButton) { collection.exitButton.visible = true; if (collection.exitButton.exitText) { collection.exitButton.exitText.visible = true; } } } }; // Handle collection close button collection.closeButton.down = function () { collection.hide(); // Show player and collection button again player.visible = true; collectionButton.visible = true; collectionText.visible = true; // Hide exit button and text if (collection.exitButton) { collection.exitButton.visible = false; if (collection.exitButton.exitText) { collection.exitButton.exitText.visible = false; } } }; // Track last player position to detect changes var lastPlayerGridX = player.gridX; var lastPlayerGridY = player.gridY; // --- Cubix system --- // Cubix rarities and their catch chances if (typeof cubixTypes === "undefined") { var cubixTypes = [{ id: 'cubix_basic', name: 'Basic Cubix', color: 0xffffff, rarity: 'basic', catchBonus: 0, chance: 0.5 }, { id: 'cubix_uncommon', name: 'Uncommon Cubix', color: 0x00ff00, rarity: 'uncommon', catchBonus: 0.15, chance: 0.65 }, { id: 'cubix_rare', name: 'Rare Cubix', color: 0x0000ff, rarity: 'rare', catchBonus: 0.3, chance: 0.8 }, { id: 'cubix_legendary', name: 'Legendary Cubix', color: 0xffd700, rarity: 'legendary', catchBonus: 0.5, chance: 0.95 }]; } // Main game update loop // Throttle update to 30FPS (every ~33ms) for better performance var lastUpdateTime = 0; game.update = function () { var now = Date.now(); if (lastUpdateTime && now - lastUpdateTime < 33) { // Defensive: check for undefined before accessing array index to prevent TypeError if (typeof mapCubixTiles === "undefined" || typeof mapCubix === "undefined") { return; } // Defensive: check for undefined or empty arrays before accessing index 0 if (!Array.isArray(mapCubixTiles) || !Array.isArray(mapCubix) || typeof mapCubixTiles[0] === "undefined" || typeof mapCubix[0] === "undefined") { return; } return; } lastUpdateTime = now; // Player's cubix inventory (legacy pokeball variable replaced) if (typeof playerCubix === "undefined") { playerCubix = { basic: 3, uncommon: 1, rare: 0, legendary: 0 }; } // Defensive: always sync playerCubix to storage and global scope at start of update syncPlayerCubix(); // Cubix map objects (legacy pokeball variable replaced) if (typeof mapCubix === "undefined") { mapCubix = []; mapCubixTiles = []; mapCubixMax = 12; // Max cubix on map at once (reduced for performance) mapCubixSpawnCooldown = 0; } // --- Creature spawn/despawn logic --- // We'll use a global array to track visible creatures on the map if (typeof mapCreatures === "undefined") { mapCreatures = []; mapCreatureTiles = []; mapCreatureLabels = []; mapCreatureMax = 12; // Max creatures on map at once (reduced for performance) mapCreatureSpawnCooldown = 0; } // --- Add despawn timer for cubixion (creature) spawns: despawn after 5 minutes (300 seconds) --- var nowTime = Date.now(); for (var i = mapCreatures.length - 1; i >= 0; i--) { // Defensive: skip if arrays are out of sync or index is out of bounds if (!mapCreatureTiles || !mapCreatures || i >= mapCreatureTiles.length || i >= mapCreatures.length) { continue; } var tile = mapCreatureTiles[i]; // Defensive: skip if tile is undefined if (typeof tile === "undefined" || tile === null) { continue; } // Prevent despawn if player is currently on this tile if (player && Math.round(player.gridX) === tile.gridX && Math.round(player.gridY) === tile.gridY) { // Do not run despawn logic for this tile while player is on it continue; } // Initialize spawn timestamp if not set if (tile && typeof tile._creatureSpawnedAt === "undefined") { tile._creatureSpawnedAt = nowTime; } // Prevent despawn until it has spawned for 5 minutes (300000 ms) // (No despawn here, so skip this block entirely) // --- Keep original explored despawn logic --- // Initialize despawn timer if not set if (tile && typeof tile._creatureDespawnTimer === "undefined") { tile._creatureDespawnTimer = 0; } // If tile is explored, start despawn timer if (tile && tile.explored) { tile._creatureDespawnTimer++; // Only despawn if timer exceeds threshold (e.g. 90 frames ~1.5s) if (tile._creatureDespawnTimer > 90) { if (typeof mapCreatureLabels !== "undefined" && Array.isArray(mapCreatureLabels) && i < mapCreatureLabels.length && typeof mapCreatureLabels[i] !== "undefined" && mapCreatureLabels[i]) { if (tile) tile.removeChild(mapCreatureLabels[i]); mapCreatureLabels.splice(i, 1); } if (tile && tile.hasCreature) { tile.hasCreature = false; } // Defensive: Only remove from mapCreatures and mapCreatureTiles if index is valid if (Array.isArray(mapCreatures) && i < mapCreatures.length && typeof mapCreatures[i] !== "undefined") { mapCreatures.splice(i, 1); } if (Array.isArray(mapCreatureTiles) && i < mapCreatureTiles.length && typeof mapCreatureTiles[i] !== "undefined") { mapCreatureTiles.splice(i, 1); } continue; } } else if (!tile || Math.random() < 0.002) { // Lower random despawn chance // Defensive: Only remove label if arrays and index are valid if (typeof mapCreatureLabels !== "undefined" && Array.isArray(mapCreatureLabels) && i < mapCreatureLabels.length && mapCreatureLabels[i] !== undefined) { if (tile) tile.removeChild(mapCreatureLabels[i]); mapCreatureLabels.splice(i, 1); } if (tile && tile.hasCreature) { tile.hasCreature = false; } // Defensive: Only remove from mapCreatures and mapCreatureTiles if arrays and index are valid if (typeof mapCreatures !== "undefined" && Array.isArray(mapCreatures) && i < mapCreatures.length && mapCreatures[i] !== undefined) { mapCreatures.splice(i, 1); } if (typeof mapCreatureTiles !== "undefined" && Array.isArray(mapCreatureTiles) && i < mapCreatureTiles.length && mapCreatureTiles[i] !== undefined) { mapCreatureTiles.splice(i, 1); } continue; } else if (tile) { // Reset timer if not explored tile._creatureDespawnTimer = 0; } } // --- Cubix no longer despawn after 5 minutes (despawn logic removed) --- // --- Guarantee at least one cubixion (creature) is always visible and collectible on the player's screen (vision area) --- (function guaranteeCubixionOnScreen() { // Get player's vision area var visionRadius = 2; var px = Math.round(player.gridX); var py = Math.round(player.gridY); var foundOnScreen = false; // Check if any visible, collectible cubixion is in vision for (var y = py - visionRadius; y <= py + visionRadius; y++) { for (var x = px - visionRadius; x <= px + visionRadius; x++) { var tile = gameMap.getTileAt(x, y); if (tile && tile.hasCreature && tile.visible && !tile._creatureCaught) { foundOnScreen = true; break; } } if (foundOnScreen) break; } // If not, spawn one in a random visible, collectible tile in vision if (!foundOnScreen) { var candidates = []; for (var y = py - visionRadius; y <= py + visionRadius; y++) { for (var x = px - visionRadius; x <= px + visionRadius; x++) { var tile = gameMap.getTileAt(x, y); // Prevent spawning on player's current tile if (tile && tile.visible && tile.biomeType !== "dark" && !tile.hasCreature && !tile._cubixVisual && !tile._creatureCaught && !(tile.gridX === Math.round(player.gridX) && tile.gridY === Math.round(player.gridY))) { candidates.push(tile); } } } if (candidates.length > 0) { var foundTile = candidates[Math.floor(Math.random() * candidates.length)]; var cType = new Creature().getRandomType(foundTile.biomeType); var rarityRand = Math.random(); var rarity = "common"; if (rarityRand < 0.60) rarity = "common";else if (rarityRand < 0.85) rarity = "uncommon";else if (rarityRand < 0.96) rarity = "rare";else if (rarityRand < 0.995) rarity = "epic";else rarity = "legendary"; foundTile.hasCreature = true; mapCreatures.push({ type: cType, rarity: rarity }); mapCreatureTiles.push(foundTile); mapCreatureLabels.push(null); // Also ensure the visual is created for the cubixion if (!foundTile._creatureVisual) { var creatureImageAsset = null; if (typeof Creature !== "undefined" && Creature.prototype && Creature.prototype.creatureList) { for (var ci = 0; ci < Creature.prototype.creatureList.length; ci++) { var c = Creature.prototype.creatureList[ci]; if (c.type === cType) { if (c.image && LK.assets && LK.assets[c.image]) { creatureImageAsset = c.image; } if (LK.assets && LK.assets["creature_" + c.id + "_" + c.name + "_" + c.type]) { creatureImageAsset = "creature_" + c.id + "_" + c.name + "_" + c.type; } break; } } } // Fallback to typeCubixion if no image found if (!creatureImageAsset) { if (LK.assets && LK.assets[cType + "Cubixion"]) { creatureImageAsset = cType + "Cubixion"; } else { creatureImageAsset = "grassCubixion"; } } var creatureVisual = LK.getAsset(creatureImageAsset, { anchorX: 0.5, anchorY: 0.5, x: TILE_SIZE / 2, y: TILE_SIZE / 2 }); creatureVisual.scale.set(1.2, 1.2); creatureVisual.alpha = 1.0; foundTile.addChild(creatureVisual); foundTile._creatureVisual = creatureVisual; } } } })(); // --- Guarantee at least one cubix is always visible and collectible on the player's screen (vision area) --- (function guaranteeCubixOnScreen() { var visionRadius = 2; var px = Math.round(player.gridX); var py = Math.round(player.gridY); var foundOnScreen = false; // Check if any visible, collectible cubix is in vision for (var y = py - visionRadius; y <= py + visionRadius; y++) { for (var x = px - visionRadius; x <= px + visionRadius; x++) { var tile = gameMap.getTileAt(x, y); if (tile && tile._cubixVisual && tile.visible) { foundOnScreen = true; break; } } if (foundOnScreen) break; } // If not, spawn one in a random visible, collectible tile in vision if (!foundOnScreen) { var candidates = []; for (var y = py - visionRadius; y <= py + visionRadius; y++) { for (var x = px - visionRadius; x <= px + visionRadius; x++) { var tile = gameMap.getTileAt(x, y); // Prevent spawning on player's current tile if (tile && tile.visible && tile.biomeType !== "dark" && !tile.hasCreature && !tile._cubixVisual && !(tile.gridX === Math.round(player.gridX) && tile.gridY === Math.round(player.gridY))) { candidates.push(tile); } } } if (candidates.length > 0) { var foundCubixTile = candidates[Math.floor(Math.random() * candidates.length)]; var rand = Math.random(); var cType = cubixTypes[0]; if (rand > 0.7) cType = cubixTypes[3]; // Legendary: 30% else if (rand > 0.45) cType = cubixTypes[2]; // Rare: 25% else if (rand > 0.2) cType = cubixTypes[1]; // Uncommon: 25% // Basic: 20% var cubixVisual = LK.getAsset('cubix_' + (cType && typeof cType.rarity !== "undefined" ? cType.rarity : "basic"), { anchorX: 0.5, anchorY: 0.5, x: TILE_SIZE / 2, y: TILE_SIZE / 2 }); cubixVisual.scale.set(0.5, 0.5); foundCubixTile.addChild(cubixVisual); foundCubixTile._cubixVisual = cubixVisual; cubixVisual.assetId = 'cubix_' + (cType && typeof cType.rarity !== "undefined" ? cType.rarity : "basic"); if (cType && typeof cType.rarity !== "undefined") { mapCubix.push(cType.rarity); } else { mapCubix.push("basic"); } mapCubixTiles.push(foundCubixTile); } } })(); // Spawn new creatures sometimes, up to max if (mapCreatures.length < mapCreatureMax && mapCreatureSpawnCooldown <= 0) { // Try to spawn a new creature var tries = 0; // --- New: spawn near player if standing still --- var spawnNearPlayer = false; if (typeof lastPlayerGridX !== "undefined" && typeof lastPlayerGridY !== "undefined") { if (player.gridX === lastPlayerGridX && player.gridY === lastPlayerGridY) { // 30% chance to try to spawn near player if standing still if (Math.random() < 0.3) spawnNearPlayer = true; } } if (spawnNearPlayer) { // Try to spawn in a random adjacent tile (including diagonals) var px = Math.round(player.gridX); var py = Math.round(player.gridY); var adjacents = []; for (var dx = -1; dx <= 1; dx++) { for (var dy = -1; dy <= 1; dy++) { if (dx === 0 && dy === 0) continue; var nx = px + dx; var ny = py + dy; if (nx >= 0 && nx < MAP_WIDTH && ny >= 0 && ny < MAP_HEIGHT) { var t = gameMap.getTileAt(nx, ny); if (t && !t.explored && !t.hasCreature && t.biomeType !== "dark") { adjacents.push(t); } } } } if (adjacents.length > 0) { var tile = adjacents[Math.floor(Math.random() * adjacents.length)]; // Mark tile as having a creature tile.hasCreature = true; var cType = new Creature().getRandomType(tile.biomeType); mapCreatures.push(cType); mapCreatureTiles.push(tile); mapCreatureLabels.push(null); // Only one spawn near player per update tries = 15; } } // Only spawn cubixion (creature) in player's nearest area (vision radius) var px = Math.round(player.gridX); var py = Math.round(player.gridY); var visionRadius = 2; var spawnCandidates = []; for (var y = py - visionRadius; y <= py + visionRadius; y++) { for (var x = px - visionRadius; x <= px + visionRadius; x++) { var tile = gameMap.getTileAt(x, y); var crossable = tile && tile.biomeType !== "dark"; // Prevent spawning on player's current tile if (tile && !tile.hasCreature && crossable && !tile._cubixVisual && !(tile.gridX === Math.round(player.gridX) && tile.gridY === Math.round(player.gridY))) { spawnCandidates.push(tile); } } } var tries = 0; while (tries < 200 && mapCreatures.length < mapCreatureMax && spawnCandidates.length > 0) { // Pick a random candidate tile near player var tile = spawnCandidates[Math.floor(Math.random() * spawnCandidates.length)]; // Mark tile as having a creature tile.hasCreature = true; // Pick a random type for this biome var cType = new Creature().getRandomType(tile.biomeType); // Assign rarity with much higher chance for rare/epic/legendary var rarityRand = Math.random(); var rarity = "common"; if (rarityRand < 0.45) rarity = "common";else if (rarityRand < 0.7) rarity = "uncommon";else if (rarityRand < 0.88) rarity = "rare";else if (rarityRand < 0.97) rarity = "epic";else rarity = "legendary"; mapCreatures.push({ type: cType, rarity: rarity }); mapCreatureTiles.push(tile); mapCreatureLabels.push(null); // Remove this tile from candidates so we don't double-spawn var idx = spawnCandidates.indexOf(tile); if (idx !== -1) spawnCandidates.splice(idx, 1); tries++; } // Reduce cooldown for much faster respawn (was 180 + Math.floor(Math.random() * 120)) mapCreatureSpawnCooldown = 20 + Math.floor(Math.random() * 10); // 0.33-0.5s, much faster } else { mapCreatureSpawnCooldown--; } // --- Cubix spawn logic with max 30, image, and no despawn --- if (typeof mapCubix === "undefined") { mapCubix = []; mapCubixTiles = []; mapCubixMax = 30; // Max cubix on map at once mapCubixSpawnCooldown = 0; } // Remove despawn logic: cubix will not despawn anymore // --- Guarantee at least one cubix is always visible on the map --- // If there are no cubix spawns, guarantee at least one lowest rarity cubix is spawned if (mapCubix.length === 0) { // Find a random valid tile for lowest rarity cubix var foundTile = null; for (var attempt = 0; attempt < 200; attempt++) { var gx = Math.floor(Math.random() * MAP_WIDTH); var gy = Math.floor(Math.random() * MAP_HEIGHT); var tile = gameMap.getTileAt(gx, gy); var crossable = tile && tile.biomeType !== "dark" && !tile.hasCreature && !tile._cubixVisual; // Prevent spawning on player's current tile if (tile && crossable && !(tile.gridX === Math.round(player.gridX) && tile.gridY === Math.round(player.gridY))) { foundTile = tile; break; } } if (foundTile) { // Always spawn a random cubix (any rarity) if map is empty var rand = Math.random(); var cType = cubixTypes[0]; if (rand > 0.7) cType = cubixTypes[3]; // Legendary: 30% else if (rand > 0.45) cType = cubixTypes[2]; // Rare: 25% else if (rand > 0.2) cType = cubixTypes[1]; // Uncommon: 25% // Basic: 20% var cubixVisual = LK.getAsset('cubix_' + (cType && typeof cType.rarity !== "undefined" ? cType.rarity : "basic"), { anchorX: 0.5, anchorY: 0.5, x: TILE_SIZE / 2, y: TILE_SIZE / 2 }); cubixVisual.scale.set(0.5, 0.5); foundTile.addChild(cubixVisual); foundTile._cubixVisual = cubixVisual; cubixVisual.assetId = 'cubix_' + (cType && typeof cType.rarity !== "undefined" ? cType.rarity : "basic"); if (cType && typeof cType.rarity !== "undefined") { mapCubix.push(cType.rarity); } else { mapCubix.push("basic"); } mapCubixTiles.push(foundTile); } } // Continue normal spawn logic, but never exceed max 30 if (mapCubix.length < mapCubixMax && mapCubixSpawnCooldown <= 0) { var tries = 0; // --- New: spawn cubix near player if standing still --- var spawnCubixNearPlayer = false; if (typeof lastPlayerGridX !== "undefined" && typeof lastPlayerGridY !== "undefined") { if (player.gridX === lastPlayerGridX && player.gridY === lastPlayerGridY) { // 30% chance to try to spawn cubix near player if standing still if (Math.random() < 0.3) spawnCubixNearPlayer = true; } } if (spawnCubixNearPlayer) { // Try to spawn in a random adjacent tile (including diagonals) var px = Math.round(player.gridX); var py = Math.round(player.gridY); var adjacents = []; for (var dx = -1; dx <= 1; dx++) { for (var dy = -1; dy <= 1; dy++) { if (dx === 0 && dy === 0) continue; var nx = px + dx; var ny = py + dy; if (nx >= 0 && nx < MAP_WIDTH && ny >= 0 && ny < MAP_HEIGHT) { var t = gameMap.getTileAt(nx, ny); var crossable = t && t.biomeType !== "dark" && !t.hasCreature && !t._cubixVisual; if (t && !t.explored && crossable) { adjacents.push(t); } } } } if (adjacents.length > 0) { var tile = adjacents[Math.floor(Math.random() * adjacents.length)]; // Pick a random cubix type (weighted: much more rare/legendary spawns) var rand = Math.random(); var cType = cubixTypes[0]; if (rand > 0.7) cType = cubixTypes[3]; // Legendary: 30% else if (rand > 0.45) cType = cubixTypes[2]; // Rare: 25% else if (rand > 0.2) cType = cubixTypes[1]; // Uncommon: 25% // Basic: 20% // Show cubix on tile with correct rarity image var cubixVisual = LK.getAsset('cubix_' + (cType && typeof cType.rarity !== "undefined" ? cType.rarity : "basic"), { anchorX: 0.5, anchorY: 0.5, x: TILE_SIZE / 2, y: TILE_SIZE / 2 }); cubixVisual.scale.set(0.5, 0.5); tile.addChild(cubixVisual); tile._cubixVisual = cubixVisual; cubixVisual.assetId = 'cubix_' + (cType && typeof cType.rarity !== "undefined" ? cType.rarity : "basic"); if (cType && typeof cType.rarity !== "undefined") { mapCubix.push(cType.rarity); } else { mapCubix.push("basic"); } mapCubixTiles.push(tile); // Only one spawn near player per update tries = 60; } } // Increase number of tries and increase spawn rate for more cubix spawns // Make cubix spawn rate 10x higher than cubixion by increasing tries 10x // Spawn cubix in a much wider area and for all types (not just adjacent or limited tiles) while (tries < 400 && mapCubix.length < mapCubixMax) { var gx = Math.floor(Math.random() * MAP_WIDTH); var gy = Math.floor(Math.random() * MAP_HEIGHT); var tile = gameMap.getTileAt(gx, gy); // Only spawn on tiles that are not dark, not already with a cubix or creature var crossable = tile && tile.biomeType !== "dark" && !tile.hasCreature && !tile._cubixVisual; // Prevent spawning on player's current tile if (tile && crossable && !(tile.gridX === Math.round(player.gridX) && tile.gridY === Math.round(player.gridY))) { // Greatly increase spawn chance per tile (much higher for all types/rarities) if (Math.random() < 0.98) { // Instead of only using weighted cubixTypes, allow all types to spawn // Pick a random cubix type from all available types var cType = cubixTypes[Math.floor(Math.random() * cubixTypes.length)]; // Show cubix on tile with correct rarity image var cubixVisual = LK.getAsset('cubix_' + (cType && typeof cType.rarity !== "undefined" ? cType.rarity : "basic"), { anchorX: 0.5, anchorY: 0.5, x: TILE_SIZE / 2, y: TILE_SIZE / 2 }); cubixVisual.scale.set(0.5, 0.5); tile.addChild(cubixVisual); tile._cubixVisual = cubixVisual; cubixVisual.assetId = 'cubix_' + (cType && typeof cType.rarity !== "undefined" ? cType.rarity : "basic"); if (cType && typeof cType.rarity !== "undefined") { mapCubix.push(cType.rarity); } else { mapCubix.push("basic"); } mapCubixTiles.push(tile); } } tries++; } // Reduce cooldown for much faster respawn (was 120 + Math.floor(Math.random() * 120)) mapCubixSpawnCooldown = 10 + Math.floor(Math.random() * 10); // 0.16-0.33s, much faster } else { mapCubixSpawnCooldown--; } // --- End creature spawn/despawn logic --- // --- Cubix collection logic --- // Always allow collection if player is on the tile with cubix (any type/rarity) var playerTile = gameMap.getTileAt(player.gridX, player.gridY); if (playerTile && playerTile._cubixVisual) { var foundType = null; for (var i = 0; i < cubixTypes.length; i++) { if (playerTile._cubixVisual.assetId === 'cubix_' + cubixTypes[i].rarity) { foundType = cubixTypes[i]; break; } } if (foundType) { // Add to inventory (bag) for use in catching cubixion if (!playerCubix[foundType.rarity]) playerCubix[foundType.rarity] = 0; playerCubix[foundType.rarity]++; // Defensive: always sync playerCubix to storage and global scope after change syncPlayerCubix(); // Remove cubix from map (despawn) if (playerTile._cubixVisual && playerTile.children.indexOf(playerTile._cubixVisual) !== -1) { playerTile.removeChild(playerTile._cubixVisual); } playerTile._cubixVisual = null; // Remove from arrays for optimization if (typeof mapCubixTiles !== "undefined" && typeof mapCubix !== "undefined") { for (var i = mapCubixTiles.length - 1; i >= 0; i--) { // Defensive: check mapCubixTiles[i] is defined before comparing if (typeof mapCubixTiles[i] !== "undefined" && mapCubixTiles[i] === playerTile) { mapCubix.splice(i, 1); mapCubixTiles.splice(i, 1); break; } } } // Show a message var msg = new Text2('Collected ' + foundType.name.replace(' Cubix', 'ion') + '!', { size: 60, fill: foundType.color }); msg.anchor.set(0.5, 0.5); msg.x = 1024; msg.y = 400; game.addChild(msg); LK.setTimeout(function () { game.removeChild(msg); }, 1000); // --- Add to Cubixion collection menu if not already present --- if (typeof playerCubixionCollection === "undefined") playerCubixionCollection = {}; // Use a synthetic id for cubix type (e.g. rarity as id) var cubixionId = foundType.rarity; if (!playerCubixionCollection[cubixionId]) { playerCubixionCollection[cubixionId] = { count: 0, gems: 0 }; } playerCubixionCollection[cubixionId].count++; // Defensive: always sync to storage and window if (typeof storage !== "undefined" && typeof storage.set === "function") { storage.set("playerCubixionCollection", playerCubixionCollection); } else if (typeof storage !== "undefined") { try { storage.playerCubixionCollection = playerCubixionCollection; } catch (e) {} } if (typeof window !== "undefined") window.playerCubixionCollection = playerCubixionCollection; } } // Skip updates if in an active encounter if (encounterActive) { encounter.update(); return; } // Check if collection is visible if (collection.visible) { // Hide player and move below collection player.visible = false; if (player.parent !== game) { game.addChild(player); } // Always reload the bag menu for all creatures if (typeof collection.show === "function") { collection.show(); } return; } // If collection is not visible, ensure player is visible player.visible = true; // Center view on player centerViewOnPlayer(); // Update minimap only every 6th update for further optimization if (typeof minimapUpdateCounter === "undefined") minimapUpdateCounter = 0; minimapUpdateCounter++; if (minimapUpdateCounter % 6 === 0) { minimap.update(player, gameMap); } // Vision update is now handled after player movement for optimization // Check if player has moved to a new tile if (player.gridX !== lastPlayerGridX || player.gridY !== lastPlayerGridY) { // Get the current tile var currentTile = gameMap.getTileAt(player.gridX, player.gridY); if (currentTile) { // Mark tile as explored if it's new if (!currentTile.explored) { currentTile.explore(); exploredCount++; } // Prevent encounters on dark (black) blocks if (currentTile.biomeType !== "dark" && currentTile.hasCreature && !currentTile._creatureCaught) { // Always trigger encounter if player and creature cross encounterActive = true; // Create creature based on biome var creatureType = new Creature().getRandomType(currentTile.biomeType); var creature = new Creature().init(creatureType, null, player.gridX, player.gridY); // Start encounter with this creature encounter.startEncounter(creature); // Remove creature from tile and mark as caught so it doesn't respawn immediately currentTile.hasCreature = false; currentTile._creatureCaught = true; // Remove indicator from tile and all references for optimization if (typeof mapCreatureTiles !== "undefined" && typeof mapCreatures !== "undefined" && typeof mapCreatureLabels !== "undefined") { for (var k = mapCreatureTiles.length - 1; k >= 0; k--) { if (mapCreatureTiles[k] === currentTile) { // Remove label if present if (mapCreatureLabels[k]) { currentTile.removeChild(mapCreatureLabels[k]); mapCreatureLabels.splice(k, 1); } // Remove creature visual if present if (currentTile._creatureVisual) { currentTile.removeChild(currentTile._creatureVisual); currentTile._creatureVisual = null; } mapCreatures.splice(k, 1); mapCreatureTiles.splice(k, 1); break; } } } } } // Update last position lastPlayerGridX = player.gridX; lastPlayerGridY = player.gridY; } }; // End throttled update // Listen for encounter end var checkEncounterInterval = LK.setInterval(function () { if (encounterActive && !encounter.active) { encounterActive = false; } }, 100); // Initialize stats // Initial centering centerViewOnPlayer(); // Fix: Only reveal vision area at game start, not the whole map if (typeof player !== "undefined" && typeof gameMap !== "undefined" && typeof player.updateVision === "function") { player.updateVision(gameMap); } // Vision mask overlay removed to fix black screen issue
===================================================================
--- original.js
+++ change.js
@@ -1780,9 +1780,9 @@
label.y = 1710;
self.addChild(label);
self.cubixButtonLabels.push(label);
btn.alpha = i === firstAvailableIdx ? 1.0 : 0.5;
- if (self.cubixButtonNameLabels[i]) {
+ if (self.cubixButtonNameLabels[i] && self.cubixButtonNameLabels[i].style) {
self.cubixButtonNameLabels[i].style.fill = i === firstAvailableIdx ? 0xFFD700 : cType.color;
}
}
// Set default selectedCubix to first available type
@@ -3293,31 +3293,31 @@
/****
* Game Code
****/
-// Example: use desertTile as legendary cubix
-// Example: use Voltix as rare cubix
-// Example: use Boulder as uncommon cubix
-// Example: use Sproutle as basic cubix
-// Cubix (pokeball) image assets
-// Out-of-world tile asset (default color, can be changed in MapTile)
-// JSON helper functions for parsing and stringifying
-// Game dimensions and settings
-// Tween for animations
-// Storage for saving game progress
-// Player character
-// Map tiles
-// Creatures by elemental type
-// UI elements
-// Encounter indicator
-// Sounds
-// Unique image for urban biome
-// Unique biome tile assets for each biome (example: add one more for each)
-// Creature type base shapes (for fallback and type-based visuals)
-// --- Creature image assets for all 100 unique creatures ---
-// Example: LK.init.image('creature_0', {width:120, height:120, id:'<image_id>'})
-// For demonstration, we use placeholder image ids. Replace with real ids as needed.
// The following assets are initialized with the creature's name and element in the asset id for clarity
+// For demonstration, we use placeholder image ids. Replace with real ids as needed.
+// Example: LK.init.image('creature_0', {width:120, height:120, id:'<image_id>'})
+// --- Creature image assets for all 100 unique creatures ---
+// Creature type base shapes (for fallback and type-based visuals)
+// Unique biome tile assets for each biome (example: add one more for each)
+// Unique image for urban biome
+// Sounds
+// Encounter indicator
+// UI elements
+// Creatures by elemental type
+// Map tiles
+// Player character
+// Storage for saving game progress
+// Tween for animations
+// Game dimensions and settings
+// JSON helper functions for parsing and stringifying
+// Out-of-world tile asset (default color, can be changed in MapTile)
+// Cubix (pokeball) image assets
+// Example: use Sproutle as basic cubix
+// Example: use Boulder as uncommon cubix
+// Example: use Voltix as rare cubix
+// Example: use desertTile as legendary cubix
function _typeof4(o) {
"@babel/helpers - typeof";
return _typeof4 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
water tile just water and top viewing. In-Game asset. 2d
dpad. In-Game asset. 2d. High contrast. No shadows
red button square. In-Game asset. 2d. High contrast. No shadows
grass tile on top viewing. In-Game asset. 2d. High contrast. No shadows
Mountain tile on top viewing. In-Game asset. 2d
sand tile on top viewing. In-Game asset. 2d. High contrast. No shadows
forest tile on top viewing. In-Game asset. 2d. No shadows
square grass tile on top viewing. In-Game asset. 2d. High contrast. No shadows
urban tile on viewing. In-Game asset. 2d
street tile on top viewing. In-Game asset. 2d. High contrast
street tile on top viewing with street way. In-Game asset. 2d
street tile on top viewing with street way horizontal. In-Game asset. 2d. High contrast. No shadows
make creature image for grass elemental name is sproutle. In-Game asset. 2d. High contrast. No shadows
make creature image for rock elemental name is boulder but dont write name on image. In-Game asset. 2d. High contrast. No shadows
make creature image for electrical elemental name is voltix but dont write name on image. In-Game asset. 2d. High contrast. No shadows
player human viewing on behind of him with all of body. In-Game asset. 2d
make a cube but like a pokeball and change the colour of original and make it the basic one make with purple and yellow but do diffrently. In-Game asset. 2d. High contrast. No shadows
make a cube but like a pokeball and make it the legendary one make with red and golden and blue but do diffrently. In-Game asset. 2d. High contrast. No shadows
make a cube but like a pokeball and make it for rare one make with grey and silver and white but do diffrently. In-Game asset. 2d. High contrast. No shadows
make a cube but like a pokeball and make it for uncommon one make with green and white and bronze but do diffrently. In-Game asset. 2d. High contrast. No shadows