User prompt
Fix Ibanman showcase size to 768 x 1528 pixels when selected
User prompt
Fix Ibanman showcase size to 768 x 1528 pixels when selected, ensuring 100% visibility relative to button size
User prompt
Fix the error L37 and L38
User prompt
Fix the plugins problems
User prompt
Make showcase size for Ibanman asset to 768x 1528 px after being selected, while the image of Ibanman is 100% to the size of Iban male button
User prompt
Fix Ibanman showcase size to 768 x 1528 px, while the whole Ibanman image is 100% visible within the Iban's male items button
User prompt
implement a custom scale factor 300x 300 px specifically for the Ibanman asset when displayed in buttons 300x300 px.
User prompt
/* Alternative scaling approach */ .ibanman-asset { min-width: 120%; min-height: 120%; width: auto; height: auto; }
User prompt
/* Alternative scaling approach */ .ibanman-asset { min-width: 120%; min-height: 120%; width: auto; height: auto; }.iban-male-item-button { background-image: url(ibanman-asset.png); background-size: contain; background-repeat: no-repeat; background-position: center; } /* For pixel-perfect positioning */ .iban-male-item-button { background-size: 300px 300px; /* Force exact size */ }
User prompt
Fix the compilation error
User prompt
/* CSS Solution */ .iban-male-item-button { /* Button dimensions */ width: 300px; height: 300px; /* Remove default button styles */ padding: 0; border: none; background: none; /* Ensure proper image containment */ overflow: hidden; position: relative; display: flex; justify-content: center; align-items: center; } .ibanman-asset { /* Fill container dimensions */ width: 100%; height: 100%; /* Maintain aspect ratio while filling space */ object-fit: contain; /* Scale up if asset is too small */ transform: scale(1.2); /* Adjust multiplier as needed */ /* Ensure clickability */ pointer-events: none; } /* If asset needs to be slightly cropped */ .ibanman-asset.cropped-version { object-fit: cover; object-position: center top; } /* Optional: Add hover effect */ .ibanman-asset:hover { transform: scale(1.25); transition: transform 0.2s ease-in-out; }
User prompt
Make Ibanman size in button to be 300% visible ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Make Ibanman size in button to be 200% visible
User prompt
Make Ibanman size in button to be 150% visible
User prompt
Make the Ibanman asset in the button bigger and same size as other asset in other button
User prompt
Asset Ibanman is 100% to the button size, as Ibanman is hardly visible in the button
User prompt
Ensuring Ibanman is 100% visibility in the Iban male button
User prompt
Fix Ibanman showcase size to 768x1528 pixels when selected, ensuring 100% visibility relative to button size
User prompt
Make Ibanman asset showcase to 768x1528 px after being selected, while the image of Ibanman is 100% to the size of Iban male buttonn
User prompt
Reset Ibanman asset size to original in ClothingItem's select method
User prompt
Make the asset Ibanman showcase to be visible to the size (768x1528) px after Iban male button is selected
User prompt
Opposite gender's attire still exists after I selected opposite gender
User prompt
Make sure the opposite gender's attire is disappeared after opposite gender's is selected
User prompt
Retry and fix the bug
User prompt
All of the male attire is removed after female character base is selected and vice versa
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { savedCharacters: [], currentLanguage: "en", currentWardrobePage: 0 }); /**** * Classes ****/ var CategorySelector = Container.expand(function () { var self = Container.call(this); self.categories = [{ id: 'siamese', label: { en: 'Siamese', ms: 'Siam', zh: '暹罗', ta: 'சியாமீஸ்' } }, { id: 'malay', label: { en: 'Malay', ms: 'Melayu', zh: '马来', ta: 'மலாய்' } }, { id: 'chinese', label: { en: 'Chinese', ms: 'Cina', zh: '华人', ta: 'சீன' } }, { id: 'indian', label: { en: 'Indian', ms: 'India', zh: '印度', ta: 'இந்திய' } }, { id: 'indigenous', label: { en: 'Indigenous', ms: 'Orang Asli', zh: '原住民', ta: 'பழங்குடி' } }, { id: 'iban', label: { en: 'Iban', ms: 'Iban', zh: '伊班族', ta: 'இபான்' } }, { id: 'kadazan', label: { en: 'Kadazan', ms: 'Kadazan', zh: '卡达山族', ta: 'கடசான்' } }, { id: 'babanyonya', label: { en: 'Baba Nyonya', ms: 'Baba Nyonya', zh: '峇峇娘惹', ta: 'பாபா நியோனியா' } }, { id: 'chetti', label: { en: 'Chetti', ms: 'Chetti', zh: '切蒂', ta: 'செட்டி' } }, { id: 'modern', label: { en: 'Serani', ms: 'Serani', zh: 'Serani', ta: 'Serani' } }]; self.selectedCategory = 'malay'; self.buttons = []; self.updateLanguage = function (lang) { for (var i = 0; i < self.categories.length; i++) { var cat = self.categories[i]; self.buttons[i].setText(cat.label[lang]); } }; self.setup = function () { var spacing = 220; var startX = -((self.categories.length - 1) * spacing) / 2; // Adjust Y position to separate from other UI elements self.y = -50; // Move category selector a bit higher for (var i = 0; i < self.categories.length; i++) { var cat = self.categories[i]; var lang = storage.currentLanguage; // Create panel background first var btnPanel = LK.getAsset('uiPanel', { anchorX: 0.5, anchorY: 0.5, width: 200, height: 80, tint: 0x87CEFA }); btnPanel.x = startX + i * spacing; btnPanel.y = -80; // Positioned higher to improve layout self.addChild(btnPanel); // Create button on top of panel var btn = new UIButton(cat.label[lang], 180, 60, 0x87CEFA); btn.x = startX + i * spacing; btn.y = -80; // Positioned higher to improve layout btn.categoryId = cat.id; btn.setCallback(function () { var catId = this.categoryId; LK.getSound('categoryChange').play(); self.selectedCategory = catId; self.updateButtonStates(); if (self.onCategoryChange) { self.onCategoryChange(catId); } }.bind(btn)); self.addChild(btn); self.buttons.push(btn); } self.updateButtonStates(); return self; }; self.updateButtonStates = function () { for (var i = 0; i < self.buttons.length; i++) { var btn = self.buttons[i]; if (btn.categoryId === self.selectedCategory) { btn.buttonText.style.fill = "#FFFFFF"; tween(btn.children[0], { tint: 0x4682B4 }, { duration: 200 }); } else { btn.buttonText.style.fill = "#000000"; tween(btn.children[0], { tint: 0x87CEFA }, { duration: 200 }); } } }; self.setChangeCallback = function (callback) { self.onCategoryChange = callback; return self; }; return self; }); var Character = Container.expand(function () { var self = Container.call(this); // Create character base - default to female self.gender = 'female'; var base = self.attachAsset('characterBaseFemale', { anchorX: 0.5, anchorY: 0.5, scaleX: 1, scaleY: 1 }); // Layers for different clothing types self.layers = { base: base, bottom: null, top: null, headdress: null, accessory: null }; // Method to change the character gender self.setGender = function (gender) { self.gender = gender; // Remove current base if (self.layers.base) { self.removeChild(self.layers.base); } // Create new base based on gender var baseAssetId = gender === 'male' ? 'Malecharacterbase' : 'characterBaseFemale'; var newBase = self.attachAsset(baseAssetId, { anchorX: 0.5, anchorY: 0.5, scaleX: gender === 'male' ? 0.6 : 1, // Scale male character width to 60% to avoid looking too fat scaleY: gender === 'male' ? 0.5127 : 1 // Scale male character to fit 1528px height }); // Update reference self.layers.base = newBase; // Ensure proper layering self.sortLayers(); return self; }; self.equip = function (item) { if (!item) return; // Check if trying to equip kurta for Indian male if (item.itemName === 'kurta' && self.gender === 'male') { return self; // Don't equip kurta for Indian male } // Check if trying to equip headdress for indigenous female if (item.type === 'headdress' && self.gender === 'female' && item.category === 'indigenous') { return self; // Don't equip headdress for indigenous female } // Remove previous item in this layer if exists if (self.layers[item.type]) { self.removeChild(self.layers[item.type]); } // Add new item and store reference self.layers[item.type] = item; self.addChild(item); // Position according to type switch (item.type) { case 'top': item.y = 50; break; case 'bottom': item.y = 300; break; case 'headdress': item.y = -300; break; case 'accessory': item.y = -100; break; } // Ensure proper layering self.sortLayers(); return self; }; self.sortLayers = function () { // Manual sorting to ensure correct layering var layerOrder = ['base', 'bottom', 'top', 'accessory', 'headdress']; var zIndex = 0; layerOrder.forEach(function (layerName) { var layer = self.layers[layerName]; if (layer) { // Remove and re-add to ensure proper order if (layer.parent === self) { self.removeChild(layer); } self.addChild(layer); } }); }; self.getData = function () { var data = { gender: self.gender, items: {} }; // Store item data for each layer for (var layerName in self.layers) { if (layerName !== 'base' && self.layers[layerName]) { data.items[layerName] = { name: self.layers[layerName].itemName, category: self.layers[layerName].category }; } } return data || {}; // Return empty object if data is undefined }; self.loadData = function (data) { // Clear current items for (var layerName in self.layers) { if (layerName !== 'base' && self.layers[layerName]) { self.removeChild(self.layers[layerName]); self.layers[layerName] = null; } } // Set gender if provided in data if (data && data.gender) { self.setGender(data.gender); } // Load saved items if (data && data.items) { for (var layerName in data.items) { var itemData = data.items[layerName]; var item = new ClothingItem(layerName, itemData.category, itemData.name); self.equip(item); } } return self; }; return self; }); var ClothingItem = Container.expand(function (type, category, itemName) { var self = Container.call(this); self.type = type; self.category = category; self.itemName = itemName; // Use the appropriate asset based on item name var itemGraphics; // For all items, use the appropriate asset itemGraphics = self.attachAsset(itemName, { anchorX: 0.5, anchorY: 0.5 }); // Add specific styling for Changsan to fit button size with minimal padding if (itemName === 'Changsan') { itemGraphics.width = itemGraphics.width * 0.98; // 98% width (1% padding on each side) itemGraphics.height = itemGraphics.height * 0.98; // 98% height (1% padding on each side) } // Center the item graphics in its container if (itemGraphics) { // Store original dimensions for reference self.originalWidth = itemGraphics.width; self.originalHeight = itemGraphics.height; // Properly center the item within the container itemGraphics.x = 0; itemGraphics.y = 0; // Allow items to be displayed at their original size in buttons // Only scale down if they're extremely large if (self.originalHeight > 1500 || self.originalWidth > 900) { var scaleFactor = Math.min(900 / self.originalWidth, 1500 / self.originalHeight); // Special case for Ibanman and Ibanwoman - maintain exact 768x1528 ratio even in buttons if (itemName === 'Ibanman' || itemName === 'Ibanwoman') { scaleFactor = Math.min(768 / self.originalWidth, 1528 / self.originalHeight); // Ensure Ibanwoman is displayed properly with 768x1528 aspect ratio if (itemName === 'Ibanwoman') { // Preserve aspect ratio while ensuring proper dimensions scaleFactor = Math.min(768 / self.originalWidth, 1528 / self.originalHeight); } } itemGraphics.scale.set(scaleFactor, scaleFactor); } // For certain types, adjust position to prevent overlap if (self.type === 'headdress') { itemGraphics.y = -itemGraphics.height * 0.25; } else if (self.type === 'accessory') { itemGraphics.y = -itemGraphics.height * 0.1; } } self.select = function () { LK.getSound('itemSelect').play(); // If we're in a character and there's a base layer, hide it if (self.parent && self.parent.layers && self.parent.layers.base) { self.parent.layers.base.visible = false; } // If this is a saree, remove any bottom layer if (self.itemName === 'saree' && self.parent && self.parent.layers && self.parent.layers.bottom) { self.parent.removeChild(self.parent.layers.bottom); self.parent.layers.bottom = null; } // Scale up the attire when selected to fit 768x1528 dimensions if (self.children[0]) { // Store original scale if not already stored if (!self.originalScale) { self.originalScale = { x: self.children[0].scale.x, y: self.children[0].scale.y }; } // Calculate scale factor to fit within 768x1528 area while maximizing size var maxWidth = 768; var maxHeight = 1528; var currentWidth = self.originalWidth * self.originalScale.x; var currentHeight = self.originalHeight * self.originalScale.y; var scaleFactor = Math.min(maxWidth / currentWidth, maxHeight / currentHeight); // Special handling for Ibanman, Ibanwoman and Nyonya to ensure exact 768x1528 dimensions if (self.itemName === 'Ibanman' || self.itemName === 'Ibanwoman') { scaleFactor = Math.min(768 / self.originalWidth, 1528 / self.originalHeight); // Force exact dimensions for Ibanwoman if (self.itemName === 'Ibanwoman') { // Calculate the exact scale needed for 768x1528px var exactScaleFactor = Math.min(768 / self.originalWidth, 1528 / self.originalHeight); scaleFactor = exactScaleFactor; } } else if (self.itemName === 'Nyonya' || self.itemName === 'Kadazanman' || self.itemName === 'Ibanman') { // Special handling for Nyonya, Kadazanman, and Ibanman to ensure exact 768x1528 px to match other items scaleFactor = Math.min(768 / self.originalWidth, 1528 / self.originalHeight); // Special handling for Kadazanman and Ibanman to ensure proper visibility after selection if (self.itemName === 'Kadazanman' || self.itemName === 'Ibanman') { // Force exact dimensions for Kadazanman and Ibanman showcase var exactScaleFactor = Math.min(768 / self.originalWidth, 1528 / self.originalHeight); scaleFactor = exactScaleFactor; } } // Apply larger scale with animation tween(self.children[0], { scaleX: self.originalScale.x * scaleFactor, scaleY: self.originalScale.y * scaleFactor }, { duration: 500, easing: tween.easeOut }); } // Force visibility for Nyonya specifically to prevent it from disappearing if (self.itemName === 'Nyonya') { // Make sure Nyonya is visible self.visible = true; self.alpha = 1; // Also ensure the child element is visible if (self.children[0]) { self.children[0].visible = true; self.children[0].alpha = 1; } } // Explicitly ensure the item is visible after selection self.visible = true; return self; }; self.down = function (x, y, obj) { // Handle item selection self.select(); // Show cultural info if this is a Baju Kurung if (self.itemName === 'bajuKurung' && typeof culturalInfoPanel !== 'undefined') { culturalInfoPanel.show('bajuKurung'); } }; return self; }); var CulturalInfoPanel = Container.expand(function () { var self = Container.call(this); // Create background panel var bg = self.attachAsset('uiPanel', { anchorX: 0.5, anchorY: 0.5, width: 1600, height: 1200, tint: 0xFFFAF0 // Ivory color }); // Title text self.titleText = new Text2("Cultural Information", { size: 60, fill: 0x4682B4 }); self.titleText.anchor.set(0.5, 0); self.titleText.y = -bg.height / 2 + 40; self.addChild(self.titleText); // Info text with word wrapping self.infoText = new Text2("", { size: 40, fill: 0x333333, wordWrap: true, wordWrapWidth: 1400 }); self.infoText.anchor.set(0.5, 0); self.infoText.y = -bg.height / 2 + 130; self.addChild(self.infoText); // Close button var closeButton = new UIButton("X", 80, 80, 0xF44336); closeButton.x = bg.width / 2 - 60; closeButton.y = -bg.height / 2 + 60; closeButton.setCallback(function () { self.hide(); }); self.addChild(closeButton); // Show panel with specific item info self.show = function (itemName) { // Hide panel initially for animation self.visible = true; self.alpha = 0; // Get current language var lang = storage.currentLanguage; // Update title based on language var titleTranslations = { en: "Cultural Information", ms: "Maklumat Budaya", zh: "文化信息", ta: "கலாச்சார தகவல்" }; self.titleText.setText(titleTranslations[lang] || "Cultural Information"); // Set content if available for this item if (culturalInfoScripts[itemName] && culturalInfoScripts[itemName][lang]) { self.infoText.setText(culturalInfoScripts[itemName][lang]); } else { // Default text if no info available var defaultText = { en: "No information available for this item.", ms: "Tiada maklumat tersedia untuk item ini.", zh: "没有关于此物品的信息。", ta: "இந்த பொருளுக்கு தகவல் இல்லை." }; self.infoText.setText(defaultText[lang]); } // Fade in animation tween(self, { alpha: 1 }, { duration: 300, easing: tween.easeOut }); return self; }; // Hide panel self.hide = function () { self.visible = false; return self; }; // Initial state self.visible = false; return self; }); var GenderSelector = Container.expand(function () { var self = Container.call(this); self.genders = [{ id: 'female', label: { en: 'Female', ms: 'Perempuan', zh: '女', ta: 'பெண்' } }, { id: 'male', label: { en: 'Male', ms: 'Lelaki', zh: '男', ta: 'ஆண்' } }]; self.selectedGender = 'female'; self.buttons = []; self.updateLanguage = function (lang) { for (var i = 0; i < self.genders.length; i++) { var gender = self.genders[i]; self.buttons[i].setText(gender.label[lang]); } }; self.setup = function () { // Create buttons vertically stacked var spacing = -100; // Vertical spacing between buttons var lang = storage.currentLanguage; // Create panel and button for female (top position) var femalePanel = LK.getAsset('uiPanel', { anchorX: 0.5, anchorY: 0.5, width: 200, height: 80, tint: 0x87CEFA }); femalePanel.y = spacing; // Position above center self.addChild(femalePanel); var femaleBtn = new UIButton(self.genders[0].label[lang], 180, 60, 0x87CEFA); femaleBtn.y = spacing; // Position above center femaleBtn.genderId = 'female'; femaleBtn.setCallback(function () { LK.getSound('categoryChange').play(); self.selectedGender = 'female'; self.updateButtonStates(); if (self.onGenderChange) { self.onGenderChange('female'); } }.bind(femaleBtn)); self.addChild(femaleBtn); self.buttons.push(femaleBtn); // Create panel and button for male (bottom position) var malePanel = LK.getAsset('uiPanel', { anchorX: 0.5, anchorY: 0.5, width: 200, height: 80, tint: 0x87CEFA }); malePanel.y = -spacing; // Position below center self.addChild(malePanel); var maleBtn = new UIButton(self.genders[1].label[lang], 180, 60, 0x87CEFA); maleBtn.y = -spacing; // Position below center maleBtn.genderId = 'male'; maleBtn.setCallback(function () { LK.getSound('categoryChange').play(); self.selectedGender = 'male'; self.updateButtonStates(); if (self.onGenderChange) { self.onGenderChange('male'); } }.bind(maleBtn)); self.addChild(maleBtn); self.buttons.push(maleBtn); self.updateButtonStates(); return self; }; self.updateButtonStates = function () { for (var i = 0; i < self.buttons.length; i++) { var btn = self.buttons[i]; if (btn.genderId === self.selectedGender) { btn.buttonText.style.fill = "#FFFFFF"; tween(btn.children[0], { tint: 0x4682B4 }, { duration: 200 }); } else { btn.buttonText.style.fill = "#000000"; tween(btn.children[0], { tint: 0x87CEFA }, { duration: 200 }); } } }; self.setChangeCallback = function (callback) { self.onGenderChange = callback; return self; }; return self; }); var ItemSelector = Container.expand(function () { var self = Container.call(this); self.items = { siamese: { female: { top: [{ name: 'siameseDress', label: { en: 'Siamese Dress', ms: 'Pakaian Siam', zh: '暹罗服装', ta: 'சியாமீஸ் ஆடை' } }], headdress: [] }, male: { top: [{ name: 'siameseTop', label: { en: 'Siamese Attire', ms: 'Pakaian Siam', zh: '暹罗男装', ta: 'சியாமீஸ் ஆடை' } }], headdress: [] } }, malay: { female: { top: [{ name: 'bajuKurung', label: { en: 'Baju Kurung', ms: 'Baju Kurung', zh: '马来传统服装', ta: 'பாஜு குருங்' } }], headdress: [] }, male: { top: [{ name: 'bajuMelayu', label: { en: 'Baju Melayu', ms: 'Baju Melayu', zh: '马来男装', ta: 'பாஜு மேலாயு' } }], headdress: [] } }, chinese: { female: { top: [{ name: 'cheongsam', label: { en: 'Cheongsam', ms: 'Cheongsam', zh: '旗袍', ta: 'சியோங்சாம்' } }], accessory: [] }, male: { top: [{ name: 'Changsan', label: { en: 'Changshan', ms: 'Changshan', zh: '长衫', ta: 'சாங்ஷான்' } }], accessory: [] } }, indian: { female: { top: [{ name: 'saree', label: { en: 'Saree', ms: 'Sari', zh: '纱丽', ta: 'சேலை' } }], accessory: [] }, male: { top: [{ name: 'kurta', label: { en: 'Kurta', ms: 'Kurta', zh: '库尔塔', ta: 'குர்தா' } }], bottom: [{ name: 'Dhotti', label: { en: 'Dhoti', ms: 'Dhoti', zh: '多蒂', ta: 'தோட்டி' } }] } }, indigenous: { female: { top: [{ name: 'indigenousVest', label: { en: 'Traditional Vest', ms: 'Rompi Tradisional', zh: '传统背心', ta: 'பாரம்பரிய மேலாடை' } }], headdress: [{ name: 'headDress', label: { en: 'Headdress', ms: 'Hiasan Kepala', zh: '头饰', ta: 'தலை அணி' } }] }, male: {} }, iban: { female: { top: [{ name: 'indigenousVest', label: { en: 'Ngepan Vest', ms: 'Rompi Ngepan', zh: '伊班族背心', ta: 'நெகபன் மேலாடை' } }], headdress: [] }, male: { top: [{ name: 'ibanVest', label: { en: 'Iban Vest', ms: 'Rompi Iban', zh: '伊班族背心', ta: 'இபான் மேலாடை' } }], headdress: [] } }, kadazan: { female: { top: [{ name: 'indigenousVest', label: { en: 'Sinuangga Vest', ms: 'Rompi Sinuangga', zh: '卡达山族背心', ta: 'சினுவாங்க மேலாடை' } }], headdress: [] }, male: { top: [{ name: 'kadazanVest', label: { en: 'Kadazan Vest', ms: 'Rompi Kadazan', zh: '卡达山族背心', ta: 'கடசான் மேலாடை' } }], headdress: [] } }, babanyonya: { female: { top: [{ name: 'babaNyonyaTop', label: { en: 'Kebaya Nyonya', ms: 'Kebaya Nyonya', zh: '娘惹峇峇服', ta: 'கெபாயா நியோனியா' } }], bottom: [], accessory: [] }, male: { top: [{ name: 'babaNyonyaTop', label: { en: 'Baba Tunic', ms: 'Tunik Baba', zh: '峇峇上衣', ta: 'பாபா மேலாடை' } }], bottom: [], accessory: [] } }, chetti: { female: { top: [{ name: 'chettiTop', label: { en: 'Chetti Saree', ms: 'Sari Chetti', zh: '切蒂纱丽', ta: 'செட்டி சேலை' } }], accessory: [] }, male: { top: [{ name: 'chettiTop', label: { en: 'Chetti Veshti', ms: 'Veshti Chetti', zh: '切蒂传统服装', ta: 'செட்டி வேஷ்டி' } }], bottom: [], accessory: [] } }, modern: { female: { top: [{ name: 'modernTop', label: { en: 'Modern Top', ms: 'Atasan Moden', zh: '现代上衣', ta: 'நவீன மேல்' } }], bottom: [] }, male: { top: [{ name: 'modernMaleTop', label: { en: 'Modern Top', ms: 'Atasan Moden', zh: '现代上衣', ta: 'நவீன மேல்' } }], bottom: [] } } }; self.currentCategory = 'malay'; self.currentType = 'top'; self.itemButtons = []; self.typeButtons = []; // Group by type instead of category, considering gender self.getItemsByType = function () { var types = {}; var currentGender = typeof genderSelector !== 'undefined' && genderSelector ? genderSelector.selectedGender : 'female'; // Get all available types for current category and gender if (self.items[self.currentCategory] && self.items[self.currentCategory][currentGender]) { for (var type in self.items[self.currentCategory][currentGender]) { types[type] = true; } } return Object.keys(types); }; self.setCategory = function (category) { self.currentCategory = category; // Determine available types for this category based on gender var types = self.getItemsByType(); // Default to first type if current not available if (!types.includes(self.currentType)) { self.currentType = types.length > 0 ? types[0] : null; } // If no valid types for the current category/gender combination, don't proceed if (!self.currentType) { self.refreshTypeButtons(); return self; } self.refreshTypeButtons(); self.refreshItems(); return self; }; self.setType = function (type) { self.currentType = type; self.refreshItems(); return self; }; self.refreshTypeButtons = function () { // Clear existing buttons for (var i = 0; i < self.typeButtons.length; i++) { self.removeChild(self.typeButtons[i]); } self.typeButtons = []; var types = self.getItemsByType(); var spacing = 180; var startX = -((types.length - 1) * spacing) / 2; // Type translation mapping var typeLabels = { top: { en: 'Top', ms: 'Atas', zh: '上身', ta: 'மேல்' }, bottom: { en: 'Bottom', ms: 'Bawah', zh: '下身', ta: 'கீழ்' }, headdress: { en: 'Headdress', ms: 'Hiasan Kepala', zh: '头饰', ta: 'தலை அணி' }, accessory: { en: 'Accessory', ms: 'Aksesori', zh: '饰品', ta: 'அணிகலன்' } }; // Create buttons for each available type for (var i = 0; i < types.length; i++) { var type = types[i]; var label = typeLabels[type][storage.currentLanguage] || type; var btn = new UIButton(label, 150, 50, 0xBBBBBB); btn.x = startX + i * spacing; btn.y = -450; // Positioned even higher to prevent overlap with other UI elements btn.typeName = type; btn.setCallback(function () { self.setType(this.typeName); self.updateTypeButtonStates(); }.bind(btn)); self.addChild(btn); self.typeButtons.push(btn); } self.updateTypeButtonStates(); }; self.updateTypeButtonStates = function () { for (var i = 0; i < self.typeButtons.length; i++) { var btn = self.typeButtons[i]; if (btn.typeName === self.currentType) { btn.buttonText.style.fill = "#FFFFFF"; tween(btn.children[0], { tint: 0x555555 }, { duration: 200 }); } else { btn.buttonText.style.fill = "#000000"; tween(btn.children[0], { tint: 0xBBBBBB }, { duration: 200 }); } } }; self.refreshItems = function () { // Clear existing item buttons for (var i = 0; i < self.itemButtons.length; i++) { self.removeChild(self.itemButtons[i]); } self.itemButtons = []; var currentGender = typeof genderSelector !== 'undefined' && genderSelector ? genderSelector.selectedGender : 'female'; var currentItems = []; // Get items for the current category, gender and type if (self.items[self.currentCategory] && self.items[self.currentCategory][currentGender] && self.items[self.currentCategory][currentGender][self.currentType]) { currentItems = self.items[self.currentCategory][currentGender][self.currentType] || []; } // Only handle Chinese male top type properly - don't empty Changsan when it should appear if (self.currentCategory === 'chinese' && currentGender === 'male' && self.currentType === 'top') { // Check if Changsan is not already in items var hasChangsan = currentItems.some(function (item) { return item.name === 'Changsan'; }); if (!hasChangsan) { // Add Changsan if it's not already present currentItems.push({ name: 'Changsan', label: { en: 'Changshan', ms: 'Changshan', zh: '长衫', ta: 'சாங்ஷான்' } }); } } // Handle Baba Nyonya category if (self.currentCategory === 'babanyonya') { if (currentGender === 'female' && self.currentType === 'top') { // Check if babaNyonyaTop is not already in items var hasBabaNyonyaTop = currentItems.some(function (item) { return item.name === 'babaNyonyaTop'; }); if (!hasBabaNyonyaTop) { currentItems.push({ name: 'babaNyonyaTop', label: { en: 'Kebaya Nyonya', ms: 'Kebaya Nyonya', zh: '娘惹峇峇服', ta: 'கெபாயா நியோனியா' } }); } } else if (currentGender === 'male' && self.currentType === 'top') { // Check if babaNyonyaTop is not already in items for male var hasBabaNyonyaTop = currentItems.some(function (item) { return item.name === 'babaNyonyaTop'; }); if (!hasBabaNyonyaTop) { currentItems.push({ name: 'babaNyonyaTop', label: { en: 'Baba Tunic', ms: 'Tunik Baba', zh: '峇峇上衣', ta: 'பாபா மேலாடை' } }); } } // Baba Nyonya bottom items are explicitly removed } // Handle Chetti category if (self.currentCategory === 'chetti') { if (self.currentType === 'top') { // Check if chettiTop is not already in items var hasChettiTop = currentItems.some(function (item) { return item.name === 'chettiTop'; }); if (!hasChettiTop) { currentItems.push({ name: 'chettiTop', label: { en: currentGender === 'female' ? 'Chetti Saree' : 'Chetti Veshti', ms: currentGender === 'female' ? 'Sari Chetti' : 'Veshti Chetti', zh: currentGender === 'female' ? '切蒂纱丽' : '切蒂传统服装', ta: currentGender === 'female' ? 'செட்டி சேலை' : 'செட்டி வேஷ்டி' } }); } } // Removed the male bottom section for Chetti } // Filter items to ensure gender-specific clothing and prevent Changsan from appearing in non-Chinese categories var filteredItems = currentItems.filter(function (item) { // Immediately remove Changsan from all non-Chinese categories if (item.name === 'Changsan' && self.currentCategory !== 'chinese') { return false; } // Double-check to explicitly prevent Changsan from appearing in Orang Asli, Iban, and Kadazan categories if (item.name === 'Changsan' && (self.currentCategory === 'indigenous' || self.currentCategory === 'iban' || self.currentCategory === 'kadazan')) { return false; } // Double-check to explicitly prevent Changsan from appearing in Orang Asli, Iban, and Kadazan categories if (item.name === 'Changsan' && (self.currentCategory === 'indigenous' || self.currentCategory === 'iban' || self.currentCategory === 'kadazan')) { return false; } // Always ensure we're only showing items appropriate for the current gender return self.items[self.currentCategory] && self.items[self.currentCategory][currentGender] && self.items[self.currentCategory][currentGender][self.currentType] && self.items[self.currentCategory][currentGender][self.currentType].some(function (validItem) { return validItem.name === item.name; }); }); // Use larger buttons to match attire's image size for better display var buttonWidth = 900; // Width for the button var buttonHeight = 1200; // Height for the button to maintain aspect ratio var itemsPerRow = 2; // Two items per row for better utilization of space var horizontalSpacing = 950; // Spacing between items horizontally var verticalSpacing = 1300; // Spacing between rows // Create a scroll container for wardrobe items if (!self.scrollContainer) { self.scrollContainer = new Container(); self.addChild(self.scrollContainer); // Implement scroll functionality self.lastY = 0; self.isDragging = false; self.scrollY = 0; self.maxScrollY = 0; self.down = function (x, y, obj) { self.isDragging = true; self.lastY = y; }; self.move = function (x, y, obj) { if (self.isDragging) { var deltaY = y - self.lastY; self.scrollY += deltaY; // Limit scrolling if (self.scrollY > 0) { self.scrollY = 0; } else if (self.scrollY < -self.maxScrollY) { self.scrollY = -self.maxScrollY; } self.scrollContainer.y = self.scrollY; self.lastY = y; } }; self.up = function (x, y, obj) { self.isDragging = false; }; } // Create buttons for each item for (var i = 0; i < filteredItems.length; i++) { var row = Math.floor(i / itemsPerRow); var col = i % itemsPerRow; var item = filteredItems[i]; var label = item.label[storage.currentLanguage] || item.name; var itemContainer = new Container(); // Use standard button for all items { // For all items, use a larger button background var bg = LK.getAsset('itemButton', { anchorX: 0.5, anchorY: 0.5, width: 300, // Fixed to 300px width height: 300 // Fixed to 300px height }); itemContainer.addChild(bg); // Create item preview with large display var itemPreview = new ClothingItem(self.currentType, self.currentCategory, item.name); // Make all attires fit 100% of the item button size var itemAsset = itemPreview.children[0]; if (itemAsset) { // Reset scale first to ensure proper sizing itemAsset.scale.set(1, 1); // Force all attires to fit exactly 100% of the button size itemAsset.width = bg.width; itemAsset.height = bg.height; // Special case for Nyonya - scale to fill button completely if (item.name === 'Nyonya') { // Ensure Nyonya fills the entire button area (scale to 100% of button) var scaleX = bg.width / itemAsset.width; var scaleY = bg.height / itemAsset.height; itemAsset.scale.set(scaleX, scaleY); } // Special case for Ibanman and Ibanwoman - ensure it displays at 100% while maintaining aspect ratio else if (item.name === 'Ibanman' || item.name === 'Ibanwoman') { var aspectRatio = 768 / 1528; // Correct aspect ratio var scaleFactor = Math.min(bg.width / (itemAsset.width * aspectRatio), bg.height / itemAsset.height); // Use exact scaling for Ibanwoman to ensure 768x1528 ratio if (item.name === 'Ibanwoman') { // Calculate the exact scale needed to fit in button while preserving aspect ratio var exactRatio = 768 / 1528; var exactScaleFactor = Math.min(bg.width / (itemAsset.width * exactRatio), bg.height / itemAsset.height); itemAsset.scale.set(exactScaleFactor * exactRatio, exactScaleFactor); } else { itemAsset.scale.set(scaleFactor * aspectRatio, scaleFactor); } } // Center perfectly in the button itemAsset.position.set(0, 0); } itemPreview.position.set(0, 0); itemContainer.addChild(itemPreview); } // Item label for all items var itemLabel = new Text2(label, { size: 50, fill: 0x000000 }); itemLabel.anchor.set(0.5, 0); itemLabel.y = buttonHeight / 2 + 30; itemContainer.addChild(itemLabel); // Calculate grid position var gridStartX = -((itemsPerRow - 1) * horizontalSpacing) / 2; var posX = gridStartX + col * horizontalSpacing; var posY = row * verticalSpacing - 700; // Moved buttons significantly higher in the scroll container itemContainer.x = posX; itemContainer.y = posY; itemContainer.itemName = item.name; // Handle selection itemContainer.interactive = true; itemContainer.down = function (x, y, obj) { // Create and return a new ClothingItem when selected var itemInstance = new ClothingItem(self.currentType, self.currentCategory, this.itemName); if (self.onItemSelected) { LK.getSound('itemSelect').play(); self.onItemSelected(itemInstance); } // Visual feedback tween(this, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100, easing: tween.easeOut, onFinish: function () { tween(this, { scaleX: 1, scaleY: 1 }, { duration: 100, easing: tween.easeOut }); }.bind(this) }); }.bind(itemContainer); self.scrollContainer.addChild(itemContainer); self.itemButtons.push(itemContainer); } // Calculate maximum scroll based on content height var totalRows = Math.ceil(filteredItems.length / itemsPerRow); var contentHeight = totalRows * verticalSpacing; var visibleHeight = 1300; // Adjusted visible area height for larger buttons self.maxScrollY = Math.max(0, contentHeight - visibleHeight); // Position scroll container for better visibility of large items self.scrollContainer.y = self.scrollY; return self; }; self.setSelectionCallback = function (callback) { self.onItemSelected = function (item) { // First call the original callback callback(item); // Show cultural info directly if this is baju kurung if (item.itemName === 'bajuKurung') { if (typeof culturalInfoPanel !== 'undefined') { culturalInfoPanel.show('bajuKurung'); } } }; return self; }; return self; }); var LanguageSelector = Container.expand(function () { var self = Container.call(this); self.languages = [{ code: 'en', name: 'English' }, { code: 'ms', name: 'Bahasa Melayu' }, { code: 'zh', name: '中文' }, { code: 'ta', name: 'தமிழ்' }]; self.buttons = []; self.setup = function () { var spacing = 250; var startX = -((self.languages.length - 1) * spacing) / 2; for (var i = 0; i < self.languages.length; i++) { var lang = self.languages[i]; // Create panel background first var btnPanel = LK.getAsset('uiPanel', { anchorX: 0.5, anchorY: 0.5, width: lang.code === 'ms' ? 220 : 160, // Wider panel for Bahasa Melayu height: 70, tint: 0xDDDDDD }); btnPanel.x = startX + i * spacing; self.addChild(btnPanel); // Create button on top of panel var btn = new UIButton(lang.name, lang.code === 'ms' ? 200 : 140, 50, 0xDDDDDD); btn.x = startX + i * spacing; btn.languageCode = lang.code; btn.setCallback(function () { var langCode = this.languageCode; storage.currentLanguage = langCode; // Update button states self.updateButtonStates(); // Notify about language change if (self.onLanguageChange) { self.onLanguageChange(langCode); } }.bind(btn)); self.addChild(btn); self.buttons.push(btn); } self.updateButtonStates(); return self; }; self.updateButtonStates = function () { for (var i = 0; i < self.buttons.length; i++) { var btn = self.buttons[i]; if (btn.languageCode === storage.currentLanguage) { btn.buttonText.style.fill = "#FFFFFF"; tween(btn.children[0], { tint: 0x4682B4 }, { duration: 200 }); } else { btn.buttonText.style.fill = "#000000"; tween(btn.children[0], { tint: 0xDDDDDD }, { duration: 200 }); } } }; self.setChangeCallback = function (callback) { self.onLanguageChange = callback; return self; }; return self; }); var UIButton = Container.expand(function (text, width, height, bgColor) { var self = Container.call(this); self.width = width || 200; self.height = height || 80; self.bgColor = bgColor || 0x6495ED; var buttonBg = self.attachAsset('button', { anchorX: 0.5, anchorY: 0.5, width: self.width, height: self.height, tint: self.bgColor }); self.buttonText = new Text2(text, { size: 30, fill: 0x000000 }); self.buttonText.anchor.set(0.5, 0.5); // Make sure style property exists before accessing it if (!self.buttonText.style) { self.buttonText.style = {}; } self.buttonText.style.fill = "#000000"; self.addChild(self.buttonText); self.setText = function (newText) { self.buttonText.setText(newText); if (!self.buttonText.style) { self.buttonText.style = {}; } // At this point we've ensured style exists, so we can safely access it self.buttonText.style.fill = self.buttonText.style.fill || "#000000"; return self; }; self.down = function (x, y, obj) { // Button pressed effect tween(buttonBg, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100, easing: tween.easeOut }); }; self.up = function (x, y, obj) { // Button release effect tween(buttonBg, { scaleX: 1, scaleY: 1 }, { duration: 100, easing: tween.easeOut }); // Trigger callback if set if (self.callback) { self.callback(); } }; self.setCallback = function (callback) { self.callback = callback; return self; }; return self; }); var Wardrobe = Container.expand(function () { var self = Container.call(this); var background = self.attachAsset('uiPanel', { anchorX: 0.5, anchorY: 0.5, width: 1800, height: 2000, tint: 0xF5F5F5 }); var title = new Text2("Ethnic Wardrobe", { size: 60, fill: 0x4682B4 }); title.anchor.set(0.5, 0); title.y = -background.height / 2 + 40; self.addChild(title); var closeButton = new UIButton("X", 80, 80, 0xF44336); closeButton.x = background.width / 2 - 60; closeButton.y = -background.height / 2 + 60; closeButton.setCallback(function () { self.hide(); }); self.addChild(closeButton); // Create outfit container var outfitContainer = new Container(); self.addChild(outfitContainer); // Add pagination controls var leftArrow = self.attachAsset('arrowLeft', { anchorX: 0.5, anchorY: 0.5 }); leftArrow.x = -background.width / 2 + 100; leftArrow.y = background.height / 2 - 100; // Add text marker inside left arrow to indicate back var leftText = new Text2("<", { size: 50, fill: 0xFFFFFF }); leftText.anchor.set(0.5, 0.5); leftArrow.addChild(leftText); self.addChild(leftArrow); var rightArrow = self.attachAsset('arrowRight', { anchorX: 0.5, anchorY: 0.5 }); rightArrow.x = background.width / 2 - 100; rightArrow.y = background.height / 2 - 100; // Add text marker inside right arrow to indicate forward var rightText = new Text2(">", { size: 50, fill: 0xFFFFFF }); rightText.anchor.set(0.5, 0.5); rightArrow.addChild(rightText); self.addChild(rightArrow); // Add page indicator self.pageIndicator = new Text2("Page 1/2", { size: 30, fill: 0x000000 }); self.pageIndicator.anchor.set(0.5, 0.5); self.pageIndicator.y = background.height / 2 - 100; self.addChild(self.pageIndicator); // Set up arrow interactivity leftArrow.interactive = true; rightArrow.interactive = true; leftArrow.down = function (x, y, obj) { if (storage.currentWardrobePage > 0) { storage.currentWardrobePage--; self.loadOutfits(); // Provide visual feedback tween(this, { scaleX: 0.8, scaleY: 0.8 }, { duration: 100, easing: tween.easeOut, onFinish: function () { tween(this, { scaleX: 1, scaleY: 1 }, { duration: 100, easing: tween.easeOut }); }.bind(this) }); } }.bind(leftArrow); rightArrow.down = function (x, y, obj) { if (storage.currentWardrobePage < 1) { // Only two pages (0 and 1) storage.currentWardrobePage++; self.loadOutfits(); // Provide visual feedback tween(this, { scaleX: 0.8, scaleY: 0.8 }, { duration: 100, easing: tween.easeOut, onFinish: function () { tween(this, { scaleX: 1, scaleY: 1 }, { duration: 100, easing: tween.easeOut }); }.bind(this) }); } }.bind(rightArrow); self.updateLanguage = function (language) { var titleTranslations = { en: "Ethnic Wardrobe", ms: "Almari Pakaian Etnik", zh: "民族服装衣柜", ta: "இன ஆடை அலமாரி" }; title.setText(titleTranslations[language] || "Ethnic Wardrobe"); return self; }; self.loadOutfits = function () { var savedCharacters = storage.savedCharacters || []; // Clear existing outfits outfitContainer.removeChildren(); // Set to true to display all ethnic outfits var displayAllEthnics = true; // Only display ethnic outfits, not saved characters var outfitsToDisplay = []; // Add ethnic outfit presets if (displayAllEthnics) { var ethnicCategories = ['siamese', 'malay', 'chinese', 'indian', 'indigenous', 'iban', 'kadazan', 'babanyonya', 'chetti', 'modern']; var currentGender = typeof genderSelector !== 'undefined' && genderSelector ? genderSelector.selectedGender : 'female'; for (var c = 0; c < ethnicCategories.length; c++) { var category = ethnicCategories[c]; var outfitData = { items: {} }; // Get available items for this ethnic category based on gender if (itemSelector.items[category] && itemSelector.items[category][currentGender]) { for (var type in itemSelector.items[category][currentGender]) { if (itemSelector.items[category][currentGender][type] && itemSelector.items[category][currentGender][type].length > 0) { // Get the first item of this type for the current gender var item = itemSelector.items[category][currentGender][type][0]; // Special case for Malay male outfit - use bajumelayu for top if (category === 'malay' && currentGender === 'male' && type === 'top') { outfitData.items[type] = { name: 'bajumelayu', category: category }; // Special case for Indian male outfit - use Dhotti for bottom } else if (category === 'indian' && currentGender === 'male' && type === 'bottom') { outfitData.items[type] = { name: 'Dhotti', category: category }; } else { outfitData.items[type] = { name: item.name, category: category }; } } } } // Only add outfit if it has items if (Object.keys(outfitData.items).length > 0) { outfitsToDisplay.push(outfitData); } } } if (outfitsToDisplay.length === 0) { var noOutfitsText = new Text2("No saved outfits", { size: 40, fill: 0x888888 }); noOutfitsText.anchor.set(0.5, 0.5); outfitContainer.addChild(noOutfitsText); return self; } // Update page indicator var totalPages = Math.ceil(outfitsToDisplay.length / 6); self.pageIndicator.setText("Page " + (storage.currentWardrobePage + 1) + "/" + totalPages); // Calculate grid layout for pagination var itemsPerRow = 3; // 3 items per row var itemsPerPage = 6; // 6 items per page var itemSize = 350; // Size for each item var padding = 60; // Padding between items var startX = -(itemsPerRow - 1) / 2 * (itemSize + padding); var startY = -300; // Position items higher in the panel // Translations for ethnic categories var categoryLabels = { siamese: { en: 'Siamese', ms: 'Siam', zh: '暹罗', ta: 'சியாமீஸ்' }, malay: { en: 'Malay', ms: 'Melayu', zh: '马来', ta: 'மலாய்' }, chinese: { en: 'Chinese', ms: 'Cina', zh: '华人', ta: 'சீன' }, indian: { en: 'Indian', ms: 'India', zh: '印度', ta: 'இந்திய' }, indigenous: { en: 'Indigenous', ms: 'Orang Asli', zh: '原住民', ta: 'பழங்குடி' }, iban: { en: 'Iban', ms: 'Iban', zh: '伊班族', ta: 'இபான்' }, kadazan: { en: 'Kadazan', ms: 'Kadazan', zh: '卡达山族', ta: 'கடசான்' }, babanyonya: { en: 'Baba Nyonya', ms: 'Baba Nyonya', zh: '峇峇娘惹', ta: 'பாபா நியோனியா' }, chetti: { en: 'Chetti', ms: 'Chetti', zh: '切蒂', ta: 'செட்டி' }, modern: { en: 'Serani', ms: 'Serani', zh: 'Serani', ta: 'Serani' } }; // Calculate start and end indices for pagination var startIndex = storage.currentWardrobePage * itemsPerPage; var endIndex = Math.min(startIndex + itemsPerPage, outfitsToDisplay.length); // Display items for current page only for (var i = startIndex; i < endIndex; i++) { var pageIndex = i - startIndex; // Index relative to current page var row = Math.floor(pageIndex / itemsPerRow); var col = pageIndex % itemsPerRow; var outfitPreview = new Character(); // Remove base from character preview in wardrobe outfitPreview.removeChild(outfitPreview.layers.base); outfitPreview.layers.base = null; outfitPreview.scale.set(0.25, 0.25); outfitPreview.loadData(outfitsToDisplay[i]); var outfitFrame = LK.getAsset('itemButton', { anchorX: 0.5, anchorY: 0.5, width: itemSize, height: itemSize, tint: 0xEEEEEE }); var outfitItem = new Container(); outfitItem.addChild(outfitFrame); // Adjust scale of outfit preview to ensure it fits within the frame // Better calculation for scaling to ensure attire is fully visible var baseScale = 0.15; // Base scale for outfit preview outfitPreview.scale.set(baseScale, baseScale); // Ensure the preview fits while keeping attire visible var maxHeight = itemSize * 0.75; if (outfitPreview.height > maxHeight) { var heightScaleFactor = maxHeight / outfitPreview.height; outfitPreview.scale.set(baseScale * heightScaleFactor, baseScale * heightScaleFactor); } // Center the preview in the frame and adjust Y position to prevent overlap outfitPreview.position.set(0, -20); // Move up slightly to avoid overlap with label outfitItem.addChild(outfitPreview); // Calculate position based on grid layout outfitItem.x = startX + col * (itemSize + padding); outfitItem.y = startY + row * (itemSize + padding + 40); // Try to determine ethnic category var categoryName = "Outfit"; var categoryId = null; if (outfitsToDisplay[i].items && Object.keys(outfitsToDisplay[i].items).length > 0) { var firstItem = Object.values(outfitsToDisplay[i].items)[0]; if (firstItem && firstItem.category && categoryLabels[firstItem.category]) { categoryId = firstItem.category; categoryName = categoryLabels[categoryId][storage.currentLanguage] || categoryId; } } var labelText = categoryId ? categoryName : "Outfit " + (i - ethnicCategories.length + 1); var outfitLabel = new Text2(labelText, { size: 30, fill: 0x000000 }); outfitLabel.anchor.set(0.5, 0); outfitLabel.y = itemSize / 2 + 15; outfitItem.addChild(outfitLabel); // Load button functionality outfitItem.outfitData = outfitsToDisplay[i]; outfitItem.interactive = true; outfitItem.down = function (x, y, obj) { if (self.onOutfitSelected) { self.onOutfitSelected(this.outfitData); } // Visual feedback tween(this, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100, easing: tween.easeOut, onFinish: function () { tween(this, { scaleX: 1, scaleY: 1 }, { duration: 100, easing: tween.easeOut }); }.bind(this) }); }.bind(outfitItem); outfitContainer.addChild(outfitItem); } return self; }; self.show = function () { // Reset to first page when opening wardrobe storage.currentWardrobePage = 0; self.visible = true; self.loadOutfits(); return self; }; self.hide = function () { self.visible = false; // Show title text when wardrobe is closed if (typeof titleText !== 'undefined' && titleText) { titleText.visible = true; } return self; }; self.setOutfitSelectedCallback = function (callback) { self.onOutfitSelected = callback; return self; }; // Initial state self.visible = false; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xE6E6FA }); /**** * Game Code ****/ // Initialize ItemSelector // Game constants var itemSelector = new ItemSelector(); itemSelector.x = 2048 / 2; itemSelector.y = 200; // Better positioned to avoid overlap with gender selector itemSelector.currentCategory = 'malay'; // Initialize current category game.addChild(itemSelector); // Initialize with category selection after adding to the game itemSelector.setCategory('malay'); // Add Indigenous female attire itemSelector.items.indigenous.female.top = [{ name: 'Indigenous', label: { en: 'Indigenous Attire', ms: 'Pakaian Orang Asli', zh: '原住民服装', ta: 'பழங்குடி ஆடை' } }]; // Add Ibanman to Iban male attire itemSelector.items.iban.male.top = [{ name: 'Ibanman', label: { en: 'Iban Attire', ms: 'Pakaian Iban', zh: '伊班族服装', ta: 'இபான் ஆடை' } }]; // Add Ibanwoman to Iban female attire itemSelector.items.iban.female.top = [{ name: 'Ibanwoman', label: { en: 'Iban Female Attire', ms: 'Pakaian Wanita Iban', zh: '伊班族女性服装', ta: 'இபான் பெண் ஆடை' } }]; // Add Kadazanman to Kadazan male attire itemSelector.items.kadazan.male.top = [{ name: 'Kadazanman', label: { en: 'Kadazan Male Attire', ms: 'Pakaian Lelaki Kadazan', zh: '卡达山族男性服装', ta: 'கடசான் ஆண் ஆடை' } }]; // Indian traditional // Indigenous traditional // Modern fusion // Sounds // Music // Initialize storage defaults if they don't exist if (storage.savedCharacters === undefined) { storage.savedCharacters = []; } if (storage.currentLanguage === undefined) { storage.currentLanguage = "en"; } var translations = { title: { en: 'Malaysian Mosaic', ms: 'Mozek Malaysia', zh: '马来西亚镶嵌', ta: 'மலேசிய மொசைக்' }, reset: { en: 'Reset', ms: 'Tetapkan Semula', zh: '重置', ta: 'மீட்டமை' } }; // Create background var background = LK.getAsset('backgroundBox', { anchorX: 0.5, anchorY: 0.5 }); background.x = 2048 / 2; background.y = 2732 / 2; game.addChild(background); // Add cultural information scripts var culturalInfoScripts = { bajuKurung: { en: "Before the 20th century, Malay women only wore kemban cloth. After the arrival of Islam, they began wearing the modest baju kurung. Baju kurung is typically known as a type of loose-fitting, long dress, sometimes reaching the knees, paired with a long folded skirt. It covers the entire body, revealing only the face and hands, seen as complying with Islamic dress rules. Baju kurung can be paired with traditional fabrics like songket or batik, and complemented with a selendang or head covering. Baju kurung is suitable for formal occasions or daily affairs.", ms: "Sebelum kurun ke-20, wanita Melayu hanya memakai kain kemban sahaja. Setelah kedatangan Islam, mereka mula memakai baju kurung yang sopan. Baju kurung lazimnya diketahui sebagai jenis baju longgar yang labuh, kadang kala hingga ke lutut dan dipadankan dengan kain panjang yang berlipat tepi. Baju tersebut meliputi seluruh tubuh, memperlihatkan wajah dan tangan sahaja, dilihat sebagai mematuhi peraturan pakaian Islam. Baju kurung boleh dipadankan dengan kain tradisional seperti songket atau batik. Digandingkan dengan kain selendang atau tudung kepala. Baju kurung sesuai dipakai dalam majlis-majlis formal atau urusan seharian.", zh: "在20世纪之前,马来女性只穿kemban布。伊斯兰教到来后,她们开始穿着保守的baju kurung。Baju kurung通常被称为一种宽松、长款的衣服,有时候长及膝盖,搭配长折边裙子。它覆盖全身,只露出脸部和双手,被视为符合伊斯兰着装规则。Baju kurung可以与传统织物如songket或batik搭配,并配以selendang或头巾。Baju kurung适合正式场合或日常事务穿着。", ta: "20ஆம் நூற்றாண்டுக்கு முன், மலாய் பெண்கள் கெம்பான் துணி மட்டுமே அணிந்தனர். இஸ்லாம் வருகைக்குப் பிறகு, அவர்கள் அடக்கமான பாஜு குருங் அணியத் தொடங்கினர். பாஜு குருங் பொதுவாக தளர்வான, நீண்ட ஆடையாக அறியப்படுகிறது, சில நேரங்களில் முழங்கால் வரை நீண்டு, மடிப்புடன் கூடிய நீண்ட பாவாடையுடன் இணைக்கப்படுகிறது. இது முகம் மற்றும் கைகள் மட்டுமே வெளிப்படும் வகையில் முழு உடலையும் மூடுகிறது, இஸ்லாமிய உடை விதிகளுக்கு இணங்குவதாக கருதப்படுகிறது. பாஜு குருங் சாங்கேட் அல்லது பாட்டிக் போன்ற பாரம்பரிய துணிகளுடன் இணைக்கப்படலாம். செலண்டாங் அல்லது தலைப்பாகை உடன் இணைக்கப்படுகிறது. பாஜு குருங் முறையான நிகழ்வுகள் அல்லது அன்றாட விவகாரங்களுக்கு ஏற்றது." } }; // Add title to GUI var titleText = new Text2(translations.title[storage.currentLanguage], { size: 80, fill: 0x4682B4 }); titleText.anchor.set(0.5, 0); titleText.y = 20; LK.gui.top.addChild(titleText); // Add gender selection var genderSelector = new GenderSelector(); genderSelector.x = 2048 / 2 - 600; // Position to left side of character genderSelector.y = 2732 / 2; // Center vertically with character genderSelector.setup(); game.addChild(genderSelector); // Add character var character = new Character(); character.x = 2048 / 2; character.y = 2732 / 2 - 100; game.addChild(character); // Replace babaNyonyaTop with Nyonya for female characters itemSelector.items.babanyonya.female.top = [{ name: 'Nyonya', label: { en: 'Kebaya Nyonya', ms: 'Kebaya Nyonya', zh: '娘惹峇峇服', ta: 'கெபாயா நியோனியா' } }]; // ItemSelector instance already created earlier in the code // Add language selector var languageSelector = new LanguageSelector(); languageSelector.x = 2048 / 2; languageSelector.y = 2732 - 150; // Positioned higher to avoid bottom edge and other UI elements languageSelector.setup(); game.addChild(languageSelector); // Add action buttons // Create panel background for reset button var resetPanel = LK.getAsset('uiPanel', { anchorX: 0.5, anchorY: 0.5, width: 240, height: 100, tint: 0xF44336 }); resetPanel.x = 2048 - 200; resetPanel.y = 200; game.addChild(resetPanel); var resetButton = new UIButton(translations.reset[storage.currentLanguage], 200, 80, 0xF44336); resetButton.x = 2048 - 200; resetButton.y = 200; game.addChild(resetButton); // Add wardrobe button var wardrobeText = { en: "Ethnic Collection", ms: "Koleksi Etnik", zh: "民族服装集", ta: "இன ஆடை தொகுப்பு" }; // Create panel background for wardrobe button var wardrobePanel = LK.getAsset('uiPanel', { anchorX: 0.5, anchorY: 0.5, width: 260, height: 110, tint: 0x8A2BE2 }); wardrobePanel.x = 2048 - 200; wardrobePanel.y = 320; game.addChild(wardrobePanel); // Create a wardrobe button with larger size and better contrast var wardrobeButton = new UIButton(wardrobeText[storage.currentLanguage], 240, 90, 0x8A2BE2); // Set button position wardrobeButton.x = 2048 - 200; wardrobeButton.y = 320; // Make text larger and bolder for better readability wardrobeButton.buttonText.style.size = 40; wardrobeButton.buttonText.style.fill = "#FFFFFF"; game.addChild(wardrobeButton); // Create wardrobe component var wardrobe = new Wardrobe(); wardrobe.x = 2048 / 2; wardrobe.y = 2732 / 2; wardrobe.updateLanguage(storage.currentLanguage); game.addChild(wardrobe); // Connect components genderSelector.setChangeCallback(function (gender) { // Change character base to gender-specific asset character.setGender(gender); }); // Initialize ItemSelector with needed functionality itemSelector.setSelectionCallback(function (item) { character.equip(item); // Show cultural info for baju kurung when selected if (item.itemName === 'bajuKurung') { // Display cultural information panel with baju kurung script culturalInfoPanel.show('bajuKurung'); } }); languageSelector.setChangeCallback(function (language) { // Update all UI text titleText.setText(translations.title[language]); resetButton.setText(translations.reset[language]); wardrobeButton.setText(wardrobeText[language]); // Update gender selector genderSelector.updateLanguage(language); wardrobe.updateLanguage(language); }); // Add cultural info panel var culturalInfoPanel = new CulturalInfoPanel(); culturalInfoPanel.x = 2048 / 2; culturalInfoPanel.y = 2732 / 2; game.addChild(culturalInfoPanel); // Add error message element var errorMessage = new Text2("", { size: 40, fill: 0xFF0000 }); errorMessage.anchor.set(0.5, 0); errorMessage.y = 2732 - 180; // Position above language selector errorMessage.visible = false; LK.gui.bottom.addChild(errorMessage); // Function to show error message temporarily function showError(message, duration) { errorMessage.setText(message); errorMessage.visible = true; LK.setTimeout(function () { errorMessage.visible = false; }, duration || 3000); } // Function to check if character is wearing baju kurung and show the cultural info function checkForBajuKurung() { // Check if character is wearing baju kurung var wearing = false; var itemName = ""; // Check all layers for (var layerName in character.layers) { if (layerName !== 'base' && character.layers[layerName]) { var item = character.layers[layerName]; // Check if this is baju kurung if (item.itemName === 'bajuKurung') { wearing = true; itemName = 'bajuKurung'; break; } } } // If wearing baju kurung, show cultural info if (wearing && itemName) { culturalInfoPanel.show(itemName); } } resetButton.setCallback(function () { // Reset character by clearing all items for (var layerName in character.layers) { if (layerName !== 'base' && character.layers[layerName]) { character.removeChild(character.layers[layerName]); character.layers[layerName] = null; } } }); // Setup wardrobe button wardrobeButton.setCallback(function () { wardrobe.show(); // Hide title text when wardrobe is open titleText.visible = false; }); // Setup wardrobe outfit selection wardrobe.setOutfitSelectedCallback(function (outfitData) { // Apply outfit to character character.loadData(outfitData); // Set character as current outfit automatically for (var categoryId in character.layers) { if (categoryId !== 'base' && character.layers[categoryId]) { if (character.layers[categoryId].select) { character.layers[categoryId].select(); } } } wardrobe.hide(); LK.getSound('itemSelect').play(); }); // Play background music LK.playMusic('malaysiaMix'); // Game update function game.update = function () { // Game logic updates would go here if needed }; // Add event handler for character character.down = function (x, y, obj) { // Check if character is wearing baju kurung for (var layerName in character.layers) { if (layerName !== 'base' && character.layers[layerName]) { var item = character.layers[layerName]; if (item.itemName === 'bajuKurung' && typeof culturalInfoPanel !== 'undefined') { culturalInfoPanel.show('bajuKurung'); break; } } } };
===================================================================
--- original.js
+++ change.js
@@ -370,38 +370,24 @@
var maxHeight = 1528;
var currentWidth = self.originalWidth * self.originalScale.x;
var currentHeight = self.originalHeight * self.originalScale.y;
var scaleFactor = Math.min(maxWidth / currentWidth, maxHeight / currentHeight);
- // Special handling for Ibanman, Ibanwoman, Nyonya and Kadazanman to ensure exact 768x1528 dimensions
- if (self.itemName === 'Ibanman' || self.itemName === 'Ibanwoman' || self.itemName === 'Nyonya' || self.itemName === 'Kadazanman') {
- // Force exact dimensions for all these assets to be 768x1528 pixels
- var exactScaleFactor = Math.min(768 / self.originalWidth, 1528 / self.originalHeight);
- scaleFactor = exactScaleFactor;
- // Special handling for Ibanman to ensure exact 768x1528 pixels while fully visible
- if (self.itemName === 'Ibanman') {
- // Reset to original scale before applying new scale to ensure proper sizing
- self.children[0].scale.set(self.originalScale.x, self.originalScale.y);
- // Calculate exact scale needed for Ibanman with correct aspect ratio
- var exactWidthFactor = 768 / self.originalWidth;
- var exactHeightFactor = 1528 / self.originalHeight;
- // Use the smaller scaling factor to ensure the entire asset is visible
- scaleFactor = Math.min(exactWidthFactor, exactHeightFactor);
- // Set exact dimensions for Ibanman
- self.children[0].scale.set(scaleFactor, scaleFactor);
- // Ensure the dimensions are exactly 768x1528
- self.children[0].width = 768;
- self.children[0].height = 1528;
- }
- // Additional handling for Ibanwoman if needed
+ // Special handling for Ibanman, Ibanwoman and Nyonya to ensure exact 768x1528 dimensions
+ if (self.itemName === 'Ibanman' || self.itemName === 'Ibanwoman') {
+ scaleFactor = Math.min(768 / self.originalWidth, 1528 / self.originalHeight);
+ // Force exact dimensions for Ibanwoman
if (self.itemName === 'Ibanwoman') {
// Calculate the exact scale needed for 768x1528px
- exactScaleFactor = Math.min(768 / self.originalWidth, 1528 / self.originalHeight);
+ var exactScaleFactor = Math.min(768 / self.originalWidth, 1528 / self.originalHeight);
scaleFactor = exactScaleFactor;
}
- // Special handling for Kadazanman to ensure proper visibility after selection
- if (self.itemName === 'Kadazanman') {
- // Force exact dimensions for Kadazanman showcase
- exactScaleFactor = Math.min(768 / self.originalWidth, 1528 / self.originalHeight);
+ } else if (self.itemName === 'Nyonya' || self.itemName === 'Kadazanman' || self.itemName === 'Ibanman') {
+ // Special handling for Nyonya, Kadazanman, and Ibanman to ensure exact 768x1528 px to match other items
+ scaleFactor = Math.min(768 / self.originalWidth, 1528 / self.originalHeight);
+ // Special handling for Kadazanman and Ibanman to ensure proper visibility after selection
+ if (self.itemName === 'Kadazanman' || self.itemName === 'Ibanman') {
+ // Force exact dimensions for Kadazanman and Ibanman showcase
+ var exactScaleFactor = Math.min(768 / self.originalWidth, 1528 / self.originalHeight);
scaleFactor = exactScaleFactor;
}
}
// Apply larger scale with animation
@@ -1198,17 +1184,8 @@
// Calculate the exact scale needed to fit in button while preserving aspect ratio
var exactRatio = 768 / 1528;
var exactScaleFactor = Math.min(bg.width / (itemAsset.width * exactRatio), bg.height / itemAsset.height);
itemAsset.scale.set(exactScaleFactor * exactRatio, exactScaleFactor);
- } else if (item.name === 'Ibanman') {
- // Custom scaling for Ibanman to exactly 300x300px in buttons
- // Reset scale first to get the original dimensions
- itemAsset.scale.set(1, 1);
- // Force exact dimensions of 300x300 for button display
- itemAsset.width = 300;
- itemAsset.height = 300;
- // Center properly within button
- itemAsset.position.set(0, 0);
} else {
itemAsset.scale.set(scaleFactor * aspectRatio, scaleFactor);
}
}
@@ -1393,11 +1370,9 @@
if (!self.buttonText.style) {
self.buttonText.style = {};
}
// At this point we've ensured style exists, so we can safely access it
- if (self.buttonText.style) {
- self.buttonText.style.fill = self.buttonText.style.fill || "#000000";
- }
+ self.buttonText.style.fill = self.buttonText.style.fill || "#000000";
return self;
};
self.down = function (x, y, obj) {
// Button pressed effect