User prompt
Add the computerbackground assets above the studiobackground assets.
User prompt
Please fix the bug: 'y is not defined' in or related to this line: 'var contentHeight = y;' Line Number: 1077
User prompt
Move the record button up a bit. Move the subscriber button, viewer count button, and money button down. Add a custom background to the video list and make the video list scrollable on that panel.
User prompt
Add computerbackground from assets to studiobackground.
User prompt
add a bug report button link to : https://upit.com/up/YouTuberTycoon
User prompt
add a bug report button link to: https://upit.com/up/YouTuberTycoon
User prompt
improve the second biggest game mechanic update
User prompt
improve the biggest game mechanic update
User prompt
improve the game with big ui update
User prompt
improve the game with big update
User prompt
improve the game with big update
User prompt
improve the game mechanics
User prompt
Please fix the bug: 'storage.get is not a function' in or related to this line: 'if (!storage.get("tutorialShown")) {' Line Number: 1275 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'storage is not defined' in or related to this line: 'if (!storage.get("tutorialShown")) {' Line Number: 1274 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
improve the game
User prompt
improve the game
User prompt
When automation is turned on, it will record a video with a random name in the trending category without directly selecting a category and name, edit it automatically and share it automatically.
User prompt
automate editing and publishing video too.
User prompt
Add a button that automates the flow of shooting, editing and publishing videos.
User prompt
Let's give up on this last animation we made, and instead let's write in green the hourly increase in subscribers, money and viewership, like this: 6 +7 (+7 will be written in green.)
User prompt
Let's forget about the animated changing of these numbers, let's try a different type of animation. The changing digit of the number goes up and the new number comes from below, let's try such an animation. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
The animated change of numbers should be slow at first and then speed up, and this should be the case for every change because the change is never obvious. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
The increasing numbers in the game should increase more smoothly. (i.e. if a number is going to increase from 5 to 8, the numbers 6-7 should also be visible so that a better image is created when increasing from 5 to 8) (if this process is already in the game, the process should be done a little slower because the change is not visible at all) ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
The increasing numbers in the game should increase more smoothly. (i.e. if a number is going to increase from 5 to 8, the numbers 6-7 should also be visible so that a better image is created when increasing from 5 to 8) ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Let the increasing numbers in the game increase more smoothly. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.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; }); // 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: "'GillSans-Bold',Impact,'Arial Black',Tahoma", 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: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); 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: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); 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: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); 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"; stats += " | $" + formatNumber(videoObj.totalMoney); 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 ****/ // --- Trending Category State --- // --- Video Categories (must be defined before use in updateTrendingCategory) --- 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 --- var trendingCategoryIdx = 0; 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; // Animate trending button for attention tween(categoryBtns[i].bg, { scaleX: 1.15, scaleY: 1.15 }, { duration: 180, yoyo: true, repeat: 1, easing: tween.cubicOut, onFinish: function onFinish() { tween(categoryBtns[i].bg, { scaleX: 1, scaleY: 1 }, { duration: 120 }); } }); } 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); // --- Time Display --- var timeTxt = new Text2('Day 1, 08:00', { size: 80, fill: 0xFFFFFF }); timeTxt.anchor.set(0.5, 0.5); timeTxt.x = 2048 / 2; timeTxt.y = 300; game.addChild(timeTxt); // --- Video List UI --- // Single area for all videos var videosLabel = new Text2("Videos:", { size: 54, fill: "#fff" }); videosLabel.anchor.set(0, 0.5); videosLabel.x = 120; videosLabel.y = 480; game.addChild(videosLabel); // Add extra vertical space between label and list var videosListContainer = new Container(); videosListContainer.x = 120; videosListContainer.y = 480 + 54 + 36; // label y + label height + extra space (36px) game.addChild(videosListContainer); // --- Pause/Resume Button --- var pauseBtn = new GameButton(); pauseBtn.setButton('editBtn', 'Pause', "#fff", 320, 120); pauseBtn.x = 2048 / 2 + 520; pauseBtn.y = 300; pauseBtn.action = function () { isTimePaused = !isTimePaused; pauseBtn.label.setText(isTimePaused ? "Resume" : "Pause"); }; game.addChild(pauseBtn); // Subscribers display var subIcon = LK.getAsset('subIcon', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 - 520, y: 140 }); game.addChild(subIcon); var subTxt = new Text2('0', { size: 64, fill: 0xFFFFFF }); subTxt.anchor.set(0, 0.5); subTxt.x = subIcon.x + 70; subTxt.y = subIcon.y; game.addChild(subTxt); // Money display var moneyIcon = LK.getAsset('moneyIcon', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 + 320, y: 140 }); game.addChild(moneyIcon); var moneyTxt = new Text2('$0', { size: 64, fill: 0xFFE066 }); moneyTxt.anchor.set(0, 0.5); moneyTxt.x = moneyIcon.x + 70; moneyTxt.y = moneyIcon.y; game.addChild(moneyTxt); // View count display (use viewersicon asset for the viewers counter icon) // Place view counter exactly in the middle between subIcon and moneyIcon var viewAreaCenterX = (subIcon.x + moneyIcon.x) / 2; var viewIcon = LK.getAsset('viewersicon', { anchorX: 0.5, anchorY: 0.5, x: viewAreaCenterX - 40, y: 110 }); game.addChild(viewIcon); var viewTxt = new Text2('0', { size: 64, fill: 0x00e0ff }); viewTxt.anchor.set(0, 0.5); viewTxt.x = viewIcon.x + 70; viewTxt.y = viewIcon.y; game.addChild(viewTxt); // --- 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 makeVideoBtn.y = btnStartY + 3 * (btnH + btnSpacingY); // --- 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) --- // --- Upgrade Mechanic --- var upgradeBtn = new GameButton(); upgradeBtn.setButton('upgradeBtn', 'Upgrade Quality\n($' + upgradeCost + ')', "#fff", 480, 140); upgradeBtn.x = 2048 / 2 - 600; upgradeBtn.y = btnStartY + 2 * (btnH + btnSpacingY); upgradeBtn.action = function () { if (money >= upgradeCost) { money -= upgradeCost; videoQuality += 1; upgradeLevel += 1; upgradeCost = Math.floor(upgradeCost * 1.7 + 10 * upgradeLevel); upgradeBtn.label.setText('Upgrade Quality\n($' + upgradeCost + ')'); updateStats(); // Show a quick popup for upgrade var upTxt = new Text2("Video Quality Upgraded!", { size: 80, fill: 0xFA4B00, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); upTxt.anchor.set(0.5, 0.5); upTxt.x = upgradeBtn.x; upTxt.y = upgradeBtn.y - 120; game.addChild(upTxt); tween(upTxt, { alpha: 0, y: upTxt.y - 80 }, { duration: 1200, onFinish: function onFinish() { upTxt.destroy(); } }); } }; game.addChild(upgradeBtn); // Track if record video panel is open var isRecordPanelOpen = false; makeVideoBtn.action = function () { if (timeProcess) return; // Only one process at a time if (isRecordPanelOpen) return; // Prevent multiple panels isRecordPanelOpen = true; // Show a panel before starting the process var panelBg = LK.getAsset('energyBarBg', { anchorX: 0.5, anchorY: 0.5 }); // Expand the panel to allow for more rows of category buttons panelBg.width = 1500; panelBg.height = 1300; panelBg.x = 2048 / 2; panelBg.y = 2732 / 2; panelBg.alpha = 0.98; // --- Panel Title --- var panelText = new Text2("Select Category & Title", { size: 90, fill: "#fff", font: "'GillSans-Bold',Impact,'Arial Black',Tahoma", 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: "'GillSans-Bold',Impact,'Arial Black',Tahoma", 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: "'GillSans-Bold',Impact,'Arial Black',Tahoma", 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(); confirmBtn.setButton('videoBtn', 'Start Recording', "#fff", 600, 180); 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 + 200; // more space below category confirmBtn.action = function () { // Remove panel panelBg.destroy(); panelText.destroy(); confirmBtn.destroy(); titleInputBg.destroy(); titleInputTxt.destroy(); randomBtn.destroy(); closeBtn.destroy(); // Also destroy the close (X) button // 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; // Start the process var recordHours = 3; if (skillEffects.faster_record) recordHours = Math.ceil(recordHours * 0.7); timeProcess = { type: 'record', hoursLeft: recordHours, total: recordHours, category: videoCategories[selectedCategoryIdx], title: videoTitle, onFinish: function onFinish() { LK.getSound('makeVideo').play(); // Create a new video object to accrue views over time 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: "recorded", // new: states are "recorded", "editing", "readyToPublish", "published" editHoursLeft: 5, // in-game hours to edit publishReady: false }; // Precompute total views to distribute realistically over 7 days // Make hourly views between 1% and 5% of the number of subscribers at publish time 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(); // 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 --- var closeBtn = new Text2("×", { size: 120, fill: "#fff", font: "'GillSans-Bold',Impact,'Arial Black',Tahoma", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); closeBtn.anchor.set(0.5, 0.5); // Place at top right of panel, with margin closeBtn.x = panelBg.x + panelBg.width / 2 - 80; closeBtn.y = panelBg.y - panelBg.height / 2 + 80; closeBtn.interactive = true; closeBtn.buttonMode = true; closeBtn.down = function () { panelBg.destroy(); panelText.destroy(); confirmBtn.destroy(); closeBtn.destroy(); titleInputBg.destroy(); titleInputTxt.destroy(); randomBtn.destroy(); // 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 all panel elements to game game.addChild(panelBg); game.addChild(panelText); game.addChild(titleInputBg); game.addChild(titleInputTxt); game.addChild(randomBtn); game.addChild(closeBtn); // 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); }; // Add buttons to game game.addChild(makeVideoBtn); // Add extra vertical space between money/sub displays and buttons subIcon.y = 110; subTxt.y = subIcon.y; moneyIcon.y = 110; moneyTxt.y = moneyIcon.y; // 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: "'GillSans-Bold',Impact,'Arial Black',Tahoma", 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; moneyTxt.setText('$' + formatNumber(money)); if (moneyIncrease > 0) { showGreenIncrease(moneyTxt, moneyIncrease, "$"); } updateStats.lastMoneyValue = money; // Enable/disable buttons based on process and resources makeVideoBtn.setEnabled(!timeProcess); // Upgrade button enable/disable if (typeof upgradeBtn !== "undefined") { upgradeBtn.setEnabled(money >= upgradeCost); upgradeBtn.label.setText('Upgrade Quality\n($' + upgradeCost + ')'); } // Add pulsing effect to Record Video button if enabled and no process if (!timeProcess && makeVideoBtn.enabled && !makeVideoBtn._pulseTween) { var _pulseBtn = function pulseBtn() { if (!makeVideoBtn.enabled) { makeVideoBtn.scaleX = 1; makeVideoBtn.scaleY = 1; makeVideoBtn._pulseTween = false; return; } tween(makeVideoBtn, { scaleX: 1.08, scaleY: 1.08 }, { duration: 320, yoyo: true, repeat: 1, easing: tween.cubicInOut, onFinish: function onFinish() { if (makeVideoBtn.enabled) { LK.setTimeout(_pulseBtn, 400); } else { makeVideoBtn._pulseTween = false; } } }); }; makeVideoBtn._pulseTween = true; _pulseBtn(); } else if (timeProcess && makeVideoBtn._pulseTween) { makeVideoBtn._pulseTween = false; makeVideoBtn.scaleX = 1; makeVideoBtn.scaleY = 1; } // --- 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: "'GillSans-Bold',Impact,'Arial Black',Tahoma", 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); // Bounce in, then fade out ach.scaleX = 0.7; ach.scaleY = 0.7; tween(ach, { scaleX: 1.1, scaleY: 1.1 }, { duration: 220, easing: tween.cubicOut, onFinish: function onFinish() { tween(ach, { scaleX: 1, scaleY: 1 }, { duration: 120, onFinish: function onFinish() { tween(ach, { alpha: 0, y: ach.y - 100 }, { duration: 1800, onFinish: function onFinish() { ach.destroy(); } }); } }); } }); // Show a quick tip at 100 subs if (m === 100) { var tip = new Text2("Tip: Try trending categories for a big boost!", { size: 72, fill: 0x00FF44, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); tip.anchor.set(0.5, 0.5); tip.x = 2048 / 2; tip.y = 900; game.addChild(tip); tween(tip, { alpha: 0, y: tip.y - 80 }, { duration: 2200, onFinish: function onFinish() { tip.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: "'GillSans-Bold',Impact,'Arial Black',Tahoma", 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: "'GillSans-Bold',Impact,'Arial Black',Tahoma", 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 --- function updateVideoLists() { // Clear all children from the single videos list container while (videosListContainer.children.length > 0) { var c = videosListContainer.children[0]; c.destroy && c.destroy(); videosListContainer.removeChild(c); } var y = 0; // Show video being recorded (if any) if (timeProcess && timeProcess.type === 'record') { var recItem = new VideoListItem(); recItem.y = y; recItem.setVideo({ title: timeProcess.title || "Untitled", hour: 0, finished: false, totalViews: 0, totalMoney: 0, totalSubs: 0, trending: timeProcess.category === videoCategories[trendingCategoryIdx] }); videosListContainer.addChild(recItem); // Show loading bar to the right of the video list item and its buttons var barW = 320; var barH = 40; var barBg = LK.getAsset('loadingbarempty', { anchorX: 0.5, anchorY: 0.5 }); barBg.width = barW; barBg.height = barH; // Place bar to the right of the list item (list item x + width + margin + half bar width) barBg.x = recItem.bg.x + recItem.bg.width + 40 + barW / 2; barBg.y = recItem.y + recItem.bg.height / 2 - 28; videosListContainer.addChild(barBg); var barFill = LK.getAsset('loadingbarfull', { anchorX: 0, anchorY: 0.5 }); // Animate loading bar fill smoothly using tween var targetWidth = Math.max(1, barW * (1 - timeProcess.hoursLeft / timeProcess.total)); // Instead of always starting at 1px, start at the current fill (if any) for smooth continuation barFill.width = typeof updateVideoLists.lastRecordBarWidth === "number" ? updateVideoLists.lastRecordBarWidth : targetWidth; barFill.height = barH; barFill.x = barBg.x - barW / 2; barFill.y = barBg.y; videosListContainer.addChild(barFill); tween(barFill, { width: targetWidth }, { duration: 400, easing: tween.cubicOut, onFinish: function onFinish() { updateVideoLists.lastRecordBarWidth = targetWidth; } }); y += 130; } // Show all uploaded videos (in any state) // Remove finished videos (whose view counts stop increasing) from the list and from uploadedVideos // Reset bar width memory if no process is running if (!timeProcess) { updateVideoLists.lastRecordBarWidth = undefined; updateVideoLists.lastEditBarWidth = undefined; } if (window.uploadedVideos) { for (var i = window.uploadedVideos.length - 1; i >= 0; i--) { var vid = window.uploadedVideos[i]; // Remove from array if finished (view counts stopped increasing) if (vid.finished === true) { window.uploadedVideos.splice(i, 1); continue; } var item = new VideoListItem(); item.y = y; item.setVideo(vid); videosListContainer.addChild(item); // Add edit or publish button if needed if (vid.state === "recorded") { // Show edit button var editBtn = new GameButton(); // Make button smaller and text fit editBtn.setButton('editBtn', 'Edit', "#fff", 220, 90); // Reduce font size to prevent overflow if (editBtn.label && typeof editBtn.label.setFontSize === "function") { editBtn.label.setFontSize(48); editBtn.label.setText('Edit'); } // Align to the right of the video list item editBtn.x = item.bg.x + item.bg.width + 40 + editBtn.bg.width / 2; // Move button higher (was -10, now -40) editBtn.y = item.y + item.bg.height / 2 - 40; editBtn.action = function (vidRef) { return function () { // Start editing process for this video if (timeProcess) return; // Only one process at a time var editHours = vidRef.editHoursLeft; if (skillEffects.faster_edit) editHours = Math.ceil(editHours * 0.7); timeProcess = { type: 'edit', hoursLeft: editHours, total: editHours, video: vidRef, onFinish: function onFinish() { vidRef.state = "readyToPublish"; vidRef.publishReady = true; // Editing Mastery: increase video quality by 1 if (skillEffects.edit_quality) { if (!vidRef.qualityBonus) vidRef.qualityBonus = 1; } updateVideoLists(); } }; updateProcessBar(); updateStats(); updateVideoLists(); }; }(vid); videosListContainer.addChild(editBtn); // Auto-edit button if skill unlocked and not used today if (skillEffects.edit_auto && (!window._autoEditUsedDay || window._autoEditUsedDay !== gameDay)) { var autoEditBtn = new GameButton(); autoEditBtn.setButton('upgradeBtn', 'Auto-Edit', "#fff", 220, 90); autoEditBtn.x = editBtn.x + editBtn.bg.width + 40 + autoEditBtn.bg.width / 2; autoEditBtn.y = editBtn.y; autoEditBtn.action = function (vidRef) { return function () { if (timeProcess) return; vidRef.state = "readyToPublish"; vidRef.publishReady = true; if (skillEffects.edit_quality) { if (!vidRef.qualityBonus) vidRef.qualityBonus = 1; } window._autoEditUsedDay = gameDay; // Show popup var autoPop = new Text2("Auto-Edit Complete!", { size: 64, fill: 0x00FF44, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); autoPop.anchor.set(0.5, 0.5); autoPop.x = autoEditBtn.x; autoPop.y = autoEditBtn.y - 80; game.addChild(autoPop); tween(autoPop, { alpha: 0, y: autoPop.y - 60 }, { duration: 1000, onFinish: function onFinish() { autoPop.destroy(); } }); updateVideoLists(); }; }(vid); videosListContainer.addChild(autoEditBtn); } // If this video is currently being edited, show a loading bar to the right of the edit button if (timeProcess && timeProcess.type === "edit" && timeProcess.video === vid) { var barW = 320; var barH = 40; var barBg = LK.getAsset('loadingbarempty', { anchorX: 0.5, anchorY: 0.5 }); barBg.width = barW; barBg.height = barH; barBg.x = editBtn.x + editBtn.bg.width / 2 + 40 + barW / 2; barBg.y = editBtn.y - 18; videosListContainer.addChild(barBg); var barFill = LK.getAsset('loadingbarfull', { anchorX: 0, anchorY: 0.5 }); // Animate loading bar fill smoothly using tween var targetWidth = Math.max(1, barW * (1 - timeProcess.hoursLeft / timeProcess.total)); // Instead of always starting at 1px, start at the current fill (if any) for smooth continuation barFill.width = typeof updateVideoLists.lastEditBarWidth === "number" ? updateVideoLists.lastEditBarWidth : targetWidth; barFill.height = barH; barFill.x = barBg.x - barW / 2; barFill.y = barBg.y; videosListContainer.addChild(barFill); tween(barFill, { width: targetWidth }, { duration: 400, easing: tween.cubicOut, onFinish: function onFinish() { updateVideoLists.lastEditBarWidth = targetWidth; } }); } } else if (vid.state === "readyToPublish") { // Show publish button var publishBtn = new GameButton(); // Make button smaller and text fit publishBtn.setButton('promoteBtn', 'Publish', "#fff", 320, 90); // Reduce font size to prevent overflow if (publishBtn.label && typeof publishBtn.label.setFontSize === "function") { publishBtn.label.setFontSize(24); publishBtn.label.setText('Publish'); } // Align to the right of the video list item publishBtn.x = item.bg.x + item.bg.width + 40 + publishBtn.bg.width / 2; // Move button higher (was -10, now -40) publishBtn.y = item.y + item.bg.height / 2 - 40; publishBtn.action = function (vidRef) { return function () { // Set video to published, start gaining views vidRef.state = "published"; vidRef.publishReady = false; updateVideoLists(); }; }(vid); videosListContainer.addChild(publishBtn); // No loading bar for publish state } y += 130; } } } // --- 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); timeTimer = LK.setInterval(function () { if (isTimePaused) return; // Advance time gameHour += 1; if (gameHour >= 24) { gameHour = 0; gameDay += 1; // 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 if published if (vid.state === "published" && vid.hour < vid.totalHours) { // --- DYNAMIC VIEWS: Make hourly views depend on current subscribers --- // Between 1% and 5% of *current* subscribers, with decay over time var minViewPercent = 0.01; var maxViewPercent = 0.05; var percent = minViewPercent + Math.random() * (maxViewPercent - minViewPercent); var baseViews = Math.floor(subscribers * percent); // Video quality multiplier: each upgrade increases by 10% var qualityMultiplier = 1 + (videoQuality - 1) * 0.1; baseViews = Math.floor(baseViews * qualityMultiplier); if (subscribers < 100) { baseViews = 100 + Math.floor(Math.random() * 400); } if (vid.trending) { baseViews = Math.floor(baseViews * 1.5); } // Decay curve: more at start, less at end var decay = 0.012; var rel = vid.hour / vid.totalHours; var viewsThisHour = Math.max(1, Math.round(baseViews * Math.exp(-decay * vid.hour))); // Clamp so we don't overshoot targetViews if (vid.totalViews + viewsThisHour > vid.targetViews) { viewsThisHour = Math.max(0, vid.targetViews - vid.totalViews); } // Skill: Viral Chance (3x views, once per video, 10% chance) if (skillEffects.viral_chance && !vid._viralChecked && Math.random() < 0.10) { viewsThisHour *= 3; vid._viralChecked = true; // Show viral popup var viralPop = new Text2("Viral Video!", { size: 100, fill: 0xff0, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 12, dropShadowDistance: 4 }); viralPop.anchor.set(0.5, 0.5); viralPop.x = 2048 / 2; viralPop.y = 600; game.addChild(viralPop); tween(viralPop, { alpha: 0, y: viralPop.y - 100 }, { duration: 1800, onFinish: function onFinish() { viralPop.destroy(); } }); } // Skill: Editing Mastery (edit_quality) - add quality bonus var totalQuality = qualityMultiplier; if (vid.qualityBonus) totalQuality += 0.1 * vid.qualityBonus; // Skill: Extra Money var moneyMult = skillEffects.extra_money ? 1.2 : 1; // Money: $3-5 per 1000 views, distributed proportionally var moneyThisHour = Math.floor(viewsThisHour / vid.targetViews * vid.targetMoney * totalQuality * moneyMult); // Sponsor deals: extra money for videos with >10k views if unlocked if (skillEffects.sponsor_deals && vid.totalViews + viewsThisHour > 10000 && !vid._sponsorGiven) { var sponsorBonus = Math.floor(vid.targetMoney * 0.5); moneyThisHour += sponsorBonus; vid._sponsorGiven = true; // Show sponsor popup var sponsorPop = new Text2("Sponsor Deal!\n+$" + formatNumber(sponsorBonus), { size: 80, fill: 0xFA4B00, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); sponsorPop.anchor.set(0.5, 0.5); sponsorPop.x = 2048 / 2; sponsorPop.y = 700; game.addChild(sponsorPop); tween(sponsorPop, { alpha: 0, y: sponsorPop.y - 80 }, { duration: 1200, onFinish: function onFinish() { sponsorPop.destroy(); } }); } // Subs: proportional to views, distributed over time var subsThisHour = Math.floor(viewsThisHour / vid.targetViews * vid.targetSubs * totalQuality); // Collab boost: big sub boost for first video after unlock if (skillEffects.collab_boost && !vid._collabGiven) { var collabBonus = Math.floor(vid.targetSubs * 0.5); subsThisHour += collabBonus; vid._collabGiven = true; // Show collab popup var collabPop = new Text2("Collab Boost!\n+" + formatNumber(collabBonus) + " subs", { size: 80, fill: 0x00FF44, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); collabPop.anchor.set(0.5, 0.5); collabPop.x = 2048 / 2; collabPop.y = 800; game.addChild(collabPop); tween(collabPop, { alpha: 0, y: collabPop.y - 80 }, { duration: 1200, onFinish: function onFinish() { collabPop.destroy(); } }); } 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) { var leftViews = vid.targetViews - vid.totalViews; var leftMoney = vid.targetMoney - vid.totalMoney; var leftSubs = vid.targetSubs - vid.totalSubs; if (leftViews > 0) { viewCount += leftViews; vid.totalViews += leftViews; } if (leftMoney > 0) { money += leftMoney; vid.totalMoney += leftMoney; } if (leftSubs > 0) { subscribers += leftSubs; vid.totalSubs += leftSubs; } vid.finished = true; } } } } updateStats(); updateVideoLists(); }, 1000); // --- 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(); // --- Tutorial Popup for First-Time Players --- if (!storage.tutorialShown) { var tutBg = LK.getAsset('studioBg', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 }); tutBg.width = 1600; tutBg.height = 1100; tutBg.alpha = 0.98; var tutTitle = new Text2("Welcome to Streamer Tycoon!", { size: 110, fill: "#fff", font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); tutTitle.anchor.set(0.5, 0); tutTitle.x = 2048 / 2; tutTitle.y = 2732 / 2 - 420; var tutText = new Text2("• Record videos by tapping 'Record Video'.\n" + "• Choose a category and title for your video.\n" + "• Edit and publish to gain views, money, and subscribers!\n" + "• Trending categories give a big boost.\n" + "• Track your progress in the Statistics tab.\n\n" + "Good luck becoming a superstar!", { size: 64, fill: "#fff", font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); tutText.anchor.set(0.5, 0.5); tutText.x = 2048 / 2; tutText.y = 2732 / 2 - 60; var tutBtn = new GameButton(); tutBtn.setButton('editBtn', 'Got it!', "#fff", 500, 140); tutBtn.x = 2048 / 2; tutBtn.y = 2732 / 2 + 340; tutBtn.action = function () { tutBg.destroy(); tutTitle.destroy(); tutText.destroy(); tutBtn.destroy(); storage.tutorialShown = true; }; game.addChild(tutBg); game.addChild(tutTitle); game.addChild(tutText); game.addChild(tutBtn); } // --- Bottom Navigation Bar --- var navBarHeight = 220; var navBarY = 2732 - navBarHeight / 2; // Background bar var navBarBg = LK.getAsset('loadingbarempty', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: navBarY }); navBarBg.width = 2048; navBarBg.height = navBarHeight; navBarBg.alpha = 0.96; game.addChild(navBarBg); // Section button width and spacing var navBtnW = 540; var navBtnH = 160; var navBtnSpacing = (2048 - 3 * navBtnW) / 4; var navBtnY = navBarY; // Video Recording Section Button var navVideoBtn = new GameButton(); navVideoBtn.setButton('videoBtn', 'Video', "#fff", navBtnW, navBtnH); navVideoBtn.x = navBtnSpacing + navBtnW / 2; navVideoBtn.y = navBtnY; navVideoBtn.action = function () { // Scroll to or focus video section (no-op for now) }; game.addChild(navVideoBtn); // --- Skill Tree System --- // Skill definitions with dependencies and branches var skillTree = [{ id: "faster_record", name: "Faster Recording", desc: "Record videos 30% faster.", cost: 100, unlocked: false, effect: function effect() { skillEffects.faster_record = true; }, requires: [] }, { id: "faster_edit", name: "Faster Editing", desc: "Edit videos 30% faster.", cost: 120, unlocked: false, effect: function effect() { skillEffects.faster_edit = true; }, requires: [] }, { id: "extra_money", name: "Ad Revenue Boost", desc: "Earn 20% more money from videos.", cost: 200, unlocked: false, effect: function effect() { skillEffects.extra_money = true; }, requires: ["faster_record"] }, { id: "viral_chance", name: "Viral Chance", desc: "Small chance for videos to go viral (3x views).", cost: 300, unlocked: false, effect: function effect() { skillEffects.viral_chance = true; }, requires: ["extra_money"] }, { id: "edit_quality", name: "Editing Mastery", desc: "Editing increases video quality by 1.", cost: 250, unlocked: false, effect: function effect() { skillEffects.edit_quality = true; }, requires: ["faster_edit"] }, { id: "sponsor_deals", name: "Sponsor Deals", desc: "Unlock sponsor offers for extra money.", cost: 500, unlocked: false, effect: function effect() { skillEffects.sponsor_deals = true; }, requires: ["extra_money"] }, { id: "collab_boost", name: "Collab Boost", desc: "Collaborations give a big subscriber boost.", cost: 700, unlocked: false, effect: function effect() { skillEffects.collab_boost = true; }, requires: ["viral_chance"] }, { id: "edit_auto", name: "Auto-Edit", desc: "Auto-edit videos instantly (once per day).", cost: 900, unlocked: false, effect: function effect() { skillEffects.edit_auto = true; }, requires: ["edit_quality"] }]; // Skill effect flags var skillEffects = { faster_record: false, faster_edit: false, extra_money: false, viral_chance: false, edit_quality: false, sponsor_deals: false, collab_boost: false, edit_auto: false }; // Skill Tree Overlay UI var skillTreeOverlay = new Container(); skillTreeOverlay.visible = false; skillTreeOverlay.x = 0; skillTreeOverlay.y = 0; game.addChild(skillTreeOverlay); // Overlay background var skillBg = LK.getAsset('studioBg', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); skillBg.alpha = 0.98; skillTreeOverlay.addChild(skillBg); // Title var skillTitle = new Text2("Skill Tree", { size: 120, fill: "#fff", font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); skillTitle.anchor.set(0.5, 0); skillTitle.x = 2048 / 2; skillTitle.y = 120; skillTreeOverlay.addChild(skillTitle); // Skill buttons var skillBtnW = 600; var skillBtnH = 160; var skillBtnSpacingY = 60; var skillBtnStartY = 400; var skillBtns = []; function updateSkillTreeUI() { // Remove old skill buttons for (var i = 0; i < skillBtns.length; i++) { skillBtns[i].destroy(); } skillBtns = []; // Draw skill buttons for (var i = 0; i < skillTree.length; i++) { (function (idx) { var skill = skillTree[idx]; var btn = new GameButton(); btn.setButton('upgradeBtn', skill.name + "\n($" + skill.cost + ")", "#fff", skillBtnW, skillBtnH); btn.x = 2048 / 2; btn.y = skillBtnStartY + idx * (skillBtnH + skillBtnSpacingY); // Check if all dependencies are unlocked var depsUnlocked = true; if (skill.requires && skill.requires.length > 0) { for (var d = 0; d < skill.requires.length; d++) { var depId = skill.requires[d]; var depSkill = null; for (var s = 0; s < skillTree.length; s++) { if (skillTree[s].id === depId) depSkill = skillTree[s]; } if (!depSkill || !depSkill.unlocked) depsUnlocked = false; } } btn.setEnabled(!skill.unlocked && money >= skill.cost && depsUnlocked); // Description text var descTxt = new Text2(skill.desc, { size: 48, fill: "#fff", font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); descTxt.anchor.set(0.5, 0); descTxt.x = btn.x; descTxt.y = btn.y + skillBtnH / 2 + 10; skillTreeOverlay.addChild(descTxt); skillBtns.push(descTxt); // Show dependencies visually if (skill.requires && skill.requires.length > 0) { var depText = new Text2("Requires: " + skill.requires.map(function (id) { for (var s = 0; s < skillTree.length; s++) { if (skillTree[s].id === id) return skillTree[s].name; } return id; }).join(", "), { size: 36, fill: depsUnlocked ? "#0f0" : "#f44", font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); depText.anchor.set(0.5, 0); depText.x = btn.x; depText.y = descTxt.y + 60; skillTreeOverlay.addChild(depText); skillBtns.push(depText); } // If unlocked, show "Unlocked" and disable if (skill.unlocked) { btn.label.setText(skill.name + "\n(Unlocked)"); btn.setEnabled(false); btn.bg.alpha = 0.5; } else if (!depsUnlocked) { btn.label.setText(skill.name + "\n(Locked)"); btn.setEnabled(false); btn.bg.alpha = 0.3; } btn.action = function () { if (money >= skill.cost && !skill.unlocked && depsUnlocked) { money -= skill.cost; skill.unlocked = true; if (typeof skill.effect === "function") skill.effect(); updateStats(); updateSkillTreeUI(); // Show popup var pop = new Text2("Unlocked: " + skill.name, { size: 80, fill: 0x00FF44, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); pop.anchor.set(0.5, 0.5); pop.x = btn.x; pop.y = btn.y - 120; game.addChild(pop); tween(pop, { alpha: 0, y: pop.y - 80 }, { duration: 1200, onFinish: function onFinish() { pop.destroy(); } }); } }; skillTreeOverlay.addChild(btn); skillBtns.push(btn); })(i); } } updateSkillTreeUI(); // Close button for skill tree var skillCloseBtn = new GameButton(); skillCloseBtn.setButton('editBtn', 'Close', "#fff", 400, 120); skillCloseBtn.x = 2048 / 2; skillCloseBtn.y = 2732 - navBarHeight - 100; skillCloseBtn.action = function () { skillTreeOverlay.visible = false; }; skillTreeOverlay.addChild(skillCloseBtn); // Skill Tree Section Button var navSkillBtn = new GameButton(); navSkillBtn.setButton('upgradeBtn', 'Skill Tree', "#fff", navBtnW, navBtnH); navSkillBtn.x = navVideoBtn.x + navBtnW / 2 + navBtnSpacing + navBtnW / 2; navSkillBtn.y = navBtnY; navSkillBtn.action = function () { updateSkillTreeUI(); skillTreeOverlay.visible = true; }; game.addChild(navSkillBtn); // --- 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 var statsBg = LK.getAsset('studioBg', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); statsBg.alpha = 0.98; statsOverlay.addChild(statsBg); // Title var statsTitle = new Text2("Statistics", { size: 120, fill: "#fff", font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); statsTitle.anchor.set(0.5, 0); statsTitle.x = 2048 / 2; statsTitle.y = 120; statsOverlay.addChild(statsTitle); // Graph area positions var graphStartY = 320; var graphSpacingY = 520; var graphW = 1600; var graphH = 320; var graphStartX = (2048 - graphW) / 2; // Helper to draw a clear, separate line graph for a stat (money, views, or subscribers) function drawStatLineGraph(container, data, color, iconAssetId, label, yOffset) { // Remove previous graph if (container.graphNodes) { for (var i = 0; i < container.graphNodes.length; i++) { container.graphNodes[i].destroy(); } } container.graphNodes = []; // Draw icon var icon = LK.getAsset(iconAssetId, { anchorX: 0.5, anchorY: 0.5, x: graphStartX - 80, y: yOffset + graphH / 2 }); container.addChild(icon); container.graphNodes.push(icon); // Draw label var labelTxt = new Text2(label, { size: 60, fill: "#fff", font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); labelTxt.anchor.set(0, 0.5); labelTxt.x = graphStartX; labelTxt.y = yOffset - 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 n = Math.max(1, data.length - 1); 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 = yOffset + 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 valTxt = new Text2("" + data[i], { 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 all three graphs, each as a clear, separate line graph, one below the other function updateStatsGraphs() { // Remove all previous graph nodes before drawing new ones if (statsOverlay.graphNodes) { for (var i = 0; i < statsOverlay.graphNodes.length; i++) { statsOverlay.graphNodes[i].destroy(); } } statsOverlay.graphNodes = []; // Divide the statistics screen into 3 different areas // Money graph (top section) drawStatLineGraph(statsOverlay, statsMoneyPerDay, 0xfa4b00, 'moneyIcon', "Money Earned per Day", graphStartY); // Viewership graph (middle section) drawStatLineGraph(statsOverlay, statsViewsPerDay, 0x00e0ff, 'viewersicon', "Views per Day", graphStartY + graphH + 60); // Subscriber graph (bottom section) drawStatLineGraph(statsOverlay, statsSubsPerDay, 0xffe066, 'subIcon', "Subscribers per Day", graphStartY + 2 * (graphH + 60)); } // Close button for stats overlay var statsCloseBtn = new GameButton(); statsCloseBtn.setButton('editBtn', 'Close', "#fff", 400, 120); statsCloseBtn.x = 2048 / 2; statsCloseBtn.y = 2732 - navBarHeight - 100; statsCloseBtn.action = function () { statsOverlay.visible = false; }; statsOverlay.addChild(statsCloseBtn); // Statistics Section Button var navStatsBtn = new GameButton(); navStatsBtn.setButton('editBtn', 'Statistics', "#fff", navBtnW, navBtnH); navStatsBtn.x = navSkillBtn.x + navBtnW / 2 + navBtnSpacing + navBtnW / 2; navStatsBtn.y = navBtnY; navStatsBtn.action = function () { updateStatsGraphs(); statsOverlay.visible = true; }; game.addChild(navStatsBtn); // --- 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); } // Patch into time timer: after day advances, record stats var oldTimeTimer = timeTimer; if (timeTimer) LK.clearInterval(timeTimer); timeTimer = LK.setInterval(function () { if (isTimePaused) return; gameHour += 1; if (gameHour >= 24) { gameHour = 0; gameDay += 1; recordDailyStats(); // Trending category logic... if (typeof trendingCategoryNextChangeDay === "undefined") { trendingCategoryNextChangeDay = trendingCategoryDay + 7 + Math.floor(Math.random() * 24); } if (gameDay >= trendingCategoryNextChangeDay) { updateTrendingCategory(); trendingCategoryNextChangeDay = gameDay + 7 + Math.floor(Math.random() * 24); } } updateTimeDisplay(); if (timeProcess) { timeProcess.hoursLeft -= 1; updateProcessBar(); if (timeProcess.hoursLeft <= 0) { var finish = timeProcess.onFinish; if (timeProcess.type === "edit" && timeProcess.video) { timeProcess.video.state = "readyToPublish"; timeProcess.video.publishReady = true; } timeProcess = null; updateProcessBar(); updateStats(); updateVideoLists(); if (typeof finish === "function") finish(); } } if (window.uploadedVideos) { for (var v = 0; v < window.uploadedVideos.length; v++) { var vid = window.uploadedVideos[v]; if (vid.state === "published" && vid.hour < vid.totalHours) { var viewsThisHour = vid.hourlyViews[vid.hour] || 0; var moneyThisHour = Math.floor(viewsThisHour / vid.targetViews * vid.targetMoney); var subsThisHour = Math.floor(viewsThisHour / vid.targetViews * vid.targetSubs); vid.totalViews += viewsThisHour; vid.totalMoney += moneyThisHour; vid.totalSubs += subsThisHour; viewCount += viewsThisHour; money += moneyThisHour; subscribers += subsThisHour; vid.hour++; if (vid.hour === vid.totalHours) { var leftViews = vid.targetViews - vid.totalViews; var leftMoney = vid.targetMoney - vid.totalMoney; var leftSubs = vid.targetSubs - vid.totalSubs; if (leftViews > 0) { viewCount += leftViews; vid.totalViews += leftViews; } if (leftMoney > 0) { money += leftMoney; vid.totalMoney += leftMoney; } if (leftSubs > 0) { subscribers += leftSubs; vid.totalSubs += leftSubs; } vid.finished = true; } } } } updateStats(); updateVideoLists(); }, 1000); // Record stats for day 1 at game start recordDailyStats();
===================================================================
--- original.js
+++ change.js
@@ -1067,8 +1067,51 @@
updateVideoLists();
};
}(vid);
videosListContainer.addChild(editBtn);
+ // Auto-edit button if skill unlocked and not used today
+ if (skillEffects.edit_auto && (!window._autoEditUsedDay || window._autoEditUsedDay !== gameDay)) {
+ var autoEditBtn = new GameButton();
+ autoEditBtn.setButton('upgradeBtn', 'Auto-Edit', "#fff", 220, 90);
+ autoEditBtn.x = editBtn.x + editBtn.bg.width + 40 + autoEditBtn.bg.width / 2;
+ autoEditBtn.y = editBtn.y;
+ autoEditBtn.action = function (vidRef) {
+ return function () {
+ if (timeProcess) return;
+ vidRef.state = "readyToPublish";
+ vidRef.publishReady = true;
+ if (skillEffects.edit_quality) {
+ if (!vidRef.qualityBonus) vidRef.qualityBonus = 1;
+ }
+ window._autoEditUsedDay = gameDay;
+ // Show popup
+ var autoPop = new Text2("Auto-Edit Complete!", {
+ size: 64,
+ fill: 0x00FF44,
+ font: "'GillSans-Bold',Impact,'Arial Black',Tahoma",
+ dropShadow: true,
+ dropShadowColor: "#222",
+ dropShadowBlur: 8,
+ dropShadowDistance: 2
+ });
+ autoPop.anchor.set(0.5, 0.5);
+ autoPop.x = autoEditBtn.x;
+ autoPop.y = autoEditBtn.y - 80;
+ game.addChild(autoPop);
+ tween(autoPop, {
+ alpha: 0,
+ y: autoPop.y - 60
+ }, {
+ duration: 1000,
+ onFinish: function onFinish() {
+ autoPop.destroy();
+ }
+ });
+ updateVideoLists();
+ };
+ }(vid);
+ videosListContainer.addChild(autoEditBtn);
+ }
// If this video is currently being edited, show a loading bar to the right of the edit button
if (timeProcess && timeProcess.type === "edit" && timeProcess.video === vid) {
var barW = 320;
var barH = 40;
@@ -1243,10 +1286,68 @@
// Skill: Extra Money
var moneyMult = skillEffects.extra_money ? 1.2 : 1;
// Money: $3-5 per 1000 views, distributed proportionally
var moneyThisHour = Math.floor(viewsThisHour / vid.targetViews * vid.targetMoney * totalQuality * moneyMult);
+ // Sponsor deals: extra money for videos with >10k views if unlocked
+ if (skillEffects.sponsor_deals && vid.totalViews + viewsThisHour > 10000 && !vid._sponsorGiven) {
+ var sponsorBonus = Math.floor(vid.targetMoney * 0.5);
+ moneyThisHour += sponsorBonus;
+ vid._sponsorGiven = true;
+ // Show sponsor popup
+ var sponsorPop = new Text2("Sponsor Deal!\n+$" + formatNumber(sponsorBonus), {
+ size: 80,
+ fill: 0xFA4B00,
+ font: "'GillSans-Bold',Impact,'Arial Black',Tahoma",
+ dropShadow: true,
+ dropShadowColor: "#222",
+ dropShadowBlur: 8,
+ dropShadowDistance: 2
+ });
+ sponsorPop.anchor.set(0.5, 0.5);
+ sponsorPop.x = 2048 / 2;
+ sponsorPop.y = 700;
+ game.addChild(sponsorPop);
+ tween(sponsorPop, {
+ alpha: 0,
+ y: sponsorPop.y - 80
+ }, {
+ duration: 1200,
+ onFinish: function onFinish() {
+ sponsorPop.destroy();
+ }
+ });
+ }
// Subs: proportional to views, distributed over time
var subsThisHour = Math.floor(viewsThisHour / vid.targetViews * vid.targetSubs * totalQuality);
+ // Collab boost: big sub boost for first video after unlock
+ if (skillEffects.collab_boost && !vid._collabGiven) {
+ var collabBonus = Math.floor(vid.targetSubs * 0.5);
+ subsThisHour += collabBonus;
+ vid._collabGiven = true;
+ // Show collab popup
+ var collabPop = new Text2("Collab Boost!\n+" + formatNumber(collabBonus) + " subs", {
+ size: 80,
+ fill: 0x00FF44,
+ font: "'GillSans-Bold',Impact,'Arial Black',Tahoma",
+ dropShadow: true,
+ dropShadowColor: "#222",
+ dropShadowBlur: 8,
+ dropShadowDistance: 2
+ });
+ collabPop.anchor.set(0.5, 0.5);
+ collabPop.x = 2048 / 2;
+ collabPop.y = 800;
+ game.addChild(collabPop);
+ tween(collabPop, {
+ alpha: 0,
+ y: collabPop.y - 80
+ }, {
+ duration: 1200,
+ onFinish: function onFinish() {
+ collabPop.destroy();
+ }
+ });
+ }
vid.totalViews += viewsThisHour;
vid.totalMoney += moneyThisHour;
vid.totalSubs += subsThisHour;
viewCount += viewsThisHour;
@@ -1362,62 +1463,100 @@
// Scroll to or focus video section (no-op for now)
};
game.addChild(navVideoBtn);
// --- Skill Tree System ---
-// Skill definitions
+// Skill definitions with dependencies and branches
var skillTree = [{
id: "faster_record",
name: "Faster Recording",
desc: "Record videos 30% faster.",
cost: 100,
unlocked: false,
effect: function effect() {
skillEffects.faster_record = true;
- }
+ },
+ requires: []
}, {
id: "faster_edit",
name: "Faster Editing",
desc: "Edit videos 30% faster.",
cost: 120,
unlocked: false,
effect: function effect() {
skillEffects.faster_edit = true;
- }
+ },
+ requires: []
}, {
id: "extra_money",
name: "Ad Revenue Boost",
desc: "Earn 20% more money from videos.",
cost: 200,
unlocked: false,
effect: function effect() {
skillEffects.extra_money = true;
- }
+ },
+ requires: ["faster_record"]
}, {
id: "viral_chance",
name: "Viral Chance",
desc: "Small chance for videos to go viral (3x views).",
cost: 300,
unlocked: false,
effect: function effect() {
skillEffects.viral_chance = true;
- }
+ },
+ requires: ["extra_money"]
}, {
id: "edit_quality",
name: "Editing Mastery",
desc: "Editing increases video quality by 1.",
cost: 250,
unlocked: false,
effect: function effect() {
skillEffects.edit_quality = true;
- }
+ },
+ requires: ["faster_edit"]
+}, {
+ id: "sponsor_deals",
+ name: "Sponsor Deals",
+ desc: "Unlock sponsor offers for extra money.",
+ cost: 500,
+ unlocked: false,
+ effect: function effect() {
+ skillEffects.sponsor_deals = true;
+ },
+ requires: ["extra_money"]
+}, {
+ id: "collab_boost",
+ name: "Collab Boost",
+ desc: "Collaborations give a big subscriber boost.",
+ cost: 700,
+ unlocked: false,
+ effect: function effect() {
+ skillEffects.collab_boost = true;
+ },
+ requires: ["viral_chance"]
+}, {
+ id: "edit_auto",
+ name: "Auto-Edit",
+ desc: "Auto-edit videos instantly (once per day).",
+ cost: 900,
+ unlocked: false,
+ effect: function effect() {
+ skillEffects.edit_auto = true;
+ },
+ requires: ["edit_quality"]
}];
// Skill effect flags
var skillEffects = {
faster_record: false,
faster_edit: false,
extra_money: false,
viral_chance: false,
- edit_quality: false
+ edit_quality: false,
+ sponsor_deals: false,
+ collab_boost: false,
+ edit_auto: false
};
// Skill Tree Overlay UI
var skillTreeOverlay = new Container();
skillTreeOverlay.visible = false;
@@ -1462,9 +1601,21 @@
var btn = new GameButton();
btn.setButton('upgradeBtn', skill.name + "\n($" + skill.cost + ")", "#fff", skillBtnW, skillBtnH);
btn.x = 2048 / 2;
btn.y = skillBtnStartY + idx * (skillBtnH + skillBtnSpacingY);
- btn.setEnabled(!skill.unlocked && money >= skill.cost);
+ // Check if all dependencies are unlocked
+ var depsUnlocked = true;
+ if (skill.requires && skill.requires.length > 0) {
+ for (var d = 0; d < skill.requires.length; d++) {
+ var depId = skill.requires[d];
+ var depSkill = null;
+ for (var s = 0; s < skillTree.length; s++) {
+ if (skillTree[s].id === depId) depSkill = skillTree[s];
+ }
+ if (!depSkill || !depSkill.unlocked) depsUnlocked = false;
+ }
+ }
+ btn.setEnabled(!skill.unlocked && money >= skill.cost && depsUnlocked);
// Description text
var descTxt = new Text2(skill.desc, {
size: 48,
fill: "#fff",
@@ -1474,16 +1625,38 @@
descTxt.x = btn.x;
descTxt.y = btn.y + skillBtnH / 2 + 10;
skillTreeOverlay.addChild(descTxt);
skillBtns.push(descTxt);
+ // Show dependencies visually
+ if (skill.requires && skill.requires.length > 0) {
+ var depText = new Text2("Requires: " + skill.requires.map(function (id) {
+ for (var s = 0; s < skillTree.length; s++) {
+ if (skillTree[s].id === id) return skillTree[s].name;
+ }
+ return id;
+ }).join(", "), {
+ size: 36,
+ fill: depsUnlocked ? "#0f0" : "#f44",
+ font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
+ });
+ depText.anchor.set(0.5, 0);
+ depText.x = btn.x;
+ depText.y = descTxt.y + 60;
+ skillTreeOverlay.addChild(depText);
+ skillBtns.push(depText);
+ }
// If unlocked, show "Unlocked" and disable
if (skill.unlocked) {
btn.label.setText(skill.name + "\n(Unlocked)");
btn.setEnabled(false);
btn.bg.alpha = 0.5;
+ } else if (!depsUnlocked) {
+ btn.label.setText(skill.name + "\n(Locked)");
+ btn.setEnabled(false);
+ btn.bg.alpha = 0.3;
}
btn.action = function () {
- if (money >= skill.cost && !skill.unlocked) {
+ if (money >= skill.cost && !skill.unlocked && depsUnlocked) {
money -= skill.cost;
skill.unlocked = true;
if (typeof skill.effect === "function") skill.effect();
updateStats();
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
çöp kutusu logosu fakat kırmızı arka planlı (çö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