JavaScript must be enabled to play.
Browser lacks capabilities required to play.
Upgrade or switch to another browser.
Loading…
<<set $player = { name: "Alex", money: 15000, reputation: 1, day: 1 }>> <<set $archetype = "">> <<set $charismaticSatBonus = 0>> <<set $studioName = "Thunder Agency">> <<set $easyMode = false>> <<set $shootingPlayedToday = false>> <<set $allPositions = [ { name: "BJ", price: 0, repMin: 0, unlocked: true, level: 1, minSat: 0 }, { name: "Missionary", price: 500, repMin: 10, unlocked: false, level: 2, minSat: 10 }, { name: "Doggy", price: 800, repMin: 20, unlocked: false, level: 3, minSat: 20 }, { name: "Cowgirl", price: 1200, repMin: 30, unlocked: false, level: 4, minSat: 30 }, { name: "Reverse Cowgirl",price: 1500, repMin: 40, unlocked: false, level: 5, minSat: 40 }, { name: "Spooning", price: 1800, repMin: 50, unlocked: false, level: 6, minSat: 50 }, { name: "Specialty 1", price: 2000, repMin: 0, unlocked: false, level: 7, minSat: 60 }, { name: "Specialty 2", price: 2500, repMin: 0, unlocked: false, level: 8, minSat: 70 }, { name: "Facial", price: 3000, repMin: 0, unlocked: false, level: 9, minSat: 80 } ]>> <<set $playerPositions = ["BJ"]>> <<set $adItem = { name: "AD", price: 3000, repMin: 0, bought: false, repBonus: 7, buyCount: 0 }>> <<set $doublePositionItem = { name: "Double Feature", price: 5000, repMin: 50, bought: false }>> <<set $marketStudyItem = { name: "Market Study", price: 4000, repMin: 25, bought: false }>> <<set $pool1UpgradeItem = { name: "Established Dip", price: 2500, repMin: 5, bought: false }>> <<set $pool1Upgrade2A = { name: "Established Surge", price: 5000, repMin: 0, bought: false }>> <<set $pool1Upgrade2B = { name: "Double Scouting", price: 2000, repMin: 10, bought: false }>> <<set $pool1Upgrade2C = { name: "Triple Scouting", price: 3000, repMin: 0, bought: false }>> <<set $pool1Upgrade2D = { name: "Quadruple Scouting", price: 4000, repMin: 0, bought: false }>> <<set $targetedScoutItem = { name: "Targeted Scout", price: 500, bought: false }>> <<set $targetedScoutStar = "">> <<set $pool2UpgradeItem = { name: "Elite Dip", price: 6000, repMin: 20, bought: false }>> <<set $pool1IntelItem = { name: "Pool 1 Intel", price: 500, bought: false }>> <<set $pool2IntelItem = { name: "Pool 2 Intel", price: 500, bought: false }>> <<set $pool3IntelItem = { name: "Pool 3 Intel", price: 500, bought: false }>> <<set $pool2Upgrade2 = { name: "Elite Surge", price: 10000, repMin: 30, bought: false }>> <<set $satisfactionDelayItem = { name: "Patience Training", price: 3500, repMin: 50, bought: false }>> <<set $poolBeginner = []>> <<set $poolConfirmed = []>> <<set $poolElite = []>> <<set $poolSpecial = null>> <<set $bonusEventStar = "">> <<set $rivalStartStar = "">> <<set $bnoEventDone = false>> <<set $day18EventDone = false>> <<set $day30EventDone = false>> <<set $rivalVideoPrefix = "">> <<set $rivalOriginalName = "">> <<set $pool2Stolen = false>> <<set $drawResult = []>> <<set $drawLuckyNames = []>> <<set $drawEliteNames = []>> <<set $drawPool = "">> <<set $drawSignName = "">> <<set $drawCount = 1>> <<set $drawCost = 200>> /* popularity = initial stat, grows with productions weekly upkeep = popularity * 70 $ repMin scales with popularity */ <<set $recruitPool = [ { name: "Octavia", favPosition: "Spooning", bonusPosition1: "Doggy", bonusPosition2: "BJ", bonusChosen: false, specialty1: "Standing", specialty2: "Titfuck", contractCost: 3000, popularity: 5, satisfaction: 12, weekShootings: 0, lastShootingDay: 0, consecutiveDays: 0, restDay: false, lowSatAlerted: false, available: true, repMin: 0, hair: "Blonde", height: "Medium", ageNum: 28, ageCat: "Neutral",breast: "Large", breastType: "Real", ethnicity: "Caucasian" }, { name: "Summers", favPosition: "Cowgirl", bonusPosition1: "Missionary", bonusPosition2: "Spooning", bonusChosen: false, specialty1: "", specialty2: "", contractCost: 2500, popularity: 4, satisfaction: 12, weekShootings: 0, lastShootingDay: 0, consecutiveDays: 0, restDay: false, lowSatAlerted: false, available: true, repMin: 0, hair: "Black", height: "Medium", ageNum: 42, ageCat: "Veteran",breast: "Small", breastType: "Real", ethnicity: "Caucasian" }, { name: "Kira", favPosition: "69", bonusPosition1: "Doggy", bonusPosition2: "Missionary", bonusChosen: false, specialty1: "Standing", specialty2: "", contractCost: 2000, popularity: 3, satisfaction: 12, weekShootings: 0, lastShootingDay: 0, consecutiveDays: 0, restDay: false, lowSatAlerted: false, available: true, repMin: 0, hair: "Brown", height: "Short", ageNum: 25, ageCat: "Neutral",breast: "Medium", breastType: "Real", ethnicity: "Latina" }, { name: "Ava", favPosition: "69", bonusPosition1: "Standing Up", bonusPosition2: "Reverse Cowgirl",bonusChosen: false, specialty1: "Standing", specialty2: "", contractCost: 4000, popularity: 8, satisfaction: 12, weekShootings: 0, lastShootingDay: 0, consecutiveDays: 0, restDay: false, lowSatAlerted: false, available: true, repMin: 10, hair: "Brown", height: "Medium", ageNum: 40, ageCat: "Veteran",breast: "Huge", breastType: "Fake", ethnicity: "Caucasian" }, { name: "Brittney", favPosition: "Doggy", bonusPosition1: "Standing Up", bonusPosition2: "BJ", bonusChosen: false, specialty1: "Titfuck", specialty2: "Standing", contractCost: 3500, popularity: 6, satisfaction: 12, weekShootings: 0, lastShootingDay: 0, consecutiveDays: 0, restDay: false, lowSatAlerted: false, available: true, repMin: 10, hair: "Black", height: "Short", ageNum: 20, ageCat: "Young", breast: "Huge", breastType: "Real", ethnicity: "Black" }, { name: "Jada", favPosition: "Doggy", bonusPosition1: "Reverse Cowgirl", bonusPosition2: "69", bonusChosen: false, specialty1: "Titfuck", specialty2: "", contractCost: 30000, popularity: 30, satisfaction: 12, weekShootings: 0, lastShootingDay: 0, consecutiveDays: 0, restDay: false, lowSatAlerted: false, available: true, repMin: 0, hair: "Black", height: "Medium", ageNum: 28, ageCat: "Neutral", breast: "Large", breastType: "Fake", ethnicity: "Black" }, { name: "Gabbie", favPosition: "Standing Up", bonusPosition1: "Missionary", bonusPosition2: "Cowgirl", bonusChosen: false, specialty1: "Standing", specialty2: "Titfuck", contractCost: 3500, popularity: 9, satisfaction: 12, weekShootings: 0, lastShootingDay: 0, consecutiveDays: 0, restDay: false, lowSatAlerted: false, available: false, repMin: 999, hair: "Blonde", height: "Medium", ageNum: 20, ageCat: "Young", breast: "Large", breastType: "Real", ethnicity: "Caucasian" }, { name: "Sharon", favPosition: "Spooning", bonusPosition1: "Cowgirl", bonusPosition2: "69", bonusChosen: false, specialty1: "Titfuck", specialty2: "Anal", contractCost: 6000, popularity: 12, satisfaction: 12, weekShootings: 0, lastShootingDay: 0, consecutiveDays: 0, restDay: false, lowSatAlerted: false, available: true, repMin: 12, hair: "Brown", height: "Medium", ageNum: 29, ageCat: "Neutral",breast: "Large", breastType: "Real", ethnicity: "Asian" }, { name: "Sirena", favPosition: "DP", bonusPosition1: "Reverse Cowgirl",bonusPosition2: "Spooning", bonusChosen: false, specialty1: "Titfuck", specialty2: "Anal", contractCost: 7000, popularity: 15, satisfaction: 12, weekShootings: 0, lastShootingDay: 0, consecutiveDays: 0, restDay: false, lowSatAlerted: false, available: true, repMin: 15, hair: "Brown", height: "Short", ageNum: 30, ageCat: "Neutral",breast: "Medium", breastType: "Fake", ethnicity: "Latina" }, { name: "Lena", favPosition: "Spooning", bonusPosition1: "Cowgirl", bonusPosition2: "Standing Up", bonusChosen: false, specialty1: "Anal", specialty2: "Titfuck", contractCost: 9000, popularity: 20, satisfaction: 12, weekShootings: 0, lastShootingDay: 0, consecutiveDays: 0, restDay: false, lowSatAlerted: false, available: true, repMin: 20, hair: "Blonde", height: "Medium", ageNum: 26, ageCat: "Neutral",breast: "Huge", breastType: "Real", ethnicity: "Caucasian" }, { name: "Eliza", favPosition: "Reverse Cowgirl", bonusPosition1: "69", bonusPosition2: "DP", bonusChosen: false, specialty1: "Standing", specialty2: "", contractCost: 8000, popularity: 18, satisfaction: 12, weekShootings: 0, lastShootingDay: 0, consecutiveDays: 0, restDay: false, lowSatAlerted: false, available: true, repMin: 18, hair: "Black", height: "Tall", ageNum: 28, ageCat: "Neutral",breast: "Medium", breastType: "Real", ethnicity: "Latina" }, { name: "Angela", favPosition: "DP", bonusPosition1: "69", bonusPosition2: "Doggy", bonusChosen: false, specialty1: "Anal", specialty2: "Titfuck", contractCost: 15000, popularity: 30, satisfaction: 12, weekShootings: 0, lastShootingDay: 0, consecutiveDays: 0, restDay: false, lowSatAlerted: false, available: true, repMin: 30, hair: "Brown", height: "Medium", ageNum: 36, ageCat: "Veteran",breast: "Huge", breastType: "Real", ethnicity: "Caucasian" }, { name: "Skylar", favPosition: "DP", bonusPosition1: "Spooning", bonusPosition2: "Reverse Cowgirl",bonusChosen: false, specialty1: "Titfuck", specialty2: "", contractCost: 20000, popularity: 40, satisfaction: 12, weekShootings: 0, lastShootingDay: 0, consecutiveDays: 0, restDay: false, lowSatAlerted: false, available: true, repMin: 40, hair: "Blonde", height: "Medium", ageNum: 27, ageCat: "Neutral",breast: "Huge", breastType: "Real", ethnicity: "Caucasian" }, { name: "Lulu", favPosition: "DP", bonusPosition1: "Reverse Cowgirl", bonusPosition2: "Spooning", bonusChosen: false, specialty1: "Anal", specialty2: "", contractCost: 25000, popularity: 25, satisfaction: 12, weekShootings: 0, lastShootingDay: 0, consecutiveDays: 0, restDay: false, lowSatAlerted: false, available: true, repMin: 0, hair: "Black", height: "Short", ageNum: 22, ageCat: "Young", breast: "Small", breastType: "Real", ethnicity: "Asian" }, { name: "Alina", favPosition: "69", bonusPosition1: "DP",bonusPosition2: "Doggy", bonusChosen: false, specialty1: "Standing", specialty2: "", contractCost: 28000, popularity: 27, satisfaction: 12, weekShootings: 0, lastShootingDay: 0, consecutiveDays: 0, restDay: false, lowSatAlerted: false, available: true, repMin: 0, hair: "Black", height: "Medium", ageNum: 29, ageCat: "Neutral", breast: "Small", breastType: "Real", ethnicity: "Latina" }, { name: "Caprice", favPosition: "Reverse Cowgirl", bonusPosition1: "Cowgirl", bonusPosition2: "69", bonusChosen: false, specialty1: "Standing", specialty2: "Anal", contractCost: 22000, popularity: 26, satisfaction: 12, weekShootings: 0, lastShootingDay: 0, consecutiveDays: 0, restDay: false, lowSatAlerted: false, available: true, repMin: 0, hair: "Brown", height: "Short", ageNum: 21, ageCat: "Young", breast: "Small", breastType: "Real", ethnicity: "Caucasian" }, { name: "Valentina", favPosition: "BJ", bonusPosition1: "Missionary", bonusPosition2: "Standing Up", bonusChosen: false, specialty1: "Anal", specialty2: "", contractCost: 30000, popularity: 30, satisfaction: 12, weekShootings: 0, lastShootingDay: 0, consecutiveDays: 0, restDay: false, lowSatAlerted: false, available: true, repMin: 0, hair: "Brown", height: "Medium", ageNum: 29, ageCat: "Neutral", breast: "Medium", breastType: "Real", ethnicity: "Caucasian" }, { name: "Kimmy", favPosition: "Spooning", bonusPosition1: "69", bonusPosition2: "Standing Up", bonusChosen: false, specialty1: "Standing", specialty2: "", contractCost: 24000, popularity: 25, satisfaction: 12, weekShootings: 0, lastShootingDay: 0, consecutiveDays: 0, restDay: false, lowSatAlerted: false, available: true, repMin: 0, hair: "Black", height: "Short", ageNum: 29, ageCat: "Neutral", breast: "Small", breastType: "Real", ethnicity: "Asian" }, { name: "Vicky", favPosition: "Standing Up", bonusPosition1: "DP",bonusPosition2: "BJ", bonusChosen: false, specialty1: "Titfuck", specialty2: "Anal", contractCost: 32000, popularity: 28, satisfaction: 12, weekShootings: 0, lastShootingDay: 0, consecutiveDays: 0, restDay: false, lowSatAlerted: false, available: true, repMin: 0, hair: "Blonde", height: "Medium", ageNum: 35, ageCat: "Veteran", breast: "Huge", breastType: "Fake", ethnicity: "Caucasian" }, { name: "Blake", favPosition: "BJ", bonusPosition1: "Cowgirl", bonusPosition2: "Missionary", bonusChosen: false, specialty1: "Titfuck", specialty2: "Standing", contractCost: 5000, popularity: 10, satisfaction: 12, weekShootings: 0, lastShootingDay: 0, consecutiveDays: 0, restDay: false, lowSatAlerted: false, available: true, repMin: 0, hair: "Blonde", height: "Tall", ageNum: 27, ageCat: "Neutral", breast: "Large", breastType: "Real", ethnicity: "Caucasian" }, { name: "Angie", favPosition: "Missionary", bonusPosition1: "BJ", bonusPosition2: "Cowgirl", bonusChosen: false, specialty1: "Anal", specialty2: "", contractCost: 4500, popularity: 8, satisfaction: 12, weekShootings: 0, lastShootingDay: 0, consecutiveDays: 0, restDay: false, lowSatAlerted: false, available: true, repMin: 0, hair: "Brown", height: "Medium", ageNum: 24, ageCat: "Neutral", breast: "Medium", breastType: "Real", ethnicity: "Caucasian" }, { name: "Eve", favPosition: "Missionary", bonusPosition1: "Cowgirl", bonusPosition2: "Doggy", bonusChosen: false, specialty1: "", specialty2: "", contractCost: 0, popularity: 0, satisfaction: 12, weekShootings: 0, lastShootingDay: 0, consecutiveDays: 0, restDay: false, lowSatAlerted: false, available: false, repMin: 999, tier: "elite", hair: "Black", height: "Short", ageNum: 21, ageCat: "Young", breast: "Medium", breastType: "Real", ethnicity: "Caucasian" } ]>> <<set $roster = []>> <<set $rival = { name: "Iron Studio", money: 60000, reputation: 8, roster: [] }>> <<set $trends = { position: "", carType: "", carValue: "", carType2: "", carValue2: "", bonusRep: 0 }>> /* ── Contest Judges ── */ <<set $judges = [ { name: "Will", portrait: "will" }, { name: "Kayden", portrait: "kayden" }, { name: "Derek", portrait: "derek" }, { name: "Greg", portrait: "greg" }, { name: "Ricky", portrait: "ricky" }, { name: "Axel", portrait: "axel" } ]>> <<for _ji = 0; _ji < $judges.length; _ji++>> <<set _jTraitPool = [ "hair:Brown","hair:Brown","hair:Blonde","hair:Blonde","hair:Black","hair:Black", "height:Short","height:Short","height:Tall","height:Tall", "ageCat:Young","ageCat:Young","ageCat:Veteran","ageCat:Veteran", "breast:Small","breast:Small","breast:Large","breast:Large","breast:Huge","breast:Huge", "breastType:Fake","breastType:Fake","breastType:Fake","breastType:Real", "ethnicity:Latina","ethnicity:Latina","ethnicity:Asian","ethnicity:Asian","ethnicity:Black","ethnicity:Caucasian" ]>> <<set _jLike1Pick = _jTraitPool[random(0, _jTraitPool.length - 1)]>> <<set _jTraitPool = _jTraitPool.filter(function(p){ return p.split(":")[0] !== _jLike1Pick.split(":")[0]; })>> <<set _jLike2Pick = _jTraitPool[random(0, _jTraitPool.length - 1)]>> <<set _jTraitPool = _jTraitPool.filter(function(p){ return p.split(":")[0] !== _jLike2Pick.split(":")[0]; })>> <<set _jHate1Pick = _jTraitPool[random(0, _jTraitPool.length - 1)]>> <<set _jTraitPool = _jTraitPool.filter(function(p){ return p.split(":")[0] !== _jHate1Pick.split(":")[0]; })>> <<set _jHate2Pick = _jTraitPool[random(0, _jTraitPool.length - 1)]>> <<set _jPosPool = $allPositions.filter(function(p){ return p.name !== "Specialty 1" && p.name !== "Specialty 2"; }).map(function(p){ return p.name; }).concat(["Anal","Titfuck","Standing"])>> <<set _jPosLike = _jPosPool.splice(random(0, _jPosPool.length - 1), 1)[0]>> <<set _jPosHate = _jPosPool[random(0, _jPosPool.length - 1)]>> <<set $judges[_ji].pref = { likePhysical: [ { type: _jLike1Pick.split(":")[0], value: _jLike1Pick.split(":")[1] }, { type: _jLike2Pick.split(":")[0], value: _jLike2Pick.split(":")[1] } ], hatePhysical: [ { type: _jHate1Pick.split(":")[0], value: _jHate1Pick.split(":")[1] }, { type: _jHate2Pick.split(":")[0], value: _jHate2Pick.split(":")[1] } ], likePosition: _jPosLike, hatePosition: _jPosHate, revealed: { likePhysical: [false, false], hatePhysical: [false, false], likePosition: false, hatePosition: false } }>> <</for>> <<set $contestJudges = []>> <<set $contestJudgesKnown = false>> <<set $contestJudgesRevealed = false>> <<set $contestPending = false>> <<set $contestIntroSeen = false>> <<set $contestJoined = false>> <<set $contestStars = []>> <<set $contestChosenStar = "">> <<set $contestChosenPosition = "">> <<set $contestNextDay = 35>> <<set $contestPick1 = -1>> <<set $judgeIntel1 = { price: 400, buyCount: 0 }>> <<set $improveIntelItem = { price: 1500, bought: false }>> <<set $judgeIntel2 = { price: 700, buyCount: 0 }>> <<set $permanentJudgeIntelItem = { price: 3000, bought: false }>> <<set $unlockJudgeStatItem = { price: 800, buyCount: 0 }>> <<set $guessJudgeStatItem = { price: 300, buyCount: 0 }>> <<set $guessStatUsedDay = 0>> <<set $judgeStatPickIdx = -1>> <<set $guessSlotCat = "">> <<set $guessSlotIdx = -1>> <<set $guessOptions = []>> <<set $guessCorrectValue = "">> <<set $guessResult = "">> <<set $judgeSpecialShoots = [ { triggerDay: 44, active: false, done: false, judgeIdx: -1, reqTraitType: "", reqTraitValue: "", reqPosition: "", favIsTrait: false, favTraitIdx: -1, deadlineDay: -1 }, { triggerDay: 51, active: false, done: false, judgeIdx: -1, reqTraitType: "", reqTraitValue: "", reqPosition: "", favIsTrait: false, favTraitIdx: -1, deadlineDay: -1 }, { triggerDay: 58, active: false, done: false, judgeIdx: -1, reqTraitType: "", reqTraitValue: "", reqPosition: "", favIsTrait: false, favTraitIdx: -1, deadlineDay: -1 }, { triggerDay: 65, active: false, done: false, judgeIdx: -1, reqTraitType: "", reqTraitValue: "", reqPosition: "", favIsTrait: false, favTraitIdx: -1, deadlineDay: -1 } ]>> <<set $judgeSpecialPending = -1>> <<set $newJudgeSpecialReveal = "">> <<set $judgeSpecialMissed = "">> <<set $totalContestsCompleted = 0>> <<set $contestJudgeRevealed = [false, false]>> <<set $shootingC1 = -1>> <<set $shootingC2 = -1>> <<set $advancedFormat = false>> <<set $selectedPositions = []>> <<set $positionToAdd = "">> <<set $shootingLastPosition = "">> <<set $shootingW1File = "">> <<set $shootingW2File = "">> <<set $positionIndex = 0>> <<set $recruitIndex = 0>> <<set $poachMessage = "">> <<set $poachVideoStar = "">> <<set $rosterMessage = "">> <<set $zeroSatStar = "">> <<set $rivalFirstPick = "">> <<set $rivalLastShooting = null>> <<set $popularityAlert = "">> <<set $lastPopGain = []>> <<set $bonusChoiceStar = "">> <<set $roxyEventTriggered = false>> <<set $roxyEventPending = false>> <<set $contract1 = { active: false, accepted: false, criteria: "", criteriaType: "", options: [], shootingsDone: 0, startDay: -1, failed: false }>> <<set $contractShopAvailable = false>> <<set $trophies = { fullHouse: false, empire: false, dealMaker: false, harderDeal: false, asianDuoComplete: false, fallenAngelsComplete: false, sweetCapriceComplete: false, first100Sat: false, firstMillion: false, brokeBurBack: false, firstPoach: false, poachMaster: false, perfectJudge: false, fullPanel: false, contestRegular: false, totalPackage: false, allTrophies: false }>> <<set $totalContractsCompleted = 0>> <<set $totalEarnings = 0>> <<set $newTrophy = "">> <<set $poachingInvestments = {}>> <<set $poachAttempts = {}>> <<set $totalPoachingSteps = 0>> <<set $lastPoachStepDay = -1>> <<set $lastPoachDay = -1>> <<set $totalPoachesSucceeded = 0>> <<set $rivalAggression = 0>> <<set $rivalSabotageStar = "">> <<set $poachingUnlocked = false>> <<set $contractShopPrice = 200>> <<set $contractShopAvailableDay = -1>> <<set $contract3rdOptionItem = { name: "3rd Option", price: 500, bought: false }>> <<set $contractHarderItem = { name: "Harder Contract", price: 1500, bought: false }>> <<set $contractIsHarder = false>> <<set $contract1.criteria2 = "">> <<set $contract1.criteriaType2 = "">> <<set $contract3 = { active: false, accepted: false, shootingsDone: 0, startDay: -1, failed: false, starName: "" }>> <<set $contract3Success = false>> <<set $contract4 = { active: false, accepted: false, star1: "", star2: "", shootingsDone: 0, failed: false }>> <<set $contract4Success = false>> <<set $contract5 = { active: false, accepted: false, star1: "", star2: "", shootingsDone: 0, failed: false, startDay: -1, everTriggered: false }>> <<set $contract5Success = false>> <<set $asianDuoLastShootingDay = -1>> <<set $asianDuoShoot1Day = -1>> <<set $asianDuoShoot2Unlocked = false>> <<set $capriceShoot1Day = -1>> <<set $capriceShoot2Unlocked = false>> <<set $fallenAngelsShoot1Day = -1>> <<set $fallenAngelsShoot2Day = -1>> <<set $fallenAngelsShoot2Unlocked = false>> <<set $fallenAngelsShoot3Unlocked = false>> <<set $asianDuoAbsentDay = -1>> <<set $asianDuoAbsentNotified = false>> <<set $asianDuoGoneDay = -1>> <<set $asianDuoGoneNotified = false>> <<set $asianDuoWebm2Day = -1>> <<set $asianDuoWebm3Day = -1>> <<set $fallenAngelsLastShootingDay = -1>> <<set $fallenAngelsAbsentDay = -1>> <<set $fallenAngelsAbsentNotified = false>> <<set $fallenAngelsGoneDay = -1>> <<set $fallenAngelsGoneNotified = false>> <<set $fallenAngelsWebm2Day = -1>> <<set $fallenAngelsWebm3Day = -1>> <<set $questlines = { asianDuo: { id: "asianDuo", name: "Asian Duo", active: false, step: 0, star1: "", star2: "", specialAvailable: false, shooting1Done: false, shooting2Done: false }, fallenAngels: { id: "fallenAngels", name: "Two Fallen Angels", active: false, step: 0, star1: "", star2: "", specialAvailable: false, shooting1Done: false, shooting2Done: false, shooting3Done: false }, sweetCaprice: { id: "sweetCaprice", name: "Sweet Caprice", active: false, step: 0, bjCount: 0, step2Notified: false, step3Notified: false, step4Notified: false, eveNotifyDay: -1, specialAvailable: false, shooting1Done: false, shooting2Done: false } }>> <<set $contract1Success = false>> <<set $rivalOfferStar = "">> <<set $rivalOfferShootingsLeft = 0>> <<set $rivalOfferDeadlineDay = -1>> <<set $thirdRecruitDay = -1>> <<set $rivalPoachEvent = false>> <<set $rivalOfferStar = "">> <<set $rivalOfferIdx = -1>> <<set $rivalOfferChallenge = false>> <<set $rivalOfferShootingsDone = 0>> <<set $rivalOfferChallengeWon = false>> <<set $rep15EventDone = false>> <<set $rep15EventPending = false>> <<set $day22EventDone = false>> <<set $day25EventDone = false>> <<set $day22Idx = -1>> <<set $day22Pop = 0>> <<set $day22Price = 0>> <<set $objective1Done = false>> <<set $objective1Notified = false>> <<set $gameOver = false>> <<set $skillfulChallengeActive = false>> <<set $skillfulChallengeEndDay = -1>> <<set $skillfulChallengeWon = false>> <<set $vacationStar = "">> <<set $vacationEndDay = -1>> <<set $lastGain = 0>> <<set $lastRepBonus = 0>> <<set $lastMulti = 1.0>> <<set $lastDoubleFeatureMulti = 1.0>> <<set $lastPositionBonus = false>> <<set $lastCarBonus = "">> <<set $lastCarBonus2 = "">> <<set $allowedPositions = 1>> <<set $weeklyPaid = 0>> <<set $shopSortCol = "name">> <<set $recruitSortCol = "name">> <<set $rosterSortCol = "name">> <<set $profileIndex = 0>> <<set $advancedThreshold = 25>> /* ════════════════════════════════════════════ WIDGET : calcAllowedPositions ════════════════════════════════════════════ */ <<widget "calcAllowedPositions">> <<if $doublePositionItem.bought>> <<set $allowedPositions = 2>> <<else>> <<set $allowedPositions = 1>> <</if>> <</widget>> /* ════════════════════════════════════════════ WIDGET : genTrends ════════════════════════════════════════════ */ <<widget "genTrends">> <<set _posWeightList = []>> <<if $player.day <= 10>> <<set _posWeightList = [["BJ",5],["Missionary",4],["Doggy",3],["Cowgirl",2],["Reverse Cowgirl",1],["Spooning",1],["Facial",1],["Anal",1],["Titfuck",1],["Standing",1]]>> <<elseif $player.day <= 20>> <<set _posWeightList = [["BJ",4],["Missionary",4],["Doggy",3],["Cowgirl",2],["Reverse Cowgirl",2],["Spooning",1],["Facial",1],["Anal",1],["Titfuck",1],["Standing",1]]>> <<elseif $player.day <= 30>> <<set _posWeightList = [["BJ",3],["Missionary",3],["Doggy",3],["Cowgirl",2],["Reverse Cowgirl",2],["Spooning",2],["Facial",1],["Anal",1],["Titfuck",1],["Standing",1]]>> <<elseif $player.day <= 40>> <<set _posWeightList = [["BJ",2],["Missionary",2],["Doggy",2],["Cowgirl",2],["Reverse Cowgirl",2],["Spooning",2],["Facial",1],["Anal",2],["Titfuck",2],["Standing",2]]>> <<else>> <<set _posWeightList = [["BJ",1],["Missionary",1],["Doggy",1],["Cowgirl",1],["Reverse Cowgirl",1],["Spooning",1],["Facial",1],["Anal",1],["Titfuck",1],["Standing",1]]>> <</if>> <<set _weightedPositions = []>> <<for _pi = 0; _pi < _posWeightList.length; _pi++>> <<set _pEntry = _posWeightList[_pi]>> <<for _pw = 0; _pw < _pEntry[1]; _pw++>> <<set _weightedPositions.push(_pEntry[0])>> <</for>> <</for>> <<set $trends.position = _weightedPositions[random(0, _weightedPositions.length - 1)]>> <<set _tPool = [ "hair:Brown","hair:Brown","hair:Blonde","hair:Blonde","hair:Black","hair:Black", "height:Short","height:Short","height:Tall","height:Tall", "ageCat:Young","ageCat:Young","ageCat:Veteran","ageCat:Veteran", "breast:Small","breast:Small","breast:Large","breast:Large","breast:Huge","breast:Huge", "breastType:Fake","breastType:Fake","breastType:Fake","breastType:Real", "ethnicity:Latina","ethnicity:Latina","ethnicity:Asian","ethnicity:Asian","ethnicity:Black","ethnicity:Caucasian" ]>> <<set _tPick = _tPool[random(0, _tPool.length - 1)]>> <<set $trends.carType = _tPick.split(":")[0]>> <<set $trends.carValue = _tPick.split(":")[1]>> <<set $trends.bonusRep = 1>> <<if $marketStudyItem.bought>> <<set _tPool2 = [ "hair:Brown","hair:Brown","hair:Blonde","hair:Blonde","hair:Black","hair:Black", "height:Short","height:Short","height:Tall","height:Tall", "ageCat:Young","ageCat:Young","ageCat:Veteran","ageCat:Veteran", "breast:Small","breast:Small","breast:Large","breast:Large","breast:Huge","breast:Huge", "breastType:Fake","breastType:Fake","breastType:Fake","breastType:Real", "ethnicity:Latina","ethnicity:Latina","ethnicity:Asian","ethnicity:Asian","ethnicity:Black","ethnicity:Caucasian" ]>> <<set _tPick2 = _tPool2[random(0, _tPool2.length - 1)]>> <<set $trends.carType2 = _tPick2.split(":")[0]>> <<set $trends.carValue2 = _tPick2.split(":")[1]>> <<else>> <<set $trends.carType2 = "">> <<set $trends.carValue2 = "">> <</if>> <</widget>> /* ════════════════════════════════════════════ WIDGET : drawContestJudges Picks 2 distinct judges at random from $judges. Pure independent draw each call — no cooldown/rotation tracking, so there is no visible pattern or stat a player could use to predict who shows up next. ════════════════════════════════════════════ */ <<widget "drawContestJudges">> <<set _availableJudges = clone($judges)>> <<set _jPick1 = _availableJudges.splice(random(0, _availableJudges.length - 1), 1)[0]>> <<set _jPick2 = _availableJudges[random(0, _availableJudges.length - 1)]>> <<set $contestJudges = [_jPick1, _jPick2]>> <</widget>> <<widget "triggerJudgeSpecialShoot">> <<set _jse = $judgeSpecialShoots[$args[0]]>> <<set _jse.active = true>> <<set _jse.deadlineDay = $player.day + 4>> <<set _usedJudgeIdx = $judgeSpecialShoots.filter(function(j){ return j !== _jse && j.judgeIdx >= 0; }).map(function(j){ return j.judgeIdx; })>> <<set _availJudgeIdx = []>> <<for _jai = 0; _jai < $judges.length; _jai++>> <<if _usedJudgeIdx.indexOf(_jai) is -1>><<set _availJudgeIdx.push(_jai)>><</if>> <</for>> <<if _availJudgeIdx.length is 0>><<for _jai = 0; _jai < $judges.length; _jai++>><<set _availJudgeIdx.push(_jai)>><</for>><</if>> <<set _jse.judgeIdx = _availJudgeIdx[random(0, _availJudgeIdx.length - 1)]>> <<set _jJ = $judges[_jse.judgeIdx]>> <<set _jLikePosObj = $allPositions.find(function(p){ return p.name === _jJ.pref.likePosition; })>> /* Nothing past Spooning (minSat 50): excludes Specialty 1/2, Facial, and anything outside $allPositions (Anal/Titfuck/Standing only ever come from a star's Specialty 1/2 slot, itself satisfaction-gated at 60/70 — so "not found" is unsafe, not unlimited). */ <<set _jLikePosSatOk = _jLikePosObj && (_jLikePosObj.minSat || 0) <= 50>> <<set _favChoicePool = []>> <<if !_jJ.pref.revealed.likePosition && _jLikePosSatOk>><<set _favChoicePool.push("position")>><</if>> <<if !_jJ.pref.revealed.likePhysical[0] || !_jJ.pref.revealed.likePhysical[1]>><<set _favChoicePool.push("trait")>><</if>> <<if _favChoicePool.length is 0>><<set _favChoicePool = _jLikePosSatOk ? ["position","trait"] : ["trait"]>><</if>> <<set _favKind = _favChoicePool[random(0, _favChoicePool.length - 1)]>> <<set _randTraitPool = [ "hair:Brown","hair:Brown","hair:Blonde","hair:Blonde","hair:Black","hair:Black", "height:Short","height:Short","height:Tall","height:Tall", "ageCat:Young","ageCat:Young","ageCat:Veteran","ageCat:Veteran", "breast:Small","breast:Small","breast:Large","breast:Large","breast:Huge","breast:Huge", "breastType:Fake","breastType:Fake","breastType:Fake","breastType:Real", "ethnicity:Latina","ethnicity:Latina","ethnicity:Asian","ethnicity:Asian","ethnicity:Black","ethnicity:Caucasian" ]>> <<if _favKind is "position">> <<set _jse.favIsTrait = false>> <<set _jse.favTraitIdx = -1>> <<set _jse.reqPosition = _jJ.pref.likePosition>> <<set _randTraitPick = _randTraitPool[random(0, _randTraitPool.length - 1)]>> <<set _jse.reqTraitType = _randTraitPick.split(":")[0]>> <<set _jse.reqTraitValue = _randTraitPick.split(":")[1]>> <<else>> <<set _jse.favIsTrait = true>> <<set _idxPool = []>> <<if !_jJ.pref.revealed.likePhysical[0]>><<set _idxPool.push(0)>><</if>> <<if !_jJ.pref.revealed.likePhysical[1]>><<set _idxPool.push(1)>><</if>> <<if _idxPool.length is 0>><<set _idxPool = [0,1]>><</if>> <<set _jse.favTraitIdx = _idxPool[random(0, _idxPool.length - 1)]>> <<set _jse.reqTraitType = _jJ.pref.likePhysical[_jse.favTraitIdx].type>> <<set _jse.reqTraitValue = _jJ.pref.likePhysical[_jse.favTraitIdx].value>> <<set _posPool = $playerPositions.filter(function(p){ if(p === "Specialty 1" || p === "Specialty 2") return false; var po = $allPositions.find(function(x){ return x.name === p; }); return !po || (po.minSat || 0) <= 50; })>> <<if _posPool.length is 0>><<set _posPool = ["BJ"]>><</if>> <<set _jse.reqPosition = _posPool[random(0, _posPool.length - 1)]>> <</if>> <</widget>> /* ════════════════════════════════════════════ WIDGET : checkRival ════════════════════════════════════════════ */ <<widget "checkRival">> <<set _sabotageChance = 10 + ($rivalAggression || 0)>> <<set $rivalSabotageStar = "">> <<set $rivalSabotageStolen = false>> <<if $poachingUnlocked && $roster.length > 0 && (random(1,100) <= _sabotageChance)>> <<set _weights = []>> <<for _wi = 0; _wi < $roster.length; _wi++>> <<if $roster[_wi].satisfaction < 100>> <<set _w = Math.max(1, 110 - $roster[_wi].satisfaction)>> <<for _wj = 0; _wj < _w; _wj++>> <<set _weights.push(_wi)>> <</for>> <</if>> <</for>> <<if _weights.length > 0>> <<set _si = _weights[random(0, _weights.length - 1)]>> <<set $roster[_si].satisfaction = Math.max(0, $roster[_si].satisfaction - 10)>> <<set $rivalSabotageStar = $roster[_si].name>> <<if $roster[_si].satisfaction <= 5>> <<set $rival.roster.push(clone($roster[_si]))>> <<run window.cleanupQuestlineForLostStar($roster[_si].name)>> <<set $roster.deleteAt(_si)>> <<set $player.reputation = Math.max(0, $player.reputation - 2)>> <<set $rivalAggression = Math.max(0, ($rivalAggression || 0) - 4)>> <<set $rivalSabotageStolen = true>> <<if $player.day >= 30>> <<set $poachVideoStar = $rivalSabotageStar>> <</if>> <</if>> <</if>> <</if>> <<for _i = $roster.length - 1; _i >= 0; _i-->> <<set _w = $roster[_i]>> <<if _w.satisfaction <= 0>> <<if true>> <<set $rival.roster.push(clone(_w))>> <<run window.cleanupQuestlineForLostStar(_w.name)>> <<set $roster.deleteAt(_i)>> <<set $player.reputation = Math.max(0, $player.reputation - 2)>> <<if $player.day >= 30>> <<set $poachMessage = _w.name + " left your roster for " + $rival.name + " — went to find out if the grass is bigger on the other side. She already shot her first BJ scene with them.">> <<set $poachVideoStar = _w.name>> <<else>> <<set $poachMessage = _w.name + " left your roster for " + $rival.name + " — went to find out if the grass is bigger on the other side.">> <<set $poachVideoStar = "">> <</if>> <</if>> <</if>> <</for>> <</widget>> /* ════════════════════════════════════════════ WIDGET : resolveShooting _w1 _w2 _positions _adv Earnings = player rep × talent popularity × multiplier Multiplier: 1.0 base, +0.3 if trending position used, +0.3 if trending profile matches Two Shootings in a Day: average popularity of both talents ════════════════════════════════════════════ */ <<widget "resolveShooting" "_w1" "_w2" "_adv">> <<set $lastPositionBonus = false>> <<set $lastCarBonus = "">> <<set $lastCarBonus2 = "">> <<set $lastPopGain = []>> /* ── Genre trend → rep bonus ── */ <<set _resolvedShootPositions = $selectedPositions.map(function(p){ if(p === "Specialty 1") return (_w1 && _w1.specialty1) || (_w2 && _w2.specialty1) || p; if(p === "Specialty 2") return (_w1 && _w1.specialty2) || (_w2 && _w2.specialty2) || p; return p; })>> <<if _resolvedShootPositions.includes($trends.position)>> <<set $lastPositionBonus = true>> <</if>> /* ── Physical trend 1 → earnings multiplier ── */ <<set _ct = $trends.carType>> <<set _cv = $trends.carValue>> <<set _carShooting = false>> <<if _w1 && _w1[_ct] is _cv>> <<set _carShooting = true>> <<set $lastCarBonus = _w1.name>> <</if>> <<if _w2 && _w2[_ct] is _cv>> <<set _carShooting = true>> <<if $lastCarBonus>><<set $lastCarBonus += " & " + _w2.name>><<else>><<set $lastCarBonus = _w2.name>><</if>> <</if>> /* ── Physical trend 2 → earnings multiplier ── */ <<set _carShooting2 = false>> <<if $trends.carType2>> <<set _ct2 = $trends.carType2>> <<set _cv2 = $trends.carValue2>> <<if _w1 && _w1[_ct2] is _cv2>> <<set _carShooting2 = true>> <<set $lastCarBonus2 = _w1.name>> <</if>> <<if _w2 && _w2[_ct2] is _cv2>> <<set _carShooting2 = true>> <<if $lastCarBonus2>><<set $lastCarBonus2 += " & " + _w2.name>><<else>><<set $lastCarBonus2 = _w2.name>><</if>> <</if>> <</if>> /* ── Earnings multiplier: physical trends only ── */ <<set _physicalMatches = (_carShooting ? 1 : 0) + (_carShooting2 ? 1 : 0)>> <<if _physicalMatches is 2>> <<set _multi = 1.6>> <<elseif _physicalMatches is 1>> <<set _multi = 1.3>> <<else>> <<set _multi = 1.0>> <</if>> <<set $lastMulti = _multi>> <<if _adv && _w2>> <<set _avgPop = (_w1.popularity + _w2.popularity) / 2>> <<elseif _w1>> <<set _avgPop = _w1.popularity>> <<else>> <<set _avgPop = 1>> <</if>> /* ── Double Feature bonus: 1.x multiplier, x = avg position rank (BJ=1 ... Facial=9) ── */ <<set _dfMulti = 1.0>> <<if $doublePositionItem.bought && $selectedPositions.length >= 2>> <<set _posLevels = $selectedPositions.map(function(pn){ var po = $allPositions.find(function(p){ return p.name === pn; }); return po ? po.level : 1; })>> <<set _avgPosLevel = _posLevels.reduce(function(a,b){ return a + b; }, 0) / _posLevels.length>> <<set _dfMulti = 1 + (_avgPosLevel / 10)>> <</if>> <<set $lastDoubleFeatureMulti = _dfMulti>> <<set $lastGain = Math.round(($player.reputation * 5 + _avgPop * 50) * _multi * _dfMulti)>> <<if $skillfulChallengeActive && $lastPositionBonus && $player.day <= $skillfulChallengeEndDay>> <<set $skillfulChallengeActive = false>> <<set $skillfulChallengeWon = true>> <</if>> /* Rival offer challenge tracking */ <<if $rivalOfferChallenge && $rivalOfferIdx >= 0>> <<if _w1 && _w1.name is $rivalOfferStar || (_w2 && _w2.name is $rivalOfferStar)>> <<set $rivalOfferShootingsDone += 1>> <<if $rivalOfferShootingsDone >= 3>> <<set $rivalOfferChallenge = false>> <<set $rivalOfferChallengeWon = true>> <<set $roster[$rivalOfferIdx].popularity += 1>> <<set $roster[$rivalOfferIdx].satisfaction = Math.min(100, $roster[$rivalOfferIdx].satisfaction + 10)>> <<set $rivalOfferIdx = -1>> <<set $rivalOfferStar = "">> <</if>> <</if>> <</if>> /* Rival offer challenge tracking */ <<if $rivalOfferShootingsLeft > 0>> <<set _os = _w1 && _w1.name is $rivalOfferStar ? _w1 : (_w2 && _w2.name is $rivalOfferStar ? _w2 : null)>> <<if _os>> <<set _os.consecutiveDays = 0>> <<set _os.restDay = false>> <</if>> <</if>> /* Contract 1 tracking — 2 shootings with matching stat within 4 days */ <<if $contract1.accepted && !$contract1.failed>> <<set _ct = $contract1.criteriaType>> <<set _cv = $contract1.criteria>> <<if $contractIsHarder>> <<set _ct2h = $contract1.criteriaType2>><<set _cv2h = $contract1.criteria2>> <<set _validStar = (_w1 && _w1[_ct] is _cv && _w1[_ct2h] is _cv2h) || (_w2 && _w2[_ct] is _cv && _w2[_ct2h] is _cv2h)>> <<else>> <<set _validStar = (_w1 && _w1[_ct] is _cv) || (_w2 && _w2[_ct] is _cv)>> <</if>> <<if _validStar>> <<set $contract1.shootingsDone += 1>> <<if $contract1.shootingsDone >= 2>> <<set $contract1.accepted = false>> <<set $contract1.active = false>> <<set $contract1Success = true>> <<set $totalContractsCompleted += 1>> <<if $contractIsHarder>> <<set $player.reputation += 5>> <<set $player.money += 1500>> <<if !$easyMode && !$trophies.harderDeal>><<set $trophies.harderDeal = true>><<set $newTrophy = "🏆 Harder Deal — first harder contract completed!">><<run window.checkAllTrophies()>><</if>> <<else>> <<set $player.reputation += 3>> <<set $player.money += 500>> <</if>> <<if !$easyMode && !$trophies.dealMaker && $totalContractsCompleted >= 5>><<set $trophies.dealMaker = true>><<set $newTrophy = "🏆 Deal Maker — 5 contracts completed!">><<run window.checkAllTrophies()>><</if>> <<set $contractShopAvailableDay = $player.day + 3>> <</if>> <</if>> <</if>> /* Judge Special Shoot tracking */ <<for _jssi = 0; _jssi < $judgeSpecialShoots.length; _jssi++>> <<set _jss = $judgeSpecialShoots[_jssi]>> <<if _jss.active && !_jss.done>> <<set _jssStar = (_w1 && _w1[_jss.reqTraitType] is _jss.reqTraitValue) ? _w1 : ((_w2 && _w2[_jss.reqTraitType] is _jss.reqTraitValue) ? _w2 : null)>> <<set _jssResolvedPositions = _jssStar ? $selectedPositions.map(function(p){ if(p === "Specialty 1") return _jssStar.specialty1 || p; if(p === "Specialty 2") return _jssStar.specialty2 || p; return p; }) : []>> <<if _jssStar && _jssResolvedPositions.includes(_jss.reqPosition)>> <<set _jss.done = true>> <<if $player.day <= _jss.deadlineDay>> <<set _jJudgeDone = $judges[_jss.judgeIdx]>> <<if _jss.favIsTrait>> <<set _jJudgeDone.pref.revealed.likePhysical[_jss.favTraitIdx] = true>> <<else>> <<set _jJudgeDone.pref.revealed.likePosition = true>> <</if>> <<set $newJudgeSpecialReveal = _jJudgeDone.name + " noticed your work — you've learned one of their preferences!">> <<run window.checkFullPanelTrophy(_jJudgeDone)>> <</if>> <</if>> <</if>> <</for>> /* Contract 4 tracking — specific confirmed stars */ <<if $contract4.accepted && !$contract4.failed>> <<set _c4match = false>> <<set _c4star = null>> <<if _w1 && (_w1.name is $contract4.star1 || _w1.name is $contract4.star2)>><<set _c4match = true>><<set _c4star = _w1>><</if>> <<if !_c4match && _w2 && (_w2.name is $contract4.star1 || _w2.name is $contract4.star2)>><<set _c4match = true>><<set _c4star = _w2>><</if>> <<if _c4match>> <<set $contract4.shootingsDone += 1>> <<set $contract4.accepted = false>> <<set $contract4.active = false>> <<set $contract4Success = true>> <<set $player.money += 1000>> <</if>> <</if>> /* Contract 5 tracking — specific elite stars */ <<if $contract5.accepted && !$contract5.failed>> <<set _c5match = false>> <<set _c5star = null>> <<if _w1 && (_w1.name is $contract5.star1 || _w1.name is $contract5.star2)>><<set _c5match = true>><<set _c5star = _w1>><</if>> <<if !_c5match && _w2 && (_w2.name is $contract5.star1 || _w2.name is $contract5.star2)>><<set _c5match = true>><<set _c5star = _w2>><</if>> <<if _c5match>> <<set $contract5.shootingsDone += 1>> <<set $contract5.accepted = false>> <<set $contract5.active = false>> <<set $contract5Success = true>> <<set $player.money += 2500>> <</if>> <</if>> /* Contract 3 tracking — any Established (pool 2) star counts */ <<if $contract3.accepted && !$contract3.failed>> <<set _c3star = null>> <<if _w1 && $poolConfirmed.indexOf(_w1.name) >= 0>><<set _c3star = _w1>><</if>> <<if !_c3star && _w2 && $poolConfirmed.indexOf(_w2.name) >= 0>><<set _c3star = _w2>><</if>> <<if _c3star>> <<set $contract3.shootingsDone += 1>> <<set $contract3.accepted = false>> <<set $contract3.active = false>> <<set $contract3Success = true>> <<set _c3star.popularity += 2>> <<set $player.money += 500>> <<set $player.reputation += 1>> <<set $contract3.starName = _c3star.name>> <</if>> <</if>> /* Sweet Caprice quest — count BJ shootings with Caprice */ <<if $questlines.sweetCaprice.active && $questlines.sweetCaprice.step is 2 && $selectedPositions.includes("BJ")>> <<if (_w1 && _w1.name is "Caprice") || (_w2 && _w2.name is "Caprice")>> <<set $questlines.sweetCaprice.bjCount += 1>> <</if>> <</if>> /* ── Rep: +1 base, +2 extra if genre trending (total +3) ── */ <<set $lastRepBonus = 1>> <<if $lastPositionBonus>><<set $lastRepBonus = 3>><</if>> <<set $player.money += $lastGain>> <<set $player.reputation += $lastRepBonus>> <<for _m = 0; _m < $selectedPositions.length; _m++>> <<set _mn = $selectedPositions[_m]>> <<set _mvObj = $allPositions.find(function(m){ return m.name is _mn; })>> <<set _mvLevel = _mvObj ? _mvObj.level : 1>> <<if _w1>> <<if _mn is _w1.favPosition || (_w1.favPosition2 && _mn is _w1.favPosition2)>> <<set _w1.satisfaction = Math.min(100, _w1.satisfaction + Math.ceil(_mvLevel * 1.5))>> <<else>> <<set _w1.satisfaction = Math.min(100, _w1.satisfaction + _mvLevel)>> <</if>> <</if>> <<if _w2>> <<if _mn is _w2.favPosition || (_w2.favPosition2 && _mn is _w2.favPosition2)>> <<set _w2.satisfaction = Math.min(100, _w2.satisfaction + Math.ceil(_mvLevel * 1.5))>> <<else>> <<set _w2.satisfaction = Math.min(100, _w2.satisfaction + _mvLevel)>> <</if>> <</if>> <</for>> <<if _w1>> <<set _w1.weekShootings += 1>> <<set _w1.totalShootings = (_w1.totalShootings || 0) + ($lastPositionBonus ? 2 : 1)>> <<set _w1popBefore = _w1.popularity>> <<set _w1.popularity = _w1.popularity + ((_w1.totalShootings % 3 is 0) ? 1 : 0)>> <<if _w1.popularity > _w1popBefore>><<set $lastPopGain.push({ name: _w1.name, pop: _w1.popularity })>><</if>> <<if _w1.lastShootingDay is $player.day - 1>> <<set _w1.consecutiveDays += 1>> <<else>> <<set _w1.consecutiveDays = 1>> <</if>> <<set _w1.lastShootingDay = $player.day>> <<if _w1.consecutiveDays >= 2>><<set _w1.restDay = true>><<set _w1.restUntilDay = $player.day + 1>><</if>> <<if _w1.popularity is 50>><<set $popularityAlert = _w1.name>><</if>> <<if _w1.satisfaction >= 30 && !_w1.bonusChosen>><<set $bonusChoiceStar = _w1.name>><</if>> <</if>> <<if _w2>> <<set _w2.weekShootings += 1>> <<set _w2.totalShootings = (_w2.totalShootings || 0) + ($lastPositionBonus ? 2 : 1)>> <<set _w2popBefore = _w2.popularity>> <<set _w2.popularity = _w2.popularity + ((_w2.totalShootings % 3 is 0) ? 1 : 0)>> <<if _w2.popularity > _w2popBefore>><<set $lastPopGain.push({ name: _w2.name, pop: _w2.popularity })>><</if>> <<if _w2.lastShootingDay is $player.day - 1>> <<set _w2.consecutiveDays += 1>> <<else>> <<set _w2.consecutiveDays = 1>> <</if>> <<set _w2.lastShootingDay = $player.day>> <<if _w2.consecutiveDays >= 2>><<set _w2.restDay = true>><<set _w2.restUntilDay = $player.day + 1>><</if>> <<if _w2.popularity is 50>><<set $popularityAlert = _w2.name>><</if>> <<if _w2.satisfaction >= 30 && !_w2.bonusChosen>><<set $bonusChoiceStar = _w2.name>><</if>> <</if>> <</widget>> <<drawContestJudges>> /* ════════════════════════════════════════════ PASSAGE : StoryStylesheet ════════════════════════════════════════════ */
<div id="sidebar-content" style="font-size:0.85em;line-height:1.4;"> <hr style="border-color:#333;margin:0 0 4px 0;"> <div style="text-align:center;font-size:2em;"><a href="https://patreon.com/hubbgames?utm_medium=unknown&utm_source=join_link&utm_campaign=creatorshare_creator&utm_content=copyLink" target="_blank">Patreon</a></div> <div class="stat-chip-row"> <span class="stat-chip day">📅 Day <<= $player.day>></span> <span class="stat-chip money">💰 $<<= $player.money.toLocaleString()>></span> <span class="stat-chip rep">🌟 <<= $player.reputation>></span> </div> <div class="stat-chip-row"> <span class="stat-chip">🎭 <<= $archetype ? $archetype.charAt(0).toUpperCase() + $archetype.slice(1) : "">></span> <<if $shootingPlayedToday>><span class="stat-chip status-live">🎬 Produced</span><<else>><span class="stat-chip status-ready">🎬 Ready</span><</if>> </div> <<if $roster.length > 0>><<set _nextPayDay = 7 - ($player.day % 7)>><<set _payDay = $player.day + _nextPayDay>><<set _upkeepTotal = 0>><<for _si = 0; _si < $roster.length; _si++>><<set _daysOwed2 = Math.min(7, _payDay - ($roster[_si].joinedDay || (_payDay - 7)) + 1)>><<set _upkeepTotal += Math.round($roster[_si].popularity * 70 * _daysOwed2 / 7)>><</for>><div class="stat-chip-row"><<if _nextPayDay <= 3 && $player.money < _upkeepTotal>><span class="stat-chip status-live">⚠️ Upkeep: $<<= _upkeepTotal.toLocaleString()>> in <<= _nextPayDay>>d</span><<else>><span class="stat-chip upkeep">💸 Upkeep: $<<= _upkeepTotal.toLocaleString()>> in <<= _nextPayDay>>d</span><</if>></div><</if>> <<if $skillfulChallengeActive>>@@color:gold;⚡ Trending position before day <<= $skillfulChallengeEndDay>>@@<br><</if>> <<if $rivalOfferShootingsLeft > 0>>@@color:orange;💬 <<= $rivalOfferStar>>: <<= $rivalOfferShootingsLeft>> shoots left, <<= Math.max(0, $rivalOfferDeadlineDay - $player.day)>>d remaining@@<br><</if>> <<if $contract1.accepted>>@@color:cyan;📋 <<= $contract1.criteria>> <<= $contract1.criteriaType>> (<<= $contract1.shootingsDone>>/2) — <<= Math.max(0, $contract1.startDay + 4 - $player.day)>>d left@@<br><</if>> <<if $judgeSpecialShoots.some(function(j){ return j.active && !j.done; })>><<set _jssActive = $judgeSpecialShoots.find(function(j){ return j.active && !j.done; })>><<set _jssJudge = $judges[_jssActive.judgeIdx]>>@@color:#6fcf73;🎬 <<= _jssJudge.name>>'s request: <<= _jssActive.reqTraitValue>> <<= _jssActive.reqTraitType>> + <<= _jssActive.reqPosition>> — <<= Math.max(0, _jssActive.deadlineDay - $player.day)>>d left@@<br><</if>> <<if $contract3.accepted>>@@color:gold;📋 Established contract: shoot before day 44@@<br><</if>> <<if $contract4.accepted>>@@color:gold;📋 Investors: <<= $contract4.star1>><<if $contract4.star2>> or <<= $contract4.star2>><</if>> before day 50@@<br><</if>><<if $contract5.accepted>>@@color:gold;💎 Elite Demand: <<= $contract5.star1>><<if $contract5.star2>> or <<= $contract5.star2>><</if>> in <<= Math.max(0, ($contract5.startDay + 5) - $player.day)>>d@@<br><</if>><<if $questlines.asianDuo.active>><<set _qlA = $questlines.asianDuo>><<if _qlA.step is 1>>@@color:cyan;🎌 Quest — Asian Duo: <<= _qlA.star1>> → 25 satis (<<= $roster.find(function(w){ return w.name is _qlA.star1; }) ? $roster.find(function(w){ return w.name is _qlA.star1; }).satisfaction : 0>>/25)@@<br><<elseif _qlA.step is 2>>@@color:cyan;🎌 Quest — Asian Duo: recruit <<= (_qlA.star1 is "Kimmy") ? "Lulu" : "Kimmy">>@@<br><<elseif _qlA.step is 3>>@@color:cyan;🎌 Quest — Asian Duo: <<= _qlA.star2>> → 25 satis (<<= $roster.find(function(w){ return w.name is _qlA.star2; }) ? $roster.find(function(w){ return w.name is _qlA.star2; }).satisfaction : 0>>/25)@@<br><</if>><<elseif $questlines.asianDuo.shooting1Done && !$questlines.asianDuo.shooting2Done>>@@color:cyan;🎌 Quest — Asian Duo: 2nd special available!@@<br><<elseif $questlines.asianDuo.specialAvailable && !$questlines.asianDuo.shooting1Done>>@@color:gold;🎌 Quest — Asian Duo: 🌟 1st special available!@@<br><</if>><<if $questlines && $questlines.fallenAngels>><<if $questlines.fallenAngels.shooting2Done && !$questlines.fallenAngels.shooting3Done>>@@color:cyan;👼 Quest — Angels: 3rd!@@<br><<elseif $questlines.fallenAngels.shooting1Done && !$questlines.fallenAngels.shooting2Done>>@@color:cyan;👼 Quest — Angels: 2nd!@@<br><<elseif $questlines.fallenAngels.specialAvailable && !$questlines.fallenAngels.shooting1Done>>@@color:gold;👼 Quest — Angels: 🌟@@<br><<elseif $questlines.fallenAngels.active>>@@color:cyan;👼 Quest — Angels: Step <<= $questlines.fallenAngels.step>>/6@@<br><</if>><</if>><<if $questlines && $questlines.sweetCaprice>><<if $questlines.sweetCaprice.shooting2Done>>@@color:gold;🍬 Quest — Caprice: ✅@@<br><<elseif $questlines.sweetCaprice.shooting1Done>>@@color:cyan;🍬 Quest — Caprice: 2nd special available!@@<br><<elseif $questlines.sweetCaprice.specialAvailable>>@@color:gold;🍬 Quest — Caprice: 🌟 special available!@@<br><<elseif $questlines.sweetCaprice.active>><<if $questlines.sweetCaprice.step is 1>>@@color:cyan;🍬 Quest — Caprice: 50 satis (<<= $roster.find(function(w){ return w.name is "Caprice"; }) ? $roster.find(function(w){ return w.name is "Caprice"; }).satisfaction : 0>>/50)@@<br><<elseif $questlines.sweetCaprice.step is 2>>@@color:cyan;🍬 Quest — Caprice: BJ shoots (<<= $questlines.sweetCaprice.bjCount>>/6)@@<br><<elseif $questlines.sweetCaprice.step is 3>>@@color:cyan;🍬 Quest — Caprice: Eve arriving in <<= Math.max(0, ($questlines.sweetCaprice.eveNotifyDay + 3) - $player.day)>>d@@<br><</if>><</if>><</if>><<if !$objective1Done && $player.day >= 10>>@@color:orange;🎯 <<= $roster.length>>/3 talents before day 16@@<br><</if>> <div class="sidebar-card"><div class="sidebar-card-title" style="margin-bottom:1px;">📈 Trends</div><div style="text-align:center;font-size:0.9em;"><<if $trends.position>>🎭 <<= $trends.position>> | ✨ <<= $trends.carType>>: <<= $trends.carValue>><<if $trends.carType2>> | ✨ <<= $trends.carType2>>: <<= $trends.carValue2>><</if>><<else>><em>Not revealed yet</em><</if>></div></div> <div class="sidebar-card"><div class="sidebar-card-title" style="margin-bottom:1px;">📋 Roster (<<= $roster.length>>)</div><<if $roster.length is 0>><div style="text-align:center;color:#666;"><em>Empty</em></div><<else>><div class="roster-chip-row"><<for _si = 0; _si < $roster.length; _si++>><<set _sw = $roster[_si]>><span class="roster-chip" style="border-color:<<if _sw.satisfaction >= 65>>darkgreen<<elseif _sw.satisfaction >= 40>>#b33<<elseif _sw.satisfaction >= 12>>orange<<elseif _sw.satisfaction >= 6>>#555<<else>>#b33<</if>>;"><<= _sw.name>> 🌟<<= _sw.popularity>><<if _sw.restDay>> 😴<</if>> <<if _sw.satisfaction >= 100>>💕<<elseif _sw.satisfaction >= 65>>💗<<elseif _sw.satisfaction >= 40>>❤️<<elseif _sw.satisfaction >= 12>>🧡<<elseif _sw.satisfaction >= 6>>🖤<<else>>⚠️<</if>><<= _sw.satisfaction>></span><</for>></div><</if>></div> <hr style="border-color:#333;margin:4px 0;"> <strong>🏆</strong> <<= $studioName>> 🌟<<= $player.reputation>> | <<= $rival.name>> 🌟<<= $rival.reputation>> <<if $poachingUnlocked>><br>😈 <<= $rival.name>> agressivity: <<= ($rivalAggression || 0).toFixed(2)>><</if>> </div> /* ════════════════════════════════════════════ PASSAGE : StoryMenu ════════════════════════════════════════════ */
[[📊 Dashboard|Dashboard]] [[📜 Questlines|QuestlinesMenu]] [[🏆 Trophies|TrophiesMenu]] [[📖 Guide|Guide]] <<if $targetedScoutItem && $targetedScoutItem.bought>>[[🎯 Scout Target<<if $targetedScoutStar>>: <<= $targetedScoutStar>><</if>>|TargetedScoutMenu]]<</if>> [[👑 Contest|ContestInfo]] <<script>> window.resolvePortraits = function(){ document.querySelectorAll('img[data-portrait-var]').forEach(function(img){ var varName = img.getAttribute('data-portrait-var'); // Remove leading underscore for SugarCube temporary variable lookup var key = varName.replace(/^_/, ''); try { var val = SugarCube.State.temporary[key] || ''; if(val) img.src = 'img/portraits/' + val + '.jpg'; } catch(e) {} }); }; window.zoomPortrait = function(src){ var ov = document.getElementById('portrait-overlay'); if(!ov){ ov = document.createElement('div'); ov.id = 'portrait-overlay'; ov.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,0.85);display:flex;align-items:center;justify-content:center;z-index:9999;cursor:zoom-out;'; ov.onclick = function(){ ov.remove(); }; document.body.appendChild(ov); } ov.innerHTML = '<img src="'+src+'" style="max-width:90vw;max-height:90vh;border-radius:12px;box-shadow:0 0 40px rgba(0,0,0,0.8);">'; }; jQuery(document).on(':passageend', function(){ if(window.resolvePortraits) window.resolvePortraits(); }); window.buildStarTable = function(roster, trends, excludeIdx, wrapperId, onSelect, emptyMsg, hideDecay, noHighlight, contractOptionsMode){ var heightOrder = {Short:1,Medium:2,Tall:3}; var breastOrder = {Small:1,Medium:2,Large:3,Huge:4}; var currentSort = 'satisfaction'; var currentDay = SugarCube.State.variables.player ? SugarCube.State.variables.player.day : 0; function isTrendStat(w, key){ if(noHighlight) return false; return (trends && trends.carType && key === trends.carType && w[key] === trends.carValue) || (trends && trends.carType2 && key === trends.carType2 && w[key] === trends.carValue2); } function isContractStat(w, key){ if(noHighlight) return false; var sv2 = SugarCube.State.variables; var c1 = sv2.contract1; return c1 && c1.accepted && !c1.failed && key === c1.criteriaType && w[key] === c1.criteria; } function tdStat(w, key){ var val = w[key] || '—'; var style = ''; if(isTrendStat(w, key)) style = 'background:#3a3a00;color:gold;font-weight:bold;'; else if(isContractStat(w, key)) style = 'background:#002244;color:#4af;font-weight:bold;outline:1px solid #4af;'; var badge = isContractStat(w, key) ? ' 📋' : ''; return '<td style="'+style+'">'+val+badge+'</td>'; } var currentDay = SugarCube.State.variables.player ? SugarCube.State.variables.player.day : 0; function isTrendStat(w, statKey){ if(noHighlight || contractOptionsMode) return false; return (trends && trends.carType && statKey === trends.carType && w[statKey] === trends.carValue) || (trends && trends.carType2 && statKey === trends.carType2 && w[statKey] === trends.carValue2); } function isContractStat(w, statKey){ if(noHighlight) return false; if(contractOptionsMode){ var opts = (SugarCube.State.variables.contract1 && SugarCube.State.variables.contract1.options) || []; return opts.some(function(o){ if(o.type2){ return (statKey === o.type || statKey === o.type2) && w[o.type] === o.value && w[o.type2] === o.value2; } return o.type === statKey && w[statKey] === o.value; }); } var sv2 = SugarCube.State.variables; var c1 = sv2.contract1; var c2 = sv2.contract2; var match1 = c1 && c1.accepted && !c1.failed && statKey === c1.criteriaType && w[statKey] === c1.criteria; var match2 = c2 && c2.accepted && !c2.failed && statKey === c2.criteriaType && w[statKey] === c2.criteria; return match1 || match2; } function tdStat(w, statKey){ var val = w[statKey] || '—'; var style = ''; if(isTrendStat(w, statKey)) style = 'background:#3a3a00;color:gold;font-weight:bold;'; else if(isContractStat(w, statKey)) style = 'background:#002244;color:#4af;font-weight:bold;outline:1px solid #4af;'; var badge = isContractStat(w, statKey) ? ' 📋' : ''; return '<td style="'+style+'">'+val+badge+'</td>'; } function buildTable(sortCol){ currentSort = sortCol; var rs = roster.slice(); rs.sort(function(a,b){ if(sortCol==='name') return a.name<b.name?-1:1; if(sortCol==='ageNum') return a.ageNum-b.ageNum; if(sortCol==='hair') return a.hair<b.hair?-1:1; if(sortCol==='height') return (heightOrder[a.height]||0)-(heightOrder[b.height]||0); if(sortCol==='breast') return (breastOrder[a.breast]||0)-(breastOrder[b.breast]||0); if(sortCol==='breastType') return a.breastType<b.breastType?-1:1; if(sortCol==='ethnicity') return (a.ethnicity||'').localeCompare(b.ethnicity||''); if(sortCol==='popularity') return b.popularity-a.popularity; if(sortCol==='satisfaction') return b.satisfaction-a.satisfaction; if(sortCol==='decay') return (a.lastShootingDay||0)-(b.lastShootingDay||0); return 0; }); var html = '<table class="recruit-table"><tr>'; html += '<th></th>'; var cols = hideDecay ? ['name','ageNum','hair','height','breast','breastType','ethnicity','specialty1','specialty2','popularity','satisfaction'] : ['name','ageNum','hair','height','breast','breastType','ethnicity','specialty1','specialty2','popularity','satisfaction','decay']; var labels = hideDecay ? ['Name ↕','Age ↕','Hair ↕','Height ↕','Tits ↕','Type ↕','Origin ↕','Spe 1','Spe 2','🌟 ↕','❤️ ↕'] : ['Name ↕','Age ↕','Hair ↕','Height ↕','Tits ↕','Type ↕','Origin ↕','Spe 1','Spe 2','🌟 ↕','❤️ ↕','⏳ ↕']; var showTier = !hideDecay; for(var c=0;c<cols.length;c++){ var thTitle = cols[c]==='decay' ? ' title="Days left before satisfaction starts dropping (−5/day) from not shooting with her"' : ''; html += '<th data-col="'+cols[c]+'"'+thTitle+'>'+labels[c]+'</th>'; } html += '</tr>'; var found = false; rs.forEach(function(w){ var origIdx = roster.indexOf(w); if(origIdx === excludeIdx) return; var file = w.name.toLowerCase().replace(/ /g,'_'); /* Absent questline stars */ var sv3 = SugarCube.State.variables; var absentStars = []; if(sv3.asianDuoAbsentDay > 0 && sv3.asianDuoGoneDay < 0){ absentStars.push('Kimmy'); absentStars.push('Lulu'); } if(sv3.fallenAngelsAbsentDay > 0 && sv3.fallenAngelsGoneDay < 0){ absentStars.push('Angie'); absentStars.push('Angela'); } var isAbsent = absentStars.indexOf(w.name) >= 0; var isResting = w.restDay || isAbsent; /* Contract match check */ var sv = SugarCube.State.variables; var matchesContract = false; if(!noHighlight && sv.contract1 && sv.contract1.accepted && !sv.contract1.failed){ if(sv.contractIsHarder && sv.contract1.criteriaType2){ matchesContract = w[sv.contract1.criteriaType] === sv.contract1.criteria && w[sv.contract1.criteriaType2] === sv.contract1.criteria2; } else { matchesContract = w[sv.contract1.criteriaType] === sv.contract1.criteria; } } var nameExtra = isAbsent ? ' 🙅' : (isResting ? ' 😴' : ''); if(matchesContract) nameExtra += ' 📋'; var matchColor = (sv.contractIsHarder && sv.contract1 && sv.contract1.criteriaType2) ? '74,222,128' : '74,158,255'; var sat = w.satisfaction; var satColor = sat>=100?'darkgreen':sat>=65?'darkgreen':sat>=40?'red':sat>=12?'orange':sat>=6?'#555':'#222'; var satIcon = sat>=100?'💕':sat>=65?'💗':sat>=40?'❤️':sat>=12?'🧡':sat>=6?'🖤':'⚠️'; var daysSince = currentDay - (w.lastShootingDay || 0); var decayThreshold = SugarCube.State.variables.satisfactionDelayItem && SugarCube.State.variables.satisfactionDelayItem.bought ? 5 : 4; if(w.satisfaction > 40) decayThreshold += 1; if(SugarCube.State.variables.easyMode) decayThreshold += 2; var dbd = decayThreshold - daysSince; var dbdStr = w.satisfaction >= 100 ? '🔒' : (isResting ? '😴' : (dbd <= 0 ? '🔴 now' : (dbd === 1 ? '⚠️ 1d' : dbd+'d'))); var dbdStyle = w.satisfaction >= 100 ? 'color:gold;font-weight:bold;' : (dbd <= 0 ? 'color:red;font-weight:bold;' : (dbd === 1 ? 'color:orange;' : '')); var sv4 = SugarCube.State.variables; /* inPlayerRoster/inRivalRoster only relevant when viewing recruit pools (hideDecay=true) */ var inPlayerRoster = hideDecay && sv4.roster && sv4.roster.find(function(r){ return r.name === w.name; }); var inRivalRoster = hideDecay && sv4.rival && sv4.rival.roster && sv4.rival.roster.find(function(r){ return r.name === w.name; }); if(isResting || inPlayerRoster || inRivalRoster){ html += '<tr style="opacity:0.35;">'; if(inPlayerRoster) nameExtra += ' ✅'; else if(inRivalRoster) nameExtra += ' ❌'; } else { found = true; var rowStyle = matchesContract ? 'cursor:pointer;background:rgba('+matchColor+',0.2);' : 'cursor:pointer;'; html += '<tr class="data-row" data-orig-idx="'+origIdx+'" style="'+rowStyle+'">'; } html += '<td style="'+(matchesContract?('border-left:3px solid rgb('+matchColor+');'):'')+'"><img style="width:72px;height:72px;object-fit:cover;border-radius:6px;display:block;" src="img/portraits/'+file+'.jpg" alt="'+w.name+'"></td>'; /* Absent questline stars */ var sv3 = SugarCube.State.variables; var absentStars = []; if(sv3.asianDuoAbsentDay > 0 && sv3.asianDuoGoneDay < 0){ absentStars.push('Kimmy'); absentStars.push('Lulu'); } if(sv3.fallenAngelsAbsentDay > 0 && sv3.fallenAngelsGoneDay < 0){ absentStars.push('Angie'); absentStars.push('Angela'); } var isAbsent = absentStars.indexOf(w.name) >= 0; /* Pool tier */ var tierLabel = '⭐'; var sv2 = SugarCube.State.variables; if(w.name === 'Eve' || (sv2.poolElite && sv2.poolElite.indexOf(w.name) >= 0)) tierLabel = '⭐⭐⭐'; else if(sv2.poolConfirmed && sv2.poolConfirmed.indexOf(w.name) >= 0) tierLabel = '⭐⭐'; html += '<td>'+w.name+nameExtra+' <span style="font-size:0.8em;opacity:0.7;">'+tierLabel+'</span></td>'; var ageStyle = isTrendStat(w,'ageCat') ? 'background:#3a3a00;color:gold;font-weight:bold;' : (isContractStat(w,'ageCat') ? 'background:#002244;color:#4af;font-weight:bold;outline:1px solid #4af;' : ''); var ageBadge = isContractStat(w,'ageCat') ? ' 📋' : ''; html += '<td style="'+ageStyle+'">'+w.ageNum+ageBadge+'</td>'; html += tdStat(w,'hair'); html += tdStat(w,'height'); html += tdStat(w,'breast'); html += tdStat(w,'breastType'); html += tdStat(w,'ethnicity'); html += '<td>'+(w.specialty1 || '—')+'</td>'; html += '<td>'+(w.specialty2 || '—')+'</td>'; html += '<td>'+w.popularity+'</td>'; html += '<td><span style="color:'+satColor+'">'+satIcon+' '+sat+'</span></td>'; if(!hideDecay) html += '<td style="'+dbdStyle+'">'+dbdStr+'</td>'; html += '</tr>'; }); html += '</table>'; if(!found) html += '<p>'+emptyMsg+'</p>'; var wrap = document.getElementById(wrapperId); if(wrap){ wrap.innerHTML = html; wrap.querySelectorAll('th[data-col]').forEach(function(th){ th.style.cursor = 'pointer'; th.addEventListener('click', function(){ buildTable(this.getAttribute('data-col')); }); }); wrap.querySelectorAll('tr.data-row').forEach(function(row){ row.addEventListener('click', function(){ onSelect(parseInt(this.getAttribute('data-orig-idx'))); }); }); } } buildTable(currentSort); }; window.buildStarCards = function(stars, trends, containerId, onClick, luckyNames, showTrending){ if(!stars || stars.length === 0){ var el = document.getElementById(containerId); if(el) el.innerHTML = '<em>No talents to display.</em>'; return; } luckyNames = luckyNames || []; var eliteNames = (SugarCube.State.variables.drawEliteNames) || []; showTrending = showTrending !== false; var trendType = trends ? trends.carType : ''; var trendVal = trends ? trends.carValue : ''; var trendType2 = trends ? trends.carType2 : ''; var trendVal2 = trends ? trends.carValue2 : ''; var html = '\x3cdiv style="display:flex;flex-wrap:wrap;justify-content:center;max-width:100%;box-sizing:border-box;">'; stars.forEach(function(w, idx){ var file = w.name.toLowerCase().replace(/ /g,'_'); var isTrending = showTrending && ((trendType && w[trendType] === trendVal) || (trendType2 && w[trendType2] === trendVal2)); var isResting = w.restDay; var isElite = eliteNames.indexOf(w.name) >= 0; var isLucky = luckyNames.indexOf(w.name) >= 0; var sat = w.satisfaction; var satColor = sat>=100?'#4caf50':sat>=65?'#4caf50':sat>=40?'#e53935':sat>=12?'#ff9800':sat>=6?'#555':'#c62828'; var satIcon = sat>=100?'💕':sat>=65?'💗':sat>=40?'❤️':sat>=12?'🧡':sat>=6?'🖤':'⚠️'; var satPct = Math.min(100, sat) + '%'; var svc = SugarCube.State.variables; var currentDay = svc.player ? svc.player.day : 0; var daysSince = currentDay - (w.lastShootingDay || 0); var decayThreshold = (svc.satisfactionDelayItem && svc.satisfactionDelayItem.bought) ? 5 : 4; if(sat > 40) decayThreshold += 1; if(svc.easyMode) decayThreshold += 2; var dbd = decayThreshold - daysSince; var dbdStr = sat >= 100 ? '🔒 locked' : (isResting ? '' : (dbd <= 0 ? '⏳ 🔴 now' : (dbd === 1 ? '⏳ ⚠️ 1d' : '⏳ '+dbd+'d'))); var dbdColor = sat >= 100 ? '#ffd700' : (dbd <= 0 ? '#e53935' : (dbd === 1 ? '#ff9800' : '#888')); var classes = 'star-card'; if(isElite) classes += ' lucky-gold'; else if(isLucky) classes += ' lucky-silver'; else if(isTrending) classes += ' trending'; if(isResting) classes += ' resting'; var clickAttr = onClick ? ' data-idx="'+idx+'" style="cursor:pointer;"' : ''; html += '<div class="'+classes+'"'+clickAttr+'>'; if(isResting) html += '<div class="badge">😴</div>'; if(isTrending && !isResting) html += '<div class="badge" style="background:rgba(255,215,0,0.85);color:#000;">🌟 Trending</div>'; html += '<img src="img/portraits/'+file+'.jpg" alt="'+w.name+'" style="cursor:zoom-in;" onclick="zoomPortrait(this.src)">'; html += '<div class="star-name">'+w.name+'</div>'; html += '\x3cdiv class="star-stats">'; html += w.ageNum+' y.o. | '+w.hair+' | '+w.height+'<br>'; html += w.breast+' ('+w.breastType+') | '+(w.ethnicity||'—')+'<br>'; html += '🌟 Pop: <b>'+w.popularity+'</b>'; if(w.favPosition) html += '<br>💖 Pos: '+w.favPosition + (w.favPosition2 ? ' & '+w.favPosition2 : ''); if(w.contractCost !== undefined) html += '<br>💳 $'+((SugarCube.State.variables.archetype==='charismatic')?Math.ceil(w.contractCost*0.9):w.contractCost).toLocaleString()+(SugarCube.State.variables.archetype==='charismatic'?' (-10%)':''); html += '\x3c/div>'; html += '<div style="margin-top:8px;color:'+satColor+';font-weight:bold;">'+satIcon+' '+sat+(dbdStr ? ' <span style="color:'+dbdColor+';font-weight:normal;font-size:0.85em;" title="Days left before satisfaction starts dropping (−5/day) from not shooting with her">'+dbdStr+'</span>' : '')+'</div>'; html += '<div class="sat-bar"><div class="sat-bar-fill" style="width:'+satPct+';background:'+satColor+';"></div></div>'; html += '\x3c/div>'; }); html += '\x3c/div>'; var wrap = document.getElementById(containerId); if(wrap){ wrap.innerHTML = html; if(onClick){ wrap.querySelectorAll('.star-card').forEach(function(card){ card.addEventListener('click', function(){ onClick(parseInt(this.getAttribute('data-idx'))); }); }); } } }; window.renderJudgeCardHTML = function(judge, imgId, size, highlighted){ var wrapStyle = highlighted ? 'background:linear-gradient(135deg,#2a2410,#1a1a2e);border:2px solid gold;border-radius:10px;padding:10px;text-align:center;' : 'background:linear-gradient(135deg,#1a1a2e,#16213e);border:1px solid #333;border-radius:10px;padding:10px;text-align:center;'; var r = judge.pref.revealed || {}; function fact(val, known){ return known ? ('<span style="color:#fff;">'+val+'</span>') : '<span style="opacity:0.5;">???</span>'; } var lp0 = fact(judge.pref.likePhysical[0].value, r.likePhysical && r.likePhysical[0]); var lp1 = fact(judge.pref.likePhysical[1].value, r.likePhysical && r.likePhysical[1]); var hp0 = fact(judge.pref.hatePhysical[0].value, r.hatePhysical && r.hatePhysical[0]); var hp1 = fact(judge.pref.hatePhysical[1].value, r.hatePhysical && r.hatePhysical[1]); var lPos = fact(judge.pref.likePosition, r.likePosition); var hPos = fact(judge.pref.hatePosition, r.hatePosition); var badge = highlighted ? '<div style="font-size:0.65em;color:#ffd700;font-weight:700;margin-top:2px;">👁️ CONFIRMED</div>' : ''; return '<div class="'+(highlighted?'judge-glow':'')+'" style="'+wrapStyle+'">' + '<img id="'+imgId+'" style="width:'+size+'px;height:'+size+'px;object-fit:cover;border-radius:8px;" src="">' + '<div style="font-weight:700;margin-top:6px;">'+judge.name+'</div>' + badge + '<div style="font-size:0.8em;color:#888;margin-top:4px;">Loves: '+lp0+' / '+lp1+'<br>Hates: '+hp0+' / '+hp1+'<div style="margin-top:4px;">Fav position: '+lPos+'<br>Hated position: '+hPos+'</div></div>' + '</div>'; }; window.renderJudgeGrid = function(judges, contestJudges, known, revealedArr, idPrefix, cols, size){ var html = '<div style="display:grid;grid-template-columns:repeat('+cols+',1fr);gap:10px;">'; for (var i=0;i<judges.length;i++){ var j = judges[i]; var isConfirmed = false; if (contestJudges && contestJudges.length === 2) { if ((known || (revealedArr && revealedArr[0])) && contestJudges[0].name === j.name) isConfirmed = true; if ((known || (revealedArr && revealedArr[1])) && contestJudges[1].name === j.name) isConfirmed = true; } html += window.renderJudgeCardHTML(j, idPrefix+'-'+i, size, isConfirmed); } html += '</div>'; return html; }; window.resolveJudgeCardPortraits = function(judges, idPrefix){ for (var i=0;i<judges.length;i++){ var el = document.getElementById(idPrefix+'-'+i); if(el) el.src = 'img/portraits/'+judges[i].portrait+'.jpg'; } }; /* ── Judge preference slots (used by Unlock Stat / Guess) ── */ window.judgeSlotList = function(){ return [ { cat:'likePhysical', idx:0 }, { cat:'likePhysical', idx:1 }, { cat:'hatePhysical', idx:0 }, { cat:'hatePhysical', idx:1 }, { cat:'likePosition' }, { cat:'hatePosition' } ]; }; window.slotIsRevealed = function(judge, slot){ return (slot.idx !== undefined) ? judge.pref.revealed[slot.cat][slot.idx] : judge.pref.revealed[slot.cat]; }; window.slotSetRevealed = function(judge, slot){ if (slot.idx !== undefined) judge.pref.revealed[slot.cat][slot.idx] = true; else judge.pref.revealed[slot.cat] = true; }; window.isJudgeFullyKnown = function(judge){ var r = judge.pref.revealed; return r.likePhysical[0] && r.likePhysical[1] && r.hatePhysical[0] && r.hatePhysical[1] && r.likePosition && r.hatePosition; }; window.checkFullPanelTrophy = function(judge){ var sv = SugarCube.State.variables; if (!sv.easyMode && !sv.trophies.fullPanel && window.isJudgeFullyKnown(judge)){ sv.trophies.fullPanel = true; sv.newTrophy = '🏆 Full Panel — fully learned every preference of a judge!'; window.checkAllTrophies(); } }; window.cleanupQuestlineForLostStar = function(name){ var sv = SugarCube.State.variables; var ql = sv.questlines; if (!ql || !name) return; if (ql.asianDuo && (ql.asianDuo.star1 === name || ql.asianDuo.star2 === name) && !ql.asianDuo.shooting2Done){ ql.asianDuo.active = false; ql.asianDuo.step = 0; ql.asianDuo.star1 = ''; ql.asianDuo.star2 = ''; ql.asianDuo.specialAvailable = false; ql.asianDuo.shooting1Done = false; ql.asianDuo.shooting2Done = false; } if (ql.fallenAngels && (ql.fallenAngels.star1 === name || ql.fallenAngels.star2 === name) && !ql.fallenAngels.shooting3Done){ ql.fallenAngels.active = false; ql.fallenAngels.step = 0; ql.fallenAngels.star1 = ''; ql.fallenAngels.star2 = ''; ql.fallenAngels.specialAvailable = false; ql.fallenAngels.shooting1Done = false; ql.fallenAngels.shooting2Done = false; ql.fallenAngels.shooting3Done = false; } if (ql.sweetCaprice && name === 'Caprice' && !ql.sweetCaprice.shooting2Done){ ql.sweetCaprice.active = false; ql.sweetCaprice.step = 0; ql.sweetCaprice.bjCount = 0; ql.sweetCaprice.step2Notified = false; ql.sweetCaprice.step3Notified = false; ql.sweetCaprice.step4Notified = false; ql.sweetCaprice.eveNotifyDay = -1; ql.sweetCaprice.specialAvailable = false; ql.sweetCaprice.shooting1Done = false; ql.sweetCaprice.shooting2Done = false; } }; window.checkAllTrophies = function(){ var sv = SugarCube.State.variables; if (sv.easyMode || sv.trophies.allTrophies) return; var allDone = Object.keys(sv.trophies).every(function(k){ return k === 'allTrophies' || sv.trophies[k]; }); if (allDone){ sv.trophies.allTrophies = true; var msg = '🏆 Completionist — every trophy earned! You finished Casting Couch Manager V3.'; sv.newTrophy = sv.newTrophy ? (sv.newTrophy + '<br><br>' + msg) : msg; } }; window.skTooltipShow = function(nodeEl){ var tip = nodeEl.querySelector('.sk-tooltip'); if(!tip) return; var r = nodeEl.getBoundingClientRect(); var tipWidth = 190; var left = r.right + 8; if (left + tipWidth + 12 > window.innerWidth) left = r.left - tipWidth - 8; if (left < 4) left = 4; tip.style.position = 'fixed'; tip.style.left = left + 'px'; tip.style.top = r.top + 'px'; tip.style.zIndex = '99999'; tip.style.display = 'block'; }; window.skTooltipHide = function(nodeEl){ var tip = nodeEl.querySelector('.sk-tooltip'); if(tip) tip.style.display = 'none'; }; window.slotValue = function(judge, slot){ return (slot.idx !== undefined) ? judge.pref[slot.cat][slot.idx].value : judge.pref[slot.cat]; }; window.slotType = function(judge, slot){ return (slot.idx !== undefined) ? judge.pref[slot.cat][slot.idx].type : 'position'; }; window.slotIsLike = function(slot){ return slot.cat === 'likePhysical' || slot.cat === 'likePosition'; }; window.slotLabel = function(slot){ var kind = (slot.cat === 'likePosition' || slot.cat === 'hatePosition') ? 'position' : 'trait'; return (window.slotIsLike(slot) ? 'liked' : 'hated') + ' ' + kind; }; window.getUnrevealedSlots = function(judge){ return window.judgeSlotList().filter(function(s){ return !window.slotIsRevealed(judge, s); }); }; window.pickRandomFrom = function(arr){ return arr[Math.floor(Math.random()*arr.length)]; }; window.physicalOptionPool = [ {type:'hair',value:'Brown'},{type:'hair',value:'Blonde'},{type:'hair',value:'Black'}, {type:'height',value:'Short'},{type:'height',value:'Tall'}, {type:'ageCat',value:'Young'},{type:'ageCat',value:'Veteran'}, {type:'breast',value:'Small'},{type:'breast',value:'Large'},{type:'breast',value:'Huge'}, {type:'breastType',value:'Fake'},{type:'breastType',value:'Real'}, {type:'ethnicity',value:'Latina'},{type:'ethnicity',value:'Asian'},{type:'ethnicity',value:'Black'},{type:'ethnicity',value:'Caucasian'} ]; window.getPositionOptionPool = function(){ return SugarCube.State.variables.allPositions.filter(function(p){ return p.name !== 'Specialty 1' && p.name !== 'Specialty 2'; }).map(function(p){ return p.name; }).concat(['Anal','Titfuck','Standing']); }; window.buildGuessOptions = function(judge, slot){ var correct = window.slotValue(judge, slot); var decoys, opts; if (window.slotType(judge, slot) === 'position') { var usedPositions = [judge.pref.likePosition, judge.pref.hatePosition]; decoys = window.getPositionOptionPool().filter(function(p){ return usedPositions.indexOf(p) === -1; }); decoys = decoys.sort(function(){ return Math.random()-0.5; }).slice(0,2); } else { var physSlots = [ { cat:'likePhysical', idx:0 }, { cat:'likePhysical', idx:1 }, { cat:'hatePhysical', idx:0 }, { cat:'hatePhysical', idx:1 } ]; var correctType = window.slotType(judge, slot); var otherTypes = physSlots .filter(function(s){ return !(s.cat === slot.cat && s.idx === slot.idx); }) .map(function(s){ return window.slotType(judge, s); }); /* Prefer decoys of the same type as the correct answer (e.g. other hair colors); only pad with a different, still-unclaimed type if that type doesn't have enough options. */ var sameTypePool = window.physicalOptionPool.filter(function(p){ return p.type === correctType && p.value !== correct; }); var otherPool = window.physicalOptionPool.filter(function(p){ return p.type !== correctType && otherTypes.indexOf(p.type) === -1; }); sameTypePool = sameTypePool.sort(function(){ return Math.random()-0.5; }); otherPool = otherPool.sort(function(){ return Math.random()-0.5; }); decoys = sameTypePool.concat(otherPool).slice(0,2).map(function(p){ return p.value; }); } opts = decoys.concat([correct]); opts = opts.sort(function(){ return Math.random()-0.5; }); return opts; }; <</script>> /* ════════════════════════════════════════════ PASSAGE : Competition ════════════════════════════════════════════ */
<h1 style="margin:0 0 0.1em 0;">🏴 <<= $rival.name>><<if $rivalVideoPrefix && $rivalOriginalName>> @@color:#888;<small>(formerly <<= $rivalOriginalName>>)</small>@@<</if>></h1> <div style="font-size:1.15em;margin:0 0 14px 0;">🌟 Reputation: <<= $rival.reputation>></div> <div style="font-size:1.25em;"> <b style="font-size:1.1em;">Their roster:</b> <div id="rival-roster"></div> <div id="poach-buttons" style="margin-top:8px;"></div> <b style="font-size:1.1em;">Their last production:</b> <div id="rival-last-shooting"></div> </div> [[⬅️ Dashboard|Dashboard]] <<script>> jQuery(document).one(':passageend', function(){ var rival = SugarCube.State.variables.rival; var rivalLastShooting = SugarCube.State.variables.rivalLastShooting; var rosterEl = document.getElementById('rival-roster'); if(rosterEl){ if(rival.roster.length === 0){ rosterEl.innerHTML = '<em>'+rival.name+' has no talents yet.</em>'; } else { var html = '<div style="display:flex;flex-wrap:wrap;gap:18px;margin:10px 0;">'; rival.roster.forEach(function(w){ var file = w.name.toLowerCase().replace(/ /g,'_'); html += '<div style="text-align:center;">'; html += '<img src="img/portraits/'+file+'.jpg" style="width:130px;height:130px;object-fit:cover;border-radius:10px;display:block;box-shadow:0 4px 12px rgba(0,0,0,0.4);">'; html += '<div style="margin-top:4px;font-size:1em;">'+w.name+'</div></div>'; }); html += '\x3c/div>'; rosterEl.innerHTML = html; } } /* ── Poach buttons ── */ var poachWrap = document.getElementById('poach-buttons'); if(poachWrap){ if(!SugarCube.State.variables.poachingUnlocked){ poachWrap.innerHTML = '<em style="color:#555;font-size:0.85em;">Poaching will become available after a special event.</em>'; } else { var agg = SugarCube.State.variables.rivalAggression || 0; var aggColor = agg >= 5 ? '#ff7a7a' : (agg >= 2 ? '#ffcc44' : '#888'); var html = '<div style="font-size:0.8em;color:'+aggColor+';margin-bottom:6px;">😈 '+rival.name+' agressivity: '+agg.toFixed(2)+' <span style="color:#555;">(+'+(10+agg).toFixed(2)+'% daily sabotage chance)</span></div>'; var investments = SugarCube.State.variables.poachingInvestments || {}; rival.roster.forEach(function(w){ var svp = SugarCube.State.variables; var isElite = w.name === 'Eve' || (svp.poolElite && svp.poolElite.indexOf(w.name) >= 0); var isEstablished = !isElite && svp.poolConfirmed && svp.poolConfirmed.indexOf(w.name) >= 0; var requiredSteps = isElite ? 5 : (isEstablished ? 4 : 3); var stepCosts = isElite ? [500, 1000, 1500, 2000, 2500] : (isEstablished ? [500, 1000, 1500, 2000] : [500, 1000, 1500]); var steps = investments[w.name] || 0; var attempts = (SugarCube.State.variables.poachAttempts || {})[w.name] || 0; var successPct = Math.round(((attempts + 1) / 4) * 100); html += '<div style="display:flex;align-items:center;gap:8px;margin:4px 0;padding:6px 10px;background:#0a0a1a;border-radius:6px;">'; html += '<b style="flex:1;font-size:0.9em;">'+w.name+(isElite?' ⭐⭐⭐':(isEstablished?' ⭐⭐':''))+'</b>'; if(steps < requiredSteps){ html += '<span style="font-size:0.78em;color:#888;">Approach: '+steps+'/'+requiredSteps+'</span>'; } else { html += '<span style="font-size:0.78em;color:#888;">'+successPct+'% chance</span>'; } if(steps < requiredSteps){ var cost = stepCosts[steps]; var usedToday = (SugarCube.State.variables.lastPoachStepDay >= SugarCube.State.variables.player.day); if(usedToday){ html += '<span style="font-size:0.78em;color:#555;opacity:0.5;">Approach tomorrow</span>'; } else if(SugarCube.State.variables.player.money >= cost){ html += '<button class="poach-step-btn" data-name="'+w.name+'" data-cost="'+cost+'" data-step="'+steps+'" style="padding:3px 10px;background:#1a1a2e;border:1px solid #4a9eff;color:#4a9eff;border-radius:4px;cursor:pointer;font-size:0.8em;">Approach $'+cost.toLocaleString()+'</button>'; } else { html += '<span style="font-size:0.78em;color:#555;">$'+cost.toLocaleString()+' needed</span>'; } } if(steps === requiredSteps){ var poachUsedToday = (SugarCube.State.variables.lastPoachDay >= SugarCube.State.variables.player.day); if(poachUsedToday){ html += '<span style="font-size:0.78em;color:#555;opacity:0.5;">Poach tomorrow</span>'; } else if(SugarCube.State.variables.player.money >= 1500){ html += '<button class="poach-btn" data-name="'+w.name+'" data-steps="'+steps+'" style="padding:3px 10px;background:#1a1a2e;border:1px solid #cc4444;color:#cc4444;border-radius:4px;cursor:pointer;font-size:0.8em;">Poach $1,500</button>'; } else { html += '<span style="font-size:0.78em;color:#555;opacity:0.5;">Poach $1,500 — no funds</span>'; } } html += '</div>'; }); poachWrap.innerHTML = html; poachWrap.querySelectorAll('.poach-step-btn').forEach(function(btn){ btn.addEventListener('click', function(){ var name = this.getAttribute('data-name'); var cost = parseInt(this.getAttribute('data-cost')); var sv = SugarCube.State.variables; if(sv.player.money < cost) return; if(sv.lastPoachStepDay >= sv.player.day){ alert('You already invested in a poaching step today. Come back tomorrow.'); return; } sv.player.money -= cost; if(!sv.poachingInvestments) sv.poachingInvestments = {}; sv.poachingInvestments[name] = (sv.poachingInvestments[name] || 0) + 1; sv.totalPoachingSteps = (sv.totalPoachingSteps || 0) + 1; sv.lastPoachStepDay = sv.player.day; sv.rivalAggression = (sv.rivalAggression || 0) + 0.25; SugarCube.Engine.play('Competition'); }); }); poachWrap.querySelectorAll('.poach-btn').forEach(function(btn){ btn.addEventListener('click', function(){ var name = this.getAttribute('data-name'); var steps = parseInt(this.getAttribute('data-steps')); var sv = SugarCube.State.variables; if(steps < 3){ alert('You need to complete all approach steps before poaching.'); return; } if(sv.player.money < 1500) return; if(sv.lastPoachDay >= sv.player.day){ alert('You already attempted a poach today. Come back tomorrow.'); return; } sv.player.money -= 1500; sv.lastPoachDay = sv.player.day; sv.totalPoachingSteps = (sv.totalPoachingSteps || 0) + 1; sv.rivalAggression = (sv.rivalAggression || 0) + 0.5; if(!sv.poachAttempts) sv.poachAttempts = {}; var attempts = sv.poachAttempts[name] || 0; var roll = Math.random(); var threshold = (attempts + 1) / 4; if(roll < threshold){ /* Success — move star to player roster */ var starIdx = sv.rival.roster.findIndex(function(w){ return w.name === name; }); if(starIdx >= 0){ var star = sv.rival.roster.splice(starIdx, 1)[0]; star.available = true; star.joinedDay = sv.player.day; /* Force SugarCube array reactivity by reassigning */ var newRoster = sv.roster.slice(); newRoster.push(star); sv.roster = newRoster; var newRivalRoster = sv.rival.roster.slice(); sv.rival.roster = newRivalRoster; /* Reset investment */ if(sv.poachingInvestments) delete sv.poachingInvestments[name]; if(sv.poachAttempts) delete sv.poachAttempts[name]; sv.totalPoachesSucceeded = (sv.totalPoachesSucceeded || 0) + 1; sv.rivalAggression = (sv.rivalAggression || 0) + 2; /* Trophy checks */ if(!sv.easyMode){ if(!sv.trophies.firstPoach){ sv.trophies.firstPoach = true; sv.newTrophy = '🏆 Poacher — first rival star successfully poached!'; window.checkAllTrophies(); } if(!sv.trophies.poachMaster && sv.totalPoachesSucceeded >= 5){ sv.trophies.poachMaster = true; sv.newTrophy = '🏆 Poach Master — 5 rival stars poached!'; window.checkAllTrophies(); } } alert('✅ ' + name + ' has joined your agency!'); } } else { sv.poachAttempts[name] = Math.min((sv.poachAttempts[name] || 0) + 1, 3); alert('❌ Poaching failed. ' + name + ' stayed with ' + sv.rival.name + '. ($1,500 lost)'); } SugarCube.Engine.play('Competition'); }); }); } /* end poachingUnlocked */ } var shootingEl = document.getElementById('rival-last-shooting'); if(shootingEl){ if(rivalLastShooting){ var prefix = SugarCube.State.variables.rivalVideoPrefix || ''; var starFile = rivalLastShooting.star.toLowerCase().replace(/ /g,'_'); var toFile = function(p){ return p.toLowerCase().replace(/ /g,'_').replace(/-/g,'_'); }; /* Prefer the daily random pick, but fall back to whichever position actually has a video on disk for this star instead of dead-ending on a "video not found" message. */ var allPosNames = ['BJ','Missionary','Doggy','Cowgirl','Reverse Cowgirl','Spooning','Facial','Anal','Titfuck','Standing']; var chosenPos = rivalLastShooting.position; var rest = allPosNames.filter(function(p){ return p !== chosenPos; }); for(var _ci = rest.length - 1; _ci > 0; _ci--){ var _cj = Math.floor(Math.random() * (_ci + 1)); var _ctmp = rest[_ci]; rest[_ci] = rest[_cj]; rest[_cj] = _ctmp; } var candidates = [chosenPos].concat(rest); shootingEl.innerHTML = '<em id="riv-vid-label">'+rivalLastShooting.star+' — <strong>'+chosenPos+'</strong></em><br><div id="riv-vid-wrap"></div>'; var wrapEl = document.getElementById('riv-vid-wrap'); var labelEl = document.getElementById('riv-vid-label'); var candIdx = 0; var tryNextCandidate = function(){ if(candIdx >= candidates.length){ wrapEl.innerHTML = '<em style="color:#888;">⚠️ No video available for '+rivalLastShooting.star+'.</em>'; return; } var pos = candidates[candIdx++]; var videoSrc = 'videos/' + prefix + starFile + '_' + toFile(pos) + '.webm'; console.log('[Competition] trying video:', videoSrc); var v = document.createElement('video'); v.autoplay = true; v.loop = true; v.muted = true; v.playsInline = true; v.style.cssText = 'width:100%;max-width:600px;border-radius:10px;margin-top:8px;box-shadow:0 4px 16px rgba(0,0,0,0.4);'; v.onerror = function(){ tryNextCandidate(); }; v.oncanplay = function(){ labelEl.innerHTML = rivalLastShooting.star+' — <strong>'+pos+'</strong>'; }; v.src = videoSrc; wrapEl.innerHTML = ''; wrapEl.appendChild(v); }; tryNextCandidate(); } else { shootingEl.innerHTML = '<em>'+rival.name+' hasn\'t produced anything yet.</em>'; } } }); <</script>> /* ════════════════════════════════════════════ PASSAGE : StarProfile ════════════════════════════════════════════ */
<<set _w = $roster[$profileIndex]>> <h1 style="margin:0 0 0.4em 0;">👤 <<= _w.name>></h1> <<= _w.ageNum>> y.o. (<<= _w.ageCat>>) 💇 Hair: <<= _w.hair>> | 📏 Height: <<= _w.height>> 🎭 Tits: <<= _w.breast>> (<<= _w.breastType>>) 🌟 Popularity: <<= _w.popularity>> | 🔄 Upkeep: $<<= (_w.popularity * 70).toLocaleString()>>/week 💖 Fav Position: <<= _w.favPosition>> | 🔓 Bonus (sat. 30+): <<= _w.bonusPosition>> Productions this week: <<= _w.weekShootings>> Satisfaction: <<if _w.satisfaction >= 70>> @@color:green;<<= _w.satisfaction>>% 😊@@ <<elseif _w.satisfaction >= 40>> @@color:orange;<<= _w.satisfaction>>% 😐@@ <<else>> @@color:red;<<= _w.satisfaction>>% 😠 (at risk of leaving!)@@ <</if>> [[⬅️ Back|Roster]] /* ════════════════════════════════════════════ PASSAGE : INTRO ════════════════════════════════════════════ */
<h1 style="margin:0 0 0.4em 0;">🎬 Casting Couch Manager V.3</h1> <img src="img/banner.jpg" style="width:100%;max-height:300px;object-fit:cover;border-radius:8px;margin-bottom:12px;"> <em>Los Angeles. 2 AM.</em> The city doesn't sleep and neither do you. Your agency is worth nothing yet — but you've got hunger, instinct, and a roster of women who know exactly what they're doing on camera. The audience is out there, credit card in hand. They want faces, bodies, chemistry — and someone bold enough to put it all on screen without blinking. Your rival is already signing contracts. They're not waiting. Neither are you. <em>Sign your talents. Direct their scenes. Make them stars — and make the audience beg for more.</em> <div style="padding:10px;background:#111;border-radius:6px;font-size:0.88em;line-height:1.6;"> 🌟 <b>Reputation</b> grows with every production. It unlocks new positions, new talents, and new opportunities.<br> 💰 <b>Money</b> comes from your productions — the more popular your talents and the higher your reputation, the bigger the earnings. But talents cost money to keep: you pay weekly upkeep based on their popularity.<br> ❤️ <b>Satisfaction</b> is everything. A happy performer gives their best and unlocks new positions. Neglect them and they'll look for work elsewhere — your rival will be happy to oblige.<br> 📈 <b>Daily trends</b> shift every day. Matching the trending position or talent profile gives you a multiplier bonus on earnings and extra reputation.<br> ⏳ <b>Rest days</b> are mandatory. After two consecutive productions, a talent needs a day off. Plan ahead.<br> 🎯 <b>Your first goal:</b> sign at least 3 talents before Day 16 — or it's game over. </div> <b>Your name:</b> <<textbox "$player.name" "Alex">> <b>Your agency name:</b> <<textbox "$studioName" "Thunder Agency">> <b>Your rival's name:</b> <<textbox "$rival.name" "Iron Studio">> <div style="padding:10px 14px;background:#111;border-radius:8px;margin:10px 0;"> <label style="cursor:pointer;"><<checkbox "$easyMode" false true>> <b>🟢 Play in Easy Mode</b></label> <div style="font-size:0.85em;color:#999;margin-top:4px;">Talents tolerate <b>2 extra days</b> before satisfaction decay kicks in, and weekly upkeep is <b>30% cheaper</b>. In exchange, <b>trophies are locked</b> for this playthrough — you won't be able to earn any.</div> </div> [[▶️ Choose your archetype|ChooseArchetype]] /* ════════════════════════════════════════════ PASSAGE : ChooseArchetype ════════════════════════════════════════════ */
<h1 style="margin:0 0 0.4em 0;">🎭 Choose Your Archetype</h1> <div class="archetype-grid"><div class="archetype-card acc-gold"><div class="archetype-icon">💰</div><h3>Rich</h3><span class="archetype-desc">You come from money. Less hustle, more capital.</span><div class="archetype-perks"><div>• Start with <b>$6,000</b></div><div>• No special bonuses</div></div>[[▶️ Play|ApplyArchetype][$archetype = "rich"]]</div><div class="archetype-card acc-blue"><div class="archetype-icon">🥋</div><h3>Skillful</h3><span class="archetype-desc">You've trained hard and know your positions.</span><div class="archetype-perks"><div>• Start with <b>$4,750</b></div><div>• Start with <b>reputation 4</b></div><div>• <b>BJ & Missionary</b> unlocked</div><div>• <b>−10%</b> on positions</div></div>[[▶️ Play|ApplyArchetype][$archetype = "skillful"]]</div><div class="archetype-card acc-pink"><div class="archetype-icon">✨</div><h3>Charismatic</h3><span class="archetype-desc">Everyone loves you. Talents want to work with you.</span><div class="archetype-perks"><div>• Start with <b>$4,500</b></div><div>• <b>−10%</b> on contracts</div><div>• Talents start at <b>15 satisfaction</b></div></div>[[▶️ Play|ApplyArchetype][$archetype = "charismatic"]]</div><div class="archetype-card acc-green"><div class="archetype-icon">🎲</div><h3>Gambler</h3><span class="archetype-desc">You live for the thrill. Every draw is a bet.</span><div class="archetype-perks"><div>• Start with <b>$5,000</b></div><div>• Draw costs <b>cut in half</b></div><div>• Quantity over certainty</div></div>[[▶️ Play|ApplyArchetype][$archetype = "gambler"]]</div></div> /* ════════════════════════════════════════════ PASSAGE : ApplyArchetype ════════════════════════════════════════════ */
<<if $archetype is "rich">> <<set $player.money = 6000>> <<elseif $archetype is "skillful">> <<set $player.money = 4750>> <<set $player.reputation = 4>> <<set $allPositions[1].unlocked = true>> <<set $playerPositions.push("Missionary")>> <<elseif $archetype is "charismatic">> <<set $player.money = 4500>> <<set $charismaticSatBonus = 5>> <<elseif $archetype is "gambler">> <<set $player.money = 5000>> <</if>> <<script>> /* All 18 stars — neutral shuffle, pools assigned at runtime */ (function(){ var pool = SugarCube.State.variables.recruitPool.slice().filter(function(w){ return w.name !== 'Eve'; }); /* Specialty 1/2 — placeholder per-star names, customize later */ pool.forEach(function(w){ w.pers1 = 'Specialty 1'; w.pers2 = 'Specialty 2'; }); /* Extract questline stars before shuffle to guarantee their pool placement */ var questlineNames = ['Kimmy', 'Lulu', 'Angie', 'Angela']; var questlineStars = {}; questlineNames.forEach(function(name){ var idx = pool.findIndex(function(w){ return w.name === name; }); if(idx >= 0){ questlineStars[name] = pool.splice(idx, 1)[0]; } }); /* Shuffle the remaining pool */ for(var i = pool.length-1; i>0; i--){ var j = Math.floor(Math.random()*(i+1)); var tmp = pool[i]; pool[i]=pool[j]; pool[j]=tmp; } /* Assign pools from shuffled non-questline stars */ /* After extracting 4 questline stars, 17 remain. Pool layout: 7 pool1 + 4 pool2 + 4 elite + 1 rival + 1 bonus = 17 */ var beginner = pool.slice(0,7); var confirmed = pool.slice(7,11); var elite = pool.slice(11,15); var rivalStar = pool[15]; var bonusStar = pool[16]; /* Force questline stars into their fixed pools */ /* Asian Duo: Kimmy → pool1, Lulu → pool2 */ if(questlineStars['Kimmy']) beginner.push(questlineStars['Kimmy']); if(questlineStars['Lulu']) confirmed.push(questlineStars['Lulu']); /* Two Fallen Angels: Angie → pool1, Angela → pool2 */ if(questlineStars['Angie']) beginner.push(questlineStars['Angie']); if(questlineStars['Angela']) confirmed.push(questlineStars['Angela']); beginner.forEach(function(w){ if(w && w.popularity !== undefined){ w.popularity = Math.floor(Math.random()*4)+3; w.contractCost = Math.floor(Math.random()*3)*250+2000; }}); confirmed.forEach(function(w){ if(w && w.popularity !== undefined){ w.popularity = Math.floor(Math.random()*4)+10; w.contractCost = (Math.floor(Math.random()*3)+10)*500; }}); elite.forEach(function(w){ if(w && w.popularity !== undefined){ w.popularity = Math.floor(Math.random()*6)+25; w.contractCost = (Math.floor(Math.random()*5)+20)*1000; }}); if(rivalStar){ rivalStar.popularity = Math.floor(Math.random()*4)+5; rivalStar.contractCost = 3000; rivalStar.available = false; } if(bonusStar){ bonusStar.popularity = Math.floor(Math.random()*4)+6; bonusStar.contractCost = Math.floor(Math.random()*(4250-3000+1))+3000; bonusStar.available = false; } /* ── Randomize favorite/bonus positions, weighted by star tier ── Beginner (1★): biased toward low-level positions Confirmed (2★): uniform across all positions Elite (3★): biased toward high-level positions */ var allPos = SugarCube.State.variables.allPositions; function weightFor(tier, level){ if(tier === 'beginner') return Math.max(1, 11 - level); if(tier === 'elite') return level; return 1; /* confirmed */ } function weightedPick(tier, exclude){ var bag = []; allPos.forEach(function(p){ if(p.name === 'Specialty 1' || p.name === 'Specialty 2') return; if(exclude && exclude.indexOf(p.name) >= 0) return; var w = weightFor(tier, p.level); for(var i=0; i<w; i++) bag.push(p.name); }); return bag[Math.floor(Math.random()*bag.length)]; } function assignFavPositions(arr, tier){ arr.forEach(function(w){ if(!w) return; var fav = weightedPick(tier); var b1 = weightedPick(tier, [fav]); var b2 = weightedPick(tier, [fav, b1]); w.favPosition = fav; w.bonusPosition1 = b1; w.bonusPosition2 = b2; }); } assignFavPositions(beginner, 'beginner'); assignFavPositions(confirmed, 'confirmed'); assignFavPositions(elite, 'elite'); if(rivalStar) assignFavPositions([rivalStar], 'confirmed'); if(bonusStar) assignFavPositions([bonusStar], 'confirmed'); SugarCube.State.variables.poolBeginner = beginner.filter(function(w){ return w && w.name; }).map(function(w){ return w.name; }); SugarCube.State.variables.poolConfirmed = confirmed.filter(function(w){ return w && w.name; }).map(function(w){ return w.name; }); SugarCube.State.variables.poolElite = elite.filter(function(w){ return w && w.name; }).map(function(w){ return w.name; }); SugarCube.State.variables.poolSpecial = null; SugarCube.State.variables.bonusEventStar = bonusStar.name; SugarCube.State.variables.rivalStartStar = rivalStar.name; SugarCube.State.variables.rivalOriginalName = SugarCube.State.variables.rival.name; rivalStar.available = false; SugarCube.State.variables.rival.roster.push(JSON.parse(JSON.stringify(rivalStar))); })(); <</script>> <<goto "Dashboard">> /* ════════════════════════════════════════════ PASSAGE : DASHBOARD ════════════════════════════════════════════ */
<h1 style="margin:0 0 0.4em 0;">📊 Dashboard — Day <<= $player.day>></h1> <<if $rivalSabotageStar>> <<if $rivalSabotageStolen>> @@color:red;😈 <b><<= $rival.name>></b> got to <b><<= $rivalSabotageStar>></b> — satisfaction crashed and she walked. <<= $rival.name>> picked her up immediately.@@<<if $player.day >= 30>><div id="poach-video-wrap"></div><<script>>jQuery(document).one(':passageend',function(){var s=SugarCube.State.variables.poachVideoStar;if(!s)return;var f=s.toLowerCase().replace(/ /g,'_');var src='videos/b_'+f+'_bj.webm';var el=document.getElementById('poach-video-wrap');if(el){var v=document.createElement('video');v.src=src;v.autoplay=true;v.loop=true;v.muted=true;v.playsInline=true;v.style.width='100%';v.style.maxWidth='480px';v.style.borderRadius='8px';v.style.marginTop='8px';v.onerror=function(){this.style.display='none';};el.innerHTML='';el.appendChild(v);}SugarCube.State.variables.poachVideoStar='';});<</script>><</if>> <<else>> @@color:orange;😈 <b><<= $rival.name>></b> got to <b><<= $rivalSabotageStar>></b> — satisfaction dropped by 10.@@ <</if>> <<set $rivalSabotageStar = "">> <<set $rivalSabotageStolen = false>> <</if>> <<if $poachMessage>> @@color:red;⚠️ <<= $poachMessage>>@@ <<set $poachMessage = "">> <<if $poachVideoStar>><div id="poach-video-wrap"></div><<script>>jQuery(document).one(':passageend',function(){var s=SugarCube.State.variables.poachVideoStar;if(!s)return;var f=s.toLowerCase().replace(/ /g,'_');var src='videos/b_'+f+'_bj.webm';var el=document.getElementById('poach-video-wrap');if(el){var v=document.createElement('video');v.src=src;v.autoplay=true;v.loop=true;v.muted=true;v.playsInline=true;v.style.width='100%';v.style.maxWidth='480px';v.style.borderRadius='8px';v.style.marginTop='8px';v.onerror=function(){this.style.display='none';};el.innerHTML='';el.appendChild(v);}SugarCube.State.variables.poachVideoStar='';});<</script>><</if>> <</if>> <<if $newJudgeSpecialReveal>> @@color:#6fcf73;🕵️ <<= $newJudgeSpecialReveal>>@@ <<set $newJudgeSpecialReveal = "">> <</if>> <<if $judgeSpecialMissed>> @@color:#ff8080;🎬 <<= $judgeSpecialMissed>>@@ <<set $judgeSpecialMissed = "">> <</if>> <<if $newTrophy>><<script>>(function(){ var text = SugarCube.State.variables.newTrophy; var ov = document.createElement('div'); ov.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,0.85);display:flex;align-items:center;justify-content:center;z-index:9999;cursor:pointer;'; ov.innerHTML = '<div style="text-align:center;padding:32px 40px;background:linear-gradient(135deg,#2a2410,#1a1a2e);border:2px solid #ffd700;border-radius:16px;box-shadow:0 0 40px rgba(255,215,0,0.4),0 10px 30px rgba(0,0,0,0.6);max-width:400px;animation:gainReveal 0.5s ease-out;"><div style="font-size:3em;margin-bottom:8px;">🏆</div><div style="font-size:1.3em;font-weight:700;color:#ffd700;margin-bottom:8px;">Trophy Unlocked!</div><div style="font-size:1.05em;color:#eee;">'+text+'</div><div style="margin-top:16px;font-size:0.85em;color:#888;">Click anywhere to continue</div></div>'; ov.onclick = function(){ ov.remove(); }; document.body.appendChild(ov); })();<</script>><<set $newTrophy = "">><</if>> <<if $shootingPlayedToday>> @@color:orange;✋ You already produced today. Move to the next day to continue.@@ <</if>> <style> #dash-buttons { display:grid; grid-template-columns:repeat(auto-fill, minmax(190px, 1fr)); gap:12px 10px; margin:14px 0; max-width:800px; } #dash-buttons > a, #dash-buttons > span { display:flex; align-items:center; justify-content:center; width:100%; min-height:64px; padding:10px 10px 16px; text-align:center; border-radius:10px; text-decoration:none; line-height:1.15; font-size:1.15em; font-weight:700; letter-spacing:0.2px; cursor:pointer; box-sizing:border-box; border-style:solid; border-width:2px 2px 5px; text-shadow:0 1px 2px rgba(0,0,0,0.7); box-shadow:0 6px 14px rgba(0,0,0,0.4), inset 0 1px 0 rgba(255,255,255,0.08); transition:transform 0.12s ease, filter 0.12s ease, box-shadow 0.12s ease, padding 0.12s ease, border-width 0.12s ease; } #dash-buttons > a:hover { transform:translateY(-2px); filter:brightness(1.2); box-shadow:0 9px 18px rgba(0,0,0,0.45), inset 0 1px 0 rgba(255,255,255,0.12); } #dash-buttons > a:active { transform:translateY(3px); padding:10px 10px 13px; border-width:2px 2px 2px; box-shadow:0 2px 4px rgba(0,0,0,0.4), inset 0 1px 0 rgba(255,255,255,0.08); filter:brightness(1.05); } #dash-buttons > a[href*="OrgShooting"] { background:linear-gradient(180deg,#1c4a2c,#0d2b1a); border-color:#2a7a3a; border-bottom-color:#0f3a1e; color:#8fe6a5; } #dash-buttons > a[href*="Shop"] { background:linear-gradient(180deg,#183462,#0d1f3a); border-color:#2a4a9e; border-bottom-color:#132a5c; color:#8fb8ff; } #dash-buttons > a[href*="SpecialShootingMenu"] { background:linear-gradient(180deg,#33165c,#1e0d3a); border-color:#6a2a9e; border-bottom-color:#3a1259; color:#d8a8ff; } #dash-buttons > a[href*="Recruitment"] { background:linear-gradient(180deg,#4a3200,#2b1d00); border-color:#9e6a00; border-bottom-color:#5c3d00; color:#ffdd77; } #dash-buttons > a[href*="Roster"] { background:linear-gradient(180deg,#00374a,#001f2b); border-color:#007a7a; border-bottom-color:#004040; color:#6fe8e8; } #dash-buttons > a[href*="Competition"] { background:linear-gradient(180deg,#4a1616,#2b0d0d); border-color:#9e2a2a; border-bottom-color:#5c1414; color:#ffa0a0; } #dash-buttons > span.db-btn-gray { background:linear-gradient(180deg,#262626,#1a1a1a); border-color:#444; border-bottom-color:#2a2a2a; color:#999; opacity:0.55; cursor:not-allowed; box-shadow:none; text-shadow:none; } #dash-buttons > a[href*="NextDay"] { background:linear-gradient(180deg,#3a2e00,#1a1200); border-color:#ffd700; border-bottom-color:#a8890a; color:#ffe680; box-shadow:0 0 20px rgba(255,215,0,0.4), 0 6px 14px rgba(0,0,0,0.4), inset 0 1px 0 rgba(255,255,255,0.15); } #dash-buttons > a[href*="NextDay"]:hover { filter:brightness(1.15); box-shadow:0 0 30px rgba(255,215,0,0.55), 0 9px 18px rgba(0,0,0,0.45), inset 0 1px 0 rgba(255,255,255,0.15); } #dash-buttons > a[href*="NextDay"]:active { box-shadow:0 0 14px rgba(255,215,0,0.4), 0 2px 4px rgba(0,0,0,0.4); } </style> <div id="dash-buttons">[[🎬 Run a production|OrgShooting]][[🌟 Special Shooting|SpecialShootingMenu]][[📋 Roster|Roster]][[🛒 Shop|Shop]][[👤 Recruit|Recruitment]]<<if $rival.roster.length > 0>>[[🏴 Competition|Competition]]<</if>><<if $contractShopAvailable && !$contract1.active && !$contract1.accepted>>[[📋 Contract Shop|ContractShop]]<<elseif $contract1.active || $contract1.accepted>><span class="db-btn-gray">📋 Contract Shop</span><<elseif $contractShopAvailableDay > 0>><span class="db-btn-gray">📋 Contract — <<= $contractShopAvailableDay - $player.day>>d</span><<else>><span class="db-btn-gray">📋 Contract Shop</span><</if>>[[📅 Next day|NextDay]]</div> /* ════════════════════════════════════════════ PASSAGE : SHOP ════════════════════════════════════════════ */
<h1 style="margin:0 0 0.4em 0;">🛒 Skill Tree</h1> <div id="skill-tree-wrap"></div> [[⬅️ Dashboard|Dashboard]] <<script>> jQuery(document).one(':passageend', function(){ var sv = SugarCube.State.variables; var p = sv.player; var arch = sv.archetype; /* ── helpers ── */ function price(base){ return (arch === 'skillful' && base > 0) ? Math.ceil(base * 0.9) : base; } function fmt(n){ return '$' + n.toLocaleString(); } /* state helpers */ function posObj(name){ return sv.allPositions.find(function(m){ return m.name === name; }); } function posUnlocked(name){ return sv.playerPositions.includes(name); } /* ── node status ── */ function status(id){ switch(id){ /* GENRES */ case 'BJ': return { ok: posUnlocked('BJ'), lock: false, reason: '' }; case 'Missionary': return chk('Missionary', posUnlocked('BJ'), 'BJ required'); case 'Doggy': return chk('Doggy', posUnlocked('Missionary'), 'Missionary required'); case 'Cowgirl': return chk('Cowgirl', posUnlocked('Doggy'), 'Doggy required'); case 'Reverse Cowgirl': return chk('Reverse Cowgirl',posUnlocked('Cowgirl'),'Cowgirl required'); case 'DoubleFeature': return chkItem(sv.doublePositionItem, posUnlocked('Reverse Cowgirl') && p.reputation >= 50, 'Reverse Cowgirl + rep 50'); case 'Spooning': return chk('Spooning', posUnlocked('Reverse Cowgirl') && p.reputation >= 50, 'Reverse Cowgirl + rep 50'); case 'Personal1': return chk('Specialty 1', sv.doublePositionItem.bought && sv.roster.some(function(w){ return w.satisfaction >= 60; }), 'Double Feature + a star at 60 satisfaction'); case 'Personal2': return chk('Specialty 2', posUnlocked('Specialty 1') && sv.roster.some(function(w){ return w.satisfaction >= 70; }), 'Specialty 1 + a star at 70 satisfaction'); case 'Facial': return chk('Facial', posUnlocked('Specialty 2') && sv.roster.some(function(w){ return w.satisfaction >= 80; }), 'Specialty 2 + a star at 80 satisfaction'); /* INTEL */ case 'P1Intel': return chkItem(sv.pool1IntelItem, true, ''); case 'P2Intel': return chkItem(sv.pool2IntelItem, sv.pool1IntelItem && sv.pool1IntelItem.bought, 'Pool 1 Intel required'); case 'P3Intel': return chkItem(sv.pool3IntelItem, sv.pool2IntelItem && sv.pool2IntelItem.bought, 'Pool 2 Intel required'); /* UPGRADES */ case 'EstDip': return chkItem(sv.pool1UpgradeItem, sv.player.day >= 30, 'Available from day 30'); case 'EstSurge': return chkItem(sv.pool1Upgrade2A, sv.pool1UpgradeItem.bought && sv.roster.filter(function(w){ return sv.poolConfirmed.indexOf(w.name) >= 0; }).length > 0, 'Est. Dip + 1 Established star'); case 'DblScouting': return chkItem(sv.pool1Upgrade2B, sv.pool1UpgradeItem.bought && p.reputation >= 10, 'Est. Dip + rep 10'); case 'TplScouting': return chkItem(sv.pool1Upgrade2C, sv.pool1Upgrade2B && sv.pool1Upgrade2B.bought, 'Double Scout required'); case 'QadScouting': return chkItem(sv.pool1Upgrade2D, sv.pool1Upgrade2C && sv.pool1Upgrade2C.bought, 'Triple Scout required'); case 'TargetedScout': return { ok: false, lock: true, reason: 'Not available in this version' }; case 'EliteDip': return chkItem(sv.pool2UpgradeItem, sv.pool1Upgrade2B.bought && sv.doublePositionItem.bought && p.reputation >= 20, 'Dbl Scout + Double Feature + rep 20'); case 'EliteSurge': return chkItem(sv.pool2Upgrade2, sv.pool2UpgradeItem.bought && p.reputation >= 30, 'Elite Dip + rep 30'); /* AGENCE */ case 'AD': { var adOk = sv.adItem.buyCount >= 3; return { ok: adOk, lock: false, canBuy: !adOk && sv.player.money >= sv.adItem.price, reason: '', count: sv.adItem.buyCount }; } case 'MarketStudy': return chkItem(sv.marketStudyItem, sv.adItem.buyCount >= 1 && p.reputation >= 25, 'AD Campaign + rep 25'); case 'Patience': return chkItem(sv.satisfactionDelayItem, sv.roster.length >= 5 && sv.adItem.buyCount >= 2 && p.reputation >= 50, '5 stars + 2 AD + rep 50'); /* CONTRACTS */ case 'ThirdOption': return chkItem(sv.contract3rdOptionItem, sv.contractShopAvailable || sv.contractShopAvailableDay > 0 || (sv.contract3rdOptionItem && sv.contract3rdOptionItem.bought), 'Complete Contract 1 first'); case 'HarderContract': return chkItem(sv.contractHarderItem, sv.contract3rdOptionItem && sv.contract3rdOptionItem.bought, '3rd Option required'); /* CONTEST */ case 'JudgeIntel1': { var ji1Ok = sv.judgeIntel1.buyCount >= 3; var ji1PrereqCount = (sv.unlockJudgeStatItem.buyCount || 0) + (sv.guessJudgeStatItem.buyCount || 0); var ji1PrereqOk = ji1PrereqCount >= 4; return { ok: ji1Ok, lock: !ji1Ok && !ji1PrereqOk, canBuy: ji1PrereqOk && !ji1Ok && sv.player.money >= sv.judgeIntel1.price, reason: !ji1PrereqOk ? ('Unlock Stat + Guess ×4 combined (' + ji1PrereqCount + '/4)') : '', count: sv.judgeIntel1.buyCount }; } case 'ImproveIntel': return chkItem(sv.improveIntelItem, p.day >= 36 && sv.judgeIntel1.buyCount >= 3, sv.judgeIntel1.buyCount < 3 ? 'Judge Intel I ×3 required' : 'Available from day 36'); case 'JudgeIntel2': { var ji2Prereq = sv.improveIntelItem.bought; var ji2DayOk = p.day >= 36; var ji2Done = sv.permanentJudgeIntelItem.bought; return { ok: ji2Done, lock: !ji2Done && (!ji2Prereq || !ji2DayOk), canBuy: !ji2Done && ji2Prereq && ji2DayOk && sv.player.money >= sv.judgeIntel2.price, reason: ji2Done ? '' : (!ji2Prereq ? 'Improve Intel required' : (!ji2DayOk ? 'Available from day 36' : '')), count: sv.judgeIntel2.buyCount }; } case 'PermanentJudgeIntel': return chkItem(sv.permanentJudgeIntelItem, p.day >= 36 && sv.judgeIntel2.buyCount >= 3, sv.judgeIntel2.buyCount < 3 ? 'Judge Intel II ×3 required' : 'Available from day 36'); /* JUDGE STATS */ case 'UnlockStat': { var usDayOk = p.day >= 36; var usAnyLeft = sv.judges.some(function(j){ return window.getUnrevealedSlots(j).length > 0; }); return { ok: false, lock: !usDayOk, canBuy: usDayOk && usAnyLeft && sv.player.money >= sv.unlockJudgeStatItem.price, reason: !usDayOk ? 'Available from day 36' : (!usAnyLeft ? 'All judge stats already known' : '') }; } case 'GuessStat': { var gsDayOk = p.day >= 36; var gsAnyLeft = sv.judges.some(function(j){ return window.getUnrevealedSlots(j).length > 0; }); var gsUsedToday = sv.guessStatUsedDay === p.day; var gsPrice = (sv.archetype === 'gambler') ? 100 : sv.guessJudgeStatItem.price; return { ok: false, lock: !gsDayOk, canBuy: gsDayOk && gsAnyLeft && !gsUsedToday && sv.player.money >= gsPrice, reason: !gsDayOk ? 'Available from day 36' : (!gsAnyLeft ? 'All judge stats already known' : (gsUsedToday ? 'Already guessed today' : '')) }; } default: return { ok: false, lock: true, reason: 'Unknown' }; } } function chk(posName, cond, reason){ var obj = sv.allPositions.find(function(m){ return m.name === posName; }); var unlocked = obj && obj.unlocked; if(unlocked) return { ok: true, lock: false, reason: '' }; if(obj && obj.comingSoon) return { ok: false, lock: true, reason: 'Coming soon' }; if(!cond) return { ok: false, lock: true, reason: reason }; var p2 = price(obj ? obj.price : 0); if(p2 > 0 && sv.player.money < p2) return { ok: false, lock: false, reason: 'No funds' }; return { ok: false, lock: false, reason: '', canBuy: true, buyId: posName }; } function chkItem(item, cond, reason){ if(!item) return { ok: false, lock: true, reason: reason || 'Not available' }; if(item.bought) return { ok: true, lock: false, reason: '' }; if(!cond) return { ok: false, lock: true, reason: reason }; if(sv.player.money < item.price) return { ok: false, lock: false, reason: 'No funds' }; return { ok: false, lock: false, reason: '', canBuy: true }; } /* ── node definitions ── */ var genres = [ { id:'BJ', label:'BJ', sub:'Gratuit', pass:null }, { id:'Missionary', label:'Missionary', sub:fmt(price(500))+' · rep10', pass:'BuyPosition', pidx:1 }, { id:'Doggy', label:'Doggy', sub:fmt(price(800))+' · rep20', pass:'BuyPosition', pidx:2 }, { id:'Cowgirl', label:'Cowgirl', sub:fmt(price(1200))+' · rep30', pass:'BuyPosition', pidx:3 }, { id:'Reverse Cowgirl', label:'Reverse Cowgirl',sub:fmt(price(1500))+' · rep40', pass:'BuyPosition', pidx:4 }, { id:'DoubleFeature',label:'Double Feature', sub:fmt(5000)+' · rep50', pass:'BuyDoubleFeature' }, { id:'Spooning', label:'Spooning', sub:fmt(price(1800))+' · rep50', pass:'BuyPosition', pidx:5 }, { id:'Personal1', label:'Specialty 1', sub:fmt(price(2000))+' · sat.60', pass:'BuyPosition', pidx:6 }, { id:'Personal2', label:'Specialty 2', sub:fmt(price(2500))+' · sat.70', pass:'BuyPosition', pidx:7 }, { id:'Facial', label:'Facial', sub:fmt(price(3000))+' · sat.80', pass:'BuyPosition', pidx:8 }, ]; var intel = [ { id:'P1Intel', label:'Pool 1 Intel', sub:fmt(500)+' · free', pass:'BuyPool1Intel' }, { id:'P2Intel', label:'Pool 2 Intel', sub:fmt(500)+' · P1 Intel', pass:'BuyPool2Intel' }, { id:'P3Intel', label:'Pool 3 Intel', sub:fmt(500)+' · Elite Dip', pass:'BuyPool3Intel' }, { id:'TargetedScout', label:'Targeted Scout', sub:'N/A', pass:'BuyTargetedScout' }, ]; var upgradesChance = [ { id:'EstDip', label:'Est. Dip', sub:fmt(2500)+' · j30', pass:'BuyPool1Upgrade' }, { id:'EstSurge', label:'Est. Surge', sub:fmt(5000)+' · 1★ Est.', pass:'BuyPool1Upgrade2A' }, { id:'EliteDip', label:'Elite Dip', sub:fmt(6000)+' · rep20', pass:'BuyPool2Upgrade' }, { id:'EliteSurge', label:'Elite Surge', sub:fmt(10000)+' · rep30', pass:'BuyPool2Upgrade2' }, ]; var upgradesMulti = [ { id:'DblScouting', label:'Double Scout', sub:fmt(2000)+' · rep10', pass:'BuyPool1Upgrade2B' }, { id:'TplScouting', label:'Triple Scout', sub:fmt(3000)+' · Dbl', pass:'BuyTripleScouting' }, { id:'QadScouting', label:'Quad Scout', sub:fmt(4000)+' · Tpl', pass:'BuyQuadScouting' }, ]; var agence = [ { id:'AD', label:'AD Campaign ×3', sub:fmt(3000)+' / achat', pass:'BuyAD' }, { id:'MarketStudy', label:'Market Study', sub:fmt(4000)+' · rep25', pass:'BuyMarketStudy' }, { id:'Patience', label:'Patience Train.', sub:fmt(3500)+' · rep50', pass:'BuySatisfactionDelay' }, ]; var contest = [ { id:'JudgeIntel1', label:'Judge Intel I', sub:fmt(400)+' · Stat/Guess ×4', pass:'BuyJudgeIntel1' }, { id:'ImproveIntel', label:'Improve Intel', sub:fmt(1500)+' · Intel I ×3', pass:'BuyImproveIntel' }, { id:'JudgeIntel2', label:'Judge Intel II', sub:fmt(700)+' · Improve', pass:'BuyJudgeIntel2' }, { id:'PermanentJudgeIntel', label:'Permanent Intel', sub:fmt(3000)+' · Intel II ×3', pass:'BuyPermanentJudgeIntel' }, ]; var judgeStats = [ { id:'UnlockStat', label:'Unlock Stat', sub:fmt(800)+' · day36', pass:'UnlockStatPickJudge' }, { id:'GuessStat', label:'Guess', sub:fmt(sv.archetype === 'gambler' ? 100 : 300)+' · 1/day', pass:'GuessStatPickJudge' }, ]; /* ── render node ── */ function renderNode(item, extraClass){ var s = status(item.id); var cls = 'sk-node'; var icon = ''; var buyBtn = ''; if(s.ok){ cls += ' sk-done'; icon = '✅'; } else if(s.lock){ cls += ' sk-lock'; icon = '🔒'; } else if(s.canBuy){ cls += ' sk-buy'; var passTarget = item.pass; var extra = ''; if(item.pidx !== undefined) extra = ' data-pidx="'+item.pidx+'"'; buyBtn = '<button class="sk-btn" data-pass="'+passTarget+'"'+extra+'>Buy</button>'; } else { cls += ' sk-no'; icon = '💸'; } if(extraClass) cls += ' ' + extraClass; var countBadge = (item.id === 'AD' && !s.ok) ? ' <small>('+sv.adItem.buyCount+'/3)</small>' : (item.id === 'JudgeIntel1' && !s.ok) ? ' <small>('+sv.judgeIntel1.buyCount+'/3)</small>' : (item.id === 'JudgeIntel2' && sv.judgeIntel2.buyCount > 0) ? ' <small>('+sv.judgeIntel2.buyCount+'×)</small>' : ''; var tip = ({ 'BJ':'Unlock BJ productions — free','Missionary':'Unlock Missionary productions', 'Doggy':'Unlock Doggy productions','Cowgirl':'Unlock Cowgirl productions', 'Reverse Cowgirl':'Unlock Reverse Cowgirl productions','DoubleFeature':'Two Shootings in a Day — film 2 stars at once', 'Spooning':'Unlock Spooning productions', 'Personal1':'Unlock Specialty 1 for every star — usable once she reaches 60 satisfaction', 'Personal2':'Unlock Specialty 2 for every star — usable once she reaches 70 satisfaction', 'Facial':'Unlock Facial productions — usable once she reaches 80 satisfaction', 'P1Intel':'Reveal Pool 1 star count & contract range', 'P2Intel':'Reveal Pool 2 star count & contract range', 'P3Intel':'Reveal Pool 3 star count & contract range', 'TargetedScout':'Target a star — she appears twice in draws (+20% chance)', 'EstDip':'15% chance to draw a Pool 2 star from Pool 1 scout', 'EstSurge':'Increase Est. Dip chance to 50%', 'EliteDip':'15% chance to draw a Pool 3 Elite star', 'EliteSurge':'Increase Elite Dip chance to 40%', 'DblScouting':'Draw 2 stars at once when scouting', 'TplScouting':'Draw 3 stars at once when scouting', 'QadScouting':'Draw 4 stars at once when scouting', 'AD':'Gain reputation instantly — up to ×3', 'MarketStudy':'Reveal a 2nd physical trend each day', 'Patience':'Stars tolerate 1 extra day without shooting before losing satisfaction', 'ThirdOption':'Contracts show 3 options instead of 2', 'HarderContract':'Unlock Harder Contracts — 2 stats to match, higher reward & penalty', 'JudgeIntel1':'Reveals the identity of one of the two upcoming Contest judges. Can be bought 3 times total.', 'ImproveIntel':'Unlocks Judge Intel II, once Judge Intel I has been bought 3 times', 'JudgeIntel2':'Reveals the identity of BOTH upcoming Contest judges. Can be bought 3 times total.', 'PermanentJudgeIntel':'Always know both upcoming Contest judges in advance, forever, once bought', 'UnlockStat':'Choose a judge and permanently reveal one of their hidden preferences, guaranteed', 'GuessStat':'Choose a judge, then guess one of their hidden preferences from 3 options — guess right to reveal it permanently', })[item.id] || ''; var tipHtml = tip ? '<div class="sk-tooltip">'+tip+'</div>' : ''; var hoverAttrs = tip ? ' onmouseenter="window.skTooltipShow(this)" onmouseleave="window.skTooltipHide(this)"' : ''; return '<div class="'+cls+'" data-id="'+item.id+'"'+hoverAttrs+'>'+tipHtml+ '<div class="sk-node-inner">'+ '<div class="sk-label">'+item.label+icon+countBadge+'</div>'+ '<div class="sk-sub">'+item.sub+'</div>'+ (s.reason && !s.ok && !s.canBuy ? '<div class="sk-reason">'+s.reason+'</div>' : '')+ buyBtn+ '</div>'+ '</div>'; } /* ── build HTML ── */ var html = '<style>'+ '#skill-tree-wrap{font-size:0.95em;}'+ '.sk-cols{display:flex;gap:18px;align-items:flex-start;}'+ '.sk-col{flex:1;min-width:0;}'+ '.sk-col.sk-col-scouting{flex:2.4;}'+ '.sk-col.sk-col-agence{flex:0.9;}'+ '.sk-col-head{text-align:center;font-weight:700;font-size:1.05em;padding:6px 0 8px;margin-bottom:10px;border-bottom:2px solid #333;background:linear-gradient(90deg,transparent,rgba(74,158,255,0.08),transparent);border-radius:6px 6px 0 0;}'+ '.sk-subcols{display:flex;gap:8px;}'+ '.sk-subcol{flex:1;min-width:0;}'+ '.sk-subcols > .sk-node{flex:1;min-width:0;}'+ '.sk-subcol-head{text-align:center;font-size:0.82em;font-weight:600;color:#999;padding:3px 0;border-bottom:1px solid #333;margin-bottom:6px;text-transform:uppercase;letter-spacing:0.5px;}'+ '.sk-node{border:1px solid #333;border-radius:10px;padding:8px 10px;margin-bottom:6px;background:linear-gradient(135deg,#1a1a2e,#16213e);box-shadow:0 3px 8px rgba(0,0,0,0.35);transition:transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;position:relative;}'+ '.sk-node:hover{z-index:100;}'+ '.sk-node .sk-tooltip{display:none;position:absolute;left:106%;top:0;z-index:99;background:#14141f;border:1px solid #4a4a6a;border-radius:8px;padding:8px 12px;font-size:0.85em;line-height:1.4;color:#eee;width:190px;white-space:normal;pointer-events:none;box-shadow:0 6px 16px rgba(0,0,0,0.6);}'+ '.sk-node:hover .sk-tooltip{display:block;}'+ '.sk-done{border-color:#2a7a3a;background:linear-gradient(135deg,#183a20,#0d2b1a);box-shadow:0 0 10px rgba(42,122,58,0.25), 0 3px 8px rgba(0,0,0,0.35);}'+ '.sk-lock .sk-node-inner{opacity:0.5;}'+ '.sk-lock:hover{transform:none;}'+ '.sk-buy{border-color:#4a9eff;cursor:pointer;box-shadow:0 0 12px rgba(74,158,255,0.25), 0 3px 8px rgba(0,0,0,0.35);}'+ '.sk-buy:hover{transform:translateY(-2px);border-color:#7ec4ff;box-shadow:0 0 18px rgba(74,158,255,0.4), 0 6px 14px rgba(0,0,0,0.4);}'+ '.sk-no{border-color:#9e6a00;opacity:0.75;}'+ '.sk-label{font-weight:700;margin-bottom:2px;font-size:1.02em;}'+ '.sk-sub{font-size:0.85em;color:#999;}'+ '.sk-reason{font-size:0.78em;color:#ff9e6a;margin-top:3px;}'+ '.sk-btn{margin-top:6px;padding:4px 14px;background:linear-gradient(180deg,#183462,#0d1f3a);border:1px solid #4a9eff;color:#8fb8ff;border-radius:6px;cursor:pointer;font-size:0.88em;font-weight:600;transition:all 0.15s ease;}'+ '.sk-btn:hover{background:linear-gradient(180deg,#2a4a9e,#183462);color:#fff;transform:translateY(-1px);}'+ '.sk-arrow{text-align:center;color:#4a4a6a;font-size:1em;margin:0;line-height:1;}'+ '</style>'; html += '<div class="sk-cols">'; /* ── GENRES col ── */ html += '<div class="sk-col"><div class="sk-col-head">🎬 Genres</div>'; genres.forEach(function(g, i){ html += renderNode(g); if(i < genres.length - 1) html += '<div class="sk-arrow">↓</div>'; }); html += '\x3c/div>'; /* ── SCOUTING col ── */ html += '<div class="sk-col sk-col-scouting"><div class="sk-col-head">🔍 Scouting</div><div class="sk-subcols">'; html += '<div class="sk-subcol"><div class="sk-subcol-head">Intel</div>'; intel.forEach(function(n){ html += renderNode(n); html += '<div class="sk-arrow">↓</div>'; }); html += '\x3c/div>'; html += '<div class="sk-subcol"><div class="sk-subcol-head">Chance</div>'; upgradesChance.forEach(function(n){ html += renderNode(n); html += '<div class="sk-arrow">↓</div>'; }); html += '\x3c/div>'; html += '<div class="sk-subcol"><div class="sk-subcol-head">Multi</div>'; upgradesMulti.forEach(function(n){ html += renderNode(n); html += '<div class="sk-arrow">↓</div>'; }); html += '\x3c/div>'; html += '\x3c/div>\x3c/div>'; /* ── AGENCE col ── */ html += '<div class="sk-col sk-col-agence"><div class="sk-col-head">📣 Agence</div>'; agence.forEach(function(n, i){ html += renderNode(n); if(i < agence.length - 1) html += '<div class="sk-arrow">↓</div>'; }); html += '\x3c/div>'; /* ── CONTRACT col ── */ html += '<div class="sk-col"><div class="sk-col-head">📋 Contracts</div>'; var contracts = [ { id:'ThirdOption', label:'3rd Option', sub:fmt(500)+' · after C1', pass:'Buy3rdOption' }, { id:'HarderContract', label:'Harder Contract', sub:fmt(1500)+' · 3rd Opt.', pass:'BuyHarderContract2' }, ]; contracts.forEach(function(n){ html += renderNode(n); html += '<div class="sk-arrow">↓</div>'; }); html += '\x3c/div>'; /* ── JUDGE INTEL col (fused: Judge Stats row + Contest chain) ── */ html += '<div class="sk-col"><div class="sk-col-head">🕵️ Judge Intel</div>'; html += '<div class="sk-subcols">'; judgeStats.forEach(function(n){ html += renderNode(n); }); html += '\x3c/div>'; html += '<div class="sk-arrow">↓</div>'; contest.forEach(function(n, i){ html += renderNode(n); if(i < contest.length - 1) html += '<div class="sk-arrow">↓</div>'; }); html += '\x3c/div>'; html += '\x3c/div>'; var wrap = document.getElementById('skill-tree-wrap'); if(wrap){ wrap.innerHTML = html; /* buy buttons */ wrap.querySelectorAll('.sk-btn').forEach(function(btn){ btn.addEventListener('click', function(){ var pass = this.getAttribute('data-pass'); var pidx = this.getAttribute('data-pidx'); if(pidx !== null){ SugarCube.State.variables.positionIndex = parseInt(pidx); } SugarCube.Engine.play(pass); }); }); } }); <</script>> /* ════════════════════════════════════════════ PASSAGE : ListShop ════════════════════════════════════════════ */
<<set _sm = $allPositions.slice().sort(function(a,b){ return a.price - b.price; })>> <<for _i = 0; _i < _sm.length; _i++>><<set _m = _sm[_i]>><<set _p = ($archetype is "skillful" && _m.price > 0) ? Math.ceil(_m.price * 0.9) : _m.price>> — <<if _m.price is 0>><b><<= _m.name>></b> ✅<<elseif _m.comingSoon>><b><<= _m.name>></b> — 🔜 <em>Coming in a future update</em><<else>><b><<= _m.name>></b> $<<= _p.toLocaleString()>> | Rep.<<= _m.repMin>> | Lvl<<= _m.level>> — <<if _m.unlocked>>✅<<elseif _m.repMin > $player.reputation>>🔒 <em>(rep <<= _m.repMin>>)</em><<elseif $player.money < _p>>@@color:red;No funds@@<<else>><<set _idx = $allPositions.indexOf(_m)>><<capture _idx>>[[🛒|BuyPosition][$positionIndex = _idx]]<</capture>><</if>><</if>> <</for>> — <b>AD Campaign</b> $<<= $adItem.price.toLocaleString()>> <em>(+<<= $adItem.repBonus>> rep)</em> — <<if $adItem.buyCount >= 3>>✅ ×3 (max)<br><<elseif $player.money < $adItem.price>>@@color:red;No funds@@<<else>>[[🛒 Buy|BuyAD]] <em>(<<= $adItem.buyCount>>/3)</em><</if>> — <b>Patience Training</b> $<<= $satisfactionDelayItem.price.toLocaleString()>> <em>(talents stay happy 4 days instead of 3)</em> — <<if $satisfactionDelayItem.bought>>✅<<elseif $roster.length < 5>>🔒 <em>(need 5 stars in roster — <<= $roster.length>>/5)</em><<elseif $adItem.buyCount < 2>>🔒 <em>(need 2 AD Campaigns — <<= $adItem.buyCount>>/2)</em><<elseif $player.reputation < $satisfactionDelayItem.repMin>>🔒 <em>(rep <<= $satisfactionDelayItem.repMin>>)</em><<elseif $player.money < $satisfactionDelayItem.price>>@@color:red;No funds@@<<else>>[[🛒 Buy|BuySatisfactionDelay]]<</if>> — <b>Established Dip</b> $<<= $pool1UpgradeItem.price.toLocaleString()>> <em>(20% chance to draw from Pool 2)</em> — <<if $pool1UpgradeItem.bought>>✅<<elseif $player.day < 30>>🔒 <em>(available from day 30)</em><<elseif $player.money < $pool1UpgradeItem.price>>@@color:red;No funds@@<<else>>[[🛒 Buy|BuyPool1Upgrade]]<</if>> — <b>Established Surge</b> $<<= $pool1Upgrade2A.price.toLocaleString()>> <em>(50% chance to draw from Pool 2)</em> — <<if !$pool1UpgradeItem.bought>>🔒 <em>(requires Established Dip)</em><<elseif $pool1Upgrade2A.bought>>✅<<elseif $roster.filter(function(w){ return $poolConfirmed.indexOf(w.name) >= 0; }).length is 0>>🔒 <em>(need 1 Established star in roster)</em><<elseif $player.money < $pool1Upgrade2A.price>>@@color:red;No funds@@<<else>>[[🛒 Buy|BuyPool1Upgrade2A]]<</if>> — <b>Double Scouting</b> $<<= $pool1Upgrade2B.price.toLocaleString()>> <em>(draw 2 talents at once)</em> — <<if !$pool1UpgradeItem.bought>>🔒 <em>(requires Established Dip)</em><<elseif $pool1Upgrade2B.bought>>✅<<elseif $player.reputation < $pool1Upgrade2B.repMin>>🔒 <em>(rep <<= $pool1Upgrade2B.repMin>>)</em><<elseif $player.money < $pool1Upgrade2B.price>>@@color:red;No funds@@<<else>>[[🛒 Buy|BuyPool1Upgrade2B]]<</if>> — <b>Double Feature</b> $<<= $doublePositionItem.price.toLocaleString()>> <em>(2 positions | rep<<= $doublePositionItem.repMin>>)</em> — <<if $doublePositionItem.bought>>✅<<elseif $player.reputation < $doublePositionItem.repMin>>🔒 <em>(rep <<= $doublePositionItem.repMin>>)</em><<elseif $player.money < $doublePositionItem.price>>@@color:red;No funds@@<<else>>[[🛒 Buy|BuyDoubleFeature]]<</if>> — <b>Pool 1 Intel</b> $<<= $pool1IntelItem.price.toLocaleString()>> <em>(view Pool 1 content)</em> — <<if $pool1IntelItem.bought>>✅<<elseif $player.money < $pool1IntelItem.price>>@@color:red;No funds@@<<else>>[[🛒 Buy|BuyPool1Intel]]<</if>> — <b>Pool 2 Intel</b> $<<= $pool2IntelItem.price.toLocaleString()>> <em>(view Pool 2 content)</em> — <<if !$pool1IntelItem.bought>>🔒 <em>(requires Pool 1 Intel)</em><<elseif $pool2IntelItem.bought>>✅<<elseif $player.money < $pool2IntelItem.price>>@@color:red;No funds@@<<else>>[[🛒 Buy|BuyPool2Intel]]<</if>> — <b>Pool 3 Intel</b> $<<= $pool3IntelItem.price.toLocaleString()>> <em>(view Pool 3 content)</em> — <<if !$pool2IntelItem.bought>>🔒 <em>(requires Pool 2 Intel)</em><<elseif $pool3IntelItem.bought>>✅<<elseif $player.money < $pool3IntelItem.price>>@@color:red;No funds@@<<else>>[[🛒 Buy|BuyPool3Intel]]<</if>> — <b>Elite Dip</b> $<<= $pool2UpgradeItem.price.toLocaleString()>> <em>(15% chance Elite | rep<<= $pool2UpgradeItem.repMin>>)</em> — <<if $pool2UpgradeItem.bought>>✅<<elseif $player.reputation < $pool2UpgradeItem.repMin>>🔒 <em>(rep <<= $pool2UpgradeItem.repMin>>)</em><<elseif $player.money < $pool2UpgradeItem.price>>@@color:red;No funds@@<<else>>[[🛒 Buy|BuyPool2Upgrade]]<</if>> — <b>Elite Surge</b> $<<= $pool2Upgrade2.price.toLocaleString()>> <em>(40% chance Elite | rep<<= $pool2Upgrade2.repMin>>)</em> — <<if !$pool2UpgradeItem.bought>>🔒 <em>(requires Elite Dip)</em><<elseif $pool2Upgrade2.bought>>✅<<elseif $player.reputation < $pool2Upgrade2.repMin>>🔒 <em>(rep <<= $pool2Upgrade2.repMin>>)</em><<elseif $player.money < $pool2Upgrade2.price>>@@color:red;No funds@@<<else>>[[🛒 Buy|BuyPool2Upgrade2]]<</if>> — <b>Market Study</b> $<<= $marketStudyItem.price.toLocaleString()>> <em>(2nd daily trend | rep<<= $marketStudyItem.repMin>>)</em> — <<if $marketStudyItem.bought>>✅<<elseif $player.reputation < $marketStudyItem.repMin>>🔒 <em>(rep <<= $marketStudyItem.repMin>>)</em><<elseif $player.money < $marketStudyItem.price>>@@color:red;No funds@@<<else>>[[🛒 Buy|BuyMarketStudy]]<</if>>
<<if $player.money < $doublePositionItem.price>>@@color:red;Not enough funds ($<<= $doublePositionItem.price>> required).@@ [[⬅️ Shop|Shop]]<<else>> <<set $player.money -= $doublePositionItem.price>> <<set $doublePositionItem.bought = true>> ✅ <b>Double Feature</b> purchased! You can now use 2 positions per production. [[🛒 Keep shopping|Shop]] | [[📊 Dashboard|Dashboard]]<</if>>
<<if $player.money < $satisfactionDelayItem.price>>@@color:red;Not enough funds ($<<= $satisfactionDelayItem.price>> required).@@ [[⬅️ Shop|Shop]]<<else>> <<set $player.money -= $satisfactionDelayItem.price>> <<set $satisfactionDelayItem.bought = true>> ✅ <b>Patience Training</b> purchased! Your talents now stay satisfied for <b>4 days</b> instead of 3 before satisfaction starts decaying. [[🛒 Keep shopping|Shop]] | [[📊 Dashboard|Dashboard]]<</if>>
<<if $player.money < $pool1UpgradeItem.price>>@@color:red;Not enough funds ($<<= $pool1UpgradeItem.price>> required).@@ [[⬅️ Shop|Shop]]<<else>> <<set $player.money -= $pool1UpgradeItem.price>> <<set $pool1UpgradeItem.bought = true>> ✅ <b>Established Dip</b> purchased! Drawing from Pool 1 now has a <b>20% chance</b> to give you a Pool 2 talent instead. [[🛒 Keep shopping|Shop]] | [[📊 Dashboard|Dashboard]]<</if>>
<<if $player.money < $pool1Upgrade2A.price>>@@color:red;Not enough funds ($<<= $pool1Upgrade2A.price>> required).@@ [[⬅️ Shop|Shop]]<<else>> <<set $player.money -= $pool1Upgrade2A.price>> <<set $pool1Upgrade2A.bought = true>> ✅ <b>Established Surge</b> purchased! Drawing from Pool 1 now has a <b>50% chance</b> to give you a Pool 2 talent. [[🛒 Keep shopping|Shop]] | [[📊 Dashboard|Dashboard]]<</if>>
<<if $player.money < $pool1Upgrade2B.price>>@@color:red;Not enough funds ($<<= $pool1Upgrade2B.price>> required).@@ [[⬅️ Shop|Shop]]<<else>> <<set $player.money -= $pool1Upgrade2B.price>> <<set $pool1Upgrade2B.bought = true>> ✅ <b>Double Scouting</b> purchased! You can now draw 2 talents at once from Pool 1. [[🛒 Keep shopping|Shop]] | [[📊 Dashboard|Dashboard]]<</if>>
<<if $player.money < $pool1IntelItem.price>>@@color:red;Not enough funds ($<<= $pool1IntelItem.price>> required).@@ [[⬅️ Shop|Shop]]<<else>> <<set $player.money -= $pool1IntelItem.price>> <<set $pool1IntelItem.bought = true>> ✅ <b>Pool 1 Intel</b> purchased! You can now view Pool 1 content in recruitment. [[🛒 Keep shopping|Shop]] | [[📊 Dashboard|Dashboard]]<</if>>
<<if $player.money < $pool2IntelItem.price>>@@color:red;Not enough funds ($<<= $pool2IntelItem.price>> required).@@ [[⬅️ Shop|Shop]]<<else>> <<set $player.money -= $pool2IntelItem.price>> <<set $pool2IntelItem.bought = true>> ✅ <b>Pool 2 Intel</b> purchased! You can now view Pool 2 content in recruitment. [[🛒 Keep shopping|Shop]] | [[📊 Dashboard|Dashboard]]<</if>>
<<if $player.money < $pool3IntelItem.price>>@@color:red;Not enough funds ($<<= $pool3IntelItem.price>> required).@@ [[⬅️ Shop|Shop]]<<else>> <<set $player.money -= $pool3IntelItem.price>> <<set $pool3IntelItem.bought = true>> ✅ <b>Pool 3 Intel</b> purchased! You can now view Pool 3 content in recruitment. [[🛒 Keep shopping|Shop]] | [[📊 Dashboard|Dashboard]]<</if>>
<<if !$targetedScoutItem.bought>> @@color:red;Not available in this version.@@ [[⬅️ Shop|Shop]] <<elseif $targetedScoutItem.bought>> Already purchased. [[⬅️ Shop|Shop]] <<elseif !$pool3IntelItem.bought>> @@color:red;Pool 3 Intel required.@@ [[⬅️ Shop|Shop]] <<elseif $player.money < $targetedScoutItem.price>> @@color:red;Not enough funds ($<<= $targetedScoutItem.price>> required).@@ [[⬅️ Shop|Shop]] <<else>> <<set $player.money -= $targetedScoutItem.price>> <<set $targetedScoutItem.bought = true>> ✅ <b>Targeted Scout</b> purchased! You can now target a specific star to increase their draw chance. [[🎯 Set Target|TargetedScoutMenu]] | [[🛒 Shop|Shop]] <</if>>
<<if $pool1Upgrade2C.bought>>Already purchased. [[⬅️ Shop|Shop]] <<elseif !$pool1Upgrade2B.bought>>@@color:red;Double Scouting required.@@ [[⬅️ Shop|Shop]] <<elseif $player.money < $pool1Upgrade2C.price>>@@color:red;Not enough funds.@@ [[⬅️ Shop|Shop]] <<else>> <<set $player.money -= $pool1Upgrade2C.price>> <<set $pool1Upgrade2C.bought = true>> ✅ <b>Triple Scouting</b> purchased! You can now draw 3 stars at once. [[🛒 Shop|Shop]] | [[📊 Dashboard|Dashboard]] <</if>>
<<if $pool1Upgrade2D.bought>>Already purchased. [[⬅️ Shop|Shop]] <<elseif !$pool1Upgrade2C.bought>>@@color:red;Triple Scouting required.@@ [[⬅️ Shop|Shop]] <<elseif $player.money < $pool1Upgrade2D.price>>@@color:red;Not enough funds.@@ [[⬅️ Shop|Shop]] <<else>> <<set $player.money -= $pool1Upgrade2D.price>> <<set $pool1Upgrade2D.bought = true>> ✅ <b>Quadruple Scouting</b> purchased! You can now draw 4 stars at once. [[🛒 Shop|Shop]] | [[📊 Dashboard|Dashboard]] <</if>>
<h1 style="margin:0 0 0.4em 0;">🎯 Targeted Scout</h1> <<if !$targetedScoutItem || !$targetedScoutItem.bought>> @@color:red;Targeted Scout not purchased yet.@@ [[⬅️ Shop|Shop]] <<else>> <<if $targetedScoutStar>> Currently targeting: <b><<= $targetedScoutStar>></b> <em style="color:#888;">(+20% draw chance)</em><br> [[❌ Clear target|TargetedScoutClear]] <<else>> <em style="color:#888;">Select a star to target — she will appear twice in your draws.</em> <</if>> <b>Available stars:</b> <<set _tsPool = $recruitPool.filter(function(w){ return w.available && !$roster.find(function(r){ return r.name is w.name; }); })>> <div id="ts-star-list"></div> <<script>> jQuery(document).one(':passageend', function(){ var sv = SugarCube.State.variables; var allPools = (sv.poolBeginner || []).concat(sv.poolConfirmed || []).concat(sv.poolElite || []); var pool = sv.recruitPool.filter(function(w){ return allPools.indexOf(w.name) >= 0 && w.available && !sv.roster.find(function(r){ return r.name === w.name; }) && !(sv.rival && sv.rival.roster && sv.rival.roster.find(function(r){ return r.name === w.name; })); }); var html = ''; pool.forEach(function(w){ html += '<div style="margin:4px 0;padding:5px 8px;background:#111;border-radius:5px;display:flex;align-items:center;gap:8px;">'; html += '<button class="ts-pick-btn" data-name="'+w.name+'" style="padding:3px 10px;background:#1a1a2e;border:1px solid #4a9eff;color:#4a9eff;border-radius:4px;cursor:pointer;font-size:0.85em;">🎯 '+w.name+'</button>'; html += '<em style="font-size:0.82em;color:#666;">'+w.hair+' | '+w.height+' | '+w.breast+'</em>'; html += '</div>'; }); var wrap = document.getElementById('ts-star-list'); if(wrap){ wrap.innerHTML = html; wrap.querySelectorAll('.ts-pick-btn').forEach(function(btn){ btn.addEventListener('click', function(){ sv.targetedScoutStar = this.getAttribute('data-name'); SugarCube.Engine.play('TargetedScoutMenu'); }); }); } }); <</script>> [[⬅️ Dashboard|Dashboard]] <</if>>
[[⬅️ Back|TargetedScoutMenu]]
<<set $targetedScoutStar = "">> [[⬅️ Back|TargetedScoutMenu]]
<<if $player.money < $pool2UpgradeItem.price>>@@color:red;Not enough funds ($<<= $pool2UpgradeItem.price>> required).@@ [[⬅️ Shop|Shop]]<<else>> <<set $player.money -= $pool2UpgradeItem.price>> <<set $pool2UpgradeItem.bought = true>> ✅ <b>Elite Dip</b> purchased! 15% chance to draw an Elite star. [[🛒 Keep shopping|Shop]] | [[📊 Dashboard|Dashboard]]<</if>>
<<if $player.money < $pool2Upgrade2.price>>@@color:red;Not enough funds ($<<= $pool2Upgrade2.price>> required).@@ [[⬅️ Shop|Shop]]<<else>> <<set $player.money -= $pool2Upgrade2.price>> <<set $pool2Upgrade2.bought = true>> ✅ <b>Elite Surge</b> purchased! 40% chance to draw an Elite star. [[🛒 Keep shopping|Shop]] | [[📊 Dashboard|Dashboard]]<</if>>
<<if $player.money < $marketStudyItem.price>>@@color:red;Not enough funds ($<<= $marketStudyItem.price>> required).@@ [[⬅️ Shop|Shop]]<<else>> <<set $player.money -= $marketStudyItem.price>> <<set $marketStudyItem.bought = true>> ✅ <b>Market Study</b> purchased! You now get <b>2 daily trends</b>. [[🛒 Keep shopping|Shop]] | [[📊 Dashboard|Dashboard]]<</if>> /* ════════════════════════════════════════════ PASSAGE : BuyAD ════════════════════════════════════════════ */
<<if $player.money < $adItem.price>>@@color:red;Not enough funds ($<<= $adItem.price>> required).@@ [[⬅️ Shop|Shop]]<<else>> <<set $player.money -= $adItem.price>> <<set $player.reputation += $adItem.repBonus>> <<set $adItem.buyCount += 1>> <<set $adItem.bought = true>> ✅ <b>AD Campaign</b> purchased! You gained <b>+<<= $adItem.repBonus>> reputation</b>. Your reputation is now <<= $player.reputation>>. [[🛒 Keep shopping|Shop]] | [[📊 Dashboard|Dashboard]]<</if>> /* ════════════════════════════════════════════ PASSAGE : BuyPosition ════════════════════════════════════════════ */
<<set _m = $allPositions[$positionIndex]>> <<set _price = _m.price>> <<if $archetype is "skillful">><<set _price = Math.ceil(_price * 0.9)>><</if>> <<if $player.money < _price>>@@color:red;Not enough funds ($<<= _price>> required).@@ [[⬅️ Shop|Shop]]<<else>> <<set _m.unlocked = true>> <<set $player.money -= _price>> <<set $playerPositions.push(_m.name)>> <<if !$easyMode && !$trophies.totalPackage && $allPositions.every(function(p){ return $playerPositions.includes(p.name); })>><<set $trophies.totalPackage = true>><<set $newTrophy = "🏆 Total Package — unlocked every position!">><<run window.checkAllTrophies()>><</if>> ✅ You've unlocked <b><<= _m.name>></b> style!<<if $archetype is "skillful">> <em>(−10% Skillful discount applied)</em><</if>> [[🛒 Keep shopping|Shop]] | [[📊 Dashboard|Dashboard]]<</if>> /* ════════════════════════════════════════════ PASSAGE : RECRUITMENT ════════════════════════════════════════════ */
<h1 style="margin:0 0 0.4em 0;">👤 Talent Scouting</h1> <<if $drawResult.length > 0>> <div style="padding:4px 0;margin-bottom:4px;"> <b>🎲 Scout result:</b><br> <div id="draw-cards-container"></div> <<script>> jQuery(document).one(':passageend', function(){ var btn = document.getElementById('new-scout-btn'); if(!btn) return; btn.addEventListener('click', function(){ var sv = SugarCube.State.variables; var cost = sv.bDrawCost || (sv.archetype === 'gambler' ? 100 : 200); if(sv.player.money < cost){ alert('Not enough funds to scout.'); return; } sv.player.money -= cost; sv.drawPool = 'beginner'; sv.drawLuckyNames = []; sv.drawEliteNames = []; var chance = 0; if(sv.pool1Upgrade2A && sv.pool1Upgrade2A.bought) chance = 50; else if(sv.pool1UpgradeItem && sv.pool1UpgradeItem.bought) chance = 20; var eliteChance = 0; if(sv.pool2Upgrade2 && sv.pool2Upgrade2.bought) eliteChance = 40; else if(sv.pool2UpgradeItem && sv.pool2UpgradeItem.bought) eliteChance = 15; var recruitPool = sv.recruitPool; var cAvail = sv.poolConfirmed.filter(function(n){ var w = recruitPool.find(function(r){ return r.name===n; }); return w && w.available; }); var eAvail = sv.poolElite.filter(function(n){ var w = recruitPool.find(function(r){ return r.name===n; }); return w && w.available; }); var bAvail = sv.poolBeginner.filter(function(n){ var w = recruitPool.find(function(r){ return r.name===n; }); return w && w.available; }); if(sv.targetedScoutItem && sv.targetedScoutItem.bought && sv.targetedScoutStar){ var ts = sv.targetedScoutStar; if(bAvail.indexOf(ts)>=0) bAvail = bAvail.concat([ts]); else if(cAvail.indexOf(ts)>=0) cAvail = cAvail.concat([ts]); else if(eAvail.indexOf(ts)>=0) eAvail = eAvail.concat([ts]); } var multiDraw = 1; if(sv.pool1Upgrade2D && sv.pool1Upgrade2D.bought) multiDraw = 4; else if(sv.pool1Upgrade2C && sv.pool1Upgrade2C.bought) multiDraw = 3; else if(sv.pool1Upgrade2B && sv.pool1Upgrade2B.bought) multiDraw = 2; if(multiDraw >= 2 && (bAvail.length + cAvail.length + eAvail.length) >= 2){ sv.drawResult = []; for(var di=0; di<multiDraw; di++){ var useUpgrade2 = chance > 0 && Math.random()*100 < chance && cAvail.length > 0; var isEstablishedDraw2 = useUpgrade2 && cAvail.length > 0; var useElite2 = isEstablishedDraw2 && eliteChance>0 && Math.random()*100<eliteChance && eAvail.length>0; if(useElite2){ var ri=Math.floor(Math.random()*eAvail.length); sv.drawPool='elite'; sv.drawResult.push(eAvail[ri]); sv.drawEliteNames.push(eAvail[ri]); eAvail.splice(ri,1); } else if(isEstablishedDraw2){ var ri=Math.floor(Math.random()*cAvail.length); sv.drawPool='confirmed'; sv.drawResult.push(cAvail[ri]); if(useUpgrade2) sv.drawLuckyNames.push(cAvail[ri]); cAvail.splice(ri,1); } else if(bAvail.length>0){ var ri=Math.floor(Math.random()*bAvail.length); sv.drawResult.push(bAvail[ri]); bAvail.splice(ri,1); } else if(cAvail.length>0 && Math.random()*100<(chance+10)){ var ri=Math.floor(Math.random()*cAvail.length); sv.drawPool='confirmed'; sv.drawResult.push(cAvail[ri]); cAvail.splice(ri,1); } else if(eAvail.length>0 && Math.random()*100<(eliteChance+10)){ var ri=Math.floor(Math.random()*eAvail.length); sv.drawPool='elite'; sv.drawResult.push(eAvail[ri]); sv.drawEliteNames.push(eAvail[ri]); eAvail.splice(ri,1); } } if(sv.drawResult.length===0){ alert('No talents available to scout.'); return; } } else { var useUpgrade = chance > 0 && Math.random()*100 < chance; var isEstablishedDraw = useUpgrade && cAvail.length>0; var useElite = isEstablishedDraw && eliteChance>0 && Math.random()*100<eliteChance && eAvail.length>0; if(useElite){ sv.drawPool='elite'; var ri=Math.floor(Math.random()*eAvail.length); sv.drawResult=[eAvail[ri]]; sv.drawEliteNames.push(eAvail[ri]); } else if(isEstablishedDraw){ sv.drawPool='confirmed'; var ri=Math.floor(Math.random()*cAvail.length); sv.drawResult=[cAvail[ri]]; if(useUpgrade) sv.drawLuckyNames.push(cAvail[ri]); } else if(bAvail.length>0){ var ri=Math.floor(Math.random()*bAvail.length); sv.drawResult=[bAvail[ri]]; } else if(cAvail.length>0 && Math.random()*100<(chance+10)){ sv.drawPool='confirmed'; var ri=Math.floor(Math.random()*cAvail.length); sv.drawResult=[cAvail[ri]]; } else if(eAvail.length>0 && Math.random()*100<(eliteChance+10)){ sv.drawPool='elite'; var ri=Math.floor(Math.random()*eAvail.length); sv.drawResult=[eAvail[ri]]; sv.drawEliteNames.push(eAvail[ri]); } else { alert('No talents available to scout.'); return; } } SugarCube.Engine.play('Recruitment'); }); }); <</script>> <button id="new-scout-btn" style="padding:6px 16px;background:#1a1a2e;border:1px solid #4a9eff;color:#4a9eff;border-radius:6px;cursor:pointer;font-size:0.9em;margin:4px 0;">🎲 Scout again ($<<= $bDrawCost>>)</button> </div> <<script>> jQuery(document).one(':passageend', function(){ var drawResult = SugarCube.State.variables.drawResult; var recruitPool = SugarCube.State.variables.recruitPool; var trends = SugarCube.State.variables.trends; var luckyNames = SugarCube.State.variables.drawLuckyNames || []; var eliteNames = SugarCube.State.variables.drawEliteNames || []; var playerMoney = SugarCube.State.variables.player.money; var stars = drawResult.map(function(name){ return recruitPool.find(function(r){ return r.name === name; }); }).filter(function(w){ return !!w; }); /* Build cards with sign buttons underneath each card */ if(!stars || stars.length === 0){ var el = document.getElementById('draw-cards-container'); if(el) el.innerHTML = '<em>No talents to display.</em>'; return; } var trendType = trends ? trends.carType : ''; var trendVal = trends ? trends.carValue : ''; var trendType2 = trends ? trends.carType2 : ''; var trendVal2 = trends ? trends.carValue2 : ''; var svC = SugarCube.State.variables; var c1 = svC.contract1; var c1Active = !!(c1 && c1.accepted && !c1.failed); var c1Type = c1Active ? c1.criteriaType : null; var c1Val = c1Active ? c1.criteria : null; var c1Type2 = (c1Active && svC.contractIsHarder) ? c1.criteriaType2 : null; var c1Val2 = (c1Active && svC.contractIsHarder) ? c1.criteria2 : null; function statSpan(type, value){ var isContract = (c1Type === type && c1Val === value) || (c1Type2 === type && c1Val2 === value); var isTrend = (trendType === type && trendVal === value) || (trendType2 === type && trendVal2 === value); if(isContract) return '<b style="color:#4a9eff;">'+value+'</b>'; if(isTrend) return '<b>'+value+'</b>'; return value; } var html = '\x3cdiv style="display:flex;flex-wrap:wrap;justify-content:center;max-width:100%;box-sizing:border-box;">'; stars.forEach(function(w){ var file = w.name.toLowerCase().replace(/ /g,'_'); var isElite = eliteNames.indexOf(w.name) >= 0; var isLucky = luckyNames.indexOf(w.name) >= 0; var sat = w.satisfaction; var satColor = sat>=65?'#4caf50':sat>=40?'#e53935':sat>=12?'#ff9800':'#c62828'; var satIcon = sat>=65?'💗':sat>=40?'❤️':sat>=12?'🧡':'⚠️'; var satPct = Math.min(100,sat)+'%'; var canAfford = playerMoney >= ((SugarCube.State.variables.archetype === 'charismatic') ? Math.ceil(w.contractCost * 0.9) : w.contractCost); var classes = 'star-card' + (isElite ? ' lucky-gold' : isLucky ? ' lucky-silver' : ''); html += '\x3cdiv style="display:inline-block;vertical-align:top;margin:8px;">'; html += '\x3cdiv class="'+classes+'">'; if(isLucky) html += ''; html += '<img src="img/portraits/'+file+'.jpg" alt="'+w.name+'" style="cursor:zoom-in;" onclick="zoomPortrait(this.src)">'; html += '<div class="star-name">'+w.name+'</div>'; /* Check contract4 investor pick */ var sv5 = SugarCube.State.variables; var c4 = sv5.contract4; var isC4Star = c4 && c4.accepted && !c4.failed && (w.name === c4.star1 || w.name === c4.star2); html += '\x3cdiv class="star-stats">'; html += w.ageNum+' y.o. | '+statSpan('hair', w.hair)+' | '+statSpan('height', w.height)+'<br>'; html += statSpan('breast', w.breast)+' ('+statSpan('breastType', w.breastType)+') | '+statSpan('ethnicity', w.ethnicity||'—')+'<br>'; html += '🌟 Pop: <b>'+w.popularity+'</b>'; if(w.favPosition) html += '<br>💖 Pos: '+w.favPosition+(w.favPosition2?' & '+w.favPosition2:''); html += '<br>💳 $'+w.contractCost.toLocaleString(); html += '\x3c/div>'; html += '<div style="margin-top:8px;color:'+satColor+';font-weight:bold;">'+satIcon+' '+sat+'</div>'; html += '<div class="sat-bar"><div class="sat-bar-fill" style="width:'+satPct+';background:'+satColor+';"></div></div>'; if(isC4Star) html += '<div style="margin-top:6px;padding:3px 8px;background:#1a1000;border:1px solid #9e6a00;border-radius:5px;font-size:0.78em;color:#ffcc44;text-align:center;">📋 💼 Investor pick</div>'; html += '\x3c/div>'; /* Sign button directly under the card */ if(canAfford){ html += '\x3cdiv style="margin-top:6px;text-align:center;">'; html += '<button class="sign-btn link-internal" data-name="'+w.name+'" style="border-color:#4a9eff;color:#4a9eff;padding:5px 14px;border-radius:6px;background:#1a1a2e;border:1px solid #4a9eff;cursor:pointer;font-size:0.85em;transition:all 0.2s;">✅ Sign ($'+((SugarCube.State.variables.archetype==='charismatic')?Math.ceil(w.contractCost*0.9):w.contractCost).toLocaleString()+')</button>'; html += '\x3c/div>'; } else { html += '<div style="margin-top:6px;text-align:center;color:#cc4444;font-size:0.8em;">❌ Not enough funds</div>'; } html += '\x3c/div>'; }); html += '\x3c/div>'; var wrap = document.getElementById('draw-cards-container'); if(wrap){ wrap.innerHTML = html; wrap.querySelectorAll('.sign-btn').forEach(function(btn){ btn.addEventListener('mouseenter', function(){ this.style.background='#4a9eff'; this.style.color='#000'; }); btn.addEventListener('mouseleave', function(){ this.style.background='#1a1a2e'; this.style.color='#4a9eff'; }); btn.addEventListener('click', function(){ var name = this.getAttribute('data-name'); SugarCube.State.variables.drawSignName = name; SugarCube.State.variables.drawPool = SugarCube.State.variables.drawPool || 'beginner'; SugarCube.Engine.play('SignDrawStar'); }); }); } }); <</script>> <</if>> <<set $bDrawCost = $archetype is "gambler" ? 100 : 200>> <<set $cDrawCost = $archetype is "gambler" ? 250 : 500>> <<if $drawResult.length is 0>> <<set _dChance = 0>><<if $pool1Upgrade2A.bought>><<set _dChance = 50>><<elseif $pool1UpgradeItem.bought>><<set _dChance = 20>><</if>> <<set _dEliteChance = 0>><<if $pool2Upgrade2.bought>><<set _dEliteChance = 40>><<elseif $pool2UpgradeItem.bought>><<set _dEliteChance = 15>><</if>> <<set _dBaseChance = Math.max(0, 100 - _dChance - _dEliteChance)>> <table style="width:100%;border-collapse:separate;border-spacing:6px;margin-bottom:8px;"> <tr> <td style="vertical-align:top;background:linear-gradient(135deg,#1a1a2e,#16213e);border:1px solid #333;border-radius:8px;padding:8px;width:33%;"> <b>🌟 Emerging Pool</b><br> <<set _bAvail = $poolBeginner.filter(function(n){ var w = $recruitPool.find(function(r){ return r.name is n; }); return w && w.available; })>> <<set _bMinCost = 9999>><<set _bMaxCost = 0>><<for _bi = 0; _bi < $poolBeginner.length; _bi++>><<set _bw = $recruitPool.find(function(w){ return w.name is $poolBeginner[_bi]; })>><<if _bw>><<if _bw.contractCost < _bMinCost>><<set _bMinCost = _bw.contractCost>><</if>><<if _bw.contractCost > _bMaxCost>><<set _bMaxCost = _bw.contractCost>><</if>><</if>><</for>> <em style="font-size:0.78em;color:#555;">💳 $<<= _bMinCost.toLocaleString()>>–$<<= _bMaxCost.toLocaleString()>></em><br> <em style="font-size:0.8em;color:#666;"><<= _bAvail.length>> available</em><br><<if !$pool1IntelItem.bought>><em style="font-size:0.78em;color:#555;">🔒 Pool 1 Intel for details</em><br><</if>> <em style="font-size:0.78em;color:gold;">🎲 <<= _dBaseChance>>% chance</em> <<set _cAvailForFallback = $poolConfirmed.filter(function(n){ var w = $recruitPool.find(function(r){ return r.name is n; }); return w && w.available; }).length>> <<set _zElitePoolCount = $poolElite.filter(function(n){ var w = $recruitPool.find(function(r){ return r.name is n; }); return w && w.available; }).length>> <<set _canDraw = (_bAvail.length > 0 || _cAvailForFallback > 0 || _zElitePoolCount > 0) && $player.money >= $bDrawCost>> </td> <td style="vertical-align:top;background:linear-gradient(135deg,#1a1a2e,#16213e);border:1px solid #333;border-radius:8px;padding:8px;width:33%;"> <b>🌟🌟 Established</b><br> <<set _cAvail = $poolConfirmed.filter(function(n){ var w = $recruitPool.find(function(r){ return r.name is n; }); return w && w.available; })>> <<set _cMinCost = 9999>><<set _cMaxCost = 0>><<for _ci = 0; _ci < $poolConfirmed.length; _ci++>><<set _cw = $recruitPool.find(function(w){ return w.name is $poolConfirmed[_ci]; })>><<if _cw>><<if _cw.contractCost < _cMinCost>><<set _cMinCost = _cw.contractCost>><</if>><<if _cw.contractCost > _cMaxCost>><<set _cMaxCost = _cw.contractCost>><</if>><</if>><</for>> <em style="font-size:0.78em;color:#555;">💳 $<<= _cMinCost.toLocaleString()>>–$<<= _cMaxCost.toLocaleString()>></em><br> <em style="font-size:0.8em;color:#666;"><<= _cAvail.length>> available</em><br><<if !$pool2IntelItem.bought>><em style="font-size:0.78em;color:#555;">🔒 Pool 2 Intel for details</em><br><</if>> <em style="font-size:0.78em;color:gold;">🎲 <<= _dChance>>% chance</em><br> <em style="font-size:0.8em;color:#666;">Via Est. Dip upgrade</em> </td> <td style="vertical-align:top;background:linear-gradient(135deg,#1a1a2e,#16213e);border:1px solid #333;border-radius:8px;padding:8px;width:33%;"> <b>🌟🌟🌟 Elite</b><br> <<set _eAvail = $poolElite.filter(function(n){ var w = $recruitPool.find(function(r){ return r.name is n; }); return w && w.available; })>> <<set _eMinCost = 9999>><<set _eMaxCost = 0>><<for _ei = 0; _ei < $poolElite.length; _ei++>><<set _ew = $recruitPool.find(function(w){ return w.name is $poolElite[_ei]; })>><<if _ew>><<if _ew.contractCost < _eMinCost>><<set _eMinCost = _ew.contractCost>><</if>><<if _ew.contractCost > _eMaxCost>><<set _eMaxCost = _ew.contractCost>><</if>><</if>><</for>> <em style="font-size:0.78em;color:#555;">💳 $<<= _eMinCost.toLocaleString()>>–$<<= _eMaxCost.toLocaleString()>></em><br> <em style="font-size:0.8em;color:#666;"><<= _eAvail.length>> available</em><br><<if !$pool3IntelItem.bought>><em style="font-size:0.78em;color:#555;">🔒 Pool 3 Intel for details</em><br><</if>> <em style="font-size:0.78em;color:gold;">🎲 <<= _dEliteChance>>% chance to upgrade an Established draw</em><br> <<if $pool2UpgradeItem.bought>> <em style="font-size:0.8em;color:#666;">Via Elite Dip upgrade</em> <<else>> <em style="font-size:0.8em;color:#555;">Unlock via Elite Dip</em> <</if>> </td> </tr> </table> <div style="text-align:center;margin-top:6px;"> <<if _canDraw>> <<set _multiDraw = ($pool1Upgrade2D && $pool1Upgrade2D.bought) ? 4 : (($pool1Upgrade2C && $pool1Upgrade2C.bought) ? 3 : ($pool1Upgrade2B.bought ? 2 : 1))>> <<if _multiDraw >= 2 && (_bAvail.length + _cAvailForFallback + _zElitePoolCount >= 2)>> <<link `"🎲×" + _multiDraw + " Scout ($" + $bDrawCost + ")"`>> <<set $player.money -= $bDrawCost>><<set $drawPool = "beginner">><<set $drawResult = []>><<set $drawLuckyNames = []>><<set $drawEliteNames = []>> <<set _chance = 0>><<if $pool1Upgrade2A.bought>><<set _chance = 50>><<elseif $pool1UpgradeItem.bought>><<set _chance = 20>><</if>> <<set _eliteChance = 0>><<if $pool2Upgrade2.bought>><<set _eliteChance = 40>><<elseif $pool2UpgradeItem.bought>><<set _eliteChance = 15>><</if>> <<set _cAvail2 = $poolConfirmed.filter(function(n){ var w = $recruitPool.find(function(r){ return r.name is n; }); return w && w.available; })>> <<set _eAvail2 = $poolElite.filter(function(n){ var w = $recruitPool.find(function(r){ return r.name is n; }); return w && w.available; })>> <<set _bAvailNow = $poolBeginner.filter(function(n){ var w = $recruitPool.find(function(r){ return r.name is n; }); return w && w.available; })>> <<for _di = 0; _di < _multiDraw; _di++>> <<set _useUpgrade = _chance > 0 && random(1, 100) <= _chance && _cAvail2.length > 0>> <<set _isEstablishedDraw = _useUpgrade && _cAvail2.length > 0>> <<set _useElite = _isEstablishedDraw && _eliteChance > 0 && random(1, 100) <= _eliteChance && _eAvail2.length > 0>> <<if _useElite>><<set $drawPool = "elite">><<set _ri = random(0, _eAvail2.length-1)>><<set $drawResult.push(_eAvail2[_ri])>><<set $drawEliteNames.push(_eAvail2[_ri])>><<set _eAvail2.splice(_ri, 1)>> <<elseif _isEstablishedDraw>><<set $drawPool = "confirmed">><<set _ri = random(0, _cAvail2.length-1)>><<set $drawResult.push(_cAvail2[_ri])>><<if _useUpgrade>><<set $drawLuckyNames.push(_cAvail2[_ri])>><</if>><<set _cAvail2.splice(_ri, 1)>> <<elseif _bAvailNow.length > 0>><<set _ri = random(0, _bAvailNow.length-1)>><<set $drawResult.push(_bAvailNow[_ri])>><<set _bAvailNow.splice(_ri, 1)>> <<elseif _cAvail2.length > 0 && random(1, 100) <= (_chance + 10)>><<set $drawPool = "confirmed">><<set _ri = random(0, _cAvail2.length-1)>><<set $drawResult.push(_cAvail2[_ri])>><<set _cAvail2.splice(_ri, 1)>> <<elseif _eAvail2.length > 0 && random(1, 100) <= (_eliteChance + 10)>><<set $drawPool = "elite">><<set _ri = random(0, _eAvail2.length-1)>><<set $drawResult.push(_eAvail2[_ri])>><<set $drawEliteNames.push(_eAvail2[_ri])>><<set _eAvail2.splice(_ri, 1)>><</if>> <</for>> <<goto "Recruitment">> <</link>> <<else>> <<link `"🎲 Scout ($" + $bDrawCost + ")"`>> <<set $player.money -= $bDrawCost>><<set $drawPool = "beginner">><<set $drawLuckyNames = []>><<set $drawEliteNames = []>> <<set _chance = 0>><<if $pool1Upgrade2A.bought>><<set _chance = 50>><<elseif $pool1UpgradeItem.bought>><<set _chance = 20>><</if>> <<set _eliteChance = 0>><<if $pool2Upgrade2.bought>><<set _eliteChance = 40>><<elseif $pool2UpgradeItem.bought>><<set _eliteChance = 15>><</if>> <<set _useUpgrade = _chance > 0 && random(1, 100) <= _chance>> <<set _cAvail2 = $poolConfirmed.filter(function(n){ var w = $recruitPool.find(function(r){ return r.name is n; }); return w && w.available; })>> <<set _eAvail2 = $poolElite.filter(function(n){ var w = $recruitPool.find(function(r){ return r.name is n; }); return w && w.available; })>> <<set _bAvailNow = $poolBeginner.filter(function(n){ var w = $recruitPool.find(function(r){ return r.name is n; }); return w && w.available; })>> <<if $targetedScoutItem && $targetedScoutItem.bought && $targetedScoutStar>> <<if _bAvailNow.indexOf($targetedScoutStar) >= 0>><<set _bAvailNow = _bAvailNow.concat([$targetedScoutStar])>> <<elseif _cAvail2.indexOf($targetedScoutStar) >= 0>><<set _cAvail2 = _cAvail2.concat([$targetedScoutStar])>> <<elseif _eAvail2.indexOf($targetedScoutStar) >= 0>><<set _eAvail2 = _eAvail2.concat([$targetedScoutStar])>><</if>> <</if>> <<set _isEstablishedDraw = _useUpgrade && _cAvail2.length > 0>> <<set _useElite = _isEstablishedDraw && _eliteChance > 0 && random(1, 100) <= _eliteChance && _eAvail2.length > 0>> <<if _useElite>><<set $drawPool = "elite">><<set _ri = random(0, _eAvail2.length-1)>><<set $drawResult = [_eAvail2[_ri]]>><<set $drawEliteNames.push(_eAvail2[_ri])>> <<elseif _isEstablishedDraw>><<set $drawPool = "confirmed">><<set _ri = random(0, _cAvail2.length-1)>><<set $drawResult = [_cAvail2[_ri]]>><<if _useUpgrade>><<set $drawLuckyNames.push(_cAvail2[_ri])>><</if>> <<elseif _bAvailNow.length > 0>><<set _ri = random(0, _bAvailNow.length-1)>><<set $drawResult = [_bAvailNow[_ri]]>> <<elseif _cAvail2.length > 0 && random(1, 100) <= (_chance + 10)>><<set $drawPool = "confirmed">><<set _ri = random(0, _cAvail2.length-1)>><<set $drawResult = [_cAvail2[_ri]]>> <<elseif _eAvail2.length > 0 && random(1, 100) <= (_eliteChance + 10)>><<set $drawPool = "elite">><<set _ri = random(0, _eAvail2.length-1)>><<set $drawResult = [_eAvail2[_ri]]>><<set $drawEliteNames.push(_eAvail2[_ri])>> <<else>><<set $drawResult = []>><</if>> <<goto "Recruitment">> <</link>> <</if>> <<elseif _bAvail.length is 0>><em style="color:#666;">Pool empty</em> <<else>>@@color:red;No funds@@ <</if>> <br><em style="font-size:0.85em;color:#888;">Scout cost: $<<= $bDrawCost>></em> </div> <</if>> <<if $pool1IntelItem.bought>><details><summary style="cursor:pointer;padding:6px 10px;background:#1a1a2e;border:1px solid #444;border-radius:6px;font-size:0.9em;color:#e0e0e0;list-style:none;">👁️ View Pool 1 — Emerging Talents</summary><div id="pool1-table" style="margin-top:8px;"></div></details><</if>> <<if $pool2IntelItem.bought>><details><summary style="cursor:pointer;padding:6px 10px;background:#1a1a2e;border:1px solid #444;border-radius:6px;font-size:0.9em;color:#e0e0e0;list-style:none;margin-top:6px;">👁️ View Pool 2 — Established Talents</summary><div id="pool2-table" style="margin-top:8px;"></div></details><</if>> <<if $pool3IntelItem.bought>><details><summary style="cursor:pointer;padding:6px 10px;background:#1a1a2e;border:1px solid #444;border-radius:6px;font-size:0.9em;color:#e0e0e0;list-style:none;margin-top:6px;">👁️ View Pool 3 — Elite Talents</summary><div id="pool3-table" style="margin-top:8px;"></div></details><</if>> <<script>> jQuery(document).one(':passageend', function(){ var sv = SugarCube.State.variables; var recruitPool = sv.recruitPool; var trends = sv.trends; function getStars(names){ return (names||[]).map(function(n){ return recruitPool.find(function(r){ return r.name===n; }); }).filter(Boolean); } var pools = [ { id: 'pool1-table', names: sv.poolBeginner, loaded: false }, { id: 'pool2-table', names: sv.poolConfirmed, loaded: false }, { id: 'pool3-table', names: sv.poolElite, loaded: false } ]; document.querySelectorAll('details').forEach(function(det){ var poolId = det.querySelector('div[id]') ? det.querySelector('div[id]').id : null; if(!poolId) return; var pool = pools.find(function(p){ return p.id === poolId; }); if(!pool) return; det.addEventListener('toggle', function(){ if(det.open && !pool.loaded){ pool.loaded = true; buildStarTable(getStars(pool.names), trends, -1, pool.id, function(){}, '<em>Pool empty.</em>', true); } }); }); }); <</script>> <<= ''>> [[⬅️ Dashboard|Dashboard]]
<<silently>> <<set _dw = $recruitPool.find(function(w){ return w.name is $drawSignName; })>> <<set _contractPrice = _dw.contractCost>> <<if $archetype is "charismatic">><<set _contractPrice = Math.ceil(_contractPrice * 0.9)>><</if>> <<set _dw.available = false>> <<set _dw.weekShootings = 0>> <<set _dw.lastShootingDay = $player.day>> <<set $drawResult = []>> <</silently>> <<if ($drawPool is "confirmed" || $poolConfirmed.indexOf(_dw.name) >= 0) && !$pool2Stolen>> <<silently>><<set $pool2Stolen = true>><<set $rival.roster.push(clone(_dw))>><</silently>> @@color:red;⚠️ <b>Outbid!</b> <<= $rival.name>> swooped in and offered <<= _dw.name>> a better deal at the last second.@@ <em>"Sorry... they made me an offer I couldn't refuse."</em> 💳 Contract cost refunded: <b>$<<= _contractPrice.toLocaleString()>></b> <<silently>><<set $poachingUnlocked = true>><</silently>> @@color:cyan;💡 <b>Poaching unlocked!</b> You can now invest in poaching rival stars from the Competition page.@@ [[👤 Keep scouting|Recruitment]] | [[📊 Dashboard|Dashboard]] <<elseif $player.money < _contractPrice>> @@color:red;Not enough funds ($<<= _contractPrice.toLocaleString()>> required).@@ [[👤 Keep scouting|Recruitment]] | [[📊 Dashboard|Dashboard]] <<else>> <<set $player.money -= _contractPrice>> <<silently>><<set $roster.push(clone(_dw))>> <<set $roster[$roster.length - 1].joinedDay = $player.day>> <<if $archetype is "charismatic">><<set $roster[$roster.length - 1].satisfaction = 15>><</if>> <<if $targetedScoutStar is _dw.name>><<set $targetedScoutStar = "">><</if>> <<if $roster.length is 3 && $thirdRecruitDay < 0>><<set $thirdRecruitDay = $player.day>><</if>><</silently>> ✅ <b><<= _dw.name>></b> signs with your agency! 💳 <b>$<<= _contractPrice.toLocaleString()>></b> paid | 🔄 <b>$<<= (_dw.popularity * 70).toLocaleString()>>/week</b> upkeep <<if $roster.length is 1 && $rivalStartStar>>@@color:red;⚠️ <b><<= $rival.name>> recruited <<= $rivalStartStar>>.</b>@@ <div id="rival-recruit-portrait-1" style="text-align:center;margin:6px 0;"></div> <<script>>jQuery(document).one(':passageend',function(){var n=SugarCube.State.variables.rivalStartStar;var el=document.getElementById('rival-recruit-portrait-1');if(el&&n){var f=n.toLowerCase().replace(/ /g,'_');el.innerHTML='<img style="width:170px;height:170px;object-fit:cover;border-radius:12px;box-shadow:0 4px 16px rgba(0,0,0,0.5);" src="img/portraits/'+f+'.jpg">';}SugarCube.State.variables.rivalStartStar='';});<</script>><</if>> <<if $roster.length is 2>><<silently>><<set _p1Avail = $poolBeginner.filter(function(n){ var w = $recruitPool.find(function(r){ return r.name is n; }); return w && w.available; })>><<if _p1Avail.length > 0>><<set _ri2 = random(0, _p1Avail.length - 1)>><<set _rs2name = _p1Avail[_ri2]>><<set _rs2 = $recruitPool.find(function(w){ return w.name is _rs2name; })>><<set _rs2.available = false>><<set $rival.roster.push(clone(_rs2))>><</if>><</silently>><<if _p1Avail.length > 0>><<silently>><<set $rivalRecruitName = _rs2name>><</silently>>@@color:red;⚠️ <b><<= $rival.name>> recruited <<= _rs2name>>.</b>@@ <div id="rival-recruit-portrait-2" style="text-align:center;margin:6px 0;"></div> <<script>>jQuery(document).one(':passageend',function(){var n=SugarCube.State.variables.rivalRecruitName;var el=document.getElementById('rival-recruit-portrait-2');if(el&&n){var f=n.toLowerCase().replace(/ /g,'_');el.innerHTML='<img style="width:170px;height:170px;object-fit:cover;border-radius:12px;box-shadow:0 4px 16px rgba(0,0,0,0.5);" src="img/portraits/'+f+'.jpg">';}});<</script>><</if>><</if>> [[👤 Keep scouting|Recruitment]] | [[📋 Roster|Roster]] <</if>> /* ════════════════════════════════════════════ PASSAGE : ROSTER ════════════════════════════════════════════ */
<h1 style="margin:0 0 0.4em 0;">🏆 Trophies</h1> <<if $easyMode>> <div style="padding:8px 14px;background:#2a1010;border:1px solid #7a2a2a;border-radius:8px;margin-bottom:10px;color:#ff9e9e;"> 🔒 Easy Mode is active — trophies are locked for this playthrough. </div> <</if>> <div style="display:grid;gap:10px;margin:14px 0;"> <div style="padding:12px 16px;font-size:1.05em;background:linear-gradient(135deg,#1a1a2e,#16213e);border-radius:10px;box-shadow:0 3px 8px rgba(0,0,0,0.35);border:2px solid <<if $trophies.fullHouse>>#ffd700<<else>>#333<</if>>;"> <<if $trophies.fullHouse>>🏆<<else>>🔒<</if>> <b>Full House</b> — Sign 10 stars </div> <div style="padding:12px 16px;font-size:1.05em;background:linear-gradient(135deg,#1a1a2e,#16213e);border-radius:10px;box-shadow:0 3px 8px rgba(0,0,0,0.35);border:2px solid <<if $trophies.empire>>#ffd700<<else>>#333<</if>>;"> <<if $trophies.empire>>🏆<<else>>🔒<</if>> <b>Empire</b> — Sign 20 stars </div> <div style="padding:12px 16px;font-size:1.05em;background:linear-gradient(135deg,#1a1a2e,#16213e);border-radius:10px;box-shadow:0 3px 8px rgba(0,0,0,0.35);border:2px solid <<if $trophies.dealMaker>>#ffd700<<else>>#333<</if>>;"> <<if $trophies.dealMaker>>🏆<<else>>🔒<</if>> <b>Deal Maker</b> — Complete 5 contracts (<<= $totalContractsCompleted>>/5) </div> <div style="padding:12px 16px;font-size:1.05em;background:linear-gradient(135deg,#1a1a2e,#16213e);border-radius:10px;box-shadow:0 3px 8px rgba(0,0,0,0.35);border:2px solid <<if $trophies.harderDeal>>#ffd700<<else>>#333<</if>>;"> <<if $trophies.harderDeal>>🏆<<else>>🔒<</if>> <b>Harder Deal</b> — Complete a Harder Contract </div> <div style="padding:12px 16px;font-size:1.05em;background:linear-gradient(135deg,#1a1a2e,#16213e);border-radius:10px;box-shadow:0 3px 8px rgba(0,0,0,0.35);border:2px solid <<if $trophies.asianDuoComplete>>#ffd700<<else>>#333<</if>>;"> <<if $trophies.asianDuoComplete>>🏆<<else>>🔒<</if>> <b>Asian Duo</b> — Complete the Asian Duo questline </div> <div style="padding:12px 16px;font-size:1.05em;background:linear-gradient(135deg,#1a1a2e,#16213e);border-radius:10px;box-shadow:0 3px 8px rgba(0,0,0,0.35);border:2px solid <<if $trophies.fallenAngelsComplete>>#ffd700<<else>>#333<</if>>;"> <<if $trophies.fallenAngelsComplete>>🏆<<else>>🔒<</if>> <b>Fallen Angels</b> — Complete the Two Fallen Angels questline </div> <div style="padding:12px 16px;font-size:1.05em;background:linear-gradient(135deg,#1a1a2e,#16213e);border-radius:10px;box-shadow:0 3px 8px rgba(0,0,0,0.35);border:2px solid <<if $trophies.sweetCapriceComplete>>#ffd700<<else>>#333<</if>>;"> <<if $trophies.sweetCapriceComplete>>🏆<<else>>🔒<</if>> <b>Sweet Caprice</b> — Complete the Sweet Caprice questline </div> <div style="padding:12px 16px;font-size:1.05em;background:linear-gradient(135deg,#1a1a2e,#16213e);border-radius:10px;box-shadow:0 3px 8px rgba(0,0,0,0.35);border:2px solid <<if $trophies.first100Sat>>#ffd700<<else>>#333<</if>>;"> <<if $trophies.first100Sat>>🏆<<else>>🔒<</if>> <b>Perfect Bond</b> — Get a star to 100 satisfaction </div> <div style="padding:12px 16px;font-size:1.05em;background:linear-gradient(135deg,#1a1a2e,#16213e);border-radius:10px;box-shadow:0 3px 8px rgba(0,0,0,0.35);border:2px solid <<if $trophies.firstMillion>>#ffd700<<else>>#333<</if>>;"> <<if $trophies.firstMillion>>🏆<<else>>🔒<</if>> <b>First Million</b> — Earn $1,000,000 total (<<if $totalEarnings >= 1000000>>✅<<else>>$<<= $totalEarnings.toLocaleString()>><</if>>) </div> <div style="padding:12px 16px;font-size:1.05em;background:linear-gradient(135deg,#1a1a2e,#16213e);border-radius:10px;box-shadow:0 3px 8px rgba(0,0,0,0.35);border:2px solid <<if $trophies.brokeBurBack>>#ffd700<<else>>#333<</if>>;"> <<if $trophies.brokeBurBack>>🏆<<else>>🔒<</if>> <b>Broke But Back</b> — Survive a negative upkeep </div> <div style="padding:12px 16px;font-size:1.05em;background:linear-gradient(135deg,#1a1a2e,#16213e);border-radius:10px;box-shadow:0 3px 8px rgba(0,0,0,0.35);border:2px solid <<if $trophies.firstPoach>>#ffd700<<else>>#333<</if>>;"> <<if $trophies.firstPoach>>🏆<<else>>🔒<</if>> <b>Poacher</b> — Successfully poach a rival star </div> <div style="padding:12px 16px;font-size:1.05em;background:linear-gradient(135deg,#1a1a2e,#16213e);border-radius:10px;box-shadow:0 3px 8px rgba(0,0,0,0.35);border:2px solid <<if $trophies.poachMaster>>#ffd700<<else>>#333<</if>>;"> <<if $trophies.poachMaster>>🏆<<else>>🔒<</if>> <b>Poach Master</b> — Poach 5 rival stars (<<= $totalPoachesSucceeded>>/5) </div> <div style="padding:12px 16px;font-size:1.05em;background:linear-gradient(135deg,#1a1a2e,#16213e);border-radius:10px;box-shadow:0 3px 8px rgba(0,0,0,0.35);border:2px solid <<if $trophies.perfectJudge>>#ffd700<<else>>#333<</if>>;"> <<if $trophies.perfectJudge>>🏆<<else>>🔒<</if>> <b>Perfect Judge</b> — Win a Contest with a judge who loved everything about your entry </div> <div style="padding:12px 16px;font-size:1.05em;background:linear-gradient(135deg,#1a1a2e,#16213e);border-radius:10px;box-shadow:0 3px 8px rgba(0,0,0,0.35);border:2px solid <<if $trophies.fullPanel>>#ffd700<<else>>#333<</if>>;"> <<if $trophies.fullPanel>>🏆<<else>>🔒<</if>> <b>Full Panel</b> — Fully learn every preference of a single judge </div> <div style="padding:12px 16px;font-size:1.05em;background:linear-gradient(135deg,#1a1a2e,#16213e);border-radius:10px;box-shadow:0 3px 8px rgba(0,0,0,0.35);border:2px solid <<if $trophies.contestRegular>>#ffd700<<else>>#333<</if>>;"> <<if $trophies.contestRegular>>🏆<<else>>🔒<</if>> <b>Contest Regular</b> — Complete 5 Contests (<<= $totalContestsCompleted>>/5) </div> <div style="padding:12px 16px;font-size:1.05em;background:linear-gradient(135deg,#1a1a2e,#16213e);border-radius:10px;box-shadow:0 3px 8px rgba(0,0,0,0.35);border:2px solid <<if $trophies.totalPackage>>#ffd700<<else>>#333<</if>>;"> <<if $trophies.totalPackage>>🏆<<else>>🔒<</if>> <b>Total Package</b> — Unlock every position in the Shop </div> <div style="padding:12px 16px;font-size:1.05em;background:linear-gradient(135deg,#1a1a2e,#16213e);border-radius:10px;box-shadow:0 3px 8px rgba(0,0,0,0.35);border:2px solid <<if $trophies.allTrophies>>#ffd700<<else>>#333<</if>>;"> <<if $trophies.allTrophies>>🏆<<else>>🔒<</if>> <b>Completionist</b> — Earn every other trophy </div> </div> [[⬅️ Dashboard|Dashboard]]
<h1 style="margin:0 0 0.4em 0;">📜 Questlines</h1> <<if $questlines.asianDuo.specialAvailable>><div style="padding:10px;background:#111;border-radius:6px;margin:6px 0;"><<if $questlines.asianDuo.shooting2Done>><b>🎌 Asian Duo</b> @@color:gold;✅ Complete!@@<<elseif $questlines.asianDuo.shooting1Done>><b>🎌 Asian Duo</b> @@color:cyan;Step 5/6 — Second special available!@@<<elseif $questlines.asianDuo.specialAvailable>><b>🎌 Asian Duo</b> @@color:gold;Step 4/6 — Special shooting unlocked!@@<br><em style="font-size:0.85em;color:#888;">Kimmy & Lulu — first special available!</em><</if>></div> <<elseif $questlines.asianDuo.active>><<set _qlA = $questlines.asianDuo>><div style="padding:10px;background:#111;border-radius:6px;margin:6px 0;"><b>🎌 Asian Duo</b> @@color:cyan;In progress — Step <<= _qlA.step>>/4@@<br><<if _qlA.step is 1>><em style="font-size:0.85em;color:#888;">Get <<= _qlA.star1>> to 25 satisfaction (<<= $roster.find(function(w){ return w.name is _qlA.star1; }) ? $roster.find(function(w){ return w.name is _qlA.star1; }).satisfaction : 0>>/25)</em><<elseif _qlA.step is 2>><em style="font-size:0.85em;color:#888;">Recruit <<= (_qlA.star1 is "Kimmy") ? "Lulu" : "Kimmy">></em><<elseif _qlA.step is 3>><em style="font-size:0.85em;color:#888;">Get <<= _qlA.star2>> to 25 satisfaction (<<= $roster.find(function(w){ return w.name is _qlA.star2; }) ? $roster.find(function(w){ return w.name is _qlA.star2; }).satisfaction : 0>>/25)</em><</if>></div> <<else>><div style="padding:10px;background:#111;border-radius:6px;margin:6px 0;opacity:0.5;"><b>🎌 Asian Duo</b> 🔒 <em style="font-size:0.85em;color:#888;">Recruit Kimmy or Lulu to unlock</em></div> <</if>> <<if $questlines.fallenAngels.shooting3Done>><div style="padding:10px;background:#111;border-radius:6px;margin:6px 0;"><b>👼 Two Fallen Angels</b> @@color:gold;✅ Complete!@@</div> <<elseif $questlines.fallenAngels.shooting2Done>><div style="padding:10px;background:#111;border-radius:6px;margin:6px 0;"><b>👼 Two Fallen Angels</b> @@color:cyan;Step 6/6 — 3rd special!@@</div> <<elseif $questlines.fallenAngels.shooting1Done>><div style="padding:10px;background:#111;border-radius:6px;margin:6px 0;"><b>👼 Two Fallen Angels</b> @@color:cyan;Step 5/6 — 2nd special!@@</div> <<elseif $questlines.fallenAngels.specialAvailable>><div style="padding:10px;background:#111;border-radius:6px;margin:6px 0;"><b>👼 Two Fallen Angels</b> @@color:gold;Step 4/6 — Specials unlocked!@@</div> <<elseif $questlines.fallenAngels.active>><<set _qlF2 = $questlines.fallenAngels>><div style="padding:10px;background:#111;border-radius:6px;margin:6px 0;"><b>👼 Two Fallen Angels</b> @@color:cyan;In progress — Step <<= _qlF2.step>>/6@@<br><<if _qlF2.step is 1>><em style="font-size:0.85em;color:#888;">Get <<= _qlF2.star1>> to 25 satis</em><<elseif _qlF2.step is 2>><em style="font-size:0.85em;color:#888;">Recruit <<= (_qlF2.star1 is "Angie") ? "Angela" : "Angie">></em><<elseif _qlF2.step is 3>><em style="font-size:0.85em;color:#888;">Get <<= _qlF2.star2>> to 25 satis</em><</if>></div> <<else>><div style="padding:10px;background:#111;border-radius:6px;margin:6px 0;opacity:0.5;"><b>👼 Two Fallen Angels</b> 🔒 <em style="font-size:0.85em;color:#888;">Recruit Angie or Angela to unlock</em></div> <</if>> <<if $questlines.sweetCaprice.shooting2Done>><div style="padding:10px;background:#111;border-radius:6px;margin:6px 0;"><b>🍬 Sweet Caprice</b> @@color:gold;✅ Complete!@@</div> <<elseif $questlines.sweetCaprice.shooting1Done>><div style="padding:10px;background:#111;border-radius:6px;margin:6px 0;"><b>🍬 Sweet Caprice</b> @@color:cyan;Second special available!@@</div> <<elseif $questlines.sweetCaprice.specialAvailable>><div style="padding:10px;background:#111;border-radius:6px;margin:6px 0;"><b>🍬 Sweet Caprice</b> @@color:gold;Special shooting unlocked!@@</div> <<elseif $questlines.sweetCaprice.active>><<set _qlC2 = $questlines.sweetCaprice>><div style="padding:10px;background:#111;border-radius:6px;margin:6px 0;"><b>🍬 Sweet Caprice</b> @@color:cyan;In progress — Step <<= _qlC2.step>>/4@@<br><<if _qlC2.step is 1>><em style="font-size:0.85em;color:#888;">Get Caprice to 50 satisfaction (<<= $roster.find(function(w){ return w.name is "Caprice"; }) ? $roster.find(function(w){ return w.name is "Caprice"; }).satisfaction : 0>>/50)</em><<elseif _qlC2.step is 2>><em style="font-size:0.85em;color:#888;">Shoot BJ productions with Caprice (<<= _qlC2.bjCount>>/6)</em><<elseif _qlC2.step is 3>><em style="font-size:0.85em;color:#888;">Eve is on her way (<<= Math.max(0, (_qlC2.eveNotifyDay + 3) - $player.day)>>d)</em><</if>></div> <<else>><div style="padding:10px;background:#111;border-radius:6px;margin:6px 0;opacity:0.5;"><b>🍬 Sweet Caprice</b> 🔒 <em style="font-size:0.85em;color:#888;">Recruit Caprice to unlock</em></div> <</if>> [[⬅️ Dashboard|Dashboard]]
<h1 style="margin:0 0 0.4em 0;">🌟 Special Shootings</h1> <<if $questlines.asianDuo.specialAvailable && !$questlines.asianDuo.shooting1Done>><div style="padding:14px 16px;background:linear-gradient(135deg,#2a2410,#1a1a2e);border:2px solid #ffd700;border-radius:10px;box-shadow:0 0 14px rgba(255,215,0,0.25),0 3px 8px rgba(0,0,0,0.35);margin-bottom:10px;"><div style="font-size:1.15em;font-weight:700;margin-bottom:4px;">🎌 Kimmy & Lulu</div><div style="font-size:0.9em;color:#aaa;margin-bottom:10px;">Their first collaboration together</div>[[🎬 Collab 1|AsianDuoShooting1]]</div><<elseif $questlines.asianDuo.shooting1Done && !$questlines.asianDuo.shooting2Done>><div style="padding:14px 16px;background:linear-gradient(135deg,#1a1a2e,#16213e);border:2px solid #4a9eff;border-radius:10px;box-shadow:0 0 12px rgba(74,158,255,0.2),0 3px 8px rgba(0,0,0,0.35);margin-bottom:10px;"><div style="font-size:1.15em;font-weight:700;margin-bottom:4px;">🎌 Kimmy & Lulu</div><div style="font-size:0.9em;color:#aaa;margin-bottom:10px;">The finale — their signature</div><<if $asianDuoShoot2Unlocked>>[[🎬 Collab 2|AsianDuoShooting2]]<<else>><em style="color:#888;">Available in <<= Math.max(0, ($asianDuoShoot1Day + 3) - $player.day)>> day(s)...</em><</if>></div><<elseif $questlines.asianDuo.shooting2Done>><div style="padding:12px 16px;background:linear-gradient(135deg,#183a20,#0d2b1a);border:2px solid #2a7a3a;border-radius:10px;margin-bottom:10px;opacity:0.85;">🎌 <b>Kimmy & Lulu</b> — <span style="color:#6fcf73;">✅ Complete</span></div><</if>> <<if $questlines.fallenAngels.specialAvailable && !$questlines.fallenAngels.shooting1Done>><div style="padding:14px 16px;background:linear-gradient(135deg,#2a2410,#1a1a2e);border:2px solid #ffd700;border-radius:10px;box-shadow:0 0 14px rgba(255,215,0,0.25),0 3px 8px rgba(0,0,0,0.35);margin-bottom:10px;"><div style="font-size:1.15em;font-weight:700;margin-bottom:4px;">👼 Angie & Angela</div><div style="font-size:0.9em;color:#aaa;margin-bottom:10px;">Two Fallen Angels — first scene together</div>[[🎬 Collab 1|FallenAngelsShoot1]]</div><<elseif $questlines.fallenAngels.shooting1Done && !$questlines.fallenAngels.shooting2Done>><div style="padding:14px 16px;background:linear-gradient(135deg,#1a1a2e,#16213e);border:2px solid #4a9eff;border-radius:10px;box-shadow:0 0 12px rgba(74,158,255,0.2),0 3px 8px rgba(0,0,0,0.35);margin-bottom:10px;"><div style="font-size:1.15em;font-weight:700;margin-bottom:4px;">👼 Angie & Angela</div><div style="font-size:0.9em;color:#aaa;margin-bottom:10px;">Two Fallen Angels — rising together</div><<if $fallenAngelsShoot2Unlocked>>[[🎬 Collab 2|FallenAngelsShoot2]]<<else>><em style="color:#888;">Available in <<= Math.max(0, ($fallenAngelsShoot1Day + 3) - $player.day)>> day(s)...</em><</if>></div><<elseif $questlines.fallenAngels.shooting2Done && !$questlines.fallenAngels.shooting3Done>><div style="padding:14px 16px;background:linear-gradient(135deg,#1a1a2e,#16213e);border:2px solid #4a9eff;border-radius:10px;box-shadow:0 0 12px rgba(74,158,255,0.2),0 3px 8px rgba(0,0,0,0.35);margin-bottom:10px;"><div style="font-size:1.15em;font-weight:700;margin-bottom:4px;">👼 Angie & Angela</div><div style="font-size:0.9em;color:#aaa;margin-bottom:10px;">Two Fallen Angels — the final act</div><<if $fallenAngelsShoot3Unlocked>>[[🎬 Collab 3|FallenAngelsShoot3]]<<else>><em style="color:#888;">Available in <<= Math.max(0, ($fallenAngelsShoot2Day + 3) - $player.day)>> day(s)...</em><</if>></div><<elseif $questlines.fallenAngels.shooting3Done>><div style="padding:12px 16px;background:linear-gradient(135deg,#183a20,#0d2b1a);border:2px solid #2a7a3a;border-radius:10px;margin-bottom:10px;opacity:0.85;">👼 <b>Angie & Angela</b> — <span style="color:#6fcf73;">✅ Complete</span></div><</if>> <<if $questlines.sweetCaprice.specialAvailable && !$questlines.sweetCaprice.shooting1Done>><div style="padding:14px 16px;background:linear-gradient(135deg,#2a2410,#1a1a2e);border:2px solid #ffd700;border-radius:10px;box-shadow:0 0 14px rgba(255,215,0,0.25),0 3px 8px rgba(0,0,0,0.35);margin-bottom:10px;"><div style="font-size:1.15em;font-weight:700;margin-bottom:4px;">🍬 Caprice</div><div style="font-size:0.9em;color:#aaa;margin-bottom:10px;">Her reward for six perfect scenes</div>[[🎬 Collab 1|SweetCapriceShoot1]]</div><<elseif $questlines.sweetCaprice.shooting1Done && !$questlines.sweetCaprice.shooting2Done>><div style="padding:14px 16px;background:linear-gradient(135deg,#1a1a2e,#16213e);border:2px solid #4a9eff;border-radius:10px;box-shadow:0 0 12px rgba(74,158,255,0.2),0 3px 8px rgba(0,0,0,0.35);margin-bottom:10px;"><div style="font-size:1.15em;font-weight:700;margin-bottom:4px;">🍬 Caprice</div><div style="font-size:0.9em;color:#aaa;margin-bottom:10px;">Bigger, and no holding back</div><<if $capriceShoot2Unlocked>>[[🎬 Collab 2|SweetCapriceShoot2]]<<else>><em style="color:#888;">Available in <<= Math.max(0, ($capriceShoot1Day + 3) - $player.day)>> day(s)...</em><</if>></div><<elseif $questlines.sweetCaprice.shooting2Done>><div style="padding:12px 16px;background:linear-gradient(135deg,#183a20,#0d2b1a);border:2px solid #2a7a3a;border-radius:10px;margin-bottom:10px;opacity:0.85;">🍬 <b>Caprice</b> — <span style="color:#6fcf73;">✅ Complete</span></div><</if>> <<if !$questlines.asianDuo.specialAvailable && !$questlines.asianDuo.shooting1Done && !$questlines.fallenAngels.specialAvailable && !$questlines.fallenAngels.shooting1Done && !$questlines.sweetCaprice.specialAvailable && !$questlines.sweetCaprice.shooting1Done>><div style="padding:14px 16px;background:linear-gradient(135deg,#1a1a2e,#16213e);border:1px solid #333;border-radius:10px;color:#888;">No special shooting available yet. They're unlockable through questlines and events.</div><</if>> [[⬅️ Dashboard|Dashboard]]
<h1 style="margin:0 0 0.4em 0;">📋 My Roster</h1> <<if $rosterMessage>>@@color:orange;⚠️ <<= $rosterMessage>>@@<<set $rosterMessage = "">><</if>> <<if $roster.length is 0>> <em>Your roster is empty.</em> <<else>> <div id="roster-controls" style="margin:8px 0;padding:6px 10px;background:linear-gradient(135deg,#1a1a2e,#16213e);border:1px solid #333;border-radius:8px;"> <div style="margin-bottom:8px;"><b style="font-size:0.9em;">Sort:</b> <span class="sort-btn" data-sort="name">Name</span><span class="sort-btn" data-sort="satisfaction">❤️ Satisfaction</span><span class="sort-btn" data-sort="popularity">🌟 Popularity</span><span class="sort-btn" data-sort="ageNum">Age</span></div> <div><b style="font-size:0.9em;">Filter:</b> <span id="filter-list"></span><span class="filter-clear" style="display:none;">✖ Clear</span></div> </div> <div id="roster-cards"></div> <style> .sort-btn, .filter-btn, .filter-clear { display: inline-block; margin: 2px 4px; padding: 3px 10px; background: #1a1a2e; border: 1px solid #444; border-radius: 12px; cursor: pointer; font-size: 0.8em; transition: all 0.15s; } .sort-btn:hover, .filter-btn:hover, .filter-clear:hover { background: #2a2a4e; border-color: #888; } .sort-btn.active, .filter-btn.active { background: #4a9eff; color: #000; border-color: #4a9eff; } </style> <<script>> jQuery(document).one(':passageend', function(){ var roster = SugarCube.State.variables.roster; var trends = SugarCube.State.variables.trends; var sortKey = 'name'; var activeFilters = {}; var filterTypes = ['hair','height','breast','breastType','ethnicity']; var filterValues = {}; filterTypes.forEach(function(k){ filterValues[k] = []; }); roster.forEach(function(w){ filterTypes.forEach(function(k){ var v = w[k]; if(v && filterValues[k].indexOf(v) < 0) filterValues[k].push(v); }); }); var filterHtml = ''; filterTypes.forEach(function(k){ filterValues[k].sort().forEach(function(v){ filterHtml += '<span class="filter-btn" data-key="'+k+'" data-val="'+v+'">'+v+'</span>'; }); }); document.getElementById('filter-list').innerHTML = filterHtml; function applyView(){ var filtered = roster.filter(function(w){ for(var k in activeFilters){ if(activeFilters[k] && w[k] !== activeFilters[k]) return false; } return true; }); filtered.sort(function(a,b){ if(sortKey === 'name') return a.name < b.name ? -1 : 1; if(sortKey === 'satisfaction') return b.satisfaction - a.satisfaction; if(sortKey === 'popularity') return b.popularity - a.popularity; if(sortKey === 'ageNum') return a.ageNum - b.ageNum; return 0; }); buildStarCards(filtered, trends, 'roster-cards', null, [], false); /* Add Let Go buttons */ var cards = document.querySelectorAll('#roster-cards .star-card'); cards.forEach(function(card, i){ var star = filtered[i]; if(!star) return; var payout = Math.round(star.contractCost * 0.30); var btn = document.createElement('button'); btn.textContent = '\u{1F6AA} Let Go (+$'+payout.toLocaleString()+')'; btn.style.cssText = 'display:block;width:90%;margin:6px auto 2px;padding:5px 8px;background:#2b0d0d;border:1px solid #cc4444;color:#ff7a7a;border-radius:6px;cursor:pointer;font-size:0.78em;transition:all 0.2s;'; btn.addEventListener('mouseenter', function(){ this.style.background='#cc4444'; this.style.color='#fff'; }); btn.addEventListener('mouseleave', function(){ this.style.background='#2b0d0d'; this.style.color='#ff7a7a'; }); btn.addEventListener('click', function(e){ e.stopPropagation(); var sv = SugarCube.State.variables; var sat = star.satisfaction; var rivalChance; if(sat <= 10) rivalChance = 1.0; else if(sat >= 30) rivalChance = 0.10; else rivalChance = 1.0 - (sat - 10) * (0.90 / 20); var rivalPct = Math.round(rivalChance * 100); if(!confirm('Let go of '+star.name+'? You receive $'+payout.toLocaleString()+' (25% of contract). '+rivalPct+'% chance she joins '+sv.rival.name+'.')) return; sv.player.money += payout; var realIdx = sv.roster.findIndex(function(w){ return w.name === star.name; }); if(realIdx >= 0) sv.roster.splice(realIdx, 1); window.cleanupQuestlineForLostStar(star.name); if(Math.random() < rivalChance){ sv.rival.roster.push(star); sv.rosterMessage = star.name+' was let go — and walked straight to '+sv.rival.name+'. She went to find out how massive they are.'; } else { /* Return star to recruit pool */ star.available = true; star.satisfaction = 10; star.weekShootings = 0; star.restDay = false; if(!sv.recruitPool) sv.recruitPool = []; sv.recruitPool.push(star); sv.rosterMessage = star.name+' has left the agency. You received $'+payout.toLocaleString()+'. She\'s back on the market.'; } SugarCube.Engine.play('Roster'); }); card.appendChild(btn); }); } document.querySelectorAll('.sort-btn').forEach(function(btn){ btn.addEventListener('click', function(){ document.querySelectorAll('.sort-btn').forEach(function(b){ b.classList.remove('active'); }); this.classList.add('active'); sortKey = this.getAttribute('data-sort'); applyView(); }); }); document.querySelectorAll('.filter-btn').forEach(function(btn){ btn.addEventListener('click', function(){ var key = this.getAttribute('data-key'); var val = this.getAttribute('data-val'); if(activeFilters[key] === val){ delete activeFilters[key]; this.classList.remove('active'); } else { document.querySelectorAll('.filter-btn[data-key="'+key+'"]').forEach(function(b){ b.classList.remove('active'); }); activeFilters[key] = val; this.classList.add('active'); } var hasFilters = Object.keys(activeFilters).length > 0; document.querySelector('.filter-clear').style.display = hasFilters ? 'inline-block' : 'none'; applyView(); }); }); document.querySelector('.filter-clear').addEventListener('click', function(){ activeFilters = {}; document.querySelectorAll('.filter-btn').forEach(function(b){ b.classList.remove('active'); }); this.style.display = 'none'; applyView(); }); document.querySelector('.sort-btn[data-sort="name"]').classList.add('active'); applyView(); }); <</script>> <</if>> [[⬅️ Dashboard|Dashboard]] /* ════════════════════════════════════════════ PASSAGE : OrgShooting — Choose format ════════════════════════════════════════════ */
<<silently>><<calcAllowedPositions>><</silently>> <h1 style="margin:0 0 0.4em 0;">🎬 Today's Production</h1> <<if $shootingPlayedToday>> @@color:orange;✋ Production already done today. Come back tomorrow!@@ [[📅 Next day|NextDay]] | [[⬅️ Dashboard|Dashboard]] <<elseif $roster.length < 1>> ⚠️ You need at least <b>1 talent</b> in your roster. [[👤 Recruit|Recruitment]] | [[⬅️ Dashboard|Dashboard]] <<else>> You can use <b><<= $allowedPositions>> position(s)</b> today <em>(rep: <<= $player.reputation>>)</em>. <b>Choose a format:</b> [[📽️ Solo production|OrgShootingClassic][$advancedFormat = false, $selectedPositions = []]] <<if $player.reputation >= $advancedThreshold>> [[🌟 Two Shootings in a Day|OrgShootingAdvanced][$advancedFormat = true, $selectedPositions = []]] <<else>> 🔒 <b>Two Shootings in a Day</b> <em>(Reputation <<= $advancedThreshold>> required — you have <<= $player.reputation>>)</em> <</if>> [[⬅️ Dashboard|Dashboard]] <</if>> /* ════════════════════════════════════════════ PASSAGE : Classic format — Pick talent ════════════════════════════════════════════ */
<h1 style="margin:0 0 0.4em 0;">📽️ Solo production — Pick your talent</h1> <div id="star-select-table"></div> <<script>> jQuery(document).one(':passageend', function(){ buildStarTable( SugarCube.State.variables.roster, SugarCube.State.variables.trends, -1, 'star-select-table', function(idx){ SugarCube.State.variables.shootingC1 = idx; SugarCube.State.variables.shootingC2 = -1; SugarCube.Engine.play('PickPositions'); }, '⚠️ No talents available — all are resting today!' ); }); <</script>> [[⬅️ Cancel|OrgShooting]]
<h1 style="margin:0 0 0.4em 0;">🌟 Two Shootings in a Day — Pick first talent</h1> <div id="star-select-table"></div> <<script>> jQuery(document).one(':passageend', function(){ buildStarTable( SugarCube.State.variables.roster, SugarCube.State.variables.trends, -1, 'star-select-table', function(idx){ SugarCube.State.variables.shootingC1 = idx; SugarCube.Engine.play('OrgShootingAdvanced2'); }, '⚠️ You need at least <b>2 talents</b> available for this format.' ); }); <</script>> [[⬅️ Cancel|OrgShooting]]
<h1 style="margin:0 0 0.4em 0;">🌟 First talent: <<= $roster[$shootingC1].name>></h1> <div id="star-select-table"></div> <<script>> jQuery(document).one(':passageend', function(){ buildStarTable( SugarCube.State.variables.roster, SugarCube.State.variables.trends, SugarCube.State.variables.shootingC1, 'star-select-table', function(idx){ SugarCube.State.variables.shootingC2 = idx; SugarCube.Engine.play('PickPositions'); }, '⚠️ You need at least <b>2 available talents</b> for this format.' ); }); <</script>> [[⬅️ Cancel|OrgShooting]] /* ════════════════════════════════════════════ PASSAGE : Pick styles for the production ════════════════════════════════════════════ */
<<calcAllowedPositions>><<set _w1 = $roster[$shootingC1]>><<if $shootingC2 >= 0>><<set _w2 = $roster[$shootingC2]>><<else>><<set _w2 = null>><</if>><h1 style="margin:0 0 0.4em 0;">🎭 Pick Your Positions</h1> <<if $advancedFormat>><b><<= $player.name>> & <<= _w1.name>></b> and <b><<= $player.name>> & <<= _w2.name>></b><<else>><b><<= $player.name>></b> with <b><<= _w1.name>></b><</if>> | <b>Slots:</b> <<= $selectedPositions.length>>/<<= $allowedPositions>> | 🎬 Trending: @@color:gold;<b><<= $trends.position || "?">></b>@@ (+rep) <div style="padding:6px 10px;background:#111;border-radius:6px;font-size:0.85em;margin:4px 0;">💖 <<= _w1.name>>: <b><<= _w1.favPosition>><<if _w1.favPosition2>> & <<= _w1.favPosition2>><</if>></b><<if !_w1.bonusChosen>> <em style="color:#666">| 🔓 sat.30: <<= _w1.bonusPosition1>> / <<= _w1.bonusPosition2>></em><</if>><<if $advancedFormat && _w2>><br>💖 <<= _w2.name>>: <b><<= _w2.favPosition>><<if _w2.favPosition2>> & <<= _w2.favPosition2>><</if>></b><<if !_w2.bonusChosen>> <em style="color:#666">| 🔓 sat.30: <<= _w2.bonusPosition1>> / <<= _w2.bonusPosition2>></em><</if>><</if>></div> <div style="margin:4px 0;"><<for _i = 0; _i < $playerPositions.length; _i++>><<set _mn = $playerPositions[_i]>><<set _specReal = "">><<if _mn is "Specialty 1">><<set _specReal = _w1.specialty1 || (_w2 ? _w2.specialty1 : "") || "">><<elseif _mn is "Specialty 2">><<set _specReal = _w1.specialty2 || (_w2 ? _w2.specialty2 : "") || "">><<else>><<set _specReal = _mn>><</if>><<set _specMissing = (_mn is "Specialty 1" || _mn is "Specialty 2") && !_specReal>><<if !_specMissing>><<set _isTrend = (_specReal is $trends.position)>><<set _posObj = $allPositions.find(function(p){ return p.name is _mn; })>><<set _minSat = _posObj ? (_posObj.minSat || 0) : 0>><<set _sat1 = _w1 ? _w1.satisfaction : 100>><<set _sat2 = _w2 ? _w2.satisfaction : 100>><<set _minRosterSat = $advancedFormat ? Math.min(_sat1, _sat2) : _sat1>><<set _satLocked = _minRosterSat < _minSat>><<if $selectedPositions.includes(_mn)>><span style="display:inline-block;margin:2px;padding:3px 8px;background:#1a3a1a;border:1px solid #4a4;border-radius:4px;">✅ <<if _isTrend>>@@color:gold;<b><<= _specReal>></b>@@<<else>><b><<= _specReal>></b><</if>></span><<elseif _satLocked>><span style="display:inline-block;margin:2px;padding:3px 8px;background:#1a1a1a;border:1px solid #444;border-radius:4px;opacity:0.5;" title="Requires <<= _minSat>> satisfaction">🔒 <<= _specReal>> <em style="font-size:0.8em">(sat.<<= _minSat>>)</em></span><<elseif $selectedPositions.length < $allowedPositions>><<if _isTrend>><<capture _mn _specReal>>@@color:gold;<span style="display:inline-block;margin:2px;"><<print "[[🌟 " + _specReal + "|AddPosition][$positionToAdd = \"" + _mn + "\"]]">></span>@@<</capture>><<else>><<capture _mn _specReal>><span style="display:inline-block;margin:2px;"><<print "[[" + _specReal + "|AddPosition][$positionToAdd = \"" + _mn + "\"]]">></span><</capture>><</if>><<else>><span style="display:inline-block;margin:2px;padding:3px 8px;background:#1a1a1a;border:1px solid #333;border-radius:4px;opacity:0.4;"><<= _specReal>></span><</if>><</if>><</for>></div> <<if $selectedPositions.length > 0>><div style="padding:4px 10px;background:#111;border-radius:4px;font-size:0.85em;margin:4px 0;"><b>Selected:</b> <<print $selectedPositions.map(function(p){ if(p==="Specialty 1") return _w1.specialty1 || (_w2 ? _w2.specialty1 : p) || p; if(p==="Specialty 2") return _w1.specialty2 || (_w2 ? _w2.specialty2 : p) || p; return p; }).join(", ")>></div><</if>> <<if $selectedPositions.length >= 1>>[[🎬 Run the production!|RunShooting]]<</if>> [[⬅️ Cancel|OrgShooting]] /* ════════════════════════════════════════════ PASSAGE : AddPosition ════════════════════════════════════════════ */
<<set $selectedPositions.push($positionToAdd)>><<goto "PickPositions">> /* ════════════════════════════════════════════ PASSAGE : RunShooting ════════════════════════════════════════════ */
<<silently>><<set _w1 = $roster[$shootingC1]>><<if $shootingC2 >= 0>><<set _w2 = $roster[$shootingC2]>><<else>><<set _w2 = null>><</if>><<set _rawLastPos = $selectedPositions[$selectedPositions.length - 1]>><<set _realLastPos = _rawLastPos>><<if _rawLastPos is "Specialty 1">><<set _realLastPos = _w1.specialty1 || (_w2 ? _w2.specialty1 : "") || _rawLastPos>><<elseif _rawLastPos is "Specialty 2">><<set _realLastPos = _w1.specialty2 || (_w2 ? _w2.specialty2 : "") || _rawLastPos>><</if>><<set $shootingLastPosition = _realLastPos.toLowerCase().replace(/ /g, "_")>><<set $shootingW1File = _w1.name.toLowerCase().replace(/ /g, "_")>><<if _w2>><<set $shootingW2File = _w2.name.toLowerCase().replace(/ /g, "_")>><<else>><<set $shootingW2File = "">><</if>><<resolveShooting _w1 _w2 $advancedFormat>><<set $shootingPlayedToday = true>><</silently>><h1 style="margin:0 0 0.4em 0;">🎬 Production Result!</h1> <<if $advancedFormat>><b><<= $player.name>> & <<= _w1.name>></b> and <b><<= $player.name>> & <<= _w2.name>></b><<else>><b><<= $player.name>></b> with <b><<= _w1.name>></b><</if>> Cut! <<if $advancedFormat>>Both talents gave everything — raw, unfiltered, completely uninhibited. The crew is speechless.<<else>><<= _w1.name>> delivered exactly what the audience wanted — raw, unfiltered, and completely uninhibited.<</if>> <b>Positions used:</b> <<= $selectedPositions.join(", ")>> <div id="shooting-videos"></div> <<script>> jQuery(document).one(':passageend', function(){ var sv = SugarCube.State.variables; var w1 = sv.shootingW1File; var w2 = sv.shootingW2File; var pos = sv.shootingLastPosition; var wrap = document.getElementById('shooting-videos'); if(!wrap) return; var html = ''; if(w1 && pos){ html += '<video src="videos/'+w1+'_'+pos+'.webm" autoplay loop muted playsinline style="width:100%;max-width:560px;display:block;margin:12px auto;border-radius:10px;" onerror="this.style.display=\'none\'"></video>'; } if(w2 && pos){ html += '<video src="videos/'+w2+'_'+pos+'.webm" autoplay loop muted playsinline style="width:100%;max-width:560px;display:block;margin:12px auto;border-radius:10px;" onerror="this.style.display=\'none\'"></video>'; } wrap.innerHTML = html; }); <</script>> <<if $lastCarBonus || $lastCarBonus2 || $lastDoubleFeatureMulti > 1>>💰 <b class="gain-reveal glow-gold">Earnings: $<<= $lastGain.toLocaleString()>></b><<if $lastCarBonus || $lastCarBonus2>> <em>(×<<= $lastMulti>> physical trend bonus)</em><</if>><<if $lastDoubleFeatureMulti > 1>> <em>(×<<= $lastDoubleFeatureMulti.toFixed(2)>> double feature bonus)</em><</if>><<else>>💰 <b>Earnings: $<<= $lastGain.toLocaleString()>></b><</if>> <<if $lastPositionBonus>>🌟 <b class="gain-reveal glow-gold">Reputation: +<<= $lastRepBonus>></b> <em>(✅ Trending genre «<<= $trends.position>>»: +2 bonus)</em><<else>>🌟 <b>Reputation: +<<= $lastRepBonus>></b><</if>> <<if $lastCarBonus>> <em>💥 <<if $trends.carType is "breast">>The crowd went feral the second <<= $lastCarBonus>> got on screen — those <<= $trends.carValue>> tits had them stroking their screens<<elseif $trends.carType is "breastType">>><<= $lastCarBonus>>'s <<= $trends.carValue>> tits broke the internet tonight — fans know what they want and they got it<<elseif $trends.carType is "hair">>Every fantasy about <<= $trends.carValue>> hair came true the moment <<= $lastCarBonus>> let it loose on those sheets<<elseif $trends.carType is "height">>That <<= $trends.carValue>> body on <<= $lastCarBonus>> wrapped around the camera like a dream — the comments section is on fire<<elseif $trends.carType is "ageCat" && $trends.carValue is "Young">>Barely legal and completely uninhibited — <<= $lastCarBonus>> left the audience begging for a second take<<elseif $trends.carType is "ageCat" && $trends.carValue is "Veteran">>><<= $lastCarBonus>> fucked like she had something to prove — and a decade of experience to back it up<<elseif $trends.carType is "ageCat">>><<= $lastCarBonus>> knew exactly what buttons to push — old enough to own it, young enough to go all night<<elseif $trends.carType is "ethnicity">>The audience had one type on their mind tonight — <<= $trends.carValue>> — and <<= $lastCarBonus>> delivered every single fantasy<<else>>✅ <<= $trends.carType>>: <<= $trends.carValue>> — <<= $lastCarBonus>><</if>></em> <</if>> <<if $lastCarBonus2>> <em>💥 <<if $trends.carType2 is "breast">>The crowd went feral the second <<= $lastCarBonus2>> got on screen — those <<= $trends.carValue2>> tits had them stroking their screens<<elseif $trends.carType2 is "breastType">>><<= $lastCarBonus2>>'s <<= $trends.carValue2>> tits broke the internet tonight — fans know what they want and they got it<<elseif $trends.carType2 is "hair">>Every fantasy about <<= $trends.carValue2>> hair came true the moment <<= $lastCarBonus2>> let it loose on those sheets<<elseif $trends.carType2 is "height">>That <<= $trends.carValue2>> body on <<= $lastCarBonus2>> wrapped around the camera like a dream — the comments section is on fire<<elseif $trends.carType2 is "ageCat" && $trends.carValue2 is "Young">>Barely legal and completely uninhibited — <<= $lastCarBonus2>> left the audience begging for a second take<<elseif $trends.carType2 is "ageCat" && $trends.carValue2 is "Veteran">>><<= $lastCarBonus2>> fucked like she had something to prove — and a decade of experience to back it up<<elseif $trends.carType2 is "ageCat">>><<= $lastCarBonus2>> knew exactly what buttons to push — old enough to own it, young enough to go all night<<elseif $trends.carType2 is "ethnicity">>The audience had one type on their mind tonight — <<= $trends.carValue2>> — and <<= $lastCarBonus2>> delivered every single fantasy<<else>>✅ <<= $trends.carType2>>: <<= $trends.carValue2>> — <<= $lastCarBonus2>><</if>></em> <</if>> <<if $contract3Success>>📋 @@color:#4a9eff;<b>Established Contract complete!</b> <<= $contract3.starName>> +2 pop,@@ @@color:gold; +$500@@@@color:#4a9eff;, +1 rep@@<<set $contract3Success = false>><</if>> <<if $rivalOfferChallengeWon>>@@color:gold;🌟 <b><<= $rivalOfferStar>> chose to stay!</b> +1 popularity, +10 satisfaction@@<<set $rivalOfferChallengeWon = false>><</if>><<if $contract1Success>><<if $contractIsHarder>>📋 @@color:#4ade80;<b>Harder Contract completed!</b>@@ @@color:gold; +$1,500@@@@color:#4ade80;, +5 rep@@<<else>>📋 @@color:#4a9eff;<b>Contract completed!</b> +3 rep,@@ @@color:gold; +$500@@<</if>><<set $contract1Success = false>><<set $contractIsHarder = false>><</if>><<if $skillfulChallengeWon>>@@color:gold;⚡ Challenge completed! +5 reputation!@@<<set $player.reputation += 5>><<set $skillfulChallengeWon = false>><</if>><<if $popularityAlert>>@@color:gold;🌟 <b><<= $popularityAlert>></b> hit popularity 50 — they're a superstar!@@<<set $popularityAlert = "">><</if>><<if $bonusChoiceStar>>@@color:cyan;💖 <b><<= $bonusChoiceStar>></b> reached 30 satisfaction! She's learning to love a new position.@@<</if>> <<if $lastPopGain.length > 0>><<for _pgi = 0; _pgi < $lastPopGain.length; _pgi++>>🌟 <b class="gain-reveal glow-gold"><<= $lastPopGain[_pgi].name>> gained popularity! Now 🌟<<= $lastPopGain[_pgi].pop>></b><br><</for>><</if>> <b>Satisfaction after production:</b> <<= _w1.name>>: ❤️ <<= _w1.satisfaction>><<if _w1.restDay>> 😴<</if>><<if $advancedFormat && _w2>> | <<= _w2.name>>: ❤️ <<= _w2.satisfaction>><<if _w2.restDay>> 😴<</if>><</if>> <<set $selectedPositions = []>> <<if $roxyEventPending>>[[🌟 Special Event!|RoxyEvent]]<<elseif $bonusChoiceStar>>[[💖 Choose their bonus position|BonusPositionChoice]]<<else>>[[📊 Dashboard|Dashboard]] | [[📅 Next day|NextDay]]<</if>>
<h1 style="margin:0 0 0.4em 0;">🎯 New Objective!</h1> Your phone buzzes. An industry contact sends you a message: <em>"The market is watching. If you can't field a proper roster by Day 16, you'll be laughed out of the business. You need at least <b>3 talents</b> signed by then."</em> @@color:cyan;Progress: <<= $roster.length>>/3 talents signed@@ <<if $roster.length >= 3>> @@color:green;✅ You're already there — well done!@@ <<else>> @@color:orange;⚠️ You have until Day 16. Don't waste time.@@ <</if>> [[📊 Dashboard|Dashboard]] | [[👤 Recruit|Recruitment]]
<h1 style="margin:0 0 0.4em 0;">💀 Game Over</h1> You didn't manage to sign <b>3 talents</b> before <b>Day 16</b>. Without enough talent, your agency collapses. <<= $rival.name>> takes over the market. <em>"Should've moved faster."</em>
<<set $rep15EventPending = false>> <h1 style="margin:0 0 0.4em 0;">🌟 Reputation Milestone!</h1> You've reached reputation 15! Your agency is making waves. <<if $archetype is "rich">> Your accountant calls, sounding almost aroused by the numbers. <em>"The portfolio is performing beautifully. Just like your roster. Your returns just came in."</em> [[💰 Take $2,000|Rep15Rich1]] <<elseif $archetype is "skillful">> A trade daynalist reaches out. <em>"I've been watching your productions. If you can pull off a trending position in the next 3 days, I'll run a feature on your agency. That kind of exposure is worth a lot."</em> <b>Challenge:</b> use a trending position in a production within 3 days. [[✅ Accept the challenge|Rep15Skillful]] <<elseif $archetype is "charismatic">> Your talents gather before the shoot, half-dressed and glowing. <em>"You make us want to give everything. Every. Single. Time."</em> One of them steps closer. The room gets warm. <b>All your talents gain +5 satisfaction!</b> [[💖 Accept their gratitude|Rep15Charismatic]] <<elseif $archetype is "gambler">> A stranger leans against the wall outside, watching you with a smirk. <em>"You've got that look. Like you know how to play rough and win. Heads or tails — $3,000 says I win."</em> She flips a coin in the air and catches it. [[🪙 Heads|Rep15GamblerFlip][$gamblerChoice = "heads"]] [[🪙 Tails|Rep15GamblerFlip][$gamblerChoice = "tails"]] <</if>> /* ════════════════════════════════════════════ PASSAGE : Rep15GamblerFlip ════════════════════════════════════════════ */
<<set _flip = either("heads", "tails")>> <<if $gamblerChoice is _flip>> <h1 style="margin:0 0 0.4em 0;">🪙 You win!</h1> The coin lands your way. The stranger laughs and hands over the cash. <em>"Not bad. You've got luck on your side."</em> 💰 <b>+$3,000</b> added to your account! <<set $player.money += 3000>> <<else>> <h1 style="margin:0 0 0.4em 0;">🪙 You lose.</h1> The coin doesn't land your way. You shrug it off — that's the game. <em>"Better luck next time, friend."</em> <em>You walk away empty-handed.</em> <</if>> [[📊 Dashboard|Dashboard]] /* ════════════════════════════════════════════ PASSAGE : Rep15Rich1 ════════════════════════════════════════════ */
<<set $player.money += 2000>> 💰 <b>+$2,000</b> added to your account! [[📊 Dashboard|Dashboard]] /* ════════════════════════════════════════════ PASSAGE : Rep15Rich2 ════════════════════════════════════════════ */
<<set _stella = $recruitPool.find(function(w){ return w.name is "Eliza"; })>> <<if _stella>><<set _stella.repMin = 0>><</if>> 🌟 <b>Eliza</b> is now available in recruitment! <em>"I heard you've been doing great things. Let's talk."</em> [[👤 Go to Recruitment|Recruitment]] | [[📊 Dashboard|Dashboard]] /* ════════════════════════════════════════════ PASSAGE : Rep15Skillful ════════════════════════════════════════════ */
<<set $skillfulChallengeActive = true>> <<set $skillfulChallengeEndDay = $player.day + 3>> ⚡ Challenge active! Use a 'trending position' in a production before day <<= $skillfulChallengeEndDay>>. [[📊 Dashboard|Dashboard]] /* ════════════════════════════════════════════ PASSAGE : Rep15Charismatic ════════════════════════════════════════════ */
<<for _i = 0; _i < $roster.length; _i++>> <<set $roster[_i].satisfaction = Math.min(100, $roster[_i].satisfaction + 5)>> <</for>> <b>💖 All talents gain +5 satisfaction!</b> [[📊 Dashboard|Dashboard]]
<<set _os = $roster.find(function(w){ return w.name is $rivalOfferStar; })>> <h1 style="margin:0 0 0.4em 0;">💬 <<= $rivalOfferStar>> Has Something to Say</h1> <<set _roeFile = $rivalOfferStar.toLowerCase().replace(/ /g, "_")>> <div style="text-align:center;margin:10px 0;"><img data-portrait-var="_roeFile" style="width:160px;height:160px;object-fit:cover;border-radius:12px;box-shadow:0 4px 16px rgba(0,0,0,0.5);" src=""></div> <em>"Hey... I need to talk to you. <<= $rival.name>> reached out to me. They made me an offer."</em> <em>"They called me. Offered more shoots, better positions, more money. I turned them down... but I'd be lying if I said I wasn't tempted. I need to know you still want me — on set and off it."</em> <<if _os>> <b><<= _os.name>></b> — 🌟 Pop: <<= _os.popularity>> <em style="color:#888">(lowest in your roster)</em> | ❤️ Sat: <<= _os.satisfaction>> <b>Contract cost:</b> $<<= _os.contractCost.toLocaleString()>> | Severance if they leave: <b>$<<= Math.ceil(_os.contractCost * 0.5).toLocaleString()>></b> <</if>> [[🎬 Keep them — 3 productions in 4 days|RivalOfferKeep]] [[👋 Let them go|RivalOfferLeave]]
<<set $rivalOfferShootingsLeft = 3>> <<set $rivalOfferDeadlineDay = $player.day + 4>> <<set $rivalOfferEvent = false>> <<set _os = $roster.find(function(w){ return w.name is $rivalOfferStar; })>> <<if _os>><<set _os.consecutiveDays = 0>><<set _os.restDay = false>><</if>> <em>"Fine. But I want to feel wanted — on set and in front of that camera. Put me to work. Show me you still know what to do with me."</em> <b><<= $rivalOfferStar>></b> stays — you must feature them in <b>3 productions within 4 days</b>. If you do, they gain +1 popularity and +10 satisfaction. If you fail, they leave with no severance. [[📊 Dashboard|Dashboard]]
<<set _os = $roster.find(function(w){ return w.name is $rivalOfferStar; })>> <<set _severance = 0>> <<if _os>> <<set _severance = Math.ceil(_os.contractCost * 0.5)>> <<set $player.money += _severance>> <<set $rival.roster.push(clone(_os))>> <<run window.cleanupQuestlineForLostStar(_os.name)>> <<set $roster.delete(_os)>> <</if>> <<set $rivalOfferEvent = false>> <em>"I understand. Thanks for the opportunity."</em> @@color:red;<b><<= $rivalOfferStar>></b> has joined <<= $rival.name>>. Heard she couldn't stop smiling after her first day there.@@ <<if _severance > 0>>You receive <b>$<<= _severance.toLocaleString()>></b> in severance.<</if>> [[📊 Dashboard|Dashboard]]
<h1 style="margin:0 0 0.4em 0;">📰 A New Player on the Market</h1> An industry insider sends you an encrypted message. <em>"Heads up. There's a new studio that just incorporated — well-funded, aggressive, and they're already making calls. Word is they're going after the same talent pool as you and <<= $rival.name>>."</em> <em>"They don't have a name yet. But they will soon. And when they do, the market won't be the same."</em> This concerns both you and <<= $rival.name>>. The landscape is about to get more crowded. @@color:orange;⚠️ A third competitor is rising. Keep an eye on the market.@@ [[📊 Dashboard|Dashboard]]
<h1 style="margin:0 0 0.4em 0;">📰 Industry News</h1> A contact in the industry sends you a message. <em>"Heard through the grapevine that <<= $rival.name>> is having serious cash flow problems. Word is they might be forced to let some of their talents go soon — maybe as early as day 30. Could be an opportunity for you..."</em> <<if $rival.roster.length > 0>> Their current roster has <b><<= $rival.roster.length>> talent(s)</b>. Keep an eye on the situation. <<else>> <em>Looks like they don't have anyone right now anyway.</em> <</if>> [[📊 Dashboard|Dashboard]]
<<set _maxPop = 0>> <<for _i = 0; _i < $roster.length; _i++>> <<if $roster[_i].popularity > _maxPop>><<set _maxPop = $roster[_i].popularity>><</if>> <</for>> <<set _ri = random(0, $rival.roster.length - 1)>> <<set _rivalStar = $rival.roster[_ri]>> <h1 style="margin:0 0 0.4em 0;">💸 <<= $rival.name>> in Trouble!</h1> Rumours spread through the industry — <<= $rival.name>> has taken a massive financial hit. <em>"We're restructuring. Some contracts need to go."</em> <<set _rivalFile = _rivalStar.name.toLowerCase().replace(/ /g, "_")>> <div style="display:flex;align-items:flex-start;gap:16px;margin:12px 0;padding:12px;background:#111;border-radius:8px;"> <img data-portrait-var="_rivalFile" style="width:120px;height:120px;object-fit:cover;border-radius:10px;flex-shrink:0;" src=""> <div> <b style="font-size:1.05em;"><<= _rivalStar.name>></b><br> <em style="color:#888;"><<= _rivalStar.ageNum>> y.o. | <<= _rivalStar.hair>> | <<= _rivalStar.height>></em><br> <em style="color:#888;"><<= _rivalStar.breast>> (<<= _rivalStar.breastType>>) | <<= _rivalStar.ethnicity>></em><br> 💖 <<= _rivalStar.favPosition>><br> 🌟 Pop: <b><<= _maxPop>></b> <em style="color:#666;">(matched to your best)</em> </div> </div> <<set _discountPrice = Math.ceil(_rivalStar.contractCost * 0.5)>> 💳 Contract: <b>$<<= _discountPrice.toLocaleString()>></b> <em style="color:#888;">(50% off — rival's loss, your gain!)</em> <<capture _ri _rivalStar _maxPop _discountPrice>> <<if $player.money >= _discountPrice>> [[✅ Sign them|Day22Sign][$day22Idx = _ri, $day22Pop = _maxPop, $day22Price = _discountPrice]] [[❌ Pass|Dashboard]] <<else>> @@color:red;Not enough funds ($<<= _discountPrice.toLocaleString()>> required)@@ [[❌ Pass|Dashboard]] <</if>> <</capture>> /* ════════════════════════════════════════════ PASSAGE : Day22Sign ════════════════════════════════════════════ */
<<set _w = $rival.roster[$day22Idx]>> <<set _w.popularity = $day22Pop>> <<set _w.satisfaction = 10>> <<set _w.lastShootingDay = $player.day>> <<set _w.weekShootings = 0>> <<set _w.totalShootings = 0>> <<set _w.consecutiveDays = 0>> <<set _w.restDay = false>> <<set _w.joinedDay = $player.day>> <<set $player.money -= $day22Price>> <<set $roster.push(clone(_w))>> <<set $rival.roster.deleteAt($day22Idx)>> ✅ <b><<= _w.name>></b> joins your roster with popularity <b><<= $day22Pop>></b>! <em>"Glad to be somewhere stable for once."</em> [[📊 Dashboard|Dashboard]]
<h1 style="margin:0 0 0.4em 0;">📋 New Contract!</h1> <em>"We need 2 consecutive productions featuring a specific type of talent. Pick a brief that works for you."</em> <<if $contractIsHarder>><b>Reward:</b> +$1,500, +5 rep | <b>Fail:</b> −5 rep<<else>><b>Reward:</b> +3 rep, +$500 | <b>Fail:</b> −2 rep<</if>> <b>Your roster:</b> <div id="contract-roster-table"></div> <b>Choose a brief:</b> <<for _oi = 0; _oi < $contract1.options.length; _oi++>><<set _opt = $contract1.options[_oi]>><<set _hasEligible = false>><<for _ri = 0; _ri < $roster.length; _ri++>><<if $contractIsHarder && _opt.type2>><<if $roster[_ri][_opt.type] is _opt.value && $roster[_ri][_opt.type2] is _opt.value2>><<set _hasEligible = true>><</if>><<elseif $roster[_ri][_opt.type] is _opt.value>><<set _hasEligible = true>><</if>><</for>><<capture _oi _opt _hasEligible>><div style="margin:3px 0;padding:5px 10px;background:#111;border-radius:4px;"><<if $contractIsHarder && _opt.type2>><b><<= _opt.value>></b> <em style="color:#888">(<<= _opt.type>>)</em> + <b><<= _opt.value2>></b> <em style="color:#888">(<<= _opt.type2>>)</em><<else>><b><<= _opt.value>></b> <em style="color:#888">(<<= _opt.type>>)</em><</if>> <<if _hasEligible>>@@color:green;✅ you have one@@<<else>>@@color:red;⚠️ none@@<</if>> <<if $contractIsHarder && _opt.type2>>[[✅ Accept|Contract1Accept][$contract1.criteriaType = _opt.type, $contract1.criteria = _opt.value, $contract1.criteriaType2 = _opt.type2, $contract1.criteria2 = _opt.value2]]<<else>>[[✅ Accept|Contract1Accept][$contract1.criteriaType = _opt.type, $contract1.criteria = _opt.value]]<</if>></div><</capture>><</for>> [[❌ Refuse all|Contract1Refuse]] <<script>> jQuery(document).one(':passageend', function(){ buildStarTable(SugarCube.State.variables.roster, SugarCube.State.variables.trends, -1, 'contract-roster-table', function(){}, '<em>Roster empty.</em>', false, false, true); }); <</script>>
<<set $contract1.accepted = true>><<set $contract1.startDay = $player.day>><<set $contract1.shootingsDone = 0>><<set $contract1.active = false>> <b>Contract accepted!</b> You have <b>4 days</b> to complete 2 productions featuring <<if $contractIsHarder>>a <b><<= $contract1.criteria>></b> <<= $contract1.criteriaType>> AND <b><<= $contract1.criteria2>></b> <<= $contract1.criteriaType2>> talent.<<else>>a <b><<= $contract1.criteria>></b> <<= $contract1.criteriaType>> talent.<</if>> [[📊 Dashboard|Dashboard]]
<<set $contract1.active = false>> <<set $contractShopAvailableDay = $player.day + 1>> <em>"Understood. Maybe next time."</em> [[📊 Dashboard|Dashboard]]
<<set $contract1.failed = false>> <h1 style="margin:0 0 0.4em 0;">❌ Contract Failed</h1> @@color:red;You failed to complete the contract in time.@@ <<if $contractIsHarder>>The client is furious. <b>−5 reputation.</b><<else>>The client is disappointed. <b>−2 reputation.</b><</if>> [[📊 Dashboard|Dashboard]]
<<set $contract3.active = false>> <h1 style="margin:0 0 0.4em 0;">📋 Established Contract (⭐⭐)</h1> An independent producer reaches out. <em>"I've heard about your agency. I need a confirmed star for an urgent shoot — you have until day 44. If you accept, I'll advance you $1,000 now."</em> <em>"Any star from your Established pool (⭐⭐) will do."</em> <div style="padding:8px 12px;background:#111;border-radius:6px;font-size:0.85em;"> ⏳ Deadline: before <b>day 44</b> (<<= 44 - $player.day>> day(s) remaining)<br> ✅ Accepted: <b>+$1,000</b> advance<br> 🏆 Success: <b>+2 pop</b> on the star, <b>+$500</b>, <b>+1 rep</b><br> ❌ Fail: <b>−$2,000</b> </div> [[✅ Accept|Contract3Accept]] [[❌ Refuse|Contract3Refuse]]
<<set $contract3.accepted = true>> <<set $contract3.startDay = $player.day>> <<set $contract3.shootingsDone = 0>> <<set $contract3.failed = false>> <<set $contract3.active = false>> <<set $player.money += 1000>> ✅ Contract accepted! Advance of <b>+$1,000</b> received. Produce with a star from the <b>Established pool (⭐⭐)</b> before day 44. <em>If you fail, you will lose <b>$2,000</b>.</em> [[📊 Dashboard|Dashboard]]
<<set $contract3.active = false>> <em>"Too bad. I'll find someone else."</em> [[📊 Dashboard|Dashboard]]
<<set $contract4.active = false>> <<set $contract4.accepted = true>> <<set $contract4.shootingsDone = 0>> <<set $contract4.failed = false>> <h1 style="margin:0 0 0.4em 0;">💼 Investor Demand</h1> Your phone rings. It's your main investor — their tone is firm. <em>"We've been watching your agency closely. We need to see a production featuring one of our preferred talents before day 50. This isn't a request."</em> They name two stars: <div style="padding:10px;background:#111;border-radius:6px;margin:12px 0;"> ⭐⭐ <b><<= $contract4.star1>></b><<if $contract4.star2>> or ⭐⭐ <b><<= $contract4.star2>></b><</if>> </div> Neither is signed anywhere yet. Recruit one and shoot with her before <b>day 50</b> or face a <b>$2,000 penalty</b>. <em style="color:#888;font-size:0.85em;">Established-tier talent shows up more often when scouting once you've bought <b>Established Dip</b> or <b>Established Surge</b> in the Shop.</em> [[📊 Dashboard|Dashboard]] | [[👤 Recruit|Recruitment]]
<<set $contract4.failed = false>> <h1 style="margin:0 0 0.4em 0;">❌ Investor Demand Failed</h1> @@color:red;You failed to produce with the requested star before day 50.@@ The investors are furious. <b>−$2,000</b> [[📊 Dashboard|Dashboard]]
<<set $contract5.active = false>> <<set $contract5.accepted = true>> <<set $contract5.shootingsDone = 0>> <<set $contract5.failed = false>> <<set $contract5.startDay = $player.day>> <h1 style="margin:0 0 0.4em 0;">💎 Elite Demand</h1> Your phone rings again — a different investor this time, one who only calls when real money is on the table. <em>"Word is your agency is doing well. Well enough for this. We want a production with one of our elite picks. Within five days."</em> They name two stars: <div style="padding:10px;background:#111;border-radius:6px;margin:12px 0;"> ⭐⭐⭐ <b><<= $contract5.star1>></b><<if $contract5.star2>> or ⭐⭐⭐ <b><<= $contract5.star2>></b><</if>> </div> Neither is signed anywhere yet. Recruit one and shoot with her within <b>5 days</b> or face a <b>$4,000 penalty</b>. <em style="color:#888;font-size:0.85em;">Elite-tier talent shows up more often when scouting once you've bought <b>Elite Dip</b> or <b>Elite Surge</b> in the Shop.</em> [[📊 Dashboard|Dashboard]] | [[👤 Recruit|Recruitment]]
<<set $contract5.failed = false>> <h1 style="margin:0 0 0.4em 0;">❌ Elite Demand Failed</h1> @@color:red;You failed to produce with the requested star in time.@@ These investors don't forget. <b>−$4,000</b> [[📊 Dashboard|Dashboard]]
<<set $contract3.failed = false>> <h1 style="margin:0 0 0.4em 0;">❌ Established Contract Failed</h1> @@color:red;You didn't produce with <<= $contract3.starName>> before day 44.@@ The producer claims damages. <b>−$2,000</b> [[📊 Dashboard|Dashboard]]
<h1 style="margin:0 0 0.4em 0;">🌟 A Visitor Arrives</h1> Word's been getting around about your agency. Your phone rings. <em>"Hey... is this <<= $player.name>>? Yeah, I've been watching your productions. Your talents look like they're actually having fun out there. That's... rare."</em> <em>"I'm <<= $bonusEventStar>>. I've done some work here and there — private shoots mostly. I know how to perform, and I know how to make people watch. I just need the right director."</em> <em>"Give me a chance. I'll make it worth your while."</em> <<set _roxy = $recruitPool.find(function(w){ return w.name is $bonusEventStar; })>> <<set _roxyFile = $bonusEventStar.toLowerCase().replace(/ /g, "_")>> <<if _roxy>> <div style="display:flex;align-items:flex-start;gap:16px;margin:12px 0;padding:12px;background:#111;border-radius:8px;"> <img data-portrait-var="_roxyFile" style="width:130px;height:130px;object-fit:cover;border-radius:10px;flex-shrink:0;" src=""> <div> <b style="font-size:1.05em;"><<= $bonusEventStar>></b><br> <em style="color:#888;"><<= _roxy.hair>> | <<= _roxy.height>> | <<= _roxy.ageCat>> (<<= _roxy.ageNum>>)</em><br> 🎭 Tits: <<= _roxy.breast>> (<<= _roxy.breastType>>) | 🌟 Popularity: <<= _roxy.popularity>> 💖 Favorite position: <<= _roxy.favPosition>><br> 💳 Contract: <b>$<<= _roxy.contractCost.toLocaleString()>></b><br> 🔄 Upkeep: <b>$<<= (_roxy.popularity * 70).toLocaleString()>>/week</b> </div> </div> <<if $player.money >= _roxy.contractCost>> [[✅ Sign them|SignRoxy]] [[❌ Pass|RoxyDecline]] <<else>> @@color:red;Not enough funds ($<<= _roxy.contractCost.toLocaleString()>> required)@@ <em>"Guess you can't afford me right now..."</em> [[⬅️ She walks away|RoxyDecline]] <</if>> <</if>> /* ════════════════════════════════════════════ PASSAGE : SignRoxy ════════════════════════════════════════════ */
<<set _roxy = $recruitPool.find(function(w){ return w.name is $bonusEventStar; })>> <<if _roxy>> <<set _roxy.available = false>> <<set _roxy.lastShootingDay = $player.day>> <<set _roxy.joinedDay = $player.day>> <<set $player.money -= _roxy.contractCost>> <<set $roster.push(clone(_roxy))>> <</if>> <<set $roxyEventPending = false>> ✅ <b><<= $bonusEventStar>></b> joins your roster! <em>She leans in close enough that you catch her perfume. "I've been watching your work. I know exactly what you want from me." A slow smile. "I won't let you down."</em> [[📊 Dashboard|Dashboard]] /* ════════════════════════════════════════════ PASSAGE : RoxyDecline ════════════════════════════════════════════ */
<<set _roxy = $recruitPool.find(function(w){ return w.name is $bonusEventStar; })>> <<if _roxy>> <<set _roxy.available = false>> <<set $rival.roster.push(clone(_roxy))>> <</if>> <<set $roxyEventPending = false>> <em>She gives you one last look — up and down, slow. "Their loss is someone else's gain." She picks up her bag, hips swaying on the way out. "<<= $rival.name>> already called. Twice."</em> @@color:red;⚠️ <<= $bonusEventStar>> has joined <<= $rival.name>>!@@ [[📊 Dashboard|Dashboard]] /* ════════════════════════════════════════════ PASSAGE : BonusPositionChoice ════════════════════════════════════════════ */
<<set _bw = $roster.find(function(w){ return w.name is $bonusChoiceStar; })>> <h1 style="margin:0 0 0.4em 0;">💖 A New Favorite!</h1> <b><<= $bonusChoiceStar>></b> pulls you aside after the shoot, cheeks flushed. <em>"I didn't expect to enjoy that so much... I think I've found something new I really love."</em> She's discovered a second favorite position. What does she want to try? <<if _bw>> <<capture _bw>> <<link `_bw.bonusPosition1`>><<set $bonusPositionChosen = _bw.bonusPosition1>><<goto "ApplyBonusPosition">><</link>> | <<link `_bw.bonusPosition2`>><<set $bonusPositionChosen = _bw.bonusPosition2>><<goto "ApplyBonusPosition">><</link>> <</capture>> <</if>>
<<set _bw = $roster.find(function(w){ return w.name is $bonusChoiceStar; })>> <<if _bw>> <<set _bw.favPosition2 = $bonusPositionChosen>> <<set _bw.bonusChosen = true>> <</if>> ✅ <b><<= $bonusChoiceStar>></b> now also loves <b><<= $bonusPositionChosen>></b>! <<set $bonusChoiceStar = "">> [[📊 Dashboard|Dashboard]] | [[📅 Next day|NextDay]] /* ════════════════════════════════════════════ PASSAGE : Day30Event ════════════════════════════════════════════ */
<<set _minSat = 9999>><<set _minIdx = -1>><<for _i = 0; _i < $roster.length; _i++>><<if $roster[_i].satisfaction < _minSat>><<set _minSat = $roster[_i].satisfaction>><<set _minIdx = _i>><</if>><</for>><<if _minIdx >= 0>><<set $roster[_minIdx].satisfaction = Math.max(0, $roster[_minIdx].satisfaction - 5)>><<set _contactedStar = $roster[_minIdx].name>><<set _portraitFile = $roster[_minIdx].name.toLowerCase().replace(/ /g, "_")>><<else>><<set _contactedStar = "one of your talents">><</if>><h1 style="margin:0 0 0.4em 0;">📞 <<= $rival.name>> Makes a Move</h1> <<if _minIdx >= 0>><div style="text-align:center;margin:6px 0;"><img data-portrait-var="_portraitFile" style="width:140px;height:140px;object-fit:cover;border-radius:10px;box-shadow:0 4px 12px rgba(0,0,0,0.5);" src=""></div><</if>> Your phone rings — unknown number. You pick up. <em>"Hello. I'm reaching out on behalf of <<= $rival.name>>. We've been watching your agency and... well, we think some of your talent deserves better opportunities."</em> The call ends before you can respond. <<= _contactedStar>> looks distracted at the next shoot. Something's on their mind. When you ask, they're honest. <em>"They called me. Said they'd let me do things you never put me in. Rougher. Longer. No limits. I said no... but my body wasn't so sure."</em> @@color:red;⚠️ <b><<= _contactedStar>></b> was contacted by <<= $rival.name>> and hesitated. <b>−5 satisfaction.</b>@@ [[📊 Dashboard|Dashboard]] /* ════════════════════════════════════════════ PASSAGE : BNOEvent ════════════════════════════════════════════ */
<h1 style="margin:0 0 0.4em 0;">🏢 A New Player Enters the Market</h1> Your phone blows up with notifications: <em>"Breaking: A major investment group has acquired <<= $rival.name>> and all its assets. The studio will be rebranded immediately under new management."</em> <em>"Their talent roster has been absorbed and put straight to work. Word is the first shoots under the new banner were intense — the kind that trend for weeks. Well-funded, aggressive, and hungry."</em> @@color:red;⚠️ All talents with satisfaction below 40 lose <b>5 satisfaction</b> immediately.@@ <<silently>><<for _i = 0; _i < $roster.length; _i++>><<if $roster[_i].satisfaction < 40>><<set $roster[_i].satisfaction = Math.max(0, $roster[_i].satisfaction - 5)>><</if>><</for>><<set $rivalOriginalName = $rival.name>><</silently>> <b>What is the new studio called?</b> <<textbox "$rival.name" "BNO">> <br> [[✅ Confirm|BNOConfirm]]
<<set $rivalVideoPrefix = "b_">> <h1 style="margin:0 0 0.4em 0;">🏢 <<= $rival.name>> — The New Rival</h1> The takeover is official. <<= $rival.name>> inherits the full roster and reputation of the old studio. Roster: <b><<= $rival.roster.length>> star(s)</b> | Reputation: <b>🌟 <<= $rival.reputation>></b> <em>"This city just got a lot more competitive."</em> [[📊 Dashboard|Dashboard]]
<<set $questlines.asianDuo.step2Notified = true>> <h1 style="margin:0 0 0.4em 0;">🎌 Asian Duo — Step 2</h1> <<set _as2File = $questlines.asianDuo.star1.toLowerCase().replace(/ /g, "_")>> <div style="text-align:center;margin:10px 0;"><img data-portrait-var="_as2File" style="width:160px;height:160px;object-fit:cover;border-radius:12px;box-shadow:0 4px 16px rgba(0,0,0,0.5);" src=""></div> <b><<= $questlines.asianDuo.star1>></b> lingers in your doorway longer than usual today, like she's been building up to something. When she finally speaks, she doesn't quite meet your eyes. <em>"So... there's someone I used to work with. Before I came here. We did a couple of scenes together, back when I was still figuring out what I actually liked." A small, private smile. "We were good together. Really good. I don't think either of us ever said so out loud, but... I think about her more than I probably should."</em> She slides a folded piece of paper across your desk — a name, scrawled in her own handwriting, like she wrote it three times before deciding to actually hand it over. <em>"I'm not asking you to sign her because of me. I'm asking because she's talented, and because this agency deserves to see what we used to be like together." A pause. "But yeah. Also because of me."</em> You know what you have to do. @@color:cyan;➡️ Recruit <<= ($questlines.asianDuo.star1 is "Kimmy") ? "Lulu" : "Kimmy">> to continue the questline.@@ [[📊 Dashboard|Dashboard]] | [[👤 Recruitment|Recruitment]]
<<set $questlines.asianDuo.step3Notified = true>> <h1 style="margin:0 0 0.4em 0;">🎌 Asian Duo — Step 3</h1> <<set _as3File = $questlines.asianDuo.star2.toLowerCase().replace(/ /g, "_")>> <div style="text-align:center;margin:10px 0;"><img data-portrait-var="_as3File" style="width:160px;height:160px;object-fit:cover;border-radius:12px;box-shadow:0 4px 16px rgba(0,0,0,0.5);" src=""></div> The front door opens and <b><<= $questlines.asianDuo.star2>></b> steps through it like she owns the place — confident, unhurried, scanning the studio until her eyes land on <<= $questlines.asianDuo.star1>> across the room. <<= $questlines.asianDuo.star1>> goes still. <em>"Well, well." Her voice carries just enough to reach across the floor. "Look who finally found somewhere decent to work."</em> <em>"Look who finally decided to call." Arms crossed, fighting a smile she clearly doesn't want to give away that easily.</em> They meet in the middle of the room. Nobody else in the studio seems to notice the way the air changes, but you do. Whatever history these two have, it didn't end — it just paused. <em>"We meet again," comes the reply, closer now, quieter now.</em> <em>"Took you long enough."</em> They hold each other's gaze a beat too long for two people who are supposedly just old coworkers. @@color:cyan;➡️ Get <<= $questlines.asianDuo.star2>> to 25 satisfaction.@@ [[📊 Dashboard|Dashboard]]
<<set $questlines.asianDuo.step4Notified = true>> <h1 style="margin:0 0 0.4em 0;">🎌 Asian Duo — Special Shooting Unlocked!</h1> <<set _as4aFile = $questlines.asianDuo.star1.toLowerCase().replace(/ /g, "_")>><<set _as4bFile = $questlines.asianDuo.star2.toLowerCase().replace(/ /g, "_")>> <div style="text-align:center;margin:10px 0;display:flex;justify-content:center;gap:12px;"><img data-portrait-var="_as4aFile" style="width:140px;height:140px;object-fit:cover;border-radius:12px;box-shadow:0 4px 16px rgba(0,0,0,0.5);" src=""><img data-portrait-var="_as4bFile" style="width:140px;height:140px;object-fit:cover;border-radius:12px;box-shadow:0 4px 16px rgba(0,0,0,0.5);" src=""></div> A few days pass. You notice them together more and more between shoots — heads bent close over a script, laughing at something only they understand, a hand resting a little too naturally on a shoulder. Today, <b><<= $questlines.asianDuo.star2>></b> comes to see you, <b><<= $questlines.asianDuo.star1>></b> right behind her, practically buzzing. <em>Lulu slides in behind Kimmy, lips at her ear, loud enough for you to hear. "We've been talking. About what we want to do together. On camera."</em> <em>Kimmy bites her lip, cheeks flushed. "All of it. Everything we never got to finish."</em> They both look at you at the same time, like they'd rehearsed it. <em>"We're ready."</em> The air in the room shifts. Whatever happens next, the camera is going to love it. @@color:gold;🌟 Asian Duo Special Shooting now available in the menu!@@ [[📊 Dashboard|Dashboard]]
<<set _kimmy = $roster.find(function(w){ return w.name is "Kimmy"; })>> <<set _lulu = $roster.find(function(w){ return w.name is "Lulu"; })>> <<if _kimmy>><<set _kimmy.popularity += 2>><<set _kimmy.lastShootingDay = $player.day>><</if>> <<if _lulu>><<set _lulu.popularity += 2>><<set _lulu.lastShootingDay = $player.day>><</if>> <<set $player.money += 1500>> <<set $player.reputation += 2>> <<set $questlines.asianDuo.shooting1Done = true>> <<set $shootingPlayedToday = true>> <<set $asianDuoShoot1Day = $player.day>> <h1 style="margin:0 0 0.4em 0;">🎬 Asian Duo — Collab 1</h1> <div style="text-align:center;margin:12px 0;display:flex;justify-content:center;gap:12px;"> <<set _kFile = "kimmy">><<set _lFile = "lulu">> <img data-portrait-var="_kFile" style="width:140px;height:140px;object-fit:cover;border-radius:12px;box-shadow:0 4px 16px rgba(0,0,0,0.5);" src=""> <img data-portrait-var="_lFile" style="width:140px;height:140px;object-fit:cover;border-radius:12px;box-shadow:0 4px 16px rgba(0,0,0,0.5);" src=""> </div> <div id="asianduo1-video-wrap" style="text-align:center;"></div><<script>>jQuery(document).one(':passageend',function(){var el=document.getElementById('asianduo1-video-wrap');if(!el)return;var v=document.createElement('video');v.src='videos/kimmy_lulu_collab.webm';v.autoplay=true;v.loop=true;v.muted=true;v.playsInline=true;v.controls=true;v.style.width='100%';v.style.maxWidth='480px';v.style.borderRadius='8px';v.style.marginTop='8px';v.onerror=function(){this.style.display='none';};el.appendChild(v);});<</script>> Nobody calls for rehearsal. They don't need one. <em>The moment the cameras roll, years of almost-forgotten muscle memory take over. Kimmy's hands find Lulu instinctively — like her body remembers exactly where they used to leave off. Lips, hips, every movement synchronized in a way that can't be choreographed, only rediscovered.</em> <em>Between breaths, Lulu murmurs something only Kimmy can hear. Whatever it is, it makes her laugh — soft, real, nothing like a performance.</em> The crew stops pretending to work and just watches. Nobody calls cut until the tape runs out. This is what the audience has been waiting for — and neither of them wanted it to end. @@color:gold;🌟 Kimmy & Lulu: +2 popularity each@@ @@color:gold;💰 +$1,500 earnings@@ @@color:gold;🌟 +2 reputation@@ <em>A second special shooting will be available!</em> [[📊 Dashboard|Dashboard]] | [[🌟 Special Shootings|SpecialShootingMenu]]
<<set _kimmy = $roster.find(function(w){ return w.name is "Kimmy"; })>> <<set _lulu = $roster.find(function(w){ return w.name is "Lulu"; })>> <<if _kimmy>><<set _kimmy.popularity += 3>><<set _kimmy.lastShootingDay = $player.day>><</if>> <<if _lulu>><<set _lulu.popularity += 3>><<set _lulu.lastShootingDay = $player.day>><</if>> <<set $player.money += 3000>> <<set $player.reputation += 3>> <<set $questlines.asianDuo.shooting2Done = true>> <<set $shootingPlayedToday = true>> <<set $asianDuoLastShootingDay = $player.day>> <h1 style="margin:0 0 0.4em 0;">🎬 Asian Duo — Collab 2</h1> <div style="text-align:center;margin:12px 0;display:flex;justify-content:center;gap:12px;"> <<set _kFile = "kimmy">><<set _lFile = "lulu">> <img data-portrait-var="_kFile" style="width:140px;height:140px;object-fit:cover;border-radius:12px;box-shadow:0 4px 16px rgba(0,0,0,0.5);" src=""> <img data-portrait-var="_lFile" style="width:140px;height:140px;object-fit:cover;border-radius:12px;box-shadow:0 4px 16px rgba(0,0,0,0.5);" src=""> </div> <div id="asianduo2-video-wrap" style="text-align:center;"></div><<script>>jQuery(document).one(':passageend',function(){var el=document.getElementById('asianduo2-video-wrap');if(!el)return;var v=document.createElement('video');v.src='videos/kimmy_lulu_special2.webm';v.autoplay=true;v.loop=true;v.muted=true;v.playsInline=true;v.controls=true;v.style.width='100%';v.style.maxWidth='480px';v.style.borderRadius='8px';v.style.marginTop='8px';v.onerror=function(){this.style.display='none';};el.appendChild(v);});<</script>> There's no script this time, and nobody asks for one. <em>Lulu pins Kimmy against the sheets and takes control — slow at first, savoring it, then relentless, like she's making up for every year they spent apart. Kimmy doesn't fight it for a second; she just holds on and lets it happen.</em> <em>Their chemistry, already dangerous on day one, has cured into something almost primal by now — two people who know each other's bodies better than their own.</em> The scene runs nearly forty minutes and nobody on set calls cut. When it's finally over, Lulu presses her forehead to Kimmy's and just breathes for a moment before either of them moves. Whatever they had before, they've found it again — and this time, it's all on camera, and it's all yours. @@color:gold;🌟 Kimmy & Lulu: +3 popularity each@@ @@color:gold;💰 +$3,000 earnings@@ @@color:gold;🌟 +3 reputation@@ @@color:gold;🎌 Asian Duo questline complete!@@ [[📊 Dashboard|Dashboard]]
<h1 style="margin:0 0 0.4em 0;">🎌 Asian Duo — Good News</h1> <div style="display:flex;justify-content:center;gap:12px;margin:10px 0;"> <img src="img/portraits/kimmy.jpg" style="width:100px;height:100px;object-fit:cover;border-radius:10px;"> <img src="img/portraits/lulu.jpg" style="width:100px;height:100px;object-fit:cover;border-radius:10px;"> </div> Kimmy and Lulu stop by your office together — an unusual thing in itself, since they usually find separate excuses to linger. Today they're not hiding it. <em>"We loved the first one." Lulu leans against the doorframe, arms loosely around Kimmy from behind. "We'd like to do another. A real one this time — no holding back."</em> <em>Kimmy just nods, a little breathless already, like she's been thinking about it since the last scene wrapped.</em> @@color:gold;🎌 Second special shooting now available!@@ [[⭐ Special Shootings|SpecialShootingMenu]] | [[📊 Dashboard|Dashboard]]
<h1 style="margin:0 0 0.4em 0;">👼 Two Fallen Angels — Good News</h1> <div style="display:flex;justify-content:center;gap:12px;margin:10px 0;"> <img src="img/portraits/angie.jpg" style="width:100px;height:100px;object-fit:cover;border-radius:10px;"> <img src="img/portraits/angela.jpg" style="width:100px;height:100px;object-fit:cover;border-radius:10px;"> </div> Angie and Angela reach out together this time — not one messenger for the other, both of them standing in your doorway like it's already decided. <em>"That was something special." Angela speaks first, but Angie's nodding before she even finishes. "We want to do it again. We're not done catching up."</em> @@color:gold;👼 Second special shooting now available!@@ [[⭐ Special Shootings|SpecialShootingMenu]] | [[📊 Dashboard|Dashboard]]
<h1 style="margin:0 0 0.4em 0;">👼 Two Fallen Angels — One More</h1> <div style="display:flex;justify-content:center;gap:12px;margin:10px 0;"> <img src="img/portraits/angie.jpg" style="width:100px;height:100px;object-fit:cover;border-radius:10px;"> <img src="img/portraits/angela.jpg" style="width:100px;height:100px;object-fit:cover;border-radius:10px;"> </div> They don't even bother knocking this time. <em>"We're not done yet." Angie says it like a fact, not a request. "One more. The real finale — everything we've been building toward."</em> <em>Angela just smiles behind her, already halfway out of her jacket.</em> @@color:gold;👼 Third special shooting now available!@@ [[⭐ Special Shootings|SpecialShootingMenu]] | [[📊 Dashboard|Dashboard]]
<<set $questlines.fallenAngels.step2Notified = true>> <h1 style="margin:0 0 0.4em 0;">👼 Two Fallen Angels — Step 2</h1> <<set _fa2pFile = $questlines.fallenAngels.star1.toLowerCase().replace(/ /g, "_")>> <div style="text-align:center;margin:10px 0;"><img data-portrait-var="_fa2pFile" style="width:160px;height:160px;object-fit:cover;border-radius:12px;box-shadow:0 4px 16px rgba(0,0,0,0.5);" src=""></div> <b><<= $questlines.fallenAngels.star1>></b> catches you in the hallway between shoots, waiting until no one else is close enough to hear. <em>"There's someone I used to work with. Years ago now — before either of us really knew what we were doing." A faraway look crosses her face, half-fond, half-something else. "We had something special on set. The kind of chemistry you don't forget, even when you try to."</em> <em>"I think you should meet her." A beat. "I think I need you to meet her, honestly."</em> She doesn't wait for you to respond before walking off, like she's already said more than she meant to. @@color:cyan;➡️ Recruit <<= ($questlines.fallenAngels.star1 is "Angie") ? "Angela" : "Angie">> to continue.@@ [[📊 Dashboard|Dashboard]] | [[👤 Recruitment|Recruitment]]
<<set $questlines.fallenAngels.step3Notified = true>> <h1 style="margin:0 0 0.4em 0;">👼 Two Fallen Angels — Step 3</h1> <<set _fa3pFile = $questlines.fallenAngels.star2.toLowerCase().replace(/ /g, "_")>> <div style="text-align:center;margin:10px 0;"><img data-portrait-var="_fa3pFile" style="width:160px;height:160px;object-fit:cover;border-radius:12px;box-shadow:0 4px 16px rgba(0,0,0,0.5);" src=""></div> The studio door opens and <b><<= $questlines.fallenAngels.star2>></b> walks in, sunglasses pushed up into her hair, looking around like she's trying to place the space. Then she sees <<= $questlines.fallenAngels.star1>>, and everything about her posture changes. For a moment, neither of them says anything. The two just look at each other — something unspoken passing between them, years of history compressed into a single held breath. <em>"I didn't think I'd see you again," she finally says, quieter than you'd expect from someone who just walked in like she owned the room.</em> <em>"Neither did I." The reply cracks just slightly on the second word.</em> Whatever happened between them back then, it clearly never got resolved. @@color:cyan;➡️ Get <<= $questlines.fallenAngels.star2>> to 25 satisfaction.@@ [[📊 Dashboard|Dashboard]]
<<set $questlines.fallenAngels.step4Notified = true>> <h1 style="margin:0 0 0.4em 0;">👼 Two Fallen Angels — Special Shooting Unlocked!</h1> <<set _fa4aF = $questlines.fallenAngels.star1.toLowerCase().replace(/ /g, "_")>> <<set _fa4bF = $questlines.fallenAngels.star2.toLowerCase().replace(/ /g, "_")>> <div style="display:flex;justify-content:center;gap:12px;margin:12px 0;"> <img data-portrait-var="_fa4aF" style="width:140px;height:140px;object-fit:cover;border-radius:12px;" src=""> <img data-portrait-var="_fa4bF" style="width:140px;height:140px;object-fit:cover;border-radius:12px;" src=""> </div> You almost don't see them coming — Angie grabs Angela's hand and pulls her forward before you can even greet them. <em>"We didn't sleep last night." Her voice is rough, like she means it literally. "Too busy remembering."</em> <em>Angela's cheeks are flushed, but she doesn't look away. "We know exactly what we want to shoot. All of it. Every scene we should've done back then and never got to." A small, nervous laugh. "And we want you to watch."</em> There's a decade of unfinished business standing in your office, and it's about to become very, very finished. @@color:gold;👼 Three special shootings now available!@@ [[📊 Dashboard|Dashboard]]
<<set _fa1a = $roster.find(function(w){ return w.name is "Angie"; })>> <<set _fa1b = $roster.find(function(w){ return w.name is "Angela"; })>> <<if _fa1a>><<set _fa1a.popularity += 2>><<set _fa1a.lastShootingDay = $player.day>><</if>> <<if _fa1b>><<set _fa1b.popularity += 2>><<set _fa1b.lastShootingDay = $player.day>><</if>> <<set $player.money += 1500>><<set $player.reputation += 2>> <<set $questlines.fallenAngels.shooting1Done = true>><<set $shootingPlayedToday = true>> <<set $fallenAngelsShoot1Day = $player.day>> <h1 style="margin:0 0 0.4em 0;">👼 Two Fallen Angels — Collab 1</h1> <div style="display:flex;justify-content:center;gap:12px;margin:12px 0;"> <img src="img/portraits/angie.jpg" style="width:140px;height:140px;object-fit:cover;border-radius:12px;"> <img src="img/portraits/angela.jpg" style="width:140px;height:140px;object-fit:cover;border-radius:12px;"> </div> <div id="fashoot1-video-wrap" style="text-align:center;"></div><<script>>jQuery(document).one(':passageend',function(){var el=document.getElementById('fashoot1-video-wrap');if(!el)return;var v=document.createElement('video');v.src='videos/FallenAngelsShoot1.webm';v.autoplay=true;v.loop=true;v.muted=true;v.playsInline=true;v.controls=true;v.style.width='100%';v.style.maxWidth='480px';v.style.borderRadius='8px';v.style.marginTop='8px';v.onerror=function(){this.style.display='none';};el.appendChild(v);});<</script>> Ten years apart, and their bodies remember everything. <em>Angie traces every curve of her like she never actually left — like the years in between were just a long pause, not an ending. Angela gasps under her hands, and for the first time in longer than she'd admit, it isn't performance. It's real, and it catches her off guard.</em> <em>Somewhere between the first take and the last, the years between them stop mattering. There's only the two of them, and everything they never got to finish.</em> The crew barely breathes. Nobody wants to be the one who calls cut on this. @@color:gold;🌟 Angie & Angela: +2 pop each | 💰 +$1,500 | 🌟 +2 rep@@ [[📊 Dashboard|Dashboard]] | [[🌟 Special Shootings|SpecialShootingMenu]]
<<set _fa2a = $roster.find(function(w){ return w.name is "Angie"; })>> <<set _fa2b = $roster.find(function(w){ return w.name is "Angela"; })>> <<if _fa2a>><<set _fa2a.popularity += 3>><<set _fa2a.lastShootingDay = $player.day>><</if>> <<if _fa2b>><<set _fa2b.popularity += 3>><<set _fa2b.lastShootingDay = $player.day>><</if>> <<set $player.money += 3000>><<set $player.reputation += 3>> <<set $questlines.fallenAngels.shooting2Done = true>><<set $shootingPlayedToday = true>> <<set $fallenAngelsShoot2Day = $player.day>> <h1 style="margin:0 0 0.4em 0;">👼 Two Fallen Angels — Collab 2</h1> <div style="display:flex;justify-content:center;gap:12px;margin:12px 0;"> <img src="img/portraits/angie.jpg" style="width:140px;height:140px;object-fit:cover;border-radius:12px;"> <img src="img/portraits/angela.jpg" style="width:140px;height:140px;object-fit:cover;border-radius:12px;"> </div> <div id="fashoot2-video-wrap" style="text-align:center;"></div><<script>>jQuery(document).one(':passageend',function(){var el=document.getElementById('fashoot2-video-wrap');if(!el)return;var v=document.createElement('video');v.src='videos/FallenAngelsShoot2.webm';v.autoplay=true;v.loop=true;v.muted=true;v.playsInline=true;v.controls=true;v.style.width='100%';v.style.maxWidth='480px';v.style.borderRadius='8px';v.style.marginTop='8px';v.onerror=function(){this.style.display='none';};el.appendChild(v);});<</script>> They've found their rhythm again, and this time there's no hesitation left to work through. <em>Angela on top, Angie pulling her down by the hips — sweat, urgency, zero pretense. Every motion says the same thing: we should have done this years ago.</em> <em>The director doesn't say a word through the entire scene. There's nothing left to direct. They're not performing anymore — they're just finally finishing what they started a decade ago.</em> @@color:gold;🌟 Angie & Angela: +3 pop each | 💰 +$3,000 | 🌟 +3 rep@@ [[📊 Dashboard|Dashboard]] | [[🌟 Special Shootings|SpecialShootingMenu]]
<<set _fa3a = $roster.find(function(w){ return w.name is "Angie"; })>> <<set _fa3b = $roster.find(function(w){ return w.name is "Angela"; })>> <<if _fa3a>><<set _fa3a.popularity += 3>><<set _fa3a.lastShootingDay = $player.day>><</if>> <<if _fa3b>><<set _fa3b.popularity += 3>><<set _fa3b.lastShootingDay = $player.day>><</if>> <<set $player.money += 3000>><<set $player.reputation += 3>> <<set $questlines.fallenAngels.shooting3Done = true>><<set $shootingPlayedToday = true>> <<set $fallenAngelsLastShootingDay = $player.day>> <h1 style="margin:0 0 0.4em 0;">👼 Two Fallen Angels — Final Act</h1> <div style="display:flex;justify-content:center;gap:12px;margin:12px 0;"> <img src="img/portraits/angie.jpg" style="width:140px;height:140px;object-fit:cover;border-radius:12px;"> <img src="img/portraits/angela.jpg" style="width:140px;height:140px;object-fit:cover;border-radius:12px;"> </div> <div id="fashoot3-video-wrap" style="text-align:center;"></div><<script>>jQuery(document).one(':passageend',function(){var el=document.getElementById('fashoot3-video-wrap');if(!el)return;var v=document.createElement('video');v.src='videos/FallenAngelsShoot3.webm';v.autoplay=true;v.loop=true;v.muted=true;v.playsInline=true;v.controls=true;v.style.width='100%';v.style.maxWidth='480px';v.style.borderRadius='8px';v.style.marginTop='8px';v.onerror=function(){this.style.display='none';};el.appendChild(v);});<</script>> The finale. Both of them completely unguarded — no performance, no filters, nothing held back for the camera's benefit. <em>Angela buries her face in Angie's neck near the end and whispers something the mic barely catches — three words, maybe four. Whatever it is, it isn't for the audience.</em> <em>Angie's answer is just to hold her tighter.</em> The crew watches in silence. Nobody moves when it's over — not the cameramen, not the assistants, not even you. A decade of unfinished business, closed for good, in front of everyone and yet somehow completely private. @@color:gold;🌟 Angie & Angela: +3 pop each | 💰 +$3,000 | 🌟 +3 rep@@ @@color:gold;👼 Two Fallen Angels questline complete!@@ [[📊 Dashboard|Dashboard]]
<<if $contract3rdOptionItem.bought>> Already purchased. [[⬅️ Dashboard|Dashboard]] <<elseif $player.money < $contract3rdOptionItem.price>> @@color:red;Not enough funds ($<<= $contract3rdOptionItem.price>> required).@@ [[⬅️ Shop|Shop]] <<else>> <<set $player.money -= $contract3rdOptionItem.price>> <<set $contract3rdOptionItem.bought = true>> ✅ <b>3rd Option</b> purchased! Contracts now offer 3 choices instead of 2. [[🛒 Shop|Shop]] | [[📊 Dashboard|Dashboard]] <</if>>
<<if $contractHarderItem.bought>> Already purchased. [[⬅️ Dashboard|Dashboard]] <<elseif !$contract3rdOptionItem.bought>> @@color:red;Requires 3rd Option first.@@ [[⬅️ Shop|Shop]] <<elseif $player.money < $contractHarderItem.price>> @@color:red;Not enough funds ($<<= $contractHarderItem.price>> required).@@ [[⬅️ Shop|Shop]] <<else>> <<set $player.money -= $contractHarderItem.price>> <<set $contractHarderItem.bought = true>> ✅ <b>Harder Contract</b> purchased! You can now buy harder contracts for $500 with double stat criteria — higher reward, higher risk. [[🛒 Shop|Shop]] | [[📊 Dashboard|Dashboard]] <</if>>
<<if !$contractHarderItem.bought>> @@color:red;Harder Contract upgrade not purchased yet.@@ [[⬅️ Dashboard|Dashboard]] <<elseif $player.money < 500>> @@color:red;Not enough funds ($500 required).@@ [[⬅️ Dashboard|Dashboard]] <<else>> <<set $player.money -= 500>> <<set _pool = ["hair:Brown","hair:Brown","hair:Blonde","hair:Blonde","hair:Black","hair:Black", "height:Short","height:Tall","height:Medium", "ageCat:Young","ageCat:Veteran","ageCat:Neutral", "breast:Small","breast:Small","breast:Large","breast:Large","breast:Huge","breast:Huge","breast:Medium", "breastType:Fake","breastType:Fake","breastType:Fake","breastType:Real", "ethnicity:Latina","ethnicity:Latina","ethnicity:Asian","ethnicity:Asian","ethnicity:Black","ethnicity:Caucasian"]>> <<set _options = []>> <<set _numOptions = $contract3rdOptionItem.bought ? 3 : 2>> <<set $contractIsHarder = true>> <<set _usedTypes = []>> <<for _oi = 0; _oi < _numOptions; _oi++>> <<set _availPool = _pool.filter(function(p){ return _usedTypes.indexOf(p.split(":")[0]) === -1; })>> <<set _pick = _availPool[random(0, _availPool.length - 1)]>> <<set _ct = _pick.split(":")[0]>> <<set _cv = _pick.split(":")[1]>> <<set _usedTypes.push(_ct)>> <<set _pool2 = _pool.filter(function(p){ return _usedTypes.indexOf(p.split(":")[0]) === -1; })>> <<set _pick2 = _pool2[random(0, _pool2.length - 1)]>> <<set _ct2 = _pick2.split(":")[0]>> <<set _cv2 = _pick2.split(":")[1]>> <<set _usedTypes.push(_ct2)>> <<set _options.push({ type: _ct, value: _cv, type2: _ct2, value2: _cv2 })>> <</for>> <<set $contract1.active = true>> <<set $contract1.options = _options>> <<set $contract1.failed = false>> <<set $contract1.accepted = false>> <<set $contract1.shootingsDone = 0>> <<set $contractShopAvailable = false>> <<set $contractShopAvailableDay = -1>> <<goto "Contract1Event">> <</if>>
<h1 style="margin:0 0 0.4em 0;">📋 Contract Shop</h1> <div style="display:flex;gap:14px;flex-wrap:wrap;margin:14px 0;"> <div style="flex:1;min-width:200px;padding:16px;background:linear-gradient(135deg,#1a1a2e,#16213e);border-radius:10px;border:2px solid #2a4a9e;box-shadow:0 4px 12px rgba(0,0,0,0.4);"> <div style="font-size:1.15em;font-weight:700;margin-bottom:4px;">📋 Standard Contract</div> <div style="font-size:0.9em;color:#999;margin-bottom:10px;">2 productions with 1 matching stat in 4 days</div> <div style="font-size:0.9em;color:#888;">Cost: <b>$200</b></div> <div style="font-size:0.9em;color:#6fcf73;">Reward: +$500, +3 rep</div> <div style="font-size:0.9em;color:#ff8080;margin-bottom:12px;">Fail: −2 rep</div> <<if $player.money >= 200>>[[✅ Buy Standard|BuyContract]]<<else>><span style="opacity:0.5;font-size:0.9em;">❌ Not enough funds</span><</if>> </div> <div id="harder-contract-card" style="flex:1;min-width:200px;padding:16px;background:linear-gradient(135deg,#2a1616,#1a1a2e);border-radius:10px;border:2px solid #9e2a2a;box-shadow:0 4px 12px rgba(0,0,0,0.4);"> <div style="font-size:1.15em;font-weight:700;margin-bottom:4px;">💀 Harder Contract</div> <div style="font-size:0.9em;color:#999;margin-bottom:10px;">2 productions with 2 matching stats in 4 days</div> <div style="font-size:0.9em;color:#888;">Cost: <b>$500</b></div> <div style="font-size:0.9em;color:#6fcf73;">Reward: +$1,500, +5 rep</div> <div style="font-size:0.9em;color:#ff8080;margin-bottom:12px;">Fail: −5 rep</div> <<if !$contractHarderItem.bought>><span style="opacity:0.5;font-size:0.9em;">🔒 Requires <b>Harder Contract</b> upgrade</span><<elseif $player.money >= 500>>[[💀 Buy Harder|BuyHarderContract]]<<else>><span style="opacity:0.5;font-size:0.9em;">❌ Not enough funds</span><</if>> </div> </div> [[⬅️ Dashboard|Dashboard]] <<script>> jQuery(document).one(':passageend', function(){ var card = document.getElementById('harder-contract-card'); if(card && SugarCube.State.variables.contractHarderItem.bought){ card.style.borderColor = '#553300'; } }); <</script>>
<<if $player.money < $contractShopPrice>> @@color:red;Not enough funds ($<<= $contractShopPrice>> required).@@ [[⬅️ Dashboard|Dashboard]] <<else>> <<set $player.money -= $contractShopPrice>> <<set _pool = ["hair:Brown","hair:Brown","hair:Blonde","hair:Blonde","hair:Black","hair:Black","height:Short","height:Short","height:Tall","height:Tall","ageCat:Young","ageCat:Young","ageCat:Veteran","ageCat:Veteran","breast:Small","breast:Small","breast:Large","breast:Large","breast:Huge","breast:Huge","breastType:Fake","breastType:Fake","breastType:Fake","breastType:Real","ethnicity:Latina","ethnicity:Latina","ethnicity:Asian","ethnicity:Asian","ethnicity:Black","ethnicity:Caucasian"]>> <<set _options = []>> <<set _numOptions = $contract3rdOptionItem.bought ? 3 : 2>> <<set $contractIsHarder = false>> <<set _usedTypes = []>> <<for _oi = 0; _oi < _numOptions; _oi++>> <<set _availPool = _pool.filter(function(p){ return _usedTypes.indexOf(p.split(":")[0]) === -1; })>> <<set _pick = _availPool[random(0, _availPool.length - 1)]>> <<set _ct = _pick.split(":")[0]>> <<set _cv = _pick.split(":")[1]>> <<set _usedTypes.push(_ct)>> <<set _options.push({ type: _ct, value: _cv })>> <</for>> <<set $contract1.active = true>> <<set $contract1.options = _options>> <<set $contract1.failed = false>> <<set $contract1.accepted = false>> <<set $contract1.shootingsDone = 0>> <<set $contractShopAvailable = false>> <<set $contractShopAvailableDay = -1>> <<goto "Contract1Event">> <</if>>
<<set $asianDuoAbsentNotified = true>> <h1 style="margin:0 0 0.4em 0;">🎌 Asian Duo — Silence</h1> <div style="display:flex;justify-content:center;gap:12px;margin:12px 0;"> <img src="img/portraits/kimmy.jpg" style="width:140px;height:140px;object-fit:cover;border-radius:12px;opacity:0.6;"> <img src="img/portraits/lulu.jpg" style="width:140px;height:140px;object-fit:cover;border-radius:12px;opacity:0.6;"> </div> Kimmy and Lulu didn't show up to the studio today. No message, no call. <em>Their chairs are empty. The set feels different without them.</em> @@color:orange;⚠️ Kimmy & Lulu are absent. Both lose 10 satisfaction. They cannot be scheduled until further notice.@@ [[📊 Dashboard|Dashboard]]
<<set $asianDuoGoneNotified = true>> <<set _kimmy = $roster.find(function(w){ return w.name is "Kimmy"; })>> <<set _lulu = $roster.find(function(w){ return w.name is "Lulu"; })>> <<set _payment = 0>> <<if _kimmy>> <<set _payment += _kimmy.contractCost + (100 * _kimmy.popularity) + (10 * _kimmy.satisfaction)>> <<set $rival.roster.push(clone(_kimmy))>> <<set $roster.delete(_kimmy)>> <</if>> <<if _lulu>> <<set _payment += _lulu.contractCost + (100 * _lulu.popularity) + (10 * _lulu.satisfaction)>> <<set $rival.roster.push(clone(_lulu))>> <<set $roster.delete(_lulu)>> <</if>> <<set $player.money += _payment>> <<set $asianDuoLastShootingDay = -1>> <<set $asianDuoShoot1Day = -1>> <<set $asianDuoShoot2Unlocked = false>> <<set $capriceShoot1Day = -1>> <<set $capriceShoot2Unlocked = false>> <<set $fallenAngelsShoot1Day = -1>> <<set $fallenAngelsShoot2Day = -1>> <<set $fallenAngelsShoot2Unlocked = false>> <<set $fallenAngelsShoot3Unlocked = false>> <<set $asianDuoAbsentDay = -1>> <<set $asianDuoAbsentNotified = false>> <<set $asianDuoGoneDay = -1>> <<set $asianDuoGoneNotified = false>> <<set $asianDuoWebm2Day = -1>> <<set $asianDuoWebm3Day = -1>> <h1 style="margin:0 0 0.4em 0;">🎌 Asian Duo — Signed Away</h1> <div style="display:flex;justify-content:center;gap:12px;margin:12px 0;"> <img src="img/portraits/kimmy.jpg" style="width:140px;height:140px;object-fit:cover;border-radius:12px;"> <img src="img/portraits/lulu.jpg" style="width:140px;height:140px;object-fit:cover;border-radius:12px;"> </div> An envelope arrives. Inside — a contract signed by both Kimmy and Lulu. Underneath, a printed still from a shoot. <em>"We found something we couldn't say no to. Thank you for everything."</em> <<= $rival.name>> has signed them both. Word is their new director pushes them harder than you ever did — and they love it. Went to BNO, learnt how massive their new co-stars are — and they're not complaining. A video of their first joint shoot under the new banner is already making the rounds. <div id="asian-duo-gone-video"></div> <<script>> jQuery(document).one(':passageend', function(){ var prefix = SugarCube.State.variables.rivalVideoPrefix || ''; var wrap = document.getElementById('asian-duo-gone-video'); if(wrap){ wrap.innerHTML = '<video src="videos/'+prefix+'kimmy_lulu_collab.webm" autoplay loop muted playsinline style="width:100%;max-width:480px;display:block;margin:12px auto;border-radius:10px;" onerror="this.style.display=\'none\'"></video>'; } }); <</script>> @@color:gold;💰 Contract buyout received: <b>$<<= _payment.toLocaleString()>></b>@@ [[📊 Dashboard|Dashboard]]
<<set $fallenAngelsAbsentNotified = true>> <h1 style="margin:0 0 0.4em 0;">👼 Two Fallen Angels — Silence</h1> <div style="display:flex;justify-content:center;gap:12px;margin:12px 0;"> <img src="img/portraits/angie.jpg" style="width:140px;height:140px;object-fit:cover;border-radius:12px;opacity:0.6;"> <img src="img/portraits/angela.jpg" style="width:140px;height:140px;object-fit:cover;border-radius:12px;opacity:0.6;"> </div> Angie and Angela didn't show up. No message, no call. <em>The set is quiet. Something feels off.</em> @@color:orange;⚠️ Angie & Angela are absent. Both lose 10 satisfaction. They cannot be scheduled until further notice.@@ [[📊 Dashboard|Dashboard]]
<<set $fallenAngelsGoneNotified = true>> <<set _angie = $roster.find(function(w){ return w.name is "Angie"; })>> <<set _angela = $roster.find(function(w){ return w.name is "Angela"; })>> <<set _payment2 = 0>> <<if _angie>> <<set _payment2 += _angie.contractCost + (100 * _angie.popularity) + (10 * _angie.satisfaction)>> <<set $rival.roster.push(clone(_angie))>> <<set $roster.delete(_angie)>> <</if>> <<if _angela>> <<set _payment2 += _angela.contractCost + (100 * _angela.popularity) + (10 * _angela.satisfaction)>> <<set $rival.roster.push(clone(_angela))>> <<set $roster.delete(_angela)>> <</if>> <<set $player.money += _payment2>> <<set $fallenAngelsLastShootingDay = -1>> <<set $fallenAngelsAbsentDay = -1>> <<set $fallenAngelsAbsentNotified = false>> <<set $fallenAngelsGoneDay = -1>> <<set $fallenAngelsGoneNotified = false>> <<set $fallenAngelsWebm2Day = -1>> <<set $fallenAngelsWebm3Day = -1>> <h1 style="margin:0 0 0.4em 0;">👼 Two Fallen Angels — Gone</h1> <div style="display:flex;justify-content:center;gap:12px;margin:12px 0;"> <img src="img/portraits/angie.jpg" style="width:140px;height:140px;object-fit:cover;border-radius:12px;"> <img src="img/portraits/angela.jpg" style="width:140px;height:140px;object-fit:cover;border-radius:12px;"> </div> A message arrives from <<= $rival.name>>. Attached — a clip from a shoot with both Angie and Angela. <em>"They came to us. We made them an offer they deserved — and a director who knows how to bring out their full potential. Stronger. Harder. Better."</em> <em>Went to BNO. Both of them. Rumour has it their first shoot left them walking differently.</em> <div id="fallen-angels-gone-video"></div> <<script>> jQuery(document).one(':passageend', function(){ var prefix = SugarCube.State.variables.rivalVideoPrefix || ''; var wrap = document.getElementById('fallen-angels-gone-video'); if(wrap){ wrap.innerHTML = '<video src="videos/'+prefix+'angie_angela_collab.webm" autoplay loop muted playsinline style="width:100%;max-width:480px;display:block;margin:12px auto;border-radius:10px;" onerror="this.style.display=\'none\'"></video>'; } }); <</script>> @@color:gold;💰 Contract buyout received: <b>$<<= _payment2.toLocaleString()>></b>@@ [[📊 Dashboard|Dashboard]]
<h1 style="margin:0 0 0.4em 0;">🎌 Asian Duo — <<= $rival.name>> Update</h1> A clip surfaces online. Kimmy and Lulu, under <<= $rival.name>>'s banner. <em>"They look... happy."</em> <div id="asian-webm2"></div> <<script>> jQuery(document).one(':passageend', function(){ var prefix = SugarCube.State.variables.rivalVideoPrefix || ''; var wrap = document.getElementById('asian-webm2'); if(wrap) wrap.innerHTML = '<video src="videos/'+prefix+'kimmy_lulu_special2.webm" autoplay loop muted playsinline style="width:100%;max-width:480px;display:block;margin:12px auto;border-radius:10px;" onerror="this.style.display=\'none\'"></video>'; }); <</script>> [[📊 Dashboard|Dashboard]]
<h1 style="margin:0 0 0.4em 0;">🎌 Asian Duo — <<= $rival.name>> Update</h1> Another clip. They're fully settled in now. <div id="asian-webm3"></div> <<script>> jQuery(document).one(':passageend', function(){ var prefix = SugarCube.State.variables.rivalVideoPrefix || ''; var wrap = document.getElementById('asian-webm3'); if(wrap) wrap.innerHTML = '<video src="videos/'+prefix+'kimmy_lulu_special3.webm" autoplay loop muted playsinline style="width:100%;max-width:480px;display:block;margin:12px auto;border-radius:10px;" onerror="this.style.display=\'none\'"></video>'; }); <</script>> [[📊 Dashboard|Dashboard]]
<h1 style="margin:0 0 0.4em 0;">👼 Two Fallen Angels — <<= $rival.name>> Update</h1> A clip of Angie and Angela surfaces. They're working again — together. <div id="fa-webm2"></div> <<script>> jQuery(document).one(':passageend', function(){ var prefix = SugarCube.State.variables.rivalVideoPrefix || ''; var wrap = document.getElementById('fa-webm2'); if(wrap) wrap.innerHTML = '<video src="videos/'+prefix+'angie_angela_special2.webm" autoplay loop muted playsinline style="width:100%;max-width:480px;display:block;margin:12px auto;border-radius:10px;" onerror="this.style.display=\'none\'"></video>'; }); <</script>> [[📊 Dashboard|Dashboard]]
<h1 style="margin:0 0 0.4em 0;">👼 Two Fallen Angels — <<= $rival.name>> Update</h1> The final clip. Angie and Angela at their best — under someone else's name. <div id="fa-webm3"></div> <<script>> jQuery(document).one(':passageend', function(){ var prefix = SugarCube.State.variables.rivalVideoPrefix || ''; var wrap = document.getElementById('fa-webm3'); if(wrap) wrap.innerHTML = '<video src="videos/'+prefix+'angie_angela_special3.webm" autoplay loop muted playsinline style="width:100%;max-width:480px;display:block;margin:12px auto;border-radius:10px;" onerror="this.style.display=\'none\'"></video>'; }); <</script>> [[📊 Dashboard|Dashboard]]
<<silently>><<set $player.day += 1>><<set $shootingPlayedToday = false>><<set $weeklyPaid = 0>><<set $drawResult = []>><<set $drawLuckyNames = []>><<set $drawEliteNames = []>><<set $drawPool = "">><<if $player.day % 7 is 0>><<for _i = 0; _i < $roster.length; _i++>><<set _daysOwed = Math.min(7, $player.day - ($roster[_i].joinedDay || ($player.day - 7)) + 1)>><<set _upkeep = Math.round($roster[_i].popularity * 70 * _daysOwed / 7 * ($easyMode ? 0.7 : 1))>><<set $weeklyPaid += _upkeep>><<set $player.money -= _upkeep>><</for>><<for _i = 0; _i < $roster.length; _i++>><<set $roster[_i].weekShootings = 0>><</for>><</if>><<for _i = 0; _i < $roster.length; _i++>><<set _daysSince = $player.day - $roster[_i].lastShootingDay>><<set _decayThreshold = $satisfactionDelayItem.bought ? 5 : 4>><<if $roster[_i].satisfaction > 40>><<set _decayThreshold += 1>><</if>><<if $easyMode>><<set _decayThreshold += 2>><</if>><<if _daysSince >= _decayThreshold && $roster[_i].satisfaction < 100>><<if $roster[_i].name isnot $vacationStar>><<set $roster[_i].satisfaction = Math.max(0, $roster[_i].satisfaction - 5)>><</if>><</if>><<if $roster[_i].name is $vacationStar>><<set $roster[_i].lastShootingDay = $player.day>><</if>><<if $roster[_i].restDay && $roster[_i].name isnot $vacationStar && $player.day > $roster[_i].restUntilDay>><<set $roster[_i].restDay = false>><<set $roster[_i].consecutiveDays = 0>><</if>><</for>><<set $zeroSatStar = "">> /* ── Rival offer deadline check ── */ <<if $rivalOfferShootingsLeft > 0 && $rivalOfferDeadlineDay > 0 && $player.day >= $rivalOfferDeadlineDay>> <<set _failStar = $roster.find(function(w){ return w.name is $rivalOfferStar; })>> <<if _failStar>> <<set $rival.roster.push(clone(_failStar))>> <<run window.cleanupQuestlineForLostStar(_failStar.name)>> <<set $roster.delete(_failStar)>> <</if>> <<set $rivalOfferShootingsLeft = 0>> <<set $rivalOfferDeadlineDay = -1>> <<set $poachMessage = $rivalOfferStar + " left for " + $rival.name + " — you didn't feature them enough.">> <</if>> /* ── Special shooting unlock checks ── */ <<if $asianDuoShoot1Day > 0 && !$asianDuoShoot2Unlocked && $player.day >= $asianDuoShoot1Day + 3>> <<set $asianDuoShoot2Unlocked = true>> <</if>> <<if $capriceShoot1Day > 0 && !$capriceShoot2Unlocked && $player.day >= $capriceShoot1Day + 3>> <<set $capriceShoot2Unlocked = true>> <</if>> <<if $fallenAngelsShoot1Day > 0 && !$fallenAngelsShoot2Unlocked && $player.day >= $fallenAngelsShoot1Day + 3>> <<set $fallenAngelsShoot2Unlocked = true>> <</if>> <<if $fallenAngelsShoot2Day > 0 && !$fallenAngelsShoot3Unlocked && $player.day >= $fallenAngelsShoot2Day + 3>> <<set $fallenAngelsShoot3Unlocked = true>> <</if>> /* ── Trophy checks ── */ <<if !$easyMode>> <<if !$trophies.fullHouse && $roster.length >= 10>> <<set $trophies.fullHouse = true>><<set $newTrophy = "🏆 Full House — 10 stars signed!">><<run window.checkAllTrophies()>> <</if>> <<if !$trophies.empire && $roster.length >= 20>> <<set $trophies.empire = true>><<set $newTrophy = "🏆 Empire — 20 stars signed!">><<run window.checkAllTrophies()>> <</if>> <<if !$trophies.asianDuoComplete && $questlines.asianDuo.shooting2Done>> <<set $trophies.asianDuoComplete = true>><<set $newTrophy = "🏆 Asian Duo — questline complete!">><<run window.checkAllTrophies()>> <</if>> <<if !$trophies.fallenAngelsComplete && $questlines.fallenAngels.shooting3Done>> <<set $trophies.fallenAngelsComplete = true>><<set $newTrophy = "🏆 Fallen Angels — questline complete!">><<run window.checkAllTrophies()>> <</if>> <<if !$trophies.sweetCapriceComplete && $questlines.sweetCaprice.shooting2Done>> <<set $trophies.sweetCapriceComplete = true>><<set $newTrophy = "🏆 Sweet Caprice — questline complete!">><<run window.checkAllTrophies()>> <</if>> <<if !$trophies.first100Sat && $roster.some(function(w){ return w.satisfaction >= 100; })>> <<set $trophies.first100Sat = true>><<set $newTrophy = "🏆 Perfect Bond — a star reached 100 satisfaction!">><<run window.checkAllTrophies()>> <</if>> <<if !$trophies.firstMillion && $totalEarnings >= 1000000>> <<set $trophies.firstMillion = true>><<set $newTrophy = "🏆 First Million — $1,000,000 earned!">><<run window.checkAllTrophies()>> <</if>> <</if>> /* ── Contract shop day check ── */ <<if $contractShopAvailableDay > 0 && $player.day >= $contractShopAvailableDay>> <<set $contractShopAvailable = true>> <<set $contractShopAvailableDay = -1>> <</if>> /* ── Questline: Asian Duo trigger ── */ <<if !$questlines.asianDuo.active && !$questlines.asianDuo.specialAvailable>> <<set _kimmy = $roster.find(function(w){ return w.name is "Kimmy"; })>> <<set _lulu = $roster.find(function(w){ return w.name is "Lulu"; })>> <<if _kimmy || _lulu>> <<set $questlines.asianDuo.active = true>> <<set $questlines.asianDuo.star1 = _kimmy ? "Kimmy" : "Lulu">> <<set $questlines.asianDuo.step = Math.max($questlines.asianDuo.step, 1)>> <</if>> <</if>> /* ── Asian Duo step progression ── */ <<if $questlines.asianDuo.active>> <<set _ql = $questlines.asianDuo>> <<set _s1 = $roster.find(function(w){ return w.name is _ql.star1; })>> <<set _kimmy2 = $roster.find(function(w){ return w.name is "Kimmy"; })>> <<set _lulu2 = $roster.find(function(w){ return w.name is "Lulu"; })>> <<if _ql.step is 1 && _s1 && _s1.satisfaction >= 25>> <<set _ql.step = 2>> <</if>> <<if _ql.step >= 2>> <<if _kimmy2 && _lulu2>> <<if !_ql.star2>> <<set _ql.star2 = (_ql.star1 is "Kimmy") ? "Lulu" : "Kimmy">> <<set _ql.step = 3>> <</if>> <</if>> <</if>> <<set _s2 = _ql.star2 ? $roster.find(function(w){ return w.name is _ql.star2; }) : null>> <<if _ql.step is 3 && _s2 && _s2.satisfaction >= 25>> <<set _ql.step = 4>> <<set _ql.specialAvailable = true>> <<set _ql.active = false>> <</if>> <</if>> /* ── Two Fallen Angels trigger ── */ <<if !$questlines.fallenAngels.active && !$questlines.fallenAngels.specialAvailable && !$questlines.fallenAngels.shooting3Done>> <<set _angie = $roster.find(function(w){ return w.name is "Angie"; })>> <<set _angela = $roster.find(function(w){ return w.name is "Angela"; })>> <<if _angie || _angela>> <<set $questlines.fallenAngels.active = true>> <<set $questlines.fallenAngels.star1 = _angie ? "Angie" : "Angela">> <<set $questlines.fallenAngels.step = Math.max($questlines.fallenAngels.step, 1)>> <</if>> <</if>> /* ── Two Fallen Angels step progression ── */ <<if $questlines.fallenAngels.active>> <<set _qlF = $questlines.fallenAngels>> <<set _fa1 = $roster.find(function(w){ return w.name is _qlF.star1; })>> <<set _angie2 = $roster.find(function(w){ return w.name is "Angie"; })>> <<set _angela2 = $roster.find(function(w){ return w.name is "Angela"; })>> <<if _qlF.step is 1 && _fa1 && _fa1.satisfaction >= 25>><<set _qlF.step = 2>><</if>> <<if _qlF.step >= 2 && _angie2 && _angela2 && !_qlF.star2>> <<set _qlF.star2 = (_qlF.star1 is "Angie") ? "Angela" : "Angie">> <<set _qlF.step = 3>> <</if>> <<set _fa2 = _qlF.star2 ? $roster.find(function(w){ return w.name is _qlF.star2; }) : null>> <<if _qlF.step is 3 && _fa2 && _fa2.satisfaction >= 25>> <<set _qlF.step = 4>> <<set _qlF.specialAvailable = true>> <<set _qlF.active = false>> <</if>> <</if>> /* ── Sweet Caprice trigger ── */ <<if !$questlines.sweetCaprice.active && $questlines.sweetCaprice.step is 0>> <<set _caprice0 = $roster.find(function(w){ return w.name is "Caprice"; })>> <<if _caprice0>> <<set $questlines.sweetCaprice.active = true>> <<set $questlines.sweetCaprice.step = 1>> <</if>> <</if>> /* ── Sweet Caprice step progression ── */ <<if $questlines.sweetCaprice.active>> <<set _qlC = $questlines.sweetCaprice>> <<set _cap = $roster.find(function(w){ return w.name is "Caprice"; })>> <<if _qlC.step is 1 && _cap && _cap.satisfaction >= 50>> <<set _qlC.step = 2>> <</if>> <<if _qlC.step is 2 && _qlC.bjCount >= 6>> <<set _qlC.step = 3>> <<set _qlC.eveNotifyDay = $player.day>> <</if>> <<if _qlC.step is 3 && _qlC.eveNotifyDay > 0 && $player.day >= _qlC.eveNotifyDay + 3>> <<set _qlC.step = 4>> <<set _qlC.specialAvailable = true>> <<set _qlC.active = false>> <</if>> <</if>><<for _i = 0; _i < $roster.length; _i++>><<if $roster[_i].satisfaction <= 5 && !$roster[_i].lowSatAlerted>><<set $roster[_i].lowSatAlerted = true>><<set $zeroSatStar = $roster[_i].name>><</if>><</for>><<if $rival.roster.length > 0 && $allPositions.length > 0>><<set _ri = random(0, $rival.roster.length - 1)>> <<if $bnoEventDone>> <<set _bnoPositions = ["BJ", "Missionary"]>> <<set _bnoPos = _bnoPositions[random(0, _bnoPositions.length - 1)]>> <<if $rival.roster[_ri]>><<set $rivalLastShooting = { star: $rival.roster[_ri].name, position: _bnoPos }>><</if>> <<else>> <<set _rivalPositions = ["BJ", "Missionary", "Doggy", "Cowgirl", "Reverse Cowgirl"]>> <<set _rm = _rivalPositions[random(0, _rivalPositions.length - 1)]>> <<if $rival.roster[_ri]>><<set $rivalLastShooting = { star: $rival.roster[_ri].name, position: _rm }>><</if>> <</if>><</if>><<genTrends>><<checkRival>><<if $thirdRecruitDay > 0 && $player.day is $thirdRecruitDay + 7 && $roster.length > 0 && !$rivalOfferEvent>> <<set _lowestPop = 9999>><<set _lowestIdx = -1>> <<for _i = 0; _i < $roster.length; _i++>> <<if $roster[_i].popularity < _lowestPop>><<set _lowestPop = $roster[_i].popularity>><<set _lowestIdx = _i>><</if>> <</for>> <<if _lowestIdx >= 0 && $roster[_lowestIdx]>> <<set $rivalOfferEvent = true>> <<set $rivalOfferStar = $roster[_lowestIdx].name>> <</if>> <</if>><<if $player.day is 12 && !$contract1.active && !$contract1.accepted>> <<set _pool12 = ["hair:Brown","hair:Brown","hair:Blonde","hair:Blonde","hair:Black","hair:Black","height:Short","height:Short","height:Tall","height:Tall","ageCat:Young","ageCat:Young","ageCat:Veteran","ageCat:Veteran","breast:Small","breast:Small","breast:Large","breast:Large","breast:Huge","breast:Huge","breastType:Fake","breastType:Fake","breastType:Fake","breastType:Real","ethnicity:Latina","ethnicity:Latina","ethnicity:Asian","ethnicity:Asian","ethnicity:Black","ethnicity:Caucasian"]>> <<set _options = []>> <<set _numOptions12 = $contract3rdOptionItem.bought ? 3 : 2>> <<set $contractIsHarder = false>> <<set _usedTypes12 = []>> <<for _oi = 0; _oi < _numOptions12; _oi++>> <<set _availPool12 = _pool12.filter(function(p){ return _usedTypes12.indexOf(p.split(":")[0]) === -1; })>> <<set _pick = _availPool12[random(0, _availPool12.length - 1)]>> <<set _ct = _pick.split(":")[0]>> <<set _cv = _pick.split(":")[1]>> <<set _usedTypes12.push(_ct)>> <<set _options.push({ type: _ct, value: _cv })>> <</for>> <<set $contract1.active = true>> <<set $contract1.options = _options>> <</if>> <<if $contract1.accepted && !$contract1.failed>> <<if $player.day > $contract1.startDay + 4 && $contract1.shootingsDone < 2>> <<set $contract1.failed = true>> <<set $contract1.accepted = false>> <<if $contractIsHarder>><<set $player.reputation = Math.max(0, $player.reputation - 5)>><<else>><<set $player.reputation = Math.max(0, $player.reputation - 2)>><</if>> <<set $contractShopAvailableDay = $player.day + 3>> <</if>> <</if>> <<if $player.day is 36 && !$contract3.active && !$contract3.accepted && !$contract3.failed>> <<set $contract3.active = true>> <</if>> <<if $player.day is 45 && !$contract4.active && !$contract4.accepted && !$contract4.failed>> <<set _c4pool = $poolConfirmed.filter(function(n){ return !$roster.some(function(w){ return w.name is n; }) && !$rival.roster.some(function(w){ return w.name is n; }); })>> <<if _c4pool.length >= 2>> <<set _c4i1 = random(0, _c4pool.length - 1)>> <<set $contract4.star1 = _c4pool[_c4i1]>> <<set _c4pool.splice(_c4i1, 1)>> <<set $contract4.star2 = _c4pool[random(0, _c4pool.length - 1)]>> <<set $contract4.active = true>> <<elseif _c4pool.length is 1>> <<set $contract4.star1 = _c4pool[0]>> <<set $contract4.star2 = "">> <<set $contract4.active = true>> <</if>> <</if>> <<if $player.money >= 25000 && !$contract5.everTriggered>> <<set _c5pool = $poolElite.filter(function(n){ return !$roster.some(function(w){ return w.name is n; }) && !$rival.roster.some(function(w){ return w.name is n; }); })>> <<if _c5pool.length >= 2>> <<set _c5i1 = random(0, _c5pool.length - 1)>> <<set $contract5.star1 = _c5pool[_c5i1]>> <<set _c5pool.splice(_c5i1, 1)>> <<set $contract5.star2 = _c5pool[random(0, _c5pool.length - 1)]>> <<set $contract5.active = true>> <<set $contract5.everTriggered = true>> <<elseif _c5pool.length is 1>> <<set $contract5.star1 = _c5pool[0]>> <<set $contract5.star2 = "">> <<set $contract5.active = true>> <<set $contract5.everTriggered = true>> <</if>> <</if>> <<if $contract3.accepted && !$contract3.failed>> <<if $player.day >= 44 && $contract3.shootingsDone < 1>> <<set $contract3.failed = true>> <<set $contract3.accepted = false>> <<set $player.money -= 2000>> <</if>> <</if>> <<if $contract4.accepted && !$contract4.failed>> <<if $player.day >= 50 && $contract4.shootingsDone < 1>> <<set $contract4.failed = true>> <<set $contract4.accepted = false>> <<set $player.money -= 2000>> <</if>> <</if>> <<if $contract5.accepted && !$contract5.failed>> <<if $player.day >= $contract5.startDay + 5 && $contract5.shootingsDone < 1>> <<set $contract5.failed = true>> <<set $contract5.accepted = false>> <<set $player.money -= 4000>> <</if>> <</if>> <<if $player.day is 8 && !$day5EventDone && $roster.length > 0>><<set $day5EventDone = true>><</if>><<if $player.day is 10 && !$objective1Notified>><<set $objective1Notified = true>><</if>><<if $player.reputation >= 15 && !$rep15EventDone>><<set $rep15EventDone = true>><<set $rep15EventPending = true>><</if>><<if $player.day is 25 && !$day22EventDone && $rival.roster.length > 0>><<set $day22EventDone = true>><</if>><<if $player.day is 18 && !$day18EventDone>><<set $day18EventDone = true>><</if>><<if $player.day is 21 && !$roxyEventTriggered>><<set $roxyEventTriggered = true>><<set $roxyEventPending = true>><</if>><<if $player.day is 22 && !$day25EventDone>><<set $day25EventDone = true>><</if>><<if $player.day is 29 && !$bnoEventDone>><<set $bnoEventDone = true>><</if>><<if $player.day is $contestNextDay && !$contestPending>><<set $contestPending = true>><</if>><<for _jsi = 0; _jsi < $judgeSpecialShoots.length; _jsi++>><<if $player.day is $judgeSpecialShoots[_jsi].triggerDay && !$judgeSpecialShoots[_jsi].active && !$judgeSpecialShoots[_jsi].done>><<triggerJudgeSpecialShoot _jsi>><<set $judgeSpecialPending = _jsi>><</if>><<if $judgeSpecialShoots[_jsi].active && !$judgeSpecialShoots[_jsi].done && $player.day > $judgeSpecialShoots[_jsi].deadlineDay>><<set $judgeSpecialShoots[_jsi].active = false>><<set $judgeSpecialMissed = $judges[$judgeSpecialShoots[_jsi].judgeIdx].name + "'s special request window closed — no matching shoot in time.">><</if>><</for>><<if $player.day is 30 && !$day30EventDone>><<set $day30EventDone = true>><</if>><<if $player.day is 16 && !$objective1Done>><<set $objective1Done = true>><<if $roster.length < 3>><<set $gameOver = true>><</if>><</if>><<if $skillfulChallengeActive && $player.day > $skillfulChallengeEndDay>><<set $skillfulChallengeActive = false>><</if>><<if $vacationEndDay > 0 && $player.day >= $vacationEndDay>><<for _i = 0; _i < $roster.length; _i++>><<if $roster[_i].name is $vacationStar>><<set $roster[_i].restDay = false>><<set $roster[_i].consecutiveDays = 0>><</if>><</for>><<set $vacationEndDay = -1>><<set $vacationStar = "">><</if>><</silently>><strong>📅 Day <<= $player.day>></strong> A new day begins! <<if $rivalSabotageStar>><<if $rivalSabotageStolen>>@@color:red;😈 <b><<= $rival.name>></b> got to <b><<= $rivalSabotageStar>></b> — satisfaction crashed and she walked. <<= $rival.name>> picked her up immediately.@@<<else>>@@color:orange;😈 <b><<= $rival.name>></b> got to <b><<= $rivalSabotageStar>></b> — satisfaction dropped by 10.@@<</if>> <<set $rivalSabotageStar = "">> <<set $rivalSabotageStolen = false>> <</if>> <<if $poachMessage>>@@color:red;⚠️ <<= $poachMessage>>@@ <<set $poachMessage = "">> <<if $poachVideoStar>><div id="poach-video-wrap"></div><<script>>jQuery(document).one(':passageend',function(){var s=SugarCube.State.variables.poachVideoStar;if(!s)return;var f=s.toLowerCase().replace(/ /g,'_');var src='videos/b_'+f+'_bj.webm';var el=document.getElementById('poach-video-wrap');if(el){var v=document.createElement('video');v.src=src;v.autoplay=true;v.loop=true;v.muted=true;v.playsInline=true;v.style.width='100%';v.style.maxWidth='480px';v.style.borderRadius='8px';v.style.marginTop='8px';v.onerror=function(){this.style.display='none';};el.innerHTML='';el.appendChild(v);}SugarCube.State.variables.poachVideoStar='';});<</script>><</if>> <</if>> <<if $rivalOfferShootingsLeft > 0>> <<set $rivalOfferShootingsLeft -= 1>> <<if $rivalOfferShootingsLeft is 0>> <<set _os = $roster.find(function(w){ return w.name is $rivalOfferStar; })>> <<if _os>> <<set _os.popularity += 1>> <<set _os.satisfaction = Math.min(100, _os.satisfaction + 10)>> <<set $rivalOfferEvent = false>> <</if>> <</if>> <</if>> <<if $gameOver>>[[💀 Game Over|GameOver]]<<elseif $player.day is 29 && $bnoEventDone>>[[🏢 New Rival!|BNOEvent]]<<elseif $weeklyPaid > 0>>[[💸 Weekly Upkeep|WeeklyUpkeep]]<<elseif $contestPending && !$contestJoined>>[[🏆 Contest|ContestIntro]]<<elseif $contestPending>>[[🏆 Contest|ContestPickStars]]<<elseif $judgeSpecialPending >= 0>>[[🎬 A Special Request|JudgeSpecialRequest]]<<elseif $rivalPoachEvent>>[[⚠️ Rival Alert|RivalPoachEvent]]<<elseif $rivalOfferEvent>>[[🌟 Special Event|RivalOfferEvent]]<<elseif $rep15EventPending>>[[🌟 Special Event|Rep15Event]]<<elseif $roxyEventPending>>[[🌟 Special Event!|RoxyEvent]]<<elseif $player.day is 25 && $day22EventDone && $rival.roster.length > 0>>[[🌟 Special Event|Day22Event]]<<elseif $player.day is 18 && $day18EventDone>>[[📰 New Studio Alert|Day18Event]]<<elseif $player.day is 22 && $day25EventDone>>[[📰 Industry News|Day25Event]]<<elseif $player.day is 30 && $day30EventDone && $roster.length > 0>><<link `"📞 " + $rival.name + " Contact"`>><<goto "Day30Event">><</link>><<elseif $contract1.active && !$contract1.accepted && !$contract1.failed>>[[📋 New Contract!|Contract1Event]]<<elseif $contract1.failed>>[[❌ Contract Failed|Contract1Failed]]<<elseif $contract3.active && !$contract3.accepted && !$contract3.failed>>[[📋 Established Contract!|Contract3Event]]<<elseif $contract3.failed>>[[❌ Established Contract Failed|Contract3Failed]]<<elseif $contract4.active && !$contract4.accepted && !$contract4.failed>>[[📋 Investor Demand!|Contract4Event]]<<elseif $contract4.failed>>[[❌ Investor Contract Failed|Contract4Failed]]<<elseif $contract5.active && !$contract5.accepted && !$contract5.failed>>[[💎 Elite Demand!|Contract5Event]]<<elseif $contract5.failed>>[[❌ Elite Contract Failed|Contract5Failed]]<<elseif $player.day is 10 && $objective1Notified>>[[🎯 Objective!|Objective1Event]]<<elseif $player.day is 8 && $day5EventDone && $roster.length > 0>>[[🌟 Special Event|Day5Event]]<<elseif $zeroSatStar>>[[⚠️ Critical Alert!|ZeroSatisfaction]]<<elseif $questlines.asianDuo.step is 2 && !$questlines.asianDuo.step2Notified>>[[🎌 Questline|AsianDuoStep2]]<<elseif $questlines.asianDuo.step is 3 && !$questlines.asianDuo.step3Notified>>[[🎌 Questline|AsianDuoStep3]]<<elseif $questlines.asianDuo.step is 4 && !$questlines.asianDuo.step4Notified>>[[🎌 Questline|AsianDuoStep4]]<<elseif $questlines.fallenAngels.step is 2 && !$questlines.fallenAngels.step2Notified>>[[👼 Questline|FallenAngelsStep2]]<<elseif $questlines.fallenAngels.step is 3 && !$questlines.fallenAngels.step3Notified>>[[👼 Questline|FallenAngelsStep3]]<<elseif $questlines.fallenAngels.step is 4 && !$questlines.fallenAngels.step4Notified>>[[👼 Questline|FallenAngelsStep4]]<<elseif $questlines.sweetCaprice.step is 2 && !$questlines.sweetCaprice.step2Notified>>[[🍬 Questline|SweetCapriceStep2]]<<elseif $questlines.sweetCaprice.step is 3 && !$questlines.sweetCaprice.step3Notified>>[[🍬 Questline|SweetCapriceStep3]]<<elseif $questlines.sweetCaprice.step is 4 && !$questlines.sweetCaprice.step4Notified>>[[🍬 Questline|SweetCapriceStep4]]<<elseif $asianDuoShoot2Unlocked && $asianDuoShoot1Day > 0 && $player.day is $asianDuoShoot1Day + 3 && !$questlines.asianDuo.shooting2Done>>[[🎌 Asian Duo|AsianDuoShootUnlock2]]<<elseif $fallenAngelsShoot2Unlocked && $fallenAngelsShoot1Day > 0 && $player.day is $fallenAngelsShoot1Day + 3 && !$questlines.fallenAngels.shooting2Done>>[[👼 Fallen Angels|FAShootUnlock2]]<<elseif $fallenAngelsShoot3Unlocked && $fallenAngelsShoot2Day > 0 && $player.day is $fallenAngelsShoot2Day + 3 && !$questlines.fallenAngels.shooting3Done>>[[👼 Fallen Angels|FAShootUnlock3]]<<elseif $capriceShoot2Unlocked && $capriceShoot1Day > 0 && $player.day is $capriceShoot1Day + 3 && !$questlines.sweetCaprice.shooting2Done>>[[🍬 Sweet Caprice|SweetCapriceShootUnlock2]]<<else>>[[📊 Dashboard|Dashboard]]<</if>>
<<set _highSat = -1>><<set _highIdx = -1>><<for _i = 0; _i < $roster.length; _i++>><<if $roster[_i].satisfaction > _highSat && !$roster[_i].restDay>><<set _highSat = $roster[_i].satisfaction>><<set _highIdx = _i>><</if>><</for>><<set _diva = $roster[_highIdx]>> <h1 style="margin:0 0 0.4em 0;">🌟 A Request</h1> <<set _portraitFile = _diva.name.toLowerCase().replace(/ /g, "_")>> <div style="text-align:center;margin:10px 0;"><img id="day5-portrait" style="width:160px;height:160px;object-fit:cover;border-radius:12px;box-shadow:0 4px 16px rgba(0,0,0,0.5);" src=""></div> <<script>> jQuery(document).one(':passageend', function(){ var f = SugarCube.State.temporary.portraitFile || ''; var img = document.getElementById('day5-portrait'); if(img && f) img.src = 'img/portraits/' + f + '.jpg'; }); <</script>> <<= _diva.name>> leans against your office doorframe, wrapped in a robe. <em>"I've given you everything this week. My body needs a break — or I won't be able to give you what you actually want on camera."</em> <em>"Three days. I'll come back and make it worth the wait, I promise."</em> Their satisfaction: ❤️ <<= _diva.satisfaction>> <<capture _highIdx>> [[✅ Grant 3 days off|VacationAccept][$vacationIdx = _highIdx, $vacationDays = 3]] [[🤝 Offer 1 day off|VacationAccept][$vacationIdx = _highIdx, $vacationDays = 1]] [[❌ Refuse|VacationRefuse][$vacationIdx = _highIdx]] <</capture>>
<<set _diva = $roster[$vacationIdx]>><<set $vacationStar = _diva.name>><<set $vacationEndDay = $player.day + $vacationDays>><<set _diva.restDay = true>> <<if $vacationDays is 3>> <<set _diva.satisfaction = Math.min(100, _diva.satisfaction + 5)>> ✅ <em>She throws her arms around you. "Three days... I'll spend every minute thinking about what I'm going to do to that camera when I'm back. Don't miss me too much."</em> <b><<= _diva.name>></b> will be back on day <<= $vacationEndDay>>. <em>(+5 satisfaction)</em> <<else>> 🤝 <em>She sighs, runs a hand slowly down her side. "One day. Fine. I'll make it count — rest up, touch myself, come back ready to put on a show."</em> <b><<= _diva.name>></b> takes a day off. <</if>> [[📊 Dashboard|Dashboard]]
<<set _diva = $roster[$vacationIdx]>><<set _diva.satisfaction = Math.max(0, _diva.satisfaction - 10)>> ❌ <em>Her jaw tightens. "Fine. But you're going to feel this on camera — and not in a good way." She turns and walks out without looking back.</em> <b><<= _diva.name>></b>'s satisfaction: ❤️ <<= _diva.satisfaction>> <em>(−10)</em> [[📊 Dashboard|Dashboard]]
<<set $rivalPoachEvent = false>> <<set _lowestPop = 9999>><<set _lowestIdx = -1>> <<for _i = 0; _i < $roster.length; _i++>> <<if $roster[_i].popularity < _lowestPop>> <<set _lowestPop = $roster[_i].popularity>> <<set _lowestIdx = _i>> <</if>> <</for>> <<set $rivalOfferIdx = _lowestIdx>> <<set $rivalOfferStar = $roster[_lowestIdx].name>> <<set $roster[_lowestIdx].restDay = false>> <<set $roster[_lowestIdx].consecutiveDays = 0>> <h1 style="margin:0 0 0.4em 0;">📞 An Unexpected Visit</h1> <b><<= $rivalOfferStar>></b> stops by, looking uneasy. <em>"Hey... I got a call from <<= $rival.name>> today. They made me an offer. I wanted to tell you first before making any decision."</em> <em>"I like it here, but... I need to feel valued, you know?"</em> Their popularity: 🌟 <<= $roster[$rivalOfferIdx].popularity>> | Satisfaction: <<if $roster[$rivalOfferIdx].satisfaction >= 65>>💗<<elseif $roster[$rivalOfferIdx].satisfaction >= 40>>❤️<<elseif $roster[$rivalOfferIdx].satisfaction >= 12>>🧡<<else>>🖤<</if>> <<= $roster[$rivalOfferIdx].satisfaction>> [[🎬 Give them 3 productions|RivalOfferChallenge]] <em>(they stay, fatigue resets — complete 3 productions to earn their loyalty)</em> [[👋 Let them go|RivalOfferLeave]] <em>(they join <<= $rival.name>>, you receive $<<= Math.ceil($roster[$rivalOfferIdx].contractCost * 0.5).toLocaleString()>>)</em>
<<set $rivalOfferChallenge = true>> <<set $rivalOfferShootingsDone = 0>> <<set $roster[$rivalOfferIdx].restDay = false>> <<set $roster[$rivalOfferIdx].consecutiveDays = 0>> <<set $roster[$rivalOfferIdx].lastShootingDay = $player.day>> <em>She presses a hand against your chest. "Three shoots. I want to feel it every single time." Her eyes don't leave yours. "Don't disappoint me."</em> <b><<= $rivalOfferStar>></b> stays! Complete <b>3 productions</b> featuring them to prove their value. The sidebar will track your progress. [[📊 Dashboard|Dashboard]] /* ════════════════════════════════════════════ PASSAGE : WeeklyUpkeep ════════════════════════════════════════════ */
<h1 style="margin:0 0 0.4em 0;">💸 Weekly Upkeep</h1> It's payday! The following amounts have been deducted from your account: <<for _i = 0; _i < $roster.length; _i++>> <<set _w = $roster[_i]>> <<set _wDaysOwed = Math.min(7, $player.day - (_w.joinedDay || ($player.day - 7)) + 1)>> <<set _wUpkeep = Math.round(_w.popularity * 70 * _wDaysOwed / 7)>> - <b><<= _w.name>></b> — $<<= _wUpkeep.toLocaleString()>><<if _wDaysOwed < 7>> <em style="font-size:0.8em;color:#888;">(<<= _wDaysOwed>>/7 days)</em><</if>> <</for>> Total paid: <b>$<<= $weeklyPaid.toLocaleString()>></b> Remaining balance: <b>@@color:<<= $player.money < 0 ? "red" : "white">>;$<<= $player.money.toLocaleString()>>@@</b> <<if $player.money < 0>> @@color:red;⚠️ <b>Your agency is in the red!</b> All talents lose <b>5 satisfaction</b>.@@ <<for _i = 0; _i < $roster.length; _i++>> <<set $roster[_i].satisfaction = Math.max(0, $roster[_i].satisfaction - 5)>> <</for>> <em>You must sell contracts to get back above $0 before continuing.</em> [[💸 Sell Contracts|SellContracts]] <<elseif $zeroSatStar>> [[⚠️ Critical Alert!|ZeroSatisfaction]] <<elseif $contestPending && !$contestJoined>> [[🏆 Contest|ContestIntro]] <<elseif $contestPending>> [[🏆 Contest|ContestPickStars]] <<else>> [[📊 Dashboard|Dashboard]] <</if>> /* ════════════════════════════════════════════ PASSAGE : SellContracts ════════════════════════════════════════════ */
<h1 style="margin:0 0 0.4em 0;">💸 Sell Contracts</h1> @@color:red;Balance: <b>$<<= $player.money.toLocaleString()>></b>@@ — You must reach $0 to continue. Sell a talent's contract at <b>25% of their contract cost</b>. They have a <b>25% chance</b> of being picked up by <<= $rival.name>>. <div id="sell-roster-container"></div> <<if $player.money >= 0>> @@color:green;✅ You're back above $0!@@ <<if !$easyMode && !$trophies.brokeBurBack>><<set $trophies.brokeBurBack = true>><<set $newTrophy = "🏆 Broke But Back — survived a negative upkeep!">><<run window.checkAllTrophies()>><</if>> [[▶️ Continue|Dashboard]] <</if>> <<script>> jQuery(document).one(':passageend', function(){ function renderSell(){ var roster = SugarCube.State.variables.roster; var rival = SugarCube.State.variables.rival; var player = SugarCube.State.variables.player; var wrap = document.getElementById('sell-roster-container'); if(!wrap) return; if(roster.length === 0){ wrap.innerHTML = '<em>No talents left to sell.</em>'; return; } var html = '<div style="display:flex;flex-wrap:wrap;gap:10px;margin:10px 0;">'; roster.forEach(function(w, idx){ var sellPrice = Math.ceil(w.contractCost * 0.25); var file = w.name.toLowerCase().replace(/ /g,'_'); html += '<div style="background:#111;border:1px solid #333;border-radius:8px;padding:10px;text-align:center;width:140px;">'; html += '<img src="img/portraits/'+file+'.jpg" style="width:80px;height:80px;object-fit:cover;border-radius:6px;display:block;margin:0 auto 6px;">'; html += '<b style="font-size:0.9em;">'+w.name+'</b><br>'; html += '<small style="color:#888;">🌟 '+w.popularity+' | ❤️ '+w.satisfaction+'</small><br>'; html += '<small style="color:#4a9eff;">+$'+sellPrice.toLocaleString()+'</small><br>'; html += '<button data-idx="'+idx+'" data-price="'+sellPrice+'" style="margin-top:6px;padding:4px 10px;background:#1a1a2e;border:1px solid #cc4444;color:#cc4444;border-radius:4px;cursor:pointer;font-size:0.8em;">💸 Sell</button>'; html += '\x3c/div>'; }); html += '\x3c/div>'; wrap.innerHTML = html; wrap.querySelectorAll('button[data-idx]').forEach(function(btn){ btn.addEventListener('click', function(){ var idx = parseInt(this.getAttribute('data-idx')); var price = parseInt(this.getAttribute('data-price')); var w = SugarCube.State.variables.roster[idx]; if(!w) return; /* Remove from roster */ SugarCube.State.variables.roster.splice(idx, 1); window.cleanupQuestlineForLostStar(w.name); SugarCube.State.variables.player.money += price; /* 25% chance rival picks them up */ if(Math.random() < 0.25){ SugarCube.State.variables.poachMessage = (SugarCube.State.variables.poachMessage || '') + ' ' + w.name + ' was picked up by ' + SugarCube.State.variables.rival.name + ' — went to find out how massive they are.'; w.available = false; SugarCube.State.variables.rival.roster.push(w); } else { /* Return to recruit pool as available */ var pool = SugarCube.State.variables.recruitPool; var existing = pool.find(function(r){ return r.name === w.name; }); if(existing) existing.available = true; } /* Re-render */ SugarCube.Engine.play('SellContracts'); }); }); } renderSell(); }); <</script>> /* ════════════════════════════════════════════ PASSAGE : ZeroSatisfaction ════════════════════════════════════════════ */
<h1 style="margin:0 0 0.4em 0;">⚠️ Warning!</h1> <<set _zsFile = $zeroSatStar.toLowerCase().replace(/ /g, "_")>> <div style="text-align:center;margin:10px 0;"><img data-portrait-var="_zsFile" style="width:160px;height:160px;object-fit:cover;border-radius:12px;box-shadow:0 4px 16px rgba(0,0,0,0.5);" src=""></div> @@color:red;<<= $zeroSatStar>>'s satisfaction has dropped to critical levels!@@ She's not performing anymore — she's enduring it. The spark is gone. Keep this up and she'll walk straight into <<= $rival.name>>'s arms — and their bed. <em>Get her back on set fast — and give her what she actually enjoys.</em> <<set $zeroSatStar = "">> /* ── Questline: Asian Duo trigger ── */ <<if !$questlines.asianDuo.active && !$questlines.asianDuo.specialAvailable>> <<set _kimmy = $roster.find(function(w){ return w.name is "Kimmy"; })>> <<set _lulu = $roster.find(function(w){ return w.name is "Lulu"; })>> <<if _kimmy || _lulu>> <<set $questlines.asianDuo.active = true>> <<set $questlines.asianDuo.star1 = _kimmy ? "Kimmy" : "Lulu">> <<set $questlines.asianDuo.step = Math.max($questlines.asianDuo.step, 1)>> <</if>> <</if>> /* ── Asian Duo step progression ── */ <<if $questlines.asianDuo.active>> <<set _ql = $questlines.asianDuo>> <<set _s1 = $roster.find(function(w){ return w.name is _ql.star1; })>> <<set _kimmy2 = $roster.find(function(w){ return w.name is "Kimmy"; })>> <<set _lulu2 = $roster.find(function(w){ return w.name is "Lulu"; })>> <<if _ql.step is 1 && _s1 && _s1.satisfaction >= 25>> <<set _ql.step = 2>> <</if>> <<if _ql.step >= 2>> <<if _kimmy2 && _lulu2>> <<if !_ql.star2>> <<set _ql.star2 = (_ql.star1 is "Kimmy") ? "Lulu" : "Kimmy">> <<set _ql.step = 3>> <</if>> <</if>> <</if>> <<set _s2 = _ql.star2 ? $roster.find(function(w){ return w.name is _ql.star2; }) : null>> <<if _ql.step is 3 && _s2 && _s2.satisfaction >= 25>> <<set _ql.step = 4>> <<set _ql.specialAvailable = true>> <<set _ql.active = false>> <</if>> <</if>> [[⚠️ Understood — Go to Dashboard|Dashboard]]
<h1 style="margin:0 0 0.4em 0;">📖 Guide</h1><div style="font-size:0.95em;line-height:1.6;display:grid;gap:12px;margin:10px 0;"><div style="padding:12px 16px;background:linear-gradient(135deg,#1a1a2e,#16213e);border:1px solid #333;border-radius:10px;"><div style="font-size:1.1em;font-weight:700;margin-bottom:6px;">🎬 Production Earnings</div>Earnings = round((Reputation × 5 + Average Popularity × 50) × Trend Multiplier × Double Feature Bonus)<br>Trend Multiplier: <b>1.0×</b> no match, <b>1.3×</b> one physical trend matched, <b>1.6×</b> both matched<br>Reputation gained: <b>+1</b> normally, <b>+3</b> if you use today's trending position</div><div style="padding:12px 16px;background:linear-gradient(135deg,#1a1a2e,#16213e);border:1px solid #333;border-radius:10px;"><div style="font-size:1.1em;font-weight:700;margin-bottom:6px;">🌟 Double Feature ($5,000 · rep 50)</div>Two separate unlocks work together here: <b>reputation 25</b> (free) lets you pick a <b>2nd star</b>, buying Double Feature lets you pick a <b>2nd position</b> — either works on its own, you don't need both<br>Using 2 positions applies a <b>Double Feature Bonus</b> to earnings: <b>×1.x</b>, where x is the average rank of the two positions used (BJ=1, Missionary=2, Doggy=3, Cowgirl=4, Reverse Cowgirl=5, Spooning=6, Specialty 1=7, Specialty 2=8, Facial=9) — so anywhere from <b>×1.15</b> (BJ + Missionary) up to <b>×1.85</b> (Specialty 2 + Facial)<br>Picking a 2nd star instead adds the <b>average popularity</b> of both stars to the earnings formula, and gives two independent shots at the physical trend multiplier above<br>Also: with 2 positions, satisfaction gain from the <em>Satisfaction</em> card below applies once per position, so it's doubled that production, and you get two chances to match the trending position for the <b>+3</b> rep bonus</div><div style="padding:12px 16px;background:linear-gradient(135deg,#1a1a2e,#16213e);border:1px solid #333;border-radius:10px;"><div style="font-size:1.1em;font-weight:700;margin-bottom:6px;">❤️ Satisfaction</div>Gain per shoot: position level (1–9), or <b>×1.5</b> if it's one of her favorite positions<br><b>25 sat</b> — advances questlines, and the first star ever to reach it triggers the one-time Roxy recruit event<br><b>30 sat</b> — she picks a permanent second favorite position<br><b>>40 sat</b> — tolerates 1 extra day before decay starts<br><b>≤5 sat</b> — critical alert fires<br>Decay: <b>−5/day</b> once she goes 4+ days (5+ with Patience Training, +1 more if she's already above 40) without a shoot<br><b>100 sat</b> — locked in: no more decay, and the rival can never poach her</div><div style="padding:12px 16px;background:linear-gradient(135deg,#1a1a2e,#16213e);border:1px solid #333;border-radius:10px;"><div style="font-size:1.1em;font-weight:700;margin-bottom:6px;">🌟 Popularity & 💸 Upkeep</div>Popularity: <b>+1</b> every 3rd production (counts double toward that if you used the trending position)<br>Upkeep: <b>Popularity × 70</b> per star, charged every 7th day for the whole roster at once<br>New signings are prorated — only charged for the days they've actually been on the roster during their first week<br>Going negative forces a sell-off: <b>25%</b> of contract cost each, <b>25%</b> chance the rival picks her up instead</div><div style="padding:12px 16px;background:linear-gradient(135deg,#1a1a2e,#16213e);border:1px solid #333;border-radius:10px;"><div style="font-size:1.1em;font-weight:700;margin-bottom:6px;">🔓 Position Satisfaction Requirements</div>A star must be at this satisfaction to be filmed in the position, on top of it being bought in the Shop:<br>BJ <b>0</b> · Missionary <b>10</b> · Doggy <b>20</b> · Cowgirl <b>30</b> · Reverse Cowgirl <b>40</b> · Spooning <b>50</b> · Specialty 1 <b>60</b> · Specialty 2 <b>70</b> · Facial <b>80</b></div><div style="padding:12px 16px;background:linear-gradient(135deg,#1a1a2e,#16213e);border:1px solid #333;border-radius:10px;"><div style="font-size:1.1em;font-weight:700;margin-bottom:6px;">📋 Contracts & Releasing Talent</div>Standard Contract: <b>$200</b> to accept, <b>+$500 / +3 rep</b> on success, <b>−2 rep</b> on failure<br>Harder Contract: <b>$500</b> to accept, <b>+$1,500 / +5 rep</b> on success, <b>−5 rep</b> on failure<br>Let Go (Roster, anytime): <b>30%</b> of contract cost, no strings attached<br>Sell Contracts (forced when broke): <b>25%</b> of contract cost, 25% rival-poach risk</div><div style="padding:12px 16px;background:linear-gradient(135deg,#1a1a2e,#16213e);border:1px solid #333;border-radius:10px;"><div style="font-size:1.1em;font-weight:700;margin-bottom:6px;">🏆 Contest</div>First contest on <b>day 35</b>, then every <b>7 days</b> after<br>Entering costs <b>$500</b> (or refuse for free and wait for the next one) — pay it after seeing the full judging pool, before picking any entrants<br>Pick 1 or 2 stars to enter, both free to pick once you've joined. Both gain <b>+2 satisfaction</b> and their decay resets, and it uses up your production for the day<br>2 judges are secretly drawn from a pool of 6 right after the previous contest ends<br>You then pick which entrant actually performs, and which position she knows well enough to use<br>Scoring per judge: <b>2+ hated things matched → 0</b> (overrides everything for that judge), <b>1 hated thing → −3</b>, <b>each liked thing matched → +3</b> (stacks up to +9)<br>If <b>any</b> judge hits 2+ hated things, the <b>whole contest</b> is wiped to $0/no rep, even if the other judge loved it<br>Reward by total score: <b>under 3</b> nothing, <b>3–5</b> $500, <b>6+</b> $1,000 + 2 rep<br>Jackpot: a judge matching <b>all 3</b> of their liked things with <b>zero</b> hated ones → <b>$2,000 + 5 rep</b>, overriding every other tier<br>The performing star also gains <b>+2 satisfaction</b> (score 2–6), <b>+4</b> (score above 6), or <b>−2</b> (score exactly 0 — losing back her entry bonus)</div><div style="padding:12px 16px;background:linear-gradient(135deg,#1a1a2e,#16213e);border:1px solid #333;border-radius:10px;"><div style="font-size:1.1em;font-weight:700;margin-bottom:6px;">🕵️ Judge Intel & Judge Stats (Shop, from day 36)</div><b>Unlock Stat</b> $800 — pick a judge, guaranteed permanent reveal of one of their hidden preferences<br><b>Guess</b> $300 ($100 for Gambler), once per day — pick a judge, guess 1 of 3 options for a hidden preference; right guess unlocks it for good, wrong guess still costs the money<br><b>Judge Intel I</b> $400, ×3 — unlocks once Unlock Stat + Guess have been used <b>4 times combined</b> (any mix); reveals one upcoming judge's identity per purchase<br><b>Improve Intel</b> $1,500 — unlocks once Judge Intel I is bought 3 times<br><b>Judge Intel II</b> $700, ×3 — reveals <b>both</b> upcoming judges' identity per purchase<br><b>Permanent Judge Intel</b> $3,000 — unlocks once Judge Intel II is bought 3 times; once bought, always know both judges automatically<br>Confirmed judges glow gold with a 👁️ CONFIRMED badge wherever their card appears</div><div style="padding:12px 16px;background:linear-gradient(135deg,#1a1a2e,#16213e);border:1px solid #333;border-radius:10px;"><div style="font-size:1.1em;font-weight:700;margin-bottom:6px;">🟢 Easy Mode</div>Talents tolerate <b>2 extra days</b> before satisfaction decay kicks in, and weekly upkeep is <b>30% cheaper</b><br>In exchange, <b>no trophies</b> can be earned for the rest of that playthrough — chosen at the start, from the archetype screen</div></div>[[⬅️ Dashboard|Dashboard]]
<<set $questlines.sweetCaprice.step2Notified = true>> <h1 style="margin:0 0 0.4em 0;">🍬 Sweet Caprice — Step 2</h1> <div style="text-align:center;margin:10px 0;"><img src="img/portraits/caprice.jpg" style="width:150px;height:150px;object-fit:cover;border-radius:12px;box-shadow:0 4px 16px rgba(0,0,0,0.5);"></div> <b>Caprice</b> catches you in the hallway between shoots, still a little breathless, hair a mess in a way that somehow works for her. <em>"Okay, so — I've been thinking." She leans in, lowering her voice like she's letting you in on a secret. "I'm happy here. Genuinely. And I want to show you exactly how happy."</em> <em>She traces a finger down your chest, grinning up at you with something equal parts sweet and filthy. "I want to make this my thing. Give me six scenes, just me on my knees, and I'll make sure every single one is better than the last."</em> <em>"And trust me... by the sixth one, you'll want to reward me properly."</em> @@color:cyan;➡️ Shoot 6 BJ productions with Caprice.@@ [[📊 Dashboard|Dashboard]]
<<set $questlines.sweetCaprice.step3Notified = true>> <h1 style="margin:0 0 0.4em 0;">🍬 Sweet Caprice — Step 3</h1> <div style="text-align:center;margin:10px 0;"><img src="img/portraits/caprice.jpg" style="width:150px;height:150px;object-fit:cover;border-radius:12px;box-shadow:0 4px 16px rgba(0,0,0,0.5);"></div> Six scenes in, and Caprice has more than kept her word — the crew talks about her takes between setups, and the numbers back it up. <em>She finds you after the last one, still catching her breath, lipstick smeared just enough to be dangerous. "Told you I'd earn it." She straightens up, eyes locked on yours.</em> <em>"Okay, so — I have a surprise. There's someone I want you to meet. Eve." A grin spreads across her face, equal parts mischief and anticipation. "We go way back. And when I told her about this place, about you... she got very interested."</em> <em>"Give me a few days to set it up. Trust me — you're going to want to clear your schedule for this one."</em> @@color:cyan;➡️ Eve is coming. Give it a few days.@@ [[📊 Dashboard|Dashboard]]
<<set $questlines.sweetCaprice.step4Notified = true>> <h1 style="margin:0 0 0.4em 0;">🍬 Sweet Caprice — Eve Arrives</h1> <div style="text-align:center;margin:10px 0;"><img src="img/portraits/caprice.jpg" style="width:150px;height:150px;object-fit:cover;border-radius:12px;box-shadow:0 4px 16px rgba(0,0,0,0.5);"></div> A few days later, Caprice practically drags a new face through your door — tall, confident, already sizing up the studio like she owns half of it. <em>"This is Eve." Caprice can barely contain herself. "Eve, this is the guy I told you about."</em> <em>Eve looks you over slowly, unhurried, a small smile pulling at the corner of her mouth. "Caprice talks about you a lot. I had to see what the fuss was about." She glances at Caprice, then back at you. "We're ready whenever you are."</em> Caprice just laughs and threads her fingers through Eve's like it's the most natural thing in the world. @@color:gold;🌟 Sweet Caprice Special Shooting now available in the menu!@@ [[📊 Dashboard|Dashboard]]
<<set _caprice1 = $roster.find(function(w){ return w.name is "Caprice"; })>> <<if _caprice1>><<set _caprice1.popularity += 2>><<set _caprice1.lastShootingDay = $player.day>><</if>> <<set $player.money += 1500>> <<set $player.reputation += 2>> <<set $questlines.sweetCaprice.shooting1Done = true>> <<set $shootingPlayedToday = true>> <<set $capriceShoot1Day = $player.day>> <h1 style="margin:0 0 0.4em 0;">🎬 Sweet Caprice — Collab 1</h1> <div style="text-align:center;margin:12px 0;"><img src="img/portraits/caprice.jpg" style="width:150px;height:150px;object-fit:cover;border-radius:12px;box-shadow:0 4px 16px rgba(0,0,0,0.5);"></div> Eve and Caprice don't wait for direction. The moment the cameras roll, they're already reaching for each other, fingers working at buttons and straps like they've done this a hundred times before. <em>Caprice peels Eve's top off first, slow, deliberate, watching her own hands like she wants you to watch them too. Eve returns the favor without breaking eye contact with the lens, undoing Caprice piece by piece until neither of them has anywhere left to hide.</em> <div id="caprice-shoot1a-video-wrap" style="text-align:center;margin:10px 0;"></div><<script>>jQuery(document).one(':passageend',function(){var el=document.getElementById('caprice-shoot1a-video-wrap');if(!el)return;var v=document.createElement('video');v.src='videos/shoot1a.webm';v.autoplay=true;v.loop=true;v.muted=true;v.playsInline=true;v.controls=true;v.style.width='100%';v.style.maxWidth='480px';v.style.borderRadius='8px';v.onerror=function(){this.style.display='none';};el.appendChild(v);});<</script>> <em>Once there's nothing left between them, Eve pushes Caprice back onto the sheets and takes her time — mouth trailing lower, unhurried, savoring every reaction she pulls out of her. Caprice's fingers tangle in Eve's hair, guiding without rushing, lost in it completely.</em> <div id="caprice-shoot1b-video-wrap" style="text-align:center;margin:10px 0;"></div><<script>>jQuery(document).one(':passageend',function(){var el=document.getElementById('caprice-shoot1b-video-wrap');if(!el)return;var v=document.createElement('video');v.src='videos/shoot1b.webm';v.autoplay=true;v.loop=true;v.muted=true;v.playsInline=true;v.controls=true;v.style.width='100%';v.style.maxWidth='480px';v.style.borderRadius='8px';v.onerror=function(){this.style.display='none';};el.appendChild(v);});<</script>> Nobody on the crew moves until it's over. Whatever history these two share, it's all right there on camera. @@color:gold;🌟 Caprice: +2 popularity@@ @@color:gold;💰 +$1,500 earnings@@ @@color:gold;🌟 +2 reputation@@ <em>A second special shooting will be available!</em> [[📊 Dashboard|Dashboard]] | [[🌟 Special Shootings|SpecialShootingMenu]]
<h1 style="margin:0 0 0.4em 0;">🍬 Sweet Caprice — Good News</h1> <div style="text-align:center;margin:10px 0;"><img src="img/portraits/caprice.jpg" style="width:120px;height:120px;object-fit:cover;border-radius:10px;"></div> Caprice catches up with you a few days later, still glowing from the reaction the first scene got online — and Eve is right behind her. <em>"Okay, we need to do that again." Caprice is practically bouncing. Eve just leans against the doorway, arms crossed, smirking. "This time, though, it's about you."</em> @@color:gold;🍬 Second special shooting now available!@@ [[⭐ Special Shootings|SpecialShootingMenu]] | [[📊 Dashboard|Dashboard]]
<<set _caprice2 = $roster.find(function(w){ return w.name is "Caprice"; })>> <<if _caprice2>><<set _caprice2.popularity += 3>><<set _caprice2.lastShootingDay = $player.day>><</if>> <<set $player.money += 3000>> <<set $player.reputation += 3>> <<set $questlines.sweetCaprice.shooting2Done = true>> <<set $shootingPlayedToday = true>> <h1 style="margin:0 0 0.4em 0;">🎬 Sweet Caprice — Collab 2</h1> <div style="text-align:center;margin:12px 0;"><img src="img/portraits/caprice.jpg" style="width:150px;height:150px;object-fit:cover;border-radius:12px;box-shadow:0 4px 16px rgba(0,0,0,0.5);"></div> Eve is back, and this time neither of them wastes a second on foreplay for the camera — they both know exactly who this scene is for. <em>Caprice drops to her knees first, pulling Eve down right beside her, the two of them trading you off between them like they planned every second of it in advance. Whatever rivalry there might've been between them evaporates completely — they work together, in sync, each one making sure the other never lets up.</em> <div id="caprice-shoot2-video-wrap" style="text-align:center;margin:10px 0;"></div><<script>>jQuery(document).one(':passageend',function(){var el=document.getElementById('caprice-shoot2-video-wrap');if(!el)return;var v=document.createElement('video');v.src='videos/shoot2.webm';v.autoplay=true;v.loop=true;v.muted=true;v.playsInline=true;v.controls=true;v.style.width='100%';v.style.maxWidth='480px';v.style.borderRadius='8px';v.onerror=function(){this.style.display='none';};el.appendChild(v);});<</script>> <em>Afterward, the two of them collapse against each other, laughing about something only they understand. "Told you," Caprice says to Eve, still catching her breath. Eve just grins.</em> By the time the footage is logged, everyone on set agrees — this is the one people are going to talk about. @@color:gold;🌟 Caprice: +3 popularity@@ @@color:gold;💰 +$3,000 earnings@@ @@color:gold;🌟 +3 reputation@@ @@color:gold;🍬 Sweet Caprice questline complete!@@ [[📊 Dashboard|Dashboard]]
<h1 style="margin:0 0 0.4em 0;">🏆 Industry Contest</h1> A courier drops off a formal invitation — the industry's seasonal Contest is back. <em>Every so often, a panel of judges holds a contest and scores productions purely on their own personal taste. You won't find out who's judging until after you've already committed your talent — so choose wisely, and pay attention to what worked once the results come in.</em> <div style="font-weight:700;margin:10px 0 6px 0;">This season's judging pool:</div> <div id="ci-judges-wrap"></div> <<script>> jQuery(document).one(':passageend', function(){ var sv = SugarCube.State.variables; var wrap = document.getElementById('ci-judges-wrap'); wrap.innerHTML = window.renderJudgeGrid(sv.judges, sv.contestJudges, sv.contestJudgesKnown, sv.contestJudgeRevealed, 'ci-judge', 3, 80); window.resolveJudgeCardPortraits(sv.judges, 'ci-judge'); }); <</script>> <<set $contestIntroSeen = true>> <<if $player.money < 500>> @@color:red;Not enough funds to enter ($500 required).@@ [[❌ Refuse — no cost|ContestRefuse]] <<else>> [[✅ Join — $500|ContestJoin]] | [[❌ Refuse — no cost|ContestRefuse]] <</if>>
<<set $player.money -= 500>><<set $contestJoined = true>><<goto "ContestPickStars">>
<h1 style="margin:0 0 0.4em 0;">🏆 Contest</h1> You decide to sit this one out. No cost, no reward — you'll get another shot at the next Contest. <<set $contestPending = false>> <<set $contestNextDay += 7>> <<set $contestIntroSeen = false>> <<set $contestJoined = false>> [[📊 Dashboard|Dashboard]]
<h1 style="margin:0 0 0.4em 0;">🏆 Contest — Choose Your First Entrant</h1> <<if $roster.length < 2>> You need at least <b>2 stars</b> in your roster to enter this contest. Come back once you've recruited more talent. [[📊 Dashboard|Dashboard]] <<else>> Pick your <b>first</b> entrant. Unless you've bought intel in the Shop, you still don't know who's judging. <div style="font-weight:700;margin:10px 0 6px 0;">This season's judging pool:</div> <div id="ps1-judges-wrap"></div> <<script>> jQuery(document).one(':passageend', function(){ var sv = SugarCube.State.variables; var wrap = document.getElementById('ps1-judges-wrap'); wrap.innerHTML = window.renderJudgeGrid(sv.judges, sv.contestJudges, sv.contestJudgesKnown, sv.contestJudgeRevealed, 'ps1-judge', 3, 80); window.resolveJudgeCardPortraits(sv.judges, 'ps1-judge'); }); <</script>> <div id="contest-star-table"></div> <<script>> jQuery(document).one(':passageend', function(){ buildStarTable( SugarCube.State.variables.roster, SugarCube.State.variables.trends, -1, 'contest-star-table', function(idx){ SugarCube.State.variables.contestPick1 = idx; SugarCube.Engine.play('ContestPickStars2'); }, '⚠️ No talents available.', false, true ); }); <</script>> [[⬅️ Dashboard|Dashboard]] <</if>>
<h1 style="margin:0 0 0.4em 0;">🏆 Contest — Choose Your Second Entrant</h1> First entrant: <b><<= $roster[$contestPick1].name>></b>. Unless you've bought intel in the Shop, you still don't know who's judging. <div style="font-weight:700;margin:10px 0 6px 0;">This season's judging pool:</div> <div id="ps2-judges-wrap"></div> <<script>> jQuery(document).one(':passageend', function(){ var sv = SugarCube.State.variables; var wrap = document.getElementById('ps2-judges-wrap'); wrap.innerHTML = window.renderJudgeGrid(sv.judges, sv.contestJudges, sv.contestJudgesKnown, sv.contestJudgeRevealed, 'ps2-judge', 3, 80); window.resolveJudgeCardPortraits(sv.judges, 'ps2-judge'); }); <</script>> <div id="contest-star-table2"></div> <<script>> jQuery(document).one(':passageend', function(){ buildStarTable( SugarCube.State.variables.roster, SugarCube.State.variables.trends, SugarCube.State.variables.contestPick1, 'contest-star-table2', function(idx){ var sv = SugarCube.State.variables; var _w1 = sv.roster[sv.contestPick1]; var _w2 = sv.roster[idx]; _w1.satisfaction = Math.min(100, _w1.satisfaction + 2); _w1.lastShootingDay = sv.player.day; _w2.satisfaction = Math.min(100, _w2.satisfaction + 2); _w2.lastShootingDay = sv.player.day; sv.shootingPlayedToday = true; sv.contestStars = [_w1.name, _w2.name]; SugarCube.Engine.play('ContestJudgeReveal'); }, '⚠️ You need at least 2 talents available for this contest.', false, true ); }); <</script>> [[⬅️ Back|ContestPickStars]]
<<if $contestJudges.length isnot 2>><<drawContestJudges>><</if>> <h1 style="margin:0 0 0.4em 0;">🏆 Contest — The Judges</h1> Your entrants: <b><<= $contestStars[0]>></b> and <b><<= $contestStars[1]>></b>. The panel takes their seats. <div id="cjr-judges-wrap"></div> <<script>> jQuery(document).one(':passageend', function(){ var sv = SugarCube.State.variables; var wrap = document.getElementById('cjr-judges-wrap'); var liveContestJudges = sv.contestJudges.map(function(cj){ return sv.judges.find(function(j){ return j.name === cj.name; }) || cj; }); wrap.innerHTML = window.renderJudgeGrid(liveContestJudges, liveContestJudges, sv.contestJudgesKnown, sv.contestJudgeRevealed, 'cjr-judge', 2, 100); window.resolveJudgeCardPortraits(liveContestJudges, 'cjr-judge'); }); <</script>> [[Continue →|ContestChoose][$contestJudgesRevealed = true]]
<h1 style="margin:0 0 0.4em 0;">🏆 Contest — Your Entry</h1> <div id="cc-judges-wrap"></div> <<script>> jQuery(document).one(':passageend', function(){ var sv = SugarCube.State.variables; var wrap = document.getElementById('cc-judges-wrap'); if(!wrap) return; var liveContestJudges = sv.contestJudges.map(function(cj){ return sv.judges.find(function(j){ return j.name === cj.name; }) || cj; }); wrap.innerHTML = window.renderJudgeGrid(liveContestJudges, liveContestJudges, sv.contestJudgesKnown, sv.contestJudgeRevealed, 'cc-judge', 2, 100); window.resolveJudgeCardPortraits(liveContestJudges, 'cc-judge'); }); <</script>> <<if $contestChosenStar is "">> Who will you put forward? <div id="contest-choose-table"></div> <<script>> jQuery(document).one(':passageend', function(){ var sv = SugarCube.State.variables; var entrants = sv.contestStars.map(function(n){ return sv.roster.find(function(w){ return w.name === n; }); }); buildStarTable(entrants, sv.trends, -1, 'contest-choose-table', function(idx){ sv.contestChosenStar = entrants[idx].name; SugarCube.Engine.play('ContestChoose'); }, 'No entrants found.', false, true); }); <</script>> <<else>> <<set _cw = $roster.find(function(w){ return w.name is $contestChosenStar; })>> Choose a position <b><<= _cw.name>></b> knows well enough to perform: <div style="display:flex;flex-wrap:wrap;gap:6px;justify-content:center;margin:10px 0;"><<for _cpi = 0; _cpi < $playerPositions.length; _cpi++>><<set _cpn = $playerPositions[_cpi]>><<set _cpReal = "">><<if _cpn is "Specialty 1">><<set _cpReal = _cw.specialty1>><<elseif _cpn is "Specialty 2">><<set _cpReal = _cw.specialty2>><<else>><<set _cpReal = _cpn>><</if>><<set _cpMissing = (_cpn is "Specialty 1" || _cpn is "Specialty 2") && !_cpReal>><<if !_cpMissing>><<set _cpo = $allPositions.find(function(p){ return p.name is _cpn; })>><<set _cpMinSat = _cpo ? (_cpo.minSat || 0) : 0>><<if _cw.satisfaction >= _cpMinSat>><<print "[[" + _cpReal + "|ContestResult][\$contestChosenPosition = \"" + _cpReal + "\"]]">><<else>><span style="opacity:0.4;padding:3px 8px;" title="Requires <<= _cpMinSat>> satisfaction">🔒 <<= _cpReal>></span><</if>><</if>><</for>></div> <</if>>
<<set _cw = $roster.find(function(w){ return w.name is $contestChosenStar; })>> <<set _totalScore = 0>> <h1 style="margin:0 0 0.4em 0;">🏆 Contest — Results</h1> <b><<= _cw.name>></b> performed <b><<= $contestChosenPosition>></b> for the panel. <<set _judgeScores = []>> <<set _anyJackpot = false>> <<set _anyHateWipe = false>> <<for _rji = 0; _rji < $contestJudges.length; _rji++>> <<set _rj = $contestJudges[_rji]>> <<set _likeCount = 0>> <<set _hateCount = 0>> <<for _rpi = 0; _rpi < _rj.pref.likePhysical.length; _rpi++>> <<set _rlp = _rj.pref.likePhysical[_rpi]>> <<if _cw[_rlp.type] is _rlp.value>><<set _likeCount += 1>><</if>> <</for>> <<for _rhi = 0; _rhi < _rj.pref.hatePhysical.length; _rhi++>> <<set _rhp = _rj.pref.hatePhysical[_rhi]>> <<if _cw[_rhp.type] is _rhp.value>><<set _hateCount += 1>><</if>> <</for>> <<if $contestChosenPosition is _rj.pref.likePosition>><<set _likeCount += 1>><<elseif $contestChosenPosition is _rj.pref.hatePosition>><<set _hateCount += 1>><</if>> <<if _likeCount is 3 && _hateCount is 0>><<set _anyJackpot = true>><</if>> <<if _hateCount >= 2>> <<set _rjScore = 0>> <<set _anyHateWipe = true>> <<else>> <<set _rjScore = (_hateCount is 1 ? -3 : 0) + (_likeCount * 3)>> <</if>> <<set _totalScore += _rjScore>> <<set _judgeScores.push(_rjScore)>> <</for>> <<if _anyHateWipe>> <<set _totalScore = 0>> <<set _anyJackpot = false>> <</if>> <<if _totalScore is 0>> <<set _satDelta = -2>> <<elseif _totalScore > 6>> <<set _satDelta = 4>> <<elseif _totalScore >= 2>> <<set _satDelta = 2>> <<else>> <<set _satDelta = 0>> <</if>> <<set _satLocked = (_cw.satisfaction >= 100 && _satDelta < 0)>> <<set _cw.satisfaction = _satLocked ? 100 : Math.max(0, Math.min(100, _cw.satisfaction + _satDelta))>> <div style="background:linear-gradient(135deg,#1a1a2e,#16213e);border:1px solid #333;border-radius:10px;padding:10px;margin:8px 0;"> <div style="display:flex;align-items:center;gap:10px;"> <img id="cr-judge-0" style="width:60px;height:60px;object-fit:cover;border-radius:8px;" src=""> <div><b><<= $contestJudges[0].name>></b><br><span style="color:<<if _judgeScores[0] > 0>>#6fcf73<<elseif _judgeScores[0] < 0>>#ff7a7a<<else>>#888<</if>>;font-weight:700;">Score: <<= _judgeScores[0]>></span></div> </div> </div> <div style="background:linear-gradient(135deg,#1a1a2e,#16213e);border:1px solid #333;border-radius:10px;padding:10px;margin:8px 0;"> <div style="display:flex;align-items:center;gap:10px;"> <img id="cr-judge-1" style="width:60px;height:60px;object-fit:cover;border-radius:8px;" src=""> <div><b><<= $contestJudges[1].name>></b><br><span style="color:<<if _judgeScores[1] > 0>>#6fcf73<<elseif _judgeScores[1] < 0>>#ff7a7a<<else>>#888<</if>>;font-weight:700;">Score: <<= _judgeScores[1]>></span></div> </div> </div> <<set _resultJudge0Portrait = $contestJudges[0].portrait>> <<set _resultJudge1Portrait = $contestJudges[1].portrait>> <<script>> jQuery(document).one(':passageend', function(){ var tv = SugarCube.State.temporary; var _img0 = document.getElementById('cr-judge-0'); if(_img0) _img0.src = 'img/portraits/'+tv.resultJudge0Portrait+'.jpg'; var _img1 = document.getElementById('cr-judge-1'); if(_img1) _img1.src = 'img/portraits/'+tv.resultJudge1Portrait+'.jpg'; }); <</script>> <<if _anyJackpot>> <<set _moneyReward = 2000>> <<set _repReward = 5>> <<if !$easyMode && !$trophies.perfectJudge>><<set $trophies.perfectJudge = true>><<set $newTrophy = "🏆 Perfect Judge — won a Contest with a judge who loved everything about your entry!">><<run window.checkAllTrophies()>><</if>> <<elseif _totalScore >= 6>> <<set _moneyReward = 1000>> <<set _repReward = 2>> <<elseif _totalScore >= 3>> <<set _moneyReward = 500>> <<set _repReward = 0>> <<else>> <<set _moneyReward = 0>> <<set _repReward = 0>> <</if>> <<set $player.money += _moneyReward>> <<set $player.reputation += _repReward>> <div style="padding:10px 14px;background:#111;border-radius:8px;margin:10px 0;text-align:center;"> <b>Total score: <<= _totalScore>></b><br> @@color:gold;💰 +$<<= _moneyReward.toLocaleString()>>@@ @@color:#4a9eff;🌟 +<<= _repReward>> rep@@<br> <<if _satLocked>>@@color:gold;🔒 <<= _cw.name>> is locked in at 100 satisfaction — no loss@@<<elseif _satDelta > 0>>@@color:#6fcf73;<<= _cw.name>> satisfaction +<<= _satDelta>>@@<<elseif _satDelta < 0>>@@color:#ff7a7a;<<= _cw.name>> satisfaction <<= _satDelta>>@@<</if>> </div> <<set $contestPending = false>> <<set $contestIntroSeen = false>> <<set $contestJoined = false>> <<set $contestStars = []>> <<set $contestChosenStar = "">> <<set $contestChosenPosition = "">> <<set $contestJudgesRevealed = false>> <<set $totalContestsCompleted += 1>> <<if !$easyMode && !$trophies.contestRegular && $totalContestsCompleted >= 5>><<set $trophies.contestRegular = true>><<set $newTrophy = "🏆 Contest Regular — completed 5 Contests!">><<run window.checkAllTrophies()>><</if>> <<set $contestNextDay += 7>> <<drawContestJudges>> <<set $contestJudgesKnown = $permanentJudgeIntelItem.bought>> <<set $contestJudgeRevealed = [false, false]>> <em style="color:#888;">Next contest in 7 days.</em> [[📊 Dashboard|Dashboard]]
<h1 style="margin:0 0 0.4em 0;">🏆 Contest</h1> <<if $contestPending>> <div style="padding:10px 14px;background:linear-gradient(135deg,#2a2410,#1a1a2e);border:2px solid #ffd700;border-radius:10px;box-shadow:0 0 14px rgba(255,215,0,0.25);margin-bottom:10px;"> You have a contest in progress. <<if !$contestJoined>>[[Resume →|ContestIntro]]<<elseif $contestStars.length < 2>>[[Resume →|ContestPickStars]]<<elseif !$contestJudgesRevealed>>[[Resume →|ContestJudgeReveal]]<<else>>[[Resume →|ContestChoose]]<</if>> </div> <<elseif $contestNextDay > 35>> <div style="padding:10px 14px;background:#111;border-radius:8px;margin-bottom:10px;text-align:center;"> Next contest: <b><<= Math.max(0, $contestNextDay - $player.day)>> day(s)</b> <em style="color:#888;">(day <<= $contestNextDay>>)</em> </div> <<if $contestJudgesKnown>> <div style="padding:8px 14px;background:linear-gradient(135deg,#1a2e1a,#16213e);border:1px solid #2a7a3a;border-radius:8px;margin-bottom:10px;text-align:center;"> 🕵️ Confirmed judges: <b><<= $contestJudges[0].name>></b> & <b><<= $contestJudges[1].name>></b> </div> <<elseif $contestJudgeRevealed[0] || $contestJudgeRevealed[1]>> <div style="padding:8px 14px;background:linear-gradient(135deg,#1a2e1a,#16213e);border:1px solid #2a7a3a;border-radius:8px;margin-bottom:10px;text-align:center;"> 🕵️ One judge scouted: <b><<= $contestJudgeRevealed[0] ? $contestJudges[0].name : $contestJudges[1].name>></b> <em style="color:#888;">— the other stays unknown</em> </div> <</if>> <<else>> <div style="padding:10px 14px;background:#111;border-radius:8px;margin-bottom:10px;text-align:center;color:#888;"> The industry's seasonal Contest hasn't been announced yet. You'll have to wait until <b>day <<= $contestNextDay>></b> (<<= Math.max(0, $contestNextDay - $player.day)>> day(s) to go). </div> <</if>> <div style="font-weight:700;margin:10px 0 6px 0;">This season's judging pool:</div> <div id="info-judges-wrap"></div> <<script>> jQuery(document).one(':passageend', function(){ var sv = SugarCube.State.variables; var wrap = document.getElementById('info-judges-wrap'); wrap.innerHTML = window.renderJudgeGrid(sv.judges, sv.contestJudges, sv.contestJudgesKnown, sv.contestJudgeRevealed, 'info-judge', 3, 80); window.resolveJudgeCardPortraits(sv.judges, 'info-judge'); }); <</script>> [[⬅️ Dashboard|Dashboard]]
<<if $player.money < $judgeIntel1.price>>@@color:red;Not enough funds ($<<= $judgeIntel1.price>> required).@@ [[⬅️ Shop|Shop]]<<else>> <<set $player.money -= $judgeIntel1.price>> <<set $judgeIntel1.buyCount += 1>> <<set $contestJudgeRevealed[0] = true>> ✅ <b>Judge Intel I</b> purchased (<<= $judgeIntel1.buyCount>>/3)! You've learned the identity of one of the two upcoming Contest judges. <div style="padding:8px 14px;background:linear-gradient(135deg,#1a2e1a,#16213e);border:1px solid #2a7a3a;border-radius:8px;margin-top:6px;text-align:center;"> 🕵️ <b><<= $contestJudges[0].name>></b> </div> [[🛒 Keep shopping|Shop]] | [[📊 Dashboard|Dashboard]]<</if>>
<<if $player.money < $improveIntelItem.price>>@@color:red;Not enough funds ($<<= $improveIntelItem.price>> required).@@ [[⬅️ Shop|Shop]]<<else>> <<set $player.money -= $improveIntelItem.price>> <<set $improveIntelItem.bought = true>> ✅ <b>Improve Intel</b> purchased! <b>Judge Intel II</b> is now available in the Shop. [[🛒 Keep shopping|Shop]] | [[📊 Dashboard|Dashboard]]<</if>>
<<if $player.money < $judgeIntel2.price>>@@color:red;Not enough funds ($<<= $judgeIntel2.price>> required).@@ [[⬅️ Shop|Shop]]<<else>> <<set $player.money -= $judgeIntel2.price>> <<set $judgeIntel2.buyCount += 1>> <<set $contestJudgesKnown = true>> ✅ <b>Judge Intel II</b> purchased (<<= $judgeIntel2.buyCount>>/3)! You've learned the identity of BOTH upcoming Contest judges. <div style="padding:8px 14px;background:linear-gradient(135deg,#1a2e1a,#16213e);border:1px solid #2a7a3a;border-radius:8px;margin-top:6px;text-align:center;"> 🕵️ <b><<= $contestJudges[0].name>></b> & <b><<= $contestJudges[1].name>></b> </div> [[🛒 Keep shopping|Shop]] | [[📊 Dashboard|Dashboard]]<</if>>
<<if $player.money < $permanentJudgeIntelItem.price>>@@color:red;Not enough funds ($<<= $permanentJudgeIntelItem.price>> required).@@ [[⬅️ Shop|Shop]]<<else>> <<set $player.money -= $permanentJudgeIntelItem.price>> <<set $permanentJudgeIntelItem.bought = true>> <<set $contestJudgesKnown = true>> ✅ <b>Permanent Judge Intel</b> purchased! From now on, you'll always know both judges for the upcoming Contest as soon as they're set. <div style="padding:8px 14px;background:linear-gradient(135deg,#1a2e1a,#16213e);border:1px solid #2a7a3a;border-radius:8px;margin-top:6px;text-align:center;"> 🕵️ <b><<= $contestJudges[0].name>></b> & <b><<= $contestJudges[1].name>></b> </div> [[🛒 Keep shopping|Shop]] | [[📊 Dashboard|Dashboard]]<</if>>
<h1 style="margin:0 0 0.4em 0;">🕵️ Unlock a Judge Stat</h1> Choose a judge to permanently reveal one of their hidden preferences for <b>$800</b>, guaranteed. <div id="unlock-judge-picker"></div> <<script>> jQuery(document).one(':passageend', function(){ var sv = SugarCube.State.variables; var wrap = document.getElementById('unlock-judge-picker'); var html = '<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:10px;">'; for (var i=0;i<sv.judges.length;i++){ var j = sv.judges[i]; var left = window.getUnrevealedSlots(j).length; var disabled = left === 0 || sv.player.money < sv.unlockJudgeStatItem.price; html += '<div class="judge-pick-card" data-idx="'+i+'" style="cursor:'+(disabled?'default':'pointer')+';opacity:'+(disabled?'0.4':'1')+';background:linear-gradient(135deg,#1a1a2e,#16213e);border:1px solid #333;border-radius:10px;padding:10px;text-align:center;">' + '<img id="usp-judge-'+i+'" style="width:70px;height:70px;object-fit:cover;border-radius:8px;" src="">' + '<div style="font-weight:700;margin-top:6px;">'+j.name+'</div>' + '<div style="font-size:0.75em;color:#888;margin-top:2px;">'+(left===0?'Fully known':(left+' unknown'))+'</div>' + '</div>'; } html += '</div>'; wrap.innerHTML = html; window.resolveJudgeCardPortraits(sv.judges, 'usp-judge'); wrap.querySelectorAll('.judge-pick-card').forEach(function(card){ var idx = parseInt(card.getAttribute('data-idx')); var j = sv.judges[idx]; if (window.getUnrevealedSlots(j).length === 0 || sv.player.money < sv.unlockJudgeStatItem.price) return; card.addEventListener('click', function(){ sv.player.money -= sv.unlockJudgeStatItem.price; sv.unlockJudgeStatItem.buyCount = (sv.unlockJudgeStatItem.buyCount || 0) + 1; var slot = window.pickRandomFrom(window.getUnrevealedSlots(j)); window.slotSetRevealed(j, slot); window.checkFullPanelTrophy(j); sv.judgeStatPickIdx = idx; sv.guessSlotCat = slot.cat; sv.guessSlotIdx = (slot.idx !== undefined) ? slot.idx : -1; SugarCube.Engine.play('UnlockStatResult'); }); }); }); <</script>> [[⬅️ Shop|Shop]]
<<set _j = $judges[$judgeStatPickIdx]>> <<set _slot = ($guessSlotIdx >= 0) ? { cat: $guessSlotCat, idx: $guessSlotIdx } : { cat: $guessSlotCat }>> <h1 style="margin:0 0 0.4em 0;">🕵️ Stat Unlocked!</h1> You paid off a contact close to <b><<= _j.name>></b>. You now know: <div style="padding:12px 16px;background:linear-gradient(135deg,#183a20,#0d2b1a);border:2px solid #2a7a3a;border-radius:10px;text-align:center;margin:10px 0;"> <<if window.slotIsLike(_slot)>><<= _j.name>> LOVES: <b><<= window.slotValue(_j, _slot)>></b><<else>><<= _j.name>> HATES: <b><<= window.slotValue(_j, _slot)>></b><</if>> </div> [[🛒 Keep shopping|Shop]] | [[📊 Dashboard|Dashboard]]
<h1 style="margin:0 0 0.4em 0;">🕵️ Guess a Judge Stat</h1> <<if $guessStatUsedDay is $player.day>> <div style="padding:10px 14px;background:#2a1010;border:1px solid #7a2a2a;border-radius:8px;margin:10px 0;color:#ff9e9e;"> You've already made your guess for today. Come back tomorrow. </div> <<else>> Choose a judge. For <b>$<<= $archetype is "gambler" ? 100 : $guessJudgeStatItem.price>></b>, you'll be shown 3 options for one of their hidden preferences — guess right and it's unlocked for good. Guess wrong, and the money is still spent. Only one guess per day. <div id="guess-judge-picker"></div> <<script>> jQuery(document).one(':passageend', function(){ var sv = SugarCube.State.variables; var gsPrice = (sv.archetype === 'gambler') ? 100 : sv.guessJudgeStatItem.price; var wrap = document.getElementById('guess-judge-picker'); var html = '<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:10px;">'; for (var i=0;i<sv.judges.length;i++){ var j = sv.judges[i]; var left = window.getUnrevealedSlots(j).length; var disabled = left === 0 || sv.player.money < gsPrice; html += '<div class="judge-pick-card" data-idx="'+i+'" style="cursor:'+(disabled?'default':'pointer')+';opacity:'+(disabled?'0.4':'1')+';background:linear-gradient(135deg,#1a1a2e,#16213e);border:1px solid #333;border-radius:10px;padding:10px;text-align:center;">' + '<img id="gsp-judge-'+i+'" style="width:70px;height:70px;object-fit:cover;border-radius:8px;" src="">' + '<div style="font-weight:700;margin-top:6px;">'+j.name+'</div>' + '<div style="font-size:0.75em;color:#888;margin-top:2px;">'+(left===0?'Fully known':(left+' unknown'))+'</div>' + '</div>'; } html += '</div>'; wrap.innerHTML = html; window.resolveJudgeCardPortraits(sv.judges, 'gsp-judge'); wrap.querySelectorAll('.judge-pick-card').forEach(function(card){ var idx = parseInt(card.getAttribute('data-idx')); var j = sv.judges[idx]; if (window.getUnrevealedSlots(j).length === 0 || sv.player.money < gsPrice) return; card.addEventListener('click', function(){ sv.player.money -= gsPrice; sv.guessJudgeStatItem.buyCount = (sv.guessJudgeStatItem.buyCount || 0) + 1; sv.guessStatUsedDay = sv.player.day; var slot = window.pickRandomFrom(window.getUnrevealedSlots(j)); sv.judgeStatPickIdx = idx; sv.guessSlotCat = slot.cat; sv.guessSlotIdx = (slot.idx !== undefined) ? slot.idx : -1; sv.guessCorrectValue = window.slotValue(j, slot); sv.guessOptions = window.buildGuessOptions(j, slot); SugarCube.Engine.play('GuessStatQuiz'); }); }); }); <</script>> <</if>> [[⬅️ Shop|Shop]]
<<set _j = $judges[$judgeStatPickIdx]>> <<set _slot = ($guessSlotIdx >= 0) ? { cat: $guessSlotCat, idx: $guessSlotIdx } : { cat: $guessSlotCat }>> <h1 style="margin:0 0 0.4em 0;">🕵️ Guess — <<= _j.name>></h1> <div style="display:flex;justify-content:center;margin:10px 0;"><img id="gsq-judge-portrait" style="width:100px;height:100px;object-fit:cover;border-radius:10px;" src=""></div> What does <b><<= _j.name>></b> <<if window.slotIsLike(_slot)>>LOVE<<else>>HATE<</if>>? <div id="guess-options"></div> <<script>> jQuery(document).one(':passageend', function(){ var sv = SugarCube.State.variables; var img = document.getElementById('gsq-judge-portrait'); if(img) img.src = 'img/portraits/' + sv.judges[sv.judgeStatPickIdx].portrait + '.jpg'; var wrap = document.getElementById('guess-options'); var html = ''; sv.guessOptions.forEach(function(opt){ html += '<button class="guess-opt-btn" data-val="'+opt+'" style="display:block;width:100%;margin:6px 0;padding:10px;background:linear-gradient(180deg,#183462,#0d1f3a);border:1px solid #4a9eff;color:#8fb8ff;border-radius:6px;cursor:pointer;font-size:0.95em;font-weight:600;">'+opt+'</button>'; }); wrap.innerHTML = html; wrap.querySelectorAll('.guess-opt-btn').forEach(function(btn){ btn.addEventListener('click', function(){ var picked = btn.getAttribute('data-val'); var j = sv.judges[sv.judgeStatPickIdx]; var slot = (sv.guessSlotIdx >= 0) ? { cat: sv.guessSlotCat, idx: sv.guessSlotIdx } : { cat: sv.guessSlotCat }; if (picked === sv.guessCorrectValue) { window.slotSetRevealed(j, slot); window.checkFullPanelTrophy(j); sv.guessResult = 'correct'; } else { sv.guessResult = 'wrong'; } SugarCube.Engine.play('GuessStatResult'); }); }); }); <</script>>
<<set _j = $judges[$judgeStatPickIdx]>> <<set _slot = ($guessSlotIdx >= 0) ? { cat: $guessSlotCat, idx: $guessSlotIdx } : { cat: $guessSlotCat }>> <h1 style="margin:0 0 0.4em 0;">🕵️ Guess Result</h1> <<if $guessResult is "correct">> <div style="padding:12px 16px;background:linear-gradient(135deg,#183a20,#0d2b1a);border:2px solid #2a7a3a;border-radius:10px;text-align:center;margin:10px 0;"> ✅ Correct! <<if window.slotIsLike(_slot)>><<= _j.name>> LOVES: <b><<= $guessCorrectValue>></b><<else>><<= _j.name>> HATES: <b><<= $guessCorrectValue>></b><</if>> </div> <<else>> <div style="padding:12px 16px;background:#2a1010;border:1px solid #7a2a2a;border-radius:10px;text-align:center;margin:10px 0;"> ❌ Wrong guess. The $300 is gone, and <<= _j.name>>'s preference stays a mystery for now. </div> <</if>> [[🛒 Keep shopping|Shop]] | [[📊 Dashboard|Dashboard]]
<<set _jseShow = $judgeSpecialShoots[$judgeSpecialPending]>> <<set _jJShow = $judges[_jseShow.judgeIdx]>> <h1 style="margin:0 0 0.4em 0;">🎬 A Special Request</h1> <<= _jJShow.name>>'s assistant reaches out with an unusual, personal request. They want you to film a talent with <b><<= _jseShow.reqTraitValue>> <<= _jseShow.reqTraitType>></b> performing <b><<= _jseShow.reqPosition>></b> — both, in the same shoot. You have until <b>day <<= _jseShow.deadlineDay>></b>. They're vague about why, but hint there might be something extra in it for you if you pull it off in time. <<set $judgeSpecialPending = -1>> [[Understood — Go to Dashboard|Dashboard]]