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: 2481
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: 2472
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: 2472
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: 2472
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: 2463
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: 2454
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: 2454
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: 2445
User prompt
Visual Cues for Off-Screen Hotels: The "Add Room button turns red when repairs are needed" is a fantastic start. Extend this: ↪💡 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: 2411
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: 2402
User prompt
The biggest existing challenge is the non-simultaneous operation. Lean into this! The challenge is managing your time and attention across 5 different hotels.
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: 2227
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: 2218
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: 2209
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: 2209
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: 2209
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: 2209
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: 2209
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: 2202
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: 2202
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: 2202
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: 2199
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: 2190
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: 2181
/**** * 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 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; 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; // Comprehensive validation before calling checkTaskCompletion if (self.scoringTask && _typeof2(self.scoringTask) === 'object' && self.scoringTask !== null && self.scoringTask.hasOwnProperty('type') && self.scoringTask.type !== null && self.scoringTask.type !== undefined && typeof self.scoringTask.type === 'string' && self.scoringTask.type.length > 0) { taskSuccess = checkTaskCompletion(self.scoringTask); } 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); if (hasBrokenRooms) { // Apply red glow effect with pulsing animation self.buttonBg.tint = 0xff4444; // Stop any existing tween tween.stop(self.buttonBg); // Start pulsing animation var _pulseAnimation2 = function pulseAnimation() { tween(self.buttonBg, { alpha: 0.6 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(self.buttonBg, { alpha: 1.0 }, { duration: 800, easing: tween.easeInOut, onFinish: _pulseAnimation2 }); } }); }; _pulseAnimation2(); } else { // Reset to normal appearance self.buttonBg.tint = 0xffffff; self.buttonBg.alpha = 1.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 ****/ // Larger VIP customer // Game state variables 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(); } updateUI(); } 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() { hotelNameText.setText('Hotel ' + (currentHotelIndex + 1)); 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 } // Spawn customers regardless of room availability if (customerSpawnTimer >= spawnDelay && hotelCounts[currentHotelIndex] > 0 && customers.length < 8) { customerSpawnTimer = 0; spawnCustomer(); } // 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 - give $30 compensation and make customer leave budget -= 30; 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) { // Immediate early return if task is undefined, null, or not an object if (!task || _typeof6(task) !== 'object' || task === null) { return false; } // Check if task has the required 'type' property and it's a valid string if (!task.hasOwnProperty('type') || task.type === undefined || task.type === null || typeof task.type !== 'string' || task.type.length === 0) { return false; } // Now safely access the type property since we know it exists and is valid var taskType = task.type; if (taskType === 'room_count') { return hotelCounts[currentHotelIndex] >= task.target; } else if (taskType === 'rating') { var ratingKey = 'hotel' + currentHotelIndex + 'Rating'; var currentRating = storage[ratingKey] || 0; return currentRating >= task.target; } else if (taskType === 'budget') { return budget >= task.target; } else if (taskType === 'empty_room') { // Check if there's at least one empty, undamaged room var currentHotelObj = hotels[currentHotelIndex]; for (var i = 0; i < currentHotelObj.roomCount; i++) { if (!currentHotelObj.occupiedRooms[i] && currentHotelObj.roomDamaged[i] === DAMAGE_TYPES.NONE) { return true; } } return false; } else if (taskType === 'perfect_maintenance') { // Check if no rooms are damaged var currentHotelObj = hotels[currentHotelIndex]; for (var i = 0; i < currentHotelObj.roomCount; i++) { if (currentHotelObj.roomDamaged[i] !== DAMAGE_TYPES.NONE) { return false; } } return true; } 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 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);
/****
* 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
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;
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;
// Comprehensive validation before calling checkTaskCompletion
if (self.scoringTask && _typeof2(self.scoringTask) === 'object' && self.scoringTask !== null && self.scoringTask.hasOwnProperty('type') && self.scoringTask.type !== null && self.scoringTask.type !== undefined && typeof self.scoringTask.type === 'string' && self.scoringTask.type.length > 0) {
taskSuccess = checkTaskCompletion(self.scoringTask);
}
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);
if (hasBrokenRooms) {
// Apply red glow effect with pulsing animation
self.buttonBg.tint = 0xff4444;
// Stop any existing tween
tween.stop(self.buttonBg);
// Start pulsing animation
var _pulseAnimation2 = function pulseAnimation() {
tween(self.buttonBg, {
alpha: 0.6
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(self.buttonBg, {
alpha: 1.0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: _pulseAnimation2
});
}
});
};
_pulseAnimation2();
} else {
// Reset to normal appearance
self.buttonBg.tint = 0xffffff;
self.buttonBg.alpha = 1.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
****/
// Larger VIP customer
// Game state variables
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();
}
updateUI();
}
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() {
hotelNameText.setText('Hotel ' + (currentHotelIndex + 1));
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
}
// Spawn customers regardless of room availability
if (customerSpawnTimer >= spawnDelay && hotelCounts[currentHotelIndex] > 0 && customers.length < 8) {
customerSpawnTimer = 0;
spawnCustomer();
}
// 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 - give $30 compensation and make customer leave
budget -= 30;
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) {
// Immediate early return if task is undefined, null, or not an object
if (!task || _typeof6(task) !== 'object' || task === null) {
return false;
}
// Check if task has the required 'type' property and it's a valid string
if (!task.hasOwnProperty('type') || task.type === undefined || task.type === null || typeof task.type !== 'string' || task.type.length === 0) {
return false;
}
// Now safely access the type property since we know it exists and is valid
var taskType = task.type;
if (taskType === 'room_count') {
return hotelCounts[currentHotelIndex] >= task.target;
} else if (taskType === 'rating') {
var ratingKey = 'hotel' + currentHotelIndex + 'Rating';
var currentRating = storage[ratingKey] || 0;
return currentRating >= task.target;
} else if (taskType === 'budget') {
return budget >= task.target;
} else if (taskType === 'empty_room') {
// Check if there's at least one empty, undamaged room
var currentHotelObj = hotels[currentHotelIndex];
for (var i = 0; i < currentHotelObj.roomCount; i++) {
if (!currentHotelObj.occupiedRooms[i] && currentHotelObj.roomDamaged[i] === DAMAGE_TYPES.NONE) {
return true;
}
}
return false;
} else if (taskType === 'perfect_maintenance') {
// Check if no rooms are damaged
var currentHotelObj = hotels[currentHotelIndex];
for (var i = 0; i < currentHotelObj.roomCount; i++) {
if (currentHotelObj.roomDamaged[i] !== DAMAGE_TYPES.NONE) {
return false;
}
}
return true;
}
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 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);
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