User prompt
"No Room Penalty" - Make it dynamic: Instead of a flat $30, make it variable based on the customer type or hotel rating (e.g., a high-paying customer who leaves costs more).
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'type')' in or related to this line: 'if (task.type === 'room_count') {' Line Number: 2811
User prompt
Green Border/Icon: If Hotel 3 has a high customer influx and empty rooms, the "right arrow" could have a green glow, indicating potential high income if you switch. This provides a strategic "pull" to switch hotels, turning the limitation into a core decision point. โช๐ก Consider importing and using the following plugins: @upit/tween.v1
User prompt
Red Border/Icon on Navigation Buttons: If Hotel 2 has a broken room, the "right arrow" button (leading to Hotel 2) could have a subtle red glow or a small "!" icon. โช๐ก Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'type')' in or related to this line: 'if (task.type === 'room_count') {' Line Number: 2776
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'type')' in or related to this line: 'if (task.type === 'room_count') {' Line Number: 2767
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'type')' in or related to this line: 'if (task.type === 'room_count') {' Line Number: 2767
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'type')' in or related to this line: 'if (task.type === 'room_count') {' Line Number: 2767
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'type')' in or related to this line: 'if (task.type === 'room_count') {' Line Number: 2758
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'type')' in or related to this line: 'if (task.type === 'room_count') {' Line Number: 2758
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'type')' in or related to this line: 'if (task.type === 'room_count') {' Line Number: 2758
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'type')' in or related to this line: 'if (task.type === 'room_count') {' Line Number: 2749
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'type')' in or related to this line: 'if (task.type === 'room_count') {' Line Number: 2740
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'type')' in or related to this line: 'if (task.type === 'room_count') {' Line Number: 2731
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'type')' in or related to this line: 'if (task.type === 'room_count') {' Line Number: 2722
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'type')' in or related to this line: 'if (task.type === 'room_count') {' Line Number: 2713
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'type')' in or related to this line: 'if (task.type === 'room_count') {' Line Number: 2713
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'type')' in or related to this line: 'if (task.type === 'room_count') {' Line Number: 2704
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'type')' in or related to this line: 'if (task.type === 'room_count') {' Line Number: 2695
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'type')' in or related to this line: 'if (task.type === 'room_count') {' Line Number: 2686
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'type')' in or related to this line: 'if (task.type === 'room_count') {' Line Number: 2686
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'type')' in or related to this line: 'if (task.type === 'room_count') {' Line Number: 2686
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'type')' in or related to this line: 'if (task.type === 'room_count') {' Line Number: 2686
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'type')' in or related to this line: 'if (task.type === 'room_count') {' Line Number: 2677
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'type')' in or related to this line: 'if (task.type === 'room_count') {' Line Number: 2677
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { hotel0Rating: 0, hotel1Rating: 0, hotel2Rating: 0, hotel3Rating: 0, hotel4Rating: 0, hotel0RatingCount: 0, hotel1RatingCount: 0, hotel2RatingCount: 0, hotel3RatingCount: 0, hotel4RatingCount: 0, hotel0GuestStays: 0, hotel1GuestStays: 0, hotel2GuestStays: 0, hotel3GuestStays: 0, hotel4GuestStays: 0, hotel0FiveStarAchieved: false, hotel1FiveStarAchieved: false, hotel2FiveStarAchieved: false, hotel3FiveStarAchieved: false, hotel4FiveStarAchieved: false, hotel0HundredStaysAchieved: false, hotel1HundredStaysAchieved: false, hotel2HundredStaysAchieved: false, hotel3HundredStaysAchieved: false, hotel4HundredStaysAchieved: false, hotel0RoomTheme: "standard", hotel1RoomTheme: "standard", hotel2RoomTheme: "standard", hotel3RoomTheme: "standard", hotel4RoomTheme: "standard", hotel0DeluxeUnlocked: false, hotel1DeluxeUnlocked: false, hotel2DeluxeUnlocked: false, hotel3DeluxeUnlocked: false, hotel4DeluxeUnlocked: false, hotel0LuxuryUnlocked: false, hotel1LuxuryUnlocked: false, hotel2LuxuryUnlocked: false, hotel3LuxuryUnlocked: false, hotel4LuxuryUnlocked: false, hotel0VipGuestsServed: 0, hotel1VipGuestsServed: 0, hotel2VipGuestsServed: 0, hotel3VipGuestsServed: 0, hotel4VipGuestsServed: 0, highestBudget: 1000, maintenanceCrewAssigned: "undefined", maintenanceCrewTimer: 0, totalMaintenanceCrews: 1, constructionNoiseActive: false, constructionNoiseTimer: 0, constructionNoiseHotelIndex: "undefined", inspectionActive: false, inspectionTimer: 0, inspectionHotelIndex: "undefined", currentLoan: 0, loanInterest: 0 }); /**** * Classes ****/ var AddRoomButton = Container.expand(function () { var self = Container.call(this); var buttonBg = self.attachAsset('add_room_button', { anchorX: 0.5, anchorY: 0.5 }); self.buttonText = self.addChild(new Text2('Add Room', { size: 50, fill: 0xFFFFFF })); self.buttonText.anchor.set(0.5, 0.5); self.buttonText.x = 0; self.buttonText.y = 0; self.down = function (x, y, obj) { var currentRoomCost = getRoomCost(); if (totalRooms < 60 && hotelCounts[currentHotelIndex] < 12 && budget >= currentRoomCost) { if (hotels[currentHotelIndex].addRoom()) { totalRooms++; hotelCounts[currentHotelIndex]++; budget -= currentRoomCost; // Deduct current room cost // Play money sound for purchase LK.getSound('money').play(); // Flash the new room with a build effect var newRoom = hotels[currentHotelIndex].rooms[hotels[currentHotelIndex].rooms.length - 1]; if (newRoom) { newRoom.alpha = 0; newRoom.scaleX = 0.1; newRoom.scaleY = 0.1; // Animate room appearing tween(newRoom, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 600, easing: tween.bounceOut }); // Flash effect for new construction LK.effects.flashObject(newRoom, 0x00ffff, 800); // Cyan flash for new room } // Show cost text var costText = game.addChild(new Text2('-$' + currentRoomCost, { size: 50, fill: 0xff4444 })); costText.anchor.set(0.5, 0.5); costText.x = self.x; costText.y = self.y - 30; // Animate cost text tween(costText, { y: self.y - 100, alpha: 0 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { costText.destroy(); } }); updateUI(); } } }; self.updateButton = function () { // Check if there are damaged rooms in current hotel var damagedRooms = []; var currentHotelObj = hotels[currentHotelIndex]; if (currentHotelObj.roomDamaged) { for (var i = 0; i < currentHotelObj.roomDamaged.length; i++) { if (currentHotelObj.roomDamaged[i] !== DAMAGE_TYPES.NONE) { var repairCost = currentHotelObj.roomRepairCosts && currentHotelObj.roomRepairCosts[i] || 0; var damageLevel = currentHotelObj.roomDamaged[i] === DAMAGE_TYPES.MINOR ? 'Minor' : 'Major'; damagedRooms.push('Room ' + (i + 1) + ' (' + damageLevel + '): $' + repairCost); } } } if (damagedRooms.length > 0) { // Check if any rooms are currently being repaired var repairsInProgress = 0; if (currentHotelObj.roomsBeingRepaired) { for (var j = 0; j < currentHotelObj.roomsBeingRepaired.length; j++) { if (currentHotelObj.roomsBeingRepaired[j]) { repairsInProgress++; } } } buttonBg.tint = 0xff4444; // Red tint to indicate repairs needed // Add pulsing animation for urgent repairs tween.stop(buttonBg); var _repairPulse = function repairPulse() { tween(buttonBg, { alpha: 0.7, scaleX: 1.05, scaleY: 1.05 }, { duration: 700, easing: tween.easeInOut, onFinish: function onFinish() { tween(buttonBg, { alpha: 1.0, scaleX: 1.0, scaleY: 1.0 }, { duration: 700, easing: tween.easeInOut, onFinish: _repairPulse }); } }); }; _repairPulse(); if (repairsInProgress > 0) { self.buttonText.setText('Repairing (' + repairsInProgress + ')'); } else { self.buttonText.setText('Repairs Needed'); } } else if (totalRooms >= 60 || hotelCounts[currentHotelIndex] >= 12 || budget < getRoomCost()) { buttonBg.tint = 0x666666; if (hotelCounts[currentHotelIndex] >= 12) { self.buttonText.setText('Hotel Full'); } else if (budget < getRoomCost()) { self.buttonText.setText('Need $' + getRoomCost()); } else { self.buttonText.setText('Limit Reached'); } } else { buttonBg.tint = 0xffffff; buttonBg.alpha = 1.0; buttonBg.scaleX = 1.0; buttonBg.scaleY = 1.0; tween.stop(buttonBg); self.buttonText.setText('Add Room'); } // Ensure text is vertically centered in button self.buttonText.y = 0; }; return self; }); var ConstructionNoiseButton = Container.expand(function () { var self = Container.call(this); var buttonBg = self.attachAsset('construction_noise_indicator', { anchorX: 0.5, anchorY: 0.5 }); self.buttonText = self.addChild(new Text2('Construction Noise', { size: 35, fill: 0xFFFFFF })); self.buttonText.anchor.set(0.5, 0.3); self.buttonText.x = 0; self.buttonText.y = 0; self.statusText = self.addChild(new Text2('', { size: 25, fill: 0xFFFFFF })); self.statusText.anchor.set(0.5, 0.7); self.statusText.x = 0; self.statusText.y = 0; self.down = function (x, y, obj) { var isActive = storage.constructionNoiseActive || false; var activeHotel = storage.constructionNoiseHotelIndex || -1; if (!isActive) { // Start construction noise for current hotel storage.constructionNoiseActive = true; storage.constructionNoiseTimer = Math.floor(Math.random() * 300) + 600; // 10-15 seconds at 60fps storage.constructionNoiseHotelIndex = currentHotelIndex; // Play construction noise sound LK.getSound('construction_noise').play(); // Visual effect for noise activation LK.effects.flashScreen(0xff6600, 800); LK.effects.flashObject(self, 0xff0000, 1000); self.updateButton(); updateUI(); } }; self.updateButton = function () { var isActive = storage.constructionNoiseActive || false; var activeHotel = storage.constructionNoiseHotelIndex || -1; var timerRemaining = storage.constructionNoiseTimer || 0; if (isActive && activeHotel === currentHotelIndex && timerRemaining > 0) { // Construction noise active on this hotel buttonBg.tint = 0xff0000; // Red self.buttonText.setText('Noise Active'); var secondsLeft = Math.ceil(timerRemaining / 60); self.statusText.setText(secondsLeft + 's remaining'); } else if (isActive && activeHotel !== currentHotelIndex) { // Construction noise active on different hotel buttonBg.tint = 0x666666; // Gray self.buttonText.setText('Noise Elsewhere'); self.statusText.setText('At Hotel ' + (activeHotel + 1)); } else { // No construction noise active buttonBg.tint = 0xFFFFFF; // White self.buttonText.setText('Start Noise'); self.statusText.setText('-20% income/spawns'); } }; return self; }); var Customer = Container.expand(function () { var self = Container.call(this); self.isVIP = false; self.customerGraphics = self.attachAsset('customer', { anchorX: 0.5, anchorY: 1.0 }); self.isAtHotel = true; self.isMoving = false; self.makeVIP = function () { self.isVIP = true; // Remove existing graphics and add VIP graphics self.removeChild(self.customerGraphics); self.customerGraphics = self.attachAsset('vip_customer', { anchorX: 0.5, anchorY: 1.0 }); // Add golden tint to VIP customers self.customerGraphics.tint = 0xFFD700; }; self.moveToGroceryStore = function () { if (self.isMoving || !self.isAtHotel) return; self.isMoving = true; tween(self, { y: 2400 }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { self.isAtHotel = false; self.isMoving = false; // Free the room when customer leaves if (self.occupiedRoomIndex !== undefined) { hotels[currentHotelIndex].setRoomOccupation(self.occupiedRoomIndex, false); self.occupiedRoomIndex = undefined; } // Stay at grocery store for a moment, then return LK.setTimeout(function () { self.returnToHotel(); }, 1500); } }); }; self.returnToHotel = function () { if (self.isMoving || self.isAtHotel) return; self.isMoving = true; // Calculate target position based on room location (customer already has a room) var targetX = 1024; // Default hotel center var targetY = 1366; // Default hotel center if (self.occupiedRoomIndex !== undefined) { // Re-occupy the same room when returning hotels[currentHotelIndex].setRoomOccupation(self.occupiedRoomIndex, true); // Calculate room position using same logic as in Hotel.updateDisplay var positions = []; for (var row = 0; row < 4; row++) { for (var col = 0; col < 3; col++) { positions.push({ x: (col - 1) * 240, y: (row - 1.5) * 240 }); } } if (self.occupiedRoomIndex < positions.length) { targetX = 1024 + positions[self.occupiedRoomIndex].x; // Add hotel offset targetY = 1366 + positions[self.occupiedRoomIndex].y; // Add hotel offset } } tween(self, { x: targetX, y: targetY }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { self.isAtHotel = true; self.isMoving = false; // Complete scoring task and give rating if (self.scoringTask && !self.hasCompletedTask) { self.hasCompletedTask = true; var taskSuccess = false; // Enhanced comprehensive validation - check all conditions before calling checkTaskCompletion if (self.scoringTask && self.scoringTask !== undefined && self.scoringTask !== null && _typeof22(self.scoringTask) === 'object' && !Array.isArray(self.scoringTask) && self.scoringTask.hasOwnProperty && self.scoringTask.hasOwnProperty('type') && self.scoringTask.type !== null && self.scoringTask.type !== undefined && typeof self.scoringTask.type === 'string' && self.scoringTask.type.length > 0) { // Additional validation for tasks that require target property var requiresTarget = false; try { requiresTarget = self.scoringTask.type === 'room_count' || self.scoringTask.type === 'rating' || self.scoringTask.type === 'budget'; } catch (typeError) { taskSuccess = false; } if (!requiresTarget || self.scoringTask.hasOwnProperty('target') && self.scoringTask.target !== null && self.scoringTask.target !== undefined && typeof self.scoringTask.target === 'number' && !isNaN(self.scoringTask.target)) { try { taskSuccess = checkTaskCompletion(self.scoringTask); } catch (completionError) { taskSuccess = false; } } else { // Task requires target but doesn't have valid target taskSuccess = false; } } else { // If task is invalid, default to failure taskSuccess = false; } var rating = taskSuccess ? Math.floor(Math.random() * 2) + 4 : Math.floor(Math.random() * 3) + 1; // 4-5 for success, 1-3 for failure // Calculate base payment proportional to rating ($10-$100 based on 1-5 star rating) var basePayment = Math.floor(rating / 5 * 90) + 10; // Maps 1-5 stars to $10-$100 // Apply income reduction if room has minor damage if (self.occupiedRoomIndex !== undefined && hotels[currentHotelIndex].roomIncomeReduction) { var incomeReduction = hotels[currentHotelIndex].roomIncomeReduction[self.occupiedRoomIndex] || 0; basePayment = Math.floor(basePayment * (1 - incomeReduction)); } // Apply VIP bonus (3x payment for VIP guests) if (self.isVIP) { basePayment = Math.floor(basePayment * 3); // Track VIP guests served for milestones var vipKey = 'hotel' + currentHotelIndex + 'VipGuestsServed'; var currentVipGuests = storage[vipKey] || 0; storage[vipKey] = currentVipGuests + 1; } // Apply peak hours bonus (25% increase during peak hours) if (isPeakHours) { basePayment = Math.floor(basePayment * 1.25); } // Apply construction noise penalty (20% reduction in payment) var isNoiseActive = storage.constructionNoiseActive || false; var noiseHotel = storage.constructionNoiseHotelIndex || -1; if (isNoiseActive && noiseHotel === currentHotelIndex) { basePayment = Math.floor(basePayment * 0.8); // 20% payment reduction } // Add shop purchases to total payment var totalPayment = basePayment + (self.totalSpent || 0); budget += totalPayment; // Play checkout sound and visual effects LK.getSound('checkout').play(); LK.getSound('money').play(); // Customer checkout flash effect LK.effects.flashObject(self, 0xFFD700, 1000); // Gold flash for checkout // Money collection visual effect var moneyText = game.addChild(new Text2('+$' + totalPayment, { size: 60, fill: 0x00ff00 })); moneyText.anchor.set(0.5, 0.5); moneyText.x = self.x; moneyText.y = self.y - 50; // Animate money text floating up and fading tween(moneyText, { y: self.y - 150, alpha: 0 }, { duration: 1500, easing: tween.easeOut, onFinish: function onFinish() { moneyText.destroy(); } }); // Update highest budget reached and save as score if (budget > highestBudget) { highestBudget = budget; storage.highestBudget = highestBudget; LK.setScore(secretHotelName + ': $' + highestBudget); } // Track guest stays for milestones var guestKey = 'hotel' + currentHotelIndex + 'GuestStays'; var currentGuests = storage[guestKey] || 0; storage[guestKey] = currentGuests + 1; // Auto-rate the hotel based on task completion var ratingKey = 'hotel' + currentHotelIndex + 'Rating'; var countKey = 'hotel' + currentHotelIndex + 'RatingCount'; var currentRating = storage[ratingKey] || 0; var currentCount = storage[countKey] || 0; var totalScore = currentRating * currentCount + rating; var newCount = currentCount + 1; var newRating = totalScore / newCount; storage[ratingKey] = newRating; storage[countKey] = newCount; // Check for milestones after updating stats checkMilestones(currentHotelIndex); updateUI(); } } }); }; return self; }); var GroceryStore = Container.expand(function () { var self = Container.call(this); var storeBg = self.attachAsset('grocery_store', { anchorX: 0.5, anchorY: 0.5 }); // Grocery store text hidden return self; }); var Hotel = Container.expand(function () { var self = Container.call(this); // Hotel background var hotelBg = self.attachAsset('hotel_bg', { anchorX: 0.5, anchorY: 0.5 }); // Properties self.hotelId = 1; self.roomCount = 0; self.rooms = []; self.occupiedRooms = []; // Track which rooms are occupied self.roomDamageCounters = []; // Track guest count for each room self.roomDamaged = []; // Track which rooms are damaged (DAMAGE_TYPES) self.roomIncomeReduction = []; // Track income reduction for minor damage self.setHotel = function (id) { self.hotelId = id; self.updateDisplay(); }; self.addRoom = function () { if (self.roomCount < 12) { // Max 12 rooms per hotel (3x4 grid) var room = self.addChild(LK.getAsset('room_empty', { anchorX: 0.5, anchorY: 0.5 })); // Position rooms in 3x4 grid layout (3 columns, 4 rows) var positions = []; for (var row = 0; row < 4; row++) { for (var col = 0; col < 3; col++) { positions.push({ x: (col - 1) * 240, // Center the grid: -240, 0, 240 y: (row - 1.5) * 240 // Center vertically around hotel with larger gaps }); } } var targetX = positions[self.roomCount].x; var targetY = positions[self.roomCount].y; // Check for overlapping with existing rooms var isOverlapping = false; for (var i = 0; i < self.rooms.length; i++) { var existingRoom = self.rooms[i]; var distanceX = Math.abs(existingRoom.x - targetX); var distanceY = Math.abs(existingRoom.y - targetY); // Check if rooms would overlap (room width is 150, height is 112.5, grid spacing is 240x240) if (distanceX < 240 && distanceY < 240) { isOverlapping = true; break; } } // If overlapping, try to find an alternative position if (isOverlapping) { var foundPosition = false; // Try different directional positions for (var tryPos = 0; tryPos < positions.length && !foundPosition; tryPos++) { if (tryPos === self.roomCount) continue; // Skip the current position targetX = positions[tryPos].x; targetY = positions[tryPos].y; isOverlapping = false; // Check this position against all existing rooms for (var i = 0; i < self.rooms.length; i++) { var existingRoom = self.rooms[i]; var distanceX = Math.abs(existingRoom.x - targetX); var distanceY = Math.abs(existingRoom.y - targetY); if (distanceX < 240 && distanceY < 240) { isOverlapping = true; break; } } if (!isOverlapping) { foundPosition = true; } } // If no position found, don't add the room if (!foundPosition) { room.destroy(); return false; } } room.x = targetX; room.y = targetY; // Room starts as empty (using room_empty asset) self.rooms.push(room); self.occupiedRooms.push(false); // Room starts as empty self.roomDamageCounters.push(0); // Initialize damage counter self.roomDamaged.push(DAMAGE_TYPES.NONE); // Initialize as not damaged self.roomIncomeReduction.push(0); // Initialize income reduction self.roomCount++; return true; } return false; }; self.updateDisplay = function () { // Clear existing rooms for (var i = 0; i < self.rooms.length; i++) { self.rooms[i].destroy(); } self.rooms = []; // Keep damage tracking arrays intact during display updates // Add rooms based on current count using 3x4 grid layout var positions = []; for (var row = 0; row < 4; row++) { for (var col = 0; col < 3; col++) { positions.push({ x: (col - 1) * 240, // Center the grid: -240, 0, 240 y: (row - 1.5) * 240 // Center vertically around hotel with larger gaps }); } } for (var i = 0; i < self.roomCount; i++) { // Use appropriate room asset based on damage and occupation status var assetName; if (self.roomDamaged[i] === DAMAGE_TYPES.MAJOR) { assetName = 'room_major_damage'; } else if (self.roomDamaged[i] === DAMAGE_TYPES.MINOR) { assetName = 'room_minor_damage'; } else { var themeKey = 'hotel' + currentHotelIndex + 'RoomTheme'; var theme = storage[themeKey] || 'standard'; if (theme === 'deluxe') { assetName = self.occupiedRooms[i] ? 'room_deluxe_full' : 'room_deluxe_empty'; } else if (theme === 'luxury') { assetName = self.occupiedRooms[i] ? 'room_luxury_full' : 'room_luxury_empty'; } else { assetName = self.occupiedRooms[i] ? 'room_full' : 'room_empty'; } } var room = self.addChild(LK.getAsset(assetName, { anchorX: 0.5, anchorY: 0.5 })); room.x = positions[i].x; room.y = positions[i].y; // Add click interaction to handle room repairs or occupation room.roomIndex = i; room.down = function (x, y, obj) { if (self.roomDamaged[this.roomIndex] !== DAMAGE_TYPES.NONE) { // Check if room is being repaired if (self.roomsBeingRepaired && self.roomsBeingRepaired[this.roomIndex]) { // Show message that repair is in progress var progressText = game.addChild(new Text2('Repair in progress...', { size: 40, fill: 0xFFFF00 })); progressText.anchor.set(0.5, 0.5); progressText.x = 1024 + this.x; progressText.y = 1366 + this.y; // Fade out the message tween(progressText, { alpha: 0, y: progressText.y - 50 }, { duration: 2000, easing: tween.easeOut, onFinish: function onFinish() { progressText.destroy(); } }); } else { self.repairRoom(this.roomIndex); } } else { self.toggleRoomOccupation(this.roomIndex); } }; self.rooms.push(room); } }; self.toggleRoomOccupation = function (roomIndex) { if (roomIndex >= 0 && roomIndex < self.roomCount) { self.occupiedRooms[roomIndex] = !self.occupiedRooms[roomIndex]; // Update room visual by refreshing display self.updateDisplay(); } }; self.setRoomOccupation = function (roomIndex, isOccupied) { if (roomIndex >= 0 && roomIndex < self.roomCount) { var wasOccupied = self.occupiedRooms[roomIndex]; self.occupiedRooms[roomIndex] = isOccupied; // If room is being occupied, increment damage counter if (isOccupied) { self.roomDamageCounters[roomIndex]++; // Check for minor damage first (earlier threshold) var minorDamageThreshold = Math.floor(Math.random() * 4) + 2; // 2-5 guests before minor damage var majorDamageThreshold = Math.floor(Math.random() * 6) + 8; // 8-13 guests before major damage if (self.roomDamageCounters[roomIndex] >= minorDamageThreshold && self.roomDamaged[roomIndex] === DAMAGE_TYPES.NONE) { // Apply minor damage self.roomDamaged[roomIndex] = DAMAGE_TYPES.MINOR; self.roomIncomeReduction[roomIndex] = 0.2; // 20% income reduction // Generate minor repair cost between $5-$50 var repairCost = Math.floor(Math.random() * 46) + 5; // Apply milestone bonus: 25% repair cost reduction if 100 stays achieved var hundredKey = 'hotel' + currentHotelIndex + 'HundredStaysAchieved'; if (storage[hundredKey]) { repairCost = Math.floor(repairCost * 0.75); } self.roomRepairCosts = self.roomRepairCosts || []; self.roomRepairCosts[roomIndex] = repairCost; } else if (self.roomDamageCounters[roomIndex] >= majorDamageThreshold && self.roomDamaged[roomIndex] === DAMAGE_TYPES.MINOR) { // Upgrade to major damage if room stays in minor damage too long self.roomDamaged[roomIndex] = DAMAGE_TYPES.MAJOR; self.roomIncomeReduction[roomIndex] = 1.0; // 100% income reduction (room unusable) // Generate major repair cost between $100-$300 var repairCost = Math.floor(Math.random() * 201) + 100; // Apply milestone bonus: 25% repair cost reduction if 100 stays achieved if (storage[hundredKey]) { repairCost = Math.floor(repairCost * 0.75); } self.roomRepairCosts[roomIndex] = repairCost; } } // Update room visual by refreshing display self.updateDisplay(); // Update navigation button appearances after potential damage if (leftButton) { leftButton.updateNavButtonAppearance(); } if (rightButton) { rightButton.updateNavButtonAppearance(); } // Add dynamic lighting effect when room becomes occupied if (!wasOccupied && isOccupied && self.rooms[roomIndex]) { var room = self.rooms[roomIndex]; // Brief bright flash effect when room becomes occupied room.tint = 0xFFFFFF; // Start with bright white // Animate to occupied color with a lighting effect tween(room, { tint: 0xFFD700 // Golden highlight }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { // Settle into normal occupied color tween(room, { tint: 0xFFFFFF // Return to normal color }, { duration: 500, easing: tween.easeIn }); } }); } } }; self.roomsBeingRepaired = self.roomsBeingRepaired || []; // Track which rooms are being repaired self.repairRoom = function (roomIndex) { if (roomIndex >= 0 && roomIndex < self.roomCount && self.roomDamaged[roomIndex] !== DAMAGE_TYPES.NONE) { // Check if room is already being repaired if (self.roomsBeingRepaired[roomIndex]) { return; // Don't allow multiple repairs on same room } self.roomRepairCosts = self.roomRepairCosts || []; var repairCost = self.roomRepairCosts[roomIndex] || 0; if (budget >= repairCost) { budget -= repairCost; // Mark room as being repaired self.roomsBeingRepaired[roomIndex] = true; // Generate repair time between 1-3 seconds (1000-3000ms) var repairTime = Math.floor(Math.random() * 2001) + 1000; // Apply maintenance crew speed bonus (50% faster) var crewAssigned = storage.maintenanceCrewAssigned || -1; var crewTimer = storage.maintenanceCrewTimer || 0; if (crewAssigned === currentHotelIndex && crewTimer > 0) { repairTime = Math.floor(repairTime * 0.5); // 50% faster repairs } // Play repair sound LK.getSound('repair').play(); // Get the room for visual effects var room = self.rooms[roomIndex]; // Show repair in progress visual if (room) { // Darken the room during repair room.tint = 0x666666; // Pulsing effect during repair var _pulseAnimation = function pulseAnimation() { tween(room, { alpha: 0.7 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { tween(room, { alpha: 1.0 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { // Continue pulsing if still being repaired if (self.roomsBeingRepaired[roomIndex]) { _pulseAnimation(); } } }); } }); }; _pulseAnimation(); } // Show repair cost text immediately var repairText = game.addChild(new Text2('-$' + repairCost, { size: 50, fill: 0xff4444 })); repairText.anchor.set(0.5, 0.5); repairText.x = 1024 + (room ? room.x : 0); repairText.y = 1366 + (room ? room.y : 0) - 30; // Animate repair cost text tween(repairText, { y: repairText.y - 100, alpha: 0 }, { duration: 1200, easing: tween.easeOut, onFinish: function onFinish() { repairText.destroy(); } }); // Show repair timer text var timerText = game.addChild(new Text2('Repairing...', { size: 40, fill: 0xFFFF00 })); timerText.anchor.set(0.5, 0.5); timerText.x = 1024 + (room ? room.x : 0); timerText.y = 1366 + (room ? room.y : 0) + 30; // Animate timer countdown var remainingTime = repairTime; var timerInterval = LK.setInterval(function () { remainingTime -= 100; var secondsLeft = Math.ceil(remainingTime / 1000); timerText.setText('Repairing... ' + secondsLeft + 's'); if (remainingTime <= 0) { LK.clearInterval(timerInterval); timerText.destroy(); } }, 100); // Complete repair after delay LK.setTimeout(function () { // Complete the repair self.roomDamaged[roomIndex] = DAMAGE_TYPES.NONE; self.roomIncomeReduction[roomIndex] = 0; // Reset income reduction self.roomDamageCounters[roomIndex] = 0; // Reset damage counter delete self.roomRepairCosts[roomIndex]; self.roomsBeingRepaired[roomIndex] = false; // Mark repair as complete // Stop any ongoing tween animations on the room if (room) { tween.stop(room); // Flash the repaired room green room.tint = 0xFFFFFF; // Reset tint room.alpha = 1.0; // Reset alpha LK.effects.flashObject(room, 0x00ff00, 1000); // Green flash for repair // Repair sparkle effect - scale animation tween(room, { scaleX: 1.3, scaleY: 1.3 }, { duration: 300, easing: tween.bounceOut, onFinish: function onFinish() { tween(room, { scaleX: 1.0, scaleY: 1.0 }, { duration: 200, easing: tween.easeIn }); } }); } updateUI(); self.updateDisplay(); // Update navigation button appearances after repair if (leftButton) { leftButton.updateNavButtonAppearance(); } if (rightButton) { rightButton.updateNavButtonAppearance(); } }, repairTime); updateUI(); } } }; return self; }); var InspectionTimerButton = Container.expand(function () { var self = Container.call(this); var buttonBg = self.attachAsset('inspection_timer', { anchorX: 0.5, anchorY: 0.5 }); self.buttonText = self.addChild(new Text2('Inspection Timer', { size: 35, fill: 0xFFFFFF })); self.buttonText.anchor.set(0.5, 0.3); self.buttonText.x = 0; self.buttonText.y = 0; self.statusText = self.addChild(new Text2('', { size: 25, fill: 0xFFFFFF })); self.statusText.anchor.set(0.5, 0.7); self.statusText.x = 0; self.statusText.y = 0; self.down = function (x, y, obj) { var isActive = storage.inspectionActive || false; if (!isActive) { // Start inspection countdown for random hotel var targetHotel = Math.floor(Math.random() * 5); storage.inspectionActive = true; storage.inspectionTimer = Math.floor(Math.random() * 600) + 900; // 15-25 seconds at 60fps storage.inspectionHotelIndex = targetHotel; // Visual effect for inspection started LK.effects.flashScreen(0xff4444, 800); LK.effects.flashObject(self, 0xff0000, 1000); self.updateButton(); updateUI(); } }; self.updateButton = function () { var isActive = storage.inspectionActive || false; var targetHotel = storage.inspectionHotelIndex || -1; var timerRemaining = storage.inspectionTimer || 0; if (isActive && timerRemaining > 0) { // Inspection countdown active buttonBg.tint = 0xff0000; // Red self.buttonText.setText('Inspection Coming!'); var secondsLeft = Math.ceil(timerRemaining / 60); if (targetHotel === currentHotelIndex) { self.statusText.setText('THIS HOTEL: ' + secondsLeft + 's'); } else { self.statusText.setText('Hotel ' + (targetHotel + 1) + ': ' + secondsLeft + 's'); } } else { // No inspection active buttonBg.tint = 0xFFFFFF; // White self.buttonText.setText('Start Inspection'); self.statusText.setText('Fine if <3 stars'); } }; return self; }); var MaintenanceCrewButton = Container.expand(function () { var self = Container.call(this); var buttonBg = self.attachAsset('maintenance_crew_button', { anchorX: 0.5, anchorY: 0.5 }); self.buttonText = self.addChild(new Text2('Assign Crew', { size: 40, fill: 0xFFFFFF })); self.buttonText.anchor.set(0.5, 0.3); self.buttonText.x = 0; self.buttonText.y = 0; self.statusText = self.addChild(new Text2('', { size: 30, fill: 0xFFD700 })); self.statusText.anchor.set(0.5, 0.7); self.statusText.x = 0; self.statusText.y = 0; self.down = function (x, y, obj) { var currentlyAssigned = storage.maintenanceCrewAssigned || -1; var totalCrews = storage.totalMaintenanceCrews || 1; if (currentlyAssigned === currentHotelIndex) { // Remove crew from current hotel storage.maintenanceCrewAssigned = -1; storage.maintenanceCrewTimer = 0; self.updateButton(); updateUI(); } else if (currentlyAssigned === -1) { // Assign crew to current hotel storage.maintenanceCrewAssigned = currentHotelIndex; storage.maintenanceCrewTimer = 1800; // 30 seconds at 60fps self.updateButton(); updateUI(); // Visual assignment effect LK.getSound('checkin').play(); LK.effects.flashObject(self, 0x00FF00, 800); } }; self.updateButton = function () { var currentlyAssigned = storage.maintenanceCrewAssigned || -1; var timerRemaining = storage.maintenanceCrewTimer || 0; if (currentlyAssigned === currentHotelIndex && timerRemaining > 0) { // Crew assigned to this hotel buttonBg.tint = 0x00FF00; // Green self.buttonText.setText('Remove Crew'); var secondsLeft = Math.ceil(timerRemaining / 60); self.statusText.setText(secondsLeft + 's remaining'); } else if (currentlyAssigned >= 0 && currentlyAssigned !== currentHotelIndex) { // Crew assigned to different hotel buttonBg.tint = 0x666666; // Gray self.buttonText.setText('Crew Busy'); self.statusText.setText('At Hotel ' + (currentlyAssigned + 1)); } else { // Crew available buttonBg.tint = 0xFFFFFF; // White self.buttonText.setText('Assign Crew'); self.statusText.setText('50% faster repairs'); } }; return self; }); var NavigationButton = Container.expand(function () { var self = Container.call(this); self.isLeft = true; self.buttonBg = null; self.buttonText = null; self.setDirection = function (isLeft) { self.isLeft = isLeft; // Remove existing background if it exists if (self.buttonBg) { self.removeChild(self.buttonBg); } // Create new background with appropriate asset var assetName = isLeft ? 'nav_button_left' : 'nav_button_right'; self.buttonBg = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 0.5 }); }; // Initialize with default direction self.setDirection(true); self.setText = function (text) { if (self.buttonText) { self.buttonText.destroy(); } self.buttonText = self.addChild(new Text2(text, { size: 40, fill: 0xFFFFFF })); self.buttonText.anchor.set(0.5, 0.5); }; self.updateNavButtonAppearance = function () { if (!self.buttonBg) return; // Determine which hotel this button leads to var targetHotelIndex; if (self.isLeft) { targetHotelIndex = (currentHotelIndex - 1 + 5) % 5; } else { targetHotelIndex = (currentHotelIndex + 1) % 5; } // Check if target hotel has broken rooms var hasBrokenRooms = hasHotelBrokenRooms(targetHotelIndex); // Check if target hotel has high customer influx potential (empty rooms + high rating) var hasHighInfluxPotential = hasHotelHighInfluxPotential(targetHotelIndex); if (hasBrokenRooms) { // Apply enhanced red border/glow effect for broken room indication self.buttonBg.tint = 0xff3333; // Enhanced bright red for maximum visibility // Stop any existing animations to prevent conflicts tween.stop(self.buttonBg); // Create prominent red border glow effect with enhanced pulsing animation var _redGlowPulse = function redGlowPulse() { tween(self.buttonBg, { alpha: 0.3, scaleX: 1.2, scaleY: 1.2, tint: 0xff0000 // Pure red for maximum alert visibility }, { duration: 900, easing: tween.easeInOut, onFinish: function onFinish() { tween(self.buttonBg, { alpha: 1.0, scaleX: 1.0, scaleY: 1.0, tint: 0xff3333 // Return to bright red base }, { duration: 900, easing: tween.easeInOut, onFinish: _redGlowPulse }); } }); }; _redGlowPulse(); // Add warning icon effect with subtle rotation animation var _warningIconAnimation = function warningIconAnimation() { tween(self.buttonBg, { rotation: 0.05 // Slight rotation for attention }, { duration: 150, easing: tween.easeInOut, onFinish: function onFinish() { tween(self.buttonBg, { rotation: -0.05 }, { duration: 150, easing: tween.easeInOut, onFinish: function onFinish() { tween(self.buttonBg, { rotation: 0 }, { duration: 150, easing: tween.easeInOut, onFinish: function onFinish() { // Repeat warning animation every 4 seconds if still broken LK.setTimeout(function () { if (hasHotelBrokenRooms(targetHotelIndex)) { _warningIconAnimation(); } }, 4000); } }); } }); } }); }; LK.setTimeout(_warningIconAnimation, 1500); // Start warning animation after glow begins } else if (hasHighInfluxPotential) { // Apply green glow effect for high income potential self.buttonBg.tint = 0x33ff33; // Bright green for high income potential // Stop any existing animations to prevent conflicts tween.stop(self.buttonBg); // Create green border glow effect with smooth pulsing animation var _greenGlowPulse = function greenGlowPulse() { tween(self.buttonBg, { alpha: 0.6, scaleX: 1.1, scaleY: 1.1, tint: 0x00ff00 // Pure green for maximum income visibility }, { duration: 1200, easing: tween.easeInOut, onFinish: function onFinish() { tween(self.buttonBg, { alpha: 1.0, scaleX: 1.0, scaleY: 1.0, tint: 0x33ff33 // Return to bright green base }, { duration: 1200, easing: tween.easeInOut, onFinish: _greenGlowPulse }); } }); }; _greenGlowPulse(); } else { // Reset to normal appearance when no special conditions self.buttonBg.tint = 0xffffff; self.buttonBg.alpha = 1.0; self.buttonBg.scaleX = 1.0; self.buttonBg.scaleY = 1.0; self.buttonBg.rotation = 0; tween.stop(self.buttonBg); } }; self.down = function (x, y, obj) { if (self.isLeft) { currentHotelIndex = (currentHotelIndex - 1 + 5) % 5; } else { currentHotelIndex = (currentHotelIndex + 1) % 5; } updateHotelDisplay(); }; return self; }); var RatingButton = Container.expand(function () { var self = Container.call(this); self.stars = []; self.hotelIndex = 0; self.currentRating = 0; // Create 5 star buttons for (var i = 0; i < 5; i++) { var star = self.addChild(LK.getAsset('nav_button_left', { anchorX: 0.5, anchorY: 0.5 })); star.scaleX = 0.6; star.scaleY = 0.6; star.x = (i - 2) * 80; // Space stars horizontally star.tint = 0x666666; // Gray by default star.starIndex = i + 1; // Add star text var starText = star.addChild(new Text2('โ ', { size: 30, fill: 0xFFFFFF })); starText.anchor.set(0.5, 0.5); star.down = function (x, y, obj) { self.setRating(this.starIndex); }; self.stars.push(star); } self.setHotelIndex = function (index) { self.hotelIndex = index; self.updateDisplay(); }; self.setRating = function (rating) { self.currentRating = rating; // Update visual stars for (var i = 0; i < 5; i++) { if (i < rating) { self.stars[i].tint = 0xFFD700; // Gold for selected stars } else { self.stars[i].tint = 0x666666; // Gray for unselected } } // Save rating to storage var ratingKey = 'hotel' + self.hotelIndex + 'Rating'; var countKey = 'hotel' + self.hotelIndex + 'RatingCount'; var currentRating = storage[ratingKey] || 0; var currentCount = storage[countKey] || 0; // Calculate new average rating var totalScore = currentRating * currentCount + rating; var newCount = currentCount + 1; var newRating = totalScore / newCount; storage[ratingKey] = newRating; storage[countKey] = newCount; // Update UI updateUI(); }; self.updateDisplay = function () { var ratingKey = 'hotel' + self.hotelIndex + 'Rating'; var rating = storage[ratingKey] || 0; // Show current average rating for (var i = 0; i < 5; i++) { if (i < Math.round(rating)) { self.stars[i].tint = 0xFFD700; // Gold for rated stars } else { self.stars[i].tint = 0x666666; // Gray for unrated } } }; return self; }); var RoomThemeButton = Container.expand(function () { var self = Container.call(this); var buttonBg = self.attachAsset('theme_button', { anchorX: 0.5, anchorY: 0.5 }); buttonBg.scaleX = 0.8; buttonBg.scaleY = 0.8; self.buttonText = self.addChild(new Text2('Standard', { size: 35, fill: 0xFFFFFF })); self.buttonText.anchor.set(0.5, 0.3); self.buttonText.x = 0; self.buttonText.y = 0; self.statusText = self.addChild(new Text2('', { size: 25, fill: 0xFFD700 })); self.statusText.anchor.set(0.5, 0.7); self.statusText.x = 0; self.statusText.y = 0; self.currentTheme = 'standard'; self.themes = [{ name: 'Standard', key: 'standard', cost: 0, unlockRequirement: 0, description: 'Basic gray rooms' }, { name: 'Deluxe', key: 'deluxe', cost: 0, unlockRequirement: 3.0, description: 'Blue themed rooms' }, { name: 'Luxury', key: 'luxury', cost: 0, unlockRequirement: 4.5, description: 'Gold themed rooms' }]; self.down = function (x, y, obj) { self.cycleTheme(); }; self.isThemeUnlocked = function (theme) { if (theme.key === 'standard') return true; var ratingKey = 'hotel' + currentHotelIndex + 'Rating'; var currentRating = storage[ratingKey] || 0; return currentRating >= theme.unlockRequirement; }; self.cycleTheme = function () { var availableThemes = []; for (var i = 0; i < self.themes.length; i++) { if (self.isThemeUnlocked(self.themes[i])) { availableThemes.push(self.themes[i]); } } if (availableThemes.length <= 1) return; var currentIndex = 0; for (var i = 0; i < availableThemes.length; i++) { if (availableThemes[i].key === self.currentTheme) { currentIndex = i; break; } } var nextIndex = (currentIndex + 1) % availableThemes.length; var nextTheme = availableThemes[nextIndex]; self.currentTheme = nextTheme.key; var themeKey = 'hotel' + currentHotelIndex + 'RoomTheme'; storage[themeKey] = nextTheme.key; updateUI(); updateHotelDisplay(); }; self.updateDisplay = function () { var themeKey = 'hotel' + currentHotelIndex + 'RoomTheme'; self.currentTheme = storage[themeKey] || 'standard'; var currentThemeObj = null; for (var i = 0; i < self.themes.length; i++) { if (self.themes[i].key === self.currentTheme) { currentThemeObj = self.themes[i]; break; } } if (currentThemeObj) { self.buttonText.setText(currentThemeObj.name); var ratingKey = 'hotel' + currentHotelIndex + 'Rating'; var currentRating = storage[ratingKey] || 0; var availableThemes = []; for (var i = 0; i < self.themes.length; i++) { if (self.isThemeUnlocked(self.themes[i])) { availableThemes.push(self.themes[i]); } } if (availableThemes.length > 1) { buttonBg.tint = 0xffffff; self.statusText.setText('Click to change'); } else { buttonBg.tint = 0x888888; var nextUnlock = null; for (var i = 0; i < self.themes.length; i++) { if (!self.isThemeUnlocked(self.themes[i])) { nextUnlock = self.themes[i]; break; } } if (nextUnlock) { self.statusText.setText('Need ' + nextUnlock.unlockRequirement.toFixed(1) + 'โ rating'); } else { self.statusText.setText('All unlocked!'); } } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2c3e50 }); /**** * Game Code ****/ // Game state variables // Larger VIP customer function _typeof41(o) { "@babel/helpers - typeof"; return _typeof41 = "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; }, _typeof41(o); } function _typeof40(o) { "@babel/helpers - typeof"; return _typeof40 = "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; }, _typeof40(o); } function _typeof39(o) { "@babel/helpers - typeof"; return _typeof39 = "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; }, _typeof39(o); } function _typeof38(o) { "@babel/helpers - typeof"; return _typeof38 = "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; }, _typeof38(o); } function _typeof37(o) { "@babel/helpers - typeof"; return _typeof37 = "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; }, _typeof37(o); } function _typeof36(o) { "@babel/helpers - typeof"; return _typeof36 = "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; }, _typeof36(o); } function _typeof35(o) { "@babel/helpers - typeof"; return _typeof35 = "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; }, _typeof35(o); } function _typeof34(o) { "@babel/helpers - typeof"; return _typeof34 = "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; }, _typeof34(o); } function _typeof33(o) { "@babel/helpers - typeof"; return _typeof33 = "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; }, _typeof33(o); } function _typeof32(o) { "@babel/helpers - typeof"; return _typeof32 = "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; }, _typeof32(o); } function _typeof31(o) { "@babel/helpers - typeof"; return _typeof31 = "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; }, _typeof31(o); } function _typeof30(o) { "@babel/helpers - typeof"; return _typeof30 = "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; }, _typeof30(o); } function _typeof29(o) { "@babel/helpers - typeof"; return _typeof29 = "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; }, _typeof29(o); } function _typeof28(o) { "@babel/helpers - typeof"; return _typeof28 = "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; }, _typeof28(o); } function _typeof27(o) { "@babel/helpers - typeof"; return _typeof27 = "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; }, _typeof27(o); } function _typeof26(o) { "@babel/helpers - typeof"; return _typeof26 = "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; }, _typeof26(o); } function _typeof25(o) { "@babel/helpers - typeof"; return _typeof25 = "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; }, _typeof25(o); } function _typeof24(o) { "@babel/helpers - typeof"; return _typeof24 = "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; }, _typeof24(o); } function _typeof23(o) { "@babel/helpers - typeof"; return _typeof23 = "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; }, _typeof23(o); } function _typeof22(o) { "@babel/helpers - typeof"; return _typeof22 = "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; }, _typeof22(o); } function _typeof21(o) { "@babel/helpers - typeof"; return _typeof21 = "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; }, _typeof21(o); } function _typeof20(o) { "@babel/helpers - typeof"; return _typeof20 = "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; }, _typeof20(o); } function _typeof19(o) { "@babel/helpers - typeof"; return _typeof19 = "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; }, _typeof19(o); } function _typeof18(o) { "@babel/helpers - typeof"; return _typeof18 = "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; }, _typeof18(o); } function _typeof17(o) { "@babel/helpers - typeof"; return _typeof17 = "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; }, _typeof17(o); } function _typeof16(o) { "@babel/helpers - typeof"; return _typeof16 = "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; }, _typeof16(o); } function _typeof15(o) { "@babel/helpers - typeof"; return _typeof15 = "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; }, _typeof15(o); } function _typeof14(o) { "@babel/helpers - typeof"; return _typeof14 = "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; }, _typeof14(o); } function _typeof13(o) { "@babel/helpers - typeof"; return _typeof13 = "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; }, _typeof13(o); } function _typeof12(o) { "@babel/helpers - typeof"; return _typeof12 = "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; }, _typeof12(o); } function _typeof11(o) { "@babel/helpers - typeof"; return _typeof11 = "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; }, _typeof11(o); } function _typeof10(o) { "@babel/helpers - typeof"; return _typeof10 = "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; }, _typeof10(o); } function _typeof1(o) { "@babel/helpers - typeof"; return _typeof1 = "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; }, _typeof1(o); } function _typeof0(o) { "@babel/helpers - typeof"; return _typeof0 = "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; }, _typeof0(o); } function _typeof9(o) { "@babel/helpers - typeof"; return _typeof9 = "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; }, _typeof9(o); } function _typeof8(o) { "@babel/helpers - typeof"; return _typeof8 = "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; }, _typeof8(o); } function _typeof7(o) { "@babel/helpers - typeof"; return _typeof7 = "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; }, _typeof7(o); } function _typeof6(o) { "@babel/helpers - typeof"; return _typeof6 = "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; }, _typeof6(o); } function _typeof5(o) { "@babel/helpers - typeof"; return _typeof5 = "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; }, _typeof5(o); } 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); } var hotels = []; var currentHotelIndex = 0; var totalRooms = 0; var hotelCounts = [0, 0, 0, 0, 0]; var budget = 1000; var highestBudget = storage.highestBudget || 1000; var hotelNames = ['Grand Palace', 'Ocean View', 'Mountain Lodge', 'City Center', 'Royal Garden']; var secretHotelName = hotelNames[Math.floor(Math.random() * hotelNames.length)]; var milestoneNotification = null; // Room damage types var DAMAGE_TYPES = { NONE: 0, MINOR: 1, MAJOR: 2 }; // Peak hours system var peakHoursTimer = 0; var peakHoursDuration = 600; // 10 seconds at 60fps var offPeakDuration = 900; // 15 seconds at 60fps var isPeakHours = false; var currentPeriodTimer = 0; function showMilestoneNotification(message, bonus) { if (milestoneNotification) { milestoneNotification.destroy(); } milestoneNotification = game.addChild(LK.getAsset('add_room_button', { anchorX: 0.5, anchorY: 0.5 })); milestoneNotification.x = 1024; milestoneNotification.y = 800; milestoneNotification.scaleX = 1.2; milestoneNotification.scaleY = 0.8; milestoneNotification.tint = 0x00ff00; // Animate milestone notification appearance milestoneNotification.alpha = 0; milestoneNotification.scaleX = 0.5; milestoneNotification.scaleY = 0.4; // Play checkout sound for milestone achievement LK.getSound('checkout').play(); tween(milestoneNotification, { alpha: 1, scaleX: 1.2, scaleY: 0.8 }, { duration: 500, easing: tween.bounceOut }); // Flash screen effect for major achievement LK.effects.flashScreen(0xFFD700, 600); var messageText = milestoneNotification.addChild(new Text2(message, { size: 35, fill: 0xFFFFFF })); messageText.anchor.set(0.5, 0.3); var bonusText = milestoneNotification.addChild(new Text2(bonus, { size: 25, fill: 0xFFD700 })); bonusText.anchor.set(0.5, 0.7); LK.setTimeout(function () { if (milestoneNotification) { milestoneNotification.destroy(); milestoneNotification = null; } }, 4000); } function checkMilestones(hotelIndex) { var guestKey = 'hotel' + hotelIndex + 'GuestStays'; var ratingKey = 'hotel' + hotelIndex + 'Rating'; var hundredKey = 'hotel' + hotelIndex + 'HundredStaysAchieved'; var fiveStarKey = 'hotel' + hotelIndex + 'FiveStarAchieved'; var guestStays = storage[guestKey] || 0; var rating = storage[ratingKey] || 0; var hundredAchieved = storage[hundredKey] || false; var fiveStarAchieved = storage[fiveStarKey] || false; if (guestStays >= 100 && !hundredAchieved) { storage[hundredKey] = true; showMilestoneNotification('Hotel ' + (hotelIndex + 1) + ' reached 100 guest stays!', 'Repair costs reduced by 25%'); } if (rating >= 4.8 && !fiveStarAchieved) { storage[fiveStarKey] = true; budget += 200; showMilestoneNotification('Hotel ' + (hotelIndex + 1) + ' achieved 5-star rating!', '+$200 bonus income!'); updateUI(); } // Check for theme unlocks based on rating if (rating >= 3.0) { var deluxeKey = 'hotel' + hotelIndex + 'DeluxeUnlocked'; if (!storage[deluxeKey]) { storage[deluxeKey] = true; showMilestoneNotification('Hotel ' + (hotelIndex + 1) + ' unlocked Deluxe rooms!', 'Blue themed rooms available'); } } if (rating >= 4.5) { var luxuryKey = 'hotel' + hotelIndex + 'LuxuryUnlocked'; if (!storage[luxuryKey]) { storage[luxuryKey] = true; showMilestoneNotification('Hotel ' + (hotelIndex + 1) + ' unlocked Luxury rooms!', 'Gold themed rooms available'); } } // Check VIP guest milestones var vipKey = 'hotel' + hotelIndex + 'VipGuestsServed'; var vipGuests = storage[vipKey] || 0; if (vipGuests >= 10 && vipGuests < 15) { showMilestoneNotification('Hotel ' + (hotelIndex + 1) + ' served 10 VIP guests!', 'VIP service excellence!'); } else if (vipGuests >= 25 && vipGuests < 30) { budget += 500; showMilestoneNotification('Hotel ' + (hotelIndex + 1) + ' served 25 VIP guests!', '+$500 VIP reputation bonus!'); updateUI(); } } // UI elements var hotelNameText; var currentRoomsText; var totalRoomsText; var budgetText; var ratingText; var peakHoursText; var leftButton; var rightButton; var addRoomButton; var ratingButton; var currentHotel; // Initialize hotels for (var i = 0; i < 5; i++) { hotels.push(new Hotel()); } // Add 1 room to the first hotel at game start if (hotels[0].addRoom()) { totalRooms++; hotelCounts[0]++; } // Initialize hotel counts to match hotel room counts for (var i = 0; i < 5; i++) { hotelCounts[i] = hotels[i].roomCount; } // Add neighborhood background behind hotel var neighborhoodBg = game.addChild(LK.getAsset('neighborhood_bg', { anchorX: 0.5, anchorY: 0.5 })); neighborhoodBg.x = 1024; neighborhoodBg.y = 1000; // Position behind hotel area // Add road below hotel - create multiple segments horizontally var roads = []; var roadCount = 6; // Number of road segments var roadWidth = 400; // Width of each road segment var startX = 1024 - roadCount * roadWidth / 2 + roadWidth / 2; // Center the road pattern for (var r = 0; r < roadCount; r++) { var road = game.addChild(LK.getAsset('road', { anchorX: 0.5, anchorY: 0.5 })); road.x = startX + r * roadWidth; road.y = 2200; // Position below hotel area roads.push(road); } // Position current hotel in center currentHotel = game.addChild(hotels[0]); currentHotel.x = 1024; currentHotel.y = 1366; // Create navigation buttons leftButton = game.addChild(new NavigationButton()); leftButton.setDirection(true); leftButton.setText('<'); leftButton.x = 400; leftButton.y = 1366; rightButton = game.addChild(new NavigationButton()); rightButton.setDirection(false); rightButton.setText('>'); rightButton.x = 1648; rightButton.y = 1366; // Create add room button addRoomButton = game.addChild(new AddRoomButton()); addRoomButton.x = 1024; addRoomButton.y = 2020; // Create room theme button var roomThemeButton = game.addChild(new RoomThemeButton()); roomThemeButton.x = 1600; roomThemeButton.y = 2020; // Create maintenance crew button var maintenanceCrewButton = game.addChild(new MaintenanceCrewButton()); maintenanceCrewButton.x = 400; maintenanceCrewButton.y = 2020; // Create construction noise button var constructionNoiseButton = game.addChild(new ConstructionNoiseButton()); constructionNoiseButton.x = 800; constructionNoiseButton.y = 2020; // Create inspection timer button var inspectionTimerButton = game.addChild(new InspectionTimerButton()); inspectionTimerButton.x = 1200; inspectionTimerButton.y = 2020; // Create rating button (hidden) ratingButton = new RatingButton(); ratingButton.x = 1024; ratingButton.y = 2100; ratingButton.setHotelIndex(0); // Create UI text elements hotelNameText = new Text2('Hotel 1', { size: 80, fill: 0xFFFFFF }); hotelNameText.anchor.set(0.5, 0); LK.gui.top.addChild(hotelNameText); hotelNameText.y = 150; currentRoomsText = new Text2('Rooms in this hotel: 0', { size: 50, fill: 0xFFFFFF }); currentRoomsText.anchor.set(0.5, 0); LK.gui.top.addChild(currentRoomsText); currentRoomsText.y = 250; totalRoomsText = new Text2('Total rooms: 0/60', { size: 50, fill: 0xFFFFFF }); totalRoomsText.anchor.set(0.5, 0); LK.gui.top.addChild(totalRoomsText); totalRoomsText.y = 320; budgetText = new Text2('Budget: $1000', { size: 50, fill: 0xFFFFFF }); budgetText.anchor.set(0, 0); LK.gui.topLeft.addChild(budgetText); budgetText.x = 120; budgetText.y = 50; ratingText = new Text2('Rating: 0.0/5 (0 reviews)', { size: 50, fill: 0xFFFFFF }); ratingText.anchor.set(0.5, 0); ratingText.y = 390; peakHoursText = new Text2('Off-Peak Hours', { size: 60, fill: 0x87CEEB }); peakHoursText.anchor.set(1, 0); LK.gui.topRight.addChild(peakHoursText); peakHoursText.x = -20; peakHoursText.y = 50; function updateHotelDisplay() { // Remove current hotel game.removeChild(currentHotel); // Add new hotel currentHotel = game.addChild(hotels[currentHotelIndex]); currentHotel.x = 1024; currentHotel.y = 1366; currentHotel.setHotel(currentHotelIndex + 1); // Update room theme button display if (roomThemeButton) { roomThemeButton.updateDisplay(); } // Update maintenance crew button if (maintenanceCrewButton) { maintenanceCrewButton.updateButton(); } // Update maintenance crew button if (maintenanceCrewButton) { maintenanceCrewButton.updateButton(); } // Update construction noise button if (constructionNoiseButton) { constructionNoiseButton.updateButton(); } // Update inspection timer button if (inspectionTimerButton) { inspectionTimerButton.updateButton(); } // Update navigation button appearances if (leftButton) { leftButton.updateNavButtonAppearance(); } if (rightButton) { rightButton.updateNavButtonAppearance(); } // Check for urgent attention needed across all hotels checkUrgentHotelAlerts(); updateUI(); } function checkUrgentHotelAlerts() { var urgentHotels = []; for (var h = 0; h < 5; h++) { if (h === currentHotelIndex) continue; // Skip current hotel var urgentLevel = 0; var reasons = []; // Check for damaged rooms var damagedCount = 0; for (var r = 0; r < hotels[h].roomCount; r++) { if (hotels[h].roomDamaged[r] !== DAMAGE_TYPES.NONE) { damagedCount++; } } if (damagedCount > 0) { urgentLevel += damagedCount; reasons.push(damagedCount + ' damaged rooms'); } // Check for low rating with inspection risk var ratingKey = 'hotel' + h + 'Rating'; var rating = storage[ratingKey] || 0; var inspectionActive = storage.inspectionActive || false; var inspectionHotel = storage.inspectionHotelIndex || -1; if (inspectionActive && inspectionHotel === h && rating < 3.0) { urgentLevel += 5; reasons.push('INSPECTION RISK'); } // Check for construction noise affecting hotel var noiseActive = storage.constructionNoiseActive || false; var noiseHotel = storage.constructionNoiseHotelIndex || -1; if (noiseActive && noiseHotel === h) { urgentLevel += 2; reasons.push('construction noise'); } if (urgentLevel > 0) { urgentHotels.push({ index: h, urgentLevel: urgentLevel, reasons: reasons }); } } // Show urgent notification for highest priority hotel if (urgentHotels.length > 0) { urgentHotels.sort(function (a, b) { return b.urgentLevel - a.urgentLevel; }); var mostUrgent = urgentHotels[0]; // Only show notification every 5 seconds to avoid spam if (LK.ticks % 300 === 0) { showUrgentHotelNotification(mostUrgent); } } } function showUrgentHotelNotification(urgentHotel) { var notificationText = game.addChild(new Text2('Hotel ' + (urgentHotel.index + 1) + ' needs attention!', { size: 50, fill: 0xff4444 })); notificationText.anchor.set(0.5, 0.5); notificationText.x = 1024; notificationText.y = 500; notificationText.alpha = 0; var reasonText = game.addChild(new Text2(urgentHotel.reasons.join(', '), { size: 35, fill: 0xffaa44 })); reasonText.anchor.set(0.5, 0.5); reasonText.x = 1024; reasonText.y = 560; reasonText.alpha = 0; // Animate notification tween(notificationText, { alpha: 1, y: 480 }, { duration: 500, easing: tween.easeOut }); tween(reasonText, { alpha: 1, y: 540 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { // Fade out after 3 seconds LK.setTimeout(function () { tween(notificationText, { alpha: 0, y: 460 }, { duration: 1000, easing: tween.easeIn, onFinish: function onFinish() { notificationText.destroy(); } }); tween(reasonText, { alpha: 0, y: 520 }, { duration: 1000, easing: tween.easeIn, onFinish: function onFinish() { reasonText.destroy(); } }); }, 3000); } }); // Flash effect for urgent notification LK.effects.flashScreen(0xff4444, 200); } function getRoomCost() { // Base cost is $175 var baseCost = 175; // Scale up costs based on total room thresholds if (totalRooms >= 40) { return 225; // After 40 rooms, cost is $225 } else if (totalRooms >= 20) { return 200; // After 20 rooms, cost is $200 } return baseCost; // Under 20 rooms, cost remains $175 } function updateUI() { // Calculate priority indicators for current hotel var priorityIndicators = []; var currentHotelObj = hotels[currentHotelIndex]; // Check for damaged rooms var damagedCount = 0; for (var r = 0; r < currentHotelObj.roomCount; r++) { if (currentHotelObj.roomDamaged[r] !== DAMAGE_TYPES.NONE) { damagedCount++; } } if (damagedCount > 0) { priorityIndicators.push('โ ๏ธ' + damagedCount); } // Check for construction noise var noiseActive = storage.constructionNoiseActive || false; var noiseHotel = storage.constructionNoiseHotelIndex || -1; if (noiseActive && noiseHotel === currentHotelIndex) { priorityIndicators.push('๐จ'); } // Check for inspection risk var inspectionActive = storage.inspectionActive || false; var inspectionHotel = storage.inspectionHotelIndex || -1; var ratingKey = 'hotel' + currentHotelIndex + 'Rating'; var rating = storage[ratingKey] || 0; if (inspectionActive && inspectionHotel === currentHotelIndex && rating < 3.0) { priorityIndicators.push('๐จ'); } var hotelTitle = 'Hotel ' + (currentHotelIndex + 1); if (priorityIndicators.length > 0) { hotelTitle += ' ' + priorityIndicators.join(' '); } hotelNameText.setText(hotelTitle); currentRoomsText.setText('Rooms in this hotel: ' + hotelCounts[currentHotelIndex]); totalRoomsText.setText('Total rooms: ' + totalRooms + '/60'); var currentLoan = storage.currentLoan || 0; var loanInterest = storage.loanInterest || 0; if (currentLoan > 0) { var totalOwed = currentLoan + loanInterest; budgetText.setText('Budget: $' + budget + ' (Loan: $' + totalOwed + ')'); budgetText.fill = 0xff8888; // Light red to indicate debt } else { budgetText.setText('Budget: $' + budget); budgetText.fill = 0xFFFFFF; // White for normal budget } addRoomButton.updateButton(); // Update room theme button display if (roomThemeButton) { roomThemeButton.updateDisplay(); } // Update peak hours display var timeRemaining = isPeakHours ? Math.ceil((peakHoursDuration - currentPeriodTimer) / 60) : Math.ceil((offPeakDuration - currentPeriodTimer) / 60); if (isPeakHours) { peakHoursText.setText('Peak Hours (' + timeRemaining + 's)'); peakHoursText.fill = 0xFFD700; // Gold color } else { peakHoursText.setText('Off-Peak (' + timeRemaining + 's)'); peakHoursText.fill = 0x87CEEB; // Light blue color } // Update cost display costText.setText('$' + getRoomCost()); // Update rating display (hidden) var ratingKey = 'hotel' + currentHotelIndex + 'Rating'; var countKey = 'hotel' + currentHotelIndex + 'RatingCount'; var guestKey = 'hotel' + currentHotelIndex + 'GuestStays'; var rating = storage[ratingKey] || 0; var count = storage[countKey] || 0; var guestStays = storage[guestKey] || 0; var hundredKey = 'hotel' + currentHotelIndex + 'HundredStaysAchieved'; var fiveStarKey = 'hotel' + currentHotelIndex + 'FiveStarAchieved'; var vipKey = 'hotel' + currentHotelIndex + 'VipGuestsServed'; var vipGuests = storage[vipKey] || 0; var hundredAchieved = storage[hundredKey] ? 'โ' : guestStays + '/100'; var fiveStarAchieved = storage[fiveStarKey] ? 'โ' : rating.toFixed(1) + '/4.8'; ratingText.setText('Rating: ' + rating.toFixed(1) + '/5 (' + count + ' reviews) | Guests: ' + hundredAchieved + ' | 5โ : ' + fiveStarAchieved + ' | VIP: ' + vipGuests); LK.gui.top.addChild(ratingText); } // Update hotel counts when rooms are added function updateHotelCounts() { totalRooms = 0; for (var i = 0; i < 5; i++) { hotelCounts[i] = hotels[i].roomCount; totalRooms += hotelCounts[i]; } } game.update = function () { updateHotelCounts(); // Update maintenance crew timer var crewTimer = storage.maintenanceCrewTimer || 0; if (crewTimer > 0) { storage.maintenanceCrewTimer = crewTimer - 1; if (storage.maintenanceCrewTimer <= 0) { // Crew assignment expired storage.maintenanceCrewAssigned = -1; storage.maintenanceCrewTimer = 0; if (maintenanceCrewButton) { maintenanceCrewButton.updateButton(); } updateUI(); } else if (crewTimer % 60 === 0) { // Update UI every second if (maintenanceCrewButton) { maintenanceCrewButton.updateButton(); } } } // Update construction noise timer var noiseTimer = storage.constructionNoiseTimer || 0; if (noiseTimer > 0) { storage.constructionNoiseTimer = noiseTimer - 1; if (storage.constructionNoiseTimer <= 0) { // Construction noise expired storage.constructionNoiseActive = false; storage.constructionNoiseHotelIndex = -1; storage.constructionNoiseTimer = 0; if (constructionNoiseButton) { constructionNoiseButton.updateButton(); } updateUI(); } else if (noiseTimer % 60 === 0) { // Update UI every second if (constructionNoiseButton) { constructionNoiseButton.updateButton(); } } } // Update inspection timer var inspectionTimer = storage.inspectionTimer || 0; if (inspectionTimer > 0) { storage.inspectionTimer = inspectionTimer - 1; if (storage.inspectionTimer <= 0) { // Inspection time expired - check rating and apply fine if needed var targetHotel = storage.inspectionHotelIndex || 0; var ratingKey = 'hotel' + targetHotel + 'Rating'; var currentRating = storage[ratingKey] || 0; if (currentRating < 3.0) { // Apply fine between $50-$100 var fine = Math.floor(Math.random() * 51) + 50; budget -= fine; // Show fine notification var fineText = game.addChild(new Text2('INSPECTION FINE: -$' + fine, { size: 60, fill: 0xff0000 })); fineText.anchor.set(0.5, 0.5); fineText.x = 1024; fineText.y = 800; fineText.alpha = 0; // Animate fine notification tween(fineText, { alpha: 1, y: 700 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { LK.setTimeout(function () { tween(fineText, { alpha: 0, y: 600 }, { duration: 1000, easing: tween.easeIn, onFinish: function onFinish() { fineText.destroy(); } }); }, 2000); } }); // Flash screen red for fine LK.effects.flashScreen(0xff0000, 1000); } // Reset inspection system storage.inspectionActive = false; storage.inspectionHotelIndex = -1; storage.inspectionTimer = 0; if (inspectionTimerButton) { inspectionTimerButton.updateButton(); } updateUI(); } else if (inspectionTimer % 60 === 0) { // Update UI every second if (inspectionTimerButton) { inspectionTimerButton.updateButton(); } } } // Handle loan system - automatic loan when budget hits $0 if (budget <= 0 && (storage.currentLoan || 0) === 0) { // Take automatic loan between $100-$200 with 5% interest var loanAmount = Math.floor(Math.random() * 101) + 100; // $100-$200 var interestAmount = Math.floor(loanAmount * 0.05); // 5% interest storage.currentLoan = loanAmount; storage.loanInterest = interestAmount; budget += loanAmount; // Show loan notification var loanText = game.addChild(new Text2('EMERGENCY LOAN: +$' + loanAmount, { size: 60, fill: 0x00ff00 })); loanText.anchor.set(0.5, 0.5); loanText.x = 1024; loanText.y = 800; loanText.alpha = 0; // Animate loan notification tween(loanText, { alpha: 1, y: 700 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { LK.setTimeout(function () { tween(loanText, { alpha: 0, y: 600 }, { duration: 1000, easing: tween.easeIn, onFinish: function onFinish() { loanText.destroy(); } }); }, 2000); } }); // Flash screen blue for loan LK.effects.flashScreen(0x0066ff, 1000); updateUI(); } // Handle loan repayment from future income var currentLoan = storage.currentLoan || 0; var loanInterest = storage.loanInterest || 0; if (currentLoan > 0 && budget > 100) { // Automatically deduct 10% of excess budget above $100 towards loan repayment var excessBudget = budget - 100; var repaymentAmount = Math.floor(excessBudget * 0.1); var totalOwed = currentLoan + loanInterest; if (repaymentAmount > 0) { repaymentAmount = Math.min(repaymentAmount, totalOwed); budget -= repaymentAmount; // Apply payment to interest first, then principal if (loanInterest > 0) { var interestPayment = Math.min(repaymentAmount, loanInterest); storage.loanInterest = loanInterest - interestPayment; repaymentAmount -= interestPayment; } if (repaymentAmount > 0) { storage.currentLoan = Math.max(0, currentLoan - repaymentAmount); } // Check if loan is fully paid if (storage.currentLoan <= 0 && storage.loanInterest <= 0) { storage.currentLoan = 0; storage.loanInterest = 0; // Show loan paid notification var paidText = game.addChild(new Text2('LOAN PAID OFF!', { size: 60, fill: 0x00ff00 })); paidText.anchor.set(0.5, 0.5); paidText.x = 1024; paidText.y = 800; paidText.alpha = 0; // Animate paid notification tween(paidText, { alpha: 1, y: 700 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { LK.setTimeout(function () { tween(paidText, { alpha: 0, y: 600 }, { duration: 1000, easing: tween.easeIn, onFinish: function onFinish() { paidText.destroy(); } }); }, 2000); } }); // Flash screen green for loan completion LK.effects.flashScreen(0x00ff00, 1000); } updateUI(); } } // Update peak hours system currentPeriodTimer++; if (isPeakHours) { if (currentPeriodTimer >= peakHoursDuration) { isPeakHours = false; currentPeriodTimer = 0; updateUI(); } } else { if (currentPeriodTimer >= offPeakDuration) { isPeakHours = true; currentPeriodTimer = 0; updateUI(); } } // Spawn customers at random intervals when game starts customerSpawnTimer++; var baseSpawnDelay = Math.floor(Math.random() * 120) + 60; // Random between 1-3 seconds (60-180 frames) var spawnDelay = isPeakHours ? Math.floor(baseSpawnDelay * 0.6) : baseSpawnDelay; // 40% faster during peak hours // Apply construction noise effect - 20% slower spawning for affected hotel var isNoiseActive = storage.constructionNoiseActive || false; var noiseHotel = storage.constructionNoiseHotelIndex || -1; if (isNoiseActive && noiseHotel === currentHotelIndex) { spawnDelay = Math.floor(spawnDelay * 1.2); // 20% slower spawning } // Dynamic customer spawning based on time pressure var timePressureMultiplier = 1.0; var totalGameTime = LK.ticks / 60; // Game time in seconds // Increase pressure every 2 minutes if (totalGameTime > 120) { timePressureMultiplier = 1.5; // 50% more customers } if (totalGameTime > 300) { timePressureMultiplier = 2.0; // Double customers } var maxCustomers = Math.floor(8 * timePressureMultiplier); // Spawn customers with time pressure if (customerSpawnTimer >= spawnDelay && hotelCounts[currentHotelIndex] > 0 && customers.length < maxCustomers) { customerSpawnTimer = 0; spawnCustomer(); // Chance to spawn customers at other hotels simultaneously if (timePressureMultiplier > 1.0 && Math.random() < 0.3) { var otherHotel = Math.floor(Math.random() * 5); if (otherHotel !== currentHotelIndex && hotelCounts[otherHotel] > 0) { // Create background customer activity indicator showBackgroundHotelActivity(otherHotel); } } } // Escalate random events based on time pressure if (LK.ticks % 600 === 0 && totalGameTime > 60) { // Every 10 seconds after 1 minute var eventChance = Math.min(0.4, totalGameTime / 300); // Up to 40% chance if (Math.random() < eventChance) { triggerRandomHotelEvent(); } } // Clean up customers that have been around too long for (var i = customers.length - 1; i >= 0; i--) { // Remove customers after they've made several trips (optional cleanup) if (Math.random() < 0.001) { // Very small chance to remove each frame customers[i].destroy(); customers.splice(i, 1); } } }; // Create grocery store at bottom of screen var groceryStore = game.addChild(new GroceryStore()); groceryStore.x = 1024; groceryStore.y = 2500; // Shop items that customers can purchase var shopItems = [{ name: 'Room Service', price: 25 }, { name: 'Spa Treatment', price: 80 }, { name: 'Restaurant Meal', price: 45 }, { name: 'Minibar Snacks', price: 15 }, { name: 'Laundry Service', price: 20 }, { name: 'WiFi Premium', price: 10 }, { name: 'Pool Access', price: 30 }, { name: 'Gym Access', price: 25 }, { name: 'Parking', price: 35 }, { name: 'Late Checkout', price: 40 }, { name: 'Room Upgrade', price: 75 }, { name: 'Airport Shuttle', price: 50 }, { name: 'Tour Guide', price: 90 }, { name: 'Concierge Service', price: 60 }, { name: 'Baby Crib', price: 20 }]; // Customer management var customers = []; var customerSpawnTimer = Math.floor(Math.random() * 150); // Start with random delay function spawnCustomer() { var customer = game.addChild(new Customer()); // Spawn from left or right side of the road var fromLeft = Math.random() < 0.5; if (fromLeft) { customer.x = -100; // Start off-screen on the left } else { customer.x = 2148; // Start off-screen on the right (2048 + 100) } customer.y = 2200; // Start at road level customers.push(customer); // Find an available room position for the customer (excluding major damaged rooms) var availableRooms = []; for (var roomIdx = 0; roomIdx < hotels[currentHotelIndex].roomCount; roomIdx++) { // Major damaged rooms cannot be occupied, minor damaged rooms can be occupied but with reduced income if (!hotels[currentHotelIndex].occupiedRooms[roomIdx] && hotels[currentHotelIndex].roomDamaged[roomIdx] !== DAMAGE_TYPES.MAJOR) { availableRooms.push(roomIdx); } } var roomIndex = -1; // Default: no room assigned var hasRoom = availableRooms.length > 0; if (hasRoom) { // Assign the first available room roomIndex = availableRooms[0]; customer.occupiedRoomIndex = roomIndex; } // Calculate target position - always go to hotel center first var targetX = 1024; // Default hotel center var targetY = 1366; // Default hotel center // If customer has a room, calculate specific room position if (hasRoom && roomIndex >= 0) { // Calculate room position using same logic as in Hotel.updateDisplay var positions = []; for (var row = 0; row < 4; row++) { for (var col = 0; col < 3; col++) { positions.push({ x: (col - 1) * 240, y: (row - 1.5) * 240 }); } } if (roomIndex < positions.length) { targetX = 1024 + positions[roomIndex].x; // Add hotel offset targetY = 1366 + positions[roomIndex].y; // Add hotel offset } } // First move customer to center of road tween(customer, { x: 1024, // Move to center of screen horizontally y: 2200 // Stay at road level }, { duration: 1000, easing: tween.easeInOut, onFinish: function onFinish() { // Then move customer to the specific room location tween(customer, { x: targetX, y: targetY }, { duration: 1500, easing: tween.easeInOut, onFinish: function onFinish() { // Customer has arrived at hotel - now check if they have a room if (!hasRoom) { // No room available - calculate dynamic penalty based on customer type and hotel rating var basePenalty = 30; var penalty = basePenalty; // Check if this is a VIP customer for higher penalty if (isVIP) { penalty = basePenalty * 3; // VIP customers cost 3x more when turned away } // Apply hotel rating multiplier - higher rated hotels face bigger penalties for turning away customers var ratingKey = 'hotel' + currentHotelIndex + 'Rating'; var currentRating = storage[ratingKey] || 0; var ratingMultiplier = 1.0; if (currentRating >= 4.5) { ratingMultiplier = 2.0; // 5-star hotels face double penalty } else if (currentRating >= 3.5) { ratingMultiplier = 1.5; // 4-star hotels face 50% higher penalty } else if (currentRating >= 2.5) { ratingMultiplier = 1.25; // 3-star hotels face 25% higher penalty } penalty = Math.floor(penalty * ratingMultiplier); // Apply peak hours penalty increase (25% more during peak hours) if (isPeakHours) { penalty = Math.floor(penalty * 1.25); } budget -= penalty; // Show dynamic penalty notification var penaltyText = game.addChild(new Text2('-$' + penalty + ' No Room!', { size: 45, fill: 0xff4444 })); penaltyText.anchor.set(0.5, 0.5); penaltyText.x = customer.x; penaltyText.y = customer.y - 60; penaltyText.alpha = 0; // Animate penalty text tween(penaltyText, { alpha: 1, y: customer.y - 100 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { LK.setTimeout(function () { tween(penaltyText, { alpha: 0, y: customer.y - 140 }, { duration: 1000, easing: tween.easeIn, onFinish: function onFinish() { penaltyText.destroy(); } }); }, 2000); } }); updateUI(); // Make customer leave immediately via the road var exitX = customer.x < 1024 ? -100 : 2148; // Exit same side they came from tween(customer, { x: exitX, y: 2200 // Move back to road level }, { duration: 1000, easing: tween.easeInOut, onFinish: function onFinish() { // Remove customer for (var i = customers.length - 1; i >= 0; i--) { if (customers[i] === customer) { customers.splice(i, 1); break; } } customer.destroy(); } }); return; } // Customer has a room - occupy it hotels[currentHotelIndex].setRoomOccupation(customer.occupiedRoomIndex, true); // Play check-in sound and visual effect LK.getSound('checkin').play(); LK.effects.flashObject(customer, 0x00ff00, 800); // Green flash for check-in // Show customer hint based on their scoring task var hintText = getCustomerHint(customer.scoringTask, isVIP); if (hintText) { var customerHint = game.addChild(new Text2(hintText, { size: 35, fill: 0xFFFFFF })); customerHint.anchor.set(0.5, 0.5); customerHint.x = customer.x; customerHint.y = customer.y - 60; customerHint.alpha = 0; // Animate hint appearing tween(customerHint, { alpha: 1, y: customer.y - 80 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { // Keep hint visible for 3 seconds then fade out LK.setTimeout(function () { tween(customerHint, { alpha: 0, y: customer.y - 100 }, { duration: 1000, easing: tween.easeIn, onFinish: function onFinish() { customerHint.destroy(); } }); }, 3000); } }); } // Scale animation for room when occupied var room = hotels[currentHotelIndex].rooms[customer.occupiedRoomIndex]; if (room) { tween(room, { scaleX: 1.2, scaleY: 1.2 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(room, { scaleX: 1.0, scaleY: 1.0 }, { duration: 200, easing: tween.easeIn }); } }); } // Determine if this is a VIP customer (10% chance, only for currently viewed hotel) var isVIP = Math.random() < 0.1; if (isVIP) { customer.makeVIP(); } // Give customer a scoring task when they arrive at hotel customer.scoringTask = generateScoringTask(isVIP); customer.hasCompletedTask = false; // Generate shop purchases for this customer customer.shopPurchases = generateShopPurchases(); customer.totalSpent = 0; for (var p = 0; p < customer.shopPurchases.length; p++) { customer.totalSpent += customer.shopPurchases[p].price; } // Customer goes to grocery store after arriving at hotel and a random delay LK.setTimeout(function () { customer.moveToGroceryStore(); }, Math.random() * 3000 + 1000); } }); } }); } function generateShopPurchases() { var purchases = []; var numItems = Math.floor(Math.random() * 10) + 1; // 1-10 items var usedItems = []; for (var i = 0; i < numItems; i++) { var availableItems = []; for (var j = 0; j < shopItems.length; j++) { if (usedItems.indexOf(j) === -1) { availableItems.push(j); } } if (availableItems.length > 0) { var randomIndex = availableItems[Math.floor(Math.random() * availableItems.length)]; purchases.push(shopItems[randomIndex]); usedItems.push(randomIndex); } } return purchases; } function generateScoringTask(isVIP) { var tasks = [{ type: 'room_count', target: Math.floor(Math.random() * 10) + 5, description: 'Wants at least X rooms' }, { type: 'rating', target: Math.random() * 3 + 2, description: 'Expects rating above X' }, { type: 'budget', target: Math.floor(Math.random() * 500) + 200, description: 'Hotel should have budget above $X' }, { type: 'empty_room', target: 1, description: 'Requires an empty room' }, { type: 'perfect_maintenance', target: 1, description: 'Requires no damaged rooms' }]; var task; if (isVIP) { // VIP guests have stricter requirements var vipTasks = tasks.slice(3); // Only special VIP tasks (empty room, perfect maintenance) if (Math.random() < 0.3) { // 30% chance for VIP to also have regular high-standard tasks vipTasks = vipTasks.concat(tasks.slice(0, 3)); } task = vipTasks[Math.floor(Math.random() * vipTasks.length)]; } else { // Regular customers get regular tasks (excluding VIP-only tasks) task = tasks.slice(0, 3)[Math.floor(Math.random() * 3)]; } // Customize target based on task type if (task.type === 'room_count') { task.target = isVIP ? Math.floor(Math.random() * 5) + 8 : Math.min(task.target, 15); // VIP wants 8-12 rooms task.description = 'Wants at least ' + task.target + ' rooms'; } else if (task.type === 'rating') { task.target = isVIP ? Math.random() * 0.5 + 4.0 : Math.min(task.target, 4.5); // VIP expects 4.0-4.5 rating task.description = 'Expects rating above ' + task.target.toFixed(1); } else if (task.type === 'budget') { task.target = isVIP ? Math.floor(Math.random() * 800) + 1000 : task.target; // VIP expects $1000-1800 budget task.description = 'Hotel should have budget above $' + task.target; } else if (task.type === 'empty_room') { task.description = 'Requires an empty room available'; } else if (task.type === 'perfect_maintenance') { task.description = 'Requires no damaged rooms'; } return task; } function getCustomerHint(task, isVIP) { var hints = []; if (task.type === 'room_count') { if (isVIP) { hints.push("This VIP guest expects a large, established hotel."); } else { hints.push("This guest prefers a hotel with plenty of rooms."); } } else if (task.type === 'rating') { if (isVIP) { hints.push("This VIP guest demands exceptional service quality."); } else { hints.push("This guest is looking for a highly-rated hotel."); } } else if (task.type === 'budget') { if (isVIP) { hints.push("This VIP guest expects financial stability."); } else { hints.push("This guest is on a tight budget."); } } else if (task.type === 'empty_room') { hints.push("This guest values privacy and space."); } else if (task.type === 'perfect_maintenance') { hints.push("This guest has high cleanliness standards."); } return hints.length > 0 ? hints[Math.floor(Math.random() * hints.length)] : null; } function checkTaskCompletion(task) { // ULTIMATE BULLETPROOF VALIDATION - Prevent all TypeError scenarios // Comprehensive null/undefined guards before ANY property access try { // Primary safety barrier - check task existence and basic validity if (!task) return false; if (task === undefined) return false; if (task === null) return false; if (task === 'undefined') return false; if (task === 'null') return false; if (typeof task === 'undefined') return false; if (typeof task === 'string') return false; if (_typeof40(task) !== 'object') return false; if (Array.isArray(task)) return false; // Secondary safety barrier - check object methods and properties if (!task.hasOwnProperty) return false; if (typeof task.hasOwnProperty !== 'function') return false; if (!task.hasOwnProperty('type')) return false; if (!('type' in task)) return false; // Tertiary safety barrier - check type property specifically var taskTypeProperty; try { taskTypeProperty = task.type; } catch (typeAccessError) { return false; } if (taskTypeProperty === undefined) return false; if (taskTypeProperty === null) return false; if (typeof taskTypeProperty === 'undefined') return false; if (typeof taskTypeProperty !== 'string') return false; if (taskTypeProperty.length === 0) return false; if (taskTypeProperty.trim().length === 0) return false; // Create absolutely safe local copy with additional protection var taskType = ''; try { taskType = String(task.type); if (!taskType || taskType === 'undefined' || taskType === 'null' || taskType.length === 0) return false; } catch (typeError) { return false; } // Ultimate safeguard - validate taskType one more time before any comparisons if (!taskType || typeof taskType !== 'string' || taskType.length === 0) return false; // Validate against known task types with individual try-catch for each comparison var validTaskTypes = ['room_count', 'rating', 'budget', 'empty_room', 'perfect_maintenance']; var isValidTaskType = false; for (var i = 0; i < validTaskTypes.length; i++) { try { if (taskType === validTaskTypes[i]) { isValidTaskType = true; break; } } catch (compareError) { return false; } } if (!isValidTaskType) return false; // Target property validation with nuclear safety var requiresTarget = false; try { requiresTarget = taskType === 'room_count' || taskType === 'rating' || taskType === 'budget'; } catch (requiresError) { return false; } if (requiresTarget) { if (!task.hasOwnProperty('target')) return false; if (task.target === null) return false; if (task.target === undefined) return false; if (typeof task.target !== 'number') return false; if (isNaN(task.target)) return false; } // Final processing with ultimate protection - each condition wrapped individually try { // Final barrier check right before any .type access if (!task || task.type === undefined || task.type === null || typeof task.type !== 'string') return false; if (!taskType || taskType.length === 0) return false; // Additional ultimate safety check - verify task and task.type one final time if (!task || !task.hasOwnProperty || typeof task.hasOwnProperty !== 'function') return false; if (!task.hasOwnProperty('type') || !task.type || typeof task.type !== 'string' || task.type.length === 0) return false; // NUCLEAR OPTION: Ultimate protection against ANY possible TypeError on task.type access var safeTaskType = ''; try { // Triple-check task existence before any property access attempts if (task && task !== null && task !== undefined && _typeof41(task) === 'object' && !Array.isArray(task) && task.hasOwnProperty && typeof task.hasOwnProperty === 'function') { // Only access .type if we've verified the object structure completely if (task.hasOwnProperty('type')) { var typeValue; try { typeValue = task.type; } catch (typeAccessError) { return false; } if (typeValue !== undefined && typeValue !== null && typeof typeValue === 'string' && typeValue.length > 0) { safeTaskType = String(typeValue); } else { return false; } } else { return false; } } else { return false; } } catch (finalSafetyError) { return false; } // Validate safeTaskType before ANY comparison operations if (!safeTaskType || typeof safeTaskType !== 'string' || safeTaskType.length === 0) return false; // Process each task type individually with maximum safety using safeTaskType if (safeTaskType === 'room_count') { try { if (!task.hasOwnProperty('target') || typeof task.target !== 'number') return false; var target = task.target; if (currentHotelIndex >= 0 && currentHotelIndex < hotelCounts.length) { return hotelCounts[currentHotelIndex] >= target; } return false; } catch (roomCountError) { return false; } } else if (safeTaskType === 'rating') { try { if (!task.hasOwnProperty('target') || typeof task.target !== 'number') return false; var target = task.target; var ratingKey = 'hotel' + currentHotelIndex + 'Rating'; var currentRating = storage[ratingKey] || 0; return currentRating >= target; } catch (ratingError) { return false; } } else if (safeTaskType === 'budget') { try { if (!task.hasOwnProperty('target') || typeof task.target !== 'number') return false; var target = task.target; return budget >= target; } catch (budgetError) { return false; } } else if (safeTaskType === 'empty_room') { try { var currentHotelObj = hotels[currentHotelIndex]; if (currentHotelObj && currentHotelObj.roomCount) { for (var i = 0; i < currentHotelObj.roomCount; i++) { if (!currentHotelObj.occupiedRooms[i] && currentHotelObj.roomDamaged[i] === DAMAGE_TYPES.NONE) { return true; } } } return false; } catch (emptyRoomError) { return false; } } else if (safeTaskType === 'perfect_maintenance') { try { var currentHotelObj = hotels[currentHotelIndex]; if (currentHotelObj && currentHotelObj.roomCount) { for (var i = 0; i < currentHotelObj.roomCount; i++) { if (currentHotelObj.roomDamaged[i] !== DAMAGE_TYPES.NONE) { return false; } } return true; } return false; } catch (maintenanceError) { return false; } } return false; } catch (error) { // Ultimate safety net - if any error occurs during processing, safely return false console.log('Task validation error:', error); return false; } } catch (outerError) { // Outer safety net for any possible error in the entire function console.log('Outer task validation error:', outerError); return false; } } function hasHotelBrokenRooms(hotelIndex) { if (hotelIndex < 0 || hotelIndex >= hotels.length) { return false; } var hotel = hotels[hotelIndex]; for (var i = 0; i < hotel.roomCount; i++) { if (hotel.roomDamaged[i] !== DAMAGE_TYPES.NONE) { return true; } } return false; } function hasHotelHighInfluxPotential(hotelIndex) { if (hotelIndex < 0 || hotelIndex >= hotels.length) { return false; } var hotel = hotels[hotelIndex]; // Check if hotel has any rooms at all if (hotel.roomCount === 0) { return false; } // Count empty, undamaged rooms var emptyRooms = 0; for (var i = 0; i < hotel.roomCount; i++) { if (!hotel.occupiedRooms[i] && hotel.roomDamaged[i] === DAMAGE_TYPES.NONE) { emptyRooms++; } } // Need at least 2 empty rooms for high influx potential if (emptyRooms < 2) { return false; } // Check hotel rating - need decent rating for customer attraction var ratingKey = 'hotel' + hotelIndex + 'Rating'; var rating = storage[ratingKey] || 0; // High influx potential if rating is 3.0+ and has multiple empty rooms return rating >= 3.0 && emptyRooms >= 2; } function showBackgroundHotelActivity(hotelIndex) { var activityText = game.addChild(new Text2('Hotel ' + (hotelIndex + 1) + ' has new guests!', { size: 40, fill: 0x44ff44 })); activityText.anchor.set(0.5, 0.5); activityText.x = 1024; activityText.y = 200; activityText.alpha = 0; // Slide in from top tween(activityText, { alpha: 0.8, y: 250 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { // Fade out after 2 seconds LK.setTimeout(function () { tween(activityText, { alpha: 0, y: 300 }, { duration: 1000, easing: tween.easeIn, onFinish: function onFinish() { activityText.destroy(); } }); }, 2000); } }); // Add income from background activity var backgroundIncome = Math.floor(Math.random() * 50) + 25; // $25-75 budget += backgroundIncome; updateUI(); } function triggerRandomHotelEvent() { var events = ['damageEvent', 'vipArrival', 'maintenanceEmergency', 'powerOutage', 'plumbingIssue']; var event = events[Math.floor(Math.random() * events.length)]; var targetHotel = Math.floor(Math.random() * 5); switch (event) { case 'damageEvent': // Random room gets damaged at random hotel if (hotels[targetHotel].roomCount > 0) { var roomIndex = Math.floor(Math.random() * hotels[targetHotel].roomCount); if (hotels[targetHotel].roomDamaged[roomIndex] === DAMAGE_TYPES.NONE) { hotels[targetHotel].roomDamaged[roomIndex] = Math.random() < 0.7 ? DAMAGE_TYPES.MINOR : DAMAGE_TYPES.MAJOR; var repairCost = hotels[targetHotel].roomDamaged[roomIndex] === DAMAGE_TYPES.MINOR ? Math.floor(Math.random() * 46) + 5 : Math.floor(Math.random() * 201) + 100; hotels[targetHotel].roomRepairCosts = hotels[targetHotel].roomRepairCosts || []; hotels[targetHotel].roomRepairCosts[roomIndex] = repairCost; showEventNotification('Emergency repair needed at Hotel ' + (targetHotel + 1) + '!', 0xff4444); } } break; case 'vipArrival': if (targetHotel === currentHotelIndex) { // Spawn VIP customer at current hotel if (customers.length < 8) { var vipCustomer = game.addChild(new Customer()); vipCustomer.makeVIP(); vipCustomer.x = -100; vipCustomer.y = 2200; customers.push(vipCustomer); showEventNotification('VIP guest arriving!', 0xffd700); } } else { // Show VIP activity at other hotel budget += 150; // VIP income from other hotel showEventNotification('VIP guest checked in at Hotel ' + (targetHotel + 1) + '! +$150', 0xffd700); updateUI(); } break; case 'maintenanceEmergency': // All rooms at target hotel get minor damage for (var r = 0; r < hotels[targetHotel].roomCount; r++) { if (hotels[targetHotel].roomDamaged[r] === DAMAGE_TYPES.NONE) { hotels[targetHotel].roomDamaged[r] = DAMAGE_TYPES.MINOR; hotels[targetHotel].roomRepairCosts = hotels[targetHotel].roomRepairCosts || []; hotels[targetHotel].roomRepairCosts[r] = Math.floor(Math.random() * 46) + 5; } } showEventNotification('Maintenance emergency at Hotel ' + (targetHotel + 1) + '!', 0xff6600); break; } // Update displays if the event affected current hotel if (targetHotel === currentHotelIndex) { updateHotelDisplay(); } } function showEventNotification(message, color) { var eventText = game.addChild(new Text2(message, { size: 55, fill: color })); eventText.anchor.set(0.5, 0.5); eventText.x = 1024; eventText.y = 400; eventText.alpha = 0; // Dramatic appearance eventText.scaleX = 0.5; eventText.scaleY = 0.5; tween(eventText, { alpha: 1, scaleX: 1.0, scaleY: 1.0, y: 450 }, { duration: 600, easing: tween.bounceOut, onFinish: function onFinish() { // Stay visible for 4 seconds LK.setTimeout(function () { tween(eventText, { alpha: 0, scaleX: 0.8, scaleY: 0.8, y: 500 }, { duration: 1000, easing: tween.easeIn, onFinish: function onFinish() { eventText.destroy(); } }); }, 4000); } }); // Flash effect LK.effects.flashScreen(color, 300); } function showHighScorePopup() { // Create popup background var popupBg = game.addChild(LK.getAsset('hotel_bg', { anchorX: 0.5, anchorY: 0.5 })); popupBg.x = 1024; popupBg.y = 1366; popupBg.scaleX = 0.8; popupBg.scaleY = 0.6; popupBg.tint = 0x000000; popupBg.alpha = 0.9; // Create popup title var popupTitle = popupBg.addChild(new Text2('High Score', { size: 80, fill: 0xFFFFFF })); popupTitle.anchor.set(0.5, 0.5); popupTitle.y = -150; // Create high score text var highScoreText = popupBg.addChild(new Text2('$' + highestBudget, { size: 120, fill: 0xFFD700 })); highScoreText.anchor.set(0.5, 0.5); highScoreText.y = -50; // Create current budget text var currentBudgetText = popupBg.addChild(new Text2('Current: $' + budget, { size: 60, fill: 0xFFFFFF })); currentBudgetText.anchor.set(0.5, 0.5); currentBudgetText.y = 50; // Create close button var closeButton = popupBg.addChild(new Text2('Close', { size: 50, fill: 0xFFFFFF })); closeButton.anchor.set(0.5, 0.5); closeButton.y = 150; // Add close functionality closeButton.down = function (x, y, obj) { popupBg.destroy(); }; // Add background click to close popupBg.down = function (x, y, obj) { popupBg.destroy(); }; } // Create cost text below add room button var costText = new Text2('$' + getRoomCost(), { size: 60, fill: 0xFFFFFF }); costText.anchor.set(0.5, 0); game.addChild(costText); costText.x = 1024; costText.y = 2050; // 30 pixels below add room button at y: 2020 // Initialize UI updateUI(); // High score button removed - no longer visible in UI // Initialize score with secret hotel name and highest budget reached LK.setScore(secretHotelName + ': $' + highestBudget);
===================================================================
--- original.js
+++ change.js
@@ -2547,10 +2547,63 @@
easing: tween.easeInOut,
onFinish: function onFinish() {
// Customer has arrived at hotel - now check if they have a room
if (!hasRoom) {
- // No room available - give $30 compensation and make customer leave
- budget -= 30;
+ // No room available - calculate dynamic penalty based on customer type and hotel rating
+ var basePenalty = 30;
+ var penalty = basePenalty;
+ // Check if this is a VIP customer for higher penalty
+ if (isVIP) {
+ penalty = basePenalty * 3; // VIP customers cost 3x more when turned away
+ }
+ // Apply hotel rating multiplier - higher rated hotels face bigger penalties for turning away customers
+ var ratingKey = 'hotel' + currentHotelIndex + 'Rating';
+ var currentRating = storage[ratingKey] || 0;
+ var ratingMultiplier = 1.0;
+ if (currentRating >= 4.5) {
+ ratingMultiplier = 2.0; // 5-star hotels face double penalty
+ } else if (currentRating >= 3.5) {
+ ratingMultiplier = 1.5; // 4-star hotels face 50% higher penalty
+ } else if (currentRating >= 2.5) {
+ ratingMultiplier = 1.25; // 3-star hotels face 25% higher penalty
+ }
+ penalty = Math.floor(penalty * ratingMultiplier);
+ // Apply peak hours penalty increase (25% more during peak hours)
+ if (isPeakHours) {
+ penalty = Math.floor(penalty * 1.25);
+ }
+ budget -= penalty;
+ // Show dynamic penalty notification
+ var penaltyText = game.addChild(new Text2('-$' + penalty + ' No Room!', {
+ size: 45,
+ fill: 0xff4444
+ }));
+ penaltyText.anchor.set(0.5, 0.5);
+ penaltyText.x = customer.x;
+ penaltyText.y = customer.y - 60;
+ penaltyText.alpha = 0;
+ // Animate penalty text
+ tween(penaltyText, {
+ alpha: 1,
+ y: customer.y - 100
+ }, {
+ duration: 800,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ LK.setTimeout(function () {
+ tween(penaltyText, {
+ alpha: 0,
+ y: customer.y - 140
+ }, {
+ duration: 1000,
+ easing: tween.easeIn,
+ onFinish: function onFinish() {
+ penaltyText.destroy();
+ }
+ });
+ }, 2000);
+ }
+ });
updateUI();
// Make customer leave immediately via the road
var exitX = customer.x < 1024 ? -100 : 2148; // Exit same side they came from
tween(customer, {
stickman top view. In-Game asset
empty room top view. In-Game asset. 2d. High contrast. No shadows
full room top view. In-Game asset. 2d. High contrast. No shadows
left arrow. In-Game asset
destroyed and damaged red flag cross the stripe
Hotel wall view from the front with flowers and mosses. In-Game asset
16:9
Building silhouettes. In-Game asset
hotel bar top view. In-Game asset