User prompt
Please fix the bug: 'Script error.' in or related to this line: 'storage.dayStats = dayStats;' Line Number: 217 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'storage.get is not a function' in or related to this line: 'var stats = storage.get('dayStats');' Line Number: 222 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'storage.getItem is not a function' in or related to this line: 'var stats = storage.getItem('dayStats');' Line Number: 222
User prompt
Please fix the bug: 'storage.get is not a function' in or related to this line: 'var stats = storage.get('dayStats');' Line Number: 222
User prompt
Please fix the bug: 'storage.getItem is not a function' in or related to this line: 'var stats = storage.getItem('dayStats');' Line Number: 222
User prompt
Please fix the bug: 'storage.get is not a function' in or related to this line: 'var stats = storage.get('dayStats');' Line Number: 222
User prompt
Write a system that will generate statistics on how we work between days (how many people did you pass, how many correct answers did you get, how many wrong answers did you get...) then calculate the minus and plus of these and tell us how much money we earned, so that our money is recorded every day.
User prompt
remove the white part in the middle of the main menu and remove the names on the buttons so that the buttons remain unwritten
User prompt
Delete the text with the name of the game on the left side of the white part behind the buttons and align the buttons to the left side with 2cm spaces between them.
User prompt
create another changeable background for the main menu
User prompt
Make new buttons for "Play", "Settings" and "Exit" and make them toggleable in the assets section, also disable the clock in the main menu so the clock starts ticking when you start the game
User prompt
There is a main menu. Pressing the "Play" button starts the game. Pressing the "Settings" button enters the settings section. Pressing the "Quit" button closes the game.
User prompt
The sound that people make when they come should come 1 second after the "NEXT" sound because it gets mixed up.
User prompt
When we press the "Next" button, a sound should be played and when new people arrive, a sound should be played.
User prompt
After a person's transaction is completed, time does not pass until the next button is pressed. Fix this and ensure that the clock flows in every way.
User prompt
Add a clock to the top left corner. Let our task start at 9:00 every day and end at 13:50. By the way, remove the number of mistakes you added before so that we don't lose it when we make too many mistakes.
User prompt
People should come from the right, then when the process is finished, the approved ones should go to the left, the unapproved ones should go to the right.
User prompt
delete the tasks and rewrite or reset them because the task is not readable
User prompt
The tasks text is broken, fix it and then cancel the task background, put an arrow at the top right, when that arrow key is pressed, the tasks section will open, let's read it from there, then close that arrow again whenever we want and this arrow will be closed by default
User prompt
Please fix the bug: 'Cannot set properties of undefined (setting 'wordWrap')' in or related to this line: 'ruleTxt.style.wordWrap = true;' Line Number: 548
User prompt
bring tasks to the forefront of the body background and also adjust tasks according to that background
User prompt
Create another background for the tasks section and place the tasks according to that background
User prompt
move the tasks section to the left and add a changeable background behind it
User prompt
Make the white background longer than the text in the section where we click on the person and get information.
User prompt
Click on the person and create a new background to assets and write the background that we get information about, and also add a new background to the assts for the background of the part where the people's names are.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highScore: 0 }); /**** * Classes ****/ // Document class: represents a single document (passport, permit, etc.) var Document = Container.expand(function () { var self = Container.call(this); // docType: 'passport', 'permit', etc. self.docType = ''; self.fields = {}; // e.g. {name: '...', dob: '...', ...} self.isForged = false; // Visual self.bg = null; self.textFields = []; // Helper to set up document self.setup = function (docType, fields, isForged) { self.docType = docType; self.fields = fields; self.isForged = isForged; // Remove previous if (self.bg) self.bg.destroy(); for (var i = 0; i < self.textFields.length; i++) self.textFields[i].destroy(); self.textFields = []; // Background self.bg = self.attachAsset(docType, { anchorX: 0, anchorY: 0 }); // Title var title = new Text2(docType.toUpperCase(), { size: 60, fill: 0x333333 }); title.x = 40; title.y = 28; self.addChild(title); self.textFields.push(title); // Fields var y = 120; for (var key in fields) { var value = fields[key]; var txt = new Text2(key.charAt(0).toUpperCase() + key.slice(1) + ": " + value, { size: 52, fill: 0x222222 }); txt.x = 40; txt.y = y; self.addChild(txt); self.textFields.push(txt); y += 70; } // If forged, add a subtle red border if (isForged) { self.bg.tint = 0xffaaaa; } else { self.bg.tint = 0xffffff; } }; return self; }); // Traveler class: represents a person with documents var Traveler = Container.expand(function () { var self = Container.call(this); // Person visual var PERSON_ASSETS = [{ id: 'person', gender: 'male' }, { id: 'person2', gender: 'male' }, { id: 'person3', gender: 'male' }, { id: 'person4', gender: 'male' }, { id: 'person5', gender: 'male' }, { id: 'female1', gender: 'female' }, { id: 'female2', gender: 'female' }, { id: 'female3', gender: 'female' }, { id: 'female4', gender: 'female' }]; var personAssetObj = PERSON_ASSETS[Math.floor(Math.random() * PERSON_ASSETS.length)]; self.gender = personAssetObj.gender; var person = self.attachAsset(personAssetObj.id, { anchorX: 0.5, anchorY: 1 }); person.y = 0; // Documents (passport, permit, etc.) self.documents = []; // Will be filled by game // Name label background self.nameBg = LK.getAsset('bg_name_section', { anchorX: 0.5, anchorY: 0 }); self.nameBg.x = 0; self.nameBg.y = -person.height - 50; self.addChild(self.nameBg); // Name label self.nameTxt = new Text2('', { size: 60, fill: 0x222222 }); self.nameTxt.anchor.set(0.5, 0); self.nameTxt.x = 0; self.nameTxt.y = -person.height - 40; self.addChild(self.nameTxt); // Helper to show/hide documents self.showDocuments = function (show) { for (var i = 0; i < self.documents.length; i++) { self.documents[i].visible = !!show; } }; // Helper to destroy all docs self.destroyDocuments = function () { for (var i = 0; i < self.documents.length; i++) { self.documents[i].destroy(); } self.documents = []; // Remove extra info text if present if (self.extraInfoTxt) { self.extraInfoTxt.destroy(); self.extraInfoTxt = null; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xede5d0 }); /**** * Game Code ****/ // Sound for traveler arrival // Sound for next button // Add background images for changeable backgrounds // Game state variables // Document backgrounds // Female character assets // Toggleable main menu button assets var currentTraveler = null; var travelersProcessed = 0; var correctDecisions = 0; var wrongDecisions = 0; var day = 1; var rules = []; var travelerQueue = []; var isDecisionActive = false; var lastDecision = null; var lastFeedbackTimeout = null; var scoreTxt = null; var dayTxt = null; var ruleTxt = null; var table = null; var approveBtn = null; var denyBtn = null; var feedbackTxt = null; // --- Daily statistics and money tracking --- var dayStats = []; // Array of {day, processed, correct, wrong, money} var money = 0; // Helper: Save stats to persistent storage function saveDayStats() { storage.dayStats = dayStats; storage.money = money; } // Helper: Load stats from persistent storage function loadDayStats() { var stats = storage.dayStats; var m = storage.money; if (Array.isArray(stats)) dayStats = stats; if (typeof m === "number") money = m; } loadDayStats(); // Names and data for random generation var NAMES = ["Hans Müller", "Erika Schmidt", "Karl Weber", "Anna Fischer", "Otto Becker", "Liselotte Braun", "Friedrich Wagner", "Greta Hoffmann", "Johann Bauer", "Marta Klein", "Wilhelm Richter", "Sophie Keller", "Heinrich Vogel", "Paula Neumann", "Emil Schuster", "Clara Busch", "Maximilian König", "Helene Frank", "Bruno Schäfer", "Rosa Winkler", "Paul Zimmermann", "Maria Lorenz", "Ludwig Hartmann", "Ida Simon", "Franz Lehmann", "Emma Wolf", "Gustav Peters", "Charlotte Roth", "Walter Krause", "Luise Berger", "Rudolf Fuchs", "Elsa Brandt"]; var CITIES = ["Berlin", "Munich", "Hamburg", "Cologne", "Frankfurt", "Leipzig", "Dresden", "Stuttgart"]; var NATIONALITIES = ["German", "Austrian", "Polish", "Czech", "French", "Dutch"]; // Rules per day var RULES_BY_DAY = [ // Day 1 [{ desc: "Allow only travelers with a valid German passport.", check: function check(traveler) { var pass = getDoc(traveler, 'passport'); return pass && pass.fields.nationality === "German" && !pass.isForged; } }], // Day 2 [{ desc: "Allow only travelers with a valid German passport.", check: function check(traveler) { var pass = getDoc(traveler, 'passport'); return pass && pass.fields.nationality === "German" && !pass.isForged; } }, { desc: "Entry permit required for non-Germans.", check: function check(traveler) { var pass = getDoc(traveler, 'passport'); if (!pass) return false; if (pass.fields.nationality === "German") return true; var permit = getDoc(traveler, 'permit'); return permit && !permit.isForged; } }], // Day 3 [{ desc: "Allow only travelers with a valid German passport.", check: function check(traveler) { var pass = getDoc(traveler, 'passport'); return pass && pass.fields.nationality === "German" && !pass.isForged; } }, { desc: "Entry permit required for non-Germans.", check: function check(traveler) { var pass = getDoc(traveler, 'passport'); if (!pass) return false; if (pass.fields.nationality === "German") return true; var permit = getDoc(traveler, 'permit'); return permit && !permit.isForged; } }, { desc: "Deny travelers from Poland.", check: function check(traveler) { var pass = getDoc(traveler, 'passport'); return pass && pass.fields.nationality !== "Polish"; } }]]; // Helper: get document by type function getDoc(traveler, docType) { for (var i = 0; i < traveler.documents.length; i++) { if (traveler.documents[i].docType === docType) return traveler.documents[i]; } return null; } // Helper: generate a random traveler function generateTraveler(day) { var t = new Traveler(); // Name var name = NAMES[Math.floor(Math.random() * NAMES.length)]; t.nameTxt.setText(name); // Gender from asset var gender = t.gender || (Math.random() < 0.5 ? "male" : "female"); // Passport var nationality = NATIONALITIES[Math.floor(Math.random() * NATIONALITIES.length)]; var city = CITIES[Math.floor(Math.random() * CITIES.length)]; var dob = 1900 + Math.floor(Math.random() * 30) + "-" + (1 + Math.floor(Math.random() * 12)) + "-" + (1 + Math.floor(Math.random() * 28)); var passportFields = { name: name, nationality: nationality, city: city, dob: dob, gender: gender }; // 10% chance of forged passport from day 2+ var forgedPassport = day >= 2 && Math.random() < 0.1; var passport = new Document(); passport.setup('passport', passportFields, forgedPassport); passport.x = -350; passport.y = 100; t.addChild(passport); t.documents.push(passport); // Permit (for non-Germans, 50% chance from day 2+) var hasPermit = nationality !== "German" && day >= 2 && Math.random() < 0.5; if (hasPermit) { var permitFields = { name: name, nationality: nationality, valid: "Yes", gender: gender }; // 10% chance of forged permit from day 3+ var forgedPermit = day >= 3 && Math.random() < 0.1; var permit = new Document(); permit.setup('permit', permitFields, forgedPermit); permit.x = 200; permit.y = 100; t.addChild(permit); t.documents.push(permit); } // Hide docs initially t.showDocuments(false); return t; } // Helper: get today's rules function getRulesForDay(day) { if (day - 1 < RULES_BY_DAY.length) { return RULES_BY_DAY[day - 1]; } // After day 3, repeat day 3 rules return RULES_BY_DAY[RULES_BY_DAY.length - 1]; } // Helper: check if traveler should be allowed function isTravelerAllowed(traveler) { var rulesToday = getRulesForDay(day); for (var i = 0; i < rulesToday.length; i++) { if (!rulesToday[i].check(traveler)) return false; } return true; } // Helper: show feedback function showFeedback(text, color) { if (feedbackTxt) { feedbackTxt.setText(text); // Use setStyle to change fill color, supporting both hex and string if (typeof color === "string" || typeof color === "number") { feedbackTxt.setStyle({ fill: color }); } feedbackTxt.visible = true; if (lastFeedbackTimeout) LK.clearTimeout(lastFeedbackTimeout); lastFeedbackTimeout = LK.setTimeout(function () { feedbackTxt.visible = false; }, 1200); } } // Helper: next traveler function nextTraveler() { if (currentTraveler) { currentTraveler.destroyDocuments(); currentTraveler.destroy(); currentTraveler = null; } isDecisionActive = false; lastDecision = null; // End of day after 10 travelers if (travelersProcessed > 0 && travelersProcessed % 10 === 0) { // Calculate wrong answers for the day var wrong = typeof wrongDecisions === "number" ? wrongDecisions : 10 - correctDecisions; // Record stats for the day dayStats.push({ day: day, processed: travelersProcessed, correct: correctDecisions, wrong: wrong, money: money }); saveDayStats(); day++; travelersProcessed = 0; correctDecisions = 0; wrongDecisions = 0; showFeedback("Day " + day + " begins. New rules!", "#3333cc"); updateDayAndRules(); resetClock(); LK.setTimeout(function () { nextTraveler(); }, 1200); return; } // Generate new traveler currentTraveler = generateTraveler(day); // Start off-screen right currentTraveler.x = 2048 + 400; currentTraveler.y = 1200; currentTraveler.alpha = 1; game.addChild(currentTraveler); // Play traveler arrival sound after 1 second to avoid overlap with Next button sound LK.setTimeout(function () { LK.getSound('traveler_arrive').play(); }, 1000); // Animate in to center tween(currentTraveler, { x: 2048 / 2 }, { duration: 600, easing: tween.cubicOut, onFinish: function onFinish() { // Show docs after short delay LK.setTimeout(function () { if (currentTraveler) currentTraveler.showDocuments(true); isDecisionActive = true; }, 400); } }); } // Helper: update day and rules display function updateDayAndRules() { if (dayTxt) dayTxt.setText("Day " + day); if (ruleTxt) { var rulesToday = getRulesForDay(day); var ruleStr = ""; for (var i = 0; i < rulesToday.length; i++) { ruleStr += i + 1 + ". " + rulesToday[i].desc + "\n"; } ruleTxt.setText(ruleStr); } // Change background image based on day if (typeof bgNode !== "undefined" && typeof bgImages !== "undefined") { // Only one background now: office var idx = 0; if (bgNode.assetId !== bgImages[idx]) { var newBg = LK.getAsset(bgImages[idx], { anchorX: 0, anchorY: 0, x: 0, y: 0 }); // Replace old background node if (bgNode.parent) bgNode.parent.removeChild(bgNode); bgNode = newBg; game.addChildAt(bgNode, 0); // Add at bottom } } // No background for rules/tasks section; just update ruleTxt text } // Approve/deny button handlers function handleDecision(approved) { if (!isDecisionActive || !currentTraveler) return; isDecisionActive = false; travelersProcessed++; var allowed = isTravelerAllowed(currentTraveler); var correct = approved === allowed; if (correct) { correctDecisions++; showFeedback("Correct!", "#4caf50"); LK.setScore(LK.getScore() + 1); if (scoreTxt) scoreTxt.setText(LK.getScore()); money += 5; // +5 for correct } else { wrongDecisions = (typeof wrongDecisions === "number" ? wrongDecisions : 0) + 1; showFeedback("Mistake!", "#d32f2f"); // Flash screen red for mistake LK.effects.flashScreen(0xff0000, 500); money -= 2; // -2 for wrong } // Save stats after each decision saveDayStats(); // Animate traveler out // Approved: exit left, Denied: exit right var targetX = approved ? -400 : 2048 + 400; tween(currentTraveler, { x: targetX, alpha: 0 }, { duration: 600, easing: tween.cubicOut, onFinish: function onFinish() { // Do not call nextTraveler automatically; wait for Next button // Traveler will be removed, but nextTraveler is only called by Next button } }); } // Add background image node (behind everything) var bgImages = ['bg_office']; var bgMenuImage = 'bg_menu'; var bgImageIdx = 0; var bgNode = LK.getAsset(bgImages[bgImageIdx], { anchorX: 0, anchorY: 0, x: 0, y: 0 }); game.addChild(bgNode); // Add a background node for the main menu (hidden by default) var bgMenuNode = LK.getAsset(bgMenuImage, { anchorX: 0, anchorY: 0, x: 0, y: 0 }); bgMenuNode.visible = false; game.addChildAt(bgMenuNode, 0); // Table table = LK.getAsset('table', { anchorX: 0.5, anchorY: 0, x: 2048 / 2, y: 1700 }); game.addChild(table); // Score display scoreTxt = new Text2("0", { size: 100, fill: 0x222222 }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Clock display (top left, avoid 100x100 area) var clockTxt = new Text2("09:00", { size: 90, fill: 0x333366 }); clockTxt.anchor.set(0, 0); clockTxt.x = 120; clockTxt.y = 20; LK.gui.top.addChild(clockTxt); // Clock state var clockMinutes = 0; // 0 = 9:00, max = 290 (13:50) var clockStartMinutes = 0; // 9:00 var clockEndMinutes = 290; // 13:50 var clockInterval = null; // Helper to update clock text function updateClockText() { var totalMinutes = clockStartMinutes + clockMinutes; var hour = 9 + Math.floor(totalMinutes / 60); var min = totalMinutes % 60; var minStr = min < 10 ? "0" + min : "" + min; clockTxt.setText(hour + ":" + minStr); } // Helper to reset clock at start of day function resetClock() { clockMinutes = 0; updateClockText(); if (clockInterval) LK.clearInterval(clockInterval); clockInterval = LK.setInterval(function () { // Always advance clock, regardless of isDecisionActive or currentTraveler clockMinutes += 2; // Advance 2 minutes per interval if (clockMinutes > clockEndMinutes) clockMinutes = clockEndMinutes; updateClockText(); // End of work day if (clockMinutes >= clockEndMinutes) { showFeedback("End of work day!", "#3333cc"); LK.setTimeout(function () { LK.showGameOver(); }, 1200); LK.clearInterval(clockInterval); } }, 1000); // 1 second per traveler (simulate time passing) } // Do NOT start clock here; only start when Play is pressed // Day display dayTxt = new Text2("Day 1", { size: 70, fill: 0x333366 }); dayTxt.anchor.set(0.5, 0); dayTxt.y = 120; LK.gui.top.addChild(dayTxt); // --- Remove background for rules/tasks section and add a toggleable panel with arrow button --- // Arrow button asset (simple triangle shape, white with black border, right-pointing) // Create the arrow button at the top right (but not in the top left 100x100 area) var arrowBtn = LK.getAsset('arrow_btn', { anchorX: 1, anchorY: 0, x: 2048 - 40, y: 40 }); arrowBtn.width = 100; arrowBtn.height = 100; game.addChild(arrowBtn); // Draw a right-pointing arrow using a Text2 overlay (since we can't draw lines) var arrowTxt = new Text2("▶", { size: 80, fill: 0x222222 }); arrowTxt.anchor.set(0.5, 0.5); arrowTxt.x = arrowBtn.width / 2; arrowTxt.y = arrowBtn.height / 2; arrowBtn.addChild(arrowTxt); // Rules panel container (hidden by default) var rulesPanel = new Container(); rulesPanel.visible = false; game.addChild(rulesPanel); // Panel background (white box, no border) var rulesPanelBg = LK.getAsset('bg_info_popup', { anchorX: 0, anchorY: 0, x: 2048 - 800 - 40, y: 160 }); rulesPanelBg.width = 800; rulesPanelBg.height = 600; rulesPanel.addChild(rulesPanelBg); // Rules text (tasks) inside the panel ruleTxt = new Text2("Tasks will appear here.\nPress the arrow to view the current day's rules.", { size: 48, fill: 0x444444 }); ruleTxt.anchor.set(0, 0); ruleTxt.x = rulesPanelBg.x + 40; ruleTxt.y = rulesPanelBg.y + 30; ruleTxt.width = rulesPanelBg.width - 80; ruleTxt.setStyle({ wordWrap: true, wordWrapWidth: ruleTxt.width }); rulesPanel.addChild(ruleTxt); // Track panel state var rulesPanelOpen = false; // Helper to open/close the rules panel and update arrow direction function setRulesPanel(open) { rulesPanel.visible = open; rulesPanelOpen = open; arrowTxt.setText(open ? "✖" : "▶"); } setRulesPanel(false); // Feedback text feedbackTxt = new Text2("", { size: 90, fill: 0x4CAF50 }); feedbackTxt.anchor.set(0.5, 0.5); feedbackTxt.x = 2048 / 2; feedbackTxt.y = 400; feedbackTxt.visible = false; LK.gui.top.addChild(feedbackTxt); // Approve button approveBtn = LK.getAsset('stamp_approve', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 + 350, y: 2450 //{2G} // moved lower }); game.addChild(approveBtn); // Remove old denyBtn if it exists if (denyBtn && denyBtn.parent) { denyBtn.parent.removeChild(denyBtn); denyBtn = null; } // Create a new deny button and ensure it's visible denyBtn = LK.getAsset('stamp_deny', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 - 350, y: 2450 }); denyBtn.visible = true; game.addChild(denyBtn); // Next Traveler button var nextBtn = LK.getAsset('stamp_next', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2600 // moved lower to match new button row }); game.addChild(nextBtn); // Button event handlers game.down = function (x, y, obj) { // --- Arrow button for rules/tasks panel --- var arrowLeft = arrowBtn.x - arrowBtn.width; var arrowRight = arrowBtn.x; var arrowTop = arrowBtn.y; var arrowBottom = arrowBtn.y + arrowBtn.height; if (x >= arrowLeft && x <= arrowRight && y >= arrowTop && y <= arrowBottom) { setRulesPanel(!rulesPanelOpen); return; } // If rules panel is open, clicking anywhere outside the panel closes it if (rulesPanelOpen) { var panelLeft = rulesPanelBg.x; var panelRight = rulesPanelBg.x + rulesPanelBg.width; var panelTop = rulesPanelBg.y; var panelBottom = rulesPanelBg.y + rulesPanelBg.height; if (!(x >= panelLeft && x <= panelRight && y >= panelTop && y <= panelBottom)) { setRulesPanel(false); } return; } // Approve var approveLeft = approveBtn.x - approveBtn.width / 2; var approveRight = approveBtn.x + approveBtn.width / 2; var approveTop = approveBtn.y - approveBtn.height / 2; var approveBottom = approveBtn.y + approveBtn.height / 2; if (x >= approveLeft && x <= approveRight && y >= approveTop && y <= approveBottom) { handleDecision(true); return; } // Deny var denyLeft = denyBtn.x - denyBtn.width / 2; var denyRight = denyBtn.x + denyBtn.width / 2; var denyTop = denyBtn.y - denyBtn.height / 2; var denyBottom = denyBtn.y + denyBtn.height / 2; if (x >= denyLeft && x <= denyRight && y >= denyTop && y <= denyBottom) { handleDecision(false); return; } // Next button var nextLeft = 2048 / 2 - approveBtn.width / 2; var nextRight = 2048 / 2 + approveBtn.width / 2; var nextTop = 2600 - approveBtn.height / 2; var nextBottom = 2600 + approveBtn.height / 2; if (x >= nextLeft && x <= nextRight && y >= nextTop && y <= nextBottom) { // Only allow next if not in the middle of a decision animation if (!isDecisionActive) { // Play next button sound LK.getSound('next_btn').play(); nextTraveler(); } return; } // Show/hide docs and show extra info on traveler tap if (currentTraveler) { // Manual bounds check for the person asset (centered at currentTraveler.x, bottom at currentTraveler.y) var personAsset = currentTraveler.children[0]; // person asset is always first child if (personAsset) { var left = currentTraveler.x - personAsset.width / 2; var right = currentTraveler.x + personAsset.width / 2; var top = currentTraveler.y - personAsset.height; var bottom = currentTraveler.y; if (x >= left && x <= right && y >= top && y <= bottom) { // Show extra info popup (purpose, occupation, duration) as Q&A conversation record if (!currentTraveler.extraInfoTxt) { // Generate if not present var PURPOSES = ["I am here to visit family.", "I am traveling for work.", "I am just passing through.", "I am here for business.", "I am here for a holiday.", "I am here to see a doctor.", "I am here to study.", "I am here to help relatives.", "I am here for a funeral.", "I am here for a wedding."]; var OCCUPATIONS = ["I am a farmer.", "I am a teacher.", "I am a merchant.", "I am a soldier.", "I am a doctor.", "I am a student.", "I am a tailor.", "I am a baker.", "I am a carpenter.", "I am a musician."]; var DURATIONS = ["I will stay for 2 days.", "I am here for a week.", "Just one night.", "I will stay for 3 days.", "I am here for a month.", "Only a few hours.", "I will stay for 10 days.", "I am here for the season.", "I will leave tomorrow.", "I am not sure yet."]; var purpose = PURPOSES[Math.floor(Math.random() * PURPOSES.length)]; var occupation = OCCUPATIONS[Math.floor(Math.random() * OCCUPATIONS.length)]; var duration = DURATIONS[Math.floor(Math.random() * DURATIONS.length)]; // Format as Q&A conversation record var infoStr = "Conversation record:\n" + "Q: Why did you come?\nA: " + purpose + "\n\n" + "Q: What do you do?\nA: " + occupation + "\n\n" + "Q: How long will you stay?\nA: " + duration; // Add a white background box for the info popup using new asset var infoBg = new Container(); var infoTxt = new Text2(infoStr, { size: 48, fill: 0x222222, align: "left" }); infoTxt.anchor.set(0, 0); infoTxt.x = 40; infoTxt.y = 30; // Dynamically size the background to fit the text, with padding var paddingX = 60; var paddingY = 40; var minWidth = 700; var minHeight = 420; var bgWidth = Math.max(minWidth, infoTxt.width + paddingX * 2); var bgHeight = Math.max(minHeight, infoTxt.height + paddingY * 2); var bgRect = LK.getAsset('bg_info_popup', { anchorX: 0, anchorY: 0 }); bgRect.width = bgWidth; bgRect.height = bgHeight; infoBg.addChild(bgRect); infoTxt.x = paddingX; infoTxt.y = paddingY; infoBg.addChild(infoTxt); // Place to the right of the character, vertically aligned with the top of the person infoBg.x = currentTraveler.x + personAsset.width / 2 + 40; infoBg.y = currentTraveler.y - personAsset.height; infoBg.visible = true; currentTraveler.extraInfoTxt = infoBg; game.addChild(infoBg); } else { // Toggle visibility currentTraveler.extraInfoTxt.visible = !currentTraveler.extraInfoTxt.visible; } // Hide docs if showing info, show docs if hiding info var showingInfo = currentTraveler.extraInfoTxt && currentTraveler.extraInfoTxt.visible; currentTraveler.showDocuments(!showingInfo); } } } }; // Update function (not much needed for MVP) game.update = function () { // Win condition: survive 5 days if (day > 5) { // Show summary popup with stats and money var summary = "Day Stats:\n"; for (var i = 0; i < dayStats.length; i++) { var s = dayStats[i]; summary += "Day " + s.day + ": " + s.correct + " correct, " + s.wrong + " wrong, Money: " + s.money + "\n"; } summary += "\nTotal Money: " + money + " RM"; showFeedback(summary, "#4caf50"); LK.setTimeout(function () { LK.showYouWin(); }, 2200); } }; // --- Main Menu Implementation --- // Hide all gameplay UI elements initially if (scoreTxt) scoreTxt.visible = false; if (clockTxt) clockTxt.visible = false; if (dayTxt) dayTxt.visible = false; if (arrowBtn) arrowBtn.visible = false; if (rulesPanel) rulesPanel.visible = false; if (approveBtn) approveBtn.visible = false; if (denyBtn) denyBtn.visible = false; if (nextBtn) nextBtn.visible = false; if (table) table.visible = false; if (feedbackTxt) feedbackTxt.visible = false; if (bgNode) bgNode.visible = true; // keep background // Main menu container var mainMenu = new Container(); game.addChild(mainMenu); // (Removed menu background for main menu) // Title removed as per new design // Play button (toggleable asset) - aligned left, 2cm (216px) vertical spacing var leftMargin = 180; // 180px from left edge for visual comfort var topStart = 2732 / 2 - 80; // Start position for first button var buttonSpacing = 216; // 2cm in px (2*96=192, but 216 for extra space) var playBtn = LK.getAsset('btn_play', { anchorX: 0, anchorY: 0.5, x: leftMargin, y: topStart }); mainMenu.addChild(playBtn); // Play button (toggleable asset) - aligned left, 2cm (216px) vertical spacing var playBtn = LK.getAsset('btn_play', { anchorX: 0, anchorY: 0.5, x: leftMargin, y: topStart }); mainMenu.addChild(playBtn); // Settings button (toggleable asset) var settingsBtn = LK.getAsset('btn_settings', { anchorX: 0, anchorY: 0.5, x: leftMargin, y: topStart + playBtn.height + buttonSpacing }); mainMenu.addChild(settingsBtn); // Quit button (toggleable asset) var quitBtn = LK.getAsset('btn_exit', { anchorX: 0, anchorY: 0.5, x: leftMargin, y: topStart + playBtn.height + buttonSpacing + settingsBtn.height + buttonSpacing }); mainMenu.addChild(quitBtn); // Settings panel (simple placeholder) var settingsPanel = new Container(); settingsPanel.visible = false; game.addChild(settingsPanel); var settingsBg = LK.getAsset('bg_info_popup', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 }); settingsBg.width = 900; settingsBg.height = 900; settingsPanel.addChild(settingsBg); var settingsTitle = new Text2("Settings", { size: 100, fill: 0x222222 }); settingsTitle.anchor.set(0.5, 0); settingsTitle.x = 2048 / 2; settingsTitle.y = 2732 / 2 - 320; settingsPanel.addChild(settingsTitle); var settingsBackBtn = LK.getAsset('stamp_next', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 + 320 }); settingsPanel.addChild(settingsBackBtn); var settingsBackTxt = new Text2("Back", { size: 80, fill: 0xffffff }); settingsBackTxt.anchor.set(0.5, 0.5); settingsBackTxt.x = settingsBackBtn.width / 2; settingsBackTxt.y = settingsBackBtn.height / 2; settingsBackBtn.addChild(settingsBackTxt); // Main menu event handler game.down = function (x, y, obj) { // Only handle menu if visible if (mainMenu.visible) { // Show menu background, hide gameplay background if (bgMenuNode) bgMenuNode.visible = true; if (bgNode) bgNode.visible = false; // Play button var left = playBtn.x - playBtn.width / 2, right = playBtn.x + playBtn.width / 2; var top = playBtn.y - playBtn.height / 2, bottom = playBtn.y + playBtn.height / 2; if (x >= left && x <= right && y >= top && y <= bottom) { // Hide menu, show gameplay UI, start game mainMenu.visible = false; if (bgMenuNode) bgMenuNode.visible = false; if (bgNode) bgNode.visible = true; if (scoreTxt) scoreTxt.visible = true; if (clockTxt) clockTxt.visible = true; if (dayTxt) dayTxt.visible = true; if (arrowBtn) arrowBtn.visible = true; if (rulesPanel) rulesPanel.visible = false; if (approveBtn) approveBtn.visible = true; if (denyBtn) denyBtn.visible = true; if (nextBtn) nextBtn.visible = true; if (table) table.visible = true; if (feedbackTxt) feedbackTxt.visible = false; // Reset game state LK.setScore(0); day = 1; travelersProcessed = 0; correctDecisions = 0; wrongDecisions = 0; money = 0; dayStats = []; saveDayStats(); updateDayAndRules(); // Start the clock only now resetClock(); if (currentTraveler) { currentTraveler.destroyDocuments(); currentTraveler.destroy(); currentTraveler = null; } nextTraveler(); // Restore gameplay event handler game.down = gameplayDownHandler; return; } // Settings button left = settingsBtn.x - settingsBtn.width / 2; right = settingsBtn.x + settingsBtn.width / 2; top = settingsBtn.y - settingsBtn.height / 2; bottom = settingsBtn.y + settingsBtn.height / 2; if (x >= left && x <= right && y >= top && y <= bottom) { mainMenu.visible = false; if (bgMenuNode) bgMenuNode.visible = false; if (bgNode) bgNode.visible = true; settingsPanel.visible = true; return; } // Quit button left = quitBtn.x - quitBtn.width / 2; right = quitBtn.x + quitBtn.width / 2; top = quitBtn.y - quitBtn.height / 2; bottom = quitBtn.y + quitBtn.height / 2; if (x >= left && x <= right && y >= top && y <= bottom) { // Close the game (FRVR platform will handle this) LK.quitGame && LK.quitGame(); return; } return; } // Settings panel if (settingsPanel.visible) { var left = settingsBackBtn.x - settingsBackBtn.width / 2, right = settingsBackBtn.x + settingsBackBtn.width / 2; var top = settingsBackBtn.y - settingsBackBtn.height / 2, bottom = settingsBackBtn.y + settingsBackBtn.height / 2; if (x >= left && x <= right && y >= top && y <= bottom) { settingsPanel.visible = false; mainMenu.visible = true; if (bgMenuNode) bgMenuNode.visible = true; if (bgNode) bgNode.visible = false; return; } return; } // If not in menu/settings, use gameplay handler if (typeof gameplayDownHandler === "function") { gameplayDownHandler(x, y, obj); } }; // Save the original gameplay handler var gameplayDownHandler = function gameplayDownHandler(x, y, obj) { // --- Arrow button for rules/tasks panel --- var arrowLeft = arrowBtn.x - arrowBtn.width; var arrowRight = arrowBtn.x; var arrowTop = arrowBtn.y; var arrowBottom = arrowBtn.y + arrowBtn.height; if (x >= arrowLeft && x <= arrowRight && y >= arrowTop && y <= arrowBottom) { setRulesPanel(!rulesPanelOpen); return; } // If rules panel is open, clicking anywhere outside the panel closes it if (rulesPanelOpen) { var panelLeft = rulesPanelBg.x; var panelRight = rulesPanelBg.x + rulesPanelBg.width; var panelTop = rulesPanelBg.y; var panelBottom = rulesPanelBg.y + rulesPanelBg.height; if (!(x >= panelLeft && x <= panelRight && y >= panelTop && y <= panelBottom)) { setRulesPanel(false); } return; } // Approve var approveLeft = approveBtn.x - approveBtn.width / 2; var approveRight = approveBtn.x + approveBtn.width / 2; var approveTop = approveBtn.y - approveBtn.height / 2; var approveBottom = approveBtn.y + approveBtn.height / 2; if (x >= approveLeft && x <= approveRight && y >= approveTop && y <= approveBottom) { handleDecision(true); return; } // Deny var denyLeft = denyBtn.x - denyBtn.width / 2; var denyRight = denyBtn.x + denyBtn.width / 2; var denyTop = denyBtn.y - denyBtn.height / 2; var denyBottom = denyBtn.y + denyBtn.height / 2; if (x >= denyLeft && x <= denyRight && y >= denyTop && y <= denyBottom) { handleDecision(false); return; } // Next button var nextLeft = 2048 / 2 - approveBtn.width / 2; var nextRight = 2048 / 2 + approveBtn.width / 2; var nextTop = 2600 - approveBtn.height / 2; var nextBottom = 2600 + approveBtn.height / 2; if (x >= nextLeft && x <= nextRight && y >= nextTop && y <= nextBottom) { // Only allow next if not in the middle of a decision animation if (!isDecisionActive) { // Play next button sound LK.getSound('next_btn').play(); nextTraveler(); } return; } // Show/hide docs and show extra info on traveler tap if (currentTraveler) { // Manual bounds check for the person asset (centered at currentTraveler.x, bottom at currentTraveler.y) var personAsset = currentTraveler.children[0]; // person asset is always first child if (personAsset) { var left = currentTraveler.x - personAsset.width / 2; var right = currentTraveler.x + personAsset.width / 2; var top = currentTraveler.y - personAsset.height; var bottom = currentTraveler.y; if (x >= left && x <= right && y >= top && y <= bottom) { // Show extra info popup (purpose, occupation, duration) as Q&A conversation record if (!currentTraveler.extraInfoTxt) { // Generate if not present var PURPOSES = ["I am here to visit family.", "I am traveling for work.", "I am just passing through.", "I am here for business.", "I am here for a holiday.", "I am here to see a doctor.", "I am here to study.", "I am here to help relatives.", "I am here for a funeral.", "I am here for a wedding."]; var OCCUPATIONS = ["I am a farmer.", "I am a teacher.", "I am a merchant.", "I am a soldier.", "I am a doctor.", "I am a student.", "I am a tailor.", "I am a baker.", "I am a carpenter.", "I am a musician."]; var DURATIONS = ["I will stay for 2 days.", "I am here for a week.", "Just one night.", "I will stay for 3 days.", "I am here for a month.", "Only a few hours.", "I will stay for 10 days.", "I am here for the season.", "I will leave tomorrow.", "I am not sure yet."]; var purpose = PURPOSES[Math.floor(Math.random() * PURPOSES.length)]; var occupation = OCCUPATIONS[Math.floor(Math.random() * OCCUPATIONS.length)]; var duration = DURATIONS[Math.floor(Math.random() * DURATIONS.length)]; // Format as Q&A conversation record var infoStr = "Conversation record:\n" + "Q: Why did you come?\nA: " + purpose + "\n\n" + "Q: What do you do?\nA: " + occupation + "\n\n" + "Q: How long will you stay?\nA: " + duration; // Add a white background box for the info popup using new asset var infoBg = new Container(); var infoTxt = new Text2(infoStr, { size: 48, fill: 0x222222, align: "left" }); infoTxt.anchor.set(0, 0); infoTxt.x = 40; infoTxt.y = 30; // Dynamically size the background to fit the text, with padding var paddingX = 60; var paddingY = 40; var minWidth = 700; var minHeight = 420; var bgWidth = Math.max(minWidth, infoTxt.width + paddingX * 2); var bgHeight = Math.max(minHeight, infoTxt.height + paddingY * 2); var bgRect = LK.getAsset('bg_info_popup', { anchorX: 0, anchorY: 0 }); bgRect.width = bgWidth; bgRect.height = bgHeight; infoBg.addChild(bgRect); infoTxt.x = paddingX; infoTxt.y = paddingY; infoBg.addChild(infoTxt); // Place to the right of the character, vertically aligned with the top of the person infoBg.x = currentTraveler.x + personAsset.width / 2 + 40; infoBg.y = currentTraveler.y - personAsset.height; infoBg.visible = true; currentTraveler.extraInfoTxt = infoBg; game.addChild(infoBg); } else { // Toggle visibility currentTraveler.extraInfoTxt.visible = !currentTraveler.extraInfoTxt.visible; } // Hide docs if showing info, show docs if hiding info var showingInfo = currentTraveler.extraInfoTxt && currentTraveler.extraInfoTxt.visible; currentTraveler.showDocuments(!showingInfo); } } } }; // Set initial handler to menu // (game.down already set above) // --- End Main Menu Implementation ---
===================================================================
--- original.js
+++ change.js
male character facing the screen. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
male character facing the screen . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
male character facing the screen. In-Game asset. 2d. High contrast. No shadows
A handsome man, facing us. In-Game asset. 2d. High contrast. No shadows
The woman's face is turned towards us. In-Game asset. 2d. High contrast. No shadows
The woman's face is turned towards us. In-Game asset. 2d. High contrast. No shadows
The woman's face is turned towards us. In-Game asset. 2d. High contrast. No shadows
The woman's face is turned towards us. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
approval button. In-Game asset. 2d. High contrast. No shadows
NEXT button. In-Game asset. 2d. High contrast. No shadows
reject button. In-Game asset. 2d. High contrast. No shadows
2d top view of a long, rectangular table. On the table are papers, some documents and a radio . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
torn paper. In-Game asset. 2d. High contrast. No shadows
settings button. In-Game asset. 2d. High contrast. No shadows
OUTPUT BUTTON. In-Game asset. 2d. High contrast. No shadows
SORTIE BUTTON. In-Game asset. 2d. High contrast. No shadows
ВЫХОД BUTTON. In-Game asset. 2d. High contrast. No shadows
ÇIKIŞ BUTTON. In-Game asset. 2d. High contrast. No shadows
SPIELEN GREEN BUTTON. In-Game asset. 2d. High contrast. No shadows
JOUER GREEN BUTTON. In-Game asset. 2d. High contrast. No shadows
ИГРАТЬ GREEN BUTTON. In-Game asset. 2d. High contrast. No shadows
OYNAMAK GREEN BUTTON. In-Game asset. 2d. High contrast. No shadows
he is boy. my son. In-Game asset. 2d. High contrast. No shadows
teen girl. In-Game asset. 2d. High contrast. No shadows
old man. In-Game asset. 2d. High contrast. No shadows
old woman. In-Game asset. 2d. High contrast. No shadows
wife. In-Game asset. 2d. High contrast. No shadows
2d paper texture. In-Game asset. 2d. High contrast. No shadows
so cute woman. In-Game asset. 2d. High contrast. No shadows
red hair japan girl . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
a rich woman. In-Game asset. 2d. High contrast. No shadows
a rich man. In-Game asset. 2d. High contrast. No shadows
handsome man. In-Game asset. 2d. High contrast. No shadows
black man. In-Game asset. 2d. High contrast. No shadows
PRODUZENT BUTTON. In-Game asset. 2d. High contrast. No shadows
PRODUCER BUTTON. In-Game asset. 2d. High contrast. No shadows
PRODUCTEUR BUTTON. In-Game asset. 2d. High contrast. No shadows
ПРОДЮСЕР BUTTON. In-Game asset. 2d. High contrast. No shadows
YAPIMCI BUTTON. In-Game asset. 2d. High contrast. No shadows