User prompt
Add Time app to app list, make it 1x2 app size, and display time and speed controls inside its overlay
User prompt
time uygulamasının arka planının konumu degĢişmedi
User prompt
time uygulamasının boyutu 2 uygulama kadar fakat arka planı yanlış yerde arka planının 50 piksel sagĢa kayması gerek
User prompt
şuan time uygulamasının boyutu iyi fakat sadece boyutu 2 uygulamaya boyutunda computerscreen'de 2 uygulama boyutunda yer kaplamıyor ekranın dışına taşıyor
User prompt
şuan time uygulamasının boyutu iyi fakat sadece boyutu 2 uygulamaya boyutunda computerscreen'de 2 uygulama boyutunda yer kaplamıyor ekranın dışına taşıyor
User prompt
time uygulaması şuanda çok buĢyuĢk 2 uygulama boyutunda degĢil 4 uygulama boyutunda yer kaplıyo benim istedigĢim yan yana 2 uygulama boyutunda yer kaplayacak.
User prompt
time uygulamasının arka planının 2 uygulama boyutunda yer kaplamasını sagĢla
User prompt
şuan time uygulaması 2 uygulama boyutunda yer kaplamıyor ve hala ortasında youtube logosu var ben ortasında bir logo olsun istemiyorum oyunun guĢn ve zaman sayısı ortasında siyah bir şekilde yazsın istiyorum
User prompt
time uygulamasının bir logosu olmasın içinde guĢn ve zaman bilgisi yazsın 2 uygulama boyutunda olsun ve uygulama listesinin en başında listelensin.
User prompt
oyundaki zamanı bir uygulamaymış gibi goĢster ve 2 uygulama boyutunda yer kaplasın uygulama listesinde goĢruĢnsuĢn zamanı ve hızlandırma butonlarının onun uĢstuĢnde goĢrelim
User prompt
Youtube Studio adında yeni bir uygulama oluştur ve logosu için youtubestudio assetsini kullan
User prompt
computerscreen'in alt kısmındaki record - edit -promote -statistics butonlarını kaldır.
User prompt
istatistik ekranındaki ikonları kaldır.
User prompt
statistics uygulamasına basınca istatistik panelinin açılmasını sagĢla.
User prompt
statistic butonuna basılınca çıkan istatistik panelinin computerscreen boyutuyla aynı olmasını ve aynı pozisyonda olmasını sagĢla
User prompt
statistic butonuna basılınca çıkan istatistik panelinin computerscreen boyutuyla aynı olmasını ve aynı pozisyonda olmasını sagĢla
User prompt
Please fix the bug: 'Uncaught ReferenceError: closePromoteBtn is not defined' in or related to this line: 'game.addChild(closePromoteBtn);' Line Number: 2003
User prompt
promote panelinin sagĢ uĢstuĢndeki "x" butonunu kaldır
User prompt
promote uygulamasına basıldıgĢında promote ekranının açılmasını sagĢla.
User prompt
promote uygulamasına basıldıgĢında promote ekranını açılmasını sagĢla hala promote butonuna basılmıyor
User prompt
promote uygulamasına basılınca promote ekranının açılmasını sagĢla
User prompt
zaman ve zaman butonlarındaki Day yazısını ve saat yazısını 50 piksel sola kaydır
User prompt
zaman yazılarını computer screen'in tam soluna dayanmasını sagĢla. arada 5-10 piksellik bir boşluk olabilir
User prompt
zaman yazılarını 50 piksel sola kaydır
User prompt
zaman ve zaman butonlarının computerscreen'in en sol uĢst koĢşesinde goĢzuĢkmesini sagĢla
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Energy bar class var EnergyBar = Container.expand(function () { var self = Container.call(this); self.bg = self.attachAsset('energyBarBg', { anchorX: 0, anchorY: 0.5 }); self.fill = self.attachAsset('energyBarFill', { anchorX: 0, anchorY: 0.5 }); self.fill.x = 0; self.bg.x = 0; self.bg.y = 0; self.fill.y = 0; self.maxWidth = self.fill.width; self.set = function (ratio) { if (ratio < 0) { ratio = 0; } if (ratio > 1) { ratio = 1; } self.fill.width = self.maxWidth * ratio; }; return self; }); // --- Finance Panel Class --- var FinancePanel = Container.expand(function () { var self = Container.call(this); // Yellow background, same size/position as computerscreen self.bg = self.attachAsset('upgradeBtn', { anchorX: 0.5, anchorY: 0.5, x: computerScreen.x, y: computerScreen.y }); self.bg.width = computerScreen.width; self.bg.height = computerScreen.height; self.bg.x = computerScreen.x; self.bg.y = computerScreen.y; self.bg.alpha = 0.98; self.addChild(self.bg); // Money text (white, large, centered) self.moneyTxt = new Text2("", { size: 120, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); self.moneyTxt.anchor.set(0.5, 0.5); self.moneyTxt.x = computerScreen.x; self.moneyTxt.y = computerScreen.y; self.addChild(self.moneyTxt); // Helper to update money display self.updateMoney = function () { // Truncate to 2 decimals var moneyDisplay = Math.floor(money * 100) / 100; self.moneyTxt.setText("Güncel Para: $" + formatNumber(moneyDisplay)); }; // Update on creation self.updateMoney(); return self; }); // Global variable to track finance panel instance // Button class for all clickable actions var GameButton = Container.expand(function () { var self = Container.call(this); self.bg = null; self.label = null; self.action = null; self.enabled = true; self.setButton = function (assetId, labelText, color, width, height) { self.bg = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); self.bg.width = width; self.bg.height = height; // Modern look: more pronounced rounded corners and soft drop shadow self.bg.cornerRadius = Math.min(width, height) * 0.28; self.bg.shadow = { color: 0x111111, blur: 36, offsetX: 0, offsetY: 16, alpha: 0.32 }; self.label = new Text2(labelText, { size: 80, fill: color, font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 12, dropShadowDistance: 2 }); self.label.anchor.set(0.5, 0.5); self.addChild(self.label); }; self.setEnabled = function (val) { self.enabled = val; if (self.bg) { self.bg.alpha = val ? 1 : 0.4; } }; self.down = function (x, y, obj) { if (!self.enabled) { return; } if (typeof self.action === 'function') { self.action(); } }; return self; }); // VideoListItem: displays a video in the list with title, state, and stats var VideoListItem = Container.expand(function () { var self = Container.call(this); self.bg = self.attachAsset('loadingbarempty', { anchorX: 0, anchorY: 0.5 }); self.bg.width = 1200; self.bg.height = 120; self.bg.alpha = 0.92; self.titleTxt = new Text2("", { size: 56, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); self.titleTxt.anchor.set(0, 0.5); self.titleTxt.x = 40; self.titleTxt.y = 0; self.addChild(self.titleTxt); self.stateTxt = new Text2("", { size: 44, fill: "#ff0", font: "Arial, Helvetica, sans-serif" }); self.stateTxt.anchor.set(0, 0.5); self.stateTxt.x = 500; self.stateTxt.y = 0; self.addChild(self.stateTxt); self.statsTxt = new Text2("", { size: 44, fill: "#0ff", font: "Arial, Helvetica, sans-serif" }); self.statsTxt.anchor.set(0, 0.5); self.statsTxt.x = 800; self.statsTxt.y = 0; self.addChild(self.statsTxt); self.setVideo = function (videoObj) { self.titleTxt.setText(videoObj.title || "Untitled"); // State: Recording, Gaining Views, Finished if (videoObj.hour === 0 && !videoObj.finished) { self.stateTxt.setText("Just Published"); } else if (!videoObj.finished) { self.stateTxt.setText("Gaining Views"); } else { self.stateTxt.setText("Finished"); } // Stats: views, money, subs var stats = formatNumber(videoObj.totalViews) + " views"; // Truncate money to 2 decimal digits for display in video list var moneyDisplay = Math.floor(videoObj.totalMoney * 100) / 100; stats += " | $" + formatNumber(moneyDisplay); stats += " | " + formatNumber(videoObj.totalSubs) + " subs"; if (videoObj.trending) { stats += " | š„"; } self.statsTxt.setText(stats); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Global variable to track finance panel instance // --- Trending Category State --- // --- Video Categories (must be defined before use in updateTrendingCategory) --- var financePanel = null; var videoCategories = ["Vlog", "Challenge", "Reaction", "Tutorial", "Unboxing", "Gaming", "Music", "Comedy", "Q&A", "Other"]; var selectedCategoryIdx = 0; // Studio background (simple box for now) // --- Game State Variables --- // Pick a random trending category at game start var trendingCategoryIdx = Math.floor(Math.random() * videoCategories.length); var trendingCategoryDay = 1; // The day this trending category started function updateTrendingCategory() { // Pick a new trending category index, different from the current one if possible var oldIdx = trendingCategoryIdx; if (videoCategories && videoCategories.length > 1) { var newIdx; do { newIdx = Math.floor(Math.random() * videoCategories.length); } while (newIdx === oldIdx); trendingCategoryIdx = newIdx; } else { trendingCategoryIdx = 0; } trendingCategoryDay = gameDay; // Set next change day if not already set if (typeof trendingCategoryNextChangeDay === "undefined") { trendingCategoryNextChangeDay = trendingCategoryDay + 7 + Math.floor(Math.random() * 24); // 7-30 days } } // If the record video panel is open, update the trending label text if it exists if (typeof isRecordPanelOpen !== "undefined" && isRecordPanelOpen && typeof categoryBtns !== "undefined") { for (var i = 0; i < categoryBtns.length; i++) { if (categoryBtns[i].trendingTxt) { categoryBtns[i].trendingTxt.setText("Trending"); // Move trending label to the new trending category if (i === trendingCategoryIdx) { categoryBtns[i].trendingTxt.visible = true; } else { categoryBtns[i].trendingTxt.visible = false; } } // Update button highlight for trending if (i === trendingCategoryIdx) { categoryBtns[i].bg.alpha = 0.95; if (categoryBtns[i].trendingTxt) { categoryBtns[i].trendingTxt.visible = true; } } else { if (categoryBtns[i].trendingTxt) { categoryBtns[i].trendingTxt.visible = false; } if (i !== selectedCategoryIdx) { categoryBtns[i].bg.alpha = 0.7; } } } } // Video button // Edit button // Promote button // Upgrade button // Energy bar background // Energy bar fill // Subscriber icon // Money icon // Sound for making a video var subscribers = 0; var viewCount = 0; var money = 0; var videoQuality = 1; // upgrades increase this var editSkill = 1; // upgrades increase this var promoteSkill = 1; // upgrades increase this var videoCount = 0; var upgradeCost = 20; var upgradeLevel = 1; // --- Time Mechanics --- var gameHour = 8; // Start at 8:00 var gameDay = 1; var isTimePaused = false; var timeTimer = null; var timeProcess = null; // {type: 'record'|'edit'|'promote', hoursLeft: int, onFinish: fn} // --- UI Elements --- var studioBg = LK.getAsset('studioBg', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); game.addChild(studioBg); var phoneBg = LK.getAsset('phonebackground', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); game.addChild(phoneBg); var computerScreen = LK.getAsset('computerscreen', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 - 5, y: 2732 / 2 - 60 }); game.addChild(computerScreen); // --- App List inside computerscreen --- // Each app is now inside its own invisible overlay container var appListContainer = new Container(); var appOverlays = {}; // key: appNameLower, value: overlay Container // Calculate app icon and background sizes for 4 per row, filling computerscreen width var appsPerRow = 4; var appListMarginX = 60; // margin from left/right inside computerscreen var appListMarginY = 120; // margin from top inside computerscreen var appListWidth = computerScreen.width - 2 * appListMarginX; var appSpacing = 48; var appRowSpacing = 120; // Further increased vertical spacing between rows var appBgW = Math.floor((appListWidth - (appsPerRow - 1) * appSpacing) / appsPerRow); var appBgH = appBgW; // make square var appIconW = Math.floor(appBgW * 0.54); var appIconH = appIconW; // Align the app list to the left edge inside computerscreen var appListStartX = computerScreen.x - computerScreen.width / 2 + appListMarginX + appBgW / 2; var appListY = computerScreen.y - computerScreen.height / 2 + appListMarginY + appBgH / 2; // Move the appListContainer visually inside the computerscreen and align to top-left appListContainer.x = computerScreen.width / -2 + appListMarginX + appBgW / 2; appListContainer.y = computerScreen.height / -2 + appListMarginY + appBgH / 2; // Helper to create an overlay for a given app function createAppOverlay(appNameLower, idx) { var overlay = new Container(); overlay.appNameLower = appNameLower; // Calculate row/col for 4 per row var row = Math.floor(idx / appsPerRow); var col = idx % appsPerRow; var bgX = col * (appBgW + appSpacing); var bgY = row * (appBgH + appRowSpacing); // Background var bg = LK.getAsset('whitebackgroundrounded', { anchorX: 0.5, anchorY: 0.5, x: bgX, y: bgY }); bg.width = appBgW; bg.height = appBgH; overlay.addChild(bg); // Icon var iconAssetId = "youtube"; if (appNameLower === "play store") iconAssetId = "playstore"; if (appNameLower === "editing") iconAssetId = "edit"; if (appNameLower === "statistics") iconAssetId = "statistics"; if (appNameLower === "promote") iconAssetId = "promotebutton"; if (appNameLower === "record") iconAssetId = "recordbutton"; if (appNameLower === "finance") iconAssetId = "financalbutton"; var icon = LK.getAsset(iconAssetId, { anchorX: 0.5, anchorY: 0.5, x: bgX, y: bgY }); if (appNameLower === "editing") { icon.width = appIconW * 1.5; icon.height = appIconH * 1.5; } else { icon.width = appIconW; icon.height = appIconH; } overlay.addChild(icon); // Label var label = new Text2(appNameLower, { size: 54, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); label.anchor.set(0.5, 0); label.x = bgX; label.y = bgY + appBgH / 2 + 18; overlay.addChild(label); // Store for later reference overlay._appBg = bg; overlay._appIcon = icon; overlay._appLabel = label; // Make Play Store app icon interactive to open Play Store overlay if (appNameLower === "play store") { overlay.interactive = true; overlay.buttonMode = true; overlay.down = function (x, y, obj) { showPlayStoreOverlay(); }; // Also make icon and bg interactive for better UX icon.interactive = true; icon.buttonMode = true; icon.down = function (x, y, obj) { showPlayStoreOverlay(); }; bg.interactive = true; bg.buttonMode = true; bg.down = function (x, y, obj) { showPlayStoreOverlay(); }; } // Make Finance app icon interactive to open finance panel if (appNameLower === "finance") { overlay.interactive = true; overlay.buttonMode = true; overlay.down = function (x, y, obj) { // Defensive: destroy previous if exists if (financePanel && typeof financePanel.destroy === "function") { try { financePanel.destroy(); } catch (e) {} financePanel = null; } financePanel = new FinancePanel(); // Insert financePanel above computerscreen (so it appears on top of computerscreen, but below everything else) var computerScreenIdx = game.children.indexOf(computerScreen); if (computerScreenIdx !== -1) { game.addChildAt(financePanel, computerScreenIdx + 1); } else { game.addChild(financePanel); } // Always update money display if (financePanel && typeof financePanel.updateMoney === "function") { financePanel.updateMoney(); } }; icon.interactive = true; icon.buttonMode = true; icon.down = overlay.down; bg.interactive = true; bg.buttonMode = true; bg.down = overlay.down; } // Make Editing app icon interactive to open the edit panel (like editBtn) if (appNameLower === "editing") { overlay.interactive = true; overlay.buttonMode = true; overlay.down = function (x, y, obj) { if (typeof editBtn !== "undefined" && editBtn && typeof editBtn.action === "function") { editBtn.action(); } }; icon.interactive = true; icon.buttonMode = true; icon.down = function (x, y, obj) { if (typeof editBtn !== "undefined" && editBtn && typeof editBtn.action === "function") { editBtn.action(); } }; bg.interactive = true; bg.buttonMode = true; bg.down = function (x, y, obj) { if (typeof editBtn !== "undefined" && editBtn && typeof editBtn.action === "function") { editBtn.action(); } }; } // Make YouTube app icon interactive to open video panel (video list) if (appNameLower === "youtube") { overlay.interactive = true; overlay.buttonMode = true; overlay.down = function (x, y, obj) { // Defensive: re-add videoListBg and videoListContainer if destroyed by closeAllBtn if (!game.children.includes(videoListBg)) { game.addChild(videoListBg); } if (!game.children.includes(videoListContainer)) { game.addChild(videoListContainer); } videoListBg.visible = true; videoListContainer.visible = true; statsOverlay.visible = false; }; // Also make icon and bg interactive for better UX icon.interactive = true; icon.buttonMode = true; icon.down = function (x, y, obj) { // Defensive: re-add videoListBg and videoListContainer if destroyed by closeAllBtn if (!game.children.includes(videoListBg)) { game.addChild(videoListBg); } if (!game.children.includes(videoListContainer)) { game.addChild(videoListContainer); } videoListBg.visible = true; videoListContainer.visible = true; statsOverlay.visible = false; }; bg.interactive = true; bg.buttonMode = true; bg.down = function (x, y, obj) { // Defensive: re-add videoListBg and videoListContainer if destroyed by closeAllBtn if (!game.children.includes(videoListBg)) { game.addChild(videoListBg); } if (!game.children.includes(videoListContainer)) { game.addChild(videoListContainer); } videoListBg.visible = true; videoListContainer.visible = true; statsOverlay.visible = false; }; } // Make Record app icon interactive to open the record panel if (appNameLower === "record") { overlay.interactive = true; overlay.buttonMode = true; overlay.down = function (x, y, obj) { if (typeof makeVideoBtn !== "undefined" && makeVideoBtn && typeof makeVideoBtn.action === "function") { makeVideoBtn.action(); } }; icon.interactive = true; icon.buttonMode = true; icon.down = function (x, y, obj) { if (typeof makeVideoBtn !== "undefined" && makeVideoBtn && typeof makeVideoBtn.action === "function") { makeVideoBtn.action(); } }; bg.interactive = true; bg.buttonMode = true; bg.down = function (x, y, obj) { if (typeof makeVideoBtn !== "undefined" && makeVideoBtn && typeof makeVideoBtn.action === "function") { makeVideoBtn.action(); } }; } return overlay; } // Initial overlays for installed apps // Always keep the app list in a fixed order: youtube, play store, editing, statistics, promote, record, finance var initialApps = [{ name: "youtube" }, { name: "play store" }, { name: "editing" }, { name: "statistics" }, { name: "promote" }, { name: "record" }, { name: "finance" }]; // Helper to re-render app overlays in correct order and position function updateAppListOrder() { // Remove all overlays from container while (appListContainer.children.length > 0) { appListContainer.children[0].destroy(); } // Re-add overlays in fixed order, skipping nulls var visibleIdx = 0; for (var i = 0; i < initialApps.length; i++) { var appNameLower = initialApps[i].name; var overlay = appOverlays[appNameLower]; if (overlay) { // Update position for this index (4 per row) var row = Math.floor(visibleIdx / appsPerRow); var col = visibleIdx % appsPerRow; var bgX = col * (appBgW + appSpacing); var bgY = row * (appBgH + appRowSpacing); // Defensive: update all children positions (bg, icon, label) if (overlay._appBg) { overlay._appBg.x = bgX; overlay._appBg.y = bgY; } if (overlay._appIcon) { overlay._appIcon.x = bgX; overlay._appIcon.y = bgY; } if (overlay._appLabel) { overlay._appLabel.x = bgX; overlay._appLabel.y = bgY + appBgH / 2 + 18; } appListContainer.addChild(overlay); visibleIdx++; } } } // Create overlays for all initial apps for (var i = 0; i < initialApps.length; i++) { var appNameLower = initialApps[i].name; var overlay = createAppOverlay(appNameLower, i); appOverlays[appNameLower] = overlay; } // Initial render updateAppListOrder(); // --- Universal Close Button (Return to ComputerScreen) --- var closeAllBtn = new GameButton(); closeAllBtn.setButton('editBtn', 'Return', "#fff", 420, 120); // Place the button below the computerscreen, centered horizontally closeAllBtn.x = computerScreen.x; closeAllBtn.y = computerScreen.y + computerScreen.height / 2 + 210; // 210px below the bottom edge of computerscreen (80+130) closeAllBtn.bg.height += 40; // Increase height by 20px on top and 20px on bottom if (closeAllBtn.label) { closeAllBtn.label.y = 0; // recenter label after height change } // Make the button invisible but always clickable closeAllBtn.bg.alpha = 0; if (closeAllBtn.label) closeAllBtn.label.visible = false; closeAllBtn.interactive = true; closeAllBtn.buttonMode = true; closeAllBtn.action = function () { // Remove all children except: // - computerscreen // - appListContainer (inside computerscreen) // - closeAllBtn // - subIcon, subTxt, viewIcon, viewTxt, moneyIcon, moneyTxt // - timeTxt, pauseBtn, resumeBtn, doubleSpeedBtn // - phoneBg for (var i = game.children.length - 1; i >= 0; i--) { var child = game.children[i]; if (child === computerScreen || child === appListContainer || child === closeAllBtn || child === subIcon || child === subTxt || child === viewIcon || child === viewTxt || child === moneyIcon || child === moneyTxt || child === timeTxt || child === pauseBtn || child === resumeBtn || child === doubleSpeedBtn || child === phoneBg || child === studioBg) continue; try { child.destroy(); } catch (e) {} } // Destroy finance panel if open if (typeof financePanel !== "undefined" && financePanel) { try { financePanel.destroy(); } catch (e) {} financePanel = null; } // Hide overlays if they are not destroyed if (typeof videoListBg !== "undefined") videoListBg.visible = false; if (typeof videoListContainer !== "undefined") videoListContainer.visible = false; if (typeof statsOverlay !== "undefined") statsOverlay.visible = false; // Remove playstore overlay and all its children if open if (typeof playStoreOverlay !== "undefined" && playStoreOverlay) { if (playStoreOverlay.children && playStoreOverlay.children.length) { for (var i = playStoreOverlay.children.length - 1; i >= 0; i--) { try { playStoreOverlay.children[i].destroy(); } catch (e) {} } } if (typeof psListContainer !== "undefined" && psListContainer) { if (psListContainer.children && psListContainer.children.length) { for (var i = psListContainer.children.length - 1; i >= 0; i--) { try { psListContainer.children[i].destroy(); } catch (e) {} } } try { psListContainer.destroy(); } catch (e) {} psListContainer = null; } if (playStoreOverlay.children && playStoreOverlay.children.length) { for (var i = playStoreOverlay.children.length - 1; i >= 0; i--) { try { playStoreOverlay.children[i].destroy(); } catch (e) {} } } try { playStoreOverlay.destroy(); } catch (e) {} playStoreOverlay = null; } // Remove edit panel if open var editPanelElements = ["editPanelBg", "editPanelTitle", "loadingBarBg", "loadingBarFill", "editPanelBtn", "closeEditBtn"]; for (var i = 0; i < editPanelElements.length; i++) { if (typeof window[editPanelElements[i]] !== "undefined" && window[editPanelElements[i]]) { try { window[editPanelElements[i]].destroy(); } catch (e) {} window[editPanelElements[i]] = null; } } // Remove record panel if open (deduplicated block) if (typeof isRecordPanelOpen !== "undefined" && isRecordPanelOpen) { var recordPanelElements = ["panelBg", "panelText", "confirmBtn", "closeBtn", "titleInputBg", "titleInputTxt", "randomBtn"]; for (var i = 0; i < recordPanelElements.length; i++) { if (typeof window[recordPanelElements[i]] !== "undefined" && window[recordPanelElements[i]]) { try { window[recordPanelElements[i]].destroy(); } catch (e) {} window[recordPanelElements[i]] = null; } } // Destroy all category buttons and trending labels if (typeof categoryBtns !== "undefined" && categoryBtns.length) { for (var i = 0; i < categoryBtns.length; i++) { if (categoryBtns[i]) { if (categoryBtns[i].trendingTxt) { try { categoryBtns[i].trendingTxt.destroy(); } catch (e) {} categoryBtns[i].trendingTxt = null; } try { categoryBtns[i].destroy(); } catch (e) {} } } } isRecordPanelOpen = false; } // Remove promote panel if open if (typeof game.promotePanelOpen !== "undefined" && game.promotePanelOpen) { var promotePanelElements = ["promotePanelBg", "promoteTitle", "moneySliderBg", "moneySliderFill", "moneySliderHandle", "moneyInputTxt", "daysSliderBg", "daysSliderFill", "daysSliderHandle", "daysInputTxt", "estViewsTxt", "confirmPromoteBtn", "closePromoteBtn"]; for (var i = 0; i < promotePanelElements.length; i++) { if (typeof window[promotePanelElements[i]] !== "undefined" && window[promotePanelElements[i]]) { try { window[promotePanelElements[i]].destroy(); } catch (e) {} window[promotePanelElements[i]] = null; } } // Destroy promote list labels if (typeof promoteListLabels !== "undefined" && promoteListLabels.length) { for (var i = 0; i < promoteListLabels.length; i++) { for (var j = 0; j < promoteListLabels[i].length; j++) { if (promoteListLabels[i][j]) { try { promoteListLabels[i][j].destroy(); } catch (e) {} } } } } game.promotePanelOpen = false; } // Remove promote stats panel if open if (typeof game.children !== "undefined") { for (var i = game.children.length - 1; i >= 0; i--) { var child = game.children[i]; if (child && child._isPromoteStatsPanel) { try { child.destroy(); } catch (e) {} } } } }; // Add the button to the game game.addChild(closeAllBtn); // (Removed: duplicate app list alignment code, now handled by appListContainer.x/y and createAppOverlay) // --- Play Store Fullscreen Overlay Logic --- var playStoreOverlay = null; function showPlayStoreOverlay() { if (playStoreOverlay) return; // Overlay background playStoreOverlay = LK.getAsset('playstoreWhiteBg', { anchorX: 0.5, anchorY: 0.5, x: computerScreen.x, y: computerScreen.y }); // Restrict overlay size to exactly match computerscreen playStoreOverlay.width = computerScreen.width; playStoreOverlay.height = computerScreen.height; playStoreOverlay.alpha = 1; // Remove playStoreOverlay if already present (defensive, should not happen) if (game.children.indexOf(playStoreOverlay) !== -1) { playStoreOverlay.destroy(); } // Insert playStoreOverlay so it is always below phoneBg but above computerscreen var phoneBgIdx = game.children.indexOf(phoneBg); var computerScreenIdx = game.children.indexOf(computerScreen); if (phoneBgIdx !== -1 && computerScreenIdx !== -1) { // Insert just before phoneBg, but after computerscreen // phoneBgIdx is the index of phoneBg, so insert at phoneBgIdx (which will be before phoneBg) // But if computerscreen is after phoneBg, adjust to insert after computerscreen var insertIdx = phoneBgIdx; if (computerScreenIdx >= phoneBgIdx) { // If computerscreen is after phoneBg, insert after computerscreen insertIdx = computerScreenIdx + 1; } else if (computerScreenIdx < phoneBgIdx - 1) { // If computerscreen is before phoneBg, but not immediately before, insert just before phoneBg insertIdx = phoneBgIdx; } else { // If computerscreen is immediately before phoneBg, insert at phoneBgIdx (between them) insertIdx = phoneBgIdx; } game.addChildAt(playStoreOverlay, insertIdx); } else if (phoneBgIdx !== -1) { // Fallback: insert just below phoneBg game.addChildAt(playStoreOverlay, phoneBgIdx); } else if (computerScreenIdx !== -1) { // Fallback: insert just above computerscreen game.addChildAt(playStoreOverlay, computerScreenIdx + 1); } else { // Fallback: add to top game.addChild(playStoreOverlay); } // --- Play Store App List Data --- // Each app: { name, description, sizeMB, publisher, installed } var playStoreApps = [{ name: "YouTube", description: "Watch, upload, and share videos with the world.", sizeMB: 120, publisher: "RiftGames", installed: true }, { name: "Editing", description: "Edit your videos with powerful tools.", sizeMB: 95, publisher: "RiftGames", installed: true }, { name: "Statistics", description: "Track your channel's growth and performance.", sizeMB: 40, publisher: "RiftGames", installed: false }, { name: "Promote", description: "Promote your channel to reach more viewers.", sizeMB: 60, publisher: "RiftGames", installed: false }, { name: "Record", description: "Record new videos for your channel.", sizeMB: 80, publisher: "RiftGames", installed: false }, { name: "Finance", description: "Manage your channel's finances and earnings.", sizeMB: 55, publisher: "RiftGames", installed: false }]; // --- Play Store Title Removed as requested --- // --- App List Container --- // The app list container is positioned at (0,0) inside playStoreOverlay, but all its children are positioned as if inside computerscreen var psListContainer = new Container(); // Align app list to top-left of playStoreOverlay, shifted 650px to the left and 1000px upward psListContainer.x = -650; psListContainer.y = -1000; playStoreOverlay.addChild(psListContainer); // --- Make Play Store app list scrollable vertically --- // Variables for scroll state var psListScrollY = psListContainer.y; var psListDragStartY = 0; var psListPointerStartY = 0; var psListDragging = false; var psListMinY = -1000; var psListMaxY = -1000; var psListHeight = 0; // Calculate total height of app list after rendering // (We will update psListHeight after rendering the app cards below) // Touch/drag logic for vertical scrolling playStoreOverlay.interactive = true; playStoreOverlay.buttonMode = false; playStoreOverlay.down = function (x, y, obj) { // Only start drag if inside the app list area var localY = y - playStoreOverlay.y + playStoreOverlay.height / 2; // Accept drag anywhere on overlay for now psListDragging = true; psListPointerStartY = y; psListDragStartY = psListContainer.y; }; playStoreOverlay.move = function (x, y, obj) { if (psListDragging) { var dy = y - psListPointerStartY; var newY = psListDragStartY + dy; // Clamp scroll to min/max if (newY > psListMaxY) newY = psListMaxY; if (newY < psListMinY) newY = psListMinY; psListContainer.y = newY; psListScrollY = newY; } }; playStoreOverlay.up = function (x, y, obj) { psListDragging = false; }; // Also allow scrolling by dragging on the app list container itself psListContainer.interactive = true; psListContainer.buttonMode = false; psListContainer.down = function (x, y, obj) { psListDragging = true; psListPointerStartY = y; psListDragStartY = psListContainer.y; }; psListContainer.move = function (x, y, obj) { if (psListDragging) { var dy = y - psListPointerStartY; var newY = psListDragStartY + dy; if (newY > psListMaxY) newY = psListMaxY; if (newY < psListMinY) newY = psListMinY; psListContainer.y = newY; psListScrollY = newY; } }; psListContainer.up = function (x, y, obj) { psListDragging = false; }; // Helper for global-to-overlay-local positioning function getComputerScreenLocal(x, y) { // Convert a global (game) x/y to local coordinates inside playStoreOverlay, as if overlay is at computerscreen return { x: x - (computerScreen.x - computerScreen.width / 2), y: y - (computerScreen.y - computerScreen.height / 2) }; } var appCardW = computerScreen.width - 160; var appCardH = 320; var appCardSpacing = 40; var iconSize = 160; // --- Determine installed apps from computerscreen --- var installedAppNames = []; for (var key in appOverlays) { if (appOverlays[key]) installedAppNames.push(key); } // --- App List Rendering --- // Only show apps that are not installed as Download, and installed as Delete var filteredPlayStoreApps = []; for (var i = 0; i < playStoreApps.length; i++) { var appNameLower = (playStoreApps[i].name || "").toLowerCase(); var isInstalled = false; for (var j = 0; j < installedAppNames.length; j++) { if (installedAppNames[j] === appNameLower) { isInstalled = true; break; } } // Always show all apps, but set .installed property accordingly playStoreApps[i].installed = isInstalled; filteredPlayStoreApps.push(playStoreApps[i]); } var numApps = filteredPlayStoreApps.length; var totalListHeight = numApps * appCardH + (numApps - 1) * appCardSpacing; for (var i = 0; i < filteredPlayStoreApps.length; i++) { (function (idx) { var app = filteredPlayStoreApps[idx]; // Card background, stack from top-left var cardBg = LK.getAsset('playstoreWhiteBg', { anchorX: 0, anchorY: 0, x: 0, y: idx * (appCardH + appCardSpacing) }); cardBg.width = appCardW; cardBg.height = appCardH; cardBg.alpha = 1; cardBg.tint = 0xffffff; // Always white background for app card psListContainer.addChild(cardBg); // App icon (logo only, no background) var iconAssetId = "youtube"; if (app.name === "Play Store") iconAssetId = "playstore"; if (app.name === "Editing") iconAssetId = "edit"; if (app.name === "Statistics") iconAssetId = "statistics"; if (app.name === "Promote") iconAssetId = "promotebutton"; if (app.name === "Record") iconAssetId = "recordbutton"; if (app.name === "Finance") iconAssetId = "financalbutton"; var appIcon = LK.getAsset(iconAssetId, { anchorX: 0.5, anchorY: 0.5, x: cardBg.x + iconSize / 2 + 36, y: cardBg.y + appCardH / 2 }); appIcon.width = iconSize; appIcon.height = iconSize; psListContainer.addChild(appIcon); // App name var nameTxt = new Text2(app.name, { size: 64, fill: "#222", font: "Arial, Helvetica, sans-serif" }); nameTxt.anchor.set(0, 0); nameTxt.x = cardBg.x + iconSize + 80; nameTxt.y = cardBg.y + 36; psListContainer.addChild(nameTxt); // Publisher var publisherTxt = new Text2("by " + app.publisher, { size: 38, fill: "#888", font: "Arial, Helvetica, sans-serif" }); publisherTxt.anchor.set(0, 0); publisherTxt.x = nameTxt.x; publisherTxt.y = nameTxt.y + nameTxt.height + 2; psListContainer.addChild(publisherTxt); // Description var descTxt = new Text2(app.description, { size: 44, fill: "#444", font: "Arial, Helvetica, sans-serif" }); descTxt.anchor.set(0, 0); descTxt.x = nameTxt.x; descTxt.y = publisherTxt.y + publisherTxt.height + 8; psListContainer.addChild(descTxt); // Size var sizeTxt = new Text2(app.sizeMB + " MB", { size: 38, fill: "#0aa", font: "Arial, Helvetica, sans-serif" }); sizeTxt.anchor.set(0, 0); sizeTxt.x = nameTxt.x; sizeTxt.y = descTxt.y + descTxt.height + 8; psListContainer.addChild(sizeTxt); // Install/Delete/Download button var appBtn = new GameButton(); var isInstalled = !!app.installed; // Helper to update button appearance and action function updateAppBtn() { // Move button lower in the card (move 120px lower than center, was 60px) appBtn.x = cardBg.x + appCardW - 180; appBtn.y = cardBg.y + appCardH / 2 + 120; // Remove previous custom children if any if (appBtn._customBg) { appBtn._customBg.destroy(); appBtn._customBg = null; } if (appBtn._customIcon) { appBtn._customIcon.destroy(); appBtn._customIcon = null; } if (appBtn.label) appBtn.label.visible = false; if (isInstalled) { // DELETE BUTTON: redbackground + deletebutton icon var bg = LK.getAsset('redbackground', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 0 }); bg.width = 260; bg.height = 90; appBtn.addChild(bg); appBtn._customBg = bg; var icon = LK.getAsset('deletebutton', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 0 }); // Fit icon inside button, keep aspect ratio var scale = Math.min((bg.width - 32) / icon.width, (bg.height - 32) / icon.height, 1); icon.width = icon.width * scale; icon.height = icon.height * scale; appBtn.addChild(icon); appBtn._customIcon = icon; appBtn.setEnabled(true); appBtn.action = function () { isInstalled = false; app.installed = false; updateAppBtn(); // Remove overlay from computerscreen UI var appNameLower = (app.name || "").toLowerCase(); if (appOverlays[appNameLower]) { appListContainer.removeChild(appOverlays[appNameLower]); if (typeof appOverlays[appNameLower].destroy === "function") { appOverlays[appNameLower].destroy(); } appOverlays[appNameLower] = null; // After uninstall, update app list order if (typeof updateAppListOrder === "function") updateAppListOrder(); } }; } else { // DOWNLOAD BUTTON: bluebackground + downloadbutton icon var bg = LK.getAsset('bluebackground', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 0 }); bg.width = 260; bg.height = 90; appBtn.addChild(bg); appBtn._customBg = bg; var icon = LK.getAsset('downloadbutton', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 0 }); // Fit icon inside button, keep aspect ratio var scale = Math.min((bg.width - 32) / icon.width, (bg.height - 32) / icon.height, 1); icon.width = icon.width * scale; icon.height = icon.height * scale; appBtn.addChild(icon); appBtn._customIcon = icon; appBtn.setEnabled(true); appBtn.action = function () { // Prevent double install if (isInstalled) return; // Show loading bar overlay on the app card var loadingBarBg = LK.getAsset('loadingbarempty', { anchorX: 0.5, anchorY: 0.5, x: cardBg.x + appCardW / 2, y: cardBg.y + appCardH - 80 }); loadingBarBg.width = 420; loadingBarBg.height = 48; loadingBarBg.alpha = 0.92; psListContainer.addChild(loadingBarBg); var loadingBarFill = LK.getAsset('loadingbarfull', { anchorX: 0, anchorY: 0.5, x: loadingBarBg.x - loadingBarBg.width / 2 + 4, y: loadingBarBg.y }); loadingBarFill.width = 0; loadingBarFill.height = 36; loadingBarFill.tint = 0x2196f3; // blue psListContainer.addChild(loadingBarFill); // Disable the button during loading appBtn.setEnabled(false); // Animate loading bar fill over 1.2 seconds var loadingDuration = 1200; tween(loadingBarFill, { width: loadingBarBg.width - 8 }, { duration: loadingDuration, easing: tween.cubicOut, onFinish: function onFinish() { // Remove loading bar loadingBarBg.destroy(); loadingBarFill.destroy(); // Actually install the app isInstalled = true; app.installed = true; updateAppBtn(); // Add overlay to computerscreen UI (appListContainer) if not already present var appNameLower = (app.name || "").toLowerCase(); if (!appOverlays[appNameLower]) { var overlay = createAppOverlay(appNameLower, idx); appOverlays[appNameLower] = overlay; } // After install, update app list order if (typeof updateAppListOrder === "function") updateAppListOrder(); } }); }; } // Hide label if button is not enabled (should not show Download/Delete text if not visible) if (!appBtn.enabled && appBtn.label) appBtn.label.visible = false; } // Initial setup updateAppBtn(); psListContainer.addChild(appBtn); })(i); } // --- Set scroll bounds for Play Store app list after rendering --- // The visible area for the app list is the height of playStoreOverlay (== computerscreen.height) psListHeight = totalListHeight; var visibleHeight = playStoreOverlay.height - 120; // 60px margin top/bottom // The minimum y is so the last card is just visible at the bottom psListMinY = Math.min(-1000, -1000 - (psListHeight - visibleHeight)); psListMaxY = -1000; // Topmost position (default) psListContainer.y = psListMaxY; psListScrollY = psListMaxY; } // Add the app list container as a child of computerscreen (so it's visually inside) computerScreen.addChild(appListContainer); // Place the videos, record, edit, promote, and statistics buttons equally at the bottom of the computerscreen, no space between them. var numBtns = 5; var btnW = computerScreen.width / numBtns; var btnH = 120; var csLeft = computerScreen.x - computerScreen.width / 2; var csBottom = computerScreen.y + computerScreen.height / 2; // Videos Button removed as requested // Helper to hide video list function hideVideoList() { videoListBg.visible = false; videoListContainer.visible = false; } // Record Button var recordVideoBtn = new GameButton(); recordVideoBtn.setButton('promoteBtn', 'Record', "#fff", btnW, btnH); recordVideoBtn.x = csLeft + btnW * 1.5; recordVideoBtn.y = csBottom - btnH / 2; recordVideoBtn.action = function () { hideVideoList(); if (typeof makeVideoBtn.action === "function") { makeVideoBtn.action(); } }; game.addChild(recordVideoBtn); // Edit Button var editBtn = new GameButton(); editBtn.setButton('editBtn', 'Edit', "#fff", btnW, btnH); editBtn.x = csLeft + btnW * 2.5; editBtn.y = csBottom - btnH / 2; editBtn.action = function () { hideVideoList(); // Only allow editing if there is a video in 'recorded' state and not finished, and no process is running if (timeProcess) return; if (!window.uploadedVideos) { // Show message: "You must record a video first!" var msg = new Text2("You must record a video first!", { size: 72, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); msg.anchor.set(0.5, 0.5); msg.x = 2048 / 2; msg.y = 2732 / 2; game.addChild(msg); tween(msg, { alpha: 0, y: msg.y - 80 }, { duration: 1600, onFinish: function onFinish() { msg.destroy(); } }); return; } var editIdx = -1; for (var i = 0; i < window.uploadedVideos.length; i++) { if (window.uploadedVideos[i].state === "recorded" && !window.uploadedVideos[i].finished) { editIdx = i; break; } } if (editIdx === -1) { // Show message: "You must record a video first!" var msg = new Text2("You must record a video first!", { size: 72, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); msg.anchor.set(0.5, 0.5); msg.x = 2048 / 2; msg.y = 2732 / 2; game.addChild(msg); tween(msg, { alpha: 0, y: msg.y - 80 }, { duration: 1600, onFinish: function onFinish() { msg.destroy(); } }); return; } // Open edit panel var editPanelBg = LK.getAsset('studioBg', { anchorX: 0.5, anchorY: 0.5 }); // Make edit panel exactly match computerscreen size and position editPanelBg.width = computerScreen.width; editPanelBg.height = computerScreen.height; editPanelBg.x = computerScreen.x; editPanelBg.y = computerScreen.y; editPanelBg.alpha = 0.98; var editPanelTitle = new Text2("Edit Video", { size: 90, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); editPanelTitle.anchor.set(0.5, 0.5); editPanelTitle.x = editPanelBg.x; editPanelTitle.y = editPanelBg.y - editPanelBg.height / 2 + 120; // Loading bar background var loadingBarBg = LK.getAsset('loadingbarempty', { anchorX: 0.5, anchorY: 0.5 }); loadingBarBg.width = 800; loadingBarBg.height = 80; loadingBarBg.x = editPanelBg.x; loadingBarBg.y = editPanelBg.y; // Loading bar fill var loadingBarFill = LK.getAsset('loadingbarfull', { anchorX: 0, anchorY: 0.5 }); loadingBarFill.width = 0; loadingBarFill.height = 64; loadingBarFill.x = loadingBarBg.x - loadingBarBg.width / 2 + 4; loadingBarFill.y = loadingBarBg.y; // Edit button (just for visual, no action) var editPanelBtn = new GameButton(); editPanelBtn.setButton('editBtn', 'Edit', "#fff", 400, 120); editPanelBtn.x = editPanelBg.x; editPanelBtn.y = loadingBarBg.y + 160; editPanelBtn.setEnabled(false); // Close (X) button var closeEditBtn = new Text2("Ć", { size: 120, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); closeEditBtn.anchor.set(0.5, 0.5); closeEditBtn.x = editPanelBg.x + editPanelBg.width / 2 - 80; closeEditBtn.y = editPanelBg.y - editPanelBg.height / 2 + 80; closeEditBtn.interactive = true; closeEditBtn.buttonMode = true; closeEditBtn.down = function () { // Do not allow closing while editing }; // Add to game game.addChild(editPanelBg); game.addChild(editPanelTitle); game.addChild(loadingBarBg); game.addChild(loadingBarFill); game.addChild(editPanelBtn); game.addChild(closeEditBtn); // Start editing process for this video var editVideo = window.uploadedVideos[editIdx]; var totalEdit = editVideo.editHoursLeft || 5; var hoursLeft = totalEdit; timeProcess = { type: 'edit', hoursLeft: totalEdit, total: totalEdit, video: editVideo, onFinish: function onFinish() { // Mark video as ready to publish editVideo.state = "readyToPublish"; editVideo.publishReady = true; updateVideoLists(); // Remove edit panel editPanelBg.destroy(); editPanelTitle.destroy(); loadingBarBg.destroy(); loadingBarFill.destroy(); editPanelBtn.destroy(); closeEditBtn.destroy(); } }; // Animate loading bar fill var lastEditBarWidth = 0; var editInterval = LK.setInterval(function () { if (!timeProcess || timeProcess.type !== 'edit') { LK.clearInterval(editInterval); return; } var progress = 1 - timeProcess.hoursLeft / (timeProcess.total || 1); var targetWidth = (loadingBarBg.width - 8) * Math.max(0, Math.min(1, progress)); // Only tween if changed if (Math.abs(targetWidth - lastEditBarWidth) > 1) { tween(loadingBarFill, { width: targetWidth }, { duration: 400, easing: tween.cubicOut }); lastEditBarWidth = targetWidth; } if (timeProcess.hoursLeft <= 0) { LK.clearInterval(editInterval); } }, 100); }; game.addChild(editBtn); // Promote Button var promoteBtn = new GameButton(); promoteBtn.setButton('promoteBtn', 'Promote', "#fff", btnW, btnH); // Reduce label font size for promote button if (promoteBtn.label) { if (promoteBtn.label.style && typeof promoteBtn.label.style.size !== "undefined") { promoteBtn.label.style.size = 44; promoteBtn.label.dirty = true; } else if (typeof promoteBtn.label.setStyle === "function") { promoteBtn.label.setStyle({ size: 44 }); } } promoteBtn.x = csLeft + btnW * 3.5; promoteBtn.y = csBottom - btnH / 2; promoteBtn.action = function () { hideVideoList(); // Prevent multiple promote panels if (game.promotePanelOpen) return; game.promotePanelOpen = true; // --- Promote Panel State --- if (!window.activePromotes) window.activePromotes = []; var maxPromotes = 5; // Panel background var promotePanelBg = LK.getAsset('studioBg', { anchorX: 0.5, anchorY: 0.5 }); // Make promote panel exactly match computerscreen size and position promotePanelBg.width = computerScreen.width; promotePanelBg.height = computerScreen.height; promotePanelBg.x = computerScreen.x; promotePanelBg.y = computerScreen.y; promotePanelBg.alpha = 0.98; // Title var promoteTitle = new Text2("Promote Your Channel", { size: 90, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); promoteTitle.anchor.set(0.5, 0.5); promoteTitle.x = promotePanelBg.x; promoteTitle.y = promotePanelBg.y - promotePanelBg.height / 2 + 120; // --- Active Promotes List (top of panel, in-panel, max 5, no conv/subs est) --- // Display: Each promote is a vertical stack of 4 labels, and campaigns are side by side horizontally var promoteListY = promoteTitle.y + 100; var promoteListLabels = []; var promoteListMaxW = promotePanelBg.width - 120; var promoteListStartX = promotePanelBg.x - promoteListMaxW / 2 + 20; var promoteListStartY = promoteListY + 20; var promoteListSpacingX = 420; // horizontal space between campaigns var promoteListSpacingY = 60; // vertical space between lines in a campaign var promoteLabelFields = [{ key: "amount", label: "Budget", prefix: "$" }, { key: "spentSoFar", label: "Spent", prefix: "$" }, { key: "viewsSoFar", label: "Views", prefix: "", isRange: false }, { key: "range", label: "Target", prefix: "", isRange: true }]; // Helper to update the in-panel promote list (max 5, no conv/subs est) function updatePromoteListDisplay() { // Remove old for (var i = 0; i < promoteListLabels.length; i++) { for (var j = 0; j < promoteListLabels[i].length; j++) { promoteListLabels[i][j].destroy(); } } promoteListLabels = []; // Show up to 5 active promotes, newest at left for (var i = 0; i < Math.min(window.activePromotes.length, maxPromotes); i++) { var p = window.activePromotes[i]; var labels = []; // Compose each line: Budget, Spent, Views, Target Range // 1. Budget var labelTxt1 = promoteLabelFields[0].label + ": $" + p.amount; var label1 = new Text2(labelTxt1, { size: 44, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); label1.anchor.set(0.5, 0.5); label1.x = promoteListStartX + i * promoteListSpacingX + promoteListSpacingX / 2; label1.y = promoteListStartY + 0 * promoteListSpacingY; labels.push(label1); game.addChild(label1); // 2. Spent so far var spentDisplay = Math.floor((p.spentSoFar || 0) * 100) / 100; var labelTxt2 = promoteLabelFields[1].label + ": $" + spentDisplay; var label2 = new Text2(labelTxt2, { size: 44, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); label2.anchor.set(0.5, 0.5); label2.x = promoteListStartX + i * promoteListSpacingX + promoteListSpacingX / 2; label2.y = promoteListStartY + 1 * promoteListSpacingY; labels.push(label2); game.addChild(label2); // 3. Views so far var labelTxt3 = promoteLabelFields[2].label + ": " + (p.viewsSoFar || 0); var label3 = new Text2(labelTxt3, { size: 44, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); label3.anchor.set(0.5, 0.5); label3.x = promoteListStartX + i * promoteListSpacingX + promoteListSpacingX / 2; label3.y = promoteListStartY + 2 * promoteListSpacingY; labels.push(label3); game.addChild(label3); // 4. Target range var labelTxt4 = p.minViews + "-" + p.maxViews + " people"; var label4 = new Text2(labelTxt4, { size: 44, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); label4.anchor.set(0.5, 0.5); label4.x = promoteListStartX + i * promoteListSpacingX + promoteListSpacingX / 2; label4.y = promoteListStartY + 3 * promoteListSpacingY; labels.push(label4); game.addChild(label4); promoteListLabels.push(labels); // Store for update p._promoteListLabel = labels; } } // Initial display updatePromoteListDisplay(); // --- Money Slider Input --- // Set promote minimum to 0, and cap to current money, disable if money is 0 var promoteAmount = 0; var moneySliderBg = LK.getAsset('loadingbarempty', { anchorX: 0.5, anchorY: 0.5 }); moneySliderBg.width = 600; moneySliderBg.height = 100; moneySliderBg.x = promotePanelBg.x - 250; moneySliderBg.y = promoteListStartY + maxPromotes * promoteListSpacingY + 80; moneySliderBg.alpha = 0.92; // Slider fill var moneySliderFill = LK.getAsset('loadingbarfull', { anchorX: 0, anchorY: 0.5 }); moneySliderFill.height = 80; moneySliderFill.x = moneySliderBg.x - moneySliderBg.width / 2 + 4; moneySliderFill.y = moneySliderBg.y; moneySliderFill.width = 0; // Slider handle var moneySliderHandle = LK.getAsset('editBtn', { anchorX: 0.5, anchorY: 0.5 }); moneySliderHandle.width = 80; moneySliderHandle.height = 120; moneySliderHandle.x = moneySliderBg.x - moneySliderBg.width / 2; moneySliderHandle.y = moneySliderBg.y; var moneyInputTxt = new Text2("$" + promoteAmount, { size: 60, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); moneyInputTxt.anchor.set(0.5, 0.5); moneyInputTxt.x = moneySliderBg.x; moneyInputTxt.y = moneySliderBg.y - 70; // --- Days Slider Input --- var promoteDays = 1; var daysSliderBg = LK.getAsset('loadingbarempty', { anchorX: 0.5, anchorY: 0.5 }); daysSliderBg.width = 400; daysSliderBg.height = 100; daysSliderBg.x = promotePanelBg.x + 350; daysSliderBg.y = moneySliderBg.y; daysSliderBg.alpha = 0.92; var daysSliderFill = LK.getAsset('loadingbarfull', { anchorX: 0, anchorY: 0.5 }); daysSliderFill.height = 80; daysSliderFill.x = daysSliderBg.x - daysSliderBg.width / 2 + 4; daysSliderFill.y = daysSliderBg.y; daysSliderFill.width = 0; var daysSliderHandle = LK.getAsset('editBtn', { anchorX: 0.5, anchorY: 0.5 }); daysSliderHandle.width = 80; daysSliderHandle.height = 120; daysSliderHandle.x = daysSliderBg.x - daysSliderBg.width / 2; daysSliderHandle.y = daysSliderBg.y; var daysInputTxt = new Text2(promoteDays + " day", { size: 60, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); daysInputTxt.anchor.set(0.5, 0.5); daysInputTxt.x = daysSliderBg.x; daysInputTxt.y = daysSliderBg.y - 70; // --- Slider Drag Logic --- var draggingMoney = false; var draggingDays = false; var lastMoneyX = 0; var lastDaysX = 0; function updateMoneySliderFromX(x) { var min = 0; var max = Math.max(0, Math.floor(money * 100) / 100); var left = moneySliderBg.x - moneySliderBg.width / 2; var right = moneySliderBg.x + moneySliderBg.width / 2; var clamped = Math.max(left, Math.min(right, x)); var ratio = max === min ? 0 : (clamped - left) / (right - left); var value = min + (max - min) * ratio; value = Math.floor(value * 100) / 100; if (value < min) value = min; if (value > max) value = max; promoteAmount = value; // Update visuals var fillW = (moneySliderBg.width - 8) * (max === 0 ? 0 : ratio); moneySliderFill.width = fillW; moneySliderHandle.x = left + (max === 0 ? 0 : ratio * (right - left)); moneyInputTxt.setText("$" + promoteAmount); updateEstimates(); } // Disable slider if money is 0 if (money <= 0) { moneySliderHandle.interactive = false; moneySliderHandle.buttonMode = false; moneySliderBg.interactive = false; moneySliderBg.buttonMode = false; promoteAmount = 0; moneySliderFill.width = 0; moneySliderHandle.x = moneySliderBg.x - moneySliderBg.width / 2; moneyInputTxt.setText("$0"); } else { moneySliderHandle.interactive = true; moneySliderHandle.buttonMode = true; moneySliderBg.interactive = true; moneySliderBg.buttonMode = true; } function updateDaysSliderFromX(x) { var min = 1; var max = 30; var left = daysSliderBg.x - daysSliderBg.width / 2; var right = daysSliderBg.x + daysSliderBg.width / 2; var clamped = Math.max(left, Math.min(right, x)); var ratio = (clamped - left) / (right - left); var value = min + (max - min) * ratio; value = Math.round(value); if (value < min) value = min; if (value > max) value = max; promoteDays = value; // Update visuals var fillW = (daysSliderBg.width - 8) * ((promoteDays - min) / (max - min)); daysSliderFill.width = fillW; daysSliderHandle.x = left + (promoteDays - min) / (max - min) * (right - left); daysInputTxt.setText(promoteDays + (promoteDays === 1 ? " day" : " days")); updateEstimates(); } // Money slider handle drag moneySliderHandle.interactive = true; moneySliderHandle.buttonMode = true; moneySliderHandle.down = function (x, y, obj) { draggingMoney = true; lastMoneyX = x; }; game.move = function (origMove) { return function (x, y, obj) { if (draggingMoney) { updateMoneySliderFromX(x); } if (draggingDays) { updateDaysSliderFromX(x); } if (typeof origMove === "function") origMove(x, y, obj); }; }(game.move); game.up = function (origUp) { return function (x, y, obj) { draggingMoney = false; draggingDays = false; if (typeof origUp === "function") origUp(x, y, obj); }; }(game.up); // Money slider background tap moneySliderBg.interactive = true; moneySliderBg.buttonMode = true; moneySliderBg.down = function (x, y, obj) { updateMoneySliderFromX(x); }; // Days slider handle drag daysSliderHandle.interactive = true; daysSliderHandle.buttonMode = true; daysSliderHandle.down = function (x, y, obj) { draggingDays = true; lastDaysX = x; }; // Days slider background tap daysSliderBg.interactive = true; daysSliderBg.buttonMode = true; daysSliderBg.down = function (x, y, obj) { updateDaysSliderFromX(x); }; // --- Estimates Display --- var estViewsTxt = new Text2("", { size: 48, fill: "#0ff", font: "Arial, Helvetica, sans-serif" }); estViewsTxt.anchor.set(0.5, 0.5); estViewsTxt.x = promotePanelBg.x; estViewsTxt.y = moneySliderBg.y + 120; // No estimated subs shown! // --- Confirm Button --- var confirmPromoteBtn = new GameButton(); confirmPromoteBtn.setButton('promoteBtn', 'Start Promote', "#fff", 480, 130); confirmPromoteBtn.x = promotePanelBg.x; confirmPromoteBtn.y = estViewsTxt.y + 120; confirmPromoteBtn.setEnabled(true); // Make the label smaller if (confirmPromoteBtn.label && confirmPromoteBtn.label.style && typeof confirmPromoteBtn.label.style.size !== "undefined") { confirmPromoteBtn.label.style.size = 44; confirmPromoteBtn.label.dirty = true; } else if (confirmPromoteBtn.label && typeof confirmPromoteBtn.label.setStyle === "function") { confirmPromoteBtn.label.setStyle({ size: 44 }); } // --- Close Button --- var closePromoteBtn = new Text2("Ć", { size: 120, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); closePromoteBtn.anchor.set(0.5, 0.5); closePromoteBtn.x = promotePanelBg.x + promotePanelBg.width / 2 - 80; closePromoteBtn.y = promotePanelBg.y - promotePanelBg.height / 2 + 80; closePromoteBtn.interactive = true; closePromoteBtn.buttonMode = true; closePromoteBtn.down = function () { promotePanelBg.destroy(); promoteTitle.destroy(); moneySliderBg.destroy(); moneySliderFill.destroy(); moneySliderHandle.destroy(); moneyInputTxt.destroy(); daysSliderBg.destroy(); daysSliderFill.destroy(); daysSliderHandle.destroy(); daysInputTxt.destroy(); estViewsTxt.destroy(); confirmPromoteBtn.destroy(); closePromoteBtn.destroy(); for (var i = 0; i < promoteListLabels.length; i++) { for (var j = 0; j < promoteListLabels[i].length; j++) { promoteListLabels[i][j].destroy(); } } game.promotePanelOpen = false; }; // --- Estimate Calculation --- var estViews = 0, estSubs = 0, estConv = 0, estSubRate = 0; function updateEstimates() { // Each $1 = 250-1000 views var minViews = Math.floor(promoteAmount * 250); var maxViews = Math.floor(promoteAmount * 1000); estViews = minViews + Math.floor(Math.random() * (maxViews - minViews + 1)); // Conversion rate: 0.1% - 2% (spread), 1-1.5% if spread over >1 day if (promoteDays === 1) { estSubRate = 0.001 + Math.random() * 0.019; // 0.1% - 2% } else { estSubRate = 0.01 + Math.random() * 0.005; // 1% - 1.5% } estSubs = Math.floor(estViews * estSubRate); estConv = Math.round(estSubRate * 10000) / 100; // Show estimated reach as a range, not a single value estViewsTxt.setText("Estimated Reach: " + formatNumber(minViews) + " - " + formatNumber(maxViews) + " people"); // No estimated subs shown! // Enable/disable confirm var canPromote = promoteAmount > 0 && promoteAmount <= money && promoteDays > 0 && promoteDays <= 30 && window.activePromotes.length < maxPromotes && money > 0; confirmPromoteBtn.setEnabled(canPromote); // Also disable slider if money is 0 if (money <= 0) { moneySliderHandle.interactive = false; moneySliderHandle.buttonMode = false; moneySliderBg.interactive = false; moneySliderBg.buttonMode = false; promoteAmount = 0; moneySliderFill.width = 0; moneySliderHandle.x = moneySliderBg.x - moneySliderBg.width / 2; moneyInputTxt.setText("$0"); } else { moneySliderHandle.interactive = true; moneySliderHandle.buttonMode = true; moneySliderBg.interactive = true; moneySliderBg.buttonMode = true; } } updateEstimates(); // --- Confirm Promote Action --- confirmPromoteBtn.action = function () { if (window.activePromotes.length >= maxPromotes) return; if (promoteAmount > money) return; // Deduct money money -= promoteAmount; updateStats(); // Schedule promote var promoteObj = { amount: promoteAmount, days: promoteDays, startDay: gameDay, targetViews: estViews, subRate: estSubRate, estimatedSubs: estSubs, viewsPerDay: [], viewsPerHour: [], subsPerDay: [], hoursPerDay: [], hoursLeft: promoteDays * 24, finished: false, shownPerHour: [], subsGained: 0, lastDay: gameDay + promoteDays - 1, // New for summary panel spentSoFar: 0, viewsSoFar: 0, summaryPanel: null, summaryLabels: [], minViews: Math.floor(promoteAmount * 250), maxViews: Math.floor(promoteAmount * 1000) }; // Distribute views per day var perDay = Math.floor(estViews / promoteDays); var remain = estViews - perDay * promoteDays; for (var d = 0; d < promoteDays; d++) { promoteObj.viewsPerDay[d] = perDay + (d < remain ? 1 : 0); // Distribute per hour randomly var perHour = Math.floor(promoteObj.viewsPerDay[d] / 24); var remainHour = promoteObj.viewsPerDay[d] - perHour * 24; var arr = []; for (var h = 0; h < 24; h++) arr[h] = perHour; // Randomly distribute the remainder for (var h = 0; h < remainHour; h++) { var idx = Math.floor(Math.random() * 24); arr[idx]++; } promoteObj.viewsPerHour[d] = arr; promoteObj.shownPerHour[d] = []; for (var h = 0; h < 24; h++) promoteObj.shownPerHour[d][h] = 0; } window.activePromotes.push(promoteObj); updatePromoteListDisplay(); updateEstimates(); // --- After starting promote, update in-panel promote list and set up per-hour update --- updatePromoteListDisplay(); updateEstimates(); // Helper to update the label for this promote in the list promoteObj.updatePromoteListLabel = function () { if (promoteObj._promoteListLabel && promoteObj._promoteListLabel.length === 4) { var spentDisplay = Math.floor((promoteObj.spentSoFar || 0) * 100) / 100; promoteObj._promoteListLabel[0].setText("Budget: $" + promoteObj.amount); promoteObj._promoteListLabel[1].setText("Spent: $" + spentDisplay); promoteObj._promoteListLabel[2].setText("Views: " + (promoteObj.viewsSoFar || 0)); promoteObj._promoteListLabel[3].setText(promoteObj.minViews + "-" + promoteObj.maxViews + " people"); } }; // Show confirmation var msg = new Text2("Promotion started!", { size: 72, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); msg.anchor.set(0.5, 0.5); msg.x = promotePanelBg.x; msg.y = confirmPromoteBtn.y + 120; game.addChild(msg); tween(msg, { alpha: 0, y: msg.y - 80 }, { duration: 1600, onFinish: function onFinish() { msg.destroy(); } }); // Optionally close panel closePromoteBtn.down(); }; // --- Add to game --- game.addChild(promotePanelBg); game.addChild(promoteTitle); for (var i = 0; i < promoteListLabels.length; i++) { for (var j = 0; j < promoteListLabels[i].length; j++) { game.addChild(promoteListLabels[i][j]); } } game.addChild(moneySliderBg); game.addChild(moneySliderFill); game.addChild(moneySliderHandle); game.addChild(moneyInputTxt); game.addChild(daysSliderBg); game.addChild(daysSliderFill); game.addChild(daysSliderHandle); game.addChild(daysInputTxt); game.addChild(estViewsTxt); game.addChild(confirmPromoteBtn); game.addChild(closePromoteBtn); }; game.addChild(promoteBtn); // Statistics Button var statsBtn = new GameButton(); statsBtn.setButton('editBtn', 'Statistics', "#fff", btnW, btnH); // Reduce label font size for statistics button if (statsBtn.label) { if (statsBtn.label.style && typeof statsBtn.label.style.size !== "undefined") { statsBtn.label.style.size = 44; statsBtn.label.dirty = true; } else if (typeof statsBtn.label.setStyle === "function") { statsBtn.label.setStyle({ size: 44 }); } } statsBtn.x = csLeft + btnW * 4.5; statsBtn.y = csBottom - btnH / 2; statsBtn.action = function () { hideVideoList(); updateStatsGraphSingle(); statsOverlay.visible = true; }; game.addChild(statsBtn); // --- Time Display --- // Place time text to the right of the money text var timeTxt = new Text2('Day 1, 08:00', { size: 44, fill: 0xFFFFFF }); timeTxt.anchor.set(0, 0.5); // Will be positioned after moneyTxt is created and positioned // --- Video List UI --- // Video list background and container (horizontal, each video on a square background, text below, side by side) var videoListBg = LK.getAsset('loadingbarempty', { anchorX: 0.5, anchorY: 0.5 }); videoListBg.alpha = 0.96; videoListBg.visible = false; // Only visible when video list is shown // Make video panel exactly match computerscreen size and position videoListBg.x = computerScreen.x; videoListBg.y = computerScreen.y; videoListBg.width = computerScreen.width; videoListBg.height = computerScreen.height; game.addChild(videoListBg); var videoListContainer = new Container(); // Place container at top-left inside videoListBg (which matches computerscreen) videoListContainer.x = videoListBg.x - videoListBg.width / 2; videoListContainer.y = videoListBg.y - videoListBg.height / 2; videoListContainer.visible = false; // Only visible when video list is shown game.addChild(videoListContainer); // Helper to update the video list display function updateVideoLists() { // Remove all previous children while (videoListContainer.children.length > 0) { videoListContainer.children[0].destroy(); } if (!window.uploadedVideos || window.uploadedVideos.length === 0) { return; } var squareSize = 340; var spacing = 48; for (var i = 0; i < window.uploadedVideos.length; i++) { var video = window.uploadedVideos[i]; // Calculate row and column for 5 per row var videosPerRow = 5; var row = Math.floor(i / videosPerRow); var col = i % videosPerRow; // Square background var bg = LK.getAsset('loadingbarempty', { anchorX: 0.5, anchorY: 0.5 }); bg.width = squareSize; bg.height = squareSize; bg.x = col * (squareSize + spacing) + squareSize / 2; bg.y = row * (squareSize + spacing) + squareSize / 2; bg.alpha = 0.93; videoListContainer.addChild(bg); // Video name (title) - top of square var nameTxt = new Text2(video.title || "Untitled", { size: 44, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); nameTxt.anchor.set(0.5, 0); nameTxt.x = bg.x; nameTxt.y = bg.y - squareSize / 2 + 18; videoListContainer.addChild(nameTxt); // Views - below name var viewsTxt = new Text2(formatNumber(video.totalViews) + " views", { size: 36, fill: "#0ff", font: "Arial, Helvetica, sans-serif" }); viewsTxt.anchor.set(0.5, 0); viewsTxt.x = bg.x; viewsTxt.y = nameTxt.y + nameTxt.height + 6; videoListContainer.addChild(viewsTxt); // Money earned - below views var moneyDisplay = Math.floor(video.totalMoney * 100) / 100; var moneyTxt = new Text2("$" + formatNumber(moneyDisplay) + " earned", { size: 36, fill: 0xFA4B00, font: "Arial, Helvetica, sans-serif" }); moneyTxt.anchor.set(0.5, 0); moneyTxt.x = bg.x; moneyTxt.y = viewsTxt.y + viewsTxt.height + 2; videoListContainer.addChild(moneyTxt); // Subscribers - below money var subsTxt = new Text2(formatNumber(video.totalSubs) + " subs", { size: 36, fill: 0xFFE066, font: "Arial, Helvetica, sans-serif" }); subsTxt.anchor.set(0.5, 0); subsTxt.x = bg.x; subsTxt.y = moneyTxt.y + moneyTxt.height + 2; videoListContainer.addChild(subsTxt); // Status - below subs // (Removed: status text such as Just Published, Gaining Views, Finished) // --- Loading Bar (progress for edit/record/publish) --- var showBar = false; var barProgress = 0; var barLabel = ""; if (video.state === "recorded" && !video.finished && typeof video.editHoursLeft === "number" && video.editHoursLeft > 0) { // Editing in progress or ready to edit showBar = true; // If currently editing, show progress if (timeProcess && timeProcess.type === "edit" && timeProcess.video === video) { barProgress = 1 - timeProcess.hoursLeft / (timeProcess.total || 1); barLabel = "Editing..."; } else { barProgress = 0; barLabel = "Ready to Edit"; } } else if (video.state === "readyToPublish" && !video.finished) { // Ready to publish, no progress bar needed showBar = true; barProgress = 1; barLabel = "Ready to Publish"; } else if (video.state === "published" && !video.finished && typeof video.totalHours === "number" && video.totalHours > 0) { // Gaining views (publishing progress) // Fill the bar over 7 days (168 hours) showBar = true; var publishTotal = 7 * 24; barProgress = Math.min(1, video.hour / publishTotal); barLabel = "Publishing..."; } else if (video.state === "recording" && !video.finished && typeof video.recordHoursLeft === "number" && video.recordHoursLeft > 0) { // Recording in progress showBar = true; if (timeProcess && timeProcess.type === "record" && timeProcess.video === video) { barProgress = 1 - timeProcess.hoursLeft / (timeProcess.total || 1); barLabel = "Recording..."; } else { barProgress = 1 - video.recordHoursLeft / (video.totalRecordHours || 1); barLabel = "Recording..."; } } if (showBar) { // Bar background var barBg = LK.getAsset('loadingbarempty', { anchorX: 0.5, anchorY: 0 }); barBg.width = squareSize - 40; barBg.height = 36; barBg.x = bg.x; barBg.y = nameTxt.y + nameTxt.height + viewsTxt.height + moneyTxt.height + subsTxt.height + 18; barBg.alpha = 0.85; videoListContainer.addChild(barBg); // Bar fill var barFill = LK.getAsset('loadingbarfull', { anchorX: 0, anchorY: 0 }); // Animate barFill width smoothly using tween, starting from current width var targetBarWidth = (squareSize - 44) * Math.max(0, Math.min(1, barProgress)); if (typeof video.barLastWidth === "undefined") { video.barLastWidth = 0; } barFill.width = video.barLastWidth; barFill.height = 28; barFill.x = barBg.x - barBg.width / 2 + 2; barFill.y = barBg.y + 4; barFill.alpha = 0.95; videoListContainer.addChild(barFill); // Only animate if the target width is different from the last width if (Math.abs(targetBarWidth - video.barLastWidth) > 1) { tween(barFill, { width: targetBarWidth }, { duration: 400, easing: tween.cubicOut, onUpdate: function onUpdate() { video.barLastWidth = barFill.width; }, onFinish: function onFinish() { video.barLastWidth = targetBarWidth; } }); } else { barFill.width = targetBarWidth; video.barLastWidth = targetBarWidth; } // Bar label var barTxt = new Text2(barLabel, { size: 28, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); barTxt.anchor.set(0.5, 0.5); barTxt.x = barBg.x; barTxt.y = barBg.y + barBg.height / 2; videoListContainer.addChild(barTxt); } // Optionally, trending badge (top of square, above name) if (video.trending) { var trendingTxt = new Text2("Trending", { size: 32, fill: "#ff0", font: "Arial, Helvetica, sans-serif" }); trendingTxt.anchor.set(0.5, 1); trendingTxt.x = bg.x; trendingTxt.y = bg.y - squareSize / 2 + 8; videoListContainer.addChild(trendingTxt); } // --- Edit and Publish Buttons --- // Only show publish button if video is ready to publish and not finished if (video.state === "readyToPublish" && video.publishReady && !video.finished) { var publishBtn = new GameButton(); publishBtn.setButton('videoBtn', '', "#fff", 180, 80); // Make the publish text smaller var publishLabel = new Text2('Publish', { size: 44, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); publishLabel.anchor.set(0.5, 0.5); publishLabel.x = 0; publishLabel.y = 0; publishBtn.addChild(publishLabel); // Place the publish button at the bottom center of the video's background publishBtn.x = bg.x; publishBtn.y = bg.y + bg.height / 2 - publishBtn.bg.height / 2 - 10; publishBtn.action = function (vidIdx) { return function () { // Publish the video var vid = window.uploadedVideos[vidIdx]; vid.state = "published"; vid.hour = 0; // Start accruing views vid.publishReady = false; updateVideoLists(); }; }(i); videoListContainer.addChild(publishBtn); } // Only show publish button if video is ready to publish and not finished if (video.state === "readyToPublish" && video.publishReady && !video.finished) { var publishBtn = new GameButton(); publishBtn.setButton('videoBtn', '', "#fff", 180, 80); // Make the publish text smaller var publishLabel = new Text2('Publish', { size: 44, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); publishLabel.anchor.set(0.5, 0.5); publishLabel.x = 0; publishLabel.y = 0; publishBtn.addChild(publishLabel); // Place the publish button at the bottom center of the video's background publishBtn.x = bg.x; publishBtn.y = bg.y + bg.height / 2 - publishBtn.bg.height / 2 - 10; publishBtn.action = function (vidIdx) { return function () { // Publish the video var vid = window.uploadedVideos[vidIdx]; vid.state = "published"; vid.hour = 0; // Start accruing views vid.publishReady = false; updateVideoLists(); }; }(i); videoListContainer.addChild(publishBtn); } } } // --- Pause/Resume/Double Speed Buttons --- // Track time speed: 0 = paused, 1 = normal, 2 = double var timeSpeed = 1; // Pause button var pauseBtn = new GameButton(); pauseBtn.setButton('pauseicon', '', "#fff", 54, 54); pauseBtn.action = function () { if (timeSpeed !== 0) { timeSpeed = 0; isTimePaused = true; } updateTimeControlButtons(); }; // Resume button var resumeBtn = new GameButton(); resumeBtn.setButton('resumeicon', '', "#fff", 54, 54); resumeBtn.action = function () { if (timeSpeed !== 1) { timeSpeed = 1; isTimePaused = false; } updateTimeControlButtons(); }; // Double speed button var doubleSpeedBtn = new GameButton(); // Double the size: 54*2 = 108 doubleSpeedBtn.setButton('doublespeedicon', '', "#fff", 108, 108); doubleSpeedBtn.action = function () { if (timeSpeed !== 2) { timeSpeed = 2; isTimePaused = false; } updateTimeControlButtons(); }; // Helper to update button enabled/disabled state and highlight function updateTimeControlButtons() { // Highlight the selected speed, dim others pauseBtn.setEnabled(timeSpeed !== 0 ? true : false); resumeBtn.setEnabled(timeSpeed !== 1 ? true : false); doubleSpeedBtn.setEnabled(timeSpeed !== 2 ? true : false); // Optionally, visually highlight the active button pauseBtn.bg.alpha = timeSpeed === 0 ? 1 : 0.6; resumeBtn.bg.alpha = timeSpeed === 1 ? 1 : 0.6; doubleSpeedBtn.bg.alpha = timeSpeed === 2 ? 1 : 0.6; } // Initial highlight updateTimeControlButtons(); // --- Position time text and pause/resume/double speed buttons to the right of the money text --- // This must be done after moneyTxt is created and positioned, so move this block after moneyTxt and icons are created and layoutCountersRow() is called. // --- Counter Row Display (subscribers, viewers, money) --- // Helper to position counters/icons in a row, matching the viewer counter/icon position function layoutCountersRow() { var counterY = 160; var centerX = 2048 / 2; var iconSpacing = 420; // Subscribers (left, further left) subIcon.x = centerX - iconSpacing * 1.7; subIcon.y = counterY; subTxt.x = subIcon.x + 70; subTxt.y = subIcon.y; // Viewers (shifted further left from center) viewIcon.x = centerX - iconSpacing * 0.9; viewIcon.y = counterY; viewTxt.x = viewIcon.x + 70; viewTxt.y = viewIcon.y; // Money (move further left) moneyIcon.x = centerX + iconSpacing * 0.1; moneyIcon.y = counterY; moneyTxt.x = moneyIcon.x + 70; moneyTxt.y = moneyIcon.y; } // Create icons and text objects var subIcon = LK.getAsset('subIcon', { anchorX: 0.5, anchorY: 0.5 }); var subTxt = new Text2('0', { size: 64, fill: 0xFFFFFF }); subTxt.anchor.set(0, 0.5); var viewIcon = LK.getAsset('viewersicon', { anchorX: 0.5, anchorY: 0.5 }); var viewTxt = new Text2('0', { size: 64, fill: 0x00e0ff }); viewTxt.anchor.set(0, 0.5); var moneyIcon = LK.getAsset('moneyIcon', { anchorX: 0.5, anchorY: 0.5 }); var moneyTxt = new Text2('0', { size: 64, fill: 0xFFE066 }); moneyTxt.anchor.set(0, 0.5); // Add all counters and icons to the game (ensure visible) game.addChild(subIcon); game.addChild(subTxt); game.addChild(viewIcon); game.addChild(viewTxt); game.addChild(moneyIcon); game.addChild(moneyTxt); // Initial layout layoutCountersRow(); // --- Position time text and time control buttons at the top-left of computerscreen --- var timePanelMargin = 32; var timePanelBtnSpacing = 24; var timePanelBtnY = computerScreen.y - computerScreen.height / 2 + timePanelMargin + pauseBtn.bg.height / 2; var timePanelX = computerScreen.x - computerScreen.width / 2 + timePanelMargin; // Place timeTxt at the top-left, leaving margin timeTxt.x = timePanelX + timeTxt.width / 2 + 10; timeTxt.y = computerScreen.y - computerScreen.height / 2 + timePanelMargin + timeTxt.height / 2 + 10; // Place pause, resume, and double speed buttons to the right of timeTxt var btnsStartX = timeTxt.x + timeTxt.width / 2 + timePanelBtnSpacing + pauseBtn.bg.width / 2; var btnsY = timeTxt.y; pauseBtn.x = btnsStartX; pauseBtn.y = btnsY; resumeBtn.x = btnsStartX + pauseBtn.bg.width + timePanelBtnSpacing; resumeBtn.y = btnsY; doubleSpeedBtn.x = btnsStartX + (pauseBtn.bg.width + timePanelBtnSpacing) * 2; doubleSpeedBtn.y = btnsY; // Add to game after positioning (ensure visible) game.addChild(timeTxt); game.addChild(pauseBtn); game.addChild(resumeBtn); game.addChild(doubleSpeedBtn); // --- Action Buttons --- // Button layout: stack vertically, bigger, with spacing var btnW = 540; var btnH = 220; var btnSpacingY = 60; var btnStartY = 900; // Make Video Button var makeVideoBtn = new GameButton(); makeVideoBtn.setButton('videoBtn', 'Record Video', "#fff", btnW, btnH); makeVideoBtn.x = 2048 / 2; // Move the record video button further down to fill the space of removed buttons // Move the record video button 250 pixels higher makeVideoBtn.y = btnStartY + 3 * (btnH + btnSpacingY) - 250; // --- Loading Bar for Process --- // (Removed: processBarBg and processBarFill, and their show/hide functions.) // No independent loading bar on the main screen. // --- Action Button Logic (time-based) --- // Track if record video panel is open var isRecordPanelOpen = false; makeVideoBtn.action = function () { if (timeProcess) { return; } // Only one process at a time // Block recording if a video is in 'recorded' state and not finished (must edit first) if (window.uploadedVideos) { for (var i = 0; i < window.uploadedVideos.length; i++) { if (window.uploadedVideos[i].state === "recorded" && !window.uploadedVideos[i].finished) { // Optionally, show a message or flash the edit button tween(editBtn, { scaleX: 1.15, scaleY: 1.15 }, { duration: 100, onFinish: function onFinish() { tween(editBtn, { scaleX: 1, scaleY: 1 }, { duration: 100 }); } }); return; } } } if (isRecordPanelOpen) { return; } // Prevent multiple panels isRecordPanelOpen = true; // Show a panel before starting the process // Place the record panel visually to exactly match computerscreen var panelBg = LK.getAsset('studioBg', { anchorX: 0.5, anchorY: 0.5 }); // Set panel size and position to exactly match computerscreen panelBg.width = computerScreen.width; panelBg.height = computerScreen.height; panelBg.x = computerScreen.x; panelBg.y = computerScreen.y; panelBg.alpha = 0.98; // Ensure panelBg is above computerscreen in the display list var csIdx = game.children.indexOf(computerScreen); if (csIdx !== -1) { // Insert panelBg just above computerscreen game.addChildAt(panelBg, csIdx + 1); } else { game.addChild(panelBg); } // --- Panel Title --- var panelText = new Text2("Select Category & Title", { size: 90, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); panelText.anchor.set(0.5, 0.5); panelText.x = panelBg.x; panelText.y = panelBg.y - panelBg.height / 2 + 120; // near top of panel // --- Video Title Input --- var titleInputBg = LK.getAsset('loadingbarempty', { anchorX: 0.5, anchorY: 0.5 }); titleInputBg.width = 1000; titleInputBg.height = 130; titleInputBg.x = panelBg.x - 180; // shift left to make space for random button titleInputBg.y = panelText.y + 200; // more space below title titleInputBg.alpha = 0.92; var videoTitle = ""; var titleInputTxt = new Text2("Enter video title...", { size: 72, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); titleInputTxt.anchor.set(0.5, 0.5); titleInputTxt.x = titleInputBg.x; titleInputTxt.y = titleInputBg.y; // Simulate input: tap to edit, prompt for text titleInputBg.down = function (x, y, obj) { var prompt = LK.prompt ? LK.prompt : window.prompt; // fallback for dev var val = prompt ? prompt("Enter video title:", videoTitle) : ""; if (typeof val === "string" && val.length > 0) { videoTitle = val; titleInputTxt.setText(videoTitle); } }; // --- Random Title Button --- var randomBtn = new GameButton(); randomBtn.setButton('promoteBtn', 'Random', "#fff", 340, 120); randomBtn.x = titleInputBg.x + titleInputBg.width / 2 + 200; // right of input with space randomBtn.y = titleInputBg.y; randomBtn.action = function () { // Titles per category var categoryTitles = { "Vlog": ["My Daily Vlog", "Life Update", "A Day in My Life", "Morning Routine", "Evening Recap"], "Challenge": ["Epic Challenge!", "24 Hour Challenge", "Impossible Task!", "Last To Leave", "Extreme Challenge"], "Reaction": ["Reacting to Comments", "Reacting to Viral Videos", "First Time Watching", "Fan Reactions", "Surprising Reactions"], "Tutorial": ["How To Edit Videos", "Beginner's Guide", "Pro Tips & Tricks", "Step by Step Tutorial", "Easy DIY"], "Unboxing": ["Unboxing Surprise", "Mystery Box Unboxing", "Tech Unboxing", "Unboxing Haul", "First Impressions"], "Gaming": ["Let's Play!", "Epic Gaming Moments", "Game Review", "Speedrun Attempt", "Funny Gaming Fails"], "Music": ["My New Song", "Music Cover", "Behind the Music", "Songwriting Session", "Live Performance"], "Comedy": ["Funny Moments", "Comedy Skit", "Prank Video", "Try Not To Laugh", "Bloopers & Outtakes"], "Q&A": ["Q&A Special", "Answering Your Questions", "Ask Me Anything", "Subscriber Q&A", "Get To Know Me"], "Other": ["Behind the Scenes", "Special Announcement", "Random Thoughts", "Channel Update", "What Happened Today"] }; var cat = videoCategories[selectedCategoryIdx]; var titles = categoryTitles[cat] || ["My Daily Vlog", "Epic Challenge!", "Reacting to Comments", "24 Hours in My Studio", "Behind the Scenes", "Q&A Special", "Trying Viral Trends", "Unboxing Surprise", "Life Update", "Funny Moments"]; var idx = Math.floor(Math.random() * titles.length); videoTitle = titles[idx]; titleInputTxt.setText(videoTitle); }; // --- Video Category Buttons --- var categoryBtnW = 340; var categoryBtnH = 120; var categoryBtnSpacingX = 40; var categoryBtnSpacingY = 40; var categoryBtns = []; // Layout: fit as many as possible per row, then wrap var maxRowWidth = panelBg.width - 120; // leave some margin var maxPerRow = Math.floor((maxRowWidth + categoryBtnSpacingX) / (categoryBtnW + categoryBtnSpacingX)); if (maxPerRow < 1) { maxPerRow = 1; } var startX = panelBg.x - (Math.min(maxPerRow, videoCategories.length) * (categoryBtnW + categoryBtnSpacingX) - categoryBtnSpacingX) / 2 + categoryBtnW / 2; var startY = titleInputBg.y + 220; // more space below input+random for (var i = 0; i < videoCategories.length; i++) { (function (idx) { var btn = new GameButton(); btn.setButton('editBtn', videoCategories[idx], "#fff", categoryBtnW, categoryBtnH); var row = Math.floor(idx / maxPerRow); var col = idx % maxPerRow; btn.x = startX + col * (categoryBtnW + categoryBtnSpacingX); btn.y = startY + row * (categoryBtnH + categoryBtnSpacingY); btn.action = function () { // Deselect all for (var j = 0; j < categoryBtns.length; j++) { // If trending, keep its highlight if (j === trendingCategoryIdx) { categoryBtns[j].bg.alpha = 0.95; } else { categoryBtns[j].bg.alpha = 0.7; } } btn.bg.alpha = 1; selectedCategoryIdx = idx; }; // Highlight the first by default if (i === 0) { btn.bg.alpha = 1; } else { btn.bg.alpha = 0.7; } // Mark trending category visually if (i === trendingCategoryIdx) { btn.bg.alpha = 0.95; // Add a "Trending" label above the button var trendingTxt = new Text2("š„ Trending", { size: 48, fill: "#ff0", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); trendingTxt.anchor.set(0.5, 1); trendingTxt.x = btn.x; trendingTxt.y = btn.y - categoryBtnH / 2 - 10; btn.trendingTxt = trendingTxt; } categoryBtns.push(btn); })(i); } // --- Confirm/Record Button --- var confirmBtn = new GameButton(); // Make the button smaller and move it 50px up confirmBtn.setButton('videoBtn', 'Record', "#fff", 480, 130); confirmBtn.x = panelBg.x; // Find the bottom Y of the last category button for spacing var lastCategoryBtn = categoryBtns[categoryBtns.length - 1]; var categoryBtnsBottomY = lastCategoryBtn ? lastCategoryBtn.y + categoryBtnH / 2 : startY + categoryBtnH / 2; confirmBtn.y = categoryBtnsBottomY + 150; // 50px higher than before confirmBtn.action = function () { // Remove panel panelBg.destroy(); panelText.destroy(); confirmBtn.destroy(); titleInputBg.destroy(); titleInputTxt.destroy(); randomBtn.destroy(); // Hide all category buttons and trending labels immediately for (var i = 0; i < categoryBtns.length; i++) { if (categoryBtns[i].trendingTxt) { categoryBtns[i].trendingTxt.visible = false; } categoryBtns[i].visible = false; } // Destroy all category buttons for (var i = 0; i < categoryBtns.length; i++) { // Destroy trending label if exists if (categoryBtns[i].trendingTxt) { categoryBtns[i].trendingTxt.destroy(); } categoryBtns[i].destroy(); } isRecordPanelOpen = false; // --- Add video to list immediately, in 'recording' state, before recording starts --- if (!window.uploadedVideos) { window.uploadedVideos = []; } var videoObj = { title: videoTitle, category: videoCategories[selectedCategoryIdx], hour: 0, totalHours: 7 * 24, totalViews: 0, totalMoney: 0, totalSubs: 0, trending: videoCategories[selectedCategoryIdx] === videoCategories[trendingCategoryIdx], baseSubscribers: subscribers, finished: false, state: "recording", // <--- show as recording recordHoursLeft: 3, totalRecordHours: 3, // new: states are "recording", "recorded", "editing", "readyToPublish", "published" editHoursLeft: 5, publishReady: false }; // Precompute total views to distribute realistically over 7 days var minViewPercent = 0.01; var maxViewPercent = 0.05; var percent = minViewPercent + Math.random() * (maxViewPercent - minViewPercent); var baseViews = Math.floor(videoObj.baseSubscribers * percent); if (videoObj.baseSubscribers < 100) { baseViews = 100 + Math.floor(Math.random() * 400); } if (videoObj.trending) { baseViews = Math.floor(baseViews * 1.5); } videoObj.targetViews = baseViews; videoObj.targetMoney = Math.floor(baseViews / 1000 * (3 + Math.random() * 2)); videoObj.targetSubs = Math.floor(baseViews / (200 + Math.floor(Math.random() * 101))); videoObj.hourlyViews = []; // Distribute views per hour: more at start, less at end (decay curve) var decay = 0.012; // controls how fast views drop off var total = 0; for (var h = 0; h < videoObj.totalHours; h++) { var rel = h / videoObj.totalHours; var hourViews = Math.max(1, Math.round(baseViews * Math.exp(-decay * h))); videoObj.hourlyViews.push(hourViews); total += hourViews; } // Normalize to match targetViews var scale = baseViews / total; for (var h = 0; h < videoObj.hourlyViews.length; h++) { videoObj.hourlyViews[h] = Math.floor(videoObj.hourlyViews[h] * scale); } window.uploadedVideos.push(videoObj); videoCount += 1; updateStats(); updateVideoLists(); // Start the process timeProcess = { type: 'record', hoursLeft: 3, total: 3, category: videoCategories[selectedCategoryIdx], title: videoTitle, video: videoObj, onFinish: function onFinish() { LK.getSound('makeVideo').play(); // Mark video as recorded, ready for editing videoObj.state = "recorded"; videoObj.recordHoursLeft = 0; updateVideoLists(); // Animate button tween(makeVideoBtn, { scaleX: 1.1, scaleY: 1.1 }, { duration: 80, onFinish: function onFinish() { tween(makeVideoBtn, { scaleX: 1, scaleY: 1 }, { duration: 80 }); } }); // Removed winning condition at 1000 subscribers; game continues forever } }; // Removed call to undefined showProcessBar(0) }; // --- Close (X) Button --- // Add all panel elements to game game.addChild(panelBg); game.addChild(panelText); game.addChild(titleInputBg); game.addChild(titleInputTxt); game.addChild(randomBtn); // (closeBtn removed) // Add all category buttons for (var i = 0; i < categoryBtns.length; i++) { game.addChild(categoryBtns[i]); // If trending label exists, add it to game if (categoryBtns[i].trendingTxt) { game.addChild(categoryBtns[i].trendingTxt); } } game.addChild(confirmBtn); }; // (Removed: makeVideoBtn from main screen, now triggered by recordVideoBtn next to videos button) // (Removed: manual y-positioning of subIcon/subTxt and moneyIcon/moneyTxt; handled by layoutCountersRow) // Removed undefined energyBar and energyTxt // --- GUI: Timer/Score (use subscribers as score) --- // Removed giant numbers next to the subscriber counter // --- Helper Functions --- function formatNumber(num) { if (num < 1000) { return "" + num; } if (num < 1000000) { var k = num / 1000; if (k % 1 === 0) { return k + "k"; } return k.toFixed(1).replace(/\.0$/, "") + "k"; } var m = num / 1000000; if (m % 1 === 0) { return m + "m"; } return m.toFixed(1).replace(/\.0$/, "") + "m"; } function updateStats() { // --- Helper for green increase text --- function showGreenIncrease(textObj, increase, prefix) { if (!increase || increase <= 0) { return; } var plusText = new Text2("+" + formatNumber(increase), { size: 48, fill: 0x00FF44, font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); plusText.anchor.set(0, 0.5); // Place to the right of the number plusText.x = textObj.x + textObj.width + 16; plusText.y = textObj.y; game.addChild(plusText); tween(plusText, { y: plusText.y - 40, alpha: 0 }, { duration: 1200, easing: tween.cubicOut, onFinish: function onFinish() { plusText.destroy(); } }); } // Subscribers if (typeof updateStats.lastSubValue !== "number") { updateStats.lastSubValue = subscribers; } var subIncrease = subscribers - updateStats.lastSubValue; subTxt.setText(formatNumber(subscribers)); if (subIncrease > 0) { showGreenIncrease(subTxt, subIncrease, ""); } updateStats.lastSubValue = subscribers; // Views if (typeof updateStats.lastViewValue !== "number") { updateStats.lastViewValue = viewCount; } var viewIncrease = viewCount - updateStats.lastViewValue; viewTxt.setText(formatNumber(viewCount)); if (viewIncrease > 0) { showGreenIncrease(viewTxt, viewIncrease, ""); } updateStats.lastViewValue = viewCount; // Money if (typeof updateStats.lastMoneyValue !== "number") { updateStats.lastMoneyValue = money; } var moneyIncrease = money - updateStats.lastMoneyValue; // Truncate money to 2 decimal digits for display var moneyDisplay = Math.floor(money * 100) / 100; moneyTxt.setText(formatNumber(moneyDisplay)); if (moneyIncrease > 0) { // Truncate moneyIncrease to 2 decimal digits for display var moneyIncreaseDisplay = Math.floor(moneyIncrease * 100) / 100; showGreenIncrease(moneyTxt, moneyIncreaseDisplay, ""); } updateStats.lastMoneyValue = money; // If financePanel is open, update its money display if (typeof financePanel !== "undefined" && financePanel && typeof financePanel.updateMoney === "function") { financePanel.updateMoney(); } // Enable/disable buttons based on process and resources makeVideoBtn.setEnabled(!timeProcess); // --- Achievements --- if (!updateStats.milestones) { updateStats.milestones = {}; } // Subscriber milestones var milestones = [10, 25, 50, 100, 250, 500, 750, 1000, 2500, 5000, 10000, 25000, 50000, 100000, 250000, 500000, 1000000]; for (var i = 0; i < milestones.length; i++) { var m = milestones[i]; if (subscribers >= m && !updateStats.milestones["subs" + m]) { updateStats.milestones["subs" + m] = true; var ach = new Text2("Milestone: " + m + " Subs!", { size: 110, fill: "#ff0", stroke: "#000", strokeThickness: 12, font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 12, dropShadowDistance: 4 }); ach.anchor.set(0.5, 0.5); ach.x = 2048 / 2; ach.y = 400 + i * 80; game.addChild(ach); tween(ach, { alpha: 0, y: ach.y - 100 }, { duration: 1800, onFinish: function onFinish() { ach.destroy(); } }); } } // View milestones var viewMilestones = [1000, 5000, 10000, 25000, 50000, 100000, 250000, 500000, 1000000, 5000000, 10000000]; for (var i = 0; i < viewMilestones.length; i++) { var m = viewMilestones[i]; if (viewCount >= m && !updateStats.milestones["views" + m]) { updateStats.milestones["views" + m] = true; var ach = new Text2("Milestone: " + formatNumber(m) + " Views!", { size: 110, fill: 0x00E0FF, stroke: "#000", strokeThickness: 12, font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 12, dropShadowDistance: 4 }); ach.anchor.set(0.5, 0.5); ach.x = 2048 / 2; ach.y = 400 + (i + milestones.length) * 80; game.addChild(ach); tween(ach, { alpha: 0, y: ach.y - 100 }, { duration: 1800, onFinish: function onFinish() { ach.destroy(); } }); } } // Money milestones var moneyMilestones = [100, 500, 1000, 5000, 10000, 25000, 50000, 100000, 250000, 500000, 1000000]; for (var i = 0; i < moneyMilestones.length; i++) { var m = moneyMilestones[i]; if (money >= m && !updateStats.milestones["money" + m]) { updateStats.milestones["money" + m] = true; var ach = new Text2("Milestone: $" + formatNumber(m) + " Earned!", { size: 110, fill: 0xFA4B00, stroke: "#000", strokeThickness: 12, font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 12, dropShadowDistance: 4 }); ach.anchor.set(0.5, 0.5); ach.x = 2048 / 2; ach.y = 400 + (i + milestones.length + viewMilestones.length) * 80; game.addChild(ach); tween(ach, { alpha: 0, y: ach.y - 100 }, { duration: 1800, onFinish: function onFinish() { ach.destroy(); } }); } } } // --- Video List UI Update --- // --- Time Update --- function updateTimeDisplay() { var h = gameHour; var hStr = (h < 10 ? "0" : "") + h + ":00"; timeTxt.setText("Day " + gameDay + ", " + hStr); } // --- Process Update --- function updateProcessBar() { // No independent loading bar on the main screen. } // --- Time Timer --- if (timeTimer) { LK.clearInterval(timeTimer); } // Helper function to process one hour of time advancement function processOneHour() { // Advance time gameHour += 1; if (gameHour >= 24) { gameHour = 0; gameDay += 1; // Record daily stats exactly once per day recordDailyStats(); // Check if it's time to change trending category // Trending category changes a random number of times every 7 to 30 days if (typeof trendingCategoryNextChangeDay === "undefined") { trendingCategoryNextChangeDay = trendingCategoryDay + 7 + Math.floor(Math.random() * 24); // 7-30 days } if (gameDay >= trendingCategoryNextChangeDay) { updateTrendingCategory(); trendingCategoryNextChangeDay = gameDay + 7 + Math.floor(Math.random() * 24); // 7-30 days } } updateTimeDisplay(); // Process logic if (timeProcess) { timeProcess.hoursLeft -= 1; updateProcessBar(); if (timeProcess.hoursLeft <= 0) { var finish = timeProcess.onFinish; // If editing, update video state if (timeProcess.type === "edit" && timeProcess.video) { timeProcess.video.state = "readyToPublish"; timeProcess.video.publishReady = true; } timeProcess = null; updateProcessBar(); updateStats(); updateVideoLists(); if (typeof finish === "function") { finish(); } } } // Per-hour video view/money/subscriber accrual if (window.uploadedVideos) { for (var v = 0; v < window.uploadedVideos.length; v++) { var vid = window.uploadedVideos[v]; // Only accrue views, money, and subs if published and not finished if (vid.state === "published" && vid.hour < vid.totalHours) { var viewsThisHour = vid.hourlyViews[vid.hour] || 0; // --- Add promote campaign views to this video if any active promote campaigns exist --- // Find all active promote campaigns for this hour and add their views to this video if the campaign is running if (window.activePromotes && window.activePromotes.length > 0) { for (var pi = 0; pi < window.activePromotes.length; pi++) { var p = window.activePromotes[pi]; if (p.finished) continue; var promoteDay = gameDay - p.startDay; var promoteHour = gameHour; if (promoteDay >= 0 && promoteDay < p.days) { var promoteViewsThisHour = p.viewsPerHour[promoteDay][promoteHour] || 0; viewsThisHour += promoteViewsThisHour; } } } // --- NEW: Instantly update subscribers and money per view --- // 1) For every 1 view, 1% chance to gain a subscriber (instantly) // 2) For every 100 views, earn 0.1 money (instantly) var subsThisHour = 0; var moneyThisHour = 0; for (var i = 0; i < viewsThisHour; i++) { if (Math.random() < 0.01) { // 1% chance per view subsThisHour += 1; } } // Each viewer gives a random amount between 0.001 and 0.01 moneyThisHour = 0; for (var vi = 0; vi < viewsThisHour; vi++) { moneyThisHour += 0.001 + Math.random() * 0.009; } vid.totalViews += viewsThisHour; vid.totalMoney += moneyThisHour; vid.totalSubs += subsThisHour; viewCount += viewsThisHour; money += moneyThisHour; subscribers += subsThisHour; vid.hour++; // Clamp to target on last hour if (vid.hour === vid.totalHours) { // Remove the video from the video list when publishing is complete window.uploadedVideos.splice(v, 1); v--; // Adjust index since we removed an item continue; // Skip further processing for this video } } } } // --- Promote Campaigns: process per hour --- if (window.activePromotes && window.activePromotes.length > 0) { for (var pi = window.activePromotes.length - 1; pi >= 0; pi--) { var p = window.activePromotes[pi]; // Determine which day/hour of campaign we are in var promoteDay = gameDay - p.startDay; var promoteHour = gameHour; if (promoteDay >= 0 && promoteDay < p.days && !p.finished) { // Show to this hour's people var viewsThisHour = p.viewsPerHour[promoteDay][promoteHour] || 0; p.shownPerHour[promoteDay][promoteHour] = viewsThisHour; // Conversion rate: use p.subRate var subsThisHour = 0; for (var vi = 0; vi < viewsThisHour; vi++) { if (Math.random() < p.subRate) subsThisHour++; } p.subsGained += subsThisHour; subscribers += subsThisHour; viewCount += viewsThisHour; // Track for stats if (!p.subsPerDay[promoteDay]) p.subsPerDay[promoteDay] = 0; p.subsPerDay[promoteDay] += subsThisHour; if (!p.viewsPerDay[promoteDay]) p.viewsPerDay[promoteDay] = 0; p.viewsPerDay[promoteDay] += viewsThisHour; // --- Update promote in-panel label values --- var totalHours = p.days * 24; var spentPerHour = p.amount / totalHours; // Defensive: never overspend if (p.spentSoFar + spentPerHour > p.amount) { spentPerHour = p.amount - p.spentSoFar; if (spentPerHour < 0) spentPerHour = 0; } p.spentSoFar += spentPerHour; // Clamp spentSoFar to not exceed amount if (p.spentSoFar > p.amount) p.spentSoFar = p.amount; p.viewsSoFar += viewsThisHour; if (typeof p.updatePromoteListLabel === "function") { p.updatePromoteListLabel(); } // If spentSoFar reached amount, mark as finished if (p.spentSoFar >= p.amount && !p.finished) { p.finished = true; // Also set lastDay to current day if not already set if (typeof p.lastDay === "undefined" || p.lastDay < gameDay) { p.lastDay = gameDay; } } } // Mark as finished if campaign is over by time if (gameDay > p.startDay + p.days - 1) { p.finished = true; } // Remove finished promotes after last day if (p.finished && gameDay > p.lastDay + 1) { // Remove label from panel if (p._promoteListLabel) { for (var li = 0; li < p._promoteListLabel.length; li++) { if (p._promoteListLabel[li] && typeof p._promoteListLabel[li].destroy === "function") { p._promoteListLabel[li].destroy(); } } p._promoteListLabel = null; } window.activePromotes.splice(pi, 1); updatePromoteListDisplay(); } } } updateStats(); updateVideoLists(); } // Timer logic for normal and double speed var doubleSpeedTimer = null; function setTimeTimer() { if (timeTimer) { LK.clearInterval(timeTimer); timeTimer = null; } if (doubleSpeedTimer) { LK.clearInterval(doubleSpeedTimer); doubleSpeedTimer = null; } // Normal speed: 1 hour every 1000ms if (timeSpeed === 1) { timeTimer = LK.setInterval(function () { if (timeSpeed !== 1 || isTimePaused) return; processOneHour(); }, 1000); } // Double speed: 1 hour every 500ms else if (timeSpeed === 2) { doubleSpeedTimer = LK.setInterval(function () { if (timeSpeed !== 2 || isTimePaused) return; processOneHour(); }, 500); } // Paused: do nothing } setTimeTimer(); // Patch time control buttons to call setTimeTimer when speed changes var oldUpdateTimeControlButtons = updateTimeControlButtons; updateTimeControlButtons = function updateTimeControlButtons() { oldUpdateTimeControlButtons(); setTimeTimer(); }; // --- Game Update Loop --- game.update = function () { // Nothing needed for now, all logic is event/click based }; // --- Touch/Drag Handling (no drag needed, but block top left 100x100) --- game.down = function (x, y, obj) { // Prevent accidental clicks in top left if (x < 100 && y < 100) { return; } }; game.move = function (x, y, obj) {}; game.up = function (x, y, obj) {}; // --- Initialize UI --- updateStats(); // Hide video list and background by default at game start videoListBg.visible = false; videoListContainer.visible = false; // --- Tutorial Items removed as requested --- // --- Promote Stats Panel (hourly breakdown) --- function showPromoteStatsPanel(promoteIdx) { if (!window.activePromotes || !window.activePromotes[promoteIdx]) return; var p = window.activePromotes[promoteIdx]; // Panel background var promoteStatsBg = LK.getAsset('studioBg', { anchorX: 0.5, anchorY: 0.5 }); promoteStatsBg.width = 1200; promoteStatsBg.height = 1200; promoteStatsBg.x = 2048 / 2; promoteStatsBg.y = 2732 / 2; promoteStatsBg.alpha = 0.98; // Title var promoteStatsTitle = new Text2("Promote Campaign Details", { size: 70, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); promoteStatsTitle.anchor.set(0.5, 0.5); promoteStatsTitle.x = promoteStatsBg.x; promoteStatsTitle.y = promoteStatsBg.y - promoteStatsBg.height / 2 + 80; // Table header var headerTxt = new Text2("Day | Hour | Views | Subs", { size: 44, fill: "#0ff", font: "Arial, Helvetica, sans-serif" }); headerTxt.anchor.set(0.5, 0.5); headerTxt.x = promoteStatsBg.x; headerTxt.y = promoteStatsTitle.y + 80; // Table rows (show up to 24 hours for each day) var tableLabels = []; var startY = headerTxt.y + 60; var rowH = 38; var maxRows = 20; var shownRows = 0; for (var d = 0; d < p.days && shownRows < maxRows; d++) { for (var h = 0; h < 24 && shownRows < maxRows; h++) { var views = p.shownPerHour[d] ? p.shownPerHour[d][h] : 0; var subs = 0; // Estimate subs for this hour (approximate, since we don't store per hour) if (views > 0) { subs = Math.floor(views * p.subRate); } var rowTxt = new Text2(d + 1 + " | " + (h < 10 ? "0" : "") + h + ":00 | " + views + " | " + subs, { size: 36, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); rowTxt.anchor.set(0.5, 0.5); rowTxt.x = promoteStatsBg.x; rowTxt.y = startY + shownRows * rowH; tableLabels.push(rowTxt); shownRows++; } } // Close button var closeStatsBtn = new GameButton(); closeStatsBtn.setButton('editBtn', 'Close', "#fff", 320, 90); closeStatsBtn.x = promoteStatsBg.x; closeStatsBtn.y = promoteStatsBg.y + promoteStatsBg.height / 2 - 80; closeStatsBtn.action = function () { promoteStatsBg.destroy(); promoteStatsTitle.destroy(); headerTxt.destroy(); closeStatsBtn.destroy(); for (var i = 0; i < tableLabels.length; i++) tableLabels[i].destroy(); }; // Add to game game.addChild(promoteStatsBg); game.addChild(promoteStatsTitle); game.addChild(headerTxt); for (var i = 0; i < tableLabels.length; i++) game.addChild(tableLabels[i]); game.addChild(closeStatsBtn); } // --- Statistics Section UI --- // Data arrays for stats (one entry per day) var statsViewsPerDay = []; var statsSubsPerDay = []; var statsMoneyPerDay = []; var statsLastDay = 0; // Statistics overlay container (hidden by default) var statsOverlay = new Container(); statsOverlay.visible = false; statsOverlay.x = 0; statsOverlay.y = 0; game.addChild(statsOverlay); // Overlay background // Move the statistics overlay 250px up, crop 10px from left/right, 200px from top/bottom var statsBgWidth = 1950 - 20; // 10px left, 10px right var statsBgHeight = 1600 - 400; // 200px top, 200px bottom var statsBg = LK.getAsset('studioBg', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 - 450 }); statsBg.width = statsBgWidth; statsBg.height = statsBgHeight; statsBg.alpha = 0.98; statsOverlay.addChild(statsBg); // Title removed as requested // --- Graph Toggle Buttons --- var statTypes = [{ key: "views", label: "Views", color: 0x00e0ff, icon: "viewersicon" }, { key: "subs", label: "Subscribers", color: 0xffe066, icon: "subIcon" }, { key: "money", label: "Money", color: 0xfa4b00, icon: "moneyIcon" }]; var statDataMap = { views: statsViewsPerDay, subs: statsSubsPerDay, money: statsMoneyPerDay }; var statLabelMap = { views: "Views per Day", subs: "Subscribers per Day", money: "Money Earned per Day" }; var statIconMap = { views: "viewersicon", subs: "subIcon", money: "moneyIcon" }; var statColorMap = { views: 0x00e0ff, subs: 0xffe066, money: 0xfa4b00 }; var selectedStatType = "views"; var statToggleBtns = []; var toggleBtnW = 260; var toggleBtnH = 80; var toggleBtnSpacing = 36; var toggleBtnStartX = 2048 / 2 - (toggleBtnW * 1.5 + toggleBtnSpacing); // Yeni statsBg yüksekliÄine gƶre toggle butonlarını hizala var toggleBtnY = statsBg.y - statsBg.height / 2 + 120; for (var i = 0; i < statTypes.length; i++) { (function (idx) { var btn = new GameButton(); btn.setButton('editBtn', statTypes[idx].label, "#fff", toggleBtnW, toggleBtnH); // Reduce label font size for statistics top buttons if (btn.label) { if (btn.label.style && typeof btn.label.style.size !== "undefined") { btn.label.style.size = 44; btn.label.dirty = true; } else if (typeof btn.label.setStyle === "function") { btn.label.setStyle({ size: 44 }); } } btn.x = toggleBtnStartX + idx * (toggleBtnW + toggleBtnSpacing); btn.y = toggleBtnY; btn.action = function () { // Deselect all for (var j = 0; j < statToggleBtns.length; j++) { statToggleBtns[j].bg.alpha = 0.7; } btn.bg.alpha = 1; selectedStatType = statTypes[idx].key; updateStatsGraphSingle(); }; // Highlight first by default btn.bg.alpha = i === 0 ? 1 : 0.7; statToggleBtns.push(btn); statsOverlay.addChild(btn); })(i); } // --- Single Graph Area --- var graphW = 1200; var graphH = 500; var graphStartX = (2048 - graphW) / 2; var graphStartY = statsBg.y - statsBg.height / 2 + 220; // Helper to draw a single stat graph function drawStatSingleGraph(container, data, color, iconAssetId, label) { if (!container.graphNodes) container.graphNodes = []; // Remove previous graph for (var i = 0; i < container.graphNodes.length; i++) { container.graphNodes[i].destroy(); } container.graphNodes = []; // Card background var cardBg = LK.getAsset('loadingbarempty', { anchorX: 0.5, anchorY: 0, x: 2048 / 2, y: graphStartY }); cardBg.width = graphW + 120; cardBg.height = graphH + 100; cardBg.alpha = 0.93; container.addChild(cardBg); container.graphNodes.push(cardBg); // Draw icon var icon = LK.getAsset(iconAssetId, { anchorX: 0.5, anchorY: 0.5, x: graphStartX - 100, y: graphStartY + 60 + graphH / 2 }); icon.width = 120; icon.height = 120; container.addChild(icon); container.graphNodes.push(icon); // Draw label var labelTxt = new Text2(label, { size: 60, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); labelTxt.anchor.set(0, 0.5); labelTxt.x = graphStartX; labelTxt.y = graphStartY + 40; container.addChild(labelTxt); container.graphNodes.push(labelTxt); // Find max value for scaling var maxVal = 1; for (var i = 0; i < data.length; i++) { if (data[i] > maxVal) maxVal = data[i]; } // Draw line graph: connect points with rectangles (simulate lines) var prevX = null, prevY = null; for (var i = 0; i < data.length; i++) { var x0 = graphStartX + i / Math.max(1, data.length - 1) * graphW; var y0 = graphStartY + 100 + graphH - data[i] / maxVal * (graphH - 20); // Draw a small circle at each data point var point = LK.getAsset('loadingbarfull', { anchorX: 0.5, anchorY: 0.5, x: x0, y: y0 }); point.width = 18; point.height = 18; point.tint = color; container.addChild(point); container.graphNodes.push(point); // Draw value label every 5 days or last if ((i % 5 === 0 || i === data.length - 1) && data[i] > 0) { var displayValue = data[i]; // If this is the money graph, format to 2 decimal places if (selectedStatType === "money") { displayValue = Math.floor(data[i] * 100) / 100; // Always show 2 decimals for money displayValue = displayValue.toFixed(2); } var valTxt = new Text2("" + displayValue, { size: 36, fill: "#fff" }); valTxt.anchor.set(0.5, 1); valTxt.x = x0; valTxt.y = y0 - 8; container.addChild(valTxt); container.graphNodes.push(valTxt); } // Draw a "line" between previous and current point using a thin rectangle if (prevX !== null && prevY !== null) { var dx = x0 - prevX; var dy = y0 - prevY; var dist = Math.sqrt(dx * dx + dy * dy); var angle = Math.atan2(dy, dx); var line = LK.getAsset('loadingbarfull', { anchorX: 0, anchorY: 0.5, x: prevX, y: prevY }); line.width = dist; line.height = 8; line.tint = color; line.rotation = angle; container.addChild(line); container.graphNodes.push(line); } prevX = x0; prevY = y0; } } // Draw the selected graph function updateStatsGraphSingle() { var key = selectedStatType; var data = statDataMap[key]; var color = statColorMap[key]; var icon = statIconMap[key]; var label = statLabelMap[key]; drawStatSingleGraph(statsOverlay, data, color, icon, label); } // Close button for stats overlay var statsCloseBtn = new GameButton(); statsCloseBtn.setButton('editBtn', 'Close', "#fff", 320, 90); statsCloseBtn.x = 2048 / 2; statsCloseBtn.y = statsBg.y + statsBg.height / 2 - 80; statsCloseBtn.action = function () { statsOverlay.visible = false; }; statsOverlay.addChild(statsCloseBtn); // Statistics Section Button removed with navigation bar // --- Track stats per day --- // Call this at the end of each day function recordDailyStats() { // Only record once per day if (statsLastDay === gameDay) { return; } statsLastDay = gameDay; statsViewsPerDay.push(viewCount); statsSubsPerDay.push(subscribers); statsMoneyPerDay.push(money); } // Record stats for day 1 at game start recordDailyStats(); // Define updatePromoteListDisplay in global scope to avoid not defined error function updatePromoteListDisplay() { // This is a stub to avoid not defined error if called outside promote panel // The real implementation is inside the promote panel logic }
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Energy bar class
var EnergyBar = Container.expand(function () {
var self = Container.call(this);
self.bg = self.attachAsset('energyBarBg', {
anchorX: 0,
anchorY: 0.5
});
self.fill = self.attachAsset('energyBarFill', {
anchorX: 0,
anchorY: 0.5
});
self.fill.x = 0;
self.bg.x = 0;
self.bg.y = 0;
self.fill.y = 0;
self.maxWidth = self.fill.width;
self.set = function (ratio) {
if (ratio < 0) {
ratio = 0;
}
if (ratio > 1) {
ratio = 1;
}
self.fill.width = self.maxWidth * ratio;
};
return self;
});
// --- Finance Panel Class ---
var FinancePanel = Container.expand(function () {
var self = Container.call(this);
// Yellow background, same size/position as computerscreen
self.bg = self.attachAsset('upgradeBtn', {
anchorX: 0.5,
anchorY: 0.5,
x: computerScreen.x,
y: computerScreen.y
});
self.bg.width = computerScreen.width;
self.bg.height = computerScreen.height;
self.bg.x = computerScreen.x;
self.bg.y = computerScreen.y;
self.bg.alpha = 0.98;
self.addChild(self.bg);
// Money text (white, large, centered)
self.moneyTxt = new Text2("", {
size: 120,
fill: "#fff",
font: "Arial, Helvetica, sans-serif",
dropShadow: true,
dropShadowColor: "#222",
dropShadowBlur: 8,
dropShadowDistance: 2
});
self.moneyTxt.anchor.set(0.5, 0.5);
self.moneyTxt.x = computerScreen.x;
self.moneyTxt.y = computerScreen.y;
self.addChild(self.moneyTxt);
// Helper to update money display
self.updateMoney = function () {
// Truncate to 2 decimals
var moneyDisplay = Math.floor(money * 100) / 100;
self.moneyTxt.setText("Güncel Para: $" + formatNumber(moneyDisplay));
};
// Update on creation
self.updateMoney();
return self;
});
// Global variable to track finance panel instance
// Button class for all clickable actions
var GameButton = Container.expand(function () {
var self = Container.call(this);
self.bg = null;
self.label = null;
self.action = null;
self.enabled = true;
self.setButton = function (assetId, labelText, color, width, height) {
self.bg = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.bg.width = width;
self.bg.height = height;
// Modern look: more pronounced rounded corners and soft drop shadow
self.bg.cornerRadius = Math.min(width, height) * 0.28;
self.bg.shadow = {
color: 0x111111,
blur: 36,
offsetX: 0,
offsetY: 16,
alpha: 0.32
};
self.label = new Text2(labelText, {
size: 80,
fill: color,
font: "Arial, Helvetica, sans-serif",
dropShadow: true,
dropShadowColor: "#222",
dropShadowBlur: 12,
dropShadowDistance: 2
});
self.label.anchor.set(0.5, 0.5);
self.addChild(self.label);
};
self.setEnabled = function (val) {
self.enabled = val;
if (self.bg) {
self.bg.alpha = val ? 1 : 0.4;
}
};
self.down = function (x, y, obj) {
if (!self.enabled) {
return;
}
if (typeof self.action === 'function') {
self.action();
}
};
return self;
});
// VideoListItem: displays a video in the list with title, state, and stats
var VideoListItem = Container.expand(function () {
var self = Container.call(this);
self.bg = self.attachAsset('loadingbarempty', {
anchorX: 0,
anchorY: 0.5
});
self.bg.width = 1200;
self.bg.height = 120;
self.bg.alpha = 0.92;
self.titleTxt = new Text2("", {
size: 56,
fill: "#fff",
font: "Arial, Helvetica, sans-serif"
});
self.titleTxt.anchor.set(0, 0.5);
self.titleTxt.x = 40;
self.titleTxt.y = 0;
self.addChild(self.titleTxt);
self.stateTxt = new Text2("", {
size: 44,
fill: "#ff0",
font: "Arial, Helvetica, sans-serif"
});
self.stateTxt.anchor.set(0, 0.5);
self.stateTxt.x = 500;
self.stateTxt.y = 0;
self.addChild(self.stateTxt);
self.statsTxt = new Text2("", {
size: 44,
fill: "#0ff",
font: "Arial, Helvetica, sans-serif"
});
self.statsTxt.anchor.set(0, 0.5);
self.statsTxt.x = 800;
self.statsTxt.y = 0;
self.addChild(self.statsTxt);
self.setVideo = function (videoObj) {
self.titleTxt.setText(videoObj.title || "Untitled");
// State: Recording, Gaining Views, Finished
if (videoObj.hour === 0 && !videoObj.finished) {
self.stateTxt.setText("Just Published");
} else if (!videoObj.finished) {
self.stateTxt.setText("Gaining Views");
} else {
self.stateTxt.setText("Finished");
}
// Stats: views, money, subs
var stats = formatNumber(videoObj.totalViews) + " views";
// Truncate money to 2 decimal digits for display in video list
var moneyDisplay = Math.floor(videoObj.totalMoney * 100) / 100;
stats += " | $" + formatNumber(moneyDisplay);
stats += " | " + formatNumber(videoObj.totalSubs) + " subs";
if (videoObj.trending) {
stats += " | š„";
}
self.statsTxt.setText(stats);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Global variable to track finance panel instance
// --- Trending Category State ---
// --- Video Categories (must be defined before use in updateTrendingCategory) ---
var financePanel = null;
var videoCategories = ["Vlog", "Challenge", "Reaction", "Tutorial", "Unboxing", "Gaming", "Music", "Comedy", "Q&A", "Other"];
var selectedCategoryIdx = 0;
// Studio background (simple box for now)
// --- Game State Variables ---
// Pick a random trending category at game start
var trendingCategoryIdx = Math.floor(Math.random() * videoCategories.length);
var trendingCategoryDay = 1; // The day this trending category started
function updateTrendingCategory() {
// Pick a new trending category index, different from the current one if possible
var oldIdx = trendingCategoryIdx;
if (videoCategories && videoCategories.length > 1) {
var newIdx;
do {
newIdx = Math.floor(Math.random() * videoCategories.length);
} while (newIdx === oldIdx);
trendingCategoryIdx = newIdx;
} else {
trendingCategoryIdx = 0;
}
trendingCategoryDay = gameDay;
// Set next change day if not already set
if (typeof trendingCategoryNextChangeDay === "undefined") {
trendingCategoryNextChangeDay = trendingCategoryDay + 7 + Math.floor(Math.random() * 24); // 7-30 days
}
}
// If the record video panel is open, update the trending label text if it exists
if (typeof isRecordPanelOpen !== "undefined" && isRecordPanelOpen && typeof categoryBtns !== "undefined") {
for (var i = 0; i < categoryBtns.length; i++) {
if (categoryBtns[i].trendingTxt) {
categoryBtns[i].trendingTxt.setText("Trending");
// Move trending label to the new trending category
if (i === trendingCategoryIdx) {
categoryBtns[i].trendingTxt.visible = true;
} else {
categoryBtns[i].trendingTxt.visible = false;
}
}
// Update button highlight for trending
if (i === trendingCategoryIdx) {
categoryBtns[i].bg.alpha = 0.95;
if (categoryBtns[i].trendingTxt) {
categoryBtns[i].trendingTxt.visible = true;
}
} else {
if (categoryBtns[i].trendingTxt) {
categoryBtns[i].trendingTxt.visible = false;
}
if (i !== selectedCategoryIdx) {
categoryBtns[i].bg.alpha = 0.7;
}
}
}
}
// Video button
// Edit button
// Promote button
// Upgrade button
// Energy bar background
// Energy bar fill
// Subscriber icon
// Money icon
// Sound for making a video
var subscribers = 0;
var viewCount = 0;
var money = 0;
var videoQuality = 1; // upgrades increase this
var editSkill = 1; // upgrades increase this
var promoteSkill = 1; // upgrades increase this
var videoCount = 0;
var upgradeCost = 20;
var upgradeLevel = 1;
// --- Time Mechanics ---
var gameHour = 8; // Start at 8:00
var gameDay = 1;
var isTimePaused = false;
var timeTimer = null;
var timeProcess = null; // {type: 'record'|'edit'|'promote', hoursLeft: int, onFinish: fn}
// --- UI Elements ---
var studioBg = LK.getAsset('studioBg', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
game.addChild(studioBg);
var phoneBg = LK.getAsset('phonebackground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
game.addChild(phoneBg);
var computerScreen = LK.getAsset('computerscreen', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 - 5,
y: 2732 / 2 - 60
});
game.addChild(computerScreen);
// --- App List inside computerscreen ---
// Each app is now inside its own invisible overlay container
var appListContainer = new Container();
var appOverlays = {}; // key: appNameLower, value: overlay Container
// Calculate app icon and background sizes for 4 per row, filling computerscreen width
var appsPerRow = 4;
var appListMarginX = 60; // margin from left/right inside computerscreen
var appListMarginY = 120; // margin from top inside computerscreen
var appListWidth = computerScreen.width - 2 * appListMarginX;
var appSpacing = 48;
var appRowSpacing = 120; // Further increased vertical spacing between rows
var appBgW = Math.floor((appListWidth - (appsPerRow - 1) * appSpacing) / appsPerRow);
var appBgH = appBgW; // make square
var appIconW = Math.floor(appBgW * 0.54);
var appIconH = appIconW;
// Align the app list to the left edge inside computerscreen
var appListStartX = computerScreen.x - computerScreen.width / 2 + appListMarginX + appBgW / 2;
var appListY = computerScreen.y - computerScreen.height / 2 + appListMarginY + appBgH / 2;
// Move the appListContainer visually inside the computerscreen and align to top-left
appListContainer.x = computerScreen.width / -2 + appListMarginX + appBgW / 2;
appListContainer.y = computerScreen.height / -2 + appListMarginY + appBgH / 2;
// Helper to create an overlay for a given app
function createAppOverlay(appNameLower, idx) {
var overlay = new Container();
overlay.appNameLower = appNameLower;
// Calculate row/col for 4 per row
var row = Math.floor(idx / appsPerRow);
var col = idx % appsPerRow;
var bgX = col * (appBgW + appSpacing);
var bgY = row * (appBgH + appRowSpacing);
// Background
var bg = LK.getAsset('whitebackgroundrounded', {
anchorX: 0.5,
anchorY: 0.5,
x: bgX,
y: bgY
});
bg.width = appBgW;
bg.height = appBgH;
overlay.addChild(bg);
// Icon
var iconAssetId = "youtube";
if (appNameLower === "play store") iconAssetId = "playstore";
if (appNameLower === "editing") iconAssetId = "edit";
if (appNameLower === "statistics") iconAssetId = "statistics";
if (appNameLower === "promote") iconAssetId = "promotebutton";
if (appNameLower === "record") iconAssetId = "recordbutton";
if (appNameLower === "finance") iconAssetId = "financalbutton";
var icon = LK.getAsset(iconAssetId, {
anchorX: 0.5,
anchorY: 0.5,
x: bgX,
y: bgY
});
if (appNameLower === "editing") {
icon.width = appIconW * 1.5;
icon.height = appIconH * 1.5;
} else {
icon.width = appIconW;
icon.height = appIconH;
}
overlay.addChild(icon);
// Label
var label = new Text2(appNameLower, {
size: 54,
fill: "#fff",
font: "Arial, Helvetica, sans-serif"
});
label.anchor.set(0.5, 0);
label.x = bgX;
label.y = bgY + appBgH / 2 + 18;
overlay.addChild(label);
// Store for later reference
overlay._appBg = bg;
overlay._appIcon = icon;
overlay._appLabel = label;
// Make Play Store app icon interactive to open Play Store overlay
if (appNameLower === "play store") {
overlay.interactive = true;
overlay.buttonMode = true;
overlay.down = function (x, y, obj) {
showPlayStoreOverlay();
};
// Also make icon and bg interactive for better UX
icon.interactive = true;
icon.buttonMode = true;
icon.down = function (x, y, obj) {
showPlayStoreOverlay();
};
bg.interactive = true;
bg.buttonMode = true;
bg.down = function (x, y, obj) {
showPlayStoreOverlay();
};
}
// Make Finance app icon interactive to open finance panel
if (appNameLower === "finance") {
overlay.interactive = true;
overlay.buttonMode = true;
overlay.down = function (x, y, obj) {
// Defensive: destroy previous if exists
if (financePanel && typeof financePanel.destroy === "function") {
try {
financePanel.destroy();
} catch (e) {}
financePanel = null;
}
financePanel = new FinancePanel();
// Insert financePanel above computerscreen (so it appears on top of computerscreen, but below everything else)
var computerScreenIdx = game.children.indexOf(computerScreen);
if (computerScreenIdx !== -1) {
game.addChildAt(financePanel, computerScreenIdx + 1);
} else {
game.addChild(financePanel);
}
// Always update money display
if (financePanel && typeof financePanel.updateMoney === "function") {
financePanel.updateMoney();
}
};
icon.interactive = true;
icon.buttonMode = true;
icon.down = overlay.down;
bg.interactive = true;
bg.buttonMode = true;
bg.down = overlay.down;
}
// Make Editing app icon interactive to open the edit panel (like editBtn)
if (appNameLower === "editing") {
overlay.interactive = true;
overlay.buttonMode = true;
overlay.down = function (x, y, obj) {
if (typeof editBtn !== "undefined" && editBtn && typeof editBtn.action === "function") {
editBtn.action();
}
};
icon.interactive = true;
icon.buttonMode = true;
icon.down = function (x, y, obj) {
if (typeof editBtn !== "undefined" && editBtn && typeof editBtn.action === "function") {
editBtn.action();
}
};
bg.interactive = true;
bg.buttonMode = true;
bg.down = function (x, y, obj) {
if (typeof editBtn !== "undefined" && editBtn && typeof editBtn.action === "function") {
editBtn.action();
}
};
}
// Make YouTube app icon interactive to open video panel (video list)
if (appNameLower === "youtube") {
overlay.interactive = true;
overlay.buttonMode = true;
overlay.down = function (x, y, obj) {
// Defensive: re-add videoListBg and videoListContainer if destroyed by closeAllBtn
if (!game.children.includes(videoListBg)) {
game.addChild(videoListBg);
}
if (!game.children.includes(videoListContainer)) {
game.addChild(videoListContainer);
}
videoListBg.visible = true;
videoListContainer.visible = true;
statsOverlay.visible = false;
};
// Also make icon and bg interactive for better UX
icon.interactive = true;
icon.buttonMode = true;
icon.down = function (x, y, obj) {
// Defensive: re-add videoListBg and videoListContainer if destroyed by closeAllBtn
if (!game.children.includes(videoListBg)) {
game.addChild(videoListBg);
}
if (!game.children.includes(videoListContainer)) {
game.addChild(videoListContainer);
}
videoListBg.visible = true;
videoListContainer.visible = true;
statsOverlay.visible = false;
};
bg.interactive = true;
bg.buttonMode = true;
bg.down = function (x, y, obj) {
// Defensive: re-add videoListBg and videoListContainer if destroyed by closeAllBtn
if (!game.children.includes(videoListBg)) {
game.addChild(videoListBg);
}
if (!game.children.includes(videoListContainer)) {
game.addChild(videoListContainer);
}
videoListBg.visible = true;
videoListContainer.visible = true;
statsOverlay.visible = false;
};
}
// Make Record app icon interactive to open the record panel
if (appNameLower === "record") {
overlay.interactive = true;
overlay.buttonMode = true;
overlay.down = function (x, y, obj) {
if (typeof makeVideoBtn !== "undefined" && makeVideoBtn && typeof makeVideoBtn.action === "function") {
makeVideoBtn.action();
}
};
icon.interactive = true;
icon.buttonMode = true;
icon.down = function (x, y, obj) {
if (typeof makeVideoBtn !== "undefined" && makeVideoBtn && typeof makeVideoBtn.action === "function") {
makeVideoBtn.action();
}
};
bg.interactive = true;
bg.buttonMode = true;
bg.down = function (x, y, obj) {
if (typeof makeVideoBtn !== "undefined" && makeVideoBtn && typeof makeVideoBtn.action === "function") {
makeVideoBtn.action();
}
};
}
return overlay;
}
// Initial overlays for installed apps
// Always keep the app list in a fixed order: youtube, play store, editing, statistics, promote, record, finance
var initialApps = [{
name: "youtube"
}, {
name: "play store"
}, {
name: "editing"
}, {
name: "statistics"
}, {
name: "promote"
}, {
name: "record"
}, {
name: "finance"
}];
// Helper to re-render app overlays in correct order and position
function updateAppListOrder() {
// Remove all overlays from container
while (appListContainer.children.length > 0) {
appListContainer.children[0].destroy();
}
// Re-add overlays in fixed order, skipping nulls
var visibleIdx = 0;
for (var i = 0; i < initialApps.length; i++) {
var appNameLower = initialApps[i].name;
var overlay = appOverlays[appNameLower];
if (overlay) {
// Update position for this index (4 per row)
var row = Math.floor(visibleIdx / appsPerRow);
var col = visibleIdx % appsPerRow;
var bgX = col * (appBgW + appSpacing);
var bgY = row * (appBgH + appRowSpacing);
// Defensive: update all children positions (bg, icon, label)
if (overlay._appBg) {
overlay._appBg.x = bgX;
overlay._appBg.y = bgY;
}
if (overlay._appIcon) {
overlay._appIcon.x = bgX;
overlay._appIcon.y = bgY;
}
if (overlay._appLabel) {
overlay._appLabel.x = bgX;
overlay._appLabel.y = bgY + appBgH / 2 + 18;
}
appListContainer.addChild(overlay);
visibleIdx++;
}
}
}
// Create overlays for all initial apps
for (var i = 0; i < initialApps.length; i++) {
var appNameLower = initialApps[i].name;
var overlay = createAppOverlay(appNameLower, i);
appOverlays[appNameLower] = overlay;
}
// Initial render
updateAppListOrder();
// --- Universal Close Button (Return to ComputerScreen) ---
var closeAllBtn = new GameButton();
closeAllBtn.setButton('editBtn', 'Return', "#fff", 420, 120);
// Place the button below the computerscreen, centered horizontally
closeAllBtn.x = computerScreen.x;
closeAllBtn.y = computerScreen.y + computerScreen.height / 2 + 210; // 210px below the bottom edge of computerscreen (80+130)
closeAllBtn.bg.height += 40; // Increase height by 20px on top and 20px on bottom
if (closeAllBtn.label) {
closeAllBtn.label.y = 0; // recenter label after height change
}
// Make the button invisible but always clickable
closeAllBtn.bg.alpha = 0;
if (closeAllBtn.label) closeAllBtn.label.visible = false;
closeAllBtn.interactive = true;
closeAllBtn.buttonMode = true;
closeAllBtn.action = function () {
// Remove all children except:
// - computerscreen
// - appListContainer (inside computerscreen)
// - closeAllBtn
// - subIcon, subTxt, viewIcon, viewTxt, moneyIcon, moneyTxt
// - timeTxt, pauseBtn, resumeBtn, doubleSpeedBtn
// - phoneBg
for (var i = game.children.length - 1; i >= 0; i--) {
var child = game.children[i];
if (child === computerScreen || child === appListContainer || child === closeAllBtn || child === subIcon || child === subTxt || child === viewIcon || child === viewTxt || child === moneyIcon || child === moneyTxt || child === timeTxt || child === pauseBtn || child === resumeBtn || child === doubleSpeedBtn || child === phoneBg || child === studioBg) continue;
try {
child.destroy();
} catch (e) {}
}
// Destroy finance panel if open
if (typeof financePanel !== "undefined" && financePanel) {
try {
financePanel.destroy();
} catch (e) {}
financePanel = null;
}
// Hide overlays if they are not destroyed
if (typeof videoListBg !== "undefined") videoListBg.visible = false;
if (typeof videoListContainer !== "undefined") videoListContainer.visible = false;
if (typeof statsOverlay !== "undefined") statsOverlay.visible = false;
// Remove playstore overlay and all its children if open
if (typeof playStoreOverlay !== "undefined" && playStoreOverlay) {
if (playStoreOverlay.children && playStoreOverlay.children.length) {
for (var i = playStoreOverlay.children.length - 1; i >= 0; i--) {
try {
playStoreOverlay.children[i].destroy();
} catch (e) {}
}
}
if (typeof psListContainer !== "undefined" && psListContainer) {
if (psListContainer.children && psListContainer.children.length) {
for (var i = psListContainer.children.length - 1; i >= 0; i--) {
try {
psListContainer.children[i].destroy();
} catch (e) {}
}
}
try {
psListContainer.destroy();
} catch (e) {}
psListContainer = null;
}
if (playStoreOverlay.children && playStoreOverlay.children.length) {
for (var i = playStoreOverlay.children.length - 1; i >= 0; i--) {
try {
playStoreOverlay.children[i].destroy();
} catch (e) {}
}
}
try {
playStoreOverlay.destroy();
} catch (e) {}
playStoreOverlay = null;
}
// Remove edit panel if open
var editPanelElements = ["editPanelBg", "editPanelTitle", "loadingBarBg", "loadingBarFill", "editPanelBtn", "closeEditBtn"];
for (var i = 0; i < editPanelElements.length; i++) {
if (typeof window[editPanelElements[i]] !== "undefined" && window[editPanelElements[i]]) {
try {
window[editPanelElements[i]].destroy();
} catch (e) {}
window[editPanelElements[i]] = null;
}
}
// Remove record panel if open (deduplicated block)
if (typeof isRecordPanelOpen !== "undefined" && isRecordPanelOpen) {
var recordPanelElements = ["panelBg", "panelText", "confirmBtn", "closeBtn", "titleInputBg", "titleInputTxt", "randomBtn"];
for (var i = 0; i < recordPanelElements.length; i++) {
if (typeof window[recordPanelElements[i]] !== "undefined" && window[recordPanelElements[i]]) {
try {
window[recordPanelElements[i]].destroy();
} catch (e) {}
window[recordPanelElements[i]] = null;
}
}
// Destroy all category buttons and trending labels
if (typeof categoryBtns !== "undefined" && categoryBtns.length) {
for (var i = 0; i < categoryBtns.length; i++) {
if (categoryBtns[i]) {
if (categoryBtns[i].trendingTxt) {
try {
categoryBtns[i].trendingTxt.destroy();
} catch (e) {}
categoryBtns[i].trendingTxt = null;
}
try {
categoryBtns[i].destroy();
} catch (e) {}
}
}
}
isRecordPanelOpen = false;
}
// Remove promote panel if open
if (typeof game.promotePanelOpen !== "undefined" && game.promotePanelOpen) {
var promotePanelElements = ["promotePanelBg", "promoteTitle", "moneySliderBg", "moneySliderFill", "moneySliderHandle", "moneyInputTxt", "daysSliderBg", "daysSliderFill", "daysSliderHandle", "daysInputTxt", "estViewsTxt", "confirmPromoteBtn", "closePromoteBtn"];
for (var i = 0; i < promotePanelElements.length; i++) {
if (typeof window[promotePanelElements[i]] !== "undefined" && window[promotePanelElements[i]]) {
try {
window[promotePanelElements[i]].destroy();
} catch (e) {}
window[promotePanelElements[i]] = null;
}
}
// Destroy promote list labels
if (typeof promoteListLabels !== "undefined" && promoteListLabels.length) {
for (var i = 0; i < promoteListLabels.length; i++) {
for (var j = 0; j < promoteListLabels[i].length; j++) {
if (promoteListLabels[i][j]) {
try {
promoteListLabels[i][j].destroy();
} catch (e) {}
}
}
}
}
game.promotePanelOpen = false;
}
// Remove promote stats panel if open
if (typeof game.children !== "undefined") {
for (var i = game.children.length - 1; i >= 0; i--) {
var child = game.children[i];
if (child && child._isPromoteStatsPanel) {
try {
child.destroy();
} catch (e) {}
}
}
}
};
// Add the button to the game
game.addChild(closeAllBtn);
// (Removed: duplicate app list alignment code, now handled by appListContainer.x/y and createAppOverlay)
// --- Play Store Fullscreen Overlay Logic ---
var playStoreOverlay = null;
function showPlayStoreOverlay() {
if (playStoreOverlay) return;
// Overlay background
playStoreOverlay = LK.getAsset('playstoreWhiteBg', {
anchorX: 0.5,
anchorY: 0.5,
x: computerScreen.x,
y: computerScreen.y
});
// Restrict overlay size to exactly match computerscreen
playStoreOverlay.width = computerScreen.width;
playStoreOverlay.height = computerScreen.height;
playStoreOverlay.alpha = 1;
// Remove playStoreOverlay if already present (defensive, should not happen)
if (game.children.indexOf(playStoreOverlay) !== -1) {
playStoreOverlay.destroy();
}
// Insert playStoreOverlay so it is always below phoneBg but above computerscreen
var phoneBgIdx = game.children.indexOf(phoneBg);
var computerScreenIdx = game.children.indexOf(computerScreen);
if (phoneBgIdx !== -1 && computerScreenIdx !== -1) {
// Insert just before phoneBg, but after computerscreen
// phoneBgIdx is the index of phoneBg, so insert at phoneBgIdx (which will be before phoneBg)
// But if computerscreen is after phoneBg, adjust to insert after computerscreen
var insertIdx = phoneBgIdx;
if (computerScreenIdx >= phoneBgIdx) {
// If computerscreen is after phoneBg, insert after computerscreen
insertIdx = computerScreenIdx + 1;
} else if (computerScreenIdx < phoneBgIdx - 1) {
// If computerscreen is before phoneBg, but not immediately before, insert just before phoneBg
insertIdx = phoneBgIdx;
} else {
// If computerscreen is immediately before phoneBg, insert at phoneBgIdx (between them)
insertIdx = phoneBgIdx;
}
game.addChildAt(playStoreOverlay, insertIdx);
} else if (phoneBgIdx !== -1) {
// Fallback: insert just below phoneBg
game.addChildAt(playStoreOverlay, phoneBgIdx);
} else if (computerScreenIdx !== -1) {
// Fallback: insert just above computerscreen
game.addChildAt(playStoreOverlay, computerScreenIdx + 1);
} else {
// Fallback: add to top
game.addChild(playStoreOverlay);
}
// --- Play Store App List Data ---
// Each app: { name, description, sizeMB, publisher, installed }
var playStoreApps = [{
name: "YouTube",
description: "Watch, upload, and share videos with the world.",
sizeMB: 120,
publisher: "RiftGames",
installed: true
}, {
name: "Editing",
description: "Edit your videos with powerful tools.",
sizeMB: 95,
publisher: "RiftGames",
installed: true
}, {
name: "Statistics",
description: "Track your channel's growth and performance.",
sizeMB: 40,
publisher: "RiftGames",
installed: false
}, {
name: "Promote",
description: "Promote your channel to reach more viewers.",
sizeMB: 60,
publisher: "RiftGames",
installed: false
}, {
name: "Record",
description: "Record new videos for your channel.",
sizeMB: 80,
publisher: "RiftGames",
installed: false
}, {
name: "Finance",
description: "Manage your channel's finances and earnings.",
sizeMB: 55,
publisher: "RiftGames",
installed: false
}];
// --- Play Store Title Removed as requested ---
// --- App List Container ---
// The app list container is positioned at (0,0) inside playStoreOverlay, but all its children are positioned as if inside computerscreen
var psListContainer = new Container();
// Align app list to top-left of playStoreOverlay, shifted 650px to the left and 1000px upward
psListContainer.x = -650;
psListContainer.y = -1000;
playStoreOverlay.addChild(psListContainer);
// --- Make Play Store app list scrollable vertically ---
// Variables for scroll state
var psListScrollY = psListContainer.y;
var psListDragStartY = 0;
var psListPointerStartY = 0;
var psListDragging = false;
var psListMinY = -1000;
var psListMaxY = -1000;
var psListHeight = 0;
// Calculate total height of app list after rendering
// (We will update psListHeight after rendering the app cards below)
// Touch/drag logic for vertical scrolling
playStoreOverlay.interactive = true;
playStoreOverlay.buttonMode = false;
playStoreOverlay.down = function (x, y, obj) {
// Only start drag if inside the app list area
var localY = y - playStoreOverlay.y + playStoreOverlay.height / 2;
// Accept drag anywhere on overlay for now
psListDragging = true;
psListPointerStartY = y;
psListDragStartY = psListContainer.y;
};
playStoreOverlay.move = function (x, y, obj) {
if (psListDragging) {
var dy = y - psListPointerStartY;
var newY = psListDragStartY + dy;
// Clamp scroll to min/max
if (newY > psListMaxY) newY = psListMaxY;
if (newY < psListMinY) newY = psListMinY;
psListContainer.y = newY;
psListScrollY = newY;
}
};
playStoreOverlay.up = function (x, y, obj) {
psListDragging = false;
};
// Also allow scrolling by dragging on the app list container itself
psListContainer.interactive = true;
psListContainer.buttonMode = false;
psListContainer.down = function (x, y, obj) {
psListDragging = true;
psListPointerStartY = y;
psListDragStartY = psListContainer.y;
};
psListContainer.move = function (x, y, obj) {
if (psListDragging) {
var dy = y - psListPointerStartY;
var newY = psListDragStartY + dy;
if (newY > psListMaxY) newY = psListMaxY;
if (newY < psListMinY) newY = psListMinY;
psListContainer.y = newY;
psListScrollY = newY;
}
};
psListContainer.up = function (x, y, obj) {
psListDragging = false;
};
// Helper for global-to-overlay-local positioning
function getComputerScreenLocal(x, y) {
// Convert a global (game) x/y to local coordinates inside playStoreOverlay, as if overlay is at computerscreen
return {
x: x - (computerScreen.x - computerScreen.width / 2),
y: y - (computerScreen.y - computerScreen.height / 2)
};
}
var appCardW = computerScreen.width - 160;
var appCardH = 320;
var appCardSpacing = 40;
var iconSize = 160;
// --- Determine installed apps from computerscreen ---
var installedAppNames = [];
for (var key in appOverlays) {
if (appOverlays[key]) installedAppNames.push(key);
}
// --- App List Rendering ---
// Only show apps that are not installed as Download, and installed as Delete
var filteredPlayStoreApps = [];
for (var i = 0; i < playStoreApps.length; i++) {
var appNameLower = (playStoreApps[i].name || "").toLowerCase();
var isInstalled = false;
for (var j = 0; j < installedAppNames.length; j++) {
if (installedAppNames[j] === appNameLower) {
isInstalled = true;
break;
}
}
// Always show all apps, but set .installed property accordingly
playStoreApps[i].installed = isInstalled;
filteredPlayStoreApps.push(playStoreApps[i]);
}
var numApps = filteredPlayStoreApps.length;
var totalListHeight = numApps * appCardH + (numApps - 1) * appCardSpacing;
for (var i = 0; i < filteredPlayStoreApps.length; i++) {
(function (idx) {
var app = filteredPlayStoreApps[idx];
// Card background, stack from top-left
var cardBg = LK.getAsset('playstoreWhiteBg', {
anchorX: 0,
anchorY: 0,
x: 0,
y: idx * (appCardH + appCardSpacing)
});
cardBg.width = appCardW;
cardBg.height = appCardH;
cardBg.alpha = 1;
cardBg.tint = 0xffffff; // Always white background for app card
psListContainer.addChild(cardBg);
// App icon (logo only, no background)
var iconAssetId = "youtube";
if (app.name === "Play Store") iconAssetId = "playstore";
if (app.name === "Editing") iconAssetId = "edit";
if (app.name === "Statistics") iconAssetId = "statistics";
if (app.name === "Promote") iconAssetId = "promotebutton";
if (app.name === "Record") iconAssetId = "recordbutton";
if (app.name === "Finance") iconAssetId = "financalbutton";
var appIcon = LK.getAsset(iconAssetId, {
anchorX: 0.5,
anchorY: 0.5,
x: cardBg.x + iconSize / 2 + 36,
y: cardBg.y + appCardH / 2
});
appIcon.width = iconSize;
appIcon.height = iconSize;
psListContainer.addChild(appIcon);
// App name
var nameTxt = new Text2(app.name, {
size: 64,
fill: "#222",
font: "Arial, Helvetica, sans-serif"
});
nameTxt.anchor.set(0, 0);
nameTxt.x = cardBg.x + iconSize + 80;
nameTxt.y = cardBg.y + 36;
psListContainer.addChild(nameTxt);
// Publisher
var publisherTxt = new Text2("by " + app.publisher, {
size: 38,
fill: "#888",
font: "Arial, Helvetica, sans-serif"
});
publisherTxt.anchor.set(0, 0);
publisherTxt.x = nameTxt.x;
publisherTxt.y = nameTxt.y + nameTxt.height + 2;
psListContainer.addChild(publisherTxt);
// Description
var descTxt = new Text2(app.description, {
size: 44,
fill: "#444",
font: "Arial, Helvetica, sans-serif"
});
descTxt.anchor.set(0, 0);
descTxt.x = nameTxt.x;
descTxt.y = publisherTxt.y + publisherTxt.height + 8;
psListContainer.addChild(descTxt);
// Size
var sizeTxt = new Text2(app.sizeMB + " MB", {
size: 38,
fill: "#0aa",
font: "Arial, Helvetica, sans-serif"
});
sizeTxt.anchor.set(0, 0);
sizeTxt.x = nameTxt.x;
sizeTxt.y = descTxt.y + descTxt.height + 8;
psListContainer.addChild(sizeTxt);
// Install/Delete/Download button
var appBtn = new GameButton();
var isInstalled = !!app.installed;
// Helper to update button appearance and action
function updateAppBtn() {
// Move button lower in the card (move 120px lower than center, was 60px)
appBtn.x = cardBg.x + appCardW - 180;
appBtn.y = cardBg.y + appCardH / 2 + 120;
// Remove previous custom children if any
if (appBtn._customBg) {
appBtn._customBg.destroy();
appBtn._customBg = null;
}
if (appBtn._customIcon) {
appBtn._customIcon.destroy();
appBtn._customIcon = null;
}
if (appBtn.label) appBtn.label.visible = false;
if (isInstalled) {
// DELETE BUTTON: redbackground + deletebutton icon
var bg = LK.getAsset('redbackground', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0
});
bg.width = 260;
bg.height = 90;
appBtn.addChild(bg);
appBtn._customBg = bg;
var icon = LK.getAsset('deletebutton', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0
});
// Fit icon inside button, keep aspect ratio
var scale = Math.min((bg.width - 32) / icon.width, (bg.height - 32) / icon.height, 1);
icon.width = icon.width * scale;
icon.height = icon.height * scale;
appBtn.addChild(icon);
appBtn._customIcon = icon;
appBtn.setEnabled(true);
appBtn.action = function () {
isInstalled = false;
app.installed = false;
updateAppBtn();
// Remove overlay from computerscreen UI
var appNameLower = (app.name || "").toLowerCase();
if (appOverlays[appNameLower]) {
appListContainer.removeChild(appOverlays[appNameLower]);
if (typeof appOverlays[appNameLower].destroy === "function") {
appOverlays[appNameLower].destroy();
}
appOverlays[appNameLower] = null;
// After uninstall, update app list order
if (typeof updateAppListOrder === "function") updateAppListOrder();
}
};
} else {
// DOWNLOAD BUTTON: bluebackground + downloadbutton icon
var bg = LK.getAsset('bluebackground', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0
});
bg.width = 260;
bg.height = 90;
appBtn.addChild(bg);
appBtn._customBg = bg;
var icon = LK.getAsset('downloadbutton', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0
});
// Fit icon inside button, keep aspect ratio
var scale = Math.min((bg.width - 32) / icon.width, (bg.height - 32) / icon.height, 1);
icon.width = icon.width * scale;
icon.height = icon.height * scale;
appBtn.addChild(icon);
appBtn._customIcon = icon;
appBtn.setEnabled(true);
appBtn.action = function () {
// Prevent double install
if (isInstalled) return;
// Show loading bar overlay on the app card
var loadingBarBg = LK.getAsset('loadingbarempty', {
anchorX: 0.5,
anchorY: 0.5,
x: cardBg.x + appCardW / 2,
y: cardBg.y + appCardH - 80
});
loadingBarBg.width = 420;
loadingBarBg.height = 48;
loadingBarBg.alpha = 0.92;
psListContainer.addChild(loadingBarBg);
var loadingBarFill = LK.getAsset('loadingbarfull', {
anchorX: 0,
anchorY: 0.5,
x: loadingBarBg.x - loadingBarBg.width / 2 + 4,
y: loadingBarBg.y
});
loadingBarFill.width = 0;
loadingBarFill.height = 36;
loadingBarFill.tint = 0x2196f3; // blue
psListContainer.addChild(loadingBarFill);
// Disable the button during loading
appBtn.setEnabled(false);
// Animate loading bar fill over 1.2 seconds
var loadingDuration = 1200;
tween(loadingBarFill, {
width: loadingBarBg.width - 8
}, {
duration: loadingDuration,
easing: tween.cubicOut,
onFinish: function onFinish() {
// Remove loading bar
loadingBarBg.destroy();
loadingBarFill.destroy();
// Actually install the app
isInstalled = true;
app.installed = true;
updateAppBtn();
// Add overlay to computerscreen UI (appListContainer) if not already present
var appNameLower = (app.name || "").toLowerCase();
if (!appOverlays[appNameLower]) {
var overlay = createAppOverlay(appNameLower, idx);
appOverlays[appNameLower] = overlay;
}
// After install, update app list order
if (typeof updateAppListOrder === "function") updateAppListOrder();
}
});
};
}
// Hide label if button is not enabled (should not show Download/Delete text if not visible)
if (!appBtn.enabled && appBtn.label) appBtn.label.visible = false;
}
// Initial setup
updateAppBtn();
psListContainer.addChild(appBtn);
})(i);
}
// --- Set scroll bounds for Play Store app list after rendering ---
// The visible area for the app list is the height of playStoreOverlay (== computerscreen.height)
psListHeight = totalListHeight;
var visibleHeight = playStoreOverlay.height - 120; // 60px margin top/bottom
// The minimum y is so the last card is just visible at the bottom
psListMinY = Math.min(-1000, -1000 - (psListHeight - visibleHeight));
psListMaxY = -1000; // Topmost position (default)
psListContainer.y = psListMaxY;
psListScrollY = psListMaxY;
}
// Add the app list container as a child of computerscreen (so it's visually inside)
computerScreen.addChild(appListContainer);
// Place the videos, record, edit, promote, and statistics buttons equally at the bottom of the computerscreen, no space between them.
var numBtns = 5;
var btnW = computerScreen.width / numBtns;
var btnH = 120;
var csLeft = computerScreen.x - computerScreen.width / 2;
var csBottom = computerScreen.y + computerScreen.height / 2;
// Videos Button removed as requested
// Helper to hide video list
function hideVideoList() {
videoListBg.visible = false;
videoListContainer.visible = false;
}
// Record Button
var recordVideoBtn = new GameButton();
recordVideoBtn.setButton('promoteBtn', 'Record', "#fff", btnW, btnH);
recordVideoBtn.x = csLeft + btnW * 1.5;
recordVideoBtn.y = csBottom - btnH / 2;
recordVideoBtn.action = function () {
hideVideoList();
if (typeof makeVideoBtn.action === "function") {
makeVideoBtn.action();
}
};
game.addChild(recordVideoBtn);
// Edit Button
var editBtn = new GameButton();
editBtn.setButton('editBtn', 'Edit', "#fff", btnW, btnH);
editBtn.x = csLeft + btnW * 2.5;
editBtn.y = csBottom - btnH / 2;
editBtn.action = function () {
hideVideoList();
// Only allow editing if there is a video in 'recorded' state and not finished, and no process is running
if (timeProcess) return;
if (!window.uploadedVideos) {
// Show message: "You must record a video first!"
var msg = new Text2("You must record a video first!", {
size: 72,
fill: "#fff",
font: "Arial, Helvetica, sans-serif",
dropShadow: true,
dropShadowColor: "#222",
dropShadowBlur: 8,
dropShadowDistance: 2
});
msg.anchor.set(0.5, 0.5);
msg.x = 2048 / 2;
msg.y = 2732 / 2;
game.addChild(msg);
tween(msg, {
alpha: 0,
y: msg.y - 80
}, {
duration: 1600,
onFinish: function onFinish() {
msg.destroy();
}
});
return;
}
var editIdx = -1;
for (var i = 0; i < window.uploadedVideos.length; i++) {
if (window.uploadedVideos[i].state === "recorded" && !window.uploadedVideos[i].finished) {
editIdx = i;
break;
}
}
if (editIdx === -1) {
// Show message: "You must record a video first!"
var msg = new Text2("You must record a video first!", {
size: 72,
fill: "#fff",
font: "Arial, Helvetica, sans-serif",
dropShadow: true,
dropShadowColor: "#222",
dropShadowBlur: 8,
dropShadowDistance: 2
});
msg.anchor.set(0.5, 0.5);
msg.x = 2048 / 2;
msg.y = 2732 / 2;
game.addChild(msg);
tween(msg, {
alpha: 0,
y: msg.y - 80
}, {
duration: 1600,
onFinish: function onFinish() {
msg.destroy();
}
});
return;
}
// Open edit panel
var editPanelBg = LK.getAsset('studioBg', {
anchorX: 0.5,
anchorY: 0.5
});
// Make edit panel exactly match computerscreen size and position
editPanelBg.width = computerScreen.width;
editPanelBg.height = computerScreen.height;
editPanelBg.x = computerScreen.x;
editPanelBg.y = computerScreen.y;
editPanelBg.alpha = 0.98;
var editPanelTitle = new Text2("Edit Video", {
size: 90,
fill: "#fff",
font: "Arial, Helvetica, sans-serif",
dropShadow: true,
dropShadowColor: "#222",
dropShadowBlur: 8,
dropShadowDistance: 2
});
editPanelTitle.anchor.set(0.5, 0.5);
editPanelTitle.x = editPanelBg.x;
editPanelTitle.y = editPanelBg.y - editPanelBg.height / 2 + 120;
// Loading bar background
var loadingBarBg = LK.getAsset('loadingbarempty', {
anchorX: 0.5,
anchorY: 0.5
});
loadingBarBg.width = 800;
loadingBarBg.height = 80;
loadingBarBg.x = editPanelBg.x;
loadingBarBg.y = editPanelBg.y;
// Loading bar fill
var loadingBarFill = LK.getAsset('loadingbarfull', {
anchorX: 0,
anchorY: 0.5
});
loadingBarFill.width = 0;
loadingBarFill.height = 64;
loadingBarFill.x = loadingBarBg.x - loadingBarBg.width / 2 + 4;
loadingBarFill.y = loadingBarBg.y;
// Edit button (just for visual, no action)
var editPanelBtn = new GameButton();
editPanelBtn.setButton('editBtn', 'Edit', "#fff", 400, 120);
editPanelBtn.x = editPanelBg.x;
editPanelBtn.y = loadingBarBg.y + 160;
editPanelBtn.setEnabled(false);
// Close (X) button
var closeEditBtn = new Text2("Ć", {
size: 120,
fill: "#fff",
font: "Arial, Helvetica, sans-serif",
dropShadow: true,
dropShadowColor: "#222",
dropShadowBlur: 8,
dropShadowDistance: 2
});
closeEditBtn.anchor.set(0.5, 0.5);
closeEditBtn.x = editPanelBg.x + editPanelBg.width / 2 - 80;
closeEditBtn.y = editPanelBg.y - editPanelBg.height / 2 + 80;
closeEditBtn.interactive = true;
closeEditBtn.buttonMode = true;
closeEditBtn.down = function () {
// Do not allow closing while editing
};
// Add to game
game.addChild(editPanelBg);
game.addChild(editPanelTitle);
game.addChild(loadingBarBg);
game.addChild(loadingBarFill);
game.addChild(editPanelBtn);
game.addChild(closeEditBtn);
// Start editing process for this video
var editVideo = window.uploadedVideos[editIdx];
var totalEdit = editVideo.editHoursLeft || 5;
var hoursLeft = totalEdit;
timeProcess = {
type: 'edit',
hoursLeft: totalEdit,
total: totalEdit,
video: editVideo,
onFinish: function onFinish() {
// Mark video as ready to publish
editVideo.state = "readyToPublish";
editVideo.publishReady = true;
updateVideoLists();
// Remove edit panel
editPanelBg.destroy();
editPanelTitle.destroy();
loadingBarBg.destroy();
loadingBarFill.destroy();
editPanelBtn.destroy();
closeEditBtn.destroy();
}
};
// Animate loading bar fill
var lastEditBarWidth = 0;
var editInterval = LK.setInterval(function () {
if (!timeProcess || timeProcess.type !== 'edit') {
LK.clearInterval(editInterval);
return;
}
var progress = 1 - timeProcess.hoursLeft / (timeProcess.total || 1);
var targetWidth = (loadingBarBg.width - 8) * Math.max(0, Math.min(1, progress));
// Only tween if changed
if (Math.abs(targetWidth - lastEditBarWidth) > 1) {
tween(loadingBarFill, {
width: targetWidth
}, {
duration: 400,
easing: tween.cubicOut
});
lastEditBarWidth = targetWidth;
}
if (timeProcess.hoursLeft <= 0) {
LK.clearInterval(editInterval);
}
}, 100);
};
game.addChild(editBtn);
// Promote Button
var promoteBtn = new GameButton();
promoteBtn.setButton('promoteBtn', 'Promote', "#fff", btnW, btnH);
// Reduce label font size for promote button
if (promoteBtn.label) {
if (promoteBtn.label.style && typeof promoteBtn.label.style.size !== "undefined") {
promoteBtn.label.style.size = 44;
promoteBtn.label.dirty = true;
} else if (typeof promoteBtn.label.setStyle === "function") {
promoteBtn.label.setStyle({
size: 44
});
}
}
promoteBtn.x = csLeft + btnW * 3.5;
promoteBtn.y = csBottom - btnH / 2;
promoteBtn.action = function () {
hideVideoList();
// Prevent multiple promote panels
if (game.promotePanelOpen) return;
game.promotePanelOpen = true;
// --- Promote Panel State ---
if (!window.activePromotes) window.activePromotes = [];
var maxPromotes = 5;
// Panel background
var promotePanelBg = LK.getAsset('studioBg', {
anchorX: 0.5,
anchorY: 0.5
});
// Make promote panel exactly match computerscreen size and position
promotePanelBg.width = computerScreen.width;
promotePanelBg.height = computerScreen.height;
promotePanelBg.x = computerScreen.x;
promotePanelBg.y = computerScreen.y;
promotePanelBg.alpha = 0.98;
// Title
var promoteTitle = new Text2("Promote Your Channel", {
size: 90,
fill: "#fff",
font: "Arial, Helvetica, sans-serif",
dropShadow: true,
dropShadowColor: "#222",
dropShadowBlur: 8,
dropShadowDistance: 2
});
promoteTitle.anchor.set(0.5, 0.5);
promoteTitle.x = promotePanelBg.x;
promoteTitle.y = promotePanelBg.y - promotePanelBg.height / 2 + 120;
// --- Active Promotes List (top of panel, in-panel, max 5, no conv/subs est) ---
// Display: Each promote is a vertical stack of 4 labels, and campaigns are side by side horizontally
var promoteListY = promoteTitle.y + 100;
var promoteListLabels = [];
var promoteListMaxW = promotePanelBg.width - 120;
var promoteListStartX = promotePanelBg.x - promoteListMaxW / 2 + 20;
var promoteListStartY = promoteListY + 20;
var promoteListSpacingX = 420; // horizontal space between campaigns
var promoteListSpacingY = 60; // vertical space between lines in a campaign
var promoteLabelFields = [{
key: "amount",
label: "Budget",
prefix: "$"
}, {
key: "spentSoFar",
label: "Spent",
prefix: "$"
}, {
key: "viewsSoFar",
label: "Views",
prefix: "",
isRange: false
}, {
key: "range",
label: "Target",
prefix: "",
isRange: true
}];
// Helper to update the in-panel promote list (max 5, no conv/subs est)
function updatePromoteListDisplay() {
// Remove old
for (var i = 0; i < promoteListLabels.length; i++) {
for (var j = 0; j < promoteListLabels[i].length; j++) {
promoteListLabels[i][j].destroy();
}
}
promoteListLabels = [];
// Show up to 5 active promotes, newest at left
for (var i = 0; i < Math.min(window.activePromotes.length, maxPromotes); i++) {
var p = window.activePromotes[i];
var labels = [];
// Compose each line: Budget, Spent, Views, Target Range
// 1. Budget
var labelTxt1 = promoteLabelFields[0].label + ": $" + p.amount;
var label1 = new Text2(labelTxt1, {
size: 44,
fill: "#fff",
font: "Arial, Helvetica, sans-serif"
});
label1.anchor.set(0.5, 0.5);
label1.x = promoteListStartX + i * promoteListSpacingX + promoteListSpacingX / 2;
label1.y = promoteListStartY + 0 * promoteListSpacingY;
labels.push(label1);
game.addChild(label1);
// 2. Spent so far
var spentDisplay = Math.floor((p.spentSoFar || 0) * 100) / 100;
var labelTxt2 = promoteLabelFields[1].label + ": $" + spentDisplay;
var label2 = new Text2(labelTxt2, {
size: 44,
fill: "#fff",
font: "Arial, Helvetica, sans-serif"
});
label2.anchor.set(0.5, 0.5);
label2.x = promoteListStartX + i * promoteListSpacingX + promoteListSpacingX / 2;
label2.y = promoteListStartY + 1 * promoteListSpacingY;
labels.push(label2);
game.addChild(label2);
// 3. Views so far
var labelTxt3 = promoteLabelFields[2].label + ": " + (p.viewsSoFar || 0);
var label3 = new Text2(labelTxt3, {
size: 44,
fill: "#fff",
font: "Arial, Helvetica, sans-serif"
});
label3.anchor.set(0.5, 0.5);
label3.x = promoteListStartX + i * promoteListSpacingX + promoteListSpacingX / 2;
label3.y = promoteListStartY + 2 * promoteListSpacingY;
labels.push(label3);
game.addChild(label3);
// 4. Target range
var labelTxt4 = p.minViews + "-" + p.maxViews + " people";
var label4 = new Text2(labelTxt4, {
size: 44,
fill: "#fff",
font: "Arial, Helvetica, sans-serif"
});
label4.anchor.set(0.5, 0.5);
label4.x = promoteListStartX + i * promoteListSpacingX + promoteListSpacingX / 2;
label4.y = promoteListStartY + 3 * promoteListSpacingY;
labels.push(label4);
game.addChild(label4);
promoteListLabels.push(labels);
// Store for update
p._promoteListLabel = labels;
}
}
// Initial display
updatePromoteListDisplay();
// --- Money Slider Input ---
// Set promote minimum to 0, and cap to current money, disable if money is 0
var promoteAmount = 0;
var moneySliderBg = LK.getAsset('loadingbarempty', {
anchorX: 0.5,
anchorY: 0.5
});
moneySliderBg.width = 600;
moneySliderBg.height = 100;
moneySliderBg.x = promotePanelBg.x - 250;
moneySliderBg.y = promoteListStartY + maxPromotes * promoteListSpacingY + 80;
moneySliderBg.alpha = 0.92;
// Slider fill
var moneySliderFill = LK.getAsset('loadingbarfull', {
anchorX: 0,
anchorY: 0.5
});
moneySliderFill.height = 80;
moneySliderFill.x = moneySliderBg.x - moneySliderBg.width / 2 + 4;
moneySliderFill.y = moneySliderBg.y;
moneySliderFill.width = 0;
// Slider handle
var moneySliderHandle = LK.getAsset('editBtn', {
anchorX: 0.5,
anchorY: 0.5
});
moneySliderHandle.width = 80;
moneySliderHandle.height = 120;
moneySliderHandle.x = moneySliderBg.x - moneySliderBg.width / 2;
moneySliderHandle.y = moneySliderBg.y;
var moneyInputTxt = new Text2("$" + promoteAmount, {
size: 60,
fill: "#fff",
font: "Arial, Helvetica, sans-serif"
});
moneyInputTxt.anchor.set(0.5, 0.5);
moneyInputTxt.x = moneySliderBg.x;
moneyInputTxt.y = moneySliderBg.y - 70;
// --- Days Slider Input ---
var promoteDays = 1;
var daysSliderBg = LK.getAsset('loadingbarempty', {
anchorX: 0.5,
anchorY: 0.5
});
daysSliderBg.width = 400;
daysSliderBg.height = 100;
daysSliderBg.x = promotePanelBg.x + 350;
daysSliderBg.y = moneySliderBg.y;
daysSliderBg.alpha = 0.92;
var daysSliderFill = LK.getAsset('loadingbarfull', {
anchorX: 0,
anchorY: 0.5
});
daysSliderFill.height = 80;
daysSliderFill.x = daysSliderBg.x - daysSliderBg.width / 2 + 4;
daysSliderFill.y = daysSliderBg.y;
daysSliderFill.width = 0;
var daysSliderHandle = LK.getAsset('editBtn', {
anchorX: 0.5,
anchorY: 0.5
});
daysSliderHandle.width = 80;
daysSliderHandle.height = 120;
daysSliderHandle.x = daysSliderBg.x - daysSliderBg.width / 2;
daysSliderHandle.y = daysSliderBg.y;
var daysInputTxt = new Text2(promoteDays + " day", {
size: 60,
fill: "#fff",
font: "Arial, Helvetica, sans-serif"
});
daysInputTxt.anchor.set(0.5, 0.5);
daysInputTxt.x = daysSliderBg.x;
daysInputTxt.y = daysSliderBg.y - 70;
// --- Slider Drag Logic ---
var draggingMoney = false;
var draggingDays = false;
var lastMoneyX = 0;
var lastDaysX = 0;
function updateMoneySliderFromX(x) {
var min = 0;
var max = Math.max(0, Math.floor(money * 100) / 100);
var left = moneySliderBg.x - moneySliderBg.width / 2;
var right = moneySliderBg.x + moneySliderBg.width / 2;
var clamped = Math.max(left, Math.min(right, x));
var ratio = max === min ? 0 : (clamped - left) / (right - left);
var value = min + (max - min) * ratio;
value = Math.floor(value * 100) / 100;
if (value < min) value = min;
if (value > max) value = max;
promoteAmount = value;
// Update visuals
var fillW = (moneySliderBg.width - 8) * (max === 0 ? 0 : ratio);
moneySliderFill.width = fillW;
moneySliderHandle.x = left + (max === 0 ? 0 : ratio * (right - left));
moneyInputTxt.setText("$" + promoteAmount);
updateEstimates();
}
// Disable slider if money is 0
if (money <= 0) {
moneySliderHandle.interactive = false;
moneySliderHandle.buttonMode = false;
moneySliderBg.interactive = false;
moneySliderBg.buttonMode = false;
promoteAmount = 0;
moneySliderFill.width = 0;
moneySliderHandle.x = moneySliderBg.x - moneySliderBg.width / 2;
moneyInputTxt.setText("$0");
} else {
moneySliderHandle.interactive = true;
moneySliderHandle.buttonMode = true;
moneySliderBg.interactive = true;
moneySliderBg.buttonMode = true;
}
function updateDaysSliderFromX(x) {
var min = 1;
var max = 30;
var left = daysSliderBg.x - daysSliderBg.width / 2;
var right = daysSliderBg.x + daysSliderBg.width / 2;
var clamped = Math.max(left, Math.min(right, x));
var ratio = (clamped - left) / (right - left);
var value = min + (max - min) * ratio;
value = Math.round(value);
if (value < min) value = min;
if (value > max) value = max;
promoteDays = value;
// Update visuals
var fillW = (daysSliderBg.width - 8) * ((promoteDays - min) / (max - min));
daysSliderFill.width = fillW;
daysSliderHandle.x = left + (promoteDays - min) / (max - min) * (right - left);
daysInputTxt.setText(promoteDays + (promoteDays === 1 ? " day" : " days"));
updateEstimates();
}
// Money slider handle drag
moneySliderHandle.interactive = true;
moneySliderHandle.buttonMode = true;
moneySliderHandle.down = function (x, y, obj) {
draggingMoney = true;
lastMoneyX = x;
};
game.move = function (origMove) {
return function (x, y, obj) {
if (draggingMoney) {
updateMoneySliderFromX(x);
}
if (draggingDays) {
updateDaysSliderFromX(x);
}
if (typeof origMove === "function") origMove(x, y, obj);
};
}(game.move);
game.up = function (origUp) {
return function (x, y, obj) {
draggingMoney = false;
draggingDays = false;
if (typeof origUp === "function") origUp(x, y, obj);
};
}(game.up);
// Money slider background tap
moneySliderBg.interactive = true;
moneySliderBg.buttonMode = true;
moneySliderBg.down = function (x, y, obj) {
updateMoneySliderFromX(x);
};
// Days slider handle drag
daysSliderHandle.interactive = true;
daysSliderHandle.buttonMode = true;
daysSliderHandle.down = function (x, y, obj) {
draggingDays = true;
lastDaysX = x;
};
// Days slider background tap
daysSliderBg.interactive = true;
daysSliderBg.buttonMode = true;
daysSliderBg.down = function (x, y, obj) {
updateDaysSliderFromX(x);
};
// --- Estimates Display ---
var estViewsTxt = new Text2("", {
size: 48,
fill: "#0ff",
font: "Arial, Helvetica, sans-serif"
});
estViewsTxt.anchor.set(0.5, 0.5);
estViewsTxt.x = promotePanelBg.x;
estViewsTxt.y = moneySliderBg.y + 120;
// No estimated subs shown!
// --- Confirm Button ---
var confirmPromoteBtn = new GameButton();
confirmPromoteBtn.setButton('promoteBtn', 'Start Promote', "#fff", 480, 130);
confirmPromoteBtn.x = promotePanelBg.x;
confirmPromoteBtn.y = estViewsTxt.y + 120;
confirmPromoteBtn.setEnabled(true);
// Make the label smaller
if (confirmPromoteBtn.label && confirmPromoteBtn.label.style && typeof confirmPromoteBtn.label.style.size !== "undefined") {
confirmPromoteBtn.label.style.size = 44;
confirmPromoteBtn.label.dirty = true;
} else if (confirmPromoteBtn.label && typeof confirmPromoteBtn.label.setStyle === "function") {
confirmPromoteBtn.label.setStyle({
size: 44
});
}
// --- Close Button ---
var closePromoteBtn = new Text2("Ć", {
size: 120,
fill: "#fff",
font: "Arial, Helvetica, sans-serif",
dropShadow: true,
dropShadowColor: "#222",
dropShadowBlur: 8,
dropShadowDistance: 2
});
closePromoteBtn.anchor.set(0.5, 0.5);
closePromoteBtn.x = promotePanelBg.x + promotePanelBg.width / 2 - 80;
closePromoteBtn.y = promotePanelBg.y - promotePanelBg.height / 2 + 80;
closePromoteBtn.interactive = true;
closePromoteBtn.buttonMode = true;
closePromoteBtn.down = function () {
promotePanelBg.destroy();
promoteTitle.destroy();
moneySliderBg.destroy();
moneySliderFill.destroy();
moneySliderHandle.destroy();
moneyInputTxt.destroy();
daysSliderBg.destroy();
daysSliderFill.destroy();
daysSliderHandle.destroy();
daysInputTxt.destroy();
estViewsTxt.destroy();
confirmPromoteBtn.destroy();
closePromoteBtn.destroy();
for (var i = 0; i < promoteListLabels.length; i++) {
for (var j = 0; j < promoteListLabels[i].length; j++) {
promoteListLabels[i][j].destroy();
}
}
game.promotePanelOpen = false;
};
// --- Estimate Calculation ---
var estViews = 0,
estSubs = 0,
estConv = 0,
estSubRate = 0;
function updateEstimates() {
// Each $1 = 250-1000 views
var minViews = Math.floor(promoteAmount * 250);
var maxViews = Math.floor(promoteAmount * 1000);
estViews = minViews + Math.floor(Math.random() * (maxViews - minViews + 1));
// Conversion rate: 0.1% - 2% (spread), 1-1.5% if spread over >1 day
if (promoteDays === 1) {
estSubRate = 0.001 + Math.random() * 0.019; // 0.1% - 2%
} else {
estSubRate = 0.01 + Math.random() * 0.005; // 1% - 1.5%
}
estSubs = Math.floor(estViews * estSubRate);
estConv = Math.round(estSubRate * 10000) / 100;
// Show estimated reach as a range, not a single value
estViewsTxt.setText("Estimated Reach: " + formatNumber(minViews) + " - " + formatNumber(maxViews) + " people");
// No estimated subs shown!
// Enable/disable confirm
var canPromote = promoteAmount > 0 && promoteAmount <= money && promoteDays > 0 && promoteDays <= 30 && window.activePromotes.length < maxPromotes && money > 0;
confirmPromoteBtn.setEnabled(canPromote);
// Also disable slider if money is 0
if (money <= 0) {
moneySliderHandle.interactive = false;
moneySliderHandle.buttonMode = false;
moneySliderBg.interactive = false;
moneySliderBg.buttonMode = false;
promoteAmount = 0;
moneySliderFill.width = 0;
moneySliderHandle.x = moneySliderBg.x - moneySliderBg.width / 2;
moneyInputTxt.setText("$0");
} else {
moneySliderHandle.interactive = true;
moneySliderHandle.buttonMode = true;
moneySliderBg.interactive = true;
moneySliderBg.buttonMode = true;
}
}
updateEstimates();
// --- Confirm Promote Action ---
confirmPromoteBtn.action = function () {
if (window.activePromotes.length >= maxPromotes) return;
if (promoteAmount > money) return;
// Deduct money
money -= promoteAmount;
updateStats();
// Schedule promote
var promoteObj = {
amount: promoteAmount,
days: promoteDays,
startDay: gameDay,
targetViews: estViews,
subRate: estSubRate,
estimatedSubs: estSubs,
viewsPerDay: [],
viewsPerHour: [],
subsPerDay: [],
hoursPerDay: [],
hoursLeft: promoteDays * 24,
finished: false,
shownPerHour: [],
subsGained: 0,
lastDay: gameDay + promoteDays - 1,
// New for summary panel
spentSoFar: 0,
viewsSoFar: 0,
summaryPanel: null,
summaryLabels: [],
minViews: Math.floor(promoteAmount * 250),
maxViews: Math.floor(promoteAmount * 1000)
};
// Distribute views per day
var perDay = Math.floor(estViews / promoteDays);
var remain = estViews - perDay * promoteDays;
for (var d = 0; d < promoteDays; d++) {
promoteObj.viewsPerDay[d] = perDay + (d < remain ? 1 : 0);
// Distribute per hour randomly
var perHour = Math.floor(promoteObj.viewsPerDay[d] / 24);
var remainHour = promoteObj.viewsPerDay[d] - perHour * 24;
var arr = [];
for (var h = 0; h < 24; h++) arr[h] = perHour;
// Randomly distribute the remainder
for (var h = 0; h < remainHour; h++) {
var idx = Math.floor(Math.random() * 24);
arr[idx]++;
}
promoteObj.viewsPerHour[d] = arr;
promoteObj.shownPerHour[d] = [];
for (var h = 0; h < 24; h++) promoteObj.shownPerHour[d][h] = 0;
}
window.activePromotes.push(promoteObj);
updatePromoteListDisplay();
updateEstimates();
// --- After starting promote, update in-panel promote list and set up per-hour update ---
updatePromoteListDisplay();
updateEstimates();
// Helper to update the label for this promote in the list
promoteObj.updatePromoteListLabel = function () {
if (promoteObj._promoteListLabel && promoteObj._promoteListLabel.length === 4) {
var spentDisplay = Math.floor((promoteObj.spentSoFar || 0) * 100) / 100;
promoteObj._promoteListLabel[0].setText("Budget: $" + promoteObj.amount);
promoteObj._promoteListLabel[1].setText("Spent: $" + spentDisplay);
promoteObj._promoteListLabel[2].setText("Views: " + (promoteObj.viewsSoFar || 0));
promoteObj._promoteListLabel[3].setText(promoteObj.minViews + "-" + promoteObj.maxViews + " people");
}
};
// Show confirmation
var msg = new Text2("Promotion started!", {
size: 72,
fill: "#fff",
font: "Arial, Helvetica, sans-serif",
dropShadow: true,
dropShadowColor: "#222",
dropShadowBlur: 8,
dropShadowDistance: 2
});
msg.anchor.set(0.5, 0.5);
msg.x = promotePanelBg.x;
msg.y = confirmPromoteBtn.y + 120;
game.addChild(msg);
tween(msg, {
alpha: 0,
y: msg.y - 80
}, {
duration: 1600,
onFinish: function onFinish() {
msg.destroy();
}
});
// Optionally close panel
closePromoteBtn.down();
};
// --- Add to game ---
game.addChild(promotePanelBg);
game.addChild(promoteTitle);
for (var i = 0; i < promoteListLabels.length; i++) {
for (var j = 0; j < promoteListLabels[i].length; j++) {
game.addChild(promoteListLabels[i][j]);
}
}
game.addChild(moneySliderBg);
game.addChild(moneySliderFill);
game.addChild(moneySliderHandle);
game.addChild(moneyInputTxt);
game.addChild(daysSliderBg);
game.addChild(daysSliderFill);
game.addChild(daysSliderHandle);
game.addChild(daysInputTxt);
game.addChild(estViewsTxt);
game.addChild(confirmPromoteBtn);
game.addChild(closePromoteBtn);
};
game.addChild(promoteBtn);
// Statistics Button
var statsBtn = new GameButton();
statsBtn.setButton('editBtn', 'Statistics', "#fff", btnW, btnH);
// Reduce label font size for statistics button
if (statsBtn.label) {
if (statsBtn.label.style && typeof statsBtn.label.style.size !== "undefined") {
statsBtn.label.style.size = 44;
statsBtn.label.dirty = true;
} else if (typeof statsBtn.label.setStyle === "function") {
statsBtn.label.setStyle({
size: 44
});
}
}
statsBtn.x = csLeft + btnW * 4.5;
statsBtn.y = csBottom - btnH / 2;
statsBtn.action = function () {
hideVideoList();
updateStatsGraphSingle();
statsOverlay.visible = true;
};
game.addChild(statsBtn);
// --- Time Display ---
// Place time text to the right of the money text
var timeTxt = new Text2('Day 1, 08:00', {
size: 44,
fill: 0xFFFFFF
});
timeTxt.anchor.set(0, 0.5);
// Will be positioned after moneyTxt is created and positioned
// --- Video List UI ---
// Video list background and container (horizontal, each video on a square background, text below, side by side)
var videoListBg = LK.getAsset('loadingbarempty', {
anchorX: 0.5,
anchorY: 0.5
});
videoListBg.alpha = 0.96;
videoListBg.visible = false; // Only visible when video list is shown
// Make video panel exactly match computerscreen size and position
videoListBg.x = computerScreen.x;
videoListBg.y = computerScreen.y;
videoListBg.width = computerScreen.width;
videoListBg.height = computerScreen.height;
game.addChild(videoListBg);
var videoListContainer = new Container();
// Place container at top-left inside videoListBg (which matches computerscreen)
videoListContainer.x = videoListBg.x - videoListBg.width / 2;
videoListContainer.y = videoListBg.y - videoListBg.height / 2;
videoListContainer.visible = false; // Only visible when video list is shown
game.addChild(videoListContainer);
// Helper to update the video list display
function updateVideoLists() {
// Remove all previous children
while (videoListContainer.children.length > 0) {
videoListContainer.children[0].destroy();
}
if (!window.uploadedVideos || window.uploadedVideos.length === 0) {
return;
}
var squareSize = 340;
var spacing = 48;
for (var i = 0; i < window.uploadedVideos.length; i++) {
var video = window.uploadedVideos[i];
// Calculate row and column for 5 per row
var videosPerRow = 5;
var row = Math.floor(i / videosPerRow);
var col = i % videosPerRow;
// Square background
var bg = LK.getAsset('loadingbarempty', {
anchorX: 0.5,
anchorY: 0.5
});
bg.width = squareSize;
bg.height = squareSize;
bg.x = col * (squareSize + spacing) + squareSize / 2;
bg.y = row * (squareSize + spacing) + squareSize / 2;
bg.alpha = 0.93;
videoListContainer.addChild(bg);
// Video name (title) - top of square
var nameTxt = new Text2(video.title || "Untitled", {
size: 44,
fill: "#fff",
font: "Arial, Helvetica, sans-serif"
});
nameTxt.anchor.set(0.5, 0);
nameTxt.x = bg.x;
nameTxt.y = bg.y - squareSize / 2 + 18;
videoListContainer.addChild(nameTxt);
// Views - below name
var viewsTxt = new Text2(formatNumber(video.totalViews) + " views", {
size: 36,
fill: "#0ff",
font: "Arial, Helvetica, sans-serif"
});
viewsTxt.anchor.set(0.5, 0);
viewsTxt.x = bg.x;
viewsTxt.y = nameTxt.y + nameTxt.height + 6;
videoListContainer.addChild(viewsTxt);
// Money earned - below views
var moneyDisplay = Math.floor(video.totalMoney * 100) / 100;
var moneyTxt = new Text2("$" + formatNumber(moneyDisplay) + " earned", {
size: 36,
fill: 0xFA4B00,
font: "Arial, Helvetica, sans-serif"
});
moneyTxt.anchor.set(0.5, 0);
moneyTxt.x = bg.x;
moneyTxt.y = viewsTxt.y + viewsTxt.height + 2;
videoListContainer.addChild(moneyTxt);
// Subscribers - below money
var subsTxt = new Text2(formatNumber(video.totalSubs) + " subs", {
size: 36,
fill: 0xFFE066,
font: "Arial, Helvetica, sans-serif"
});
subsTxt.anchor.set(0.5, 0);
subsTxt.x = bg.x;
subsTxt.y = moneyTxt.y + moneyTxt.height + 2;
videoListContainer.addChild(subsTxt);
// Status - below subs
// (Removed: status text such as Just Published, Gaining Views, Finished)
// --- Loading Bar (progress for edit/record/publish) ---
var showBar = false;
var barProgress = 0;
var barLabel = "";
if (video.state === "recorded" && !video.finished && typeof video.editHoursLeft === "number" && video.editHoursLeft > 0) {
// Editing in progress or ready to edit
showBar = true;
// If currently editing, show progress
if (timeProcess && timeProcess.type === "edit" && timeProcess.video === video) {
barProgress = 1 - timeProcess.hoursLeft / (timeProcess.total || 1);
barLabel = "Editing...";
} else {
barProgress = 0;
barLabel = "Ready to Edit";
}
} else if (video.state === "readyToPublish" && !video.finished) {
// Ready to publish, no progress bar needed
showBar = true;
barProgress = 1;
barLabel = "Ready to Publish";
} else if (video.state === "published" && !video.finished && typeof video.totalHours === "number" && video.totalHours > 0) {
// Gaining views (publishing progress)
// Fill the bar over 7 days (168 hours)
showBar = true;
var publishTotal = 7 * 24;
barProgress = Math.min(1, video.hour / publishTotal);
barLabel = "Publishing...";
} else if (video.state === "recording" && !video.finished && typeof video.recordHoursLeft === "number" && video.recordHoursLeft > 0) {
// Recording in progress
showBar = true;
if (timeProcess && timeProcess.type === "record" && timeProcess.video === video) {
barProgress = 1 - timeProcess.hoursLeft / (timeProcess.total || 1);
barLabel = "Recording...";
} else {
barProgress = 1 - video.recordHoursLeft / (video.totalRecordHours || 1);
barLabel = "Recording...";
}
}
if (showBar) {
// Bar background
var barBg = LK.getAsset('loadingbarempty', {
anchorX: 0.5,
anchorY: 0
});
barBg.width = squareSize - 40;
barBg.height = 36;
barBg.x = bg.x;
barBg.y = nameTxt.y + nameTxt.height + viewsTxt.height + moneyTxt.height + subsTxt.height + 18;
barBg.alpha = 0.85;
videoListContainer.addChild(barBg);
// Bar fill
var barFill = LK.getAsset('loadingbarfull', {
anchorX: 0,
anchorY: 0
});
// Animate barFill width smoothly using tween, starting from current width
var targetBarWidth = (squareSize - 44) * Math.max(0, Math.min(1, barProgress));
if (typeof video.barLastWidth === "undefined") {
video.barLastWidth = 0;
}
barFill.width = video.barLastWidth;
barFill.height = 28;
barFill.x = barBg.x - barBg.width / 2 + 2;
barFill.y = barBg.y + 4;
barFill.alpha = 0.95;
videoListContainer.addChild(barFill);
// Only animate if the target width is different from the last width
if (Math.abs(targetBarWidth - video.barLastWidth) > 1) {
tween(barFill, {
width: targetBarWidth
}, {
duration: 400,
easing: tween.cubicOut,
onUpdate: function onUpdate() {
video.barLastWidth = barFill.width;
},
onFinish: function onFinish() {
video.barLastWidth = targetBarWidth;
}
});
} else {
barFill.width = targetBarWidth;
video.barLastWidth = targetBarWidth;
}
// Bar label
var barTxt = new Text2(barLabel, {
size: 28,
fill: "#fff",
font: "Arial, Helvetica, sans-serif"
});
barTxt.anchor.set(0.5, 0.5);
barTxt.x = barBg.x;
barTxt.y = barBg.y + barBg.height / 2;
videoListContainer.addChild(barTxt);
}
// Optionally, trending badge (top of square, above name)
if (video.trending) {
var trendingTxt = new Text2("Trending", {
size: 32,
fill: "#ff0",
font: "Arial, Helvetica, sans-serif"
});
trendingTxt.anchor.set(0.5, 1);
trendingTxt.x = bg.x;
trendingTxt.y = bg.y - squareSize / 2 + 8;
videoListContainer.addChild(trendingTxt);
}
// --- Edit and Publish Buttons ---
// Only show publish button if video is ready to publish and not finished
if (video.state === "readyToPublish" && video.publishReady && !video.finished) {
var publishBtn = new GameButton();
publishBtn.setButton('videoBtn', '', "#fff", 180, 80);
// Make the publish text smaller
var publishLabel = new Text2('Publish', {
size: 44,
fill: "#fff",
font: "Arial, Helvetica, sans-serif"
});
publishLabel.anchor.set(0.5, 0.5);
publishLabel.x = 0;
publishLabel.y = 0;
publishBtn.addChild(publishLabel);
// Place the publish button at the bottom center of the video's background
publishBtn.x = bg.x;
publishBtn.y = bg.y + bg.height / 2 - publishBtn.bg.height / 2 - 10;
publishBtn.action = function (vidIdx) {
return function () {
// Publish the video
var vid = window.uploadedVideos[vidIdx];
vid.state = "published";
vid.hour = 0; // Start accruing views
vid.publishReady = false;
updateVideoLists();
};
}(i);
videoListContainer.addChild(publishBtn);
}
// Only show publish button if video is ready to publish and not finished
if (video.state === "readyToPublish" && video.publishReady && !video.finished) {
var publishBtn = new GameButton();
publishBtn.setButton('videoBtn', '', "#fff", 180, 80);
// Make the publish text smaller
var publishLabel = new Text2('Publish', {
size: 44,
fill: "#fff",
font: "Arial, Helvetica, sans-serif"
});
publishLabel.anchor.set(0.5, 0.5);
publishLabel.x = 0;
publishLabel.y = 0;
publishBtn.addChild(publishLabel);
// Place the publish button at the bottom center of the video's background
publishBtn.x = bg.x;
publishBtn.y = bg.y + bg.height / 2 - publishBtn.bg.height / 2 - 10;
publishBtn.action = function (vidIdx) {
return function () {
// Publish the video
var vid = window.uploadedVideos[vidIdx];
vid.state = "published";
vid.hour = 0; // Start accruing views
vid.publishReady = false;
updateVideoLists();
};
}(i);
videoListContainer.addChild(publishBtn);
}
}
}
// --- Pause/Resume/Double Speed Buttons ---
// Track time speed: 0 = paused, 1 = normal, 2 = double
var timeSpeed = 1;
// Pause button
var pauseBtn = new GameButton();
pauseBtn.setButton('pauseicon', '', "#fff", 54, 54);
pauseBtn.action = function () {
if (timeSpeed !== 0) {
timeSpeed = 0;
isTimePaused = true;
}
updateTimeControlButtons();
};
// Resume button
var resumeBtn = new GameButton();
resumeBtn.setButton('resumeicon', '', "#fff", 54, 54);
resumeBtn.action = function () {
if (timeSpeed !== 1) {
timeSpeed = 1;
isTimePaused = false;
}
updateTimeControlButtons();
};
// Double speed button
var doubleSpeedBtn = new GameButton();
// Double the size: 54*2 = 108
doubleSpeedBtn.setButton('doublespeedicon', '', "#fff", 108, 108);
doubleSpeedBtn.action = function () {
if (timeSpeed !== 2) {
timeSpeed = 2;
isTimePaused = false;
}
updateTimeControlButtons();
};
// Helper to update button enabled/disabled state and highlight
function updateTimeControlButtons() {
// Highlight the selected speed, dim others
pauseBtn.setEnabled(timeSpeed !== 0 ? true : false);
resumeBtn.setEnabled(timeSpeed !== 1 ? true : false);
doubleSpeedBtn.setEnabled(timeSpeed !== 2 ? true : false);
// Optionally, visually highlight the active button
pauseBtn.bg.alpha = timeSpeed === 0 ? 1 : 0.6;
resumeBtn.bg.alpha = timeSpeed === 1 ? 1 : 0.6;
doubleSpeedBtn.bg.alpha = timeSpeed === 2 ? 1 : 0.6;
}
// Initial highlight
updateTimeControlButtons();
// --- Position time text and pause/resume/double speed buttons to the right of the money text ---
// This must be done after moneyTxt is created and positioned, so move this block after moneyTxt and icons are created and layoutCountersRow() is called.
// --- Counter Row Display (subscribers, viewers, money) ---
// Helper to position counters/icons in a row, matching the viewer counter/icon position
function layoutCountersRow() {
var counterY = 160;
var centerX = 2048 / 2;
var iconSpacing = 420;
// Subscribers (left, further left)
subIcon.x = centerX - iconSpacing * 1.7;
subIcon.y = counterY;
subTxt.x = subIcon.x + 70;
subTxt.y = subIcon.y;
// Viewers (shifted further left from center)
viewIcon.x = centerX - iconSpacing * 0.9;
viewIcon.y = counterY;
viewTxt.x = viewIcon.x + 70;
viewTxt.y = viewIcon.y;
// Money (move further left)
moneyIcon.x = centerX + iconSpacing * 0.1;
moneyIcon.y = counterY;
moneyTxt.x = moneyIcon.x + 70;
moneyTxt.y = moneyIcon.y;
}
// Create icons and text objects
var subIcon = LK.getAsset('subIcon', {
anchorX: 0.5,
anchorY: 0.5
});
var subTxt = new Text2('0', {
size: 64,
fill: 0xFFFFFF
});
subTxt.anchor.set(0, 0.5);
var viewIcon = LK.getAsset('viewersicon', {
anchorX: 0.5,
anchorY: 0.5
});
var viewTxt = new Text2('0', {
size: 64,
fill: 0x00e0ff
});
viewTxt.anchor.set(0, 0.5);
var moneyIcon = LK.getAsset('moneyIcon', {
anchorX: 0.5,
anchorY: 0.5
});
var moneyTxt = new Text2('0', {
size: 64,
fill: 0xFFE066
});
moneyTxt.anchor.set(0, 0.5);
// Add all counters and icons to the game (ensure visible)
game.addChild(subIcon);
game.addChild(subTxt);
game.addChild(viewIcon);
game.addChild(viewTxt);
game.addChild(moneyIcon);
game.addChild(moneyTxt);
// Initial layout
layoutCountersRow();
// --- Position time text and time control buttons at the top-left of computerscreen ---
var timePanelMargin = 32;
var timePanelBtnSpacing = 24;
var timePanelBtnY = computerScreen.y - computerScreen.height / 2 + timePanelMargin + pauseBtn.bg.height / 2;
var timePanelX = computerScreen.x - computerScreen.width / 2 + timePanelMargin;
// Place timeTxt at the top-left, leaving margin
timeTxt.x = timePanelX + timeTxt.width / 2 + 10;
timeTxt.y = computerScreen.y - computerScreen.height / 2 + timePanelMargin + timeTxt.height / 2 + 10;
// Place pause, resume, and double speed buttons to the right of timeTxt
var btnsStartX = timeTxt.x + timeTxt.width / 2 + timePanelBtnSpacing + pauseBtn.bg.width / 2;
var btnsY = timeTxt.y;
pauseBtn.x = btnsStartX;
pauseBtn.y = btnsY;
resumeBtn.x = btnsStartX + pauseBtn.bg.width + timePanelBtnSpacing;
resumeBtn.y = btnsY;
doubleSpeedBtn.x = btnsStartX + (pauseBtn.bg.width + timePanelBtnSpacing) * 2;
doubleSpeedBtn.y = btnsY;
// Add to game after positioning (ensure visible)
game.addChild(timeTxt);
game.addChild(pauseBtn);
game.addChild(resumeBtn);
game.addChild(doubleSpeedBtn);
// --- Action Buttons ---
// Button layout: stack vertically, bigger, with spacing
var btnW = 540;
var btnH = 220;
var btnSpacingY = 60;
var btnStartY = 900;
// Make Video Button
var makeVideoBtn = new GameButton();
makeVideoBtn.setButton('videoBtn', 'Record Video', "#fff", btnW, btnH);
makeVideoBtn.x = 2048 / 2;
// Move the record video button further down to fill the space of removed buttons
// Move the record video button 250 pixels higher
makeVideoBtn.y = btnStartY + 3 * (btnH + btnSpacingY) - 250;
// --- Loading Bar for Process ---
// (Removed: processBarBg and processBarFill, and their show/hide functions.)
// No independent loading bar on the main screen.
// --- Action Button Logic (time-based) ---
// Track if record video panel is open
var isRecordPanelOpen = false;
makeVideoBtn.action = function () {
if (timeProcess) {
return;
} // Only one process at a time
// Block recording if a video is in 'recorded' state and not finished (must edit first)
if (window.uploadedVideos) {
for (var i = 0; i < window.uploadedVideos.length; i++) {
if (window.uploadedVideos[i].state === "recorded" && !window.uploadedVideos[i].finished) {
// Optionally, show a message or flash the edit button
tween(editBtn, {
scaleX: 1.15,
scaleY: 1.15
}, {
duration: 100,
onFinish: function onFinish() {
tween(editBtn, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
return;
}
}
}
if (isRecordPanelOpen) {
return;
} // Prevent multiple panels
isRecordPanelOpen = true;
// Show a panel before starting the process
// Place the record panel visually to exactly match computerscreen
var panelBg = LK.getAsset('studioBg', {
anchorX: 0.5,
anchorY: 0.5
});
// Set panel size and position to exactly match computerscreen
panelBg.width = computerScreen.width;
panelBg.height = computerScreen.height;
panelBg.x = computerScreen.x;
panelBg.y = computerScreen.y;
panelBg.alpha = 0.98;
// Ensure panelBg is above computerscreen in the display list
var csIdx = game.children.indexOf(computerScreen);
if (csIdx !== -1) {
// Insert panelBg just above computerscreen
game.addChildAt(panelBg, csIdx + 1);
} else {
game.addChild(panelBg);
}
// --- Panel Title ---
var panelText = new Text2("Select Category & Title", {
size: 90,
fill: "#fff",
font: "Arial, Helvetica, sans-serif",
dropShadow: true,
dropShadowColor: "#222",
dropShadowBlur: 8,
dropShadowDistance: 2
});
panelText.anchor.set(0.5, 0.5);
panelText.x = panelBg.x;
panelText.y = panelBg.y - panelBg.height / 2 + 120; // near top of panel
// --- Video Title Input ---
var titleInputBg = LK.getAsset('loadingbarempty', {
anchorX: 0.5,
anchorY: 0.5
});
titleInputBg.width = 1000;
titleInputBg.height = 130;
titleInputBg.x = panelBg.x - 180; // shift left to make space for random button
titleInputBg.y = panelText.y + 200; // more space below title
titleInputBg.alpha = 0.92;
var videoTitle = "";
var titleInputTxt = new Text2("Enter video title...", {
size: 72,
fill: "#fff",
font: "Arial, Helvetica, sans-serif",
dropShadow: true,
dropShadowColor: "#222",
dropShadowBlur: 8,
dropShadowDistance: 2
});
titleInputTxt.anchor.set(0.5, 0.5);
titleInputTxt.x = titleInputBg.x;
titleInputTxt.y = titleInputBg.y;
// Simulate input: tap to edit, prompt for text
titleInputBg.down = function (x, y, obj) {
var prompt = LK.prompt ? LK.prompt : window.prompt; // fallback for dev
var val = prompt ? prompt("Enter video title:", videoTitle) : "";
if (typeof val === "string" && val.length > 0) {
videoTitle = val;
titleInputTxt.setText(videoTitle);
}
};
// --- Random Title Button ---
var randomBtn = new GameButton();
randomBtn.setButton('promoteBtn', 'Random', "#fff", 340, 120);
randomBtn.x = titleInputBg.x + titleInputBg.width / 2 + 200; // right of input with space
randomBtn.y = titleInputBg.y;
randomBtn.action = function () {
// Titles per category
var categoryTitles = {
"Vlog": ["My Daily Vlog", "Life Update", "A Day in My Life", "Morning Routine", "Evening Recap"],
"Challenge": ["Epic Challenge!", "24 Hour Challenge", "Impossible Task!", "Last To Leave", "Extreme Challenge"],
"Reaction": ["Reacting to Comments", "Reacting to Viral Videos", "First Time Watching", "Fan Reactions", "Surprising Reactions"],
"Tutorial": ["How To Edit Videos", "Beginner's Guide", "Pro Tips & Tricks", "Step by Step Tutorial", "Easy DIY"],
"Unboxing": ["Unboxing Surprise", "Mystery Box Unboxing", "Tech Unboxing", "Unboxing Haul", "First Impressions"],
"Gaming": ["Let's Play!", "Epic Gaming Moments", "Game Review", "Speedrun Attempt", "Funny Gaming Fails"],
"Music": ["My New Song", "Music Cover", "Behind the Music", "Songwriting Session", "Live Performance"],
"Comedy": ["Funny Moments", "Comedy Skit", "Prank Video", "Try Not To Laugh", "Bloopers & Outtakes"],
"Q&A": ["Q&A Special", "Answering Your Questions", "Ask Me Anything", "Subscriber Q&A", "Get To Know Me"],
"Other": ["Behind the Scenes", "Special Announcement", "Random Thoughts", "Channel Update", "What Happened Today"]
};
var cat = videoCategories[selectedCategoryIdx];
var titles = categoryTitles[cat] || ["My Daily Vlog", "Epic Challenge!", "Reacting to Comments", "24 Hours in My Studio", "Behind the Scenes", "Q&A Special", "Trying Viral Trends", "Unboxing Surprise", "Life Update", "Funny Moments"];
var idx = Math.floor(Math.random() * titles.length);
videoTitle = titles[idx];
titleInputTxt.setText(videoTitle);
};
// --- Video Category Buttons ---
var categoryBtnW = 340;
var categoryBtnH = 120;
var categoryBtnSpacingX = 40;
var categoryBtnSpacingY = 40;
var categoryBtns = [];
// Layout: fit as many as possible per row, then wrap
var maxRowWidth = panelBg.width - 120; // leave some margin
var maxPerRow = Math.floor((maxRowWidth + categoryBtnSpacingX) / (categoryBtnW + categoryBtnSpacingX));
if (maxPerRow < 1) {
maxPerRow = 1;
}
var startX = panelBg.x - (Math.min(maxPerRow, videoCategories.length) * (categoryBtnW + categoryBtnSpacingX) - categoryBtnSpacingX) / 2 + categoryBtnW / 2;
var startY = titleInputBg.y + 220; // more space below input+random
for (var i = 0; i < videoCategories.length; i++) {
(function (idx) {
var btn = new GameButton();
btn.setButton('editBtn', videoCategories[idx], "#fff", categoryBtnW, categoryBtnH);
var row = Math.floor(idx / maxPerRow);
var col = idx % maxPerRow;
btn.x = startX + col * (categoryBtnW + categoryBtnSpacingX);
btn.y = startY + row * (categoryBtnH + categoryBtnSpacingY);
btn.action = function () {
// Deselect all
for (var j = 0; j < categoryBtns.length; j++) {
// If trending, keep its highlight
if (j === trendingCategoryIdx) {
categoryBtns[j].bg.alpha = 0.95;
} else {
categoryBtns[j].bg.alpha = 0.7;
}
}
btn.bg.alpha = 1;
selectedCategoryIdx = idx;
};
// Highlight the first by default
if (i === 0) {
btn.bg.alpha = 1;
} else {
btn.bg.alpha = 0.7;
}
// Mark trending category visually
if (i === trendingCategoryIdx) {
btn.bg.alpha = 0.95;
// Add a "Trending" label above the button
var trendingTxt = new Text2("š„ Trending", {
size: 48,
fill: "#ff0",
font: "Arial, Helvetica, sans-serif",
dropShadow: true,
dropShadowColor: "#222",
dropShadowBlur: 8,
dropShadowDistance: 2
});
trendingTxt.anchor.set(0.5, 1);
trendingTxt.x = btn.x;
trendingTxt.y = btn.y - categoryBtnH / 2 - 10;
btn.trendingTxt = trendingTxt;
}
categoryBtns.push(btn);
})(i);
}
// --- Confirm/Record Button ---
var confirmBtn = new GameButton();
// Make the button smaller and move it 50px up
confirmBtn.setButton('videoBtn', 'Record', "#fff", 480, 130);
confirmBtn.x = panelBg.x;
// Find the bottom Y of the last category button for spacing
var lastCategoryBtn = categoryBtns[categoryBtns.length - 1];
var categoryBtnsBottomY = lastCategoryBtn ? lastCategoryBtn.y + categoryBtnH / 2 : startY + categoryBtnH / 2;
confirmBtn.y = categoryBtnsBottomY + 150; // 50px higher than before
confirmBtn.action = function () {
// Remove panel
panelBg.destroy();
panelText.destroy();
confirmBtn.destroy();
titleInputBg.destroy();
titleInputTxt.destroy();
randomBtn.destroy();
// Hide all category buttons and trending labels immediately
for (var i = 0; i < categoryBtns.length; i++) {
if (categoryBtns[i].trendingTxt) {
categoryBtns[i].trendingTxt.visible = false;
}
categoryBtns[i].visible = false;
}
// Destroy all category buttons
for (var i = 0; i < categoryBtns.length; i++) {
// Destroy trending label if exists
if (categoryBtns[i].trendingTxt) {
categoryBtns[i].trendingTxt.destroy();
}
categoryBtns[i].destroy();
}
isRecordPanelOpen = false;
// --- Add video to list immediately, in 'recording' state, before recording starts ---
if (!window.uploadedVideos) {
window.uploadedVideos = [];
}
var videoObj = {
title: videoTitle,
category: videoCategories[selectedCategoryIdx],
hour: 0,
totalHours: 7 * 24,
totalViews: 0,
totalMoney: 0,
totalSubs: 0,
trending: videoCategories[selectedCategoryIdx] === videoCategories[trendingCategoryIdx],
baseSubscribers: subscribers,
finished: false,
state: "recording",
// <--- show as recording
recordHoursLeft: 3,
totalRecordHours: 3,
// new: states are "recording", "recorded", "editing", "readyToPublish", "published"
editHoursLeft: 5,
publishReady: false
};
// Precompute total views to distribute realistically over 7 days
var minViewPercent = 0.01;
var maxViewPercent = 0.05;
var percent = minViewPercent + Math.random() * (maxViewPercent - minViewPercent);
var baseViews = Math.floor(videoObj.baseSubscribers * percent);
if (videoObj.baseSubscribers < 100) {
baseViews = 100 + Math.floor(Math.random() * 400);
}
if (videoObj.trending) {
baseViews = Math.floor(baseViews * 1.5);
}
videoObj.targetViews = baseViews;
videoObj.targetMoney = Math.floor(baseViews / 1000 * (3 + Math.random() * 2));
videoObj.targetSubs = Math.floor(baseViews / (200 + Math.floor(Math.random() * 101)));
videoObj.hourlyViews = [];
// Distribute views per hour: more at start, less at end (decay curve)
var decay = 0.012; // controls how fast views drop off
var total = 0;
for (var h = 0; h < videoObj.totalHours; h++) {
var rel = h / videoObj.totalHours;
var hourViews = Math.max(1, Math.round(baseViews * Math.exp(-decay * h)));
videoObj.hourlyViews.push(hourViews);
total += hourViews;
}
// Normalize to match targetViews
var scale = baseViews / total;
for (var h = 0; h < videoObj.hourlyViews.length; h++) {
videoObj.hourlyViews[h] = Math.floor(videoObj.hourlyViews[h] * scale);
}
window.uploadedVideos.push(videoObj);
videoCount += 1;
updateStats();
updateVideoLists();
// Start the process
timeProcess = {
type: 'record',
hoursLeft: 3,
total: 3,
category: videoCategories[selectedCategoryIdx],
title: videoTitle,
video: videoObj,
onFinish: function onFinish() {
LK.getSound('makeVideo').play();
// Mark video as recorded, ready for editing
videoObj.state = "recorded";
videoObj.recordHoursLeft = 0;
updateVideoLists();
// Animate button
tween(makeVideoBtn, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 80,
onFinish: function onFinish() {
tween(makeVideoBtn, {
scaleX: 1,
scaleY: 1
}, {
duration: 80
});
}
});
// Removed winning condition at 1000 subscribers; game continues forever
}
};
// Removed call to undefined showProcessBar(0)
};
// --- Close (X) Button ---
// Add all panel elements to game
game.addChild(panelBg);
game.addChild(panelText);
game.addChild(titleInputBg);
game.addChild(titleInputTxt);
game.addChild(randomBtn);
// (closeBtn removed)
// Add all category buttons
for (var i = 0; i < categoryBtns.length; i++) {
game.addChild(categoryBtns[i]);
// If trending label exists, add it to game
if (categoryBtns[i].trendingTxt) {
game.addChild(categoryBtns[i].trendingTxt);
}
}
game.addChild(confirmBtn);
};
// (Removed: makeVideoBtn from main screen, now triggered by recordVideoBtn next to videos button)
// (Removed: manual y-positioning of subIcon/subTxt and moneyIcon/moneyTxt; handled by layoutCountersRow)
// Removed undefined energyBar and energyTxt
// --- GUI: Timer/Score (use subscribers as score) ---
// Removed giant numbers next to the subscriber counter
// --- Helper Functions ---
function formatNumber(num) {
if (num < 1000) {
return "" + num;
}
if (num < 1000000) {
var k = num / 1000;
if (k % 1 === 0) {
return k + "k";
}
return k.toFixed(1).replace(/\.0$/, "") + "k";
}
var m = num / 1000000;
if (m % 1 === 0) {
return m + "m";
}
return m.toFixed(1).replace(/\.0$/, "") + "m";
}
function updateStats() {
// --- Helper for green increase text ---
function showGreenIncrease(textObj, increase, prefix) {
if (!increase || increase <= 0) {
return;
}
var plusText = new Text2("+" + formatNumber(increase), {
size: 48,
fill: 0x00FF44,
font: "Arial, Helvetica, sans-serif",
dropShadow: true,
dropShadowColor: "#222",
dropShadowBlur: 8,
dropShadowDistance: 2
});
plusText.anchor.set(0, 0.5);
// Place to the right of the number
plusText.x = textObj.x + textObj.width + 16;
plusText.y = textObj.y;
game.addChild(plusText);
tween(plusText, {
y: plusText.y - 40,
alpha: 0
}, {
duration: 1200,
easing: tween.cubicOut,
onFinish: function onFinish() {
plusText.destroy();
}
});
}
// Subscribers
if (typeof updateStats.lastSubValue !== "number") {
updateStats.lastSubValue = subscribers;
}
var subIncrease = subscribers - updateStats.lastSubValue;
subTxt.setText(formatNumber(subscribers));
if (subIncrease > 0) {
showGreenIncrease(subTxt, subIncrease, "");
}
updateStats.lastSubValue = subscribers;
// Views
if (typeof updateStats.lastViewValue !== "number") {
updateStats.lastViewValue = viewCount;
}
var viewIncrease = viewCount - updateStats.lastViewValue;
viewTxt.setText(formatNumber(viewCount));
if (viewIncrease > 0) {
showGreenIncrease(viewTxt, viewIncrease, "");
}
updateStats.lastViewValue = viewCount;
// Money
if (typeof updateStats.lastMoneyValue !== "number") {
updateStats.lastMoneyValue = money;
}
var moneyIncrease = money - updateStats.lastMoneyValue;
// Truncate money to 2 decimal digits for display
var moneyDisplay = Math.floor(money * 100) / 100;
moneyTxt.setText(formatNumber(moneyDisplay));
if (moneyIncrease > 0) {
// Truncate moneyIncrease to 2 decimal digits for display
var moneyIncreaseDisplay = Math.floor(moneyIncrease * 100) / 100;
showGreenIncrease(moneyTxt, moneyIncreaseDisplay, "");
}
updateStats.lastMoneyValue = money;
// If financePanel is open, update its money display
if (typeof financePanel !== "undefined" && financePanel && typeof financePanel.updateMoney === "function") {
financePanel.updateMoney();
}
// Enable/disable buttons based on process and resources
makeVideoBtn.setEnabled(!timeProcess);
// --- Achievements ---
if (!updateStats.milestones) {
updateStats.milestones = {};
}
// Subscriber milestones
var milestones = [10, 25, 50, 100, 250, 500, 750, 1000, 2500, 5000, 10000, 25000, 50000, 100000, 250000, 500000, 1000000];
for (var i = 0; i < milestones.length; i++) {
var m = milestones[i];
if (subscribers >= m && !updateStats.milestones["subs" + m]) {
updateStats.milestones["subs" + m] = true;
var ach = new Text2("Milestone: " + m + " Subs!", {
size: 110,
fill: "#ff0",
stroke: "#000",
strokeThickness: 12,
font: "Arial, Helvetica, sans-serif",
dropShadow: true,
dropShadowColor: "#222",
dropShadowBlur: 12,
dropShadowDistance: 4
});
ach.anchor.set(0.5, 0.5);
ach.x = 2048 / 2;
ach.y = 400 + i * 80;
game.addChild(ach);
tween(ach, {
alpha: 0,
y: ach.y - 100
}, {
duration: 1800,
onFinish: function onFinish() {
ach.destroy();
}
});
}
}
// View milestones
var viewMilestones = [1000, 5000, 10000, 25000, 50000, 100000, 250000, 500000, 1000000, 5000000, 10000000];
for (var i = 0; i < viewMilestones.length; i++) {
var m = viewMilestones[i];
if (viewCount >= m && !updateStats.milestones["views" + m]) {
updateStats.milestones["views" + m] = true;
var ach = new Text2("Milestone: " + formatNumber(m) + " Views!", {
size: 110,
fill: 0x00E0FF,
stroke: "#000",
strokeThickness: 12,
font: "Arial, Helvetica, sans-serif",
dropShadow: true,
dropShadowColor: "#222",
dropShadowBlur: 12,
dropShadowDistance: 4
});
ach.anchor.set(0.5, 0.5);
ach.x = 2048 / 2;
ach.y = 400 + (i + milestones.length) * 80;
game.addChild(ach);
tween(ach, {
alpha: 0,
y: ach.y - 100
}, {
duration: 1800,
onFinish: function onFinish() {
ach.destroy();
}
});
}
}
// Money milestones
var moneyMilestones = [100, 500, 1000, 5000, 10000, 25000, 50000, 100000, 250000, 500000, 1000000];
for (var i = 0; i < moneyMilestones.length; i++) {
var m = moneyMilestones[i];
if (money >= m && !updateStats.milestones["money" + m]) {
updateStats.milestones["money" + m] = true;
var ach = new Text2("Milestone: $" + formatNumber(m) + " Earned!", {
size: 110,
fill: 0xFA4B00,
stroke: "#000",
strokeThickness: 12,
font: "Arial, Helvetica, sans-serif",
dropShadow: true,
dropShadowColor: "#222",
dropShadowBlur: 12,
dropShadowDistance: 4
});
ach.anchor.set(0.5, 0.5);
ach.x = 2048 / 2;
ach.y = 400 + (i + milestones.length + viewMilestones.length) * 80;
game.addChild(ach);
tween(ach, {
alpha: 0,
y: ach.y - 100
}, {
duration: 1800,
onFinish: function onFinish() {
ach.destroy();
}
});
}
}
}
// --- Video List UI Update ---
// --- Time Update ---
function updateTimeDisplay() {
var h = gameHour;
var hStr = (h < 10 ? "0" : "") + h + ":00";
timeTxt.setText("Day " + gameDay + ", " + hStr);
}
// --- Process Update ---
function updateProcessBar() {
// No independent loading bar on the main screen.
}
// --- Time Timer ---
if (timeTimer) {
LK.clearInterval(timeTimer);
}
// Helper function to process one hour of time advancement
function processOneHour() {
// Advance time
gameHour += 1;
if (gameHour >= 24) {
gameHour = 0;
gameDay += 1;
// Record daily stats exactly once per day
recordDailyStats();
// Check if it's time to change trending category
// Trending category changes a random number of times every 7 to 30 days
if (typeof trendingCategoryNextChangeDay === "undefined") {
trendingCategoryNextChangeDay = trendingCategoryDay + 7 + Math.floor(Math.random() * 24); // 7-30 days
}
if (gameDay >= trendingCategoryNextChangeDay) {
updateTrendingCategory();
trendingCategoryNextChangeDay = gameDay + 7 + Math.floor(Math.random() * 24); // 7-30 days
}
}
updateTimeDisplay();
// Process logic
if (timeProcess) {
timeProcess.hoursLeft -= 1;
updateProcessBar();
if (timeProcess.hoursLeft <= 0) {
var finish = timeProcess.onFinish;
// If editing, update video state
if (timeProcess.type === "edit" && timeProcess.video) {
timeProcess.video.state = "readyToPublish";
timeProcess.video.publishReady = true;
}
timeProcess = null;
updateProcessBar();
updateStats();
updateVideoLists();
if (typeof finish === "function") {
finish();
}
}
}
// Per-hour video view/money/subscriber accrual
if (window.uploadedVideos) {
for (var v = 0; v < window.uploadedVideos.length; v++) {
var vid = window.uploadedVideos[v];
// Only accrue views, money, and subs if published and not finished
if (vid.state === "published" && vid.hour < vid.totalHours) {
var viewsThisHour = vid.hourlyViews[vid.hour] || 0;
// --- Add promote campaign views to this video if any active promote campaigns exist ---
// Find all active promote campaigns for this hour and add their views to this video if the campaign is running
if (window.activePromotes && window.activePromotes.length > 0) {
for (var pi = 0; pi < window.activePromotes.length; pi++) {
var p = window.activePromotes[pi];
if (p.finished) continue;
var promoteDay = gameDay - p.startDay;
var promoteHour = gameHour;
if (promoteDay >= 0 && promoteDay < p.days) {
var promoteViewsThisHour = p.viewsPerHour[promoteDay][promoteHour] || 0;
viewsThisHour += promoteViewsThisHour;
}
}
}
// --- NEW: Instantly update subscribers and money per view ---
// 1) For every 1 view, 1% chance to gain a subscriber (instantly)
// 2) For every 100 views, earn 0.1 money (instantly)
var subsThisHour = 0;
var moneyThisHour = 0;
for (var i = 0; i < viewsThisHour; i++) {
if (Math.random() < 0.01) {
// 1% chance per view
subsThisHour += 1;
}
}
// Each viewer gives a random amount between 0.001 and 0.01
moneyThisHour = 0;
for (var vi = 0; vi < viewsThisHour; vi++) {
moneyThisHour += 0.001 + Math.random() * 0.009;
}
vid.totalViews += viewsThisHour;
vid.totalMoney += moneyThisHour;
vid.totalSubs += subsThisHour;
viewCount += viewsThisHour;
money += moneyThisHour;
subscribers += subsThisHour;
vid.hour++;
// Clamp to target on last hour
if (vid.hour === vid.totalHours) {
// Remove the video from the video list when publishing is complete
window.uploadedVideos.splice(v, 1);
v--; // Adjust index since we removed an item
continue; // Skip further processing for this video
}
}
}
}
// --- Promote Campaigns: process per hour ---
if (window.activePromotes && window.activePromotes.length > 0) {
for (var pi = window.activePromotes.length - 1; pi >= 0; pi--) {
var p = window.activePromotes[pi];
// Determine which day/hour of campaign we are in
var promoteDay = gameDay - p.startDay;
var promoteHour = gameHour;
if (promoteDay >= 0 && promoteDay < p.days && !p.finished) {
// Show to this hour's people
var viewsThisHour = p.viewsPerHour[promoteDay][promoteHour] || 0;
p.shownPerHour[promoteDay][promoteHour] = viewsThisHour;
// Conversion rate: use p.subRate
var subsThisHour = 0;
for (var vi = 0; vi < viewsThisHour; vi++) {
if (Math.random() < p.subRate) subsThisHour++;
}
p.subsGained += subsThisHour;
subscribers += subsThisHour;
viewCount += viewsThisHour;
// Track for stats
if (!p.subsPerDay[promoteDay]) p.subsPerDay[promoteDay] = 0;
p.subsPerDay[promoteDay] += subsThisHour;
if (!p.viewsPerDay[promoteDay]) p.viewsPerDay[promoteDay] = 0;
p.viewsPerDay[promoteDay] += viewsThisHour;
// --- Update promote in-panel label values ---
var totalHours = p.days * 24;
var spentPerHour = p.amount / totalHours;
// Defensive: never overspend
if (p.spentSoFar + spentPerHour > p.amount) {
spentPerHour = p.amount - p.spentSoFar;
if (spentPerHour < 0) spentPerHour = 0;
}
p.spentSoFar += spentPerHour;
// Clamp spentSoFar to not exceed amount
if (p.spentSoFar > p.amount) p.spentSoFar = p.amount;
p.viewsSoFar += viewsThisHour;
if (typeof p.updatePromoteListLabel === "function") {
p.updatePromoteListLabel();
}
// If spentSoFar reached amount, mark as finished
if (p.spentSoFar >= p.amount && !p.finished) {
p.finished = true;
// Also set lastDay to current day if not already set
if (typeof p.lastDay === "undefined" || p.lastDay < gameDay) {
p.lastDay = gameDay;
}
}
}
// Mark as finished if campaign is over by time
if (gameDay > p.startDay + p.days - 1) {
p.finished = true;
}
// Remove finished promotes after last day
if (p.finished && gameDay > p.lastDay + 1) {
// Remove label from panel
if (p._promoteListLabel) {
for (var li = 0; li < p._promoteListLabel.length; li++) {
if (p._promoteListLabel[li] && typeof p._promoteListLabel[li].destroy === "function") {
p._promoteListLabel[li].destroy();
}
}
p._promoteListLabel = null;
}
window.activePromotes.splice(pi, 1);
updatePromoteListDisplay();
}
}
}
updateStats();
updateVideoLists();
}
// Timer logic for normal and double speed
var doubleSpeedTimer = null;
function setTimeTimer() {
if (timeTimer) {
LK.clearInterval(timeTimer);
timeTimer = null;
}
if (doubleSpeedTimer) {
LK.clearInterval(doubleSpeedTimer);
doubleSpeedTimer = null;
}
// Normal speed: 1 hour every 1000ms
if (timeSpeed === 1) {
timeTimer = LK.setInterval(function () {
if (timeSpeed !== 1 || isTimePaused) return;
processOneHour();
}, 1000);
}
// Double speed: 1 hour every 500ms
else if (timeSpeed === 2) {
doubleSpeedTimer = LK.setInterval(function () {
if (timeSpeed !== 2 || isTimePaused) return;
processOneHour();
}, 500);
}
// Paused: do nothing
}
setTimeTimer();
// Patch time control buttons to call setTimeTimer when speed changes
var oldUpdateTimeControlButtons = updateTimeControlButtons;
updateTimeControlButtons = function updateTimeControlButtons() {
oldUpdateTimeControlButtons();
setTimeTimer();
};
// --- Game Update Loop ---
game.update = function () {
// Nothing needed for now, all logic is event/click based
};
// --- Touch/Drag Handling (no drag needed, but block top left 100x100) ---
game.down = function (x, y, obj) {
// Prevent accidental clicks in top left
if (x < 100 && y < 100) {
return;
}
};
game.move = function (x, y, obj) {};
game.up = function (x, y, obj) {};
// --- Initialize UI ---
updateStats();
// Hide video list and background by default at game start
videoListBg.visible = false;
videoListContainer.visible = false;
// --- Tutorial Items removed as requested ---
// --- Promote Stats Panel (hourly breakdown) ---
function showPromoteStatsPanel(promoteIdx) {
if (!window.activePromotes || !window.activePromotes[promoteIdx]) return;
var p = window.activePromotes[promoteIdx];
// Panel background
var promoteStatsBg = LK.getAsset('studioBg', {
anchorX: 0.5,
anchorY: 0.5
});
promoteStatsBg.width = 1200;
promoteStatsBg.height = 1200;
promoteStatsBg.x = 2048 / 2;
promoteStatsBg.y = 2732 / 2;
promoteStatsBg.alpha = 0.98;
// Title
var promoteStatsTitle = new Text2("Promote Campaign Details", {
size: 70,
fill: "#fff",
font: "Arial, Helvetica, sans-serif"
});
promoteStatsTitle.anchor.set(0.5, 0.5);
promoteStatsTitle.x = promoteStatsBg.x;
promoteStatsTitle.y = promoteStatsBg.y - promoteStatsBg.height / 2 + 80;
// Table header
var headerTxt = new Text2("Day | Hour | Views | Subs", {
size: 44,
fill: "#0ff",
font: "Arial, Helvetica, sans-serif"
});
headerTxt.anchor.set(0.5, 0.5);
headerTxt.x = promoteStatsBg.x;
headerTxt.y = promoteStatsTitle.y + 80;
// Table rows (show up to 24 hours for each day)
var tableLabels = [];
var startY = headerTxt.y + 60;
var rowH = 38;
var maxRows = 20;
var shownRows = 0;
for (var d = 0; d < p.days && shownRows < maxRows; d++) {
for (var h = 0; h < 24 && shownRows < maxRows; h++) {
var views = p.shownPerHour[d] ? p.shownPerHour[d][h] : 0;
var subs = 0;
// Estimate subs for this hour (approximate, since we don't store per hour)
if (views > 0) {
subs = Math.floor(views * p.subRate);
}
var rowTxt = new Text2(d + 1 + " | " + (h < 10 ? "0" : "") + h + ":00 | " + views + " | " + subs, {
size: 36,
fill: "#fff",
font: "Arial, Helvetica, sans-serif"
});
rowTxt.anchor.set(0.5, 0.5);
rowTxt.x = promoteStatsBg.x;
rowTxt.y = startY + shownRows * rowH;
tableLabels.push(rowTxt);
shownRows++;
}
}
// Close button
var closeStatsBtn = new GameButton();
closeStatsBtn.setButton('editBtn', 'Close', "#fff", 320, 90);
closeStatsBtn.x = promoteStatsBg.x;
closeStatsBtn.y = promoteStatsBg.y + promoteStatsBg.height / 2 - 80;
closeStatsBtn.action = function () {
promoteStatsBg.destroy();
promoteStatsTitle.destroy();
headerTxt.destroy();
closeStatsBtn.destroy();
for (var i = 0; i < tableLabels.length; i++) tableLabels[i].destroy();
};
// Add to game
game.addChild(promoteStatsBg);
game.addChild(promoteStatsTitle);
game.addChild(headerTxt);
for (var i = 0; i < tableLabels.length; i++) game.addChild(tableLabels[i]);
game.addChild(closeStatsBtn);
}
// --- Statistics Section UI ---
// Data arrays for stats (one entry per day)
var statsViewsPerDay = [];
var statsSubsPerDay = [];
var statsMoneyPerDay = [];
var statsLastDay = 0;
// Statistics overlay container (hidden by default)
var statsOverlay = new Container();
statsOverlay.visible = false;
statsOverlay.x = 0;
statsOverlay.y = 0;
game.addChild(statsOverlay);
// Overlay background
// Move the statistics overlay 250px up, crop 10px from left/right, 200px from top/bottom
var statsBgWidth = 1950 - 20; // 10px left, 10px right
var statsBgHeight = 1600 - 400; // 200px top, 200px bottom
var statsBg = LK.getAsset('studioBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2 - 450
});
statsBg.width = statsBgWidth;
statsBg.height = statsBgHeight;
statsBg.alpha = 0.98;
statsOverlay.addChild(statsBg);
// Title removed as requested
// --- Graph Toggle Buttons ---
var statTypes = [{
key: "views",
label: "Views",
color: 0x00e0ff,
icon: "viewersicon"
}, {
key: "subs",
label: "Subscribers",
color: 0xffe066,
icon: "subIcon"
}, {
key: "money",
label: "Money",
color: 0xfa4b00,
icon: "moneyIcon"
}];
var statDataMap = {
views: statsViewsPerDay,
subs: statsSubsPerDay,
money: statsMoneyPerDay
};
var statLabelMap = {
views: "Views per Day",
subs: "Subscribers per Day",
money: "Money Earned per Day"
};
var statIconMap = {
views: "viewersicon",
subs: "subIcon",
money: "moneyIcon"
};
var statColorMap = {
views: 0x00e0ff,
subs: 0xffe066,
money: 0xfa4b00
};
var selectedStatType = "views";
var statToggleBtns = [];
var toggleBtnW = 260;
var toggleBtnH = 80;
var toggleBtnSpacing = 36;
var toggleBtnStartX = 2048 / 2 - (toggleBtnW * 1.5 + toggleBtnSpacing);
// Yeni statsBg yüksekliÄine gƶre toggle butonlarını hizala
var toggleBtnY = statsBg.y - statsBg.height / 2 + 120;
for (var i = 0; i < statTypes.length; i++) {
(function (idx) {
var btn = new GameButton();
btn.setButton('editBtn', statTypes[idx].label, "#fff", toggleBtnW, toggleBtnH);
// Reduce label font size for statistics top buttons
if (btn.label) {
if (btn.label.style && typeof btn.label.style.size !== "undefined") {
btn.label.style.size = 44;
btn.label.dirty = true;
} else if (typeof btn.label.setStyle === "function") {
btn.label.setStyle({
size: 44
});
}
}
btn.x = toggleBtnStartX + idx * (toggleBtnW + toggleBtnSpacing);
btn.y = toggleBtnY;
btn.action = function () {
// Deselect all
for (var j = 0; j < statToggleBtns.length; j++) {
statToggleBtns[j].bg.alpha = 0.7;
}
btn.bg.alpha = 1;
selectedStatType = statTypes[idx].key;
updateStatsGraphSingle();
};
// Highlight first by default
btn.bg.alpha = i === 0 ? 1 : 0.7;
statToggleBtns.push(btn);
statsOverlay.addChild(btn);
})(i);
}
// --- Single Graph Area ---
var graphW = 1200;
var graphH = 500;
var graphStartX = (2048 - graphW) / 2;
var graphStartY = statsBg.y - statsBg.height / 2 + 220;
// Helper to draw a single stat graph
function drawStatSingleGraph(container, data, color, iconAssetId, label) {
if (!container.graphNodes) container.graphNodes = [];
// Remove previous graph
for (var i = 0; i < container.graphNodes.length; i++) {
container.graphNodes[i].destroy();
}
container.graphNodes = [];
// Card background
var cardBg = LK.getAsset('loadingbarempty', {
anchorX: 0.5,
anchorY: 0,
x: 2048 / 2,
y: graphStartY
});
cardBg.width = graphW + 120;
cardBg.height = graphH + 100;
cardBg.alpha = 0.93;
container.addChild(cardBg);
container.graphNodes.push(cardBg);
// Draw icon
var icon = LK.getAsset(iconAssetId, {
anchorX: 0.5,
anchorY: 0.5,
x: graphStartX - 100,
y: graphStartY + 60 + graphH / 2
});
icon.width = 120;
icon.height = 120;
container.addChild(icon);
container.graphNodes.push(icon);
// Draw label
var labelTxt = new Text2(label, {
size: 60,
fill: "#fff",
font: "Arial, Helvetica, sans-serif"
});
labelTxt.anchor.set(0, 0.5);
labelTxt.x = graphStartX;
labelTxt.y = graphStartY + 40;
container.addChild(labelTxt);
container.graphNodes.push(labelTxt);
// Find max value for scaling
var maxVal = 1;
for (var i = 0; i < data.length; i++) {
if (data[i] > maxVal) maxVal = data[i];
}
// Draw line graph: connect points with rectangles (simulate lines)
var prevX = null,
prevY = null;
for (var i = 0; i < data.length; i++) {
var x0 = graphStartX + i / Math.max(1, data.length - 1) * graphW;
var y0 = graphStartY + 100 + graphH - data[i] / maxVal * (graphH - 20);
// Draw a small circle at each data point
var point = LK.getAsset('loadingbarfull', {
anchorX: 0.5,
anchorY: 0.5,
x: x0,
y: y0
});
point.width = 18;
point.height = 18;
point.tint = color;
container.addChild(point);
container.graphNodes.push(point);
// Draw value label every 5 days or last
if ((i % 5 === 0 || i === data.length - 1) && data[i] > 0) {
var displayValue = data[i];
// If this is the money graph, format to 2 decimal places
if (selectedStatType === "money") {
displayValue = Math.floor(data[i] * 100) / 100;
// Always show 2 decimals for money
displayValue = displayValue.toFixed(2);
}
var valTxt = new Text2("" + displayValue, {
size: 36,
fill: "#fff"
});
valTxt.anchor.set(0.5, 1);
valTxt.x = x0;
valTxt.y = y0 - 8;
container.addChild(valTxt);
container.graphNodes.push(valTxt);
}
// Draw a "line" between previous and current point using a thin rectangle
if (prevX !== null && prevY !== null) {
var dx = x0 - prevX;
var dy = y0 - prevY;
var dist = Math.sqrt(dx * dx + dy * dy);
var angle = Math.atan2(dy, dx);
var line = LK.getAsset('loadingbarfull', {
anchorX: 0,
anchorY: 0.5,
x: prevX,
y: prevY
});
line.width = dist;
line.height = 8;
line.tint = color;
line.rotation = angle;
container.addChild(line);
container.graphNodes.push(line);
}
prevX = x0;
prevY = y0;
}
}
// Draw the selected graph
function updateStatsGraphSingle() {
var key = selectedStatType;
var data = statDataMap[key];
var color = statColorMap[key];
var icon = statIconMap[key];
var label = statLabelMap[key];
drawStatSingleGraph(statsOverlay, data, color, icon, label);
}
// Close button for stats overlay
var statsCloseBtn = new GameButton();
statsCloseBtn.setButton('editBtn', 'Close', "#fff", 320, 90);
statsCloseBtn.x = 2048 / 2;
statsCloseBtn.y = statsBg.y + statsBg.height / 2 - 80;
statsCloseBtn.action = function () {
statsOverlay.visible = false;
};
statsOverlay.addChild(statsCloseBtn);
// Statistics Section Button removed with navigation bar
// --- Track stats per day ---
// Call this at the end of each day
function recordDailyStats() {
// Only record once per day
if (statsLastDay === gameDay) {
return;
}
statsLastDay = gameDay;
statsViewsPerDay.push(viewCount);
statsSubsPerDay.push(subscribers);
statsMoneyPerDay.push(money);
}
// Record stats for day 1 at game start
recordDailyStats();
// Define updatePromoteListDisplay in global scope to avoid not defined error
function updatePromoteListDisplay() {
// This is a stub to avoid not defined error if called outside promote panel
// The real implementation is inside the promote panel logic
}
subscriber icon 2d. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
money icon 2d. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
solid grey colour background for panel. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
viewers icon for a mobile game. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
make bigger this monitor
please to this white color
white play button solid white color. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
double speed icon for mobile games. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat. no text. only white color.
2d phone for mobile games. modern phone. looks good but phone is one color, phone's screen one color. Let it be completely 2-dimensional and not look like 3-dimensional. There should be a mute button and small volume up and down and hang up buttons on the sides of the phone.. In-Game asset. 2d. High contrast. No shadows - Fill the entire screen with a light gray color. - The outer cover color of the phone should be dark gray.
youtube button logo. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
white background rounded corners. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat white color. all white color no border.
playstore logo. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
editing application logo. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
çoĢp kutusu logosu fakat kırmızı arka planlı (çoĢp kutusu logosu beyaz renkte olacak). In-Game asset. 2d. High contrast. No shadows
kırmızıya boya
beyaza boya
maviye boya
istatistik logosu. In-Game asset. 2d. High contrast. No shadows
reklam logosu herhangi bir yazı olmasın. In-Game asset. 2d. High contrast. No shadows
record video logo with not text. In-Game asset. 2d. High contrast. No shadows
finans logosu. In-Game asset. 2d. High contrast. No shadows
youtube studio logo with no text only logo. In-Game asset. 2d. High contrast. No shadows
create youtube channel avatar cartoon 2d. In-Game asset. 2d. High contrast. No shadows
youtube channel logo. In-Game asset. 2d. High contrast. No shadows
"rastgele" ikonu, beyaz renginde olacak.. In-Game asset. 2d. High contrast. No shadows
youtube thumbnail for vlog. 2d. High contrast. No shadows
kilit ikonu beyaz. In-Game asset. 2d. High contrast. No shadows