From ced8f251d431d5543c92e0683b9b9d3985118d28 Mon Sep 17 00:00:00 2001 From: 33333-33333 Date: Thu, 11 Jun 2026 01:09:49 +0900 Subject: [PATCH 1/5] before visual update --- BALANCE_PATCH_NOTES.md | 78 +++++++++ README.md | 8 +- dist/game.js | 85 +++++----- index.html | 45 +++--- package-lock.json | 4 +- package.json | 2 +- src/core/balance.js | 71 +++++---- src/core/config.js | 6 +- src/core/entities.js | 2 +- src/core/state.js | 25 ++- src/game.js | 243 +++++++++++++++++----------- src/render/draw.js | 4 +- src/systems/buildSystem.js | 8 +- src/systems/cards.js | 99 +++++++----- src/systems/chickSystem.js | 32 ++-- src/systems/economy.js | 132 ++++++--------- src/systems/events.js | 318 +++++++++++++++++++++++++++++++++++++ src/systems/maintenance.js | 12 +- src/systems/uiSystem.js | 78 +++++---- styles.css | 71 +++++---- 20 files changed, 904 insertions(+), 419 deletions(-) create mode 100644 BALANCE_PATCH_NOTES.md create mode 100644 src/systems/events.js diff --git a/BALANCE_PATCH_NOTES.md b/BALANCE_PATCH_NOTES.md new file mode 100644 index 0000000..58b64b1 --- /dev/null +++ b/BALANCE_PATCH_NOTES.md @@ -0,0 +1,78 @@ +# Balance Patch Notes v27.14 + +## Event system + +The old shipment-goal terminology has been replaced by one-day Events in player-facing UI and balance notes. Internal names are mostly event-based; a few generic helper concepts are preserved only where they are not player-facing. + +Events start appearing from Day 8 with a 10% chance. An offered event is forced and applies only to the next running day. + +Implemented events: + +1. Premium Female Shipment + - Female -> Truck event. + - Target = estimated total production x 0.3. + - Success pays an event bonus. + +2. Contaminant Sample Export + - Poop is valid Truck cargo. + - All poop income is doubled. + - Target = estimated total production x 0.3. + - Success pays an event bonus. + +3. Health Inspection + - Poop mistake fines are doubled. + - Shredding enough poop pays an event bonus. + +4. Conveyor Jam Warning + - Jam explosion threshold becomes 85% congestion. + - Finishing with zero explosions pays an event bonus. + +5. Power Saving Order + - Conveyor speed x0.8. + - Auto Scanner cooldown x1.2. + - Settlement pays a flat subsidy. + +6. Overtime Day + - Day length becomes 80 seconds. + - No extra effect. + +7. Short Shift + - Day length becomes 40 seconds. + - Next Fairies tribute is reduced by 10%. + +8. Chick Boom + - Egg interval x0.65. + - Poop rate +5 percentage points. + +9. Rotten Feed + - Poop rate +20 percentage points. + - Shredder poop payout x1.5. + +10. Maintenance Audit + - No penalty. + - If no maintained machine is below 50% remaining durability, settlement pays a bonus. + +## Related balance behavior + +- Shredder Upgrade payout is affected by Event poop/shredder multipliers. +- COMPOSTER payout is also affected by Event shredder payout multipliers. +- Poop target Truck events no longer fine poop when poop is the valid cargo. +- Chemical Weapons Subsidy remains 70 poop / 1200 yen. +- Fairies tribute is paid on Next Day press. +- Normal Loan card and repayment state are removed. Emergency Loan remains. +- The old tax system is removed. Fairies tribute is the only recurring day-start levy. + +## v27.14 consistency/debug changes + +- Debug UI restored intentionally for balancing builds. HTML/CSS/JS include comments stating it should not be removed during cleanup unless explicitly requested. +- Debug card selector is grouped by gameplay genre. +- Debug single-card grant supports selecting the target for target-consuming build-phase cards. +- Debug All Cards still uses automatic valid targets. +- Removed unused special weight logic left over from old SPARE PARTS BIN behavior. +- Removed unused Egg Farm cash upgrade cost data; Egg upgrades are card-based. +- Shredder Upgrade now sums upgrades across all Shredder facilities, not only the original primary Shredder. +- Maintenance and repair target collection now includes additional Mixer/Shredder facilities. +- Maintenance Audit low-durability checks now include additional Mixer/Shredder facilities. +- Fixed duplicate Emergency Loan button in the bankruptcy decision modal. +- Fixed stale debug-removal CSS fragments left from the previous audit pass. +- Fixed corrupted score-breakdown formula text. diff --git a/README.md b/README.md index cd1f243..e4a0cca 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Chick Sorter v27.0 Cleanup Build +# Chick Sorter v27.14 Balancing Build Open `index.html` in a browser. @@ -24,8 +24,8 @@ After deploying, purge any CDN or reverse-proxy cache once. - Build, move, box-select, sell, and repair factory equipment during Build phase. - Start the next day only when at least one EGG route reaches a scanner and then any valid exit. -- Fairies tribute is paid after day-end settlement and before the next Build phase. -- Bankruptcy is checked only at that day-end transition. Temporary negative cash during production does not immediately end the game. +- Fairies tribute is paid when pressing Next Day, using the previous day's net profit as part of the calculation. +- Bankruptcy is checked at day-end settlement after shipment/event/subsidy revenue. Temporary negative cash during production does not immediately end the game. - Cards use English names and descriptions with numeric effect summaries. - `poop.png` is the only bundled image asset currently used by default; other art falls back to canvas drawing. @@ -41,6 +41,6 @@ After deploying, purge any CDN or reverse-proxy cache once. ## Cleanup in this build - Removed duplicate `src/index.html` and `src/styles.css`; root `index.html` and `styles.css` are the single launch surface. -- Removed the old debug panel, debug hotkey, debug event log, and free-upgrade/debug-cash code. +- Debug panel is intentionally present for balancing builds. Do not remove it during cleanup unless explicitly requested. Its card menu is grouped and target-consuming cards can be applied to selected targets. - Removed the obsolete right-side selected-facility panel code left behind after the UI removal. - Removed stale historical README files and old changelog text that no longer matched the current specification. diff --git a/dist/game.js b/dist/game.js index 6b28b61..c6ea3cf 100644 --- a/dist/game.js +++ b/dist/game.js @@ -1,61 +1,60 @@ -var q={version:"v27.6 direct conveyor chick movement",time:{daySeconds:60,farmShutdownGraceSeconds:10},cash:{starting:250},grid:{x:170,y:78,cols:20,rows:10,cell:46,expansion:{colsPerPurchase:10,rowsPerPurchase:10,costBase:1e3,costMultiplier:1.3333333333333333,truncateUnit:100}},map:{blockedRatio:.075},economy:{income:{mixer:5,truck:10},poopFine:10,zundaTax:{exemption:500,legalWorkExemptionBonus:250,maxRateCash:1e4,stepAmount:500,stepRate:.05,maxRate:.95},fairiesTribute:{perDay:10},incomeUpgradeRate:1.1,explosionDamageDivisor:30,maleTruckFinePerHalfDay:30,shredderBonus:{maxCards:30,probabilityPercentDivisor:2}},production:{poopRate:.08,autoScannerCooldown:3.5,autoScannerUpgradeRate:.95,autoScannerMinCooldown:.5,eggSpawnRanges:[[1.95,4.35],[1.55,3.45],[1.25,2.8],[1.05,2.35]]},conveyor:{baseSpeed:52,maxSpeed:300,bearingSpeedMultiplier:1.075},cards:{definitions:[{id:"upgradeEgg",title:"EGG Improvement",rarity:"common",type:"equipmentUpgrade",target:"eggFarm",description:"Choose one EGG FARM on the map and raise it by 1 level.",tags:["EGG","ACTIVE"]},{id:"upgradeAutoScanner",title:"AUTO SCANNER Improvement",rarity:"common",type:"equipmentUpgrade",target:"autoScanner",description:"Choose one AUTO SCANNER on the map and raise it by 1 level.",tags:["SCANNER","ACTIVE"]},{id:"upgradeMixer",title:"MIXER Improvement",rarity:"common",type:"equipmentUpgrade",target:"mixer",description:"Choose MIXER on the map and raise it by 1 level.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeTruck",title:"TRUCK Improvement",rarity:"common",type:"equipmentUpgrade",target:"truck",description:"Choose TRUCK on the map and raise it by 1 level.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeTrash",title:"SHREDDER Improvement",rarity:"common",type:"equipmentUpgrade",target:"trash",description:"Shred poops for a little money. Max 30 upgrades.",tags:["POOP","ACTIVE"]},{id:"crowdedFarming",title:"Crowded Farming Contract",rarity:"common",type:"instant",description:"EGG production interval -5%. Equipment deterioration +4%. Max 10 cards.",tags:["EGG","RISK","PASSIVE"]},{id:"hatchingFeed",title:"Hatching Feed",rarity:"common",type:"instant",description:"EGG production interval -4%. Poop rate +3%. No card limit.",tags:["EGG","POOP","PASSIVE"]},{id:"safetyCover",title:"Safety Cover",rarity:"common",type:"instant",description:"Explosion damage -5%. No card limit.",tags:["RISK","PASSIVE"]},{id:"preventiveMaintenance",title:"Preventive Maintenance Manual",rarity:"common",type:"instant",description:"All equipment deterioration speed -5%. No card limit.",tags:["MAINTENANCE","PASSIVE"]},{id:"dudFilter",title:"DUD Filter",rarity:"common",type:"instant",description:"DUD chance -5 percentage points. Stacks until DUD chance reaches 0%.",tags:["CARD","PASSIVE"]},{id:"durabilityCoating",title:"Durability Coating",rarity:"common",type:"instant",description:"All equipment maximum durability +3%. No card limit.",tags:["MAINTENANCE","PASSIVE"]},{id:"bearing",title:"High-Quality Bearing",rarity:"common",type:"instant",description:"Conveyor speed +7.5%.",tags:["CONVEYOR","PASSIVE"]},{id:"sparePartsBin",title:"SPARE PARTS BIN",rarity:"common",type:"instant",description:"Restores 2% durability to every machine. A box of almost-compatible parts.",tags:["MAINTENANCE","ACTIVE"],weightBase:100,weightLossPerCopy:2},{id:"dudRefund",title:"DUD REFUND",rarity:"common",type:"instant",description:"DUDs now come with paperwork. Gain JPY 50 per copy when you pick a DUD.",tags:["CARD","ECONOMY","PASSIVE"]},{id:"freeReroll",title:"FREE REROLL",rarity:"common",type:"instant",description:"The first bad ideas are free.",tags:["CARD","PASSIVE"]},{id:"composter",title:"COMPOSTER",rarity:"common",type:"instant",description:"Turns shredder waste into suspicious fertilizer. Gain JPY 3 per copy when SHREDDER processes poop.",tags:["POOP","ECONOMY","PASSIVE"]},{id:"scannerQueueSpacing",title:"Scanner Queue Spacing",rarity:"common",type:"instant",description:"Manual and Auto Scanner queue spacing -15%. No card limit.",tags:["SCANNER","PASSIVE"]},{id:"extraEggOutlet",title:"Extra Egg Outlet",rarity:"rare",type:"equipmentUpgrade",target:"eggOutlet",description:"Choose one EGG FARM and add +1 output port to that EGG. Max +3 per EGG.",tags:["EGG","RARE","ACTIVE"]},{id:"recyclingSubsidy",title:"Recycling Subsidy",rarity:"rare",type:"instant",description:"SELL refund rate +10 points. Max 3 cards; normal SELL can reach 80%.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"dynamite",title:"Dynamite",rarity:"rare",type:"cellAction",target:"blockedCell",description:"Remove any 3 unbuildable cells",tags:["RISK","RARE","ONE-SHOT"]},{id:"usedMachine",title:"Used Machines",rarity:"rare",type:"instant",description:"Future equipment costs half. New purchases have no refund and 60% durability. New Machines cancels it.",tags:["ECONOMY","RISK","RARE"]},{id:"newMachine",title:"New Machines",rarity:"common",type:"instant",description:"Cancel Used Machines and restore normal prices, refunds, and durability.",tags:["ECONOMY","ONE-SHOT"]},{id:"flattery",title:"Flattery",rarity:"rare",type:"instant",description:"Next Fairies tribute -50%.",tags:["ECONOMY","RARE","ONE-SHOT"]},{id:"loan",title:"Loan",rarity:"rare",type:"instant",description:"Gain JPY 300 per elapsed day now. Pay JPY 400 per day for that many days starting tomorrow.",tags:["ECONOMY","RISK","RARE"]},{id:"extraCards",title:"Extra Cards",rarity:"rare",type:"instant",description:"Draw 2 cards now and choose both.",tags:["RARE","ACTIVE"]},{id:"legalWork",title:"Legal Work",rarity:"rare",type:"instant",description:"ZUNDA TAX exemption +\uFFE5250. The 95% cap point also moves up by \uFFE5250.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"chemicalWeaponSubsidy",title:"Chemical Weapons Subsidy",rarity:"ultraRare",type:"instant",description:"Each day, gain JPY 2000 per 100 poop shipped by truck. No card limit.",tags:["POOP","ULTRA RARE","PASSIVE"]},{id:"laborExploitation",title:"Motivational Exploitation",rarity:"ultraRare",type:"instant",description:"Repairman labor cost -30%. The repairman smiles with bloodshot eyes. One time only.",tags:["MAINTENANCE","ULTRA RARE","PASSIVE"]},{id:"rescueLoan",title:"Emergency Loan",rarity:"ultraRare",type:"instant",description:"If cash is below JPY 0 at day-end settlement, gain JPY 500. Consumed on use.",tags:["ECONOMY","ULTRA RARE","ONE-SHOT"]}],defaultEffects:{bearing:0,legalWork:0,fairiesFlatteryNext:0,crowdedFarming:0,extraEggOutlet:0,hatchingFeed:0,safetyCover:0,recyclingSubsidy:0,chemicalWeaponSubsidy:0,preventiveMaintenance:0,dudFilter:0,durabilityCoating:0,sparePartsBin:0,dudRefund:0,freeReroll:0,composter:0,scannerQueueSpacing:0,laborExploitation:0,usedMachineActive:!1,rescueLoanCharges:0,loans:[]},commonWeight:8,rareWeight:2,ultraRareWeight:.45,baseDraftSize:3,maxDudsPerDraft:2,dudChancePerCard:.3,dudChanceReductionPerFilter:.05,extraCardsAddedPicks:2,rerollCost:{dayDivisor:2,multiplier:100}},contracts:{eventChance:.7,firstTurn:8},maintenance:{fullPerformanceUntilWear:.5,minimumPerformance:.5,durability:{conveyor:1300,eggFarm:475,autoScanner:850,mixer:775,trash:950},processingDelayMaxSeconds:{mixer:1.2,trash:1},repairman:{dailyCost:100,secondsPerOnePercent:.5,walkSpeed:90}},facilities:{conveyor:{id:"conveyor",type:"conveyor",name:"Conveyor",shortName:"Belt",price:30,buildable:!0,upgradeable:!1},boostConveyor:{id:"boostConveyor",type:"conveyor",name:"Boost Conveyor",shortName:"BOOST BELT",price:75,buildable:!0,upgradeable:!1,speedMultiplier:2},eggFarm:{id:"eggFarm",type:"eggFarm",name:"Egg Farm",shortName:"EGG",price:250,buildable:!0,upgradeable:!0,maxLevel:4,upgradeCosts:[null,300,720,1600]},manualScanner:{id:"manualScanner",type:"scanner",kind:"manual",name:"Manual Scanner",shortName:"Manual Scanner",price:260,buildable:!0,upgradeable:!1},autoScanner:{id:"autoScanner",type:"scanner",kind:"auto",name:"Auto Scanner",shortName:"Auto Scanner",price:360,buildable:!0,upgradeable:!1},mixer:{id:"mixer",type:"facility",name:"Mixer",shortName:"MIXER",price:450,buildable:!0,upgradeable:!0,incomeKey:"mixer",body:{w:164,h:126}},trash:{id:"trash",type:"facility",name:"Waste Shredder",shortName:"SHREDDER",price:240,buildable:!0,upgradeable:!0,body:{w:180,h:100}},truck:{id:"truck",type:"facility",name:"Truck",shortName:"TRUCK",price:450,buildable:!0,upgradeable:!0,incomeKey:"truck",body:{w:176,h:138}}}};var yn=q.version,Bt=q.time.daySeconds,Jt=q.cash.starting,Ce=q.economy,tr=q.time.farmShutdownGraceSeconds,hn=q.production.autoScannerCooldown,nr=q.production.autoScannerUpgradeRate,eo=q.production.autoScannerMinCooldown,or=q.contracts.eventChance,ft=q.contracts.firstTurn,rr=q.production.poopRate,mn=q.conveyor.baseSpeed,Lt=q.conveyor.maxSpeed,bn=q.conveyor.bearingSpeedMultiplier,Ee=q.cards,ir=q.cards.definitions,to=q.cards.defaultEffects,et=q.production.eggSpawnRanges,y=q.grid,we=q.facilities,no=["conveyor","boostConveyor","eggFarm","autoScanner","manualScanner","mixer","trash","truck"],Zt=["mixer","trash","truck"],sr=["mixer","truck"],pt=Object.fromEntries(Object.entries(we).map(([e,t])=>[e,t.price])),pe=[{name:"right",dc:1,dr:0,angle:0,opposite:"left"},{name:"left",dc:-1,dr:0,angle:Math.PI,opposite:"right"},{name:"down",dc:0,dr:1,angle:Math.PI/2,opposite:"up"},{name:"up",dc:0,dr:-1,angle:-Math.PI/2,opposite:"down"}],f={bg:"#eefbea",ink:"#102015",muted:"#526456",green:"#22b94f",greenSoft:"#b7f5c6",mixerBlue:"#2477ff",truckPink:"#ff6aa8",wasteGreen:"#22b94f",danger:"#c42424",warn:"#f0a020",white:"#ffffff",poop:"#7b4a23",male:"#62a9ff",female:"#ff8bc6"},Se={ambient:0,important:1,critical:2};function S(e){let t=Number(e)||0;return`${t<0?"-":""}\uFFE5${Math.ceil(Math.abs(t)).toLocaleString("ja-JP")}`}function I(e,t){return`${e},${t}`}function J(e){let[t,n]=String(e).split(",").map(Number);return{col:t,row:n}}function jt(e,t,n){return Math.max(t,Math.min(n,e))}function W(e,t){return e+Math.random()*(t-e)}function Pe(e,t){return e>=0&&e=0&&tMath.round(jt(r,0,255)).toString(16).padStart(2,"0");return`#${o(e)}${o(t)}${o(n)}`}function ro(e,t,n){let o=lr(e),r=lr(t);return As(oo(o.r,r.r,n),oo(o.g,r.g,n),oo(o.b,r.b,n))}var re={appTitle:"Chick Sorter",versionTitle:`Chick Sorter ${yn}`,currency:"\uFFE5",phases:{title:"Title",build:"Build",running:"Sorting",clearing:"Clearing",loanDecision:"Emergency Loan",gameover:"Game Over"},actions:{startGame:"Start Game",nextDay:"Next Day",buildPhase:"Build Phase",restart:"Restart",close:"Close",remove:"Remove",refund:"Refund",autoMenu:"Auto Menu"},status:{build:e=>`BUILD: ${(e==="erase"?"SELL":e||"SELECT").toUpperCase()} | Right-drag pan | Hover equipment for info`,sorting:"Sorting: use scanner keys. Build after clearing the day.",allPortsConnected:"Start condition met: one EGG route reaches an exit.",equipmentPanelEmpty:"Hover equipment in Build phase.",eventPanelRunning:"Forced events appear in Build phase."},routeLabels:{mixer:"MIXER",truck:"TRUCK",trash:"WASTE",scanner:"NEXT","scanner-role-1":"NEXT",input:"IN"},fail:{outOfGrid:"Out of grid",cellOccupied:"Cell occupied",notEnoughCash:"Not enough cash",facilityExists:"Facility already exists",facilityOverlap:"Facility overlap",nothingToErase:"Nothing to sell",noUpgrade:"No upgrade available"}};function ht(e){return we[e]?.name||String(e||"").replace(/^[a-z]/,t=>t.toUpperCase())}function $s(e){let t=we[e];return t?e==="conveyor"||e==="boostConveyor"?`${S(t.price)} / tile`:e==="autoScanner"?`${S(t.price)} / ${hn.toFixed(1)}s cooldown`:e==="trash"?S(t.price):S(t.price):""}function Is(e){return{conveyor:"A narrow green belt. Routes decide whether chicks live, ship, or become invoices.",boostConveyor:"Moves chicks twice as fast. Wears down like a normal belt.",eggFarm:"A tiny gatehouse producing questionable eggs on schedule.",autoScanner:"Slower than hands without upgrades.",manualScanner:"A manual checkpoint. The operator is the algorithm.",mixer:"Male chicks become revenue here. Do not feed it poop.",trash:"A polite shredder for poop and other regrets.",truck:"Ships the target cargo. Wrong cargo still leaves a paper trail."}[e]||""}function cr(e){let t=Is(e);return`${ht(e)}${$s(e)}${t?`${t}`:""}`}function ur(e){return re.routeLabels[e]||String(e).toUpperCase()}function dr(e){let t=2166136261;for(let n=0;n>>0}function fr(e){let t=e>>>0;return()=>{t+=1831565813;let n=Math.imul(t^t>>>15,1|t);return n^=n+Math.imul(n^n>>>7,61|n),((n^n>>>14)>>>0)/4294967296}}function vn(){return`RUN-${Date.now().toString(36)}-${Math.floor(Math.random()*1e6).toString(36)}`.toUpperCase()}function pr({seed:e,targetRatio:t=.2,reserved:n=[]}={}){let o=fr(dr(e||vn())),r=new Set(n.map(d=>typeof d=="string"?d:I(d.col,d.row))),s=[];for(let d=0;d0;d-=1){let k=Math.floor(o()*(d+1));[s[d],s[k]]=[s[k],s[d]]}let l=Math.round(y.cols*y.rows*t);return new Set(s.slice(0,Math.min(l,s.length)).map(d=>d.k))}function yr({seed:e,colStart:t=0,colEnd:n=y.cols,rowStart:o=0,rowEnd:r=y.rows,targetRatio:s=.2,reserved:l=[]}={}){let d=fr(dr(e||vn())),k=new Set(l.map(X=>typeof X=="string"?X:I(X.col,X.row))),M=[],D=Math.max(0,Math.floor(t)),L=Math.max(D,Math.floor(n)),F=Math.max(0,Math.floor(o)),z=Math.max(F,Math.floor(r));for(let X=F;X0;X-=1){let ae=Math.floor(d()*(X+1));[M[X],M[ae]]=[M[ae],M[X]]}let oe=Math.round((L-D)*(z-F)*s);return new Set(M.slice(0,Math.min(oe,M.length)).map(X=>X.k))}var Ot=10,hr=2,mr=1;function Nt(e,t){return`${e},${t}`}function Fs(e){let[t,n]=String(e).split(",").map(Number);return{chunkX:t,chunkY:n}}function xn(e){let t=q.grid.expansion||{},n=Math.max(1,(e.gridExpansionPurchases||0)+1),o=(t.costBase||1e3)*n*(t.costMultiplier||4/3),r=Math.max(1,t.truncateUnit||100);return Math.floor(o/r)*r}function br(e){e.ownedCells=new Set,e.ownedChunks=new Set,e.gridChunkOriginY=0,e.gridExpansionPurchases=0,e.gridExpansionPurchasesByDirection={right:0,up:0};for(let t=0;t=0&&t=0&&n0)continue;let M=Nt(k.chunkX,k.chunkY);t.has(M)||n.has(M)||n.set(M,io(e,k.chunkX,k.chunkY,k.direction))}}return[...n.values()].sort((o,r)=>{let s=o.direction===r.direction?0:o.direction==="right"?-1:1;return s||(o.chunkY!==r.chunkY?o.chunkY-r.chunkY:o.chunkX-r.chunkX)})}function xr(e,t="right"){let n=mt(e);return n.find(o=>o.direction===t)||n[0]||null}function bt(e){return{x:y.x+e.colStart*y.cell,y:y.y+e.rowStart*y.cell,w:e.cols*y.cell,h:e.rows*y.cell}}function so(e){let t=bt(e);return{x:t.x+t.w/2-116,y:t.y+t.h/2-36,w:232,h:72,cx:t.x+t.w/2,cy:t.y+t.h/2}}function kr(e,t){let n=so(e);return t.x>=n.x&&t.x<=n.x+n.w&&t.y>=n.y&&t.y<=n.y+n.h}function Cr(e){let t=[];for(let n=e.rowStart;nPe(t.col,t.row))}function _s(e){return[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}].filter(t=>Pe(t.col,t.row))}function Ks(e){return[{col:e.col,row:e.row+1},{col:e.col-1,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row-1}].filter(t=>Pe(t.col,t.row))}function Pr(e){let t=new Set([...e.conveyorTiles]),n=o=>{o&&Pe(o.col,o.row)&&t.add(I(o.col,o.row))};for(let o of e.scanners){for(let r of _s(o))n(r);for(let r of Ws(o))n(r)}for(let o of e.eggFarms){n(o);for(let r of Ks(o))n(r)}for(let o of Object.values(e.facilities))n(o.entry);return t}function gr(e){let t=Os.map(([n,o])=>({col:n,row:o}));for(let{col:n,row:o}of t)Er(e,n,o);for(let n=0;n({...n,keys:n.keys?{left:{...n.keys.left},right:{...n.keys.right}}:null,queue:[]})),e.eggFarms=Gs.map(n=>{let o=wt(n);return{...n,nextSpawn:o,lastInterval:o}});let t=Pr(e);e.blockedCells=pr({seed:e.runSeed,targetRatio:q.map.blockedRatio,reserved:[...t]}),Hs(e),gr(e),e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function xt(e){return e?[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}]:[]}function de(e){let t=$(e.col,e.row);return{x:t.x+y.cell/2,y:t.y}}function kt(e,t,n){return e.eggFarms.find(o=>o.col===t&&o.row===n)||null}function Ct(e,t,n){return e.scanners.find(o=>xt(o).some(r=>r.col===t&&r.row===n))||null}function St(e,t){return e.scanners.find(n=>n.id===t)||null}function fo(e,t){return e.scanners.find(n=>n.kind==="manual"&&n.slot===t)||null}function Mn(e){return e?.baseId||e?.id||""}function po(e,t){return Object.entries(e.facilities||{}).filter(([,n])=>Mn(n)===t)}function Me(e,t){return{inputA:{col:e.col,row:e.row-2},inputB:null,left:{col:e.col-1,row:e.row},right:{col:e.col+2,row:e.row}}[t]}function Ar(e){return e?pe.map(t=>({col:e.col+t.dc,row:e.row+t.dr})).filter(t=>Pe(t.col,t.row)):[]}function $r(e,t,n=[],o=[]){if(!t||!Pe(t.col,t.row))return[];let r=[],s=l=>{!l||!Pe(l.col,l.row)||!e.conveyorTiles.has(I(l.col,l.row))||n.some(d=>d&&wn(l,d))||r.some(d=>wn(d,l))||r.push({...l,viaTolerance:!wn(l,t)})};s(t);for(let l of o)s(l);for(let l of Ar(t))s(l);return r}function Rr(e,t,n=[],o=[]){let r=$r(e,t,n,o),s=r.filter(l=>!l.viaTolerance);return s.length?s:r}function qs(e,t){let n=Me(t,"inputA");return!n||!Pe(n.col,n.row)?[]:e.conveyorTiles.has(I(n.col,n.row))?[{...n,viaTolerance:!1}]:[]}function Ys(e,t,n){let o=Me(t,n);return $r(e,o,xt(t))}function zs(e,t){let n=e.facilities[t]||po(e,t)[0]?.[1];if(!n)return null;if(n.entry)return $(n.entry.col,n.entry.row);let o=Mn(n)||t;return o==="mixer"?{x:n.x+n.w,y:n.y+n.h*.52}:o==="truck"?{x:n.x,y:n.y+n.h*.52}:o==="trash"?{x:n.x+n.w/2,y:n.y+8}:{x:n.x+n.w/2,y:n.y+n.h/2}}function Ir(e,t,n){return n==="inputA"?qs(e,t).length>0:Ys(e,t,n).length>0}function be(e){e.branchCounters?.clear?.(),e.routeCache=null,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function Re(e,t){return I(e,t)}function vt(e){return J(e)}function Vs(e,t){let n=e.conveyorMeta?.get?.(t)||{},o=[];return Array.isArray(n.outDirs)&&o.push(...n.outDirs),n.dir&&o.push(n.dir),[...new Set(o)].filter(r=>pe.some(s=>s.name===r))}function Xs(e,t){let n=vt(t),o=pe.filter(l=>e.conveyorTiles.has(Re(n.col+l.dc,n.row+l.dr))).map(l=>l.name),r=Vs(e,t).filter(l=>o.includes(l)),s=o,d=r.length?r:s,k=e.conveyorMeta?.get?.(t)||{};if(o.length<3)return d;let M=new Set(o.filter(D=>{let L=pe.find(F=>F.name===D);if(!L)return!1;let F=e.conveyorMeta?.get?.(Re(n.col+L.dc,n.row+L.dr));if(!F)return!1;let z=[...new Set([...Array.isArray(F.outDirs)?F.outDirs:[],F.dir].filter(Boolean))];return z.includes(L.opposite)}));if(k.branchMode&&k.branchMode!=="random"&&o.includes(k.branchMode)){let D=new Set(M);D.add(k.branchMode),o.filter(L=>!D.has(L)).length>=2&&M.add(k.branchMode)}let D=o.filter(L=>!M.has(L));if(D.length)return D;let L=d.filter(F=>!M.has(F));return L.length?L:d}function Qs(e){return{version:e.routingVersion||0,cells:new Set,adjacency:new Map,components:new Map,cellToComponent:new Map,scannerInputs:new Map,scannerPorts:new Map,facilityPorts:new Map,farmOutputs:new Map,pathCache:new Map,metrics:{conveyorCells:0,edges:0,components:0,deadEnds:0,crosses:0,scannerPorts:0,connectedScannerPorts:0,facilityPorts:0,connectedFacilityPorts:0,farmOutputs:0},issues:[]}}function Js(e){let t=Qs(e);for(let o of e.conveyorTiles)t.cells.add(o),t.adjacency.set(o,[]);for(let o of t.cells){let r=vt(o),s=Xs(e,o),l=pe.filter(d=>s.includes(d.name));for(let d of l){let k=Re(r.col+d.dc,r.row+d.dr);t.cells.has(k)&&t.adjacency.get(o).push({key:k,dir:d.name})}}let n=0;for(let[o,r]of t.adjacency.entries()){n+=r.length;let s=new Set(r.map(l=>l.dir));r.length===1&&(t.metrics.deadEnds+=1),r.length===4&&s.has("left")&&s.has("right")&&s.has("up")&&s.has("down")&&(t.metrics.crosses+=1)}return t.metrics.conveyorCells=t.cells.size,t.metrics.edges=Math.floor(n/2),Zs(t),js(e,t),t.issues=dl(e,t,{includeRoutes:!1}),t}function Zs(e){let t=1;for(let n of e.cells){if(e.cellToComponent.has(n))continue;let o=t++,r=[n],s=[];for(e.cellToComponent.set(n,o);r.length;){let l=r.shift();s.push(l);for(let d of e.adjacency.get(l)||[])e.cellToComponent.has(d.key)||(e.cellToComponent.set(d.key,o),r.push(d.key))}e.components.set(o,{id:o,cells:s,capacity:Math.max(1,s.length),count:0,ratio:0})}e.metrics.components=e.components.size}function js(e,t){for(let n of e.scanners){let o={};for(let r of["inputA","left","right"]){let s=Me(n,r),l=r==="inputA"?s&&t.cells.has(Re(s.col,s.row))?[{...s}]:[]:Rr(e,s,xt(n)).filter(M=>t.cells.has(Re(M.col,M.row))),d=l.map(M=>Re(M.col,M.row)),k=d.length>0;if(o[r]={type:r,cell:s,cells:l,keys:d,key:d[0]||null,connected:k},t.metrics.scannerPorts+=1,k&&(t.metrics.connectedScannerPorts+=1),r==="inputA")for(let M of d)t.scannerInputs.set(M,n.id)}t.scannerPorts.set(n.id,o)}for(let[n,o]of Object.entries(e.facilities)){if(!o.entry)continue;let r=Rr(e,o.entry).filter(d=>t.cells.has(Re(d.col,d.row))),s=r.map(d=>Re(d.col,d.row)),l=s.length>0;t.facilityPorts.set(n,{id:n,cell:{...o.entry},cells:r,keys:s,key:s[0]||null,connected:l}),t.metrics.facilityPorts+=1,l&&(t.metrics.connectedFacilityPorts+=1)}for(let n of e.eggFarms){let o=Ar({col:n.col,row:n.row}).map(r=>Re(r.col,r.row)).filter(r=>t.cells.has(r));t.farmOutputs.set(n.id,o),t.metrics.farmOutputs+=o.length}}function De(e){let t=e.routingVersion||0;return(!e.factoryGraph||e.factoryGraph.version!==t)&&(e.factoryGraph=Js(e)),e.factoryGraph}function Fr(e){let t=De(e);return e.factoryGraphCommittedVersion=t.version,e.factoryGraphSnapshot=el(t),t}function el(e){return e?{version:e.version,conveyorCells:e.metrics.conveyorCells,edges:e.metrics.edges,components:e.metrics.components,deadEnds:e.metrics.deadEnds,crosses:e.metrics.crosses,scannerPorts:`${e.metrics.connectedScannerPorts}/${e.metrics.scannerPorts}`,facilityPorts:`${e.metrics.connectedFacilityPorts}/${e.metrics.facilityPorts}`,farmOutputs:e.metrics.farmOutputs,issues:[...e.issues||[]]}:null}function Br(e,t,n){let o=De(e),r=Re(t,n);return(o.adjacency.get(r)||[]).map(s=>({...vt(s.key),dir:pe.find(l=>l.name===s.dir)||{name:s.dir,dc:0,dr:0}}))}function tl(e,t){let n=t.col-e.col,o=t.row-e.row;return pe.find(r=>r.dc===n&&r.dr===o)?.name||null}function nl(e,t,n){return!1}function yo(e,t,n){let o=De(e),r=Re(t.col,t.row);if(!o.cells.has(r))return[];let s=`${r}|${n.cacheKey||"dynamic"}`;if(n.cacheKey&&o.pathCache.has(s))return o.pathCache.get(s).map(g=>g.map(_=>({..._})));let l=`${r}|none`,d=[{key:r,col:t.col,row:t.row,incoming:"none",depth:0}],k=new Map([[l,0]]),M=new Map,D=[],L=1/0,F=8,z=24,oe=80;for(;d.length;){let g=d.shift();if(g.depth>L)break;let _=`${g.key}|${g.incoming}`;if(n(g)){if(D.push(_),L=g.depth,D.length>=z)break;continue}for(let U of o.adjacency.get(g.key)||[]){let le=vt(U.key),me=tl(g,le);if(g.incoming!=="none"&&nl(e,o,g.key)&&me!==g.incoming)continue;let fe=g.depth+1;if(fe>L)continue;let E=`${U.key}|${me}`,G=k.get(E);if(G==null)k.set(E,fe),M.set(E,[_]),d.push({key:U.key,col:le.col,row:le.row,incoming:me,depth:fe});else if(G===fe){let w=M.get(E)||[];w.length{if(X.length>=oe)return;let[U]=g.split("|"),le=[vt(U),..._];if(g===l||U===r){X.push(le);return}for(let me of M.get(g)||[])ae(me,le)};for(let g of D)ae(g,[]);let he=[],j=new Set;for(let g of X){let _=g.map(U=>Re(U.col,U.row)).join(">");j.has(_)||(j.add(_),he.push(g))}return n.cacheKey&&o.pathCache.set(s,he.map(g=>g.map(_=>({..._})))),he}function Lr(e){let t=De(e),n=new Map;for(let[o,r]of t.components.entries())n.set(o,{id:o,cells:[...r.cells],capacity:r.capacity,count:0,ratio:0});return{components:n,cellToComponent:new Map(t.cellToComponent)}}function Or(e,t,n){let o=De(e),r=null,s=1/0;for(let l of o.cells){let d=J(l),k=$(d.col,d.row),M=Math.hypot(k.x-t,k.y-n);M$(o.col,o.row));return t&&n.push(t),n}function tt(e,t){t&&(!e.length||ar(e[e.length-1],t)>1)&&e.push(t)}function ol(e,t,n,o=null){let r=[{x:e.x,y:e.y}];tt(r,$(t.col,t.row));for(let s of Tn(n,o))tt(r,s);return r}function rl(e,t){let n=Tn(e),o=Me(t,"inputA");return o&&tt(n,$(o.col,o.row)),tt(n,de(t)),n}function il(e,t,n,o){let r=[{x:e.x,y:e.y}];tt(r,$(t.col,t.row));for(let l of Tn(n))tt(r,l);let s=Me(o,"inputA");return s&&tt(r,$(s.col,s.row)),tt(r,de(o)),r}function sl(e,t,n=0){let o=$(t.col,t.row),r=0;for(let s of e.chicks||[]){if(s.stage==="flying"||s.stage==="queued")continue;Math.hypot(s.x-o.x,s.y-o.y){let L=M.roleBias??0,F=D.roleBias??0;if(L!==F)return L-F;let z=M.cells?.length??M.route?.length??Number.POSITIVE_INFINITY,oe=D.cells?.length??D.route?.length??Number.POSITIVE_INFINITY;if(z!==oe)return z-oe;let X=M.key||JSON.stringify(M.route||M.cells||M),ae=D.key||JSON.stringify(D.route||D.cells||D);return X.localeCompare(ae)});if(!o||r.length===1)return r[0];let s=r[0].roleBias??0,l=r.filter(M=>(M.roleBias??0)===s),d=Math.min(...l.map(M=>Dr(e,M)));l=l.filter(M=>Dr(e,M)===d);let k=e.branchCounters.get(t)||0;return e.branchCounters.set(t,k+1),l[Math.floor(Math.random()*l.length)]}function Nr(e){return e.role===0?{left:{match:"male",destination:"mixer"},right:{match:"default",destination:"scanner-role-1"}}:{left:{match:"poop",destination:"trash"},right:{match:"default",destination:"truck"}}}function ho(e){let t=Nr(e);return{left:t.left.destination,right:t.right.destination}}function mo(e,t){return Nr(e).left.match===t.sex?"left":"right"}function bo(e){return ur(e)}function wo(e){return{mixer:"#2477ff",truck:"#ff6aa8",trash:"#22b94f","scanner-role-1":"#526456",scanner:"#526456",input:"#526456"}[e]||"#102015"}function Mt(e,t,n=!1){let o=De(e),r=(o.farmOutputs.get(t.id)||[]).map(vt),s=[];for(let k of r){let M=L=>o.scannerInputs.has(Re(L.col,L.row));M.cacheKey=`farmInput:${k.col},${k.row}:v${o.version}`;let D=yo(e,k,M);for(let L of D){let F=L[L.length-1],z=o.scannerInputs.get(Re(F.col,F.row)),oe=St(e,z);oe&&s.push({key:`${oe.id}:${F.col},${F.row}:${L.length}`,scanner:oe,cells:L})}}let l=Sn(e,`farm:${t.id}`,s,n);if(l)return{scannerId:l.scanner.id,route:rl(l.cells,l.scanner)};let d=Sn(e,`farm:${t.id}:output`,r.map(k=>({key:I(k.col,k.row),cells:[k]})),n);return d?{scannerId:null,route:Tn(d.cells)}:null}function Gr(e,t,n,o,r=!1){let s=St(e,o);if(!s)return null;let d=De(e).scannerPorts.get(s.id)?.[t],k=Me(s,t),M=d?.connected?(d.keys||[d.key]).filter(Boolean).map(vt):[];if(!k||!M.length)return null;let D=ho(s)[t];return D==="scanner-role-1"?ll(e,s,t,n,k,M,r):al(e,s,t,n,k,M,D,r)}function ll(e,t,n,o,r,s,l){let d=De(e),k=e.scanners.filter(L=>L.id!==t.id&&d.scannerPorts.get(L.id)?.inputA?.connected),M=[];for(let L of s)for(let F of k){let z=d.scannerPorts.get(F.id)?.inputA?.key;if(!z)continue;let oe=(d.scannerPorts.get(F.id)?.inputA?.keys||[z]).filter(Boolean),X=j=>oe.includes(Re(j.col,j.row));X.cacheKey=`toScanner:${L.col},${L.row}:${F.id}:v${d.version}`;let ae=yo(e,L,X),he=F.role===1?0:1;for(let j of ae)M.push({key:`${he}:start${I(L.col,L.row)}:s${F.id}:${j.length}:${I(j[j.length-1].col,j[j.length-1].row)}`,target:F,cells:j,roleBias:he})}let D=Sn(e,`scanner:${t.id}:${n}:toRole1`,M,l);return D?{destination:"scanner",nextScannerId:D.target.id,route:il(o,r,D.cells,D.target)}:null}function al(e,t,n,o,r,s,l,d){let k=De(e),M=[...k.facilityPorts.entries()].filter(([F,z])=>z?.connected&&Mn(e.facilities?.[F])===l);if(!M.length)return null;let D=[];for(let F of s)for(let[z,oe]of M){let X=(oe.keys||[oe.key]).filter(Boolean);if(!X.length)continue;let ae=j=>X.includes(Re(j.col,j.row));ae.cacheKey=`toFacility:${F.col},${F.row}:${z}:v${k.version}`;let he=yo(e,F,ae);for(let j of he)D.push({key:`start${I(F.col,F.row)}:${z}:${j.length}:${I(j[j.length-1].col,j[j.length-1].row)}`,cells:j,facilityId:z})}let L=Sn(e,`scanner:${t.id}:${n}:${l}`,D,d);return L?{destination:l,facilityId:L.facilityId,route:ol(o,r,L.cells,zs(e,L.facilityId))}:null}function Ur(e,t,n=new Set){if(!t||n.has(t.id))return!1;n.add(t.id);for(let o of["left","right"]){let r=Gr(e,o,de(t),t.id,!1);if(r){if(["mixer","trash","truck"].includes(r.destination))return!0;if(r.destination==="scanner"){let s=St(e,r.nextScannerId);if(Ur(e,s,n))return!0}}}return!1}function cl(e,t){return!!Mt(e,t,!1)?.scannerId}function gn(e){if(e.phase!=="build")return[];let t=[];for(let n of e.eggFarms||[])cl(e,n)||t.push({type:"eggFarm",id:n.id,ref:n,message:"This Egg will not produce chicks"});for(let n of Zt)for(let[o,r]of po(e,n))De(e).facilityPorts.get(o)?.connected||t.push({type:"facility",id:o,ref:r,message:"This facility cannot receive items"});return t}function ul(e){let t=De(e);for(let r of e.eggFarms||[]){let s=Mt(e,r,!1);if(!s?.scannerId)continue;let l=St(e,s.scannerId);if(Ur(e,l))return[]}let n=e.eggFarms?.length||0,o=[...t.facilityPorts.entries()].filter(([r,s])=>s?.connected&&["mixer","trash","truck"].includes(Mn(e.facilities?.[r]))).length;return n?t.metrics.farmOutputs?e.scanners?.length?o?["Connect at least one EGG through a scanner to any valid exit."]:["Connect at least one receiver exit: Mixer, Shredder, or Truck."]:["Build at least one scanner and connect it to an EGG route."]:["Connect at least one EGG to a conveyor."]:["Build at least one EGG before starting the next day."]}function Cn(e){return e.kind==="manual"?`S${(e.slot??0)+1}`:`Auto Scanner #${e.id}`}function dl(e,t=De(e),n={}){let o=n.includeRoutes!==!1,r=[],s={mixer:"Mixer",trash:"Shredder",truck:"Truck"};for(let l of Zt){let d=po(e,l);if(!d.length){r.push(`${s[l]||l} is missing`);continue}for(let[k]of d)t.facilityPorts.get(k)?.connected||r.push(`${s[l]||l} receiver has no conveyor`)}for(let l of e.scanners){let d=t.scannerPorts.get(l.id)||{};if(d.inputA?.connected||r.push(`${Cn(l)} input has no conveyor`),d.left?.connected||r.push(`${Cn(l)} left output has no conveyor`),d.right?.connected||r.push(`${Cn(l)} right output has no conveyor`),!!o)for(let k of["left","right"])d[k]?.connected&&!Gr(e,k,de(l),l.id)&&r.push(`${Cn(l)} ${k} route is incomplete`)}if(o)for(let l of e.eggFarms)Mt(e,l)?.scannerId||r.push(`Egg Farm #${l.id} has no scanner route`);else for(let l of e.eggFarms)(t.farmOutputs.get(l.id)||[]).length||r.push(`Egg Farm #${l.id} has no output conveyor`);return[...new Set(r)]}function tn(e){return ul(e)}function Wr(e){return tn(e).length===0}var _r=[{target:"female",title:"Premium Female Shipment",route:"Female -> Truck",note:"Only female chicks are valid truck cargo this turn."},{target:"male",title:"Male Export Trial",route:"Male -> Truck",note:"Male chicks are temporarily valid truck cargo. Male truck fines are suspended for valid male cargo."},{target:"poop",title:"Contaminant Sample Export",route:"Poop -> Truck",note:"Poop is temporarily valid truck cargo. Shipped poop does not soil this contract shipment."}];function vo(e){return[...e.eggFarms.map(t=>t.price||0),...e.scanners.map(t=>t.price||0),...Object.values(e.facilities).map(t=>t.price||0),...[...e.conveyorMeta.values()].map(t=>t.price||0)].reduce((t,n)=>t+n,0)}function fl(e,t=1){return e.eggFarms.reduce((n,o)=>{let[r,s]=en(o),l=Math.max(.1,(r+s)/2);return n+Bt/l*t},0)}function Kr(e){if(e.turn+1or)return null;let n=_r[Math.floor(Math.random()*_r.length)],o=2,r=3,s=fl(e,o),l=Math.max(1,Math.ceil(s*.9)),d=Math.round((.08+Math.random()*.08)*100)/100,k=Math.floor(vo(e)*d),M=Math.floor(Math.max(0,e.cash)*.25),D=Math.max(k,M);return{id:`contract-${e.turn}-${Date.now()}-${Math.floor(Math.random()*9999)}`,...n,forced:!0,productionMultiplier:o,poopMultiplier:r,targetAmount:l,estimatedOutput:Math.round(s),rewardRate:d,reward:D,rewardByFactory:k,rewardByCash:M,createdTurn:e.turn,oneTurnOnly:!0}}function Hr(e){e.contractActive=e.contractOffer?{...e.contractOffer}:null,e.contractOffer=null}function qr(e){e.contractActive=null}function Yr(e){return e.contractActive?.productionMultiplier||1}function zr(e){let t=Math.max(0,Number(e?.cardEffects?.hatchingFeed)||0),n=Math.pow(1.03,t);return Math.min(.95,rr*(e.contractActive?.poopMultiplier||1)*n)}function ze(e){return e.contractActive?.target||"female"}function xo(e,t){return t==="male"?e.truckMale||0:t==="poop"?e.poopTruck||0:e.truckFemale||0}function Vr(e,t){return ze(e)===t}function Xr(e){return ze(e)!=="male"}function Qr(e){let t=e.contractActive;if(!t)return null;let n=xo(e.stats,t.target),o=n>=t.targetAmount,r=o?t.reward:0;r>0?(Ae(e,r),e.stats.contractBonus=r,e.totals.contractBonus+=r,e.totals.contractSuccess+=1):(e.stats.contractBonus=0,e.totals.contractFailed+=1);let s={title:t.title,target:t.target,route:t.route,targetAmount:t.targetAmount,count:n,success:o,bonus:r,reward:t.reward,productionMultiplier:t.productionMultiplier,poopMultiplier:t.poopMultiplier};return e.stats.contractResult=s,s}function ko(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function pl(e){return!!e?.cardEffects?.usedMachineActive}function yl(e,t){return t?1:Math.min(.8,.5+.1*Math.min(3,ko(e,"recyclingSubsidy")))}function hl(e){return Math.pow(.95,ko(e,"safetyCover"))}function En(e){let t=e?.ref||e||{},n=e?.type||t.type;return n==="conveyor"?t.price||we[t.kind]?.price||we.conveyor.price:n==="eggFarm"?t.price||we.eggFarm.price:n==="scanner"?t.price||(t.kind==="auto"?we.autoScanner.price:we.manualScanner.price):n==="facility"?t.price||we[t.id]?.price||0:we[t.id]?.price||0}function Be(e,t=null){let n=we[e]?.price||0;return pl(t)?Math.ceil(n*.5):n}function ml(e,t){return e?.facilities?Object.values(e.facilities).filter(n=>(n?.baseId||n?.id)===t).reduce((n,o)=>n+Math.max(0,(o.level||1)-1),0):0}function nt(e,t){return sr.includes(t)?Math.pow(Ce.incomeUpgradeRate,ml(e,t)):1}function _e(e){return Math.ceil(Ce.income.mixer*nt(e,"mixer"))}function Le(e){return Math.ceil(Ce.income.truck*nt(e,"truck"))}function nn(e){return Math.ceil(Ce.poopFine*nt(e,"mixer"))}function on(e){return Math.ceil(Ce.poopFine*nt(e,"truck"))}function Co(e){let t=Ce.maleTruckFinePerHalfDay*(e.turn/2);return Math.ceil(t*nt(e,"truck"))}function Tt(e){let t=Math.max(0,(e.facilities?.trash?.level||1)-1);return Math.min(Ce.shredderBonus.maxCards,t)}function Jr(e){return Math.max(0,(e.facilities?.trash?.level||1)-1)}function Gt(){return Ce.shredderBonus.maxCards}function ot(e){let t=typeof e=="number"?e:Tt(e),n=Math.min(Ce.shredderBonus.maxCards,Math.max(0,t)),o=Math.sqrt(n)/Ce.shredderBonus.probabilityPercentDivisor*n;return Math.min(1,o/100)}function bl(e){let t=Tt(e),n=ot(t),o=t>0&&Math.random()0&&(e.stats.shredderBonus=(e.stats.shredderBonus||0)+t.amount,e.totals.shredderBonus=(e.totals.shredderBonus||0)+t.amount,Ae(e,t.amount)),t}function Pn(e,t=null){let n=Ce.zundaTax,o=Math.max(0,t?.cardEffects?.legalWork||0),r=n.exemption+o*n.legalWorkExemptionBonus,s=n.maxRateCash+o*n.legalWorkExemptionBonus,l=Math.max(0,Math.floor(Number(e)||0)),d=Math.max(0,l-r);if(d<=0)return{profit:l,exemption:r,maxRateCash:s,taxable:0,rate:0,ratePercent:0,tax:0,step:0,legalWork:o};let k=Math.max(1,Math.ceil(d/n.stepAmount)),M=Math.min(n.maxRate,k*n.stepRate),D=Math.ceil(d*M);return{profit:l,exemption:r,maxRateCash:s,taxable:d,rate:M,ratePercent:Math.round(M*100),tax:D,step:k,legalWork:o}}function So(e,t=e.turn){let n=Math.max(1,Math.floor(Number(t)||1)),o=Math.ceil(n*Ce.fairiesTribute.perDay),r=Math.max(0,e?.cardEffects?.fairiesFlatteryNext||e?.cardEffects?.flattery||0),s=r>0?Math.pow(.5,r):1,l=Math.max(0,Math.ceil(o*s)),d=Math.max(0,o-l);return{day:n,base:o,flatteryCount:r,perCardReduction:Math.ceil(o*.5),reduction:d,amount:l}}function gt(e,t){let n=e?.ref||e||{},o=e?.type==="conveyor"?t?.conveyorMeta?.get(e.oldKey||n.id):n,r=o?.price||En(e||n),s=o?.builtSession===t?.buildSession;if(o?.noRefund||n?.noRefund)return{amount:0,sameBuild:s,price:r,rate:0,noRefund:!0};let l=yl(t,s);return{amount:Math.max(0,Math.ceil(r*l)),sameBuild:s,price:r,rate:l,noRefund:!1}}function wl(e,t=null){let n=Math.max(1,Math.ceil((Number(e)||0)/Ce.explosionDamageDivisor));return Math.max(1,Math.ceil(n*hl(t)))}function vl(e,t){return Math.max(0,Math.ceil(t))}function jr(e,t){let n=e.cash;e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,t>=0?(e.stats.revenue+=t,e.totals.revenue+=t):(e.stats.penalty+=Math.abs(t),e.totals.penalty+=Math.abs(t)),e.totals.maxCash=Math.max(e.totals.maxCash,e.cash)}function Ae(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&jr(e,n),n}function Ve(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&jr(e,-n),n}function rt(e,t){Ve(e,t)}function ei(e,t){if(t<=0)return;let n=e.cash;e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,e.totals.maxCash=Math.max(e.totals.maxCash,e.cash)}function ti(e){let t=_e(e);return e.stats.mixerRevenue+=t,Ae(e,t),t}function ni(e){let t=nn(e);return e.stats.mixerPoopFine+=t,e.totals.mixerPoopFine+=t,Ve(e,t),t}function oi(e){let t=on(e);return e.stats.truckPoopFine+=t,e.totals.truckPoopFine+=t,Ve(e,t),t}function ri(e){let t=Co(e);return e.stats.maleTruckFine+=t,e.totals.maleTruckFine+=t,Ve(e,t),t}function ii(e,t){let n=wl(t,e);return e.stats.explosionDamage+=n,e.totals.explosionDamage+=n,Ve(e,n),n}function si(e){let t=ze(e),n=xo(e.stats,t),o=Le(e),r=n*o,s=vl(e,r);return e.stats.pendingTruckRevenue=s,e.stats.truckRevenue=s,t==="poop"?e.stats.poopShipmentIncome=s:e.stats.chickShipmentIncome=s,s>0&&Ae(e,s),{base:r,adjusted:s,target:t,targetCount:n,unitPrice:o}}function li(e,t=0){let n=Pn(t,e);return n.tax<=0||(e.totals.zundaTax=(e.totals.zundaTax||0)+n.tax,e.totals.penalty=(e.totals.penalty||0)+n.tax,e.totals.profit=(e.totals.profit||0)-n.tax,e.cash-=n.tax),n}function ai(e,t=e.turn){let n=So(e,t);return e.cardEffects&&(e.cardEffects.fairiesFlatteryNext=0,e.cardEffects.flattery!=null&&delete e.cardEffects.flattery),n.amount<=0||(e.stats.fairiesTribute=(e.stats.fairiesTribute||0)+n.amount,e.totals.fairiesTribute=(e.totals.fairiesTribute||0)+n.amount,Ve(e,n.amount)),n}function ci(e){let t=ko(e,"chemicalWeaponSubsidy"),n=Math.max(0,e?.stats?.poopTruck||0),o=Math.floor(n/100),r=t>0&&o>0?o*2e3*t:0;return r>0&&(e.stats.chemicalWeaponSubsidy=(e.stats.chemicalWeaponSubsidy||0)+r,e.totals.chemicalWeaponSubsidy=(e.totals.chemicalWeaponSubsidy||0)+r,Ae(e,r)),{cards:t,poopTruck:n,blocks:o,amount:r}}function ui(e){let t=e?.cardEffects;if(!t||!Array.isArray(t.loans)||!t.loans.length)return{amount:0,paidLoans:0,remainingLoans:0};let n=0,o=0,r=[];for(let s of t.loans){if((s.daysRemaining||0)<=0)continue;let l=Math.max(0,Math.ceil(s.dailyPayment||400));n+=l,o+=1;let d=Math.max(0,(s.daysRemaining||0)-1);d>0&&r.push({...s,daysRemaining:d})}return t.loans=r,n>0&&(e.stats.loanRepayment=(e.stats.loanRepayment||0)+n,e.totals.loanRepayment=(e.totals.loanRepayment||0)+n,Ve(e,n)),{amount:n,paidLoans:o,remainingLoans:r.length}}function di(e){let t=vo(e),n=Math.max(1,e.totals.turnsCompleted||e.turn||1),o=Math.max(0,e.cash+e.totals.revenue+t*.5+e.totals.contractBonus*.5),r=Math.ceil(o/n),s=Math.floor(n*35+Math.max(0,n-5)*15),l=e.totals.correct*5,d=e.totals.explosionDamage;return{score:Math.max(0,Math.floor(o+r+l-e.totals.penalty-s)),factoryValue:t,base:o,dailyEarned:r,dayPenalty:s,correctBonus:l,explosionPenalty:d,days:n}}function xl(e){return{...e,keys:e.keys?{left:{...e.keys.left},right:{...e.keys.right}}:null,queue:[],cooldown:e.cooldown||0}}function rn(e){return JSON.stringify({cash:e.cash,stats:e.stats,totals:e.totals,nextId:e.nextId,gridX:y.x,gridY:y.y,gridCols:e.gridCols||y.cols,gridRows:e.gridRows||y.rows,gridExpansionPurchases:e.gridExpansionPurchases||0,gridExpansionPurchasesByDirection:e.gridExpansionPurchasesByDirection||{right:0,up:0},gridChunkOriginY:e.gridChunkOriginY||0,ownedCells:[...e.ownedCells||[]],ownedChunks:[...e.ownedChunks||[]],blockedCells:[...e.blockedCells||[]],selected:e.selected,multiSelected:e.multiSelected||[],buildTool:e.buildTool,view:e.view,facilities:e.facilities,eggFarms:e.eggFarms,scanners:e.scanners.map(xl),conveyorTiles:[...e.conveyorTiles],conveyorMeta:[...e.conveyorMeta.entries()],branchCounters:[...e.branchCounters.entries()],cardEffects:e.cardEffects,cardDraft:e.cardDraft,cardTargetPick:e.cardTargetPick})}function fi(e,t){let n=JSON.parse(t);e.cash=n.cash,e.stats=n.stats,e.totals=n.totals,e.nextId=n.nextId,y.x=n.gridX??q.grid.x,y.y=n.gridY??q.grid.y,y.cols=n.gridCols||q.grid.cols,y.rows=n.gridRows||q.grid.rows,e.gridCols=y.cols,e.gridRows=y.rows,e.gridExpansionPurchases=n.gridExpansionPurchases||0,e.gridExpansionPurchasesByDirection=n.gridExpansionPurchasesByDirection||{right:0,up:0},e.gridChunkOriginY=n.gridChunkOriginY||0,e.ownedCells=new Set(n.ownedCells||[]),e.ownedChunks=new Set(n.ownedChunks||[]),e.gridOwnedCells=e.ownedCells.size||y.cols*y.rows,e.blockedCells=new Set(n.blockedCells||[]),e.selected=n.selected,e.multiSelected=n.multiSelected||[],e.buildTool=n.buildTool,e.view=n.view||{x:0,y:0,scale:1},e.view.scale==null&&(e.view.scale=1),e.facilities=n.facilities||{},e.eggFarms=n.eggFarms||[],e.scanners=(n.scanners||[]).map(o=>({...o,queue:[],cooldown:o.cooldown||0})),e.conveyorTiles=new Set(n.conveyorTiles||[]),e.conveyorMeta=new Map(n.conveyorMeta||[]),e.branchCounters=new Map(n.branchCounters||[]),e.cardEffects=n.cardEffects||{bearing:0,legalWork:0,fairiesFlatteryNext:0,scannerQueueSpacing:0},e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft=n.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardTargetPick=n.cardTargetPick||null,e.groupDrag=null,e.selectionBox=null,e.pan=null,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function Oe(e){e.phase==="build"&&(e.undoStack.push(rn(e)),e.undoStack.length>80&&e.undoStack.shift(),e.redoStack=[])}function Mo(e){return e.phase!=="build"||!e.undoStack.length?!1:(e.redoStack.push(rn(e)),fi(e,e.undoStack.pop()),!0)}function To(e){return e.phase!=="build"||!e.redoStack.length?!1:(e.undoStack.push(rn(e)),fi(e,e.redoStack.pop()),!0)}function N(e,t,n,o,r=f.ink){e.floatingTexts.push({x:t,y:n,text:o,color:r,life:1,maxLife:1})}function Et(e,t,n){e.shake.strength=Math.max(e.shake.strength,t),e.shake.time=Math.max(e.shake.time,n)}function pi(e,t,n){e.effects.push({type:"spawn",priority:Se.ambient,x:t,y:n,life:.42,maxLife:.42,size:12})}function yi(e,t,n,o=f.green){e.effects.push({type:"scannerPulse",priority:Se.important,x:t,y:n,color:o,life:.42,maxLife:.42,size:24})}function hi(e,t,n){for(let o=0;o<12;o+=1)e.effects.push({type:"meat",priority:Se.important,x:t+W(-18,18),y:n+W(-12,16),vx:W(-60,60),vy:W(-90,-25),life:W(.45,.85),maxLife:.85,size:W(4,8)})}function mi(e,t,n){for(let o=0;o<16;o+=1)e.effects.push({type:"sludge",priority:Se.important,x:t+W(-18,18),y:n+W(-12,16),vx:W(-46,46),vy:W(-70,-20),life:W(.45,.9),maxLife:.9,size:W(4,8)})}function bi(e,t,n,o){let r=o==="poop"?f.poop:o==="male"?f.male:f.female;for(let s=0;s<22;s+=1)e.effects.push({type:"shred",priority:Se.important,x:t+W(-16,16),y:n+W(-8,8),vx:W(-70,70),vy:W(40,160),color:s%3===0?f.white:r,life:W(.45,.95),maxLife:.95,w:W(3,7),h:W(10,24),rot:W(-Math.PI,Math.PI)});Xe(e,t,n,f.green,34,Se.important)}function wi(e,t,n,o){let r=o==="poop"?f.poop:o==="male"?f.danger:f.green;for(let s=0;s<8;s+=1)e.effects.push({type:"load",priority:Se.important,x:t+W(-18,18),y:n+W(-18,18),vx:W(-42,42),vy:W(-90,-25),color:r,life:W(.35,.65),maxLife:.65,size:8})}function Xe(e,t,n,o=f.danger,r=52,s=Se.critical){e.effects.push({type:"shockwave",priority:s,x:t,y:n,color:o,life:.55,maxLife:.55,size:8,maxSize:r})}function it(e,t,n,o=12,r=f.danger,s=Se.critical){for(let l=0;l0&&(e.shake.time=Math.max(0,e.shake.time-t),e.shake.time<=0&&(e.shake.strength=0));for(let r of e.effects)if(r.life-=t,["meat","sludge","spark","smoke","shred","load","rage"].includes(r.type))r.x+=(r.vx||0)*t,r.y+=(r.vy||0)*t,r.vy=(r.vy||0)+150*t;else if(r.type==="flyingChick"){r.x+=r.vx*t,r.y+=r.vy*t,r.vy+=360*t,r.noDamage||kl(e,r,o);let s=r.x+e.view.x,l=r.y+e.view.y;(s<-100||l<-100||s>n.width+100||l>n.height+100)&&(r.life=0)}e.effects=e.effects.filter(r=>r.life>0);for(let r of e.floatingTexts)r.life-=t,r.y-=34*t;e.floatingTexts=e.floatingTexts.filter(r=>r.life>0)}function kl(e,t,n){t.hit||(t.hit=new Set);for(let o of n()){if(t.hit.has(o.id)||t.xo.x+o.w||t.yo.y+o.h)continue;t.hit.add(o.id);let r=ii(e,o.price);N(e,t.x,t.y-10,`-${S(r)}`,f.danger),Xe(e,t.x,t.y,f.danger,30),it(e,t.x,t.y,5,f.danger),Et(e,5,.18)}}var $e=q.maintenance;function Eo(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function $n(e){let t=Math.min(1.4,1+.04*Math.min(10,Eo(e,"crowdedFarming"))),n=Math.pow(.95,Eo(e,"preventiveMaintenance"));return t*n}function Cl(e){return Math.pow(1.03,Eo(e,"durabilityCoating"))}function In(e,t,n=1){let o=$e.durability[t]||1e3;return Math.max(1,Math.ceil(o*Math.max(.1,n||1)*Cl(e)))}function Do(e){let t=$e.repairman.dailyCost;return e?.cardEffects?.laborExploitation?Math.ceil(t*.7):t}function ki(e){return Math.max(.1,Number(e?.durabilityBaseMultiplier)||1)}function ye(e){e.repairman||(e.repairman={hiredForNextDay:!1,active:!1,x:y.x+y.cell*.5,y:y.y+y.rows*y.cell+84,target:null,repairedToday:0});for(let[t,n]of e.conveyorMeta||[]){n.uses==null&&(n.uses=0),n.maintenanceType==null&&(n.maintenanceType="conveyor"),n.kind||(n.kind="conveyor"),n.speedMultiplier||(n.speedMultiplier=n.kind==="boostConveyor"?2:1),n.branchMode||(n.branchMode="random");let o=In(e,"conveyor",ki(n));(n.durability==null||n.durability0&&(n.processingCooldown=Math.max(0,n.processingCooldown-t))}function On(e){ye(e);let t=[];for(let[n,o]of e.conveyorMeta||[])t.push({type:"conveyor",key:n,meta:o,label:`${o.kind==="boostConveyor"?"Boost Belt":"Belt"} ${n}`,center:$(J(n).col,J(n).row)});for(let n of e.eggFarms||[])t.push({type:"eggFarm",ref:n,label:`EGG #${n.id}`,center:$(n.col,n.row)});for(let n of(e.scanners||[]).filter(o=>o.kind==="auto"))t.push({type:"autoScanner",ref:n,label:`AUTO #${n.id}`,center:$(n.col,n.row)});for(let n of["mixer","trash"]){let o=e.facilities?.[n];o&&t.push({type:n,ref:o,label:o.shortName||o.name||n,center:{x:o.x+o.w/2,y:o.y+o.h/2}})}return t}function Dn(e){return e.meta?Ut(e):Ut(e.ref)}function sn(e){return e.meta?Po(e):Po(e.ref)}function An(e){return e.meta?Ro(e):Ro(e.ref)}function Ei(e,t){Sl(e.meta?e:e.ref,Math.max(0,sn(e)-t))}function Pi(e){return e.type==="conveyor"?`conveyor:${e.key}`:`${e.type}:${e.ref?.id||e.ref?.type||e.type}`}function Ri(e,t=.02){ye(e);let n=Math.max(0,Number(t)||0),o=0;for(let r of On(e)){let s=sn(r);Ei(r,An(r)*n),o+=Math.max(0,s-sn(r))/An(r)*100}return o}function Di(e){if(ye(e),e.repairman.hiredForNextDay)return{ok:!1,reason:"Repairman already hired."};let t=Do(e);return e.cashPi(o)===t.key)||null}function gl(e){let t=null;for(let n of On(e)){let o=Dn(n);o<=.001||(!t||o>Dn(t))&&(t=n)}return t}function Ii(e,t){ye(e);let n=e.repairman;if(!n.active||e.phase!=="running")return;let o=Tl(e,n.target)||gl(e);if(!o){n.target=null;return}n.target={key:Pi(o),label:o.label};let r=$e.repairman.walkSpeed,s=o.center.x-n.x,l=o.center.y-n.y,d=Math.hypot(s,l);if(d>8){let F=Math.min(d,r*t);n.x+=s/d*F,n.y+=l/d*F;return}let k=t/($e.repairman.secondsPerOnePercent*100),M=sn(o),D=k*An(o);Ei(o,D);let L=Math.max(0,(M-sn(o))/An(o)*100);n.repairedToday=(n.repairedToday||0)+L,L>0&&Math.random()<.02&&N(e,n.x,n.y-28,"REPAIR",f.green),Dn(o)<=.001&&(n.target=null)}function El(e){let t=0,n="none";for(let o of On(e)){let r=Dn(o);r>t&&(t=r,n=o.label)}return{ratio:t,percent:Math.round(t*100),label:n}}function No(e){let t=El(e),n=$o(e);return{worst:t,avgBeltPerformance:n,repairman:e.repairman||null}}var Pl=Ee.commonWeight,Rl=Ee.rareWeight,Dl=Ee.ultraRareWeight||.45,Pt=Ee.baseDraftSize,Kt=ir;function _t(e,t){let n=Ie(e);return Math.max(0,Number(n[t])||0)}function Ie(e){e.cardEffects||(e.cardEffects={...to,loans:[]});for(let[t,n]of Object.entries(to))e.cardEffects[t]==null&&(e.cardEffects[t]=Array.isArray(n)?[]:n);return e.cardEffects.flattery!=null&&(e.cardEffects.fairiesFlatteryNext=Math.max(0,e.cardEffects.fairiesFlatteryNext||0)+Math.max(0,e.cardEffects.flattery||0),delete e.cardEffects.flattery),Array.isArray(e.cardEffects.loans)||(e.cardEffects.loans=[]),e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft||(e.cardDraft={pending:!1,choices:[],rerolls:0,picksRemaining:0}),e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardEffects}function Wi(e){let t=Math.max(.5,1-.05*Math.min(10,_t(e,"crowdedFarming"))),n=Math.pow(.96,_t(e,"hatchingFeed"));return t*n}function _i(e,t=null){return Math.min(3,Math.max(0,Number(t?.extraEggOutlet)||0))}function Ki(e){return Math.pow(.85,_t(e,"scannerQueueSpacing"))}function Gn(e,t=null){let n=Ie(e),o=mn*Math.pow(bn,Math.max(0,n.bearing||0)),r=t?Math.max(.1,Number(e?.conveyorMeta?.get?.(t)?.speedMultiplier)||1):1,s=t?1:$o(e);return Math.min(Lt,o*s)*r}function Qe(e,t=null){let n=Math.max(0,(e?.level||1)-1),o=Math.max(eo,hn*Math.pow(nr,n));return t?Math.max(eo,o*Bn(e)):o}function Fi(e){let t=e.cardDraft||{rerolls:0},n=Math.max(1,(t.rerolls||0)+1);return Math.ceil(Math.max(1,e.turn||1)/Ee.rerollCost.dayDivisor*n*Ee.rerollCost.multiplier)}function Uo(e){return Kt.find(t=>t.id===e)||null}function Wo(e,t){let n=typeof t=="string"?Uo(t):t;if(Ie(e),!n||n.type==="dud")return{ok:!1,reason:"Card not found."};if(n.id==="extraCards")return e.cardDraft=e.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.choices.push(...Nn(e,2)),{ok:!0,reason:`${n.title} added draft cards.`};if(n.type==="instant")return qi(e,n),{ok:!0,reason:`${n.title} granted.`};if(n.type==="equipmentUpgrade"){let o=Ue(e,n)[0];return o?(Hi(e,o),{ok:!0,reason:`${n.title} applied.`}):{ok:!1,reason:`No valid target for ${n.title}.`}}if(n.type==="cellAction"&&n.target==="blockedCell"){let o=Ue(e,n).slice(0,3);if(!o.length)return{ok:!1,reason:"No blocked cells to remove."};for(let r of o){e.blockedCells.delete(I(r.col,r.row));let s=$(r.col,r.row);st(e,s.x,s.y)}return be(e),{ok:!0,reason:`${n.title} removed ${o.length} blocked cells.`}}return{ok:!1,reason:`${n.title} cannot be debug-granted.`}}function Al(e,t){if(t.type==="blockedCell")return`Blocked cell ${t.col},${t.row}`;if(t.type==="eggFarm")return`EGG #${t.id} L${t.level} -> L${t.level+1}`;if(t.type==="eggOutlet"){let n=Math.max(0,Number(t.farm?.extraEggOutlet)||0);return`EGG #${t.id} OUTLET ${1+n} -> ${2+n}`}if(t.type==="scanner")return`AUTO #${t.id} L${t.level} -> L${t.level+1} | CD ${Qe(t,e).toFixed(1)}s -> ${Qe({...t,level:t.level+1},e).toFixed(1)}s`;if(t.type==="facility"&&(t.baseId||t.id)==="mixer"){let n=t.level,o=_e(e);t.level=n+1;let r=_e(e);return t.level=n,`MIXER L${t.level} -> L${t.level+1} | ${S(o)} -> ${S(r)}`}if(t.type==="facility"&&(t.baseId||t.id)==="truck"){let n=t.level,o=Le(e);t.level=n+1;let r=Le(e);return t.level=n,`TRUCK L${t.level} -> L${t.level+1} | ${S(o)} -> ${S(r)}`}if(t.type==="facility"&&t.id==="trash"){let n=Tt(e),o=Math.min(Gt(),n+1),r=(ot(n)*100).toFixed(2),s=(ot(o)*100).toFixed(2);return`SHREDDER L${t.level||1} -> L${(t.level||1)+1} | ${r}% -> ${s}% per item`}return`${t.name||t.id} L${t.level||1} -> L${(t.level||1)+1}`}function $l(e){return[...e.blockedCells||[]].map(t=>{let[n,o]=String(t).split(",").map(Number);return{type:"blockedCell",id:t,col:n,row:o}}).filter(t=>Number.isFinite(t.col)&&Number.isFinite(t.row))}function Ue(e,t){let n=typeof t=="string"?Uo(t):t;return Ie(e),n?n.target==="blockedCell"?$l(e):n.target==="eggFarm"?e.eggFarms.filter(o=>(o.level||1)<4):n.target==="eggOutlet"?e.eggFarms.filter(o=>Math.max(0,Number(o.extraEggOutlet)||0)<3).map(o=>({type:"eggOutlet",id:o.id,col:o.col,row:o.row,farm:o})):n.target==="autoScanner"?e.scanners.filter(o=>o.kind==="auto"):n.target==="mixer"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="mixer"):n.target==="truck"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="truck"):n.target==="trash"?Jr(e)(o.baseId||o.id)==="trash"):[]:[]:[]}function Il(e,t){let n=Ie(e);if(t.id==="crowdedFarming")return(n.crowdedFarming||0)>=10;if(t.id==="recyclingSubsidy")return(n.recyclingSubsidy||0)>=3;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,Ee.dudChancePerCard||0)),r=Math.max(1e-4,Math.min(1,Ee.dudChanceReductionPerFilter||.05));return(n.dudFilter||0)>=Math.ceil(o/r)}return t.id==="laborExploitation"?!!n.laborExploitation:t.id==="usedMachine"?!!n.usedMachineActive:t.id==="newMachine"?!n.usedMachineActive:!1}function Fl(e){let t=e.repairman||{};return!!(t.active||t.hiredForNextDay||e.pendingRepairWorkerWages>0)}function Bl(e){return Kt.filter(t=>!(t.id==="laborExploitation"&&!Fl(e)||Il(e,t)||(t.type==="equipmentUpgrade"||t.type==="cellAction")&&Ue(e,t).length<=0))}function Bi(e,t){if(t.weightBase!=null){let n=_t(e,t.id);return Math.max(0,Number(t.weightBase)-Math.max(0,Number(t.weightLossPerCopy)||0)*n)}return t.rarity==="ultraRare"?Dl:t.rarity==="rare"?Rl:Pl}function Ll(e,t){let n=t.reduce((r,s)=>r+Bi(e,s),0);if(n<=0)return t[Math.floor(Math.random()*t.length)];let o=Math.random()*n;for(let r of t)if(o-=Bi(e,r),o<=0)return r;return t[t.length-1]}var Li=0;function Ol(){return Li+=1,{id:`dud:${Date.now()}:${Li}`,title:"Dud",rarity:"dud",type:"dud",description:"Click to flick this dud away. It does not consume a pick."}}function Nl(e){let t=Ie(e),n=Math.max(0,Math.min(1,Ee.dudChancePerCard||0)),o=Math.max(0,Math.min(1,Ee.dudChanceReductionPerFilter||0));return Math.max(0,n-o*Math.max(0,t.dudFilter||0))}function Gl(e,t){let n=[...t],o=0,r=Math.max(0,Ee.maxDudsPerDraft||0),s=Nl(e);for(let l=0;ld.id===s.id);l>=0&&r.splice(l,1)}return Gl(e,o)}function Wt(e){return e?e.type==="blockedCell"?`blockedCell:${e.id}`:e.type==="eggFarm"?`eggFarm:${e.id}`:e.type==="eggOutlet"?`eggOutlet:${e.id}`:e.type==="scanner"?`scanner:${e.id}`:e.type==="facility"?`facility:${e.id}`:`${e.type}:${e.id}`:""}function Oi(e){if(!e)return null;if(e.type==="blockedCell"){let t=$(e.col,e.row);return{x:t.x-y.cell*.48,y:t.y-y.cell*.48,w:y.cell*.96,h:y.cell*.96,cx:t.x,cy:t.y}}if(e.type==="eggFarm"||e.type==="eggOutlet"){let t=$(e.col,e.row);return{x:t.x-34,y:t.y-34,w:68,h:68,cx:t.x,cy:t.y}}if(e.type==="scanner"){let t=de(e);return{x:t.x-54,y:t.y-77,w:108,h:154,cx:t.x,cy:t.y}}return e.type==="facility"?{x:e.x,y:e.y,w:e.w,h:e.h,cx:e.x+e.w/2,cy:e.y+e.h/2}:null}function _o(e){if(!e.cardTargetPick?.pending)return[];if(e.cardTargetPick.mode==="autoScannerMenu"){let n=new Set(e.cardTargetPick.targetKeys||[]);return e.scanners.filter(o=>o.kind==="auto"&&n.has(Wt(o))).map(o=>({key:Wt(o),label:"AUTO ROUTE SETTINGS",target:o,bounds:Oi(o)})).filter(o=>o.bounds)}let t=new Set(e.cardTargetPick.targetKeys||[]);return Ue(e,e.cardTargetPick.cardId).filter(n=>t.has(Wt(n))).map(n=>({key:Wt(n),label:Al(e,n),target:n,bounds:Oi(n)})).filter(n=>n.bounds)}function Ul(e,t){let n=_o(e);for(let o of n){let r=o.bounds;if(t.x>=r.x&&t.x<=r.x+r.w&&t.y>=r.y&&t.y<=r.y+r.h)return o.target}return null}function Hi(e,t){if(t.type==="eggOutlet"){let n=t.farm||e.eggFarms.find(r=>r.id===t.id);if(!n)return;n.extraEggOutlet=Math.min(3,Math.max(0,Number(n.extraEggOutlet)||0)+1);let o=$(n.col,n.row);N(e,o.x,o.y-30,`OUTLET ${1+n.extraEggOutlet}`,f.green),be(e);return}if(t.level=(t.level||1)+1,t.type==="eggFarm"){t.nextSpawn=wt(t),t.lastInterval=t.nextSpawn;let n=$(t.col,t.row);N(e,n.x,n.y-30,`LV ${t.level}`,f.green);return}if(t.type==="scanner"){let n=de(t);N(e,n.x,n.y-34,`LV ${t.level}`,f.green);return}t.type==="facility"&&N(e,t.x+t.w/2,t.y+18,`LV ${t.level}`,f.green)}function qi(e,t){let n=Ie(e),o=r=>{n[r]=Math.max(0,n[r]||0)+1};if(t.id==="bearing"&&o("bearing"),t.id==="legalWork"&&o("legalWork"),t.id==="crowdedFarming"&&(n.crowdedFarming=Math.min(10,(n.crowdedFarming||0)+1)),t.id==="hatchingFeed"&&o("hatchingFeed"),t.id==="safetyCover"&&o("safetyCover"),t.id==="recyclingSubsidy"&&(n.recyclingSubsidy=Math.min(3,(n.recyclingSubsidy||0)+1)),t.id==="chemicalWeaponSubsidy"&&o("chemicalWeaponSubsidy"),t.id==="preventiveMaintenance"&&o("preventiveMaintenance"),t.id==="dudFilter"&&o("dudFilter"),t.id==="durabilityCoating"&&(o("durabilityCoating"),ye(e)),t.id==="sparePartsBin"){o("sparePartsBin");let r=Ri(e,.02);e.stats.sparePartsRepair=(e.stats.sparePartsRepair||0)+r,e.totals.sparePartsRepair=(e.totals.sparePartsRepair||0)+r,N(e,y.x+y.cols*y.cell/2,y.y-30,"REPAIR +2%",f.green)}if(t.id==="dudRefund"&&o("dudRefund"),t.id==="freeReroll"&&o("freeReroll"),t.id==="composter"&&o("composter"),t.id==="scannerQueueSpacing"&&o("scannerQueueSpacing"),t.id==="flattery"&&o("fairiesFlatteryNext"),t.id==="usedMachine"&&(n.usedMachineActive=!0),t.id==="newMachine"&&(n.usedMachineActive=!1),t.id==="laborExploitation"&&(n.laborExploitation=1),t.id==="rescueLoan"&&(o("rescueLoanCharges"),N(e,y.x+y.cols*y.cell/2,y.y-30,"RESCUE HELD",f.green)),t.id==="loan"){let r=Math.max(1,Math.floor(Number(e.turn)||1)),s=300*r;Ae(e,s),n.loans.push({daysRemaining:r,dailyPayment:400,borrowedOnTurn:e.turn||1}),N(e,y.x+y.cols*y.cell/2,y.y-30,`LOAN +${S(s)}`,f.green)}}function Ne(e){return`${Math.round(Number(e||0)*100)}%`}function Ni(e){let t=et[Math.max(0,Math.min(et.length-1,e-1))]||et[0]||[0,0];return`${t[0].toFixed(2)}-${t[1].toFixed(2)}s`}function Gi(e,t){return Math.ceil(e*Math.pow(Ce.incomeUpgradeRate,Math.max(0,t-1)))}function Ui(e,t,n){let r=Ue(e,t==="mixer"?"upgradeMixer":"upgradeTruck")[0];if(!r)return{before:Gi(n,1),after:Gi(n,2)};let s=t==="mixer"?_e(e):Le(e),l=r.level||1;r.level=l+1;let d=t==="mixer"?_e(e):Le(e);return r.level=l,{before:s,after:d}}function Wl(e,t){let n=Ie(e);if(t.id==="upgradeEgg"){let o=Ue(e,t),r=Math.min(3,Math.max(1,o[0]?.level||1));return`Choose one EGG. Level +1. Production interval ${Ni(r)} -> ${Ni(r+1)}.`}if(t.id==="upgradeAutoScanner"){let o=Ue(e,t)[0]||{level:1},r=Qe(o,e),s=Qe({...o,level:(o.level||1)+1},e);return`Choose one AUTO SCANNER. Level +1. Cooldown ${r.toFixed(2)}s -> ${s.toFixed(2)}s.`}if(t.id==="upgradeMixer"){let o=Ui(e,"mixer",Ce.income.mixer);return`Choose one MIXER. Earning +10%. Male-chick income ${S(o.before)} -> ${S(o.after)}.`}if(t.id==="upgradeTruck"){let o=Ui(e,"truck",Ce.income.truck);return`Choose one TRUCK. Earning +10%. Correct shipment income ${S(o.before)} -> ${S(o.after)}.`}if(t.id==="upgradeTrash"){let o=Tt(e),r=Math.min(Gt(),o+1);return`SHREDDER level +1. Bonus chance per item ${Ne(ot(o))} -> ${Ne(ot(r))}.`}if(t.id==="bearing"){let o=Math.min(Lt,mn*Math.pow(bn,Math.max(0,n.bearing||0))),r=Math.min(Lt,mn*Math.pow(bn,Math.max(0,(n.bearing||0)+1)));return`Conveyor speed +7.5%. After pick: ${o.toFixed(1)} -> ${r.toFixed(1)} px/s.`}if(t.id==="legalWork"){let o=Math.max(0,n.legalWork||0);return`ZUNDA TAX exemption +${S(250)}. After pick: exemption bonus ${S(250*(o+1))}.`}if(t.id==="crowdedFarming"){let o=Math.min(10,(n.crowdedFarming||0)+1);return`Held ${n.crowdedFarming||0}/10. After pick: EGG interval ${Ne(Math.max(.5,1-.05*o))}, deterioration ${Ne(Math.min(1.4,1+.04*o))}.`}if(t.id==="extraEggOutlet"){let o=Ue(e,t),r=Math.max(0,Number(o[0]?.farm?.extraEggOutlet)||0);return`Choose one EGG. Output ports ${1+r} -> ${2+r}. Max 4 ports per EGG.`}if(t.id==="hatchingFeed")return`Held ${n.hatchingFeed||0}. After pick: EGG interval ${Ne(Math.pow(.96,(n.hatchingFeed||0)+1))}, poop rate ${Ne(Math.pow(1.03,(n.hatchingFeed||0)+1))}.`;if(t.id==="safetyCover")return`Held ${n.safetyCover||0}. After pick: explosion damage ${Ne(Math.pow(.95,(n.safetyCover||0)+1))}.`;if(t.id==="recyclingSubsidy")return`Held ${n.recyclingSubsidy||0}/3. After pick: normal SELL refund ${Math.round(Math.min(.8,.5+.1*((n.recyclingSubsidy||0)+1))*100)}%.`;if(t.id==="chemicalWeaponSubsidy")return`Held ${n.chemicalWeaponSubsidy||0}. After pick: ${S(2e3*((n.chemicalWeaponSubsidy||0)+1))} per 100 truck-shipped poop each day.`;if(t.id==="preventiveMaintenance")return`Held ${n.preventiveMaintenance||0}. After pick: deterioration speed ${Ne(Math.pow(.95,(n.preventiveMaintenance||0)+1))}.`;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,Ee.dudChancePerCard||0)),r=Math.max(0,Math.min(1,Ee.dudChanceReductionPerFilter||.05)),s=Math.max(0,n.dudFilter||0),l=Math.max(0,o-r*s),d=Math.max(0,o-r*(s+1));return`Held ${s}. DUD chance per card ${Ne(l)} -> ${Ne(d)}.`}if(t.id==="durabilityCoating")return`Held ${n.durabilityCoating||0}. After pick: maximum durability ${Ne(Math.pow(1.03,(n.durabilityCoating||0)+1))}.`;if(t.id==="sparePartsBin")return`Held ${n.sparePartsBin||0}. Immediately restores 2% durability to every maintained machine. Offer weight: ${Math.max(0,100-2*Math.max(0,n.sparePartsBin||0))}.`;if(t.id==="dudRefund")return`Held ${n.dudRefund||0}. After pick: DUD clicks award ${S(50*((n.dudRefund||0)+1))}.`;if(t.id==="freeReroll")return`Held ${n.freeReroll||0}. After pick: each card screen starts with ${(n.freeReroll||0)+1} free reroll${(n.freeReroll||0)+1===1?"":"s"}.`;if(t.id==="composter")return`Held ${n.composter||0}. After pick: SHREDDER poop grants ${S(3*((n.composter||0)+1))}.`;if(t.id==="scannerQueueSpacing")return`Held ${n.scannerQueueSpacing||0}. After pick: Manual/Auto Scanner queue spacing ${Ne(Math.pow(.85,(n.scannerQueueSpacing||0)+1))}.`;if(t.id==="flattery")return`Next Fairies tribute -50%. Held for next tribute: ${n.fairiesFlatteryNext||0}.`;if(t.id==="usedMachine")return"Enable Used Machines: future equipment costs 50%, has no SELL refund, and starts with 60% durability.";if(t.id==="newMachine")return"Cancel Used Machines. Future equipment returns to normal price, refund, and durability.";if(t.id==="laborExploitation")return"Repairman labor cost -30% permanently. One time only.";if(t.id==="rescueLoan")return`At day-end bankruptcy check, gain ${S(500)} if cash is below ${S(0)}. Held: ${n.rescueLoanCharges||0}.`;if(t.id==="loan"){let o=Math.max(1,Math.floor(Number(e.turn)||1));return`Gain ${S(300*o)} now. Starting tomorrow, pay ${S(400)} per day for ${o} days.`}return t.description}function Go(e,t){let n=e.cardDraft?.choices||[],o=n.findIndex(r=>r.id===t.id);o>=0&&n.splice(o,1)}function Yi({game:e,ui:t,onUpdatePanels:n}){function o(){n&&n()}function r(){Ie(e),e.cardTargetPick=null,e.cardDraft={pending:!0,choices:Nn(e,Pt),rerolls:0,freeRerolls:_t(e,"freeReroll"),picksRemaining:1}}function s(){Ie(e),e.cardDraft.pending=!1,e.cardDraft.choices=[],e.cardDraft.picksRemaining=0,e.cardTargetPick=null,t.modal.classList.remove("visible","equipment-popover"),o()}function l(g=Pt){Ie(e),e.cardDraft.choices=Nn(e,g)}function d(){Ie(e),!e.cardDraft.choices.length&&e.cardDraft.picksRemaining>0&&l(Pt)}function k(g){Go(e,g),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1),e.cardTargetPick=null,d(),e.cardDraft.picksRemaining<=0?s():j()}function M(g){Go(e,g),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1)+Ee.extraCardsAddedPicks,e.cardDraft.choices.push(...Nn(e,2)),j()}function D(g,_){let U=_t(e,"dudRefund")*50;if(U>0){let le=Ae(e,U);e.stats.dudRefundIncome=(e.stats.dudRefundIncome||0)+le,e.totals.dudRefundIncome=(e.totals.dudRefundIncome||0)+le,N(e,y.x+y.cols*y.cell/2,y.y-30,`DUD REFUND +${S(le)}`,f.green)}Et(e,34,.62),document.body?.animate&&document.body.animate([{transform:"translate(0, 0)"},{transform:"translate(-10px, 7px)"},{transform:"translate(12px, -8px)"},{transform:"translate(-8px, -5px)"},{transform:"translate(9px, 6px)"},{transform:"translate(0, 0)"}],{duration:260,easing:"steps(5, end)"}),_&&(_.style.setProperty("--fling-x",`${260+Math.random()*260}px`),_.style.setProperty("--fling-y",`${-260-Math.random()*170}px`),_.style.setProperty("--fling-r",`${(Math.random()<.5?-1:1)*(52+Math.random()*38)}deg`),_.classList.add("flung")),window.setTimeout(()=>{Go(e,g),d(),j()},340)}function L(g,_=null){if(g.type==="dud")return D(g,_);if(g.id==="extraCards")return M(g);if(g.type==="equipmentUpgrade"||g.type==="cellAction")return F(g);qi(e,g),k(g)}function F(g){let _=Ue(e,g);_.length&&(e.cardTargetPick={pending:!0,cardId:g.id,mode:g.target==="blockedCell"?"blockedCell":"equipment",targetKeys:_.map(Wt),remaining:g.id==="dynamite"?Math.min(3,_.length):1},t.modal.classList.remove("visible","equipment-popover"),o())}function z(g){if(!g||g.type!=="blockedCell")return!1;let _=I(g.col,g.row);if(!e.blockedCells?.has(_))return!1;e.blockedCells.delete(_);let U=$(g.col,g.row);return st(e,U.x,U.y),Xe(e,U.x,U.y,f.danger,62),it(e,U.x,U.y,18,f.warn),Rn(e,U.x,U.y,8),Et(e,16,.35),N(e,U.x,U.y-18,"BOOM",f.danger),be(e),e.cardTargetPick.remaining=Math.max(0,(e.cardTargetPick.remaining||1)-1),e.cardTargetPick.targetKeys=Ue(e,"dynamite").map(Wt),o(),!0}function oe(g){if(!e.cardTargetPick?.pending)return!1;let _=Uo(e.cardTargetPick.cardId),U=Ul(e,g);return!_||!U?(X(),!0):_.id==="dynamite"?(z(U)&&((e.cardTargetPick.remaining||0)<=0||!Ue(e,"dynamite").length)&&k(_),!0):(Hi(e,U),k(_),!0)}function X(){e.cardTargetPick?.pending&&(e.cardTargetPick=null,j())}function ae(){let g=Math.max(0,e.cardDraft?.freeRerolls||0);if(g>0){e.cardDraft.freeRerolls=g-1,e.cardDraft.rerolls+=1,l(Pt),j();return}let _=Fi(e);e.cash<_||(Ve(e,_),e.stats.cardRerollCost=(e.stats.cardRerollCost||0)+_,e.totals.cardRerollCost=(e.totals.cardRerollCost||0)+_,e.cardDraft.rerolls+=1,l(Pt),j())}function he(g,_){let U=document.createElement("button");U.type="button";let le=g.type==="dud"?"dud":g.rarity==="ultraRare"?"ultra-rare":g.rarity==="rare"?"rare":"common";U.className=`card-choice ${le}`;let me=g.type==="dud"?"MISS":g.rarity==="ultraRare"?"ULTRA RARE":g.rarity==="rare"?"RARE":"COMMON",fe=[me,...(g.tags||[]).filter(E=>E!==me)].slice(0,5);return U.innerHTML=`${g.title}
${fe.map(E=>`${E}`).join("")}
${Wl(e,g)}`,U.addEventListener("click",()=>L(g,U)),U.dataset.index=String(_),U}function j(){Ie(e),e.cardTargetPick=null,e.cardDraft?.pending||r(),e.cardDraft.choices?.length||l(Pt);let g=e.cardDraft.choices||[],_=Fi(e),U=Math.max(0,e.cardDraft?.freeRerolls||0),le=Math.max(1,e.cardDraft.picksRemaining||1);t.modalTitle.textContent="Choose Upgrade Card",t.modalBody.innerHTML=`

Choose ${le} card${le===1?"":"s"} before Build phase. Dud cards can be flicked away without consuming a pick. Equipment cards target machines; Dynamite targets blocked cells.

`;let me=t.modalBody.querySelector("#cardChoices");g.forEach((G,w)=>me.appendChild(he(G,w))),t.modalActions.innerHTML="";let fe=document.createElement("button");fe.type="button",fe.className="facility-action warn reroll-button",fe.textContent=U>0?`Reroll (FREE x${U})`:`Reroll ${S(_)}`,fe.disabled=U<=0&&e.cash<_,fe.title=U>0?`${U} free reroll${U===1?"":"s"} remaining.`:fe.disabled?"Not enough cash":"",fe.addEventListener("click",ae),t.modalActions.appendChild(fe);let E=document.createElement("button");E.type="button",E.className="facility-action",E.textContent="No Card",E.title="Skip this upgrade pick and enter Build phase.",E.addEventListener("click",s),t.modalActions.appendChild(E),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible")}return{prepareDraft:r,showDraft:j,finishDraft:s,chooseTargetAtPoint:oe,cancelTargetPick:X}}var _l=!1,Kl={chickMale:"./assets/images/chick_male.png",chickFemale:"./assets/images/chick_female.png",poop:new URL("../../assets/images/poop.png",import.meta.url).href,conveyor:"./assets/images/conveyor.png",scannerManual:"./assets/images/scanner_manual.png",scannerAuto:"./assets/images/scanner_auto.png",eggFarm:"./assets/images/egg_farm.png",mixer:"./assets/images/mixer.png",shredder:"./assets/images/shredder.png",truck:"./assets/images/truck.png"},He={};for(let[e,t]of Object.entries(Kl)){let n=new Image;n.loaded=!1,n.onerror=()=>{n.loaded=!1},(_l||e==="poop")&&t&&(n.onload=()=>{n.loaded=!0},n.src=t),He[e]=n}function Xi(e,t,n,o){e.clearRect(0,0,t.width,t.height),Yl(e,t),e.save();let r=n.shake.time>0?W(-n.shake.strength,n.shake.strength):0,s=n.shake.time>0?W(-n.shake.strength,n.shake.strength):0,l=n.view?.scale||1;e.translate((n.view?.x||0)+r,(n.view?.y||0)+s),e.scale(l,l),Vl(e,n),Xl(e,n),Ql(e,n),sa(e,n),pa(e,n),la(e,n),ca(e,n),ql(e,n),ba(e,n,o.activeQueuedChick),ga(e,n),Ca(e,t,n),ka(e,n,o.selectedObject,o.selectedTitle),Sa(e,n),Ma(e,n),Ta(e,n),e.restore(),Ea(e,n,t)}function Hl(e){if(e.type==="eggFarm"){let n=$(e.ref.col,e.ref.row);return{x:n.x-34,y:n.y-34,w:68,h:68,cx:n.x,cy:n.y}}let t=e.ref;return{x:t.x,y:t.y,w:t.w,h:t.h,cx:t.x+t.w/2,cy:t.y+t.h/2}}function ql(e,t){if(t.phase!=="build")return;let n=gn(t);for(let o of n){let r=Hl(o);e.save(),e.fillStyle="rgba(196,36,36,.22)",e.strokeStyle=f.danger,e.lineWidth=5,e.setLineDash([10,6]),ee(e,r.x,r.y,r.w,r.h,!0,!0),e.setLineDash([]),e.fillStyle=f.danger,e.strokeStyle=f.white,e.lineWidth=4,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.strokeText("!",r.cx,r.y+24),e.fillText("!",r.cx,r.y+24),e.font="900 11px ui-monospace, monospace",e.strokeText("NO ROUTE",r.cx,r.y+r.h-8),e.fillText("NO ROUTE",r.cx,r.y+r.h-8),e.restore()}}function ee(e,t,n,o,r,s=!0,l=!0){e.beginPath(),e.rect(t,n,o,r),s&&e.fill(),l&&e.stroke()}function Ho(e,t,n,o,r=f.ink){e.save(),e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.lineWidth=4,e.strokeStyle=f.white,e.fillStyle=r,e.strokeText(o,t,n),e.fillText(o,t,n),e.restore()}function Rt(e,t,n,o,r,s){return t?.loaded?(e.drawImage(t,n,o,r,s),!0):!1}function Yl(e,t){e.fillStyle=f.bg,e.fillRect(0,0,t.width,t.height),e.save(),e.strokeStyle="rgba(16, 32, 21, 0.035)",e.lineWidth=1;for(let n=0;n=n;for(let r of mt(t)){let s=bt(r);e.save(),e.fillStyle=o?"rgba(183,245,198,.34)":"rgba(255,255,255,.22)",e.strokeStyle=o?f.green:f.muted,e.lineWidth=5,e.setLineDash([16,10]),ee(e,s.x,s.y,s.w,s.h,!0,!0),e.setLineDash([]);let l=so(r),d=l.cx,k=l.cy;e.fillStyle="rgba(255,255,255,.94)",e.strokeStyle=f.ink,e.lineWidth=4,ee(e,l.x,l.y,l.w,l.h,!0,!0),e.fillStyle=o?f.green:f.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText(r.direction==="right"?"BUY RIGHT LOT":"BUY UPPER LOT",d,k-12),e.fillStyle=f.ink,e.font="900 16px ui-monospace, monospace",e.fillText(`${S(n)} / 10\xD710`,d,k+15),e.fillStyle=f.muted,e.font="900 11px ui-monospace, monospace",e.fillText("blocked tiles included",d,k+30),e.restore()}}function Je(e,t,n,o,r,s,l=0){let d=Ut(s);d<.5||(e.save(),e.globalAlpha=Math.min(.62,.12+d*.54),e.fillStyle="#6b4a23",l>0?(e.beginPath(),e.roundRect?.(t,n,o,r,l),e.roundRect?e.fill():ee(e,t,n,o,r,!0,!1)):ee(e,t,n,o,r,!0,!1),e.globalAlpha=Math.min(.9,.25+d*.6),e.strokeStyle="#3a2a16",e.lineWidth=Math.max(2,Math.floor(2+d*5)),e.setLineDash([5,6]),ee(e,t+3,n+3,o-6,r-6,!1,!0),e.restore())}function Ko(e,t){let n=e.componentLookup?.get(t);return(n?e.congestion.get(n):null)?.ratio||0}function Ql(e,t){let n=[],o=new Set;for(let s of t.conveyorTiles){let{col:l,row:d}=J(s);for(let k of pe){let M={col:l+k.dc,row:d+k.dr},D=I(M.col,M.row);if(!t.conveyorTiles.has(D))continue;let L=[s,D].sort().join("|");if(o.has(L))continue;o.add(L);let F=Math.max(Ko(t,s),Ko(t,D));n.push({a:$(l,d),b:$(M.col,M.row),ratio:F})}}e.save(),e.lineCap="round",e.lineJoin="round";for(let s of[{width:33,color:f.ink,alpha:1},{width:25,color:f.white,alpha:1},{width:17,color:f.greenSoft,alpha:1}]){e.globalAlpha=s.alpha,e.strokeStyle=s.color,e.lineWidth=s.width;for(let l of n)e.beginPath(),e.moveTo(l.a.x,l.a.y),e.lineTo(l.b.x,l.b.y),e.stroke()}for(let s of n){let l=Math.max(0,(s.ratio-.5)/.5);e.strokeStyle=ro(f.green,f.danger,l),e.globalAlpha=s.ratio>.5?.35+l*.55:.8,e.lineWidth=6,e.beginPath(),e.moveTo(s.a.x,s.a.y),e.lineTo(s.b.x,s.b.y),e.stroke()}let r=oa(t);for(let s of t.conveyorTiles){let l=$(...Object.values(J(s))),d=t.conveyorMeta.get(s)||{},k=Ko(t,s),M=d.kind==="boostConveyor"?"#fff2b8":f.white;e.fillStyle=k>.5?ro(M,"#ffd6d6",Math.max(0,(k-.5)/.5)):M,e.strokeStyle=f.ink,e.lineWidth=2,ee(e,l.x-8,l.y-8,16,16,!0,!0),d.kind==="boostConveyor"&&(e.save(),e.strokeStyle=f.warn,e.lineWidth=3,e.beginPath(),e.moveTo(l.x-15,l.y+13),e.lineTo(l.x-3,l.y-13),e.lineTo(l.x+2,l.y-2),e.lineTo(l.x+15,l.y-13),e.stroke(),e.restore()),Je(e,l.x-14,l.y-14,28,28,{meta:d}),We(e,t,"conveyor",s,l.x,l.y,38,38),ra(e,l,r.get(s)||[]),ta(e,l,d,branchSelectable(t,s,jl(t,s)),jl(t,s)),k>.5&&Ho(e,l.x,l.y-15,`${Math.floor(k*100)}%`,f.danger)}e.restore()}function Jl(e){return{random:"RND",pass:"PASS",up:"UP",right:"RT",down:"DN",left:"LF"}[e||"random"]||"RND"}function Zl(e,t,n){let o=J(t),r=pe.filter(d=>e.conveyorTiles.has(I(o.col+d.dc,o.row+d.dr))).map(d=>d.name),s=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(d=>r.includes(d)),l=s.length?s:r;if(r.length<3)return l;let k=new Set(r.filter(M=>{let D=pe.find(L=>L.name===M);if(!D)return!1;let L=e.conveyorMeta?.get?.(I(o.col+D.dc,o.row+D.dr));if(!L)return!1;let F=[...new Set([...Array.isArray(L.outDirs)?L.outDirs:[],L.dir].filter(Boolean))];return F.includes(D.opposite)}));if(n.branchMode&&n.branchMode!=="random"&&r.includes(n.branchMode)){let M=new Set(k);M.add(n.branchMode),r.filter(D=>!M.has(D)).length>=2&&k.add(n.branchMode)}let M=r.filter(D=>!k.has(D));if(M.length)return M;let D=l.filter(L=>!k.has(L));return D.length?D:l}function jl(e,t){let n=J(t);return pe.filter(o=>e.conveyorTiles.has(I(n.col+o.dc,n.row+o.dr))).map(o=>o.name)}function branchSelectable(e,t,n=jl(e,t)){if(n.length<3)return[];let o=J(t),r=new Set(n.filter(s=>{let l=pe.find(d=>d.name===s);if(!l)return!1;let d=e.conveyorMeta?.get?.(I(o.col+l.dc,o.row+l.dr));if(!d)return!1;let k=[...new Set([...Array.isArray(d.outDirs)?d.outDirs:[],d.dir].filter(Boolean))];return k.includes(l.opposite)}));return n.filter(s=>{let l=new Set(r);return l.add(s),n.filter(d=>!l.has(d)).length>=2})}function ea(e,t,n){let o=J(t),r=pe.filter(d=>e.conveyorTiles.has(I(o.col+d.dc,o.row+d.dr))).map(d=>d.name),s=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(d=>r.includes(d)),l=r;return s.length?s:l}function ta(e,t,n,o,r=o){if(r.length<3||o.length<2)return;e.save();let s=o.includes(n.branchMode)?n.branchMode:"random",l=s!=="random";e.lineJoin="round",e.lineCap="round",e.lineWidth=2,e.fillStyle="rgba(255,255,255,.9)",e.strokeStyle=l?f.warn:f.green,ee(e,t.x-17,t.y-17,34,34,!0,!0),e.strokeStyle=f.ink,e.lineWidth=2,e.fillStyle=f.ink,s!=="random"?(l=pe.find(d=>d.name===s),ia(e,t.x,t.y,l?.angle||0,9,6)):(e.beginPath(),e.moveTo(t.x-10,t.y),e.lineTo(t.x-2,t.y),e.lineTo(t.x+8,t.y-8),e.moveTo(t.x-2,t.y),e.lineTo(t.x+8,t.y+8),e.stroke(),ia(e,t.x+9,t.y-9,-Math.PI/4,4,3),ia(e,t.x+9,t.y+9,Math.PI/4,4,3)),e.restore()}function na(e,t,n){if(!n)return[];return Zl(e,t,n).map(o=>pe.find(r=>r.name===o)).filter(Boolean)}function oa(e){let t=new Map;for(let[n,o]of e.conveyorMeta||[]){let r=na(e,n,o);r.length&&t.set(n,r)}return t}function ra(e,t,n){let o=n.slice(0,4);o.length&&(e.save(),e.fillStyle=f.ink,e.globalAlpha=.86,o.forEach(r=>{ia(e,t.x+r.dc*12,t.y+r.dr*12,r.angle,6,5)}),e.restore())}function ia(e,t,n,o,r=11,s=8){e.save(),e.translate(t,n),e.rotate(o),e.beginPath(),e.moveTo(r,0),e.lineTo(-r*.72,-s),e.lineTo(-r*.72,s),e.closePath(),e.fill(),e.restore()}function sa(e,t){e.save(),e.lineWidth=2,e.font="900 12px ui-monospace, monospace",e.textAlign="center";for(let n of t.scanners){let o=ho(n),r=[{type:"inputA",p:Me(n,"inputA"),label:"IN",color:f.green},{type:"left",p:Me(n,"left"),label:bo(o.left),color:wo(o.left)},{type:"right",p:Me(n,"right"),label:bo(o.right),color:wo(o.right)}];for(let s of r){if(!s.p)continue;let l=$(s.p.col,s.p.row),d=Ir(t,n,s.type||(s.label==="IN"?"inputA":null))||t.conveyorTiles.has(I(s.p.col,s.p.row));e.fillStyle=d?s.color:"#f4c2c2",e.strokeStyle=f.ink,ee(e,l.x-18,l.y-12,36,24,!0,!0),e.fillStyle=d&&s.color===f.white?f.ink:f.white,e.fillText(s.label,l.x,l.y+4)}}e.restore()}function la(e,t){for(let n of t.eggFarms)aa(e,n,t)}function aa(e,t,n){let o=$(t.col,t.row);if(e.save(),Rt(e,He.eggFarm,o.x-29,o.y-29,58,58)){Je(e,o.x-29,o.y-29,58,58,t);let l=1+Math.max(0,Number(t.extraEggOutlet)||0);e.fillStyle="rgba(255,255,255,.92)",e.strokeStyle=f.ink,e.lineWidth=2,ee(e,o.x+9,o.y+12,30,18,!0,!0),e.fillStyle=f.ink,e.font="900 10px ui-monospace, monospace",e.textAlign="center",e.fillText(`O${l}`,o.x+24,o.y+24),We(e,n,"eggFarm",t.id,o.x,o.y,68,68),e.restore();return}e.fillStyle=f.white,e.strokeStyle=f.ink,e.lineWidth=4,ee(e,o.x-28,o.y-28,56,56,!0,!0),e.fillStyle=f.green,e.font="900 19px ui-monospace, monospace",e.textAlign="center",e.fillText("EGG",o.x,o.y-4);let r=1+Math.max(0,Number(t.extraEggOutlet)||0);e.font="900 11px ui-monospace, monospace",e.fillStyle=f.ink,e.fillText(`L${t.level} O${r}`,o.x,o.y+13),e.fillText(`${t.nextSpawn.toFixed(1)}s`,o.x,o.y+26);let s=Math.max(0,Math.min(1,t.shutterProgress||0));if(s>0){let l=56*s;e.fillStyle=f.ink,ee(e,o.x-28,o.y-28,56,l,!0,!1),e.strokeStyle=f.white,e.lineWidth=2;for(let d=o.y-24;d=1&&(e.fillStyle=f.white,e.font="900 12px ui-monospace, monospace",e.fillText("SHUT",o.x,o.y+4))}Je(e,o.x-28,o.y-28,56,56,t),We(e,n,"eggFarm",t.id,o.x,o.y,68,68),e.restore()}function ca(e,t){for(let n of t.scanners)ua(e,n,t)}function ua(e,t,n){let o=de(t);if(e.save(),t.kind==="manual"&&(n.manualCombo?.count||0)>=10){let k=n.manualCombo.count;e.save(),e.globalAlpha=Math.min(.55,.16+k/120),e.strokeStyle=k>=30?f.warn:f.green,e.lineWidth=Math.min(14,5+Math.floor(k/10)),e.shadowColor=e.strokeStyle,e.shadowBlur=Math.min(28,8+k),ee(e,o.x-54,o.y-76,108,152,!1,!0),e.restore()}let r=t.kind==="auto"?He.scannerAuto:He.scannerManual;if(Rt(e,r,o.x-50,o.y-73,100,146)){t.kind==="auto"?Je(e,o.x-50,o.y-73,100,146,t):zi(e,t,o),We(e,n,"scanner",t.id,o.x,o.y,108,154),e.restore();return}e.fillStyle=t.kind==="auto"?"#d8ffe2":f.white,e.strokeStyle=f.ink,e.lineWidth=4,ee(e,o.x-50,o.y-73,100,146,!0,!0),e.fillStyle=t.kind==="auto"?f.green:f.ink,e.font="900 19px ui-monospace, monospace",e.textAlign="center",e.fillText(`${t.kind==="auto"?"AUTO":`S${(t.slot??0)+1}`}`,o.x,o.y-48),e.font="900 11px ui-monospace, monospace";let s=t.keys?.left?.label||(t.slot===0?"A":"Left"),l=t.keys?.right?.label||(t.slot===0?"D":"Right");e.fillText(t.role===0?`${s}:M ${l}:NEXT`:`${s}:WASTE ${l}:TRUCK`,o.x,o.y-28);let d=t.queue.length;t.kind==="manual"?(zi(e,t,o),e.fillStyle=d>0?f.green:f.muted,e.font="900 10px ui-monospace, monospace",e.fillText(`Q:${d}`,o.x,o.y+54)):(e.fillStyle=d>0?f.green:f.muted,e.font="900 12px ui-monospace, monospace",e.fillText(`Q:${d} CD:${t.cooldown.toFixed(1)}`,o.x,o.y+54),Je(e,o.x-50,o.y-73,100,146,t)),We(e,n,"scanner",t.id,o.x,o.y,108,154),e.restore()}function zi(e,t,n){if(t.kind!=="manual")return;let r=(t.slot??0)===0?[{side:"left",text:"A"},{side:"right",text:"D"}]:[{side:"left",text:"\u2190"},{side:"right",text:"\u2192"}];r[0].text=t.keys?.left?.label||r[0].text,r[1].text=t.keys?.right?.label||r[1].text;let s=t.keyPressTime>0?t.keyPressSide:null,l=n.x-30,d=n.y+18;e.save(),e.lineWidth=3,e.fillStyle="#f7fff5",e.strokeStyle=f.ink,ee(e,l-4,d-4,68,25,!0,!0),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let k=0;k.8,s=t.y+Math.sin(t.bob)*(r?5:1.5);if(e.save(),n&&(e.strokeStyle=f.green,e.lineWidth=5,e.beginPath(),e.arc(t.x,s,t.radius+8,0,Math.PI*2),e.stroke()),r&&(e.strokeStyle=f.danger,e.lineWidth=3,e.beginPath(),e.arc(t.x,s,t.radius+12+Math.sin(t.bob*2)*4,0,Math.PI*2),e.stroke()),t.sex==="poop")Vo(e,t.x,s,t.radius);else{let l=t.sex==="male"?He.chickMale:He.chickFemale;Rt(e,l,t.x-t.radius,s-t.radius,t.radius*2,t.radius*2)||(e.fillStyle=t.sex==="male"?f.male:f.female,e.strokeStyle=f.ink,e.lineWidth=5,e.beginPath(),e.arc(t.x,s,t.radius,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle=f.ink,e.beginPath(),e.arc(t.x-6,s-5,2.5,0,Math.PI*2),e.arc(t.x+6,s-5,2.5,0,Math.PI*2),e.fill(),e.fillStyle="#ffaa2e",e.beginPath(),e.moveTo(t.x,s+2),e.lineTo(t.x+9,s+6),e.lineTo(t.x,s+10),e.closePath(),e.fill())}e.restore()}function va(e,t){let n=null,o=1/0;for(let[r,s]of e.componentLookup.entries()){let l=J(r),d=$(l.col,l.row),k=Math.hypot(t.x-d.x,t.y-d.y);kVi(o.type,o.id)===Vi(t,n))}function We(e,t,n,o,r,s,l,d){xa(t,n,o)&&(e.save(),e.fillStyle="rgba(34,185,79,.18)",e.strokeStyle=f.green,e.lineWidth=(t.multiSelected||[]).length>1?6:4,e.setLineDash((t.multiSelected||[]).length>1?[]:[8,5]),ee(e,r-l/2,s-d/2,l,d,!0,!0),e.restore())}function ka(e,t,n,o){if(t.phase==="build"&&(t.multiSelected||[]).length>1){e.save(),e.fillStyle="rgba(255,255,255,.96)",e.strokeStyle=f.ink,e.lineWidth=3,ee(e,54-t.view.x,66-t.view.y,214,42,!0,!0),e.fillStyle=f.ink,e.font="900 11px ui-monospace, monospace",e.fillText(`${t.multiSelected.length} ITEMS SELECTED`,65-t.view.x,83-t.view.y),e.fillStyle=f.muted,e.font="900 11px ui-monospace, monospace",e.fillText("drag any selected item to move group",65-t.view.x,99-t.view.y),e.restore();return}}function Ca(e,t,n){if(!n.cardTargetPick?.pending)return;let o=_o(n);e.save(),e.fillStyle="rgba(0,0,0,.66)",e.beginPath();let r=n.view?.scale||1;e.rect(-(n.view?.x||0)/r,-(n.view?.y||0)/r,t.width/r,t.height/r);for(let k of o){let M=k.bounds,D=8;e.rect(M.x-D,M.y-D,M.w+D*2,M.h+D*2)}e.fill("evenodd");let s=n.cardTargetPick?.mode==="blockedCell";if(!o.length){e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=f.ink,e.lineWidth=3,ee(e,(260-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,420/r,42/r,!0,!0),e.fillStyle=f.danger,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(s?"NO BLOCKED CELL. PRESS ESC.":"NO VALID UPGRADE TARGET. PRESS ESC.",(470-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore();return}e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=f.ink,e.lineWidth=3;let l=Math.max(1,n.cardTargetPick?.remaining||1),d=n.cardTargetPick?.mode==="autoScannerMenu"?"AUTO SCANNER ROUTE SETTINGS. CLICK EMPTY AREA TO CLOSE.":s?`CLICK BLOCKED CELL: ${l} LEFT. PRESS ESC TO CANCEL.`:"CLICK AN UPGRADEABLE MACHINE. PRESS ESC TO CANCEL.";ee(e,(216-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,560/r,42/r,!0,!0),e.fillStyle=f.ink,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(d,(496-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore()}function Sa(e,t){if(t.phase!=="build"||!t.selectionBox)return;let n=t.selectionBox,o=Math.min(n.x1,n.x2),r=Math.min(n.y1,n.y2),s=Math.abs(n.x2-n.x1),l=Math.abs(n.y2-n.y1);e.save(),e.fillStyle="rgba(34,185,79,.12)",e.strokeStyle=f.green,e.lineWidth=2,e.setLineDash([7,4]),ee(e,o,r,s,l,!0,!0),e.restore()}function Ma(e,t){let n=[...t.effects].sort((o,r)=>(o.priority??Se.ambient)-(r.priority??Se.ambient));for(let o of n){let r=Math.max(0,o.life/o.maxLife);e.save(),e.globalAlpha=r,o.type==="meat"?(e.fillStyle=f.green,ee(e,o.x-o.size/2,o.y-o.size/2,o.size*1.5,o.size,!0,!1)):o.type==="sludge"?(e.fillStyle=f.poop,ee(e,o.x-o.size/2,o.y-o.size/2,o.size*1.4,o.size,!0,!1)):o.type==="spawn"?(e.strokeStyle=f.green,e.lineWidth=3,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*20,0,Math.PI*2),e.stroke()):o.type==="spark"?(e.fillStyle=o.color||f.danger,ee(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!0,!1)):o.type==="smoke"?(e.fillStyle="rgba(16,32,21,.24)",e.beginPath(),e.arc(o.x,o.y,o.size*(1.2-r*.2),0,Math.PI*2),e.fill()):o.type==="shockwave"?(e.strokeStyle=o.color||f.danger,e.lineWidth=4,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*(o.maxSize||44),0,Math.PI*2),e.stroke()):o.type==="scannerPulse"?(e.strokeStyle=o.color||f.green,e.lineWidth=5,e.setLineDash([8,6]),e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*38,0,Math.PI*2),e.stroke()):o.type==="shred"?(e.fillStyle=o.color||f.ink,e.save(),e.translate(o.x,o.y),e.rotate(o.rot||0),ee(e,-o.w/2,-o.h/2,o.w,o.h,!0,!1),e.restore()):o.type==="load"?(e.strokeStyle=o.color||f.green,e.lineWidth=3,e.beginPath(),e.moveTo(o.x-14,o.y),e.lineTo(o.x+14,o.y),e.moveTo(o.x,o.y-14),e.lineTo(o.x,o.y+14),e.stroke()):o.type==="erase"?(e.strokeStyle=f.ink,e.lineWidth=3,e.setLineDash([4,4]),ee(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!1,!0)):o.type==="rage"?(e.fillStyle=o.color||f.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText("!",o.x,o.y)):o.type==="flyingChick"&&(o.sex==="poop"?Vo(e,o.x,o.y,o.radius||11):Xo(e,o.x,o.y,o.sex,o.sex==="male")),e.restore()}}function Ta(e,t){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let n of t.floatingTexts){let o=Math.max(0,n.life/n.maxLife);e.globalAlpha=o,e.lineWidth=5,e.strokeStyle=f.white,e.fillStyle=n.color,e.strokeText(n.text,n.x,n.y),e.fillText(n.text,n.x,n.y)}e.restore()}function ga(e,t){let n=t.repairman;if(!(!!n?.active||t.phase==="build"&&!!n?.hiredForNextDay))return;e.save(),e.lineWidth=3,e.fillStyle="#fff0d1",e.strokeStyle=f.ink,e.beginPath(),e.arc(n.x,n.y,17,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle="#ffd6e7",e.beginPath(),e.arc(n.x-6,n.y-2,3.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+6,n.y-2,3.2,0,Math.PI*2),e.fill();let r=!!t.cardEffects?.laborExploitation;e.fillStyle=r?f.danger:f.ink,e.beginPath(),e.arc(n.x-5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.strokeStyle=f.ink,e.lineWidth=r?3:2,e.beginPath(),e.arc(n.x,n.y+(r?0:1),r?8:7,.1*Math.PI,.9*Math.PI),e.stroke(),e.fillStyle=f.green,ee(e,n.x-9,n.y+14,18,8,!0,!0),e.strokeStyle=f.ink,e.lineWidth=3,e.beginPath(),e.moveTo(n.x-11,n.y+18),e.lineTo(n.x-20,n.y+24),e.stroke(),e.beginPath(),e.moveTo(n.x+11,n.y+18),e.lineTo(n.x+20,n.y+24),e.stroke(),e.fillStyle=f.ink,e.font="900 11px ui-monospace, monospace",e.textAlign="center",e.fillText(n.active?"FIX":"HIRED",n.x,n.y+33),n.target?.label?Ho(e,n.x,n.y-24,n.target.label,f.green):!n.active&&n.hiredForNextDay&&Ho(e,n.x,n.y-24,"NEXT DAY",f.green),e.restore()}function Ea(e,t,n){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="left",e.fillStyle=f.ink,e.fillStyle="rgba(255,255,255,.92)",e.strokeStyle=f.ink,e.lineWidth=3,ee(e,n.width-284,18,260,34,!0,!0),e.fillStyle=f.green,e.font="900 12px ui-monospace, monospace",e.fillText(yn,n.width-270,40),e.font="900 19px ui-monospace, monospace",e.fillStyle=f.ink;let o=[];t.phase==="running"&&o.push(t.timeLeft<=0?"TIME UP: FARMS SHUT. CLEAR LINE.":"A/D: S1 \u2190/\u2192: S2"),t.phase==="build"&&o.push(`BUILD: ${t.buildTool||"SELECT"} | connect 1 EGG route to any exit`);let r=76;for(let s of o)e.strokeStyle=f.white,e.lineWidth=4,e.strokeText(s,24,r),e.fillText(s,24,r),r+=20;e.restore()}var ji=[[{key:"a",code:"KeyA",label:"A"},{key:"d",code:"KeyD",label:"D"}],[{key:"arrowleft",code:"ArrowLeft",label:"Left"},{key:"arrowright",code:"ArrowRight",label:"Right"}],[{key:"j",code:"KeyJ",label:"J"},{key:"l",code:"KeyL",label:"L"}],[{key:"f",code:"KeyF",label:"F"},{key:"h",code:"KeyH",label:"H"}],[{key:"q",code:"KeyQ",label:"Q"},{key:"e",code:"KeyE",label:"E"}],[{key:"z",code:"KeyZ",label:"Z"},{key:"x",code:"KeyX",label:"X"}],[{key:"u",code:"KeyU",label:"U"},{key:"o",code:"KeyO",label:"O"}],[{key:"n",code:"KeyN",label:"N"},{key:"m",code:"KeyM",label:"M"}]];function Pa(e){let t=ji[e]||ji[0];return{left:{...t[0]},right:{...t[1]}}}function es(e,t,n){let o={type:"eggFarm",id:e.nextId++,col:t,row:n,level:1,nextSpawn:2,lastInterval:2,extraEggOutlet:0,price:pt.eggFarm,builtSession:e.buildSession};return o.nextSpawn=wt(o),o.lastInterval=o.nextSpawn,o}function ts(e,t,n,o){let r=o==="auto"?we.autoScanner.price:we.manualScanner.price,s=new Set(e.scanners.filter(d=>d.kind==="manual").map(d=>d.slot)),l=0;for(;s.has(l);)l+=1;return{type:"scanner",id:e.nextId++,kind:o,slot:o==="manual"?l:null,role:o==="manual"?l%2:0,col:t,row:n,level:1,queue:[],cooldown:0,price:r,builtSession:e.buildSession,autoMode:"standard",keys:o==="manual"?Pa(l):null}}function Un(e){let t=(e.x-y.x)/y.cell,n=(e.y-y.y)/y.cell,o=Math.max(0,Math.min(y.cols-1,Math.round(t-.5))),r=Math.max(0,Math.min(y.rows-1,Math.round(n-.5))),s=Math.abs(e.x-y.x),l=Math.abs(e.x-(y.x+y.cols*y.cell)),d=Math.abs(e.y-y.y),k=Math.abs(e.y-(y.y+y.rows*y.cell)),M=[["left",s],["right",l],["top",d],["bottom",k]].sort((D,L)=>D[1]-L[1])[0][0];return M==="left"?{side:M,entry:{col:0,row:r}}:M==="right"?{side:M,entry:{col:y.cols-1,row:r}}:M==="top"?{side:M,entry:{col:o,row:0}}:{side:M,entry:{col:o,row:y.rows-1}}}function Wn(e,t,n){let o={x:y.x+t.col*y.cell+y.cell/2,y:y.y+t.row*y.cell+y.cell/2},r={left:y.x,right:y.x+y.cols*y.cell,top:y.y,bottom:y.y+y.rows*y.cell};return e.entry={...t},e.side=n,n==="left"?(e.x=r.left-e.w-18,e.y=o.y-e.h/2):n==="right"?(e.x=r.right+18,e.y=o.y-e.h/2):n==="top"?(e.x=o.x-e.w/2,e.y=r.top-e.h-18):(e.x=o.x-e.w/2,e.y=r.bottom+18),e}function ns(e,t,n,o){let{entry:r,side:s}=Un(n),l=we[t],d=l?{name:l.name,w:l.body?.w||168,h:l.body?.h||110,price:l.price}:{name:t[0].toUpperCase()+t.slice(1),w:168,h:110,price:o},k={type:"facility",id:t,name:d.name,x:0,y:0,w:d.w,h:d.h,level:1,price:o||d.price,builtSession:e.buildSession};return Wn(k,r,s)}function Ra(e){return Math.random()({x:s.x,y:s.y})),r=o[0];return{id:e.nextId++,sex:n,x:r.x,y:r.y,route:o,targetIndex:o.length>1?1:o.length,stage:t.stage||"belt",scannerId:t.scannerId??null,nextScannerId:null,pendingScannerId:null,radius:n==="poop"?15:17,bob:Math.random()*Math.PI*2,queueIndex:-1,queueRoute:null}}function rs({game:e,canvasPoint:t,updatePanels:n,equipmentAtPoint:o,fail:r,pointInGrid:s,rectOfFacility:l,rectsOverlap:d}){function k(w){return w?w.type==="conveyor"?`conveyor:${w.id||w.oldKey}`:w.type==="facility"?`facility:${w.id||w.ref?.id}`:`${w.type}:${w.id||w.ref?.id}`:""}function M(w){return w?w.type==="conveyor"?{type:"conveyor",id:w.oldKey}:{type:w.type,id:w.ref.id}:null}function D(w){let C=k(M(w));return(e.multiSelected||[]).some(O=>k(O)===C)}function L(w){return w?w.type==="eggFarm"?e.eggFarms.find(C=>C.id===w.id)||null:w.type==="scanner"?e.scanners.find(C=>C.id===w.id)||null:w.type==="facility"?e.facilities[w.id]||null:w.type==="conveyor"&&e.conveyorTiles.has(w.id)?{type:"conveyor",id:w.id}:null:null}function F(){let w=[];for(let C of e.conveyorTiles){let O=J(C),Y=$(O.col,O.row);w.push({type:"conveyor",id:C,center:Y,cell:O})}for(let C of e.eggFarms)w.push({type:"eggFarm",id:C.id,ref:C,center:$(C.col,C.row),cell:{col:C.col,row:C.row}});for(let C of e.scanners)w.push({type:"scanner",id:C.id,ref:C,center:de(C),cell:{col:C.col,row:C.row}});for(let C of Object.values(e.facilities)){let O={x:C.x+C.w/2,y:C.y+C.h/2},Y=C.entry?$(C.entry.col,C.entry.row):O;w.push({type:"facility",id:C.id,ref:C,center:O,portCenter:Y})}return w}function z(w,C){let O=Math.min(C.x1,C.x2),Y=Math.max(C.x1,C.x2),te=Math.min(C.y1,C.y2),se=Math.max(C.y1,C.y2);return w.x>=O&&w.x<=Y&&w.y>=te&&w.y<=se}function oe(w){let C=[];for(let O of F())(z(O.center,w)||O.portCenter&&z(O.portCenter,w))&&C.push({type:O.type,id:O.id});return e.multiSelected=C,e.selected=C[0]||null,n(),C.length}function X(){e.multiSelected=[],e.selected=null,n()}function ae(w){let C=t(w);return e.selectionBox={x1:C.x,y1:C.y,x2:C.x,y2:C.y},e.multiSelected=[],e.selected=null,n(),!0}function he(w){if(!e.selectionBox)return;let C=t(w);e.selectionBox.x2=C.x,e.selectionBox.y2=C.y}function j(){if(!e.selectionBox)return 0;let w=e.selectionBox,C=Math.abs(w.x2-w.x1),O=Math.abs(w.y2-w.y1);return e.selectionBox=null,C<6&&O<6?(X(),0):oe(w)}function g(w){let C=M(w);return C?(e.multiSelected||[]).length&&D(w)?[...e.multiSelected]:[C]:[]}function _(w){let C=L(w);if(!C)return null;if(w.type==="conveyor"){let O=J(w.id);return{...w,obj:C,oldKey:w.id,currentKey:w.id,meta:e.conveyorMeta.get(w.id)||{price:Be("conveyor"),builtSession:null},col:O.col,row:O.row}}return w.type==="eggFarm"||w.type==="scanner"?{...w,obj:C,col:C.col,row:C.row}:w.type==="facility"?{...w,obj:C,x:C.x,y:C.y,w:C.w,h:C.h,entry:C.entry?{...C.entry}:null,side:C.side,center:{x:C.x+C.w/2,y:C.y+C.h/2}}:null}function U(w){let C=t(w),O=o(C);if(!O)return!1;let Y=g(O),te=Y.map(_).filter(Boolean);return te.length?(e.groupDrag={start:C,selections:Y,origins:te,historySnapshot:rn(e),committed:!1,lastDCol:0,lastDRow:0},e.multiSelected=Y,e.selected=Y[0]||null,n(),!0):!1}function le(){!e.groupDrag||e.groupDrag.committed||(e.undoStack.push(e.groupDrag.historySnapshot),e.redoStack=[],e.groupDrag.committed=!0)}function me(w,C,O){let Y=I(w,C),te=kt(e,w,C);if(te&&!O.has(`eggFarm:${te.id}`))return!0;let se=Ct(e,w,C);return!!(se&&!O.has(`scanner:${se.id}`)||e.conveyorTiles.has(Y)&&!O.has(`conveyor:${Y}`))}function fe(w,C,O){let Y=[];for(let te of e.groupDrag.origins){if(te.type!=="facility")continue;let se={x:te.center.x+w,y:te.center.y+C},{entry:ve,side:ce}=Un(se);if(!s(ve.col,ve.row)||e.blockedCells?.has?.(I(ve.col,ve.row)))return!0;let je={...te.obj,entry:{...ve},side:ce};Wn(je,ve,ce),Y.push({id:te.id,rect:l(je)})}for(let te of Y)for(let se of Object.values(e.facilities))if(!O.has(`facility:${se.id}`)&&d(te.rect,l(se),12))return!0;for(let te=0;teQ.type==="conveyor");for(let Q of je){let xe=Q.currentKey||Q.oldKey;e.conveyorTiles.delete(xe),e.conveyorMeta.delete(xe)}for(let Q of je){let xe=I(Q.col+te,Q.row+se);e.conveyorTiles.add(xe),e.conveyorMeta.set(xe,Q.meta||{price:Be("conveyor"),builtSession:null,uses:0}),Q.currentKey=xe}for(let Q of e.groupDrag.origins)if(Q.type==="eggFarm")Q.obj.col=Q.col+te,Q.obj.row=Q.row+se;else if(Q.type==="scanner")Q.obj.col=Q.col+te,Q.obj.row=Q.row+se;else if(Q.type==="facility"){let xe={x:Q.center.x+O,y:Q.center.y+Y},{entry:ut,side:qe}=Un(xe);Wn(Q.obj,ut,qe)}e.groupDrag.selections=e.groupDrag.origins.map(Q=>Q.type==="conveyor"?{type:"conveyor",id:Q.currentKey||Q.oldKey}:{type:Q.type,id:Q.id}),e.multiSelected=[...e.groupDrag.selections],e.selected=e.multiSelected[0]||null,be(e),n()}function G(){e.groupDrag&&(be(e),e.groupDrag=null,n())}return{selectionFromHit:M,startSelectionBox:ae,updateSelectionBox:he,finishSelectionBox:j,startGroupDrag:U,updateGroupDrag:E,finishGroupDrag:G}}function is({game:e,ui:t,canvas:n,canvasPoint:o,onUpdatePanels:r}){function s(){r&&r()}let l=null,d=!1,k=null,M=!1,D=["random","up","right","down","left"],L={random:"RND",up:"UP",right:"RT",down:"DN",left:"LF"},F={w:40,h:40,y:0};function z(){return xn(e)}function oe(){e.gridCols=y.cols,e.gridRows=y.rows,e.gridOwnedCells=vr(e)}function X(i){if(i){y.y-=i*y.cell,y.rows+=i,e.gridChunkOriginY=(e.gridChunkOriginY||0)-Math.floor(i/10),e.ownedCells=kn(e.ownedCells,i),e.blockedCells=kn(e.blockedCells,i),e.conveyorTiles=kn(e.conveyorTiles,i),e.conveyorMeta=Sr(e.conveyorMeta,i);for(let c of e.eggFarms||[])c.row+=i;for(let c of e.scanners||[])c.row+=i;for(let c of Object.values(e.facilities||{}))c.entry&&(c.entry.row+=i)}}function ae(i){e.ownedCells=e.ownedCells||new Set;for(let c of Cr(i))e.ownedCells.add(I(c.col,c.row))}function he(i){return e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending?null:mt(e).find(c=>c&&kr(c,i))||null}function j(i="right"){if(i&&typeof i=="object"&&Number.isFinite(i.chunkX)&&Number.isFinite(i.chunkY))return i;let c=["right","up"].includes(i)?i:"right";return xr(e,c)}function g(i="right"){let c=j(i);if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return{ok:!1,reason:"Cannot expand now."};if(!c)return{ok:!1,reason:"Invalid expansion lot."};let h=c.direction||"right",m=z();if(e.cashy.cols&&(y.cols=A.colStart+A.cols),A.rowStart+A.rows>y.rows&&(y.rows=A.rowStart+A.rows),ae(A),Mr(e,A.chunkX,A.chunkY),e.gridExpansionPurchases=(e.gridExpansionPurchases||0)+1,e.gridExpansionPurchasesByDirection[h]=(e.gridExpansionPurchasesByDirection[h]||0)+1,oe();let ne=yr({seed:`${e.runSeed}:grid-expansion:${A.chunkX},${A.chunkY}:${e.gridExpansionPurchases}`,colStart:A.colStart,colEnd:A.colStart+A.cols,rowStart:A.rowStart,rowEnd:A.rowStart+A.rows,targetRatio:q.map.blockedRatio});for(let Ft of ne)e.blockedCells.add(Ft);be(e);let ue=A.cols*A.rows,ke=bt(A);return N(e,ke.x+ke.w/2,ke.y+ke.h/2,`${h.toUpperCase()} +${ue} CELLS -${S(m)}`,f.green),s(),{ok:!0,direction:h,cost:m,addedCells:ue,blocked:ne.size,chunkX:A.chunkX,chunkY:A.chunkY}}function _(i,c){return i>=0&&i=0&&c!c.has(m.id)&&me(h,le(m),12))}function E(i,c,h=null){if(!_(i,c))return!1;if(U(i,c))return!0;let m=I(i,c),T=kt(e,i,c);if(T&&!(h?.type==="eggFarm"&&h.ref?.id===T.id))return!0;let A=Ct(e,i,c);return!!(A&&!(h?.type==="scanner"&&h.ref?.id===A.id)||e.conveyorTiles.has(m)&&!(h?.type==="conveyor"&&h.oldKey===m))}function G(i,c,h=null){let m={col:i,row:c};for(let T of xt(m)){if(!_(T.col,T.row)||U(T.col,T.row))return!0;let A=I(T.col,T.row);if(kt(e,T.col,T.row))return!0;let ue=Ct(e,T.col,T.row);if(ue&&!(h?.type==="scanner"&&h.ref?.id===ue.id)||e.conveyorTiles.has(A))return!0}return!1}function w(){return e.selected?e.selected.type==="eggFarm"?e.eggFarms.find(i=>i.id===e.selected.id)||null:e.selected.type==="scanner"?e.scanners.find(i=>i.id===e.selected.id)||null:e.selected.type==="conveyor"?e.conveyorTiles.has(e.selected.id)?{type:"conveyor",id:e.selected.id}:null:e.selected.type==="facility"&&e.facilities[e.selected.id]||null:null}function C(i){return i?i.type==="eggFarm"?`${ht("eggFarm")} #${i.id}`:i.type==="scanner"?`${i.kind==="auto"?ht("autoScanner"):ht("manualScanner")} #${i.id}`:i.type==="conveyor"?e.conveyorMeta.get(i.id)?.kind==="boostConveyor"?ht("boostConveyor"):ht("conveyor"):i.type==="facility"?i.name:"Equipment":"Equipment"}function O(i){return i?.type==="conveyor"?e.conveyorMeta?.get(i.oldKey||i.ref?.id)?.price||En(i):En(i)}function Y(){return!!e.cardEffects?.usedMachineActive}function te(){return Y()?{usedMachine:!0,noRefund:!0,durabilityBaseMultiplier:.6}:{usedMachine:!1,noRefund:!1,durabilityBaseMultiplier:1}}function se(i){let c=te();return Object.assign(i,c),i}function ve(i){let c=i?.ref||i||{};if(i?.type==="eggFarm"||c.type==="eggFarm")return e.eggFarms.length<=1?"Cannot sell the last EGG FARM.":"";if((i?.type==="facility"||c.type==="facility")&&["mixer","trash","truck"].includes(c.baseId||c.id)){let h=c.baseId||c.id;if(Object.values(e.facilities).filter(T=>(T.baseId||T.id)===h).length<=1)return`Cannot sell the last ${c.shortName||c.name||c.id}.`}return""}function ce(i){t.buildStatus.textContent=i,N(e,n.width/2-e.view.x,86-e.view.y,i.toUpperCase(),f.danger)}function je(i){if(!i)return null;let c=I(i.col,i.row);return e.conveyorMeta.get(c)||null}function Q(i){return i?(Array.isArray(i.outDirs)||(i.outDirs=[]),i.outDirs=[...new Set(i.outDirs.filter(c=>["right","left","down","up"].includes(c)))],D.includes(i.branchMode)||(i.branchMode="random"),i.kind||(i.kind="conveyor"),i.speedMultiplier||(i.speedMultiplier=i.kind==="boostConveyor"?2:1),i.outDirs):[]}function xe(i){return i?pe.filter(c=>e.conveyorTiles.has(I(i.col+c.dc,i.row+c.dr))).map(c=>c.name):[]}function ut(i,c){let h=pe.find(ue=>ue.name===c);if(!i||!h)return!1;let m=I(i.col+h.dc,i.row+h.dr),T=e.conveyorMeta.get(m);if(!T)return!1;let A=h.opposite;return[...new Set([...Array.isArray(T.outDirs)?T.outDirs:[],T.dir].filter(Boolean))].includes(A)}function qe(i){if(!e.conveyorTiles.has(i))return[];let c=J(i),h=e.conveyorMeta.get(i),m=Q(h),T=xe(c),A=[...new Set([...m,h?.dir].filter(Boolean))].filter(ke=>T.includes(ke)),ne=T,ue=A.length?A:ne;return h&&(h.outDirs=m.filter(ke=>T.includes(ke)),h.dir&&!T.includes(h.dir)&&(h.dir=h.outDirs[0]||null),h.branchMode!=="random"&&!T.includes(h.branchMode)&&(h.branchMode="random")),ue}function Fe(i,c){let h=yt(i,c);if(!h)return!1;let m=I(i.col,i.row),T=I(c.col,c.row),A=e.conveyorMeta.get(m),ne=e.conveyorMeta.get(T);if(!A||!ne)return!1;let ue=Q(A),ke=!ue.includes(h)||A.dir!==h||!ne.dir;return ue.includes(h)||ue.push(h),A.dir=h,ne.dir||(ne.dir=h),ke}function At(i){return i?pe.map(c=>({col:i.col+c.dc,row:i.row+c.dr})).filter(c=>e.conveyorTiles.has(I(c.col,c.row))):[]}function rn(i){return xe(i).length>=3}function sn(i){if(!i||!e.conveyorTiles.has(I(i.col,i.row))||rn(i))return[];let c=At(i);if(!c.length||c.length>2)return[];let h=m=>{let T=[],A=i,ne=m,ue=0,ke=new Set([I(i.col,i.row)]);for(;ne&&ue<200;){ue+=1;let Ft=I(ne.col,ne.row);if(ke.has(Ft))break;if(ke.add(Ft),T.push(ne),rn(ne))break;m=At(ne).filter(ae=>!(ae.col===A.col&&ae.row===A.row)),m.length===1?(A=ne,ne=m[0]):ne=null}return T};return[...(c[0]?h(c[0]).reverse():[]),i,...(c[1]?h(c[1]):[])]}function ln(i,c){return!!i&&[...new Set([...Array.isArray(i.outDirs)?i.outDirs:[],i.dir].filter(Boolean))].includes(c)}function hn(i){let c=0,h=0;for(let m=0;mh?[...i].reverse():i;for(let T=0;TA.name),A=m.dir&&T.includes(m.dir)?m.dir:null,ne=T[(Math.max(-1,T.indexOf(A))+1)%T.length];return Oe(e),m.dir=ne,m.outDirs=[ne],m.branchMode="random",be(e),s(),!0}return Oe(e),hn(c),be(e),s(),!0}function un(){return q.facilities[e.buildTool==="boostConveyor"?"boostConveyor":"conveyor"]}function dt(i,c=null){if(!i)return{ok:!1,reason:re.fail.outOfGrid};let{col:h,row:m}=i,T=I(h,m);if(e.conveyorTiles.has(T))return{ok:!1,exists:!0};if(U(h,m))return{ok:!1,reason:"Cannot build on blocked ground."};if(kt(e,h,m)||Ct(e,h,m))return{ok:!1,reason:re.fail.cellOccupied};let A=un(),ne=A.id||"conveyor",ue=Be(ne,e);if(e.cash=Math.abs(m)?{col:i.col+Math.sign(h),row:i.row}:{col:i.col,row:i.row+Math.sign(m)}}function zn(i){d=!1,k=i?{col:i.col,row:i.row}:null,M=!1,l=null,zt(i)}function $t(i){if(!i)return;if(!l)return zt(i);let c=l,h=0;for(;(c.col!==i.col||c.row!==i.row)&&h<64;){let m=Yn(c,i);if(zt(m),c=l||m,h+=1,!l)break}}function dn(){!M&&k&&e.conveyorTiles.has(I(k.col,k.row))&&cn(k),k=null,M=!1,l=null,d=!1}function Vt(i){if(!i)return ce(re.fail.outOfGrid);let{col:c,row:h}=i;if(e.buildTool==="conveyor"||e.buildTool==="boostConveyor"){let m=dt(i,null);if(!m.ok)return ce(m.reason||re.fail.cellOccupied);be(e);return}if(U(c,h))return ce("Cannot build on blocked ground.");if(e.buildTool==="manualScanner"||e.buildTool==="autoScanner"?G(c,h):E(c,h))return ce(re.fail.cellOccupied);e.buildTool==="eggFarm"?Vn(c,h):e.buildTool==="manualScanner"?It(c,h,"manual"):e.buildTool==="autoScanner"&&It(c,h,"auto")}function Xt(i){let c=Ge(i.x,i.y);if(["conveyor","boostConveyor","eggFarm","manualScanner","autoScanner"].includes(e.buildTool))return Vt(c);if(Zt.includes(e.buildTool))return Xn(i,e.buildTool)}function Vn(i,c){let h=Be("eggFarm",e);if(e.cashA.kind==="manual").length>=8)return ce("Manual Scanner limit reached (8 max).");let m=h==="auto"?Be("autoScanner",e):Be("manualScanner",e);if(e.cashT.id!==c.ref.id),st(e,m.x,m.y),be(e)}if(c.type==="scanner"){let m=de(c.ref);u(c,m.x,m.y),e.scanners=e.scanners.filter(T=>T.id!==c.ref.id),st(e,m.x,m.y),be(e)}if(c.type==="facility"){let m=c.ref;u(c,m.x+m.w/2,m.y+m.h/2),delete e.facilities[m.id],st(e,m.x+m.w/2,m.y+m.h/2),be(e)}e.selected=null,e.multiSelected=[],s()}function b(i){let c=Object.values(e.facilities).find(ne=>{if(i.x>=ne.x&&i.x<=ne.x+ne.w&&i.y>=ne.y&&i.y<=ne.y+ne.h)return!0;if(!ne.entry)return!1;let ke=$(ne.entry.col,ne.entry.row);return Math.abs(i.x-ke.x)<=y.cell*.46&&Math.abs(i.y-ke.y)<=y.cell*.46});if(c)return{type:"facility",ref:c};let h=Ge(i.x,i.y);if(!h)return null;let m=kt(e,h.col,h.row);if(m)return{type:"eggFarm",ref:m};let T=Ct(e,h.col,h.row);if(T)return{type:"scanner",ref:T};let A=I(h.col,h.row);return e.conveyorTiles.has(A)?{type:"conveyor",oldKey:A,ref:{type:"conveyor",id:A}}:null}let x=rs({game:e,canvasPoint:o,updatePanels:s,equipmentAtPoint:b,fail:ce,pointInGrid:_,rectOfFacility:le,rectsOverlap:me});function v(i){return null}function P(){let i=w();i&&(i.type==="conveyor"?p($(...Object.values(J(i.id)))):i.type==="eggFarm"?p($(i.col,i.row)):i.type==="scanner"?p(de(i)):i.type==="facility"&&p({x:i.x+i.w/2,y:i.y+i.h/2}))}function R(i,c,h="primary-button"){let m=document.createElement("button");return m.type="button",m.className=h,m.textContent=i,m.addEventListener("click",c),m}function V(){e.cardTargetPick?.mode==="autoScannerMenu"&&(e.cardTargetPick=null),t.modal.classList.remove("visible","equipment-popover"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function Z(i){t.modalTitle.textContent="Auto Scanner",e.cardTargetPick={pending:!0,mode:"autoScannerMenu",cardId:null,targetKeys:[`scanner:${i.id}`],remaining:1},t.modalBody.innerHTML=` +var q={version:"v27.14 debug restore consistency patch",time:{daySeconds:60,farmShutdownGraceSeconds:10},cash:{starting:250},grid:{x:170,y:78,cols:20,rows:10,cell:46,expansion:{colsPerPurchase:10,rowsPerPurchase:10,costBase:1e3,costMultiplier:1.3333333333333333,truncateUnit:100}},map:{blockedRatio:.075},economy:{income:{mixer:5,truck:10},poopFine:10,fairiesTribute:{perDay:10,profitExemption:300,legalWorkExemptionBonus:250,profitRate:.12},incomeUpgradeRate:1.1,explosionDamageDivisor:30,maleTruckFinePerHalfDay:30,shredderBonus:{maxCards:30,incomePerUpgrade:1.25},chemicalWeaponSubsidy:{poopPerBlock:70,yenPerBlock:1200}},production:{poopRate:.08,autoScannerCooldown:3.5,autoScannerUpgradeRate:.95,autoScannerCardUpgradeRate:.95,autoScannerMinCooldown:.5,poopRateCardBonus:.04,eggSpawnRanges:[[1.95,4.35],[1.55,3.45],[1.25,2.8],[1.05,2.35]]},conveyor:{baseSpeed:52,maxSpeed:300,bearingSpeedMultiplier:1.075},cards:{definitions:[{id:"upgradeEgg",title:"EGG Improvement",rarity:"common",type:"equipmentUpgrade",target:"eggFarm",description:"Choose one EGG FARM on the map and raise it by 1 level.",tags:["EGG","ACTIVE"]},{id:"upgradeAutoScanner",title:"AUTO SCANNER Improvement",rarity:"common",type:"equipmentUpgrade",target:"autoScanner",description:"Choose one AUTO SCANNER on the map and raise it by 1 level.",tags:["SCANNER","ACTIVE"]},{id:"autoScannerTuning",title:"AUTO SCANNER Tuning",rarity:"common",type:"instant",description:"All AUTO SCANNER cooldowns use default cooldown x0.95 per copy.",tags:["SCANNER","PASSIVE"]},{id:"upgradeMixer",title:"MIXER Improvement",rarity:"common",type:"equipmentUpgrade",target:"mixer",description:"Choose MIXER on the map and raise it by 1 level.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeTruck",title:"TRUCK Improvement",rarity:"common",type:"equipmentUpgrade",target:"truck",description:"Choose TRUCK on the map and raise it by 1 level.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeTrash",title:"SHREDDER Improvement",rarity:"common",type:"equipmentUpgrade",target:"trash",description:"Shred poops for a little money. Max 30 upgrades.",tags:["POOP","ACTIVE"]},{id:"crowdedFarming",title:"Crowded Farming",rarity:"common",type:"instant",description:"EGG production interval -5%. Equipment deterioration +4%. Max 10 cards.",tags:["EGG","RISK","PASSIVE"]},{id:"hatchingFeed",title:"Hatching Feed",rarity:"common",type:"instant",description:"EGG production interval -4%. Poop rate +3%. No card limit.",tags:["EGG","POOP","PASSIVE"]},{id:"poopRateBooster",title:"Poop Culture",rarity:"common",type:"instant",description:"Base poop rate +4 percentage points. No card limit.",tags:["POOP","PASSIVE"]},{id:"safetyCover",title:"Safety Cover",rarity:"common",type:"instant",description:"Explosion damage -5%. No card limit.",tags:["RISK","PASSIVE"]},{id:"preventiveMaintenance",title:"Preventive Maintenance Manual",rarity:"common",type:"instant",description:"All equipment deterioration speed -5%. No card limit.",tags:["MAINTENANCE","PASSIVE"]},{id:"dudFilter",title:"DUD Filter",rarity:"common",type:"instant",description:"DUD chance -5 percentage points. Stacks until DUD chance reaches 0%.",tags:["CARD","PASSIVE"]},{id:"durabilityCoating",title:"Durability Coating",rarity:"common",type:"instant",description:"All equipment maximum durability +3%. No card limit.",tags:["MAINTENANCE","PASSIVE"]},{id:"bearing",title:"High-Quality Bearing",rarity:"common",type:"instant",description:"Conveyor speed +7.5%.",tags:["CONVEYOR","PASSIVE"]},{id:"sparePartsBin",title:"SPARE PARTS BIN",rarity:"common",type:"instant",description:"Restores 2% durability to every machine. A box of almost-compatible parts.",tags:["MAINTENANCE","ACTIVE"]},{id:"dudRefund",title:"DUD REFUND",rarity:"common",type:"instant",description:"DUDs now come with paperwork. Gain JPY 50 per copy when you pick a DUD.",tags:["CARD","ECONOMY","PASSIVE"]},{id:"freeReroll",title:"FREE REROLL",rarity:"common",type:"instant",description:"The first bad ideas are free.",tags:["CARD","PASSIVE"]},{id:"composter",title:"COMPOSTER",rarity:"common",type:"instant",description:"Turns shredder waste into suspicious fertilizer. Gain JPY 3 per copy when SHREDDER processes poop.",tags:["POOP","ECONOMY","PASSIVE"]},{id:"scannerQueueSpacing",title:"Scanner Queue Spacing",rarity:"common",type:"instant",description:"Manual and Auto Scanner queue spacing -15%. No card limit.",tags:["SCANNER","PASSIVE"]},{id:"extraEggOutlet",title:"Extra Egg Outlet",rarity:"rare",type:"equipmentUpgrade",target:"eggOutlet",description:"Choose one EGG FARM and add +1 output port to that EGG. Max +3 per EGG.",tags:["EGG","RARE","ACTIVE"]},{id:"recyclingSubsidy",title:"Recycling Subsidy",rarity:"rare",type:"instant",description:"SELL refund rate +10 points. Max 3 cards; normal SELL can reach 80%.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"dynamite",title:"Dynamite",rarity:"rare",type:"cellAction",target:"blockedCell",description:"Remove any 3 unbuildable cells",tags:["RISK","RARE","ONE-SHOT"]},{id:"usedMachine",title:"Used Machines",rarity:"rare",type:"instant",description:"Future equipment costs half. New purchases have no refund and 60% durability. New Machines cancels it.",tags:["ECONOMY","RISK","RARE"]},{id:"newMachine",title:"New Machines",rarity:"common",type:"instant",description:"Cancel Used Machines and restore normal prices, refunds, and durability.",tags:["ECONOMY","ONE-SHOT"]},{id:"flattery",title:"Flattery",rarity:"rare",type:"instant",description:"Next Fairies tribute -50%.",tags:["ECONOMY","RARE","ONE-SHOT"]},{id:"extraCards",title:"Extra Cards",rarity:"rare",type:"instant",description:"Draw 2 cards now and choose both.",tags:["RARE","ACTIVE"]},{id:"legalWork",title:"Legal Work",rarity:"rare",type:"instant",description:"Fairies tribute profit exemption +JPY 250.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"chemicalWeaponSubsidy",title:"Chemical Weapons Subsidy",rarity:"ultraRare",type:"instant",description:"Each day, gain JPY 1200 per 70 poop shipped by truck. No card limit.",tags:["POOP","ULTRA RARE","PASSIVE"]},{id:"laborExploitation",title:"Motivational Exploitation",rarity:"ultraRare",type:"instant",description:"Repairman labor cost -30%. The repairman smiles with bloodshot eyes. One time only.",tags:["MAINTENANCE","ULTRA RARE","PASSIVE"]},{id:"rescueLoan",title:"Emergency Loan",rarity:"ultraRare",type:"instant",description:"If cash is below JPY 0 at day-end settlement, gain JPY 500. Consumed on use.",tags:["ECONOMY","ULTRA RARE","ONE-SHOT"]}],defaultEffects:{bearing:0,legalWork:0,fairiesFlatteryNext:0,autoScannerTuning:0,poopRateBooster:0,crowdedFarming:0,hatchingFeed:0,safetyCover:0,recyclingSubsidy:0,chemicalWeaponSubsidy:0,preventiveMaintenance:0,dudFilter:0,durabilityCoating:0,sparePartsBin:0,dudRefund:0,freeReroll:0,composter:0,scannerQueueSpacing:0,laborExploitation:0,usedMachineActive:!1,rescueLoanCharges:0},commonWeight:8,rareWeight:2,ultraRareWeight:.45,baseDraftSize:3,maxDudsPerDraft:2,dudChancePerCard:.3,dudChanceReductionPerFilter:.05,extraCardsAddedPicks:2,rerollCost:{dayDivisor:2,multiplier:100}},events:{eventChance:.1,firstTurn:8},maintenance:{fullPerformanceUntilWear:.5,minimumPerformance:.5,durability:{conveyor:1300,eggFarm:475,autoScanner:850,mixer:775,trash:950},processingDelayMaxSeconds:{mixer:1.2,trash:1},repairman:{dailyCost:100,secondsPerOnePercent:.5,walkSpeed:90}},facilities:{conveyor:{id:"conveyor",type:"conveyor",name:"Conveyor",shortName:"Belt",price:30,buildable:!0,upgradeable:!1},boostConveyor:{id:"boostConveyor",type:"conveyor",name:"Boost Conveyor",shortName:"BOOST BELT",price:75,buildable:!0,upgradeable:!1,speedMultiplier:2},eggFarm:{id:"eggFarm",type:"eggFarm",name:"Egg Farm",shortName:"EGG",price:250,buildable:!0,upgradeable:!0,maxLevel:4},manualScanner:{id:"manualScanner",type:"scanner",kind:"manual",name:"Manual Scanner",shortName:"Manual Scanner",price:260,buildable:!0,upgradeable:!1},autoScanner:{id:"autoScanner",type:"scanner",kind:"auto",name:"Auto Scanner",shortName:"Auto Scanner",price:180,buildable:!0,upgradeable:!1},mixer:{id:"mixer",type:"facility",name:"Mixer",shortName:"MIXER",price:450,buildable:!0,upgradeable:!0,incomeKey:"mixer",body:{w:164,h:126}},trash:{id:"trash",type:"facility",name:"Waste Shredder",shortName:"SHREDDER",price:240,buildable:!0,upgradeable:!0,body:{w:180,h:100}},truck:{id:"truck",type:"facility",name:"Truck",shortName:"TRUCK",price:450,buildable:!0,upgradeable:!0,incomeKey:"truck",body:{w:176,h:138}}}};var wn=q.version,vt=q.time.daySeconds,tn=q.cash.starting,xe=q.economy,xr=q.time.farmShutdownGraceSeconds,Sn=q.production.autoScannerCooldown,kr=q.production.autoScannerUpgradeRate,so=q.production.autoScannerCardUpgradeRate||q.production.autoScannerUpgradeRate,lo=q.production.autoScannerMinCooldown,Cr=q.events.eventChance,wt=q.events.firstTurn,ao=q.production.poopRate,co=q.production.poopRateCardBonus||0,xn=q.conveyor.baseSpeed,Gt=q.conveyor.maxSpeed,kn=q.conveyor.bearingSpeedMultiplier,Re=q.cards,Mr=q.cards.definitions,uo=q.cards.defaultEffects,st=q.production.eggSpawnRanges,y=q.grid,Se=q.facilities,fo=["conveyor","boostConveyor","eggFarm","autoScanner","manualScanner","mixer","trash","truck"],nn=["mixer","trash","truck"],gr=["mixer","truck"],St=Object.fromEntries(Object.entries(Se).map(([e,t])=>[e,t.price])),ue=[{name:"right",dc:1,dr:0,angle:0,opposite:"left"},{name:"left",dc:-1,dr:0,angle:Math.PI,opposite:"right"},{name:"down",dc:0,dr:1,angle:Math.PI/2,opposite:"up"},{name:"up",dc:0,dr:-1,angle:-Math.PI/2,opposite:"down"}],f={bg:"#eefbea",ink:"#102015",muted:"#526456",green:"#22b94f",greenSoft:"#b7f5c6",mixerBlue:"#2477ff",truckPink:"#ff6aa8",wasteGreen:"#22b94f",danger:"#c42424",warn:"#f0a020",white:"#ffffff",poop:"#7b4a23",male:"#62a9ff",female:"#ff8bc6"},ke={ambient:0,important:1,critical:2};function M(e){let t=Number(e)||0;return`${t<0?"-":""}\uFFE5${Math.ceil(Math.abs(t)).toLocaleString("ja-JP")}`}function $(e,t){return`${e},${t}`}function Q(e){let[t,n]=String(e).split(",").map(Number);return{col:t,row:n}}function on(e,t,n){return Math.max(t,Math.min(n,e))}function U(e,t){return e+Math.random()*(t-e)}function Te(e,t){return e>=0&&e=0&&tMath.round(on(r,0,255)).toString(16).padStart(2,"0");return`#${o(e)}${o(t)}${o(n)}`}function yo(e,t,n){let o=Tr(e),r=Tr(t);return tl(po(o.r,r.r,n),po(o.g,r.g,n),po(o.b,r.b,n))}var re={appTitle:"Chick Sorter",versionTitle:`Chick Sorter ${wn}`,currency:"\uFFE5",phases:{title:"Title",build:"Build",running:"Sorting",clearing:"Clearing",loanDecision:"Emergency Loan",gameover:"Game Over"},actions:{startGame:"Start Game",nextDay:"Next Day",buildPhase:"Build Phase",restart:"Restart",close:"Close",remove:"Remove",refund:"Refund",autoMenu:"Auto Menu"},status:{build:e=>`BUILD: ${(e==="erase"?"SELL":e||"SELECT").toUpperCase()} | Right-drag pan | Hover equipment for info`,sorting:"Sorting: use scanner keys. Build after clearing the day.",allPortsConnected:"Start condition met: one EGG route reaches an exit.",equipmentPanelEmpty:"Hover equipment in Build phase.",eventPanelRunning:"Forced events appear in Build phase."},routeLabels:{mixer:"MIXER",truck:"TRUCK",trash:"WASTE",scanner:"NEXT","scanner-role-1":"NEXT",input:"IN"},fail:{outOfGrid:"Out of grid",cellOccupied:"Cell occupied",notEnoughCash:"Not enough cash",facilityExists:"Facility already exists",facilityOverlap:"Facility overlap",nothingToErase:"Nothing to sell",noUpgrade:"No upgrade available"}};function xt(e){return Se[e]?.name||String(e||"").replace(/^[a-z]/,t=>t.toUpperCase())}function nl(e){let t=Se[e];return t?e==="conveyor"||e==="boostConveyor"?`${M(t.price)} / tile`:e==="autoScanner"?`${M(t.price)} / ${Sn.toFixed(1)}s cooldown`:e==="trash"?M(t.price):M(t.price):""}function ol(e){return{conveyor:"A narrow green belt. Routes decide whether chicks live, ship, or become invoices.",boostConveyor:"Moves chicks twice as fast. Wears down like a normal belt.",eggFarm:"A tiny gatehouse producing questionable eggs on schedule.",autoScanner:"Slower than hands without upgrades.",manualScanner:"A manual checkpoint. The operator is the algorithm.",mixer:"Male chicks become revenue here. Do not feed it poop.",trash:"A polite shredder for poop and other regrets.",truck:"Ships the target cargo. Wrong cargo still leaves a paper trail."}[e]||""}function Pr(e){let t=ol(e);return`${xt(e)}${nl(e)}${t?`${t}`:""}`}function Rr(e){return re.routeLabels[e]||String(e).toUpperCase()}function Ar(e){let t=2166136261;for(let n=0;n>>0}function Dr(e){let t=e>>>0;return()=>{t+=1831565813;let n=Math.imul(t^t>>>15,1|t);return n^=n+Math.imul(n^n>>>7,61|n),((n^n>>>14)>>>0)/4294967296}}function Mn(){return`RUN-${Date.now().toString(36)}-${Math.floor(Math.random()*1e6).toString(36)}`.toUpperCase()}function Ir({seed:e,targetRatio:t=.2,reserved:n=[]}={}){let o=Dr(Ar(e||Mn())),r=new Set(n.map(d=>typeof d=="string"?d:$(d.col,d.row))),s=[];for(let d=0;d0;d-=1){let v=Math.floor(o()*(d+1));[s[d],s[v]]=[s[v],s[d]]}let l=Math.round(y.cols*y.rows*t);return new Set(s.slice(0,Math.min(l,s.length)).map(d=>d.k))}function $r({seed:e,colStart:t=0,colEnd:n=y.cols,rowStart:o=0,rowEnd:r=y.rows,targetRatio:s=.2,reserved:l=[]}={}){let d=Dr(Ar(e||Mn())),v=new Set(l.map(z=>typeof z=="string"?z:$(z.col,z.row))),C=[],P=Math.max(0,Math.floor(t)),A=Math.max(P,Math.floor(n)),L=Math.max(0,Math.floor(o)),V=Math.max(L,Math.floor(r));for(let z=L;z0;z-=1){let se=Math.floor(d()*(z+1));[C[z],C[se]]=[C[se],C[z]]}let ne=Math.round((A-P)*(V-L)*s);return new Set(C.slice(0,Math.min(ne,C.length)).map(z=>z.k))}var Ut=10,Fr=2,Br=1;function Wt(e,t){return`${e},${t}`}function rl(e){let[t,n]=String(e).split(",").map(Number);return{chunkX:t,chunkY:n}}function gn(e){let t=q.grid.expansion||{},n=Math.max(1,(e.gridExpansionPurchases||0)+1),o=(t.costBase||1e3)*n*(t.costMultiplier||4/3),r=Math.max(1,t.truncateUnit||100);return Math.floor(o/r)*r}function Lr(e){e.ownedCells=new Set,e.ownedChunks=new Set,e.gridChunkOriginY=0,e.gridExpansionPurchases=0,e.gridExpansionPurchasesByDirection={right:0,up:0};for(let t=0;t=0&&t=0&&n0)continue;let C=Wt(v.chunkX,v.chunkY);t.has(C)||n.has(C)||n.set(C,ho(e,v.chunkX,v.chunkY,v.direction))}}return[...n.values()].sort((o,r)=>{let s=o.direction===r.direction?0:o.direction==="right"?-1:1;return s||(o.chunkY!==r.chunkY?o.chunkY-r.chunkY:o.chunkX-r.chunkX)})}function Gr(e,t="right"){let n=kt(e);return n.find(o=>o.direction===t)||n[0]||null}function Ct(e){return{x:y.x+e.colStart*y.cell,y:y.y+e.rowStart*y.cell,w:e.cols*y.cell,h:e.rows*y.cell}}function mo(e){let t=Ct(e);return{x:t.x+t.w/2-116,y:t.y+t.h/2-36,w:232,h:72,cx:t.x+t.w/2,cy:t.y+t.h/2}}function Ur(e,t){let n=mo(e);return t.x>=n.x&&t.x<=n.x+n.w&&t.y>=n.y&&t.y<=n.y+n.h}function Wr(e){let t=[];for(let n=e.rowStart;nTe(t.col,t.row))}function fl(e){return[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}].filter(t=>Te(t.col,t.row))}function pl(e){return[{col:e.col,row:e.row+1},{col:e.col-1,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row-1}].filter(t=>Te(t.col,t.row))}function Vr(e){let t=new Set([...e.conveyorTiles]),n=o=>{o&&Te(o.col,o.row)&&t.add($(o.col,o.row))};for(let o of e.scanners){for(let r of fl(o))n(r);for(let r of dl(o))n(r)}for(let o of e.eggFarms){n(o);for(let r of pl(o))n(r)}for(let o of Object.values(e.facilities))n(o.entry);return t}function qr(e){let t=ll.map(([n,o])=>({col:n,row:o}));for(let{col:n,row:o}of t)Yr(e,n,o);for(let n=0;n({...n,keys:n.keys?{left:{...n.keys.left},right:{...n.keys.right}}:null,queue:[]})),e.eggFarms=cl.map(n=>{let o=Mt(n);return{...n,nextSpawn:o,lastInterval:o}});let t=Vr(e);e.blockedCells=Ir({seed:e.runSeed,targetRatio:q.map.blockedRatio,reserved:[...t]}),yl(e),qr(e),e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function gt(e){return e?[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}]:[]}function pe(e){let t=F(e.col,e.row);return{x:t.x+y.cell/2,y:t.y}}function Tt(e,t,n){return e.eggFarms.find(o=>o.col===t&&o.row===n)||null}function Et(e,t,n){return e.scanners.find(o=>gt(o).some(r=>r.col===t&&r.row===n))||null}function Pt(e,t){return e.scanners.find(n=>n.id===t)||null}function xo(e,t){return e.scanners.find(n=>n.kind==="manual"&&n.slot===t)||null}function Rn(e){return e?.baseId||e?.id||""}function ko(e,t){return Object.entries(e.facilities||{}).filter(([,n])=>Rn(n)===t)}function Ee(e,t){return{inputA:{col:e.col,row:e.row-2},inputB:null,left:{col:e.col-1,row:e.row},right:{col:e.col+2,row:e.row}}[t]}function Qr(e){return e?ue.map(t=>({col:e.col+t.dc,row:e.row+t.dr})).filter(t=>Te(t.col,t.row)):[]}function Jr(e,t,n=[],o=[]){if(!t||!Te(t.col,t.row))return[];let r=[],s=l=>{!l||!Te(l.col,l.row)||!e.conveyorTiles.has($(l.col,l.row))||n.some(d=>d&&Cn(l,d))||r.some(d=>Cn(d,l))||r.push({...l,viaTolerance:!Cn(l,t)})};s(t);for(let l of o)s(l);for(let l of Qr(t))s(l);return r}function zr(e,t,n=[],o=[]){let r=Jr(e,t,n,o),s=r.filter(l=>!l.viaTolerance);return s.length?s:r}function hl(e,t){let n=Ee(t,"inputA");return!n||!Te(n.col,n.row)?[]:e.conveyorTiles.has($(n.col,n.row))?[{...n,viaTolerance:!1}]:[]}function ml(e,t,n){let o=Ee(t,n);return Jr(e,o,gt(t))}function bl(e,t){let n=e.facilities[t]||ko(e,t)[0]?.[1];if(!n)return null;if(n.entry)return F(n.entry.col,n.entry.row);let o=Rn(n)||t;return o==="mixer"?{x:n.x+n.w,y:n.y+n.h*.52}:o==="truck"?{x:n.x,y:n.y+n.h*.52}:o==="trash"?{x:n.x+n.w/2,y:n.y+8}:{x:n.x+n.w/2,y:n.y+n.h/2}}function jr(e,t,n){return n==="inputA"?hl(e,t).length>0:ml(e,t,n).length>0}function be(e){e.branchCounters?.clear?.(),e.routeCache=null,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function Ae(e,t){return $(e,t)}function _t(e){return Q(e)}function vl(e,t){let n=e.conveyorMeta?.get?.(t)||{},o=[];return Array.isArray(n.outDirs)&&o.push(...n.outDirs),n.dir&&o.push(n.dir),[...new Set(o)].filter(r=>ue.some(s=>s.name===r))}function wl(e,t,n){let o=ue.find(l=>l.name===n);if(!o)return!1;let r=e.conveyorMeta?.get?.(Ae(t.col+o.dc,t.row+o.dr));return r?[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))].includes(o.opposite):!1}function Sl(e,t){let n=_t(t),o=e.conveyorMeta?.get?.(t)||{},r=ue.filter(A=>e.conveyorTiles.has(Ae(n.col+A.dc,n.row+A.dr))).map(A=>A.name),s=vl(e,t).filter(A=>r.includes(A)),l=r,d=s.length?s:l;if(r.length<3)return d;let v=new Set(r.filter(A=>wl(e,n,A)));if(o.branchMode&&o.branchMode!=="random"&&r.includes(o.branchMode)){let A=new Set(v);A.add(o.branchMode),r.filter(L=>!A.has(L)).length>=2&&v.add(o.branchMode)}let C=r.filter(A=>!v.has(A));if(C.length)return C;let P=d.filter(A=>!v.has(A));return P.length?P:d}function xl(e){return{version:e.routingVersion||0,cells:new Set,adjacency:new Map,components:new Map,cellToComponent:new Map,scannerInputs:new Map,scannerPorts:new Map,facilityPorts:new Map,farmOutputs:new Map,pathCache:new Map,metrics:{conveyorCells:0,edges:0,components:0,deadEnds:0,crosses:0,scannerPorts:0,connectedScannerPorts:0,facilityPorts:0,connectedFacilityPorts:0,farmOutputs:0},issues:[]}}function kl(e){let t=xl(e);for(let o of e.conveyorTiles)t.cells.add(o),t.adjacency.set(o,[]);for(let o of t.cells){let r=_t(o),s=Sl(e,o),l=ue.filter(d=>s.includes(d.name));for(let d of l){let v=Ae(r.col+d.dc,r.row+d.dr);t.cells.has(v)&&t.adjacency.get(o).push({key:v,dir:d.name})}}let n=0;for(let[o,r]of t.adjacency.entries()){n+=r.length;let s=new Set(r.map(l=>l.dir));r.length===1&&(t.metrics.deadEnds+=1),r.length===4&&s.has("left")&&s.has("right")&&s.has("up")&&s.has("down")&&(t.metrics.crosses+=1)}return t.metrics.conveyorCells=t.cells.size,t.metrics.edges=Math.floor(n/2),Cl(t),Ml(e,t),t.issues=Bl(e,t,{includeRoutes:!1}),t}function Cl(e){let t=1;for(let n of e.cells){if(e.cellToComponent.has(n))continue;let o=t++,r=[n],s=[];for(e.cellToComponent.set(n,o);r.length;){let l=r.shift();s.push(l);for(let d of e.adjacency.get(l)||[])e.cellToComponent.has(d.key)||(e.cellToComponent.set(d.key,o),r.push(d.key))}e.components.set(o,{id:o,cells:s,capacity:Math.max(1,s.length),count:0,ratio:0})}e.metrics.components=e.components.size}function Ml(e,t){for(let n of e.scanners){let o={};for(let r of["inputA","left","right"]){let s=Ee(n,r),l=r==="inputA"?s&&t.cells.has(Ae(s.col,s.row))?[{...s}]:[]:zr(e,s,gt(n)).filter(C=>t.cells.has(Ae(C.col,C.row))),d=l.map(C=>Ae(C.col,C.row)),v=d.length>0;if(o[r]={type:r,cell:s,cells:l,keys:d,key:d[0]||null,connected:v},t.metrics.scannerPorts+=1,v&&(t.metrics.connectedScannerPorts+=1),r==="inputA")for(let C of d)t.scannerInputs.set(C,n.id)}t.scannerPorts.set(n.id,o)}for(let[n,o]of Object.entries(e.facilities)){if(!o.entry)continue;let r=zr(e,o.entry).filter(d=>t.cells.has(Ae(d.col,d.row))),s=r.map(d=>Ae(d.col,d.row)),l=s.length>0;t.facilityPorts.set(n,{id:n,cell:{...o.entry},cells:r,keys:s,key:s[0]||null,connected:l}),t.metrics.facilityPorts+=1,l&&(t.metrics.connectedFacilityPorts+=1)}for(let n of e.eggFarms){let o=Qr({col:n.col,row:n.row}).map(r=>Ae(r.col,r.row)).filter(r=>t.cells.has(r));t.farmOutputs.set(n.id,o),t.metrics.farmOutputs+=o.length}}function Le(e){let t=e.routingVersion||0;return(!e.factoryGraph||e.factoryGraph.version!==t)&&(e.factoryGraph=kl(e)),e.factoryGraph}function Zr(e){let t=Le(e);return e.factoryGraphCommittedVersion=t.version,e.factoryGraphSnapshot=gl(t),t}function gl(e){return e?{version:e.version,conveyorCells:e.metrics.conveyorCells,edges:e.metrics.edges,components:e.metrics.components,deadEnds:e.metrics.deadEnds,crosses:e.metrics.crosses,scannerPorts:`${e.metrics.connectedScannerPorts}/${e.metrics.scannerPorts}`,facilityPorts:`${e.metrics.connectedFacilityPorts}/${e.metrics.facilityPorts}`,farmOutputs:e.metrics.farmOutputs,issues:[...e.issues||[]]}:null}function Tl(e,t){let n=t.col-e.col,o=t.row-e.row;return ue.find(r=>r.dc===n&&r.dr===o)?.name||null}function Co(e,t,n){let o=Le(e),r=Ae(t.col,t.row);if(!o.cells.has(r))return[];let s=`${r}|${n.cacheKey||"dynamic"}`;if(n.cacheKey&&o.pathCache.has(s))return o.pathCache.get(s).map(I=>I.map(W=>({...W})));let l=`${r}|none`,d=[{key:r,col:t.col,row:t.row,incoming:"none",depth:0}],v=new Map([[l,0]]),C=new Map,P=[],A=1/0,L=8,V=24,ne=80;for(;d.length;){let I=d.shift();if(I.depth>A)break;let W=`${I.key}|${I.incoming}`;if(n(I)){if(P.push(W),A=I.depth,P.length>=V)break;continue}for(let N of o.adjacency.get(I.key)||[]){let le=_t(N.key),we=Tl(I,le),he=I.depth+1;if(he>A)continue;let R=`${N.key}|${we}`,G=v.get(R);if(G==null)v.set(R,he),C.set(R,[W]),d.push({key:N.key,col:le.col,row:le.row,incoming:we,depth:he});else if(G===he){let x=C.get(R)||[];x.length{if(z.length>=ne)return;let[N]=I.split("|"),le=[_t(N),...W];if(I===l||N===r){z.push(le);return}for(let we of C.get(I)||[])se(we,le)};for(let I of P)se(I,[]);let ye=[],Z=new Set;for(let I of z){let W=I.map(N=>Ae(N.col,N.row)).join(">");Z.has(W)||(Z.add(W),ye.push(I))}return n.cacheKey&&o.pathCache.set(s,ye.map(I=>I.map(W=>({...W})))),ye}function ei(e){let t=Le(e),n=new Map;for(let[o,r]of t.components.entries())n.set(o,{id:o,cells:[...r.cells],capacity:r.capacity,count:0,ratio:0});return{components:n,cellToComponent:new Map(t.cellToComponent)}}function ti(e,t,n){let o=Le(e),r=null,s=1/0;for(let l of o.cells){let d=Q(l),v=F(d.col,d.row),C=Math.hypot(v.x-t,v.y-n);CF(o.col,o.row));return t&&n.push(t),n}function at(e,t){t&&(!e.length||Er(e[e.length-1],t)>1)&&e.push(t)}function El(e,t,n,o=null){let r=[{x:e.x,y:e.y}];at(r,F(t.col,t.row));for(let s of An(n,o))at(r,s);return r}function Pl(e,t){let n=An(e),o=Ee(t,"inputA");return o&&at(n,F(o.col,o.row)),at(n,pe(t)),n}function Rl(e,t,n,o){let r=[{x:e.x,y:e.y}];at(r,F(t.col,t.row));for(let l of An(n))at(r,l);let s=Ee(o,"inputA");return s&&at(r,F(s.col,s.row)),at(r,pe(o)),r}function Al(e,t,n=0){let o=F(t.col,t.row),r=0;for(let s of e.chicks||[]){if(s.stage==="flying"||s.stage==="queued")continue;Math.hypot(s.x-o.x,s.y-o.y){let A=C.roleBias??0,L=P.roleBias??0;if(A!==L)return A-L;let V=C.cells?.length??C.route?.length??Number.POSITIVE_INFINITY,ne=P.cells?.length??P.route?.length??Number.POSITIVE_INFINITY;if(V!==ne)return V-ne;let z=C.key||JSON.stringify(C.route||C.cells||C),se=P.key||JSON.stringify(P.route||P.cells||P);return z.localeCompare(se)});if(!o||r.length===1)return r[0];let s=r[0].roleBias??0,l=r.filter(C=>(C.roleBias??0)===s),d=Math.min(...l.map(C=>Xr(e,C)));l=l.filter(C=>Xr(e,C)===d);let v=e.branchCounters.get(t)||0;return e.branchCounters.set(t,v+1),l[Math.floor(Math.random()*l.length)]}function ni(e){return e.role===0?{left:{match:"male",destination:"mixer"},right:{match:"default",destination:"scanner-role-1"}}:{left:{match:"poop",destination:"trash"},right:{match:"default",destination:"truck"}}}function Mo(e){let t=ni(e);return{left:t.left.destination,right:t.right.destination}}function go(e,t){return ni(e).left.match===t.sex?"left":"right"}function To(e){return Rr(e)}function Eo(e){return{mixer:"#2477ff",truck:"#ff6aa8",trash:"#22b94f","scanner-role-1":"#526456",scanner:"#526456",input:"#526456"}[e]||"#102015"}function Rt(e,t,n=!1){let o=Le(e),r=(o.farmOutputs.get(t.id)||[]).map(_t),s=[];for(let v of r){let C=A=>o.scannerInputs.has(Ae(A.col,A.row));C.cacheKey=`farmInput:${v.col},${v.row}:v${o.version}`;let P=Co(e,v,C);for(let A of P){let L=A[A.length-1],V=o.scannerInputs.get(Ae(L.col,L.row)),ne=Pt(e,V);ne&&s.push({key:`${ne.id}:${L.col},${L.row}:${A.length}`,scanner:ne,cells:A})}}let l=Pn(e,`farm:${t.id}`,s,n);if(l)return{scannerId:l.scanner.id,route:Pl(l.cells,l.scanner)};let d=Pn(e,`farm:${t.id}:output`,r.map(v=>({key:$(v.col,v.row),cells:[v]})),n);return d?{scannerId:null,route:An(d.cells)}:null}function oi(e,t,n,o,r=!1){let s=Pt(e,o);if(!s)return null;let d=Le(e).scannerPorts.get(s.id)?.[t],v=Ee(s,t),C=d?.connected?(d.keys||[d.key]).filter(Boolean).map(_t):[];if(!v||!C.length)return null;let P=Mo(s)[t];return P==="scanner-role-1"?Dl(e,s,t,n,v,C,r):Il(e,s,t,n,v,C,P,r)}function Dl(e,t,n,o,r,s,l){let d=Le(e),v=e.scanners.filter(A=>A.id!==t.id&&d.scannerPorts.get(A.id)?.inputA?.connected),C=[];for(let A of s)for(let L of v){let V=d.scannerPorts.get(L.id)?.inputA?.key;if(!V)continue;let ne=(d.scannerPorts.get(L.id)?.inputA?.keys||[V]).filter(Boolean),z=Z=>ne.includes(Ae(Z.col,Z.row));z.cacheKey=`toScanner:${A.col},${A.row}:${L.id}:v${d.version}`;let se=Co(e,A,z),ye=L.role===1?0:1;for(let Z of se)C.push({key:`${ye}:start${$(A.col,A.row)}:s${L.id}:${Z.length}:${$(Z[Z.length-1].col,Z[Z.length-1].row)}`,target:L,cells:Z,roleBias:ye})}let P=Pn(e,`scanner:${t.id}:${n}:toRole1`,C,l);return P?{destination:"scanner",nextScannerId:P.target.id,route:Rl(o,r,P.cells,P.target)}:null}function Il(e,t,n,o,r,s,l,d){let v=Le(e),C=[...v.facilityPorts.entries()].filter(([L,V])=>V?.connected&&Rn(e.facilities?.[L])===l);if(!C.length)return null;let P=[];for(let L of s)for(let[V,ne]of C){let z=(ne.keys||[ne.key]).filter(Boolean);if(!z.length)continue;let se=Z=>z.includes(Ae(Z.col,Z.row));se.cacheKey=`toFacility:${L.col},${L.row}:${V}:v${v.version}`;let ye=Co(e,L,se);for(let Z of ye)P.push({key:`start${$(L.col,L.row)}:${V}:${Z.length}:${$(Z[Z.length-1].col,Z[Z.length-1].row)}`,cells:Z,facilityId:V})}let A=Pn(e,`scanner:${t.id}:${n}:${l}`,P,d);return A?{destination:l,facilityId:A.facilityId,route:El(o,r,A.cells,bl(e,A.facilityId))}:null}function ri(e,t,n=new Set){if(!t||n.has(t.id))return!1;n.add(t.id);for(let o of["left","right"]){let r=oi(e,o,pe(t),t.id,!1);if(r){if(["mixer","trash","truck"].includes(r.destination))return!0;if(r.destination==="scanner"){let s=Pt(e,r.nextScannerId);if(ri(e,s,n))return!0}}}return!1}function $l(e,t){return!!Rt(e,t,!1)?.scannerId}function Dn(e){if(e.phase!=="build")return[];let t=[];for(let n of e.eggFarms||[])$l(e,n)||t.push({type:"eggFarm",id:n.id,ref:n,message:"This Egg will not produce chicks"});for(let n of nn)for(let[o,r]of ko(e,n))Le(e).facilityPorts.get(o)?.connected||t.push({type:"facility",id:o,ref:r,message:"This facility cannot receive items"});return t}function Fl(e){let t=Le(e);for(let r of e.eggFarms||[]){let s=Rt(e,r,!1);if(!s?.scannerId)continue;let l=Pt(e,s.scannerId);if(ri(e,l))return[]}let n=e.eggFarms?.length||0,o=[...t.facilityPorts.entries()].filter(([r,s])=>s?.connected&&["mixer","trash","truck"].includes(Rn(e.facilities?.[r]))).length;return n?t.metrics.farmOutputs?e.scanners?.length?o?["Connect at least one EGG through a scanner to any valid exit."]:["Connect at least one receiver exit: Mixer, Shredder, or Truck."]:["Build at least one scanner and connect it to an EGG route."]:["Connect at least one EGG to a conveyor."]:["Build at least one EGG before starting the next day."]}function En(e){return e.kind==="manual"?`S${(e.slot??0)+1}`:`Auto Scanner #${e.id}`}function Bl(e,t=Le(e),n={}){let o=n.includeRoutes!==!1,r=[],s={mixer:"Mixer",trash:"Shredder",truck:"Truck"};for(let l of nn){let d=ko(e,l);if(!d.length){r.push(`${s[l]||l} is missing`);continue}for(let[v]of d)t.facilityPorts.get(v)?.connected||r.push(`${s[l]||l} receiver has no conveyor`)}for(let l of e.scanners){let d=t.scannerPorts.get(l.id)||{};if(d.inputA?.connected||r.push(`${En(l)} input has no conveyor`),d.left?.connected||r.push(`${En(l)} left output has no conveyor`),d.right?.connected||r.push(`${En(l)} right output has no conveyor`),!!o)for(let v of["left","right"])d[v]?.connected&&!oi(e,v,pe(l),l.id)&&r.push(`${En(l)} ${v} route is incomplete`)}if(o)for(let l of e.eggFarms)Rt(e,l)?.scannerId||r.push(`Egg Farm #${l.id} has no scanner route`);else for(let l of e.eggFarms)(t.farmOutputs.get(l.id)||[]).length||r.push(`Egg Farm #${l.id} has no output conveyor`);return[...new Set(r)]}function sn(e){return Fl(e)}function ii(e){return sn(e).length===0}var si=[{key:"premiumFemaleShipment",target:"female",truckTarget:"female",title:"Premium Female Shipment",route:"Female -> Truck",note:"Today only: ship female chicks to Truck. Meet the export target for a bonus.",objective:"truckTarget"},{key:"contaminantSampleExport",target:"poop",truckTarget:"poop",title:"Contaminant Sample Export",route:"Poop value x2",note:"Today only: poop is valid Truck cargo and all poop income is doubled.",objective:"truckTarget",poopValueMultiplier:2},{key:"healthInspection",title:"Health Inspection",route:"Poop -> Shredder",note:"Today only: poop mistakes are fined double. Shred enough poop for an inspection bonus.",objective:"poopTrash",poopFineMultiplier:2},{key:"conveyorJamWarning",title:"Conveyor Jam Warning",route:"No explosions",note:"Today only: jam explosions trigger at 85% congestion. Finish with zero explosions for a bonus.",objective:"noExplosion",congestionExplosionThreshold:.85,congestionWarningThreshold:.68},{key:"powerSavingOrder",title:"Power Saving Order",route:"Slow factory subsidy",note:"Today only: conveyors -20% speed and Auto Scanners +20% cooldown. A subsidy is paid at settlement.",objective:"flatBonus",conveyorSpeedMultiplier:.8,autoScannerCooldownMultiplier:1.2},{key:"overtimeDay",title:"Overtime Day",route:"80 second day",note:"Today only: the work day is longer. No extra reward or penalty.",objective:"none",daySeconds:80},{key:"shortShift",title:"Short Shift",route:"40 second day",note:"Today only: the work day is shorter. The next Fairies tribute is reduced by 10%.",objective:"none",daySeconds:40,fairiesTributeMultiplier:.9},{key:"chickBoom",title:"Chick Boom",route:"EGG interval x0.65",note:"Today only: eggs hatch faster and poop rate rises by 5 percentage points.",objective:"none",productionMultiplier:1/.65,poopRateAdd:.05},{key:"rottenFeed",title:"Rotten Feed",route:"Poop surge",note:"Today only: poop rate rises by 20 percentage points and Shredder poop income is multiplied by 1.5.",objective:"none",poopRateAdd:.2,shredderIncomeMultiplier:1.5},{key:"maintenanceAudit",title:"Maintenance Audit",route:"Durability check",note:"Today only: machines below 50% remaining durability fail the audit. Passing with none below 50% pays a bonus.",objective:"maintenanceAudit"}];function ve(e,t=0){let n=Number(e);return Number.isFinite(n)?n:t}function Ll(e,t=0,n=1){let o=Math.max(1,Number(e?.turn||1)+1),r=Math.floor(Po(e)*(.08+Math.random()*.08)),s=Math.floor(Math.max(0,e.cash||0)*.25),l=Math.floor(Math.max(0,t)*Math.max(1,o)*.75);return Math.max(120,Math.ceil(Math.max(r,s,l)*n))}function li(e){return Math.max(0,Math.ceil(500+Math.max(1,e?.turn||1)*25))}function Po(e){return[...e.eggFarms.map(t=>t.price||0),...e.scanners.map(t=>t.price||0),...Object.values(e.facilities).map(t=>t.price||0),...[...e.conveyorMeta.values()].map(t=>t.price||0)].reduce((t,n)=>t+n,0)}function Ol(e,t=1,n=vt){return e.eggFarms.reduce((o,r)=>{let[s,l]=rn(r),d=Math.max(.1,(s+l)/2);return o+Math.max(1,n)/d*Math.max(.01,t||1)},0)}function Nl(e,t){let n=ve(t.productionMultiplier,1),o=ve(t.daySeconds,vt),r=Ol(e,n,o),s=Math.max(0,Number(e?.cardEffects?.hatchingFeed)||0),l=Math.max(0,Number(e?.cardEffects?.poopRateBooster)||0),d=Math.pow(1.03,s),v=ao+co*l,C=Math.min(.95,Math.max(0,(v+ve(t.poopRateAdd,0))*ve(t.poopMultiplier,1)*d));return{estimate:r,poopRate:C}}function ai(e){if(e.turn+1Cr)return null;let n=si[Math.floor(Math.random()*si.length)],{estimate:o,poopRate:r}=Nl(e,n),s=0;n.objective==="truckTarget"?s=Math.max(1,Math.ceil(o*.3)):n.objective==="poopTrash"&&(s=Math.max(1,Math.ceil(o*r*.8)));let l=0;return["truckTarget","poopTrash","noExplosion"].includes(n.objective)&&(l=Ll(e,o)),n.objective==="flatBonus"&&(l=li(e)),n.objective==="maintenanceAudit"&&(l=li(e)),{id:`event-${e.turn}-${Date.now()}-${Math.floor(Math.random()*9999)}`,...n,target:n.target||null,truckTarget:n.truckTarget||null,forced:!0,productionMultiplier:ve(n.productionMultiplier,1),poopMultiplier:ve(n.poopMultiplier,1),poopRateAdd:ve(n.poopRateAdd,0),daySeconds:ve(n.daySeconds,vt),targetAmount:s,estimatedOutput:Math.round(o),reward:l,createdTurn:e.turn,oneTurnOnly:!0}}function ci(e){e.eventActive=e.eventOffer?{...e.eventOffer}:null,e.eventOffer=null}function ui(e){e.eventActive=null}function di(e){return Math.max(1,ve(e.eventActive?.daySeconds,vt))}function fi(e){return ve(e.eventActive?.productionMultiplier,1)}function pi(e){let t=Math.max(0,Number(e?.cardEffects?.hatchingFeed)||0),n=Math.max(0,Number(e?.cardEffects?.poopRateBooster)||0),o=Math.pow(1.03,t),r=ao+co*n,s=ve(e.eventActive?.poopRateAdd,0);return Math.min(.95,Math.max(0,(r+s)*ve(e.eventActive?.poopMultiplier,1)*o))}function Je(e){return e.eventActive?.truckTarget||e.eventActive?.target||"female"}function Ro(e,t){return t==="male"?e.truckMale||0:t==="poop"?e.poopTruck||0:e.truckFemale||0}function yi(e,t){return Je(e)===t}function hi(e){return Je(e)!=="male"}function Ao(e){return Math.max(.01,ve(e.eventActive?.poopValueMultiplier,1))}function In(e){return Math.max(.01,Ao(e)*ve(e.eventActive?.shredderIncomeMultiplier,1))}function Do(e){return Math.max(.01,ve(e.eventActive?.poopFineMultiplier,1))}function Io(e){return Math.max(.1,Math.min(1,ve(e.eventActive?.congestionExplosionThreshold,1)))}function mi(e){return Math.max(.1,Math.min(1,ve(e.eventActive?.congestionWarningThreshold,.8)))}function bi(e){return Math.max(.01,ve(e?.fairiesTributeMultiplier,1))}function Gl(e){let t=0,n=(o,r)=>{let s=Math.max(1,ve(r,1)),l=Math.max(0,ve(o,0));1-Math.min(1,l/s)<.5&&(t+=1)};for(let o of e.conveyorMeta?.values?.()||[])n(o.uses,o.durability);for(let o of e.eggFarms||[])n(o.maintenance?.uses,o.maintenance?.durability);for(let o of e.scanners||[])o.kind==="auto"&&n(o.maintenance?.uses,o.maintenance?.durability);for(let o of Object.values(e.facilities||{})){let r=o?.baseId||o?.id;(r==="mixer"||r==="trash")&&n(o.maintenance?.uses,o.maintenance?.durability)}return t}function vi(e){let t=e.eventActive;if(!t)return null;let n=0,o=!0,r=0,s="";t.objective==="truckTarget"?(n=Ro(e.stats,t.target),o=n>=t.targetAmount,r=o?t.reward:0):t.objective==="poopTrash"?(n=e.stats.poopTrash||0,o=n>=t.targetAmount,r=o?t.reward:0):t.objective==="noExplosion"?(n=e.stats.explosions||0,o=n===0,r=o?t.reward:0,s=`${n} explosion(s)`):t.objective==="flatBonus"?(o=!0,r=t.reward):t.objective==="maintenanceAudit"?(n=Gl(e),o=n===0,o&&(r=t.reward),s=`${n} machine(s) below 50%`):o=!0,r>0?(Oe(e,r),e.stats.eventBonus=(e.stats.eventBonus||0)+r,e.totals.eventBonus+=r,e.totals.eventSuccess+=1):t.objective&&t.objective!=="none"&&(e.stats.eventBonus=e.stats.eventBonus||0,e.totals.eventFailed+=o?0:1,o&&(e.totals.eventSuccess+=1));let l={title:t.title,key:t.key,target:t.target,route:t.route,objective:t.objective,targetAmount:t.targetAmount||0,count:n,success:o,bonus:r,reward:t.reward||0,productionMultiplier:t.productionMultiplier,poopMultiplier:t.poopMultiplier,daySeconds:t.daySeconds,detail:s};return e.stats.eventResult=l,l}function $o(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function Ul(e){return!!e?.cardEffects?.usedMachineActive}function Wl(e,t){return t?1:Math.min(.8,.5+.1*Math.min(3,$o(e,"recyclingSubsidy")))}function _l(e){return Math.pow(.95,$o(e,"safetyCover"))}function $n(e){let t=e?.ref||e||{},n=e?.type||t.type;return n==="conveyor"?t.price||Se[t.kind]?.price||Se.conveyor.price:n==="eggFarm"?t.price||Se.eggFarm.price:n==="scanner"?t.price||(t.kind==="auto"?Se.autoScanner.price:Se.manualScanner.price):n==="facility"?t.price||Se[t.id]?.price||0:Se[t.id]?.price||0}function Ne(e,t=null){let n=Se[e]?.price||0;return Ul(t)?Math.ceil(n*.5):n}function Kl(e,t){return e?.facilities?Object.values(e.facilities).filter(n=>(n?.baseId||n?.id)===t).reduce((n,o)=>n+Math.max(0,(o.level||1)-1),0):0}function ct(e,t){return gr.includes(t)?Math.pow(xe.incomeUpgradeRate,Kl(e,t)):1}function qe(e){return Math.ceil(xe.income.mixer*ct(e,"mixer"))}function De(e){return Math.ceil(xe.income.truck*ct(e,"truck"))}function ln(e){return Math.ceil(xe.poopFine*ct(e,"mixer")*Do(e))}function an(e){return Math.ceil(xe.poopFine*ct(e,"truck")*Do(e))}function Fo(e){let t=xe.maleTruckFinePerHalfDay*(e.turn/2);return Math.ceil(t*ct(e,"truck"))}function Bo(e){return e?.facilities?Object.values(e.facilities).filter(t=>(t?.baseId||t?.id)==="trash").reduce((t,n)=>t+Math.max(0,(n.level||1)-1),0):0}function At(e){return Math.min(xe.shredderBonus.maxCards,Bo(e))}function Kt(){return xe.shredderBonus.maxCards}function ut(e){let t=typeof e=="number"?e:At(e),n=Math.min(xe.shredderBonus.maxCards,Math.max(0,t));return n>0?Math.ceil(n*(xe.shredderBonus.incomePerUpgrade||1)):0}function Hl(e){let t=At(e),n=ut(t),o=Math.ceil(n*In(e));return{cards:t,chance:o>0?1:0,amount:o,expected:o,baseAmount:n}}function wi(e){let t=Hl(e);return t.amount>0&&(e.stats.shredderBonus=(e.stats.shredderBonus||0)+t.amount,e.totals.shredderBonus=(e.totals.shredderBonus||0)+t.amount,Oe(e,t.amount)),t}function Fn(e,t=e.turn,n=null){let o=Math.max(1,Math.floor(Number(t)||1)),r=xe.fairiesTribute||{perDay:10,profitExemption:300,legalWorkExemptionBonus:250,profitRate:.12},s=Math.ceil(o*(r.perDay||10)),l=Math.max(0,Math.floor(Number(n??e?.lastResult?.profit??e?.stats?.profit??0)||0)),d=Math.max(0,e?.cardEffects?.legalWork||0),v=Math.max(0,(r.profitExemption||0)+d*(r.legalWorkExemptionBonus||0)),C=Math.max(0,l-v),P=Math.ceil(C*Math.max(0,Number(r.profitRate)||0)),A=s+P,L=Math.max(0,e?.cardEffects?.fairiesFlatteryNext||e?.cardEffects?.flattery||0),V=L>0?Math.pow(.5,L):1,ne=Math.max(.01,Number(e?.pendingFairiesTributeMultiplier)||1),z=V*ne,se=Math.max(0,Math.ceil(A*z)),ye=Math.max(0,A-se);return{day:o,base:s,profit:l,legalWork:d,profitExemption:v,taxableProfit:C,profitTribute:P,gross:A,flatteryCount:L,eventMultiplier:ne,perCardReduction:Math.ceil(A*.5),reduction:ye,amount:se}}function Dt(e,t){let n=e?.ref||e||{},o=e?.type==="conveyor"?t?.conveyorMeta?.get(e.oldKey||n.id):n,r=o?.price||$n(e||n),s=o?.builtSession===t?.buildSession;if(o?.noRefund||n?.noRefund)return{amount:0,sameBuild:s,price:r,rate:0,noRefund:!0};let l=Wl(t,s);return{amount:Math.max(0,Math.ceil(r*l)),sameBuild:s,price:r,rate:l,noRefund:!1}}function ql(e,t=null){let n=Math.max(1,Math.ceil((Number(e)||0)/xe.explosionDamageDivisor));return Math.max(1,Math.ceil(n*_l(t)))}function Yl(e,t){return Math.max(0,Math.ceil(t))}function Si(e,t){e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,t>=0?(e.stats.revenue+=t,e.totals.revenue+=t):(e.stats.penalty+=Math.abs(t),e.totals.penalty+=Math.abs(t)),e.totals.maxCash=Math.max(e.totals.maxCash,e.cash)}function Oe(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&Si(e,n),n}function dt(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&Si(e,-n),n}function ft(e,t){dt(e,t)}function xi(e,t){t<=0||(e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,e.totals.maxCash=Math.max(e.totals.maxCash,e.cash))}function ki(e){let t=qe(e);return e.stats.mixerRevenue+=t,Oe(e,t),t}function Ci(e){let t=ln(e);return e.stats.mixerPoopFine+=t,e.totals.mixerPoopFine+=t,dt(e,t),t}function Mi(e){let t=an(e);return e.stats.truckPoopFine+=t,e.totals.truckPoopFine+=t,dt(e,t),t}function gi(e){let t=Fo(e);return e.stats.maleTruckFine+=t,e.totals.maleTruckFine+=t,dt(e,t),t}function Ti(e,t){let n=ql(t,e);return e.stats.explosionDamage+=n,e.totals.explosionDamage+=n,dt(e,n),n}function Ei(e){let t=Je(e),n=Ro(e.stats,t),o=t==="poop"?Math.ceil(De(e)*Ao(e)):De(e),r=n*o,s=Yl(e,r);return e.stats.pendingTruckRevenue=s,e.stats.truckRevenue=s,t==="poop"?e.stats.poopShipmentIncome=s:e.stats.chickShipmentIncome=s,s>0&&Oe(e,s),{base:r,adjusted:s,target:t,targetCount:n,unitPrice:o}}function Pi(e,t=e.turn,n=null,o={}){let r=Fn(e,t,n);return e.cardEffects&&(e.cardEffects.fairiesFlatteryNext=0,e.cardEffects.flattery!=null&&delete e.cardEffects.flattery),e.pendingFairiesTributeMultiplier!=null&&(e.pendingFairiesTributeMultiplier=1),r.amount<=0||(o.recordStats?(e.stats.fairiesTribute=(e.stats.fairiesTribute||0)+r.amount,e.totals.fairiesTribute=(e.totals.fairiesTribute||0)+r.amount,dt(e,r.amount)):(e.totals.fairiesTribute=(e.totals.fairiesTribute||0)+r.amount,e.totals.penalty=(e.totals.penalty||0)+r.amount,e.totals.profit=(e.totals.profit||0)-r.amount,e.cash-=r.amount)),r}function Ri(e){let t=$o(e,"chemicalWeaponSubsidy"),n=Math.max(0,e?.stats?.poopTruck||0),o=xe.chemicalWeaponSubsidy||{poopPerBlock:70,yenPerBlock:1200},r=Math.floor(n/Math.max(1,o.poopPerBlock||70)),s=t>0&&r>0?r*Math.max(0,o.yenPerBlock||1200)*t:0;return s>0&&(e.stats.chemicalWeaponSubsidy=(e.stats.chemicalWeaponSubsidy||0)+s,e.totals.chemicalWeaponSubsidy=(e.totals.chemicalWeaponSubsidy||0)+s,Oe(e,s)),{cards:t,poopTruck:n,blocks:r,amount:s}}function Ai(e){let t=Po(e),n=Math.max(1,e.totals.turnsCompleted||e.turn||1),o=Math.max(0,e.cash+e.totals.revenue+t*.5+e.totals.eventBonus*.5),r=Math.ceil(o/n),s=Math.floor(n*35+Math.max(0,n-5)*15),l=e.totals.correct*5,d=e.totals.explosionDamage;return{score:Math.max(0,Math.floor(o+r+l-e.totals.penalty-s)),factoryValue:t,base:o,dailyEarned:r,dayPenalty:s,correctBonus:l,explosionPenalty:d,days:n}}function Vl(e){return{...e,keys:e.keys?{left:{...e.keys.left},right:{...e.keys.right}}:null,queue:[],cooldown:e.cooldown||0}}function cn(e){return JSON.stringify({cash:e.cash,stats:e.stats,totals:e.totals,nextId:e.nextId,gridX:y.x,gridY:y.y,gridCols:e.gridCols||y.cols,gridRows:e.gridRows||y.rows,gridExpansionPurchases:e.gridExpansionPurchases||0,gridExpansionPurchasesByDirection:e.gridExpansionPurchasesByDirection||{right:0,up:0},gridChunkOriginY:e.gridChunkOriginY||0,ownedCells:[...e.ownedCells||[]],ownedChunks:[...e.ownedChunks||[]],blockedCells:[...e.blockedCells||[]],selected:e.selected,multiSelected:e.multiSelected||[],buildTool:e.buildTool,view:e.view,facilities:e.facilities,eggFarms:e.eggFarms,scanners:e.scanners.map(Vl),conveyorTiles:[...e.conveyorTiles],conveyorMeta:[...e.conveyorMeta.entries()],branchCounters:[...e.branchCounters.entries()],cardEffects:e.cardEffects,cardDraft:e.cardDraft,cardTargetPick:e.cardTargetPick})}function Di(e,t){let n=JSON.parse(t);e.cash=n.cash,e.stats=n.stats,e.totals=n.totals,e.nextId=n.nextId,y.x=n.gridX??q.grid.x,y.y=n.gridY??q.grid.y,y.cols=n.gridCols||q.grid.cols,y.rows=n.gridRows||q.grid.rows,e.gridCols=y.cols,e.gridRows=y.rows,e.gridExpansionPurchases=n.gridExpansionPurchases||0,e.gridExpansionPurchasesByDirection=n.gridExpansionPurchasesByDirection||{right:0,up:0},e.gridChunkOriginY=n.gridChunkOriginY||0,e.ownedCells=new Set(n.ownedCells||[]),e.ownedChunks=new Set(n.ownedChunks||[]),e.gridOwnedCells=e.ownedCells.size||y.cols*y.rows,e.blockedCells=new Set(n.blockedCells||[]),e.selected=n.selected,e.multiSelected=n.multiSelected||[],e.buildTool=n.buildTool,e.view=n.view||{x:0,y:0,scale:1},e.view.scale==null&&(e.view.scale=1),e.facilities=n.facilities||{},e.eggFarms=n.eggFarms||[],e.scanners=(n.scanners||[]).map(o=>({...o,queue:[],cooldown:o.cooldown||0})),e.conveyorTiles=new Set(n.conveyorTiles||[]),e.conveyorMeta=new Map(n.conveyorMeta||[]),e.branchCounters=new Map(n.branchCounters||[]),e.cardEffects=n.cardEffects||{bearing:0,legalWork:0,fairiesFlatteryNext:0,scannerQueueSpacing:0},e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft=n.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardTargetPick=n.cardTargetPick||null,e.groupDrag=null,e.selectionBox=null,e.pan=null,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function $e(e){e.phase==="build"&&(e.undoStack.push(cn(e)),e.undoStack.length>80&&e.undoStack.shift(),e.redoStack=[])}function Lo(e){return e.phase!=="build"||!e.undoStack.length?!1:(e.redoStack.push(cn(e)),Di(e,e.undoStack.pop()),!0)}function Oo(e){return e.phase!=="build"||!e.redoStack.length?!1:(e.undoStack.push(cn(e)),Di(e,e.redoStack.pop()),!0)}function _(e,t,n,o,r=f.ink){e.floatingTexts.push({x:t,y:n,text:o,color:r,life:1,maxLife:1})}function It(e,t,n){e.shake.strength=Math.max(e.shake.strength,t),e.shake.time=Math.max(e.shake.time,n)}function Ii(e,t,n){e.effects.push({type:"spawn",priority:ke.ambient,x:t,y:n,life:.42,maxLife:.42,size:12})}function $i(e,t,n,o=f.green){e.effects.push({type:"scannerPulse",priority:ke.important,x:t,y:n,color:o,life:.42,maxLife:.42,size:24})}function Fi(e,t,n){for(let o=0;o<12;o+=1)e.effects.push({type:"meat",priority:ke.important,x:t+U(-18,18),y:n+U(-12,16),vx:U(-60,60),vy:U(-90,-25),life:U(.45,.85),maxLife:.85,size:U(4,8)})}function Bi(e,t,n){for(let o=0;o<16;o+=1)e.effects.push({type:"sludge",priority:ke.important,x:t+U(-18,18),y:n+U(-12,16),vx:U(-46,46),vy:U(-70,-20),life:U(.45,.9),maxLife:.9,size:U(4,8)})}function Li(e,t,n,o){let r=o==="poop"?f.poop:o==="male"?f.male:f.female;for(let s=0;s<22;s+=1)e.effects.push({type:"shred",priority:ke.important,x:t+U(-16,16),y:n+U(-8,8),vx:U(-70,70),vy:U(40,160),color:s%3===0?f.white:r,life:U(.45,.95),maxLife:.95,w:U(3,7),h:U(10,24),rot:U(-Math.PI,Math.PI)});Ye(e,t,n,f.green,34,ke.important)}function Oi(e,t,n,o){let r=o==="poop"?f.poop:o==="male"?f.danger:f.green;for(let s=0;s<8;s+=1)e.effects.push({type:"load",priority:ke.important,x:t+U(-18,18),y:n+U(-18,18),vx:U(-42,42),vy:U(-90,-25),color:r,life:U(.35,.65),maxLife:.65,size:8})}function Ye(e,t,n,o=f.danger,r=52,s=ke.critical){e.effects.push({type:"shockwave",priority:s,x:t,y:n,color:o,life:.55,maxLife:.55,size:8,maxSize:r})}function je(e,t,n,o=12,r=f.danger,s=ke.critical){for(let l=0;l0&&(e.shake.time=Math.max(0,e.shake.time-t),e.shake.time<=0&&(e.shake.strength=0));for(let r of e.effects)if(r.life-=t,["meat","sludge","spark","smoke","shred","load","rage"].includes(r.type))r.x+=(r.vx||0)*t,r.y+=(r.vy||0)*t,r.vy=(r.vy||0)+150*t;else if(r.type==="flyingChick"){r.x+=r.vx*t,r.y+=r.vy*t,r.vy+=360*t,r.noDamage||zl(e,r,o);let s=r.x+e.view.x,l=r.y+e.view.y;(s<-100||l<-100||s>n.width+100||l>n.height+100)&&(r.life=0)}e.effects=e.effects.filter(r=>r.life>0);for(let r of e.floatingTexts)r.life-=t,r.y-=34*t;e.floatingTexts=e.floatingTexts.filter(r=>r.life>0)}function zl(e,t,n){t.hit||(t.hit=new Set);for(let o of n()){if(t.hit.has(o.id)||t.xo.x+o.w||t.yo.y+o.h)continue;t.hit.add(o.id);let r=Ti(e,o.price);_(e,t.x,t.y-10,`-${M(r)}`,f.danger),Ye(e,t.x,t.y,f.danger,30),je(e,t.x,t.y,5,f.danger),It(e,5,.18)}}var Fe=q.maintenance;function Go(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function Nn(e){let t=Math.min(1.4,1+.04*Math.min(10,Go(e,"crowdedFarming"))),n=Math.pow(.95,Go(e,"preventiveMaintenance"));return t*n}function Xl(e){return Math.pow(1.03,Go(e,"durabilityCoating"))}function Gn(e,t,n=1){let o=Fe.durability[t]||1e3;return Math.max(1,Math.ceil(o*Math.max(.1,n||1)*Xl(e)))}function _o(e){let t=Fe.repairman.dailyCost;return e?.cardEffects?.laborExploitation?Math.ceil(t*.7):t}function Ui(e){return Math.max(.1,Number(e?.durabilityBaseMultiplier)||1)}function me(e){e.repairman||(e.repairman={hiredForNextDay:!1,active:!1,x:y.x+y.cell*.5,y:y.y+y.rows*y.cell+84,target:null,repairedToday:0});for(let[t,n]of e.conveyorMeta||[]){n.uses==null&&(n.uses=0),n.maintenanceType==null&&(n.maintenanceType="conveyor"),n.kind||(n.kind="conveyor"),n.speedMultiplier||(n.speedMultiplier=n.kind==="boostConveyor"?2:1),n.branchMode||(n.branchMode="random");let o=Gn(e,"conveyor",Ui(n));(n.durability==null||n.durability0&&(n.processingCooldown=Math.max(0,n.processingCooldown-t))}function Hn(e){me(e);let t=[];for(let[n,o]of e.conveyorMeta||[])t.push({type:"conveyor",key:n,meta:o,label:`${o.kind==="boostConveyor"?"Boost Belt":"Belt"} ${n}`,center:F(Q(n).col,Q(n).row)});for(let n of e.eggFarms||[])t.push({type:"eggFarm",ref:n,label:`EGG #${n.id}`,center:F(n.col,n.row)});for(let n of(e.scanners||[]).filter(o=>o.kind==="auto"))t.push({type:"autoScanner",ref:n,label:`AUTO #${n.id}`,center:F(n.col,n.row)});for(let n of Object.values(e.facilities||{})){let o=Kn(n);["mixer","trash"].includes(o)&&t.push({type:o,ref:n,label:`${n.shortName||n.name||o} #${n.id}`,center:{x:n.x+n.w/2,y:n.y+n.h/2}})}return t}function Ln(e){return e.meta?Ht(e):Ht(e.ref)}function un(e){return e.meta?Uo(e):Uo(e.ref)}function On(e){return e.meta?Wo(e):Wo(e.ref)}function qi(e,t){Ql(e.meta?e:e.ref,Math.max(0,un(e)-t))}function Yi(e){return e.type==="conveyor"?`conveyor:${e.key}`:`${e.type}:${e.ref?.id||e.ref?.type||e.type}`}function Vi(e,t=.02){me(e);let n=Math.max(0,Number(t)||0),o=0;for(let r of Hn(e)){let s=un(r);qi(r,On(r)*n),o+=Math.max(0,s-un(r))/On(r)*100}return o}function zi(e){if(me(e),e.repairman.hiredForNextDay)return{ok:!1,reason:"Repairman already hired."};let t=_o(e);return e.cashYi(o)===t.key)||null}function Zl(e){let t=null;for(let n of Hn(e)){let o=Ln(n);o<=.001||(!t||o>Ln(t))&&(t=n)}return t}function Ji(e,t){me(e);let n=e.repairman;if(!n.active||e.phase!=="running")return;let o=jl(e,n.target)||Zl(e);if(!o){n.target=null;return}n.target={key:Yi(o),label:o.label};let r=Fe.repairman.walkSpeed,s=o.center.x-n.x,l=o.center.y-n.y,d=Math.hypot(s,l);if(d>8){let L=Math.min(d,r*t);n.x+=s/d*L,n.y+=l/d*L;return}let v=t/(Fe.repairman.secondsPerOnePercent*100),C=un(o),P=v*On(o);qi(o,P);let A=Math.max(0,(C-un(o))/On(o)*100);n.repairedToday=(n.repairedToday||0)+A,A>0&&Math.random()<.02&&_(e,n.x,n.y-28,"REPAIR",f.green),Ln(o)<=.001&&(n.target=null)}function ea(e){let t=0,n="none";for(let o of Hn(e)){let r=Ln(o);r>t&&(t=r,n=o.label)}return{ratio:t,percent:Math.round(t*100),label:n}}function Qo(e){let t=ea(e),n=Ho(e);return{worst:t,avgBeltPerformance:n,repairman:e.repairman||null}}var ta=Re.commonWeight,na=Re.rareWeight,oa=Re.ultraRareWeight||.45,$t=Re.baseDraftSize,Yt=Mr;function qt(e,t){let n=Ie(e);return Math.max(0,Number(n[t])||0)}function Ie(e){e.cardEffects||(e.cardEffects={...uo});for(let[t,n]of Object.entries(uo))e.cardEffects[t]==null&&(e.cardEffects[t]=Array.isArray(n)?[]:n);return e.cardEffects.flattery!=null&&(e.cardEffects.fairiesFlatteryNext=Math.max(0,e.cardEffects.fairiesFlatteryNext||0)+Math.max(0,e.cardEffects.flattery||0),delete e.cardEffects.flattery),e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft||(e.cardDraft={pending:!1,choices:[],rerolls:0,picksRemaining:0}),e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardEffects}function is(e){let t=Math.max(.5,1-.05*Math.min(10,qt(e,"crowdedFarming"))),n=Math.pow(.96,qt(e,"hatchingFeed"));return t*n}function ss(e,t=null){return Math.min(3,Math.max(0,Number(t?.extraEggOutlet)||0))}function ls(e){return Math.pow(.85,qt(e,"scannerQueueSpacing"))}function Yn(e,t=null){let n=Ie(e),o=xn*Math.pow(kn,Math.max(0,n.bearing||0)),r=t?Math.max(.1,Number(e?.conveyorMeta?.get?.(t)?.speedMultiplier)||1):1,s=t?1:Ho(e),l=Math.max(.01,Number(e?.eventActive?.conveyorSpeedMultiplier)||1);return Math.min(Gt,o*s)*r*l}function et(e,t=null){let n=Math.max(0,(e?.level||1)-1),o=t?qt(t,"autoScannerTuning"):0,r=Sn*Math.pow(kr,n)*Math.pow(so,o),s=Math.max(lo,r),l=t?Math.max(.01,Number(t?.eventActive?.autoScannerCooldownMultiplier)||1):1;return t?Math.max(lo,s*Wn(e)*l):s}function ji(e){let t=e.cardDraft||{rerolls:0},n=Math.max(1,(t.rerolls||0)+1);return Math.ceil(Math.max(1,e.turn||1)/Re.rerollCost.dayDivisor*n*Re.rerollCost.multiplier)}function Vt(e){return Yt.find(t=>t.id===e)||null}function as(e,t){let n=typeof t=="string"?Vt(t):t;return Ie(e),!n||!(n.type==="equipmentUpgrade"||n.type==="cellAction")?[]:Ue(e,n).map(o=>({key:Ze(o),label:Zo(e,o),type:o.type}))}function jo(e,t,n={}){let o=typeof t=="string"?Vt(t):t;if(Ie(e),!o||o.type==="dud")return{ok:!1,reason:"Card not found."};if(o.id==="extraCards")return e.cardDraft=e.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.choices.push(...qn(e,2)),{ok:!0,reason:`${o.title} added 2 draft cards.`};if(o.type==="instant")return us(e,o),{ok:!0,reason:`${o.title} granted.`};if(o.type==="equipmentUpgrade"){let r=Ue(e,o);if(!r.length)return{ok:!1,reason:`No valid target for ${o.title}.`};let s=n.targetKey&&n.targetKey!=="__auto__"?String(n.targetKey):"",l=s?r.find(d=>Ze(d)===s):r[0];return l?(cs(e,l),{ok:!0,reason:`${o.title} applied to ${Zo(e,l)}.`}):{ok:!1,reason:`Selected target is no longer valid for ${o.title}.`}}if(o.type==="cellAction"&&o.target==="blockedCell"){let r=Ue(e,o);if(!r.length)return{ok:!1,reason:"No blocked cells to remove."};let s=new Set((Array.isArray(n.targetKeys)?n.targetKeys:[n.targetKey]).filter(d=>d&&d!=="__auto__").map(String)),l=s.size?r.filter(d=>s.has(Ze(d))):r.slice(0,3);if(!l.length)return{ok:!1,reason:`Selected target is no longer valid for ${o.title}.`};for(let d of l.slice(0,3)){e.blockedCells.delete($(d.col,d.row));let v=F(d.col,d.row);pt(e,v.x,v.y),Ye(e,v.x,v.y,f.danger,42),je(e,v.x,v.y,8,f.warn)}return be(e),{ok:!0,reason:`${o.title} removed ${Math.min(3,l.length)} blocked cell(s).`}}return{ok:!1,reason:`${o.title} cannot be debug-granted.`}}function Zo(e,t){if(t.type==="blockedCell")return`Blocked cell ${t.col},${t.row}`;if(t.type==="eggFarm")return`EGG #${t.id} L${t.level} -> L${t.level+1}`;if(t.type==="eggOutlet"){let n=Math.max(0,Number(t.farm?.extraEggOutlet)||0);return`EGG #${t.id} OUTLET ${1+n} -> ${2+n}`}if(t.type==="scanner")return`AUTO #${t.id} L${t.level} -> L${t.level+1} | CD ${et(t,e).toFixed(1)}s -> ${et({...t,level:t.level+1},e).toFixed(1)}s`;if(t.type==="facility"&&(t.baseId||t.id)==="mixer"){let n=t.level,o=qe(e);t.level=n+1;let r=qe(e);return t.level=n,`MIXER L${t.level} -> L${t.level+1} | ${M(o)} -> ${M(r)}`}if(t.type==="facility"&&(t.baseId||t.id)==="truck"){let n=t.level,o=De(e);t.level=n+1;let r=De(e);return t.level=n,`TRUCK L${t.level} -> L${t.level+1} | ${M(o)} -> ${M(r)}`}if(t.type==="facility"&&t.id==="trash"){let n=At(e),o=Math.min(Kt(),n+1),r=ut(n),s=ut(o);return`SHREDDER L${t.level||1} -> L${(t.level||1)+1} | poop income ${M(r)} -> ${M(s)} per item`}return`${t.name||t.id} L${t.level||1} -> L${(t.level||1)+1}`}function ra(e){return[...e.blockedCells||[]].map(t=>{let[n,o]=String(t).split(",").map(Number);return{type:"blockedCell",id:t,col:n,row:o}}).filter(t=>Number.isFinite(t.col)&&Number.isFinite(t.row))}function Ue(e,t){let n=typeof t=="string"?Vt(t):t;return Ie(e),n?n.target==="blockedCell"?ra(e):n.target==="eggFarm"?e.eggFarms.filter(o=>(o.level||1)<4):n.target==="eggOutlet"?e.eggFarms.filter(o=>Math.max(0,Number(o.extraEggOutlet)||0)<3).map(o=>({type:"eggOutlet",id:o.id,col:o.col,row:o.row,farm:o})):n.target==="autoScanner"?e.scanners.filter(o=>o.kind==="auto"):n.target==="mixer"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="mixer"):n.target==="truck"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="truck"):n.target==="trash"?Bo(e)(o.baseId||o.id)==="trash"):[]:[]:[]}function ia(e,t){let n=Ie(e);if(t.id==="crowdedFarming")return(n.crowdedFarming||0)>=10;if(t.id==="recyclingSubsidy")return(n.recyclingSubsidy||0)>=3;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,Re.dudChancePerCard||0)),r=Math.max(1e-4,Math.min(1,Re.dudChanceReductionPerFilter||.05));return(n.dudFilter||0)>=Math.ceil(o/r)}return t.id==="laborExploitation"?!!n.laborExploitation:t.id==="usedMachine"?!!n.usedMachineActive:t.id==="newMachine"?!n.usedMachineActive:!1}function sa(e){let t=e.repairman||{};return!!(t.active||t.hiredForNextDay||e.pendingRepairWorkerWages>0)}function la(e){return Yt.filter(t=>!(t.id==="laborExploitation"&&!sa(e)||ia(e,t)||(t.type==="equipmentUpgrade"||t.type==="cellAction")&&Ue(e,t).length<=0))}function Zi(e,t){return t.rarity==="ultraRare"?oa:t.rarity==="rare"?na:ta}function aa(e,t){let n=t.reduce((r,s)=>r+Zi(e,s),0);if(n<=0)return t[Math.floor(Math.random()*t.length)];let o=Math.random()*n;for(let r of t)if(o-=Zi(e,r),o<=0)return r;return t[t.length-1]}var es=0;function ca(){return es+=1,{id:`dud:${Date.now()}:${es}`,title:"Dud",rarity:"dud",type:"dud",description:"Click to flick this dud away. It does not consume a pick."}}function ua(e){let t=Ie(e),n=Math.max(0,Math.min(1,Re.dudChancePerCard||0)),o=Math.max(0,Math.min(1,Re.dudChanceReductionPerFilter||0));return Math.max(0,n-o*Math.max(0,t.dudFilter||0))}function da(e,t){let n=[...t],o=0,r=Math.max(0,Re.maxDudsPerDraft||0),s=ua(e);for(let l=0;ld.id===s.id);l>=0&&r.splice(l,1)}return da(e,o)}function Ze(e){return e?e.type==="blockedCell"?`blockedCell:${e.id}`:e.type==="eggFarm"?`eggFarm:${e.id}`:e.type==="eggOutlet"?`eggOutlet:${e.id}`:e.type==="scanner"?`scanner:${e.id}`:e.type==="facility"?`facility:${e.id}`:`${e.type}:${e.id}`:""}function ts(e){if(!e)return null;if(e.type==="blockedCell"){let t=F(e.col,e.row);return{x:t.x-y.cell*.48,y:t.y-y.cell*.48,w:y.cell*.96,h:y.cell*.96,cx:t.x,cy:t.y}}if(e.type==="eggFarm"||e.type==="eggOutlet"){let t=F(e.col,e.row);return{x:t.x-34,y:t.y-34,w:68,h:68,cx:t.x,cy:t.y}}if(e.type==="scanner"){let t=pe(e);return{x:t.x-54,y:t.y-77,w:108,h:154,cx:t.x,cy:t.y}}return e.type==="facility"?{x:e.x,y:e.y,w:e.w,h:e.h,cx:e.x+e.w/2,cy:e.y+e.h/2}:null}function er(e){if(!e.cardTargetPick?.pending)return[];if(e.cardTargetPick.mode==="autoScannerMenu"){let n=new Set(e.cardTargetPick.targetKeys||[]);return e.scanners.filter(o=>o.kind==="auto"&&n.has(Ze(o))).map(o=>({key:Ze(o),label:"AUTO ROUTE SETTINGS",target:o,bounds:ts(o)})).filter(o=>o.bounds)}let t=new Set(e.cardTargetPick.targetKeys||[]);return Ue(e,e.cardTargetPick.cardId).filter(n=>t.has(Ze(n))).map(n=>({key:Ze(n),label:Zo(e,n),target:n,bounds:ts(n)})).filter(n=>n.bounds)}function fa(e,t){let n=er(e);for(let o of n){let r=o.bounds;if(t.x>=r.x&&t.x<=r.x+r.w&&t.y>=r.y&&t.y<=r.y+r.h)return o.target}return null}function cs(e,t){if(t.type==="eggOutlet"){let n=t.farm||e.eggFarms.find(r=>r.id===t.id);if(!n)return;n.extraEggOutlet=Math.min(3,Math.max(0,Number(n.extraEggOutlet)||0)+1);let o=F(n.col,n.row);_(e,o.x,o.y-30,`OUTLET ${1+n.extraEggOutlet}`,f.green),be(e);return}if(t.level=(t.level||1)+1,t.type==="eggFarm"){t.nextSpawn=Mt(t),t.lastInterval=t.nextSpawn;let n=F(t.col,t.row);_(e,n.x,n.y-30,`LV ${t.level}`,f.green);return}if(t.type==="scanner"){let n=pe(t);_(e,n.x,n.y-34,`LV ${t.level}`,f.green);return}t.type==="facility"&&_(e,t.x+t.w/2,t.y+18,`LV ${t.level}`,f.green)}function us(e,t){let n=Ie(e),o=r=>{n[r]=Math.max(0,n[r]||0)+1};if(t.id==="bearing"&&o("bearing"),t.id==="autoScannerTuning"&&o("autoScannerTuning"),t.id==="legalWork"&&o("legalWork"),t.id==="crowdedFarming"&&(n.crowdedFarming=Math.min(10,(n.crowdedFarming||0)+1)),t.id==="hatchingFeed"&&o("hatchingFeed"),t.id==="poopRateBooster"&&o("poopRateBooster"),t.id==="safetyCover"&&o("safetyCover"),t.id==="recyclingSubsidy"&&(n.recyclingSubsidy=Math.min(3,(n.recyclingSubsidy||0)+1)),t.id==="chemicalWeaponSubsidy"&&o("chemicalWeaponSubsidy"),t.id==="preventiveMaintenance"&&o("preventiveMaintenance"),t.id==="dudFilter"&&o("dudFilter"),t.id==="durabilityCoating"&&(o("durabilityCoating"),me(e)),t.id==="sparePartsBin"){o("sparePartsBin");let r=Vi(e,.02);e.stats.sparePartsRepair=(e.stats.sparePartsRepair||0)+r,e.totals.sparePartsRepair=(e.totals.sparePartsRepair||0)+r,_(e,y.x+y.cols*y.cell/2,y.y-30,"REPAIR +2%",f.green)}t.id==="dudRefund"&&o("dudRefund"),t.id==="freeReroll"&&o("freeReroll"),t.id==="composter"&&o("composter"),t.id==="scannerQueueSpacing"&&o("scannerQueueSpacing"),t.id==="flattery"&&o("fairiesFlatteryNext"),t.id==="usedMachine"&&(n.usedMachineActive=!0),t.id==="newMachine"&&(n.usedMachineActive=!1),t.id==="laborExploitation"&&(n.laborExploitation=1),t.id==="rescueLoan"&&(o("rescueLoanCharges"),_(e,y.x+y.cols*y.cell/2,y.y-30,"RESCUE HELD",f.green))}function _e(e){return`${Math.round(Number(e||0)*100)}%`}function ns(e){let t=st[Math.max(0,Math.min(st.length-1,e-1))]||st[0]||[0,0];return`${t[0].toFixed(2)}-${t[1].toFixed(2)}s`}function os(e,t){return Math.ceil(e*Math.pow(xe.incomeUpgradeRate,Math.max(0,t-1)))}function rs(e,t,n){let r=Ue(e,t==="mixer"?"upgradeMixer":"upgradeTruck")[0];if(!r)return{before:os(n,1),after:os(n,2)};let s=t==="mixer"?qe(e):De(e),l=r.level||1;r.level=l+1;let d=t==="mixer"?qe(e):De(e);return r.level=l,{before:s,after:d}}function pa(e,t){let n=Ie(e);if(t.id==="upgradeEgg"){let o=Ue(e,t),r=Math.min(3,Math.max(1,o[0]?.level||1));return`Choose one EGG. Level +1. Production interval ${ns(r)} -> ${ns(r+1)}.`}if(t.id==="upgradeAutoScanner"){let o=Ue(e,t)[0]||{level:1},r=et(o,e),s=et({...o,level:(o.level||1)+1},e);return`Choose one AUTO SCANNER. Level +1. Cooldown ${r.toFixed(2)}s -> ${s.toFixed(2)}s.`}if(t.id==="upgradeMixer"){let o=rs(e,"mixer",xe.income.mixer);return`Choose one MIXER. Earning +10%. Male-chick income ${M(o.before)} -> ${M(o.after)}.`}if(t.id==="upgradeTruck"){let o=rs(e,"truck",xe.income.truck);return`Choose one TRUCK. Earning +10%. Correct shipment income ${M(o.before)} -> ${M(o.after)}.`}if(t.id==="upgradeTrash"){let o=At(e),r=Math.min(Kt(),o+1),s=ut(o),l=ut(r);return`SHREDDER level +1. Poop income ${M(s)} -> ${M(l)} per item.`}if(t.id==="bearing"){let o=Math.min(Gt,xn*Math.pow(kn,Math.max(0,n.bearing||0))),r=Math.min(Gt,xn*Math.pow(kn,Math.max(0,(n.bearing||0)+1)));return`Conveyor speed +7.5%. After pick: ${o.toFixed(1)} -> ${r.toFixed(1)} px/s.`}if(t.id==="legalWork"){let o=Math.max(0,n.legalWork||0);return`Fairies tribute profit exemption +${M(250)}. After pick: exemption bonus ${M(250*(o+1))}.`}if(t.id==="crowdedFarming"){let o=Math.min(10,(n.crowdedFarming||0)+1);return`Held ${n.crowdedFarming||0}/10. After pick: EGG interval ${_e(Math.max(.5,1-.05*o))}, deterioration ${_e(Math.min(1.4,1+.04*o))}.`}if(t.id==="extraEggOutlet"){let o=Ue(e,t),r=Math.max(0,Number(o[0]?.farm?.extraEggOutlet)||0);return`Choose one EGG. Output ports ${1+r} -> ${2+r}. Max 4 ports per EGG.`}if(t.id==="hatchingFeed")return`Held ${n.hatchingFeed||0}. After pick: EGG interval ${_e(Math.pow(.96,(n.hatchingFeed||0)+1))}, poop rate multiplier ${_e(Math.pow(1.03,(n.hatchingFeed||0)+1))}.`;if(t.id==="poopRateBooster")return`Held ${n.poopRateBooster||0}. After pick: base poop rate +${Math.round((n.poopRateBooster||0)+1)*4} percentage points.`;if(t.id==="autoScannerTuning")return`Held ${n.autoScannerTuning||0}. After pick: all AUTO SCANNER default cooldown ${_e(Math.pow(so,(n.autoScannerTuning||0)+1))}.`;if(t.id==="safetyCover")return`Held ${n.safetyCover||0}. After pick: explosion damage ${_e(Math.pow(.95,(n.safetyCover||0)+1))}.`;if(t.id==="recyclingSubsidy")return`Held ${n.recyclingSubsidy||0}/3. After pick: normal SELL refund ${Math.round(Math.min(.8,.5+.1*((n.recyclingSubsidy||0)+1))*100)}%.`;if(t.id==="chemicalWeaponSubsidy")return`Held ${n.chemicalWeaponSubsidy||0}. After pick: ${M(1200*((n.chemicalWeaponSubsidy||0)+1))} per 70 truck-shipped poop each day.`;if(t.id==="preventiveMaintenance")return`Held ${n.preventiveMaintenance||0}. After pick: deterioration speed ${_e(Math.pow(.95,(n.preventiveMaintenance||0)+1))}.`;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,Re.dudChancePerCard||0)),r=Math.max(0,Math.min(1,Re.dudChanceReductionPerFilter||.05)),s=Math.max(0,n.dudFilter||0),l=Math.max(0,o-r*s),d=Math.max(0,o-r*(s+1));return`Held ${s}. DUD chance per card ${_e(l)} -> ${_e(d)}.`}return t.id==="durabilityCoating"?`Held ${n.durabilityCoating||0}. After pick: maximum durability ${_e(Math.pow(1.03,(n.durabilityCoating||0)+1))}.`:t.id==="sparePartsBin"?`Held ${n.sparePartsBin||0}. Immediately restores 2% durability to every maintained machine. Common card weight.`:t.id==="dudRefund"?`Held ${n.dudRefund||0}. After pick: DUD clicks award ${M(50*((n.dudRefund||0)+1))}.`:t.id==="freeReroll"?`Held ${n.freeReroll||0}. After pick: each card screen starts with ${(n.freeReroll||0)+1} free reroll${(n.freeReroll||0)+1===1?"":"s"}.`:t.id==="composter"?`Held ${n.composter||0}. After pick: SHREDDER poop grants ${M(3*((n.composter||0)+1))}.`:t.id==="scannerQueueSpacing"?`Held ${n.scannerQueueSpacing||0}. After pick: Manual/Auto Scanner queue spacing ${_e(Math.pow(.85,(n.scannerQueueSpacing||0)+1))}.`:t.id==="flattery"?`Next Fairies tribute -50%. Held for next tribute: ${n.fairiesFlatteryNext||0}.`:t.id==="usedMachine"?"Enable Used Machines: future equipment costs 50%, has no SELL refund, and starts with 60% durability.":t.id==="newMachine"?"Cancel Used Machines. Future equipment returns to normal price, refund, and durability.":t.id==="laborExploitation"?"Repairman labor cost -30% permanently. One time only.":t.id==="rescueLoan"?`At day-end bankruptcy check, gain ${M(500)} if cash is below ${M(0)}. Held: ${n.rescueLoanCharges||0}.`:t.description}function Jo(e,t){let n=e.cardDraft?.choices||[],o=n.findIndex(r=>r.id===t.id);o>=0&&n.splice(o,1)}function ds({game:e,ui:t,onUpdatePanels:n}){function o(){n&&n()}function r(){Ie(e),e.cardTargetPick=null,e.cardDraft={pending:!0,choices:qn(e,$t),rerolls:0,freeRerolls:qt(e,"freeReroll"),picksRemaining:1}}function s(){Ie(e),e.cardDraft.pending=!1,e.cardDraft.choices=[],e.cardDraft.picksRemaining=0,e.cardTargetPick=null,t.modal.classList.remove("visible","equipment-popover"),o()}function l(I=$t){Ie(e),e.cardDraft.choices=qn(e,I)}function d(){Ie(e),!e.cardDraft.choices.length&&e.cardDraft.picksRemaining>0&&l($t)}function v(I){Jo(e,I),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1),e.cardTargetPick=null,d(),e.cardDraft.picksRemaining<=0?s():Z()}function C(I){Jo(e,I),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1)+Re.extraCardsAddedPicks,e.cardDraft.choices.push(...qn(e,2)),Z()}function P(I,W){let N=qt(e,"dudRefund")*50;if(N>0){let le=Oe(e,N);e.stats.dudRefundIncome=(e.stats.dudRefundIncome||0)+le,e.totals.dudRefundIncome=(e.totals.dudRefundIncome||0)+le,_(e,y.x+y.cols*y.cell/2,y.y-30,`DUD REFUND +${M(le)}`,f.green)}It(e,34,.62),document.body?.animate&&document.body.animate([{transform:"translate(0, 0)"},{transform:"translate(-10px, 7px)"},{transform:"translate(12px, -8px)"},{transform:"translate(-8px, -5px)"},{transform:"translate(9px, 6px)"},{transform:"translate(0, 0)"}],{duration:260,easing:"steps(5, end)"}),W&&(W.style.setProperty("--fling-x",`${260+Math.random()*260}px`),W.style.setProperty("--fling-y",`${-260-Math.random()*170}px`),W.style.setProperty("--fling-r",`${(Math.random()<.5?-1:1)*(52+Math.random()*38)}deg`),W.classList.add("flung")),window.setTimeout(()=>{Jo(e,I),d(),Z()},340)}function A(I,W=null){if(I.type==="dud")return P(I,W);if(I.id==="extraCards")return C(I);if(I.type==="equipmentUpgrade"||I.type==="cellAction")return L(I);us(e,I),v(I)}function L(I){let W=Ue(e,I);W.length&&(e.cardTargetPick={pending:!0,cardId:I.id,mode:I.target==="blockedCell"?"blockedCell":"equipment",targetKeys:W.map(Ze),remaining:I.id==="dynamite"?Math.min(3,W.length):1},t.modal.classList.remove("visible","equipment-popover"),o())}function V(I){if(!I||I.type!=="blockedCell")return!1;let W=$(I.col,I.row);if(!e.blockedCells?.has(W))return!1;e.blockedCells.delete(W);let N=F(I.col,I.row);return pt(e,N.x,N.y),Ye(e,N.x,N.y,f.danger,62),je(e,N.x,N.y,18,f.warn),Bn(e,N.x,N.y,8),It(e,16,.35),_(e,N.x,N.y-18,"BOOM",f.danger),be(e),e.cardTargetPick.remaining=Math.max(0,(e.cardTargetPick.remaining||1)-1),e.cardTargetPick.targetKeys=Ue(e,"dynamite").map(Ze),o(),!0}function ne(I){if(!e.cardTargetPick?.pending)return!1;let W=Vt(e.cardTargetPick.cardId),N=fa(e,I);return!W||!N?(z(),!0):W.id==="dynamite"?(V(N)&&((e.cardTargetPick.remaining||0)<=0||!Ue(e,"dynamite").length)&&v(W),!0):(cs(e,N),v(W),!0)}function z(){e.cardTargetPick?.pending&&(e.cardTargetPick=null,Z())}function se(){let I=Math.max(0,e.cardDraft?.freeRerolls||0);if(I>0){e.cardDraft.freeRerolls=I-1,e.cardDraft.rerolls+=1,l($t),Z();return}let W=ji(e);e.cashR!==we)].slice(0,5);return N.innerHTML=`${I.title}
${he.map(R=>`${R}`).join("")}
${pa(e,I)}`,N.addEventListener("click",()=>A(I,N)),N.dataset.index=String(W),N}function Z(){Ie(e),e.cardTargetPick=null,e.cardDraft?.pending||r(),e.cardDraft.choices?.length||l($t);let I=e.cardDraft.choices||[],W=ji(e),N=Math.max(0,e.cardDraft?.freeRerolls||0),le=Math.max(1,e.cardDraft.picksRemaining||1);t.modalTitle.textContent="Choose Upgrade Card",t.modalBody.innerHTML=`

Choose ${le} card${le===1?"":"s"} before Build phase. Dud cards can be flicked away without consuming a pick. Equipment cards target machines; Dynamite targets blocked cells.

`;let we=t.modalBody.querySelector("#cardChoices");I.forEach((G,x)=>we.appendChild(ye(G,x))),t.modalActions.innerHTML="";let he=document.createElement("button");he.type="button",he.className="facility-action warn reroll-button",he.textContent=N>0?`Reroll (FREE x${N})`:`Reroll ${M(W)}`,he.disabled=N<=0&&e.cash0?`${N} free reroll${N===1?"":"s"} remaining.`:he.disabled?"Not enough cash":"",he.addEventListener("click",se),t.modalActions.appendChild(he);let R=document.createElement("button");R.type="button",R.className="facility-action",R.textContent="No Card",R.title="Skip this upgrade pick and enter Build phase.",R.addEventListener("click",s),t.modalActions.appendChild(R),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible")}return{prepareDraft:r,showDraft:Z,finishDraft:s,chooseTargetAtPoint:ne,cancelTargetPick:z}}var ya=!1,ha={chickMale:"./assets/images/chick_male.png",chickFemale:"./assets/images/chick_female.png",poop:new URL("../../assets/images/poop.png",import.meta.url).href,conveyor:"./assets/images/conveyor.png",scannerManual:"./assets/images/scanner_manual.png",scannerAuto:"./assets/images/scanner_auto.png",eggFarm:"./assets/images/egg_farm.png",mixer:"./assets/images/mixer.png",shredder:"./assets/images/shredder.png",truck:"./assets/images/truck.png"},ze={};for(let[e,t]of Object.entries(ha)){let n=new Image;n.loaded=!1,n.onerror=()=>{n.loaded=!1},(ya||e==="poop")&&t&&(n.onload=()=>{n.loaded=!0},n.src=t),ze[e]=n}function ys(e,t,n,o){e.clearRect(0,0,t.width,t.height),va(e,t),e.save();let r=n.shake.time>0?U(-n.shake.strength,n.shake.strength):0,s=n.shake.time>0?U(-n.shake.strength,n.shake.strength):0,l=n.view?.scale||1;e.translate((n.view?.x||0)+r,(n.view?.y||0)+s),e.scale(l,l),Sa(e,n),xa(e,n),ka(e,n),Aa(e,n),Oa(e,n),Da(e,n),$a(e,n),ba(e,n),Wa(e,n,o.activeQueuedChick),Qa(e,n),Ya(e,t,n),qa(e,n,o.selectedObject,o.selectedTitle),Va(e,n),za(e,n),Xa(e,n),e.restore(),Ja(e,n,t)}function ma(e){if(e.type==="eggFarm"){let n=F(e.ref.col,e.ref.row);return{x:n.x-34,y:n.y-34,w:68,h:68,cx:n.x,cy:n.y}}let t=e.ref;return{x:t.x,y:t.y,w:t.w,h:t.h,cx:t.x+t.w/2,cy:t.y+t.h/2}}function ba(e,t){if(t.phase!=="build")return;let n=Dn(t);for(let o of n){let r=ma(o);e.save(),e.fillStyle="rgba(196,36,36,.22)",e.strokeStyle=f.danger,e.lineWidth=5,e.setLineDash([10,6]),te(e,r.x,r.y,r.w,r.h,!0,!0),e.setLineDash([]),e.fillStyle=f.danger,e.strokeStyle=f.white,e.lineWidth=4,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.strokeText("!",r.cx,r.y+24),e.fillText("!",r.cx,r.y+24),e.font="900 11px ui-monospace, monospace",e.strokeText("NO ROUTE",r.cx,r.y+r.h-8),e.fillText("NO ROUTE",r.cx,r.y+r.h-8),e.restore()}}function te(e,t,n,o,r,s=!0,l=!0){e.beginPath(),e.rect(t,n,o,r),s&&e.fill(),l&&e.stroke()}function nr(e,t,n,o,r=f.ink){e.save(),e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.lineWidth=4,e.strokeStyle=f.white,e.fillStyle=r,e.strokeText(o,t,n),e.fillText(o,t,n),e.restore()}function Ft(e,t,n,o,r,s){return t?.loaded?(e.drawImage(t,n,o,r,s),!0):!1}function va(e,t){e.fillStyle=f.bg,e.fillRect(0,0,t.width,t.height),e.save(),e.strokeStyle="rgba(16, 32, 21, 0.035)",e.lineWidth=1;for(let n=0;n=n;for(let r of kt(t)){let s=Ct(r);e.save(),e.fillStyle=o?"rgba(183,245,198,.34)":"rgba(255,255,255,.22)",e.strokeStyle=o?f.green:f.muted,e.lineWidth=5,e.setLineDash([16,10]),te(e,s.x,s.y,s.w,s.h,!0,!0),e.setLineDash([]);let l=mo(r),d=l.cx,v=l.cy;e.fillStyle="rgba(255,255,255,.94)",e.strokeStyle=f.ink,e.lineWidth=4,te(e,l.x,l.y,l.w,l.h,!0,!0),e.fillStyle=o?f.green:f.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText(r.direction==="right"?"BUY RIGHT LOT":"BUY UPPER LOT",d,v-12),e.fillStyle=f.ink,e.font="900 16px ui-monospace, monospace",e.fillText(`${M(n)} / 10\xD710`,d,v+15),e.fillStyle=f.muted,e.font="900 11px ui-monospace, monospace",e.fillText("blocked tiles included",d,v+30),e.restore()}}function tt(e,t,n,o,r,s,l=0){let d=Ht(s);d<.5||(e.save(),e.globalAlpha=Math.min(.62,.12+d*.54),e.fillStyle="#6b4a23",l>0?(e.beginPath(),e.roundRect?.(t,n,o,r,l),e.roundRect?e.fill():te(e,t,n,o,r,!0,!1)):te(e,t,n,o,r,!0,!1),e.globalAlpha=Math.min(.9,.25+d*.6),e.strokeStyle="#3a2a16",e.lineWidth=Math.max(2,Math.floor(2+d*5)),e.setLineDash([5,6]),te(e,t+3,n+3,o-6,r-6,!1,!0),e.restore())}function tr(e,t){let n=e.componentLookup?.get(t);return(n?e.congestion.get(n):null)?.ratio||0}function ka(e,t){let n=[],o=new Set;for(let s of t.conveyorTiles){let{col:l,row:d}=Q(s);for(let v of ue){let C={col:l+v.dc,row:d+v.dr},P=$(C.col,C.row);if(!t.conveyorTiles.has(P))continue;let A=[s,P].sort().join("|");if(o.has(A))continue;o.add(A);let L=Math.max(tr(t,s),tr(t,P));n.push({a:F(l,d),b:F(C.col,C.row),ratio:L})}}e.save(),e.lineCap="round",e.lineJoin="round";for(let s of[{width:33,color:f.ink,alpha:1},{width:25,color:f.white,alpha:1},{width:17,color:f.greenSoft,alpha:1}]){e.globalAlpha=s.alpha,e.strokeStyle=s.color,e.lineWidth=s.width;for(let l of n)e.beginPath(),e.moveTo(l.a.x,l.a.y),e.lineTo(l.b.x,l.b.y),e.stroke()}for(let s of n){let l=Math.max(0,(s.ratio-.5)/.5);e.strokeStyle=yo(f.green,f.danger,l),e.globalAlpha=s.ratio>.5?.35+l*.55:.8,e.lineWidth=6,e.beginPath(),e.moveTo(s.a.x,s.a.y),e.lineTo(s.b.x,s.b.y),e.stroke()}let r=Pa(t);for(let s of t.conveyorTiles){let l=F(...Object.values(Q(s))),d=t.conveyorMeta.get(s)||{},v=tr(t,s),C=d.kind==="boostConveyor"?"#fff2b8":f.white;e.fillStyle=v>.5?yo(C,"#ffd6d6",Math.max(0,(v-.5)/.5)):C,e.strokeStyle=f.ink,e.lineWidth=2,te(e,l.x-8,l.y-8,16,16,!0,!0),d.kind==="boostConveyor"&&(e.save(),e.strokeStyle=f.warn,e.lineWidth=3,e.beginPath(),e.moveTo(l.x-15,l.y+13),e.lineTo(l.x-3,l.y-13),e.lineTo(l.x+2,l.y-2),e.lineTo(l.x+15,l.y-13),e.stroke(),e.restore()),tt(e,l.x-14,l.y-14,28,28,{meta:d}),Ke(e,t,"conveyor",s,l.x,l.y,38,38),Ra(e,l,r.get(s)||[]);let P=rr(t,s);Ta(e,l,d,Ma(t,s,P),P),v>.5&&nr(e,l.x,l.y-15,`${Math.floor(v*100)}%`,f.danger)}e.restore()}function rr(e,t){let n=Q(t);return ue.filter(o=>e.conveyorTiles.has($(n.col+o.dc,n.row+o.dr))).map(o=>o.name)}function hs(e,t,n){let o=ue.find(l=>l.name===n);if(!o)return!1;let r=e.conveyorMeta?.get?.($(t.col+o.dc,t.row+o.dr));return r?[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))].includes(o.opposite):!1}function Ca(e,t,n,o=rr(e,t),r="random"){if(o.length<3)return n;let s=Q(t),l=new Set(o.filter(C=>hs(e,s,C)));if(r&&r!=="random"&&o.includes(r)){let C=new Set(l);C.add(r),o.filter(P=>!C.has(P)).length>=2&&l.add(r)}let d=o.filter(C=>!l.has(C));if(d.length)return d;let v=n.filter(C=>!l.has(C));return v.length?v:n}function Ma(e,t,n=rr(e,t)){if(n.length<3)return[];let o=Q(t),r=new Set(n.filter(s=>hs(e,o,s)));return n.filter(s=>{let l=new Set(r);return l.add(s),n.filter(d=>!l.has(d)).length>=2})}function ga(e,t,n){let o=Q(t),r=ue.filter(d=>e.conveyorTiles.has($(o.col+d.dc,o.row+d.dr))).map(d=>d.name),s=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(d=>r.includes(d)),l=r;return s.length?s:l}function Ta(e,t,n,o,r=o){if(r.length<3||o.length<2)return;e.save();let s=o.includes(n.branchMode)?n.branchMode:"random",l=s!=="random";if(e.lineJoin="round",e.lineCap="round",e.lineWidth=2,e.fillStyle="rgba(255,255,255,.9)",e.strokeStyle=l?f.warn:f.green,te(e,t.x-17,t.y-17,34,34,!0,!0),e.strokeStyle=f.ink,e.lineWidth=2,e.fillStyle=f.ink,s!=="random"){let d=ue.find(v=>v.name===s);Vn(e,t.x,t.y,d?.angle||0,9,6)}else e.beginPath(),e.moveTo(t.x-10,t.y),e.lineTo(t.x-2,t.y),e.lineTo(t.x+8,t.y-8),e.moveTo(t.x-2,t.y),e.lineTo(t.x+8,t.y+8),e.stroke(),Vn(e,t.x+9,t.y-9,-Math.PI/4,4,3),Vn(e,t.x+9,t.y+9,Math.PI/4,4,3);e.restore()}function Ea(e,t,n){if(!n)return[];let o=Q(t),r=ue.filter(d=>e.conveyorTiles.has($(o.col+d.dc,o.row+d.dr))).map(d=>d.name),s=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(d=>r.includes(d));return Ca(e,t,s.length?s:ga(e,t,n),r,n.branchMode||"random").map(d=>ue.find(v=>v.name===d)).filter(Boolean)}function Pa(e){let t=new Map;for(let[n,o]of e.conveyorMeta||[]){let r=Ea(e,n,o);r.length&&t.set(n,r)}return t}function Ra(e,t,n){let o=n.slice(0,4);o.length&&(e.save(),e.fillStyle=f.ink,e.globalAlpha=.86,o.forEach(r=>{Vn(e,t.x+r.dc*12,t.y+r.dr*12,r.angle,6,5)}),e.restore())}function Vn(e,t,n,o,r=11,s=8){e.save(),e.translate(t,n),e.rotate(o),e.beginPath(),e.moveTo(r,0),e.lineTo(-r*.72,-s),e.lineTo(-r*.72,s),e.closePath(),e.fill(),e.restore()}function Aa(e,t){e.save(),e.lineWidth=2,e.font="900 12px ui-monospace, monospace",e.textAlign="center";for(let n of t.scanners){let o=Mo(n),r=[{type:"inputA",p:Ee(n,"inputA"),label:"IN",color:f.green},{type:"left",p:Ee(n,"left"),label:To(o.left),color:Eo(o.left)},{type:"right",p:Ee(n,"right"),label:To(o.right),color:Eo(o.right)}];for(let s of r){if(!s.p)continue;let l=F(s.p.col,s.p.row),d=jr(t,n,s.type||(s.label==="IN"?"inputA":null))||t.conveyorTiles.has($(s.p.col,s.p.row));e.fillStyle=d?s.color:"#f4c2c2",e.strokeStyle=f.ink,te(e,l.x-18,l.y-12,36,24,!0,!0),e.fillStyle=d&&s.color===f.white?f.ink:f.white,e.fillText(s.label,l.x,l.y+4)}}e.restore()}function Da(e,t){for(let n of t.eggFarms)Ia(e,n,t)}function Ia(e,t,n){let o=F(t.col,t.row);if(e.save(),Ft(e,ze.eggFarm,o.x-29,o.y-29,58,58)){tt(e,o.x-29,o.y-29,58,58,t);let l=1+Math.max(0,Number(t.extraEggOutlet)||0);e.fillStyle="rgba(255,255,255,.92)",e.strokeStyle=f.ink,e.lineWidth=2,te(e,o.x+9,o.y+12,30,18,!0,!0),e.fillStyle=f.ink,e.font="900 10px ui-monospace, monospace",e.textAlign="center",e.fillText(`O${l}`,o.x+24,o.y+24),Ke(e,n,"eggFarm",t.id,o.x,o.y,68,68),e.restore();return}e.fillStyle=f.white,e.strokeStyle=f.ink,e.lineWidth=4,te(e,o.x-28,o.y-28,56,56,!0,!0),e.fillStyle=f.green,e.font="900 19px ui-monospace, monospace",e.textAlign="center",e.fillText("EGG",o.x,o.y-4);let r=1+Math.max(0,Number(t.extraEggOutlet)||0);e.font="900 11px ui-monospace, monospace",e.fillStyle=f.ink,e.fillText(`L${t.level} O${r}`,o.x,o.y+13),e.fillText(`${t.nextSpawn.toFixed(1)}s`,o.x,o.y+26);let s=Math.max(0,Math.min(1,t.shutterProgress||0));if(s>0){let l=56*s;e.fillStyle=f.ink,te(e,o.x-28,o.y-28,56,l,!0,!1),e.strokeStyle=f.white,e.lineWidth=2;for(let d=o.y-24;d=1&&(e.fillStyle=f.white,e.font="900 12px ui-monospace, monospace",e.fillText("SHUT",o.x,o.y+4))}tt(e,o.x-28,o.y-28,56,56,t),Ke(e,n,"eggFarm",t.id,o.x,o.y,68,68),e.restore()}function $a(e,t){for(let n of t.scanners)Fa(e,n,t)}function Fa(e,t,n){let o=pe(t);if(e.save(),t.kind==="manual"&&(n.manualCombo?.count||0)>=10){let v=n.manualCombo.count;e.save(),e.globalAlpha=Math.min(.55,.16+v/120),e.strokeStyle=v>=30?f.warn:f.green,e.lineWidth=Math.min(14,5+Math.floor(v/10)),e.shadowColor=e.strokeStyle,e.shadowBlur=Math.min(28,8+v),te(e,o.x-54,o.y-76,108,152,!1,!0),e.restore()}let r=t.kind==="auto"?ze.scannerAuto:ze.scannerManual;if(Ft(e,r,o.x-50,o.y-73,100,146)){t.kind==="auto"?tt(e,o.x-50,o.y-73,100,146,t):fs(e,t,o),Ke(e,n,"scanner",t.id,o.x,o.y,108,154),e.restore();return}e.fillStyle=t.kind==="auto"?"#d8ffe2":f.white,e.strokeStyle=f.ink,e.lineWidth=4,te(e,o.x-50,o.y-73,100,146,!0,!0),e.fillStyle=t.kind==="auto"?f.green:f.ink,e.font="900 19px ui-monospace, monospace",e.textAlign="center",e.fillText(`${t.kind==="auto"?"AUTO":`S${(t.slot??0)+1}`}`,o.x,o.y-48),e.font="900 11px ui-monospace, monospace";let s=t.keys?.left?.label||(t.slot===0?"A":"Left"),l=t.keys?.right?.label||(t.slot===0?"D":"Right");e.fillText(t.role===0?`${s}:M ${l}:NEXT`:`${s}:WASTE ${l}:TRUCK`,o.x,o.y-28);let d=t.queue.length;t.kind==="manual"?(fs(e,t,o),e.fillStyle=d>0?f.green:f.muted,e.font="900 10px ui-monospace, monospace",e.fillText(`Q:${d}`,o.x,o.y+54)):(e.fillStyle=d>0?f.green:f.muted,e.font="900 12px ui-monospace, monospace",e.fillText(`Q:${d} CD:${t.cooldown.toFixed(1)}`,o.x,o.y+54),tt(e,o.x-50,o.y-73,100,146,t)),Ke(e,n,"scanner",t.id,o.x,o.y,108,154),e.restore()}function fs(e,t,n){if(t.kind!=="manual")return;let r=(t.slot??0)===0?[{side:"left",text:"A"},{side:"right",text:"D"}]:[{side:"left",text:"\u2190"},{side:"right",text:"\u2192"}];r[0].text=t.keys?.left?.label||r[0].text,r[1].text=t.keys?.right?.label||r[1].text;let s=t.keyPressTime>0?t.keyPressSide:null,l=n.x-30,d=n.y+18;e.save(),e.lineWidth=3,e.fillStyle="#f7fff5",e.strokeStyle=f.ink,te(e,l-4,d-4,68,25,!0,!0),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let v=0;v.8,s=t.y+Math.sin(t.bob)*(r?5:1.5);if(e.save(),n&&(e.strokeStyle=f.green,e.lineWidth=5,e.beginPath(),e.arc(t.x,s,t.radius+8,0,Math.PI*2),e.stroke()),r&&(e.strokeStyle=f.danger,e.lineWidth=3,e.beginPath(),e.arc(t.x,s,t.radius+12+Math.sin(t.bob*2)*4,0,Math.PI*2),e.stroke()),t.sex==="poop")lr(e,t.x,s,t.radius);else{let l=t.sex==="male"?ze.chickMale:ze.chickFemale;Ft(e,l,t.x-t.radius,s-t.radius,t.radius*2,t.radius*2)||(e.fillStyle=t.sex==="male"?f.male:f.female,e.strokeStyle=f.ink,e.lineWidth=5,e.beginPath(),e.arc(t.x,s,t.radius,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle=f.ink,e.beginPath(),e.arc(t.x-6,s-5,2.5,0,Math.PI*2),e.arc(t.x+6,s-5,2.5,0,Math.PI*2),e.fill(),e.fillStyle="#ffaa2e",e.beginPath(),e.moveTo(t.x,s+2),e.lineTo(t.x+9,s+6),e.lineTo(t.x,s+10),e.closePath(),e.fill())}e.restore()}function Ka(e,t){let n=null,o=1/0;for(let[r,s]of e.componentLookup.entries()){let l=Q(r),d=F(l.col,l.row),v=Math.hypot(t.x-d.x,t.y-d.y);vps(o.type,o.id)===ps(t,n))}function Ke(e,t,n,o,r,s,l,d){Ha(t,n,o)&&(e.save(),e.fillStyle="rgba(34,185,79,.18)",e.strokeStyle=f.green,e.lineWidth=(t.multiSelected||[]).length>1?6:4,e.setLineDash((t.multiSelected||[]).length>1?[]:[8,5]),te(e,r-l/2,s-d/2,l,d,!0,!0),e.restore())}function qa(e,t,n,o){if(t.phase==="build"&&(t.multiSelected||[]).length>1){e.save(),e.fillStyle="rgba(255,255,255,.96)",e.strokeStyle=f.ink,e.lineWidth=3,te(e,54-t.view.x,66-t.view.y,214,42,!0,!0),e.fillStyle=f.ink,e.font="900 11px ui-monospace, monospace",e.fillText(`${t.multiSelected.length} ITEMS SELECTED`,65-t.view.x,83-t.view.y),e.fillStyle=f.muted,e.font="900 11px ui-monospace, monospace",e.fillText("drag any selected item to move group",65-t.view.x,99-t.view.y),e.restore();return}}function Ya(e,t,n){if(!n.cardTargetPick?.pending)return;let o=er(n);e.save(),e.fillStyle="rgba(0,0,0,.66)",e.beginPath();let r=n.view?.scale||1;e.rect(-(n.view?.x||0)/r,-(n.view?.y||0)/r,t.width/r,t.height/r);for(let v of o){let C=v.bounds,P=8;e.rect(C.x-P,C.y-P,C.w+P*2,C.h+P*2)}e.fill("evenodd");let s=n.cardTargetPick?.mode==="blockedCell";if(!o.length){e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=f.ink,e.lineWidth=3,te(e,(260-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,420/r,42/r,!0,!0),e.fillStyle=f.danger,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(s?"NO BLOCKED CELL. PRESS ESC.":"NO VALID UPGRADE TARGET. PRESS ESC.",(470-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore();return}e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=f.ink,e.lineWidth=3;let l=Math.max(1,n.cardTargetPick?.remaining||1),d=n.cardTargetPick?.mode==="autoScannerMenu"?"AUTO SCANNER ROUTE SETTINGS. CLICK EMPTY AREA TO CLOSE.":s?`CLICK BLOCKED CELL: ${l} LEFT. PRESS ESC TO CANCEL.`:"CLICK AN UPGRADEABLE MACHINE. PRESS ESC TO CANCEL.";te(e,(216-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,560/r,42/r,!0,!0),e.fillStyle=f.ink,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(d,(496-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore()}function Va(e,t){if(t.phase!=="build"||!t.selectionBox)return;let n=t.selectionBox,o=Math.min(n.x1,n.x2),r=Math.min(n.y1,n.y2),s=Math.abs(n.x2-n.x1),l=Math.abs(n.y2-n.y1);e.save(),e.fillStyle="rgba(34,185,79,.12)",e.strokeStyle=f.green,e.lineWidth=2,e.setLineDash([7,4]),te(e,o,r,s,l,!0,!0),e.restore()}function za(e,t){let n=[...t.effects].sort((o,r)=>(o.priority??ke.ambient)-(r.priority??ke.ambient));for(let o of n){let r=Math.max(0,o.life/o.maxLife);e.save(),e.globalAlpha=r,o.type==="meat"?(e.fillStyle=f.green,te(e,o.x-o.size/2,o.y-o.size/2,o.size*1.5,o.size,!0,!1)):o.type==="sludge"?(e.fillStyle=f.poop,te(e,o.x-o.size/2,o.y-o.size/2,o.size*1.4,o.size,!0,!1)):o.type==="spawn"?(e.strokeStyle=f.green,e.lineWidth=3,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*20,0,Math.PI*2),e.stroke()):o.type==="spark"?(e.fillStyle=o.color||f.danger,te(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!0,!1)):o.type==="smoke"?(e.fillStyle="rgba(16,32,21,.24)",e.beginPath(),e.arc(o.x,o.y,o.size*(1.2-r*.2),0,Math.PI*2),e.fill()):o.type==="shockwave"?(e.strokeStyle=o.color||f.danger,e.lineWidth=4,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*(o.maxSize||44),0,Math.PI*2),e.stroke()):o.type==="scannerPulse"?(e.strokeStyle=o.color||f.green,e.lineWidth=5,e.setLineDash([8,6]),e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*38,0,Math.PI*2),e.stroke()):o.type==="shred"?(e.fillStyle=o.color||f.ink,e.save(),e.translate(o.x,o.y),e.rotate(o.rot||0),te(e,-o.w/2,-o.h/2,o.w,o.h,!0,!1),e.restore()):o.type==="load"?(e.strokeStyle=o.color||f.green,e.lineWidth=3,e.beginPath(),e.moveTo(o.x-14,o.y),e.lineTo(o.x+14,o.y),e.moveTo(o.x,o.y-14),e.lineTo(o.x,o.y+14),e.stroke()):o.type==="erase"?(e.strokeStyle=f.ink,e.lineWidth=3,e.setLineDash([4,4]),te(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!1,!0)):o.type==="rage"?(e.fillStyle=o.color||f.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText("!",o.x,o.y)):o.type==="flyingChick"&&(o.sex==="poop"?lr(e,o.x,o.y,o.radius||11):ar(e,o.x,o.y,o.sex,o.sex==="male")),e.restore()}}function Xa(e,t){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let n of t.floatingTexts){let o=Math.max(0,n.life/n.maxLife);e.globalAlpha=o,e.lineWidth=5,e.strokeStyle=f.white,e.fillStyle=n.color,e.strokeText(n.text,n.x,n.y),e.fillText(n.text,n.x,n.y)}e.restore()}function Qa(e,t){let n=t.repairman;if(!(!!n?.active||t.phase==="build"&&!!n?.hiredForNextDay))return;e.save(),e.lineWidth=3,e.fillStyle="#fff0d1",e.strokeStyle=f.ink,e.beginPath(),e.arc(n.x,n.y,17,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle="#ffd6e7",e.beginPath(),e.arc(n.x-6,n.y-2,3.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+6,n.y-2,3.2,0,Math.PI*2),e.fill();let r=!!t.cardEffects?.laborExploitation;e.fillStyle=r?f.danger:f.ink,e.beginPath(),e.arc(n.x-5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.strokeStyle=f.ink,e.lineWidth=r?3:2,e.beginPath(),e.arc(n.x,n.y+(r?0:1),r?8:7,.1*Math.PI,.9*Math.PI),e.stroke(),e.fillStyle=f.green,te(e,n.x-9,n.y+14,18,8,!0,!0),e.strokeStyle=f.ink,e.lineWidth=3,e.beginPath(),e.moveTo(n.x-11,n.y+18),e.lineTo(n.x-20,n.y+24),e.stroke(),e.beginPath(),e.moveTo(n.x+11,n.y+18),e.lineTo(n.x+20,n.y+24),e.stroke(),e.fillStyle=f.ink,e.font="900 11px ui-monospace, monospace",e.textAlign="center",e.fillText(n.active?"FIX":"HIRED",n.x,n.y+33),n.target?.label?nr(e,n.x,n.y-24,n.target.label,f.green):!n.active&&n.hiredForNextDay&&nr(e,n.x,n.y-24,"NEXT DAY",f.green),e.restore()}function Ja(e,t,n){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="left",e.fillStyle=f.ink,e.fillStyle="rgba(255,255,255,.92)",e.strokeStyle=f.ink,e.lineWidth=3,te(e,n.width-284,18,260,34,!0,!0),e.fillStyle=f.green,e.font="900 12px ui-monospace, monospace",e.fillText(wn,n.width-270,40),e.font="900 19px ui-monospace, monospace",e.fillStyle=f.ink;let o=[];t.phase==="running"&&o.push(t.timeLeft<=0?"TIME UP: FARMS SHUT. CLEAR LINE.":"A/D: S1 \u2190/\u2192: S2"),t.phase==="build"&&o.push(`BUILD: ${t.buildTool||"SELECT"} | connect 1 EGG route to any exit`);let r=76;for(let s of o)e.strokeStyle=f.white,e.lineWidth=4,e.strokeText(s,24,r),e.fillText(s,24,r),r+=20;e.restore()}var ws=[[{key:"a",code:"KeyA",label:"A"},{key:"d",code:"KeyD",label:"D"}],[{key:"arrowleft",code:"ArrowLeft",label:"Left"},{key:"arrowright",code:"ArrowRight",label:"Right"}],[{key:"j",code:"KeyJ",label:"J"},{key:"l",code:"KeyL",label:"L"}],[{key:"f",code:"KeyF",label:"F"},{key:"h",code:"KeyH",label:"H"}],[{key:"q",code:"KeyQ",label:"Q"},{key:"e",code:"KeyE",label:"E"}],[{key:"z",code:"KeyZ",label:"Z"},{key:"x",code:"KeyX",label:"X"}],[{key:"u",code:"KeyU",label:"U"},{key:"o",code:"KeyO",label:"O"}],[{key:"n",code:"KeyN",label:"N"},{key:"m",code:"KeyM",label:"M"}]];function ja(e){let t=ws[e]||ws[0];return{left:{...t[0]},right:{...t[1]}}}function Ss(e,t,n){let o={type:"eggFarm",id:e.nextId++,col:t,row:n,level:1,nextSpawn:2,lastInterval:2,extraEggOutlet:0,price:St.eggFarm,builtSession:e.buildSession};return o.nextSpawn=Mt(o),o.lastInterval=o.nextSpawn,o}function xs(e,t,n,o){let r=o==="auto"?Se.autoScanner.price:Se.manualScanner.price,s=new Set(e.scanners.filter(d=>d.kind==="manual").map(d=>d.slot)),l=0;for(;s.has(l);)l+=1;return{type:"scanner",id:e.nextId++,kind:o,slot:o==="manual"?l:null,role:o==="manual"?l%2:0,col:t,row:n,level:1,queue:[],cooldown:0,price:r,builtSession:e.buildSession,autoMode:"standard",keys:o==="manual"?ja(l):null}}function zn(e){let t=(e.x-y.x)/y.cell,n=(e.y-y.y)/y.cell,o=Math.max(0,Math.min(y.cols-1,Math.round(t-.5))),r=Math.max(0,Math.min(y.rows-1,Math.round(n-.5))),s=Math.abs(e.x-y.x),l=Math.abs(e.x-(y.x+y.cols*y.cell)),d=Math.abs(e.y-y.y),v=Math.abs(e.y-(y.y+y.rows*y.cell)),C=[["left",s],["right",l],["top",d],["bottom",v]].sort((P,A)=>P[1]-A[1])[0][0];return C==="left"?{side:C,entry:{col:0,row:r}}:C==="right"?{side:C,entry:{col:y.cols-1,row:r}}:C==="top"?{side:C,entry:{col:o,row:0}}:{side:C,entry:{col:o,row:y.rows-1}}}function Xn(e,t,n){let o={x:y.x+t.col*y.cell+y.cell/2,y:y.y+t.row*y.cell+y.cell/2},r={left:y.x,right:y.x+y.cols*y.cell,top:y.y,bottom:y.y+y.rows*y.cell};return e.entry={...t},e.side=n,n==="left"?(e.x=r.left-e.w-18,e.y=o.y-e.h/2):n==="right"?(e.x=r.right+18,e.y=o.y-e.h/2):n==="top"?(e.x=o.x-e.w/2,e.y=r.top-e.h-18):(e.x=o.x-e.w/2,e.y=r.bottom+18),e}function ks(e,t,n,o){let{entry:r,side:s}=zn(n),l=Se[t],d=l?{name:l.name,w:l.body?.w||168,h:l.body?.h||110,price:l.price}:{name:t[0].toUpperCase()+t.slice(1),w:168,h:110,price:o},v={type:"facility",id:t,name:d.name,x:0,y:0,w:d.w,h:d.h,level:1,price:o||d.price,builtSession:e.buildSession};return Xn(v,r,s)}function Za(e){return Math.random()({x:s.x,y:s.y})),r=o[0];return{id:e.nextId++,sex:n,x:r.x,y:r.y,route:o,targetIndex:o.length>1?1:o.length,stage:t.stage||"belt",scannerId:t.scannerId??null,nextScannerId:null,pendingScannerId:null,radius:n==="poop"?15:17,bob:Math.random()*Math.PI*2,queueIndex:-1,queueRoute:null}}function Ms({game:e,canvasPoint:t,updatePanels:n,equipmentAtPoint:o,fail:r,pointInGrid:s,rectOfFacility:l,rectsOverlap:d}){function v(x){return x?x.type==="conveyor"?`conveyor:${x.id||x.oldKey}`:x.type==="facility"?`facility:${x.id||x.ref?.id}`:`${x.type}:${x.id||x.ref?.id}`:""}function C(x){return x?x.type==="conveyor"?{type:"conveyor",id:x.oldKey}:{type:x.type,id:x.ref.id}:null}function P(x){let g=v(C(x));return(e.multiSelected||[]).some(O=>v(O)===g)}function A(x){return x?x.type==="eggFarm"?e.eggFarms.find(g=>g.id===x.id)||null:x.type==="scanner"?e.scanners.find(g=>g.id===x.id)||null:x.type==="facility"?e.facilities[x.id]||null:x.type==="conveyor"&&e.conveyorTiles.has(x.id)?{type:"conveyor",id:x.id}:null:null}function L(){let x=[];for(let g of e.conveyorTiles){let O=Q(g),X=F(O.col,O.row);x.push({type:"conveyor",id:g,center:X,cell:O})}for(let g of e.eggFarms)x.push({type:"eggFarm",id:g.id,ref:g,center:F(g.col,g.row),cell:{col:g.col,row:g.row}});for(let g of e.scanners)x.push({type:"scanner",id:g.id,ref:g,center:pe(g),cell:{col:g.col,row:g.row}});for(let g of Object.values(e.facilities)){let O={x:g.x+g.w/2,y:g.y+g.h/2},X=g.entry?F(g.entry.col,g.entry.row):O;x.push({type:"facility",id:g.id,ref:g,center:O,portCenter:X})}return x}function V(x,g){let O=Math.min(g.x1,g.x2),X=Math.max(g.x1,g.x2),oe=Math.min(g.y1,g.y2),de=Math.max(g.y1,g.y2);return x.x>=O&&x.x<=X&&x.y>=oe&&x.y<=de}function ne(x){let g=[];for(let O of L())(V(O.center,x)||O.portCenter&&V(O.portCenter,x))&&g.push({type:O.type,id:O.id});return e.multiSelected=g,e.selected=g[0]||null,n(),g.length}function z(){e.multiSelected=[],e.selected=null,n()}function se(x){let g=t(x);return e.selectionBox={x1:g.x,y1:g.y,x2:g.x,y2:g.y},e.multiSelected=[],e.selected=null,n(),!0}function ye(x){if(!e.selectionBox)return;let g=t(x);e.selectionBox.x2=g.x,e.selectionBox.y2=g.y}function Z(){if(!e.selectionBox)return 0;let x=e.selectionBox,g=Math.abs(x.x2-x.x1),O=Math.abs(x.y2-x.y1);return e.selectionBox=null,g<6&&O<6?(z(),0):ne(x)}function I(x){let g=C(x);return g?(e.multiSelected||[]).length&&P(x)?[...e.multiSelected]:[g]:[]}function W(x){let g=A(x);if(!g)return null;if(x.type==="conveyor"){let O=Q(x.id);return{...x,obj:g,oldKey:x.id,currentKey:x.id,meta:e.conveyorMeta.get(x.id)||{price:Ne("conveyor"),builtSession:null},col:O.col,row:O.row}}return x.type==="eggFarm"||x.type==="scanner"?{...x,obj:g,col:g.col,row:g.row}:x.type==="facility"?{...x,obj:g,x:g.x,y:g.y,w:g.w,h:g.h,entry:g.entry?{...g.entry}:null,side:g.side,center:{x:g.x+g.w/2,y:g.y+g.h/2}}:null}function N(x){let g=t(x),O=o(g);if(!O)return!1;let X=I(O),oe=X.map(W).filter(Boolean);return oe.length?(e.groupDrag={start:g,selections:X,origins:oe,historySnapshot:cn(e),committed:!1,lastDCol:0,lastDRow:0},e.multiSelected=X,e.selected=X[0]||null,n(),!0):!1}function le(){!e.groupDrag||e.groupDrag.committed||(e.undoStack.push(e.groupDrag.historySnapshot),e.redoStack=[],e.groupDrag.committed=!0)}function we(x,g,O){let X=$(x,g),oe=Tt(e,x,g);if(oe&&!O.has(`eggFarm:${oe.id}`))return!0;let de=Et(e,x,g);return!!(de&&!O.has(`scanner:${de.id}`)||e.conveyorTiles.has(X)&&!O.has(`conveyor:${X}`))}function he(x,g,O){let X=[];for(let oe of e.groupDrag.origins){if(oe.type!=="facility")continue;let de={x:oe.center.x+x,y:oe.center.y+g},{entry:ge,side:ce}=zn(de);if(!s(ge.col,ge.row)||e.blockedCells?.has?.($(ge.col,ge.row)))return!0;let ot={...oe.obj,entry:{...ge},side:ce};Xn(ot,ge,ce),X.push({id:oe.id,rect:l(ot)})}for(let oe of X)for(let de of Object.values(e.facilities))if(!O.has(`facility:${de.id}`)&&d(oe.rect,l(de),12))return!0;for(let oe=0;oeJ.type==="conveyor");for(let J of ot){let Me=J.currentKey||J.oldKey;e.conveyorTiles.delete(Me),e.conveyorMeta.delete(Me)}for(let J of ot){let Me=$(J.col+oe,J.row+de);e.conveyorTiles.add(Me),e.conveyorMeta.set(Me,J.meta||{price:Ne("conveyor"),builtSession:null,uses:0}),J.currentKey=Me}for(let J of e.groupDrag.origins)if(J.type==="eggFarm")J.obj.col=J.col+oe,J.obj.row=J.row+de;else if(J.type==="scanner")J.obj.col=J.col+oe,J.obj.row=J.row+de;else if(J.type==="facility"){let Me={x:J.center.x+O,y:J.center.y+X},{entry:Be,side:rt}=zn(Me);Xn(J.obj,Be,rt)}e.groupDrag.selections=e.groupDrag.origins.map(J=>J.type==="conveyor"?{type:"conveyor",id:J.currentKey||J.oldKey}:{type:J.type,id:J.id}),e.multiSelected=[...e.groupDrag.selections],e.selected=e.multiSelected[0]||null,be(e),n()}function G(){e.groupDrag&&(be(e),e.groupDrag=null,n())}return{selectionFromHit:C,startSelectionBox:se,updateSelectionBox:ye,finishSelectionBox:Z,startGroupDrag:N,updateGroupDrag:R,finishGroupDrag:G}}function gs({game:e,ui:t,canvas:n,canvasPoint:o,onUpdatePanels:r}){function s(){r&&r()}let l=null,d=!1,v=null,C=!1,P=["random","up","right","down","left"],A={random:"RND",up:"UP",right:"RT",down:"DN",left:"LF"},L={w:40,h:40,y:0};function V(){return gn(e)}function ne(){e.gridCols=y.cols,e.gridRows=y.rows,e.gridOwnedCells=Nr(e)}function z(i){if(i){y.y-=i*y.cell,y.rows+=i,e.gridChunkOriginY=(e.gridChunkOriginY||0)-Math.floor(i/10),e.ownedCells=Tn(e.ownedCells,i),e.blockedCells=Tn(e.blockedCells,i),e.conveyorTiles=Tn(e.conveyorTiles,i),e.conveyorMeta=_r(e.conveyorMeta,i);for(let c of e.eggFarms||[])c.row+=i;for(let c of e.scanners||[])c.row+=i;for(let c of Object.values(e.facilities||{}))c.entry&&(c.entry.row+=i)}}function se(i){e.ownedCells=e.ownedCells||new Set;for(let c of Wr(i))e.ownedCells.add($(c.col,c.row))}function ye(i){return e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending?null:kt(e).find(c=>c&&Ur(c,i))||null}function Z(i="right"){if(i&&typeof i=="object"&&Number.isFinite(i.chunkX)&&Number.isFinite(i.chunkY))return i;let c=["right","up"].includes(i)?i:"right";return Gr(e,c)}function I(i="right"){let c=Z(i);if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return{ok:!1,reason:"Cannot expand now."};if(!c)return{ok:!1,reason:"Invalid expansion lot."};let h=c.direction||"right",m=V();if(e.cashy.cols&&(y.cols=T.colStart+T.cols),T.rowStart+T.rows>y.rows&&(y.rows=T.rowStart+T.rows),se(T),Kr(e,T.chunkX,T.chunkY),e.gridExpansionPurchases=(e.gridExpansionPurchases||0)+1,e.gridExpansionPurchasesByDirection[h]=(e.gridExpansionPurchasesByDirection[h]||0)+1,ne();let j=$r({seed:`${e.runSeed}:grid-expansion:${T.chunkX},${T.chunkY}:${e.gridExpansionPurchases}`,colStart:T.colStart,colEnd:T.colStart+T.cols,rowStart:T.rowStart,rowEnd:T.rowStart+T.rows,targetRatio:q.map.blockedRatio});for(let Pe of j)e.blockedCells.add(Pe);be(e);let ie=T.cols*T.rows,fe=Ct(T);return _(e,fe.x+fe.w/2,fe.y+fe.h/2,`${h.toUpperCase()} +${ie} CELLS -${M(m)}`,f.green),s(),{ok:!0,direction:h,cost:m,addedCells:ie,blocked:j.size,chunkX:T.chunkX,chunkY:T.chunkY}}function W(i,c){return i>=0&&i=0&&c!c.has(m.id)&&we(h,le(m),12))}function R(i,c,h=null){if(!W(i,c))return!1;if(N(i,c))return!0;let m=$(i,c),k=Tt(e,i,c);if(k&&!(h?.type==="eggFarm"&&h.ref?.id===k.id))return!0;let T=Et(e,i,c);return!!(T&&!(h?.type==="scanner"&&h.ref?.id===T.id)||e.conveyorTiles.has(m)&&!(h?.type==="conveyor"&&h.oldKey===m))}function G(i,c,h=null){let m={col:i,row:c};for(let k of gt(m)){if(!W(k.col,k.row)||N(k.col,k.row))return!0;let T=$(k.col,k.row);if(Tt(e,k.col,k.row))return!0;let ie=Et(e,k.col,k.row);if(ie&&!(h?.type==="scanner"&&h.ref?.id===ie.id)||e.conveyorTiles.has(T))return!0}return!1}function x(){return e.selected?e.selected.type==="eggFarm"?e.eggFarms.find(i=>i.id===e.selected.id)||null:e.selected.type==="scanner"?e.scanners.find(i=>i.id===e.selected.id)||null:e.selected.type==="conveyor"?e.conveyorTiles.has(e.selected.id)?{type:"conveyor",id:e.selected.id}:null:e.selected.type==="facility"&&e.facilities[e.selected.id]||null:null}function g(i){return i?i.type==="eggFarm"?`${xt("eggFarm")} #${i.id}`:i.type==="scanner"?`${i.kind==="auto"?xt("autoScanner"):xt("manualScanner")} #${i.id}`:i.type==="conveyor"?e.conveyorMeta.get(i.id)?.kind==="boostConveyor"?xt("boostConveyor"):xt("conveyor"):i.type==="facility"?i.name:"Equipment":"Equipment"}function O(i){return i?.type==="conveyor"?e.conveyorMeta?.get(i.oldKey||i.ref?.id)?.price||$n(i):$n(i)}function X(){return!!e.cardEffects?.usedMachineActive}function oe(){return X()?{usedMachine:!0,noRefund:!0,durabilityBaseMultiplier:.6}:{usedMachine:!1,noRefund:!1,durabilityBaseMultiplier:1}}function de(i){let c=oe();return Object.assign(i,c),i}function ge(i){let c=i?.ref||i||{};if(i?.type==="eggFarm"||c.type==="eggFarm")return e.eggFarms.length<=1?"Cannot sell the last EGG FARM.":"";if((i?.type==="facility"||c.type==="facility")&&["mixer","trash","truck"].includes(c.baseId||c.id)){let h=c.baseId||c.id;if(Object.values(e.facilities).filter(k=>(k.baseId||k.id)===h).length<=1)return`Cannot sell the last ${c.shortName||c.name||c.id}.`}return""}function ce(i){t.buildStatus.textContent=i,_(e,n.width/2-e.view.x,86-e.view.y,i.toUpperCase(),f.danger)}function ot(i){if(!i)return null;let c=$(i.col,i.row);return e.conveyorMeta.get(c)||null}function J(i){return i?(Array.isArray(i.outDirs)||(i.outDirs=[]),i.outDirs=[...new Set(i.outDirs.filter(c=>["right","left","down","up"].includes(c)))],P.includes(i.branchMode)||(i.branchMode="random"),i.kind||(i.kind="conveyor"),i.speedMultiplier||(i.speedMultiplier=i.kind==="boostConveyor"?2:1),i.outDirs):[]}function Me(i){return i?ue.filter(c=>e.conveyorTiles.has($(i.col+c.dc,i.row+c.dr))).map(c=>c.name):[]}function Be(i){return Me(i).length>=3}function rt(i,c){let h=ue.find(ie=>ie.name===c);if(!i||!h)return!1;let m=$(i.col+h.dc,i.row+h.dr),k=e.conveyorMeta.get(m);if(!k)return!1;let T=h.opposite;return[...new Set([...Array.isArray(k.outDirs)?k.outDirs:[],k.dir].filter(Boolean))].includes(T)}function Ge(i){if(!e.conveyorTiles.has(i))return[];let c=Q(i),h=e.conveyorMeta.get(i),m=J(h),k=Me(c),T=[...new Set([...m,h?.dir].filter(Boolean))].filter(fe=>k.includes(fe)),j=k,ie=T.length?T:j;return h&&(h.outDirs=m.filter(fe=>k.includes(fe)),h.dir&&!k.includes(h.dir)&&(h.dir=h.outDirs[0]||null),h.branchMode!=="random"&&!k.includes(h.branchMode)&&(h.branchMode="random")),ie}function it(i){if(!e.conveyorTiles.has(i))return[];let c=Q(i),h=Me(c);return Be(c)||h.length?h:Ge(i)}function eo(i){let c=Q(i),h=it(i);if(h.length<3)return[];let m=new Set(h.filter(k=>rt(c,k)));return h.filter(k=>{let T=new Set(m);return T.add(k),h.filter(j=>!T.has(j)).length>=2})}function pn(i,c){let h=lt(i,c);if(!h)return!1;let m=$(i.col,i.row),k=$(c.col,c.row),T=e.conveyorMeta.get(m),j=e.conveyorMeta.get(k);if(!T||!j)return!1;let ie=J(T),fe=!ie.includes(h)||T.dir!==h||!j.dir;return ie.includes(h)||ie.push(h),T.dir=h,j.dir||(j.dir=h),fe}function yn(i){let c=to(i);return c.length<2?hn(i):($e(e),no(c),be(e),s(),!0)}function hn(i){if(!i)return!1;let c=$(i.col,i.row),h=e.conveyorMeta.get(c);if(!h||Be(i))return!1;let m=ue.map(j=>j.name),k=h.dir&&m.includes(h.dir)?h.dir:null,T=m[(Math.max(-1,m.indexOf(k))+1)%m.length];return $e(e),h.dir=T,h.outDirs=[T],h.branchMode="random",be(e),s(),!0}function bt(i){return i?ue.map(c=>({col:i.col+c.dc,row:i.row+c.dr})).filter(c=>e.conveyorTiles.has($(c.col,c.row))):[]}function to(i){if(!i||!e.conveyorTiles.has($(i.col,i.row))||Be(i))return[];let c=bt(i);if(!c.length||c.length>2)return[];let h=T=>{let j=[],ie=new Set([$(i.col,i.row)]),fe=i,Pe=T,br=0;for(;Pe&&br<200;){br+=1;let vr=$(Pe.col,Pe.row);if(ie.has(vr)||(ie.add(vr),j.push(Pe),Be(Pe)))break;let wr=bt(Pe).filter(Sr=>!(Sr.col===fe.col&&Sr.row===fe.row));if(wr.length!==1)break;fe=Pe,Pe=wr[0]}return j},m=c[0]?h(c[0]).reverse():[],k=c[1]?h(c[1]):[];return[...m,i,...k]}function mn(i,c){return!!i&&[...new Set([...Array.isArray(i.outDirs)?i.outDirs:[],i.dir].filter(Boolean))].includes(c)}function no(i){let c=0,h=0;for(let k=0;kh?[...i].reverse():i;for(let k=0;k=Math.abs(m)?{col:i.col+Math.sign(h),row:i.row}:{col:i.col,row:i.row+Math.sign(m)}}function oo(i){d=!1,v=i?{col:i.col,row:i.row}:null,C=!1,l=null,Nt(i)}function jt(i){if(!i)return;if(!l)return Nt(i);let c=l,h=0;for(;(c.col!==i.col||c.row!==i.row)&&h<64;){let m=Jt(c,i);if(Nt(m),c=l||m,h+=1,!l)break}}function vn(){!C&&v&&e.conveyorTiles.has($(v.col,v.row))&&yn(v),v=null,C=!1,l=null,d=!1}function u(i){if(!i)return ce(re.fail.outOfGrid);let{col:c,row:h}=i;if(e.buildTool==="conveyor"||e.buildTool==="boostConveyor"){let m=bn(i,null);if(!m.ok)return ce(m.reason||re.fail.cellOccupied);be(e);return}if(N(c,h))return ce("Cannot build on blocked ground.");if(e.buildTool==="manualScanner"||e.buildTool==="autoScanner"?G(c,h):R(c,h))return ce(re.fail.cellOccupied);e.buildTool==="eggFarm"?b(c,h):e.buildTool==="manualScanner"?S(c,h,"manual"):e.buildTool==="autoScanner"&&S(c,h,"auto")}function p(i){let c=We(i.x,i.y);if(["conveyor","boostConveyor","eggFarm","manualScanner","autoScanner"].includes(e.buildTool))return u(c);if(nn.includes(e.buildTool))return w(i,e.buildTool)}function b(i,c){let h=Ne("eggFarm",e);if(e.cashT.kind==="manual").length>=8)return ce("Manual Scanner limit reached (8 max).");let m=h==="auto"?Ne("autoScanner",e):Ne("manualScanner",e);if(e.cashk.id!==c.ref.id),pt(e,m.x,m.y),be(e)}if(c.type==="scanner"){let m=pe(c.ref);E(c,m.x,m.y),e.scanners=e.scanners.filter(k=>k.id!==c.ref.id),pt(e,m.x,m.y),be(e)}if(c.type==="facility"){let m=c.ref;E(c,m.x+m.w/2,m.y+m.h/2),delete e.facilities[m.id],pt(e,m.x+m.w/2,m.y+m.h/2),be(e)}e.selected=null,e.multiSelected=[],s()}function K(i){let c=Object.values(e.facilities).find(j=>{if(i.x>=j.x&&i.x<=j.x+j.w&&i.y>=j.y&&i.y<=j.y+j.h)return!0;if(!j.entry)return!1;let fe=F(j.entry.col,j.entry.row);return Math.abs(i.x-fe.x)<=y.cell*.46&&Math.abs(i.y-fe.y)<=y.cell*.46});if(c)return{type:"facility",ref:c};let h=We(i.x,i.y);if(!h)return null;let m=Tt(e,h.col,h.row);if(m)return{type:"eggFarm",ref:m};let k=Et(e,h.col,h.row);if(k)return{type:"scanner",ref:k};let T=$(h.col,h.row);return e.conveyorTiles.has(T)?{type:"conveyor",oldKey:T,ref:{type:"conveyor",id:T}}:null}let ee=Ms({game:e,canvasPoint:o,updatePanels:s,equipmentAtPoint:K,fail:ce,pointInGrid:W,rectOfFacility:le,rectsOverlap:we});function Xe(i){return null}function ur(){let i=x();i&&(i.type==="conveyor"?D(F(...Object.values(Q(i.id)))):i.type==="eggFarm"?D(F(i.col,i.row)):i.type==="scanner"?D(pe(i)):i.type==="facility"&&D({x:i.x+i.w/2,y:i.y+i.h/2}))}function He(i,c,h="primary-button"){let m=document.createElement("button");return m.type="button",m.className=h,m.textContent=i,m.addEventListener("click",c),m}function Zt(){e.cardTargetPick?.mode==="autoScannerMenu"&&(e.cardTargetPick=null),t.modal.classList.remove("visible","equipment-popover"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function ro(i){t.modalTitle.textContent="Auto Scanner",e.cardTargetPick={pending:!0,mode:"autoScannerMenu",cardId:null,targetKeys:[`scanner:${i.id}`],remaining:1},t.modalBody.innerHTML=`

Left / right output routing for this AUTO scanner.

Current: ${i.role===0?"Male left / others right":"Poop left / others right"}

-

Cooldown: ${Qe(i).toFixed(1)}s.

-
`,t.modalActions.innerHTML="";let c=R("Male Left / Others Right",()=>{Oe(e),i.role=0,V(),s()},i.role===0?"facility-action warn":"facility-action"),h=R("Poop Left / Others Right",()=>{Oe(e),i.role=1,V(),s()},i.role===1?"facility-action warn":"facility-action");t.modalActions.append(c,h,R("Close",V,"facility-action")),Jn(i),t.modal.classList.add("visible","equipment-popover"),s()}function ge(i){return i?.label||i?.key||"?"}function fn(i){let c=i.key===" "?"Space":i.key.length===1?i.key.toUpperCase():i.key.replace(/^Arrow/,"");return{key:i.key.toLowerCase(),code:i.code,label:c}}function Qn(i,c,h){for(let m of e.scanners.filter(T=>T.kind==="manual"))for(let T of["left","right"]){if(m.id===i.id&&T===c)continue;let A=m.keys?.[T];if(A&&(A.code===h.code||A.key===h.key))return!0}return!1}function Qt(i,c=""){if(!i||i.kind!=="manual")return;t.modalTitle.textContent=`Manual Scanner #${i.id}`;let h=ge(i.keys?.left),m=ge(i.keys?.right),T=Ss(i);t.modalBody.innerHTML=` +

Cooldown: ${et(i).toFixed(1)}s.

+ `,t.modalActions.innerHTML="";let c=He("Male Left / Others Right",()=>{$e(e),i.role=0,Zt(),s()},i.role===0?"facility-action warn":"facility-action"),h=He("Poop Left / Others Right",()=>{$e(e),i.role=1,Zt(),s()},i.role===1?"facility-action warn":"facility-action");t.modalActions.append(c,h,He("Close",Zt,"facility-action")),io(i),t.modal.classList.add("visible","equipment-popover"),s()}function dr(i){return i?.label||i?.key||"?"}function Ks(i){let c=i.key===" "?"Space":i.key.length===1?i.key.toUpperCase():i.key.replace(/^Arrow/,"");return{key:i.key.toLowerCase(),code:i.code,label:c}}function Hs(i,c,h){for(let m of e.scanners.filter(k=>k.kind==="manual"))for(let k of["left","right"]){if(m.id===i.id&&k===c)continue;let T=m.keys?.[k];if(T&&(T.code===h.code||T.key===h.key))return!0}return!1}function en(i,c=""){if(!i||i.kind!=="manual")return;t.modalTitle.textContent=`Manual Scanner #${i.id}`;let h=dr(i.keys?.left),m=dr(i.keys?.right),k=qs(i);t.modalBody.innerHTML=`

Left route key: ${h}

Right route key: ${m}

${c?`

${c}

`:""} - ${T?`

${T}

`:""} -
`,t.modalActions.innerHTML="",t.modalActions.appendChild(R("Set Left Key",()=>Jo(i,"left"),"facility-action warn")),t.modalActions.appendChild(R("Set Right Key",()=>Jo(i,"right"),"facility-action warn")),t.modalActions.appendChild(R("Close",V,"facility-action")),Jn(i),t.modal.classList.add("visible","equipment-popover")}function Ss(i){let c=[{side:"left",binding:i.keys?.left},{side:"right",binding:i.keys?.right}];if(c[0].binding&&c[1].binding&&(c[0].binding.code===c[1].binding.code||c[0].binding.key===c[1].binding.key))return"Left and right keys conflict.";for(let h of c)if(h.binding)for(let m of e.scanners.filter(T=>T.kind==="manual"&&T.id!==i.id)){if(m.keys?.left&&(m.keys.left.code===h.binding.code||m.keys.left.key===h.binding.key))return`Key conflicts with Manual Scanner #${m.id} left.`;if(m.keys?.right&&(m.keys.right.code===h.binding.code||m.keys.right.key===h.binding.key))return`Key conflicts with Manual Scanner #${m.id} right.`}return""}function Jo(i,c){t.modalBody.innerHTML=`

Press a key for ${c.toUpperCase()} route.

Esc cancels.

`,t.modalActions.innerHTML="";let h=m=>{if(m.preventDefault(),m.stopPropagation(),window.removeEventListener("keydown",h,!0),m.key==="Escape")return Qt(i);let T=fn(m),A=Qn(i,c,T);Oe(e),i.keys=i.keys||{left:null,right:null},i.keys[c]=T,s(),Qt(i,A?`${T.label} assigned, but another scanner already uses it.`:`${c.toUpperCase()} set to ${T.label}.`)};window.addEventListener("keydown",h,!0)}function Ms(){let i=w();if(!(!i||i.type!=="scanner"))return i.kind==="auto"?Z(i):Qt(i)}function Ts(i){if(!i)return{x:80,y:80};if(i.type==="conveyor"){let c=J(i.id);return $(c.col,c.row)}return i.type==="eggFarm"?$(i.col,i.row):i.type==="scanner"?de(i):i.type==="facility"?{x:i.x+i.w/2,y:i.y+10}:{x:80,y:80}}function Jn(i){let c=n.getBoundingClientRect(),h=Ts(i),m=e.view?.scale||1,T=c.left+(h.x*m+(e.view?.x||0))/n.width*c.width+18,A=c.top+(h.y*m+(e.view?.y||0))/n.height*c.height-12,ne=Math.max(12,window.innerWidth-274),ue=Math.max(12,window.innerHeight-220);t.modal.style.setProperty("--popover-x",`${Math.max(12,Math.min(ne,T))}px`),t.modal.style.setProperty("--popover-y",`${Math.max(12,Math.min(ue,A))}px`)}function Zo(){let i=w();if(!i)return;let c=er(i);t.modalTitle.textContent=C(i),t.modalBody.innerHTML=` -
${c.map(T=>`

${T}

`).join("")}
- ${["mixer","truck"].includes(i.baseId||i.id)?'

Income/Fine = ceil(base x 1.10^upgrades)

':""}`,t.modalActions.innerHTML="",i.type==="scanner"&&i.kind==="auto"&&t.modalActions.appendChild(R("Auto Menu",()=>Z(i),"facility-action warn")),i.type==="scanner"&&i.kind==="manual"&&t.modalActions.appendChild(R("Set Keys",()=>Qt(i),"facility-action warn"));let h=i.type==="conveyor"?{type:"conveyor",oldKey:i.id,ref:i}:{type:i.type,ref:i},m=ve(h);if(m){let T=R(m,()=>{},"facility-action danger disabled");T.disabled=!0,t.modalActions.appendChild(T)}else{let T=gt(h,e),A=T.sameBuild?`Remove / Refund ${S(T.amount)}`:`Sell ${S(T.amount)}`;t.modalActions.appendChild(R(A,()=>{P(),V()},"facility-action danger"))}Jn(i),t.modal.classList.add("visible","equipment-popover")}function gs(i){e.phase==="build"&&(dn(),e.buildTool=e.buildTool===i?null:i,e.selected=null,e.multiSelected=[],e.selectionBox=null,s())}function Es(){let i=[];for(let[c,h]of Object.entries(e.facilities))if(i.push({id:`facility:${c}`,price:O({type:"facility",ref:h}),x:h.x,y:h.y,w:h.w,h:h.h}),h.entry){let m=$(h.entry.col,h.entry.row);i.push({id:`facilityPort:${c}`,price:O({type:"facility",ref:h}),x:m.x-18,y:m.y-18,w:36,h:36})}for(let c of e.eggFarms){let h=$(c.col,c.row);i.push({id:`eggFarm:${c.id}`,price:O({type:"eggFarm",ref:c}),x:h.x-24,y:h.y-24,w:48,h:48})}for(let c of e.scanners){let h=de(c);i.push({id:`scanner:${c.id}`,price:O({type:"scanner",ref:c}),x:h.x-50,y:h.y-73,w:100,h:146})}for(let c of e.conveyorTiles){let h=J(c),m=$(h.col,h.row),T=e.conveyorMeta.get(c)||{};i.push({id:`conveyor:${c}`,price:T.price||Be(T.kind==="boostConveyor"?"boostConveyor":"conveyor",e),x:m.x-22,y:m.y-22,w:44,h:44})}return i}function pn(i){return L[i]||L.random}function nc(i){return nr(i)}function nr(i){if(!e.conveyorTiles.has(i))return[];let c=J(i),h=xe(c);return rn(c)?h:h.length?h:qe(i)}function Zn(i){return e.conveyorTiles.has(i)?rn(J(i)):!1}function jo(i){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return null;for(let c of e.conveyorTiles){if(!Zn(c))continue;let h=J(c),m=$(h.col,h.row),T=m.x-F.w/2,A=m.y+F.y-F.h/2;if(i.x>=T&&i.x<=T+F.w&&i.y>=A&&i.y<=A+F.h)return c}return null}function Ps(i){let c=jo(i);return c?(jn(c),!0):!1}function jn(i){let c=e.conveyorMeta.get(i);if(!c)return!1;let h=nr(i),m=J(i),T=new Set(h.filter(ne=>ut(m,ne))),A=h.filter(ne=>{let ue=new Set(T);return ue.add(ne),h.filter(ke=>!ue.has(ke)).length>=2});if(A.length<2)return!1;Oe(e);let ne=D.includes(c.branchMode)?c.branchMode:"random",ue=["random",...pe.map(ke=>ke.name).filter(ke=>A.includes(ke))];c.branchMode=ue[(Math.max(0,ue.indexOf(ne))+1)%ue.length],e.selected=null,e.multiSelected=[];return s(),!0}function er(i){ye(e);let c=[],h=i?.type==="facility"?i.baseId||i.id:"";if(i.type==="eggFarm"){let[m,T]=en(i);c.push(`Price: ${S(O(i))}`);{let A=ve({type:i.type,ref:i});c.push(A?`Sale: blocked (${A})`:`Sale value: ${S(gt({type:i.type,ref:i},e).amount)}`)}c.push(`Level: ${i.level}/4`),c.push(`Random interval: ${m.toFixed(2)}-${T.toFixed(2)}s`),c.push(`Durability: ${ln(i)}% | Spawn delay x${Ln(i).toFixed(2)}`)}else if(i.type==="scanner")c.push(`Price: ${S(O(i))}`),c.push(`Sale value: ${S(gt({type:i.type,ref:i},e).amount)}`),c.push(`Type: ${i.kind.toUpperCase()} / Standard`),i.kind==="auto"&&c.push(`Role: ${i.role===0?"Male left / Others right":"Poop left / Others right"}`),c.push(`Queue: ${i.queue.length}`),i.kind==="auto"&&c.push(`Cooldown: ${i.cooldown.toFixed(1)}s / ${Qe(i,e).toFixed(1)}s`),i.kind==="auto"&&c.push(`Durability: ${ln(i)}% | Delay x${Bn(i).toFixed(2)}`),i.kind==="manual"&&c.push("Durability: none | Always normal");else if(i.type==="conveyor"){let m=e.conveyorMeta.get(i.id),T=e.componentLookup?.get(i.id),A=T?e.congestion.get(T):null;c.push(`Price: ${S(O({type:"conveyor",oldKey:i.id,ref:i}))}`),c.push(`Cell: ${i.id}`),c.push(`Type: ${m?.kind==="boostConveyor"?"BOOST BELT":"Normal Belt"} | Speed x${Number(m?.speedMultiplier||1).toFixed(1)}`),c.push(`Congestion: ${A?Math.floor(A.ratio*100):0}%`),c.push(`Durability: ${ln({meta:m})}% | Speed x${Fn({meta:m}).toFixed(2)}`),Zn(i.id)?(c.push(`Branch mode: ${pn(m?.branchMode||"random")}`),c.push("Use the Branch button below or the on-belt branch badge.")):c.push("Branch mode: needs 3+ conveyor connections."),c.push(`Sale value: ${S(gt({type:"conveyor",oldKey:i.id,ref:i},e).amount)}`)}else if(i.type==="facility"){c.push(`Price: ${S(O(i))}`);{let m=ve({type:i.type,ref:i});c.push(m?`Sale: blocked (${m})`:`Sale value: ${S(gt({type:i.type,ref:i},e).amount)}`)}if(c.push(["mixer","truck","trash"].includes(i.id)?`Level: ${i.level} / no cap`:`Level: ${i.level}`),h==="truck"&&c.push("Durability: none | Always normal"),["mixer","trash"].includes(h)&&c.push(`Durability: ${ln(i)}% | Extra delay ${Bo(e,i).toFixed(2)}s`),h==="mixer"&&(c.push(`Income: ${S(_e(e))} per chick | upgrade x${nt(e,"mixer").toFixed(3)}`),c.push(`Poop fine: -${S(nn(e))}`)),h==="truck"&&(c.push(`Income: ${S(Le(e))} per target cargo | upgrade x${nt(e,"truck").toFixed(3)}`),c.push(`Poop shipment fine: -${S(on(e))}`)),h==="trash"){let m=Tt(e),T=ot(m);c.push(`Bonus cards: ${m}/${Gt()}`),c.push(`Bonus chance: ${(T*100).toFixed(2)}% for ${S(1)} per processed item.`),c.push(`Expected value: ${T.toFixed(3)} JPY per item.`)}i.entry&&c.push(`Receiver: edge cell ${i.entry.col},${i.entry.row} (${i.side})`)}return c}function Rs(i){if(!i||e.phase!=="build")return"";let c=gn(e).find(h=>h.type===i.type&&h.id===i.id);return c?c.message||"Not connected to conveyor route":""}function Ds(i){return i?i.type==="conveyor"&&e.conveyorMeta.get(i.id)?.kind==="boostConveyor"?"Moves chicks twice as fast. Wears down like a normal belt.":i.type==="conveyor"?"A stubborn belt tile. It only cares about the next cell.":i.type==="eggFarm"?"A tiny gatehouse producing questionable eggs on schedule.":i.type==="scanner"&&i.kind==="auto"?"Slower than hands without upgrades.":i.type==="scanner"?"A manual checkpoint. The operator is the algorithm.":i.type==="facility"&&(i.baseId||i.id)==="mixer"?"Male chicks become revenue here. Do not feed it poop.":i.type==="facility"&&(i.baseId||i.id)==="trash"?"Poop goes in. Sometimes coins come out, for reasons best left unaudited.":i.type==="facility"&&(i.baseId||i.id)==="truck"?"The shipping endpoint. Correct cargo pays; wrong cargo complains.":"Factory equipment.":""}return{buildAtCell:Vt,buildAtPoint:Xt,eraseAtPoint:p,equipmentAtPoint:b,startSelectionBox:x.startSelectionBox,updateSelectionBox:x.updateSelectionBox,finishSelectionBox:x.finishSelectionBox,startGroupDrag:x.startGroupDrag,updateGroupDrag:x.updateGroupDrag,finishGroupDrag:x.finishGroupDrag,selectedObject:w,selectedTitle:C,equipmentPrice:O,selectedUpgradeCost:v,selectedInfoLines:er,flavorText:Ds,disconnectedWarningFor:Rs,gridExpansionCost:z,buyGridExpansion:g,expansionOfferAtPoint:he,beginConveyorDrag:zn,continueConveyorDrag:$t,endConveyorDrag:dn,cycleSingleConveyorDirection:cn,branchSwitcherAtPoint:jo,cycleBranchModeAtPoint:Ps,cycleBranchModeForKey:jn,removeSelected:P,switchScannerRole:Ms,showManualScannerMenu:Qt,showAutoScannerMenu:Z,showSelectedMenu:Zo,setBuildTool:gs,fail:ce,isEquipmentCell:E,equipmentHitBoxes:Es,routeFromFarmToScanner:Mt}}function ss({game:e,ui:t,build:n,startGame:o,beginCardDraft:r,activeQueuedChick:s}){function l(E){return String(E).replace(/[&<>"']/g,G=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[G])}function d(){return Math.round(Gn(e))}function k(){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return!1;let E=!1;for(let G of no)if(E=!0,e.cash>=Be(G,e))return!1;return E}function M(){D(),L(),oe(),z(),F()}function D(){for(let[G,w]of Object.entries(t.buttons))w?.classList?.contains("tool-button")&&w.classList.toggle("active",e.buildTool===G);for(let G of no){let w=t.buttons[G];if(!w)continue;let C=Be(G,e),O=w.querySelector("span");O&&(O.textContent=G==="conveyor"||G==="boostConveyor"?`${S(C)} / tile`:S(C));let Y=G==="manualScanner"&&e.scanners.filter(se=>se.kind==="manual").length>=8,te=e.cashMt(e,ve)?.scannerId).length,G=tn(e),w=Math.max(0,Math.floor(e.lastResult?.profit??e.stats?.profit??0)),C=Pn(w,e),O=e.phase==="running"?Math.max(1,(e.totals.turnsCompleted||0)+1):Math.max(1,Number(e.turn)||1),Y=So(e,O),te=e.lastBuildFees?.turn===O?e.lastBuildFees.fairiesTribute||0:null,se=e.lastBuildFees?.turn===O&&e.lastBuildFees.reduction||0;t.turnSummary.innerHTML=[`Seed: ${l(e.runSeed||"none")} | Grid box: ${e.gridRows||10}x${e.gridCols||20} | Owned: ${e.gridOwnedCells||e.ownedCells?.size||(e.gridRows||10)*(e.gridCols||20)} cells | Blocked: ${e.blockedCells?.size||0} cells`,`Truck target: ${ze(e).toUpperCase()} | Male fine: -${S(Co(e))}`,`Poop fine: Mixer -${S(nn(e))} / Shipment -${S(on(e))}`,`ZUNDA TAX on Next Day: -${S(C.tax)} | basis net ${S(w)} | taxable ${S(C.taxable)} x${C.ratePercent}% | exemption ${S(C.exemption)} | 95% at ${S(C.maxRateCash)}`,te!=null?`Fairies tribute paid before Build: -${S(te)}${se?` | Flattery -${S(se)}`:""}`:`Fairies tribute before Build: -${S(Y.amount)}${Y.reduction?` | Flattery -${S(Y.reduction)}`:""}`,`Maintenance: worst ${No(e).worst.percent}% dirty (${No(e).worst.label}) | Repairman: ${e.repairman?.hiredForNextDay?"hired next day":e.repairman?.active?"working":"none"}`,`Manual combo: ${e.manualCombo?.count||0} | Card draft: ${e.cardDraft?.pending?Math.max(1,e.cardDraft.picksRemaining||1)+" pick(s) left":"ready after each day"} | Belt: ${d()}px/s | Farms with scanner route: ${E}/${e.eggFarms.length}`,e.cardEffects?.usedMachineActive?'Procurement: USED MACHINE MODE / no refunds / 60% durability':"",G.length?`Blocked: ${G[0]}`:`${re.status.allPortsConnected}`].join("
")}function oe(){if(!t.contractPanel)return;let E=e.contractOffer;if(e.phase!=="build"){t.contractPanel.innerHTML=re.status.eventPanelRunning;return}if(!E){t.contractPanel.className="contract-card empty",e.turn+1Event lock active.No irregular events during Days 1-7. First possible forced event: Day ${ft}.`:t.contractPanel.innerHTML="No event.Random forced events can appear later.";return}t.contractPanel.className="contract-card accepted",t.contractPanel.innerHTML=` -
FORCED NEXT DAY
-

${E.title}

-
- Route: ${E.route} - Target: ${E.targetAmount} truck exports - Reward: ${S(E.reward)} - Output x${E.productionMultiplier} / Poop x${E.poopMultiplier} -
`}function X(){D(),t.shell.classList.toggle("phase-running",e.phase==="running"),t.shell.classList.toggle("phase-build",e.phase==="build"),t.shell.classList.toggle("phase-gameover",e.phase==="gameover"),t.shell.classList.toggle("phase-title",e.phase==="title"),t.shell.classList.toggle("phase-loanDecision",e.phase==="loanDecision"),t.money.textContent=S(e.cash),t.money.classList.toggle("cash-negative",e.cash<0),t.money.classList.toggle("cash-positive",e.cash>Jt),t.turn.textContent=e.turn,t.timeLeft.textContent=e.phase==="running"&&e.timeLeft<=0&&e.shutdownTimeLeft>0?`+${e.shutdownTimeLeft.toFixed(1)}s`:`${Math.max(0,e.timeLeft).toFixed(1)}s`,t.timeLeft.closest?.(".hud-card")?.classList.toggle("time-critical",e.phase==="running"&&(e.timeLeft<=10||e.timeLeft<=0&&e.shutdownTimeLeft>0)),t.phase.textContent=he(),t.comboCount&&(t.comboCount.textContent=e.manualCombo?.count||0),ae(),t.turnProfit.textContent=S(e.stats.profit),t.turnProfit.classList.toggle("cash-negative",e.stats.profit<0),t.turnProfit.classList.toggle("cash-positive",e.stats.profit>0),t.mixerCount.textContent=e.stats.mixerCount,t.truckFemaleCount.textContent=e.stats.truckFemale,t.truckMaleCount.textContent=e.stats.truckMale,t.poopCount.textContent=e.stats.poopSpawned,t.buttons.s1Left.disabled=e.phase!=="running"||!s(0),t.buttons.s1Right.disabled=e.phase!=="running"||!s(0),t.buttons.s2Left.disabled=e.phase!=="running"||!s(1),t.buttons.s2Right.disabled=e.phase!=="running"||!s(1);let E=e.scanners.find(C=>C.kind==="manual"&&C.slot===0),G=e.scanners.find(C=>C.kind==="manual"&&C.slot===1);E&&(t.buttons.s1Left.textContent=`S1 ${E.keys?.left?.label||"A"} -> Mixer`,t.buttons.s1Right.textContent=`S1 ${E.keys?.right?.label||"D"} -> S2`),G&&(t.buttons.s2Left.textContent=`S2 ${G.keys?.left?.label||"Left"} -> Waste`,t.buttons.s2Right.textContent=`S2 ${G.keys?.right?.label||"Right"} -> Truck`);let w=Pn(Math.max(0,Math.floor(e.lastResult?.profit??e.stats?.profit??0)),e).tax;t.buttons.nextTurn.textContent=e.phase==="build"&&w>0?`Next Day - ZUNDA ${S(w)}`:re.actions.nextDay,t.buttons.nextTurn.disabled=e.phase!=="build"||!!e.cardDraft?.pending||!!e.cardTargetPick?.pending||!Wr(e)}function ae(){if(!t.eventBrief||!t.targetBrief||!t.speedBrief)return;let E=ze(e).toUpperCase();t.targetBrief.textContent=`TRUCK TARGET: ${E}`,t.speedBrief.textContent=`BELT: ${d()} px/s | COMBO: ${e.manualCombo?.count||0}`,t.speedBrief.title=`Conveyor speed does not increase by day. Degraded belts reduce speed. Cap: ${Lt}px/s.`;let G=e.contractActive,w=e.contractOffer;G?(t.eventBrief.textContent=`ACTIVE EVENT: ${G.route} | Output x${G.productionMultiplier} | Poop x${G.poopMultiplier}`,t.eventBrief.className="event-brief active"):e.phase==="build"&&w?(t.eventBrief.textContent=`NEXT DAY EVENT: ${w.route} | Target ${w.targetAmount} | Reward ${S(w.reward)}`,t.eventBrief.className="event-brief next"):e.phase==="build"&&e.turn+1
\u2642Male->MixerS1: A
\u2640Female->TruckS1: D, then S2: right
\u{1F4A9}Poop->ShredderS1: D, then S2: left

Build phase: connect at least one EGG through a scanner to Mixer, Shredder, or Truck before Next Day. One day is one run.

',t.modalActions.innerHTML="",t.modalActions.appendChild(le(re.actions.startGame,o,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function g(E){let G=Y=>`${Y>0?"+":""}${S(Y)}`,w=Y=>`${Y>0?"-":""}${S(Y)}`,C=E.profit>=0?"cash-positive":"cash-negative",O=(E.mixerPoopFine||0)+(E.truckPoopFine||0)+(E.maleTruckFine||0)+(E.explosionDamage||0)+(E.cardRerollCost||0);t.modalTitle.textContent=`Day ${E.turn} Settlement`,t.modalBody.innerHTML=` -
Net result${S(E.profit)}
+ ${k?`

${k}

`:""} + `,t.modalActions.innerHTML="",t.modalActions.appendChild(He("Set Left Key",()=>fr(i,"left"),"facility-action warn")),t.modalActions.appendChild(He("Set Right Key",()=>fr(i,"right"),"facility-action warn")),t.modalActions.appendChild(He("Close",Zt,"facility-action")),io(i),t.modal.classList.add("visible","equipment-popover")}function qs(i){let c=[{side:"left",binding:i.keys?.left},{side:"right",binding:i.keys?.right}];if(c[0].binding&&c[1].binding&&(c[0].binding.code===c[1].binding.code||c[0].binding.key===c[1].binding.key))return"Left and right keys conflict.";for(let h of c)if(h.binding)for(let m of e.scanners.filter(k=>k.kind==="manual"&&k.id!==i.id)){if(m.keys?.left&&(m.keys.left.code===h.binding.code||m.keys.left.key===h.binding.key))return`Key conflicts with Manual Scanner #${m.id} left.`;if(m.keys?.right&&(m.keys.right.code===h.binding.code||m.keys.right.key===h.binding.key))return`Key conflicts with Manual Scanner #${m.id} right.`}return""}function fr(i,c){t.modalBody.innerHTML=`

Press a key for ${c.toUpperCase()} route.

Esc cancels.

`,t.modalActions.innerHTML="";let h=m=>{if(m.preventDefault(),m.stopPropagation(),window.removeEventListener("keydown",h,!0),m.key==="Escape")return en(i);let k=Ks(m),T=Hs(i,c,k);$e(e),i.keys=i.keys||{left:null,right:null},i.keys[c]=k,s(),en(i,T?`${k.label} assigned, but another scanner already uses it.`:`${c.toUpperCase()} set to ${k.label}.`)};window.addEventListener("keydown",h,!0)}function Ys(){let i=x();if(!(!i||i.type!=="scanner"))return i.kind==="auto"?ro(i):en(i)}function Vs(i){if(!i)return{x:80,y:80};if(i.type==="conveyor"){let c=Q(i.id);return F(c.col,c.row)}return i.type==="eggFarm"?F(i.col,i.row):i.type==="scanner"?pe(i):i.type==="facility"?{x:i.x+i.w/2,y:i.y+10}:{x:80,y:80}}function io(i){let c=n.getBoundingClientRect(),h=Vs(i),m=e.view?.scale||1,k=c.left+(h.x*m+(e.view?.x||0))/n.width*c.width+18,T=c.top+(h.y*m+(e.view?.y||0))/n.height*c.height-12,j=Math.max(12,window.innerWidth-274),ie=Math.max(12,window.innerHeight-220);t.modal.style.setProperty("--popover-x",`${Math.max(12,Math.min(j,k))}px`),t.modal.style.setProperty("--popover-y",`${Math.max(12,Math.min(ie,T))}px`)}function zs(){let i=x();if(!i)return;let c=mr(i);t.modalTitle.textContent=g(i),t.modalBody.innerHTML=` +
${c.map(k=>`

${k}

`).join("")}
+ ${["mixer","truck"].includes(i.baseId||i.id)?'

Income/Fine = ceil(base x 1.10^upgrades)

':""}`,t.modalActions.innerHTML="",i.type==="scanner"&&i.kind==="auto"&&t.modalActions.appendChild(He("Auto Menu",()=>ro(i),"facility-action warn")),i.type==="scanner"&&i.kind==="manual"&&t.modalActions.appendChild(He("Set Keys",()=>en(i),"facility-action warn"));let h=i.type==="conveyor"?{type:"conveyor",oldKey:i.id,ref:i}:{type:i.type,ref:i},m=ge(h);if(m){let k=He(m,()=>{},"facility-action danger disabled");k.disabled=!0,t.modalActions.appendChild(k)}else{let k=Dt(h,e),T=k.sameBuild?`Remove / Refund ${M(k.amount)}`:`Sell ${M(k.amount)}`;t.modalActions.appendChild(He(T,()=>{ur(),Zt()},"facility-action danger"))}io(i),t.modal.classList.add("visible","equipment-popover")}function Xs(i){e.phase==="build"&&(vn(),e.buildTool=e.buildTool===i?null:i,e.selected=null,e.multiSelected=[],e.selectionBox=null,s())}function Qs(){let i=[];for(let[c,h]of Object.entries(e.facilities))if(i.push({id:`facility:${c}`,price:O({type:"facility",ref:h}),x:h.x,y:h.y,w:h.w,h:h.h}),h.entry){let m=F(h.entry.col,h.entry.row);i.push({id:`facilityPort:${c}`,price:O({type:"facility",ref:h}),x:m.x-18,y:m.y-18,w:36,h:36})}for(let c of e.eggFarms){let h=F(c.col,c.row);i.push({id:`eggFarm:${c.id}`,price:O({type:"eggFarm",ref:c}),x:h.x-24,y:h.y-24,w:48,h:48})}for(let c of e.scanners){let h=pe(c);i.push({id:`scanner:${c.id}`,price:O({type:"scanner",ref:c}),x:h.x-50,y:h.y-73,w:100,h:146})}for(let c of e.conveyorTiles){let h=Q(c),m=F(h.col,h.row),k=e.conveyorMeta.get(c)||{};i.push({id:`conveyor:${c}`,price:k.price||Ne(k.kind==="boostConveyor"?"boostConveyor":"conveyor",e),x:m.x-22,y:m.y-22,w:44,h:44})}return i}function Js(i){return A[i]||A.random}function Ec(i){return it(i)}function pr(i){return e.conveyorTiles.has(i)?Be(Q(i)):!1}function yr(i){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return null;for(let c of e.conveyorTiles){if(!pr(c))continue;let h=Q(c),m=F(h.col,h.row),k=m.x-L.w/2,T=m.y+L.y-L.h/2;if(i.x>=k&&i.x<=k+L.w&&i.y>=T&&i.y<=T+L.h)return c}return null}function js(i){let c=yr(i);return c?(hr(c),!0):!1}function hr(i){let c=e.conveyorMeta.get(i);if(!c)return!1;let h=eo(i);if(h.length<2)return!1;$e(e);let m=P.includes(c.branchMode)?c.branchMode:"random",k=["random",...ue.map(T=>T.name).filter(T=>h.includes(T))];return c.branchMode=k[(Math.max(0,k.indexOf(m))+1)%k.length],e.selected=null,e.multiSelected=[],s(),!0}function mr(i){me(e);let c=[],h=i?.type==="facility"?i.baseId||i.id:"";if(i.type==="eggFarm"){let[m,k]=rn(i);c.push(`Price: ${M(O(i))}`);{let T=ge({type:i.type,ref:i});c.push(T?`Sale: blocked (${T})`:`Sale value: ${M(Dt({type:i.type,ref:i},e).amount)}`)}c.push(`Level: ${i.level}/4`),c.push(`Random interval: ${m.toFixed(2)}-${k.toFixed(2)}s`),c.push(`Durability: ${dn(i)}% | Spawn delay x${_n(i).toFixed(2)}`)}else if(i.type==="scanner")c.push(`Price: ${M(O(i))}`),c.push(`Sale value: ${M(Dt({type:i.type,ref:i},e).amount)}`),c.push(`Type: ${i.kind.toUpperCase()} / Standard`),i.kind==="auto"&&c.push(`Role: ${i.role===0?"Male left / Others right":"Poop left / Others right"}`),c.push(`Queue: ${i.queue.length}`),i.kind==="auto"&&c.push(`Cooldown: ${i.cooldown.toFixed(1)}s / ${et(i,e).toFixed(1)}s`),i.kind==="auto"&&c.push(`Durability: ${dn(i)}% | Delay x${Wn(i).toFixed(2)}`),i.kind==="manual"&&c.push("Durability: none | Always normal");else if(i.type==="conveyor"){let m=e.conveyorMeta.get(i.id),k=e.componentLookup?.get(i.id),T=k?e.congestion.get(k):null;c.push(`Price: ${M(O({type:"conveyor",oldKey:i.id,ref:i}))}`),c.push(`Cell: ${i.id}`),c.push(`Type: ${m?.kind==="boostConveyor"?"BOOST BELT":"Normal Belt"} | Speed x${Number(m?.speedMultiplier||1).toFixed(1)}`),c.push(`Congestion: ${T?Math.floor(T.ratio*100):0}%`),c.push(`Durability: ${dn({meta:m})}% | Speed x${Un({meta:m}).toFixed(2)}`),pr(i.id)?(c.push(`Branch mode: ${Js(m?.branchMode||"random")}`),c.push("Use the Branch button below or the on-belt branch badge.")):c.push("Branch mode: needs 3+ conveyor connections."),c.push(`Sale value: ${M(Dt({type:"conveyor",oldKey:i.id,ref:i},e).amount)}`)}else if(i.type==="facility"){c.push(`Price: ${M(O(i))}`);{let m=ge({type:i.type,ref:i});c.push(m?`Sale: blocked (${m})`:`Sale value: ${M(Dt({type:i.type,ref:i},e).amount)}`)}if(c.push(["mixer","truck","trash"].includes(i.id)?`Level: ${i.level} / no cap`:`Level: ${i.level}`),h==="truck"&&c.push("Durability: none | Always normal"),["mixer","trash"].includes(h)&&c.push(`Durability: ${dn(i)}% | Extra delay ${Vo(e,i).toFixed(2)}s`),h==="mixer"&&(c.push(`Income: ${M(qe(e))} per chick | upgrade x${ct(e,"mixer").toFixed(3)}`),c.push(`Poop fine: -${M(ln(e))}`)),h==="truck"&&(c.push(`Income: ${M(De(e))} per target cargo | upgrade x${ct(e,"truck").toFixed(3)}`),c.push(`Poop shipment fine: -${M(an(e))}`)),h==="trash"){let m=At(e),k=ut(m);c.push(`Bonus cards: ${m}/${Kt()}`),c.push(`Poop income bonus: ${M(k)} per processed poop.`),c.push("With enough upgrades, poop can out-earn male/female routes.")}i.entry&&c.push(`Receiver: edge cell ${i.entry.col},${i.entry.row} (${i.side})`)}return c}function Zs(i){if(!i||e.phase!=="build")return"";let c=Dn(e).find(h=>h.type===i.type&&h.id===i.id);return c?c.message||"Not connected to conveyor route":""}function el(i){return i?i.type==="conveyor"&&e.conveyorMeta.get(i.id)?.kind==="boostConveyor"?"Moves chicks twice as fast. Wears down like a normal belt.":i.type==="conveyor"?"A stubborn belt tile. It only cares about the next cell.":i.type==="eggFarm"?"A tiny gatehouse producing questionable eggs on schedule.":i.type==="scanner"&&i.kind==="auto"?"Slower than hands without upgrades.":i.type==="scanner"?"A manual checkpoint. The operator is the algorithm.":i.type==="facility"&&(i.baseId||i.id)==="mixer"?"Male chicks become revenue here. Do not feed it poop.":i.type==="facility"&&(i.baseId||i.id)==="trash"?"Poop goes in. Sometimes coins come out, for reasons best left unaudited.":i.type==="facility"&&(i.baseId||i.id)==="truck"?"The shipping endpoint. Correct cargo pays; wrong cargo complains.":"Factory equipment.":""}return{buildAtCell:u,buildAtPoint:p,eraseAtPoint:D,equipmentAtPoint:K,startSelectionBox:ee.startSelectionBox,updateSelectionBox:ee.updateSelectionBox,finishSelectionBox:ee.finishSelectionBox,startGroupDrag:ee.startGroupDrag,updateGroupDrag:ee.updateGroupDrag,finishGroupDrag:ee.finishGroupDrag,selectedObject:x,selectedTitle:g,equipmentPrice:O,selectedUpgradeCost:Xe,selectedInfoLines:mr,flavorText:el,disconnectedWarningFor:Zs,gridExpansionCost:V,buyGridExpansion:I,expansionOfferAtPoint:ye,beginConveyorDrag:oo,continueConveyorDrag:jt,endConveyorDrag:vn,cycleSingleConveyorDirection:yn,branchSwitcherAtPoint:yr,cycleBranchModeAtPoint:js,cycleBranchModeForKey:hr,removeSelected:ur,switchScannerRole:Ys,showManualScannerMenu:en,showAutoScannerMenu:ro,showSelectedMenu:zs,setBuildTool:Xs,fail:ce,isEquipmentCell:R,equipmentHitBoxes:Qs,routeFromFarmToScanner:Rt}}function Ts({game:e,ui:t,build:n,startGame:o,beginCardDraft:r,activeQueuedChick:s}){function l(R){return String(R).replace(/[&<>"']/g,G=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[G])}function d(){return Math.round(Yn(e))}function v(){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return!1;let R=!1;for(let G of fo)if(R=!0,e.cash>=Ne(G,e))return!1;return R}function C(){P(),A(),ne(),V(),L()}function P(){for(let[G,x]of Object.entries(t.buttons))x?.classList?.contains("tool-button")&&x.classList.toggle("active",e.buildTool===G);for(let G of fo){let x=t.buttons[G];if(!x)continue;let g=Ne(G,e),O=x.querySelector("span");O&&(O.textContent=G==="conveyor"||G==="boostConveyor"?`${M(g)} / tile`:M(g));let X=G==="manualScanner"&&e.scanners.filter(de=>de.kind==="manual").length>=8,oe=e.cashRt(e,X)?.scannerId).length,G=sn(e),x=Math.max(0,Math.floor(e.lastResult?.profit??e.stats?.profit??0)),g=Math.max(1,Number(e.turn)||1),O=Fn(e,g,x);t.turnSummary.innerHTML=[`Seed: ${l(e.runSeed||"none")} | Grid box: ${e.gridRows||10}x${e.gridCols||20} | Owned: ${e.gridOwnedCells||e.ownedCells?.size||(e.gridRows||10)*(e.gridCols||20)} cells | Blocked: ${e.blockedCells?.size||0} cells`,`Truck target: ${Je(e).toUpperCase()} | Male fine: -${M(Fo(e))}`,`Poop fine: Mixer -${M(ln(e))} / Shipment -${M(an(e))}`,`Fairies tribute on Next Day: -${M(O.amount)} | base ${M(O.base)} + profit share ${M(O.profitTribute)} | basis net ${M(x)} | exemption ${M(O.profitExemption)}${O.reduction?` | reduction -${M(O.reduction)}`:""}`,`Maintenance: worst ${Qo(e).worst.percent}% dirty (${Qo(e).worst.label}) | Repairman: ${e.repairman?.hiredForNextDay?"hired next day":e.repairman?.active?"working":"none"}`,`Manual combo: ${e.manualCombo?.count||0} | Card draft: ${e.cardDraft?.pending?Math.max(1,e.cardDraft.picksRemaining||1)+" pick(s) left":"ready after each day"} | Belt: ${d()}px/s | Farms with scanner route: ${R}/${e.eggFarms.length}`,e.cardEffects?.usedMachineActive?'Procurement: USED MACHINE MODE / no refunds / 60% durability':"",G.length?`Blocked: ${G[0]}`:`${re.status.allPortsConnected}`].join("
")}function ne(){if(!t.eventPanel)return;let R=e.eventOffer;if(e.phase!=="build"){t.eventPanel.innerHTML=re.status.eventPanelRunning;return}if(!R){t.eventPanel.className="event-card empty",e.turn+1Event lock active.No irregular events during Days 1-7. First possible forced event: Day ${wt}.`:t.eventPanel.innerHTML="No event.Random forced events can appear later.";return}t.eventPanel.className="event-card accepted",t.eventPanel.innerHTML=` +
FORCED NEXT DAY
+

${R.title}

+
+ Effect: ${R.route} + ${R.targetAmount?`Target: ${R.targetAmount}`:"Target: none"} + ${R.reward?`Reward: ${M(R.reward)}`:"Reward: none"} + Time ${R.daySeconds||60}s / Output x${Number(R.productionMultiplier||1).toFixed(2)} / Poop +${Math.round((R.poopRateAdd||0)*100)}pt +
`}function z(){P(),t.shell.classList.toggle("phase-running",e.phase==="running"),t.shell.classList.toggle("phase-build",e.phase==="build"),t.shell.classList.toggle("phase-gameover",e.phase==="gameover"),t.shell.classList.toggle("phase-title",e.phase==="title"),t.shell.classList.toggle("phase-loanDecision",e.phase==="loanDecision"),t.money.textContent=M(e.cash),t.money.classList.toggle("cash-negative",e.cash<0),t.money.classList.toggle("cash-positive",e.cash>tn),t.turn.textContent=e.turn,t.timeLeft.textContent=e.phase==="running"&&e.timeLeft<=0&&e.shutdownTimeLeft>0?`+${e.shutdownTimeLeft.toFixed(1)}s`:`${Math.max(0,e.timeLeft).toFixed(1)}s`,t.timeLeft.closest?.(".hud-card")?.classList.toggle("time-critical",e.phase==="running"&&(e.timeLeft<=10||e.timeLeft<=0&&e.shutdownTimeLeft>0)),t.phase.textContent=ye(),t.comboCount&&(t.comboCount.textContent=e.manualCombo?.count||0),se(),t.turnProfit.textContent=M(e.stats.profit),t.turnProfit.classList.toggle("cash-negative",e.stats.profit<0),t.turnProfit.classList.toggle("cash-positive",e.stats.profit>0),t.mixerCount.textContent=e.stats.mixerCount,t.truckFemaleCount.textContent=e.stats.truckFemale,t.truckMaleCount.textContent=e.stats.truckMale,t.poopCount.textContent=e.stats.poopSpawned,t.buttons.s1Left.disabled=e.phase!=="running"||!s(0),t.buttons.s1Right.disabled=e.phase!=="running"||!s(0),t.buttons.s2Left.disabled=e.phase!=="running"||!s(1),t.buttons.s2Right.disabled=e.phase!=="running"||!s(1);let R=e.scanners.find(O=>O.kind==="manual"&&O.slot===0),G=e.scanners.find(O=>O.kind==="manual"&&O.slot===1);R&&(t.buttons.s1Left.textContent=`S1 ${R.keys?.left?.label||"A"} -> Mixer`,t.buttons.s1Right.textContent=`S1 ${R.keys?.right?.label||"D"} -> S2`),G&&(t.buttons.s2Left.textContent=`S2 ${G.keys?.left?.label||"Left"} -> Waste`,t.buttons.s2Right.textContent=`S2 ${G.keys?.right?.label||"Right"} -> Truck`);let x=Math.max(0,Math.floor(e.lastResult?.profit??e.stats?.profit??0)),g=Fn(e,Math.max(1,Number(e.turn)||1),x).amount;t.buttons.nextTurn.textContent=e.phase==="build"&&g>0?`Next Day - Fairies ${M(g)}`:re.actions.nextDay,t.buttons.nextTurn.disabled=e.phase!=="build"||!!e.cardDraft?.pending||!!e.cardTargetPick?.pending||!ii(e)}function se(){if(!t.eventBrief||!t.targetBrief||!t.speedBrief)return;let R=Je(e).toUpperCase();t.targetBrief.textContent=`TRUCK TARGET: ${R}`,t.speedBrief.textContent=`BELT: ${d()} px/s | COMBO: ${e.manualCombo?.count||0}`,t.speedBrief.title=`Conveyor speed does not increase by day. Degraded belts reduce speed. Cap: ${Gt}px/s.`;let G=e.eventActive,x=e.eventOffer;G?(t.eventBrief.textContent=`ACTIVE EVENT: ${G.title} | ${G.route}`,t.eventBrief.className="event-brief active"):e.phase==="build"&&x?(t.eventBrief.textContent=`NEXT DAY EVENT: ${x.title} | ${x.route}${x.targetAmount?` | Target ${x.targetAmount}`:""}${x.reward?` | Reward ${M(x.reward)}`:""}`,t.eventBrief.className="event-brief next"):e.phase==="build"&&e.turn+1
\u2642Male->MixerS1: A
\u2640Female->TruckS1: D, then S2: right
\u{1F4A9}Poop->ShredderS1: D, then S2: left

Build phase: connect at least one EGG through a scanner to Mixer, Shredder, or Truck before Next Day. One day is one run.

',t.modalActions.innerHTML="",t.modalActions.appendChild(le(re.actions.startGame,o,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function I(R){let G=X=>`${X>0?"+":""}${M(X)}`,x=X=>`${X>0?"-":""}${M(X)}`,g=R.profit>=0?"cash-positive":"cash-negative",O=(R.mixerPoopFine||0)+(R.truckPoopFine||0)+(R.maleTruckFine||0)+(R.explosionDamage||0)+(R.cardRerollCost||0);t.modalTitle.textContent=`Day ${R.turn} Settlement`,t.modalBody.innerHTML=` +
Net result${M(R.profit)}
-
Chick shipment income${G(E.chickShipmentIncome||0)}
-
Poop shipment income${G(E.poopShipmentIncome||0)}
-
Mixer income${G(E.mixerRevenue||0)}
-
Composter income${G(E.composterIncome||0)}
-
DUD refund income${G(E.dudRefundIncome||0)}
-
Manual combo bonus${G(E.manualComboBonus||0)}
-
Chemical subsidy${G(E.chemicalWeaponSubsidy||0)}
-
Contract bonus${G(E.contractBonus||0)}
-
Penalties${w(O)}
-
Fairies fee${w(E.fairiesTribute?.amount||E.fairiesTribute||0)}
-
Repair worker wages${w(E.repairWorkerWages||0)}
-
Loan repayments${w(E.loanRepayment||0)}
+
Chick shipment income${G(R.chickShipmentIncome||0)}
+
Poop shipment income${G(R.poopShipmentIncome||0)}
+
Mixer income${G(R.mixerRevenue||0)}
+
Composter income${G(R.composterIncome||0)}
+
DUD refund income${G(R.dudRefundIncome||0)}
+
Manual combo bonus${G(R.manualComboBonus||0)}
+
Chemical subsidy${G(R.chemicalWeaponSubsidy||0)}
+
Event bonus${G(R.eventBonus||0)}
+
Penalties${x(O)}
+
Fairies fee${x(R.fairiesTribute?.amount||R.fairiesTribute||0)}
+
Repair worker wages${x(R.repairWorkerWages||0)}
-

Income ${S(E.revenue)} - losses ${S(E.penalty)} = ${S(E.profit)}

`,t.modalActions.innerHTML="",t.modalActions.appendChild(le("Choose Upgrade Card",r||me,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function _(E,G){let w=Math.max(0,e.cardEffects?.rescueLoanCharges||0);t.modalTitle.textContent="Emergency Loan Available",t.modalBody.innerHTML=` -

End-of-day cash is below ${S(0)}.

+

Income ${M(R.revenue)} - losses ${M(R.penalty)} = ${M(R.profit)}

`,t.modalActions.innerHTML="",t.modalActions.appendChild(le("Choose Upgrade Card",r||we,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function W(R,G){let x=Math.max(0,e.cardEffects?.rescueLoanCharges||0);t.modalTitle.textContent="Emergency Loan Available",t.modalBody.innerHTML=` +

End-of-day cash is below ${M(0)}.

-
Current money${S(e.cash)}
-
Emergency Loan+${S(500)}
-
Cards remaining${w}
+
Current money${M(e.cash)}
+
Emergency Loan+${M(500)}
+
Cards remaining${x}
-

Use one Emergency Loan to gain ${S(500)} immediately. If cash is still negative, another decision will be shown if another card remains.

`,t.modalActions.innerHTML="",t.modalActions.appendChild(le("Accept Game Over",G,"facility-action danger")),t.modalActions.appendChild(le("Use Emergency Loan",E,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function U(){let E=e.totals.processed,G=E?Math.round(e.totals.correct/E*100):0,w=di(e);t.modalTitle.textContent=re.phases.gameover,t.modalBody.innerHTML=`

Your cash went negative.

-
Final Score${w.score}
Survival${e.totals.turnsCompleted} days
Final Cash${S(e.cash)}
Accuracy${G}%
+

Use one Emergency Loan to gain ${M(500)} immediately. If cash is still negative, another decision will be shown if another card remains.

`,t.modalActions.innerHTML="",t.modalActions.appendChild(le("Accept Game Over",G,"facility-action danger")),t.modalActions.appendChild(le("Use Emergency Loan",R,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function N(){let R=e.totals.processed,G=R?Math.round(e.totals.correct/R*100):0,x=Ai(e);t.modalTitle.textContent=re.phases.gameover,t.modalBody.innerHTML=`

Your cash went negative.

+
Final Score${x.score}
Survival${e.totals.turnsCompleted} days
Final Cash${M(e.cash)}
Accuracy${G}%
Score breakdown -
Formula
Base = Cash + Total revenue + Factory value \u7E5D\uFF7B\u7E5D\uFF7B\u7E5D\uFF7B0.5 + Contract bonus \u7E5D\uFF7B\u7E5D\uFF7B\u7E5D\uFF7B0.5 = ${S(w.base)}
Daily earned = ceil(Base \u7E5D\uFF7B\u7E5D\uFF7B\u30FB\uFF7D\u30FB\uFF77 Days) = ${S(w.dailyEarned)}
Score = max(0, floor(Base + Daily earned + Correct\u7E5D\uFF7B\u7E5D\uFF7B\u7E5D\uFF7B - Total outflow - Day penalty)) = ${w.score}
-
Factory Value${S(w.factoryValue)}
Total Revenue${S(e.totals.revenue)}
Daily Earned${S(w.dailyEarned)} / day
Total Outflow${S(e.totals.penalty)}
ZUNDA TAX${S(e.totals.zundaTax)}
Fairies Tribute${S(e.totals.fairiesTribute||0)}
Correct Sorts${e.totals.correct}
Auto Sorted${e.totals.autoSorted}
Poop Control${e.totals.poopTrash} trashed / ${e.totals.poopTruck} shipped / ${e.totals.poopMixer} mixer
Explosion Penalty${S(e.totals.explosionDamage)}
Contract Bonus${S(e.totals.contractBonus)}
Day Penalty-${w.dayPenalty}
Contracts${e.totals.contractSuccess} success / ${e.totals.contractFailed} failed
-
`,t.modalActions.innerHTML="",t.modalActions.appendChild(le(re.actions.restart||"Restart",o,"primary-button restart-button")),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible","gameover-modal")}function le(E,G,w="primary-button"){let C=document.createElement("button");return C.type="button",C.className=w,C.textContent=E,C.addEventListener("click",G),C}function me(){t.modal.classList.remove("visible","equipment-popover","gameover-modal"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function fe(){}return{updatePanels:M,updateUI:X,showTitle:j,showTurnResult:g,showEmergencyLoanDecision:_,showGameOver:U,hideModal:me,checkGameOver:fe}}function Qo(e){e.totals.processed+=1}function Ht(e){e.stats.correct+=1,e.totals.correct+=1}function lt(e){e.stats.mistakes+=1,e.totals.mistakes+=1}function ls(e){e.stats.autoSorted+=1,e.totals.autoSorted+=1}function as(e){e.stats.poopSpawned+=1}function cs(e){e.stats.mixerCount+=1,Qo(e)}function us(e){e.stats.trashCount+=1,Qo(e)}function ds(e,t){t==="female"?e.stats.truckFemale+=1:t==="male"&&(e.stats.truckMale+=1),Qo(e)}function _n(e,t){let n=t==="truck"?"poopTruck":t==="trash"?"poopTrash":t==="mixer"?"poopMixer":null;n&&(e.stats[n]+=1,e.totals[n]+=1)}function fs({game:e,currentConveyorSpeed:t,onGameOverCheck:n}){function o(u){return wt(u)*Ln(u)*Wi(e)/Yr(e)}function r(u){let p=$(u.col,u.row),b=1+_i(e,u),x=l(u,b);if(!x.length)return s(u,p),!0;let v=0,P=0;for(let R of x){let V=$(R.col,R.row),Z=d(V);if(Z){Z.stoppedTimer=.85,P+=1;continue}let ge=os(e,{stage:"belt",scannerId:null,route:[V]});ge.sex==="poop"&&as(e),e.chicks.push(ge),Mi(e,u),v+=1}return v>0?(pi(e,p.x,p.y),v>1&&N(e,p.x,p.y-28,`x${v}`,f.green),!0):P===0}function s(u,p){(u.noRouteNoticeCooldown||0)<=0&&(N(e,p.x,p.y-24,"NO BELT: PAUSED",f.warn),u.noRouteNoticeCooldown=2.5)}function l(u,p){let x=pe.map(v=>({col:u.col+v.dc,row:u.row+v.dr})).filter(v=>Pe(v.col,v.row)&&e.conveyorTiles.has(I(v.col,v.row))).map(v=>({p:v,blocked:F(null,$(v.col,v.row))?1:0,roll:Math.random()}));return x.sort((v,P)=>v.blocked-P.blocked||v.roll-P.roll),x.slice(0,Math.max(1,p||1)).map(v=>v.p)}function d(u){return e.chicks.find(p=>p.stage!=="flying"&&Math.hypot(p.x-u.x,p.y-u.y)0;if(e.timeLeft=Math.max(0,e.timeLeft-u),x&&e.timeLeft<=0&&p(),e.timeLeft<=0){e.shutdownTimeLeft>0&&(e.shutdownTimeLeft=Math.max(0,e.shutdownTimeLeft-u));for(let v of e.eggFarms)v.shutterProgress=Math.min(1,(v.shutterProgress||0)+u*2.8)}if(x&&e.timeLeft>0){for(let v of e.eggFarms)if(v.noRouteNoticeCooldown>0&&(v.noRouteNoticeCooldown=Math.max(0,v.noRouteNoticeCooldown-u)),v.nextSpawn-=u,v.nextSpawn<=0){let P=r(v);v.nextSpawn=P?o(v):.15,v.lastInterval=v.nextSpawn}}for(let v=e.chicks.length-1;v>=0;v-=1){let P=e.chicks[v];P.bob+=u*7,P.stoppedTimer>0&&(P.stoppedTimer=Math.max(0,P.stoppedTimer-u)),P.stage!=="queued"&&D(P,v,u)}ce(u),Xt(),Vn(),e.timeLeft<=0&&(e.chicks.length===0?b():e.shutdownTimeLeft<=0&&M())}function M(){if(e.cleanupBlown)return;e.cleanupBlown=!0,e.cleanupTimer=1;let u=[...e.chicks];for(let p of u)go(e,p.sex,p.x,p.y,-Math.PI/2,!0);e.chicks=[];for(let p of e.scanners)p.queue=[];if(Xt(),u.length){let p=u.reduce((x,v)=>x+v.x,0)/u.length,b=u.reduce((x,v)=>x+v.y,0)/u.length;Xe(e,p,b,f.warn,58),N(e,p,b-24,"CLEANUP",f.warn)}}function D(u,p,b){if(L(u)){u.stoppedTimer=.35;return}if(Y(u,b),!(u.route&&u.targetIndex=u.route.length)return!1;let p=u.route[u.targetIndex];return F(u,p)}function F(u,p){if(!p)return!1;for(let b of e.chicks)if(!(u&&b.id===u.id)&&b.stage!=="flying"&&Math.hypot(b.x-p.x,b.y-p.y)1)&&u.push({x:p.x,y:p.y})}function oe(u){let p=e.conveyorMeta?.get?.(u)||{},b=[];Array.isArray(p.outDirs)&&b.push(...p.outDirs),p.dir&&b.push(p.dir);let x=[...new Set(b)].filter(Z=>pe.some(ge=>ge.name===Z)),v=J(u),P=pe.filter(Z=>U(v,Z.name)).map(Z=>Z.name),R=x.filter(Z=>P.includes(Z)),V=P;return R.length?R:V}function X(u){return pe.find(p=>p.name===u)||null}function ae(u,p){return e.scanners.find(b=>b.col<=u&&u<=b.col+1&&b.row-1<=p&&p<=b.row+1)||null}function he(u,p){let b=X(p);if(!b)return null;let x=ae(u.col+b.dc,u.row+b.dr);if(!x)return null;let v=Me(x,"inputA");return v&&v.col===u.col&&v.row===u.row?x:null}function j(u){return Object.entries(e.facilities||{}).find(([,p])=>p?.entry&&p.entry.col===u.col&&p.entry.row===u.row)||null}function g(u){return u?.baseId||u?.id||""}function _(u,p){return u.side==="left"&&p==="left"||u.side==="right"&&p==="right"||u.side==="top"&&p==="up"||u.side==="bottom"&&p==="down"}function U(u,p){let b=X(p);if(!b)return null;let x={col:u.col+b.dc,row:u.row+b.dr};if(Pe(x.col,x.row)&&e.conveyorTiles.has(I(x.col,x.row)))return{type:"conveyor",dirName:p,target:$(x.col,x.row),nextCell:x};let v=he(u,p);if(v)return{type:"scanner",dirName:p,target:de(v),scanner:v};let P=j(u);return P&&_(P[1],p)?{type:"facility",dirName:p,facilityId:P[0],facility:P[1],target:$(u.col,u.row)}:null}function le(u,p){let b=X(p);if(!b)return!1;let x=e.conveyorMeta?.get?.(I(u.col+b.dc,u.row+b.dr));return x?[...new Set([...Array.isArray(x.outDirs)?x.outDirs:[],x.dir].filter(Boolean))].includes(b.opposite):!1}function le2(u,p,b="random"){let x=pe.filter(v=>Pe(u.col+v.dc,u.row+v.dr)&&e.conveyorTiles.has(I(u.col+v.dc,u.row+v.dr))).map(v=>v.name);if(x.length<3)return p;let v=new Set(x.filter(P=>le(u,P)));if(b&&b!=="random"&&b!=="pass"&&x.includes(b)){let P=new Set(v);P.add(b),x.filter(R=>!P.has(R)).length>=2&&v.add(b)}let P=x.filter(R=>!v.has(R));if(P.length)return P;let R=p.filter(V=>!v.has(V));return R.length?R:p}function me(u,p){return p&&(p.type==="facility"||!F(u,p.target))}function fe(u,p,b,x="random"){let v=b.map(Z=>U(p,Z)).filter(Boolean);if(!v.length)return null;let R=v.filter(Z=>Z.type!=="facility").filter(Z=>!F(u,Z.target)),V=R.length?R:v.filter(Z=>Z.type==="facility");return V.length?V[Math.floor(Math.random()*V.length)]:null}function E(u,p){let b=[];z(b,{x:u.x,y:u.y}),z(b,p),u.route=b.length?b:[{x:u.x,y:u.y}],u.targetIndex=u.route.length>1?1:u.route.length}function G(u,p){let b=Ge(u.x,u.y);if(!b)return $t(p,"OFF GRID");let x=I(b.col,b.row);if(!e.conveyorTiles.has(x))return $t(p,"OFF BELT");let v=e.conveyorMeta?.get(x)||{},P=le2(b,oe(x),v.branchMode||"random");if(!P.length){u.stoppedTimer=.25;return}let R=fe(u,b,P,v.branchMode||"random");if(!R){u.stoppedTimer=.25;return}if(R.type==="facility"){let V=g(R.facility);V==="mixer"?zt(p,R.facility):V==="truck"?Yn(p,R.facility):V==="trash"?zn(p,R.facility):$t(p,"DONE");return}R.type==="scanner"&&(u.pendingScannerId=R.scanner.id),u.prevConveyorCell=x,E(u,R.target)}function w(u){let p=Ge(u.x,u.y);if(!p)return null;let b=I(p.col,p.row);return e.conveyorTiles.has(b)?b:null}function C(u){let p=w(u)||w(u.route?.[u.targetIndex]||u);return t(p)}function O(u,p){let b=w(p);!b||u.lastWearKey===b||(u.lastWearKey=b,Si(e,b))}function Y(u,p){let b=C(u)*p;for(;b>0&&u.targetIndex=R?(u.x=x.x,u.y=x.y,O(u,x),u.targetIndex+=1,b-=R):(u.x+=v/R*b,u.y+=P/R*b,b=0)}}function te(u,p,b){u.stage="queued",u.route=null,u.queueRoute=b?b.map(x=>({x:x.x,y:x.y})):[de(p)],u.scannerId=p.id,p.queue.includes(u.id)||p.queue.push(u.id),se(p)}function se(u){u.queue=u.queue.filter(b=>e.chicks.some(x=>x.id===b&&x.stage==="queued"));let p=y.cell*.86*Ki(e);u.queue.forEach((b,x)=>{let v=e.chicks.find(P=>P.id===b);v&&(ve(v,v.queueRoute||[de(u)],x*p),v.queueIndex=x)})}function ve(u,p,b){if(!p||!p.length)return;if(p.length===1||b<=0){let P=p[p.length-1];u.x=P.x,u.y=P.y;return}let x=b;for(let P=p.length-1;P>0;P-=1){let R=p[P-1],V=p[P],Z=Math.hypot(V.x-R.x,V.y-R.y);if(x<=Z){let ge=1-x/Z;u.x=R.x+(V.x-R.x)*ge,u.y=R.y+(V.y-R.y)*ge;return}x-=Z}let v=p[0];u.x=v.x,u.y=v.y}function ce(u){for(let p of e.scanners){if(p.cooldown>0&&(p.cooldown=Math.max(0,p.cooldown-u)),p.keyPressTime>0&&(p.keyPressTime=Math.max(0,p.keyPressTime-u)),se(p),p.kind!=="auto"||p.cooldown>0||!p.queue.length)continue;let b=p.queue[0],x=e.chicks.findIndex(v=>v.id===b);if(x<0){p.queue.shift();continue}un(x,mo(p,e.chicks[x]),!0)&&(Ti(e,p),p.cooldown=Qe(p,e),ls(e))}}function je(u){let p=fo(e,u);return!p||!p.queue.length?null:e.chicks.find(b=>b.id===p.queue[0])||null}function Q(u,p){if(e.phase!=="running")return;let b=fo(e,u);xe(b,p)}function xe(u,p){if(e.phase!=="running"||!u||u.kind!=="manual"||(u.keyPressTime=.18,u.keyPressSide=p,!u.queue.length))return;let b=e.chicks.findIndex(x=>x.id===u.queue[0]);b>=0&&un(b,p,!1)}function ut(u,p,b){return u.kind==="manual"&&mo(u,p)===b}function qe(u){let p=e.manualCombo?.count||0;if(e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=0,e.manualCombo.lastBonus=0,e.stats.manualComboFailure=(e.stats.manualComboFailure||0)+1,e.totals.manualComboFailure=(e.totals.manualComboFailure||0)+1,p>=10){let b=de(u);Et(e,10,.25),N(e,b.x,b.y-36,"COMBO RESET",f.danger)}}function Fe(u){e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=Math.max(0,e.manualCombo.count||0)+1,e.stats.manualComboSuccess=(e.stats.manualComboSuccess||0)+1,e.totals.manualComboSuccess=(e.totals.manualComboSuccess||0)+1;let p=e.manualCombo.count;if(e.manualCombo.lastBonus=0,p<10)return 0;let b=Math.max(1,Math.floor(p/10)),x=e.scanners.filter(V=>V.kind==="manual").length,v=Math.min(1,(20+x*10)/100),P=0;for(let V=0;V0){Ae(e,R),e.stats.manualComboBonus=(e.stats.manualComboBonus||0)+R,e.totals.manualComboBonus=(e.totals.manualComboBonus||0)+R,e.manualCombo.lastBonus=R;let V=de(u);N(e,V.x,V.y-42,`COMBO +${S(R)}`,f.green)}return R}function At(u,p){let b=Me(u,p);if(!b)return null;let x=I(b.col,b.row);if(e.conveyorTiles.has(x))return{...b};let P=(De(e).scannerPorts.get(u.id)?.[p]?.keys||[]).filter(Boolean);if(!P.length)return null;let R=P.map(J);return R.find(Z=>Z.col===b.col&&Z.row===b.row)||R[0]||null}function cn(u,p,b,x){let v=[];z(v,{x:u.x,y:u.y});let P=Me(p,b);return P&&z(v,$(P.col,P.row)),z(v,$(x.col,x.row)),v}function un(u,p,b){let x=e.chicks[u];if(!x||x.stage!=="queued")return!1;let v=St(e,x.scannerId);if(!v)return!1;let P=At(v,p);if(!P)return!b&&v.kind==="manual"&&qe(v),N(e,x.x,x.y-16,p==="left"?"NO LEFT BELT":"NO RIGHT BELT",f.danger),!1;!b&&v.kind==="manual"&&(ut(v,x,p)?Fe(v):qe(v)),v.queue=v.queue.filter(V=>V!==x.id),x.stage="belt",x.route=cn(x,v,p,P),x.targetIndex=x.route.length>1?1:x.route.length,x.scannerId=null,x.nextScannerId=null,x.pendingScannerId=null,x.queueRoute=null,x.queueIndex=-1;let R=b?f.green:p==="left"?f.mixerBlue:f.truckPink;return yi(e,de(v).x,de(v).y,R),N(e,x.x,x.y-20,b?"AUTO":p.toUpperCase(),R),!0}function dt(u){let p=e.chicks[u];return p?(e.chicks.splice(u,1),p):null}function zt(u,p=e.facilities.mixer){if(p?.processingCooldown>0){let R=e.chicks[u];R&&(R.stoppedTimer=.25);return}let b=dt(u);if(!b)return;let{x,y:v}=b;if(cs(e),Lo(e,p),Oo(e,p),b.sex==="poop"){let R=ni(e);_n(e,"mixer"),lt(e),mi(e,x,v),N(e,x,v-18,`-${S(R)}`,f.danger);return}let P=ti(e);b.sex==="male"?Ht(e):lt(e),hi(e,x,v),N(e,x,v-18,`+${S(P)}`,f.green)}function Yn(u,p=e.facilities.truck){let b=dt(u);if(!b)return;let{x,y:v}=b;dn(b.sex,p),wi(e,x,v,b.sex),ds(e,b.sex);let P=ze(e),R=Vr(e,b.sex);if(b.sex==="poop"){let V=oi(e);_n(e,"truck"),R?Ht(e):lt(e),N(e,x,v-18,`-${S(V)}`,f.danger);return}if(b.sex==="female"){R?(Ht(e),N(e,x,v-18,`+${S(Le(e))}`,f.green)):(lt(e),N(e,x,v-18,P==="male"?"REJECT":"NO SALE",f.warn));return}if(R){Ht(e),N(e,x,v-18,`+${S(Le(e))}`,f.green);return}if(Xr(e)){let V=ri(e);lt(e),N(e,x,v-18,`-${S(V)}`,f.danger)}else lt(e),N(e,x,v-18,"REJECT",f.warn)}function zn(u,p=e.facilities.trash){if(p?.processingCooldown>0){let V=e.chicks[u];V&&(V.stoppedTimer=.25);return}let b=dt(u);if(!b)return;let{x,y:v}=b;bi(e,x,v,b.sex),us(e),Lo(e,p),Oo(e,p);let P=Zr(e),R=P.amount>0?` +${S(P.amount)}`:"";if(b.sex==="poop"){_n(e,"trash"),Ht(e);let V=Math.max(0,Number(e.cardEffects?.composter)||0)*3;if(V>0){let Z=Ae(e,V);e.stats.composterIncome=(e.stats.composterIncome||0)+Z,e.totals.composterIncome=(e.totals.composterIncome||0)+Z,N(e,x,v-36,`COMPOST +${S(Z)}`,f.green)}N(e,x,v-18,`CLEAN${R}`,P.amount>0?f.green:f.green)}else lt(e),N(e,x,v-18,P.amount>0?`WASTE${R}`:"WASTE",P.amount>0?f.green:f.ink)}function $t(u,p){let b=dt(u);b&&N(e,b.x,b.y-12,p,f.muted)}function dn(u,p=e.facilities.truck){let b=p||e.facilities.truck;b&&(e.truckCargo.push({sex:u,x:W(22,b.w-22),y:W(66,b.h-24)}),e.truckCargo.length>45&&e.truckCargo.shift())}function Vt(u){let p=Ge(u.x,u.y);if(p){let P=I(p.col,p.row);if(e.conveyorTiles.has(P))return P}let b=Or(e,u.x,u.y);if(!b)return null;let x=J(b),v=$(x.col,x.row);return Math.hypot(u.x-v.x,u.y-v.y)<=y.cell*.55?b:null}function Xt(){let{components:u,cellToComponent:p}=Lr(e);for(let b of e.chicks){if(b.stage==="flying")continue;let x=Vt(b);if(!x)continue;let v=p.get(x),P=u.get(v);P&&(P.count+=1)}for(let b of u.values())b.ratio=b.count/b.capacity;e.congestion=u,e.componentLookup=p}function Vn(){for(let u of e.congestion.values()){if(u.ratio>.8&&u.ratio<1)for(let p of It(u.id).slice(0,3))Math.random()<.06&&vi(e,p.x,p.y-p.radius-8);if(u.ratio>=1){let p=It(u.id);if(!p.length||p.some(v=>v.stage!=="queued"&&v.stoppedTimer<=.2))continue;let b=e.lastExplodedComponent.get(u.id)||0,x=performance.now();x-b>900&&(e.lastExplodedComponent.set(u.id,x),Xn(u))}}}function It(u){return e.chicks.filter(p=>{let b=Vt(p);return b&&e.componentLookup?.get(b)===u})}function Xn(u){let p=It(u.id);if(!p.length)return;for(let v of p)go(e,v.sex,v.x,v.y);e.chicks=e.chicks.filter(v=>!p.some(P=>P.id===v.id));for(let v of e.scanners)v.queue=v.queue.filter(P=>e.chicks.some(R=>R.id===P));for(let v of u.cells){let P=J(v),R=$(P.col,P.row);Xe(e,R.x,R.y,f.danger),it(e,R.x,R.y,6),Rn(e,R.x,R.y,4)}Et(e,18,.75);let b=J(u.cells[0]),x=$(b.col,b.row);N(e,x.x,x.y-22,"100% JAM EXPLOSION",f.danger)}return{activeQueuedChick:je,currentSpawnDelay:o,sortSlot:Q,updateCongestion:Xt,sortScanner:xe,updateRunning:k}}var ie=document.getElementById("gameCanvas"),Da=ie.getContext("2d"),B={shell:document.getElementById("gameShell"),money:document.getElementById("money"),turn:document.getElementById("turn"),timeLeft:document.getElementById("timeLeft"),phase:document.getElementById("phaseLabel"),comboCount:document.getElementById("comboCount"),eventBrief:document.getElementById("eventBrief"),targetBrief:document.getElementById("targetBrief"),speedBrief:document.getElementById("speedBrief"),turnProfit:document.getElementById("turnProfit"),mixerCount:document.getElementById("mixerCount"),truckFemaleCount:document.getElementById("truckFemaleCount"),truckMaleCount:document.getElementById("truckMaleCount"),poopCount:document.getElementById("poopCount"),buildStatus:document.getElementById("buildStatus"),turnSummary:document.getElementById("turnSummary"),contractPanel:document.getElementById("contractPanel"),modal:document.getElementById("modal"),modalTitle:document.getElementById("modalTitle"),modalBody:document.getElementById("modalBody"),modalActions:document.getElementById("modalActions"),hoverTooltip:document.getElementById("hoverTooltip"),manualScannerMonitor:document.getElementById("manualScannerMonitor"),hireRepairmanButton:document.getElementById("hireRepairmanButton"),debug:{panel:document.getElementById("debugPanel"),infiniteCash:document.getElementById("debugInfiniteCash"),dayInput:document.getElementById("debugDayInput"),setDay:document.getElementById("debugSetDayButton"),zeroTimer:document.getElementById("debugZeroTimerButton"),cardSelect:document.getElementById("debugCardSelect"),grantCard:document.getElementById("debugGrantCardButton"),grantAllCards:document.getElementById("debugGrantAllCardsButton"),readout:document.getElementById("debugReadout")},buttons:{s1Left:document.getElementById("scanner1MixerButton"),s1Right:document.getElementById("scanner1TruckButton"),s2Left:document.getElementById("scanner2MixerButton"),s2Right:document.getElementById("scanner2TruckButton"),nextTurn:document.getElementById("nextTurnButton"),conveyor:document.getElementById("buildConveyorButton"),boostConveyor:document.getElementById("buildBoostConveyorButton"),eggFarm:document.getElementById("buildEggFarmButton"),autoScanner:document.getElementById("buildAutoScannerButton"),manualScanner:document.getElementById("buildManualScannerButton"),mixer:document.getElementById("buildMixerButton"),trash:document.getElementById("buildTrashButton"),truck:document.getElementById("buildTruckButton"),erase:document.getElementById("eraseButton"),undo:document.getElementById("undoButton"),redo:document.getElementById("redoButton")}};function Aa(){let e={conveyor:"conveyor",boostConveyor:"boostConveyor",eggFarm:"eggFarm",autoScanner:"autoScanner",manualScanner:"manualScanner",mixer:"mixer",trash:"trash",truck:"truck"};for(let[t,n]of Object.entries(e))B.buttons[t]&&(B.buttons[t].innerHTML=cr(n))}function $a(){B.debug?.panel&&B.debug.cardSelect&&(B.debug.cardSelect.innerHTML=Kt.map(e=>``).join(""))}var a=co(),H,K,Te,Yt;function Ia(e=null){let t=Gn(a,e);return e?t*Ao(a,e):t}function Fa(){Object.assign(a,co()),a.phase="running",a.view={x:0,y:0,scale:1},uo(a),xs(),ye(a),K.hideModal(),Te.updateCongestion(),K.updatePanels(),K.updateUI(),Dt()}function Ba(){let e=Math.max(1,Math.floor(Number(B.debug.dayInput?.value)||1));a.turn=e,B.debug.dayInput&&(B.debug.dayInput.value=String(e)),N(a,ie.width/2-a.view.x,86-a.view.y,`DAY ${e}`,f.green),K.updatePanels(),K.updateUI(),Dt(`Day set to ${e}.`)}function La(){a.timeLeft=0,a.phase==="running"&&ws(),N(a,ie.width/2-a.view.x,86-a.view.y,"TIMER 0",f.warn),K.updatePanels(),K.updateUI(),Dt("Timer set to 0.")}function Oa(){let e=B.debug.cardSelect?.value,t=Wo(a,e);B.debug.grantCard&&(B.debug.grantCard.textContent=t.ok?"Granted":"Grant failed",window.setTimeout(()=>{B.debug.grantCard&&(B.debug.grantCard.textContent="Grant Card")},900)),K.updatePanels(),K.updateUI(),Dt(t.reason)}function Na(){let t=Kt.map(n=>Wo(a,n)).filter(n=>n.ok).length;K.updatePanels(),K.updateUI(),Dt(`Granted ${t}/${Kt.length} cards.`)}function Ga(){B.debug?.infiniteCash?.checked&&a.cash<999999&&(a.cash=999999,a.totals.maxCash=Math.max(a.totals.maxCash,a.cash))}function Dt(e=""){B.debug?.readout&&(B.debug.readout.textContent=[e,`D${a.turn}`,S(a.cash),`Combo ${a.manualCombo?.count||0}`,`Rescue ${a.cardEffects?.rescueLoanCharges||0}`,`Chem ${a.cardEffects?.chemicalWeaponSubsidy||0}`].filter(Boolean).join(" | "))}function Ua(){if(a.phase!=="build")return;if(a.cardDraft?.pending||a.cardTargetPick?.pending){H.fail(a.cardTargetPick?.pending?"Choose upgrade target first.":"Choose an upgrade card first."),K.updatePanels();return}let e=tn(a);if(e.length){H.fail(`Cannot start: ${e[0]}`),K.updatePanels();return}ye(a),Fr(a),Ai(a);let t=Math.max(0,Math.floor(a.lastResult?.profit??a.stats?.profit??0)),n=li(a,t),o=ui(a);a.lastStartFees={zundaTax:n.tax||0,loanRepayment:o.amount||0,fairiesTribute:0},n.tax>0&&N(a,ie.width/2-a.view.x,116-a.view.y,`ZUNDA TAX -${S(n.tax)}`,f.danger),o.amount>0&&N(a,ie.width/2-a.view.x,146-a.view.y,`LOAN -${S(o.amount)}`,f.danger),Hr(a),a.phase="running",a.turn+=1,a.timeLeft=Bt,a.shutdownTimeLeft=0,a.cleanupTimer=null,a.cleanupBlown=!1,a.chicks=[],a.effects=[],a.floatingTexts=[],a.shake={time:0,strength:0},a.truckCargo=[],xs(),a.stats=ao(),a.stats.zundaTax=0,a.stats.loanRepayment=a.lastStartFees?.loanRepayment||0,a.stats.repairWorkerWages=a.pendingRepairWorkerWages||0;let r=a.stats.loanRepayment+a.stats.repairWorkerWages;r>0&&(a.stats.penalty+=r,a.stats.profit-=r),a.pendingRepairWorkerWages=0;for(let s of a.scanners)s.queue=[],s.cooldown=0;for(let s of a.eggFarms)s.nextSpawn=Te.currentSpawnDelay(s),s.lastInterval=s.nextSpawn,s.shutterProgress=0,s.shutterSparked=!1;a.buildTool=null,a.selected=null,a.groupDrag=null,a.selectionBox=null,a.pan=null,Te.updateCongestion(),K.updatePanels(),K.updateUI()}function Wa(){ye(a);let e=Di(a);e.ok?N(a,ie.width/2-a.view.x,96-a.view.y,`Repairman hired -${S(e.cost)}`,f.green):(N(a,ie.width/2-a.view.x,96-a.view.y,e.reason||"Cannot hire repairman.",f.danger),H?.fail?.(e.reason||"Cannot hire repairman.")),K.updatePanels(),K.updateUI()}function _a(){if(a.phase!=="running")return;let e=si(a),t=Qr(a),n=ci(a);if(e.adjusted>0){let s=a.facilities.truck,l=s?s.x+s.w/2:ie.width/2-a.view.x,d=s?s.y+26:96-a.view.y;N(a,l,d,`${e.target==="poop"?"POOP SHIP":"SHIP"} +${S(e.adjusted)}`,f.green)}t?.bonus>0&&N(a,ie.width/2-a.view.x,96-a.view.y,`CONTRACT +${S(t.bonus)}`,f.green),n.amount>0&&N(a,ie.width/2-a.view.x,116-a.view.y,`CHEM SUBSIDY +${S(n.amount)}`,f.green),qr(a);let o=Math.max(1,(a.totals.turnsCompleted||0)+1),r=ai(a,o);if(a.lastBuildFees={fairiesTribute:r.amount||0,reduction:r.reduction||0,turn:o},r.amount>0&&N(a,ie.width/2-a.view.x,146-a.view.y,`FAIRIES -${S(r.amount)}`,f.danger),a.totals.turnsCompleted+=1,a.lastResult={...a.stats,ship:e,contract:t,chemical:n,rescue:{amount:0,used:0,remaining:a.cardEffects?.rescueLoanCharges||0},fairiesTribute:r,turn:a.turn,cash:a.cash},a.cash<0){if((a.cardEffects?.rescueLoanCharges||0)>0){a.phase="loanDecision",K.showEmergencyLoanDecision(bs,Kn);return}a.phase="gameover",K.showGameOver();return}ms()}function ms(){a.phase="build",a.truckCargo=[],a.chicks=[],a.shutdownTimeLeft=0,a.cleanupTimer=null,a.cleanupBlown=!1,a.buildSession+=1,a.undoStack=[],a.redoStack=[],a.timeLeft=0;for(let e of a.scanners)e.queue=[];for(let e of a.eggFarms)e.shutterProgress=0,e.shutterSparked=!1;$i(a),a.contractOffer=Kr(a),Yt&&Yt.prepareDraft(),a.cardTargetPick=null,a.buildTool=null,a.groupDrag=null,a.selectionBox=null,a.pan=null,K.updatePanels(),K.showTurnResult(a.lastResult)}function bs(){if((a.cardEffects?.rescueLoanCharges||0)<=0)return Kn();a.cardEffects.rescueLoanCharges-=1,a.stats.rescueLoan=(a.stats.rescueLoan||0)+500,a.totals.rescueLoan=(a.totals.rescueLoan||0)+500;let e=Ae(a,500);a.lastResult={...a.lastResult||{},...a.stats,rescue:{amount:(a.lastResult?.rescue?.amount||0)+e,used:(a.lastResult?.rescue?.used||0)+1,remaining:a.cardEffects.rescueLoanCharges},cash:a.cash},N(a,ie.width/2-a.view.x,176-a.view.y,`RESCUE +${S(e)}`,f.green),a.cash>=0?ms():(a.cardEffects?.rescueLoanCharges||0)>0?(a.phase="loanDecision",K.showEmergencyLoanDecision(bs,Kn)):Kn()}function Kn(){a.phase="gameover",K.showGameOver()}function ws(){a.shutdownTimeLeft<=0&&(a.shutdownTimeLeft=a.shutdownGraceSeconds||10);for(let e of a.eggFarms){if(e.shutterSparked)continue;e.shutterProgress=.02,e.shutterSparked=!0;let t=$(e.col,e.row);Xe(a,t.x,t.y,f.ink),it(a,t.x,t.y+10,10),N(a,t.x,t.y-34,"SHUT +10s",f.ink)}}function vs(e){a.lastTimestamp||(a.lastTimestamp=e);let t=Math.min((e-a.lastTimestamp)/1e3,.05);a.lastTimestamp=e,Ga(),a.phase==="running"&&Te.updateRunning(t,{closeFarmShutters:ws,completeTurn:_a}),xi(a,t,ie,H.equipmentHitBoxes),Te.updateCongestion(),Xi(Da,ie,a,{activeQueuedChick:Te.activeQueuedChick,selectedObject:H.selectedObject,selectedTitle:H.selectedTitle}),K.updateUI(),Cs(),Dt(),requestAnimationFrame(vs)}function Hn(){return a.view?.scale||1}function an(){a.view||(a.view={x:0,y:0,scale:1}),a.view.scale==null&&(a.view.scale=1)}function qn(e){let t=ie.getBoundingClientRect();return{x:(e.clientX-t.left)*ie.width/t.width,y:(e.clientY-t.top)*ie.height/t.height}}function at(e){let t=qn(e),n=Hn();return{x:(t.x-(a.view?.x||0))/n,y:(t.y-(a.view?.y||0))/n}}function Ka(e){let t=Hn();return{x:e.x*t+(a.view?.x||0),y:e.y*t+(a.view?.y||0)}}function Ha(){let e={left:y.x-90,top:y.y-130,right:y.x+y.cols*y.cell+260,bottom:y.y+y.rows*y.cell+220};if(a.phase==="build")for(let t of mt(a)){let n=bt(t);e.left=Math.min(e.left,n.x-60),e.top=Math.min(e.top,n.y-80),e.right=Math.max(e.right,n.x+n.w+80),e.bottom=Math.max(e.bottom,n.y+n.h+80)}return e}function ps(e,t){if(e<=t)return[e,t];let n=(e+t)/2;return[n,n]}function ct(){an();let e=Hn(),t=Ha(),[n,o]=ps(ie.width-160-t.right*e,110-t.left*e),[r,s]=ps(ie.height-150-t.bottom*e,150-t.top*e);a.view.x=jt(a.view.x,n,o),a.view.y=jt(a.view.y,r,s)}function xs(){an(),a.view.scale=1;let e=a.eggFarms?.[0],t=e?$(e.col,e.row):{x:y.x,y:y.y};a.view.x=280-t.x,a.view.y=190-t.y,ct()}function qa(e){let t=qn(e);an(),a.pan={start:t,viewX:a.view.x,viewY:a.view.y,moved:!1}}function Ya(e){if(!a.pan)return;let t=qn(e);Math.hypot(t.x-a.pan.start.x,t.y-a.pan.start.y)>5&&(a.pan.moved=!0),an(),a.view.x=a.pan.viewX+t.x-a.pan.start.x,a.view.y=a.pan.viewY+t.y-a.pan.start.y,ct()}function za(e){e.preventDefault(),an();let t=qn(e),n=at(e),o=Math.exp(-e.deltaY*.0012),r=jt(Hn()*o,.55,1.8);a.view.scale=r,a.view.x=t.x-n.x*r,a.view.y=t.y-n.y*r,ct(),Ze()}function Va(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:{type:e.type,id:e.ref.id}:null}function Xa(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:e.ref||null:null}function Ze(){B.hoverTooltip&&(B.hoverTooltip.classList.remove("visible"),B.hoverTooltip.setAttribute("aria-hidden","true"),a.hover=null)}function Qa(e,t){if(!B.hoverTooltip||a.phase!=="build"||a.cardTargetPick?.pending||a.groupDrag||a.selectionBox||a.pan)return Ze();let n=Xa(t);if(!n)return Ze();let o=H.selectedTitle(n),r=H.flavorText?H.flavorText(n):"",s=H.disconnectedWarningFor?H.disconnectedWarningFor(n):"",l=H.selectedInfoLines(n).slice(0,7);B.hoverTooltip.innerHTML=`${o}${s?`${s}`:r?`${r}`:""}${l.map(M=>`${M}`).join("")}`;let d=Math.min(window.innerWidth-330,e.clientX+18),k=Math.min(window.innerHeight-220,e.clientY+18);B.hoverTooltip.style.left=`${Math.max(8,d)}px`,B.hoverTooltip.style.top=`${Math.max(8,k)}px`,B.hoverTooltip.classList.add("visible"),B.hoverTooltip.setAttribute("aria-hidden","false"),a.hover={type:t.type,id:t.oldKey||t.ref?.id||null}}function Ja(e){if(a.phase!=="build")return Ze();Qa(e,H.equipmentAtPoint(at(e)))}function ks(e){Ze();let t=at(e),n=H.equipmentAtPoint(t),o=Va(n);if(!o){a.selected=null,a.multiSelected=[],K.updatePanels();return}a.selected=o,a.multiSelected=[o],K.updatePanels();let r=H.selectedObject();r?.type==="scanner"&&r.kind==="manual"&&H.showManualScannerMenu(r),r?.type==="scanner"&&r.kind==="auto"&&H.showAutoScannerMenu(r)}function qt(){a.buildTool=null,a.selected=null,a.multiSelected=[],a.selectionBox=null,a.cardTargetPick?.mode==="autoScannerMenu"&&(a.cardTargetPick=null),K.hideModal(),Ze(),K.updatePanels(),K.updateUI()}function ys(e){return String(e).replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function Za(e){let t=e?.queue?.[0];return t==null?null:a.chicks.find(n=>n.id===t)||null}function ja(e){if(!e)return'WAIT';let t=e.sex==="poop"?"\u{1F4A9} POOP":e.sex==="male"?"\u2642 MALE":"\u2640 FEMALE";return`${t}`}function ec(e,t){let n=new Set(a.eggFarms.map(D=>I(D.col,D.row))),o=new Map(a.scanners.map(D=>[I(D.col,D.row),D])),r=Me(e,"inputA"),s=r?I(r.col,r.row):null,l=new Set(Object.values(a.facilities||{}).map(D=>D.entry?I(D.entry.col,D.entry.row):null).filter(Boolean)),d=t?.sex||"",k=d==="poop"?"\u{1F4A9}":d==="male"?"\u2642":d==="female"?"\u2640":"",M=[];for(let D=e.row-2;D<=e.row+2;D+=1)for(let L=e.col-2;L<=e.col+2;L+=1){let F=I(L,D),z=["mini-cell"],oe="";L===e.col&&D===e.row?(z.push("scanner"),d&&z.push(d),oe=k||"S"):F===s?(z.push("input"),oe="IN"):n.has(F)?(z.push("egg"),oe="E"):o.has(F)?(z.push("scanner-other"),oe="S"):l.has(F)?(z.push("port"),oe="P"):a.conveyorTiles.has(F)?(z.push("belt"),oe="\u2022"):a.blockedCells?.has?.(F)&&(z.push("blocked"),oe="\xD7"),M.push(`${oe}`)}return`
${M.join("")}
`}function tc(e){let t=Ka($(e.col,e.row)),n=76;return t.x<-n||t.y<-n||t.x>ie.width+n||t.y>ie.height+n}function Cs(){if(!B.manualScannerMonitor)return;if(a.phase!=="running"){B.manualScannerMonitor.classList.remove("visible"),B.manualScannerMonitor.innerHTML="";return}let e=a.scanners.filter(t=>t.kind==="manual"&&tc(t));if(!e.length){B.manualScannerMonitor.classList.remove("visible"),B.manualScannerMonitor.innerHTML="";return}B.manualScannerMonitor.innerHTML=e.map(t=>{let n=Za(t),o=t.keys?.left?.label||(t.slot===0?"A":"Left"),r=t.keys?.right?.label||(t.slot===0?"D":"Right"),s=t.role===0?"MIXER":"WASTE",l=t.role===0?"S2":"TRUCK",d=n?"":" disabled";return` +
Formula
Base = Cash + Total revenue + Factory value \xD70.5 + Event bonus \xD70.5 = ${M(x.base)}
Daily earned = ceil(Base \xF7 Days) = ${M(x.dailyEarned)}
Score = max(0, floor(Base + Daily earned + Correct bonus - Total outflow - Day penalty)) = ${x.score}
+
Factory Value${M(x.factoryValue)}
Total Revenue${M(e.totals.revenue)}
Daily Earned${M(x.dailyEarned)} / day
Total Outflow${M(e.totals.penalty)}
Fairies Tribute${M(e.totals.fairiesTribute||0)}
Correct Sorts${e.totals.correct}
Auto Sorted${e.totals.autoSorted}
Poop Control${e.totals.poopTrash} trashed / ${e.totals.poopTruck} shipped / ${e.totals.poopMixer} mixer
Explosion Penalty${M(e.totals.explosionDamage)}
Event Bonus${M(e.totals.eventBonus)}
Day Penalty-${x.dayPenalty}
Events${e.totals.eventSuccess} success / ${e.totals.eventFailed} failed
+ `,t.modalActions.innerHTML="",t.modalActions.appendChild(le(re.actions.restart||"Restart",o,"primary-button restart-button")),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible","gameover-modal")}function le(R,G,x="primary-button"){let g=document.createElement("button");return g.type="button",g.className=x,g.textContent=R,g.addEventListener("click",G),g}function we(){t.modal.classList.remove("visible","equipment-popover","gameover-modal"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function he(){}return{updatePanels:C,updateUI:z,showTitle:Z,showTurnResult:I,showEmergencyLoanDecision:W,showGameOver:N,hideModal:we,checkGameOver:he}}function cr(e){e.totals.processed+=1}function zt(e){e.stats.correct+=1,e.totals.correct+=1}function yt(e){e.stats.mistakes+=1,e.totals.mistakes+=1}function Es(e){e.stats.autoSorted+=1,e.totals.autoSorted+=1}function Ps(e){e.stats.poopSpawned+=1}function Rs(e){e.stats.mixerCount+=1,cr(e)}function As(e){e.stats.trashCount+=1,cr(e)}function Ds(e,t){t==="female"?e.stats.truckFemale+=1:t==="male"&&(e.stats.truckMale+=1),cr(e)}function Qn(e,t){let n=t==="truck"?"poopTruck":t==="trash"?"poopTrash":t==="mixer"?"poopMixer":null;n&&(e.stats[n]+=1,e.totals[n]+=1)}function Is({game:e,currentConveyorSpeed:t,onGameOverCheck:n}){function o(u){return Mt(u)*_n(u)*is(e)/fi(e)}function r(u){let p=F(u.col,u.row),b=1+ss(e,u),S=l(u,b);if(!S.length)return s(u,p),!0;let w=0,E=0;for(let D of S){let K=F(D.col,D.row),ee=d(K);if(ee){ee.stoppedTimer=.85,E+=1;continue}let Xe=Cs(e,{stage:"belt",scannerId:null,route:[K]});Xe.sex==="poop"&&Ps(e),e.chicks.push(Xe),_i(e,u),w+=1}return w>0?(Ii(e,p.x,p.y),w>1&&_(e,p.x,p.y-28,`x${w}`,f.green),!0):E===0}function s(u,p){(u.noRouteNoticeCooldown||0)<=0&&(_(e,p.x,p.y-24,"NO BELT: PAUSED",f.warn),u.noRouteNoticeCooldown=2.5)}function l(u,p){let S=ue.map(w=>({col:u.col+w.dc,row:u.row+w.dr})).filter(w=>Te(w.col,w.row)&&e.conveyorTiles.has($(w.col,w.row))).map(w=>({p:w,blocked:L(null,F(w.col,w.row))?1:0,roll:Math.random()}));return S.sort((w,E)=>w.blocked-E.blocked||w.roll-E.roll),S.slice(0,Math.max(1,p||1)).map(w=>w.p)}function d(u){return e.chicks.find(p=>p.stage!=="flying"&&Math.hypot(p.x-u.x,p.y-u.y)0;if(e.timeLeft=Math.max(0,e.timeLeft-u),S&&e.timeLeft<=0&&p(),e.timeLeft<=0){e.shutdownTimeLeft>0&&(e.shutdownTimeLeft=Math.max(0,e.shutdownTimeLeft-u));for(let w of e.eggFarms)w.shutterProgress=Math.min(1,(w.shutterProgress||0)+u*2.8)}if(S&&e.timeLeft>0){for(let w of e.eggFarms)if(w.noRouteNoticeCooldown>0&&(w.noRouteNoticeCooldown=Math.max(0,w.noRouteNoticeCooldown-u)),w.nextSpawn-=u,w.nextSpawn<=0){let E=r(w);w.nextSpawn=E?o(w):.15,w.lastInterval=w.nextSpawn}}for(let w=e.chicks.length-1;w>=0;w-=1){let E=e.chicks[w];E.bob+=u*7,E.stoppedTimer>0&&(E.stoppedTimer=Math.max(0,E.stoppedTimer-u)),E.stage!=="queued"&&P(E,w,u)}J(u),Jt(),oo(),e.timeLeft<=0&&(e.chicks.length===0?b():e.shutdownTimeLeft<=0&&C())}function C(){if(e.cleanupBlown)return;e.cleanupBlown=!0,e.cleanupTimer=1;let u=[...e.chicks];for(let p of u)No(e,p.sex,p.x,p.y,-Math.PI/2,!0);e.chicks=[];for(let p of e.scanners)p.queue=[];if(Jt(),u.length){let p=u.reduce((S,w)=>S+w.x,0)/u.length,b=u.reduce((S,w)=>S+w.y,0)/u.length;Ye(e,p,b,f.warn,58),_(e,p,b-24,"CLEANUP",f.warn)}}function P(u,p,b){if(A(u)){u.stoppedTimer=.35;return}if(de(u,b),!(u.route&&u.targetIndex=u.route.length)return!1;let p=u.route[u.targetIndex];return L(u,p)}function L(u,p){if(!p)return!1;for(let b of e.chicks)if(!(u&&b.id===u.id)&&b.stage!=="flying"&&Math.hypot(b.x-p.x,b.y-p.y)1)&&u.push({x:p.x,y:p.y})}function ne(u){let p=e.conveyorMeta?.get?.(u)||{},b=[];Array.isArray(p.outDirs)&&b.push(...p.outDirs),p.dir&&b.push(p.dir);let S=[...new Set(b)].filter(ee=>ue.some(Xe=>Xe.name===ee)),w=Q(u),E=ue.filter(ee=>N(w,ee.name)).map(ee=>ee.name),D=S.filter(ee=>E.includes(ee)),K=E;return D.length?D:K}function z(u){return ue.find(p=>p.name===u)||null}function se(u,p){return e.scanners.find(b=>b.col<=u&&u<=b.col+1&&b.row-1<=p&&p<=b.row+1)||null}function ye(u,p){let b=z(p);if(!b)return null;let S=se(u.col+b.dc,u.row+b.dr);if(!S)return null;let w=Ee(S,"inputA");return w&&w.col===u.col&&w.row===u.row?S:null}function Z(u){return Object.entries(e.facilities||{}).find(([,p])=>p?.entry&&p.entry.col===u.col&&p.entry.row===u.row)||null}function I(u){return u?.baseId||u?.id||""}function W(u,p){return u.side==="left"&&p==="left"||u.side==="right"&&p==="right"||u.side==="top"&&p==="up"||u.side==="bottom"&&p==="down"}function N(u,p){let b=z(p);if(!b)return null;let S={col:u.col+b.dc,row:u.row+b.dr};if(Te(S.col,S.row)&&e.conveyorTiles.has($(S.col,S.row)))return{type:"conveyor",dirName:p,target:F(S.col,S.row),nextCell:S};let w=ye(u,p);if(w)return{type:"scanner",dirName:p,target:pe(w),scanner:w};let E=Z(u);return E&&W(E[1],p)?{type:"facility",dirName:p,facilityId:E[0],facility:E[1],target:F(u.col,u.row)}:null}function le(u,p){let b=z(p);if(!b)return!1;let S=e.conveyorMeta?.get?.($(u.col+b.dc,u.row+b.dr));return S?[...new Set([...Array.isArray(S.outDirs)?S.outDirs:[],S.dir].filter(Boolean))].includes(b.opposite):!1}function we(u){return ue.filter(p=>Te(u.col+p.dc,u.row+p.dr)&&e.conveyorTiles.has($(u.col+p.dc,u.row+p.dr))).map(p=>p.name)}function he(u,p,b="random"){let S=we(u);if(S.length<3)return p;let w=new Set(S.filter(K=>le(u,K)));if(b&&b!=="random"&&b!=="pass"&&S.includes(b)){let K=new Set(w);K.add(b),S.filter(ee=>!K.has(ee)).length>=2&&w.add(b)}let E=S.filter(K=>!w.has(K));if(E.length)return E;let D=p.filter(K=>!w.has(K));return D.length?D:p}function R(u,p){return p&&(p.type==="facility"||!L(u,p.target))}function G(u,p,b,S="random"){let w=b.map(ee=>N(p,ee)).filter(Boolean);if(!w.length)return null;let D=w.filter(ee=>ee.type!=="facility").filter(ee=>!L(u,ee.target)),K=D.length?D:w.filter(ee=>ee.type==="facility");return K.length?K[Math.floor(Math.random()*K.length)]:null}function x(u,p){let b=[];V(b,{x:u.x,y:u.y}),V(b,p),u.route=b.length?b:[{x:u.x,y:u.y}],u.targetIndex=u.route.length>1?1:u.route.length}function g(u,p){let b=We(u.x,u.y);if(!b)return Ot(p,"OFF GRID");let S=$(b.col,b.row);if(!e.conveyorTiles.has(S))return Ot(p,"OFF BELT");let w=e.conveyorMeta?.get(S)||{},E=he(b,ne(S),w.branchMode||"random");if(!E.length){u.stoppedTimer=.25;return}let D=G(u,b,E,w.branchMode||"random");if(!D){u.stoppedTimer=.25;return}if(D.type==="facility"){let K=I(D.facility);K==="mixer"?to(p,D.facility):K==="truck"?mn(p,D.facility):K==="trash"?no(p,D.facility):Ot(p,"DONE");return}D.type==="scanner"&&(u.pendingScannerId=D.scanner.id),u.prevConveyorCell=S,x(u,D.target)}function O(u){let p=We(u.x,u.y);if(!p)return null;let b=$(p.col,p.row);return e.conveyorTiles.has(b)?b:null}function X(u){let p=O(u)||O(u.route?.[u.targetIndex]||u);return t(p)}function oe(u,p){let b=O(p);!b||u.lastWearKey===b||(u.lastWearKey=b,Wi(e,b))}function de(u,p){let b=X(u)*p;for(;b>0&&u.targetIndex=D?(u.x=S.x,u.y=S.y,oe(u,S),u.targetIndex+=1,b-=D):(u.x+=w/D*b,u.y+=E/D*b,b=0)}}function ge(u,p,b){u.stage="queued",u.route=null,u.queueRoute=b?b.map(S=>({x:S.x,y:S.y})):[pe(p)],u.scannerId=p.id,p.queue.includes(u.id)||p.queue.push(u.id),ce(p)}function ce(u){u.queue=u.queue.filter(b=>e.chicks.some(S=>S.id===b&&S.stage==="queued"));let p=y.cell*.86*ls(e);u.queue.forEach((b,S)=>{let w=e.chicks.find(E=>E.id===b);w&&(ot(w,w.queueRoute||[pe(u)],S*p),w.queueIndex=S)})}function ot(u,p,b){if(!p||!p.length)return;if(p.length===1||b<=0){let E=p[p.length-1];u.x=E.x,u.y=E.y;return}let S=b;for(let E=p.length-1;E>0;E-=1){let D=p[E-1],K=p[E],ee=Math.hypot(K.x-D.x,K.y-D.y);if(S<=ee){let Xe=1-S/ee;u.x=D.x+(K.x-D.x)*Xe,u.y=D.y+(K.y-D.y)*Xe;return}S-=ee}let w=p[0];u.x=w.x,u.y=w.y}function J(u){for(let p of e.scanners){if(p.cooldown>0&&(p.cooldown=Math.max(0,p.cooldown-u)),p.keyPressTime>0&&(p.keyPressTime=Math.max(0,p.keyPressTime-u)),ce(p),p.kind!=="auto"||p.cooldown>0||!p.queue.length)continue;let b=p.queue[0],S=e.chicks.findIndex(w=>w.id===b);if(S<0){p.queue.shift();continue}hn(S,go(p,e.chicks[S]),!0)&&(Ki(e,p),p.cooldown=et(p,e),Es(e))}}function Me(u){let p=xo(e,u);return!p||!p.queue.length?null:e.chicks.find(b=>b.id===p.queue[0])||null}function Be(u,p){if(e.phase!=="running")return;let b=xo(e,u);rt(b,p)}function rt(u,p){if(e.phase!=="running"||!u||u.kind!=="manual"||(u.keyPressTime=.18,u.keyPressSide=p,!u.queue.length))return;let b=e.chicks.findIndex(S=>S.id===u.queue[0]);b>=0&&hn(b,p,!1)}function Ge(u,p,b){return u.kind==="manual"&&go(u,p)===b}function it(u){let p=e.manualCombo?.count||0;if(e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=0,e.manualCombo.lastBonus=0,e.stats.manualComboFailure=(e.stats.manualComboFailure||0)+1,e.totals.manualComboFailure=(e.totals.manualComboFailure||0)+1,p>=10){let b=pe(u);It(e,10,.25),_(e,b.x,b.y-36,"COMBO RESET",f.danger)}}function eo(u){e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=Math.max(0,e.manualCombo.count||0)+1,e.stats.manualComboSuccess=(e.stats.manualComboSuccess||0)+1,e.totals.manualComboSuccess=(e.totals.manualComboSuccess||0)+1;let p=e.manualCombo.count;if(e.manualCombo.lastBonus=0,p<10)return 0;let b=Math.max(1,Math.floor(p/10)),S=e.scanners.filter(K=>K.kind==="manual").length,w=Math.min(1,(20+S*10)/100),E=0;for(let K=0;K0){Oe(e,D),e.stats.manualComboBonus=(e.stats.manualComboBonus||0)+D,e.totals.manualComboBonus=(e.totals.manualComboBonus||0)+D,e.manualCombo.lastBonus=D;let K=pe(u);_(e,K.x,K.y-42,`COMBO +${M(D)}`,f.green)}return D}function pn(u,p){let b=Ee(u,p);if(!b)return null;let S=$(b.col,b.row);if(e.conveyorTiles.has(S))return{...b};let E=(Le(e).scannerPorts.get(u.id)?.[p]?.keys||[]).filter(Boolean);if(!E.length)return null;let D=E.map(Q);return D.find(ee=>ee.col===b.col&&ee.row===b.row)||D[0]||null}function yn(u,p,b,S){let w=[];V(w,{x:u.x,y:u.y});let E=Ee(p,b);return E&&V(w,F(E.col,E.row)),V(w,F(S.col,S.row)),w}function hn(u,p,b){let S=e.chicks[u];if(!S||S.stage!=="queued")return!1;let w=Pt(e,S.scannerId);if(!w)return!1;let E=pn(w,p);if(!E)return!b&&w.kind==="manual"&&it(w),_(e,S.x,S.y-16,p==="left"?"NO LEFT BELT":"NO RIGHT BELT",f.danger),!1;!b&&w.kind==="manual"&&(Ge(w,S,p)?eo(w):it(w)),w.queue=w.queue.filter(K=>K!==S.id),S.stage="belt",S.route=yn(S,w,p,E),S.targetIndex=S.route.length>1?1:S.route.length,S.scannerId=null,S.nextScannerId=null,S.pendingScannerId=null,S.queueRoute=null,S.queueIndex=-1;let D=b?f.green:p==="left"?f.mixerBlue:f.truckPink;return $i(e,pe(w).x,pe(w).y,D),_(e,S.x,S.y-20,b?"AUTO":p.toUpperCase(),D),!0}function bt(u){let p=e.chicks[u];return p?(e.chicks.splice(u,1),p):null}function to(u,p=e.facilities.mixer){if(p?.processingCooldown>0){let D=e.chicks[u];D&&(D.stoppedTimer=.25);return}let b=bt(u);if(!b)return;let{x:S,y:w}=b;if(Rs(e),zo(e,p),Xo(e,p),b.sex==="poop"){let D=Ci(e);Qn(e,"mixer"),yt(e),Bi(e,S,w),_(e,S,w-18,`-${M(D)}`,f.danger);return}let E=ki(e);b.sex==="male"?zt(e):yt(e),Fi(e,S,w),_(e,S,w-18,`+${M(E)}`,f.green)}function mn(u,p=e.facilities.truck){let b=bt(u);if(!b)return;let{x:S,y:w}=b;bn(b.sex,p),Oi(e,S,w,b.sex),Ds(e,b.sex);let E=Je(e),D=yi(e,b.sex);if(b.sex==="poop"){if(Qn(e,"truck"),D)zt(e),_(e,S,w-18,`+${M(De(e))}`,f.green);else{let K=Mi(e);yt(e),_(e,S,w-18,`-${M(K)}`,f.danger)}return}if(b.sex==="female"){D?(zt(e),_(e,S,w-18,`+${M(De(e))}`,f.green)):(yt(e),_(e,S,w-18,E==="male"?"REJECT":"NO SALE",f.warn));return}if(D){zt(e),_(e,S,w-18,`+${M(De(e))}`,f.green);return}if(hi(e)){let K=gi(e);yt(e),_(e,S,w-18,`-${M(K)}`,f.danger)}else yt(e),_(e,S,w-18,"REJECT",f.warn)}function no(u,p=e.facilities.trash){if(p?.processingCooldown>0){let K=e.chicks[u];K&&(K.stoppedTimer=.25);return}let b=bt(u);if(!b)return;let{x:S,y:w}=b;Li(e,S,w,b.sex),As(e),zo(e,p),Xo(e,p);let E={amount:0},D="";if(b.sex==="poop"){E=wi(e),D=E.amount>0?` +${M(E.amount)}`:"",Qn(e,"trash"),zt(e);let K=Math.ceil(Math.max(0,Number(e.cardEffects?.composter)||0)*3*In(e));if(K>0){let ee=Oe(e,K);e.stats.composterIncome=(e.stats.composterIncome||0)+ee,e.totals.composterIncome=(e.totals.composterIncome||0)+ee,_(e,S,w-36,`COMPOST +${M(ee)}`,f.green)}_(e,S,w-18,`CLEAN${D}`,E.amount>0?f.green:f.green)}else yt(e),_(e,S,w-18,E.amount>0?`WASTE${D}`:"WASTE",E.amount>0?f.green:f.ink)}function Ot(u,p){let b=bt(u);b&&_(e,b.x,b.y-12,p,f.muted)}function bn(u,p=e.facilities.truck){let b=p||e.facilities.truck;b&&(e.truckCargo.push({sex:u,x:U(22,b.w-22),y:U(66,b.h-24)}),e.truckCargo.length>45&&e.truckCargo.shift())}function Nt(u){let p=We(u.x,u.y);if(p){let E=$(p.col,p.row);if(e.conveyorTiles.has(E))return E}let b=ti(e,u.x,u.y);if(!b)return null;let S=Q(b),w=F(S.col,S.row);return Math.hypot(u.x-w.x,u.y-w.y)<=y.cell*.55?b:null}function Jt(){let{components:u,cellToComponent:p}=ei(e);for(let b of e.chicks){if(b.stage==="flying")continue;let S=Nt(b);if(!S)continue;let w=p.get(S),E=u.get(w);E&&(E.count+=1)}for(let b of u.values())b.ratio=b.count/b.capacity;e.congestion=u,e.componentLookup=p}function oo(){for(let u of e.congestion.values()){let p=Io(e),b=mi(e);if(u.ratio>b&&u.ratio=p){let S=jt(u.id);if(!S.length||S.some(D=>D.stage!=="queued"&&D.stoppedTimer<=.2))continue;let w=e.lastExplodedComponent.get(u.id)||0,E=performance.now();E-w>900&&(e.lastExplodedComponent.set(u.id,E),vn(u))}}}function jt(u){return e.chicks.filter(p=>{let b=Nt(p);return b&&e.componentLookup?.get(b)===u})}function vn(u){let p=jt(u.id);if(!p.length)return;for(let w of p)No(e,w.sex,w.x,w.y);e.chicks=e.chicks.filter(w=>!p.some(E=>E.id===w.id));for(let w of e.scanners)w.queue=w.queue.filter(E=>e.chicks.some(D=>D.id===E));for(let w of u.cells){let E=Q(w),D=F(E.col,E.row);Ye(e,D.x,D.y,f.danger),je(e,D.x,D.y,6),Bn(e,D.x,D.y,4)}It(e,18,.75);let b=Q(u.cells[0]),S=F(b.col,b.row);e.stats.explosions=(e.stats.explosions||0)+1,e.totals.explosions=(e.totals.explosions||0)+1,_(e,S.x,S.y-22,`${Math.round(Io(e)*100)}% JAM EXPLOSION`,f.danger)}return{activeQueuedChick:Me,currentSpawnDelay:o,sortSlot:Be,updateCongestion:Jt,sortScanner:rt,updateRunning:v}}var ae=document.getElementById("gameCanvas"),ec=ae.getContext("2d"),B={shell:document.getElementById("gameShell"),money:document.getElementById("money"),turn:document.getElementById("turn"),timeLeft:document.getElementById("timeLeft"),phase:document.getElementById("phaseLabel"),comboCount:document.getElementById("comboCount"),eventBrief:document.getElementById("eventBrief"),targetBrief:document.getElementById("targetBrief"),speedBrief:document.getElementById("speedBrief"),turnProfit:document.getElementById("turnProfit"),mixerCount:document.getElementById("mixerCount"),truckFemaleCount:document.getElementById("truckFemaleCount"),truckMaleCount:document.getElementById("truckMaleCount"),poopCount:document.getElementById("poopCount"),buildStatus:document.getElementById("buildStatus"),turnSummary:document.getElementById("turnSummary"),eventPanel:document.getElementById("eventPanel"),modal:document.getElementById("modal"),modalTitle:document.getElementById("modalTitle"),modalBody:document.getElementById("modalBody"),modalActions:document.getElementById("modalActions"),hoverTooltip:document.getElementById("hoverTooltip"),manualScannerMonitor:document.getElementById("manualScannerMonitor"),hireRepairmanButton:document.getElementById("hireRepairmanButton"),debug:{panel:document.getElementById("debugPanel"),infiniteCash:document.getElementById("debugInfiniteCash"),dayInput:document.getElementById("debugDayInput"),setDay:document.getElementById("debugSetDayButton"),zeroTimer:document.getElementById("debugZeroTimerButton"),cardSelect:document.getElementById("debugCardSelect"),targetSelect:document.getElementById("debugTargetSelect"),grantCard:document.getElementById("debugGrantCardButton"),grantAllCards:document.getElementById("debugGrantAllCardsButton"),readout:document.getElementById("debugReadout")},buttons:{s1Left:document.getElementById("scanner1MixerButton"),s1Right:document.getElementById("scanner1TruckButton"),s2Left:document.getElementById("scanner2MixerButton"),s2Right:document.getElementById("scanner2TruckButton"),nextTurn:document.getElementById("nextTurnButton"),conveyor:document.getElementById("buildConveyorButton"),boostConveyor:document.getElementById("buildBoostConveyorButton"),eggFarm:document.getElementById("buildEggFarmButton"),autoScanner:document.getElementById("buildAutoScannerButton"),manualScanner:document.getElementById("buildManualScannerButton"),mixer:document.getElementById("buildMixerButton"),trash:document.getElementById("buildTrashButton"),truck:document.getElementById("buildTruckButton"),erase:document.getElementById("eraseButton"),undo:document.getElementById("undoButton"),redo:document.getElementById("redoButton")}};function tc(){let e={conveyor:"conveyor",boostConveyor:"boostConveyor",eggFarm:"eggFarm",autoScanner:"autoScanner",manualScanner:"manualScanner",mixer:"mixer",trash:"trash",truck:"truck"};for(let[t,n]of Object.entries(e))B.buttons[t]&&(B.buttons[t].innerHTML=Pr(n))}function nc(e){let t=new Set(e.tags||[]);return["upgradeEgg","crowdedFarming","hatchingFeed","extraEggOutlet"].includes(e.id)||t.has("EGG")?"Production / EGG":["upgradeTrash","poopRateBooster","composter","chemicalWeaponSubsidy"].includes(e.id)||t.has("POOP")?"Poop / Shredder":["upgradeAutoScanner","autoScannerTuning","scannerQueueSpacing"].includes(e.id)||t.has("SCANNER")?"Scanner":["bearing","dynamite"].includes(e.id)||t.has("CONVEYOR")?"Conveyor / Map":["safetyCover","preventiveMaintenance","durabilityCoating","sparePartsBin","laborExploitation"].includes(e.id)||t.has("MAINTENANCE")?"Maintenance / Risk":["dudFilter","dudRefund","freeReroll","extraCards"].includes(e.id)||t.has("CARD")?"Card Engine":t.has("ULTRA RARE")?"Ultra Rare":t.has("ECONOMY")||["upgradeMixer","upgradeTruck","recyclingSubsidy","usedMachine","newMachine","flattery","legalWork","rescueLoan"].includes(e.id)?"Economy / Shipment":"Other"}function oc(){if(!B.debug?.panel||!B.debug.cardSelect)return;let e=["Production / EGG","Poop / Shredder","Scanner","Conveyor / Map","Maintenance / Risk","Card Engine","Economy / Shipment","Ultra Rare","Other"],t=new Map(e.map(n=>[n,[]]));for(let n of Yt){let o=nc(n);t.has(o)||t.set(o,[]),t.get(o).push(n)}B.debug.cardSelect.innerHTML="";for(let n of e){let o=t.get(n)||[];if(!o.length)continue;let r=document.createElement("optgroup");r.label=n;for(let s of o){let l=document.createElement("option");l.value=s.id;let d=s.rarity==="ultraRare"?"UR":s.rarity==="rare"?"R":"C";l.textContent=`[${d}] ${s.title}`,r.appendChild(l)}B.debug.cardSelect.appendChild(r)}B.debug.cardSelect.addEventListener("change",Bt),Bt()}function Bt(){if(!B.debug?.targetSelect)return;let e=B.debug.cardSelect?.value,t=Vt(e),n=t?as(a,t):[];if(B.debug.targetSelect.innerHTML="",!n.length){let r=document.createElement("option");r.value="__none__",r.textContent=t?"No target required":"No card selected",B.debug.targetSelect.appendChild(r),B.debug.targetSelect.disabled=!0;return}let o=document.createElement("option");o.value="__auto__",o.textContent=t?.id==="dynamite"?"Auto: first 3 blocked cells":"Auto: first valid target",B.debug.targetSelect.appendChild(o);for(let r of n){let s=document.createElement("option");s.value=r.key,s.textContent=r.label,B.debug.targetSelect.appendChild(s)}B.debug.targetSelect.disabled=!1}function rc(){let e=Math.max(1,Math.floor(Number(B.debug.dayInput?.value)||1));a.turn=e,B.debug.dayInput&&(B.debug.dayInput.value=String(e)),_(a,ae.width/2-a.view.x,86-a.view.y,`DAY ${e}`,f.green),H.updatePanels(),H.updateUI(),Bt(),Lt(`Day set to ${e}.`)}function ic(){a.timeLeft=0,a.phase==="running"&&Ns(),_(a,ae.width/2-a.view.x,86-a.view.y,"TIMER 0",f.warn),H.updatePanels(),H.updateUI(),Lt("Timer set to 0.")}function sc(){let e=B.debug.cardSelect?.value,t=B.debug.targetSelect?.disabled?void 0:B.debug.targetSelect?.value,n=jo(a,e,{targetKey:t});B.debug.grantCard&&(B.debug.grantCard.textContent=n.ok?"Granted":"Failed",window.setTimeout(()=>{B.debug.grantCard&&(B.debug.grantCard.textContent="Grant Selected")},900)),Ce?.updateCongestion?.(),H.updatePanels(),H.updateUI(),Bt(),Lt(n.reason)}function lc(){let t=Yt.map(n=>jo(a,n,{targetKey:"__auto__"})).filter(n=>n.ok).length;Ce?.updateCongestion?.(),H.updatePanels(),H.updateUI(),Bt(),Lt(`Granted ${t}/${Yt.length} cards.`)}function ac(){B.debug?.infiniteCash?.checked&&a.cash<999999&&(a.cash=999999,a.totals.maxCash=Math.max(a.totals.maxCash,a.cash))}function Lt(e=""){B.debug?.readout&&(B.debug.readout.textContent=[e,`D${a.turn}`,M(a.cash),`Combo ${a.manualCombo?.count||0}`,`Event ${a.eventActive?.title||a.eventOffer?.title||"none"}`,`Rescue ${a.cardEffects?.rescueLoanCharges||0}`,`Chem ${a.cardEffects?.chemicalWeaponSubsidy||0}`].filter(Boolean).join(" | "))}var a=wo(),Y,H,Ce,Qt;function cc(e=null){let t=Yn(a,e);return e?t*Ko(a,e):t}function uc(){Object.assign(a,wo()),a.phase="running",a.view={x:0,y:0,scale:1},So(a),Us(),me(a),H.hideModal(),Ce.updateCongestion(),H.updatePanels(),H.updateUI(),Lt()}function dc(){if(a.phase!=="build")return;if(a.cardDraft?.pending||a.cardTargetPick?.pending){Y.fail(a.cardTargetPick?.pending?"Choose upgrade target first.":"Choose an upgrade card first."),H.updatePanels();return}let e=sn(a);if(e.length){Y.fail(`Cannot start: ${e[0]}`),H.updatePanels();return}me(a),Zr(a),Xi(a);let t=Math.max(0,Math.floor(a.lastResult?.profit??a.stats?.profit??0)),n=Pi(a,Math.max(1,a.turn||1),t);a.lastStartFees={fairiesTribute:n.amount||0,tribute:n},n.amount>0&&_(a,ae.width/2-a.view.x,116-a.view.y,`FAIRIES -${M(n.amount)}`,f.danger),ci(a),a.phase="running",a.turn+=1,a.timeLeft=di(a),a.shutdownTimeLeft=0,a.cleanupTimer=null,a.cleanupBlown=!1,a.chicks=[],a.effects=[],a.floatingTexts=[],a.shake={time:0,strength:0},a.truckCargo=[],Us(),a.stats=vo(),a.stats.fairiesTribute=a.lastStartFees?.fairiesTribute||0,a.stats.repairWorkerWages=a.pendingRepairWorkerWages||0;let o=a.stats.fairiesTribute+a.stats.repairWorkerWages;o>0&&(a.stats.penalty+=o,a.stats.profit-=o),a.pendingRepairWorkerWages=0;for(let r of a.scanners)r.queue=[],r.cooldown=0;for(let r of a.eggFarms)r.nextSpawn=Ce.currentSpawnDelay(r),r.lastInterval=r.nextSpawn,r.shutterProgress=0,r.shutterSparked=!1;a.buildTool=null,a.selected=null,a.groupDrag=null,a.selectionBox=null,a.pan=null,Ce.updateCongestion(),H.updatePanels(),H.updateUI()}function fc(){me(a);let e=zi(a);e.ok?_(a,ae.width/2-a.view.x,96-a.view.y,`Repairman hired -${M(e.cost)}`,f.green):(_(a,ae.width/2-a.view.x,96-a.view.y,e.reason||"Cannot hire repairman.",f.danger),Y?.fail?.(e.reason||"Cannot hire repairman.")),H.updatePanels(),H.updateUI()}function pc(){if(a.phase!=="running")return;let e=Ei(a),t=a.eventActive?{...a.eventActive}:null,n=vi(a),o=Ri(a);if(e.adjusted>0){let s=a.facilities.truck,l=s?s.x+s.w/2:ae.width/2-a.view.x,d=s?s.y+26:96-a.view.y;_(a,l,d,`${e.target==="poop"?"POOP SHIP":"SHIP"} +${M(e.adjusted)}`,f.green)}n?.bonus>0&&_(a,ae.width/2-a.view.x,96-a.view.y,`EVENT +${M(n.bonus)}`,f.green),o.amount>0&&_(a,ae.width/2-a.view.x,116-a.view.y,`CHEM SUBSIDY +${M(o.amount)}`,f.green),ui(a),a.totals.turnsCompleted+=1;let r=bi(t);if(r!==1&&(a.pendingFairiesTributeMultiplier=r),a.lastResult={...a.stats,ship:e,event:n,chemical:o,rescue:{amount:0,used:0,remaining:a.cardEffects?.rescueLoanCharges||0},fairiesTribute:{amount:a.stats.fairiesTribute||0},tributeMultiplier:r,turn:a.turn,cash:a.cash},a.cash<0){if((a.cardEffects?.rescueLoanCharges||0)>0){a.phase="loanDecision",H.showEmergencyLoanDecision(Os,Jn);return}a.phase="gameover",H.showGameOver();return}Ls()}function Ls(){a.phase="build",a.truckCargo=[],a.chicks=[],a.shutdownTimeLeft=0,a.cleanupTimer=null,a.cleanupBlown=!1,a.buildSession+=1,a.undoStack=[],a.redoStack=[],a.timeLeft=0;for(let e of a.scanners)e.queue=[];for(let e of a.eggFarms)e.shutterProgress=0,e.shutterSparked=!1;Qi(a),a.eventOffer=ai(a),Qt&&Qt.prepareDraft(),a.cardTargetPick=null,a.buildTool=null,a.groupDrag=null,a.selectionBox=null,a.pan=null,H.updatePanels(),H.showTurnResult(a.lastResult)}function Os(){if((a.cardEffects?.rescueLoanCharges||0)<=0)return Jn();a.cardEffects.rescueLoanCharges-=1,a.stats.rescueLoan=(a.stats.rescueLoan||0)+500,a.totals.rescueLoan=(a.totals.rescueLoan||0)+500;let e=Oe(a,500);a.lastResult={...a.lastResult||{},...a.stats,rescue:{amount:(a.lastResult?.rescue?.amount||0)+e,used:(a.lastResult?.rescue?.used||0)+1,remaining:a.cardEffects.rescueLoanCharges},cash:a.cash},_(a,ae.width/2-a.view.x,176-a.view.y,`RESCUE +${M(e)}`,f.green),a.cash>=0?Ls():(a.cardEffects?.rescueLoanCharges||0)>0?(a.phase="loanDecision",H.showEmergencyLoanDecision(Os,Jn)):Jn()}function Jn(){a.phase="gameover",H.showGameOver()}function Ns(){a.shutdownTimeLeft<=0&&(a.shutdownTimeLeft=a.shutdownGraceSeconds||10);for(let e of a.eggFarms){if(e.shutterSparked)continue;e.shutterProgress=.02,e.shutterSparked=!0;let t=F(e.col,e.row);Ye(a,t.x,t.y,f.ink),je(a,t.x,t.y+10,10),_(a,t.x,t.y-34,"SHUT +10s",f.ink)}}function Gs(e){a.lastTimestamp||(a.lastTimestamp=e);let t=Math.min((e-a.lastTimestamp)/1e3,.05);a.lastTimestamp=e,a.phase==="running"&&Ce.updateRunning(t,{closeFarmShutters:Ns,completeTurn:pc}),Gi(a,t,ae,Y.equipmentHitBoxes),Ce.updateCongestion(),ys(ec,ae,a,{activeQueuedChick:Ce.activeQueuedChick,selectedObject:Y.selectedObject,selectedTitle:Y.selectedTitle}),ac(),H.updateUI(),_s(),Lt(),requestAnimationFrame(Gs)}function jn(){return a.view?.scale||1}function fn(){a.view||(a.view={x:0,y:0,scale:1}),a.view.scale==null&&(a.view.scale=1)}function Zn(e){let t=ae.getBoundingClientRect();return{x:(e.clientX-t.left)*ae.width/t.width,y:(e.clientY-t.top)*ae.height/t.height}}function ht(e){let t=Zn(e),n=jn();return{x:(t.x-(a.view?.x||0))/n,y:(t.y-(a.view?.y||0))/n}}function yc(e){let t=jn();return{x:e.x*t+(a.view?.x||0),y:e.y*t+(a.view?.y||0)}}function hc(){let e={left:y.x-90,top:y.y-130,right:y.x+y.cols*y.cell+260,bottom:y.y+y.rows*y.cell+220};if(a.phase==="build")for(let t of kt(a)){let n=Ct(t);e.left=Math.min(e.left,n.x-60),e.top=Math.min(e.top,n.y-80),e.right=Math.max(e.right,n.x+n.w+80),e.bottom=Math.max(e.bottom,n.y+n.h+80)}return e}function $s(e,t){if(e<=t)return[e,t];let n=(e+t)/2;return[n,n]}function mt(){fn();let e=jn(),t=hc(),[n,o]=$s(ae.width-160-t.right*e,110-t.left*e),[r,s]=$s(ae.height-150-t.bottom*e,150-t.top*e);a.view.x=on(a.view.x,n,o),a.view.y=on(a.view.y,r,s)}function Us(){fn(),a.view.scale=1;let e=a.eggFarms?.[0],t=e?F(e.col,e.row):{x:y.x,y:y.y};a.view.x=280-t.x,a.view.y=190-t.y,mt()}function mc(e){let t=Zn(e);fn(),a.pan={start:t,viewX:a.view.x,viewY:a.view.y,moved:!1}}function bc(e){if(!a.pan)return;let t=Zn(e);Math.hypot(t.x-a.pan.start.x,t.y-a.pan.start.y)>5&&(a.pan.moved=!0),fn(),a.view.x=a.pan.viewX+t.x-a.pan.start.x,a.view.y=a.pan.viewY+t.y-a.pan.start.y,mt()}function vc(e){e.preventDefault(),fn();let t=Zn(e),n=ht(e),o=Math.exp(-e.deltaY*.0012),r=on(jn()*o,.55,1.8);a.view.scale=r,a.view.x=t.x-n.x*r,a.view.y=t.y-n.y*r,mt(),nt()}function wc(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:{type:e.type,id:e.ref.id}:null}function Sc(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:e.ref||null:null}function nt(){B.hoverTooltip&&(B.hoverTooltip.classList.remove("visible"),B.hoverTooltip.setAttribute("aria-hidden","true"),a.hover=null)}function xc(e,t){if(!B.hoverTooltip||a.phase!=="build"||a.cardTargetPick?.pending||a.groupDrag||a.selectionBox||a.pan)return nt();let n=Sc(t);if(!n)return nt();let o=Y.selectedTitle(n),r=Y.flavorText?Y.flavorText(n):"",s=Y.disconnectedWarningFor?Y.disconnectedWarningFor(n):"",l=Y.selectedInfoLines(n).slice(0,7);B.hoverTooltip.innerHTML=`${o}${s?`${s}`:r?`${r}`:""}${l.map(C=>`${C}`).join("")}`;let d=Math.min(window.innerWidth-330,e.clientX+18),v=Math.min(window.innerHeight-220,e.clientY+18);B.hoverTooltip.style.left=`${Math.max(8,d)}px`,B.hoverTooltip.style.top=`${Math.max(8,v)}px`,B.hoverTooltip.classList.add("visible"),B.hoverTooltip.setAttribute("aria-hidden","false"),a.hover={type:t.type,id:t.oldKey||t.ref?.id||null}}function kc(e){if(a.phase!=="build")return nt();xc(e,Y.equipmentAtPoint(ht(e)))}function Ws(e){nt();let t=ht(e),n=Y.equipmentAtPoint(t),o=wc(n);if(!o){a.selected=null,a.multiSelected=[],H.updatePanels();return}a.selected=o,a.multiSelected=[o],H.updatePanels();let r=Y.selectedObject();r?.type==="scanner"&&r.kind==="manual"&&Y.showManualScannerMenu(r),r?.type==="scanner"&&r.kind==="auto"&&Y.showAutoScannerMenu(r)}function Xt(){a.buildTool=null,a.selected=null,a.multiSelected=[],a.selectionBox=null,a.cardTargetPick?.mode==="autoScannerMenu"&&(a.cardTargetPick=null),H.hideModal(),nt(),H.updatePanels(),H.updateUI()}function Fs(e){return String(e).replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function Cc(e){let t=e?.queue?.[0];return t==null?null:a.chicks.find(n=>n.id===t)||null}function Mc(e){if(!e)return'WAIT';let t=e.sex==="poop"?"\u{1F4A9} POOP":e.sex==="male"?"\u2642 MALE":"\u2640 FEMALE";return`${t}`}function gc(e,t){let n=new Set(a.eggFarms.map(P=>$(P.col,P.row))),o=new Map(a.scanners.map(P=>[$(P.col,P.row),P])),r=Ee(e,"inputA"),s=r?$(r.col,r.row):null,l=new Set(Object.values(a.facilities||{}).map(P=>P.entry?$(P.entry.col,P.entry.row):null).filter(Boolean)),d=t?.sex||"",v=d==="poop"?"\u{1F4A9}":d==="male"?"\u2642":d==="female"?"\u2640":"",C=[];for(let P=e.row-2;P<=e.row+2;P+=1)for(let A=e.col-2;A<=e.col+2;A+=1){let L=$(A,P),V=["mini-cell"],ne="";A===e.col&&P===e.row?(V.push("scanner"),d&&V.push(d),ne=v||"S"):L===s?(V.push("input"),ne="IN"):n.has(L)?(V.push("egg"),ne="E"):o.has(L)?(V.push("scanner-other"),ne="S"):l.has(L)?(V.push("port"),ne="P"):a.conveyorTiles.has(L)?(V.push("belt"),ne="\u2022"):a.blockedCells?.has?.(L)&&(V.push("blocked"),ne="\xD7"),C.push(`${ne}`)}return`
${C.join("")}
`}function Tc(e){let t=yc(F(e.col,e.row)),n=76;return t.x<-n||t.y<-n||t.x>ae.width+n||t.y>ae.height+n}function _s(){if(!B.manualScannerMonitor)return;if(a.phase!=="running"){B.manualScannerMonitor.classList.remove("visible"),B.manualScannerMonitor.innerHTML="";return}let e=a.scanners.filter(t=>t.kind==="manual"&&Tc(t));if(!e.length){B.manualScannerMonitor.classList.remove("visible"),B.manualScannerMonitor.innerHTML="";return}B.manualScannerMonitor.innerHTML=e.map(t=>{let n=Cc(t),o=t.keys?.left?.label||(t.slot===0?"A":"Left"),r=t.keys?.right?.label||(t.slot===0?"D":"Right"),s=t.role===0?"MIXER":"WASTE",l=t.role===0?"S2":"TRUCK",d=n?"":" disabled";return`
S${(t.slot??0)+1}OFFSCREEN / Q:${t.queue.length}
- IN${ja(n)}SCANNER + IN${Mc(n)}SCANNER
- ${ec(t,n)} + ${gc(t,n)}
- - + +
-
`}).join(""),B.manualScannerMonitor.classList.add("visible")}B.manualScannerMonitor?.addEventListener("click",e=>{let t=e.target.closest("button[data-scanner-id]");if(!t||t.disabled)return;let n=a.scanners.find(o=>o.id===Number(t.dataset.scannerId));n&&(Te.sortScanner(n,t.dataset.side),Cs())});ie.addEventListener("contextmenu",e=>e.preventDefault());ie.addEventListener("wheel",za,{passive:!1});ie.addEventListener("pointerdown",e=>{if(a.phase!=="build")return;ie.setPointerCapture(e.pointerId);let t=at(e);if(e.button===2){qa(e);return}if(e.button!==0)return;if(a.cardTargetPick?.mode==="autoScannerMenu"){qt();return}if(a.cardTargetPick?.pending){Yt.chooseTargetAtPoint(t);return}let n=H.expansionOfferAtPoint?.(t);if(n){H.buyGridExpansion(n),ct(),K.updatePanels(),K.updateUI();return}if(H.cycleBranchModeAtPoint?.(t)){K.updatePanels(),K.updateUI();return}let o=Ge(t.x,t.y),r=H.equipmentAtPoint(t);if(!a.buildTool&&r?.type==="conveyor"&&o&&H.cycleSingleConveyorDirection?.(o)){K.updatePanels(),K.updateUI();return}if(a.buildTool==="erase"){if(!H.equipmentAtPoint(t)){qt();return}H.eraseAtPoint(t);return}if(a.buildTool){let s=Ge(t.x,t.y);if(!s&&!["mixer","trash","truck"].includes(a.buildTool)){qt();return}if(a.buildTool==="conveyor"||a.buildTool==="boostConveyor"){H.beginConveyorDrag(s);return}if(H.equipmentAtPoint(t)){a.buildTool=null,ks(e);return}H.buildAtPoint(t);return}H.startGroupDrag(e)||H.startSelectionBox(e)});ie.addEventListener("pointermove",e=>{if(a.phase!=="build"){Ze();return}Ja(e),a.pan&&e.buttons&2&&Ya(e),a.groupDrag&&e.buttons&1&&H.updateGroupDrag(e),a.selectionBox&&e.buttons&1&&H.updateSelectionBox(e),(a.buildTool==="conveyor"||a.buildTool==="boostConveyor")&&e.buttons&1&&H.continueConveyorDrag(Ge(at(e).x,at(e).y)),a.buildTool==="erase"&&e.buttons&1&&H.eraseAtPoint(at(e))});ie.addEventListener("pointerup",e=>{a.selectionBox?H.finishSelectionBox():a.groupDrag&&(a.groupDrag.committed||ks(e),H.finishGroupDrag()),e.button===2&&a.pan&&!a.pan.moved&&a.buildTool&&qt(),(a.buildTool==="conveyor"||a.buildTool==="boostConveyor")&&H.endConveyorDrag?.(),a.groupDrag=null,a.pan=null;try{ie.releasePointerCapture(e.pointerId)}catch{}});ie.addEventListener("pointerleave",Ze);ie.addEventListener("pointercancel",()=>{H?.endConveyorDrag?.(),a.groupDrag=null,a.selectionBox=null,a.pan=null,Ze()});document.addEventListener("pointerdown",e=>{!B.modal.classList.contains("visible")||!B.modal.classList.contains("equipment-popover")||e.target.closest("#modal .modal-card")||qt()},!0);B.buttons.s1Left.addEventListener("click",()=>Te.sortSlot(0,"left"));B.buttons.s1Right.addEventListener("click",()=>Te.sortSlot(0,"right"));B.buttons.s2Left.addEventListener("click",()=>Te.sortSlot(1,"left"));B.buttons.s2Right.addEventListener("click",()=>Te.sortSlot(1,"right"));B.buttons.nextTurn.addEventListener("click",Ua);B.buttons.conveyor.addEventListener("click",()=>H.setBuildTool("conveyor"));B.buttons.boostConveyor.addEventListener("click",()=>H.setBuildTool("boostConveyor"));B.buttons.eggFarm.addEventListener("click",()=>H.setBuildTool("eggFarm"));B.buttons.autoScanner.addEventListener("click",()=>H.setBuildTool("autoScanner"));B.buttons.manualScanner.addEventListener("click",()=>H.setBuildTool("manualScanner"));B.buttons.mixer.addEventListener("click",()=>H.setBuildTool("mixer"));B.buttons.trash.addEventListener("click",()=>H.setBuildTool("trash"));B.buttons.truck.addEventListener("click",()=>H.setBuildTool("truck"));B.buttons.erase.addEventListener("click",()=>H.setBuildTool("erase"));B.hireRepairmanButton?.addEventListener("click",Wa);B.debug.setDay?.addEventListener("click",Ba);B.debug.zeroTimer?.addEventListener("click",La);B.debug.grantCard?.addEventListener("click",Oa);B.debug.grantAllCards?.addEventListener("click",Na);B.buttons.undo.addEventListener("click",()=>{Mo(a)&&(ct(),K.updatePanels(),K.updateUI())});B.buttons.redo.addEventListener("click",()=>{To(a)&&(ct(),K.updatePanels(),K.updateUI())});function hs(e,t,n){let o=e.keys?.[t];return o?o.code&&n.code===o.code||o.key&&n.key.toLowerCase()===o.key:!1}window.addEventListener("keydown",e=>{if(e.repeat)return;let t=e.key.toLowerCase();if(a.phase==="running")for(let n of a.scanners.filter(o=>o.kind==="manual")){if(hs(n,"left",e)){e.preventDefault(),Te.sortScanner(n,"left");return}if(hs(n,"right",e)){e.preventDefault(),Te.sortScanner(n,"right");return}}a.phase==="build"&&(e.ctrlKey||e.metaKey)&&t==="z"&&(e.preventDefault(),Mo(a)&&(ct(),K.updatePanels(),K.updateUI())),a.phase==="build"&&(e.ctrlKey||e.metaKey)&&(t==="y"||e.shiftKey&&t==="z")&&(e.preventDefault(),To(a)&&(ct(),K.updatePanels(),K.updateUI())),e.key==="Escape"&&a.cardTargetPick?.pending&&(e.preventDefault(),a.cardTargetPick.mode==="autoScannerMenu"?qt():Yt.cancelTargetPick())});H=is({game:a,ui:B,canvas:ie,canvasPoint:at,onUpdatePanels:()=>K?.updatePanels()});Te=fs({game:a,currentConveyorSpeed:Ia,onGameOverCheck:()=>K?.checkGameOver()});Yt=Yi({game:a,ui:B,onUpdatePanels:()=>K?.updatePanels()});K=ss({game:a,ui:B,build:H,startGame:Fa,beginCardDraft:()=>Yt.showDraft(),activeQueuedChick:Te.activeQueuedChick});Aa();$a();uo(a);ye(a);Te.updateCongestion();K.updatePanels();K.updateUI();K.showTitle();Dt();requestAnimationFrame(vs); + `}).join(""),B.manualScannerMonitor.classList.add("visible")}B.manualScannerMonitor?.addEventListener("click",e=>{let t=e.target.closest("button[data-scanner-id]");if(!t||t.disabled)return;let n=a.scanners.find(o=>o.id===Number(t.dataset.scannerId));n&&(Ce.sortScanner(n,t.dataset.side),_s())});ae.addEventListener("contextmenu",e=>e.preventDefault());ae.addEventListener("wheel",vc,{passive:!1});ae.addEventListener("pointerdown",e=>{if(a.phase!=="build")return;ae.setPointerCapture(e.pointerId);let t=ht(e);if(e.button===2){mc(e);return}if(e.button!==0)return;if(a.cardTargetPick?.mode==="autoScannerMenu"){Xt();return}if(a.cardTargetPick?.pending){Qt.chooseTargetAtPoint(t);return}let n=Y.expansionOfferAtPoint?.(t);if(n){Y.buyGridExpansion(n),mt(),H.updatePanels(),H.updateUI();return}if(Y.cycleBranchModeAtPoint?.(t)){H.updatePanels(),H.updateUI();return}let o=We(t.x,t.y),r=Y.equipmentAtPoint(t);if(!a.buildTool&&r?.type==="conveyor"&&o&&Y.cycleSingleConveyorDirection?.(o)){H.updatePanels(),H.updateUI();return}if(a.buildTool==="erase"){if(!Y.equipmentAtPoint(t)){Xt();return}Y.eraseAtPoint(t);return}if(a.buildTool){let s=We(t.x,t.y);if(!s&&!["mixer","trash","truck"].includes(a.buildTool)){Xt();return}if(a.buildTool==="conveyor"||a.buildTool==="boostConveyor"){Y.beginConveyorDrag(s);return}if(Y.equipmentAtPoint(t)){a.buildTool=null,Ws(e);return}Y.buildAtPoint(t);return}Y.startGroupDrag(e)||Y.startSelectionBox(e)});ae.addEventListener("pointermove",e=>{if(a.phase!=="build"){nt();return}kc(e),a.pan&&e.buttons&2&&bc(e),a.groupDrag&&e.buttons&1&&Y.updateGroupDrag(e),a.selectionBox&&e.buttons&1&&Y.updateSelectionBox(e),(a.buildTool==="conveyor"||a.buildTool==="boostConveyor")&&e.buttons&1&&Y.continueConveyorDrag(We(ht(e).x,ht(e).y)),a.buildTool==="erase"&&e.buttons&1&&Y.eraseAtPoint(ht(e))});ae.addEventListener("pointerup",e=>{a.selectionBox?Y.finishSelectionBox():a.groupDrag&&(a.groupDrag.committed||Ws(e),Y.finishGroupDrag()),e.button===2&&a.pan&&!a.pan.moved&&a.buildTool&&Xt(),(a.buildTool==="conveyor"||a.buildTool==="boostConveyor")&&Y.endConveyorDrag?.(),a.groupDrag=null,a.pan=null;try{ae.releasePointerCapture(e.pointerId)}catch{}});ae.addEventListener("pointerleave",nt);ae.addEventListener("pointercancel",()=>{Y?.endConveyorDrag?.(),a.groupDrag=null,a.selectionBox=null,a.pan=null,nt()});document.addEventListener("pointerdown",e=>{!B.modal.classList.contains("visible")||!B.modal.classList.contains("equipment-popover")||e.target.closest("#modal .modal-card")||Xt()},!0);B.buttons.s1Left.addEventListener("click",()=>Ce.sortSlot(0,"left"));B.buttons.s1Right.addEventListener("click",()=>Ce.sortSlot(0,"right"));B.buttons.s2Left.addEventListener("click",()=>Ce.sortSlot(1,"left"));B.buttons.s2Right.addEventListener("click",()=>Ce.sortSlot(1,"right"));B.buttons.nextTurn.addEventListener("click",dc);B.buttons.conveyor.addEventListener("click",()=>Y.setBuildTool("conveyor"));B.buttons.boostConveyor.addEventListener("click",()=>Y.setBuildTool("boostConveyor"));B.buttons.eggFarm.addEventListener("click",()=>Y.setBuildTool("eggFarm"));B.buttons.autoScanner.addEventListener("click",()=>Y.setBuildTool("autoScanner"));B.buttons.manualScanner.addEventListener("click",()=>Y.setBuildTool("manualScanner"));B.buttons.mixer.addEventListener("click",()=>Y.setBuildTool("mixer"));B.buttons.trash.addEventListener("click",()=>Y.setBuildTool("trash"));B.buttons.truck.addEventListener("click",()=>Y.setBuildTool("truck"));B.buttons.erase.addEventListener("click",()=>Y.setBuildTool("erase"));B.hireRepairmanButton?.addEventListener("click",fc);B.debug.setDay?.addEventListener("click",rc);B.debug.zeroTimer?.addEventListener("click",ic);B.debug.grantCard?.addEventListener("click",sc);B.debug.grantAllCards?.addEventListener("click",lc);B.buttons.undo.addEventListener("click",()=>{Lo(a)&&(mt(),H.updatePanels(),H.updateUI(),Bt())});B.buttons.redo.addEventListener("click",()=>{Oo(a)&&(mt(),H.updatePanels(),H.updateUI(),Bt())});function Bs(e,t,n){let o=e.keys?.[t];return o?o.code&&n.code===o.code||o.key&&n.key.toLowerCase()===o.key:!1}window.addEventListener("keydown",e=>{if(e.repeat)return;let t=e.key.toLowerCase();if(a.phase==="running")for(let n of a.scanners.filter(o=>o.kind==="manual")){if(Bs(n,"left",e)){e.preventDefault(),Ce.sortScanner(n,"left");return}if(Bs(n,"right",e)){e.preventDefault(),Ce.sortScanner(n,"right");return}}a.phase==="build"&&(e.ctrlKey||e.metaKey)&&t==="z"&&(e.preventDefault(),Lo(a)&&(mt(),H.updatePanels(),H.updateUI())),a.phase==="build"&&(e.ctrlKey||e.metaKey)&&(t==="y"||e.shiftKey&&t==="z")&&(e.preventDefault(),Oo(a)&&(mt(),H.updatePanels(),H.updateUI())),e.key==="Escape"&&a.cardTargetPick?.pending&&(e.preventDefault(),a.cardTargetPick.mode==="autoScannerMenu"?Xt():Qt.cancelTargetPick())});Y=gs({game:a,ui:B,canvas:ae,canvasPoint:ht,onUpdatePanels:()=>H?.updatePanels()});Ce=Is({game:a,currentConveyorSpeed:cc,onGameOverCheck:()=>H?.checkGameOver()});Qt=ds({game:a,ui:B,onUpdatePanels:()=>H?.updatePanels()});H=Ts({game:a,ui:B,build:Y,startGame:uc,beginCardDraft:()=>Qt.showDraft(),activeQueuedChick:Ce.activeQueuedChick});tc();oc();So(a);me(a);Ce.updateCongestion();H.updatePanels();H.updateUI();H.showTitle();Lt();requestAnimationFrame(Gs); diff --git a/index.html b/index.html index a17a4a9..c4d8f27 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,7 @@ - Chick Sorter v27.6 + Chick Sorter v27.14 @@ -12,9 +12,9 @@
-
CASH・・250
+
CASH¥250
TIME60.0s
-
NET・・0
+
NET¥0
DAY1
PHASETitle
COMBO0
@@ -36,7 +36,7 @@
-

CHICK SORTER v27.6

+

CHICK SORTER v27.14

Build, expand, connect at least one valid EGG route, then start the next day.

@@ -46,24 +46,28 @@

Add / Edit Equipment

- - - - - - - - + + + + + + + + - +
Build tools unlock after each day.
-
+

Status

+
+

Next Event

+
+
@@ -77,19 +81,24 @@
+
DBG
- - +
+ + +
- - + + +
+ diff --git a/package-lock.json b/package-lock.json index ecd8824..8ba8995 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "zunda-shiwake", - "version": "27.10.0", + "version": "27.13.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "zunda-shiwake", - "version": "27.10.0", + "version": "27.13.0", "devDependencies": { "esbuild": "^0.25.0" } diff --git a/package.json b/package.json index 6e13396..94483f5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "zunda-shiwake", - "version": "27.6.0", + "version": "27.14.0", "private": true, "type": "module", "scripts": { diff --git a/src/core/balance.js b/src/core/balance.js index 083b2d2..6135bd5 100644 --- a/src/core/balance.js +++ b/src/core/balance.js @@ -1,7 +1,7 @@ // Central balance sheet for tuning gameplay. // Edit this file first when adjusting prices, income, penalties, timing, card rates, or caps. export const BALANCE = { - version: 'v27.6 direct conveyor chick movement', + version: 'v27.14 debug restore consistency patch', time: { daySeconds: 60, farmShutdownGraceSeconds: 10 @@ -32,30 +32,31 @@ export const BALANCE = { truck: 10 }, poopFine: 10, - zundaTax: { - exemption: 500, - legalWorkExemptionBonus: 250, - maxRateCash: 10000, - stepAmount: 500, - stepRate: 0.05, - maxRate: 0.95 - }, fairiesTribute: { - perDay: 10 + perDay: 10, + profitExemption: 300, + legalWorkExemptionBonus: 250, + profitRate: 0.12 }, incomeUpgradeRate: 1.10, explosionDamageDivisor: 30, maleTruckFinePerHalfDay: 30, shredderBonus: { maxCards: 30, - probabilityPercentDivisor: 2 + incomePerUpgrade: 1.25 + }, + chemicalWeaponSubsidy: { + poopPerBlock: 70, + yenPerBlock: 1200 } }, production: { poopRate: 0.08, autoScannerCooldown: 3.5, autoScannerUpgradeRate: 0.95, + autoScannerCardUpgradeRate: 0.95, autoScannerMinCooldown: 0.5, + poopRateCardBonus: 0.04, eggSpawnRanges: [ [1.95, 4.35], [1.55, 3.45], @@ -88,6 +89,14 @@ export const BALANCE = { description: 'Choose one AUTO SCANNER on the map and raise it by 1 level.', tags: ['SCANNER', 'ACTIVE'] }, + { + id: 'autoScannerTuning', + title: 'AUTO SCANNER Tuning', + rarity: 'common', + type: 'instant', + description: 'All AUTO SCANNER cooldowns use default cooldown x0.95 per copy.', + tags: ['SCANNER', 'PASSIVE'] + }, { id: 'upgradeMixer', title: 'MIXER Improvement', @@ -117,7 +126,7 @@ export const BALANCE = { }, { id: 'crowdedFarming', - title: 'Crowded Farming Contract', + title: 'Crowded Farming', rarity: 'common', type: 'instant', description: 'EGG production interval -5%. Equipment deterioration +4%. Max 10 cards.', @@ -131,6 +140,14 @@ export const BALANCE = { description: 'EGG production interval -4%. Poop rate +3%. No card limit.', tags: ['EGG', 'POOP', 'PASSIVE'] }, + { + id: 'poopRateBooster', + title: 'Poop Culture', + rarity: 'common', + type: 'instant', + description: 'Base poop rate +4 percentage points. No card limit.', + tags: ['POOP', 'PASSIVE'] + }, { id: 'safetyCover', title: 'Safety Cover', @@ -177,9 +194,7 @@ export const BALANCE = { rarity: 'common', type: 'instant', description: 'Restores 2% durability to every machine. A box of almost-compatible parts.', - tags: ['MAINTENANCE', 'ACTIVE'], - weightBase: 100, - weightLossPerCopy: 2 + tags: ['MAINTENANCE', 'ACTIVE'] }, { id: 'dudRefund', @@ -263,14 +278,6 @@ export const BALANCE = { description: 'Next Fairies tribute -50%.', tags: ['ECONOMY', 'RARE', 'ONE-SHOT'] }, - { - id: 'loan', - title: 'Loan', - rarity: 'rare', - type: 'instant', - description: 'Gain JPY 300 per elapsed day now. Pay JPY 400 per day for that many days starting tomorrow.', - tags: ['ECONOMY', 'RISK', 'RARE'] - }, { id: 'extraCards', title: 'Extra Cards', @@ -284,7 +291,7 @@ export const BALANCE = { title: 'Legal Work', rarity: 'rare', type: 'instant', - description: 'ZUNDA TAX exemption +¥250. The 95% cap point also moves up by ¥250.', + description: 'Fairies tribute profit exemption +JPY 250.', tags: ['ECONOMY', 'RARE', 'PASSIVE'] }, { @@ -292,7 +299,7 @@ export const BALANCE = { title: 'Chemical Weapons Subsidy', rarity: 'ultraRare', type: 'instant', - description: 'Each day, gain JPY 2000 per 100 poop shipped by truck. No card limit.', + description: 'Each day, gain JPY 1200 per 70 poop shipped by truck. No card limit.', tags: ['POOP', 'ULTRA RARE', 'PASSIVE'] }, { @@ -316,8 +323,9 @@ export const BALANCE = { bearing: 0, legalWork: 0, fairiesFlatteryNext: 0, + autoScannerTuning: 0, + poopRateBooster: 0, crowdedFarming: 0, - extraEggOutlet: 0, hatchingFeed: 0, safetyCover: 0, recyclingSubsidy: 0, @@ -332,8 +340,7 @@ export const BALANCE = { scannerQueueSpacing: 0, laborExploitation: 0, usedMachineActive: false, - rescueLoanCharges: 0, - loans: [] + rescueLoanCharges: 0 }, commonWeight: 8, rareWeight: 2, @@ -348,8 +355,8 @@ export const BALANCE = { multiplier: 100 } }, - contracts: { - eventChance: 0.70, + events: { + eventChance: 0.10, firstTurn: 8 }, maintenance: { @@ -383,14 +390,14 @@ export const BALANCE = { }, eggFarm: { id: 'eggFarm', type: 'eggFarm', name: 'Egg Farm', shortName: 'EGG', price: 250, - buildable: true, upgradeable: true, maxLevel: 4, upgradeCosts: [null, 300, 720, 1600] + buildable: true, upgradeable: true, maxLevel: 4 }, manualScanner: { id: 'manualScanner', type: 'scanner', kind: 'manual', name: 'Manual Scanner', shortName: 'Manual Scanner', price: 260, buildable: true, upgradeable: false }, autoScanner: { - id: 'autoScanner', type: 'scanner', kind: 'auto', name: 'Auto Scanner', shortName: 'Auto Scanner', price: 360, + id: 'autoScanner', type: 'scanner', kind: 'auto', name: 'Auto Scanner', shortName: 'Auto Scanner', price: 180, buildable: true, upgradeable: false }, mixer: { diff --git a/src/core/config.js b/src/core/config.js index 020a362..595dcb9 100644 --- a/src/core/config.js +++ b/src/core/config.js @@ -9,10 +9,12 @@ export const ECONOMY = BALANCE.economy; export const FARM_SHUTDOWN_GRACE_SECONDS = BALANCE.time.farmShutdownGraceSeconds; export const AUTO_SCANNER_COOLDOWN = BALANCE.production.autoScannerCooldown; export const AUTO_SCANNER_UPGRADE_RATE = BALANCE.production.autoScannerUpgradeRate; +export const AUTO_SCANNER_CARD_UPGRADE_RATE = BALANCE.production.autoScannerCardUpgradeRate || BALANCE.production.autoScannerUpgradeRate; export const AUTO_SCANNER_MIN_COOLDOWN = BALANCE.production.autoScannerMinCooldown; -export const CONTRACT_EVENT_CHANCE = BALANCE.contracts.eventChance; -export const CONTRACT_EVENT_FIRST_TURN = BALANCE.contracts.firstTurn; +export const DAILY_EVENT_CHANCE = BALANCE.events.eventChance; +export const DAILY_EVENT_FIRST_TURN = BALANCE.events.firstTurn; export const POOP_RATE = BALANCE.production.poopRate; +export const POOP_RATE_CARD_BONUS = BALANCE.production.poopRateCardBonus || 0; export const CONVEYOR_SPEED = BALANCE.conveyor.baseSpeed; export const CONVEYOR_SPEED_MAX = BALANCE.conveyor.maxSpeed; export const BEARING_SPEED_MULTIPLIER = BALANCE.conveyor.bearingSpeedMultiplier; diff --git a/src/core/entities.js b/src/core/entities.js index 9aa24fe..71e9c7a 100644 --- a/src/core/entities.js +++ b/src/core/entities.js @@ -1,6 +1,6 @@ import { BUILD_COSTS, FACILITY_DEFS, GRID } from './config.js'; import { nextSpawnDelay } from './state.js'; -import { currentPoopRate } from '../systems/contracts.js'; +import { currentPoopRate } from '../systems/events.js'; const DEFAULT_MANUAL_KEYS = [ [{ key: 'a', code: 'KeyA', label: 'A' }, { key: 'd', code: 'KeyD', label: 'D' }], diff --git a/src/core/state.js b/src/core/state.js index 97ad388..d44b5ac 100644 --- a/src/core/state.js +++ b/src/core/state.js @@ -27,9 +27,7 @@ export function newTurnStats() { manualComboSuccess: 0, manualComboFailure: 0, repairWorkerWages: 0, - zundaTax: 0, fairiesTribute: 0, - loanRepayment: 0, chemicalWeaponSubsidy: 0, rescueLoan: 0, cardRerollCost: 0, @@ -43,8 +41,9 @@ export function newTurnStats() { shredderBonus: 0, correct: 0, mistakes: 0, - contractBonus: 0, - contractResult: null, + eventBonus: 0, + explosions: 0, + eventResult: null, conveyorPasses: 0, eggProduced: 0 }; @@ -66,10 +65,9 @@ export function newTotalStats() { poopMixer: 0, explosionDamage: 0, shredderBonus: 0, - contractBonus: 0, - zundaTax: 0, + eventBonus: 0, + explosions: 0, fairiesTribute: 0, - loanRepayment: 0, chemicalWeaponSubsidy: 0, rescueLoan: 0, manualComboBonus: 0, @@ -83,8 +81,8 @@ export function newTotalStats() { mixerPoopFine: 0, truckPoopFine: 0, maleTruckFine: 0, - contractSuccess: 0, - contractFailed: 0, + eventSuccess: 0, + eventFailed: 0, conveyorPasses: 0, eggProduced: 0 }; @@ -139,9 +137,10 @@ export function createGame() { mixerHalfTimer: 0, congestion: new Map(), lastExplodedComponent: new Map(), - contractOffer: null, - contractActive: null, - cardEffects: { bearing: 0, legalWork: 0, fairiesFlatteryNext: 0, crowdedFarming: 0, extraEggOutlet: 0, hatchingFeed: 0, safetyCover: 0, recyclingSubsidy: 0, chemicalWeaponSubsidy: 0, preventiveMaintenance: 0, dudFilter: 0, durabilityCoating: 0, sparePartsBin: 0, dudRefund: 0, freeReroll: 0, composter: 0, scannerQueueSpacing: 0, laborExploitation: 0, usedMachineActive: false, rescueLoanCharges: 0, loans: [] }, + eventOffer: null, + eventActive: null, + pendingFairiesTributeMultiplier: 1, + cardEffects: { bearing: 0, legalWork: 0, fairiesFlatteryNext: 0, autoScannerTuning: 0, poopRateBooster: 0, crowdedFarming: 0, hatchingFeed: 0, safetyCover: 0, recyclingSubsidy: 0, chemicalWeaponSubsidy: 0, preventiveMaintenance: 0, dudFilter: 0, durabilityCoating: 0, sparePartsBin: 0, dudRefund: 0, freeReroll: 0, composter: 0, scannerQueueSpacing: 0, laborExploitation: 0, usedMachineActive: false, rescueLoanCharges: 0 }, cardDraft: { pending: false, choices: [], rerolls: 0, picksRemaining: 0 }, cardTargetPick: null, manualCombo: { count: 0, lastBonus: 0 }, @@ -205,7 +204,7 @@ const INITIAL_SCANNERS = Object.freeze([ ]); const INITIAL_EGG_FARMS = Object.freeze([ - { type: 'eggFarm', id: 1, col: 1, row: 0, level: 1, extraEggOutlet: 0, nextSpawn: 2, lastInterval: 2, spawnCounter: 0, price: BUILD_COSTS.eggFarm, builtSession: null } + { type: 'eggFarm', id: 1, col: 1, row: 0, level: 1, nextSpawn: 2, lastInterval: 2, spawnCounter: 0, price: BUILD_COSTS.eggFarm, builtSession: null } ]); function addConveyorTile(game, col, row, options = {}) { diff --git a/src/game.js b/src/game.js index 12d00cf..de630df 100644 --- a/src/game.js +++ b/src/game.js @@ -4,15 +4,15 @@ import { createGame, resetLayout, newTurnStats } from './core/state.js'; import { clamp, pointToCell, cellCenter, key, yen } from './core/utils.js'; import { expansionLots, lotBounds } from './core/gridExpansion.js'; import { commitFactoryGraphForDay, facilityConnectionIssues, scannerConnector } from './systems/routing.js'; -import { applyRevenue, collectChemicalWeaponSubsidy, collectFairiesTribute, collectLoanRepayments, collectZundaTax, settleTruckRevenue } from './systems/economy.js'; +import { applyRevenue, collectChemicalWeaponSubsidy, collectFairiesTribute, settleTruckRevenue } from './systems/economy.js'; import { undo, redo } from './systems/history.js'; import { drawAll } from './render/draw.js'; import { createBuildSystem } from './systems/buildSystem.js'; import { createUISystem } from './systems/uiSystem.js'; import { createChickSystem } from './systems/chickSystem.js'; -import { CARD_DEFS, conveyorSpeedForGame, createCardSystem, debugGrantCard } from './systems/cards.js'; +import { CARD_DEFS, cardById, conveyorSpeedForGame, createCardSystem, debugCardTargets, debugGrantCard } from './systems/cards.js'; import { floating, shockwave, sparkBurst, updateEffects } from './systems/effects.js'; -import { rollContractOffer, activateAcceptedContract, clearActiveContract, resolveContract } from './systems/contracts.js'; +import { rollEventOffer, activateEventOffer, clearActiveEvent, resolveEvent, eventDaySeconds, fairiesTributeMultiplierFromEvent } from './systems/events.js'; import { ensureMaintenanceState, hireRepairmanForNextDay, activateRepairmanForDay, deactivateRepairman, conveyorSpeedFactorForKey } from './systems/maintenance.js'; const canvas = document.getElementById('gameCanvas'); @@ -23,7 +23,7 @@ const ui = { money: document.getElementById('money'), turn: document.getElementById('turn'), timeLeft: document.getElementById('timeLeft'), phase: document.getElementById('phaseLabel'), comboCount: document.getElementById('comboCount'), eventBrief: document.getElementById('eventBrief'), targetBrief: document.getElementById('targetBrief'), speedBrief: document.getElementById('speedBrief'), turnProfit: document.getElementById('turnProfit'), mixerCount: document.getElementById('mixerCount'), truckFemaleCount: document.getElementById('truckFemaleCount'), truckMaleCount: document.getElementById('truckMaleCount'), poopCount: document.getElementById('poopCount'), - buildStatus: document.getElementById('buildStatus'), turnSummary: document.getElementById('turnSummary'), contractPanel: document.getElementById('contractPanel'), + buildStatus: document.getElementById('buildStatus'), turnSummary: document.getElementById('turnSummary'), eventPanel: document.getElementById('eventPanel'), modal: document.getElementById('modal'), modalTitle: document.getElementById('modalTitle'), modalBody: document.getElementById('modalBody'), modalActions: document.getElementById('modalActions'), hoverTooltip: document.getElementById('hoverTooltip'), manualScannerMonitor: document.getElementById('manualScannerMonitor'), @@ -35,6 +35,7 @@ const ui = { setDay: document.getElementById('debugSetDayButton'), zeroTimer: document.getElementById('debugZeroTimerButton'), cardSelect: document.getElementById('debugCardSelect'), + targetSelect: document.getElementById('debugTargetSelect'), grantCard: document.getElementById('debugGrantCardButton'), grantAllCards: document.getElementById('debugGrantAllCardsButton'), readout: document.getElementById('debugReadout') @@ -62,13 +63,139 @@ function initializeStaticText() { } } +// DEBUG UI is intentionally part of this non-production balancing build. +// Do not remove it during consistency cleanup/audit passes unless explicitly requested. +function debugCategoryForCard(card) { + const tags = new Set(card.tags || []); + if (['upgradeEgg', 'crowdedFarming', 'hatchingFeed', 'extraEggOutlet'].includes(card.id) || tags.has('EGG')) return 'Production / EGG'; + if (['upgradeTrash', 'poopRateBooster', 'composter', 'chemicalWeaponSubsidy'].includes(card.id) || tags.has('POOP')) return 'Poop / Shredder'; + if (['upgradeAutoScanner', 'autoScannerTuning', 'scannerQueueSpacing'].includes(card.id) || tags.has('SCANNER')) return 'Scanner'; + if (['bearing', 'dynamite'].includes(card.id) || tags.has('CONVEYOR')) return 'Conveyor / Map'; + if (['safetyCover', 'preventiveMaintenance', 'durabilityCoating', 'sparePartsBin', 'laborExploitation'].includes(card.id) || tags.has('MAINTENANCE')) return 'Maintenance / Risk'; + if (['dudFilter', 'dudRefund', 'freeReroll', 'extraCards'].includes(card.id) || tags.has('CARD')) return 'Card Engine'; + if (tags.has('ULTRA RARE')) return 'Ultra Rare'; + if (tags.has('ECONOMY') || ['upgradeMixer', 'upgradeTruck', 'recyclingSubsidy', 'usedMachine', 'newMachine', 'flattery', 'legalWork', 'rescueLoan'].includes(card.id)) return 'Economy / Shipment'; + return 'Other'; +} + function initializeDebugPanel() { - if (!ui.debug?.panel) return; - if (ui.debug.cardSelect) { - ui.debug.cardSelect.innerHTML = CARD_DEFS - .map(card => ``) - .join(''); + if (!ui.debug?.panel || !ui.debug.cardSelect) return; + const order = ['Production / EGG', 'Poop / Shredder', 'Scanner', 'Conveyor / Map', 'Maintenance / Risk', 'Card Engine', 'Economy / Shipment', 'Ultra Rare', 'Other']; + const groups = new Map(order.map(label => [label, []])); + for (const card of CARD_DEFS) { + const label = debugCategoryForCard(card); + if (!groups.has(label)) groups.set(label, []); + groups.get(label).push(card); } + ui.debug.cardSelect.innerHTML = ''; + for (const label of order) { + const cards = groups.get(label) || []; + if (!cards.length) continue; + const optGroup = document.createElement('optgroup'); + optGroup.label = label; + for (const card of cards) { + const option = document.createElement('option'); + option.value = card.id; + const rarity = card.rarity === 'ultraRare' ? 'UR' : card.rarity === 'rare' ? 'R' : 'C'; + option.textContent = `[${rarity}] ${card.title}`; + optGroup.appendChild(option); + } + ui.debug.cardSelect.appendChild(optGroup); + } + ui.debug.cardSelect.addEventListener('change', refreshDebugTargetSelect); + refreshDebugTargetSelect(); +} + +function refreshDebugTargetSelect() { + if (!ui.debug?.targetSelect) return; + const id = ui.debug.cardSelect?.value; + const card = cardById(id); + const targets = card ? debugCardTargets(game, card) : []; + ui.debug.targetSelect.innerHTML = ''; + if (!targets.length) { + const option = document.createElement('option'); + option.value = '__none__'; + option.textContent = card ? 'No target required' : 'No card selected'; + ui.debug.targetSelect.appendChild(option); + ui.debug.targetSelect.disabled = true; + return; + } + const auto = document.createElement('option'); + auto.value = '__auto__'; + auto.textContent = card?.id === 'dynamite' ? 'Auto: first 3 blocked cells' : 'Auto: first valid target'; + ui.debug.targetSelect.appendChild(auto); + for (const target of targets) { + const option = document.createElement('option'); + option.value = target.key; + option.textContent = target.label; + ui.debug.targetSelect.appendChild(option); + } + ui.debug.targetSelect.disabled = false; +} + +function debugSetDay() { + const day = Math.max(1, Math.floor(Number(ui.debug.dayInput?.value) || 1)); + game.turn = day; + if (ui.debug.dayInput) ui.debug.dayInput.value = String(day); + floating(game, canvas.width / 2 - game.view.x, 86 - game.view.y, `DAY ${day}`, THEME.green); + uiSystem.updatePanels(); + uiSystem.updateUI(); + refreshDebugTargetSelect(); + updateDebugReadout(`Day set to ${day}.`); +} + +function debugZeroTimer() { + game.timeLeft = 0; + if (game.phase === 'running') closeFarmShutters(); + floating(game, canvas.width / 2 - game.view.x, 86 - game.view.y, 'TIMER 0', THEME.warn); + uiSystem.updatePanels(); + uiSystem.updateUI(); + updateDebugReadout('Timer set to 0.'); +} + +function debugGrantSelectedCard() { + const id = ui.debug.cardSelect?.value; + const targetKey = ui.debug.targetSelect?.disabled ? undefined : ui.debug.targetSelect?.value; + const result = debugGrantCard(game, id, { targetKey }); + if (ui.debug.grantCard) { + ui.debug.grantCard.textContent = result.ok ? 'Granted' : 'Failed'; + window.setTimeout(() => { if (ui.debug.grantCard) ui.debug.grantCard.textContent = 'Grant Selected'; }, 900); + } + chicks?.updateCongestion?.(); + uiSystem.updatePanels(); + uiSystem.updateUI(); + refreshDebugTargetSelect(); + updateDebugReadout(result.reason); +} + +function debugGrantAllCards() { + const results = CARD_DEFS.map(card => debugGrantCard(game, card, { targetKey: '__auto__' })); + const ok = results.filter(result => result.ok).length; + chicks?.updateCongestion?.(); + uiSystem.updatePanels(); + uiSystem.updateUI(); + refreshDebugTargetSelect(); + updateDebugReadout(`Granted ${ok}/${CARD_DEFS.length} cards.`); +} + +function applyDebugState() { + if (ui.debug?.infiniteCash?.checked && game.cash < 999999) { + game.cash = 999999; + game.totals.maxCash = Math.max(game.totals.maxCash, game.cash); + } +} + +function updateDebugReadout(message = '') { + if (!ui.debug?.readout) return; + ui.debug.readout.textContent = [ + message, + `D${game.turn}`, + yen(game.cash), + `Combo ${game.manualCombo?.count || 0}`, + `Event ${game.eventActive?.title || game.eventOffer?.title || 'none'}`, + `Rescue ${game.cardEffects?.rescueLoanCharges || 0}`, + `Chem ${game.cardEffects?.chemicalWeaponSubsidy || 0}` + ].filter(Boolean).join(' | '); } const game = createGame(); @@ -96,64 +223,6 @@ function startGame() { updateDebugReadout(); } -function debugSetDay() { - const day = Math.max(1, Math.floor(Number(ui.debug.dayInput?.value) || 1)); - game.turn = day; - if (ui.debug.dayInput) ui.debug.dayInput.value = String(day); - floating(game, canvas.width / 2 - game.view.x, 86 - game.view.y, `DAY ${day}`, THEME.green); - uiSystem.updatePanels(); - uiSystem.updateUI(); - updateDebugReadout(`Day set to ${day}.`); -} - -function debugZeroTimer() { - game.timeLeft = 0; - if (game.phase === 'running') closeFarmShutters(); - floating(game, canvas.width / 2 - game.view.x, 86 - game.view.y, 'TIMER 0', THEME.warn); - uiSystem.updatePanels(); - uiSystem.updateUI(); - updateDebugReadout('Timer set to 0.'); -} - -function debugGrantSelectedCard() { - const id = ui.debug.cardSelect?.value; - const result = debugGrantCard(game, id); - if (ui.debug.grantCard) { - ui.debug.grantCard.textContent = result.ok ? 'Granted' : 'Grant failed'; - window.setTimeout(() => { if (ui.debug.grantCard) ui.debug.grantCard.textContent = 'Grant Card'; }, 900); - } - uiSystem.updatePanels(); - uiSystem.updateUI(); - updateDebugReadout(result.reason); -} - -function debugGrantAllCards() { - const results = CARD_DEFS.map(card => debugGrantCard(game, card)); - const ok = results.filter(result => result.ok).length; - uiSystem.updatePanels(); - uiSystem.updateUI(); - updateDebugReadout(`Granted ${ok}/${CARD_DEFS.length} cards.`); -} - -function applyDebugState() { - if (ui.debug?.infiniteCash?.checked && game.cash < 999999) { - game.cash = 999999; - game.totals.maxCash = Math.max(game.totals.maxCash, game.cash); - } -} - -function updateDebugReadout(message = '') { - if (!ui.debug?.readout) return; - ui.debug.readout.textContent = [ - message, - `D${game.turn}`, - yen(game.cash), - `Combo ${game.manualCombo?.count || 0}`, - `Rescue ${game.cardEffects?.rescueLoanCharges || 0}`, - `Chem ${game.cardEffects?.chemicalWeaponSubsidy || 0}` - ].filter(Boolean).join(' | '); -} - function startNextTurn() { if (game.phase !== 'build') return; if (game.cardDraft?.pending || game.cardTargetPick?.pending) { @@ -170,17 +239,15 @@ function startNextTurn() { ensureMaintenanceState(game); commitFactoryGraphForDay(game); activateRepairmanForDay(game); - const zundaBasisProfit = Math.max(0, Math.floor(game.lastResult?.profit ?? game.stats?.profit ?? 0)); - const zunda = collectZundaTax(game, zundaBasisProfit); - const loanRepayment = collectLoanRepayments(game); - game.lastStartFees = { zundaTax: zunda.tax || 0, loanRepayment: loanRepayment.amount || 0, fairiesTribute: 0 }; - if (zunda.tax > 0) floating(game, canvas.width / 2 - game.view.x, 116 - game.view.y, `ZUNDA TAX -${yen(zunda.tax)}`, THEME.danger); - if (loanRepayment.amount > 0) floating(game, canvas.width / 2 - game.view.x, 146 - game.view.y, `LOAN -${yen(loanRepayment.amount)}`, THEME.danger); + const priorProfit = Math.max(0, Math.floor(game.lastResult?.profit ?? game.stats?.profit ?? 0)); + const tribute = collectFairiesTribute(game, Math.max(1, game.turn || 1), priorProfit); + game.lastStartFees = { fairiesTribute: tribute.amount || 0, tribute }; + if (tribute.amount > 0) floating(game, canvas.width / 2 - game.view.x, 116 - game.view.y, `FAIRIES -${yen(tribute.amount)}`, THEME.danger); // Negative cash during the next production day is allowed; bankruptcy is checked only at day-end settlement before Build phase. - activateAcceptedContract(game); + activateEventOffer(game); game.phase = 'running'; game.turn += 1; - game.timeLeft = TURN_SECONDS; + game.timeLeft = eventDaySeconds(game); game.shutdownTimeLeft = 0; game.cleanupTimer = null; game.cleanupBlown = false; @@ -191,10 +258,9 @@ function startNextTurn() { game.truckCargo = []; resetCameraToFactoryStart(); game.stats = newTurnStats(); - game.stats.zundaTax = 0; - game.stats.loanRepayment = game.lastStartFees?.loanRepayment || 0; + game.stats.fairiesTribute = game.lastStartFees?.fairiesTribute || 0; game.stats.repairWorkerWages = game.pendingRepairWorkerWages || 0; - const carriedStartCosts = game.stats.loanRepayment + game.stats.repairWorkerWages; + const carriedStartCosts = game.stats.fairiesTribute + game.stats.repairWorkerWages; if (carriedStartCosts > 0) { game.stats.penalty += carriedStartCosts; game.stats.profit -= carriedStartCosts; @@ -229,7 +295,8 @@ function hireRepairman() { function completeTurn() { if (game.phase !== 'running') return; const ship = settleTruckRevenue(game); - const contract = resolveContract(game); + const activeEvent = game.eventActive ? { ...game.eventActive } : null; + const eventResult = resolveEvent(game); const chemical = collectChemicalWeaponSubsidy(game); if (ship.adjusted > 0) { const truck = game.facilities.truck; @@ -237,15 +304,13 @@ function completeTurn() { const y = truck ? truck.y + 26 : 96 - game.view.y; floating(game, x, y, `${ship.target === 'poop' ? 'POOP SHIP' : 'SHIP'} +${yen(ship.adjusted)}`, THEME.green); } - if (contract?.bonus > 0) floating(game, canvas.width / 2 - game.view.x, 96 - game.view.y, `CONTRACT +${yen(contract.bonus)}`, THEME.green); + if (eventResult?.bonus > 0) floating(game, canvas.width / 2 - game.view.x, 96 - game.view.y, `EVENT +${yen(eventResult.bonus)}`, THEME.green); if (chemical.amount > 0) floating(game, canvas.width / 2 - game.view.x, 116 - game.view.y, `CHEM SUBSIDY +${yen(chemical.amount)}`, THEME.green); - clearActiveContract(game); - const settlementDay = Math.max(1, (game.totals.turnsCompleted || 0) + 1); - const tribute = collectFairiesTribute(game, settlementDay); - game.lastBuildFees = { fairiesTribute: tribute.amount || 0, reduction: tribute.reduction || 0, turn: settlementDay }; - if (tribute.amount > 0) floating(game, canvas.width / 2 - game.view.x, 146 - game.view.y, `FAIRIES -${yen(tribute.amount)}`, THEME.danger); + clearActiveEvent(game); game.totals.turnsCompleted += 1; - game.lastResult = { ...game.stats, ship, contract, chemical, rescue: { amount: 0, used: 0, remaining: game.cardEffects?.rescueLoanCharges || 0 }, fairiesTribute: tribute, turn: game.turn, cash: game.cash }; + const tributeMultiplier = fairiesTributeMultiplierFromEvent(activeEvent); + if (tributeMultiplier !== 1) game.pendingFairiesTributeMultiplier = tributeMultiplier; + game.lastResult = { ...game.stats, ship, event: eventResult, chemical, rescue: { amount: 0, used: 0, remaining: game.cardEffects?.rescueLoanCharges || 0 }, fairiesTribute: { amount: game.stats.fairiesTribute || 0 }, tributeMultiplier, turn: game.turn, cash: game.cash }; if (game.cash < 0) { if ((game.cardEffects?.rescueLoanCharges || 0) > 0) { game.phase = 'loanDecision'; @@ -271,7 +336,7 @@ function enterBuildPhase() { for (const scanner of game.scanners) scanner.queue = []; for (const farm of game.eggFarms) { farm.shutterProgress = 0; farm.shutterSparked = false; } deactivateRepairman(game); - game.contractOffer = rollContractOffer(game); + game.eventOffer = rollEventOffer(game); if (cardSystem) cardSystem.prepareDraft(); game.cardTargetPick = null; game.buildTool = null; @@ -317,11 +382,11 @@ function update(timestamp) { if (!game.lastTimestamp) game.lastTimestamp = timestamp; const dt = Math.min((timestamp - game.lastTimestamp) / 1000, 0.05); game.lastTimestamp = timestamp; - applyDebugState(); if (game.phase === 'running') chicks.updateRunning(dt, { closeFarmShutters, completeTurn }); updateEffects(game, dt, canvas, build.equipmentHitBoxes); chicks.updateCongestion(); drawAll(ctx, canvas, game, { activeQueuedChick: chicks.activeQueuedChick, selectedObject: build.selectedObject, selectedTitle: build.selectedTitle }); + applyDebugState(); uiSystem.updateUI(); updateManualScannerMonitor(); updateDebugReadout(); @@ -654,7 +719,7 @@ ui.debug.setDay?.addEventListener('click', debugSetDay); ui.debug.zeroTimer?.addEventListener('click', debugZeroTimer); ui.debug.grantCard?.addEventListener('click', debugGrantSelectedCard); ui.debug.grantAllCards?.addEventListener('click', debugGrantAllCards); -ui.buttons.undo.addEventListener('click', () => { if (undo(game)) { clampCamera(); uiSystem.updatePanels(); uiSystem.updateUI(); } }); ui.buttons.redo.addEventListener('click', () => { if (redo(game)) { clampCamera(); uiSystem.updatePanels(); uiSystem.updateUI(); } }); +ui.buttons.undo.addEventListener('click', () => { if (undo(game)) { clampCamera(); uiSystem.updatePanels(); uiSystem.updateUI(); refreshDebugTargetSelect(); } }); ui.buttons.redo.addEventListener('click', () => { if (redo(game)) { clampCamera(); uiSystem.updatePanels(); uiSystem.updateUI(); refreshDebugTargetSelect(); } }); function scannerKeyMatches(scanner, side, event) { const binding = scanner.keys?.[side]; if (!binding) return false; diff --git a/src/render/draw.js b/src/render/draw.js index a215924..93a274d 100644 --- a/src/render/draw.js +++ b/src/render/draw.js @@ -558,7 +558,7 @@ function drawManualKeyboardIcon(ctx, scanner, c) { } function targetForTruck(game) { - return game.contractActive?.target || game.contractOffer?.target || 'female'; + return game.eventActive?.target || game.eventOffer?.target || 'female'; } function drawItemIcon(ctx, x, y, type) { if (type === 'poop') drawTinyPoop(ctx, x, y); @@ -672,7 +672,7 @@ function drawTruck(ctx, game, t = game.facilities.truck) { ctx.fillStyle = THEME.ink; ctx.font = '900 19px ui-monospace, monospace'; ctx.textAlign = 'center'; ctx.fillText(`TRUCK L${t.level}`, t.x + t.w / 2, t.y + 24); ctx.font = '900 11px ui-monospace, monospace'; ctx.fillText(`UNIT ${yen(upgradedTruckPrice(game))}`, t.x + t.w / 2, t.y + 42); const truckTargetType = targetForTruck(game); - drawTargetBadge(ctx, t.x + 15, t.y + 50, t.w - 30, `SEND ${truckTargetType.toUpperCase()}`, truckTargetType, game.contractOffer && !game.contractActive ? 'next event' : 'truck cargo'); + drawTargetBadge(ctx, t.x + 15, t.y + 50, t.w - 30, `SEND ${truckTargetType.toUpperCase()}`, truckTargetType, game.eventOffer && !game.eventActive ? 'next event' : 'truck cargo'); ctx.fillStyle = THEME.greenSoft; rect(ctx, t.x + 13, t.y + 88, t.w - 26, t.h - 103, true, false); for (const cargo of game.truckCargo) cargo.sex === 'poop' ? drawTinyPoop(ctx, t.x + cargo.x, t.y + cargo.y) : drawTinyChick(ctx, t.x + cargo.x, t.y + cargo.y, cargo.sex, cargo.sex === 'male'); drawSelection(ctx, game, 'facility', t.id, t.x + t.w / 2, t.y + t.h / 2, t.w + 12, t.h + 12); diff --git a/src/systems/buildSystem.js b/src/systems/buildSystem.js index 08bc11e..c10bc6f 100644 --- a/src/systems/buildSystem.js +++ b/src/systems/buildSystem.js @@ -7,7 +7,7 @@ import { expansionCost, expansionLot, expansionLots, lotFromChunk, lotBounds, lo import { key, parseKey, pointToCell, cellCenter, yen, directionNameBetweenCells } from '../core/utils.js'; import { TEXT, equipmentName } from '../core/text.js'; import { farmAt, scannerAt, scannerCenter, scannerFootprintCells, routeFromFarmToScanner, refreshRoutingAfterEdit, disconnectedBuildWarnings } from './routing.js'; -import { buildPrice, equipmentBasePrice, incomeMultiplier, mixerPoopPenalty, refundCash, spendCash, truckPoopPenalty, upgradedMixerPrice, upgradedTruckPrice, resaleValueFor, shredderUpgradeCount, shredderBonusChance, shredderBonusMaxCards } from './economy.js'; +import { buildPrice, equipmentBasePrice, incomeMultiplier, mixerPoopPenalty, refundCash, spendCash, truckPoopPenalty, upgradedMixerPrice, upgradedTruckPrice, resaleValueFor, shredderUpgradeCount, shredderBonusIncome, shredderBonusMaxCards } from './economy.js'; import { autoScannerCooldownSeconds } from './cards.js'; import { record } from './history.js'; import { floating, eraseEffect } from './effects.js'; @@ -941,10 +941,10 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel } if (facilityKind === 'trash') { const cards = shredderUpgradeCount(game); - const chance = shredderBonusChance(cards); + const income = shredderBonusIncome(cards); lines.push(`Bonus cards: ${cards}/${shredderBonusMaxCards()}`); - lines.push(`Bonus chance: ${(chance * 100).toFixed(2)}% for ${yen(1)} per processed item.`); - lines.push(`Expected value: ${chance.toFixed(3)} JPY per item.`); + lines.push(`Poop income bonus: ${yen(income)} per processed poop.`); + lines.push(`With enough upgrades, poop can out-earn male/female routes.`); } if (obj.entry) lines.push(`Receiver: edge cell ${obj.entry.col},${obj.entry.row} (${obj.side})`); } diff --git a/src/systems/cards.js b/src/systems/cards.js index fc2f474..091504a 100644 --- a/src/systems/cards.js +++ b/src/systems/cards.js @@ -1,7 +1,7 @@ -import { AUTO_SCANNER_COOLDOWN, AUTO_SCANNER_UPGRADE_RATE, AUTO_SCANNER_MIN_COOLDOWN, BEARING_SPEED_MULTIPLIER, CARD_BALANCE, CARD_DEFAULT_EFFECTS, CARD_DEFS as CARD_DEFINITIONS, CONVEYOR_SPEED, CONVEYOR_SPEED_MAX, ECONOMY, EGG_SPAWN_RANGES, GRID, THEME } from '../core/config.js'; +import { AUTO_SCANNER_COOLDOWN, AUTO_SCANNER_UPGRADE_RATE, AUTO_SCANNER_CARD_UPGRADE_RATE, AUTO_SCANNER_MIN_COOLDOWN, BEARING_SPEED_MULTIPLIER, CARD_BALANCE, CARD_DEFAULT_EFFECTS, CARD_DEFS as CARD_DEFINITIONS, CONVEYOR_SPEED, CONVEYOR_SPEED_MAX, ECONOMY, EGG_SPAWN_RANGES, GRID, THEME } from '../core/config.js'; import { nextSpawnDelay } from '../core/state.js'; import { cellCenter, key, yen } from '../core/utils.js'; -import { applyPenalty, applyRevenue, upgradedMixerPrice, upgradedTruckPrice, shredderUpgradeCount, rawShredderUpgradeCount, shredderBonusChance, shredderBonusMaxCards } from './economy.js'; +import { applyPenalty, applyRevenue, upgradedMixerPrice, upgradedTruckPrice, shredderUpgradeCount, rawShredderUpgradeCount, shredderBonusIncome, shredderBonusMaxCards } from './economy.js'; import { floating, shake, eraseEffect, shockwave, sparkBurst, smokeBurst } from './effects.js'; import { averageConveyorPerformance, autoScannerDelayMultiplier, ensureMaintenanceState, repairAllEquipment } from './maintenance.js'; import { scannerCenter, refreshRoutingAfterEdit } from './routing.js'; @@ -19,7 +19,7 @@ function effectCount(game, id) { } export function ensureCardState(game) { - if (!game.cardEffects) game.cardEffects = { ...CARD_DEFAULT_EFFECTS, loans: [] }; + if (!game.cardEffects) game.cardEffects = { ...CARD_DEFAULT_EFFECTS }; for (const [k, v] of Object.entries(CARD_DEFAULT_EFFECTS)) { if (game.cardEffects[k] == null) game.cardEffects[k] = Array.isArray(v) ? [] : v; } @@ -27,7 +27,6 @@ export function ensureCardState(game) { game.cardEffects.fairiesFlatteryNext = Math.max(0, game.cardEffects.fairiesFlatteryNext || 0) + Math.max(0, game.cardEffects.flattery || 0); delete game.cardEffects.flattery; } - if (!Array.isArray(game.cardEffects.loans)) game.cardEffects.loans = []; if (game.cardEffects.drawBonus != null) delete game.cardEffects.drawBonus; if (!game.cardDraft) game.cardDraft = { pending: false, choices: [], rerolls: 0, picksRemaining: 0 }; if (game.cardDraft.picksRemaining == null) game.cardDraft.picksRemaining = game.cardDraft.pending ? 1 : 0; @@ -54,13 +53,19 @@ export function conveyorSpeedForGame(game, conveyorKey = null) { const speed = CONVEYOR_SPEED * Math.pow(BEARING_SPEED_MULTIPLIER, Math.max(0, effects.bearing || 0)); const beltMultiplier = conveyorKey ? Math.max(0.1, Number(game?.conveyorMeta?.get?.(conveyorKey)?.speedMultiplier) || 1) : 1; const perf = conveyorKey ? 1 : averageConveyorPerformance(game); - return Math.min(CONVEYOR_SPEED_MAX, speed * perf) * beltMultiplier; + const eventMult = Math.max(0.01, Number(game?.eventActive?.conveyorSpeedMultiplier) || 1); + return Math.min(CONVEYOR_SPEED_MAX, speed * perf) * beltMultiplier * eventMult; } export function autoScannerCooldownSeconds(scanner, game = null) { - const upgrades = Math.max(0, (scanner?.level || 1) - 1); - const base = Math.max(AUTO_SCANNER_MIN_COOLDOWN, AUTO_SCANNER_COOLDOWN * Math.pow(AUTO_SCANNER_UPGRADE_RATE, upgrades)); - return game ? Math.max(AUTO_SCANNER_MIN_COOLDOWN, base * autoScannerDelayMultiplier(scanner)) : base; + const localUpgrades = Math.max(0, (scanner?.level || 1) - 1); + const globalUpgrades = game ? effectCount(game, 'autoScannerTuning') : 0; + const tunedBase = AUTO_SCANNER_COOLDOWN + * Math.pow(AUTO_SCANNER_UPGRADE_RATE, localUpgrades) + * Math.pow(AUTO_SCANNER_CARD_UPGRADE_RATE, globalUpgrades); + const base = Math.max(AUTO_SCANNER_MIN_COOLDOWN, tunedBase); + const eventMult = game ? Math.max(0.01, Number(game?.eventActive?.autoScannerCooldownMultiplier) || 1) : 1; + return game ? Math.max(AUTO_SCANNER_MIN_COOLDOWN, base * autoScannerDelayMultiplier(scanner) * eventMult) : base; } export function rerollCost(game) { @@ -73,35 +78,58 @@ export function cardById(id) { return CARD_DEFS.find(card => card.id === id) || null; } -export function debugGrantCard(game, cardOrId) { +export function debugCardTargets(game, cardOrId) { + const card = typeof cardOrId === 'string' ? cardById(cardOrId) : cardOrId; + ensureCardState(game); + if (!card || !(card.type === 'equipmentUpgrade' || card.type === 'cellAction')) return []; + return targetsForCard(game, card).map(target => ({ + key: targetKey(target), + label: targetLabel(game, target), + type: target.type + })); +} + +export function debugGrantCard(game, cardOrId, options = {}) { const card = typeof cardOrId === 'string' ? cardById(cardOrId) : cardOrId; ensureCardState(game); if (!card || card.type === 'dud') return { ok: false, reason: 'Card not found.' }; if (card.id === 'extraCards') { game.cardDraft = game.cardDraft || { pending: false, choices: [], rerolls: 0, picksRemaining: 0 }; game.cardDraft.choices.push(...dealCards(game, 2)); - return { ok: true, reason: `${card.title} added draft cards.` }; + return { ok: true, reason: `${card.title} added 2 draft cards.` }; } if (card.type === 'instant') { applyInstantCard(game, card); return { ok: true, reason: `${card.title} granted.` }; } if (card.type === 'equipmentUpgrade') { - const target = targetsForCard(game, card)[0]; - if (!target) return { ok: false, reason: `No valid target for ${card.title}.` }; + const targets = targetsForCard(game, card); + if (!targets.length) return { ok: false, reason: `No valid target for ${card.title}.` }; + const requestedKey = options.targetKey && options.targetKey !== '__auto__' ? String(options.targetKey) : ''; + const target = requestedKey ? targets.find(t => targetKey(t) === requestedKey) : targets[0]; + if (!target) return { ok: false, reason: `Selected target is no longer valid for ${card.title}.` }; applyEquipmentUpgrade(game, target); - return { ok: true, reason: `${card.title} applied.` }; + return { ok: true, reason: `${card.title} applied to ${targetLabel(game, target)}.` }; } if (card.type === 'cellAction' && card.target === 'blockedCell') { - const targets = targetsForCard(game, card).slice(0, 3); + const targets = targetsForCard(game, card); if (!targets.length) return { ok: false, reason: 'No blocked cells to remove.' }; - for (const target of targets) { + const requestedKeys = new Set((Array.isArray(options.targetKeys) ? options.targetKeys : [options.targetKey]) + .filter(k => k && k !== '__auto__') + .map(String)); + const selected = requestedKeys.size + ? targets.filter(t => requestedKeys.has(targetKey(t))) + : targets.slice(0, 3); + if (!selected.length) return { ok: false, reason: `Selected target is no longer valid for ${card.title}.` }; + for (const target of selected.slice(0, 3)) { game.blockedCells.delete(key(target.col, target.row)); const c = cellCenter(target.col, target.row); eraseEffect(game, c.x, c.y); + shockwave(game, c.x, c.y, THEME.danger, 42); + sparkBurst(game, c.x, c.y, 8, THEME.warn); } refreshRoutingAfterEdit(game); - return { ok: true, reason: `${card.title} removed ${targets.length} blocked cells.` }; + return { ok: true, reason: `${card.title} removed ${Math.min(3, selected.length)} blocked cell(s).` }; } return { ok: false, reason: `${card.title} cannot be debug-granted.` }; } @@ -137,9 +165,9 @@ function targetLabel(game, target) { if (target.type === 'facility' && target.id === 'trash') { const before = shredderUpgradeCount(game); const after = Math.min(shredderBonusMaxCards(), before + 1); - const beforePercent = (shredderBonusChance(before) * 100).toFixed(2); - const afterPercent = (shredderBonusChance(after) * 100).toFixed(2); - return `SHREDDER L${target.level || 1} -> L${(target.level || 1) + 1} | ${beforePercent}% -> ${afterPercent}% per item`; + const beforeIncome = shredderBonusIncome(before); + const afterIncome = shredderBonusIncome(after); + return `SHREDDER L${target.level || 1} -> L${(target.level || 1) + 1} | poop income ${yen(beforeIncome)} -> ${yen(afterIncome)} per item`; } return `${target.name || target.id} L${target.level || 1} -> L${(target.level || 1) + 1}`; } @@ -198,11 +226,7 @@ function availableCards(game) { }); } -function cardWeight(game, card) { - if (card.weightBase != null) { - const held = effectCount(game, card.id); - return Math.max(0, Number(card.weightBase) - Math.max(0, Number(card.weightLossPerCopy) || 0) * held); - } +function cardWeight(_game, card) { if (card.rarity === 'ultraRare') return ULTRA_RARE_WEIGHT; if (card.rarity === 'rare') return RARE_WEIGHT; return COMMON_WEIGHT; @@ -355,9 +379,11 @@ function applyInstantCard(game, card) { const effects = ensureCardState(game); const inc = id => { effects[id] = Math.max(0, effects[id] || 0) + 1; }; if (card.id === 'bearing') inc('bearing'); + if (card.id === 'autoScannerTuning') inc('autoScannerTuning'); if (card.id === 'legalWork') inc('legalWork'); if (card.id === 'crowdedFarming') effects.crowdedFarming = Math.min(10, (effects.crowdedFarming || 0) + 1); if (card.id === 'hatchingFeed') inc('hatchingFeed'); + if (card.id === 'poopRateBooster') inc('poopRateBooster'); if (card.id === 'safetyCover') inc('safetyCover'); if (card.id === 'recyclingSubsidy') effects.recyclingSubsidy = Math.min(3, (effects.recyclingSubsidy || 0) + 1); if (card.id === 'chemicalWeaponSubsidy') inc('chemicalWeaponSubsidy'); @@ -383,13 +409,6 @@ function applyInstantCard(game, card) { inc('rescueLoanCharges'); floating(game, GRID.x + GRID.cols * GRID.cell / 2, GRID.y - 30, 'RESCUE HELD', THEME.green); } - if (card.id === 'loan') { - const day = Math.max(1, Math.floor(Number(game.turn) || 1)); - const amount = 300 * day; - applyRevenue(game, amount); - effects.loans.push({ daysRemaining: day, dailyPayment: 400, borrowedOnTurn: game.turn || 1 }); - floating(game, GRID.x + GRID.cols * GRID.cell / 2, GRID.y - 30, `LOAN +${yen(amount)}`, THEME.green); - } } function formatPercent(value) { @@ -441,7 +460,9 @@ function cardDescription(game, card) { if (card.id === 'upgradeTrash') { const before = shredderUpgradeCount(game); const after = Math.min(shredderBonusMaxCards(), before + 1); - return `SHREDDER level +1. Bonus chance per item ${formatPercent(shredderBonusChance(before))} -> ${formatPercent(shredderBonusChance(after))}.`; + const beforeIncome = shredderBonusIncome(before); + const afterIncome = shredderBonusIncome(after); + return `SHREDDER level +1. Poop income ${yen(beforeIncome)} -> ${yen(afterIncome)} per item.`; } if (card.id === 'bearing') { const before = Math.min(CONVEYOR_SPEED_MAX, CONVEYOR_SPEED * Math.pow(BEARING_SPEED_MULTIPLIER, Math.max(0, e.bearing || 0))); @@ -450,7 +471,7 @@ function cardDescription(game, card) { } if (card.id === 'legalWork') { const before = Math.max(0, e.legalWork || 0); - return `ZUNDA TAX exemption +${yen(250)}. After pick: exemption bonus ${yen(250 * (before + 1))}.`; + return `Fairies tribute profit exemption +${yen(250)}. After pick: exemption bonus ${yen(250 * (before + 1))}.`; } if (card.id === 'crowdedFarming') { const next = Math.min(10, (e.crowdedFarming || 0) + 1); @@ -461,10 +482,12 @@ function cardDescription(game, card) { const held = Math.max(0, Number(targets[0]?.farm?.extraEggOutlet) || 0); return `Choose one EGG. Output ports ${1 + held} -> ${2 + held}. Max 4 ports per EGG.`; } - if (card.id === 'hatchingFeed') return `Held ${e.hatchingFeed || 0}. After pick: EGG interval ${formatPercent(Math.pow(0.96, (e.hatchingFeed || 0) + 1))}, poop rate ${formatPercent(Math.pow(1.03, (e.hatchingFeed || 0) + 1))}.`; + if (card.id === 'hatchingFeed') return `Held ${e.hatchingFeed || 0}. After pick: EGG interval ${formatPercent(Math.pow(0.96, (e.hatchingFeed || 0) + 1))}, poop rate multiplier ${formatPercent(Math.pow(1.03, (e.hatchingFeed || 0) + 1))}.`; + if (card.id === 'poopRateBooster') return `Held ${e.poopRateBooster || 0}. After pick: base poop rate +${Math.round((e.poopRateBooster || 0) + 1) * 4} percentage points.`; + if (card.id === 'autoScannerTuning') return `Held ${e.autoScannerTuning || 0}. After pick: all AUTO SCANNER default cooldown ${formatPercent(Math.pow(AUTO_SCANNER_CARD_UPGRADE_RATE, (e.autoScannerTuning || 0) + 1))}.`; if (card.id === 'safetyCover') return `Held ${e.safetyCover || 0}. After pick: explosion damage ${formatPercent(Math.pow(0.95, (e.safetyCover || 0) + 1))}.`; if (card.id === 'recyclingSubsidy') return `Held ${e.recyclingSubsidy || 0}/3. After pick: normal SELL refund ${Math.round(Math.min(0.8, 0.5 + 0.1 * ((e.recyclingSubsidy || 0) + 1)) * 100)}%.`; - if (card.id === 'chemicalWeaponSubsidy') return `Held ${e.chemicalWeaponSubsidy || 0}. After pick: ${yen(2000 * ((e.chemicalWeaponSubsidy || 0) + 1))} per 100 truck-shipped poop each day.`; + if (card.id === 'chemicalWeaponSubsidy') return `Held ${e.chemicalWeaponSubsidy || 0}. After pick: ${yen(1200 * ((e.chemicalWeaponSubsidy || 0) + 1))} per 70 truck-shipped poop each day.`; if (card.id === 'preventiveMaintenance') return `Held ${e.preventiveMaintenance || 0}. After pick: deterioration speed ${formatPercent(Math.pow(0.95, (e.preventiveMaintenance || 0) + 1))}.`; if (card.id === 'dudFilter') { const base = Math.max(0, Math.min(1, CARD_BALANCE.dudChancePerCard || 0)); @@ -475,7 +498,7 @@ function cardDescription(game, card) { return `Held ${held}. DUD chance per card ${formatPercent(before)} -> ${formatPercent(after)}.`; } if (card.id === 'durabilityCoating') return `Held ${e.durabilityCoating || 0}. After pick: maximum durability ${formatPercent(Math.pow(1.03, (e.durabilityCoating || 0) + 1))}.`; - if (card.id === 'sparePartsBin') return `Held ${e.sparePartsBin || 0}. Immediately restores 2% durability to every maintained machine. Offer weight: ${Math.max(0, 100 - 2 * Math.max(0, e.sparePartsBin || 0))}.`; + if (card.id === 'sparePartsBin') return `Held ${e.sparePartsBin || 0}. Immediately restores 2% durability to every maintained machine. Common card weight.`; if (card.id === 'dudRefund') return `Held ${e.dudRefund || 0}. After pick: DUD clicks award ${yen(50 * ((e.dudRefund || 0) + 1))}.`; if (card.id === 'freeReroll') return `Held ${e.freeReroll || 0}. After pick: each card screen starts with ${(e.freeReroll || 0) + 1} free reroll${(e.freeReroll || 0) + 1 === 1 ? '' : 's'}.`; if (card.id === 'composter') return `Held ${e.composter || 0}. After pick: SHREDDER poop grants ${yen(3 * ((e.composter || 0) + 1))}.`; @@ -485,10 +508,6 @@ function cardDescription(game, card) { if (card.id === 'newMachine') return 'Cancel Used Machines. Future equipment returns to normal price, refund, and durability.'; if (card.id === 'laborExploitation') return 'Repairman labor cost -30% permanently. One time only.'; if (card.id === 'rescueLoan') return `At day-end bankruptcy check, gain ${yen(500)} if cash is below ${yen(0)}. Held: ${e.rescueLoanCharges || 0}.`; - if (card.id === 'loan') { - const day = Math.max(1, Math.floor(Number(game.turn) || 1)); - return `Gain ${yen(300 * day)} now. Starting tomorrow, pay ${yen(400)} per day for ${day} days.`; - } return card.description; } diff --git a/src/systems/chickSystem.js b/src/systems/chickSystem.js index 2856079..0282165 100644 --- a/src/systems/chickSystem.js +++ b/src/systems/chickSystem.js @@ -5,7 +5,7 @@ import { key, parseKey, pointToCell, cellCenter, randomBetween, yen, inGrid } fr import { scannerById, scannerBySlot, scannerCenter, scannerConnector, nearestConveyorKey, buildConveyorComponents, autoSideFor, ensureFactoryGraph } from './routing.js'; import { applyMixerIncome, applyMixerPoopFine, applyTruckPoopFine, applyWrongTruckFine, upgradedTruckPrice, applyShredderBonus, applyRevenue } from './economy.js'; import { autoScannerCooldownSeconds, eggProductionDelayMultiplier, extraEggOutletCount, scannerQueueSpacingMultiplier } from './cards.js'; -import { productionMultiplier, truckTarget, isTargetTruckCargo, shouldFineMaleTruck } from './contracts.js'; +import { productionMultiplier, truckTarget, isTargetTruckCargo, shouldFineMaleTruck, shredderPayoutMultiplier, congestionExplosionThreshold, congestionWarningThreshold } from './events.js'; import { floating, shake, spawnPulse, scannerPulse, meatEffect, sludgeEffect, shredEffect, truckLoadEffect, shockwave, sparkBurst, smokeBurst, flyingDebris, rageEffect } from './effects.js'; import { countAutoSorted, countCorrect, countMistake, countMixer, countPoopDestination, countPoopSpawned, countTrash, countTruckCargo } from './stats.js'; import { eggSpawnDelayMultiplier, recordFarmProduction, recordConveyorPass, recordAutoScan, recordFacilityProcess, updateProcessingCooldowns, setFacilityCooldownAfterProcess, updateRepairman } from './maintenance.js'; @@ -582,11 +582,15 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck const target = truckTarget(game); const isTarget = isTargetTruckCargo(game, chick.sex); if (chick.sex === 'poop') { - const penalty = applyTruckPoopFine(game); countPoopDestination(game, 'truck'); - if (isTarget) countCorrect(game); - else countMistake(game); - floating(game, x, y - 18, `-${yen(penalty)}`, THEME.danger); + if (isTarget) { + countCorrect(game); + floating(game, x, y - 18, `+${yen(upgradedTruckPrice(game))}`, THEME.green); + } else { + const penalty = applyTruckPoopFine(game); + countMistake(game); + floating(game, x, y - 18, `-${yen(penalty)}`, THEME.danger); + } return; } if (chick.sex === 'female') { @@ -627,12 +631,14 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck countTrash(game); recordFacilityProcess(game, trash); setFacilityCooldownAfterProcess(game, trash); - const bonus = applyShredderBonus(game); - const bonusText = bonus.amount > 0 ? ` +${yen(bonus.amount)}` : ''; + let bonus = { amount: 0 }; + let bonusText = ''; if (chick.sex === 'poop') { + bonus = applyShredderBonus(game); + bonusText = bonus.amount > 0 ? ` +${yen(bonus.amount)}` : ''; countPoopDestination(game, 'trash'); countCorrect(game); - const compost = Math.max(0, Number(game.cardEffects?.composter) || 0) * 3; + const compost = Math.ceil(Math.max(0, Number(game.cardEffects?.composter) || 0) * 3 * shredderPayoutMultiplier(game)); if (compost > 0) { const compostAmount = applyRevenue(game, compost); game.stats.composterIncome = (game.stats.composterIncome || 0) + compostAmount; @@ -689,12 +695,14 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck function checkCongestionExplosions() { for (const comp of game.congestion.values()) { - if (comp.ratio > 0.8 && comp.ratio < 1) { + const explodeAt = congestionExplosionThreshold(game); + const warnAt = congestionWarningThreshold(game); + if (comp.ratio > warnAt && comp.ratio < explodeAt) { for (const chick of chicksInComponent(comp.id).slice(0, 3)) { if (Math.random() < 0.06) rageEffect(game, chick.x, chick.y - chick.radius - 8); } } - if (comp.ratio >= 1) { + if (comp.ratio >= explodeAt) { const victims = chicksInComponent(comp.id); if (!victims.length || victims.some(chick => chick.stage !== 'queued' && chick.stoppedTimer <= 0.2)) continue; const last = game.lastExplodedComponent.get(comp.id) || 0; @@ -730,7 +738,9 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck shake(game, 18, .75); const first = parseKey(comp.cells[0]); const fc = cellCenter(first.col, first.row); - floating(game, fc.x, fc.y - 22, '100% JAM EXPLOSION', THEME.danger); + game.stats.explosions = (game.stats.explosions || 0) + 1; + game.totals.explosions = (game.totals.explosions || 0) + 1; + floating(game, fc.x, fc.y - 22, `${Math.round(congestionExplosionThreshold(game) * 100)}% JAM EXPLOSION`, THEME.danger); } return { diff --git a/src/systems/economy.js b/src/systems/economy.js index e295355..8dd772d 100644 --- a/src/systems/economy.js +++ b/src/systems/economy.js @@ -1,5 +1,5 @@ import { ECONOMY, FACILITY_DEFS, INCOME_FACILITY_IDS } from '../core/config.js'; -import { factoryValue, targetTruckCount, truckTarget } from './contracts.js'; +import { factoryValue, targetTruckCount, truckTarget, poopFineMultiplier, poopValueMultiplier, shredderPayoutMultiplier } from './events.js'; function effectCount(game, id) { return Math.max(0, Number(game?.cardEffects?.[id]) || 0); @@ -53,11 +53,11 @@ export function upgradedTruckPrice(game) { } export function mixerPoopPenalty(game) { - return Math.ceil(ECONOMY.poopFine * incomeMultiplier(game, 'mixer')); + return Math.ceil(ECONOMY.poopFine * incomeMultiplier(game, 'mixer') * poopFineMultiplier(game)); } export function truckPoopPenalty(game) { - return Math.ceil(ECONOMY.poopFine * incomeMultiplier(game, 'truck')); + return Math.ceil(ECONOMY.poopFine * incomeMultiplier(game, 'truck') * poopFineMultiplier(game)); } export function maleTruckPenalty(game) { @@ -65,31 +65,36 @@ export function maleTruckPenalty(game) { return Math.ceil(baseFine * incomeMultiplier(game, 'truck')); } -export function shredderUpgradeCount(game) { - const raw = Math.max(0, (game.facilities?.trash?.level || 1) - 1); - return Math.min(ECONOMY.shredderBonus.maxCards, raw); +export function rawShredderUpgradeCount(game) { + if (!game?.facilities) return 0; + return Object.values(game.facilities) + .filter(f => (f?.baseId || f?.id) === 'trash') + .reduce((sum, f) => sum + Math.max(0, (f.level || 1) - 1), 0); } -export function rawShredderUpgradeCount(game) { - return Math.max(0, (game.facilities?.trash?.level || 1) - 1); +export function shredderUpgradeCount(game) { + return Math.min(ECONOMY.shredderBonus.maxCards, rawShredderUpgradeCount(game)); } export function shredderBonusMaxCards() { return ECONOMY.shredderBonus.maxCards; } -export function shredderBonusChance(gameOrCount) { +export function shredderBonusIncome(gameOrCount) { const count = typeof gameOrCount === 'number' ? gameOrCount : shredderUpgradeCount(gameOrCount); const capped = Math.min(ECONOMY.shredderBonus.maxCards, Math.max(0, count)); - const percent = (Math.sqrt(capped) / ECONOMY.shredderBonus.probabilityPercentDivisor) * capped; - return Math.min(1, percent / 100); + return capped > 0 ? Math.ceil(capped * (ECONOMY.shredderBonus.incomePerUpgrade || 1)) : 0; +} + +export function shredderBonusChance(gameOrCount) { + return shredderBonusIncome(gameOrCount) > 0 ? 1 : 0; } export function rollShredderBonus(game) { const cards = shredderUpgradeCount(game); - const chance = shredderBonusChance(cards); - const amount = cards > 0 && Math.random() < chance ? 1 : 0; - return { cards, chance, amount, expected: chance }; + const baseAmount = shredderBonusIncome(cards); + const amount = Math.ceil(baseAmount * shredderPayoutMultiplier(game)); + return { cards, chance: amount > 0 ? 1 : 0, amount, expected: amount, baseAmount }; } export function applyShredderBonus(game) { @@ -102,28 +107,23 @@ export function applyShredderBonus(game) { return result; } -export function zundaTaxInfo(cash, game = null) { - const rules = ECONOMY.zundaTax; - const legalWork = Math.max(0, game?.cardEffects?.legalWork || 0); - const exemption = rules.exemption + legalWork * rules.legalWorkExemptionBonus; - const maxRateCash = rules.maxRateCash + legalWork * rules.legalWorkExemptionBonus; - const profit = Math.max(0, Math.floor(Number(cash) || 0)); - const taxable = Math.max(0, profit - exemption); - if (taxable <= 0) return { profit, exemption, maxRateCash, taxable: 0, rate: 0, ratePercent: 0, tax: 0, step: 0, legalWork }; - const step = Math.max(1, Math.ceil(taxable / rules.stepAmount)); - const rate = Math.min(rules.maxRate, step * rules.stepRate); - const tax = Math.ceil(taxable * rate); - return { profit, exemption, maxRateCash, taxable, rate, ratePercent: Math.round(rate * 100), tax, step, legalWork }; -} - -export function fairiesTributeInfo(game, turn = game.turn) { +export function fairiesTributeInfo(game, turn = game.turn, basisProfit = null) { const day = Math.max(1, Math.floor(Number(turn) || 1)); - const base = Math.ceil(day * ECONOMY.fairiesTribute.perDay); + const rules = ECONOMY.fairiesTribute || { perDay: 10, profitExemption: 300, legalWorkExemptionBonus: 250, profitRate: 0.12 }; + const base = Math.ceil(day * (rules.perDay || 10)); + const profit = Math.max(0, Math.floor(Number(basisProfit ?? game?.lastResult?.profit ?? game?.stats?.profit ?? 0) || 0)); + const legalWork = Math.max(0, game?.cardEffects?.legalWork || 0); + const profitExemption = Math.max(0, (rules.profitExemption || 0) + legalWork * (rules.legalWorkExemptionBonus || 0)); + const taxableProfit = Math.max(0, profit - profitExemption); + const profitTribute = Math.ceil(taxableProfit * Math.max(0, Number(rules.profitRate) || 0)); + const gross = base + profitTribute; const flatteryCount = Math.max(0, game?.cardEffects?.fairiesFlatteryNext || game?.cardEffects?.flattery || 0); - const multiplier = flatteryCount > 0 ? Math.pow(0.5, flatteryCount) : 1; - const amount = Math.max(0, Math.ceil(base * multiplier)); - const reduction = Math.max(0, base - amount); - return { day, base, flatteryCount, perCardReduction: Math.ceil(base * 0.5), reduction, amount }; + const flatteryMultiplier = flatteryCount > 0 ? Math.pow(0.5, flatteryCount) : 1; + const eventMultiplier = Math.max(0.01, Number(game?.pendingFairiesTributeMultiplier) || 1); + const multiplier = flatteryMultiplier * eventMultiplier; + const amount = Math.max(0, Math.ceil(gross * multiplier)); + const reduction = Math.max(0, gross - amount); + return { day, base, profit, legalWork, profitExemption, taxableProfit, profitTribute, gross, flatteryCount, eventMultiplier, perCardReduction: Math.ceil(gross * 0.5), reduction, amount }; } export function resaleValueFor(hit, game) { @@ -146,7 +146,6 @@ function positivePayout(_game, amount) { } export function applyCashDelta(game, delta) { - const before = game.cash; game.cash += delta; game.stats.profit += delta; game.totals.profit += delta; @@ -173,7 +172,6 @@ export function spendCash(game, amount) { export function refundCash(game, amount) { if (amount <= 0) return; - const before = game.cash; game.cash += amount; game.stats.profit += amount; game.totals.profit += amount; @@ -222,7 +220,7 @@ export function applyExplosionDamage(game, price) { export function settleTruckRevenue(game) { const target = truckTarget(game); const targetCount = targetTruckCount(game.stats, target); - const unitPrice = upgradedTruckPrice(game); + const unitPrice = target === 'poop' ? Math.ceil(upgradedTruckPrice(game) * poopValueMultiplier(game)) : upgradedTruckPrice(game); const base = targetCount * unitPrice; const adjusted = positivePayout(game, base); game.stats.pendingTruckRevenue = adjusted; @@ -233,36 +231,33 @@ export function settleTruckRevenue(game) { return { base, adjusted, target, targetCount, unitPrice }; } -export function collectZundaTax(game, basisProfit = 0) { - const info = zundaTaxInfo(basisProfit, game); - if (info.tax <= 0) return info; - // ZUNDA TAX is settled between days. It reduces cash and lifetime totals, - // but it is intentionally excluded from the next day's NET display. - game.totals.zundaTax = (game.totals.zundaTax || 0) + info.tax; - game.totals.penalty = (game.totals.penalty || 0) + info.tax; - game.totals.profit = (game.totals.profit || 0) - info.tax; - game.cash -= info.tax; - return info; -} - -export function collectFairiesTribute(game, turn = game.turn) { - const info = fairiesTributeInfo(game, turn); +export function collectFairiesTribute(game, turn = game.turn, basisProfit = null, options = {}) { + const info = fairiesTributeInfo(game, turn, basisProfit); if (game.cardEffects) { game.cardEffects.fairiesFlatteryNext = 0; if (game.cardEffects.flattery != null) delete game.cardEffects.flattery; } + if (game.pendingFairiesTributeMultiplier != null) game.pendingFairiesTributeMultiplier = 1; if (info.amount <= 0) return info; - game.stats.fairiesTribute = (game.stats.fairiesTribute || 0) + info.amount; - game.totals.fairiesTribute = (game.totals.fairiesTribute || 0) + info.amount; - applyPenalty(game, info.amount); + if (options.recordStats) { + game.stats.fairiesTribute = (game.stats.fairiesTribute || 0) + info.amount; + game.totals.fairiesTribute = (game.totals.fairiesTribute || 0) + info.amount; + applyPenalty(game, info.amount); + } else { + game.totals.fairiesTribute = (game.totals.fairiesTribute || 0) + info.amount; + game.totals.penalty = (game.totals.penalty || 0) + info.amount; + game.totals.profit = (game.totals.profit || 0) - info.amount; + game.cash -= info.amount; + } return info; } export function collectChemicalWeaponSubsidy(game) { const cards = effectCount(game, 'chemicalWeaponSubsidy'); const poopTruck = Math.max(0, game?.stats?.poopTruck || 0); - const blocks = Math.floor(poopTruck / 100); - const amount = cards > 0 && blocks > 0 ? blocks * 2000 * cards : 0; + const rules = ECONOMY.chemicalWeaponSubsidy || { poopPerBlock: 70, yenPerBlock: 1200 }; + const blocks = Math.floor(poopTruck / Math.max(1, rules.poopPerBlock || 70)); + const amount = cards > 0 && blocks > 0 ? blocks * Math.max(0, rules.yenPerBlock || 1200) * cards : 0; if (amount > 0) { game.stats.chemicalWeaponSubsidy = (game.stats.chemicalWeaponSubsidy || 0) + amount; game.totals.chemicalWeaponSubsidy = (game.totals.chemicalWeaponSubsidy || 0) + amount; @@ -271,33 +266,10 @@ export function collectChemicalWeaponSubsidy(game) { return { cards, poopTruck, blocks, amount }; } -export function collectLoanRepayments(game) { - const effects = game?.cardEffects; - if (!effects || !Array.isArray(effects.loans) || !effects.loans.length) return { amount: 0, paidLoans: 0, remainingLoans: 0 }; - let amount = 0; - let paidLoans = 0; - const nextLoans = []; - for (const loan of effects.loans) { - if ((loan.daysRemaining || 0) <= 0) continue; - const payment = Math.max(0, Math.ceil(loan.dailyPayment || 400)); - amount += payment; - paidLoans += 1; - const daysRemaining = Math.max(0, (loan.daysRemaining || 0) - 1); - if (daysRemaining > 0) nextLoans.push({ ...loan, daysRemaining }); - } - effects.loans = nextLoans; - if (amount > 0) { - game.stats.loanRepayment = (game.stats.loanRepayment || 0) + amount; - game.totals.loanRepayment = (game.totals.loanRepayment || 0) + amount; - applyPenalty(game, amount); - } - return { amount, paidLoans, remainingLoans: nextLoans.length }; -} - export function finalScore(game) { const value = factoryValue(game); const days = Math.max(1, game.totals.turnsCompleted || game.turn || 1); - const base = Math.max(0, game.cash + game.totals.revenue + value * 0.5 + game.totals.contractBonus * 0.5); + const base = Math.max(0, game.cash + game.totals.revenue + value * 0.5 + game.totals.eventBonus * 0.5); const dailyEarned = Math.ceil(base / days); const dayPenalty = Math.floor(days * 35 + Math.max(0, days - 5) * 15); const correctBonus = game.totals.correct * 5; diff --git a/src/systems/events.js b/src/systems/events.js new file mode 100644 index 0000000..47ec63e --- /dev/null +++ b/src/systems/events.js @@ -0,0 +1,318 @@ +import { TURN_SECONDS, POOP_RATE, POOP_RATE_CARD_BONUS, DAILY_EVENT_CHANCE, DAILY_EVENT_FIRST_TURN } from '../core/config.js'; +import { getSpawnRange } from '../core/state.js'; +import { applyRevenue } from './economy.js'; + +const EVENT_TARGETS = [ + { + key: 'premiumFemaleShipment', + target: 'female', + truckTarget: 'female', + title: 'Premium Female Shipment', + route: 'Female -> Truck', + note: 'Today only: ship female chicks to Truck. Meet the export target for a bonus.', + objective: 'truckTarget' + }, + { + key: 'contaminantSampleExport', + target: 'poop', + truckTarget: 'poop', + title: 'Contaminant Sample Export', + route: 'Poop value x2', + note: 'Today only: poop is valid Truck cargo and all poop income is doubled.', + objective: 'truckTarget', + poopValueMultiplier: 2 + }, + { + key: 'healthInspection', + title: 'Health Inspection', + route: 'Poop -> Shredder', + note: 'Today only: poop mistakes are fined double. Shred enough poop for an inspection bonus.', + objective: 'poopTrash', + poopFineMultiplier: 2 + }, + { + key: 'conveyorJamWarning', + title: 'Conveyor Jam Warning', + route: 'No explosions', + note: 'Today only: jam explosions trigger at 85% congestion. Finish with zero explosions for a bonus.', + objective: 'noExplosion', + congestionExplosionThreshold: 0.85, + congestionWarningThreshold: 0.68 + }, + { + key: 'powerSavingOrder', + title: 'Power Saving Order', + route: 'Slow factory subsidy', + note: 'Today only: conveyors -20% speed and Auto Scanners +20% cooldown. A subsidy is paid at settlement.', + objective: 'flatBonus', + conveyorSpeedMultiplier: 0.8, + autoScannerCooldownMultiplier: 1.2 + }, + { + key: 'overtimeDay', + title: 'Overtime Day', + route: '80 second day', + note: 'Today only: the work day is longer. No extra reward or penalty.', + objective: 'none', + daySeconds: 80 + }, + { + key: 'shortShift', + title: 'Short Shift', + route: '40 second day', + note: 'Today only: the work day is shorter. The next Fairies tribute is reduced by 10%.', + objective: 'none', + daySeconds: 40, + fairiesTributeMultiplier: 0.9 + }, + { + key: 'chickBoom', + title: 'Chick Boom', + route: 'EGG interval x0.65', + note: 'Today only: eggs hatch faster and poop rate rises by 5 percentage points.', + objective: 'none', + productionMultiplier: 1 / 0.65, + poopRateAdd: 0.05 + }, + { + key: 'rottenFeed', + title: 'Rotten Feed', + route: 'Poop surge', + note: 'Today only: poop rate rises by 20 percentage points and Shredder poop income is multiplied by 1.5.', + objective: 'none', + poopRateAdd: 0.20, + shredderIncomeMultiplier: 1.5 + }, + { + key: 'maintenanceAudit', + title: 'Maintenance Audit', + route: 'Durability check', + note: 'Today only: machines below 50% remaining durability fail the audit. Passing with none below 50% pays a bonus.', + objective: 'maintenanceAudit' + } +]; + +function fixed(n, fallback = 0) { + const v = Number(n); + return Number.isFinite(v) ? v : fallback; +} + +function rewardFor(game, estimate = 0, scale = 1) { + const day = Math.max(1, Number(game?.turn || 1) + 1); + const valuePart = Math.floor(factoryValue(game) * (0.08 + Math.random() * 0.08)); + const cashPart = Math.floor(Math.max(0, game.cash || 0) * 0.25); + const outputPart = Math.floor(Math.max(0, estimate) * Math.max(1, day) * 0.75); + return Math.max(120, Math.ceil(Math.max(valuePart, cashPart, outputPart) * scale)); +} + +function flatEventBonus(game) { + return Math.max(0, Math.ceil(500 + Math.max(1, game?.turn || 1) * 25)); +} + +export function factoryValue(game) { + return [ + ...game.eggFarms.map(f => f.price || 0), + ...game.scanners.map(s => s.price || 0), + ...Object.values(game.facilities).map(f => f.price || 0), + ...[...game.conveyorMeta.values()].map(m => m.price || 0) + ].reduce((a, b) => a + b, 0); +} + +export function estimatedChicksPerTurn(game, productionMultiplier = 1, daySeconds = TURN_SECONDS) { + return game.eggFarms.reduce((sum, farm) => { + const [min, max] = getSpawnRange(farm); + const avg = Math.max(0.1, (min + max) / 2); + return sum + (Math.max(1, daySeconds) / avg) * Math.max(0.01, productionMultiplier || 1); + }, 0); +} + +function estimateForTemplate(game, template) { + const production = fixed(template.productionMultiplier, 1); + const seconds = fixed(template.daySeconds, TURN_SECONDS); + const estimate = estimatedChicksPerTurn(game, production, seconds); + const feedCards = Math.max(0, Number(game?.cardEffects?.hatchingFeed) || 0); + const poopRateCards = Math.max(0, Number(game?.cardEffects?.poopRateBooster) || 0); + const feedMultiplier = Math.pow(1.03, feedCards); + const baseRate = POOP_RATE + POOP_RATE_CARD_BONUS * poopRateCards; + const poopRate = Math.min(0.95, Math.max(0, (baseRate + fixed(template.poopRateAdd, 0)) * fixed(template.poopMultiplier, 1) * feedMultiplier)); + return { estimate, poopRate }; +} + +export function rollEventOffer(game) { + const nextTurn = game.turn + 1; + if (nextTurn < DAILY_EVENT_FIRST_TURN) return null; + if (Math.random() > DAILY_EVENT_CHANCE) return null; + const template = EVENT_TARGETS[Math.floor(Math.random() * EVENT_TARGETS.length)]; + const { estimate, poopRate } = estimateForTemplate(game, template); + let targetAmount = 0; + if (template.objective === 'truckTarget') targetAmount = Math.max(1, Math.ceil(estimate * 0.3)); + else if (template.objective === 'poopTrash') targetAmount = Math.max(1, Math.ceil(estimate * poopRate * 0.8)); + let reward = 0; + if (['truckTarget', 'poopTrash', 'noExplosion'].includes(template.objective)) reward = rewardFor(game, estimate); + if (template.objective === 'flatBonus') reward = flatEventBonus(game); + if (template.objective === 'maintenanceAudit') reward = flatEventBonus(game); + return { + id: `event-${game.turn}-${Date.now()}-${Math.floor(Math.random() * 9999)}`, + ...template, + target: template.target || null, + truckTarget: template.truckTarget || null, + forced: true, + productionMultiplier: fixed(template.productionMultiplier, 1), + poopMultiplier: fixed(template.poopMultiplier, 1), + poopRateAdd: fixed(template.poopRateAdd, 0), + daySeconds: fixed(template.daySeconds, TURN_SECONDS), + targetAmount, + estimatedOutput: Math.round(estimate), + reward, + createdTurn: game.turn, + oneTurnOnly: true + }; +} + +export function activateEventOffer(game) { + game.eventActive = game.eventOffer ? { ...game.eventOffer } : null; + game.eventOffer = null; +} + +export function clearActiveEvent(game) { + game.eventActive = null; +} + +export function eventDaySeconds(game) { + return Math.max(1, fixed(game.eventActive?.daySeconds, TURN_SECONDS)); +} + +export function productionMultiplier(game) { + return fixed(game.eventActive?.productionMultiplier, 1); +} + +export function currentPoopRate(game) { + const feedCards = Math.max(0, Number(game?.cardEffects?.hatchingFeed) || 0); + const poopRateCards = Math.max(0, Number(game?.cardEffects?.poopRateBooster) || 0); + const feedMultiplier = Math.pow(1.03, feedCards); + const baseRate = POOP_RATE + POOP_RATE_CARD_BONUS * poopRateCards; + const add = fixed(game.eventActive?.poopRateAdd, 0); + return Math.min(0.95, Math.max(0, (baseRate + add) * fixed(game.eventActive?.poopMultiplier, 1) * feedMultiplier)); +} + +export function truckTarget(game) { + return game.eventActive?.truckTarget || game.eventActive?.target || 'female'; +} + +export function targetTruckCount(stats, target) { + if (target === 'male') return stats.truckMale || 0; + if (target === 'poop') return stats.poopTruck || 0; + return stats.truckFemale || 0; +} + +export function isTargetTruckCargo(game, sex) { + return truckTarget(game) === sex; +} + +export function shouldFineMaleTruck(game) { + return truckTarget(game) !== 'male'; +} + +export function poopValueMultiplier(game) { + return Math.max(0.01, fixed(game.eventActive?.poopValueMultiplier, 1)); +} + +export function shredderPayoutMultiplier(game) { + return Math.max(0.01, poopValueMultiplier(game) * fixed(game.eventActive?.shredderIncomeMultiplier, 1)); +} + +export function poopFineMultiplier(game) { + return Math.max(0.01, fixed(game.eventActive?.poopFineMultiplier, 1)); +} + +export function congestionExplosionThreshold(game) { + return Math.max(0.1, Math.min(1, fixed(game.eventActive?.congestionExplosionThreshold, 1))); +} + +export function congestionWarningThreshold(game) { + return Math.max(0.1, Math.min(1, fixed(game.eventActive?.congestionWarningThreshold, 0.8))); +} + +export function fairiesTributeMultiplierFromEvent(event) { + return Math.max(0.01, fixed(event?.fairiesTributeMultiplier, 1)); +} + +function countLowDurabilityMachines(game) { + let count = 0; + const add = (uses, durability) => { + const d = Math.max(1, fixed(durability, 1)); + const u = Math.max(0, fixed(uses, 0)); + if ((1 - Math.min(1, u / d)) < 0.5) count += 1; + }; + for (const meta of game.conveyorMeta?.values?.() || []) add(meta.uses, meta.durability); + for (const farm of game.eggFarms || []) add(farm.maintenance?.uses, farm.maintenance?.durability); + for (const scanner of game.scanners || []) if (scanner.kind === 'auto') add(scanner.maintenance?.uses, scanner.maintenance?.durability); + for (const f of Object.values(game.facilities || {})) { + const kind = f?.baseId || f?.id; + if (kind === 'mixer' || kind === 'trash') add(f.maintenance?.uses, f.maintenance?.durability); + } + return count; +} + +export function resolveEvent(game) { + const event = game.eventActive; + if (!event) return null; + let count = 0; + let success = true; + let bonus = 0; + let detail = ''; + if (event.objective === 'truckTarget') { + count = targetTruckCount(game.stats, event.target); + success = count >= event.targetAmount; + bonus = success ? event.reward : 0; + } else if (event.objective === 'poopTrash') { + count = game.stats.poopTrash || 0; + success = count >= event.targetAmount; + bonus = success ? event.reward : 0; + } else if (event.objective === 'noExplosion') { + count = game.stats.explosions || 0; + success = count === 0; + bonus = success ? event.reward : 0; + detail = `${count} explosion(s)`; + } else if (event.objective === 'flatBonus') { + success = true; + bonus = event.reward; + } else if (event.objective === 'maintenanceAudit') { + count = countLowDurabilityMachines(game); + success = count === 0; + if (success) bonus = event.reward; + detail = `${count} machine(s) below 50%`; + } else { + success = true; + } + + if (bonus > 0) { + applyRevenue(game, bonus); + game.stats.eventBonus = (game.stats.eventBonus || 0) + bonus; + game.totals.eventBonus += bonus; + game.totals.eventSuccess += 1; + } else if (event.objective && event.objective !== 'none') { + game.stats.eventBonus = game.stats.eventBonus || 0; + game.totals.eventFailed += success ? 0 : 1; + if (success) game.totals.eventSuccess += 1; + } + + const result = { + title: event.title, + key: event.key, + target: event.target, + route: event.route, + objective: event.objective, + targetAmount: event.targetAmount || 0, + count, + success, + bonus, + reward: event.reward || 0, + productionMultiplier: event.productionMultiplier, + poopMultiplier: event.poopMultiplier, + daySeconds: event.daySeconds, + detail + }; + game.stats.eventResult = result; + return result; +} diff --git a/src/systems/maintenance.js b/src/systems/maintenance.js index b17815d..2c9ffaa 100644 --- a/src/systems/maintenance.js +++ b/src/systems/maintenance.js @@ -59,8 +59,9 @@ export function ensureMaintenanceState(game) { if (scanner.kind === 'auto') attachMaintenance(scanner, 'autoScanner', game); } for (const f of Object.values(game.facilities || {})) { - if (f.id === 'mixer') attachMaintenance(f, 'mixer', game); - if (f.id === 'trash') attachMaintenance(f, 'trash', game); + const kind = facilityKind(f); + if (kind === 'mixer') attachMaintenance(f, 'mixer', game); + if (kind === 'trash') attachMaintenance(f, 'trash', game); } } @@ -213,9 +214,10 @@ export function equipmentMaintenanceTargets(game) { for (const [k, meta] of game.conveyorMeta || []) targets.push({ type: 'conveyor', key: k, meta, label: `${meta.kind === 'boostConveyor' ? 'Boost Belt' : 'Belt'} ${k}`, center: cellCenter(parseKey(k).col, parseKey(k).row) }); for (const farm of game.eggFarms || []) targets.push({ type: 'eggFarm', ref: farm, label: `EGG #${farm.id}`, center: cellCenter(farm.col, farm.row) }); for (const scanner of (game.scanners || []).filter(s => s.kind === 'auto')) targets.push({ type: 'autoScanner', ref: scanner, label: `AUTO #${scanner.id}`, center: cellCenter(scanner.col, scanner.row) }); - for (const id of ['mixer', 'trash']) { - const f = game.facilities?.[id]; - if (f) targets.push({ type: id, ref: f, label: f.shortName || f.name || id, center: { x: f.x + f.w / 2, y: f.y + f.h / 2 } }); + for (const f of Object.values(game.facilities || {})) { + const kind = facilityKind(f); + if (!['mixer', 'trash'].includes(kind)) continue; + targets.push({ type: kind, ref: f, label: `${f.shortName || f.name || kind} #${f.id}`, center: { x: f.x + f.w / 2, y: f.y + f.h / 2 } }); } return targets; } diff --git a/src/systems/uiSystem.js b/src/systems/uiSystem.js index fc1a9df..0c57b2a 100644 --- a/src/systems/uiSystem.js +++ b/src/systems/uiSystem.js @@ -1,9 +1,9 @@ -import { BUILD_TOOL_IDS, CONVEYOR_SPEED_MAX, CONTRACT_EVENT_FIRST_TURN, FACILITY_DEFS, MACHINE_FACILITY_IDS, STARTING_CASH } from '../core/config.js'; +import { BUILD_TOOL_IDS, CONVEYOR_SPEED_MAX, DAILY_EVENT_FIRST_TURN, FACILITY_DEFS, MACHINE_FACILITY_IDS, STARTING_CASH } from '../core/config.js'; import { yen } from '../core/utils.js'; import { TEXT } from '../core/text.js'; import { routeFromFarmToScanner, factoryReady, facilityConnectionIssues } from './routing.js'; -import { buildPrice, fairiesTributeInfo, finalScore, maleTruckPenalty, mixerPoopPenalty, truckPoopPenalty, zundaTaxInfo } from './economy.js'; -import { truckTarget } from './contracts.js'; +import { buildPrice, fairiesTributeInfo, finalScore, maleTruckPenalty, mixerPoopPenalty, truckPoopPenalty } from './economy.js'; +import { truckTarget } from './events.js'; import { conveyorSpeedForGame } from './cards.js'; import { maintenanceSummary, repairmanDailyCost } from './maintenance.js'; @@ -27,7 +27,7 @@ export function createUISystem({ game, ui, build, startGame, beginCardDraft, act function updatePanels() { updateToolButtons(); updateBuildStatus(); - updateContractPanel(); + updateEventPanel(); updateTurnSummary(); updateHistoryButtons(); } @@ -89,52 +89,46 @@ export function createUISystem({ game, ui, build, startGame, beginCardDraft, act function updateTurnSummary() { const connected = game.eggFarms.filter(f => routeFromFarmToScanner(game, f)?.scannerId).length; const issues = facilityConnectionIssues(game); - const zundaBasisProfit = Math.max(0, Math.floor(game.lastResult?.profit ?? game.stats?.profit ?? 0)); - const tax = zundaTaxInfo(zundaBasisProfit, game); - const tributeDay = game.phase === 'running' ? Math.max(1, (game.totals.turnsCompleted || 0) + 1) : Math.max(1, Number(game.turn) || 1); - const tribute = fairiesTributeInfo(game, tributeDay); - const lastTribute = game.lastBuildFees?.turn === tributeDay ? game.lastBuildFees.fairiesTribute || 0 : null; - const lastTributeReduction = game.lastBuildFees?.turn === tributeDay ? game.lastBuildFees.reduction || 0 : 0; + const tributeBasisProfit = Math.max(0, Math.floor(game.lastResult?.profit ?? game.stats?.profit ?? 0)); + const tributeDay = Math.max(1, Number(game.turn) || 1); + const tribute = fairiesTributeInfo(game, tributeDay, tributeBasisProfit); ui.turnSummary.innerHTML = [ `Seed: ${escapeHtml(game.runSeed || 'none')} | Grid box: ${game.gridRows || 10}x${game.gridCols || 20} | Owned: ${game.gridOwnedCells || game.ownedCells?.size || ((game.gridRows || 10) * (game.gridCols || 20))} cells | Blocked: ${game.blockedCells?.size || 0} cells`, `Truck target: ${truckTarget(game).toUpperCase()} | Male fine: -${yen(maleTruckPenalty(game))}`, `Poop fine: Mixer -${yen(mixerPoopPenalty(game))} / Shipment -${yen(truckPoopPenalty(game))}`, - `ZUNDA TAX on Next Day: -${yen(tax.tax)} | basis net ${yen(zundaBasisProfit)} | taxable ${yen(tax.taxable)} x${tax.ratePercent}% | exemption ${yen(tax.exemption)} | 95% at ${yen(tax.maxRateCash)}`, - lastTribute != null - ? `Fairies tribute paid before Build: -${yen(lastTribute)}${lastTributeReduction ? ` | Flattery -${yen(lastTributeReduction)}` : ''}` - : `Fairies tribute before Build: -${yen(tribute.amount)}${tribute.reduction ? ` | Flattery -${yen(tribute.reduction)}` : ''}`, + `Fairies tribute on Next Day: -${yen(tribute.amount)} | base ${yen(tribute.base)} + profit share ${yen(tribute.profitTribute)} | basis net ${yen(tributeBasisProfit)} | exemption ${yen(tribute.profitExemption)}${tribute.reduction ? ` | reduction -${yen(tribute.reduction)}` : ''}`, `Maintenance: worst ${maintenanceSummary(game).worst.percent}% dirty (${maintenanceSummary(game).worst.label}) | Repairman: ${game.repairman?.hiredForNextDay ? 'hired next day' : game.repairman?.active ? 'working' : 'none'}`, `Manual combo: ${game.manualCombo?.count || 0} | Card draft: ${game.cardDraft?.pending ? Math.max(1, game.cardDraft.picksRemaining || 1) + ' pick(s) left' : 'ready after each day'} | Belt: ${displaySpeed()}px/s | Farms with scanner route: ${connected}/${game.eggFarms.length}`, game.cardEffects?.usedMachineActive ? 'Procurement: USED MACHINE MODE / no refunds / 60% durability' : '', issues.length ? `Blocked: ${issues[0]}` : `${TEXT.status.allPortsConnected}` ].join('
'); } - function updateContractPanel() { - if (!ui.contractPanel) return; - const offer = game.contractOffer; + function updateEventPanel() { + if (!ui.eventPanel) return; + const offer = game.eventOffer; if (game.phase !== 'build') { - ui.contractPanel.innerHTML = TEXT.status.eventPanelRunning; + ui.eventPanel.innerHTML = TEXT.status.eventPanelRunning; return; } if (!offer) { - ui.contractPanel.className = 'contract-card empty'; + ui.eventPanel.className = 'event-card empty'; const nextTurn = game.turn + 1; - if (nextTurn < CONTRACT_EVENT_FIRST_TURN) { - ui.contractPanel.innerHTML = `Event lock active.No irregular events during Days 1-7. First possible forced event: Day ${CONTRACT_EVENT_FIRST_TURN}.`; + if (nextTurn < DAILY_EVENT_FIRST_TURN) { + ui.eventPanel.innerHTML = `Event lock active.No irregular events during Days 1-7. First possible forced event: Day ${DAILY_EVENT_FIRST_TURN}.`; } else { - ui.contractPanel.innerHTML = 'No event.Random forced events can appear later.'; + ui.eventPanel.innerHTML = 'No event.Random forced events can appear later.'; } return; } - ui.contractPanel.className = 'contract-card accepted'; - ui.contractPanel.innerHTML = ` -
FORCED NEXT DAY
+ ui.eventPanel.className = 'event-card accepted'; + ui.eventPanel.innerHTML = ` +
FORCED NEXT DAY

${offer.title}

-
- Route: ${offer.route} - Target: ${offer.targetAmount} truck exports - Reward: ${yen(offer.reward)} - Output x${offer.productionMultiplier} / Poop x${offer.poopMultiplier} +
+ Effect: ${offer.route} + ${offer.targetAmount ? `Target: ${offer.targetAmount}` : 'Target: none'} + ${offer.reward ? `Reward: ${yen(offer.reward)}` : 'Reward: none'} + Time ${offer.daySeconds || 60}s / Output x${Number(offer.productionMultiplier || 1).toFixed(2)} / Poop +${Math.round((offer.poopRateAdd || 0) * 100)}pt
`; } function updateUI() { @@ -176,8 +170,9 @@ export function createUISystem({ game, ui, build, startGame, beginCardDraft, act ui.buttons.s2Left.textContent = `S2 ${s2.keys?.left?.label || 'Left'} -> Waste`; ui.buttons.s2Right.textContent = `S2 ${s2.keys?.right?.label || 'Right'} -> Truck`; } - const nextTax = zundaTaxInfo(Math.max(0, Math.floor(game.lastResult?.profit ?? game.stats?.profit ?? 0)), game).tax; - ui.buttons.nextTurn.textContent = game.phase === 'build' && nextTax > 0 ? `Next Day - ZUNDA ${yen(nextTax)}` : TEXT.actions.nextDay; + const nextTributeBasis = Math.max(0, Math.floor(game.lastResult?.profit ?? game.stats?.profit ?? 0)); + const nextTribute = fairiesTributeInfo(game, Math.max(1, Number(game.turn) || 1), nextTributeBasis).amount; + ui.buttons.nextTurn.textContent = game.phase === 'build' && nextTribute > 0 ? `Next Day - Fairies ${yen(nextTribute)}` : TEXT.actions.nextDay; ui.buttons.nextTurn.disabled = game.phase !== 'build' || !!game.cardDraft?.pending || !!game.cardTargetPick?.pending || !factoryReady(game); } @@ -187,16 +182,16 @@ export function createUISystem({ game, ui, build, startGame, beginCardDraft, act ui.targetBrief.textContent = `TRUCK TARGET: ${target}`; ui.speedBrief.textContent = `BELT: ${displaySpeed()} px/s | COMBO: ${game.manualCombo?.count || 0}`; ui.speedBrief.title = `Conveyor speed does not increase by day. Degraded belts reduce speed. Cap: ${CONVEYOR_SPEED_MAX}px/s.`; - const active = game.contractActive; - const offer = game.contractOffer; + const active = game.eventActive; + const offer = game.eventOffer; if (active) { - ui.eventBrief.textContent = `ACTIVE EVENT: ${active.route} | Output x${active.productionMultiplier} | Poop x${active.poopMultiplier}`; + ui.eventBrief.textContent = `ACTIVE EVENT: ${active.title} | ${active.route}`; ui.eventBrief.className = 'event-brief active'; } else if (game.phase === 'build' && offer) { - ui.eventBrief.textContent = `NEXT DAY EVENT: ${offer.route} | Target ${offer.targetAmount} | Reward ${yen(offer.reward)}`; + ui.eventBrief.textContent = `NEXT DAY EVENT: ${offer.title} | ${offer.route}${offer.targetAmount ? ` | Target ${offer.targetAmount}` : ''}${offer.reward ? ` | Reward ${yen(offer.reward)}` : ''}`; ui.eventBrief.className = 'event-brief next'; - } else if (game.phase === 'build' && game.turn + 1 < CONTRACT_EVENT_FIRST_TURN) { - ui.eventBrief.textContent = `NO EVENTS UNTIL DAY ${CONTRACT_EVENT_FIRST_TURN}`; + } else if (game.phase === 'build' && game.turn + 1 < DAILY_EVENT_FIRST_TURN) { + ui.eventBrief.textContent = `NO EVENTS UNTIL DAY ${DAILY_EVENT_FIRST_TURN}`; ui.eventBrief.className = 'event-brief locked'; } else { ui.eventBrief.textContent = 'NO ACTIVE EVENT'; @@ -237,11 +232,10 @@ export function createUISystem({ game, ui, build, startGame, beginCardDraft, act
DUD refund income${positive(r.dudRefundIncome || 0)}
Manual combo bonus${positive(r.manualComboBonus || 0)}
Chemical subsidy${positive(r.chemicalWeaponSubsidy || 0)}
-
Contract bonus${positive(r.contractBonus || 0)}
+
Event bonus${positive(r.eventBonus || 0)}
Penalties${negative(penalties)}
Fairies fee${negative(r.fairiesTribute?.amount || r.fairiesTribute || 0)}
Repair worker wages${negative(r.repairWorkerWages || 0)}
-
Loan repayments${negative(r.loanRepayment || 0)}

Income ${yen(r.revenue)} - losses ${yen(r.penalty)} = ${yen(r.profit)}

`; ui.modalActions.innerHTML = ''; @@ -277,8 +271,8 @@ export function createUISystem({ game, ui, build, startGame, beginCardDraft, act ui.modalBody.innerHTML = `

Your cash went negative.

Final Score${fs.score}
Survival${game.totals.turnsCompleted} days
Final Cash${yen(game.cash)}
Accuracy${accuracy}%
Score breakdown -
Formula
Base = Cash + Total revenue + Factory value 繝サ繝サ繝サ0.5 + Contract bonus 繝サ繝サ繝サ0.5 = ${yen(fs.base)}
Daily earned = ceil(Base 繝サ繝サ・ス・キ Days) = ${yen(fs.dailyEarned)}
Score = max(0, floor(Base + Daily earned + Correct繝サ繝サ繝サ - Total outflow - Day penalty)) = ${fs.score}
-
Factory Value${yen(fs.factoryValue)}
Total Revenue${yen(game.totals.revenue)}
Daily Earned${yen(fs.dailyEarned)} / day
Total Outflow${yen(game.totals.penalty)}
ZUNDA TAX${yen(game.totals.zundaTax)}
Fairies Tribute${yen(game.totals.fairiesTribute || 0)}
Correct Sorts${game.totals.correct}
Auto Sorted${game.totals.autoSorted}
Poop Control${game.totals.poopTrash} trashed / ${game.totals.poopTruck} shipped / ${game.totals.poopMixer} mixer
Explosion Penalty${yen(game.totals.explosionDamage)}
Contract Bonus${yen(game.totals.contractBonus)}
Day Penalty-${fs.dayPenalty}
Contracts${game.totals.contractSuccess} success / ${game.totals.contractFailed} failed
+
Formula
Base = Cash + Total revenue + Factory value ×0.5 + Event bonus ×0.5 = ${yen(fs.base)}
Daily earned = ceil(Base ÷ Days) = ${yen(fs.dailyEarned)}
Score = max(0, floor(Base + Daily earned + Correct bonus - Total outflow - Day penalty)) = ${fs.score}
+
Factory Value${yen(fs.factoryValue)}
Total Revenue${yen(game.totals.revenue)}
Daily Earned${yen(fs.dailyEarned)} / day
Total Outflow${yen(game.totals.penalty)}
Fairies Tribute${yen(game.totals.fairiesTribute || 0)}
Correct Sorts${game.totals.correct}
Auto Sorted${game.totals.autoSorted}
Poop Control${game.totals.poopTrash} trashed / ${game.totals.poopTruck} shipped / ${game.totals.poopMixer} mixer
Explosion Penalty${yen(game.totals.explosionDamage)}
Event Bonus${yen(game.totals.eventBonus)}
Day Penalty-${fs.dayPenalty}
Events${game.totals.eventSuccess} success / ${game.totals.eventFailed} failed
`; ui.modalActions.innerHTML = ''; ui.modalActions.appendChild(button(TEXT.actions.restart || 'Restart', startGame, 'primary-button restart-button')); diff --git a/styles.css b/styles.css index 796ac90..83b96a5 100644 --- a/styles.css +++ b/styles.css @@ -66,31 +66,32 @@ h1, h2, p { margin: 0; } .facility-action.danger { background: #ffdada; } .control-dock { position: absolute; z-index: 7; left: 50%; bottom: 12px; transform: translateX(-50%); display: grid; grid-template-columns: repeat(4, 150px); gap: 8px; padding: 7px; border: 3px solid var(--line); background: rgba(255,255,255,.90); } .sort-button { min-height: 46px; font-size: 12px; } +/* Debug UI is intentionally kept for active balancing builds. Do not remove during cleanup/audit passes unless explicitly requested. */ .debug-panel { position: absolute; z-index: 9; left: 10px; bottom: 10px; - width: min(292px, calc(100% - 20px)); + width: min(410px, calc(100% - 20px)); border: 3px solid var(--line); - background: rgba(255,255,255,.94); + background: rgba(255,255,255,.96); box-shadow: 4px 4px 0 rgba(16,32,21,.16); font-weight: 900; } .debug-panel summary { cursor: pointer; - padding: 4px 8px; + padding: 5px 8px; color: var(--danger); font-size: 14px; line-height: 1.1; } .debug-body { display: grid; - grid-template-columns: 1fr 74px; - gap: 5px; - padding: 6px; + grid-template-columns: 1fr 92px; + gap: 6px; + padding: 7px; border-top: 3px solid var(--line); - font-size: 13px; + font-size: 12px; line-height: 1.15; } .debug-body label, @@ -101,12 +102,20 @@ h1, h2, p { margin: 0; } font: inherit; } .debug-check, -.debug-card { +.debug-card, +.debug-target, +.debug-readout { + grid-column: 1 / -1; +} +.debug-row { + display: grid; + grid-template-columns: 1fr 92px; + gap: 6px; grid-column: 1 / -1; } .debug-day { display: grid; - grid-template-columns: 34px 1fr; + grid-template-columns: 38px 1fr; align-items: center; gap: 4px; } @@ -115,7 +124,7 @@ h1, h2, p { margin: 0; } background: var(--white); cursor: pointer; font-weight: 900; - padding: 4px 5px; + padding: 5px 6px; line-height: 1.05; } .debug-body input[type="number"], @@ -123,18 +132,20 @@ h1, h2, p { margin: 0; } width: 100%; border: 2px solid var(--line); background: var(--white); - padding: 3px 4px; - min-height: 28px; + padding: 4px 5px; + min-height: 29px; +} +.debug-target select:disabled { + opacity: .55; } .debug-readout { - grid-column: 1 / -1; border: 2px solid var(--line); background: #f7fff5; color: var(--muted); padding: 5px; - line-height: 1.2; - max-height: 48px; - overflow: hidden; + line-height: 1.25; + max-height: 64px; + overflow: auto; } .modal { position: fixed; inset: 0; z-index: 20; display: none; align-items: center; justify-content: center; padding: 22px; background: rgba(16,32,21,.45); } .modal.visible { display: flex; } @@ -168,17 +179,17 @@ h1, h2, p { margin: 0; } .route-cards, .result-grid { grid-template-columns: 1fr; } } -.contract-card { border: 3px solid var(--line); background: #f7fff5; padding: 12px; line-height: 1.35; color: var(--ink); font-size: 11px; box-shadow: 4px 4px 0 rgba(16,32,21,.14); } -.contract-card.empty { color: var(--muted); background: rgba(255,255,255,.72); } -.contract-card.empty strong { display: block; color: var(--ink); margin-bottom: 4px; } -.contract-card h3 { margin: 2px 0 7px; font-size: 14px; text-transform: uppercase; letter-spacing: .04em; } -.contract-card p { margin: 5px 0; } -.contract-card.accepted { background: var(--green-soft); box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(16,32,21,.14); } -.contract-card.declined { background: #f1f1f1; color: var(--muted); } -.contract-status { display: inline-block; padding: 2px 7px; border: 2px solid var(--line); background: var(--white); font-size: 9px; font-weight: 900; letter-spacing: .1em; margin-bottom: 4px; } -.contract-metrics { display: grid; grid-template-columns: 1fr; gap: 4px; margin: 8px 0; } -.contract-metrics span { display: block; border: 2px solid rgba(16,32,21,.55); background: rgba(255,255,255,.82); padding: 5px; font-weight: 900; color: var(--ink); } -.contract-actions { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; } +.event-card { border: 3px solid var(--line); background: #f7fff5; padding: 12px; line-height: 1.35; color: var(--ink); font-size: 11px; box-shadow: 4px 4px 0 rgba(16,32,21,.14); } +.event-card.empty { color: var(--muted); background: rgba(255,255,255,.72); } +.event-card.empty strong { display: block; color: var(--ink); margin-bottom: 4px; } +.event-card h3 { margin: 2px 0 7px; font-size: 14px; text-transform: uppercase; letter-spacing: .04em; } +.event-card p { margin: 5px 0; } +.event-card.accepted { background: var(--green-soft); box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(16,32,21,.14); } +.event-card.declined { background: #f1f1f1; color: var(--muted); } +.event-status { display: inline-block; padding: 2px 7px; border: 2px solid var(--line); background: var(--white); font-size: 9px; font-weight: 900; letter-spacing: .1em; margin-bottom: 4px; } +.event-metrics { display: grid; grid-template-columns: 1fr; gap: 4px; margin: 8px 0; } +.event-metrics span { display: block; border: 2px solid rgba(16,32,21,.55); background: rgba(255,255,255,.82); padding: 5px; font-weight: 900; color: var(--ink); } +.event-actions { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; } .result-section-title { margin: 16px 0 8px; font-size: 12px; font-weight: 900; text-transform: uppercase; letter-spacing: .12em; color: var(--green); } .result-section-title:first-child { margin-top: 0; } .muted-title { color: var(--muted); border: 3px solid var(--line); padding: 10px; background: #f7fff5; } @@ -293,7 +304,7 @@ body { font-size: 16px; } .build-panel h2 { font-size: 13px; } .tool-button strong { font-size: 14px; } .tool-button span { font-size: 11px; } -.mini-box, .contract-card { font-size: 12px; } +.mini-box, .event-card { font-size: 12px; } .sort-button { font-size: 14px; } .modal-card h2 { font-size: 29px; } .card-choice strong { font-size: 16px; } @@ -462,7 +473,7 @@ body { font-size: 18px; } .priority-strip > div { font-size: 15px; } .hud-card span { font-size: 12px; } .hud-card strong { font-size: clamp(20px, 1.7vw, 28px); } -.mini-box, .contract-card { font-size: 14px; line-height: 1.45; } +.mini-box, .event-card { font-size: 14px; line-height: 1.45; } .compact-rules .mini-box { font-size: 13px; } .tool-button { position: relative; @@ -559,7 +570,7 @@ body { font-size: 20px; } .priority-strip > div { font-size: 16px; } .hud-card span { font-size: 13px; } .hud-card strong { font-size: clamp(22px, 1.8vw, 30px); } -.mini-box, .contract-card { font-size: 15px; line-height: 1.5; } +.mini-box, .event-card { font-size: 15px; line-height: 1.5; } .compact-rules .mini-box { font-size: 14px; } .tool-button strong { font-size: 16px; line-height: 1.15; } .tool-button span { font-size: 13px; line-height: 1.2; } From 368de90c6c2c07693249b17465af389aa9316173 Mon Sep 17 00:00:00 2001 From: 33333-33333 Date: Thu, 11 Jun 2026 14:34:37 +0900 Subject: [PATCH 2/5] visual --- BALANCE_PATCH_NOTES.md | 36 + PATCH_VERIFICATION.md | 20 + README.md | 55 +- assets/README_ASSETS_DARK_FACTORY.md | 19 + assets/_legacy/images/README.md | 3 + assets/_legacy/images/poop.png | Bin 0 -> 1211 bytes assets/chicks/README.md | 1 + assets/dark_factory/facilities/README.md | 1 + .../conveyor/boost_conveyor_straight_h_16.png | Bin 0 -> 423 bytes .../conveyor/boost_conveyor_straight_v_16.png | Bin 0 -> 473 bytes .../conveyor/boost_conveyor_turn_ne_16.png | Bin 0 -> 575 bytes .../conveyor/boost_conveyor_turn_nw_16.png | Bin 0 -> 563 bytes .../conveyor/boost_conveyor_turn_se_16.png | Bin 0 -> 548 bytes .../conveyor/boost_conveyor_turn_sw_16.png | Bin 0 -> 534 bytes .../conveyor/conveyor_straight_h_16.png | Bin 0 -> 426 bytes .../conveyor/conveyor_straight_v_16.png | Bin 0 -> 480 bytes .../conveyor/conveyor_turn_ne_16.png | Bin 0 -> 581 bytes .../conveyor/conveyor_turn_nw_16.png | Bin 0 -> 565 bytes .../conveyor/conveyor_turn_se_16.png | Bin 0 -> 558 bytes .../conveyor/conveyor_turn_sw_16.png | Bin 0 -> 539 bytes .../machines/auto_scanner_32x48.png | Bin 0 -> 850 bytes .../facilities/machines/egg_farm_16.png | Bin 0 -> 314 bytes .../machines/manual_scanner_32x48.png | Bin 0 -> 714 bytes .../facilities/machines/mixer_32.png | Bin 0 -> 557 bytes .../facilities/machines/mixer_compact_16.png | Bin 0 -> 475 bytes .../facilities/machines/shredder_32.png | Bin 0 -> 410 bytes .../machines/shredder_compact_16.png | Bin 0 -> 326 bytes .../utility/maintenance_room_32.png | Bin 0 -> 843 bytes .../facilities/utility/obstacle_crate_16.png | Bin 0 -> 387 bytes .../facilities/utility/repairman_16.png | Bin 0 -> 222 bytes .../facilities/vehicles/truck_32.png | Bin 0 -> 496 bytes .../facilities/vehicles/truck_compact_16.png | Bin 0 -> 401 bytes assets/dark_factory/manifest.json | 103 ++ assets/dark_factory/previews/README.md | 1 + .../facilities_overview_dark_factory.png | Bin 0 -> 2448 bytes assets/images/chick_female.png | Bin 0 -> 430 bytes assets/images/chick_male.png | Bin 0 -> 385 bytes assets/images/poop.png | Bin 1211 -> 378 bytes assets/poop/README.md | 1 + assets/poop/poop.png | Bin 0 -> 378 bytes assets/ui/README.md | 1 + dist/game-v27.17.js | 59 + dist/game-v27.18.js | 59 + dist/game-v27.19.js | 51 + dist/game.js | 74 +- index.html | 30 +- package-lock.json | 58 +- package.json | 4 +- src/core/balance.js | 15 +- src/core/config.js | 28 +- src/core/entities.js | 20 + src/core/mapGen.js | 10 +- src/core/state.js | 12 +- src/core/text.js | 4 +- src/game.js | 35 +- src/render/draw.js | 552 +++++-- src/systems/buildSystem.js | 110 +- src/systems/cards.js | 59 +- src/systems/chickSystem.js | 16 +- src/systems/economy.js | 1 + src/systems/maintenance.js | 107 +- src/systems/routing.js | 17 +- src/systems/selectionSystem.js | 17 +- src/systems/uiSystem.js | 60 +- styles-v27.17.css | 1130 +++++++++++++++ styles-v27.18.css | 1253 ++++++++++++++++ styles-v27.19.css | 1279 +++++++++++++++++ styles.css | 518 +++++++ 68 files changed, 5418 insertions(+), 401 deletions(-) create mode 100644 PATCH_VERIFICATION.md create mode 100644 assets/README_ASSETS_DARK_FACTORY.md create mode 100644 assets/_legacy/images/README.md create mode 100644 assets/_legacy/images/poop.png create mode 100644 assets/chicks/README.md create mode 100644 assets/dark_factory/facilities/README.md create mode 100644 assets/dark_factory/facilities/conveyor/boost_conveyor_straight_h_16.png create mode 100644 assets/dark_factory/facilities/conveyor/boost_conveyor_straight_v_16.png create mode 100644 assets/dark_factory/facilities/conveyor/boost_conveyor_turn_ne_16.png create mode 100644 assets/dark_factory/facilities/conveyor/boost_conveyor_turn_nw_16.png create mode 100644 assets/dark_factory/facilities/conveyor/boost_conveyor_turn_se_16.png create mode 100644 assets/dark_factory/facilities/conveyor/boost_conveyor_turn_sw_16.png create mode 100644 assets/dark_factory/facilities/conveyor/conveyor_straight_h_16.png create mode 100644 assets/dark_factory/facilities/conveyor/conveyor_straight_v_16.png create mode 100644 assets/dark_factory/facilities/conveyor/conveyor_turn_ne_16.png create mode 100644 assets/dark_factory/facilities/conveyor/conveyor_turn_nw_16.png create mode 100644 assets/dark_factory/facilities/conveyor/conveyor_turn_se_16.png create mode 100644 assets/dark_factory/facilities/conveyor/conveyor_turn_sw_16.png create mode 100644 assets/dark_factory/facilities/machines/auto_scanner_32x48.png create mode 100644 assets/dark_factory/facilities/machines/egg_farm_16.png create mode 100644 assets/dark_factory/facilities/machines/manual_scanner_32x48.png create mode 100644 assets/dark_factory/facilities/machines/mixer_32.png create mode 100644 assets/dark_factory/facilities/machines/mixer_compact_16.png create mode 100644 assets/dark_factory/facilities/machines/shredder_32.png create mode 100644 assets/dark_factory/facilities/machines/shredder_compact_16.png create mode 100644 assets/dark_factory/facilities/utility/maintenance_room_32.png create mode 100644 assets/dark_factory/facilities/utility/obstacle_crate_16.png create mode 100644 assets/dark_factory/facilities/utility/repairman_16.png create mode 100644 assets/dark_factory/facilities/vehicles/truck_32.png create mode 100644 assets/dark_factory/facilities/vehicles/truck_compact_16.png create mode 100644 assets/dark_factory/manifest.json create mode 100644 assets/dark_factory/previews/README.md create mode 100644 assets/dark_factory/previews/facilities_overview_dark_factory.png create mode 100644 assets/images/chick_female.png create mode 100644 assets/images/chick_male.png create mode 100644 assets/poop/README.md create mode 100644 assets/poop/poop.png create mode 100644 assets/ui/README.md create mode 100644 dist/game-v27.17.js create mode 100644 dist/game-v27.18.js create mode 100644 dist/game-v27.19.js create mode 100644 styles-v27.17.css create mode 100644 styles-v27.18.css create mode 100644 styles-v27.19.css diff --git a/BALANCE_PATCH_NOTES.md b/BALANCE_PATCH_NOTES.md index 58b64b1..b00bc7f 100644 --- a/BALANCE_PATCH_NOTES.md +++ b/BALANCE_PATCH_NOTES.md @@ -76,3 +76,39 @@ Implemented events: - Fixed duplicate Emergency Loan button in the bankruptcy decision modal. - Fixed stale debug-removal CSS fragments left from the previous audit pass. - Fixed corrupted score-breakdown formula text. + +## v27.15 dark factory visual patch + +- Wired `assets/dark_factory/facilities/` sprites into canvas rendering. +- Added pixelated rendering for facility sprites and dark factory grid/floor colors. +- Changed CSS theme from green/white panels to dark industrial panels with amber/red/blue accents. +- Moved UI emphasis: status HUD across the top, event/status strip down the left, build/equipment panel on the right, sorting controls at the bottom. +- Kept user-supplied chick/poop slots unmodified. Chick art is not auto-requested; existing poop compatibility path remains. +- Debug UI remains intentionally present for balancing builds. + + +## v27.17 verified visual patch + +- Versioned CSS and JavaScript launch filenames prevent the old visual bundle from being reused from cache. +- Removed all player-facing remnants of wage-based Repairman hiring. +- Maintenance Room remains a 2×2 buildable object and dispatches one Repairman per room. +- Conveyor slats now animate perpendicular to travel, with blue-green rubber on Boost Conveyors. +- DEBUG collapsed width reduced to 58 px. +- Facility sprite scale aligned to grid-object pixel density. +- Scanner ducts, blocked-cell coverage, chick sex colors/symbols, metal/grime decoration, and card texture icons verified in browser. + +## v27.18 UI and routing patch + +- Moved event, belt speed, combo, and truck target indicators to a non-overlapping lower-left group. +- Reworked T-junction branch mode as explicit output selection: random or a valid fixed exit. +- Lightened floor tiles, added deterministic green-fluid stains, increased conveyor arrow contrast, and centered blocked-cell X marks. +- Converted card icons into translucent background watermarks and normalized modal button styling. +- Replaced Maintenance Room art with storage/break-room pixel art. + + +## v27.19 land/UI/dynamite patch + +- Starting blocked ratio: 3%. +- Purchased-lot blocked ratio: base 3% + 0.5 percentage points per purchase, max 10%. +- Dynamite target selection is map-driven and consumes the card correctly after any blast. +- Duplicate event/status information removed. diff --git a/PATCH_VERIFICATION.md b/PATCH_VERIFICATION.md new file mode 100644 index 0000000..180730f --- /dev/null +++ b/PATCH_VERIFICATION.md @@ -0,0 +1,20 @@ +# v27.19 verification + +## Automated checks + +- All source JavaScript files pass `node --check`. +- Production bundle `dist/game-v27.19.js` builds successfully. +- Initial blocked-cell generation: 6 / 200 cells = 3%. +- Purchased-lot ratios: purchase 1 = 3.5%, purchase 2 = 4.0%, purchase 14+ = 10% cap. +- A 10x10 lot at the cap generates 10 blocked cells. +- Dynamite empty-space click leaves target mode active. +- Clicking a chosen blocked cell removes that exact cell and consumes one charge. +- Escape after at least one blast finishes and consumes the card, preventing reuse. +- Browser check: no console/page errors, duplicate right-side event panel absent, Status contains no event/belt/combo/truck-target duplicates. +- Browser check: NEXT DAY Fairies fee remains inside the button. + +## Visual checks + +- Green floor residue is sparse and splattered. +- Blocked cells use subdued black/yellow hazard striping. +- Initial Status reports 6 blocked cells. diff --git a/README.md b/README.md index e4a0cca..5ffb72b 100644 --- a/README.md +++ b/README.md @@ -1,46 +1,25 @@ -# Chick Sorter v27.14 Balancing Build +# Chick Sorter v27.19 — Land and UI Patch -Open `index.html` in a browser. +Serve this folder with a static HTTP server and open `index.html`. -Production uses the committed `dist/game.js` bundle. Edit source files under -`src/`, then run `npm install` once and `npm run build` after JavaScript -changes to regenerate the bundle. +The launch page uses cache-busted files: -## Static server cache setup +- `styles-v27.19.css?build=2719` +- `dist/game-v27.19.js?build=2719` -Serve `index.html`, the bundled JavaScript, and CSS with cache validation -instead of import query strings. This prevents stale files while keeping reloads -fast. +A `v27.19 VERIFIED` badge appears near the upper-right when the current build is loaded. -Use the example in `deploy/` for your HTTP server: +## Build -- nginx: include `deploy/nginx-cache.conf` inside the server block. -- Apache: copy or include `deploy/apache-cache.htaccess` from the site root. -- Caddy: adapt `deploy/Caddyfile-cache`. +Run `npm install` once, then `npm run build` after editing JavaScript or `styles.css`. -After deploying, purge any CDN or reverse-proxy cache once. +## v27.19 changes -## Current baseline - -- Build, move, box-select, sell, and repair factory equipment during Build phase. -- Start the next day only when at least one EGG route reaches a scanner and then any valid exit. -- Fairies tribute is paid when pressing Next Day, using the previous day's net profit as part of the calculation. -- Bankruptcy is checked at day-end settlement after shipment/event/subsidy revenue. Temporary negative cash during production does not immediately end the game. -- Cards use English names and descriptions with numeric effect summaries. -- `poop.png` is the only bundled image asset currently used by default; other art falls back to canvas drawing. - -## Controls - -- S1 manual scanner: `A` = left / `D` = right. -- S2 manual scanner: `←` = left / `→` = right. -- Build phase: left-drag empty map for box selection; drag selected equipment to move it. -- Right-drag: pan. -- `Ctrl+Z` / `Ctrl+Y`: undo / redo. -- `Esc`: cancel upgrade-card target selection. - -## Cleanup in this build - -- Removed duplicate `src/index.html` and `src/styles.css`; root `index.html` and `styles.css` are the single launch surface. -- Debug panel is intentionally present for balancing builds. Do not remove it during cleanup unless explicitly requested. Its card menu is grouped and target-consuming cards can be applied to selected targets. -- Removed the obsolete right-side selected-facility panel code left behind after the UI removal. -- Removed stale historical README files and old changelog text that no longer matched the current specification. +- Initial no-build tiles are 3% of the starting 20x10 land. +- Each purchased 10x10 lot increases its own no-build ratio by 0.5 percentage points, capped at 10%. +- Floor slime is sparse, deterministic splatter instead of frequent puddles. +- No-build tiles use subdued black/yellow hazard striping. +- The duplicate right-side event panel was removed. +- The Status panel no longer repeats event, belt speed, combo, or truck target data. +- NEXT DAY displays the Fairies fee on a contained second line. +- Dynamite lets the player select any highlighted no-build tiles, up to three. Empty clicks do not cancel selection. diff --git a/assets/README_ASSETS_DARK_FACTORY.md b/assets/README_ASSETS_DARK_FACTORY.md new file mode 100644 index 0000000..1e49cb5 --- /dev/null +++ b/assets/README_ASSETS_DARK_FACTORY.md @@ -0,0 +1,19 @@ +# Assets organization (prepared, not yet wired into the game) + +This patch adds a **dark factory** art set without changing runtime references yet. + +## Folder guide +- `assets/dark_factory/facilities/` : new factory equipment sprites +- `assets/dark_factory/previews/` : visual overview sheet +- `assets/ui/` : future UI asset buckets (buttons / panels / icons / debug) +- `assets/chicks/` : reserved for user-supplied chick sprites +- `assets/poop/` : reserved for user-supplied poop sprites +- `assets/_legacy/` : copied backup of older loose files +- `assets/images/` : left untouched for compatibility with the current build + +## Notes +- Grid base unit: **16x16** +- Non-grid UI object base unit: **32x32** +- Color count intentionally limited for a coarse pixel-art look +- Sprites are supplied as individual PNG files with transparency +- This patch **does not yet hook the new art into the live game** diff --git a/assets/_legacy/images/README.md b/assets/_legacy/images/README.md new file mode 100644 index 0000000..0e29b23 --- /dev/null +++ b/assets/_legacy/images/README.md @@ -0,0 +1,3 @@ +# Image assets + +`poop.png` is bundled and loaded by default. Other equipment/chick art is optional and currently falls back to canvas drawing unless external art loading is enabled in `src/render/draw.js`. diff --git a/assets/_legacy/images/poop.png b/assets/_legacy/images/poop.png new file mode 100644 index 0000000000000000000000000000000000000000..75fde9d97f6e0e8e3cec842c7b2d3c52709ed5f9 GIT binary patch literal 1211 zcmV;s1VsCZP) zO>Wdc5Jn5c8ihr&P9#=bg`;oH5A%qY@2qAR;mVN1n^Eu6$wg| zvfgBT`tbJb&%S>D({=3Z!$Ioc7g_|^OZqulWXLW+`XRt7`K_PJJ`|)Dz%uzgpU*5o zY5^`Wntbhc5J@Y*rK?UmX_wl|S_RSyu!q$ZTd@+96o9moQUKI)iyGG+DFxWWx=dFa z2FeLQ`k(-lLjfj-0!$7Cm>dc)IpqZC{XQS9eQ#0Z#$X36iOq&(UUqV!O_oWkpR9_X`M)`RlzMF z4+*e=iP&95n)?D;L6rb9D3SijUc?N&_qd1>K+XY<%=En%Y8*K(;=BOPNRhGi{vMTJ z;Qwy#VV;*yH`fi=RE-KMYR-t=o^L)NP>1|4GW$zBkaffxWY5niPS{^jZL5Ev;R|Q^vPNR^ErUlj^7OT|7*1RWIZPce-hY} z*enuc>XT`Cv0UtdI3!s1$7(1D6Tox3w>2Jpu@WHtqR{op_mm;JbZcQIK*aNHYZ)Sw zesz2OWKjjoh5)ob_%QPD#uM*hApH=~N|lnWP55mfiG>184h5K;5CIVG-4Tg6FJ=ND zEP1Yk)%oNQFgalYa2R+=)cG(K;8NM51pkQKJsds+%q~H6|IGzxu{Zi8L@~vRAQ4J% z3WVf~fUgR!$h5117ouMM8V%~(#Zv4H$}9rBLKv`B)3IVc3W=xKPqi>bUGbl`A4?m54E&V_4Yf=Kv}FhL|DvWH_SA|ksH)oPg_ zl8Ff-h0YTkc=_?Fd*PmQj{9dP0hj?GSt?@RHIHPeII^h}k8=OCXI+QK0H6Y>)5XQx z3jmqU@UT`bgF0O`kQ6s%o}Nik+$1S(a^`b1n6oe|IrBMkD6>>qSs)9u z^0P7Bh5Mv^a0CEYeEfTidI|=*PRZ zPj;&fF>J%=P)6wEFNic3-G(58@pFmX4 z%t9i8&+BQ2imHi-I3uy7h=?;+D2n4`za?^oqKJsIHCItJu_>x1GY{gX;mdEI*?GHU zIaxOhjtq?uIOR6^fV&TyqH1zFILVDOXL<4U69A>`N}Kr7;6+P2*|l|iUJtzh_lJj= zUQ7e9cXg2cBY*o0^9z8ZjuR%^-r6+tdorte?xfxzjXKh(15nk&L}edUJxo;(H}7iU zDF7e)H2`+sXE=1sNsrI#K^hG+T6=C?d-@ar=f3=Gd z!1b<4*|l}-4i~Om7Q4fR-QhATZ5q@YJRS>hJMp|tSgVw&Rm%SyD%~)e22YGJrsfk! zqfW^`Y6?@!Y19J;sa48d#Q?Tkp(vAc^Xz(d#>2-6E zj$gh)@VtlkMjn9ZM3C^axWyzo5#-vipSv>;iErfjv9gF|ln2~>gkrN6aV&I;P;8c) z7rZ9BHyvz#CSW`gOG>U#6kxnFI(a0P6q75eCW@*_u27Ue`_}j${|)v02K>pX4~YN( N002ovPDHLkV1gXS2EG6Q literal 0 HcmV?d00001 diff --git a/assets/dark_factory/facilities/conveyor/boost_conveyor_turn_nw_16.png b/assets/dark_factory/facilities/conveyor/boost_conveyor_turn_nw_16.png new file mode 100644 index 0000000000000000000000000000000000000000..e1e1fc79db72baeacb1735e09b35c329c4e9da3f GIT binary patch literal 563 zcmV-30?hr1P)W5R8Z)vq=X7; zu#`5n5o}+`kaox}2#QOw(4ozcfS4{X$0773d5L)7z`Y;m{Oi;+b-Cik6EwMC%)~1^n0(!-ks~xtMtj$ zSV9z4lb(OQwv!)C%>r=a`)>fGUI%Dca7H)LgZBencX0ask#WaUsJ_B$z`=P6iaySCO@>-VoVj6&7s~;PK)PL_j(VGEMJ9z-+ zr=!fgNp*N?eJnDE?stOGxo2 z7}Q1*Q9IJbY@D@%ptuniF0?`d)^sy-U4$7-GQDu%ao#!aoeTG(sG5wzwCpi%D;`DF zL`0&MYC}XMYFf64NOTnc^PW~wH3=!ICRcAfz^lh!Kl$emH?L*W7cRFeCy#OIGVjqhow$b&YIhiV07&_^buM=IQAnVTr#0 z?9uo8+|M81e0{k6_8k|S&k@%_TnB)SVu^dQjg4Z7jbaG^W%(`u?~@t;zhAf6wJ%CI zo0&pf*9X9Iy-v|EhLUU+7XUc?`OgqP0U(YuM2?!h*g+Kr{P?%>xj<28b&ZG~BW8Ap z=rJOC%uhOaz;U@fm*;%_;gGT4>(cLa0~2{|h5_yvb1c;Ai0iOEGwU0hD=pORJLvbi zfo6b^Y1vXhBJ~InIbEQRjsRqFJ7f(S^HA&o68Ot&Kqd0000%=lmc literal 0 HcmV?d00001 diff --git a/assets/dark_factory/facilities/conveyor/boost_conveyor_turn_sw_16.png b/assets/dark_factory/facilities/conveyor/boost_conveyor_turn_sw_16.png new file mode 100644 index 0000000000000000000000000000000000000000..06444d762a33e47a5cf28aa2e28603dd5144cccc GIT binary patch literal 534 zcmV+x0_pvUP)yWk+ki&A|mOy_w!JzsG6h{Rg;I0pA*{4A76=E<<@mp-+cgJ-podPDmzI^Q8hWc zRO0Tri@f;$WhnU3?VH?~xjMvKTWw}@(;Nv!_lH!{-CN0l)#x7%{sI4{4hU6N5{OfD>!MNu^wS+uO7_SWll;{0H71%S)n z{s17p4-kwHx1^+dyE_AK@jL)V;+2!Ewbf=^pJ2jnVH7Nkf`#}V?>~J$Opw%euiK&5 z?F?}7e8ls4vM|qVZaPTNAG|+Thyph@o2W;R(d%{&6Zjratp!$ULANQ}aiz3YE@BVLOF;)fu~Kb_?YIIIlPc>*Mu1|d1&X%g2G;XQZ|5k#e6kwZg6P(cJCQA8yq1ri8iON|Y-2~CcXqeCr);3651c>S?N zB#@w@cqBMFIRp|x^Scf99#--a`oZD;IGp?4b1oc*BrAgdNRkyHgz)U8GC~O9=_Jfr zNmhhIk`~JR4uGcS2(B!nsW~(?2S7Ly1)w~l z08p*y^trt_Z3k{qCVdRRboJv~-qk7KwO(tR?+DQE83G^>T(d?pWjn(ATZ8wvhAsS8 z2brTo0M^%5>FVyWK&JmGha@Xva@x5Bc4dodWWxVjP9i}0*H1JX05eMfA(#oPfG5z UPQAq%$N&HU07*qoM6N<$f1unheT2&1WK)@8qH8>5Ya^(lwz$FDPp06fe@ipaMnq1%4p+O1!Ex+xE-Vg zky!jg>L48&i4w6}tx01Egb*xsyQf2PPrN^M@xbAn@4Mgop67g*W3xM)0>il9&}2*j z@cY+KQ|=DH)!$3c+rB&(K!1n&vjFmxuPnQQkt98`g&DiV?rwB)uWYL$M&!mqJ zEeZT>9rQjOl=1A;M44c3E5VazL+ouOEQJ@@A9CH^_y|DX^O5QmRH3rFxeh?9&xg0Q zMQ5=5F2cPB%`(pC&QOI~H4v(*6C~C?nJ5Cm5K4T7gGWw$xvHj2U@%yEzpRU24D_MI zR{-e#{)g+DGJ((=OuT+$BFN{?bg>XO5Ew^&qZfdo;g_7Aq|F5XGbj}c0MxnMGH0wc zHBpI0&EO70mN5jlWhEoZa5sO*(p zl@mj8t_H7h! z>^lH1`~9xq%=;P6UFdM$hX?!g^hNn>t7ReB0yv#Y=Su*L#oqy3*N6)QmJt;rFkfE(h&i9{{HSL{x+2RwFz-*mrRN zZ2(Fslv0d5f7UW+ZDW&muaEfCVcNYur~3S2=2&3##R$_=uNx9;)gx-vqkk?{Vkll0 z7<)O&RB9SgitN&YlbFjdbNb9#YSp8b$p9Y9E=g))lFH6k00tjFY1u}0X#s#-ewoz7 zBmiHwY}(9l2vLf$)GUEuH@oF+qGp8M@^%9P!ESQ-Wd`o|V?KE3jNG-#T>&4-@ubT^ zaw17`JW2mR%;8=QC+eRGh^6PUV%a4DV$Epg({ovIcuhA%(+#oglKj1&#Q*p|QlbrO T;>EVz00000NkvXXu0mjfIB5{G literal 0 HcmV?d00001 diff --git a/assets/dark_factory/facilities/conveyor/conveyor_turn_nw_16.png b/assets/dark_factory/facilities/conveyor/conveyor_turn_nw_16.png new file mode 100644 index 0000000000000000000000000000000000000000..66b24af7423485746aa0f375105663dfe2e49dc2 GIT binary patch literal 565 zcmV-50?Pe~P)F|9LGPqbeMsGh#)BTptOfzW5tenNULo(qgkwjV8jNRmySYMkqoYN5j_NXPy-_v z@G^@oOFEm>T--ypsI0L^PaXsjq4WE7SRLJ&jUN2q{XV?k_xI<$7twS>2(0CmGQ)#I zLCox@dCW|z8EU#AA`+XNu|-5;u2+$^cp_x3R}m43ojt4RhD0>oko?rFFX(;yN^QFu z$~-(c#P#G2Zr#1_^NvJ25luJbb~;PXy$5`EO91??Z8ilzOy3E$Q(Rrc%%mCu%PVE3 zr#}F2H69Ngp8q(-r7LZ|zrVLjPddvFw@CD4VD+7C>O0#2l$IQ_W-p~BhtiS*z`)ZS z0PEKb07NMOqW_w9klSBA18}qc2LN>}a4r-LEw6BYZ@0-8Ij$g>xz#GJu5mfm&d`ey zy1LVJb*E8EvAj|~6=+rV(cu9{hX+kuDTPvs(N`}qGpUBa*&= z3k4z2O-fp$cC^TBItvj*D!9{yCeopawg@GgE$m(I3qrwcm> z$FJ!kB1SG>6cI5j+Yu2lI=dBba{ZbvKEI|*cA-GC?2qr<^PAG^Q+x@!)?U! z=34-c91XhIzdyfRe$VFn4=lWRi716A1wf@-B9$DbQZ7*`mjD$NKNTGi80VRePfSh_Lb@sla$vh#>i6xWtr z;d*I9*Bkx%sl;Unyc4M7kfIMX*dAPT)rrl?Fe9c wy&Mcj1u&ajz_e_qv5lRp>Lm__qn@k%AILQ+_j^|oKmY&$07*qoM6N<$g6~TE1ONa4 literal 0 HcmV?d00001 diff --git a/assets/dark_factory/facilities/conveyor/conveyor_turn_sw_16.png b/assets/dark_factory/facilities/conveyor/conveyor_turn_sw_16.png new file mode 100644 index 0000000000000000000000000000000000000000..5f55830d4b989d9e4ca76128db37b271c136a169 GIT binary patch literal 539 zcmV+$0_6RPP)1unhdVfsQV^9431$#7bhiN;wWd)_aS{r0LSqIMs}!VKl+sj}V8IR<(iSSh zL6?-IMBA%HZs`poNU@NylY+#`aoQS3y zaxF7K`sQuE*^Pkt+4Cpd$y^Wct(`q`<6{i;L`zG{09;BWP6=!E&j6ge81vYl-$$PQ zOnrNo!c?B-;Q`IV0{|MeDigU|G-_2EwJHFU_e}uyFB<@eQr!WCseB+_Wo;Edw?2IY z;7ao^0P1+aK)?+Fb1!y(i5w^JpBz?OJ9}J+#>qdPVPrJJ$Y=(o6!q=hlL29|JM9*o zcIy;ZN}-fu_T>w5<73?c{bp-@#WQYHH#s{vM5o<4iLMl{=4N?YdgTEMg&x4Vu0RSh%8 d63Nij{s&n*COctAE~o$i002ovPDHLkV1m!%@Q(lh literal 0 HcmV?d00001 diff --git a/assets/dark_factory/facilities/machines/auto_scanner_32x48.png b/assets/dark_factory/facilities/machines/auto_scanner_32x48.png new file mode 100644 index 0000000000000000000000000000000000000000..4a6d6dbbea2752406f4c96acf5a0187af3847455 GIT binary patch literal 850 zcmV-Y1FigtP)74P3uan1fw7kZ{wlerR~n_qn(y7nPfWu%zWSe^Z);JR}dwc zU=`s4faSk`Jb}B9)ZR14J;fl^xTG~}RY8#>84`+QIB%=LHl z=>5wVIw6RXOtv;P;8aHs267;`gU_K)hOwIF9r*HYGI<0b1Otz66og#EhKg#vKNpVz zBpG@x+T_FcD!7sdlnI=CR)@j%X^eVh)W%nAQ~>~Rd(RkG5rgg10DzXrQpUIo00=33 zCeFp98NZ3y5ol;RaEJ@}=!+-l9`RwgYt~@XgOIh5D=0k4BVf$u=>Zmxi)le2Jirpb zP{7**G#=9+yE~ zZ7s^1Y%XdR44sZ~CugCgXiN+g?KWh=)C1F@@n)+Hjt*4kCBXDHtZUj8VpgeiiCT5!rpMJ-ai)H0ssgouT0l?cGoflFrHz38T~!Q|J=(I6>N)8ZSx70 z%HucUpHZUr%BDW{P$g%3T zA(u4FgWtRm@mIhh3wXn}06S@xZnp~73;~1?L(4^k6*-MV5G9$EH*7Xcj!#4#S3)!L z`Gks!#_Ei*?~`9sM_{)SS&&$|ox)+7hROO(M?gv1dc&=jmypg+8Dkcr^6gc&Hgz=D z>5GYdp#C}b;)^Eb1x{yWUwpwcnJNx~Zn$^+}xYU0grIl{IQEzAmEq$-j zN;ekO1-+f??9;=>@TvCJ{VRDrxfRZL_33^6Q|-UyCI8hs4}%xap70lxJq3+Rl;ohW c+MnzH13IgQL2fa!ga7~l07*qoM6N<$f?Yw55C8xG literal 0 HcmV?d00001 diff --git a/assets/dark_factory/facilities/machines/egg_farm_16.png b/assets/dark_factory/facilities/machines/egg_farm_16.png new file mode 100644 index 0000000000000000000000000000000000000000..dd9dd9f5fe5fd5f56a4b8e7ead496445eef21917 GIT binary patch literal 314 zcmV-A0mc4_P)eF~FB2q6h(z{9<36wT6`J6k#?PhT|VXNJB z>+z^hptOc% zyxCJAiGpmVL2c>wvqL8b2B@3}{7PoQ0E61nQ{)rayn>=p0kBfOml6w4D#%(0RmAMj z@y>2NVp4^?g)GT6Fo0|2@u>fp_B4{;*qg>{0eVG7de?oXa;Z=856f1Hn}&Qdi~s-t M07*qoM6N<$g6B|%eErQmaT)_72Pe;eT~j-Tu!tBG%c%)2ojQOarf25B zaQXBhNEH14|DR#y^2Ic<90tUs6yWSv&mJ)R{|`xeEZ7vEuD(ZA%Q*rV7#>ag%OID< z%y3MDhe72TLJl4R=s+;$6IC4{m&MG$z`(#@b>j;IvYl8%fEM7@vjJl|;vOZlsC>;C5mWW5F#&-4MWK4+|dqsU8B@?14wY z`D42r4XxbvBTG^{1aL>e|NjhzmahBJ6C?FQ09O>?0Mt(dm;f3D*b@Qua{-Bokm>+e zA{$-LbPa(^r}n#}i_tX% zbWI(0qT4k%(g3#9dF%3Ns#~U}Yl__gq{M)T1f=is=EY-@aMgy?x1WpLBkcf>%;$mRlu1MuZT zYUTnhL+cCZb`6e_kY05GHhTzmPN|v;uz*353vk2$uGCB}AgL};RM(@b<+$vjZ(V=| zkX0AFdioGUOiWsydNklz zPe_zO7{-4q9@O+8is*`H_ymSP1eO5?&3$gVG;Jy{sZ` ztAa-0!9x@TB8njkma=N-)j!+mTMyfOGQ;d*Bz^-ur*GbQ-g#!8@12?Nb7f>^$8iv8 zPKpDhi-*|RaS6ciSTG7O(Eq69DuvW>GqZA{V1NTIQ3FFS-)IS;>B)Z*c-ZaJ#-Bgy z159$@c0&^YT|JKhn4Ox?CWJoBTx#H(#f94Vox9BdtbO|o7~p`t3#_;Wz)bMHmKYAt z0^s#_0g&JKNz2<9tO20FT_(kk4t69R0dpLPTlxcWZaxHne=!G0zH))u7n@T1b+8eD ziUYllK@KSIW_}?IK<5K500sTaQvcCdtJL0D{R%+q+fylif9phQt2!n*psxXS<%gp! zDFKjt#iGDTT90#l~pJS>g#t1W#c94{zz?A^`244yoU92kh^Gs#|pcM0b8j zgw04|W#TUQTfFNy2Efzik>Zi>>wrlPR94plu($j3T7+X~i95n^2kZ&>`~iIafO8XY v3U&?rj-B)ZpI1!&00000NkvXXu0mjfoO}I= literal 0 HcmV?d00001 diff --git a/assets/dark_factory/facilities/machines/mixer_compact_16.png b/assets/dark_factory/facilities/machines/mixer_compact_16.png new file mode 100644 index 0000000000000000000000000000000000000000..980ab2e9eed9c330e277f6d5bdac90d686b1fdfa GIT binary patch literal 475 zcmV<10VMv3P)LW%{!T0*cC8w({NV6=#e zxIT~-0u~lxVIztn7kn&H!EIe)sxv9pd)DP*@bSZe;h*{cGc%lHn3gR(2c~6eaLZZP0JR;v}_p}`=$+J^E3awu(P{Y$HPMd7^Y=QL+CACJs(+|o6Z<5EqKHg zFN<~D*wn)A&K9`A zJU>eeQ2*rsfUmP}@Ly&$IRGLG5yi@CjE)asElN(dlALU1qd!k`%||I*%^d?lB<)!A zX#;?(iFaANYvOj|^0y->&%*9r7YK%Q{&tDpx1>Z!96JEKs;cqiTx9J4V0*9x z0AF;IvPwT?m3|V(4!-Cn02kve#Mjq!yC_+YzB_fk0L6U;_I;qCu^E8W$OHf%@sd})U)N^(9)R1MD?oq&I|J6vS2MF; zjf_vki1Sss0XqZl#n)i~t-F3L2=L?C6ClZes#0#?6W>61G$msr!vFvP07*qoM6N<$ Ef)PEjApigX literal 0 HcmV?d00001 diff --git a/assets/dark_factory/facilities/machines/shredder_compact_16.png b/assets/dark_factory/facilities/machines/shredder_compact_16.png new file mode 100644 index 0000000000000000000000000000000000000000..573e8d79dd46bd75a92d8d85bc5a1b4d49b94fec GIT binary patch literal 326 zcmV-M0lEH(P)dH$N3Qo zqxF8f00|Ns?X;xGM30hGABc<6H Y0J&0;{a?*IS*07*qoM6N<$f_A5p+W-In literal 0 HcmV?d00001 diff --git a/assets/dark_factory/facilities/utility/maintenance_room_32.png b/assets/dark_factory/facilities/utility/maintenance_room_32.png new file mode 100644 index 0000000000000000000000000000000000000000..ed4e45b30e1d03a335d9fe68979bdc1bb886b6c0 GIT binary patch literal 843 zcmV-R1GM~!P)`$&Z(vJ;UvH_FEK#t;WZ3l6sTIlq&Z;XI4MgIfSi@V^eYeaC&M-r&2 zt|tryAxexH#dq0A%mk51YMQ8b9w^Kx=Ql%I-tJPxV(Wl6nU2o;xhb z!Q7*g?0dq)W-mv0W=bN_+MBOQqW(e)cy1J|y8!^;ANHzjh+Cjc84ZFEg}Km%@XQn# z#w4YcVN4K&sPs$ZUz+y^!7-njKq?SP06@o}1rI%6(wc|51O-asm!lohrcW0y|wjhZ*FfcNoVEyWV08m!xjt3f#_k_+< z9t%YayV-m zB$?;@;OAC|Ezl*9N{dxi=_aFmb)in}hv5nd+y)J>Rz&`@= VBmlBX*d_n~002ovPDHLkV1hG9g;W3l literal 0 HcmV?d00001 diff --git a/assets/dark_factory/facilities/utility/obstacle_crate_16.png b/assets/dark_factory/facilities/utility/obstacle_crate_16.png new file mode 100644 index 0000000000000000000000000000000000000000..8dfba88f524e534c2595504d07f046c69572afcd GIT binary patch literal 387 zcmV-}0et?6P)Nkl zt6#MpQ|D)S@(djS6cIN%rVd3ES$^@^)dv80232Rp&2A$R5_cO3?pK`^6p_zBeO1}^ zOnO$5@t&1rylk%+2LMe-gH8{20y%Fkwj%SFF5d(9+s79#g1?H*Wk_6XE<-$E{TY?| zdllk1krNE;RERjRQ;`#_4ZIq*1d9sR0tIWq_hCx}xSoL`C`A}Ko;Yv1jOR_4@sT4K z4@4NZC6jXXd1%~Rea`)HTmFnd$kt{6fNX6RyNTZ%0JytO16c3D!hNemzT%ie_j`Tq hcv2D4=xdw)&YuHy{V?jTG;ja_002ovPDHLkV1oZ|pp^gs literal 0 HcmV?d00001 diff --git a/assets/dark_factory/facilities/utility/repairman_16.png b/assets/dark_factory/facilities/utility/repairman_16.png new file mode 100644 index 0000000000000000000000000000000000000000..1fb17b04102c4d077aba978c13a07c92b2226e88 GIT binary patch literal 222 zcmV<403rX0P)pD8_+!<~g3qAh^Uf&z01sCTH8^8|SU|A>@K8igVZ;Dj8H^+V Y0Fwbw^1=;l{r~^~07*qoM6N<$f}n?A(*OVf literal 0 HcmV?d00001 diff --git a/assets/dark_factory/facilities/vehicles/truck_32.png b/assets/dark_factory/facilities/vehicles/truck_32.png new file mode 100644 index 0000000000000000000000000000000000000000..c8c3360d64c3385a49ae99f836f79cbdf897bc3e GIT binary patch literal 496 zcmVEP~@MWd@YzFMM?QsVTF~CvZ1653!ky_ABe>$6tb`p zH4Bl2X@C-o&$;J3=f2N-&g~d3x7Wf!q&Zm}AYD8}!mkAYbIV%~ z0HggK1*t3)&+GPNK7a-a7@`NJ=2w&f2Rj={6=-hjQu-%H`T(62sIF}UprySVfc@?D zKM|b=j%>x%)HMNcae54Bpg?pAOv?mdZ)+_n!o2(2o8HfN`L*t zJ@DQAiRx&ifNA~~XB*<=0-`qrt}jj{TOS2XE47P}zcowg_wBw&wmu5P&u60UPBk=A zAi)&Wjo(RjV5Z0xare%%WUsenE8`qjAi5EimRA9Advgi=?1>+VhWgw8n&-Fz(H`jP z9h6>74EO$;SW;H0^a}+OL2TdpZN+bqkPl#XY10odHqhw<$Z&c5u?g>QVV@o1_`K!#{aq~Eabue#pN~QF~0Duz3?bTW6 z=8@5HQ`c)gN)!MQ08tW}0M(Nr0G<;r8Ur*Hh$!C5#Xq-ORs<*Y0>Cn3XiR{h$u>MO z(*=Im{x82ogS8rf_e!ZvprpUIbe*KV$<8qIt>5Tn vb9n*0s2!829TULoOx@G7<}>v)+-Lj%$Qrti8HC?l00000NkvXXu0mjfUn;bi literal 0 HcmV?d00001 diff --git a/assets/dark_factory/manifest.json b/assets/dark_factory/manifest.json new file mode 100644 index 0000000..98ccc56 --- /dev/null +++ b/assets/dark_factory/manifest.json @@ -0,0 +1,103 @@ +{ + "theme": "dark_factory", + "grid_unit_px": 16, + "ui_unit_px": 32, + "palette_note": "restricted palette / coarse pixel art", + "facilities": [ + { + "id": "conveyor", + "files": [ + "conveyor_straight_h_16.png", + "conveyor_straight_v_16.png", + "conveyor_turn_ne_16.png", + "conveyor_turn_nw_16.png", + "conveyor_turn_se_16.png", + "conveyor_turn_sw_16.png" + ], + "size": "16x16", + "folder": "facilities/conveyor" + }, + { + "id": "boost_conveyor", + "files": [ + "boost_conveyor_straight_h_16.png", + "boost_conveyor_straight_v_16.png", + "boost_conveyor_turn_ne_16.png", + "boost_conveyor_turn_nw_16.png", + "boost_conveyor_turn_se_16.png", + "boost_conveyor_turn_sw_16.png" + ], + "size": "16x16", + "folder": "facilities/conveyor" + }, + { + "id": "egg_farm", + "files": [ + "egg_farm_16.png" + ], + "size": "16x16", + "folder": "facilities/machines" + }, + { + "id": "manual_scanner", + "files": [ + "manual_scanner_32x48.png" + ], + "size": "32x48", + "footprint": "2x3 tiles", + "folder": "facilities/machines" + }, + { + "id": "auto_scanner", + "files": [ + "auto_scanner_32x48.png" + ], + "size": "32x48", + "footprint": "2x3 tiles", + "folder": "facilities/machines" + }, + { + "id": "mixer", + "files": [ + "mixer_32.png", + "mixer_compact_16.png" + ], + "size": "32x32 + 16x16 compact", + "folder": "facilities/machines" + }, + { + "id": "shredder", + "files": [ + "shredder_32.png", + "shredder_compact_16.png" + ], + "size": "32x32 + 16x16 compact", + "folder": "facilities/machines" + }, + { + "id": "truck", + "files": [ + "truck_32.png", + "truck_compact_16.png" + ], + "size": "32x32 + 16x16 compact", + "folder": "facilities/vehicles" + }, + { + "id": "repairman", + "files": [ + "repairman_16.png" + ], + "size": "16x16", + "folder": "facilities/utility" + }, + { + "id": "obstacle_crate", + "files": [ + "obstacle_crate_16.png" + ], + "size": "16x16", + "folder": "facilities/utility" + } + ] +} \ No newline at end of file diff --git a/assets/dark_factory/previews/README.md b/assets/dark_factory/previews/README.md new file mode 100644 index 0000000..b1790a8 --- /dev/null +++ b/assets/dark_factory/previews/README.md @@ -0,0 +1 @@ +Preview sheet(s) for quick inspection. These are reference only, not runtime assets.\n \ No newline at end of file diff --git a/assets/dark_factory/previews/facilities_overview_dark_factory.png b/assets/dark_factory/previews/facilities_overview_dark_factory.png new file mode 100644 index 0000000000000000000000000000000000000000..b387a8d20efd2f4034e8530c98ba612523318b60 GIT binary patch literal 2448 zcmc(heLT}^AIB$_A?#MEROZ$>IY>?qEXAgsn&Yw1OjvZXkQSAxC6A|4x+8g5(x^l? zi-~5Ar#02VNK!0ptelCh%{*;pPxsuXbHD1`-GAJFoqw*^_4-}k@Ar3I*XR5Dynk2r z`?wkEo9P1p07Lg5_xJ$-TCSQo7qnC}o|4nW0DvCaeb4R#XKxER`!3&(Sg$LNz#FZ! z_ka7;W^dgMguU-&&vxtMdATl|K)$#1wdTMet?ZvpMeYs+oBci85&`<{4&q7Ko0RJG z=l3q%_E>GOkqErnefaKaPy3(jYs}-IwY8HiligkNh+$bG416|Xj3gyAkd&gC$;6{~ zhcIk!fEM1*BWmIz?~48RZzmoQ>2+JDf?y$A5Vp z!7_4AnvJzhoE?A43O{vK{>XXMDXO6trie-CRMhaSu% zfOmh3;g;GfW7ZuLcUa8SA0zPKm3I}MQXg{=qhW&II(48Is2UhB*3Tl(7T3ZzJ6E+% z)JDtg*v;UFLxZxba&=9SZc+I+faC>n$h(tyFtwO?u?-(-sY4TuaMVOUk2Av@XR)*R zAMV#P9R8N3RJBp_b#bVU)m&~4BfBk>P@Z9u6`B-O)uQmlX8||c7oQD~2n5u8LtIUd zaI+|%YC?~^^oYNvy{z+PknYXW41CJL(FA1{O>+pl;Qx zQf=k1K9PpBEq%{%&R9{YZF^4BQWy~8DZEQDQc5Ue{<%Uqf{akuzz;Iy!4hzhG z&R#Y&q*rdY%Yr976Euhze+6D|)VB56W1GzT)BAb5#7r!*)m){F#4 zVMLTED#_}{*R&e%=tDtp^`X$U0)_qY6Q~2r2e}mb{QK0lk@*g~S%o|Gc>41$8!|Nj zPd;Ui1r8sI2`dUpqXN10g_d1GohR8-j|ovuj<`vpkO6_d=92}>*FO*zvw|m_(0$eI zJo4I$ELgYG=yxsvC{d+GCq!8*V}GMIG1?E8)b_&XIZ$a9tx9?17T+7&yRf`%du2(T zm(2m5S! zT%3eyn_d+>CqigC*h{l6QCbyH=y+AQCfJigK?kHWeh!X`nq#U?dQ9|;Zp|}Kv2A9k zraI6qAxwwlnP&JT^)HcKhR${nyS=XqKRIl3d zD(d1@?^TcBJ-kT#s`>9~9m%_@9J~2riEi%wJ1LGTXg4{Xrt(WD*n1>_I81Ia@+6~; zfSgo|kGR~RBKPZn%*G25vrPv<&)%7Sj5Roadvs`Je~h`1dQ2MhxFn10SO2V(wng3< zcFAE5cLH1RpirGo6tC;cgLgZjI)fF?9cg14IoAi?@{?RoIT1t1oKcsp>%xXiMtj0ZBPqmTN_t1Js{NDVHS_uW)@$2;zm`j2<=oR8<73NdP-~6`oqyt3#+-s zCtxnq)EG=6>~z|O=#c91ohWM?X!O75 z;~bhhRMuo{Z_ad+G0`p4R;32Z{(#nJz81YmzZZp_#LX7I+6uX@=cwg!yB zAaahM3c+Cb(90?Sx%QJtV@%lRJp8QmV#a?TW|4vtZJk#BqRHfI%yzJARf%>uSo8Q3 z9KW9P#xFRafOpOlz@FOxr^`^%fEgGi5&m$?p1OLp}E zmwpcGzh*xf$KfKL$SN?r`n5(qjn+se>;K=^Tqur3Ie85u4%hr?0o?cc?5RS8rTq)A CxMX<% literal 0 HcmV?d00001 diff --git a/assets/images/chick_female.png b/assets/images/chick_female.png new file mode 100644 index 0000000000000000000000000000000000000000..2280bb985ad07512c77291cc45fa2a66f7d26d18 GIT binary patch literal 430 zcmV;f0a5;mP)v&WzQyXWS8Vjai)fn@w2kgKuHE&YfL3B)2#U6N=AZ8p;2 zmc9^xHsJE}L;YrTdoRA%AWR8_j6)#F3HT7cdHeLH_T}}w0}-o(D8Q6&jtR8;ue(m; zVpAg^-|bHIfw$qnoQUZ4VffDV52OSGxY>*51_(bz7~p6Q&LkDW^d~%rM1Zko?-WV_ zOTepk&hnbGyq4OC{;J>K0WslAu-J5rIm>IwTzVb{;7l?B_%$KbN331awFN*NxTuJ> zmDxBMKvZ!8@L>?C|7dtC`sRHdU|c~;XTmrMXga{P#f-RY#4c(PI$Fz~9%x$;mkn{* zs3#(P9IH#wUjnZNLeV?HOTg>74j~jCnjCy9?p#d38&PQHW`I6KOo+J|00BXbFS^L- Y7dzRk%U6%d{Qv*}07*qoM6N<$g333*k^lez literal 0 HcmV?d00001 diff --git a/assets/images/chick_male.png b/assets/images/chick_male.png new file mode 100644 index 0000000000000000000000000000000000000000..b6d8eab0db379887ca31c90c49caab046be4ca6e GIT binary patch literal 385 zcmV-{0e=38P)b;@5Ji8YNX}Z>mIH7Ae226yxIiR2dQOs_E)o}@*p@rs18@LZ5DryRL=z3pjCU4{ zoWj4dyz7~_Gk?7c4C+}A)`_F(`&Vl4{dy6N|Ck!IYxNFbZUF#1yBBjCKI@|?wi$pY ze_bBbd7HUUf{0GwiR;s0!pF)Ls#`(K9%v>9fbfPt??`P`G6T@+rQ|6PZQfA<=p*Y& zu7&7*8;Ss3t)A3Y1ycpM+g@7;;R89g{=5}<}eni|7h!0N7&4@ECfwD8AuABF0`+$`U0#ePW&P#$00000NkvXXu0mjf?D(lO literal 0 HcmV?d00001 diff --git a/assets/images/poop.png b/assets/images/poop.png index 75fde9d97f6e0e8e3cec842c7b2d3c52709ed5f9..13517e795f1f26ac264d6801f59ba005e4256064 100644 GIT binary patch literal 378 zcmV-=0fqjFP)VnmIUm{=?WmzJDRhEGBALj*U+&Aj{P-%O)jh!^QIEU1eZkAUz~V4go?w zB{d|-jsj%gW8>4@0n`FR%K^m3FDdDOXa}Gh3QP64_{2JbCz*;Z%z( zPmCjo%Cj(o&@EPyk;1SXU7k?6KrjSgmNy3~;8ll9o=_+d3;}cpL{C1(z`(%3ur${S zt9oSl+Vu|@7#Q%Ejx2;6fDUk3OsqUQ7~JIma{R%9lURVP9$z}Z=>Tk+h;;-ub+{aX zHE|#-E_M`WU|?Wi=-vMkMGdx8k8UwGz32%NuLEEPzyP`<@Bv(U(H%fiF2EHU_$(#_ zh>ikE0KO=|nh22viN8j@5Qkpl=-MkKe2iE#|MeT0z- Y0JdI?It5RF8~^|S07*qoM6N<$f>6DX4FCWD literal 1211 zcmV;s1VsCZP) zO>Wdc5Jn5c8ihr&P9#=bg`;oH5A%qY@2qAR;mVN1n^Eu6$wg| zvfgBT`tbJb&%S>D({=3Z!$Ioc7g_|^OZqulWXLW+`XRt7`K_PJJ`|)Dz%uzgpU*5o zY5^`Wntbhc5J@Y*rK?UmX_wl|S_RSyu!q$ZTd@+96o9moQUKI)iyGG+DFxWWx=dFa z2FeLQ`k(-lLjfj-0!$7Cm>dc)IpqZC{XQS9eQ#0Z#$X36iOq&(UUqV!O_oWkpR9_X`M)`RlzMF z4+*e=iP&95n)?D;L6rb9D3SijUc?N&_qd1>K+XY<%=En%Y8*K(;=BOPNRhGi{vMTJ z;Qwy#VV;*yH`fi=RE-KMYR-t=o^L)NP>1|4GW$zBkaffxWY5niPS{^jZL5Ev;R|Q^vPNR^ErUlj^7OT|7*1RWIZPce-hY} z*enuc>XT`Cv0UtdI3!s1$7(1D6Tox3w>2Jpu@WHtqR{op_mm;JbZcQIK*aNHYZ)Sw zesz2OWKjjoh5)ob_%QPD#uM*hApH=~N|lnWP55mfiG>184h5K;5CIVG-4Tg6FJ=ND zEP1Yk)%oNQFgalYa2R+=)cG(K;8NM51pkQKJsds+%q~H6|IGzxu{Zi8L@~vRAQ4J% z3WVf~fUgR!$h5117ouMM8V%~(#Zv4H$}9rVnmIUm{=?WmzJDRhEGBALj*U+&Aj{P-%O)jh!^QIEU1eZkAUz~V4go?w zB{d|-jsj%gW8>4@0n`FR%K^m3FDdDOXa}Gh3QP64_{2JbCz*;Z%z( zPmCjo%Cj(o&@EPyk;1SXU7k?6KrjSgmNy3~;8ll9o=_+d3;}cpL{C1(z`(%3ur${S zt9oSl+Vu|@7#Q%Ejx2;6fDUk3OsqUQ7~JIma{R%9lURVP9$z}Z=>Tk+h;;-ub+{aX zHE|#-E_M`WU|?Wi=-vMkMGdx8k8UwGz32%NuLEEPzyP`<@Bv(U(H%fiF2EHU_$(#_ zh>ikE0KO=|nh22viN8j@5Qkpl=-MkKe2iE#|MeT0z- Y0JdI?It5RF8~^|S07*qoM6N<$f>6DX4FCWD literal 0 HcmV?d00001 diff --git a/assets/ui/README.md b/assets/ui/README.md new file mode 100644 index 0000000..94d658a --- /dev/null +++ b/assets/ui/README.md @@ -0,0 +1 @@ +Future UI asset buckets. Nothing is wired yet. Use 32x32 as the base size for non-grid UI objects.\n \ No newline at end of file diff --git a/dist/game-v27.17.js b/dist/game-v27.17.js new file mode 100644 index 0000000..1863d48 --- /dev/null +++ b/dist/game-v27.17.js @@ -0,0 +1,59 @@ +var Y={version:"v27.17 VERIFIED VISUAL PATCH",time:{daySeconds:60,farmShutdownGraceSeconds:10},cash:{starting:250},grid:{x:170,y:78,cols:20,rows:10,cell:46,expansion:{colsPerPurchase:10,rowsPerPurchase:10,costBase:1e3,costMultiplier:1.3333333333333333,truncateUnit:100}},map:{blockedRatio:.075},economy:{income:{mixer:5,truck:10},poopFine:10,fairiesTribute:{perDay:10,profitExemption:300,legalWorkExemptionBonus:250,profitRate:.12},incomeUpgradeRate:1.1,explosionDamageDivisor:30,maleTruckFinePerHalfDay:30,shredderBonus:{maxCards:30,incomePerUpgrade:1.25},chemicalWeaponSubsidy:{poopPerBlock:70,yenPerBlock:1200}},production:{poopRate:.08,autoScannerCooldown:3.5,autoScannerUpgradeRate:.95,autoScannerCardUpgradeRate:.95,autoScannerMinCooldown:.5,poopRateCardBonus:.04,eggSpawnRanges:[[1.95,4.35],[1.55,3.45],[1.25,2.8],[1.05,2.35]]},conveyor:{baseSpeed:52,maxSpeed:300,bearingSpeedMultiplier:1.075},cards:{definitions:[{id:"upgradeEgg",title:"EGG Improvement",rarity:"common",type:"equipmentUpgrade",target:"eggFarm",description:"Choose one EGG FARM on the map and raise it by 1 level.",tags:["EGG","ACTIVE"]},{id:"upgradeAutoScanner",title:"AUTO SCANNER Improvement",rarity:"common",type:"equipmentUpgrade",target:"autoScanner",description:"Choose one AUTO SCANNER on the map and raise it by 1 level.",tags:["SCANNER","ACTIVE"]},{id:"autoScannerTuning",title:"AUTO SCANNER Tuning",rarity:"common",type:"instant",description:"All AUTO SCANNER cooldowns use default cooldown x0.95 per copy.",tags:["SCANNER","PASSIVE"]},{id:"upgradeMixer",title:"MIXER Improvement",rarity:"common",type:"equipmentUpgrade",target:"mixer",description:"Choose MIXER on the map and raise it by 1 level.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeTruck",title:"TRUCK Improvement",rarity:"common",type:"equipmentUpgrade",target:"truck",description:"Choose TRUCK on the map and raise it by 1 level.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeTrash",title:"SHREDDER Improvement",rarity:"common",type:"equipmentUpgrade",target:"trash",description:"Shred poops for a little money. Max 30 upgrades.",tags:["POOP","ACTIVE"]},{id:"crowdedFarming",title:"Crowded Farming",rarity:"common",type:"instant",description:"EGG production interval -5%. Equipment deterioration +4%. Max 10 cards.",tags:["EGG","RISK","PASSIVE"]},{id:"hatchingFeed",title:"Hatching Feed",rarity:"common",type:"instant",description:"EGG production interval -4%. Poop rate +3%. No card limit.",tags:["EGG","POOP","PASSIVE"]},{id:"poopRateBooster",title:"Poop Culture",rarity:"common",type:"instant",description:"Base poop rate +4 percentage points. No card limit.",tags:["POOP","PASSIVE"]},{id:"safetyCover",title:"Safety Cover",rarity:"common",type:"instant",description:"Explosion damage -5%. No card limit.",tags:["RISK","PASSIVE"]},{id:"preventiveMaintenance",title:"Preventive Maintenance Manual",rarity:"common",type:"instant",description:"All equipment deterioration speed -5%. No card limit.",tags:["MAINTENANCE","PASSIVE"]},{id:"dudFilter",title:"DUD Filter",rarity:"common",type:"instant",description:"DUD chance -5 percentage points. Stacks until DUD chance reaches 0%.",tags:["CARD","PASSIVE"]},{id:"durabilityCoating",title:"Durability Coating",rarity:"common",type:"instant",description:"All equipment maximum durability +3%. No card limit.",tags:["MAINTENANCE","PASSIVE"]},{id:"bearing",title:"High-Quality Bearing",rarity:"common",type:"instant",description:"Conveyor speed +7.5%.",tags:["CONVEYOR","PASSIVE"]},{id:"sparePartsBin",title:"SPARE PARTS BIN",rarity:"common",type:"instant",description:"Restores 2% durability to every machine. A box of almost-compatible parts.",tags:["MAINTENANCE","ACTIVE"]},{id:"dudRefund",title:"DUD REFUND",rarity:"common",type:"instant",description:"DUDs now come with paperwork. Gain JPY 50 per copy when you pick a DUD.",tags:["CARD","ECONOMY","PASSIVE"]},{id:"freeReroll",title:"FREE REROLL",rarity:"common",type:"instant",description:"The first bad ideas are free.",tags:["CARD","PASSIVE"]},{id:"composter",title:"COMPOSTER",rarity:"common",type:"instant",description:"Turns shredder waste into suspicious fertilizer. Gain JPY 3 per copy when SHREDDER processes poop.",tags:["POOP","ECONOMY","PASSIVE"]},{id:"scannerQueueSpacing",title:"Scanner Queue Spacing",rarity:"common",type:"instant",description:"Manual and Auto Scanner queue spacing -15%. No card limit.",tags:["SCANNER","PASSIVE"]},{id:"extraEggOutlet",title:"Extra Egg Outlet",rarity:"rare",type:"equipmentUpgrade",target:"eggOutlet",description:"Choose one EGG FARM and add +1 output port to that EGG. Max +3 per EGG.",tags:["EGG","RARE","ACTIVE"]},{id:"recyclingSubsidy",title:"Recycling Subsidy",rarity:"rare",type:"instant",description:"SELL refund rate +10 points. Max 3 cards; normal SELL can reach 80%.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"dynamite",title:"Dynamite",rarity:"rare",type:"cellAction",target:"blockedCell",description:"Remove any 3 unbuildable cells",tags:["RISK","RARE","ONE-SHOT"]},{id:"usedMachine",title:"Used Machines",rarity:"rare",type:"instant",description:"Future equipment costs half. New purchases have no refund and 60% durability. New Machines cancels it.",tags:["ECONOMY","RISK","RARE"]},{id:"newMachine",title:"New Machines",rarity:"common",type:"instant",description:"Cancel Used Machines and restore normal prices, refunds, and durability.",tags:["ECONOMY","ONE-SHOT"]},{id:"flattery",title:"Flattery",rarity:"rare",type:"instant",description:"Next Fairies tribute -50%.",tags:["ECONOMY","RARE","ONE-SHOT"]},{id:"extraCards",title:"Extra Cards",rarity:"rare",type:"instant",description:"Draw 2 cards now and choose both.",tags:["RARE","ACTIVE"]},{id:"legalWork",title:"Legal Work",rarity:"rare",type:"instant",description:"Fairies tribute profit exemption +JPY 250.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"chemicalWeaponSubsidy",title:"Chemical Weapons Subsidy",rarity:"ultraRare",type:"instant",description:"Each day, gain JPY 1200 per 70 poop shipped by truck. No card limit.",tags:["POOP","ULTRA RARE","PASSIVE"]},{id:"laborExploitation",title:"Motivational Exploitation",rarity:"ultraRare",type:"instant",description:"Repair room work time -30%. The repairman smiles with bloodshot eyes. One time only.",tags:["MAINTENANCE","ULTRA RARE","PASSIVE"]},{id:"rescueLoan",title:"Emergency Loan",rarity:"ultraRare",type:"instant",description:"If cash is below JPY 0 at day-end settlement, gain JPY 500. Consumed on use.",tags:["ECONOMY","ULTRA RARE","ONE-SHOT"]}],defaultEffects:{bearing:0,legalWork:0,fairiesFlatteryNext:0,autoScannerTuning:0,poopRateBooster:0,crowdedFarming:0,hatchingFeed:0,safetyCover:0,recyclingSubsidy:0,chemicalWeaponSubsidy:0,preventiveMaintenance:0,dudFilter:0,durabilityCoating:0,sparePartsBin:0,dudRefund:0,freeReroll:0,composter:0,scannerQueueSpacing:0,laborExploitation:0,usedMachineActive:!1,rescueLoanCharges:0},commonWeight:8,rareWeight:2,ultraRareWeight:.45,baseDraftSize:3,maxDudsPerDraft:2,dudChancePerCard:.3,dudChanceReductionPerFilter:.05,extraCardsAddedPicks:2,rerollCost:{dayDivisor:2,multiplier:100}},events:{eventChance:.1,firstTurn:8},maintenance:{fullPerformanceUntilWear:.5,minimumPerformance:.5,durability:{conveyor:1300,eggFarm:475,autoScanner:850,mixer:775,trash:950},processingDelayMaxSeconds:{mixer:1.2,trash:1},repairman:{secondsPerOnePercent:.5,walkSpeed:90}},facilities:{conveyor:{id:"conveyor",type:"conveyor",name:"Conveyor",shortName:"Belt",price:30,buildable:!0,upgradeable:!1},boostConveyor:{id:"boostConveyor",type:"conveyor",name:"Boost Conveyor",shortName:"BOOST BELT",price:75,buildable:!0,upgradeable:!1,speedMultiplier:2},eggFarm:{id:"eggFarm",type:"eggFarm",name:"Egg Farm",shortName:"EGG",price:250,buildable:!0,upgradeable:!0,maxLevel:4},manualScanner:{id:"manualScanner",type:"scanner",kind:"manual",name:"Manual Scanner",shortName:"Manual Scanner",price:260,buildable:!0,upgradeable:!1},autoScanner:{id:"autoScanner",type:"scanner",kind:"auto",name:"Auto Scanner",shortName:"Auto Scanner",price:180,buildable:!0,upgradeable:!1},mixer:{id:"mixer",type:"facility",name:"Mixer",shortName:"MIXER",price:450,buildable:!0,upgradeable:!0,incomeKey:"mixer",body:{w:164,h:126}},trash:{id:"trash",type:"facility",name:"Waste Shredder",shortName:"SHREDDER",price:240,buildable:!0,upgradeable:!0,body:{w:180,h:100}},truck:{id:"truck",type:"facility",name:"Truck",shortName:"TRUCK",price:450,buildable:!0,upgradeable:!0,incomeKey:"truck",body:{w:176,h:138}},maintenanceRoom:{id:"maintenanceRoom",type:"maintenanceRoom",name:"Maintenance Room",shortName:"REPAIR ROOM",price:220,buildable:!0,upgradeable:!1,footprint:{cols:2,rows:2}}}};var Er=Y.version,Mt=Y.time.daySeconds,an=Y.cash.starting,Ce=Y.economy,Rr=Y.time.farmShutdownGraceSeconds,xn=Y.production.autoScannerCooldown,Pr=Y.production.autoScannerUpgradeRate,po=Y.production.autoScannerCardUpgradeRate||Y.production.autoScannerUpgradeRate,yo=Y.production.autoScannerMinCooldown,Ar=Y.events.eventChance,gt=Y.events.firstTurn,ho=Y.production.poopRate,mo=Y.production.poopRateCardBonus||0,Mn=Y.conveyor.baseSpeed,Wt=Y.conveyor.maxSpeed,gn=Y.conveyor.bearingSpeedMultiplier,$e=Y.cards,Ir=Y.cards.definitions,bo=Y.cards.defaultEffects,st=Y.production.eggSpawnRanges,f=Y.grid,ve=Y.facilities,vo=["conveyor","boostConveyor","eggFarm","autoScanner","manualScanner","mixer","trash","truck","maintenanceRoom"],cn=["mixer","trash","truck"],$r=["mixer","truck"],lt=Object.fromEntries(Object.entries(ve).map(([e,t])=>[e,t.price])),de=[{name:"right",dc:1,dr:0,angle:0,opposite:"left"},{name:"left",dc:-1,dr:0,angle:Math.PI,opposite:"right"},{name:"down",dc:0,dr:1,angle:Math.PI/2,opposite:"up"},{name:"up",dc:0,dr:-1,angle:-Math.PI/2,opposite:"down"}],p={bg:"#111318",ink:"#090a0d",muted:"#8f9bab",green:"#7bd84f",greenSoft:"#273c24",mixerBlue:"#4aa3ff",truckPink:"#ffb33e",wasteGreen:"#88d35a",danger:"#e34a36",warn:"#ffb827",white:"#e6edf2",poop:"#7b4a23",male:"#4aa3ff",female:"#ff6fae"},xe={ambient:0,important:1,critical:2};function g(e){let t=Number(e)||0;return`${t<0?"-":""}\uFFE5${Math.ceil(Math.abs(t)).toLocaleString("ja-JP")}`}function I(e,t){return`${e},${t}`}function Z(e){let[t,n]=String(e).split(",").map(Number);return{col:t,row:n}}function un(e,t,n){return Math.max(t,Math.min(n,e))}function W(e,t){return e+Math.random()*(t-e)}function Ee(e,t){return e>=0&&e=0&&tMath.round(un(r,0,255)).toString(16).padStart(2,"0");return`#${o(e)}${o(t)}${o(n)}`}function Kt(e,t,n){let o=Dr(e),r=Dr(t);return cl(wo(o.r,r.r,n),wo(o.g,r.g,n),wo(o.b,r.b,n))}var oe={appTitle:"Chick Sorter",versionTitle:`Chick Sorter ${Er}`,currency:"\uFFE5",phases:{title:"Title",build:"Build",running:"Sorting",clearing:"Clearing",loanDecision:"Emergency Loan",gameover:"Game Over"},actions:{startGame:"Start Game",nextDay:"Next Day",buildPhase:"Build Phase",restart:"Restart",close:"Close",remove:"Remove",refund:"Refund",autoMenu:"Auto Menu"},status:{build:e=>`BUILD: ${(e==="erase"?"SELL":e||"SELECT").toUpperCase()} | Right-drag pan | Hover equipment for info`,sorting:"Sorting: use scanner keys. Build after clearing the day.",allPortsConnected:"Start condition met: one EGG route reaches an exit.",equipmentPanelEmpty:"Hover equipment in Build phase.",eventPanelRunning:"Forced events appear in Build phase."},routeLabels:{mixer:"MIXER",truck:"TRUCK",trash:"WASTE",scanner:"NEXT","scanner-role-1":"NEXT",input:"IN"},fail:{outOfGrid:"Out of grid",cellOccupied:"Cell occupied",notEnoughCash:"Not enough cash",facilityExists:"Facility already exists",facilityOverlap:"Facility overlap",nothingToErase:"Nothing to sell",noUpgrade:"No upgrade available"}};function ct(e){return ve[e]?.name||String(e||"").replace(/^[a-z]/,t=>t.toUpperCase())}function ul(e){let t=ve[e];return t?e==="conveyor"||e==="boostConveyor"?`${g(t.price)} / tile`:e==="autoScanner"?`${g(t.price)} / ${xn.toFixed(1)}s cooldown`:e==="trash"?g(t.price):g(t.price):""}function dl(e){return{conveyor:"A narrow green belt. Routes decide whether chicks live, ship, or become invoices.",boostConveyor:"Moves chicks twice as fast. Wears down like a normal belt.",eggFarm:"A tiny gatehouse producing questionable eggs on schedule.",autoScanner:"Slower than hands without upgrades.",manualScanner:"A manual checkpoint. The operator is the algorithm.",mixer:"Male chicks become revenue here. Do not feed it poop.",trash:"A polite shredder for poop and other regrets.",truck:"Ships the target cargo. Wrong cargo still leaves a paper trail.",maintenanceRoom:"2\xD72 repair bay. Each room dispatches one repairman during the day."}[e]||""}function Br(e){let t=dl(e);return`${ct(e)}${ul(e)}${t?`${t}`:""}`}function Lr(e){return oe.routeLabels[e]||String(e).toUpperCase()}function Or(e){let t=2166136261;for(let n=0;n>>0}function Nr(e){let t=e>>>0;return()=>{t+=1831565813;let n=Math.imul(t^t>>>15,1|t);return n^=n+Math.imul(n^n>>>7,61|n),((n^n>>>14)>>>0)/4294967296}}function En(){return`RUN-${Date.now().toString(36)}-${Math.floor(Math.random()*1e6).toString(36)}`.toUpperCase()}function _r({seed:e,targetRatio:t=.2,reserved:n=[]}={}){let o=Nr(Or(e||En())),r=new Set(n.map(c=>typeof c=="string"?c:I(c.col,c.row))),i=[];for(let c=0;c0;c-=1){let v=Math.floor(o()*(c+1));[i[c],i[v]]=[i[v],i[c]]}let l=Math.round(f.cols*f.rows*t);return new Set(i.slice(0,Math.min(l,i.length)).map(c=>c.k))}function Gr({seed:e,colStart:t=0,colEnd:n=f.cols,rowStart:o=0,rowEnd:r=f.rows,targetRatio:i=.2,reserved:l=[]}={}){let c=Nr(Or(e||En())),v=new Set(l.map(X=>typeof X=="string"?X:I(X.col,X.row))),x=[],E=Math.max(0,Math.floor(t)),R=Math.max(E,Math.floor(n)),B=Math.max(0,Math.floor(o)),O=Math.max(B,Math.floor(r));for(let X=B;X0;X-=1){let ae=Math.floor(c()*(X+1));[x[X],x[ae]]=[x[ae],x[X]]}let ee=Math.round((R-E)*(O-B)*i);return new Set(x.slice(0,Math.min(ee,x.length)).map(X=>X.k))}var Ht=10,Ur=2,Wr=1;function qt(e,t){return`${e},${t}`}function fl(e){let[t,n]=String(e).split(",").map(Number);return{chunkX:t,chunkY:n}}function Rn(e){let t=Y.grid.expansion||{},n=Math.max(1,(e.gridExpansionPurchases||0)+1),o=(t.costBase||1e3)*n*(t.costMultiplier||4/3),r=Math.max(1,t.truncateUnit||100);return Math.floor(o/r)*r}function Kr(e){e.ownedCells=new Set,e.ownedChunks=new Set,e.gridChunkOriginY=0,e.gridExpansionPurchases=0,e.gridExpansionPurchasesByDirection={right:0,up:0};for(let t=0;t=0&&t=0&&n0)continue;let x=qt(v.chunkX,v.chunkY);t.has(x)||n.has(x)||n.set(x,So(e,v.chunkX,v.chunkY,v.direction))}}return[...n.values()].sort((o,r)=>{let i=o.direction===r.direction?0:o.direction==="right"?-1:1;return i||(o.chunkY!==r.chunkY?o.chunkY-r.chunkY:o.chunkX-r.chunkX)})}function Yr(e,t="right"){let n=Tt(e);return n.find(o=>o.direction===t)||n[0]||null}function Et(e){return{x:f.x+e.colStart*f.cell,y:f.y+e.rowStart*f.cell,w:e.cols*f.cell,h:e.rows*f.cell}}function ko(e){let t=Et(e);return{x:t.x+t.w/2-116,y:t.y+t.h/2-36,w:232,h:72,cx:t.x+t.w/2,cy:t.y+t.h/2}}function Vr(e,t){let n=ko(e);return t.x>=n.x&&t.x<=n.x+n.w&&t.y>=n.y&&t.y<=n.y+n.h}function zr(e){let t=[];for(let n=e.rowStart;nEe(t.col,t.row))}function Sl(e){return[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}].filter(t=>Ee(t.col,t.row))}function kl(e){return[{col:e.col,row:e.row+1},{col:e.col-1,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row-1}].filter(t=>Ee(t.col,t.row))}function ei(e){let t=new Set([...e.conveyorTiles]),n=o=>{o&&Ee(o.col,o.row)&&t.add(I(o.col,o.row))};for(let o of e.scanners){for(let r of Sl(o))n(r);for(let r of wl(o))n(r)}for(let o of e.eggFarms){n(o);for(let r of kl(o))n(r)}for(let o of Object.values(e.facilities))n(o.entry);return t}function jr(e){let t=hl.map(([n,o])=>({col:n,row:o}));for(let{col:n,row:o}of t)Zr(e,n,o);for(let n=0;n({...n,keys:n.keys?{left:{...n.keys.left},right:{...n.keys.right}}:null,queue:[]})),e.eggFarms=bl.map(n=>{let o=Rt(n);return{...n,nextSpawn:o,lastInterval:o}});let t=ei(e);e.blockedCells=_r({seed:e.runSeed,targetRatio:Y.map.blockedRatio,reserved:[...t]}),Cl(e),jr(e),e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function Pt(e){return e?[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}]:[]}function ye(e){let t=F(e.col,e.row);return{x:t.x+f.cell/2,y:t.y}}function dt(e,t,n){return e.eggFarms.find(o=>o.col===t&&o.row===n)||null}function ft(e,t,n){return e.scanners.find(o=>Pt(o).some(r=>r.col===t&&r.row===n))||null}function At(e,t){return e.scanners.find(n=>n.id===t)||null}function To(e,t){return e.scanners.find(n=>n.kind==="manual"&&n.slot===t)||null}function $n(e){return e?.baseId||e?.id||""}function Eo(e,t){return Object.entries(e.facilities||{}).filter(([,n])=>$n(n)===t)}function Re(e,t){return{inputA:{col:e.col,row:e.row-2},inputB:null,left:{col:e.col-1,row:e.row},right:{col:e.col+2,row:e.row}}[t]}function oi(e){return e?de.map(t=>({col:e.col+t.dc,row:e.row+t.dr})).filter(t=>Ee(t.col,t.row)):[]}function ri(e,t,n=[],o=[]){if(!t||!Ee(t.col,t.row))return[];let r=[],i=l=>{!l||!Ee(l.col,l.row)||!e.conveyorTiles.has(I(l.col,l.row))||n.some(c=>c&&Tn(l,c))||r.some(c=>Tn(c,l))||r.push({...l,viaTolerance:!Tn(l,t)})};i(t);for(let l of o)i(l);for(let l of oi(t))i(l);return r}function ti(e,t,n=[],o=[]){let r=ri(e,t,n,o),i=r.filter(l=>!l.viaTolerance);return i.length?i:r}function xl(e,t){let n=Re(t,"inputA");return!n||!Ee(n.col,n.row)?[]:e.conveyorTiles.has(I(n.col,n.row))?[{...n,viaTolerance:!1}]:[]}function Ml(e,t,n){let o=Re(t,n);return ri(e,o,Pt(t))}function gl(e,t){let n=e.facilities[t]||Eo(e,t)[0]?.[1];if(!n)return null;if(n.entry)return F(n.entry.col,n.entry.row);let o=$n(n)||t;return o==="mixer"?{x:n.x+n.w,y:n.y+n.h*.52}:o==="truck"?{x:n.x,y:n.y+n.h*.52}:o==="trash"?{x:n.x+n.w/2,y:n.y+8}:{x:n.x+n.w/2,y:n.y+n.h/2}}function ii(e,t,n){return n==="inputA"?xl(e,t).length>0:Ml(e,t,n).length>0}function be(e){e.branchCounters?.clear?.(),e.routeCache=null,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function De(e,t){return I(e,t)}function Yt(e){return Z(e)}function Tl(e,t){let n=e.conveyorMeta?.get?.(t)||{},o=[];return Array.isArray(n.outDirs)&&o.push(...n.outDirs),n.dir&&o.push(n.dir),[...new Set(o)].filter(r=>de.some(i=>i.name===r))}function El(e,t,n){let o=de.find(l=>l.name===n);if(!o)return!1;let r=e.conveyorMeta?.get?.(De(t.col+o.dc,t.row+o.dr));return r?[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))].includes(o.opposite):!1}function Rl(e,t){let n=Yt(t),o=e.conveyorMeta?.get?.(t)||{},r=de.filter(R=>e.conveyorTiles.has(De(n.col+R.dc,n.row+R.dr))).map(R=>R.name),i=Tl(e,t).filter(R=>r.includes(R)),l=r,c=i.length?i:l;if(r.length<3)return c;let v=new Set(r.filter(R=>El(e,n,R)));if(o.branchMode&&o.branchMode!=="random"&&r.includes(o.branchMode)){let R=new Set(v);R.add(o.branchMode),r.filter(B=>!R.has(B)).length>=2&&v.add(o.branchMode)}let x=r.filter(R=>!v.has(R));if(x.length)return x;let E=c.filter(R=>!v.has(R));return E.length?E:c}function Pl(e){return{version:e.routingVersion||0,cells:new Set,adjacency:new Map,components:new Map,cellToComponent:new Map,scannerInputs:new Map,scannerPorts:new Map,facilityPorts:new Map,farmOutputs:new Map,pathCache:new Map,metrics:{conveyorCells:0,edges:0,components:0,deadEnds:0,crosses:0,scannerPorts:0,connectedScannerPorts:0,facilityPorts:0,connectedFacilityPorts:0,farmOutputs:0},issues:[]}}function Al(e){let t=Pl(e);for(let o of e.conveyorTiles)t.cells.add(o),t.adjacency.set(o,[]);for(let o of t.cells){let r=Yt(o),i=Rl(e,o),l=de.filter(c=>i.includes(c.name));for(let c of l){let v=De(r.col+c.dc,r.row+c.dr);t.cells.has(v)&&t.adjacency.get(o).push({key:v,dir:c.name})}}let n=0;for(let[o,r]of t.adjacency.entries()){n+=r.length;let i=new Set(r.map(l=>l.dir));r.length===1&&(t.metrics.deadEnds+=1),r.length===4&&i.has("left")&&i.has("right")&&i.has("up")&&i.has("down")&&(t.metrics.crosses+=1)}return t.metrics.conveyorCells=t.cells.size,t.metrics.edges=Math.floor(n/2),Il(t),$l(e,t),t.issues=Kl(e,t,{includeRoutes:!1}),t}function Il(e){let t=1;for(let n of e.cells){if(e.cellToComponent.has(n))continue;let o=t++,r=[n],i=[];for(e.cellToComponent.set(n,o);r.length;){let l=r.shift();i.push(l);for(let c of e.adjacency.get(l)||[])e.cellToComponent.has(c.key)||(e.cellToComponent.set(c.key,o),r.push(c.key))}e.components.set(o,{id:o,cells:i,capacity:Math.max(1,i.length),count:0,ratio:0})}e.metrics.components=e.components.size}function $l(e,t){for(let n of e.scanners){let o={};for(let r of["inputA","left","right"]){let i=Re(n,r),l=r==="inputA"?i&&t.cells.has(De(i.col,i.row))?[{...i}]:[]:ti(e,i,Pt(n)).filter(x=>t.cells.has(De(x.col,x.row))),c=l.map(x=>De(x.col,x.row)),v=c.length>0;if(o[r]={type:r,cell:i,cells:l,keys:c,key:c[0]||null,connected:v},t.metrics.scannerPorts+=1,v&&(t.metrics.connectedScannerPorts+=1),r==="inputA")for(let x of c)t.scannerInputs.set(x,n.id)}t.scannerPorts.set(n.id,o)}for(let[n,o]of Object.entries(e.facilities)){if(!o.entry)continue;let r=ti(e,o.entry).filter(c=>t.cells.has(De(c.col,c.row))),i=r.map(c=>De(c.col,c.row)),l=i.length>0;t.facilityPorts.set(n,{id:n,cell:{...o.entry},cells:r,keys:i,key:i[0]||null,connected:l}),t.metrics.facilityPorts+=1,l&&(t.metrics.connectedFacilityPorts+=1)}for(let n of e.eggFarms){let o=oi({col:n.col,row:n.row}).map(r=>De(r.col,r.row)).filter(r=>t.cells.has(r));t.farmOutputs.set(n.id,o),t.metrics.farmOutputs+=o.length}}function _e(e){let t=e.routingVersion||0;return(!e.factoryGraph||e.factoryGraph.version!==t)&&(e.factoryGraph=Al(e)),e.factoryGraph}function si(e){let t=_e(e);return e.factoryGraphCommittedVersion=t.version,e.factoryGraphSnapshot=Dl(t),t}function Dl(e){return e?{version:e.version,conveyorCells:e.metrics.conveyorCells,edges:e.metrics.edges,components:e.metrics.components,deadEnds:e.metrics.deadEnds,crosses:e.metrics.crosses,scannerPorts:`${e.metrics.connectedScannerPorts}/${e.metrics.scannerPorts}`,facilityPorts:`${e.metrics.connectedFacilityPorts}/${e.metrics.facilityPorts}`,farmOutputs:e.metrics.farmOutputs,issues:[...e.issues||[]]}:null}function Fl(e,t){let n=t.col-e.col,o=t.row-e.row;return de.find(r=>r.dc===n&&r.dr===o)?.name||null}function Ro(e,t,n){let o=_e(e),r=De(t.col,t.row);if(!o.cells.has(r))return[];let i=`${r}|${n.cacheKey||"dynamic"}`;if(n.cacheKey&&o.pathCache.has(i))return o.pathCache.get(i).map(le=>le.map(se=>({...se})));let l=`${r}|none`,c=[{key:r,col:t.col,row:t.row,incoming:"none",depth:0}],v=new Map([[l,0]]),x=new Map,E=[],R=1/0,B=8,O=24,ee=80;for(;c.length;){let le=c.shift();if(le.depth>R)break;let se=`${le.key}|${le.incoming}`;if(n(le)){if(E.push(se),R=le.depth,E.length>=O)break;continue}for(let A of o.adjacency.get(le.key)||[]){let G=Yt(A.key),q=Fl(le,G),me=le.depth+1;if(me>R)continue;let D=`${A.key}|${q}`,U=v.get(D);if(U==null)v.set(D,me),x.set(D,[se]),c.push({key:A.key,col:G.col,row:G.row,incoming:q,depth:me});else if(U===me){let S=x.get(D)||[];S.length{if(X.length>=ee)return;let[A]=le.split("|"),G=[Yt(A),...se];if(le===l||A===r){X.push(G);return}for(let q of x.get(le)||[])ae(q,G)};for(let le of E)ae(le,[]);let he=[],ie=new Set;for(let le of X){let se=le.map(A=>De(A.col,A.row)).join(">");ie.has(se)||(ie.add(se),he.push(le))}return n.cacheKey&&o.pathCache.set(i,he.map(le=>le.map(se=>({...se})))),he}function li(e){let t=_e(e),n=new Map;for(let[o,r]of t.components.entries())n.set(o,{id:o,cells:[...r.cells],capacity:r.capacity,count:0,ratio:0});return{components:n,cellToComponent:new Map(t.cellToComponent)}}function ai(e,t,n){let o=_e(e),r=null,i=1/0;for(let l of o.cells){let c=Z(l),v=F(c.col,c.row),x=Math.hypot(v.x-t,v.y-n);xF(o.col,o.row));return t&&n.push(t),n}function ut(e,t){t&&(!e.length||Fr(e[e.length-1],t)>1)&&e.push(t)}function Bl(e,t,n,o=null){let r=[{x:e.x,y:e.y}];ut(r,F(t.col,t.row));for(let i of Dn(n,o))ut(r,i);return r}function Ll(e,t){let n=Dn(e),o=Re(t,"inputA");return o&&ut(n,F(o.col,o.row)),ut(n,ye(t)),n}function Ol(e,t,n,o){let r=[{x:e.x,y:e.y}];ut(r,F(t.col,t.row));for(let l of Dn(n))ut(r,l);let i=Re(o,"inputA");return i&&ut(r,F(i.col,i.row)),ut(r,ye(o)),r}function Nl(e,t,n=0){let o=F(t.col,t.row),r=0;for(let i of e.chicks||[]){if(i.stage==="flying"||i.stage==="queued")continue;Math.hypot(i.x-o.x,i.y-o.y){let R=x.roleBias??0,B=E.roleBias??0;if(R!==B)return R-B;let O=x.cells?.length??x.route?.length??Number.POSITIVE_INFINITY,ee=E.cells?.length??E.route?.length??Number.POSITIVE_INFINITY;if(O!==ee)return O-ee;let X=x.key||JSON.stringify(x.route||x.cells||x),ae=E.key||JSON.stringify(E.route||E.cells||E);return X.localeCompare(ae)});if(!o||r.length===1)return r[0];let i=r[0].roleBias??0,l=r.filter(x=>(x.roleBias??0)===i),c=Math.min(...l.map(x=>ni(e,x)));l=l.filter(x=>ni(e,x)===c);let v=e.branchCounters.get(t)||0;return e.branchCounters.set(t,v+1),l[Math.floor(Math.random()*l.length)]}function ci(e){return e.role===0?{left:{match:"male",destination:"mixer"},right:{match:"default",destination:"scanner-role-1"}}:{left:{match:"poop",destination:"trash"},right:{match:"default",destination:"truck"}}}function Po(e){let t=ci(e);return{left:t.left.destination,right:t.right.destination}}function Ao(e,t){return ci(e).left.match===t.sex?"left":"right"}function Io(e){return Lr(e)}function $o(e){return{mixer:"#2477ff",truck:"#ff6aa8",trash:"#22b94f","scanner-role-1":"#526456",scanner:"#526456",input:"#526456"}[e]||"#102015"}function It(e,t,n=!1){let o=_e(e),r=(o.farmOutputs.get(t.id)||[]).map(Yt),i=[];for(let v of r){let x=R=>o.scannerInputs.has(De(R.col,R.row));x.cacheKey=`farmInput:${v.col},${v.row}:v${o.version}`;let E=Ro(e,v,x);for(let R of E){let B=R[R.length-1],O=o.scannerInputs.get(De(B.col,B.row)),ee=At(e,O);ee&&i.push({key:`${ee.id}:${B.col},${B.row}:${R.length}`,scanner:ee,cells:R})}}let l=In(e,`farm:${t.id}`,i,n);if(l)return{scannerId:l.scanner.id,route:Ll(l.cells,l.scanner)};let c=In(e,`farm:${t.id}:output`,r.map(v=>({key:I(v.col,v.row),cells:[v]})),n);return c?{scannerId:null,route:Dn(c.cells)}:null}function ui(e,t,n,o,r=!1){let i=At(e,o);if(!i)return null;let c=_e(e).scannerPorts.get(i.id)?.[t],v=Re(i,t),x=c?.connected?(c.keys||[c.key]).filter(Boolean).map(Yt):[];if(!v||!x.length)return null;let E=Po(i)[t];return E==="scanner-role-1"?_l(e,i,t,n,v,x,r):Gl(e,i,t,n,v,x,E,r)}function _l(e,t,n,o,r,i,l){let c=_e(e),v=e.scanners.filter(R=>R.id!==t.id&&c.scannerPorts.get(R.id)?.inputA?.connected),x=[];for(let R of i)for(let B of v){let O=c.scannerPorts.get(B.id)?.inputA?.key;if(!O)continue;let ee=(c.scannerPorts.get(B.id)?.inputA?.keys||[O]).filter(Boolean),X=ie=>ee.includes(De(ie.col,ie.row));X.cacheKey=`toScanner:${R.col},${R.row}:${B.id}:v${c.version}`;let ae=Ro(e,R,X),he=B.role===1?0:1;for(let ie of ae)x.push({key:`${he}:start${I(R.col,R.row)}:s${B.id}:${ie.length}:${I(ie[ie.length-1].col,ie[ie.length-1].row)}`,target:B,cells:ie,roleBias:he})}let E=In(e,`scanner:${t.id}:${n}:toRole1`,x,l);return E?{destination:"scanner",nextScannerId:E.target.id,route:Ol(o,r,E.cells,E.target)}:null}function Gl(e,t,n,o,r,i,l,c){let v=_e(e),x=[...v.facilityPorts.entries()].filter(([B,O])=>O?.connected&&$n(e.facilities?.[B])===l);if(!x.length)return null;let E=[];for(let B of i)for(let[O,ee]of x){let X=(ee.keys||[ee.key]).filter(Boolean);if(!X.length)continue;let ae=ie=>X.includes(De(ie.col,ie.row));ae.cacheKey=`toFacility:${B.col},${B.row}:${O}:v${v.version}`;let he=Ro(e,B,ae);for(let ie of he)E.push({key:`start${I(B.col,B.row)}:${O}:${ie.length}:${I(ie[ie.length-1].col,ie[ie.length-1].row)}`,cells:ie,facilityId:O})}let R=In(e,`scanner:${t.id}:${n}:${l}`,E,c);return R?{destination:l,facilityId:R.facilityId,route:Bl(o,r,R.cells,gl(e,R.facilityId))}:null}function di(e,t,n=new Set){if(!t||n.has(t.id))return!1;n.add(t.id);for(let o of["left","right"]){let r=ui(e,o,ye(t),t.id,!1);if(r){if(["mixer","trash","truck"].includes(r.destination))return!0;if(r.destination==="scanner"){let i=At(e,r.nextScannerId);if(di(e,i,n))return!0}}}return!1}function Ul(e,t){return!!It(e,t,!1)?.scannerId}function Fn(e){if(e.phase!=="build")return[];let t=[];for(let n of e.eggFarms||[])Ul(e,n)||t.push({type:"eggFarm",id:n.id,ref:n,message:"This Egg will not produce chicks"});for(let n of cn)for(let[o,r]of Eo(e,n))_e(e).facilityPorts.get(o)?.connected||t.push({type:"facility",id:o,ref:r,message:"This facility cannot receive items"});return t}function Wl(e){let t=_e(e);for(let r of e.eggFarms||[]){let i=It(e,r,!1);if(!i?.scannerId)continue;let l=At(e,i.scannerId);if(di(e,l))return[]}let n=e.eggFarms?.length||0,o=[...t.facilityPorts.entries()].filter(([r,i])=>i?.connected&&["mixer","trash","truck"].includes($n(e.facilities?.[r]))).length;return n?t.metrics.farmOutputs?e.scanners?.length?o?["Connect at least one EGG through a scanner to any valid exit."]:["Connect at least one receiver exit: Mixer, Shredder, or Truck."]:["Build at least one scanner and connect it to an EGG route."]:["Connect at least one EGG to a conveyor."]:["Build at least one EGG before starting the next day."]}function An(e){return e.kind==="manual"?`S${(e.slot??0)+1}`:`Auto Scanner #${e.id}`}function Kl(e,t=_e(e),n={}){let o=n.includeRoutes!==!1,r=[],i={mixer:"Mixer",trash:"Shredder",truck:"Truck"};for(let l of cn){let c=Eo(e,l);if(!c.length){r.push(`${i[l]||l} is missing`);continue}for(let[v]of c)t.facilityPorts.get(v)?.connected||r.push(`${i[l]||l} receiver has no conveyor`)}for(let l of e.scanners){let c=t.scannerPorts.get(l.id)||{};if(c.inputA?.connected||r.push(`${An(l)} input has no conveyor`),c.left?.connected||r.push(`${An(l)} left output has no conveyor`),c.right?.connected||r.push(`${An(l)} right output has no conveyor`),!!o)for(let v of["left","right"])c[v]?.connected&&!ui(e,v,ye(l),l.id)&&r.push(`${An(l)} ${v} route is incomplete`)}if(o)for(let l of e.eggFarms)It(e,l)?.scannerId||r.push(`Egg Farm #${l.id} has no scanner route`);else for(let l of e.eggFarms)(t.farmOutputs.get(l.id)||[]).length||r.push(`Egg Farm #${l.id} has no output conveyor`);return[...new Set(r)]}function fn(e){return Wl(e)}function fi(e){return fn(e).length===0}var pi=[{key:"premiumFemaleShipment",target:"female",truckTarget:"female",title:"Premium Female Shipment",route:"Female -> Truck",note:"Today only: ship female chicks to Truck. Meet the export target for a bonus.",objective:"truckTarget"},{key:"contaminantSampleExport",target:"poop",truckTarget:"poop",title:"Contaminant Sample Export",route:"Poop value x2",note:"Today only: poop is valid Truck cargo and all poop income is doubled.",objective:"truckTarget",poopValueMultiplier:2},{key:"healthInspection",title:"Health Inspection",route:"Poop -> Shredder",note:"Today only: poop mistakes are fined double. Shred enough poop for an inspection bonus.",objective:"poopTrash",poopFineMultiplier:2},{key:"conveyorJamWarning",title:"Conveyor Jam Warning",route:"No explosions",note:"Today only: jam explosions trigger at 85% congestion. Finish with zero explosions for a bonus.",objective:"noExplosion",congestionExplosionThreshold:.85,congestionWarningThreshold:.68},{key:"powerSavingOrder",title:"Power Saving Order",route:"Slow factory subsidy",note:"Today only: conveyors -20% speed and Auto Scanners +20% cooldown. A subsidy is paid at settlement.",objective:"flatBonus",conveyorSpeedMultiplier:.8,autoScannerCooldownMultiplier:1.2},{key:"overtimeDay",title:"Overtime Day",route:"80 second day",note:"Today only: the work day is longer. No extra reward or penalty.",objective:"none",daySeconds:80},{key:"shortShift",title:"Short Shift",route:"40 second day",note:"Today only: the work day is shorter. The next Fairies tribute is reduced by 10%.",objective:"none",daySeconds:40,fairiesTributeMultiplier:.9},{key:"chickBoom",title:"Chick Boom",route:"EGG interval x0.65",note:"Today only: eggs hatch faster and poop rate rises by 5 percentage points.",objective:"none",productionMultiplier:1/.65,poopRateAdd:.05},{key:"rottenFeed",title:"Rotten Feed",route:"Poop surge",note:"Today only: poop rate rises by 20 percentage points and Shredder poop income is multiplied by 1.5.",objective:"none",poopRateAdd:.2,shredderIncomeMultiplier:1.5},{key:"maintenanceAudit",title:"Maintenance Audit",route:"Durability check",note:"Today only: machines below 50% remaining durability fail the audit. Passing with none below 50% pays a bonus.",objective:"maintenanceAudit"}];function we(e,t=0){let n=Number(e);return Number.isFinite(n)?n:t}function Hl(e,t=0,n=1){let o=Math.max(1,Number(e?.turn||1)+1),r=Math.floor(Do(e)*(.08+Math.random()*.08)),i=Math.floor(Math.max(0,e.cash||0)*.25),l=Math.floor(Math.max(0,t)*Math.max(1,o)*.75);return Math.max(120,Math.ceil(Math.max(r,i,l)*n))}function yi(e){return Math.max(0,Math.ceil(500+Math.max(1,e?.turn||1)*25))}function Do(e){return[...e.eggFarms.map(t=>t.price||0),...e.scanners.map(t=>t.price||0),...Object.values(e.facilities).map(t=>t.price||0),...[...e.conveyorMeta.values()].map(t=>t.price||0)].reduce((t,n)=>t+n,0)}function ql(e,t=1,n=Mt){return e.eggFarms.reduce((o,r)=>{let[i,l]=dn(r),c=Math.max(.1,(i+l)/2);return o+Math.max(1,n)/c*Math.max(.01,t||1)},0)}function Yl(e,t){let n=we(t.productionMultiplier,1),o=we(t.daySeconds,Mt),r=ql(e,n,o),i=Math.max(0,Number(e?.cardEffects?.hatchingFeed)||0),l=Math.max(0,Number(e?.cardEffects?.poopRateBooster)||0),c=Math.pow(1.03,i),v=ho+mo*l,x=Math.min(.95,Math.max(0,(v+we(t.poopRateAdd,0))*we(t.poopMultiplier,1)*c));return{estimate:r,poopRate:x}}function hi(e){if(e.turn+1Ar)return null;let n=pi[Math.floor(Math.random()*pi.length)],{estimate:o,poopRate:r}=Yl(e,n),i=0;n.objective==="truckTarget"?i=Math.max(1,Math.ceil(o*.3)):n.objective==="poopTrash"&&(i=Math.max(1,Math.ceil(o*r*.8)));let l=0;return["truckTarget","poopTrash","noExplosion"].includes(n.objective)&&(l=Hl(e,o)),n.objective==="flatBonus"&&(l=yi(e)),n.objective==="maintenanceAudit"&&(l=yi(e)),{id:`event-${e.turn}-${Date.now()}-${Math.floor(Math.random()*9999)}`,...n,target:n.target||null,truckTarget:n.truckTarget||null,forced:!0,productionMultiplier:we(n.productionMultiplier,1),poopMultiplier:we(n.poopMultiplier,1),poopRateAdd:we(n.poopRateAdd,0),daySeconds:we(n.daySeconds,Mt),targetAmount:i,estimatedOutput:Math.round(o),reward:l,createdTurn:e.turn,oneTurnOnly:!0}}function mi(e){e.eventActive=e.eventOffer?{...e.eventOffer}:null,e.eventOffer=null}function bi(e){e.eventActive=null}function vi(e){return Math.max(1,we(e.eventActive?.daySeconds,Mt))}function wi(e){return we(e.eventActive?.productionMultiplier,1)}function Si(e){let t=Math.max(0,Number(e?.cardEffects?.hatchingFeed)||0),n=Math.max(0,Number(e?.cardEffects?.poopRateBooster)||0),o=Math.pow(1.03,t),r=ho+mo*n,i=we(e.eventActive?.poopRateAdd,0);return Math.min(.95,Math.max(0,(r+i)*we(e.eventActive?.poopMultiplier,1)*o))}function je(e){return e.eventActive?.truckTarget||e.eventActive?.target||"female"}function Fo(e,t){return t==="male"?e.truckMale||0:t==="poop"?e.poopTruck||0:e.truckFemale||0}function ki(e,t){return je(e)===t}function Ci(e){return je(e)!=="male"}function Bo(e){return Math.max(.01,we(e.eventActive?.poopValueMultiplier,1))}function Bn(e){return Math.max(.01,Bo(e)*we(e.eventActive?.shredderIncomeMultiplier,1))}function Lo(e){return Math.max(.01,we(e.eventActive?.poopFineMultiplier,1))}function Oo(e){return Math.max(.1,Math.min(1,we(e.eventActive?.congestionExplosionThreshold,1)))}function xi(e){return Math.max(.1,Math.min(1,we(e.eventActive?.congestionWarningThreshold,.8)))}function Mi(e){return Math.max(.01,we(e?.fairiesTributeMultiplier,1))}function Vl(e){let t=0,n=(o,r)=>{let i=Math.max(1,we(r,1)),l=Math.max(0,we(o,0));1-Math.min(1,l/i)<.5&&(t+=1)};for(let o of e.conveyorMeta?.values?.()||[])n(o.uses,o.durability);for(let o of e.eggFarms||[])n(o.maintenance?.uses,o.maintenance?.durability);for(let o of e.scanners||[])o.kind==="auto"&&n(o.maintenance?.uses,o.maintenance?.durability);for(let o of Object.values(e.facilities||{})){let r=o?.baseId||o?.id;(r==="mixer"||r==="trash")&&n(o.maintenance?.uses,o.maintenance?.durability)}return t}function gi(e){let t=e.eventActive;if(!t)return null;let n=0,o=!0,r=0,i="";t.objective==="truckTarget"?(n=Fo(e.stats,t.target),o=n>=t.targetAmount,r=o?t.reward:0):t.objective==="poopTrash"?(n=e.stats.poopTrash||0,o=n>=t.targetAmount,r=o?t.reward:0):t.objective==="noExplosion"?(n=e.stats.explosions||0,o=n===0,r=o?t.reward:0,i=`${n} explosion(s)`):t.objective==="flatBonus"?(o=!0,r=t.reward):t.objective==="maintenanceAudit"?(n=Vl(e),o=n===0,o&&(r=t.reward),i=`${n} machine(s) below 50%`):o=!0,r>0?(Ge(e,r),e.stats.eventBonus=(e.stats.eventBonus||0)+r,e.totals.eventBonus+=r,e.totals.eventSuccess+=1):t.objective&&t.objective!=="none"&&(e.stats.eventBonus=e.stats.eventBonus||0,e.totals.eventFailed+=o?0:1,o&&(e.totals.eventSuccess+=1));let l={title:t.title,key:t.key,target:t.target,route:t.route,objective:t.objective,targetAmount:t.targetAmount||0,count:n,success:o,bonus:r,reward:t.reward||0,productionMultiplier:t.productionMultiplier,poopMultiplier:t.poopMultiplier,daySeconds:t.daySeconds,detail:i};return e.stats.eventResult=l,l}function No(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function zl(e){return!!e?.cardEffects?.usedMachineActive}function Xl(e,t){return t?1:Math.min(.8,.5+.1*Math.min(3,No(e,"recyclingSubsidy")))}function Ql(e){return Math.pow(.95,No(e,"safetyCover"))}function Ln(e){let t=e?.ref||e||{},n=e?.type||t.type;return n==="conveyor"?t.price||ve[t.kind]?.price||ve.conveyor.price:n==="eggFarm"?t.price||ve.eggFarm.price:n==="scanner"?t.price||(t.kind==="auto"?ve.autoScanner.price:ve.manualScanner.price):n==="facility"?t.price||ve[t.id]?.price||0:n==="maintenanceRoom"?t.price||ve.maintenanceRoom.price:ve[t.id]?.price||0}function Oe(e,t=null){let n=ve[e]?.price||0;return zl(t)?Math.ceil(n*.5):n}function Jl(e,t){return e?.facilities?Object.values(e.facilities).filter(n=>(n?.baseId||n?.id)===t).reduce((n,o)=>n+Math.max(0,(o.level||1)-1),0):0}function pt(e,t){return $r.includes(t)?Math.pow(Ce.incomeUpgradeRate,Jl(e,t)):1}function ze(e){return Math.ceil(Ce.income.mixer*pt(e,"mixer"))}function Fe(e){return Math.ceil(Ce.income.truck*pt(e,"truck"))}function pn(e){return Math.ceil(Ce.poopFine*pt(e,"mixer")*Lo(e))}function yn(e){return Math.ceil(Ce.poopFine*pt(e,"truck")*Lo(e))}function _o(e){let t=Ce.maleTruckFinePerHalfDay*(e.turn/2);return Math.ceil(t*pt(e,"truck"))}function Go(e){return e?.facilities?Object.values(e.facilities).filter(t=>(t?.baseId||t?.id)==="trash").reduce((t,n)=>t+Math.max(0,(n.level||1)-1),0):0}function $t(e){return Math.min(Ce.shredderBonus.maxCards,Go(e))}function Vt(){return Ce.shredderBonus.maxCards}function yt(e){let t=typeof e=="number"?e:$t(e),n=Math.min(Ce.shredderBonus.maxCards,Math.max(0,t));return n>0?Math.ceil(n*(Ce.shredderBonus.incomePerUpgrade||1)):0}function jl(e){let t=$t(e),n=yt(t),o=Math.ceil(n*Bn(e));return{cards:t,chance:o>0?1:0,amount:o,expected:o,baseAmount:n}}function Ti(e){let t=jl(e);return t.amount>0&&(e.stats.shredderBonus=(e.stats.shredderBonus||0)+t.amount,e.totals.shredderBonus=(e.totals.shredderBonus||0)+t.amount,Ge(e,t.amount)),t}function On(e,t=e.turn,n=null){let o=Math.max(1,Math.floor(Number(t)||1)),r=Ce.fairiesTribute||{perDay:10,profitExemption:300,legalWorkExemptionBonus:250,profitRate:.12},i=Math.ceil(o*(r.perDay||10)),l=Math.max(0,Math.floor(Number(n??e?.lastResult?.profit??e?.stats?.profit??0)||0)),c=Math.max(0,e?.cardEffects?.legalWork||0),v=Math.max(0,(r.profitExemption||0)+c*(r.legalWorkExemptionBonus||0)),x=Math.max(0,l-v),E=Math.ceil(x*Math.max(0,Number(r.profitRate)||0)),R=i+E,B=Math.max(0,e?.cardEffects?.fairiesFlatteryNext||e?.cardEffects?.flattery||0),O=B>0?Math.pow(.5,B):1,ee=Math.max(.01,Number(e?.pendingFairiesTributeMultiplier)||1),X=O*ee,ae=Math.max(0,Math.ceil(R*X)),he=Math.max(0,R-ae);return{day:o,base:i,profit:l,legalWork:c,profitExemption:v,taxableProfit:x,profitTribute:E,gross:R,flatteryCount:B,eventMultiplier:ee,perCardReduction:Math.ceil(R*.5),reduction:he,amount:ae}}function ht(e,t){let n=e?.ref||e||{},o=e?.type==="conveyor"?t?.conveyorMeta?.get(e.oldKey||n.id):n,r=o?.price||Ln(e||n),i=o?.builtSession===t?.buildSession;if(o?.noRefund||n?.noRefund)return{amount:0,sameBuild:i,price:r,rate:0,noRefund:!0};let l=Xl(t,i);return{amount:Math.max(0,Math.ceil(r*l)),sameBuild:i,price:r,rate:l,noRefund:!1}}function Zl(e,t=null){let n=Math.max(1,Math.ceil((Number(e)||0)/Ce.explosionDamageDivisor));return Math.max(1,Math.ceil(n*Ql(t)))}function ea(e,t){return Math.max(0,Math.ceil(t))}function Ei(e,t){e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,t>=0?(e.stats.revenue+=t,e.totals.revenue+=t):(e.stats.penalty+=Math.abs(t),e.totals.penalty+=Math.abs(t)),e.totals.maxCash=Math.max(e.totals.maxCash,e.cash)}function Ge(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&Ei(e,n),n}function mt(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&Ei(e,-n),n}function Dt(e,t){mt(e,t)}function Ri(e,t){t<=0||(e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,e.totals.maxCash=Math.max(e.totals.maxCash,e.cash))}function Pi(e){let t=ze(e);return e.stats.mixerRevenue+=t,Ge(e,t),t}function Ai(e){let t=pn(e);return e.stats.mixerPoopFine+=t,e.totals.mixerPoopFine+=t,mt(e,t),t}function Ii(e){let t=yn(e);return e.stats.truckPoopFine+=t,e.totals.truckPoopFine+=t,mt(e,t),t}function $i(e){let t=_o(e);return e.stats.maleTruckFine+=t,e.totals.maleTruckFine+=t,mt(e,t),t}function Di(e,t){let n=Zl(t,e);return e.stats.explosionDamage+=n,e.totals.explosionDamage+=n,mt(e,n),n}function Fi(e){let t=je(e),n=Fo(e.stats,t),o=t==="poop"?Math.ceil(Fe(e)*Bo(e)):Fe(e),r=n*o,i=ea(e,r);return e.stats.pendingTruckRevenue=i,e.stats.truckRevenue=i,t==="poop"?e.stats.poopShipmentIncome=i:e.stats.chickShipmentIncome=i,i>0&&Ge(e,i),{base:r,adjusted:i,target:t,targetCount:n,unitPrice:o}}function Bi(e,t=e.turn,n=null,o={}){let r=On(e,t,n);return e.cardEffects&&(e.cardEffects.fairiesFlatteryNext=0,e.cardEffects.flattery!=null&&delete e.cardEffects.flattery),e.pendingFairiesTributeMultiplier!=null&&(e.pendingFairiesTributeMultiplier=1),r.amount<=0||(o.recordStats?(e.stats.fairiesTribute=(e.stats.fairiesTribute||0)+r.amount,e.totals.fairiesTribute=(e.totals.fairiesTribute||0)+r.amount,mt(e,r.amount)):(e.totals.fairiesTribute=(e.totals.fairiesTribute||0)+r.amount,e.totals.penalty=(e.totals.penalty||0)+r.amount,e.totals.profit=(e.totals.profit||0)-r.amount,e.cash-=r.amount)),r}function Li(e){let t=No(e,"chemicalWeaponSubsidy"),n=Math.max(0,e?.stats?.poopTruck||0),o=Ce.chemicalWeaponSubsidy||{poopPerBlock:70,yenPerBlock:1200},r=Math.floor(n/Math.max(1,o.poopPerBlock||70)),i=t>0&&r>0?r*Math.max(0,o.yenPerBlock||1200)*t:0;return i>0&&(e.stats.chemicalWeaponSubsidy=(e.stats.chemicalWeaponSubsidy||0)+i,e.totals.chemicalWeaponSubsidy=(e.totals.chemicalWeaponSubsidy||0)+i,Ge(e,i)),{cards:t,poopTruck:n,blocks:r,amount:i}}function Oi(e){let t=Do(e),n=Math.max(1,e.totals.turnsCompleted||e.turn||1),o=Math.max(0,e.cash+e.totals.revenue+t*.5+e.totals.eventBonus*.5),r=Math.ceil(o/n),i=Math.floor(n*35+Math.max(0,n-5)*15),l=e.totals.correct*5,c=e.totals.explosionDamage;return{score:Math.max(0,Math.floor(o+r+l-e.totals.penalty-i)),factoryValue:t,base:o,dailyEarned:r,dayPenalty:i,correctBonus:l,explosionPenalty:c,days:n}}function ta(e){return{...e,keys:e.keys?{left:{...e.keys.left},right:{...e.keys.right}}:null,queue:[],cooldown:e.cooldown||0}}function hn(e){return JSON.stringify({cash:e.cash,stats:e.stats,totals:e.totals,nextId:e.nextId,gridX:f.x,gridY:f.y,gridCols:e.gridCols||f.cols,gridRows:e.gridRows||f.rows,gridExpansionPurchases:e.gridExpansionPurchases||0,gridExpansionPurchasesByDirection:e.gridExpansionPurchasesByDirection||{right:0,up:0},gridChunkOriginY:e.gridChunkOriginY||0,ownedCells:[...e.ownedCells||[]],ownedChunks:[...e.ownedChunks||[]],blockedCells:[...e.blockedCells||[]],selected:e.selected,multiSelected:e.multiSelected||[],buildTool:e.buildTool,view:e.view,facilities:e.facilities,eggFarms:e.eggFarms,scanners:e.scanners.map(ta),conveyorTiles:[...e.conveyorTiles],conveyorMeta:[...e.conveyorMeta.entries()],branchCounters:[...e.branchCounters.entries()],cardEffects:e.cardEffects,cardDraft:e.cardDraft,cardTargetPick:e.cardTargetPick})}function Ni(e,t){let n=JSON.parse(t);e.cash=n.cash,e.stats=n.stats,e.totals=n.totals,e.nextId=n.nextId,f.x=n.gridX??Y.grid.x,f.y=n.gridY??Y.grid.y,f.cols=n.gridCols||Y.grid.cols,f.rows=n.gridRows||Y.grid.rows,e.gridCols=f.cols,e.gridRows=f.rows,e.gridExpansionPurchases=n.gridExpansionPurchases||0,e.gridExpansionPurchasesByDirection=n.gridExpansionPurchasesByDirection||{right:0,up:0},e.gridChunkOriginY=n.gridChunkOriginY||0,e.ownedCells=new Set(n.ownedCells||[]),e.ownedChunks=new Set(n.ownedChunks||[]),e.gridOwnedCells=e.ownedCells.size||f.cols*f.rows,e.blockedCells=new Set(n.blockedCells||[]),e.selected=n.selected,e.multiSelected=n.multiSelected||[],e.buildTool=n.buildTool,e.view=n.view||{x:0,y:0,scale:1},e.view.scale==null&&(e.view.scale=1),e.facilities=n.facilities||{},e.eggFarms=n.eggFarms||[],e.scanners=(n.scanners||[]).map(o=>({...o,queue:[],cooldown:o.cooldown||0})),e.conveyorTiles=new Set(n.conveyorTiles||[]),e.conveyorMeta=new Map(n.conveyorMeta||[]),e.branchCounters=new Map(n.branchCounters||[]),e.cardEffects=n.cardEffects||{bearing:0,legalWork:0,fairiesFlatteryNext:0,scannerQueueSpacing:0},e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft=n.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardTargetPick=n.cardTargetPick||null,e.groupDrag=null,e.selectionBox=null,e.pan=null,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function Be(e){e.phase==="build"&&(e.undoStack.push(hn(e)),e.undoStack.length>80&&e.undoStack.shift(),e.redoStack=[])}function Uo(e){return e.phase!=="build"||!e.undoStack.length?!1:(e.redoStack.push(hn(e)),Ni(e,e.undoStack.pop()),!0)}function Wo(e){return e.phase!=="build"||!e.redoStack.length?!1:(e.undoStack.push(hn(e)),Ni(e,e.redoStack.pop()),!0)}function H(e,t,n,o,r=p.ink){e.floatingTexts.push({x:t,y:n,text:o,color:r,life:1,maxLife:1})}function Ft(e,t,n){e.shake.strength=Math.max(e.shake.strength,t),e.shake.time=Math.max(e.shake.time,n)}function _i(e,t,n){e.effects.push({type:"spawn",priority:xe.ambient,x:t,y:n,life:.42,maxLife:.42,size:12})}function Gi(e,t,n,o=p.green){e.effects.push({type:"scannerPulse",priority:xe.important,x:t,y:n,color:o,life:.42,maxLife:.42,size:24})}function Ui(e,t,n){for(let o=0;o<12;o+=1)e.effects.push({type:"meat",priority:xe.important,x:t+W(-18,18),y:n+W(-12,16),vx:W(-60,60),vy:W(-90,-25),life:W(.45,.85),maxLife:.85,size:W(4,8)})}function Wi(e,t,n){for(let o=0;o<16;o+=1)e.effects.push({type:"sludge",priority:xe.important,x:t+W(-18,18),y:n+W(-12,16),vx:W(-46,46),vy:W(-70,-20),life:W(.45,.9),maxLife:.9,size:W(4,8)})}function Ki(e,t,n,o){let r=o==="poop"?p.poop:o==="male"?p.male:p.female;for(let i=0;i<22;i+=1)e.effects.push({type:"shred",priority:xe.important,x:t+W(-16,16),y:n+W(-8,8),vx:W(-70,70),vy:W(40,160),color:i%3===0?p.white:r,life:W(.45,.95),maxLife:.95,w:W(3,7),h:W(10,24),rot:W(-Math.PI,Math.PI)});Xe(e,t,n,p.green,34,xe.important)}function Hi(e,t,n,o){let r=o==="poop"?p.poop:o==="male"?p.danger:p.green;for(let i=0;i<8;i+=1)e.effects.push({type:"load",priority:xe.important,x:t+W(-18,18),y:n+W(-18,18),vx:W(-42,42),vy:W(-90,-25),color:r,life:W(.35,.65),maxLife:.65,size:8})}function Xe(e,t,n,o=p.danger,r=52,i=xe.critical){e.effects.push({type:"shockwave",priority:i,x:t,y:n,color:o,life:.55,maxLife:.55,size:8,maxSize:r})}function Ze(e,t,n,o=12,r=p.danger,i=xe.critical){for(let l=0;l0&&(e.shake.time=Math.max(0,e.shake.time-t),e.shake.time<=0&&(e.shake.strength=0));for(let r of e.effects)if(r.life-=t,["meat","sludge","spark","smoke","shred","load","rage"].includes(r.type))r.x+=(r.vx||0)*t,r.y+=(r.vy||0)*t,r.vy=(r.vy||0)+150*t;else if(r.type==="flyingChick"){r.x+=r.vx*t,r.y+=r.vy*t,r.vy+=360*t,r.noDamage||na(e,r,o);let i=r.x+e.view.x,l=r.y+e.view.y;(i<-100||l<-100||i>n.width+100||l>n.height+100)&&(r.life=0)}e.effects=e.effects.filter(r=>r.life>0);for(let r of e.floatingTexts)r.life-=t,r.y-=34*t;e.floatingTexts=e.floatingTexts.filter(r=>r.life>0)}function na(e,t,n){t.hit||(t.hit=new Set);for(let o of n()){if(t.hit.has(o.id)||t.xo.x+o.w||t.yo.y+o.h)continue;t.hit.add(o.id);let r=Di(e,o.price);H(e,t.x,t.y-10,`-${g(r)}`,p.danger),Xe(e,t.x,t.y,p.danger,30),Ze(e,t.x,t.y,5,p.danger),Ft(e,5,.18)}}var Ue=Y.maintenance;function Ho(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function Gn(e){let t=Math.min(1.4,1+.04*Math.min(10,Ho(e,"crowdedFarming"))),n=Math.pow(.95,Ho(e,"preventiveMaintenance"));return t*n}function oa(e){return Math.pow(1.03,Ho(e,"durabilityCoating"))}function Un(e,t,n=1){let o=Ue.durability[t]||1e3;return Math.max(1,Math.ceil(o*Math.max(.1,n||1)*oa(e)))}function Vi(e){return Math.max(.1,Number(e?.durabilityBaseMultiplier)||1)}function ra(e,t=0){if(!e)return{x:f.x+f.cell*(.5+t*.55),y:f.y+f.rows*f.cell+84};let n=f.x+e.col*f.cell+f.cell,o=f.y+e.row*f.cell+f.cell;return{x:n,y:o}}function ia(e,t=0){let n=(e.maintenanceRooms||[])[t];return ra(n,t)}function Se(e){e.repairman||(e.repairman={active:!1,x:f.x+f.cell*.5,y:f.y+f.rows*f.cell+84,target:null,repairedToday:0}),Array.isArray(e.maintenanceRooms)||(e.maintenanceRooms=[]),Array.isArray(e.repairmen)||(e.repairmen=[]);for(let[t,n]of e.conveyorMeta||[]){n.uses==null&&(n.uses=0),n.maintenanceType==null&&(n.maintenanceType="conveyor"),n.kind||(n.kind="conveyor"),n.speedMultiplier||(n.speedMultiplier=n.kind==="boostConveyor"?2:1),n.branchMode||(n.branchMode="random");let o=Un(e,"conveyor",Vi(n));(n.durability==null||n.durability0&&(n.processingCooldown=Math.max(0,n.processingCooldown-t))}function vn(e){Se(e);let t=[];for(let[n,o]of e.conveyorMeta||[])t.push({type:"conveyor",key:n,meta:o,label:`${o.kind==="boostConveyor"?"Boost Belt":"Belt"} ${n}`,center:F(Z(n).col,Z(n).row)});for(let n of e.eggFarms||[])t.push({type:"eggFarm",ref:n,label:`EGG #${n.id}`,center:F(n.col,n.row)});for(let n of(e.scanners||[]).filter(o=>o.kind==="auto"))t.push({type:"autoScanner",ref:n,label:`AUTO #${n.id}`,center:F(n.col,n.row)});for(let n of Object.values(e.facilities||{})){let o=qn(n);["mixer","trash"].includes(o)&&t.push({type:o,ref:n,label:`${n.shortName||n.name||o} #${n.id}`,center:{x:n.x+n.w/2,y:n.y+n.h/2}})}return t}function Bt(e){return e.meta?zt(e):zt(e.ref)}function mn(e){return e.meta?qo(e):qo(e.ref)}function _n(e){return e.meta?Yo(e):Yo(e.ref)}function ji(e,t){sa(e.meta?e:e.ref,Math.max(0,mn(e)-t))}function er(e){return e.type==="conveyor"?`conveyor:${e.key}`:`${e.type}:${e.ref?.id||e.ref?.type||e.type}`}function Zi(e,t=.02){Se(e);let n=Math.max(0,Number(t)||0),o=0;for(let r of vn(e)){let i=mn(r);ji(r,_n(r)*n),o+=Math.max(0,i-mn(r))/_n(r)*100}return o}function es(e){Se(e);let t=e.maintenanceRooms||[];e.repairmen=t.map((o,r)=>{let i=ia(e,r);return{id:`room-${o.id}`,roomId:o.id,active:!0,x:i.x,y:i.y,target:null,repairedToday:0}});let n=e.repairmen[0];e.repairman.active=!!n,e.repairman.target=n?.target||null,e.repairman.repairedToday=0,n&&(e.repairman.x=n.x,e.repairman.y=n.y)}function ts(e){Se(e);for(let t of e.repairmen||[])t.active=!1,t.target=null;e.repairmen=[],e.repairman.active=!1,e.repairman.target=null}function aa(e,t){return t&&vn(e).find(o=>er(o)===t.key)||null}function ca(e){let t=null;for(let n of vn(e)){let o=Bt(n);o<=.001||(!t||o>Bt(t))&&(t=n)}return t}function ns(e,t){Se(e);let n=e.repairmen?.length?e.repairmen:e.repairman?.active?[e.repairman]:[];if(!n.length||e.phase!=="running")return;let o=new Set(n.map(i=>i.target?.key).filter(Boolean));for(let i of n)ua(e,i,t,o);let r=n[0];r&&e.repairman!==r&&(e.repairman.active=!0,e.repairman.x=r.x,e.repairman.y=r.y,e.repairman.target=r.target,e.repairman.repairedToday=r.repairedToday||0)}function ua(e,t,n,o){if(!t.active)return;let r=aa(e,t.target);if((!r||Bt(r)<=.001)&&(t.target?.key&&o.delete(t.target.key),r=da(e,o)),!r){t.target=null;return}let i=er(r);o.add(i),t.target={key:i,label:r.label};let l=Ue.repairman.walkSpeed,c=r.center.x-t.x,v=r.center.y-t.y,x=Math.hypot(c,v);if(x>8){let X=Math.min(x,l*n);t.x+=c/x*X,t.y+=v/x*X;return}let E=e?.cardEffects?.laborExploitation?.7:1,R=n/(Ue.repairman.secondsPerOnePercent*E*100),B=mn(r),O=R*_n(r);ji(r,O);let ee=Math.max(0,(B-mn(r))/_n(r)*100);t.repairedToday=(t.repairedToday||0)+ee,ee>0&&Math.random()<.02&&H(e,t.x,t.y-28,"REPAIR",p.green),Bt(r)<=.001&&(o.delete(i),t.target=null)}function da(e,t=new Set){let n=null;for(let o of vn(e)){if(t.has(er(o)))continue;let r=Bt(o);r<=.001||(!n||r>Bt(n))&&(n=o)}return n||ca(e)}function fa(e){let t=0,n="none";for(let o of vn(e)){let r=Bt(o);r>t&&(t=r,n=o.label)}return{ratio:t,percent:Math.round(t*100),label:n}}function tr(e){let t=fa(e),n=zo(e);return{worst:t,avgBeltPerformance:n,repairman:e.repairman||null,repairmen:e.repairmen||[],rooms:e.maintenanceRooms||[]}}var pa=$e.commonWeight,ya=$e.rareWeight,ha=$e.ultraRareWeight||.45,Lt=$e.baseDraftSize,Qt=Ir;function Xt(e,t){let n=Le(e);return Math.max(0,Number(n[t])||0)}function Le(e){e.cardEffects||(e.cardEffects={...bo});for(let[t,n]of Object.entries(bo))e.cardEffects[t]==null&&(e.cardEffects[t]=Array.isArray(n)?[]:n);return e.cardEffects.flattery!=null&&(e.cardEffects.fairiesFlatteryNext=Math.max(0,e.cardEffects.fairiesFlatteryNext||0)+Math.max(0,e.cardEffects.flattery||0),delete e.cardEffects.flattery),e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft||(e.cardDraft={pending:!1,choices:[],rerolls:0,picksRemaining:0}),e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardEffects}function us(e){let t=Math.max(.5,1-.05*Math.min(10,Xt(e,"crowdedFarming"))),n=Math.pow(.96,Xt(e,"hatchingFeed"));return t*n}function ds(e,t=null){return Math.min(3,Math.max(0,Number(t?.extraEggOutlet)||0))}function fs(e){return Math.pow(.85,Xt(e,"scannerQueueSpacing"))}function Vn(e,t=null){let n=Le(e),o=Mn*Math.pow(gn,Math.max(0,n.bearing||0)),r=t?Math.max(.1,Number(e?.conveyorMeta?.get?.(t)?.speedMultiplier)||1):1,i=t?1:zo(e),l=Math.max(.01,Number(e?.eventActive?.conveyorSpeedMultiplier)||1);return Math.min(Wt,o*i)*r*l}function nt(e,t=null){let n=Math.max(0,(e?.level||1)-1),o=t?Xt(t,"autoScannerTuning"):0,r=xn*Math.pow(Pr,n)*Math.pow(po,o),i=Math.max(yo,r),l=t?Math.max(.01,Number(t?.eventActive?.autoScannerCooldownMultiplier)||1):1;return t?Math.max(yo,i*Kn(e)*l):i}function os(e){let t=e.cardDraft||{rerolls:0},n=Math.max(1,(t.rerolls||0)+1);return Math.ceil(Math.max(1,e.turn||1)/$e.rerollCost.dayDivisor*n*$e.rerollCost.multiplier)}function Jt(e){return Qt.find(t=>t.id===e)||null}function ps(e,t){let n=typeof t=="string"?Jt(t):t;return Le(e),!n||!(n.type==="equipmentUpgrade"||n.type==="cellAction")?[]:We(e,n).map(o=>({key:tt(o),label:rr(e,o),type:o.type}))}function or(e,t,n={}){let o=typeof t=="string"?Jt(t):t;if(Le(e),!o||o.type==="dud")return{ok:!1,reason:"Card not found."};if(o.id==="extraCards")return e.cardDraft=e.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.choices.push(...Yn(e,2)),{ok:!0,reason:`${o.title} added 2 draft cards.`};if(o.type==="instant")return hs(e,o),{ok:!0,reason:`${o.title} granted.`};if(o.type==="equipmentUpgrade"){let r=We(e,o);if(!r.length)return{ok:!1,reason:`No valid target for ${o.title}.`};let i=n.targetKey&&n.targetKey!=="__auto__"?String(n.targetKey):"",l=i?r.find(c=>tt(c)===i):r[0];return l?(ys(e,l),{ok:!0,reason:`${o.title} applied to ${rr(e,l)}.`}):{ok:!1,reason:`Selected target is no longer valid for ${o.title}.`}}if(o.type==="cellAction"&&o.target==="blockedCell"){let r=We(e,o);if(!r.length)return{ok:!1,reason:"No blocked cells to remove."};let i=new Set((Array.isArray(n.targetKeys)?n.targetKeys:[n.targetKey]).filter(c=>c&&c!=="__auto__").map(String)),l=i.size?r.filter(c=>i.has(tt(c))):r.slice(0,3);if(!l.length)return{ok:!1,reason:`Selected target is no longer valid for ${o.title}.`};for(let c of l.slice(0,3)){e.blockedCells.delete(I(c.col,c.row));let v=F(c.col,c.row);et(e,v.x,v.y),Xe(e,v.x,v.y,p.danger,42),Ze(e,v.x,v.y,8,p.warn)}return be(e),{ok:!0,reason:`${o.title} removed ${Math.min(3,l.length)} blocked cell(s).`}}return{ok:!1,reason:`${o.title} cannot be debug-granted.`}}function rr(e,t){if(t.type==="blockedCell")return`Blocked cell ${t.col},${t.row}`;if(t.type==="eggFarm")return`EGG #${t.id} L${t.level} -> L${t.level+1}`;if(t.type==="eggOutlet"){let n=Math.max(0,Number(t.farm?.extraEggOutlet)||0);return`EGG #${t.id} OUTLET ${1+n} -> ${2+n}`}if(t.type==="scanner")return`AUTO #${t.id} L${t.level} -> L${t.level+1} | CD ${nt(t,e).toFixed(1)}s -> ${nt({...t,level:t.level+1},e).toFixed(1)}s`;if(t.type==="facility"&&(t.baseId||t.id)==="mixer"){let n=t.level,o=ze(e);t.level=n+1;let r=ze(e);return t.level=n,`MIXER L${t.level} -> L${t.level+1} | ${g(o)} -> ${g(r)}`}if(t.type==="facility"&&(t.baseId||t.id)==="truck"){let n=t.level,o=Fe(e);t.level=n+1;let r=Fe(e);return t.level=n,`TRUCK L${t.level} -> L${t.level+1} | ${g(o)} -> ${g(r)}`}if(t.type==="facility"&&t.id==="trash"){let n=$t(e),o=Math.min(Vt(),n+1),r=yt(n),i=yt(o);return`SHREDDER L${t.level||1} -> L${(t.level||1)+1} | poop income ${g(r)} -> ${g(i)} per item`}return`${t.name||t.id} L${t.level||1} -> L${(t.level||1)+1}`}function ma(e){return[...e.blockedCells||[]].map(t=>{let[n,o]=String(t).split(",").map(Number);return{type:"blockedCell",id:t,col:n,row:o}}).filter(t=>Number.isFinite(t.col)&&Number.isFinite(t.row))}function We(e,t){let n=typeof t=="string"?Jt(t):t;return Le(e),n?n.target==="blockedCell"?ma(e):n.target==="eggFarm"?e.eggFarms.filter(o=>(o.level||1)<4):n.target==="eggOutlet"?e.eggFarms.filter(o=>Math.max(0,Number(o.extraEggOutlet)||0)<3).map(o=>({type:"eggOutlet",id:o.id,col:o.col,row:o.row,farm:o})):n.target==="autoScanner"?e.scanners.filter(o=>o.kind==="auto"):n.target==="mixer"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="mixer"):n.target==="truck"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="truck"):n.target==="trash"?Go(e)(o.baseId||o.id)==="trash"):[]:[]:[]}function ba(e,t){let n=Le(e);if(t.id==="crowdedFarming")return(n.crowdedFarming||0)>=10;if(t.id==="recyclingSubsidy")return(n.recyclingSubsidy||0)>=3;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,$e.dudChancePerCard||0)),r=Math.max(1e-4,Math.min(1,$e.dudChanceReductionPerFilter||.05));return(n.dudFilter||0)>=Math.ceil(o/r)}return t.id==="laborExploitation"?!!n.laborExploitation:t.id==="usedMachine"?!!n.usedMachineActive:t.id==="newMachine"?!n.usedMachineActive:!1}function va(e){return!!((e.maintenanceRooms||[]).length||(e.repairmen||[]).length||e.repairman?.active)}function wa(e){return Qt.filter(t=>!(t.id==="laborExploitation"&&!va(e)||ba(e,t)||(t.type==="equipmentUpgrade"||t.type==="cellAction")&&We(e,t).length<=0))}function rs(e,t){return t.rarity==="ultraRare"?ha:t.rarity==="rare"?ya:pa}function Sa(e,t){let n=t.reduce((r,i)=>r+rs(e,i),0);if(n<=0)return t[Math.floor(Math.random()*t.length)];let o=Math.random()*n;for(let r of t)if(o-=rs(e,r),o<=0)return r;return t[t.length-1]}var is=0;function ka(){return is+=1,{id:`dud:${Date.now()}:${is}`,title:"Dud",rarity:"dud",type:"dud",description:"Click to flick this dud away. It does not consume a pick."}}function Ca(e){let t=Le(e),n=Math.max(0,Math.min(1,$e.dudChancePerCard||0)),o=Math.max(0,Math.min(1,$e.dudChanceReductionPerFilter||0));return Math.max(0,n-o*Math.max(0,t.dudFilter||0))}function xa(e,t){let n=[...t],o=0,r=Math.max(0,$e.maxDudsPerDraft||0),i=Ca(e);for(let l=0;lc.id===i.id);l>=0&&r.splice(l,1)}return xa(e,o)}function tt(e){return e?e.type==="blockedCell"?`blockedCell:${e.id}`:e.type==="eggFarm"?`eggFarm:${e.id}`:e.type==="eggOutlet"?`eggOutlet:${e.id}`:e.type==="scanner"?`scanner:${e.id}`:e.type==="facility"?`facility:${e.id}`:`${e.type}:${e.id}`:""}function ss(e){if(!e)return null;if(e.type==="blockedCell"){let t=F(e.col,e.row);return{x:t.x-f.cell*.48,y:t.y-f.cell*.48,w:f.cell*.96,h:f.cell*.96,cx:t.x,cy:t.y}}if(e.type==="eggFarm"||e.type==="eggOutlet"){let t=F(e.col,e.row);return{x:t.x-34,y:t.y-34,w:68,h:68,cx:t.x,cy:t.y}}if(e.type==="scanner"){let t=ye(e);return{x:t.x-54,y:t.y-77,w:108,h:154,cx:t.x,cy:t.y}}return e.type==="facility"?{x:e.x,y:e.y,w:e.w,h:e.h,cx:e.x+e.w/2,cy:e.y+e.h/2}:null}function ir(e){if(!e.cardTargetPick?.pending)return[];if(e.cardTargetPick.mode==="autoScannerMenu"){let n=new Set(e.cardTargetPick.targetKeys||[]);return e.scanners.filter(o=>o.kind==="auto"&&n.has(tt(o))).map(o=>({key:tt(o),label:"AUTO ROUTE SETTINGS",target:o,bounds:ss(o)})).filter(o=>o.bounds)}let t=new Set(e.cardTargetPick.targetKeys||[]);return We(e,e.cardTargetPick.cardId).filter(n=>t.has(tt(n))).map(n=>({key:tt(n),label:rr(e,n),target:n,bounds:ss(n)})).filter(n=>n.bounds)}function Ma(e,t){let n=ir(e);for(let o of n){let r=o.bounds;if(t.x>=r.x&&t.x<=r.x+r.w&&t.y>=r.y&&t.y<=r.y+r.h)return o.target}return null}function ys(e,t){if(t.type==="eggOutlet"){let n=t.farm||e.eggFarms.find(r=>r.id===t.id);if(!n)return;n.extraEggOutlet=Math.min(3,Math.max(0,Number(n.extraEggOutlet)||0)+1);let o=F(n.col,n.row);H(e,o.x,o.y-30,`OUTLET ${1+n.extraEggOutlet}`,p.green),be(e);return}if(t.level=(t.level||1)+1,t.type==="eggFarm"){t.nextSpawn=Rt(t),t.lastInterval=t.nextSpawn;let n=F(t.col,t.row);H(e,n.x,n.y-30,`LV ${t.level}`,p.green);return}if(t.type==="scanner"){let n=ye(t);H(e,n.x,n.y-34,`LV ${t.level}`,p.green);return}t.type==="facility"&&H(e,t.x+t.w/2,t.y+18,`LV ${t.level}`,p.green)}function hs(e,t){let n=Le(e),o=r=>{n[r]=Math.max(0,n[r]||0)+1};if(t.id==="bearing"&&o("bearing"),t.id==="autoScannerTuning"&&o("autoScannerTuning"),t.id==="legalWork"&&o("legalWork"),t.id==="crowdedFarming"&&(n.crowdedFarming=Math.min(10,(n.crowdedFarming||0)+1)),t.id==="hatchingFeed"&&o("hatchingFeed"),t.id==="poopRateBooster"&&o("poopRateBooster"),t.id==="safetyCover"&&o("safetyCover"),t.id==="recyclingSubsidy"&&(n.recyclingSubsidy=Math.min(3,(n.recyclingSubsidy||0)+1)),t.id==="chemicalWeaponSubsidy"&&o("chemicalWeaponSubsidy"),t.id==="preventiveMaintenance"&&o("preventiveMaintenance"),t.id==="dudFilter"&&o("dudFilter"),t.id==="durabilityCoating"&&(o("durabilityCoating"),Se(e)),t.id==="sparePartsBin"){o("sparePartsBin");let r=Zi(e,.02);e.stats.sparePartsRepair=(e.stats.sparePartsRepair||0)+r,e.totals.sparePartsRepair=(e.totals.sparePartsRepair||0)+r,H(e,f.x+f.cols*f.cell/2,f.y-30,"REPAIR +2%",p.green)}t.id==="dudRefund"&&o("dudRefund"),t.id==="freeReroll"&&o("freeReroll"),t.id==="composter"&&o("composter"),t.id==="scannerQueueSpacing"&&o("scannerQueueSpacing"),t.id==="flattery"&&o("fairiesFlatteryNext"),t.id==="usedMachine"&&(n.usedMachineActive=!0),t.id==="newMachine"&&(n.usedMachineActive=!1),t.id==="laborExploitation"&&(n.laborExploitation=1),t.id==="rescueLoan"&&(o("rescueLoanCharges"),H(e,f.x+f.cols*f.cell/2,f.y-30,"RESCUE HELD",p.green))}function He(e){return`${Math.round(Number(e||0)*100)}%`}function ls(e){let t=st[Math.max(0,Math.min(st.length-1,e-1))]||st[0]||[0,0];return`${t[0].toFixed(2)}-${t[1].toFixed(2)}s`}function as(e,t){return Math.ceil(e*Math.pow(Ce.incomeUpgradeRate,Math.max(0,t-1)))}function cs(e,t,n){let r=We(e,t==="mixer"?"upgradeMixer":"upgradeTruck")[0];if(!r)return{before:as(n,1),after:as(n,2)};let i=t==="mixer"?ze(e):Fe(e),l=r.level||1;r.level=l+1;let c=t==="mixer"?ze(e):Fe(e);return r.level=l,{before:i,after:c}}function ga(e,t){let n=Le(e);if(t.id==="upgradeEgg"){let o=We(e,t),r=Math.min(3,Math.max(1,o[0]?.level||1));return`Choose one EGG. Level +1. Production interval ${ls(r)} -> ${ls(r+1)}.`}if(t.id==="upgradeAutoScanner"){let o=We(e,t)[0]||{level:1},r=nt(o,e),i=nt({...o,level:(o.level||1)+1},e);return`Choose one AUTO SCANNER. Level +1. Cooldown ${r.toFixed(2)}s -> ${i.toFixed(2)}s.`}if(t.id==="upgradeMixer"){let o=cs(e,"mixer",Ce.income.mixer);return`Choose one MIXER. Earning +10%. Male-chick income ${g(o.before)} -> ${g(o.after)}.`}if(t.id==="upgradeTruck"){let o=cs(e,"truck",Ce.income.truck);return`Choose one TRUCK. Earning +10%. Correct shipment income ${g(o.before)} -> ${g(o.after)}.`}if(t.id==="upgradeTrash"){let o=$t(e),r=Math.min(Vt(),o+1),i=yt(o),l=yt(r);return`SHREDDER level +1. Poop income ${g(i)} -> ${g(l)} per item.`}if(t.id==="bearing"){let o=Math.min(Wt,Mn*Math.pow(gn,Math.max(0,n.bearing||0))),r=Math.min(Wt,Mn*Math.pow(gn,Math.max(0,(n.bearing||0)+1)));return`Conveyor speed +7.5%. After pick: ${o.toFixed(1)} -> ${r.toFixed(1)} px/s.`}if(t.id==="legalWork"){let o=Math.max(0,n.legalWork||0);return`Fairies tribute profit exemption +${g(250)}. After pick: exemption bonus ${g(250*(o+1))}.`}if(t.id==="crowdedFarming"){let o=Math.min(10,(n.crowdedFarming||0)+1);return`Held ${n.crowdedFarming||0}/10. After pick: EGG interval ${He(Math.max(.5,1-.05*o))}, deterioration ${He(Math.min(1.4,1+.04*o))}.`}if(t.id==="extraEggOutlet"){let o=We(e,t),r=Math.max(0,Number(o[0]?.farm?.extraEggOutlet)||0);return`Choose one EGG. Output ports ${1+r} -> ${2+r}. Max 4 ports per EGG.`}if(t.id==="hatchingFeed")return`Held ${n.hatchingFeed||0}. After pick: EGG interval ${He(Math.pow(.96,(n.hatchingFeed||0)+1))}, poop rate multiplier ${He(Math.pow(1.03,(n.hatchingFeed||0)+1))}.`;if(t.id==="poopRateBooster")return`Held ${n.poopRateBooster||0}. After pick: base poop rate +${Math.round((n.poopRateBooster||0)+1)*4} percentage points.`;if(t.id==="autoScannerTuning")return`Held ${n.autoScannerTuning||0}. After pick: all AUTO SCANNER default cooldown ${He(Math.pow(po,(n.autoScannerTuning||0)+1))}.`;if(t.id==="safetyCover")return`Held ${n.safetyCover||0}. After pick: explosion damage ${He(Math.pow(.95,(n.safetyCover||0)+1))}.`;if(t.id==="recyclingSubsidy")return`Held ${n.recyclingSubsidy||0}/3. After pick: normal SELL refund ${Math.round(Math.min(.8,.5+.1*((n.recyclingSubsidy||0)+1))*100)}%.`;if(t.id==="chemicalWeaponSubsidy")return`Held ${n.chemicalWeaponSubsidy||0}. After pick: ${g(1200*((n.chemicalWeaponSubsidy||0)+1))} per 70 truck-shipped poop each day.`;if(t.id==="preventiveMaintenance")return`Held ${n.preventiveMaintenance||0}. After pick: deterioration speed ${He(Math.pow(.95,(n.preventiveMaintenance||0)+1))}.`;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,$e.dudChancePerCard||0)),r=Math.max(0,Math.min(1,$e.dudChanceReductionPerFilter||.05)),i=Math.max(0,n.dudFilter||0),l=Math.max(0,o-r*i),c=Math.max(0,o-r*(i+1));return`Held ${i}. DUD chance per card ${He(l)} -> ${He(c)}.`}return t.id==="durabilityCoating"?`Held ${n.durabilityCoating||0}. After pick: maximum durability ${He(Math.pow(1.03,(n.durabilityCoating||0)+1))}.`:t.id==="sparePartsBin"?`Held ${n.sparePartsBin||0}. Immediately restores 2% durability to every maintained machine. Common card weight.`:t.id==="dudRefund"?`Held ${n.dudRefund||0}. After pick: DUD clicks award ${g(50*((n.dudRefund||0)+1))}.`:t.id==="freeReroll"?`Held ${n.freeReroll||0}. After pick: each card screen starts with ${(n.freeReroll||0)+1} free reroll${(n.freeReroll||0)+1===1?"":"s"}.`:t.id==="composter"?`Held ${n.composter||0}. After pick: SHREDDER poop grants ${g(3*((n.composter||0)+1))}.`:t.id==="scannerQueueSpacing"?`Held ${n.scannerQueueSpacing||0}. After pick: Manual/Auto Scanner queue spacing ${He(Math.pow(.85,(n.scannerQueueSpacing||0)+1))}.`:t.id==="flattery"?`Next Fairies tribute -50%. Held for next tribute: ${n.fairiesFlatteryNext||0}.`:t.id==="usedMachine"?"Enable Used Machines: future equipment costs 50%, has no SELL refund, and starts with 60% durability.":t.id==="newMachine"?"Cancel Used Machines. Future equipment returns to normal price, refund, and durability.":t.id==="laborExploitation"?"Repairman dispatch paperwork is streamlined. Repair rooms keep operating; one time only.":t.id==="rescueLoan"?`At day-end bankruptcy check, gain ${g(500)} if cash is below ${g(0)}. Held: ${n.rescueLoanCharges||0}.`:t.description}function nr(e,t){let n=e.cardDraft?.choices||[],o=n.findIndex(r=>r.id===t.id);o>=0&&n.splice(o,1)}function ms({game:e,ui:t,onUpdatePanels:n}){function o(){n&&n()}function r(){Le(e),e.cardTargetPick=null,e.cardDraft={pending:!0,choices:Yn(e,Lt),rerolls:0,freeRerolls:Xt(e,"freeReroll"),picksRemaining:1}}function i(){Le(e),e.cardDraft.pending=!1,e.cardDraft.choices=[],e.cardDraft.picksRemaining=0,e.cardTargetPick=null,t.modal.classList.remove("visible","equipment-popover"),o()}function l(A=Lt){Le(e),e.cardDraft.choices=Yn(e,A)}function c(){Le(e),!e.cardDraft.choices.length&&e.cardDraft.picksRemaining>0&&l(Lt)}function v(A){nr(e,A),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1),e.cardTargetPick=null,c(),e.cardDraft.picksRemaining<=0?i():se()}function x(A){nr(e,A),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1)+$e.extraCardsAddedPicks,e.cardDraft.choices.push(...Yn(e,2)),se()}function E(A,G){let q=Xt(e,"dudRefund")*50;if(q>0){let me=Ge(e,q);e.stats.dudRefundIncome=(e.stats.dudRefundIncome||0)+me,e.totals.dudRefundIncome=(e.totals.dudRefundIncome||0)+me,H(e,f.x+f.cols*f.cell/2,f.y-30,`DUD REFUND +${g(me)}`,p.green)}Ft(e,34,.62),document.body?.animate&&document.body.animate([{transform:"translate(0, 0)"},{transform:"translate(-10px, 7px)"},{transform:"translate(12px, -8px)"},{transform:"translate(-8px, -5px)"},{transform:"translate(9px, 6px)"},{transform:"translate(0, 0)"}],{duration:260,easing:"steps(5, end)"}),G&&(G.style.setProperty("--fling-x",`${260+Math.random()*260}px`),G.style.setProperty("--fling-y",`${-260-Math.random()*170}px`),G.style.setProperty("--fling-r",`${(Math.random()<.5?-1:1)*(52+Math.random()*38)}deg`),G.classList.add("flung")),window.setTimeout(()=>{nr(e,A),c(),se()},340)}function R(A,G=null){if(A.type==="dud")return E(A,G);if(A.id==="extraCards")return x(A);if(A.type==="equipmentUpgrade"||A.type==="cellAction")return B(A);hs(e,A),v(A)}function B(A){let G=We(e,A);G.length&&(e.cardTargetPick={pending:!0,cardId:A.id,mode:A.target==="blockedCell"?"blockedCell":"equipment",targetKeys:G.map(tt),remaining:A.id==="dynamite"?Math.min(3,G.length):1},t.modal.classList.remove("visible","equipment-popover"),o())}function O(A){if(!A||A.type!=="blockedCell")return!1;let G=I(A.col,A.row);if(!e.blockedCells?.has(G))return!1;e.blockedCells.delete(G);let q=F(A.col,A.row);return et(e,q.x,q.y),Xe(e,q.x,q.y,p.danger,62),Ze(e,q.x,q.y,18,p.warn),Nn(e,q.x,q.y,8),Ft(e,16,.35),H(e,q.x,q.y-18,"BOOM",p.danger),be(e),e.cardTargetPick.remaining=Math.max(0,(e.cardTargetPick.remaining||1)-1),e.cardTargetPick.targetKeys=We(e,"dynamite").map(tt),o(),!0}function ee(A){if(!e.cardTargetPick?.pending)return!1;let G=Jt(e.cardTargetPick.cardId),q=Ma(e,A);return!G||!q?(X(),!0):G.id==="dynamite"?(O(q)&&((e.cardTargetPick.remaining||0)<=0||!We(e,"dynamite").length)&&v(G),!0):(ys(e,q),v(G),!0)}function X(){e.cardTargetPick?.pending&&(e.cardTargetPick=null,se())}function ae(){let A=Math.max(0,e.cardDraft?.freeRerolls||0);if(A>0){e.cardDraft.freeRerolls=A-1,e.cardDraft.rerolls+=1,l(Lt),se();return}let G=os(e);e.cash${G.alt||`:``}function le(A,G){let q=document.createElement("button");q.type="button";let me=A.type==="dud"?"dud":A.rarity==="ultraRare"?"ultra-rare":A.rarity==="rare"?"rare":"common";q.className=`card-choice ${me}`;let D=A.type==="dud"?"MISS":A.rarity==="ultraRare"?"ULTRA RARE":A.rarity==="rare"?"RARE":"COMMON",U=[D,...(A.tags||[]).filter(S=>S!==D)].slice(0,5);return q.innerHTML=`${ie(A)}
${A.title}
${U.map(S=>`${S}`).join("")}
${ga(e,A)}
`,q.addEventListener("click",()=>R(A,q)),q.dataset.index=String(G),q}function se(){Le(e),e.cardTargetPick=null,e.cardDraft?.pending||r(),e.cardDraft.choices?.length||l(Lt);let A=e.cardDraft.choices||[],G=os(e),q=Math.max(0,e.cardDraft?.freeRerolls||0),me=Math.max(1,e.cardDraft.picksRemaining||1);t.modalTitle.textContent="Choose Upgrade Card",t.modalBody.innerHTML=`

Choose ${me} card${me===1?"":"s"} before Build phase. Dud cards can be flicked away without consuming a pick. Equipment cards target machines; Dynamite targets blocked cells.

`;let D=t.modalBody.querySelector("#cardChoices");A.forEach((M,N)=>D.appendChild(le(M,N))),t.modalActions.innerHTML="";let U=document.createElement("button");U.type="button",U.className="facility-action warn reroll-button",U.textContent=q>0?`Reroll (FREE x${q})`:`Reroll ${g(G)}`,U.disabled=q<=0&&e.cash0?`${q} free reroll${q===1?"":"s"} remaining.`:U.disabled?"Not enough cash":"",U.addEventListener("click",ae),t.modalActions.appendChild(U);let S=document.createElement("button");S.type="button",S.className="facility-action",S.textContent="No Card",S.title="Skip this upgrade pick and enter Build phase.",S.addEventListener("click",i),t.modalActions.appendChild(S),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible")}return{prepareDraft:r,showDraft:se,finishDraft:i,chooseTargetAtPoint:ee,cancelTargetPick:X}}var Ta=!0,Ea={chickMale:"./assets/images/chick_male.png",chickFemale:"./assets/images/chick_female.png",poop:"./assets/images/poop.png",conveyorStraightH:"./assets/dark_factory/facilities/conveyor/conveyor_straight_h_16.png",conveyorStraightV:"./assets/dark_factory/facilities/conveyor/conveyor_straight_v_16.png",conveyorTurnNe:"./assets/dark_factory/facilities/conveyor/conveyor_turn_ne_16.png",conveyorTurnNw:"./assets/dark_factory/facilities/conveyor/conveyor_turn_nw_16.png",conveyorTurnSe:"./assets/dark_factory/facilities/conveyor/conveyor_turn_se_16.png",conveyorTurnSw:"./assets/dark_factory/facilities/conveyor/conveyor_turn_sw_16.png",boostConveyorStraightH:"./assets/dark_factory/facilities/conveyor/boost_conveyor_straight_h_16.png",boostConveyorStraightV:"./assets/dark_factory/facilities/conveyor/boost_conveyor_straight_v_16.png",boostConveyorTurnNe:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_ne_16.png",boostConveyorTurnNw:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_nw_16.png",boostConveyorTurnSe:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_se_16.png",boostConveyorTurnSw:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_sw_16.png",scannerManual:"./assets/dark_factory/facilities/machines/manual_scanner_32x48.png",scannerAuto:"./assets/dark_factory/facilities/machines/auto_scanner_32x48.png",eggFarm:"./assets/dark_factory/facilities/machines/egg_farm_16.png",mixer:"./assets/dark_factory/facilities/machines/mixer_32.png",shredder:"./assets/dark_factory/facilities/machines/shredder_32.png",truck:"./assets/dark_factory/facilities/vehicles/truck_32.png",mixerCompact:"./assets/dark_factory/facilities/machines/mixer_compact_16.png",shredderCompact:"./assets/dark_factory/facilities/machines/shredder_compact_16.png",truckCompact:"./assets/dark_factory/facilities/vehicles/truck_compact_16.png",maintenanceRoom:"./assets/dark_factory/facilities/utility/maintenance_room_32.png",repairman:"./assets/dark_factory/facilities/utility/repairman_16.png",obstacleCrate:"./assets/dark_factory/facilities/utility/obstacle_crate_16.png"},ce={};for(let[e,t]of Object.entries(Ea)){let n=new Image;n.loaded=!1,n.onerror=()=>{n.loaded=!1},Ta&&t&&(n.onload=()=>{n.loaded=!0},n.src=t),ce[e]=n}function Ss(e,t,n,o){e.imageSmoothingEnabled=!1,e.clearRect(0,0,t.width,t.height),Aa(e,t),e.save();let r=n.shake.time>0?W(-n.shake.strength,n.shake.strength):0,i=n.shake.time>0?W(-n.shake.strength,n.shake.strength):0,l=n.view?.scale||1;e.translate((n.view?.x||0)+r,(n.view?.y||0)+i),e.scale(l,l),$a(e,n),Da(e,n),Ba(e,n),qa(e,n),Za(e,n),ec(e,n),Ya(e,n),za(e,n),Pa(e,n),rc(e,n,o.activeQueuedChick),pc(e,n),cc(e,t,n),ac(e,n,o.selectedObject,o.selectedTitle),uc(e,n),dc(e,n),fc(e,n),e.restore(),hc(e,n,t)}function Ra(e){if(e.type==="eggFarm"){let n=F(e.ref.col,e.ref.row);return{x:n.x-34,y:n.y-34,w:68,h:68,cx:n.x,cy:n.y}}let t=e.ref;return{x:t.x,y:t.y,w:t.w,h:t.h,cx:t.x+t.w/2,cy:t.y+t.h/2}}function Pa(e,t){if(t.phase!=="build")return;let n=Fn(t);for(let o of n){let r=Ra(o);e.save(),e.fillStyle="rgba(196,36,36,.22)",e.strokeStyle=p.danger,e.lineWidth=5,e.setLineDash([10,6]),ne(e,r.x,r.y,r.w,r.h,!0,!0),e.setLineDash([]),e.fillStyle=p.danger,e.strokeStyle=p.white,e.lineWidth=4,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.strokeText("!",r.cx,r.y+24),e.fillText("!",r.cx,r.y+24),e.font="900 11px ui-monospace, monospace",e.strokeText("NO ROUTE",r.cx,r.y+r.h-8),e.fillText("NO ROUTE",r.cx,r.y+r.h-8),e.restore()}}function ne(e,t,n,o,r,i=!0,l=!0){e.beginPath(),e.rect(t,n,o,r),i&&e.fill(),l&&e.stroke()}function lr(e,t,n,o,r=p.ink){e.save(),e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.lineWidth=4,e.strokeStyle=p.white,e.fillStyle=r,e.strokeText(o,t,n),e.fillText(o,t,n),e.restore()}function rt(e,t,n,o,r,i){if(!t?.loaded)return!1;let l=e.imageSmoothingEnabled;return e.imageSmoothingEnabled=!1,e.drawImage(t,Math.round(n),Math.round(o),Math.round(r),Math.round(i)),e.imageSmoothingEnabled=l,!0}function bs(e,t,n,o,r,i,l=null,c=1){e.fillStyle=i,e.fillRect(Math.round(t),Math.round(n),Math.round(o),Math.round(r)),l&&(e.strokeStyle=l,e.lineWidth=c,e.strokeRect(Math.round(t)+.5,Math.round(n)+.5,Math.round(o)-1,Math.round(r)-1))}function Aa(e,t){e.fillStyle=p.bg,e.fillRect(0,0,t.width,t.height),e.save(),e.globalAlpha=.85;for(let n=0;n=n;for(let r of Tt(t)){let i=Et(r);e.save(),e.fillStyle=o?"rgba(183,245,198,.34)":"rgba(255,255,255,.22)",e.strokeStyle=o?p.green:p.muted,e.lineWidth=5,e.setLineDash([16,10]),ne(e,i.x,i.y,i.w,i.h,!0,!0),e.setLineDash([]);let l=ko(r),c=l.cx,v=l.cy;e.fillStyle="rgba(255,255,255,.94)",e.strokeStyle=p.ink,e.lineWidth=4,ne(e,l.x,l.y,l.w,l.h,!0,!0),e.fillStyle=o?p.green:p.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText(r.direction==="right"?"BUY RIGHT LOT":"BUY UPPER LOT",c,v-12),e.fillStyle=p.ink,e.font="900 16px ui-monospace, monospace",e.fillText(`${g(n)} / 10\xD710`,c,v+15),e.fillStyle=p.muted,e.font="900 11px ui-monospace, monospace",e.fillText("blocked tiles included",c,v+30),e.restore()}}function bt(e,t,n,o,r,i,l=0){let c=zt(i);c<.5||(e.save(),e.globalAlpha=Math.min(.62,.12+c*.54),e.fillStyle="#6b4a23",l>0?(e.beginPath(),e.roundRect?.(t,n,o,r,l),e.roundRect?e.fill():ne(e,t,n,o,r,!0,!1)):ne(e,t,n,o,r,!0,!1),e.globalAlpha=Math.min(.9,.25+c*.6),e.strokeStyle="#3a2a16",e.lineWidth=Math.max(2,Math.floor(2+c*5)),e.setLineDash([5,6]),ne(e,t+3,n+3,o-6,r-6,!1,!0),e.restore())}function sr(e,t){let n=e.componentLookup?.get(t);return(n?e.congestion.get(n):null)?.ratio||0}function Fa(e,t,n={}){let o=Xn(e,t).sort(),i=n.kind==="boostConveyor"?"boostConveyor":"conveyor",l=c=>o.includes(c);if(o.length===2){if(l("left")&&l("right"))return ce[`${i}StraightH`];if(l("up")&&l("down"))return ce[`${i}StraightV`];if(l("up")&&l("right"))return ce[`${i}TurnNe`];if(l("up")&&l("left"))return ce[`${i}TurnNw`];if(l("down")&&l("right"))return ce[`${i}TurnSe`];if(l("down")&&l("left"))return ce[`${i}TurnSw`]}return o.length===1?l("up")||l("down")?ce[`${i}StraightV`]:ce[`${i}StraightH`]:l("up")||l("down")?ce[`${i}StraightV`]:ce[`${i}StraightH`]}function Ba(e,t){let n=[],o=new Set;for(let i of t.conveyorTiles){let{col:l,row:c}=Z(i);for(let v of de){let x={col:l+v.dc,row:c+v.dr},E=I(x.col,x.row);if(!t.conveyorTiles.has(E))continue;let R=[i,E].sort().join("|");if(o.has(R))continue;o.add(R);let B=Math.max(sr(t,i),sr(t,E));n.push({a:F(l,c),b:F(x.col,x.row),ratio:B})}}e.save(),e.lineCap="round",e.lineJoin="round";for(let i of[{width:31,color:"#0b0c0f",alpha:1},{width:23,color:"#444b56",alpha:1},{width:15,color:"#171a1f",alpha:1}]){e.globalAlpha=i.alpha,e.strokeStyle=i.color,e.lineWidth=i.width;for(let l of n)e.beginPath(),e.moveTo(l.a.x,l.a.y),e.lineTo(l.b.x,l.b.y),e.stroke()}for(let i of n){let l=Math.max(0,(i.ratio-.5)/.5);e.strokeStyle=Kt(p.green,p.danger,l),e.globalAlpha=i.ratio>.5?.35+l*.55:.8,e.lineWidth=6,e.beginPath(),e.moveTo(i.a.x,i.a.y),e.lineTo(i.b.x,i.b.y),e.stroke()}let r=Wa(t);for(let i of t.conveyorTiles){let l=F(...Object.values(Z(i))),c=t.conveyorMeta.get(i)||{},v=sr(t,i),x=Fa(t,i,c),E=v>.5;if(e.fillStyle=E?"rgba(196,36,36,.28)":"rgba(0,0,0,.35)",e.strokeStyle=E?p.danger:"rgba(255,184,39,.34)",e.lineWidth=E?3:1,ne(e,l.x-20,l.y-20,40,40,!0,!0),!rt(e,x,l.x-19,l.y-19,38,38)){let B=c.kind==="boostConveyor"?"#315e92":"#454b55";e.fillStyle=v>.5?Kt(B,"#a12c2c",Math.max(0,(v-.5)/.5)):B,e.strokeStyle=p.ink,e.lineWidth=2,ne(e,l.x-18,l.y-18,36,36,!0,!0)}La(e,l,i,c,v),bt(e,l.x-18,l.y-18,36,36,{meta:c}),ot(e,t,"conveyor",i,l.x,l.y,38,38),Ka(e,l,r.get(i)||[]);let R=Xn(t,i);Ga(e,l,c,Na(t,i,R),R),v>.5&&lr(e,l.x,l.y-15,`${Math.floor(v*100)}%`,p.danger)}e.restore()}function La(e,t,n,o={},r=0){let l=[...new Set([...Array.isArray(o.outDirs)?o.outDirs:[],o.dir].filter(Boolean))][0]||"right",c=l==="up"||l==="down",v=l==="left"||l==="up",x=o.kind==="boostConveyor",E=typeof performance<"u"?performance.now()/(x?70:105):0,R=((v?-E:E)%10+10)%10;e.save(),e.beginPath(),e.rect(t.x-18,t.y-18,36,36),e.clip();let B=x?"rgba(20,126,124,.62)":"rgba(42,47,54,.72)";if(e.fillStyle=B,e.fillRect(t.x-18,t.y-18,36,36),e.strokeStyle=r>.5?"rgba(238,83,61,.90)":"rgba(184,190,198,.92)",e.lineWidth=4,c)for(let O=t.y-28+R;Oe.conveyorTiles.has(I(n.col+o.dc,n.row+o.dr))).map(o=>o.name)}function ks(e,t,n){let o=de.find(l=>l.name===n);if(!o)return!1;let r=e.conveyorMeta?.get?.(I(t.col+o.dc,t.row+o.dr));return r?[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))].includes(o.opposite):!1}function Oa(e,t,n,o=Xn(e,t),r="random"){if(o.length<3)return n;let i=Z(t),l=new Set(o.filter(x=>ks(e,i,x)));if(r&&r!=="random"&&o.includes(r)){let x=new Set(l);x.add(r),o.filter(E=>!x.has(E)).length>=2&&l.add(r)}let c=o.filter(x=>!l.has(x));if(c.length)return c;let v=n.filter(x=>!l.has(x));return v.length?v:n}function Na(e,t,n=Xn(e,t)){if(n.length<3)return[];let o=Z(t),r=new Set(n.filter(i=>ks(e,o,i)));return n.filter(i=>{let l=new Set(r);return l.add(i),n.filter(c=>!l.has(c)).length>=2})}function _a(e,t,n){let o=Z(t),r=de.filter(c=>e.conveyorTiles.has(I(o.col+c.dc,o.row+c.dr))).map(c=>c.name),i=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(c=>r.includes(c)),l=r;return i.length?i:l}function Ga(e,t,n,o,r=o){if(r.length<3||o.length<2)return;e.save();let i=o.includes(n.branchMode)?n.branchMode:"random",l=i!=="random";if(e.lineJoin="round",e.lineCap="round",e.lineWidth=2,e.fillStyle="rgba(255,255,255,.9)",e.strokeStyle=l?p.warn:p.green,ne(e,t.x-17,t.y-17,34,34,!0,!0),e.strokeStyle=p.ink,e.lineWidth=2,e.fillStyle=p.ink,i!=="random"){let c=de.find(v=>v.name===i);zn(e,t.x,t.y,c?.angle||0,9,6)}else e.beginPath(),e.moveTo(t.x-10,t.y),e.lineTo(t.x-2,t.y),e.lineTo(t.x+8,t.y-8),e.moveTo(t.x-2,t.y),e.lineTo(t.x+8,t.y+8),e.stroke(),zn(e,t.x+9,t.y-9,-Math.PI/4,4,3),zn(e,t.x+9,t.y+9,Math.PI/4,4,3);e.restore()}function Ua(e,t,n){if(!n)return[];let o=Z(t),r=de.filter(c=>e.conveyorTiles.has(I(o.col+c.dc,o.row+c.dr))).map(c=>c.name),i=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(c=>r.includes(c));return Oa(e,t,i.length?i:_a(e,t,n),r,n.branchMode||"random").map(c=>de.find(v=>v.name===c)).filter(Boolean)}function Wa(e){let t=new Map;for(let[n,o]of e.conveyorMeta||[]){let r=Ua(e,n,o);r.length&&t.set(n,r)}return t}function Ka(e,t,n){let o=n.slice(0,4);o.length&&(e.save(),e.fillStyle=p.ink,e.globalAlpha=.86,o.forEach(r=>{zn(e,t.x+r.dc*12,t.y+r.dr*12,r.angle,6,5)}),e.restore())}function zn(e,t,n,o,r=11,i=8){e.save(),e.translate(t,n),e.rotate(o),e.beginPath(),e.moveTo(r,0),e.lineTo(-r*.72,-i),e.lineTo(-r*.72,i),e.closePath(),e.fill(),e.restore()}function Ha(e,t,n,o,r){let i=ye(t),l=null;if(n==="inputA"&&(l={x:i.x,y:i.y-67}),n==="left"&&(l={x:i.x-49,y:i.y+14}),n==="right"&&(l={x:i.x+49,y:i.y+14}),!l)return;let c=n==="inputA"?{x:o.x,y:l.y}:{x:l.x,y:o.y};e.save(),e.lineCap="square",e.lineJoin="bevel",e.strokeStyle="#050609",e.lineWidth=15,e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(c.x,c.y),e.lineTo(l.x,l.y),e.stroke(),e.strokeStyle="#596473",e.lineWidth=9,e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(c.x,c.y),e.lineTo(l.x,l.y),e.stroke(),e.strokeStyle=r||"#7b8795",e.lineWidth=3,e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(c.x,c.y),e.lineTo(l.x,l.y),e.stroke(),e.fillStyle=r||"#7b8795",e.strokeStyle="#050609",e.lineWidth=3,ne(e,l.x-9,l.y-7,18,14,!0,!0),e.restore()}function qa(e,t){e.save(),e.lineWidth=2,e.font="900 12px ui-monospace, monospace",e.textAlign="center";for(let n of t.scanners){let o=Po(n),r=[{type:"inputA",p:Re(n,"inputA"),label:"IN",color:p.green},{type:"left",p:Re(n,"left"),label:Io(o.left),color:$o(o.left)},{type:"right",p:Re(n,"right"),label:Io(o.right),color:$o(o.right)}];for(let i of r){if(!i.p)continue;let l=F(i.p.col,i.p.row);Ha(e,n,i.type,l,i.color);let c=ii(t,n,i.type||(i.label==="IN"?"inputA":null))||t.conveyorTiles.has(I(i.p.col,i.p.row));e.fillStyle=c?Kt("#1a1d23",i.color,.24):"#3a1e22",e.strokeStyle=c?i.color:p.danger,ne(e,l.x-18,l.y-12,36,24,!0,!0),e.fillStyle=p.white,e.fillText(i.label,l.x,l.y+4)}}e.restore()}function Ya(e,t){for(let n of t.eggFarms)Va(e,n,t)}function Va(e,t,n){let o=F(t.col,t.row);if(e.save(),rt(e,ce.eggFarm,o.x-29,o.y-29,58,58)){bt(e,o.x-29,o.y-29,58,58,t);let l=1+Math.max(0,Number(t.extraEggOutlet)||0);e.fillStyle="rgba(255,255,255,.92)",e.strokeStyle=p.ink,e.lineWidth=2,ne(e,o.x+9,o.y+12,30,18,!0,!0),e.fillStyle=p.ink,e.font="900 10px ui-monospace, monospace",e.textAlign="center",e.fillText(`O${l}`,o.x+24,o.y+24),ot(e,n,"eggFarm",t.id,o.x,o.y,68,68),e.restore();return}e.fillStyle=p.white,e.strokeStyle=p.ink,e.lineWidth=4,ne(e,o.x-28,o.y-28,56,56,!0,!0),e.fillStyle=p.green,e.font="900 19px ui-monospace, monospace",e.textAlign="center",e.fillText("EGG",o.x,o.y-4);let r=1+Math.max(0,Number(t.extraEggOutlet)||0);e.font="900 11px ui-monospace, monospace",e.fillStyle=p.ink,e.fillText(`L${t.level} O${r}`,o.x,o.y+13),e.fillText(`${t.nextSpawn.toFixed(1)}s`,o.x,o.y+26);let i=Math.max(0,Math.min(1,t.shutterProgress||0));if(i>0){let l=56*i;e.fillStyle=p.ink,ne(e,o.x-28,o.y-28,56,l,!0,!1),e.strokeStyle=p.white,e.lineWidth=2;for(let c=o.y-24;c=1&&(e.fillStyle=p.white,e.font="900 12px ui-monospace, monospace",e.fillText("SHUT",o.x,o.y+4))}bt(e,o.x-28,o.y-28,56,56,t),ot(e,n,"eggFarm",t.id,o.x,o.y,68,68),e.restore()}function za(e,t){for(let n of t.scanners)Xa(e,n,t)}function Xa(e,t,n){let o=ye(t);if(e.save(),t.kind==="manual"&&(n.manualCombo?.count||0)>=10){let v=n.manualCombo.count;e.save(),e.globalAlpha=Math.min(.55,.16+v/120),e.strokeStyle=v>=30?p.warn:p.green,e.lineWidth=Math.min(14,5+Math.floor(v/10)),e.shadowColor=e.strokeStyle,e.shadowBlur=Math.min(28,8+v),ne(e,o.x-54,o.y-76,108,152,!1,!0),e.restore()}let r=t.kind==="auto"?ce.scannerAuto:ce.scannerManual;if(rt(e,r,o.x-50,o.y-73,100,146)){t.kind==="auto"?bt(e,o.x-50,o.y-73,100,146,t):vs(e,t,o),ot(e,n,"scanner",t.id,o.x,o.y,108,154),e.restore();return}e.fillStyle=t.kind==="auto"?"#d8ffe2":p.white,e.strokeStyle=p.ink,e.lineWidth=4,ne(e,o.x-50,o.y-73,100,146,!0,!0),e.fillStyle=t.kind==="auto"?p.green:p.ink,e.font="900 19px ui-monospace, monospace",e.textAlign="center",e.fillText(`${t.kind==="auto"?"AUTO":`S${(t.slot??0)+1}`}`,o.x,o.y-48),e.font="900 11px ui-monospace, monospace";let i=t.keys?.left?.label||(t.slot===0?"A":"Left"),l=t.keys?.right?.label||(t.slot===0?"D":"Right");e.fillText(t.role===0?`${i}:M ${l}:NEXT`:`${i}:WASTE ${l}:TRUCK`,o.x,o.y-28);let c=t.queue.length;t.kind==="manual"?(vs(e,t,o),e.fillStyle=c>0?p.green:p.muted,e.font="900 10px ui-monospace, monospace",e.fillText(`Q:${c}`,o.x,o.y+54)):(e.fillStyle=c>0?p.green:p.muted,e.font="900 12px ui-monospace, monospace",e.fillText(`Q:${c} CD:${t.cooldown.toFixed(1)}`,o.x,o.y+54),bt(e,o.x-50,o.y-73,100,146,t)),ot(e,n,"scanner",t.id,o.x,o.y,108,154),e.restore()}function vs(e,t,n){if(t.kind!=="manual")return;let r=(t.slot??0)===0?[{side:"left",text:"A"},{side:"right",text:"D"}]:[{side:"left",text:"\u2190"},{side:"right",text:"\u2192"}];r[0].text=t.keys?.left?.label||r[0].text,r[1].text=t.keys?.right?.label||r[1].text;let i=t.keyPressTime>0?t.keyPressSide:null,l=n.x-30,c=n.y+18;e.save(),e.lineWidth=3,e.fillStyle="#f7fff5",e.strokeStyle=p.ink,ne(e,l-4,c-4,68,25,!0,!0),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let v=0;v.8,i=t.y+Math.sin(t.bob)*(r?5:1.5);if(e.save(),n&&(e.strokeStyle=p.green,e.lineWidth=5,e.beginPath(),e.arc(t.x,i,t.radius+8,0,Math.PI*2),e.stroke()),r&&(e.strokeStyle=p.danger,e.lineWidth=3,e.beginPath(),e.arc(t.x,i,t.radius+12+Math.sin(t.bob*2)*4,0,Math.PI*2),e.stroke()),t.sex==="poop")pr(e,t.x,i,t.radius);else{let l=t.sex==="male"?ce.chickMale:ce.chickFemale;if(!rt(e,l,t.x-t.radius,i-t.radius,t.radius*2,t.radius*2)){let x=t.sex==="male"?p.male:p.female,E=t.sex==="male"?"#164f8f":"#8b2252";e.fillStyle=x,e.strokeStyle=p.ink,e.lineWidth=5,e.beginPath(),e.arc(t.x,i,t.radius,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle="rgba(255,255,255,.24)",e.beginPath(),e.arc(t.x-5,i-7,t.radius*.36,0,Math.PI*2),e.fill(),e.fillStyle=p.ink,e.beginPath(),e.arc(t.x-6,i-5,2.5,0,Math.PI*2),e.arc(t.x+6,i-5,2.5,0,Math.PI*2),e.fill(),e.fillStyle="#ffaa2e",e.beginPath(),e.moveTo(t.x,i+2),e.lineTo(t.x+9,i+6),e.lineTo(t.x,i+10),e.closePath(),e.fill(),e.strokeStyle=E,e.lineWidth=3,t.sex==="male"?(e.beginPath(),e.moveTo(t.x-8,i-t.radius-2),e.lineTo(t.x+8,i-t.radius-2),e.stroke()):(e.beginPath(),e.moveTo(t.x-9,i-t.radius+2),e.lineTo(t.x,i-t.radius-6),e.lineTo(t.x+9,i-t.radius+2),e.stroke())}e.fillStyle=t.sex==="male"?"#dff1ff":"#fff0f7",e.strokeStyle="#050609",e.lineWidth=3,e.font=`900 ${Math.max(10,Math.round(t.radius*.72))}px ui-monospace, monospace`,e.textAlign="center";let v=t.sex==="male"?"\u2642":"\u2640";e.strokeText(v,t.x+t.radius*.54,i+t.radius*.7),e.fillText(v,t.x+t.radius*.54,i+t.radius*.7)}e.restore()}function sc(e,t){let n=null,o=1/0;for(let[r,i]of e.componentLookup.entries()){let l=Z(r),c=F(l.col,l.row),v=Math.hypot(t.x-c.x,t.y-c.y);vws(o.type,o.id)===ws(t,n))}function ot(e,t,n,o,r,i,l,c){lc(t,n,o)&&(e.save(),e.fillStyle="rgba(34,185,79,.18)",e.strokeStyle=p.green,e.lineWidth=(t.multiSelected||[]).length>1?6:4,e.setLineDash((t.multiSelected||[]).length>1?[]:[8,5]),ne(e,r-l/2,i-c/2,l,c,!0,!0),e.restore())}function ac(e,t,n,o){if(t.phase==="build"&&(t.multiSelected||[]).length>1){e.save(),e.fillStyle="rgba(255,255,255,.96)",e.strokeStyle=p.ink,e.lineWidth=3,ne(e,54-t.view.x,66-t.view.y,214,42,!0,!0),e.fillStyle=p.ink,e.font="900 11px ui-monospace, monospace",e.fillText(`${t.multiSelected.length} ITEMS SELECTED`,65-t.view.x,83-t.view.y),e.fillStyle=p.muted,e.font="900 11px ui-monospace, monospace",e.fillText("drag any selected item to move group",65-t.view.x,99-t.view.y),e.restore();return}}function cc(e,t,n){if(!n.cardTargetPick?.pending)return;let o=ir(n);e.save(),e.fillStyle="rgba(0,0,0,.66)",e.beginPath();let r=n.view?.scale||1;e.rect(-(n.view?.x||0)/r,-(n.view?.y||0)/r,t.width/r,t.height/r);for(let v of o){let x=v.bounds,E=8;e.rect(x.x-E,x.y-E,x.w+E*2,x.h+E*2)}e.fill("evenodd");let i=n.cardTargetPick?.mode==="blockedCell";if(!o.length){e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=p.ink,e.lineWidth=3,ne(e,(260-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,420/r,42/r,!0,!0),e.fillStyle=p.danger,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(i?"NO BLOCKED CELL. PRESS ESC.":"NO VALID UPGRADE TARGET. PRESS ESC.",(470-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore();return}e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=p.ink,e.lineWidth=3;let l=Math.max(1,n.cardTargetPick?.remaining||1),c=n.cardTargetPick?.mode==="autoScannerMenu"?"AUTO SCANNER ROUTE SETTINGS. CLICK EMPTY AREA TO CLOSE.":i?`CLICK BLOCKED CELL: ${l} LEFT. PRESS ESC TO CANCEL.`:"CLICK AN UPGRADEABLE MACHINE. PRESS ESC TO CANCEL.";ne(e,(216-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,560/r,42/r,!0,!0),e.fillStyle=p.ink,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(c,(496-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore()}function uc(e,t){if(t.phase!=="build"||!t.selectionBox)return;let n=t.selectionBox,o=Math.min(n.x1,n.x2),r=Math.min(n.y1,n.y2),i=Math.abs(n.x2-n.x1),l=Math.abs(n.y2-n.y1);e.save(),e.fillStyle="rgba(34,185,79,.12)",e.strokeStyle=p.green,e.lineWidth=2,e.setLineDash([7,4]),ne(e,o,r,i,l,!0,!0),e.restore()}function dc(e,t){let n=[...t.effects].sort((o,r)=>(o.priority??xe.ambient)-(r.priority??xe.ambient));for(let o of n){let r=Math.max(0,o.life/o.maxLife);e.save(),e.globalAlpha=r,o.type==="meat"?(e.fillStyle=p.green,ne(e,o.x-o.size/2,o.y-o.size/2,o.size*1.5,o.size,!0,!1)):o.type==="sludge"?(e.fillStyle=p.poop,ne(e,o.x-o.size/2,o.y-o.size/2,o.size*1.4,o.size,!0,!1)):o.type==="spawn"?(e.strokeStyle=p.green,e.lineWidth=3,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*20,0,Math.PI*2),e.stroke()):o.type==="spark"?(e.fillStyle=o.color||p.danger,ne(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!0,!1)):o.type==="smoke"?(e.fillStyle="rgba(16,32,21,.24)",e.beginPath(),e.arc(o.x,o.y,o.size*(1.2-r*.2),0,Math.PI*2),e.fill()):o.type==="shockwave"?(e.strokeStyle=o.color||p.danger,e.lineWidth=4,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*(o.maxSize||44),0,Math.PI*2),e.stroke()):o.type==="scannerPulse"?(e.strokeStyle=o.color||p.green,e.lineWidth=5,e.setLineDash([8,6]),e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*38,0,Math.PI*2),e.stroke()):o.type==="shred"?(e.fillStyle=o.color||p.ink,e.save(),e.translate(o.x,o.y),e.rotate(o.rot||0),ne(e,-o.w/2,-o.h/2,o.w,o.h,!0,!1),e.restore()):o.type==="load"?(e.strokeStyle=o.color||p.green,e.lineWidth=3,e.beginPath(),e.moveTo(o.x-14,o.y),e.lineTo(o.x+14,o.y),e.moveTo(o.x,o.y-14),e.lineTo(o.x,o.y+14),e.stroke()):o.type==="erase"?(e.strokeStyle=p.ink,e.lineWidth=3,e.setLineDash([4,4]),ne(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!1,!0)):o.type==="rage"?(e.fillStyle=o.color||p.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText("!",o.x,o.y)):o.type==="flyingChick"&&(o.sex==="poop"?pr(e,o.x,o.y,o.radius||11):yr(e,o.x,o.y,o.sex,o.sex==="male")),e.restore()}}function fc(e,t){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let n of t.floatingTexts){let o=Math.max(0,n.life/n.maxLife);e.globalAlpha=o,e.lineWidth=5,e.strokeStyle=p.white,e.fillStyle=n.color,e.strokeText(n.text,n.x,n.y),e.fillText(n.text,n.x,n.y)}e.restore()}function pc(e,t){let n=t.repairmen&&t.repairmen.length?t.repairmen:t.repairman?[t.repairman]:[];for(let o of n)yc(e,t,o)}function yc(e,t,n){if(!!!n?.active)return;if(e.save(),rt(e,ce.repairman,n.x-18,n.y-18,36,36)){n.target?.label&&lr(e,n.x,n.y-24,n.target.label,p.green),e.restore();return}e.lineWidth=3,e.fillStyle="#fff0d1",e.strokeStyle=p.ink,e.beginPath(),e.arc(n.x,n.y,17,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle="#ffd6e7",e.beginPath(),e.arc(n.x-6,n.y-2,3.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+6,n.y-2,3.2,0,Math.PI*2),e.fill();let r=!!t.cardEffects?.laborExploitation;e.fillStyle=r?p.danger:p.ink,e.beginPath(),e.arc(n.x-5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.strokeStyle=p.ink,e.lineWidth=r?3:2,e.beginPath(),e.arc(n.x,n.y+(r?0:1),r?8:7,.1*Math.PI,.9*Math.PI),e.stroke(),e.fillStyle=p.green,ne(e,n.x-9,n.y+14,18,8,!0,!0),e.strokeStyle=p.ink,e.lineWidth=3,e.beginPath(),e.moveTo(n.x-11,n.y+18),e.lineTo(n.x-20,n.y+24),e.stroke(),e.beginPath(),e.moveTo(n.x+11,n.y+18),e.lineTo(n.x+20,n.y+24),e.stroke(),e.fillStyle=p.ink,e.font="900 11px ui-monospace, monospace",e.textAlign="center",e.fillText("FIX",n.x,n.y+33),n.target?.label&&lr(e,n.x,n.y-24,n.target.label,p.green),e.restore()}function hc(e,t,n){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="left",e.fillStyle=p.ink,e.font="900 19px ui-monospace, monospace",e.fillStyle=p.ink;let o=[];t.phase==="running"&&o.push(t.timeLeft<=0?"TIME UP: FARMS SHUT. CLEAR LINE.":"A/D: S1 \u2190/\u2192: S2"),t.phase==="build"&&o.push(`BUILD: ${t.buildTool||"SELECT"} | connect 1 EGG route to any exit`);let r=76;for(let i of o)e.strokeStyle=p.white,e.lineWidth=4,e.strokeText(i,24,r),e.fillText(i,24,r),r+=20;e.restore()}var gs=[[{key:"a",code:"KeyA",label:"A"},{key:"d",code:"KeyD",label:"D"}],[{key:"arrowleft",code:"ArrowLeft",label:"Left"},{key:"arrowright",code:"ArrowRight",label:"Right"}],[{key:"j",code:"KeyJ",label:"J"},{key:"l",code:"KeyL",label:"L"}],[{key:"f",code:"KeyF",label:"F"},{key:"h",code:"KeyH",label:"H"}],[{key:"q",code:"KeyQ",label:"Q"},{key:"e",code:"KeyE",label:"E"}],[{key:"z",code:"KeyZ",label:"Z"},{key:"x",code:"KeyX",label:"X"}],[{key:"u",code:"KeyU",label:"U"},{key:"o",code:"KeyO",label:"O"}],[{key:"n",code:"KeyN",label:"N"},{key:"m",code:"KeyM",label:"M"}]];function mc(e){let t=gs[e]||gs[0];return{left:{...t[0]},right:{...t[1]}}}function Ts(e,t,n){let o={type:"eggFarm",id:e.nextId++,col:t,row:n,level:1,nextSpawn:2,lastInterval:2,extraEggOutlet:0,price:lt.eggFarm,builtSession:e.buildSession};return o.nextSpawn=Rt(o),o.lastInterval=o.nextSpawn,o}function Es(e,t,n,o){let r=o==="auto"?ve.autoScanner.price:ve.manualScanner.price,i=new Set(e.scanners.filter(c=>c.kind==="manual").map(c=>c.slot)),l=0;for(;i.has(l);)l+=1;return{type:"scanner",id:e.nextId++,kind:o,slot:o==="manual"?l:null,role:o==="manual"?l%2:0,col:t,row:n,level:1,queue:[],cooldown:0,price:r,builtSession:e.buildSession,autoMode:"standard",keys:o==="manual"?mc(l):null}}function Jn(e){let t=(e.x-f.x)/f.cell,n=(e.y-f.y)/f.cell,o=Math.max(0,Math.min(f.cols-1,Math.round(t-.5))),r=Math.max(0,Math.min(f.rows-1,Math.round(n-.5))),i=Math.abs(e.x-f.x),l=Math.abs(e.x-(f.x+f.cols*f.cell)),c=Math.abs(e.y-f.y),v=Math.abs(e.y-(f.y+f.rows*f.cell)),x=[["left",i],["right",l],["top",c],["bottom",v]].sort((E,R)=>E[1]-R[1])[0][0];return x==="left"?{side:x,entry:{col:0,row:r}}:x==="right"?{side:x,entry:{col:f.cols-1,row:r}}:x==="top"?{side:x,entry:{col:o,row:0}}:{side:x,entry:{col:o,row:f.rows-1}}}function jn(e,t,n){let o={x:f.x+t.col*f.cell+f.cell/2,y:f.y+t.row*f.cell+f.cell/2},r={left:f.x,right:f.x+f.cols*f.cell,top:f.y,bottom:f.y+f.rows*f.cell};return e.entry={...t},e.side=n,n==="left"?(e.x=r.left-e.w-18,e.y=o.y-e.h/2):n==="right"?(e.x=r.right+18,e.y=o.y-e.h/2):n==="top"?(e.x=o.x-e.w/2,e.y=r.top-e.h-18):(e.x=o.x-e.w/2,e.y=r.bottom+18),e}function Rs(e,t,n,o){let{entry:r,side:i}=Jn(n),l=ve[t],c=l?{name:l.name,w:l.body?.w||168,h:l.body?.h||110,price:l.price}:{name:t[0].toUpperCase()+t.slice(1),w:168,h:110,price:o},v={type:"facility",id:t,name:c.name,x:0,y:0,w:c.w,h:c.h,level:1,price:o||c.price,builtSession:e.buildSession};return jn(v,r,i)}function jt(e){return e?[{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}]:[]}function Ps(e,t,n){return{type:"maintenanceRoom",id:e.nextId++,col:t,row:n,price:lt.maintenanceRoom,builtSession:e.buildSession,wCells:2,hCells:2}}function bc(e){return Math.random()({x:i.x,y:i.y})),r=o[0];return{id:e.nextId++,sex:n,x:r.x,y:r.y,route:o,targetIndex:o.length>1?1:o.length,stage:t.stage||"belt",scannerId:t.scannerId??null,nextScannerId:null,pendingScannerId:null,radius:n==="poop"?15:17,bob:Math.random()*Math.PI*2,queueIndex:-1,queueRoute:null}}function Is({game:e,canvasPoint:t,updatePanels:n,equipmentAtPoint:o,fail:r,pointInGrid:i,rectOfFacility:l,rectsOverlap:c}){function v(S){return S?S.type==="conveyor"?`conveyor:${S.id||S.oldKey}`:S.type==="facility"?`facility:${S.id||S.ref?.id}`:S.type==="maintenanceRoom"?`maintenanceRoom:${S.id||S.ref?.id}`:`${S.type}:${S.id||S.ref?.id}`:""}function x(S){return S?S.type==="conveyor"?{type:"conveyor",id:S.oldKey}:{type:S.type,id:S.ref.id}:null}function E(S){let M=v(x(S));return(e.multiSelected||[]).some(N=>v(N)===M)}function R(S){return S?S.type==="eggFarm"?e.eggFarms.find(M=>M.id===S.id)||null:S.type==="scanner"?e.scanners.find(M=>M.id===S.id)||null:S.type==="facility"?e.facilities[S.id]||null:S.type==="maintenanceRoom"?(e.maintenanceRooms||[]).find(M=>M.id===S.id)||null:S.type==="conveyor"&&e.conveyorTiles.has(S.id)?{type:"conveyor",id:S.id}:null:null}function B(){let S=[];for(let M of e.conveyorTiles){let N=Z(M),J=F(N.col,N.row);S.push({type:"conveyor",id:M,center:J,cell:N})}for(let M of e.eggFarms)S.push({type:"eggFarm",id:M.id,ref:M,center:F(M.col,M.row),cell:{col:M.col,row:M.row}});for(let M of e.scanners)S.push({type:"scanner",id:M.id,ref:M,center:ye(M),cell:{col:M.col,row:M.row}});for(let M of e.maintenanceRooms||[]){let N=F(M.col,M.row);S.push({type:"maintenanceRoom",id:M.id,ref:M,center:{x:N.x+f.cell/2,y:N.y+f.cell/2},cell:{col:M.col,row:M.row}})}for(let M of Object.values(e.facilities)){let N={x:M.x+M.w/2,y:M.y+M.h/2},J=M.entry?F(M.entry.col,M.entry.row):N;S.push({type:"facility",id:M.id,ref:M,center:N,portCenter:J})}return S}function O(S,M){let N=Math.min(M.x1,M.x2),J=Math.max(M.x1,M.x2),Q=Math.min(M.y1,M.y2),pe=Math.max(M.y1,M.y2);return S.x>=N&&S.x<=J&&S.y>=Q&&S.y<=pe}function ee(S){let M=[];for(let N of B())(O(N.center,S)||N.portCenter&&O(N.portCenter,S))&&M.push({type:N.type,id:N.id});return e.multiSelected=M,e.selected=M[0]||null,n(),M.length}function X(){e.multiSelected=[],e.selected=null,n()}function ae(S){let M=t(S);return e.selectionBox={x1:M.x,y1:M.y,x2:M.x,y2:M.y},e.multiSelected=[],e.selected=null,n(),!0}function he(S){if(!e.selectionBox)return;let M=t(S);e.selectionBox.x2=M.x,e.selectionBox.y2=M.y}function ie(){if(!e.selectionBox)return 0;let S=e.selectionBox,M=Math.abs(S.x2-S.x1),N=Math.abs(S.y2-S.y1);return e.selectionBox=null,M<6&&N<6?(X(),0):ee(S)}function le(S){let M=x(S);return M?(e.multiSelected||[]).length&&E(S)?[...e.multiSelected]:[M]:[]}function se(S){let M=R(S);if(!M)return null;if(S.type==="conveyor"){let N=Z(S.id);return{...S,obj:M,oldKey:S.id,currentKey:S.id,meta:e.conveyorMeta.get(S.id)||{price:Oe("conveyor"),builtSession:null},col:N.col,row:N.row}}return S.type==="eggFarm"||S.type==="scanner"||S.type==="maintenanceRoom"?{...S,obj:M,col:M.col,row:M.row}:S.type==="facility"?{...S,obj:M,x:M.x,y:M.y,w:M.w,h:M.h,entry:M.entry?{...M.entry}:null,side:M.side,center:{x:M.x+M.w/2,y:M.y+M.h/2}}:null}function A(S){let M=t(S),N=o(M);if(!N)return!1;let J=le(N),Q=J.map(se).filter(Boolean);return Q.length?(e.groupDrag={start:M,selections:J,origins:Q,historySnapshot:hn(e),committed:!1,lastDCol:0,lastDRow:0},e.multiSelected=J,e.selected=J[0]||null,n(),!0):!1}function G(){!e.groupDrag||e.groupDrag.committed||(e.undoStack.push(e.groupDrag.historySnapshot),e.redoStack=[],e.groupDrag.committed=!0)}function q(S,M,N){let J=I(S,M),Q=dt(e,S,M);if(Q&&!N.has(`eggFarm:${Q.id}`))return!0;let pe=ft(e,S,M);if(pe&&!N.has(`scanner:${pe.id}`))return!0;let ge=(e.maintenanceRooms||[]).find(Pe=>jt(Pe).some(Ae=>Ae.col===S&&Ae.row===M));return!!(ge&&!N.has(`maintenanceRoom:${ge.id}`)||e.conveyorTiles.has(J)&&!N.has(`conveyor:${J}`))}function me(S,M,N){let J=[];for(let Q of e.groupDrag.origins){if(Q.type!=="facility")continue;let pe={x:Q.center.x+S,y:Q.center.y+M},{entry:ge,side:Pe}=Jn(pe);if(!i(ge.col,ge.row)||e.blockedCells?.has?.(I(ge.col,ge.row)))return!0;let Ae={...Q.obj,entry:{...ge},side:Pe};jn(Ae,ge,Pe),J.push({id:Q.id,rect:l(Ae)})}for(let Q of J)for(let pe of Object.values(e.facilities))if(!N.has(`facility:${pe.id}`)&&c(Q.rect,l(pe),12))return!0;for(let Q=0;Q_.type==="conveyor");for(let _ of Ae){let Ie=_.currentKey||_.oldKey;e.conveyorTiles.delete(Ie),e.conveyorMeta.delete(Ie)}for(let _ of Ae){let Ie=I(_.col+Q,_.row+pe);e.conveyorTiles.add(Ie),e.conveyorMeta.set(Ie,_.meta||{price:Oe("conveyor"),builtSession:null,uses:0}),_.currentKey=Ie}for(let _ of e.groupDrag.origins)if(_.type==="eggFarm")_.obj.col=_.col+Q,_.obj.row=_.row+pe;else if(_.type==="scanner")_.obj.col=_.col+Q,_.obj.row=_.row+pe;else if(_.type==="maintenanceRoom")_.obj.col=_.col+Q,_.obj.row=_.row+pe;else if(_.type==="facility"){let Ie={x:_.center.x+N,y:_.center.y+J},{entry:qe,side:Ye}=Jn(Ie);jn(_.obj,qe,Ye)}e.groupDrag.selections=e.groupDrag.origins.map(_=>_.type==="conveyor"?{type:"conveyor",id:_.currentKey||_.oldKey}:{type:_.type,id:_.id}),e.multiSelected=[...e.groupDrag.selections],e.selected=e.multiSelected[0]||null,be(e),n()}function U(){e.groupDrag&&(be(e),e.groupDrag=null,n())}return{selectionFromHit:x,startSelectionBox:ae,updateSelectionBox:he,finishSelectionBox:ie,startGroupDrag:A,updateGroupDrag:D,finishGroupDrag:U}}function $s({game:e,ui:t,canvas:n,canvasPoint:o,onUpdatePanels:r}){function i(){r&&r()}let l=null,c=!1,v=null,x=!1,E=["random","up","right","down","left"],R={random:"RND",up:"UP",right:"RT",down:"DN",left:"LF"},B={w:40,h:40,y:0};function O(){return Rn(e)}function ee(){e.gridCols=f.cols,e.gridRows=f.rows,e.gridOwnedCells=qr(e)}function X(s){if(s){f.y-=s*f.cell,f.rows+=s,e.gridChunkOriginY=(e.gridChunkOriginY||0)-Math.floor(s/10),e.ownedCells=Pn(e.ownedCells,s),e.blockedCells=Pn(e.blockedCells,s),e.conveyorTiles=Pn(e.conveyorTiles,s),e.conveyorMeta=Xr(e.conveyorMeta,s);for(let a of e.eggFarms||[])a.row+=s;for(let a of e.scanners||[])a.row+=s;for(let a of Object.values(e.facilities||{}))a.entry&&(a.entry.row+=s)}}function ae(s){e.ownedCells=e.ownedCells||new Set;for(let a of zr(s))e.ownedCells.add(I(a.col,a.row))}function he(s){return e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending?null:Tt(e).find(a=>a&&Vr(a,s))||null}function ie(s="right"){if(s&&typeof s=="object"&&Number.isFinite(s.chunkX)&&Number.isFinite(s.chunkY))return s;let a=["right","up"].includes(s)?s:"right";return Yr(e,a)}function le(s="right"){let a=ie(s);if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return{ok:!1,reason:"Cannot expand now."};if(!a)return{ok:!1,reason:"Invalid expansion lot."};let h=a.direction||"right",m=O();if(e.cashf.cols&&(f.cols=T.colStart+T.cols),T.rowStart+T.rows>f.rows&&(f.rows=T.rowStart+T.rows),ae(T),Qr(e,T.chunkX,T.chunkY),e.gridExpansionPurchases=(e.gridExpansionPurchases||0)+1,e.gridExpansionPurchasesByDirection[h]=(e.gridExpansionPurchasesByDirection[h]||0)+1,ee();let te=Gr({seed:`${e.runSeed}:grid-expansion:${T.chunkX},${T.chunkY}:${e.gridExpansionPurchases}`,colStart:T.colStart,colEnd:T.colStart+T.cols,rowStart:T.rowStart,rowEnd:T.rowStart+T.rows,targetRatio:Y.map.blockedRatio});for(let ke of te)e.blockedCells.add(ke);be(e);let j=T.cols*T.rows,ue=Et(T);return H(e,ue.x+ue.w/2,ue.y+ue.h/2,`${h.toUpperCase()} +${j} CELLS -${g(m)}`,p.green),i(),{ok:!0,direction:h,cost:m,addedCells:j,blocked:te.size,chunkX:T.chunkX,chunkY:T.chunkY}}function se(s,a){return s>=0&&s=0&&a!a.has(m.id)&&q(h,G(m),12))}function D(s,a,h=null){if(!se(s,a))return!1;if(A(s,a))return!0;let m=I(s,a),w=dt(e,s,a);if(w&&!(h?.type==="eggFarm"&&h.ref?.id===w.id))return!0;let T=ft(e,s,a);if(T&&!(h?.type==="scanner"&&h.ref?.id===T.id))return!0;let te=U(e,s,a);return!!(te&&!(h?.type==="maintenanceRoom"&&h.ref?.id===te.id)||e.conveyorTiles.has(m)&&!(h?.type==="conveyor"&&h.oldKey===m))}function U(s,a,h){return(s.maintenanceRooms||[]).find(m=>jt(m).some(w=>w.col===a&&w.row===h))||null}function S(s,a,h=null){let m={col:s,row:a};for(let w of jt(m)){if(!se(w.col,w.row)||A(w.col,w.row))return!0;let T=I(w.col,w.row);if(dt(e,w.col,w.row)||ft(e,w.col,w.row))return!0;let ue=U(e,w.col,w.row);if(ue&&!(h?.type==="maintenanceRoom"&&h.ref?.id===ue.id)||e.conveyorTiles.has(T))return!0}return!1}function M(s,a,h=null){let m={col:s,row:a};for(let w of Pt(m)){if(!se(w.col,w.row)||A(w.col,w.row))return!0;let T=I(w.col,w.row);if(dt(e,w.col,w.row))return!0;let j=ft(e,w.col,w.row);if(j&&!(h?.type==="scanner"&&h.ref?.id===j.id)||e.conveyorTiles.has(T))return!0}return!1}function N(){return e.selected?e.selected.type==="eggFarm"?e.eggFarms.find(s=>s.id===e.selected.id)||null:e.selected.type==="scanner"?e.scanners.find(s=>s.id===e.selected.id)||null:e.selected.type==="conveyor"?e.conveyorTiles.has(e.selected.id)?{type:"conveyor",id:e.selected.id}:null:e.selected.type==="facility"?e.facilities[e.selected.id]||null:e.selected.type==="maintenanceRoom"&&(e.maintenanceRooms||[]).find(s=>s.id===e.selected.id)||null:null}function J(s){return s?s.type==="eggFarm"?`${ct("eggFarm")} #${s.id}`:s.type==="scanner"?`${s.kind==="auto"?ct("autoScanner"):ct("manualScanner")} #${s.id}`:s.type==="conveyor"?e.conveyorMeta.get(s.id)?.kind==="boostConveyor"?ct("boostConveyor"):ct("conveyor"):s.type==="facility"?s.name:s.type==="maintenanceRoom"?`${ct("maintenanceRoom")} #${s.id}`:"Equipment":"Equipment"}function Q(s){return s?.type==="conveyor"?e.conveyorMeta?.get(s.oldKey||s.ref?.id)?.price||Ln(s):Ln(s)}function pe(){return!!e.cardEffects?.usedMachineActive}function ge(){return pe()?{usedMachine:!0,noRefund:!0,durabilityBaseMultiplier:.6}:{usedMachine:!1,noRefund:!1,durabilityBaseMultiplier:1}}function Pe(s){let a=ge();return Object.assign(s,a),s}function Ae(s){let a=s?.ref||s||{};if(s?.type==="eggFarm"||a.type==="eggFarm")return e.eggFarms.length<=1?"Cannot sell the last EGG FARM.":"";if((s?.type==="facility"||a.type==="facility")&&["mixer","trash","truck"].includes(a.baseId||a.id)){let h=a.baseId||a.id;if(Object.values(e.facilities).filter(w=>(w.baseId||w.id)===h).length<=1)return`Cannot sell the last ${a.shortName||a.name||a.id}.`}return""}function _(s){t.buildStatus.textContent=s,H(e,n.width/2-e.view.x,86-e.view.y,s.toUpperCase(),p.danger)}function Ie(s){if(!s)return null;let a=I(s.col,s.row);return e.conveyorMeta.get(a)||null}function qe(s){return s?(Array.isArray(s.outDirs)||(s.outDirs=[]),s.outDirs=[...new Set(s.outDirs.filter(a=>["right","left","down","up"].includes(a)))],E.includes(s.branchMode)||(s.branchMode="random"),s.kind||(s.kind="conveyor"),s.speedMultiplier||(s.speedMultiplier=s.kind==="boostConveyor"?2:1),s.outDirs):[]}function Ye(s){return s?de.filter(a=>e.conveyorTiles.has(I(s.col+a.dc,s.row+a.dr))).map(a=>a.name):[]}function Te(s){return Ye(s).length>=3}function kt(s,a){let h=de.find(j=>j.name===a);if(!s||!h)return!1;let m=I(s.col+h.dc,s.row+h.dr),w=e.conveyorMeta.get(m);if(!w)return!1;let T=h.opposite;return[...new Set([...Array.isArray(w.outDirs)?w.outDirs:[],w.dir].filter(Boolean))].includes(T)}function oo(s){if(!e.conveyorTiles.has(s))return[];let a=Z(s),h=e.conveyorMeta.get(s),m=qe(h),w=Ye(a),T=[...new Set([...m,h?.dir].filter(Boolean))].filter(ue=>w.includes(ue)),te=w,j=T.length?T:te;return h&&(h.outDirs=m.filter(ue=>w.includes(ue)),h.dir&&!w.includes(h.dir)&&(h.dir=h.outDirs[0]||null),h.branchMode!=="random"&&!w.includes(h.branchMode)&&(h.branchMode="random")),j}function Sn(s){if(!e.conveyorTiles.has(s))return[];let a=Z(s),h=Ye(a);return Te(a)||h.length?h:oo(s)}function ro(s){let a=Z(s),h=Sn(s);if(h.length<3)return[];let m=new Set(h.filter(w=>kt(a,w)));return h.filter(w=>{let T=new Set(m);return T.add(w),h.filter(te=>!T.has(te)).length>=2})}function nn(s,a){let h=at(s,a);if(!h)return!1;let m=I(s.col,s.row),w=I(a.col,a.row),T=e.conveyorMeta.get(m),te=e.conveyorMeta.get(w);if(!T||!te)return!1;let j=qe(T),ue=!j.includes(h)||T.dir!==h||!te.dir;return j.includes(h)||j.push(h),T.dir=h,te.dir||(te.dir=h),ue}function Ct(s){let a=so(s);return a.length<2?io(s):(Be(e),lo(a),be(e),i(),!0)}function io(s){if(!s)return!1;let a=I(s.col,s.row),h=e.conveyorMeta.get(a);if(!h||Te(s))return!1;let m=de.map(te=>te.name),w=h.dir&&m.includes(h.dir)?h.dir:null,T=m[(Math.max(-1,m.indexOf(w))+1)%m.length];return Be(e),h.dir=T,h.outDirs=[T],h.branchMode="random",be(e),i(),!0}function kn(s){return s?de.map(a=>({col:s.col+a.dc,row:s.row+a.dr})).filter(a=>e.conveyorTiles.has(I(a.col,a.row))):[]}function so(s){if(!s||!e.conveyorTiles.has(I(s.col,s.row))||Te(s))return[];let a=kn(s);if(!a.length||a.length>2)return[];let h=T=>{let te=[],j=new Set([I(s.col,s.row)]),ue=s,ke=T,xr=0;for(;ke&&xr<200;){xr+=1;let Mr=I(ke.col,ke.row);if(j.has(Mr)||(j.add(Mr),te.push(ke),Te(ke)))break;let gr=kn(ke).filter(Tr=>!(Tr.col===ue.col&&Tr.row===ue.row));if(gr.length!==1)break;ue=ke,ke=gr[0]}return te},m=a[0]?h(a[0]).reverse():[],w=a[1]?h(a[1]):[];return[...m,s,...w]}function xt(s,a){return!!s&&[...new Set([...Array.isArray(s.outDirs)?s.outDirs:[],s.dir].filter(Boolean))].includes(a)}function lo(s){let a=0,h=0;for(let w=0;wh?[...s].reverse():s;for(let w=0;w=Math.abs(m)?{col:s.col+Math.sign(h),row:s.row}:{col:s.col,row:s.row+Math.sign(m)}}function ao(s){c=!1,v=s?{col:s.col,row:s.row}:null,x=!1,l=null,on(s)}function d(s){if(!s)return;if(!l)return on(s);let a=l,h=0;for(;(a.col!==s.col||a.row!==s.row)&&h<64;){let m=rn(a,s);if(on(m),a=l||m,h+=1,!l)break}}function y(){!x&&v&&e.conveyorTiles.has(I(v.col,v.row))&&Ct(v),v=null,x=!1,l=null,c=!1}function b(s){if(!s)return _(oe.fail.outOfGrid);let{col:a,row:h}=s;if(e.buildTool==="conveyor"||e.buildTool==="boostConveyor"){let m=_t(s,null);if(!m.ok)return _(m.reason||oe.fail.cellOccupied);be(e);return}if(A(a,h))return _("Cannot build on blocked ground.");if(e.buildTool==="maintenanceRoom")return S(a,h)?_(oe.fail.cellOccupied):$(a,h);if(e.buildTool==="manualScanner"||e.buildTool==="autoScanner"?M(a,h):D(a,h))return _(oe.fail.cellOccupied);e.buildTool==="eggFarm"?k(a,h):e.buildTool==="manualScanner"?P(a,h,"manual"):e.buildTool==="autoScanner"&&P(a,h,"auto")}function C(s){let a=Ke(s.x,s.y);if(["conveyor","boostConveyor","eggFarm","manualScanner","autoScanner","maintenanceRoom"].includes(e.buildTool))return b(a);if(cn.includes(e.buildTool))return re(s,e.buildTool)}function k(s,a){let h=Oe("eggFarm",e);if(e.cashT.kind==="manual").length>=8)return _("Manual Scanner limit reached (8 max).");let m=h==="auto"?Oe("autoScanner",e):Oe("manualScanner",e);if(e.cashw.id!==a.ref.id),et(e,m.x,m.y),be(e)}if(a.type==="scanner"){let m=ye(a.ref);Ne(a,m.x,m.y),e.scanners=e.scanners.filter(w=>w.id!==a.ref.id),et(e,m.x,m.y),be(e)}if(a.type==="facility"){let m=a.ref;Ne(a,m.x+m.w/2,m.y+m.h/2),delete e.facilities[m.id],et(e,m.x+m.w/2,m.y+m.h/2),be(e)}if(a.type==="maintenanceRoom"){let m=a.ref,w=K(m);Ne(a,w.x,w.y),e.maintenanceRooms=(e.maintenanceRooms||[]).filter(T=>T.id!==m.id),et(e,w.x,w.y)}e.selected=null,e.multiSelected=[],i()}function co(s){let a=Object.values(e.facilities).find(j=>{if(s.x>=j.x&&s.x<=j.x+j.w&&s.y>=j.y&&s.y<=j.y+j.h)return!0;if(!j.entry)return!1;let ke=F(j.entry.col,j.entry.row);return Math.abs(s.x-ke.x)<=f.cell*.46&&Math.abs(s.y-ke.y)<=f.cell*.46});if(a)return{type:"facility",ref:a};let h=Ke(s.x,s.y);if(!h)return null;let m=dt(e,h.col,h.row);if(m)return{type:"eggFarm",ref:m};let w=ft(e,h.col,h.row);if(w)return{type:"scanner",ref:w};let T=U(e,h.col,h.row);if(T)return{type:"maintenanceRoom",ref:T};let te=I(h.col,h.row);return e.conveyorTiles.has(te)?{type:"conveyor",oldKey:te,ref:{type:"conveyor",id:te}}:null}let Ut=Is({game:e,canvasPoint:o,updatePanels:i,equipmentAtPoint:co,fail:_,pointInGrid:se,rectOfFacility:G,rectsOverlap:q});function Qs(s){return null}function mr(){let s=N();s&&(s.type==="conveyor"?Gt(F(...Object.values(Z(s.id)))):s.type==="eggFarm"?Gt(F(s.col,s.row)):s.type==="scanner"?Gt(ye(s)):s.type==="facility"?Gt({x:s.x+s.w/2,y:s.y+s.h/2}):s.type==="maintenanceRoom"&&Gt(K(s)))}function Ve(s,a,h="primary-button"){let m=document.createElement("button");return m.type="button",m.className=h,m.textContent=s,m.addEventListener("click",a),m}function sn(){e.cardTargetPick?.mode==="autoScannerMenu"&&(e.cardTargetPick=null),t.modal.classList.remove("visible","equipment-popover"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function uo(s){t.modalTitle.textContent="Auto Scanner",e.cardTargetPick={pending:!0,mode:"autoScannerMenu",cardId:null,targetKeys:[`scanner:${s.id}`],remaining:1},t.modalBody.innerHTML=` +
+

Left / right output routing for this AUTO scanner.

+

Current: ${s.role===0?"Male left / others right":"Poop left / others right"}

+

Cooldown: ${nt(s).toFixed(1)}s.

+
`,t.modalActions.innerHTML="";let a=Ve("Male Left / Others Right",()=>{Be(e),s.role=0,sn(),i()},s.role===0?"facility-action warn":"facility-action"),h=Ve("Poop Left / Others Right",()=>{Be(e),s.role=1,sn(),i()},s.role===1?"facility-action warn":"facility-action");t.modalActions.append(a,h,Ve("Close",sn,"facility-action")),fo(s),t.modal.classList.add("visible","equipment-popover"),i()}function br(s){return s?.label||s?.key||"?"}function Js(s){let a=s.key===" "?"Space":s.key.length===1?s.key.toUpperCase():s.key.replace(/^Arrow/,"");return{key:s.key.toLowerCase(),code:s.code,label:a}}function js(s,a,h){for(let m of e.scanners.filter(w=>w.kind==="manual"))for(let w of["left","right"]){if(m.id===s.id&&w===a)continue;let T=m.keys?.[w];if(T&&(T.code===h.code||T.key===h.key))return!0}return!1}function ln(s,a=""){if(!s||s.kind!=="manual")return;t.modalTitle.textContent=`Manual Scanner #${s.id}`;let h=br(s.keys?.left),m=br(s.keys?.right),w=Zs(s);t.modalBody.innerHTML=` +
+

Left route key: ${h}

+

Right route key: ${m}

+ ${a?`

${a}

`:""} + ${w?`

${w}

`:""} +
`,t.modalActions.innerHTML="",t.modalActions.appendChild(Ve("Set Left Key",()=>vr(s,"left"),"facility-action warn")),t.modalActions.appendChild(Ve("Set Right Key",()=>vr(s,"right"),"facility-action warn")),t.modalActions.appendChild(Ve("Close",sn,"facility-action")),fo(s),t.modal.classList.add("visible","equipment-popover")}function Zs(s){let a=[{side:"left",binding:s.keys?.left},{side:"right",binding:s.keys?.right}];if(a[0].binding&&a[1].binding&&(a[0].binding.code===a[1].binding.code||a[0].binding.key===a[1].binding.key))return"Left and right keys conflict.";for(let h of a)if(h.binding)for(let m of e.scanners.filter(w=>w.kind==="manual"&&w.id!==s.id)){if(m.keys?.left&&(m.keys.left.code===h.binding.code||m.keys.left.key===h.binding.key))return`Key conflicts with Manual Scanner #${m.id} left.`;if(m.keys?.right&&(m.keys.right.code===h.binding.code||m.keys.right.key===h.binding.key))return`Key conflicts with Manual Scanner #${m.id} right.`}return""}function vr(s,a){t.modalBody.innerHTML=`

Press a key for ${a.toUpperCase()} route.

Esc cancels.

`,t.modalActions.innerHTML="";let h=m=>{if(m.preventDefault(),m.stopPropagation(),window.removeEventListener("keydown",h,!0),m.key==="Escape")return ln(s);let w=Js(m),T=js(s,a,w);Be(e),s.keys=s.keys||{left:null,right:null},s.keys[a]=w,i(),ln(s,T?`${w.label} assigned, but another scanner already uses it.`:`${a.toUpperCase()} set to ${w.label}.`)};window.addEventListener("keydown",h,!0)}function el(){let s=N();if(!(!s||s.type!=="scanner"))return s.kind==="auto"?uo(s):ln(s)}function tl(s){if(!s)return{x:80,y:80};if(s.type==="conveyor"){let a=Z(s.id);return F(a.col,a.row)}return s.type==="eggFarm"?F(s.col,s.row):s.type==="scanner"?ye(s):s.type==="facility"?{x:s.x+s.w/2,y:s.y+10}:{x:80,y:80}}function fo(s){let a=n.getBoundingClientRect(),h=tl(s),m=e.view?.scale||1,w=a.left+(h.x*m+(e.view?.x||0))/n.width*a.width+18,T=a.top+(h.y*m+(e.view?.y||0))/n.height*a.height-12,te=Math.max(12,window.innerWidth-274),j=Math.max(12,window.innerHeight-220);t.modal.style.setProperty("--popover-x",`${Math.max(12,Math.min(te,w))}px`),t.modal.style.setProperty("--popover-y",`${Math.max(12,Math.min(j,T))}px`)}function nl(){let s=N();if(!s)return;let a=Cr(s);t.modalTitle.textContent=J(s),t.modalBody.innerHTML=` +
${a.map(w=>`

${w}

`).join("")}
+ ${["mixer","truck"].includes(s.baseId||s.id)?'

Income/Fine = ceil(base x 1.10^upgrades)

':""}`,t.modalActions.innerHTML="",s.type==="scanner"&&s.kind==="auto"&&t.modalActions.appendChild(Ve("Auto Menu",()=>uo(s),"facility-action warn")),s.type==="scanner"&&s.kind==="manual"&&t.modalActions.appendChild(Ve("Set Keys",()=>ln(s),"facility-action warn"));let h=s.type==="conveyor"?{type:"conveyor",oldKey:s.id,ref:s}:{type:s.type,ref:s},m=Ae(h);if(m){let w=Ve(m,()=>{},"facility-action danger disabled");w.disabled=!0,t.modalActions.appendChild(w)}else{let w=ht(h,e),T=w.sameBuild?`Remove / Refund ${g(w.amount)}`:`Sell ${g(w.amount)}`;t.modalActions.appendChild(Ve(T,()=>{mr(),sn()},"facility-action danger"))}fo(s),t.modal.classList.add("visible","equipment-popover")}function ol(s){e.phase==="build"&&(y(),e.buildTool=e.buildTool===s?null:s,e.selected=null,e.multiSelected=[],e.selectionBox=null,i())}function rl(){let s=[];for(let[a,h]of Object.entries(e.facilities))if(s.push({id:`facility:${a}`,price:Q({type:"facility",ref:h}),x:h.x,y:h.y,w:h.w,h:h.h}),h.entry){let m=F(h.entry.col,h.entry.row);s.push({id:`facilityPort:${a}`,price:Q({type:"facility",ref:h}),x:m.x-18,y:m.y-18,w:36,h:36})}for(let a of e.maintenanceRooms||[]){let h=K(a);s.push({id:`maintenanceRoom:${a.id}`,price:Q({type:"maintenanceRoom",ref:a}),x:h.x-f.cell,y:h.y-f.cell,w:f.cell*2,h:f.cell*2})}for(let a of e.eggFarms){let h=F(a.col,a.row);s.push({id:`eggFarm:${a.id}`,price:Q({type:"eggFarm",ref:a}),x:h.x-24,y:h.y-24,w:48,h:48})}for(let a of e.scanners){let h=ye(a);s.push({id:`scanner:${a.id}`,price:Q({type:"scanner",ref:a}),x:h.x-50,y:h.y-73,w:100,h:146})}for(let a of e.conveyorTiles){let h=Z(a),m=F(h.col,h.row),w=e.conveyorMeta.get(a)||{};s.push({id:`conveyor:${a}`,price:w.price||Oe(w.kind==="boostConveyor"?"boostConveyor":"conveyor",e),x:m.x-22,y:m.y-22,w:44,h:44})}return s}function il(s){return R[s]||R.random}function Hc(s){return Sn(s)}function wr(s){return e.conveyorTiles.has(s)?Te(Z(s)):!1}function Sr(s){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return null;for(let a of e.conveyorTiles){if(!wr(a))continue;let h=Z(a),m=F(h.col,h.row),w=m.x-B.w/2,T=m.y+B.y-B.h/2;if(s.x>=w&&s.x<=w+B.w&&s.y>=T&&s.y<=T+B.h)return a}return null}function sl(s){let a=Sr(s);return a?(kr(a),!0):!1}function kr(s){let a=e.conveyorMeta.get(s);if(!a)return!1;let h=ro(s);if(h.length<2)return!1;Be(e);let m=E.includes(a.branchMode)?a.branchMode:"random",w=["random",...de.map(T=>T.name).filter(T=>h.includes(T))];return a.branchMode=w[(Math.max(0,w.indexOf(m))+1)%w.length],e.selected=null,e.multiSelected=[],i(),!0}function Cr(s){Se(e);let a=[],h=s?.type==="facility"?s.baseId||s.id:"";if(s.type==="eggFarm"){let[m,w]=dn(s);a.push(`Price: ${g(Q(s))}`);{let T=Ae({type:s.type,ref:s});a.push(T?`Sale: blocked (${T})`:`Sale value: ${g(ht({type:s.type,ref:s},e).amount)}`)}a.push(`Level: ${s.level}/4`),a.push(`Random interval: ${m.toFixed(2)}-${w.toFixed(2)}s`),a.push(`Durability: ${bn(s)}% | Spawn delay x${Hn(s).toFixed(2)}`)}else if(s.type==="scanner")a.push(`Price: ${g(Q(s))}`),a.push(`Sale value: ${g(ht({type:s.type,ref:s},e).amount)}`),a.push(`Type: ${s.kind.toUpperCase()} / Standard`),s.kind==="auto"&&a.push(`Role: ${s.role===0?"Male left / Others right":"Poop left / Others right"}`),a.push(`Queue: ${s.queue.length}`),s.kind==="auto"&&a.push(`Cooldown: ${s.cooldown.toFixed(1)}s / ${nt(s,e).toFixed(1)}s`),s.kind==="auto"&&a.push(`Durability: ${bn(s)}% | Delay x${Kn(s).toFixed(2)}`),s.kind==="manual"&&a.push("Durability: none | Always normal");else if(s.type==="conveyor"){let m=e.conveyorMeta.get(s.id),w=e.componentLookup?.get(s.id),T=w?e.congestion.get(w):null;a.push(`Price: ${g(Q({type:"conveyor",oldKey:s.id,ref:s}))}`),a.push(`Cell: ${s.id}`),a.push(`Type: ${m?.kind==="boostConveyor"?"BOOST BELT":"Normal Belt"} | Speed x${Number(m?.speedMultiplier||1).toFixed(1)}`),a.push(`Congestion: ${T?Math.floor(T.ratio*100):0}%`),a.push(`Durability: ${bn({meta:m})}% | Speed x${Wn({meta:m}).toFixed(2)}`),wr(s.id)?(a.push(`Branch mode: ${il(m?.branchMode||"random")}`),a.push("Use the Branch button below or the on-belt branch badge.")):a.push("Branch mode: needs 3+ conveyor connections."),a.push(`Sale value: ${g(ht({type:"conveyor",oldKey:s.id,ref:s},e).amount)}`)}else if(s.type==="maintenanceRoom")a.push(`Price: ${g(Q({type:"maintenanceRoom",ref:s}))}`),a.push(`Sale value: ${g(ht({type:"maintenanceRoom",ref:s},e).amount)}`),a.push("Size: 2\xD72 grid cells"),a.push("Dispatch: 1 repairman during each production day");else if(s.type==="facility"){a.push(`Price: ${g(Q(s))}`);{let m=Ae({type:s.type,ref:s});a.push(m?`Sale: blocked (${m})`:`Sale value: ${g(ht({type:s.type,ref:s},e).amount)}`)}if(a.push(["mixer","truck","trash"].includes(s.id)?`Level: ${s.level} / no cap`:`Level: ${s.level}`),h==="truck"&&a.push("Durability: none | Always normal"),["mixer","trash"].includes(h)&&a.push(`Durability: ${bn(s)}% | Extra delay ${Jo(e,s).toFixed(2)}s`),h==="mixer"&&(a.push(`Income: ${g(ze(e))} per chick | upgrade x${pt(e,"mixer").toFixed(3)}`),a.push(`Poop fine: -${g(pn(e))}`)),h==="truck"&&(a.push(`Income: ${g(Fe(e))} per target cargo | upgrade x${pt(e,"truck").toFixed(3)}`),a.push(`Poop shipment fine: -${g(yn(e))}`)),h==="trash"){let m=$t(e),w=yt(m);a.push(`Bonus cards: ${m}/${Vt()}`),a.push(`Poop income bonus: ${g(w)} per processed poop.`),a.push("With enough upgrades, poop can out-earn male/female routes.")}s.entry&&a.push(`Receiver: edge cell ${s.entry.col},${s.entry.row} (${s.side})`)}return a}function ll(s){if(!s||e.phase!=="build")return"";let a=Fn(e).find(h=>h.type===s.type&&h.id===s.id);return a?a.message||"Not connected to conveyor route":""}function al(s){return s?s.type==="conveyor"&&e.conveyorMeta.get(s.id)?.kind==="boostConveyor"?"Moves chicks twice as fast. Wears down like a normal belt.":s.type==="conveyor"?"A stubborn belt tile. It only cares about the next cell.":s.type==="eggFarm"?"A tiny gatehouse producing questionable eggs on schedule.":s.type==="scanner"&&s.kind==="auto"?"Slower than hands without upgrades.":s.type==="scanner"?"A manual checkpoint. The operator is the algorithm.":s.type==="facility"&&(s.baseId||s.id)==="mixer"?"Male chicks become revenue here. Do not feed it poop.":s.type==="facility"&&(s.baseId||s.id)==="trash"?"Poop goes in. Sometimes coins come out, for reasons best left unaudited.":s.type==="facility"&&(s.baseId||s.id)==="truck"?"The shipping endpoint. Correct cargo pays; wrong cargo complains.":s.type==="maintenanceRoom"?"A 2\xD72 repair bay. One room dispatches one repairman per day.":"Factory equipment.":""}return{buildAtCell:b,buildAtPoint:C,eraseAtPoint:Gt,equipmentAtPoint:co,startSelectionBox:Ut.startSelectionBox,updateSelectionBox:Ut.updateSelectionBox,finishSelectionBox:Ut.finishSelectionBox,startGroupDrag:Ut.startGroupDrag,updateGroupDrag:Ut.updateGroupDrag,finishGroupDrag:Ut.finishGroupDrag,selectedObject:N,selectedTitle:J,equipmentPrice:Q,selectedUpgradeCost:Qs,selectedInfoLines:Cr,flavorText:al,disconnectedWarningFor:ll,gridExpansionCost:O,buyGridExpansion:le,expansionOfferAtPoint:he,beginConveyorDrag:ao,continueConveyorDrag:d,endConveyorDrag:y,cycleSingleConveyorDirection:Ct,branchSwitcherAtPoint:Sr,cycleBranchModeAtPoint:sl,cycleBranchModeForKey:kr,removeSelected:mr,switchScannerRole:el,showManualScannerMenu:ln,showAutoScannerMenu:uo,showSelectedMenu:nl,setBuildTool:ol,fail:_,isEquipmentCell:D,equipmentHitBoxes:rl,routeFromFarmToScanner:It}}function Ds({game:e,ui:t,build:n,startGame:o,beginCardDraft:r,activeQueuedChick:i}){function l(D){return String(D).replace(/[&<>"']/g,U=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[U])}function c(){return Math.round(Vn(e))}function v(){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return!1;let D=!1;for(let U of vo)if(D=!0,e.cash>=Oe(U,e))return!1;return D}function x(){E(),R(),ee(),O(),B()}function E(){for(let[U,S]of Object.entries(t.buttons))S?.classList?.contains("tool-button")&&S.classList.toggle("active",e.buildTool===U);for(let U of vo){let S=t.buttons[U];if(!S)continue;let M=Oe(U,e),N=S.querySelector("span");N&&(N.textContent=U==="conveyor"||U==="boostConveyor"?`${g(M)} / tile`:g(M));let J=U==="manualScanner"&&e.scanners.filter(pe=>pe.kind==="manual").length>=8,Q=e.cashIt(e,J)?.scannerId).length,U=fn(e),S=Math.max(0,Math.floor(e.lastResult?.profit??e.stats?.profit??0)),M=Math.max(1,Number(e.turn)||1),N=On(e,M,S);t.turnSummary.innerHTML=[`Seed: ${l(e.runSeed||"none")} | Grid box: ${e.gridRows||10}x${e.gridCols||20} | Owned: ${e.gridOwnedCells||e.ownedCells?.size||(e.gridRows||10)*(e.gridCols||20)} cells | Blocked: ${e.blockedCells?.size||0} cells`,`Truck target: ${je(e).toUpperCase()} | Male fine: -${g(_o(e))}`,`Poop fine: Mixer -${g(pn(e))} / Shipment -${g(yn(e))}`,`Fairies tribute on Next Day: -${g(N.amount)} | base ${g(N.base)} + profit share ${g(N.profitTribute)} | basis net ${g(S)} | exemption ${g(N.profitExemption)}${N.reduction?` | reduction -${g(N.reduction)}`:""}`,`Maintenance: worst ${tr(e).worst.percent}% dirty (${tr(e).worst.label}) | Repair rooms: ${(e.maintenanceRooms||[]).length} | Repairmen: ${(e.repairmen||[]).length}`,`Manual combo: ${e.manualCombo?.count||0} | Card draft: ${e.cardDraft?.pending?Math.max(1,e.cardDraft.picksRemaining||1)+" pick(s) left":"ready after each day"} | Belt: ${c()}px/s | Farms with scanner route: ${D}/${e.eggFarms.length}`,e.cardEffects?.usedMachineActive?'Procurement: USED MACHINE MODE / no refunds / 60% durability':"",U.length?`Blocked: ${U[0]}`:`${oe.status.allPortsConnected}`].join("
")}function ee(){if(!t.eventPanel)return;let D=e.eventOffer;if(e.phase!=="build"){t.eventPanel.innerHTML=oe.status.eventPanelRunning;return}if(!D){t.eventPanel.className="event-card empty",e.turn+1Event lock active.No irregular events during Days 1-7. First possible forced event: Day ${gt}.`:t.eventPanel.innerHTML="No event.Random forced events can appear later.";return}t.eventPanel.className="event-card accepted",t.eventPanel.innerHTML=` +
FORCED NEXT DAY
+

${D.title}

+
+ Effect: ${D.route} + ${D.targetAmount?`Target: ${D.targetAmount}`:"Target: none"} + ${D.reward?`Reward: ${g(D.reward)}`:"Reward: none"} + Time ${D.daySeconds||60}s / Output x${Number(D.productionMultiplier||1).toFixed(2)} / Poop +${Math.round((D.poopRateAdd||0)*100)}pt +
`}function X(){E(),t.shell.classList.toggle("phase-running",e.phase==="running"),t.shell.classList.toggle("phase-build",e.phase==="build"),t.shell.classList.toggle("phase-gameover",e.phase==="gameover"),t.shell.classList.toggle("phase-title",e.phase==="title"),t.shell.classList.toggle("phase-loanDecision",e.phase==="loanDecision"),t.money.textContent=g(e.cash),t.money.classList.toggle("cash-negative",e.cash<0),t.money.classList.toggle("cash-positive",e.cash>an),t.turn.textContent=e.turn,t.timeLeft.textContent=e.phase==="running"&&e.timeLeft<=0&&e.shutdownTimeLeft>0?`+${e.shutdownTimeLeft.toFixed(1)}s`:`${Math.max(0,e.timeLeft).toFixed(1)}s`,t.timeLeft.closest?.(".hud-card")?.classList.toggle("time-critical",e.phase==="running"&&(e.timeLeft<=10||e.timeLeft<=0&&e.shutdownTimeLeft>0)),t.phase.textContent=he(),t.comboCount&&(t.comboCount.textContent=e.manualCombo?.count||0),ae(),t.turnProfit.textContent=g(e.stats.profit),t.turnProfit.classList.toggle("cash-negative",e.stats.profit<0),t.turnProfit.classList.toggle("cash-positive",e.stats.profit>0),t.mixerCount.textContent=e.stats.mixerCount,t.truckFemaleCount.textContent=e.stats.truckFemale,t.truckMaleCount.textContent=e.stats.truckMale,t.poopCount.textContent=e.stats.poopSpawned,t.buttons.s1Left.disabled=e.phase!=="running"||!i(0),t.buttons.s1Right.disabled=e.phase!=="running"||!i(0),t.buttons.s2Left.disabled=e.phase!=="running"||!i(1),t.buttons.s2Right.disabled=e.phase!=="running"||!i(1);let D=e.scanners.find(N=>N.kind==="manual"&&N.slot===0),U=e.scanners.find(N=>N.kind==="manual"&&N.slot===1);D&&(t.buttons.s1Left.textContent=`S1 ${D.keys?.left?.label||"A"} -> Mixer`,t.buttons.s1Right.textContent=`S1 ${D.keys?.right?.label||"D"} -> S2`),U&&(t.buttons.s2Left.textContent=`S2 ${U.keys?.left?.label||"Left"} -> Waste`,t.buttons.s2Right.textContent=`S2 ${U.keys?.right?.label||"Right"} -> Truck`);let S=Math.max(0,Math.floor(e.lastResult?.profit??e.stats?.profit??0)),M=On(e,Math.max(1,Number(e.turn)||1),S).amount;t.buttons.nextTurn.textContent=e.phase==="build"&&M>0?`Next Day - Fairies ${g(M)}`:oe.actions.nextDay,t.buttons.nextTurn.disabled=e.phase!=="build"||!!e.cardDraft?.pending||!!e.cardTargetPick?.pending||!fi(e)}function ae(){if(!t.eventBrief||!t.targetBrief||!t.speedBrief)return;let D=je(e).toUpperCase();t.targetBrief.textContent=`TRUCK TARGET: ${D}`,t.speedBrief.textContent=`BELT: ${c()} px/s | COMBO: ${e.manualCombo?.count||0}`,t.speedBrief.title=`Conveyor speed does not increase by day. Degraded belts reduce speed. Cap: ${Wt}px/s.`;let U=e.eventActive,S=e.eventOffer;U?(t.eventBrief.textContent=`ACTIVE EVENT: ${U.title} | ${U.route}`,t.eventBrief.className="event-brief active"):e.phase==="build"&&S?(t.eventBrief.textContent=`NEXT DAY EVENT: ${S.title} | ${S.route}${S.targetAmount?` | Target ${S.targetAmount}`:""}${S.reward?` | Reward ${g(S.reward)}`:""}`,t.eventBrief.className="event-brief next"):e.phase==="build"&&e.turn+1
\u2642Male->MixerS1: A
\u2640Female->TruckS1: D, then S2: right
\u{1F4A9}Poop->ShredderS1: D, then S2: left

Build phase: connect at least one EGG through a scanner to Mixer, Shredder, or Truck before Next Day. One day is one run.

',t.modalActions.innerHTML="",t.modalActions.appendChild(G(oe.actions.startGame,o,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function le(D){let U=J=>`${J>0?"+":""}${g(J)}`,S=J=>`${J>0?"-":""}${g(J)}`,M=D.profit>=0?"cash-positive":"cash-negative",N=(D.mixerPoopFine||0)+(D.truckPoopFine||0)+(D.maleTruckFine||0)+(D.explosionDamage||0)+(D.cardRerollCost||0);t.modalTitle.textContent=`Day ${D.turn} Settlement`,t.modalBody.innerHTML=` +
Net result${g(D.profit)}
+
+
Chick shipment income${U(D.chickShipmentIncome||0)}
+
Poop shipment income${U(D.poopShipmentIncome||0)}
+
Mixer income${U(D.mixerRevenue||0)}
+
Composter income${U(D.composterIncome||0)}
+
DUD refund income${U(D.dudRefundIncome||0)}
+
Manual combo bonus${U(D.manualComboBonus||0)}
+
Chemical subsidy${U(D.chemicalWeaponSubsidy||0)}
+
Event bonus${U(D.eventBonus||0)}
+
Penalties${S(N)}
+
Fairies fee${S(D.fairiesTribute?.amount||D.fairiesTribute||0)}
+
+

Income ${g(D.revenue)} - losses ${g(D.penalty)} = ${g(D.profit)}

`,t.modalActions.innerHTML="",t.modalActions.appendChild(G("Choose Upgrade Card",r||q,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function se(D,U){let S=Math.max(0,e.cardEffects?.rescueLoanCharges||0);t.modalTitle.textContent="Emergency Loan Available",t.modalBody.innerHTML=` +

End-of-day cash is below ${g(0)}.

+
+
Current money${g(e.cash)}
+
Emergency Loan+${g(500)}
+
Cards remaining${S}
+
+

Use one Emergency Loan to gain ${g(500)} immediately. If cash is still negative, another decision will be shown if another card remains.

`,t.modalActions.innerHTML="",t.modalActions.appendChild(G("Accept Game Over",U,"facility-action danger")),t.modalActions.appendChild(G("Use Emergency Loan",D,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function A(){let D=e.totals.processed,U=D?Math.round(e.totals.correct/D*100):0,S=Oi(e);t.modalTitle.textContent=oe.phases.gameover,t.modalBody.innerHTML=`

Your cash went negative.

+
Final Score${S.score}
Survival${e.totals.turnsCompleted} days
Final Cash${g(e.cash)}
Accuracy${U}%
+
Score breakdown +
Formula
Base = Cash + Total revenue + Factory value \xD70.5 + Event bonus \xD70.5 = ${g(S.base)}
Daily earned = ceil(Base \xF7 Days) = ${g(S.dailyEarned)}
Score = max(0, floor(Base + Daily earned + Correct bonus - Total outflow - Day penalty)) = ${S.score}
+
Factory Value${g(S.factoryValue)}
Total Revenue${g(e.totals.revenue)}
Daily Earned${g(S.dailyEarned)} / day
Total Outflow${g(e.totals.penalty)}
Fairies Tribute${g(e.totals.fairiesTribute||0)}
Correct Sorts${e.totals.correct}
Auto Sorted${e.totals.autoSorted}
Poop Control${e.totals.poopTrash} trashed / ${e.totals.poopTruck} shipped / ${e.totals.poopMixer} mixer
Explosion Penalty${g(e.totals.explosionDamage)}
Event Bonus${g(e.totals.eventBonus)}
Day Penalty-${S.dayPenalty}
Events${e.totals.eventSuccess} success / ${e.totals.eventFailed} failed
+
`,t.modalActions.innerHTML="",t.modalActions.appendChild(G(oe.actions.restart||"Restart",o,"primary-button restart-button")),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible","gameover-modal")}function G(D,U,S="primary-button"){let M=document.createElement("button");return M.type="button",M.className=S,M.textContent=D,M.addEventListener("click",U),M}function q(){t.modal.classList.remove("visible","equipment-popover","gameover-modal"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function me(){}return{updatePanels:x,updateUI:X,showTitle:ie,showTurnResult:le,showEmergencyLoanDecision:se,showGameOver:A,hideModal:q,checkGameOver:me}}function hr(e){e.totals.processed+=1}function Zt(e){e.stats.correct+=1,e.totals.correct+=1}function vt(e){e.stats.mistakes+=1,e.totals.mistakes+=1}function Fs(e){e.stats.autoSorted+=1,e.totals.autoSorted+=1}function Bs(e){e.stats.poopSpawned+=1}function Ls(e){e.stats.mixerCount+=1,hr(e)}function Os(e){e.stats.trashCount+=1,hr(e)}function Ns(e,t){t==="female"?e.stats.truckFemale+=1:t==="male"&&(e.stats.truckMale+=1),hr(e)}function Zn(e,t){let n=t==="truck"?"poopTruck":t==="trash"?"poopTrash":t==="mixer"?"poopMixer":null;n&&(e.stats[n]+=1,e.totals[n]+=1)}function _s({game:e,currentConveyorSpeed:t,onGameOverCheck:n}){function o(d){return Rt(d)*Hn(d)*us(e)/wi(e)}function r(d){let y=F(d.col,d.row),b=1+ds(e,d),C=l(d,b);if(!C.length)return i(d,y),!0;let k=0,P=0;for(let $ of C){let K=F($.col,$.row),re=c(K);if(re){re.stoppedTimer=.85,P+=1;continue}let Ne=As(e,{stage:"belt",scannerId:null,route:[K]});Ne.sex==="poop"&&Bs(e),e.chicks.push(Ne),Xi(e,d),k+=1}return k>0?(_i(e,y.x,y.y),k>1&&H(e,y.x,y.y-28,`x${k}`,p.green),!0):P===0}function i(d,y){(d.noRouteNoticeCooldown||0)<=0&&(H(e,y.x,y.y-24,"NO BELT: PAUSED",p.warn),d.noRouteNoticeCooldown=2.5)}function l(d,y){let C=de.map(k=>({col:d.col+k.dc,row:d.row+k.dr})).filter(k=>Ee(k.col,k.row)&&e.conveyorTiles.has(I(k.col,k.row))).map(k=>({p:k,blocked:B(null,F(k.col,k.row))?1:0,roll:Math.random()}));return C.sort((k,P)=>k.blocked-P.blocked||k.roll-P.roll),C.slice(0,Math.max(1,y||1)).map(k=>k.p)}function c(d){return e.chicks.find(y=>y.stage!=="flying"&&Math.hypot(y.x-d.x,y.y-d.y)0;if(e.timeLeft=Math.max(0,e.timeLeft-d),C&&e.timeLeft<=0&&y(),e.timeLeft<=0){e.shutdownTimeLeft>0&&(e.shutdownTimeLeft=Math.max(0,e.shutdownTimeLeft-d));for(let k of e.eggFarms)k.shutterProgress=Math.min(1,(k.shutterProgress||0)+d*2.8)}if(C&&e.timeLeft>0){for(let k of e.eggFarms)if(k.noRouteNoticeCooldown>0&&(k.noRouteNoticeCooldown=Math.max(0,k.noRouteNoticeCooldown-d)),k.nextSpawn-=d,k.nextSpawn<=0){let P=r(k);k.nextSpawn=P?o(k):.15,k.lastInterval=k.nextSpawn}}for(let k=e.chicks.length-1;k>=0;k-=1){let P=e.chicks[k];P.bob+=d*7,P.stoppedTimer>0&&(P.stoppedTimer=Math.max(0,P.stoppedTimer-d)),P.stage!=="queued"&&E(P,k,d)}_(d),_t(),on(),e.timeLeft<=0&&(e.chicks.length===0?b():e.shutdownTimeLeft<=0&&x())}function x(){if(e.cleanupBlown)return;e.cleanupBlown=!0,e.cleanupTimer=1;let d=[...e.chicks];for(let y of d)Ko(e,y.sex,y.x,y.y,-Math.PI/2,!0);e.chicks=[];for(let y of e.scanners)y.queue=[];if(_t(),d.length){let y=d.reduce((C,k)=>C+k.x,0)/d.length,b=d.reduce((C,k)=>C+k.y,0)/d.length;Xe(e,y,b,p.warn,58),H(e,y,b-24,"CLEANUP",p.warn)}}function E(d,y,b){if(R(d)){d.stoppedTimer=.35;return}if(pe(d,b),!(d.route&&d.targetIndex=d.route.length)return!1;let y=d.route[d.targetIndex];return B(d,y)}function B(d,y){if(!y)return!1;for(let b of e.chicks)if(!(d&&b.id===d.id)&&b.stage!=="flying"&&Math.hypot(b.x-y.x,b.y-y.y)1)&&d.push({x:y.x,y:y.y})}function ee(d){let y=e.conveyorMeta?.get?.(d)||{},b=[];Array.isArray(y.outDirs)&&b.push(...y.outDirs),y.dir&&b.push(y.dir);let C=[...new Set(b)].filter(re=>de.some(Ne=>Ne.name===re)),k=Z(d),P=de.filter(re=>A(k,re.name)).map(re=>re.name),$=C.filter(re=>P.includes(re)),K=P;return $.length?$:K}function X(d){return de.find(y=>y.name===d)||null}function ae(d,y){return e.scanners.find(b=>b.col<=d&&d<=b.col+1&&b.row-1<=y&&y<=b.row+1)||null}function he(d,y){let b=X(y);if(!b)return null;let C=ae(d.col+b.dc,d.row+b.dr);if(!C)return null;let k=Re(C,"inputA");return k&&k.col===d.col&&k.row===d.row?C:null}function ie(d){return Object.entries(e.facilities||{}).find(([,y])=>y?.entry&&y.entry.col===d.col&&y.entry.row===d.row)||null}function le(d){return d?.baseId||d?.id||""}function se(d,y){return d.side==="left"&&y==="left"||d.side==="right"&&y==="right"||d.side==="top"&&y==="up"||d.side==="bottom"&&y==="down"}function A(d,y){let b=X(y);if(!b)return null;let C={col:d.col+b.dc,row:d.row+b.dr};if(Ee(C.col,C.row)&&e.conveyorTiles.has(I(C.col,C.row)))return{type:"conveyor",dirName:y,target:F(C.col,C.row),nextCell:C};let k=he(d,y);if(k)return{type:"scanner",dirName:y,target:ye(k),scanner:k};let P=ie(d);return P&&se(P[1],y)?{type:"facility",dirName:y,facilityId:P[0],facility:P[1],target:F(d.col,d.row)}:null}function G(d,y){let b=X(y);if(!b)return!1;let C=e.conveyorMeta?.get?.(I(d.col+b.dc,d.row+b.dr));return C?[...new Set([...Array.isArray(C.outDirs)?C.outDirs:[],C.dir].filter(Boolean))].includes(b.opposite):!1}function q(d){return de.filter(y=>Ee(d.col+y.dc,d.row+y.dr)&&e.conveyorTiles.has(I(d.col+y.dc,d.row+y.dr))).map(y=>y.name)}function me(d,y,b="random"){let C=q(d);if(C.length<3)return y;let k=new Set(C.filter(K=>G(d,K)));if(b&&b!=="random"&&b!=="pass"&&C.includes(b)){let K=new Set(k);K.add(b),C.filter(re=>!K.has(re)).length>=2&&k.add(b)}let P=C.filter(K=>!k.has(K));if(P.length)return P;let $=y.filter(K=>!k.has(K));return $.length?$:y}function D(d,y){return y&&(y.type==="facility"||!B(d,y.target))}function U(d,y,b,C="random"){let k=b.map(re=>A(y,re)).filter(Boolean);if(!k.length)return null;let $=k.filter(re=>re.type!=="facility").filter(re=>!B(d,re.target)),K=$.length?$:k.filter(re=>re.type==="facility");return K.length?K[Math.floor(Math.random()*K.length)]:null}function S(d,y){let b=[];O(b,{x:d.x,y:d.y}),O(b,y),d.route=b.length?b:[{x:d.x,y:d.y}],d.targetIndex=d.route.length>1?1:d.route.length}function M(d,y){let b=Ke(d.x,d.y);if(!b)return xt(y,"OFF GRID");let C=I(b.col,b.row);if(!e.conveyorTiles.has(C))return xt(y,"OFF BELT");let k=e.conveyorMeta?.get(C)||{},P=me(b,ee(C),k.branchMode||"random");if(!P.length){d.stoppedTimer=.25;return}let $=U(d,b,P,k.branchMode||"random");if(!$){d.stoppedTimer=.25;return}if($.type==="facility"){let K=le($.facility);K==="mixer"?io(y,$.facility):K==="truck"?kn(y,$.facility):K==="trash"?so(y,$.facility):xt(y,"DONE");return}$.type==="scanner"&&(d.pendingScannerId=$.scanner.id),d.prevConveyorCell=C,S(d,$.target)}function N(d){let y=Ke(d.x,d.y);if(!y)return null;let b=I(y.col,y.row);return e.conveyorTiles.has(b)?b:null}function J(d){let y=N(d)||N(d.route?.[d.targetIndex]||d);return t(y)}function Q(d,y){let b=N(y);!b||d.lastWearKey===b||(d.lastWearKey=b,zi(e,b))}function pe(d,y){let b=J(d)*y;for(;b>0&&d.targetIndex=$?(d.x=C.x,d.y=C.y,Q(d,C),d.targetIndex+=1,b-=$):(d.x+=k/$*b,d.y+=P/$*b,b=0)}}function ge(d,y,b){d.stage="queued",d.route=null,d.queueRoute=b?b.map(C=>({x:C.x,y:C.y})):[ye(y)],d.scannerId=y.id,y.queue.includes(d.id)||y.queue.push(d.id),Pe(y)}function Pe(d){d.queue=d.queue.filter(b=>e.chicks.some(C=>C.id===b&&C.stage==="queued"));let y=f.cell*.86*fs(e);d.queue.forEach((b,C)=>{let k=e.chicks.find(P=>P.id===b);k&&(Ae(k,k.queueRoute||[ye(d)],C*y),k.queueIndex=C)})}function Ae(d,y,b){if(!y||!y.length)return;if(y.length===1||b<=0){let P=y[y.length-1];d.x=P.x,d.y=P.y;return}let C=b;for(let P=y.length-1;P>0;P-=1){let $=y[P-1],K=y[P],re=Math.hypot(K.x-$.x,K.y-$.y);if(C<=re){let Ne=1-C/re;d.x=$.x+(K.x-$.x)*Ne,d.y=$.y+(K.y-$.y)*Ne;return}C-=re}let k=y[0];d.x=k.x,d.y=k.y}function _(d){for(let y of e.scanners){if(y.cooldown>0&&(y.cooldown=Math.max(0,y.cooldown-d)),y.keyPressTime>0&&(y.keyPressTime=Math.max(0,y.keyPressTime-d)),Pe(y),y.kind!=="auto"||y.cooldown>0||!y.queue.length)continue;let b=y.queue[0],C=e.chicks.findIndex(k=>k.id===b);if(C<0){y.queue.shift();continue}nn(C,Ao(y,e.chicks[C]),!0)&&(Qi(e,y),y.cooldown=nt(y,e),Fs(e))}}function Ie(d){let y=To(e,d);return!y||!y.queue.length?null:e.chicks.find(b=>b.id===y.queue[0])||null}function qe(d,y){if(e.phase!=="running")return;let b=To(e,d);Ye(b,y)}function Ye(d,y){if(e.phase!=="running"||!d||d.kind!=="manual"||(d.keyPressTime=.18,d.keyPressSide=y,!d.queue.length))return;let b=e.chicks.findIndex(C=>C.id===d.queue[0]);b>=0&&nn(b,y,!1)}function Te(d,y,b){return d.kind==="manual"&&Ao(d,y)===b}function kt(d){let y=e.manualCombo?.count||0;if(e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=0,e.manualCombo.lastBonus=0,e.stats.manualComboFailure=(e.stats.manualComboFailure||0)+1,e.totals.manualComboFailure=(e.totals.manualComboFailure||0)+1,y>=10){let b=ye(d);Ft(e,10,.25),H(e,b.x,b.y-36,"COMBO RESET",p.danger)}}function oo(d){e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=Math.max(0,e.manualCombo.count||0)+1,e.stats.manualComboSuccess=(e.stats.manualComboSuccess||0)+1,e.totals.manualComboSuccess=(e.totals.manualComboSuccess||0)+1;let y=e.manualCombo.count;if(e.manualCombo.lastBonus=0,y<10)return 0;let b=Math.max(1,Math.floor(y/10)),C=e.scanners.filter(K=>K.kind==="manual").length,k=Math.min(1,(20+C*10)/100),P=0;for(let K=0;K0){Ge(e,$),e.stats.manualComboBonus=(e.stats.manualComboBonus||0)+$,e.totals.manualComboBonus=(e.totals.manualComboBonus||0)+$,e.manualCombo.lastBonus=$;let K=ye(d);H(e,K.x,K.y-42,`COMBO +${g($)}`,p.green)}return $}function Sn(d,y){let b=Re(d,y);if(!b)return null;let C=I(b.col,b.row);if(e.conveyorTiles.has(C))return{...b};let P=(_e(e).scannerPorts.get(d.id)?.[y]?.keys||[]).filter(Boolean);if(!P.length)return null;let $=P.map(Z);return $.find(re=>re.col===b.col&&re.row===b.row)||$[0]||null}function ro(d,y,b,C){let k=[];O(k,{x:d.x,y:d.y});let P=Re(y,b);return P&&O(k,F(P.col,P.row)),O(k,F(C.col,C.row)),k}function nn(d,y,b){let C=e.chicks[d];if(!C||C.stage!=="queued")return!1;let k=At(e,C.scannerId);if(!k)return!1;let P=Sn(k,y);if(!P)return!b&&k.kind==="manual"&&kt(k),H(e,C.x,C.y-16,y==="left"?"NO LEFT BELT":"NO RIGHT BELT",p.danger),!1;!b&&k.kind==="manual"&&(Te(k,C,y)?oo(k):kt(k)),k.queue=k.queue.filter(K=>K!==C.id),C.stage="belt",C.route=ro(C,k,y,P),C.targetIndex=C.route.length>1?1:C.route.length,C.scannerId=null,C.nextScannerId=null,C.pendingScannerId=null,C.queueRoute=null,C.queueIndex=-1;let $=b?p.green:y==="left"?p.mixerBlue:p.truckPink;return Gi(e,ye(k).x,ye(k).y,$),H(e,C.x,C.y-20,b?"AUTO":y.toUpperCase(),$),!0}function Ct(d){let y=e.chicks[d];return y?(e.chicks.splice(d,1),y):null}function io(d,y=e.facilities.mixer){if(y?.processingCooldown>0){let $=e.chicks[d];$&&($.stoppedTimer=.25);return}let b=Ct(d);if(!b)return;let{x:C,y:k}=b;if(Ls(e),jo(e,y),Zo(e,y),b.sex==="poop"){let $=Ai(e);Zn(e,"mixer"),vt(e),Wi(e,C,k),H(e,C,k-18,`-${g($)}`,p.danger);return}let P=Pi(e);b.sex==="male"?Zt(e):vt(e),Ui(e,C,k),H(e,C,k-18,`+${g(P)}`,p.green)}function kn(d,y=e.facilities.truck){let b=Ct(d);if(!b)return;let{x:C,y:k}=b;lo(b.sex,y),Hi(e,C,k,b.sex),Ns(e,b.sex);let P=je(e),$=ki(e,b.sex);if(b.sex==="poop"){if(Zn(e,"truck"),$)Zt(e),H(e,C,k-18,`+${g(Fe(e))}`,p.green);else{let K=Ii(e);vt(e),H(e,C,k-18,`-${g(K)}`,p.danger)}return}if(b.sex==="female"){$?(Zt(e),H(e,C,k-18,`+${g(Fe(e))}`,p.green)):(vt(e),H(e,C,k-18,P==="male"?"REJECT":"NO SALE",p.warn));return}if($){Zt(e),H(e,C,k-18,`+${g(Fe(e))}`,p.green);return}if(Ci(e)){let K=$i(e);vt(e),H(e,C,k-18,`-${g(K)}`,p.danger)}else vt(e),H(e,C,k-18,"REJECT",p.warn)}function so(d,y=e.facilities.trash){if(y?.processingCooldown>0){let K=e.chicks[d];K&&(K.stoppedTimer=.25);return}let b=Ct(d);if(!b)return;let{x:C,y:k}=b;Ki(e,C,k,b.sex),Os(e),jo(e,y),Zo(e,y);let P={amount:0},$="";if(b.sex==="poop"){P=Ti(e),$=P.amount>0?` +${g(P.amount)}`:"",Zn(e,"trash"),Zt(e);let K=Math.ceil(Math.max(0,Number(e.cardEffects?.composter)||0)*3*Bn(e));if(K>0){let re=Ge(e,K);e.stats.composterIncome=(e.stats.composterIncome||0)+re,e.totals.composterIncome=(e.totals.composterIncome||0)+re,H(e,C,k-36,`COMPOST +${g(re)}`,p.green)}H(e,C,k-18,`CLEAN${$}`,P.amount>0?p.green:p.green)}else vt(e),H(e,C,k-18,P.amount>0?`WASTE${$}`:"WASTE",P.amount>0?p.green:p.ink)}function xt(d,y){let b=Ct(d);b&&H(e,b.x,b.y-12,y,p.muted)}function lo(d,y=e.facilities.truck){let b=y||e.facilities.truck;b&&(e.truckCargo.push({sex:d,x:W(22,b.w-22),y:W(66,b.h-24)}),e.truckCargo.length>45&&e.truckCargo.shift())}function Cn(d){let y=Ke(d.x,d.y);if(y){let P=I(y.col,y.row);if(e.conveyorTiles.has(P))return P}let b=ai(e,d.x,d.y);if(!b)return null;let C=Z(b),k=F(C.col,C.row);return Math.hypot(d.x-k.x,d.y-k.y)<=f.cell*.55?b:null}function _t(){let{components:d,cellToComponent:y}=li(e);for(let b of e.chicks){if(b.stage==="flying")continue;let C=Cn(b);if(!C)continue;let k=y.get(C),P=d.get(k);P&&(P.count+=1)}for(let b of d.values())b.ratio=b.count/b.capacity;e.congestion=d,e.componentLookup=y}function on(){for(let d of e.congestion.values()){let y=Oo(e),b=xi(e);if(d.ratio>b&&d.ratio=y){let C=rn(d.id);if(!C.length||C.some($=>$.stage!=="queued"&&$.stoppedTimer<=.2))continue;let k=e.lastExplodedComponent.get(d.id)||0,P=performance.now();P-k>900&&(e.lastExplodedComponent.set(d.id,P),ao(d))}}}function rn(d){return e.chicks.filter(y=>{let b=Cn(y);return b&&e.componentLookup?.get(b)===d})}function ao(d){let y=rn(d.id);if(!y.length)return;for(let k of y)Ko(e,k.sex,k.x,k.y);e.chicks=e.chicks.filter(k=>!y.some(P=>P.id===k.id));for(let k of e.scanners)k.queue=k.queue.filter(P=>e.chicks.some($=>$.id===P));for(let k of d.cells){let P=Z(k),$=F(P.col,P.row);Xe(e,$.x,$.y,p.danger),Ze(e,$.x,$.y,6),Nn(e,$.x,$.y,4)}Ft(e,18,.75);let b=Z(d.cells[0]),C=F(b.col,b.row);e.stats.explosions=(e.stats.explosions||0)+1,e.totals.explosions=(e.totals.explosions||0)+1,H(e,C.x,C.y-22,`${Math.round(Oo(e)*100)}% JAM EXPLOSION`,p.danger)}return{activeQueuedChick:Ie,currentSpawnDelay:o,sortSlot:qe,updateCongestion:_t,sortScanner:Ye,updateRunning:v}}var fe=document.getElementById("gameCanvas"),vc=fe.getContext("2d"),L={shell:document.getElementById("gameShell"),money:document.getElementById("money"),turn:document.getElementById("turn"),timeLeft:document.getElementById("timeLeft"),phase:document.getElementById("phaseLabel"),comboCount:document.getElementById("comboCount"),eventBrief:document.getElementById("eventBrief"),targetBrief:document.getElementById("targetBrief"),speedBrief:document.getElementById("speedBrief"),turnProfit:document.getElementById("turnProfit"),mixerCount:document.getElementById("mixerCount"),truckFemaleCount:document.getElementById("truckFemaleCount"),truckMaleCount:document.getElementById("truckMaleCount"),poopCount:document.getElementById("poopCount"),buildStatus:document.getElementById("buildStatus"),turnSummary:document.getElementById("turnSummary"),eventPanel:document.getElementById("eventPanel"),modal:document.getElementById("modal"),modalTitle:document.getElementById("modalTitle"),modalBody:document.getElementById("modalBody"),modalActions:document.getElementById("modalActions"),hoverTooltip:document.getElementById("hoverTooltip"),manualScannerMonitor:document.getElementById("manualScannerMonitor"),debug:{panel:document.getElementById("debugPanel"),infiniteCash:document.getElementById("debugInfiniteCash"),dayInput:document.getElementById("debugDayInput"),setDay:document.getElementById("debugSetDayButton"),zeroTimer:document.getElementById("debugZeroTimerButton"),cardSelect:document.getElementById("debugCardSelect"),targetSelect:document.getElementById("debugTargetSelect"),grantCard:document.getElementById("debugGrantCardButton"),grantAllCards:document.getElementById("debugGrantAllCardsButton"),readout:document.getElementById("debugReadout")},buttons:{s1Left:document.getElementById("scanner1MixerButton"),s1Right:document.getElementById("scanner1TruckButton"),s2Left:document.getElementById("scanner2MixerButton"),s2Right:document.getElementById("scanner2TruckButton"),nextTurn:document.getElementById("nextTurnButton"),conveyor:document.getElementById("buildConveyorButton"),boostConveyor:document.getElementById("buildBoostConveyorButton"),eggFarm:document.getElementById("buildEggFarmButton"),autoScanner:document.getElementById("buildAutoScannerButton"),manualScanner:document.getElementById("buildManualScannerButton"),mixer:document.getElementById("buildMixerButton"),trash:document.getElementById("buildTrashButton"),truck:document.getElementById("buildTruckButton"),maintenanceRoom:document.getElementById("buildMaintenanceRoomButton"),erase:document.getElementById("eraseButton"),undo:document.getElementById("undoButton"),redo:document.getElementById("redoButton")}};function wc(){let e={conveyor:"conveyor",boostConveyor:"boostConveyor",eggFarm:"eggFarm",autoScanner:"autoScanner",manualScanner:"manualScanner",mixer:"mixer",trash:"trash",truck:"truck",maintenanceRoom:"maintenanceRoom"};for(let[t,n]of Object.entries(e))L.buttons[t]&&(L.buttons[t].innerHTML=Br(n))}function Sc(e){let t=new Set(e.tags||[]);return["upgradeEgg","crowdedFarming","hatchingFeed","extraEggOutlet"].includes(e.id)||t.has("EGG")?"Production / EGG":["upgradeTrash","poopRateBooster","composter","chemicalWeaponSubsidy"].includes(e.id)||t.has("POOP")?"Poop / Shredder":["upgradeAutoScanner","autoScannerTuning","scannerQueueSpacing"].includes(e.id)||t.has("SCANNER")?"Scanner":["bearing","dynamite"].includes(e.id)||t.has("CONVEYOR")?"Conveyor / Map":["safetyCover","preventiveMaintenance","durabilityCoating","sparePartsBin","laborExploitation"].includes(e.id)||t.has("MAINTENANCE")?"Maintenance / Risk":["dudFilter","dudRefund","freeReroll","extraCards"].includes(e.id)||t.has("CARD")?"Card Engine":t.has("ULTRA RARE")?"Ultra Rare":t.has("ECONOMY")||["upgradeMixer","upgradeTruck","recyclingSubsidy","usedMachine","newMachine","flattery","legalWork","rescueLoan"].includes(e.id)?"Economy / Shipment":"Other"}function kc(){if(!L.debug?.panel||!L.debug.cardSelect)return;let e=["Production / EGG","Poop / Shredder","Scanner","Conveyor / Map","Maintenance / Risk","Card Engine","Economy / Shipment","Ultra Rare","Other"],t=new Map(e.map(n=>[n,[]]));for(let n of Qt){let o=Sc(n);t.has(o)||t.set(o,[]),t.get(o).push(n)}L.debug.cardSelect.innerHTML="";for(let n of e){let o=t.get(n)||[];if(!o.length)continue;let r=document.createElement("optgroup");r.label=n;for(let i of o){let l=document.createElement("option");l.value=i.id;let c=i.rarity==="ultraRare"?"UR":i.rarity==="rare"?"R":"C";l.textContent=`[${c}] ${i.title}`,r.appendChild(l)}L.debug.cardSelect.appendChild(r)}L.debug.cardSelect.addEventListener("change",Ot),Ot()}function Ot(){if(!L.debug?.targetSelect)return;let e=L.debug.cardSelect?.value,t=Jt(e),n=t?ps(u,t):[];if(L.debug.targetSelect.innerHTML="",!n.length){let r=document.createElement("option");r.value="__none__",r.textContent=t?"No target required":"No card selected",L.debug.targetSelect.appendChild(r),L.debug.targetSelect.disabled=!0;return}let o=document.createElement("option");o.value="__auto__",o.textContent=t?.id==="dynamite"?"Auto: first 3 blocked cells":"Auto: first valid target",L.debug.targetSelect.appendChild(o);for(let r of n){let i=document.createElement("option");i.value=r.key,i.textContent=r.label,L.debug.targetSelect.appendChild(i)}L.debug.targetSelect.disabled=!1}function Cc(){let e=Math.max(1,Math.floor(Number(L.debug.dayInput?.value)||1));u.turn=e,L.debug.dayInput&&(L.debug.dayInput.value=String(e)),H(u,fe.width/2-u.view.x,86-u.view.y,`DAY ${e}`,p.green),z.updatePanels(),z.updateUI(),Ot(),Nt(`Day set to ${e}.`)}function xc(){u.timeLeft=0,u.phase==="running"&&qs(),H(u,fe.width/2-u.view.x,86-u.view.y,"TIMER 0",p.warn),z.updatePanels(),z.updateUI(),Nt("Timer set to 0.")}function Mc(){let e=L.debug.cardSelect?.value,t=L.debug.targetSelect?.disabled?void 0:L.debug.targetSelect?.value,n=or(u,e,{targetKey:t});L.debug.grantCard&&(L.debug.grantCard.textContent=n.ok?"Granted":"Failed",window.setTimeout(()=>{L.debug.grantCard&&(L.debug.grantCard.textContent="Grant Selected")},900)),Me?.updateCongestion?.(),z.updatePanels(),z.updateUI(),Ot(),Nt(n.reason)}function gc(){let t=Qt.map(n=>or(u,n,{targetKey:"__auto__"})).filter(n=>n.ok).length;Me?.updateCongestion?.(),z.updatePanels(),z.updateUI(),Ot(),Nt(`Granted ${t}/${Qt.length} cards.`)}function Tc(){L.debug?.infiniteCash?.checked&&u.cash<999999&&(u.cash=999999,u.totals.maxCash=Math.max(u.totals.maxCash,u.cash))}function Nt(e=""){L.debug?.readout&&(L.debug.readout.textContent=[e,`D${u.turn}`,g(u.cash),`Combo ${u.manualCombo?.count||0}`,`Event ${u.eventActive?.title||u.eventOffer?.title||"none"}`,`Rescue ${u.cardEffects?.rescueLoanCharges||0}`,`Chem ${u.cardEffects?.chemicalWeaponSubsidy||0}`].filter(Boolean).join(" | "))}var u=Mo(),V,z,Me,tn;function Ec(e=null){let t=Vn(u,e);return e?t*Vo(u,e):t}function Rc(){Object.assign(u,Mo()),u.phase="running",u.view={x:0,y:0,scale:1},go(u),Vs(),Se(u),z.hideModal(),Me.updateCongestion(),z.updatePanels(),z.updateUI(),Nt()}function Pc(){if(u.phase!=="build")return;if(u.cardDraft?.pending||u.cardTargetPick?.pending){V.fail(u.cardTargetPick?.pending?"Choose upgrade target first.":"Choose an upgrade card first."),z.updatePanels();return}let e=fn(u);if(e.length){V.fail(`Cannot start: ${e[0]}`),z.updatePanels();return}Se(u),si(u),es(u);let t=Math.max(0,Math.floor(u.lastResult?.profit??u.stats?.profit??0)),n=Bi(u,Math.max(1,u.turn||1),t);u.lastStartFees={fairiesTribute:n.amount||0,tribute:n},n.amount>0&&H(u,fe.width/2-u.view.x,116-u.view.y,`FAIRIES -${g(n.amount)}`,p.danger),mi(u),u.phase="running",u.turn+=1,u.timeLeft=vi(u),u.shutdownTimeLeft=0,u.cleanupTimer=null,u.cleanupBlown=!1,u.chicks=[],u.effects=[],u.floatingTexts=[],u.shake={time:0,strength:0},u.truckCargo=[],Vs(),u.stats=xo(),u.stats.fairiesTribute=u.lastStartFees?.fairiesTribute||0,u.stats.fairiesTribute>0&&(u.stats.penalty+=u.stats.fairiesTribute,u.stats.profit-=u.stats.fairiesTribute);for(let o of u.scanners)o.queue=[],o.cooldown=0;for(let o of u.eggFarms)o.nextSpawn=Me.currentSpawnDelay(o),o.lastInterval=o.nextSpawn,o.shutterProgress=0,o.shutterSparked=!1;u.buildTool=null,u.selected=null,u.groupDrag=null,u.selectionBox=null,u.pan=null,Me.updateCongestion(),z.updatePanels(),z.updateUI()}function Ac(){if(u.phase!=="running")return;let e=Fi(u),t=u.eventActive?{...u.eventActive}:null,n=gi(u),o=Li(u);if(e.adjusted>0){let i=u.facilities.truck,l=i?i.x+i.w/2:fe.width/2-u.view.x,c=i?i.y+26:96-u.view.y;H(u,l,c,`${e.target==="poop"?"POOP SHIP":"SHIP"} +${g(e.adjusted)}`,p.green)}n?.bonus>0&&H(u,fe.width/2-u.view.x,96-u.view.y,`EVENT +${g(n.bonus)}`,p.green),o.amount>0&&H(u,fe.width/2-u.view.x,116-u.view.y,`CHEM SUBSIDY +${g(o.amount)}`,p.green),bi(u),u.totals.turnsCompleted+=1;let r=Mi(t);if(r!==1&&(u.pendingFairiesTributeMultiplier=r),u.lastResult={...u.stats,ship:e,event:n,chemical:o,rescue:{amount:0,used:0,remaining:u.cardEffects?.rescueLoanCharges||0},fairiesTribute:{amount:u.stats.fairiesTribute||0},tributeMultiplier:r,turn:u.turn,cash:u.cash},u.cash<0){if((u.cardEffects?.rescueLoanCharges||0)>0){u.phase="loanDecision",z.showEmergencyLoanDecision(Hs,eo);return}u.phase="gameover",z.showGameOver();return}Ks()}function Ks(){u.phase="build",u.truckCargo=[],u.chicks=[],u.shutdownTimeLeft=0,u.cleanupTimer=null,u.cleanupBlown=!1,u.buildSession+=1,u.undoStack=[],u.redoStack=[],u.timeLeft=0;for(let e of u.scanners)e.queue=[];for(let e of u.eggFarms)e.shutterProgress=0,e.shutterSparked=!1;ts(u),u.eventOffer=hi(u),tn&&tn.prepareDraft(),u.cardTargetPick=null,u.buildTool=null,u.groupDrag=null,u.selectionBox=null,u.pan=null,z.updatePanels(),z.showTurnResult(u.lastResult)}function Hs(){if((u.cardEffects?.rescueLoanCharges||0)<=0)return eo();u.cardEffects.rescueLoanCharges-=1,u.stats.rescueLoan=(u.stats.rescueLoan||0)+500,u.totals.rescueLoan=(u.totals.rescueLoan||0)+500;let e=Ge(u,500);u.lastResult={...u.lastResult||{},...u.stats,rescue:{amount:(u.lastResult?.rescue?.amount||0)+e,used:(u.lastResult?.rescue?.used||0)+1,remaining:u.cardEffects.rescueLoanCharges},cash:u.cash},H(u,fe.width/2-u.view.x,176-u.view.y,`RESCUE +${g(e)}`,p.green),u.cash>=0?Ks():(u.cardEffects?.rescueLoanCharges||0)>0?(u.phase="loanDecision",z.showEmergencyLoanDecision(Hs,eo)):eo()}function eo(){u.phase="gameover",z.showGameOver()}function qs(){u.shutdownTimeLeft<=0&&(u.shutdownTimeLeft=u.shutdownGraceSeconds||10);for(let e of u.eggFarms){if(e.shutterSparked)continue;e.shutterProgress=.02,e.shutterSparked=!0;let t=F(e.col,e.row);Xe(u,t.x,t.y,p.ink),Ze(u,t.x,t.y+10,10),H(u,t.x,t.y-34,"SHUT +10s",p.ink)}}function Ys(e){u.lastTimestamp||(u.lastTimestamp=e);let t=Math.min((e-u.lastTimestamp)/1e3,.05);u.lastTimestamp=e,u.phase==="running"&&Me.updateRunning(t,{closeFarmShutters:qs,completeTurn:Ac}),Yi(u,t,fe,V.equipmentHitBoxes),Me.updateCongestion(),Ss(vc,fe,u,{activeQueuedChick:Me.activeQueuedChick,selectedObject:V.selectedObject,selectedTitle:V.selectedTitle}),Tc(),z.updateUI(),Xs(),Nt(),requestAnimationFrame(Ys)}function to(){return u.view?.scale||1}function wn(){u.view||(u.view={x:0,y:0,scale:1}),u.view.scale==null&&(u.view.scale=1)}function no(e){let t=fe.getBoundingClientRect();return{x:(e.clientX-t.left)*fe.width/t.width,y:(e.clientY-t.top)*fe.height/t.height}}function wt(e){let t=no(e),n=to();return{x:(t.x-(u.view?.x||0))/n,y:(t.y-(u.view?.y||0))/n}}function Ic(e){let t=to();return{x:e.x*t+(u.view?.x||0),y:e.y*t+(u.view?.y||0)}}function $c(){let e={left:f.x-90,top:f.y-130,right:f.x+f.cols*f.cell+260,bottom:f.y+f.rows*f.cell+220};if(u.phase==="build")for(let t of Tt(u)){let n=Et(t);e.left=Math.min(e.left,n.x-60),e.top=Math.min(e.top,n.y-80),e.right=Math.max(e.right,n.x+n.w+80),e.bottom=Math.max(e.bottom,n.y+n.h+80)}return e}function Gs(e,t){if(e<=t)return[e,t];let n=(e+t)/2;return[n,n]}function St(){wn();let e=to(),t=$c(),[n,o]=Gs(fe.width-160-t.right*e,110-t.left*e),[r,i]=Gs(fe.height-150-t.bottom*e,150-t.top*e);u.view.x=un(u.view.x,n,o),u.view.y=un(u.view.y,r,i)}function Vs(){wn(),u.view.scale=1;let e=u.eggFarms?.[0],t=e?F(e.col,e.row):{x:f.x,y:f.y};u.view.x=280-t.x,u.view.y=190-t.y,St()}function Dc(e){let t=no(e);wn(),u.pan={start:t,viewX:u.view.x,viewY:u.view.y,moved:!1}}function Fc(e){if(!u.pan)return;let t=no(e);Math.hypot(t.x-u.pan.start.x,t.y-u.pan.start.y)>5&&(u.pan.moved=!0),wn(),u.view.x=u.pan.viewX+t.x-u.pan.start.x,u.view.y=u.pan.viewY+t.y-u.pan.start.y,St()}function Bc(e){e.preventDefault(),wn();let t=no(e),n=wt(e),o=Math.exp(-e.deltaY*.0012),r=un(to()*o,.55,1.8);u.view.scale=r,u.view.x=t.x-n.x*r,u.view.y=t.y-n.y*r,St(),it()}function Lc(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:{type:e.type,id:e.ref.id}:null}function Oc(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:e.ref||null:null}function it(){L.hoverTooltip&&(L.hoverTooltip.classList.remove("visible"),L.hoverTooltip.setAttribute("aria-hidden","true"),u.hover=null)}function Nc(e,t){if(!L.hoverTooltip||u.phase!=="build"||u.cardTargetPick?.pending||u.groupDrag||u.selectionBox||u.pan)return it();let n=Oc(t);if(!n)return it();let o=V.selectedTitle(n),r=V.flavorText?V.flavorText(n):"",i=V.disconnectedWarningFor?V.disconnectedWarningFor(n):"",l=V.selectedInfoLines(n).slice(0,7);L.hoverTooltip.innerHTML=`${o}${i?`${i}`:r?`${r}`:""}${l.map(x=>`${x}`).join("")}`;let c=Math.min(window.innerWidth-330,e.clientX+18),v=Math.min(window.innerHeight-220,e.clientY+18);L.hoverTooltip.style.left=`${Math.max(8,c)}px`,L.hoverTooltip.style.top=`${Math.max(8,v)}px`,L.hoverTooltip.classList.add("visible"),L.hoverTooltip.setAttribute("aria-hidden","false"),u.hover={type:t.type,id:t.oldKey||t.ref?.id||null}}function _c(e){if(u.phase!=="build")return it();Nc(e,V.equipmentAtPoint(wt(e)))}function zs(e){it();let t=wt(e),n=V.equipmentAtPoint(t),o=Lc(n);if(!o){u.selected=null,u.multiSelected=[],z.updatePanels();return}u.selected=o,u.multiSelected=[o],z.updatePanels();let r=V.selectedObject();r?.type==="scanner"&&r.kind==="manual"&&V.showManualScannerMenu(r),r?.type==="scanner"&&r.kind==="auto"&&V.showAutoScannerMenu(r)}function en(){u.buildTool=null,u.selected=null,u.multiSelected=[],u.selectionBox=null,u.cardTargetPick?.mode==="autoScannerMenu"&&(u.cardTargetPick=null),z.hideModal(),it(),z.updatePanels(),z.updateUI()}function Us(e){return String(e).replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function Gc(e){let t=e?.queue?.[0];return t==null?null:u.chicks.find(n=>n.id===t)||null}function Uc(e){if(!e)return'WAIT';let t=e.sex==="poop"?"\u{1F4A9} POOP":e.sex==="male"?"\u2642 MALE":"\u2640 FEMALE";return`${t}`}function Wc(e,t){let n=new Set(u.eggFarms.map(E=>I(E.col,E.row))),o=new Map(u.scanners.map(E=>[I(E.col,E.row),E])),r=Re(e,"inputA"),i=r?I(r.col,r.row):null,l=new Set(Object.values(u.facilities||{}).map(E=>E.entry?I(E.entry.col,E.entry.row):null).filter(Boolean)),c=t?.sex||"",v=c==="poop"?"\u{1F4A9}":c==="male"?"\u2642":c==="female"?"\u2640":"",x=[];for(let E=e.row-2;E<=e.row+2;E+=1)for(let R=e.col-2;R<=e.col+2;R+=1){let B=I(R,E),O=["mini-cell"],ee="";R===e.col&&E===e.row?(O.push("scanner"),c&&O.push(c),ee=v||"S"):B===i?(O.push("input"),ee="IN"):n.has(B)?(O.push("egg"),ee="E"):o.has(B)?(O.push("scanner-other"),ee="S"):l.has(B)?(O.push("port"),ee="P"):u.conveyorTiles.has(B)?(O.push("belt"),ee="\u2022"):u.blockedCells?.has?.(B)&&(O.push("blocked"),ee="\xD7"),x.push(`${ee}`)}return`
${x.join("")}
`}function Kc(e){let t=Ic(F(e.col,e.row)),n=76;return t.x<-n||t.y<-n||t.x>fe.width+n||t.y>fe.height+n}function Xs(){if(!L.manualScannerMonitor)return;if(u.phase!=="running"){L.manualScannerMonitor.classList.remove("visible"),L.manualScannerMonitor.innerHTML="";return}let e=u.scanners.filter(t=>t.kind==="manual"&&Kc(t));if(!e.length){L.manualScannerMonitor.classList.remove("visible"),L.manualScannerMonitor.innerHTML="";return}L.manualScannerMonitor.innerHTML=e.map(t=>{let n=Gc(t),o=t.keys?.left?.label||(t.slot===0?"A":"Left"),r=t.keys?.right?.label||(t.slot===0?"D":"Right"),i=t.role===0?"MIXER":"WASTE",l=t.role===0?"S2":"TRUCK",c=n?"":" disabled";return` +
+
S${(t.slot??0)+1}OFFSCREEN / Q:${t.queue.length}
+
+ IN${Uc(n)}SCANNER +
+ ${Wc(t,n)} +
+ + +
+
`}).join(""),L.manualScannerMonitor.classList.add("visible")}L.manualScannerMonitor?.addEventListener("click",e=>{let t=e.target.closest("button[data-scanner-id]");if(!t||t.disabled)return;let n=u.scanners.find(o=>o.id===Number(t.dataset.scannerId));n&&(Me.sortScanner(n,t.dataset.side),Xs())});fe.addEventListener("contextmenu",e=>e.preventDefault());fe.addEventListener("wheel",Bc,{passive:!1});fe.addEventListener("pointerdown",e=>{if(u.phase!=="build")return;fe.setPointerCapture(e.pointerId);let t=wt(e);if(e.button===2){Dc(e);return}if(e.button!==0)return;if(u.cardTargetPick?.mode==="autoScannerMenu"){en();return}if(u.cardTargetPick?.pending){tn.chooseTargetAtPoint(t);return}let n=V.expansionOfferAtPoint?.(t);if(n){V.buyGridExpansion(n),St(),z.updatePanels(),z.updateUI();return}if(V.cycleBranchModeAtPoint?.(t)){z.updatePanels(),z.updateUI();return}let o=Ke(t.x,t.y),r=V.equipmentAtPoint(t);if(!u.buildTool&&r?.type==="conveyor"&&o&&V.cycleSingleConveyorDirection?.(o)){z.updatePanels(),z.updateUI();return}if(u.buildTool==="erase"){if(!V.equipmentAtPoint(t)){en();return}V.eraseAtPoint(t);return}if(u.buildTool){let i=Ke(t.x,t.y);if(!i&&!["mixer","trash","truck"].includes(u.buildTool)){en();return}if(u.buildTool==="conveyor"||u.buildTool==="boostConveyor"){V.beginConveyorDrag(i);return}if(V.equipmentAtPoint(t)){u.buildTool=null,zs(e);return}V.buildAtPoint(t);return}V.startGroupDrag(e)||V.startSelectionBox(e)});fe.addEventListener("pointermove",e=>{if(u.phase!=="build"){it();return}_c(e),u.pan&&e.buttons&2&&Fc(e),u.groupDrag&&e.buttons&1&&V.updateGroupDrag(e),u.selectionBox&&e.buttons&1&&V.updateSelectionBox(e),(u.buildTool==="conveyor"||u.buildTool==="boostConveyor")&&e.buttons&1&&V.continueConveyorDrag(Ke(wt(e).x,wt(e).y)),u.buildTool==="erase"&&e.buttons&1&&V.eraseAtPoint(wt(e))});fe.addEventListener("pointerup",e=>{u.selectionBox?V.finishSelectionBox():u.groupDrag&&(u.groupDrag.committed||zs(e),V.finishGroupDrag()),e.button===2&&u.pan&&!u.pan.moved&&u.buildTool&&en(),(u.buildTool==="conveyor"||u.buildTool==="boostConveyor")&&V.endConveyorDrag?.(),u.groupDrag=null,u.pan=null;try{fe.releasePointerCapture(e.pointerId)}catch{}});fe.addEventListener("pointerleave",it);fe.addEventListener("pointercancel",()=>{V?.endConveyorDrag?.(),u.groupDrag=null,u.selectionBox=null,u.pan=null,it()});document.addEventListener("pointerdown",e=>{!L.modal.classList.contains("visible")||!L.modal.classList.contains("equipment-popover")||e.target.closest("#modal .modal-card")||en()},!0);L.buttons.s1Left.addEventListener("click",()=>Me.sortSlot(0,"left"));L.buttons.s1Right.addEventListener("click",()=>Me.sortSlot(0,"right"));L.buttons.s2Left.addEventListener("click",()=>Me.sortSlot(1,"left"));L.buttons.s2Right.addEventListener("click",()=>Me.sortSlot(1,"right"));L.buttons.nextTurn.addEventListener("click",Pc);L.buttons.conveyor.addEventListener("click",()=>V.setBuildTool("conveyor"));L.buttons.boostConveyor.addEventListener("click",()=>V.setBuildTool("boostConveyor"));L.buttons.eggFarm.addEventListener("click",()=>V.setBuildTool("eggFarm"));L.buttons.autoScanner.addEventListener("click",()=>V.setBuildTool("autoScanner"));L.buttons.manualScanner.addEventListener("click",()=>V.setBuildTool("manualScanner"));L.buttons.mixer.addEventListener("click",()=>V.setBuildTool("mixer"));L.buttons.trash.addEventListener("click",()=>V.setBuildTool("trash"));L.buttons.truck.addEventListener("click",()=>V.setBuildTool("truck"));L.buttons.maintenanceRoom.addEventListener("click",()=>V.setBuildTool("maintenanceRoom"));L.buttons.erase.addEventListener("click",()=>V.setBuildTool("erase"));L.debug.setDay?.addEventListener("click",Cc);L.debug.zeroTimer?.addEventListener("click",xc);L.debug.grantCard?.addEventListener("click",Mc);L.debug.grantAllCards?.addEventListener("click",gc);L.buttons.undo.addEventListener("click",()=>{Uo(u)&&(St(),z.updatePanels(),z.updateUI(),Ot())});L.buttons.redo.addEventListener("click",()=>{Wo(u)&&(St(),z.updatePanels(),z.updateUI(),Ot())});function Ws(e,t,n){let o=e.keys?.[t];return o?o.code&&n.code===o.code||o.key&&n.key.toLowerCase()===o.key:!1}window.addEventListener("keydown",e=>{if(e.repeat)return;let t=e.key.toLowerCase();if(u.phase==="running")for(let n of u.scanners.filter(o=>o.kind==="manual")){if(Ws(n,"left",e)){e.preventDefault(),Me.sortScanner(n,"left");return}if(Ws(n,"right",e)){e.preventDefault(),Me.sortScanner(n,"right");return}}u.phase==="build"&&(e.ctrlKey||e.metaKey)&&t==="z"&&(e.preventDefault(),Uo(u)&&(St(),z.updatePanels(),z.updateUI())),u.phase==="build"&&(e.ctrlKey||e.metaKey)&&(t==="y"||e.shiftKey&&t==="z")&&(e.preventDefault(),Wo(u)&&(St(),z.updatePanels(),z.updateUI())),e.key==="Escape"&&u.cardTargetPick?.pending&&(e.preventDefault(),u.cardTargetPick.mode==="autoScannerMenu"?en():tn.cancelTargetPick())});V=$s({game:u,ui:L,canvas:fe,canvasPoint:wt,onUpdatePanels:()=>z?.updatePanels()});Me=_s({game:u,currentConveyorSpeed:Ec,onGameOverCheck:()=>z?.checkGameOver()});tn=ms({game:u,ui:L,onUpdatePanels:()=>z?.updatePanels()});z=Ds({game:u,ui:L,build:V,startGame:Rc,beginCardDraft:()=>tn.showDraft(),activeQueuedChick:Me.activeQueuedChick});wc();kc();go(u);Se(u);Me.updateCongestion();z.updatePanels();z.updateUI();z.showTitle();Nt();requestAnimationFrame(Ys); diff --git a/dist/game-v27.18.js b/dist/game-v27.18.js new file mode 100644 index 0000000..b796070 --- /dev/null +++ b/dist/game-v27.18.js @@ -0,0 +1,59 @@ +var Y={version:"v27.18 UI + ROUTING PATCH",time:{daySeconds:60,farmShutdownGraceSeconds:10},cash:{starting:250},grid:{x:170,y:78,cols:20,rows:10,cell:46,expansion:{colsPerPurchase:10,rowsPerPurchase:10,costBase:1e3,costMultiplier:1.3333333333333333,truncateUnit:100}},map:{blockedRatio:.075},economy:{income:{mixer:5,truck:10},poopFine:10,fairiesTribute:{perDay:10,profitExemption:300,legalWorkExemptionBonus:250,profitRate:.12},incomeUpgradeRate:1.1,explosionDamageDivisor:30,maleTruckFinePerHalfDay:30,shredderBonus:{maxCards:30,incomePerUpgrade:1.25},chemicalWeaponSubsidy:{poopPerBlock:70,yenPerBlock:1200}},production:{poopRate:.08,autoScannerCooldown:3.5,autoScannerUpgradeRate:.95,autoScannerCardUpgradeRate:.95,autoScannerMinCooldown:.5,poopRateCardBonus:.04,eggSpawnRanges:[[1.95,4.35],[1.55,3.45],[1.25,2.8],[1.05,2.35]]},conveyor:{baseSpeed:52,maxSpeed:300,bearingSpeedMultiplier:1.075},cards:{definitions:[{id:"upgradeEgg",title:"EGG Improvement",rarity:"common",type:"equipmentUpgrade",target:"eggFarm",description:"Choose one EGG FARM on the map and raise it by 1 level.",tags:["EGG","ACTIVE"]},{id:"upgradeAutoScanner",title:"AUTO SCANNER Improvement",rarity:"common",type:"equipmentUpgrade",target:"autoScanner",description:"Choose one AUTO SCANNER on the map and raise it by 1 level.",tags:["SCANNER","ACTIVE"]},{id:"autoScannerTuning",title:"AUTO SCANNER Tuning",rarity:"common",type:"instant",description:"All AUTO SCANNER cooldowns use default cooldown x0.95 per copy.",tags:["SCANNER","PASSIVE"]},{id:"upgradeMixer",title:"MIXER Improvement",rarity:"common",type:"equipmentUpgrade",target:"mixer",description:"Choose MIXER on the map and raise it by 1 level.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeTruck",title:"TRUCK Improvement",rarity:"common",type:"equipmentUpgrade",target:"truck",description:"Choose TRUCK on the map and raise it by 1 level.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeTrash",title:"SHREDDER Improvement",rarity:"common",type:"equipmentUpgrade",target:"trash",description:"Shred poops for a little money. Max 30 upgrades.",tags:["POOP","ACTIVE"]},{id:"crowdedFarming",title:"Crowded Farming",rarity:"common",type:"instant",description:"EGG production interval -5%. Equipment deterioration +4%. Max 10 cards.",tags:["EGG","RISK","PASSIVE"]},{id:"hatchingFeed",title:"Hatching Feed",rarity:"common",type:"instant",description:"EGG production interval -4%. Poop rate +3%. No card limit.",tags:["EGG","POOP","PASSIVE"]},{id:"poopRateBooster",title:"Poop Culture",rarity:"common",type:"instant",description:"Base poop rate +4 percentage points. No card limit.",tags:["POOP","PASSIVE"]},{id:"safetyCover",title:"Safety Cover",rarity:"common",type:"instant",description:"Explosion damage -5%. No card limit.",tags:["RISK","PASSIVE"]},{id:"preventiveMaintenance",title:"Preventive Maintenance Manual",rarity:"common",type:"instant",description:"All equipment deterioration speed -5%. No card limit.",tags:["MAINTENANCE","PASSIVE"]},{id:"dudFilter",title:"DUD Filter",rarity:"common",type:"instant",description:"DUD chance -5 percentage points. Stacks until DUD chance reaches 0%.",tags:["CARD","PASSIVE"]},{id:"durabilityCoating",title:"Durability Coating",rarity:"common",type:"instant",description:"All equipment maximum durability +3%. No card limit.",tags:["MAINTENANCE","PASSIVE"]},{id:"bearing",title:"High-Quality Bearing",rarity:"common",type:"instant",description:"Conveyor speed +7.5%.",tags:["CONVEYOR","PASSIVE"]},{id:"sparePartsBin",title:"SPARE PARTS BIN",rarity:"common",type:"instant",description:"Restores 2% durability to every machine. A box of almost-compatible parts.",tags:["MAINTENANCE","ACTIVE"]},{id:"dudRefund",title:"DUD REFUND",rarity:"common",type:"instant",description:"DUDs now come with paperwork. Gain JPY 50 per copy when you pick a DUD.",tags:["CARD","ECONOMY","PASSIVE"]},{id:"freeReroll",title:"FREE REROLL",rarity:"common",type:"instant",description:"The first bad ideas are free.",tags:["CARD","PASSIVE"]},{id:"composter",title:"COMPOSTER",rarity:"common",type:"instant",description:"Turns shredder waste into suspicious fertilizer. Gain JPY 3 per copy when SHREDDER processes poop.",tags:["POOP","ECONOMY","PASSIVE"]},{id:"scannerQueueSpacing",title:"Scanner Queue Spacing",rarity:"common",type:"instant",description:"Manual and Auto Scanner queue spacing -15%. No card limit.",tags:["SCANNER","PASSIVE"]},{id:"extraEggOutlet",title:"Extra Egg Outlet",rarity:"rare",type:"equipmentUpgrade",target:"eggOutlet",description:"Choose one EGG FARM and add +1 output port to that EGG. Max +3 per EGG.",tags:["EGG","RARE","ACTIVE"]},{id:"recyclingSubsidy",title:"Recycling Subsidy",rarity:"rare",type:"instant",description:"SELL refund rate +10 points. Max 3 cards; normal SELL can reach 80%.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"dynamite",title:"Dynamite",rarity:"rare",type:"cellAction",target:"blockedCell",description:"Remove any 3 unbuildable cells",tags:["RISK","RARE","ONE-SHOT"]},{id:"usedMachine",title:"Used Machines",rarity:"rare",type:"instant",description:"Future equipment costs half. New purchases have no refund and 60% durability. New Machines cancels it.",tags:["ECONOMY","RISK","RARE"]},{id:"newMachine",title:"New Machines",rarity:"common",type:"instant",description:"Cancel Used Machines and restore normal prices, refunds, and durability.",tags:["ECONOMY","ONE-SHOT"]},{id:"flattery",title:"Flattery",rarity:"rare",type:"instant",description:"Next Fairies tribute -50%.",tags:["ECONOMY","RARE","ONE-SHOT"]},{id:"extraCards",title:"Extra Cards",rarity:"rare",type:"instant",description:"Draw 2 cards now and choose both.",tags:["RARE","ACTIVE"]},{id:"legalWork",title:"Legal Work",rarity:"rare",type:"instant",description:"Fairies tribute profit exemption +JPY 250.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"chemicalWeaponSubsidy",title:"Chemical Weapons Subsidy",rarity:"ultraRare",type:"instant",description:"Each day, gain JPY 1200 per 70 poop shipped by truck. No card limit.",tags:["POOP","ULTRA RARE","PASSIVE"]},{id:"laborExploitation",title:"Motivational Exploitation",rarity:"ultraRare",type:"instant",description:"Repair room work time -30%. The repairman smiles with bloodshot eyes. One time only.",tags:["MAINTENANCE","ULTRA RARE","PASSIVE"]},{id:"rescueLoan",title:"Emergency Loan",rarity:"ultraRare",type:"instant",description:"If cash is below JPY 0 at day-end settlement, gain JPY 500. Consumed on use.",tags:["ECONOMY","ULTRA RARE","ONE-SHOT"]}],defaultEffects:{bearing:0,legalWork:0,fairiesFlatteryNext:0,autoScannerTuning:0,poopRateBooster:0,crowdedFarming:0,hatchingFeed:0,safetyCover:0,recyclingSubsidy:0,chemicalWeaponSubsidy:0,preventiveMaintenance:0,dudFilter:0,durabilityCoating:0,sparePartsBin:0,dudRefund:0,freeReroll:0,composter:0,scannerQueueSpacing:0,laborExploitation:0,usedMachineActive:!1,rescueLoanCharges:0},commonWeight:8,rareWeight:2,ultraRareWeight:.45,baseDraftSize:3,maxDudsPerDraft:2,dudChancePerCard:.3,dudChanceReductionPerFilter:.05,extraCardsAddedPicks:2,rerollCost:{dayDivisor:2,multiplier:100}},events:{eventChance:.1,firstTurn:8},maintenance:{fullPerformanceUntilWear:.5,minimumPerformance:.5,durability:{conveyor:1300,eggFarm:475,autoScanner:850,mixer:775,trash:950},processingDelayMaxSeconds:{mixer:1.2,trash:1},repairman:{secondsPerOnePercent:.5,walkSpeed:90}},facilities:{conveyor:{id:"conveyor",type:"conveyor",name:"Conveyor",shortName:"Belt",price:30,buildable:!0,upgradeable:!1},boostConveyor:{id:"boostConveyor",type:"conveyor",name:"Boost Conveyor",shortName:"BOOST BELT",price:75,buildable:!0,upgradeable:!1,speedMultiplier:2},eggFarm:{id:"eggFarm",type:"eggFarm",name:"Egg Farm",shortName:"EGG",price:250,buildable:!0,upgradeable:!0,maxLevel:4},manualScanner:{id:"manualScanner",type:"scanner",kind:"manual",name:"Manual Scanner",shortName:"Manual Scanner",price:260,buildable:!0,upgradeable:!1},autoScanner:{id:"autoScanner",type:"scanner",kind:"auto",name:"Auto Scanner",shortName:"Auto Scanner",price:180,buildable:!0,upgradeable:!1},mixer:{id:"mixer",type:"facility",name:"Mixer",shortName:"MIXER",price:450,buildable:!0,upgradeable:!0,incomeKey:"mixer",body:{w:164,h:126}},trash:{id:"trash",type:"facility",name:"Waste Shredder",shortName:"SHREDDER",price:240,buildable:!0,upgradeable:!0,body:{w:180,h:100}},truck:{id:"truck",type:"facility",name:"Truck",shortName:"TRUCK",price:450,buildable:!0,upgradeable:!0,incomeKey:"truck",body:{w:176,h:138}},maintenanceRoom:{id:"maintenanceRoom",type:"maintenanceRoom",name:"Maintenance Room",shortName:"REPAIR ROOM",price:220,buildable:!0,upgradeable:!1,footprint:{cols:2,rows:2}}}};var Pr=Y.version,gt=Y.time.daySeconds,an=Y.cash.starting,Ce=Y.economy,Ar=Y.time.farmShutdownGraceSeconds,xn=Y.production.autoScannerCooldown,Dr=Y.production.autoScannerUpgradeRate,ho=Y.production.autoScannerCardUpgradeRate||Y.production.autoScannerUpgradeRate,mo=Y.production.autoScannerMinCooldown,Ir=Y.events.eventChance,xt=Y.events.firstTurn,bo=Y.production.poopRate,vo=Y.production.poopRateCardBonus||0,Tn=Y.conveyor.baseSpeed,Wt=Y.conveyor.maxSpeed,En=Y.conveyor.bearingSpeedMultiplier,Ie=Y.cards,$r=Y.cards.definitions,wo=Y.cards.defaultEffects,lt=Y.production.eggSpawnRanges,f=Y.grid,ve=Y.facilities,So=["conveyor","boostConveyor","eggFarm","autoScanner","manualScanner","mixer","trash","truck","maintenanceRoom"],cn=["mixer","trash","truck"],Fr=["mixer","truck"],at=Object.fromEntries(Object.entries(ve).map(([e,t])=>[e,t.price])),de=[{name:"right",dc:1,dr:0,angle:0,opposite:"left"},{name:"left",dc:-1,dr:0,angle:Math.PI,opposite:"right"},{name:"down",dc:0,dr:1,angle:Math.PI/2,opposite:"up"},{name:"up",dc:0,dr:-1,angle:-Math.PI/2,opposite:"down"}],y={bg:"#111318",ink:"#090a0d",muted:"#8f9bab",green:"#7bd84f",greenSoft:"#273c24",mixerBlue:"#4aa3ff",truckPink:"#ffb33e",wasteGreen:"#88d35a",danger:"#e34a36",warn:"#ffb827",white:"#e6edf2",poop:"#7b4a23",male:"#4aa3ff",female:"#ff6fae"},Me={ambient:0,important:1,critical:2};function x(e){let t=Number(e)||0;return`${t<0?"-":""}\uFFE5${Math.ceil(Math.abs(t)).toLocaleString("ja-JP")}`}function A(e,t){return`${e},${t}`}function te(e){let[t,n]=String(e).split(",").map(Number);return{col:t,row:n}}function un(e,t,n){return Math.max(t,Math.min(n,e))}function W(e,t){return e+Math.random()*(t-e)}function Ee(e,t){return e>=0&&e=0&&tMath.round(un(r,0,255)).toString(16).padStart(2,"0");return`#${o(e)}${o(t)}${o(n)}`}function Kt(e,t,n){let o=Br(e),r=Br(t);return cl(ko(o.r,r.r,n),ko(o.g,r.g,n),ko(o.b,r.b,n))}var oe={appTitle:"Chick Sorter",versionTitle:`Chick Sorter ${Pr}`,currency:"\uFFE5",phases:{title:"Title",build:"Build",running:"Sorting",clearing:"Clearing",loanDecision:"Emergency Loan",gameover:"Game Over"},actions:{startGame:"Start Game",nextDay:"Next Day",buildPhase:"Build Phase",restart:"Restart",close:"Close",remove:"Remove",refund:"Refund",autoMenu:"Auto Menu"},status:{build:e=>`BUILD: ${(e==="erase"?"SELL":e||"SELECT").toUpperCase()} | Right-drag pan | Hover equipment for info`,sorting:"Sorting: use scanner keys. Build after clearing the day.",allPortsConnected:"Start condition met: one EGG route reaches an exit.",equipmentPanelEmpty:"Hover equipment in Build phase.",eventPanelRunning:"Forced events appear in Build phase."},routeLabels:{mixer:"MIXER",truck:"TRUCK",trash:"WASTE",scanner:"NEXT","scanner-role-1":"NEXT",input:"IN"},fail:{outOfGrid:"Out of grid",cellOccupied:"Cell occupied",notEnoughCash:"Not enough cash",facilityExists:"Facility already exists",facilityOverlap:"Facility overlap",nothingToErase:"Nothing to sell",noUpgrade:"No upgrade available"}};function ut(e){return ve[e]?.name||String(e||"").replace(/^[a-z]/,t=>t.toUpperCase())}function ul(e){let t=ve[e];return t?e==="conveyor"||e==="boostConveyor"?`${x(t.price)} / tile`:e==="autoScanner"?`${x(t.price)} / ${xn.toFixed(1)}s cooldown`:e==="trash"?x(t.price):x(t.price):""}function dl(e){return{conveyor:"A narrow green belt. Routes decide whether chicks live, ship, or become invoices.",boostConveyor:"Moves chicks twice as fast. Wears down like a normal belt.",eggFarm:"A tiny gatehouse producing questionable eggs on schedule.",autoScanner:"Slower than hands without upgrades.",manualScanner:"A manual checkpoint. The operator is the algorithm.",mixer:"Male chicks become revenue here. Do not feed it poop.",trash:"A polite shredder for poop and other regrets.",truck:"Ships the target cargo. Wrong cargo still leaves a paper trail.",maintenanceRoom:"2\xD72 repair bay. Each room dispatches one repairman during the day."}[e]||""}function Or(e){let t=dl(e);return`${ut(e)}${ul(e)}${t?`${t}`:""}`}function Nr(e){return oe.routeLabels[e]||String(e).toUpperCase()}function _r(e){let t=2166136261;for(let n=0;n>>0}function Gr(e){let t=e>>>0;return()=>{t+=1831565813;let n=Math.imul(t^t>>>15,1|t);return n^=n+Math.imul(n^n>>>7,61|n),((n^n>>>14)>>>0)/4294967296}}function Pn(){return`RUN-${Date.now().toString(36)}-${Math.floor(Math.random()*1e6).toString(36)}`.toUpperCase()}function Ur({seed:e,targetRatio:t=.2,reserved:n=[]}={}){let o=Gr(_r(e||Pn())),r=new Set(n.map(c=>typeof c=="string"?c:A(c.col,c.row))),i=[];for(let c=0;c0;c-=1){let b=Math.floor(o()*(c+1));[i[c],i[b]]=[i[b],i[c]]}let l=Math.round(f.cols*f.rows*t);return new Set(i.slice(0,Math.min(l,i.length)).map(c=>c.k))}function Wr({seed:e,colStart:t=0,colEnd:n=f.cols,rowStart:o=0,rowEnd:r=f.rows,targetRatio:i=.2,reserved:l=[]}={}){let c=Gr(_r(e||Pn())),b=new Set(l.map(X=>typeof X=="string"?X:A(X.col,X.row))),C=[],T=Math.max(0,Math.floor(t)),I=Math.max(T,Math.floor(n)),$=Math.max(0,Math.floor(o)),O=Math.max($,Math.floor(r));for(let X=$;X0;X-=1){let ae=Math.floor(c()*(X+1));[C[X],C[ae]]=[C[ae],C[X]]}let ee=Math.round((I-T)*(O-$)*i);return new Set(C.slice(0,Math.min(ee,C.length)).map(X=>X.k))}var Ht=10,Kr=2,Hr=1;function qt(e,t){return`${e},${t}`}function fl(e){let[t,n]=String(e).split(",").map(Number);return{chunkX:t,chunkY:n}}function An(e){let t=Y.grid.expansion||{},n=Math.max(1,(e.gridExpansionPurchases||0)+1),o=(t.costBase||1e3)*n*(t.costMultiplier||4/3),r=Math.max(1,t.truncateUnit||100);return Math.floor(o/r)*r}function qr(e){e.ownedCells=new Set,e.ownedChunks=new Set,e.gridChunkOriginY=0,e.gridExpansionPurchases=0,e.gridExpansionPurchasesByDirection={right:0,up:0};for(let t=0;t=0&&t=0&&n0)continue;let C=qt(b.chunkX,b.chunkY);t.has(C)||n.has(C)||n.set(C,Co(e,b.chunkX,b.chunkY,b.direction))}}return[...n.values()].sort((o,r)=>{let i=o.direction===r.direction?0:o.direction==="right"?-1:1;return i||(o.chunkY!==r.chunkY?o.chunkY-r.chunkY:o.chunkX-r.chunkX)})}function zr(e,t="right"){let n=Tt(e);return n.find(o=>o.direction===t)||n[0]||null}function Et(e){return{x:f.x+e.colStart*f.cell,y:f.y+e.rowStart*f.cell,w:e.cols*f.cell,h:e.rows*f.cell}}function Mo(e){let t=Et(e);return{x:t.x+t.w/2-116,y:t.y+t.h/2-36,w:232,h:72,cx:t.x+t.w/2,cy:t.y+t.h/2}}function Xr(e,t){let n=Mo(e);return t.x>=n.x&&t.x<=n.x+n.w&&t.y>=n.y&&t.y<=n.y+n.h}function Qr(e){let t=[];for(let n=e.rowStart;nEe(t.col,t.row))}function Sl(e){return[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}].filter(t=>Ee(t.col,t.row))}function kl(e){return[{col:e.col,row:e.row+1},{col:e.col-1,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row-1}].filter(t=>Ee(t.col,t.row))}function ni(e){let t=new Set([...e.conveyorTiles]),n=o=>{o&&Ee(o.col,o.row)&&t.add(A(o.col,o.row))};for(let o of e.scanners){for(let r of Sl(o))n(r);for(let r of wl(o))n(r)}for(let o of e.eggFarms){n(o);for(let r of kl(o))n(r)}for(let o of Object.values(e.facilities))n(o.entry);return t}function ei(e){let t=hl.map(([n,o])=>({col:n,row:o}));for(let{col:n,row:o}of t)ti(e,n,o);for(let n=0;n({...n,keys:n.keys?{left:{...n.keys.left},right:{...n.keys.right}}:null,queue:[]})),e.eggFarms=bl.map(n=>{let o=Rt(n);return{...n,nextSpawn:o,lastInterval:o}});let t=ni(e);e.blockedCells=Ur({seed:e.runSeed,targetRatio:Y.map.blockedRatio,reserved:[...t]}),Cl(e),ei(e),e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function Pt(e){return e?[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}]:[]}function ye(e){let t=B(e.col,e.row);return{x:t.x+f.cell/2,y:t.y}}function ft(e,t,n){return e.eggFarms.find(o=>o.col===t&&o.row===n)||null}function pt(e,t,n){return e.scanners.find(o=>Pt(o).some(r=>r.col===t&&r.row===n))||null}function At(e,t){return e.scanners.find(n=>n.id===t)||null}function Ro(e,t){return e.scanners.find(n=>n.kind==="manual"&&n.slot===t)||null}function Fn(e){return e?.baseId||e?.id||""}function Po(e,t){return Object.entries(e.facilities||{}).filter(([,n])=>Fn(n)===t)}function Re(e,t){return{inputA:{col:e.col,row:e.row-2},inputB:null,left:{col:e.col-1,row:e.row},right:{col:e.col+2,row:e.row}}[t]}function ii(e){return e?de.map(t=>({col:e.col+t.dc,row:e.row+t.dr})).filter(t=>Ee(t.col,t.row)):[]}function si(e,t,n=[],o=[]){if(!t||!Ee(t.col,t.row))return[];let r=[],i=l=>{!l||!Ee(l.col,l.row)||!e.conveyorTiles.has(A(l.col,l.row))||n.some(c=>c&&Rn(l,c))||r.some(c=>Rn(c,l))||r.push({...l,viaTolerance:!Rn(l,t)})};i(t);for(let l of o)i(l);for(let l of ii(t))i(l);return r}function oi(e,t,n=[],o=[]){let r=si(e,t,n,o),i=r.filter(l=>!l.viaTolerance);return i.length?i:r}function Ml(e,t){let n=Re(t,"inputA");return!n||!Ee(n.col,n.row)?[]:e.conveyorTiles.has(A(n.col,n.row))?[{...n,viaTolerance:!1}]:[]}function gl(e,t,n){let o=Re(t,n);return si(e,o,Pt(t))}function xl(e,t){let n=e.facilities[t]||Po(e,t)[0]?.[1];if(!n)return null;if(n.entry)return B(n.entry.col,n.entry.row);let o=Fn(n)||t;return o==="mixer"?{x:n.x+n.w,y:n.y+n.h*.52}:o==="truck"?{x:n.x,y:n.y+n.h*.52}:o==="trash"?{x:n.x+n.w/2,y:n.y+8}:{x:n.x+n.w/2,y:n.y+n.h/2}}function li(e,t,n){return n==="inputA"?Ml(e,t).length>0:gl(e,t,n).length>0}function me(e){e.branchCounters?.clear?.(),e.routeCache=null,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function $e(e,t){return A(e,t)}function Yt(e){return te(e)}function Tl(e,t){let n=e.conveyorMeta?.get?.(t)||{},o=[];return Array.isArray(n.outDirs)&&o.push(...n.outDirs),n.dir&&o.push(n.dir),[...new Set(o)].filter(r=>de.some(i=>i.name===r))}function El(e,t,n){let o=de.find(l=>l.name===n);if(!o)return!1;let r=e.conveyorMeta?.get?.($e(t.col+o.dc,t.row+o.dr));return r?[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))].includes(o.opposite):!1}function Rl(e,t){let n=Yt(t),o=e.conveyorMeta?.get?.(t)||{},r=de.filter(T=>e.conveyorTiles.has($e(n.col+T.dc,n.row+T.dr))).map(T=>T.name),i=Tl(e,t).filter(T=>r.includes(T)),l=i.length?i:r;if(r.length<3)return l;let c=new Set(r.filter(T=>El(e,n,T))),b=r.filter(T=>!c.has(T)),C=c.size&&b.length>=2?b:[...new Set(l)];return C.length<2&&(C=r),o.branchMode&&o.branchMode!=="random"&&C.includes(o.branchMode)?[o.branchMode]:C}function Pl(e){return{version:e.routingVersion||0,cells:new Set,adjacency:new Map,components:new Map,cellToComponent:new Map,scannerInputs:new Map,scannerPorts:new Map,facilityPorts:new Map,farmOutputs:new Map,pathCache:new Map,metrics:{conveyorCells:0,edges:0,components:0,deadEnds:0,crosses:0,scannerPorts:0,connectedScannerPorts:0,facilityPorts:0,connectedFacilityPorts:0,farmOutputs:0},issues:[]}}function Al(e){let t=Pl(e);for(let o of e.conveyorTiles)t.cells.add(o),t.adjacency.set(o,[]);for(let o of t.cells){let r=Yt(o),i=Rl(e,o),l=de.filter(c=>i.includes(c.name));for(let c of l){let b=$e(r.col+c.dc,r.row+c.dr);t.cells.has(b)&&t.adjacency.get(o).push({key:b,dir:c.name})}}let n=0;for(let[o,r]of t.adjacency.entries()){n+=r.length;let i=new Set(r.map(l=>l.dir));r.length===1&&(t.metrics.deadEnds+=1),r.length===4&&i.has("left")&&i.has("right")&&i.has("up")&&i.has("down")&&(t.metrics.crosses+=1)}return t.metrics.conveyorCells=t.cells.size,t.metrics.edges=Math.floor(n/2),Dl(t),Il(e,t),t.issues=Kl(e,t,{includeRoutes:!1}),t}function Dl(e){let t=1;for(let n of e.cells){if(e.cellToComponent.has(n))continue;let o=t++,r=[n],i=[];for(e.cellToComponent.set(n,o);r.length;){let l=r.shift();i.push(l);for(let c of e.adjacency.get(l)||[])e.cellToComponent.has(c.key)||(e.cellToComponent.set(c.key,o),r.push(c.key))}e.components.set(o,{id:o,cells:i,capacity:Math.max(1,i.length),count:0,ratio:0})}e.metrics.components=e.components.size}function Il(e,t){for(let n of e.scanners){let o={};for(let r of["inputA","left","right"]){let i=Re(n,r),l=r==="inputA"?i&&t.cells.has($e(i.col,i.row))?[{...i}]:[]:oi(e,i,Pt(n)).filter(C=>t.cells.has($e(C.col,C.row))),c=l.map(C=>$e(C.col,C.row)),b=c.length>0;if(o[r]={type:r,cell:i,cells:l,keys:c,key:c[0]||null,connected:b},t.metrics.scannerPorts+=1,b&&(t.metrics.connectedScannerPorts+=1),r==="inputA")for(let C of c)t.scannerInputs.set(C,n.id)}t.scannerPorts.set(n.id,o)}for(let[n,o]of Object.entries(e.facilities)){if(!o.entry)continue;let r=oi(e,o.entry).filter(c=>t.cells.has($e(c.col,c.row))),i=r.map(c=>$e(c.col,c.row)),l=i.length>0;t.facilityPorts.set(n,{id:n,cell:{...o.entry},cells:r,keys:i,key:i[0]||null,connected:l}),t.metrics.facilityPorts+=1,l&&(t.metrics.connectedFacilityPorts+=1)}for(let n of e.eggFarms){let o=ii({col:n.col,row:n.row}).map(r=>$e(r.col,r.row)).filter(r=>t.cells.has(r));t.farmOutputs.set(n.id,o),t.metrics.farmOutputs+=o.length}}function _e(e){let t=e.routingVersion||0;return(!e.factoryGraph||e.factoryGraph.version!==t)&&(e.factoryGraph=Al(e)),e.factoryGraph}function ai(e){let t=_e(e);return e.factoryGraphCommittedVersion=t.version,e.factoryGraphSnapshot=$l(t),t}function $l(e){return e?{version:e.version,conveyorCells:e.metrics.conveyorCells,edges:e.metrics.edges,components:e.metrics.components,deadEnds:e.metrics.deadEnds,crosses:e.metrics.crosses,scannerPorts:`${e.metrics.connectedScannerPorts}/${e.metrics.scannerPorts}`,facilityPorts:`${e.metrics.connectedFacilityPorts}/${e.metrics.facilityPorts}`,farmOutputs:e.metrics.farmOutputs,issues:[...e.issues||[]]}:null}function Fl(e,t){let n=t.col-e.col,o=t.row-e.row;return de.find(r=>r.dc===n&&r.dr===o)?.name||null}function Ao(e,t,n){let o=_e(e),r=$e(t.col,t.row);if(!o.cells.has(r))return[];let i=`${r}|${n.cacheKey||"dynamic"}`;if(n.cacheKey&&o.pathCache.has(i))return o.pathCache.get(i).map(se=>se.map(ie=>({...ie})));let l=`${r}|none`,c=[{key:r,col:t.col,row:t.row,incoming:"none",depth:0}],b=new Map([[l,0]]),C=new Map,T=[],I=1/0,$=8,O=24,ee=80;for(;c.length;){let se=c.shift();if(se.depth>I)break;let ie=`${se.key}|${se.incoming}`;if(n(se)){if(T.push(ie),I=se.depth,T.length>=O)break;continue}for(let P of o.adjacency.get(se.key)||[]){let G=Yt(P.key),H=Fl(se,G),be=se.depth+1;if(be>I)continue;let F=`${P.key}|${H}`,U=b.get(F);if(U==null)b.set(F,be),C.set(F,[ie]),c.push({key:P.key,col:G.col,row:G.row,incoming:H,depth:be});else if(U===be){let S=C.get(F)||[];S.length<$&&!S.includes(ie)&&S.push(ie),C.set(F,S)}}}let X=[],ae=(se,ie)=>{if(X.length>=ee)return;let[P]=se.split("|"),G=[Yt(P),...ie];if(se===l||P===r){X.push(G);return}for(let H of C.get(se)||[])ae(H,G)};for(let se of T)ae(se,[]);let he=[],re=new Set;for(let se of X){let ie=se.map(P=>$e(P.col,P.row)).join(">");re.has(ie)||(re.add(ie),he.push(se))}return n.cacheKey&&o.pathCache.set(i,he.map(se=>se.map(ie=>({...ie})))),he}function ci(e){let t=_e(e),n=new Map;for(let[o,r]of t.components.entries())n.set(o,{id:o,cells:[...r.cells],capacity:r.capacity,count:0,ratio:0});return{components:n,cellToComponent:new Map(t.cellToComponent)}}function ui(e,t,n){let o=_e(e),r=null,i=1/0;for(let l of o.cells){let c=te(l),b=B(c.col,c.row),C=Math.hypot(b.x-t,b.y-n);CB(o.col,o.row));return t&&n.push(t),n}function dt(e,t){t&&(!e.length||Lr(e[e.length-1],t)>1)&&e.push(t)}function Bl(e,t,n,o=null){let r=[{x:e.x,y:e.y}];dt(r,B(t.col,t.row));for(let i of Bn(n,o))dt(r,i);return r}function Ll(e,t){let n=Bn(e),o=Re(t,"inputA");return o&&dt(n,B(o.col,o.row)),dt(n,ye(t)),n}function Ol(e,t,n,o){let r=[{x:e.x,y:e.y}];dt(r,B(t.col,t.row));for(let l of Bn(n))dt(r,l);let i=Re(o,"inputA");return i&&dt(r,B(i.col,i.row)),dt(r,ye(o)),r}function Nl(e,t,n=0){let o=B(t.col,t.row),r=0;for(let i of e.chicks||[]){if(i.stage==="flying"||i.stage==="queued")continue;Math.hypot(i.x-o.x,i.y-o.y){let I=C.roleBias??0,$=T.roleBias??0;if(I!==$)return I-$;let O=C.cells?.length??C.route?.length??Number.POSITIVE_INFINITY,ee=T.cells?.length??T.route?.length??Number.POSITIVE_INFINITY;if(O!==ee)return O-ee;let X=C.key||JSON.stringify(C.route||C.cells||C),ae=T.key||JSON.stringify(T.route||T.cells||T);return X.localeCompare(ae)});if(!o||r.length===1)return r[0];let i=r[0].roleBias??0,l=r.filter(C=>(C.roleBias??0)===i),c=Math.min(...l.map(C=>ri(e,C)));l=l.filter(C=>ri(e,C)===c);let b=e.branchCounters.get(t)||0;return e.branchCounters.set(t,b+1),l[Math.floor(Math.random()*l.length)]}function di(e){return e.role===0?{left:{match:"male",destination:"mixer"},right:{match:"default",destination:"scanner-role-1"}}:{left:{match:"poop",destination:"trash"},right:{match:"default",destination:"truck"}}}function Do(e){let t=di(e);return{left:t.left.destination,right:t.right.destination}}function Io(e,t){return di(e).left.match===t.sex?"left":"right"}function $o(e){return Nr(e)}function Fo(e){return{mixer:"#2477ff",truck:"#ff6aa8",trash:"#22b94f","scanner-role-1":"#526456",scanner:"#526456",input:"#526456"}[e]||"#102015"}function Dt(e,t,n=!1){let o=_e(e),r=(o.farmOutputs.get(t.id)||[]).map(Yt),i=[];for(let b of r){let C=I=>o.scannerInputs.has($e(I.col,I.row));C.cacheKey=`farmInput:${b.col},${b.row}:v${o.version}`;let T=Ao(e,b,C);for(let I of T){let $=I[I.length-1],O=o.scannerInputs.get($e($.col,$.row)),ee=At(e,O);ee&&i.push({key:`${ee.id}:${$.col},${$.row}:${I.length}`,scanner:ee,cells:I})}}let l=$n(e,`farm:${t.id}`,i,n);if(l)return{scannerId:l.scanner.id,route:Ll(l.cells,l.scanner)};let c=$n(e,`farm:${t.id}:output`,r.map(b=>({key:A(b.col,b.row),cells:[b]})),n);return c?{scannerId:null,route:Bn(c.cells)}:null}function fi(e,t,n,o,r=!1){let i=At(e,o);if(!i)return null;let c=_e(e).scannerPorts.get(i.id)?.[t],b=Re(i,t),C=c?.connected?(c.keys||[c.key]).filter(Boolean).map(Yt):[];if(!b||!C.length)return null;let T=Do(i)[t];return T==="scanner-role-1"?_l(e,i,t,n,b,C,r):Gl(e,i,t,n,b,C,T,r)}function _l(e,t,n,o,r,i,l){let c=_e(e),b=e.scanners.filter(I=>I.id!==t.id&&c.scannerPorts.get(I.id)?.inputA?.connected),C=[];for(let I of i)for(let $ of b){let O=c.scannerPorts.get($.id)?.inputA?.key;if(!O)continue;let ee=(c.scannerPorts.get($.id)?.inputA?.keys||[O]).filter(Boolean),X=re=>ee.includes($e(re.col,re.row));X.cacheKey=`toScanner:${I.col},${I.row}:${$.id}:v${c.version}`;let ae=Ao(e,I,X),he=$.role===1?0:1;for(let re of ae)C.push({key:`${he}:start${A(I.col,I.row)}:s${$.id}:${re.length}:${A(re[re.length-1].col,re[re.length-1].row)}`,target:$,cells:re,roleBias:he})}let T=$n(e,`scanner:${t.id}:${n}:toRole1`,C,l);return T?{destination:"scanner",nextScannerId:T.target.id,route:Ol(o,r,T.cells,T.target)}:null}function Gl(e,t,n,o,r,i,l,c){let b=_e(e),C=[...b.facilityPorts.entries()].filter(([$,O])=>O?.connected&&Fn(e.facilities?.[$])===l);if(!C.length)return null;let T=[];for(let $ of i)for(let[O,ee]of C){let X=(ee.keys||[ee.key]).filter(Boolean);if(!X.length)continue;let ae=re=>X.includes($e(re.col,re.row));ae.cacheKey=`toFacility:${$.col},${$.row}:${O}:v${b.version}`;let he=Ao(e,$,ae);for(let re of he)T.push({key:`start${A($.col,$.row)}:${O}:${re.length}:${A(re[re.length-1].col,re[re.length-1].row)}`,cells:re,facilityId:O})}let I=$n(e,`scanner:${t.id}:${n}:${l}`,T,c);return I?{destination:l,facilityId:I.facilityId,route:Bl(o,r,I.cells,xl(e,I.facilityId))}:null}function pi(e,t,n=new Set){if(!t||n.has(t.id))return!1;n.add(t.id);for(let o of["left","right"]){let r=fi(e,o,ye(t),t.id,!1);if(r){if(["mixer","trash","truck"].includes(r.destination))return!0;if(r.destination==="scanner"){let i=At(e,r.nextScannerId);if(pi(e,i,n))return!0}}}return!1}function Ul(e,t){return!!Dt(e,t,!1)?.scannerId}function Ln(e){if(e.phase!=="build")return[];let t=[];for(let n of e.eggFarms||[])Ul(e,n)||t.push({type:"eggFarm",id:n.id,ref:n,message:"This Egg will not produce chicks"});for(let n of cn)for(let[o,r]of Po(e,n))_e(e).facilityPorts.get(o)?.connected||t.push({type:"facility",id:o,ref:r,message:"This facility cannot receive items"});return t}function Wl(e){let t=_e(e);for(let r of e.eggFarms||[]){let i=Dt(e,r,!1);if(!i?.scannerId)continue;let l=At(e,i.scannerId);if(pi(e,l))return[]}let n=e.eggFarms?.length||0,o=[...t.facilityPorts.entries()].filter(([r,i])=>i?.connected&&["mixer","trash","truck"].includes(Fn(e.facilities?.[r]))).length;return n?t.metrics.farmOutputs?e.scanners?.length?o?["Connect at least one EGG through a scanner to any valid exit."]:["Connect at least one receiver exit: Mixer, Shredder, or Truck."]:["Build at least one scanner and connect it to an EGG route."]:["Connect at least one EGG to a conveyor."]:["Build at least one EGG before starting the next day."]}function In(e){return e.kind==="manual"?`S${(e.slot??0)+1}`:`Auto Scanner #${e.id}`}function Kl(e,t=_e(e),n={}){let o=n.includeRoutes!==!1,r=[],i={mixer:"Mixer",trash:"Shredder",truck:"Truck"};for(let l of cn){let c=Po(e,l);if(!c.length){r.push(`${i[l]||l} is missing`);continue}for(let[b]of c)t.facilityPorts.get(b)?.connected||r.push(`${i[l]||l} receiver has no conveyor`)}for(let l of e.scanners){let c=t.scannerPorts.get(l.id)||{};if(c.inputA?.connected||r.push(`${In(l)} input has no conveyor`),c.left?.connected||r.push(`${In(l)} left output has no conveyor`),c.right?.connected||r.push(`${In(l)} right output has no conveyor`),!!o)for(let b of["left","right"])c[b]?.connected&&!fi(e,b,ye(l),l.id)&&r.push(`${In(l)} ${b} route is incomplete`)}if(o)for(let l of e.eggFarms)Dt(e,l)?.scannerId||r.push(`Egg Farm #${l.id} has no scanner route`);else for(let l of e.eggFarms)(t.farmOutputs.get(l.id)||[]).length||r.push(`Egg Farm #${l.id} has no output conveyor`);return[...new Set(r)]}function fn(e){return Wl(e)}function yi(e){return fn(e).length===0}var hi=[{key:"premiumFemaleShipment",target:"female",truckTarget:"female",title:"Premium Female Shipment",route:"Female -> Truck",note:"Today only: ship female chicks to Truck. Meet the export target for a bonus.",objective:"truckTarget"},{key:"contaminantSampleExport",target:"poop",truckTarget:"poop",title:"Contaminant Sample Export",route:"Poop value x2",note:"Today only: poop is valid Truck cargo and all poop income is doubled.",objective:"truckTarget",poopValueMultiplier:2},{key:"healthInspection",title:"Health Inspection",route:"Poop -> Shredder",note:"Today only: poop mistakes are fined double. Shred enough poop for an inspection bonus.",objective:"poopTrash",poopFineMultiplier:2},{key:"conveyorJamWarning",title:"Conveyor Jam Warning",route:"No explosions",note:"Today only: jam explosions trigger at 85% congestion. Finish with zero explosions for a bonus.",objective:"noExplosion",congestionExplosionThreshold:.85,congestionWarningThreshold:.68},{key:"powerSavingOrder",title:"Power Saving Order",route:"Slow factory subsidy",note:"Today only: conveyors -20% speed and Auto Scanners +20% cooldown. A subsidy is paid at settlement.",objective:"flatBonus",conveyorSpeedMultiplier:.8,autoScannerCooldownMultiplier:1.2},{key:"overtimeDay",title:"Overtime Day",route:"80 second day",note:"Today only: the work day is longer. No extra reward or penalty.",objective:"none",daySeconds:80},{key:"shortShift",title:"Short Shift",route:"40 second day",note:"Today only: the work day is shorter. The next Fairies tribute is reduced by 10%.",objective:"none",daySeconds:40,fairiesTributeMultiplier:.9},{key:"chickBoom",title:"Chick Boom",route:"EGG interval x0.65",note:"Today only: eggs hatch faster and poop rate rises by 5 percentage points.",objective:"none",productionMultiplier:1/.65,poopRateAdd:.05},{key:"rottenFeed",title:"Rotten Feed",route:"Poop surge",note:"Today only: poop rate rises by 20 percentage points and Shredder poop income is multiplied by 1.5.",objective:"none",poopRateAdd:.2,shredderIncomeMultiplier:1.5},{key:"maintenanceAudit",title:"Maintenance Audit",route:"Durability check",note:"Today only: machines below 50% remaining durability fail the audit. Passing with none below 50% pays a bonus.",objective:"maintenanceAudit"}];function we(e,t=0){let n=Number(e);return Number.isFinite(n)?n:t}function Hl(e,t=0,n=1){let o=Math.max(1,Number(e?.turn||1)+1),r=Math.floor(Bo(e)*(.08+Math.random()*.08)),i=Math.floor(Math.max(0,e.cash||0)*.25),l=Math.floor(Math.max(0,t)*Math.max(1,o)*.75);return Math.max(120,Math.ceil(Math.max(r,i,l)*n))}function mi(e){return Math.max(0,Math.ceil(500+Math.max(1,e?.turn||1)*25))}function Bo(e){return[...e.eggFarms.map(t=>t.price||0),...e.scanners.map(t=>t.price||0),...Object.values(e.facilities).map(t=>t.price||0),...[...e.conveyorMeta.values()].map(t=>t.price||0)].reduce((t,n)=>t+n,0)}function ql(e,t=1,n=gt){return e.eggFarms.reduce((o,r)=>{let[i,l]=dn(r),c=Math.max(.1,(i+l)/2);return o+Math.max(1,n)/c*Math.max(.01,t||1)},0)}function Yl(e,t){let n=we(t.productionMultiplier,1),o=we(t.daySeconds,gt),r=ql(e,n,o),i=Math.max(0,Number(e?.cardEffects?.hatchingFeed)||0),l=Math.max(0,Number(e?.cardEffects?.poopRateBooster)||0),c=Math.pow(1.03,i),b=bo+vo*l,C=Math.min(.95,Math.max(0,(b+we(t.poopRateAdd,0))*we(t.poopMultiplier,1)*c));return{estimate:r,poopRate:C}}function bi(e){if(e.turn+1Ir)return null;let n=hi[Math.floor(Math.random()*hi.length)],{estimate:o,poopRate:r}=Yl(e,n),i=0;n.objective==="truckTarget"?i=Math.max(1,Math.ceil(o*.3)):n.objective==="poopTrash"&&(i=Math.max(1,Math.ceil(o*r*.8)));let l=0;return["truckTarget","poopTrash","noExplosion"].includes(n.objective)&&(l=Hl(e,o)),n.objective==="flatBonus"&&(l=mi(e)),n.objective==="maintenanceAudit"&&(l=mi(e)),{id:`event-${e.turn}-${Date.now()}-${Math.floor(Math.random()*9999)}`,...n,target:n.target||null,truckTarget:n.truckTarget||null,forced:!0,productionMultiplier:we(n.productionMultiplier,1),poopMultiplier:we(n.poopMultiplier,1),poopRateAdd:we(n.poopRateAdd,0),daySeconds:we(n.daySeconds,gt),targetAmount:i,estimatedOutput:Math.round(o),reward:l,createdTurn:e.turn,oneTurnOnly:!0}}function vi(e){e.eventActive=e.eventOffer?{...e.eventOffer}:null,e.eventOffer=null}function wi(e){e.eventActive=null}function Si(e){return Math.max(1,we(e.eventActive?.daySeconds,gt))}function ki(e){return we(e.eventActive?.productionMultiplier,1)}function Ci(e){let t=Math.max(0,Number(e?.cardEffects?.hatchingFeed)||0),n=Math.max(0,Number(e?.cardEffects?.poopRateBooster)||0),o=Math.pow(1.03,t),r=bo+vo*n,i=we(e.eventActive?.poopRateAdd,0);return Math.min(.95,Math.max(0,(r+i)*we(e.eventActive?.poopMultiplier,1)*o))}function je(e){return e.eventActive?.truckTarget||e.eventActive?.target||"female"}function Lo(e,t){return t==="male"?e.truckMale||0:t==="poop"?e.poopTruck||0:e.truckFemale||0}function Mi(e,t){return je(e)===t}function gi(e){return je(e)!=="male"}function Oo(e){return Math.max(.01,we(e.eventActive?.poopValueMultiplier,1))}function On(e){return Math.max(.01,Oo(e)*we(e.eventActive?.shredderIncomeMultiplier,1))}function No(e){return Math.max(.01,we(e.eventActive?.poopFineMultiplier,1))}function _o(e){return Math.max(.1,Math.min(1,we(e.eventActive?.congestionExplosionThreshold,1)))}function xi(e){return Math.max(.1,Math.min(1,we(e.eventActive?.congestionWarningThreshold,.8)))}function Ti(e){return Math.max(.01,we(e?.fairiesTributeMultiplier,1))}function Vl(e){let t=0,n=(o,r)=>{let i=Math.max(1,we(r,1)),l=Math.max(0,we(o,0));1-Math.min(1,l/i)<.5&&(t+=1)};for(let o of e.conveyorMeta?.values?.()||[])n(o.uses,o.durability);for(let o of e.eggFarms||[])n(o.maintenance?.uses,o.maintenance?.durability);for(let o of e.scanners||[])o.kind==="auto"&&n(o.maintenance?.uses,o.maintenance?.durability);for(let o of Object.values(e.facilities||{})){let r=o?.baseId||o?.id;(r==="mixer"||r==="trash")&&n(o.maintenance?.uses,o.maintenance?.durability)}return t}function Ei(e){let t=e.eventActive;if(!t)return null;let n=0,o=!0,r=0,i="";t.objective==="truckTarget"?(n=Lo(e.stats,t.target),o=n>=t.targetAmount,r=o?t.reward:0):t.objective==="poopTrash"?(n=e.stats.poopTrash||0,o=n>=t.targetAmount,r=o?t.reward:0):t.objective==="noExplosion"?(n=e.stats.explosions||0,o=n===0,r=o?t.reward:0,i=`${n} explosion(s)`):t.objective==="flatBonus"?(o=!0,r=t.reward):t.objective==="maintenanceAudit"?(n=Vl(e),o=n===0,o&&(r=t.reward),i=`${n} machine(s) below 50%`):o=!0,r>0?(Ge(e,r),e.stats.eventBonus=(e.stats.eventBonus||0)+r,e.totals.eventBonus+=r,e.totals.eventSuccess+=1):t.objective&&t.objective!=="none"&&(e.stats.eventBonus=e.stats.eventBonus||0,e.totals.eventFailed+=o?0:1,o&&(e.totals.eventSuccess+=1));let l={title:t.title,key:t.key,target:t.target,route:t.route,objective:t.objective,targetAmount:t.targetAmount||0,count:n,success:o,bonus:r,reward:t.reward||0,productionMultiplier:t.productionMultiplier,poopMultiplier:t.poopMultiplier,daySeconds:t.daySeconds,detail:i};return e.stats.eventResult=l,l}function Go(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function zl(e){return!!e?.cardEffects?.usedMachineActive}function Xl(e,t){return t?1:Math.min(.8,.5+.1*Math.min(3,Go(e,"recyclingSubsidy")))}function Ql(e){return Math.pow(.95,Go(e,"safetyCover"))}function Nn(e){let t=e?.ref||e||{},n=e?.type||t.type;return n==="conveyor"?t.price||ve[t.kind]?.price||ve.conveyor.price:n==="eggFarm"?t.price||ve.eggFarm.price:n==="scanner"?t.price||(t.kind==="auto"?ve.autoScanner.price:ve.manualScanner.price):n==="facility"?t.price||ve[t.id]?.price||0:n==="maintenanceRoom"?t.price||ve.maintenanceRoom.price:ve[t.id]?.price||0}function Oe(e,t=null){let n=ve[e]?.price||0;return zl(t)?Math.ceil(n*.5):n}function Jl(e,t){return e?.facilities?Object.values(e.facilities).filter(n=>(n?.baseId||n?.id)===t).reduce((n,o)=>n+Math.max(0,(o.level||1)-1),0):0}function yt(e,t){return Fr.includes(t)?Math.pow(Ce.incomeUpgradeRate,Jl(e,t)):1}function ze(e){return Math.ceil(Ce.income.mixer*yt(e,"mixer"))}function Fe(e){return Math.ceil(Ce.income.truck*yt(e,"truck"))}function pn(e){return Math.ceil(Ce.poopFine*yt(e,"mixer")*No(e))}function yn(e){return Math.ceil(Ce.poopFine*yt(e,"truck")*No(e))}function Uo(e){let t=Ce.maleTruckFinePerHalfDay*(e.turn/2);return Math.ceil(t*yt(e,"truck"))}function Wo(e){return e?.facilities?Object.values(e.facilities).filter(t=>(t?.baseId||t?.id)==="trash").reduce((t,n)=>t+Math.max(0,(n.level||1)-1),0):0}function It(e){return Math.min(Ce.shredderBonus.maxCards,Wo(e))}function Vt(){return Ce.shredderBonus.maxCards}function ht(e){let t=typeof e=="number"?e:It(e),n=Math.min(Ce.shredderBonus.maxCards,Math.max(0,t));return n>0?Math.ceil(n*(Ce.shredderBonus.incomePerUpgrade||1)):0}function jl(e){let t=It(e),n=ht(t),o=Math.ceil(n*On(e));return{cards:t,chance:o>0?1:0,amount:o,expected:o,baseAmount:n}}function Ri(e){let t=jl(e);return t.amount>0&&(e.stats.shredderBonus=(e.stats.shredderBonus||0)+t.amount,e.totals.shredderBonus=(e.totals.shredderBonus||0)+t.amount,Ge(e,t.amount)),t}function _n(e,t=e.turn,n=null){let o=Math.max(1,Math.floor(Number(t)||1)),r=Ce.fairiesTribute||{perDay:10,profitExemption:300,legalWorkExemptionBonus:250,profitRate:.12},i=Math.ceil(o*(r.perDay||10)),l=Math.max(0,Math.floor(Number(n??e?.lastResult?.profit??e?.stats?.profit??0)||0)),c=Math.max(0,e?.cardEffects?.legalWork||0),b=Math.max(0,(r.profitExemption||0)+c*(r.legalWorkExemptionBonus||0)),C=Math.max(0,l-b),T=Math.ceil(C*Math.max(0,Number(r.profitRate)||0)),I=i+T,$=Math.max(0,e?.cardEffects?.fairiesFlatteryNext||e?.cardEffects?.flattery||0),O=$>0?Math.pow(.5,$):1,ee=Math.max(.01,Number(e?.pendingFairiesTributeMultiplier)||1),X=O*ee,ae=Math.max(0,Math.ceil(I*X)),he=Math.max(0,I-ae);return{day:o,base:i,profit:l,legalWork:c,profitExemption:b,taxableProfit:C,profitTribute:T,gross:I,flatteryCount:$,eventMultiplier:ee,perCardReduction:Math.ceil(I*.5),reduction:he,amount:ae}}function mt(e,t){let n=e?.ref||e||{},o=e?.type==="conveyor"?t?.conveyorMeta?.get(e.oldKey||n.id):n,r=o?.price||Nn(e||n),i=o?.builtSession===t?.buildSession;if(o?.noRefund||n?.noRefund)return{amount:0,sameBuild:i,price:r,rate:0,noRefund:!0};let l=Xl(t,i);return{amount:Math.max(0,Math.ceil(r*l)),sameBuild:i,price:r,rate:l,noRefund:!1}}function Zl(e,t=null){let n=Math.max(1,Math.ceil((Number(e)||0)/Ce.explosionDamageDivisor));return Math.max(1,Math.ceil(n*Ql(t)))}function ea(e,t){return Math.max(0,Math.ceil(t))}function Pi(e,t){e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,t>=0?(e.stats.revenue+=t,e.totals.revenue+=t):(e.stats.penalty+=Math.abs(t),e.totals.penalty+=Math.abs(t)),e.totals.maxCash=Math.max(e.totals.maxCash,e.cash)}function Ge(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&Pi(e,n),n}function bt(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&Pi(e,-n),n}function $t(e,t){bt(e,t)}function Ai(e,t){t<=0||(e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,e.totals.maxCash=Math.max(e.totals.maxCash,e.cash))}function Di(e){let t=ze(e);return e.stats.mixerRevenue+=t,Ge(e,t),t}function Ii(e){let t=pn(e);return e.stats.mixerPoopFine+=t,e.totals.mixerPoopFine+=t,bt(e,t),t}function $i(e){let t=yn(e);return e.stats.truckPoopFine+=t,e.totals.truckPoopFine+=t,bt(e,t),t}function Fi(e){let t=Uo(e);return e.stats.maleTruckFine+=t,e.totals.maleTruckFine+=t,bt(e,t),t}function Bi(e,t){let n=Zl(t,e);return e.stats.explosionDamage+=n,e.totals.explosionDamage+=n,bt(e,n),n}function Li(e){let t=je(e),n=Lo(e.stats,t),o=t==="poop"?Math.ceil(Fe(e)*Oo(e)):Fe(e),r=n*o,i=ea(e,r);return e.stats.pendingTruckRevenue=i,e.stats.truckRevenue=i,t==="poop"?e.stats.poopShipmentIncome=i:e.stats.chickShipmentIncome=i,i>0&&Ge(e,i),{base:r,adjusted:i,target:t,targetCount:n,unitPrice:o}}function Oi(e,t=e.turn,n=null,o={}){let r=_n(e,t,n);return e.cardEffects&&(e.cardEffects.fairiesFlatteryNext=0,e.cardEffects.flattery!=null&&delete e.cardEffects.flattery),e.pendingFairiesTributeMultiplier!=null&&(e.pendingFairiesTributeMultiplier=1),r.amount<=0||(o.recordStats?(e.stats.fairiesTribute=(e.stats.fairiesTribute||0)+r.amount,e.totals.fairiesTribute=(e.totals.fairiesTribute||0)+r.amount,bt(e,r.amount)):(e.totals.fairiesTribute=(e.totals.fairiesTribute||0)+r.amount,e.totals.penalty=(e.totals.penalty||0)+r.amount,e.totals.profit=(e.totals.profit||0)-r.amount,e.cash-=r.amount)),r}function Ni(e){let t=Go(e,"chemicalWeaponSubsidy"),n=Math.max(0,e?.stats?.poopTruck||0),o=Ce.chemicalWeaponSubsidy||{poopPerBlock:70,yenPerBlock:1200},r=Math.floor(n/Math.max(1,o.poopPerBlock||70)),i=t>0&&r>0?r*Math.max(0,o.yenPerBlock||1200)*t:0;return i>0&&(e.stats.chemicalWeaponSubsidy=(e.stats.chemicalWeaponSubsidy||0)+i,e.totals.chemicalWeaponSubsidy=(e.totals.chemicalWeaponSubsidy||0)+i,Ge(e,i)),{cards:t,poopTruck:n,blocks:r,amount:i}}function _i(e){let t=Bo(e),n=Math.max(1,e.totals.turnsCompleted||e.turn||1),o=Math.max(0,e.cash+e.totals.revenue+t*.5+e.totals.eventBonus*.5),r=Math.ceil(o/n),i=Math.floor(n*35+Math.max(0,n-5)*15),l=e.totals.correct*5,c=e.totals.explosionDamage;return{score:Math.max(0,Math.floor(o+r+l-e.totals.penalty-i)),factoryValue:t,base:o,dailyEarned:r,dayPenalty:i,correctBonus:l,explosionPenalty:c,days:n}}function ta(e){return{...e,keys:e.keys?{left:{...e.keys.left},right:{...e.keys.right}}:null,queue:[],cooldown:e.cooldown||0}}function hn(e){return JSON.stringify({cash:e.cash,stats:e.stats,totals:e.totals,nextId:e.nextId,gridX:f.x,gridY:f.y,gridCols:e.gridCols||f.cols,gridRows:e.gridRows||f.rows,gridExpansionPurchases:e.gridExpansionPurchases||0,gridExpansionPurchasesByDirection:e.gridExpansionPurchasesByDirection||{right:0,up:0},gridChunkOriginY:e.gridChunkOriginY||0,ownedCells:[...e.ownedCells||[]],ownedChunks:[...e.ownedChunks||[]],blockedCells:[...e.blockedCells||[]],selected:e.selected,multiSelected:e.multiSelected||[],buildTool:e.buildTool,view:e.view,facilities:e.facilities,eggFarms:e.eggFarms,scanners:e.scanners.map(ta),conveyorTiles:[...e.conveyorTiles],conveyorMeta:[...e.conveyorMeta.entries()],branchCounters:[...e.branchCounters.entries()],cardEffects:e.cardEffects,cardDraft:e.cardDraft,cardTargetPick:e.cardTargetPick})}function Gi(e,t){let n=JSON.parse(t);e.cash=n.cash,e.stats=n.stats,e.totals=n.totals,e.nextId=n.nextId,f.x=n.gridX??Y.grid.x,f.y=n.gridY??Y.grid.y,f.cols=n.gridCols||Y.grid.cols,f.rows=n.gridRows||Y.grid.rows,e.gridCols=f.cols,e.gridRows=f.rows,e.gridExpansionPurchases=n.gridExpansionPurchases||0,e.gridExpansionPurchasesByDirection=n.gridExpansionPurchasesByDirection||{right:0,up:0},e.gridChunkOriginY=n.gridChunkOriginY||0,e.ownedCells=new Set(n.ownedCells||[]),e.ownedChunks=new Set(n.ownedChunks||[]),e.gridOwnedCells=e.ownedCells.size||f.cols*f.rows,e.blockedCells=new Set(n.blockedCells||[]),e.selected=n.selected,e.multiSelected=n.multiSelected||[],e.buildTool=n.buildTool,e.view=n.view||{x:0,y:0,scale:1},e.view.scale==null&&(e.view.scale=1),e.facilities=n.facilities||{},e.eggFarms=n.eggFarms||[],e.scanners=(n.scanners||[]).map(o=>({...o,queue:[],cooldown:o.cooldown||0})),e.conveyorTiles=new Set(n.conveyorTiles||[]),e.conveyorMeta=new Map(n.conveyorMeta||[]),e.branchCounters=new Map(n.branchCounters||[]),e.cardEffects=n.cardEffects||{bearing:0,legalWork:0,fairiesFlatteryNext:0,scannerQueueSpacing:0},e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft=n.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardTargetPick=n.cardTargetPick||null,e.groupDrag=null,e.selectionBox=null,e.pan=null,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function Be(e){e.phase==="build"&&(e.undoStack.push(hn(e)),e.undoStack.length>80&&e.undoStack.shift(),e.redoStack=[])}function Ko(e){return e.phase!=="build"||!e.undoStack.length?!1:(e.redoStack.push(hn(e)),Gi(e,e.undoStack.pop()),!0)}function Ho(e){return e.phase!=="build"||!e.redoStack.length?!1:(e.undoStack.push(hn(e)),Gi(e,e.redoStack.pop()),!0)}function K(e,t,n,o,r=y.ink){e.floatingTexts.push({x:t,y:n,text:o,color:r,life:1,maxLife:1})}function Ft(e,t,n){e.shake.strength=Math.max(e.shake.strength,t),e.shake.time=Math.max(e.shake.time,n)}function Ui(e,t,n){e.effects.push({type:"spawn",priority:Me.ambient,x:t,y:n,life:.42,maxLife:.42,size:12})}function Wi(e,t,n,o=y.green){e.effects.push({type:"scannerPulse",priority:Me.important,x:t,y:n,color:o,life:.42,maxLife:.42,size:24})}function Ki(e,t,n){for(let o=0;o<12;o+=1)e.effects.push({type:"meat",priority:Me.important,x:t+W(-18,18),y:n+W(-12,16),vx:W(-60,60),vy:W(-90,-25),life:W(.45,.85),maxLife:.85,size:W(4,8)})}function Hi(e,t,n){for(let o=0;o<16;o+=1)e.effects.push({type:"sludge",priority:Me.important,x:t+W(-18,18),y:n+W(-12,16),vx:W(-46,46),vy:W(-70,-20),life:W(.45,.9),maxLife:.9,size:W(4,8)})}function qi(e,t,n,o){let r=o==="poop"?y.poop:o==="male"?y.male:y.female;for(let i=0;i<22;i+=1)e.effects.push({type:"shred",priority:Me.important,x:t+W(-16,16),y:n+W(-8,8),vx:W(-70,70),vy:W(40,160),color:i%3===0?y.white:r,life:W(.45,.95),maxLife:.95,w:W(3,7),h:W(10,24),rot:W(-Math.PI,Math.PI)});Xe(e,t,n,y.green,34,Me.important)}function Yi(e,t,n,o){let r=o==="poop"?y.poop:o==="male"?y.danger:y.green;for(let i=0;i<8;i+=1)e.effects.push({type:"load",priority:Me.important,x:t+W(-18,18),y:n+W(-18,18),vx:W(-42,42),vy:W(-90,-25),color:r,life:W(.35,.65),maxLife:.65,size:8})}function Xe(e,t,n,o=y.danger,r=52,i=Me.critical){e.effects.push({type:"shockwave",priority:i,x:t,y:n,color:o,life:.55,maxLife:.55,size:8,maxSize:r})}function Ze(e,t,n,o=12,r=y.danger,i=Me.critical){for(let l=0;l0&&(e.shake.time=Math.max(0,e.shake.time-t),e.shake.time<=0&&(e.shake.strength=0));for(let r of e.effects)if(r.life-=t,["meat","sludge","spark","smoke","shred","load","rage"].includes(r.type))r.x+=(r.vx||0)*t,r.y+=(r.vy||0)*t,r.vy=(r.vy||0)+150*t;else if(r.type==="flyingChick"){r.x+=r.vx*t,r.y+=r.vy*t,r.vy+=360*t,r.noDamage||na(e,r,o);let i=r.x+e.view.x,l=r.y+e.view.y;(i<-100||l<-100||i>n.width+100||l>n.height+100)&&(r.life=0)}e.effects=e.effects.filter(r=>r.life>0);for(let r of e.floatingTexts)r.life-=t,r.y-=34*t;e.floatingTexts=e.floatingTexts.filter(r=>r.life>0)}function na(e,t,n){t.hit||(t.hit=new Set);for(let o of n()){if(t.hit.has(o.id)||t.xo.x+o.w||t.yo.y+o.h)continue;t.hit.add(o.id);let r=Bi(e,o.price);K(e,t.x,t.y-10,`-${x(r)}`,y.danger),Xe(e,t.x,t.y,y.danger,30),Ze(e,t.x,t.y,5,y.danger),Ft(e,5,.18)}}var Ue=Y.maintenance;function Yo(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function Wn(e){let t=Math.min(1.4,1+.04*Math.min(10,Yo(e,"crowdedFarming"))),n=Math.pow(.95,Yo(e,"preventiveMaintenance"));return t*n}function oa(e){return Math.pow(1.03,Yo(e,"durabilityCoating"))}function Kn(e,t,n=1){let o=Ue.durability[t]||1e3;return Math.max(1,Math.ceil(o*Math.max(.1,n||1)*oa(e)))}function Xi(e){return Math.max(.1,Number(e?.durabilityBaseMultiplier)||1)}function ra(e,t=0){if(!e)return{x:f.x+f.cell*(.5+t*.55),y:f.y+f.rows*f.cell+84};let n=f.x+e.col*f.cell+f.cell,o=f.y+e.row*f.cell+f.cell;return{x:n,y:o}}function ia(e,t=0){let n=(e.maintenanceRooms||[])[t];return ra(n,t)}function Se(e){e.repairman||(e.repairman={active:!1,x:f.x+f.cell*.5,y:f.y+f.rows*f.cell+84,target:null,repairedToday:0}),Array.isArray(e.maintenanceRooms)||(e.maintenanceRooms=[]),Array.isArray(e.repairmen)||(e.repairmen=[]);for(let[t,n]of e.conveyorMeta||[]){n.uses==null&&(n.uses=0),n.maintenanceType==null&&(n.maintenanceType="conveyor"),n.kind||(n.kind="conveyor"),n.speedMultiplier||(n.speedMultiplier=n.kind==="boostConveyor"?2:1),n.branchMode||(n.branchMode="random");let o=Kn(e,"conveyor",Xi(n));(n.durability==null||n.durability0&&(n.processingCooldown=Math.max(0,n.processingCooldown-t))}function vn(e){Se(e);let t=[];for(let[n,o]of e.conveyorMeta||[])t.push({type:"conveyor",key:n,meta:o,label:`${o.kind==="boostConveyor"?"Boost Belt":"Belt"} ${n}`,center:B(te(n).col,te(n).row)});for(let n of e.eggFarms||[])t.push({type:"eggFarm",ref:n,label:`EGG #${n.id}`,center:B(n.col,n.row)});for(let n of(e.scanners||[]).filter(o=>o.kind==="auto"))t.push({type:"autoScanner",ref:n,label:`AUTO #${n.id}`,center:B(n.col,n.row)});for(let n of Object.values(e.facilities||{})){let o=Vn(n);["mixer","trash"].includes(o)&&t.push({type:o,ref:n,label:`${n.shortName||n.name||o} #${n.id}`,center:{x:n.x+n.w/2,y:n.y+n.h/2}})}return t}function Bt(e){return e.meta?zt(e):zt(e.ref)}function mn(e){return e.meta?Vo(e):Vo(e.ref)}function Un(e){return e.meta?zo(e):zo(e.ref)}function es(e,t){sa(e.meta?e:e.ref,Math.max(0,mn(e)-t))}function nr(e){return e.type==="conveyor"?`conveyor:${e.key}`:`${e.type}:${e.ref?.id||e.ref?.type||e.type}`}function ts(e,t=.02){Se(e);let n=Math.max(0,Number(t)||0),o=0;for(let r of vn(e)){let i=mn(r);es(r,Un(r)*n),o+=Math.max(0,i-mn(r))/Un(r)*100}return o}function ns(e){Se(e);let t=e.maintenanceRooms||[];e.repairmen=t.map((o,r)=>{let i=ia(e,r);return{id:`room-${o.id}`,roomId:o.id,active:!0,x:i.x,y:i.y,target:null,repairedToday:0}});let n=e.repairmen[0];e.repairman.active=!!n,e.repairman.target=n?.target||null,e.repairman.repairedToday=0,n&&(e.repairman.x=n.x,e.repairman.y=n.y)}function os(e){Se(e);for(let t of e.repairmen||[])t.active=!1,t.target=null;e.repairmen=[],e.repairman.active=!1,e.repairman.target=null}function aa(e,t){return t&&vn(e).find(o=>nr(o)===t.key)||null}function ca(e){let t=null;for(let n of vn(e)){let o=Bt(n);o<=.001||(!t||o>Bt(t))&&(t=n)}return t}function rs(e,t){Se(e);let n=e.repairmen?.length?e.repairmen:e.repairman?.active?[e.repairman]:[];if(!n.length||e.phase!=="running")return;let o=new Set(n.map(i=>i.target?.key).filter(Boolean));for(let i of n)ua(e,i,t,o);let r=n[0];r&&e.repairman!==r&&(e.repairman.active=!0,e.repairman.x=r.x,e.repairman.y=r.y,e.repairman.target=r.target,e.repairman.repairedToday=r.repairedToday||0)}function ua(e,t,n,o){if(!t.active)return;let r=aa(e,t.target);if((!r||Bt(r)<=.001)&&(t.target?.key&&o.delete(t.target.key),r=da(e,o)),!r){t.target=null;return}let i=nr(r);o.add(i),t.target={key:i,label:r.label};let l=Ue.repairman.walkSpeed,c=r.center.x-t.x,b=r.center.y-t.y,C=Math.hypot(c,b);if(C>8){let X=Math.min(C,l*n);t.x+=c/C*X,t.y+=b/C*X;return}let T=e?.cardEffects?.laborExploitation?.7:1,I=n/(Ue.repairman.secondsPerOnePercent*T*100),$=mn(r),O=I*Un(r);es(r,O);let ee=Math.max(0,($-mn(r))/Un(r)*100);t.repairedToday=(t.repairedToday||0)+ee,ee>0&&Math.random()<.02&&K(e,t.x,t.y-28,"REPAIR",y.green),Bt(r)<=.001&&(o.delete(i),t.target=null)}function da(e,t=new Set){let n=null;for(let o of vn(e)){if(t.has(nr(o)))continue;let r=Bt(o);r<=.001||(!n||r>Bt(n))&&(n=o)}return n||ca(e)}function fa(e){let t=0,n="none";for(let o of vn(e)){let r=Bt(o);r>t&&(t=r,n=o.label)}return{ratio:t,percent:Math.round(t*100),label:n}}function or(e){let t=fa(e),n=Qo(e);return{worst:t,avgBeltPerformance:n,repairman:e.repairman||null,repairmen:e.repairmen||[],rooms:e.maintenanceRooms||[]}}var pa=Ie.commonWeight,ya=Ie.rareWeight,ha=Ie.ultraRareWeight||.45,Lt=Ie.baseDraftSize,Qt=$r;function Xt(e,t){let n=Le(e);return Math.max(0,Number(n[t])||0)}function Le(e){e.cardEffects||(e.cardEffects={...wo});for(let[t,n]of Object.entries(wo))e.cardEffects[t]==null&&(e.cardEffects[t]=Array.isArray(n)?[]:n);return e.cardEffects.flattery!=null&&(e.cardEffects.fairiesFlatteryNext=Math.max(0,e.cardEffects.fairiesFlatteryNext||0)+Math.max(0,e.cardEffects.flattery||0),delete e.cardEffects.flattery),e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft||(e.cardDraft={pending:!1,choices:[],rerolls:0,picksRemaining:0}),e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardEffects}function fs(e){let t=Math.max(.5,1-.05*Math.min(10,Xt(e,"crowdedFarming"))),n=Math.pow(.96,Xt(e,"hatchingFeed"));return t*n}function ps(e,t=null){return Math.min(3,Math.max(0,Number(t?.extraEggOutlet)||0))}function ys(e){return Math.pow(.85,Xt(e,"scannerQueueSpacing"))}function Xn(e,t=null){let n=Le(e),o=Tn*Math.pow(En,Math.max(0,n.bearing||0)),r=t?Math.max(.1,Number(e?.conveyorMeta?.get?.(t)?.speedMultiplier)||1):1,i=t?1:Qo(e),l=Math.max(.01,Number(e?.eventActive?.conveyorSpeedMultiplier)||1);return Math.min(Wt,o*i)*r*l}function nt(e,t=null){let n=Math.max(0,(e?.level||1)-1),o=t?Xt(t,"autoScannerTuning"):0,r=xn*Math.pow(Dr,n)*Math.pow(ho,o),i=Math.max(mo,r),l=t?Math.max(.01,Number(t?.eventActive?.autoScannerCooldownMultiplier)||1):1;return t?Math.max(mo,i*qn(e)*l):i}function is(e){let t=e.cardDraft||{rerolls:0},n=Math.max(1,(t.rerolls||0)+1);return Math.ceil(Math.max(1,e.turn||1)/Ie.rerollCost.dayDivisor*n*Ie.rerollCost.multiplier)}function Jt(e){return Qt.find(t=>t.id===e)||null}function hs(e,t){let n=typeof t=="string"?Jt(t):t;return Le(e),!n||!(n.type==="equipmentUpgrade"||n.type==="cellAction")?[]:We(e,n).map(o=>({key:tt(o),label:sr(e,o),type:o.type}))}function ir(e,t,n={}){let o=typeof t=="string"?Jt(t):t;if(Le(e),!o||o.type==="dud")return{ok:!1,reason:"Card not found."};if(o.id==="extraCards")return e.cardDraft=e.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.choices.push(...zn(e,2)),{ok:!0,reason:`${o.title} added 2 draft cards.`};if(o.type==="instant")return bs(e,o),{ok:!0,reason:`${o.title} granted.`};if(o.type==="equipmentUpgrade"){let r=We(e,o);if(!r.length)return{ok:!1,reason:`No valid target for ${o.title}.`};let i=n.targetKey&&n.targetKey!=="__auto__"?String(n.targetKey):"",l=i?r.find(c=>tt(c)===i):r[0];return l?(ms(e,l),{ok:!0,reason:`${o.title} applied to ${sr(e,l)}.`}):{ok:!1,reason:`Selected target is no longer valid for ${o.title}.`}}if(o.type==="cellAction"&&o.target==="blockedCell"){let r=We(e,o);if(!r.length)return{ok:!1,reason:"No blocked cells to remove."};let i=new Set((Array.isArray(n.targetKeys)?n.targetKeys:[n.targetKey]).filter(c=>c&&c!=="__auto__").map(String)),l=i.size?r.filter(c=>i.has(tt(c))):r.slice(0,3);if(!l.length)return{ok:!1,reason:`Selected target is no longer valid for ${o.title}.`};for(let c of l.slice(0,3)){e.blockedCells.delete(A(c.col,c.row));let b=B(c.col,c.row);et(e,b.x,b.y),Xe(e,b.x,b.y,y.danger,42),Ze(e,b.x,b.y,8,y.warn)}return me(e),{ok:!0,reason:`${o.title} removed ${Math.min(3,l.length)} blocked cell(s).`}}return{ok:!1,reason:`${o.title} cannot be debug-granted.`}}function sr(e,t){if(t.type==="blockedCell")return`Blocked cell ${t.col},${t.row}`;if(t.type==="eggFarm")return`EGG #${t.id} L${t.level} -> L${t.level+1}`;if(t.type==="eggOutlet"){let n=Math.max(0,Number(t.farm?.extraEggOutlet)||0);return`EGG #${t.id} OUTLET ${1+n} -> ${2+n}`}if(t.type==="scanner")return`AUTO #${t.id} L${t.level} -> L${t.level+1} | CD ${nt(t,e).toFixed(1)}s -> ${nt({...t,level:t.level+1},e).toFixed(1)}s`;if(t.type==="facility"&&(t.baseId||t.id)==="mixer"){let n=t.level,o=ze(e);t.level=n+1;let r=ze(e);return t.level=n,`MIXER L${t.level} -> L${t.level+1} | ${x(o)} -> ${x(r)}`}if(t.type==="facility"&&(t.baseId||t.id)==="truck"){let n=t.level,o=Fe(e);t.level=n+1;let r=Fe(e);return t.level=n,`TRUCK L${t.level} -> L${t.level+1} | ${x(o)} -> ${x(r)}`}if(t.type==="facility"&&t.id==="trash"){let n=It(e),o=Math.min(Vt(),n+1),r=ht(n),i=ht(o);return`SHREDDER L${t.level||1} -> L${(t.level||1)+1} | poop income ${x(r)} -> ${x(i)} per item`}return`${t.name||t.id} L${t.level||1} -> L${(t.level||1)+1}`}function ma(e){return[...e.blockedCells||[]].map(t=>{let[n,o]=String(t).split(",").map(Number);return{type:"blockedCell",id:t,col:n,row:o}}).filter(t=>Number.isFinite(t.col)&&Number.isFinite(t.row))}function We(e,t){let n=typeof t=="string"?Jt(t):t;return Le(e),n?n.target==="blockedCell"?ma(e):n.target==="eggFarm"?e.eggFarms.filter(o=>(o.level||1)<4):n.target==="eggOutlet"?e.eggFarms.filter(o=>Math.max(0,Number(o.extraEggOutlet)||0)<3).map(o=>({type:"eggOutlet",id:o.id,col:o.col,row:o.row,farm:o})):n.target==="autoScanner"?e.scanners.filter(o=>o.kind==="auto"):n.target==="mixer"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="mixer"):n.target==="truck"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="truck"):n.target==="trash"?Wo(e)(o.baseId||o.id)==="trash"):[]:[]:[]}function ba(e,t){let n=Le(e);if(t.id==="crowdedFarming")return(n.crowdedFarming||0)>=10;if(t.id==="recyclingSubsidy")return(n.recyclingSubsidy||0)>=3;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,Ie.dudChancePerCard||0)),r=Math.max(1e-4,Math.min(1,Ie.dudChanceReductionPerFilter||.05));return(n.dudFilter||0)>=Math.ceil(o/r)}return t.id==="laborExploitation"?!!n.laborExploitation:t.id==="usedMachine"?!!n.usedMachineActive:t.id==="newMachine"?!n.usedMachineActive:!1}function va(e){return!!((e.maintenanceRooms||[]).length||(e.repairmen||[]).length||e.repairman?.active)}function wa(e){return Qt.filter(t=>!(t.id==="laborExploitation"&&!va(e)||ba(e,t)||(t.type==="equipmentUpgrade"||t.type==="cellAction")&&We(e,t).length<=0))}function ss(e,t){return t.rarity==="ultraRare"?ha:t.rarity==="rare"?ya:pa}function Sa(e,t){let n=t.reduce((r,i)=>r+ss(e,i),0);if(n<=0)return t[Math.floor(Math.random()*t.length)];let o=Math.random()*n;for(let r of t)if(o-=ss(e,r),o<=0)return r;return t[t.length-1]}var ls=0;function ka(){return ls+=1,{id:`dud:${Date.now()}:${ls}`,title:"Dud",rarity:"dud",type:"dud",description:"Click to flick this dud away. It does not consume a pick."}}function Ca(e){let t=Le(e),n=Math.max(0,Math.min(1,Ie.dudChancePerCard||0)),o=Math.max(0,Math.min(1,Ie.dudChanceReductionPerFilter||0));return Math.max(0,n-o*Math.max(0,t.dudFilter||0))}function Ma(e,t){let n=[...t],o=0,r=Math.max(0,Ie.maxDudsPerDraft||0),i=Ca(e);for(let l=0;lc.id===i.id);l>=0&&r.splice(l,1)}return Ma(e,o)}function tt(e){return e?e.type==="blockedCell"?`blockedCell:${e.id}`:e.type==="eggFarm"?`eggFarm:${e.id}`:e.type==="eggOutlet"?`eggOutlet:${e.id}`:e.type==="scanner"?`scanner:${e.id}`:e.type==="facility"?`facility:${e.id}`:`${e.type}:${e.id}`:""}function as(e){if(!e)return null;if(e.type==="blockedCell"){let t=B(e.col,e.row);return{x:t.x-f.cell*.48,y:t.y-f.cell*.48,w:f.cell*.96,h:f.cell*.96,cx:t.x,cy:t.y}}if(e.type==="eggFarm"||e.type==="eggOutlet"){let t=B(e.col,e.row);return{x:t.x-34,y:t.y-34,w:68,h:68,cx:t.x,cy:t.y}}if(e.type==="scanner"){let t=ye(e);return{x:t.x-54,y:t.y-77,w:108,h:154,cx:t.x,cy:t.y}}return e.type==="facility"?{x:e.x,y:e.y,w:e.w,h:e.h,cx:e.x+e.w/2,cy:e.y+e.h/2}:null}function lr(e){if(!e.cardTargetPick?.pending)return[];if(e.cardTargetPick.mode==="autoScannerMenu"){let n=new Set(e.cardTargetPick.targetKeys||[]);return e.scanners.filter(o=>o.kind==="auto"&&n.has(tt(o))).map(o=>({key:tt(o),label:"AUTO ROUTE SETTINGS",target:o,bounds:as(o)})).filter(o=>o.bounds)}let t=new Set(e.cardTargetPick.targetKeys||[]);return We(e,e.cardTargetPick.cardId).filter(n=>t.has(tt(n))).map(n=>({key:tt(n),label:sr(e,n),target:n,bounds:as(n)})).filter(n=>n.bounds)}function ga(e,t){let n=lr(e);for(let o of n){let r=o.bounds;if(t.x>=r.x&&t.x<=r.x+r.w&&t.y>=r.y&&t.y<=r.y+r.h)return o.target}return null}function ms(e,t){if(t.type==="eggOutlet"){let n=t.farm||e.eggFarms.find(r=>r.id===t.id);if(!n)return;n.extraEggOutlet=Math.min(3,Math.max(0,Number(n.extraEggOutlet)||0)+1);let o=B(n.col,n.row);K(e,o.x,o.y-30,`OUTLET ${1+n.extraEggOutlet}`,y.green),me(e);return}if(t.level=(t.level||1)+1,t.type==="eggFarm"){t.nextSpawn=Rt(t),t.lastInterval=t.nextSpawn;let n=B(t.col,t.row);K(e,n.x,n.y-30,`LV ${t.level}`,y.green);return}if(t.type==="scanner"){let n=ye(t);K(e,n.x,n.y-34,`LV ${t.level}`,y.green);return}t.type==="facility"&&K(e,t.x+t.w/2,t.y+18,`LV ${t.level}`,y.green)}function bs(e,t){let n=Le(e),o=r=>{n[r]=Math.max(0,n[r]||0)+1};if(t.id==="bearing"&&o("bearing"),t.id==="autoScannerTuning"&&o("autoScannerTuning"),t.id==="legalWork"&&o("legalWork"),t.id==="crowdedFarming"&&(n.crowdedFarming=Math.min(10,(n.crowdedFarming||0)+1)),t.id==="hatchingFeed"&&o("hatchingFeed"),t.id==="poopRateBooster"&&o("poopRateBooster"),t.id==="safetyCover"&&o("safetyCover"),t.id==="recyclingSubsidy"&&(n.recyclingSubsidy=Math.min(3,(n.recyclingSubsidy||0)+1)),t.id==="chemicalWeaponSubsidy"&&o("chemicalWeaponSubsidy"),t.id==="preventiveMaintenance"&&o("preventiveMaintenance"),t.id==="dudFilter"&&o("dudFilter"),t.id==="durabilityCoating"&&(o("durabilityCoating"),Se(e)),t.id==="sparePartsBin"){o("sparePartsBin");let r=ts(e,.02);e.stats.sparePartsRepair=(e.stats.sparePartsRepair||0)+r,e.totals.sparePartsRepair=(e.totals.sparePartsRepair||0)+r,K(e,f.x+f.cols*f.cell/2,f.y-30,"REPAIR +2%",y.green)}t.id==="dudRefund"&&o("dudRefund"),t.id==="freeReroll"&&o("freeReroll"),t.id==="composter"&&o("composter"),t.id==="scannerQueueSpacing"&&o("scannerQueueSpacing"),t.id==="flattery"&&o("fairiesFlatteryNext"),t.id==="usedMachine"&&(n.usedMachineActive=!0),t.id==="newMachine"&&(n.usedMachineActive=!1),t.id==="laborExploitation"&&(n.laborExploitation=1),t.id==="rescueLoan"&&(o("rescueLoanCharges"),K(e,f.x+f.cols*f.cell/2,f.y-30,"RESCUE HELD",y.green))}function qe(e){return`${Math.round(Number(e||0)*100)}%`}function cs(e){let t=lt[Math.max(0,Math.min(lt.length-1,e-1))]||lt[0]||[0,0];return`${t[0].toFixed(2)}-${t[1].toFixed(2)}s`}function us(e,t){return Math.ceil(e*Math.pow(Ce.incomeUpgradeRate,Math.max(0,t-1)))}function ds(e,t,n){let r=We(e,t==="mixer"?"upgradeMixer":"upgradeTruck")[0];if(!r)return{before:us(n,1),after:us(n,2)};let i=t==="mixer"?ze(e):Fe(e),l=r.level||1;r.level=l+1;let c=t==="mixer"?ze(e):Fe(e);return r.level=l,{before:i,after:c}}function xa(e,t){let n=Le(e);if(t.id==="upgradeEgg"){let o=We(e,t),r=Math.min(3,Math.max(1,o[0]?.level||1));return`Choose one EGG. Level +1. Production interval ${cs(r)} -> ${cs(r+1)}.`}if(t.id==="upgradeAutoScanner"){let o=We(e,t)[0]||{level:1},r=nt(o,e),i=nt({...o,level:(o.level||1)+1},e);return`Choose one AUTO SCANNER. Level +1. Cooldown ${r.toFixed(2)}s -> ${i.toFixed(2)}s.`}if(t.id==="upgradeMixer"){let o=ds(e,"mixer",Ce.income.mixer);return`Choose one MIXER. Earning +10%. Male-chick income ${x(o.before)} -> ${x(o.after)}.`}if(t.id==="upgradeTruck"){let o=ds(e,"truck",Ce.income.truck);return`Choose one TRUCK. Earning +10%. Correct shipment income ${x(o.before)} -> ${x(o.after)}.`}if(t.id==="upgradeTrash"){let o=It(e),r=Math.min(Vt(),o+1),i=ht(o),l=ht(r);return`SHREDDER level +1. Poop income ${x(i)} -> ${x(l)} per item.`}if(t.id==="bearing"){let o=Math.min(Wt,Tn*Math.pow(En,Math.max(0,n.bearing||0))),r=Math.min(Wt,Tn*Math.pow(En,Math.max(0,(n.bearing||0)+1)));return`Conveyor speed +7.5%. After pick: ${o.toFixed(1)} -> ${r.toFixed(1)} px/s.`}if(t.id==="legalWork"){let o=Math.max(0,n.legalWork||0);return`Fairies tribute profit exemption +${x(250)}. After pick: exemption bonus ${x(250*(o+1))}.`}if(t.id==="crowdedFarming"){let o=Math.min(10,(n.crowdedFarming||0)+1);return`Held ${n.crowdedFarming||0}/10. After pick: EGG interval ${qe(Math.max(.5,1-.05*o))}, deterioration ${qe(Math.min(1.4,1+.04*o))}.`}if(t.id==="extraEggOutlet"){let o=We(e,t),r=Math.max(0,Number(o[0]?.farm?.extraEggOutlet)||0);return`Choose one EGG. Output ports ${1+r} -> ${2+r}. Max 4 ports per EGG.`}if(t.id==="hatchingFeed")return`Held ${n.hatchingFeed||0}. After pick: EGG interval ${qe(Math.pow(.96,(n.hatchingFeed||0)+1))}, poop rate multiplier ${qe(Math.pow(1.03,(n.hatchingFeed||0)+1))}.`;if(t.id==="poopRateBooster")return`Held ${n.poopRateBooster||0}. After pick: base poop rate +${Math.round((n.poopRateBooster||0)+1)*4} percentage points.`;if(t.id==="autoScannerTuning")return`Held ${n.autoScannerTuning||0}. After pick: all AUTO SCANNER default cooldown ${qe(Math.pow(ho,(n.autoScannerTuning||0)+1))}.`;if(t.id==="safetyCover")return`Held ${n.safetyCover||0}. After pick: explosion damage ${qe(Math.pow(.95,(n.safetyCover||0)+1))}.`;if(t.id==="recyclingSubsidy")return`Held ${n.recyclingSubsidy||0}/3. After pick: normal SELL refund ${Math.round(Math.min(.8,.5+.1*((n.recyclingSubsidy||0)+1))*100)}%.`;if(t.id==="chemicalWeaponSubsidy")return`Held ${n.chemicalWeaponSubsidy||0}. After pick: ${x(1200*((n.chemicalWeaponSubsidy||0)+1))} per 70 truck-shipped poop each day.`;if(t.id==="preventiveMaintenance")return`Held ${n.preventiveMaintenance||0}. After pick: deterioration speed ${qe(Math.pow(.95,(n.preventiveMaintenance||0)+1))}.`;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,Ie.dudChancePerCard||0)),r=Math.max(0,Math.min(1,Ie.dudChanceReductionPerFilter||.05)),i=Math.max(0,n.dudFilter||0),l=Math.max(0,o-r*i),c=Math.max(0,o-r*(i+1));return`Held ${i}. DUD chance per card ${qe(l)} -> ${qe(c)}.`}return t.id==="durabilityCoating"?`Held ${n.durabilityCoating||0}. After pick: maximum durability ${qe(Math.pow(1.03,(n.durabilityCoating||0)+1))}.`:t.id==="sparePartsBin"?`Held ${n.sparePartsBin||0}. Immediately restores 2% durability to every maintained machine. Common card weight.`:t.id==="dudRefund"?`Held ${n.dudRefund||0}. After pick: DUD clicks award ${x(50*((n.dudRefund||0)+1))}.`:t.id==="freeReroll"?`Held ${n.freeReroll||0}. After pick: each card screen starts with ${(n.freeReroll||0)+1} free reroll${(n.freeReroll||0)+1===1?"":"s"}.`:t.id==="composter"?`Held ${n.composter||0}. After pick: SHREDDER poop grants ${x(3*((n.composter||0)+1))}.`:t.id==="scannerQueueSpacing"?`Held ${n.scannerQueueSpacing||0}. After pick: Manual/Auto Scanner queue spacing ${qe(Math.pow(.85,(n.scannerQueueSpacing||0)+1))}.`:t.id==="flattery"?`Next Fairies tribute -50%. Held for next tribute: ${n.fairiesFlatteryNext||0}.`:t.id==="usedMachine"?"Enable Used Machines: future equipment costs 50%, has no SELL refund, and starts with 60% durability.":t.id==="newMachine"?"Cancel Used Machines. Future equipment returns to normal price, refund, and durability.":t.id==="laborExploitation"?"Repairman dispatch paperwork is streamlined. Repair rooms keep operating; one time only.":t.id==="rescueLoan"?`At day-end bankruptcy check, gain ${x(500)} if cash is below ${x(0)}. Held: ${n.rescueLoanCharges||0}.`:t.description}function rr(e,t){let n=e.cardDraft?.choices||[],o=n.findIndex(r=>r.id===t.id);o>=0&&n.splice(o,1)}function vs({game:e,ui:t,onUpdatePanels:n}){function o(){n&&n()}function r(){Le(e),e.cardTargetPick=null,e.cardDraft={pending:!0,choices:zn(e,Lt),rerolls:0,freeRerolls:Xt(e,"freeReroll"),picksRemaining:1}}function i(){Le(e),e.cardDraft.pending=!1,e.cardDraft.choices=[],e.cardDraft.picksRemaining=0,e.cardTargetPick=null,t.modal.classList.remove("visible","equipment-popover"),o()}function l(P=Lt){Le(e),e.cardDraft.choices=zn(e,P)}function c(){Le(e),!e.cardDraft.choices.length&&e.cardDraft.picksRemaining>0&&l(Lt)}function b(P){rr(e,P),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1),e.cardTargetPick=null,c(),e.cardDraft.picksRemaining<=0?i():ie()}function C(P){rr(e,P),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1)+Ie.extraCardsAddedPicks,e.cardDraft.choices.push(...zn(e,2)),ie()}function T(P,G){let H=Xt(e,"dudRefund")*50;if(H>0){let be=Ge(e,H);e.stats.dudRefundIncome=(e.stats.dudRefundIncome||0)+be,e.totals.dudRefundIncome=(e.totals.dudRefundIncome||0)+be,K(e,f.x+f.cols*f.cell/2,f.y-30,`DUD REFUND +${x(be)}`,y.green)}Ft(e,34,.62),document.body?.animate&&document.body.animate([{transform:"translate(0, 0)"},{transform:"translate(-10px, 7px)"},{transform:"translate(12px, -8px)"},{transform:"translate(-8px, -5px)"},{transform:"translate(9px, 6px)"},{transform:"translate(0, 0)"}],{duration:260,easing:"steps(5, end)"}),G&&(G.style.setProperty("--fling-x",`${260+Math.random()*260}px`),G.style.setProperty("--fling-y",`${-260-Math.random()*170}px`),G.style.setProperty("--fling-r",`${(Math.random()<.5?-1:1)*(52+Math.random()*38)}deg`),G.classList.add("flung")),window.setTimeout(()=>{rr(e,P),c(),ie()},340)}function I(P,G=null){if(P.type==="dud")return T(P,G);if(P.id==="extraCards")return C(P);if(P.type==="equipmentUpgrade"||P.type==="cellAction")return $(P);bs(e,P),b(P)}function $(P){let G=We(e,P);G.length&&(e.cardTargetPick={pending:!0,cardId:P.id,mode:P.target==="blockedCell"?"blockedCell":"equipment",targetKeys:G.map(tt),remaining:P.id==="dynamite"?Math.min(3,G.length):1},t.modal.classList.remove("visible","equipment-popover"),o())}function O(P){if(!P||P.type!=="blockedCell")return!1;let G=A(P.col,P.row);if(!e.blockedCells?.has(G))return!1;e.blockedCells.delete(G);let H=B(P.col,P.row);return et(e,H.x,H.y),Xe(e,H.x,H.y,y.danger,62),Ze(e,H.x,H.y,18,y.warn),Gn(e,H.x,H.y,8),Ft(e,16,.35),K(e,H.x,H.y-18,"BOOM",y.danger),me(e),e.cardTargetPick.remaining=Math.max(0,(e.cardTargetPick.remaining||1)-1),e.cardTargetPick.targetKeys=We(e,"dynamite").map(tt),o(),!0}function ee(P){if(!e.cardTargetPick?.pending)return!1;let G=Jt(e.cardTargetPick.cardId),H=ga(e,P);return!G||!H?(X(),!0):G.id==="dynamite"?(O(H)&&((e.cardTargetPick.remaining||0)<=0||!We(e,"dynamite").length)&&b(G),!0):(ms(e,H),b(G),!0)}function X(){e.cardTargetPick?.pending&&(e.cardTargetPick=null,ie())}function ae(){let P=Math.max(0,e.cardDraft?.freeRerolls||0);if(P>0){e.cardDraft.freeRerolls=P-1,e.cardDraft.rerolls+=1,l(Lt),ie();return}let G=is(e);e.cash${G.alt||`:``}function se(P,G){let H=document.createElement("button");H.type="button";let be=P.type==="dud"?"dud":P.rarity==="ultraRare"?"ultra-rare":P.rarity==="rare"?"rare":"common";H.className=`card-choice ${be}`;let F=P.type==="dud"?"MISS":P.rarity==="ultraRare"?"ULTRA RARE":P.rarity==="rare"?"RARE":"COMMON",U=[F,...(P.tags||[]).filter(S=>S!==F)].slice(0,5);return H.innerHTML=`${re(P)}
${P.title}
${U.map(S=>`${S}`).join("")}
${xa(e,P)}
`,H.addEventListener("click",()=>I(P,H)),H.dataset.index=String(G),H}function ie(){Le(e),e.cardTargetPick=null,e.cardDraft?.pending||r(),e.cardDraft.choices?.length||l(Lt);let P=e.cardDraft.choices||[],G=is(e),H=Math.max(0,e.cardDraft?.freeRerolls||0),be=Math.max(1,e.cardDraft.picksRemaining||1);t.modalTitle.textContent="Choose Upgrade Card",t.modalBody.innerHTML=`

Choose ${be} card${be===1?"":"s"} before Build phase. Dud cards can be flicked away without consuming a pick. Equipment cards target machines; Dynamite targets blocked cells.

`;let F=t.modalBody.querySelector("#cardChoices");P.forEach((g,N)=>F.appendChild(se(g,N))),t.modalActions.innerHTML="";let U=document.createElement("button");U.type="button",U.className="facility-action warn reroll-button",U.textContent=H>0?`Reroll (FREE x${H})`:`Reroll ${x(G)}`,U.disabled=H<=0&&e.cash0?`${H} free reroll${H===1?"":"s"} remaining.`:U.disabled?"Not enough cash":"",U.addEventListener("click",ae),t.modalActions.appendChild(U);let S=document.createElement("button");S.type="button",S.className="facility-action",S.textContent="No Card",S.title="Skip this upgrade pick and enter Build phase.",S.addEventListener("click",i),t.modalActions.appendChild(S),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible")}return{prepareDraft:r,showDraft:ie,finishDraft:i,chooseTargetAtPoint:ee,cancelTargetPick:X}}var Ta=!0,Ea={chickMale:"./assets/images/chick_male.png",chickFemale:"./assets/images/chick_female.png",poop:"./assets/images/poop.png",conveyorStraightH:"./assets/dark_factory/facilities/conveyor/conveyor_straight_h_16.png",conveyorStraightV:"./assets/dark_factory/facilities/conveyor/conveyor_straight_v_16.png",conveyorTurnNe:"./assets/dark_factory/facilities/conveyor/conveyor_turn_ne_16.png",conveyorTurnNw:"./assets/dark_factory/facilities/conveyor/conveyor_turn_nw_16.png",conveyorTurnSe:"./assets/dark_factory/facilities/conveyor/conveyor_turn_se_16.png",conveyorTurnSw:"./assets/dark_factory/facilities/conveyor/conveyor_turn_sw_16.png",boostConveyorStraightH:"./assets/dark_factory/facilities/conveyor/boost_conveyor_straight_h_16.png",boostConveyorStraightV:"./assets/dark_factory/facilities/conveyor/boost_conveyor_straight_v_16.png",boostConveyorTurnNe:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_ne_16.png",boostConveyorTurnNw:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_nw_16.png",boostConveyorTurnSe:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_se_16.png",boostConveyorTurnSw:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_sw_16.png",scannerManual:"./assets/dark_factory/facilities/machines/manual_scanner_32x48.png",scannerAuto:"./assets/dark_factory/facilities/machines/auto_scanner_32x48.png",eggFarm:"./assets/dark_factory/facilities/machines/egg_farm_16.png",mixer:"./assets/dark_factory/facilities/machines/mixer_32.png",shredder:"./assets/dark_factory/facilities/machines/shredder_32.png",truck:"./assets/dark_factory/facilities/vehicles/truck_32.png",mixerCompact:"./assets/dark_factory/facilities/machines/mixer_compact_16.png",shredderCompact:"./assets/dark_factory/facilities/machines/shredder_compact_16.png",truckCompact:"./assets/dark_factory/facilities/vehicles/truck_compact_16.png",maintenanceRoom:"./assets/dark_factory/facilities/utility/maintenance_room_32.png",repairman:"./assets/dark_factory/facilities/utility/repairman_16.png",obstacleCrate:"./assets/dark_factory/facilities/utility/obstacle_crate_16.png"},ce={};for(let[e,t]of Object.entries(Ea)){let n=new Image;n.loaded=!1,n.onerror=()=>{n.loaded=!1},Ta&&t&&(n.onload=()=>{n.loaded=!0},n.src=t),ce[e]=n}function Cs(e,t,n,o){e.imageSmoothingEnabled=!1,e.clearRect(0,0,t.width,t.height),Ia(e,t),e.save();let r=n.shake.time>0?W(-n.shake.strength,n.shake.strength):0,i=n.shake.time>0?W(-n.shake.strength,n.shake.strength):0,l=n.view?.scale||1;e.translate((n.view?.x||0)+r,(n.view?.y||0)+i),e.scale(l,l),Fa(e,n),Ba(e,n),Oa(e,n),za(e,n),nc(e,n),oc(e,n),Xa(e,n),Ja(e,n),Pa(e,n),lc(e,n,o.activeQueuedChick),mc(e,n),fc(e,t,n),dc(e,n,o.selectedObject,o.selectedTitle),pc(e,n),yc(e,n),hc(e,n),e.restore(),vc(e,n,t)}function Ra(e){if(e.type==="eggFarm"){let n=B(e.ref.col,e.ref.row);return{x:n.x-34,y:n.y-34,w:68,h:68,cx:n.x,cy:n.y}}let t=e.ref;return{x:t.x,y:t.y,w:t.w,h:t.h,cx:t.x+t.w/2,cy:t.y+t.h/2}}function Pa(e,t){if(t.phase!=="build")return;let n=Ln(t);for(let o of n){let r=Ra(o);e.save(),e.fillStyle="rgba(196,36,36,.22)",e.strokeStyle=y.danger,e.lineWidth=5,e.setLineDash([10,6]),Z(e,r.x,r.y,r.w,r.h,!0,!0),e.setLineDash([]),e.fillStyle=y.danger,e.strokeStyle=y.white,e.lineWidth=4,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.strokeText("!",r.cx,r.y+24),e.fillText("!",r.cx,r.y+24),e.font="900 11px ui-monospace, monospace",e.strokeText("NO ROUTE",r.cx,r.y+r.h-8),e.fillText("NO ROUTE",r.cx,r.y+r.h-8),e.restore()}}function Z(e,t,n,o,r,i=!0,l=!0){e.beginPath(),e.rect(t,n,o,r),i&&e.fill(),l&&e.stroke()}function cr(e,t,n,o,r=y.ink){e.save(),e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.lineWidth=4,e.strokeStyle=y.white,e.fillStyle=r,e.strokeText(o,t,n),e.fillText(o,t,n),e.restore()}function it(e,t,n,o,r,i){if(!t?.loaded)return!1;let l=e.imageSmoothingEnabled;return e.imageSmoothingEnabled=!1,e.drawImage(t,Math.round(n),Math.round(o),Math.round(r),Math.round(i)),e.imageSmoothingEnabled=l,!0}function ws(e,t,n,o,r,i,l=null,c=1){e.fillStyle=i,e.fillRect(Math.round(t),Math.round(n),Math.round(o),Math.round(r)),l&&(e.strokeStyle=l,e.lineWidth=c,e.strokeRect(Math.round(t)+.5,Math.round(n)+.5,Math.round(o)-1,Math.round(r)-1))}function Aa(e,t){let n=(Math.imul(e+37,73856093)^Math.imul(t+71,19349663))>>>0;return n^=n>>>13,n>>>0}function Da(e,t,n,o,r){let i=Aa(o,r);if(i%11>1)return;let l=8+(i>>>4)%Math.max(1,f.cell-20),c=9+(i>>>9)%Math.max(1,f.cell-20),b=7+(i>>>14)%7,C=4+(i>>>18)%5;e.save(),e.globalAlpha=.72,e.fillStyle="#4f9e39",e.strokeStyle="rgba(21,55,21,.72)",e.lineWidth=1.5,e.beginPath(),e.ellipse(t+l,n+c,b,C,(i>>>22)%8*Math.PI/16,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle="rgba(135,214,83,.58)",e.beginPath(),e.ellipse(t+l-b*.22,n+c-C*.28,Math.max(2,b*.34),Math.max(1.5,C*.26),0,0,Math.PI*2),e.fill(),i%3===0&&(e.fillStyle="rgba(55,132,42,.72)",e.beginPath(),e.arc(t+l+b+3,n+c+(i>>>27)%5-2,2.2,0,Math.PI*2),e.fill()),e.restore()}function Ia(e,t){e.fillStyle=y.bg,e.fillRect(0,0,t.width,t.height),e.save(),e.globalAlpha=.85;for(let n=0;n=n;for(let r of Tt(t)){let i=Et(r);e.save(),e.fillStyle=o?"rgba(183,245,198,.34)":"rgba(255,255,255,.22)",e.strokeStyle=o?y.green:y.muted,e.lineWidth=5,e.setLineDash([16,10]),Z(e,i.x,i.y,i.w,i.h,!0,!0),e.setLineDash([]);let l=Mo(r),c=l.cx,b=l.cy;e.fillStyle="rgba(255,255,255,.94)",e.strokeStyle=y.ink,e.lineWidth=4,Z(e,l.x,l.y,l.w,l.h,!0,!0),e.fillStyle=o?y.green:y.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText(r.direction==="right"?"BUY RIGHT LOT":"BUY UPPER LOT",c,b-12),e.fillStyle=y.ink,e.font="900 16px ui-monospace, monospace",e.fillText(`${x(n)} / 10\xD710`,c,b+15),e.fillStyle=y.muted,e.font="900 11px ui-monospace, monospace",e.fillText("blocked tiles included",c,b+30),e.restore()}}function ot(e,t,n,o,r,i,l=0){let c=zt(i);c<.5||(e.save(),e.globalAlpha=Math.min(.62,.12+c*.54),e.fillStyle="#6b4a23",l>0?(e.beginPath(),e.roundRect?.(t,n,o,r,l),e.roundRect?e.fill():Z(e,t,n,o,r,!0,!1)):Z(e,t,n,o,r,!0,!1),e.globalAlpha=Math.min(.9,.25+c*.6),e.strokeStyle="#3a2a16",e.lineWidth=Math.max(2,Math.floor(2+c*5)),e.setLineDash([5,6]),Z(e,t+3,n+3,o-6,r-6,!1,!0),e.restore())}function ar(e,t){let n=e.componentLookup?.get(t);return(n?e.congestion.get(n):null)?.ratio||0}function La(e,t,n={}){let o=Sn(e,t).sort(),i=n.kind==="boostConveyor"?"boostConveyor":"conveyor",l=c=>o.includes(c);if(o.length===2){if(l("left")&&l("right"))return ce[`${i}StraightH`];if(l("up")&&l("down"))return ce[`${i}StraightV`];if(l("up")&&l("right"))return ce[`${i}TurnNe`];if(l("up")&&l("left"))return ce[`${i}TurnNw`];if(l("down")&&l("right"))return ce[`${i}TurnSe`];if(l("down")&&l("left"))return ce[`${i}TurnSw`]}return o.length===1?l("up")||l("down")?ce[`${i}StraightV`]:ce[`${i}StraightH`]:l("up")||l("down")?ce[`${i}StraightV`]:ce[`${i}StraightH`]}function Oa(e,t){let n=[],o=new Set;for(let i of t.conveyorTiles){let{col:l,row:c}=te(i);for(let b of de){let C={col:l+b.dc,row:c+b.dr},T=A(C.col,C.row);if(!t.conveyorTiles.has(T))continue;let I=[i,T].sort().join("|");if(o.has(I))continue;o.add(I);let $=Math.max(ar(t,i),ar(t,T));n.push({a:B(l,c),b:B(C.col,C.row),ratio:$})}}e.save(),e.lineCap="round",e.lineJoin="round";for(let i of[{width:31,color:"#0b0c0f",alpha:1},{width:23,color:"#444b56",alpha:1},{width:15,color:"#171a1f",alpha:1}]){e.globalAlpha=i.alpha,e.strokeStyle=i.color,e.lineWidth=i.width;for(let l of n)e.beginPath(),e.moveTo(l.a.x,l.a.y),e.lineTo(l.b.x,l.b.y),e.stroke()}for(let i of n){let l=Math.max(0,(i.ratio-.5)/.5);e.strokeStyle=Kt(y.green,y.danger,l),e.globalAlpha=i.ratio>.5?.35+l*.55:.8,e.lineWidth=6,e.beginPath(),e.moveTo(i.a.x,i.a.y),e.lineTo(i.b.x,i.b.y),e.stroke()}let r=qa(t);for(let i of t.conveyorTiles){let l=B(...Object.values(te(i))),c=t.conveyorMeta.get(i)||{},b=ar(t,i),C=La(t,i,c),T=b>.5;if(e.fillStyle=T?"rgba(196,36,36,.28)":"rgba(0,0,0,.35)",e.strokeStyle=T?y.danger:"rgba(255,184,39,.34)",e.lineWidth=T?3:1,Z(e,l.x-20,l.y-20,40,40,!0,!0),!it(e,C,l.x-19,l.y-19,38,38)){let $=c.kind==="boostConveyor"?"#315e92":"#454b55";e.fillStyle=b>.5?Kt($,"#a12c2c",Math.max(0,(b-.5)/.5)):$,e.strokeStyle=y.ink,e.lineWidth=2,Z(e,l.x-18,l.y-18,36,36,!0,!0)}Na(e,l,i,c,b),ot(e,l.x-18,l.y-18,36,36,{meta:c}),rt(e,t,"conveyor",i,l.x,l.y,38,38),Ya(e,l,r.get(i)||[]);let I=Sn(t,i);Ka(e,l,c,Ua(t,i,I),I),b>.5&&cr(e,l.x,l.y-15,`${Math.floor(b*100)}%`,y.danger)}e.restore()}function Na(e,t,n,o={},r=0){let l=[...new Set([...Array.isArray(o.outDirs)?o.outDirs:[],o.dir].filter(Boolean))][0]||"right",c=l==="up"||l==="down",b=l==="left"||l==="up",C=o.kind==="boostConveyor",T=typeof performance<"u"?performance.now()/(C?70:105):0,I=((b?-T:T)%10+10)%10;e.save(),e.beginPath(),e.rect(t.x-18,t.y-18,36,36),e.clip();let $=C?"rgba(20,126,124,.62)":"rgba(42,47,54,.72)";if(e.fillStyle=$,e.fillRect(t.x-18,t.y-18,36,36),e.strokeStyle=r>.5?"rgba(238,83,61,.90)":"rgba(184,190,198,.92)",e.lineWidth=4,c)for(let O=t.y-28+I;Oe.conveyorTiles.has(A(n.col+o.dc,n.row+o.dr))).map(o=>o.name)}function _a(e,t,n){let o=de.find(l=>l.name===n);if(!o)return!1;let r=e.conveyorMeta?.get?.(A(t.col+o.dc,t.row+o.dr));return r?[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))].includes(o.opposite):!1}function Ms(e,t,n,o=Sn(e,t)){if(o.length<3)return n;let r=te(t),i=new Set(o.filter(b=>_a(e,r,b))),l=o.filter(b=>!i.has(b));if(i.size&&l.length>=2)return l;let c=n.filter(b=>o.includes(b));return c.length>=2?[...new Set(c)]:o}function Ga(e,t,n,o=Sn(e,t),r="random"){let i=Ms(e,t,n,o);return o.length>=3&&r&&r!=="random"&&i.includes(r)?[r]:i}function Ua(e,t,n=Sn(e,t)){let o=e.conveyorMeta?.get?.(t)||{},r=[...new Set([...Array.isArray(o.outDirs)?o.outDirs:[],o.dir].filter(Boolean))];return n.length<3?[]:Ms(e,t,r,n)}function Wa(e,t,n){let o=te(t),r=de.filter(c=>e.conveyorTiles.has(A(o.col+c.dc,o.row+c.dr))).map(c=>c.name),i=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(c=>r.includes(c)),l=r;return i.length?i:l}function Ka(e,t,n,o,r=o){if(r.length<3||o.length<2)return;e.save();let i=o.includes(n.branchMode)?n.branchMode:"random",l=i!=="random";if(e.lineJoin="round",e.lineCap="round",e.lineWidth=2,e.fillStyle="rgba(18,21,26,.94)",e.strokeStyle=l?y.warn:y.green,e.lineWidth=4,Z(e,t.x-18,t.y-18,36,36,!0,!0),e.strokeStyle="#ffd36a",e.lineWidth=3,e.fillStyle="#020304",i!=="random"){let c=de.find(b=>b.name===i);wn(e,t.x,t.y,c?.angle||0,9,6)}else e.beginPath(),e.moveTo(t.x-10,t.y),e.lineTo(t.x-2,t.y),e.lineTo(t.x+8,t.y-8),e.moveTo(t.x-2,t.y),e.lineTo(t.x+8,t.y+8),e.stroke(),wn(e,t.x+9,t.y-9,-Math.PI/4,4,3),wn(e,t.x+9,t.y+9,Math.PI/4,4,3);e.restore()}function Ha(e,t,n){if(!n)return[];let o=te(t),r=de.filter(c=>e.conveyorTiles.has(A(o.col+c.dc,o.row+c.dr))).map(c=>c.name),i=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(c=>r.includes(c));return Ga(e,t,i.length?i:Wa(e,t,n),r,n.branchMode||"random").map(c=>de.find(b=>b.name===c)).filter(Boolean)}function qa(e){let t=new Map;for(let[n,o]of e.conveyorMeta||[]){let r=Ha(e,n,o);r.length&&t.set(n,r)}return t}function Ya(e,t,n){let o=n.slice(0,4);o.length&&(e.save(),e.globalAlpha=1,o.forEach(r=>{let i=t.x+r.dc*11,l=t.y+r.dr*11;e.fillStyle="rgba(255,205,83,.96)",wn(e,i,l,r.angle,9,7),e.fillStyle="#020304",wn(e,i,l,r.angle,6.5,4.6)}),e.restore())}function wn(e,t,n,o,r=11,i=8){e.save(),e.translate(t,n),e.rotate(o),e.beginPath(),e.moveTo(r,0),e.lineTo(-r*.72,-i),e.lineTo(-r*.72,i),e.closePath(),e.fill(),e.restore()}function Va(e,t,n,o,r){let i=ye(t),l=null;if(n==="inputA"&&(l={x:i.x,y:i.y-67}),n==="left"&&(l={x:i.x-49,y:i.y+14}),n==="right"&&(l={x:i.x+49,y:i.y+14}),!l)return;let c=n==="inputA"?{x:o.x,y:l.y}:{x:l.x,y:o.y};e.save(),e.lineCap="square",e.lineJoin="bevel",e.strokeStyle="#050609",e.lineWidth=15,e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(c.x,c.y),e.lineTo(l.x,l.y),e.stroke(),e.strokeStyle="#596473",e.lineWidth=9,e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(c.x,c.y),e.lineTo(l.x,l.y),e.stroke(),e.strokeStyle=r||"#7b8795",e.lineWidth=3,e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(c.x,c.y),e.lineTo(l.x,l.y),e.stroke(),e.fillStyle=r||"#7b8795",e.strokeStyle="#050609",e.lineWidth=3,Z(e,l.x-9,l.y-7,18,14,!0,!0),e.restore()}function za(e,t){e.save(),e.lineWidth=2,e.font="900 12px ui-monospace, monospace",e.textAlign="center";for(let n of t.scanners){let o=Do(n),r=[{type:"inputA",p:Re(n,"inputA"),label:"IN",color:y.green},{type:"left",p:Re(n,"left"),label:$o(o.left),color:Fo(o.left)},{type:"right",p:Re(n,"right"),label:$o(o.right),color:Fo(o.right)}];for(let i of r){if(!i.p)continue;let l=B(i.p.col,i.p.row);Va(e,n,i.type,l,i.color);let c=li(t,n,i.type||(i.label==="IN"?"inputA":null))||t.conveyorTiles.has(A(i.p.col,i.p.row));e.fillStyle=c?Kt("#1a1d23",i.color,.24):"#3a1e22",e.strokeStyle=c?i.color:y.danger,Z(e,l.x-18,l.y-12,36,24,!0,!0),e.fillStyle=y.white,e.fillText(i.label,l.x,l.y+4)}}e.restore()}function Xa(e,t){for(let n of t.eggFarms)Qa(e,n,t)}function Qa(e,t,n){let o=B(t.col,t.row);if(e.save(),it(e,ce.eggFarm,o.x-29,o.y-29,58,58)){ot(e,o.x-29,o.y-29,58,58,t);let l=1+Math.max(0,Number(t.extraEggOutlet)||0);e.fillStyle="rgba(255,255,255,.92)",e.strokeStyle=y.ink,e.lineWidth=2,Z(e,o.x+9,o.y+12,30,18,!0,!0),e.fillStyle=y.ink,e.font="900 10px ui-monospace, monospace",e.textAlign="center",e.fillText(`O${l}`,o.x+24,o.y+24),rt(e,n,"eggFarm",t.id,o.x,o.y,68,68),e.restore();return}e.fillStyle=y.white,e.strokeStyle=y.ink,e.lineWidth=4,Z(e,o.x-28,o.y-28,56,56,!0,!0),e.fillStyle=y.green,e.font="900 19px ui-monospace, monospace",e.textAlign="center",e.fillText("EGG",o.x,o.y-4);let r=1+Math.max(0,Number(t.extraEggOutlet)||0);e.font="900 11px ui-monospace, monospace",e.fillStyle=y.ink,e.fillText(`L${t.level} O${r}`,o.x,o.y+13),e.fillText(`${t.nextSpawn.toFixed(1)}s`,o.x,o.y+26);let i=Math.max(0,Math.min(1,t.shutterProgress||0));if(i>0){let l=56*i;e.fillStyle=y.ink,Z(e,o.x-28,o.y-28,56,l,!0,!1),e.strokeStyle=y.white,e.lineWidth=2;for(let c=o.y-24;c=1&&(e.fillStyle=y.white,e.font="900 12px ui-monospace, monospace",e.fillText("SHUT",o.x,o.y+4))}ot(e,o.x-28,o.y-28,56,56,t),rt(e,n,"eggFarm",t.id,o.x,o.y,68,68),e.restore()}function Ja(e,t){for(let n of t.scanners)ja(e,n,t)}function ja(e,t,n){let o=ye(t);if(e.save(),t.kind==="manual"&&(n.manualCombo?.count||0)>=10){let b=n.manualCombo.count;e.save(),e.globalAlpha=Math.min(.55,.16+b/120),e.strokeStyle=b>=30?y.warn:y.green,e.lineWidth=Math.min(14,5+Math.floor(b/10)),e.shadowColor=e.strokeStyle,e.shadowBlur=Math.min(28,8+b),Z(e,o.x-54,o.y-76,108,152,!1,!0),e.restore()}let r=t.kind==="auto"?ce.scannerAuto:ce.scannerManual;if(it(e,r,o.x-50,o.y-73,100,146)){t.kind==="auto"?ot(e,o.x-50,o.y-73,100,146,t):Ss(e,t,o),rt(e,n,"scanner",t.id,o.x,o.y,108,154),e.restore();return}e.fillStyle=t.kind==="auto"?"#d8ffe2":y.white,e.strokeStyle=y.ink,e.lineWidth=4,Z(e,o.x-50,o.y-73,100,146,!0,!0),e.fillStyle=t.kind==="auto"?y.green:y.ink,e.font="900 19px ui-monospace, monospace",e.textAlign="center",e.fillText(`${t.kind==="auto"?"AUTO":`S${(t.slot??0)+1}`}`,o.x,o.y-48),e.font="900 11px ui-monospace, monospace";let i=t.keys?.left?.label||(t.slot===0?"A":"Left"),l=t.keys?.right?.label||(t.slot===0?"D":"Right");e.fillText(t.role===0?`${i}:M ${l}:NEXT`:`${i}:WASTE ${l}:TRUCK`,o.x,o.y-28);let c=t.queue.length;t.kind==="manual"?(Ss(e,t,o),e.fillStyle=c>0?y.green:y.muted,e.font="900 10px ui-monospace, monospace",e.fillText(`Q:${c}`,o.x,o.y+54)):(e.fillStyle=c>0?y.green:y.muted,e.font="900 12px ui-monospace, monospace",e.fillText(`Q:${c} CD:${t.cooldown.toFixed(1)}`,o.x,o.y+54),ot(e,o.x-50,o.y-73,100,146,t)),rt(e,n,"scanner",t.id,o.x,o.y,108,154),e.restore()}function Ss(e,t,n){if(t.kind!=="manual")return;let r=(t.slot??0)===0?[{side:"left",text:"A"},{side:"right",text:"D"}]:[{side:"left",text:"\u2190"},{side:"right",text:"\u2192"}];r[0].text=t.keys?.left?.label||r[0].text,r[1].text=t.keys?.right?.label||r[1].text;let i=t.keyPressTime>0?t.keyPressSide:null,l=n.x-30,c=n.y+18;e.save(),e.lineWidth=3,e.fillStyle="#f7fff5",e.strokeStyle=y.ink,Z(e,l-4,c-4,68,25,!0,!0),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let b=0;b.8,i=t.y+Math.sin(t.bob)*(r?5:1.5);if(e.save(),n&&(e.strokeStyle=y.green,e.lineWidth=5,e.beginPath(),e.arc(t.x,i,t.radius+8,0,Math.PI*2),e.stroke()),r&&(e.strokeStyle=y.danger,e.lineWidth=3,e.beginPath(),e.arc(t.x,i,t.radius+12+Math.sin(t.bob*2)*4,0,Math.PI*2),e.stroke()),t.sex==="poop")hr(e,t.x,i,t.radius);else{let l=t.sex==="male"?ce.chickMale:ce.chickFemale;if(!it(e,l,t.x-t.radius,i-t.radius,t.radius*2,t.radius*2)){let C=t.sex==="male"?y.male:y.female,T=t.sex==="male"?"#164f8f":"#8b2252";e.fillStyle=C,e.strokeStyle=y.ink,e.lineWidth=5,e.beginPath(),e.arc(t.x,i,t.radius,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle="rgba(255,255,255,.24)",e.beginPath(),e.arc(t.x-5,i-7,t.radius*.36,0,Math.PI*2),e.fill(),e.fillStyle=y.ink,e.beginPath(),e.arc(t.x-6,i-5,2.5,0,Math.PI*2),e.arc(t.x+6,i-5,2.5,0,Math.PI*2),e.fill(),e.fillStyle="#ffaa2e",e.beginPath(),e.moveTo(t.x,i+2),e.lineTo(t.x+9,i+6),e.lineTo(t.x,i+10),e.closePath(),e.fill(),e.strokeStyle=T,e.lineWidth=3,t.sex==="male"?(e.beginPath(),e.moveTo(t.x-8,i-t.radius-2),e.lineTo(t.x+8,i-t.radius-2),e.stroke()):(e.beginPath(),e.moveTo(t.x-9,i-t.radius+2),e.lineTo(t.x,i-t.radius-6),e.lineTo(t.x+9,i-t.radius+2),e.stroke())}e.fillStyle=t.sex==="male"?"#dff1ff":"#fff0f7",e.strokeStyle="#050609",e.lineWidth=3,e.font=`900 ${Math.max(10,Math.round(t.radius*.72))}px ui-monospace, monospace`,e.textAlign="center";let b=t.sex==="male"?"\u2642":"\u2640";e.strokeText(b,t.x+t.radius*.54,i+t.radius*.7),e.fillText(b,t.x+t.radius*.54,i+t.radius*.7)}e.restore()}function cc(e,t){let n=null,o=1/0;for(let[r,i]of e.componentLookup.entries()){let l=te(r),c=B(l.col,l.row),b=Math.hypot(t.x-c.x,t.y-c.y);bks(o.type,o.id)===ks(t,n))}function rt(e,t,n,o,r,i,l,c){uc(t,n,o)&&(e.save(),e.fillStyle="rgba(34,185,79,.18)",e.strokeStyle=y.green,e.lineWidth=(t.multiSelected||[]).length>1?6:4,e.setLineDash((t.multiSelected||[]).length>1?[]:[8,5]),Z(e,r-l/2,i-c/2,l,c,!0,!0),e.restore())}function dc(e,t,n,o){if(t.phase==="build"&&(t.multiSelected||[]).length>1){e.save(),e.fillStyle="rgba(255,255,255,.96)",e.strokeStyle=y.ink,e.lineWidth=3,Z(e,54-t.view.x,66-t.view.y,214,42,!0,!0),e.fillStyle=y.ink,e.font="900 11px ui-monospace, monospace",e.fillText(`${t.multiSelected.length} ITEMS SELECTED`,65-t.view.x,83-t.view.y),e.fillStyle=y.muted,e.font="900 11px ui-monospace, monospace",e.fillText("drag any selected item to move group",65-t.view.x,99-t.view.y),e.restore();return}}function fc(e,t,n){if(!n.cardTargetPick?.pending)return;let o=lr(n);e.save(),e.fillStyle="rgba(0,0,0,.66)",e.beginPath();let r=n.view?.scale||1;e.rect(-(n.view?.x||0)/r,-(n.view?.y||0)/r,t.width/r,t.height/r);for(let b of o){let C=b.bounds,T=8;e.rect(C.x-T,C.y-T,C.w+T*2,C.h+T*2)}e.fill("evenodd");let i=n.cardTargetPick?.mode==="blockedCell";if(!o.length){e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=y.ink,e.lineWidth=3,Z(e,(260-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,420/r,42/r,!0,!0),e.fillStyle=y.danger,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(i?"NO BLOCKED CELL. PRESS ESC.":"NO VALID UPGRADE TARGET. PRESS ESC.",(470-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore();return}e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=y.ink,e.lineWidth=3;let l=Math.max(1,n.cardTargetPick?.remaining||1),c=n.cardTargetPick?.mode==="autoScannerMenu"?"AUTO SCANNER ROUTE SETTINGS. CLICK EMPTY AREA TO CLOSE.":i?`CLICK BLOCKED CELL: ${l} LEFT. PRESS ESC TO CANCEL.`:"CLICK AN UPGRADEABLE MACHINE. PRESS ESC TO CANCEL.";Z(e,(216-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,560/r,42/r,!0,!0),e.fillStyle=y.ink,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(c,(496-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore()}function pc(e,t){if(t.phase!=="build"||!t.selectionBox)return;let n=t.selectionBox,o=Math.min(n.x1,n.x2),r=Math.min(n.y1,n.y2),i=Math.abs(n.x2-n.x1),l=Math.abs(n.y2-n.y1);e.save(),e.fillStyle="rgba(34,185,79,.12)",e.strokeStyle=y.green,e.lineWidth=2,e.setLineDash([7,4]),Z(e,o,r,i,l,!0,!0),e.restore()}function yc(e,t){let n=[...t.effects].sort((o,r)=>(o.priority??Me.ambient)-(r.priority??Me.ambient));for(let o of n){let r=Math.max(0,o.life/o.maxLife);e.save(),e.globalAlpha=r,o.type==="meat"?(e.fillStyle=y.green,Z(e,o.x-o.size/2,o.y-o.size/2,o.size*1.5,o.size,!0,!1)):o.type==="sludge"?(e.fillStyle=y.poop,Z(e,o.x-o.size/2,o.y-o.size/2,o.size*1.4,o.size,!0,!1)):o.type==="spawn"?(e.strokeStyle=y.green,e.lineWidth=3,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*20,0,Math.PI*2),e.stroke()):o.type==="spark"?(e.fillStyle=o.color||y.danger,Z(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!0,!1)):o.type==="smoke"?(e.fillStyle="rgba(16,32,21,.24)",e.beginPath(),e.arc(o.x,o.y,o.size*(1.2-r*.2),0,Math.PI*2),e.fill()):o.type==="shockwave"?(e.strokeStyle=o.color||y.danger,e.lineWidth=4,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*(o.maxSize||44),0,Math.PI*2),e.stroke()):o.type==="scannerPulse"?(e.strokeStyle=o.color||y.green,e.lineWidth=5,e.setLineDash([8,6]),e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*38,0,Math.PI*2),e.stroke()):o.type==="shred"?(e.fillStyle=o.color||y.ink,e.save(),e.translate(o.x,o.y),e.rotate(o.rot||0),Z(e,-o.w/2,-o.h/2,o.w,o.h,!0,!1),e.restore()):o.type==="load"?(e.strokeStyle=o.color||y.green,e.lineWidth=3,e.beginPath(),e.moveTo(o.x-14,o.y),e.lineTo(o.x+14,o.y),e.moveTo(o.x,o.y-14),e.lineTo(o.x,o.y+14),e.stroke()):o.type==="erase"?(e.strokeStyle=y.ink,e.lineWidth=3,e.setLineDash([4,4]),Z(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!1,!0)):o.type==="rage"?(e.fillStyle=o.color||y.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText("!",o.x,o.y)):o.type==="flyingChick"&&(o.sex==="poop"?hr(e,o.x,o.y,o.radius||11):mr(e,o.x,o.y,o.sex,o.sex==="male")),e.restore()}}function hc(e,t){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let n of t.floatingTexts){let o=Math.max(0,n.life/n.maxLife);e.globalAlpha=o,e.lineWidth=5,e.strokeStyle=y.white,e.fillStyle=n.color,e.strokeText(n.text,n.x,n.y),e.fillText(n.text,n.x,n.y)}e.restore()}function mc(e,t){let n=t.repairmen&&t.repairmen.length?t.repairmen:t.repairman?[t.repairman]:[];for(let o of n)bc(e,t,o)}function bc(e,t,n){if(!!!n?.active)return;if(e.save(),it(e,ce.repairman,n.x-18,n.y-18,36,36)){n.target?.label&&cr(e,n.x,n.y-24,n.target.label,y.green),e.restore();return}e.lineWidth=3,e.fillStyle="#fff0d1",e.strokeStyle=y.ink,e.beginPath(),e.arc(n.x,n.y,17,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle="#ffd6e7",e.beginPath(),e.arc(n.x-6,n.y-2,3.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+6,n.y-2,3.2,0,Math.PI*2),e.fill();let r=!!t.cardEffects?.laborExploitation;e.fillStyle=r?y.danger:y.ink,e.beginPath(),e.arc(n.x-5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.strokeStyle=y.ink,e.lineWidth=r?3:2,e.beginPath(),e.arc(n.x,n.y+(r?0:1),r?8:7,.1*Math.PI,.9*Math.PI),e.stroke(),e.fillStyle=y.green,Z(e,n.x-9,n.y+14,18,8,!0,!0),e.strokeStyle=y.ink,e.lineWidth=3,e.beginPath(),e.moveTo(n.x-11,n.y+18),e.lineTo(n.x-20,n.y+24),e.stroke(),e.beginPath(),e.moveTo(n.x+11,n.y+18),e.lineTo(n.x+20,n.y+24),e.stroke(),e.fillStyle=y.ink,e.font="900 11px ui-monospace, monospace",e.textAlign="center",e.fillText("FIX",n.x,n.y+33),n.target?.label&&cr(e,n.x,n.y-24,n.target.label,y.green),e.restore()}function vc(e,t,n){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="left",e.fillStyle=y.ink,e.font="900 19px ui-monospace, monospace",e.fillStyle=y.ink;let o=[];t.phase==="running"&&o.push(t.timeLeft<=0?"TIME UP: FARMS SHUT. CLEAR LINE.":"A/D: S1 \u2190/\u2192: S2"),t.phase==="build"&&o.push(`BUILD: ${t.buildTool||"SELECT"} | connect 1 EGG route to any exit`);let r=76;for(let i of o)e.strokeStyle=y.white,e.lineWidth=4,e.strokeText(i,24,r),e.fillText(i,24,r),r+=20;e.restore()}var Es=[[{key:"a",code:"KeyA",label:"A"},{key:"d",code:"KeyD",label:"D"}],[{key:"arrowleft",code:"ArrowLeft",label:"Left"},{key:"arrowright",code:"ArrowRight",label:"Right"}],[{key:"j",code:"KeyJ",label:"J"},{key:"l",code:"KeyL",label:"L"}],[{key:"f",code:"KeyF",label:"F"},{key:"h",code:"KeyH",label:"H"}],[{key:"q",code:"KeyQ",label:"Q"},{key:"e",code:"KeyE",label:"E"}],[{key:"z",code:"KeyZ",label:"Z"},{key:"x",code:"KeyX",label:"X"}],[{key:"u",code:"KeyU",label:"U"},{key:"o",code:"KeyO",label:"O"}],[{key:"n",code:"KeyN",label:"N"},{key:"m",code:"KeyM",label:"M"}]];function wc(e){let t=Es[e]||Es[0];return{left:{...t[0]},right:{...t[1]}}}function Rs(e,t,n){let o={type:"eggFarm",id:e.nextId++,col:t,row:n,level:1,nextSpawn:2,lastInterval:2,extraEggOutlet:0,price:at.eggFarm,builtSession:e.buildSession};return o.nextSpawn=Rt(o),o.lastInterval=o.nextSpawn,o}function Ps(e,t,n,o){let r=o==="auto"?ve.autoScanner.price:ve.manualScanner.price,i=new Set(e.scanners.filter(c=>c.kind==="manual").map(c=>c.slot)),l=0;for(;i.has(l);)l+=1;return{type:"scanner",id:e.nextId++,kind:o,slot:o==="manual"?l:null,role:o==="manual"?l%2:0,col:t,row:n,level:1,queue:[],cooldown:0,price:r,builtSession:e.buildSession,autoMode:"standard",keys:o==="manual"?wc(l):null}}function Jn(e){let t=(e.x-f.x)/f.cell,n=(e.y-f.y)/f.cell,o=Math.max(0,Math.min(f.cols-1,Math.round(t-.5))),r=Math.max(0,Math.min(f.rows-1,Math.round(n-.5))),i=Math.abs(e.x-f.x),l=Math.abs(e.x-(f.x+f.cols*f.cell)),c=Math.abs(e.y-f.y),b=Math.abs(e.y-(f.y+f.rows*f.cell)),C=[["left",i],["right",l],["top",c],["bottom",b]].sort((T,I)=>T[1]-I[1])[0][0];return C==="left"?{side:C,entry:{col:0,row:r}}:C==="right"?{side:C,entry:{col:f.cols-1,row:r}}:C==="top"?{side:C,entry:{col:o,row:0}}:{side:C,entry:{col:o,row:f.rows-1}}}function jn(e,t,n){let o={x:f.x+t.col*f.cell+f.cell/2,y:f.y+t.row*f.cell+f.cell/2},r={left:f.x,right:f.x+f.cols*f.cell,top:f.y,bottom:f.y+f.rows*f.cell};return e.entry={...t},e.side=n,n==="left"?(e.x=r.left-e.w-18,e.y=o.y-e.h/2):n==="right"?(e.x=r.right+18,e.y=o.y-e.h/2):n==="top"?(e.x=o.x-e.w/2,e.y=r.top-e.h-18):(e.x=o.x-e.w/2,e.y=r.bottom+18),e}function As(e,t,n,o){let{entry:r,side:i}=Jn(n),l=ve[t],c=l?{name:l.name,w:l.body?.w||168,h:l.body?.h||110,price:l.price}:{name:t[0].toUpperCase()+t.slice(1),w:168,h:110,price:o},b={type:"facility",id:t,name:c.name,x:0,y:0,w:c.w,h:c.h,level:1,price:o||c.price,builtSession:e.buildSession};return jn(b,r,i)}function jt(e){return e?[{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}]:[]}function Ds(e,t,n){return{type:"maintenanceRoom",id:e.nextId++,col:t,row:n,price:at.maintenanceRoom,builtSession:e.buildSession,wCells:2,hCells:2}}function Sc(e){return Math.random()({x:i.x,y:i.y})),r=o[0];return{id:e.nextId++,sex:n,x:r.x,y:r.y,route:o,targetIndex:o.length>1?1:o.length,stage:t.stage||"belt",scannerId:t.scannerId??null,nextScannerId:null,pendingScannerId:null,radius:n==="poop"?15:17,bob:Math.random()*Math.PI*2,queueIndex:-1,queueRoute:null}}function $s({game:e,canvasPoint:t,updatePanels:n,equipmentAtPoint:o,fail:r,pointInGrid:i,rectOfFacility:l,rectsOverlap:c}){function b(S){return S?S.type==="conveyor"?`conveyor:${S.id||S.oldKey}`:S.type==="facility"?`facility:${S.id||S.ref?.id}`:S.type==="maintenanceRoom"?`maintenanceRoom:${S.id||S.ref?.id}`:`${S.type}:${S.id||S.ref?.id}`:""}function C(S){return S?S.type==="conveyor"?{type:"conveyor",id:S.oldKey}:{type:S.type,id:S.ref.id}:null}function T(S){let g=b(C(S));return(e.multiSelected||[]).some(N=>b(N)===g)}function I(S){return S?S.type==="eggFarm"?e.eggFarms.find(g=>g.id===S.id)||null:S.type==="scanner"?e.scanners.find(g=>g.id===S.id)||null:S.type==="facility"?e.facilities[S.id]||null:S.type==="maintenanceRoom"?(e.maintenanceRooms||[]).find(g=>g.id===S.id)||null:S.type==="conveyor"&&e.conveyorTiles.has(S.id)?{type:"conveyor",id:S.id}:null:null}function $(){let S=[];for(let g of e.conveyorTiles){let N=te(g),j=B(N.col,N.row);S.push({type:"conveyor",id:g,center:j,cell:N})}for(let g of e.eggFarms)S.push({type:"eggFarm",id:g.id,ref:g,center:B(g.col,g.row),cell:{col:g.col,row:g.row}});for(let g of e.scanners)S.push({type:"scanner",id:g.id,ref:g,center:ye(g),cell:{col:g.col,row:g.row}});for(let g of e.maintenanceRooms||[]){let N=B(g.col,g.row);S.push({type:"maintenanceRoom",id:g.id,ref:g,center:{x:N.x+f.cell/2,y:N.y+f.cell/2},cell:{col:g.col,row:g.row}})}for(let g of Object.values(e.facilities)){let N={x:g.x+g.w/2,y:g.y+g.h/2},j=g.entry?B(g.entry.col,g.entry.row):N;S.push({type:"facility",id:g.id,ref:g,center:N,portCenter:j})}return S}function O(S,g){let N=Math.min(g.x1,g.x2),j=Math.max(g.x1,g.x2),J=Math.min(g.y1,g.y2),pe=Math.max(g.y1,g.y2);return S.x>=N&&S.x<=j&&S.y>=J&&S.y<=pe}function ee(S){let g=[];for(let N of $())(O(N.center,S)||N.portCenter&&O(N.portCenter,S))&&g.push({type:N.type,id:N.id});return e.multiSelected=g,e.selected=g[0]||null,n(),g.length}function X(){e.multiSelected=[],e.selected=null,n()}function ae(S){let g=t(S);return e.selectionBox={x1:g.x,y1:g.y,x2:g.x,y2:g.y},e.multiSelected=[],e.selected=null,n(),!0}function he(S){if(!e.selectionBox)return;let g=t(S);e.selectionBox.x2=g.x,e.selectionBox.y2=g.y}function re(){if(!e.selectionBox)return 0;let S=e.selectionBox,g=Math.abs(S.x2-S.x1),N=Math.abs(S.y2-S.y1);return e.selectionBox=null,g<6&&N<6?(X(),0):ee(S)}function se(S){let g=C(S);return g?(e.multiSelected||[]).length&&T(S)?[...e.multiSelected]:[g]:[]}function ie(S){let g=I(S);if(!g)return null;if(S.type==="conveyor"){let N=te(S.id);return{...S,obj:g,oldKey:S.id,currentKey:S.id,meta:e.conveyorMeta.get(S.id)||{price:Oe("conveyor"),builtSession:null},col:N.col,row:N.row}}return S.type==="eggFarm"||S.type==="scanner"||S.type==="maintenanceRoom"?{...S,obj:g,col:g.col,row:g.row}:S.type==="facility"?{...S,obj:g,x:g.x,y:g.y,w:g.w,h:g.h,entry:g.entry?{...g.entry}:null,side:g.side,center:{x:g.x+g.w/2,y:g.y+g.h/2}}:null}function P(S){let g=t(S),N=o(g);if(!N)return!1;let j=se(N),J=j.map(ie).filter(Boolean);return J.length?(e.groupDrag={start:g,selections:j,origins:J,historySnapshot:hn(e),committed:!1,lastDCol:0,lastDRow:0},e.multiSelected=j,e.selected=j[0]||null,n(),!0):!1}function G(){!e.groupDrag||e.groupDrag.committed||(e.undoStack.push(e.groupDrag.historySnapshot),e.redoStack=[],e.groupDrag.committed=!0)}function H(S,g,N){let j=A(S,g),J=ft(e,S,g);if(J&&!N.has(`eggFarm:${J.id}`))return!0;let pe=pt(e,S,g);if(pe&&!N.has(`scanner:${pe.id}`))return!0;let xe=(e.maintenanceRooms||[]).find(Pe=>jt(Pe).some(Ae=>Ae.col===S&&Ae.row===g));return!!(xe&&!N.has(`maintenanceRoom:${xe.id}`)||e.conveyorTiles.has(j)&&!N.has(`conveyor:${j}`))}function be(S,g,N){let j=[];for(let J of e.groupDrag.origins){if(J.type!=="facility")continue;let pe={x:J.center.x+S,y:J.center.y+g},{entry:xe,side:Pe}=Jn(pe);if(!i(xe.col,xe.row)||e.blockedCells?.has?.(A(xe.col,xe.row)))return!0;let Ae={...J.obj,entry:{...xe},side:Pe};jn(Ae,xe,Pe),j.push({id:J.id,rect:l(Ae)})}for(let J of j)for(let pe of Object.values(e.facilities))if(!N.has(`facility:${pe.id}`)&&c(J.rect,l(pe),12))return!0;for(let J=0;J_.type==="conveyor");for(let _ of Ae){let De=_.currentKey||_.oldKey;e.conveyorTiles.delete(De),e.conveyorMeta.delete(De)}for(let _ of Ae){let De=A(_.col+J,_.row+pe);e.conveyorTiles.add(De),e.conveyorMeta.set(De,_.meta||{price:Oe("conveyor"),builtSession:null,uses:0}),_.currentKey=De}for(let _ of e.groupDrag.origins)if(_.type==="eggFarm")_.obj.col=_.col+J,_.obj.row=_.row+pe;else if(_.type==="scanner")_.obj.col=_.col+J,_.obj.row=_.row+pe;else if(_.type==="maintenanceRoom")_.obj.col=_.col+J,_.obj.row=_.row+pe;else if(_.type==="facility"){let De={x:_.center.x+N,y:_.center.y+j},{entry:Ye,side:Ve}=Jn(De);jn(_.obj,Ye,Ve)}e.groupDrag.selections=e.groupDrag.origins.map(_=>_.type==="conveyor"?{type:"conveyor",id:_.currentKey||_.oldKey}:{type:_.type,id:_.id}),e.multiSelected=[...e.groupDrag.selections],e.selected=e.multiSelected[0]||null,me(e),n()}function U(){e.groupDrag&&(me(e),e.groupDrag=null,n())}return{selectionFromHit:C,startSelectionBox:ae,updateSelectionBox:he,finishSelectionBox:re,startGroupDrag:P,updateGroupDrag:F,finishGroupDrag:U}}function Fs({game:e,ui:t,canvas:n,canvasPoint:o,onUpdatePanels:r}){function i(){r&&r()}let l=null,c=!1,b=null,C=!1,T=["random","up","right","down","left"],I={random:"RND",up:"UP",right:"RT",down:"DN",left:"LF"},$={w:40,h:40,y:0};function O(){return An(e)}function ee(){e.gridCols=f.cols,e.gridRows=f.rows,e.gridOwnedCells=Vr(e)}function X(s){if(s){f.y-=s*f.cell,f.rows+=s,e.gridChunkOriginY=(e.gridChunkOriginY||0)-Math.floor(s/10),e.ownedCells=Dn(e.ownedCells,s),e.blockedCells=Dn(e.blockedCells,s),e.conveyorTiles=Dn(e.conveyorTiles,s),e.conveyorMeta=Jr(e.conveyorMeta,s);for(let a of e.eggFarms||[])a.row+=s;for(let a of e.scanners||[])a.row+=s;for(let a of Object.values(e.facilities||{}))a.entry&&(a.entry.row+=s)}}function ae(s){e.ownedCells=e.ownedCells||new Set;for(let a of Qr(s))e.ownedCells.add(A(a.col,a.row))}function he(s){return e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending?null:Tt(e).find(a=>a&&Xr(a,s))||null}function re(s="right"){if(s&&typeof s=="object"&&Number.isFinite(s.chunkX)&&Number.isFinite(s.chunkY))return s;let a=["right","up"].includes(s)?s:"right";return zr(e,a)}function se(s="right"){let a=re(s);if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return{ok:!1,reason:"Cannot expand now."};if(!a)return{ok:!1,reason:"Invalid expansion lot."};let h=a.direction||"right",m=O();if(e.cashf.cols&&(f.cols=E.colStart+E.cols),E.rowStart+E.rows>f.rows&&(f.rows=E.rowStart+E.rows),ae(E),jr(e,E.chunkX,E.chunkY),e.gridExpansionPurchases=(e.gridExpansionPurchases||0)+1,e.gridExpansionPurchasesByDirection[h]=(e.gridExpansionPurchasesByDirection[h]||0)+1,ee();let ne=Wr({seed:`${e.runSeed}:grid-expansion:${E.chunkX},${E.chunkY}:${e.gridExpansionPurchases}`,colStart:E.colStart,colEnd:E.colStart+E.cols,rowStart:E.rowStart,rowEnd:E.rowStart+E.rows,targetRatio:Y.map.blockedRatio});for(let ke of ne)e.blockedCells.add(ke);me(e);let Q=E.cols*E.rows,ue=Et(E);return K(e,ue.x+ue.w/2,ue.y+ue.h/2,`${h.toUpperCase()} +${Q} CELLS -${x(m)}`,y.green),i(),{ok:!0,direction:h,cost:m,addedCells:Q,blocked:ne.size,chunkX:E.chunkX,chunkY:E.chunkY}}function ie(s,a){return s>=0&&s=0&&a!a.has(m.id)&&H(h,G(m),12))}function F(s,a,h=null){if(!ie(s,a))return!1;if(P(s,a))return!0;let m=A(s,a),w=ft(e,s,a);if(w&&!(h?.type==="eggFarm"&&h.ref?.id===w.id))return!0;let E=pt(e,s,a);if(E&&!(h?.type==="scanner"&&h.ref?.id===E.id))return!0;let ne=U(e,s,a);return!!(ne&&!(h?.type==="maintenanceRoom"&&h.ref?.id===ne.id)||e.conveyorTiles.has(m)&&!(h?.type==="conveyor"&&h.oldKey===m))}function U(s,a,h){return(s.maintenanceRooms||[]).find(m=>jt(m).some(w=>w.col===a&&w.row===h))||null}function S(s,a,h=null){let m={col:s,row:a};for(let w of jt(m)){if(!ie(w.col,w.row)||P(w.col,w.row))return!0;let E=A(w.col,w.row);if(ft(e,w.col,w.row)||pt(e,w.col,w.row))return!0;let ue=U(e,w.col,w.row);if(ue&&!(h?.type==="maintenanceRoom"&&h.ref?.id===ue.id)||e.conveyorTiles.has(E))return!0}return!1}function g(s,a,h=null){let m={col:s,row:a};for(let w of Pt(m)){if(!ie(w.col,w.row)||P(w.col,w.row))return!0;let E=A(w.col,w.row);if(ft(e,w.col,w.row))return!0;let Q=pt(e,w.col,w.row);if(Q&&!(h?.type==="scanner"&&h.ref?.id===Q.id)||e.conveyorTiles.has(E))return!0}return!1}function N(){return e.selected?e.selected.type==="eggFarm"?e.eggFarms.find(s=>s.id===e.selected.id)||null:e.selected.type==="scanner"?e.scanners.find(s=>s.id===e.selected.id)||null:e.selected.type==="conveyor"?e.conveyorTiles.has(e.selected.id)?{type:"conveyor",id:e.selected.id}:null:e.selected.type==="facility"?e.facilities[e.selected.id]||null:e.selected.type==="maintenanceRoom"&&(e.maintenanceRooms||[]).find(s=>s.id===e.selected.id)||null:null}function j(s){return s?s.type==="eggFarm"?`${ut("eggFarm")} #${s.id}`:s.type==="scanner"?`${s.kind==="auto"?ut("autoScanner"):ut("manualScanner")} #${s.id}`:s.type==="conveyor"?e.conveyorMeta.get(s.id)?.kind==="boostConveyor"?ut("boostConveyor"):ut("conveyor"):s.type==="facility"?s.name:s.type==="maintenanceRoom"?`${ut("maintenanceRoom")} #${s.id}`:"Equipment":"Equipment"}function J(s){return s?.type==="conveyor"?e.conveyorMeta?.get(s.oldKey||s.ref?.id)?.price||Nn(s):Nn(s)}function pe(){return!!e.cardEffects?.usedMachineActive}function xe(){return pe()?{usedMachine:!0,noRefund:!0,durabilityBaseMultiplier:.6}:{usedMachine:!1,noRefund:!1,durabilityBaseMultiplier:1}}function Pe(s){let a=xe();return Object.assign(s,a),s}function Ae(s){let a=s?.ref||s||{};if(s?.type==="eggFarm"||a.type==="eggFarm")return e.eggFarms.length<=1?"Cannot sell the last EGG FARM.":"";if((s?.type==="facility"||a.type==="facility")&&["mixer","trash","truck"].includes(a.baseId||a.id)){let h=a.baseId||a.id;if(Object.values(e.facilities).filter(w=>(w.baseId||w.id)===h).length<=1)return`Cannot sell the last ${a.shortName||a.name||a.id}.`}return""}function _(s){t.buildStatus.textContent=s,K(e,n.width/2-e.view.x,86-e.view.y,s.toUpperCase(),y.danger)}function De(s){if(!s)return null;let a=A(s.col,s.row);return e.conveyorMeta.get(a)||null}function Ye(s){return s?(Array.isArray(s.outDirs)||(s.outDirs=[]),s.outDirs=[...new Set(s.outDirs.filter(a=>["right","left","down","up"].includes(a)))],T.includes(s.branchMode)||(s.branchMode="random"),s.kind||(s.kind="conveyor"),s.speedMultiplier||(s.speedMultiplier=s.kind==="boostConveyor"?2:1),s.outDirs):[]}function Ve(s){return s?de.filter(a=>e.conveyorTiles.has(A(s.col+a.dc,s.row+a.dr))).map(a=>a.name):[]}function Te(s){return Ve(s).length>=3}function kt(s,a){let h=de.find(Q=>Q.name===a);if(!s||!h)return!1;let m=A(s.col+h.dc,s.row+h.dr),w=e.conveyorMeta.get(m);if(!w)return!1;let E=h.opposite;return[...new Set([...Array.isArray(w.outDirs)?w.outDirs:[],w.dir].filter(Boolean))].includes(E)}function oo(s){if(!e.conveyorTiles.has(s))return[];let a=te(s),h=e.conveyorMeta.get(s),m=Ye(h),w=Ve(a),E=[...new Set([...m,h?.dir].filter(Boolean))].filter(ue=>w.includes(ue)),ne=w,Q=E.length?E:ne;return h&&(h.outDirs=m.filter(ue=>w.includes(ue)),h.dir&&!w.includes(h.dir)&&(h.dir=h.outDirs[0]||null),h.branchMode!=="random"&&!w.includes(h.branchMode)&&(h.branchMode="random")),Q}function Cn(s){if(!e.conveyorTiles.has(s))return[];let a=te(s),h=Ve(a);return Te(a)||h.length?h:oo(s)}function ro(s){let a=te(s),h=Cn(s);if(h.length<3)return[];let m=e.conveyorMeta.get(s)||{},w=new Set(h.filter(Q=>kt(a,Q))),E=h.filter(Q=>!w.has(Q));if(w.size&&E.length>=2)return E;let ne=[...new Set([...Array.isArray(m.outDirs)?m.outDirs:[],m.dir].filter(Boolean))].filter(Q=>h.includes(Q));return ne.length>=2?ne:h}function nn(s,a){let h=ct(s,a);if(!h)return!1;let m=A(s.col,s.row),w=A(a.col,a.row),E=e.conveyorMeta.get(m),ne=e.conveyorMeta.get(w);if(!E||!ne)return!1;let Q=Ye(E),ue=!Q.includes(h)||E.dir!==h||!ne.dir;return Q.includes(h)||Q.push(h),E.dir=h,ne.dir||(ne.dir=h),ue}function Ct(s){let a=so(s);return a.length<2?io(s):(Be(e),lo(a),me(e),i(),!0)}function io(s){if(!s)return!1;let a=A(s.col,s.row),h=e.conveyorMeta.get(a);if(!h||Te(s))return!1;let m=de.map(ne=>ne.name),w=h.dir&&m.includes(h.dir)?h.dir:null,E=m[(Math.max(-1,m.indexOf(w))+1)%m.length];return Be(e),h.dir=E,h.outDirs=[E],h.branchMode="random",me(e),i(),!0}function Mn(s){return s?de.map(a=>({col:s.col+a.dc,row:s.row+a.dr})).filter(a=>e.conveyorTiles.has(A(a.col,a.row))):[]}function so(s){if(!s||!e.conveyorTiles.has(A(s.col,s.row))||Te(s))return[];let a=Mn(s);if(!a.length||a.length>2)return[];let h=E=>{let ne=[],Q=new Set([A(s.col,s.row)]),ue=s,ke=E,xr=0;for(;ke&&xr<200;){xr+=1;let Tr=A(ke.col,ke.row);if(Q.has(Tr)||(Q.add(Tr),ne.push(ke),Te(ke)))break;let Er=Mn(ke).filter(Rr=>!(Rr.col===ue.col&&Rr.row===ue.row));if(Er.length!==1)break;ue=ke,ke=Er[0]}return ne},m=a[0]?h(a[0]).reverse():[],w=a[1]?h(a[1]):[];return[...m,s,...w]}function Mt(s,a){return!!s&&[...new Set([...Array.isArray(s.outDirs)?s.outDirs:[],s.dir].filter(Boolean))].includes(a)}function lo(s){let a=0,h=0;for(let w=0;wh?[...s].reverse():s;for(let w=0;w=Math.abs(m)?{col:s.col+Math.sign(h),row:s.row}:{col:s.col,row:s.row+Math.sign(m)}}function ao(s){c=!1,b=s?{col:s.col,row:s.row}:null,C=!1,l=null,on(s)}function d(s){if(!s)return;if(!l)return on(s);let a=l,h=0;for(;(a.col!==s.col||a.row!==s.row)&&h<64;){let m=rn(a,s);if(on(m),a=l||m,h+=1,!l)break}}function p(){!C&&b&&e.conveyorTiles.has(A(b.col,b.row))&&Ct(b),b=null,C=!1,l=null,c=!1}function v(s){if(!s)return _(oe.fail.outOfGrid);let{col:a,row:h}=s;if(e.buildTool==="conveyor"||e.buildTool==="boostConveyor"){let m=_t(s,null);if(!m.ok)return _(m.reason||oe.fail.cellOccupied);me(e);return}if(P(a,h))return _("Cannot build on blocked ground.");if(e.buildTool==="maintenanceRoom")return S(a,h)?_(oe.fail.cellOccupied):D(a,h);if(e.buildTool==="manualScanner"||e.buildTool==="autoScanner"?g(a,h):F(a,h))return _(oe.fail.cellOccupied);e.buildTool==="eggFarm"?k(a,h):e.buildTool==="manualScanner"?R(a,h,"manual"):e.buildTool==="autoScanner"&&R(a,h,"auto")}function M(s){let a=He(s.x,s.y);if(["conveyor","boostConveyor","eggFarm","manualScanner","autoScanner","maintenanceRoom"].includes(e.buildTool))return v(a);if(cn.includes(e.buildTool))return le(s,e.buildTool)}function k(s,a){let h=Oe("eggFarm",e);if(e.cashE.kind==="manual").length>=8)return _("Manual Scanner limit reached (8 max).");let m=h==="auto"?Oe("autoScanner",e):Oe("manualScanner",e);if(e.cashw.id!==a.ref.id),et(e,m.x,m.y),me(e)}if(a.type==="scanner"){let m=ye(a.ref);Ne(a,m.x,m.y),e.scanners=e.scanners.filter(w=>w.id!==a.ref.id),et(e,m.x,m.y),me(e)}if(a.type==="facility"){let m=a.ref;Ne(a,m.x+m.w/2,m.y+m.h/2),delete e.facilities[m.id],et(e,m.x+m.w/2,m.y+m.h/2),me(e)}if(a.type==="maintenanceRoom"){let m=a.ref,w=q(m);Ne(a,w.x,w.y),e.maintenanceRooms=(e.maintenanceRooms||[]).filter(E=>E.id!==m.id),et(e,w.x,w.y)}e.selected=null,e.multiSelected=[],i()}function co(s){let a=Object.values(e.facilities).find(Q=>{if(s.x>=Q.x&&s.x<=Q.x+Q.w&&s.y>=Q.y&&s.y<=Q.y+Q.h)return!0;if(!Q.entry)return!1;let ke=B(Q.entry.col,Q.entry.row);return Math.abs(s.x-ke.x)<=f.cell*.46&&Math.abs(s.y-ke.y)<=f.cell*.46});if(a)return{type:"facility",ref:a};let h=He(s.x,s.y);if(!h)return null;let m=ft(e,h.col,h.row);if(m)return{type:"eggFarm",ref:m};let w=pt(e,h.col,h.row);if(w)return{type:"scanner",ref:w};let E=U(e,h.col,h.row);if(E)return{type:"maintenanceRoom",ref:E};let ne=A(h.col,h.row);return e.conveyorTiles.has(ne)?{type:"conveyor",oldKey:ne,ref:{type:"conveyor",id:ne}}:null}let Ut=$s({game:e,canvasPoint:o,updatePanels:i,equipmentAtPoint:co,fail:_,pointInGrid:ie,rectOfFacility:G,rectsOverlap:H});function js(s){return null}function vr(){let s=N();s&&(s.type==="conveyor"?Gt(B(...Object.values(te(s.id)))):s.type==="eggFarm"?Gt(B(s.col,s.row)):s.type==="scanner"?Gt(ye(s)):s.type==="facility"?Gt({x:s.x+s.w/2,y:s.y+s.h/2}):s.type==="maintenanceRoom"&&Gt(q(s)))}function Ke(s,a,h="primary-button"){let m=document.createElement("button");return m.type="button",m.className=h,m.textContent=s,m.addEventListener("click",a),m}function sn(){e.cardTargetPick?.mode==="autoScannerMenu"&&(e.cardTargetPick=null),t.modal.classList.remove("visible","equipment-popover"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function uo(s){t.modalTitle.textContent="Auto Scanner",e.cardTargetPick={pending:!0,mode:"autoScannerMenu",cardId:null,targetKeys:[`scanner:${s.id}`],remaining:1},t.modalBody.innerHTML=` +
+

Left / right output routing for this AUTO scanner.

+

Current: ${s.role===0?"Male left / others right":"Poop left / others right"}

+

Cooldown: ${nt(s).toFixed(1)}s.

+
`,t.modalActions.innerHTML="";let a=Ke("Male Left / Others Right",()=>{Be(e),s.role=0,sn(),i()},s.role===0?"facility-action warn":"facility-action"),h=Ke("Poop Left / Others Right",()=>{Be(e),s.role=1,sn(),i()},s.role===1?"facility-action warn":"facility-action");t.modalActions.append(a,h,Ke("Close",sn,"facility-action")),fo(s),t.modal.classList.add("visible","equipment-popover"),i()}function wr(s){return s?.label||s?.key||"?"}function Zs(s){let a=s.key===" "?"Space":s.key.length===1?s.key.toUpperCase():s.key.replace(/^Arrow/,"");return{key:s.key.toLowerCase(),code:s.code,label:a}}function el(s,a,h){for(let m of e.scanners.filter(w=>w.kind==="manual"))for(let w of["left","right"]){if(m.id===s.id&&w===a)continue;let E=m.keys?.[w];if(E&&(E.code===h.code||E.key===h.key))return!0}return!1}function ln(s,a=""){if(!s||s.kind!=="manual")return;t.modalTitle.textContent=`Manual Scanner #${s.id}`;let h=wr(s.keys?.left),m=wr(s.keys?.right),w=tl(s);t.modalBody.innerHTML=` +
+

Left route key: ${h}

+

Right route key: ${m}

+ ${a?`

${a}

`:""} + ${w?`

${w}

`:""} +
`,t.modalActions.innerHTML="",t.modalActions.appendChild(Ke("Set Left Key",()=>Sr(s,"left"),"facility-action warn")),t.modalActions.appendChild(Ke("Set Right Key",()=>Sr(s,"right"),"facility-action warn")),t.modalActions.appendChild(Ke("Close",sn,"facility-action")),fo(s),t.modal.classList.add("visible","equipment-popover")}function tl(s){let a=[{side:"left",binding:s.keys?.left},{side:"right",binding:s.keys?.right}];if(a[0].binding&&a[1].binding&&(a[0].binding.code===a[1].binding.code||a[0].binding.key===a[1].binding.key))return"Left and right keys conflict.";for(let h of a)if(h.binding)for(let m of e.scanners.filter(w=>w.kind==="manual"&&w.id!==s.id)){if(m.keys?.left&&(m.keys.left.code===h.binding.code||m.keys.left.key===h.binding.key))return`Key conflicts with Manual Scanner #${m.id} left.`;if(m.keys?.right&&(m.keys.right.code===h.binding.code||m.keys.right.key===h.binding.key))return`Key conflicts with Manual Scanner #${m.id} right.`}return""}function Sr(s,a){t.modalBody.innerHTML=`

Press a key for ${a.toUpperCase()} route.

Esc cancels.

`,t.modalActions.innerHTML="";let h=m=>{if(m.preventDefault(),m.stopPropagation(),window.removeEventListener("keydown",h,!0),m.key==="Escape")return ln(s);let w=Zs(m),E=el(s,a,w);Be(e),s.keys=s.keys||{left:null,right:null},s.keys[a]=w,i(),ln(s,E?`${w.label} assigned, but another scanner already uses it.`:`${a.toUpperCase()} set to ${w.label}.`)};window.addEventListener("keydown",h,!0)}function nl(){let s=N();if(!(!s||s.type!=="scanner"))return s.kind==="auto"?uo(s):ln(s)}function ol(s){if(!s)return{x:80,y:80};if(s.type==="conveyor"){let a=te(s.id);return B(a.col,a.row)}return s.type==="eggFarm"?B(s.col,s.row):s.type==="scanner"?ye(s):s.type==="facility"?{x:s.x+s.w/2,y:s.y+10}:{x:80,y:80}}function fo(s){let a=n.getBoundingClientRect(),h=ol(s),m=e.view?.scale||1,w=a.left+(h.x*m+(e.view?.x||0))/n.width*a.width+18,E=a.top+(h.y*m+(e.view?.y||0))/n.height*a.height-12,ne=Math.max(12,window.innerWidth-274),Q=Math.max(12,window.innerHeight-220);t.modal.style.setProperty("--popover-x",`${Math.max(12,Math.min(ne,w))}px`),t.modal.style.setProperty("--popover-y",`${Math.max(12,Math.min(Q,E))}px`)}function kr(){let s=N();if(!s)return;let a=gr(s);if(t.modalTitle.textContent=j(s),t.modalBody.innerHTML=` +
${a.map(w=>`

${w}

`).join("")}
+ ${["mixer","truck"].includes(s.baseId||s.id)?'

Income/Fine = ceil(base x 1.10^upgrades)

':""}`,t.modalActions.innerHTML="",s.type==="scanner"&&s.kind==="auto"&&t.modalActions.appendChild(Ke("Auto Menu",()=>uo(s),"facility-action warn")),s.type==="scanner"&&s.kind==="manual"&&t.modalActions.appendChild(Ke("Set Keys",()=>ln(s),"facility-action warn")),s.type==="conveyor"&&po(s.id)){let w=e.conveyorMeta.get(s.id)?.branchMode||"random";t.modalActions.appendChild(Ke(`Branch: ${Cr(w)}`,()=>{yo(s.id),e.selected={type:"conveyor",id:s.id},kr()},"facility-action warn branch-action"))}let h=s.type==="conveyor"?{type:"conveyor",oldKey:s.id,ref:s}:{type:s.type,ref:s},m=Ae(h);if(m){let w=Ke(m,()=>{},"facility-action danger disabled");w.disabled=!0,t.modalActions.appendChild(w)}else{let w=mt(h,e),E=w.sameBuild?`Remove / Refund ${x(w.amount)}`:`Sell ${x(w.amount)}`;t.modalActions.appendChild(Ke(E,()=>{vr(),sn()},"facility-action danger"))}fo(s),t.modal.classList.add("visible","equipment-popover")}function rl(s){e.phase==="build"&&(p(),e.buildTool=e.buildTool===s?null:s,e.selected=null,e.multiSelected=[],e.selectionBox=null,i())}function il(){let s=[];for(let[a,h]of Object.entries(e.facilities))if(s.push({id:`facility:${a}`,price:J({type:"facility",ref:h}),x:h.x,y:h.y,w:h.w,h:h.h}),h.entry){let m=B(h.entry.col,h.entry.row);s.push({id:`facilityPort:${a}`,price:J({type:"facility",ref:h}),x:m.x-18,y:m.y-18,w:36,h:36})}for(let a of e.maintenanceRooms||[]){let h=q(a);s.push({id:`maintenanceRoom:${a.id}`,price:J({type:"maintenanceRoom",ref:a}),x:h.x-f.cell,y:h.y-f.cell,w:f.cell*2,h:f.cell*2})}for(let a of e.eggFarms){let h=B(a.col,a.row);s.push({id:`eggFarm:${a.id}`,price:J({type:"eggFarm",ref:a}),x:h.x-24,y:h.y-24,w:48,h:48})}for(let a of e.scanners){let h=ye(a);s.push({id:`scanner:${a.id}`,price:J({type:"scanner",ref:a}),x:h.x-50,y:h.y-73,w:100,h:146})}for(let a of e.conveyorTiles){let h=te(a),m=B(h.col,h.row),w=e.conveyorMeta.get(a)||{};s.push({id:`conveyor:${a}`,price:w.price||Oe(w.kind==="boostConveyor"?"boostConveyor":"conveyor",e),x:m.x-22,y:m.y-22,w:44,h:44})}return s}function Cr(s){return I[s]||I.random}function Vc(s){return Cn(s)}function po(s){return e.conveyorTiles.has(s)?Te(te(s)):!1}function Mr(s){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return null;for(let a of e.conveyorTiles){if(!po(a))continue;let h=te(a),m=B(h.col,h.row),w=m.x-$.w/2,E=m.y+$.y-$.h/2;if(s.x>=w&&s.x<=w+$.w&&s.y>=E&&s.y<=E+$.h)return a}return null}function sl(s){let a=Mr(s);return a?yo(a):!1}function yo(s){let a=e.conveyorMeta.get(s);if(!a)return!1;let h=ro(s);if(h.length<2)return!1;Be(e);let m=T.includes(a.branchMode)?a.branchMode:"random",w=["random",...de.map(E=>E.name).filter(E=>h.includes(E))];return a.branchMode=w[(Math.max(0,w.indexOf(m))+1)%w.length],me(e),e.selected=null,e.multiSelected=[],i(),!0}function gr(s){Se(e);let a=[],h=s?.type==="facility"?s.baseId||s.id:"";if(s.type==="eggFarm"){let[m,w]=dn(s);a.push(`Price: ${x(J(s))}`);{let E=Ae({type:s.type,ref:s});a.push(E?`Sale: blocked (${E})`:`Sale value: ${x(mt({type:s.type,ref:s},e).amount)}`)}a.push(`Level: ${s.level}/4`),a.push(`Random interval: ${m.toFixed(2)}-${w.toFixed(2)}s`),a.push(`Durability: ${bn(s)}% | Spawn delay x${Yn(s).toFixed(2)}`)}else if(s.type==="scanner")a.push(`Price: ${x(J(s))}`),a.push(`Sale value: ${x(mt({type:s.type,ref:s},e).amount)}`),a.push(`Type: ${s.kind.toUpperCase()} / Standard`),s.kind==="auto"&&a.push(`Role: ${s.role===0?"Male left / Others right":"Poop left / Others right"}`),a.push(`Queue: ${s.queue.length}`),s.kind==="auto"&&a.push(`Cooldown: ${s.cooldown.toFixed(1)}s / ${nt(s,e).toFixed(1)}s`),s.kind==="auto"&&a.push(`Durability: ${bn(s)}% | Delay x${qn(s).toFixed(2)}`),s.kind==="manual"&&a.push("Durability: none | Always normal");else if(s.type==="conveyor"){let m=e.conveyorMeta.get(s.id),w=e.componentLookup?.get(s.id),E=w?e.congestion.get(w):null;a.push(`Price: ${x(J({type:"conveyor",oldKey:s.id,ref:s}))}`),a.push(`Cell: ${s.id}`),a.push(`Type: ${m?.kind==="boostConveyor"?"BOOST BELT":"Normal Belt"} | Speed x${Number(m?.speedMultiplier||1).toFixed(1)}`),a.push(`Congestion: ${E?Math.floor(E.ratio*100):0}%`),a.push(`Durability: ${bn({meta:m})}% | Speed x${Hn({meta:m}).toFixed(2)}`),po(s.id)?(a.push(`Branch mode: ${Cr(m?.branchMode||"random")}`),a.push("Click the Branch button or the large on-belt badge to cycle RANDOM / fixed exit.")):a.push("Branch mode: needs 3+ conveyor connections."),a.push(`Sale value: ${x(mt({type:"conveyor",oldKey:s.id,ref:s},e).amount)}`)}else if(s.type==="maintenanceRoom")a.push(`Price: ${x(J({type:"maintenanceRoom",ref:s}))}`),a.push(`Sale value: ${x(mt({type:"maintenanceRoom",ref:s},e).amount)}`),a.push("Size: 2\xD72 grid cells"),a.push("Dispatch: 1 repairman during each production day");else if(s.type==="facility"){a.push(`Price: ${x(J(s))}`);{let m=Ae({type:s.type,ref:s});a.push(m?`Sale: blocked (${m})`:`Sale value: ${x(mt({type:s.type,ref:s},e).amount)}`)}if(a.push(["mixer","truck","trash"].includes(s.id)?`Level: ${s.level} / no cap`:`Level: ${s.level}`),h==="truck"&&a.push("Durability: none | Always normal"),["mixer","trash"].includes(h)&&a.push(`Durability: ${bn(s)}% | Extra delay ${Zo(e,s).toFixed(2)}s`),h==="mixer"&&(a.push(`Income: ${x(ze(e))} per chick | upgrade x${yt(e,"mixer").toFixed(3)}`),a.push(`Poop fine: -${x(pn(e))}`)),h==="truck"&&(a.push(`Income: ${x(Fe(e))} per target cargo | upgrade x${yt(e,"truck").toFixed(3)}`),a.push(`Poop shipment fine: -${x(yn(e))}`)),h==="trash"){let m=It(e),w=ht(m);a.push(`Bonus cards: ${m}/${Vt()}`),a.push(`Poop income bonus: ${x(w)} per processed poop.`),a.push("With enough upgrades, poop can out-earn male/female routes.")}s.entry&&a.push(`Receiver: edge cell ${s.entry.col},${s.entry.row} (${s.side})`)}return a}function ll(s){if(!s||e.phase!=="build")return"";let a=Ln(e).find(h=>h.type===s.type&&h.id===s.id);return a?a.message||"Not connected to conveyor route":""}function al(s){return s?s.type==="conveyor"&&e.conveyorMeta.get(s.id)?.kind==="boostConveyor"?"Moves chicks twice as fast. Wears down like a normal belt.":s.type==="conveyor"?"A stubborn belt tile. It only cares about the next cell.":s.type==="eggFarm"?"A tiny gatehouse producing questionable eggs on schedule.":s.type==="scanner"&&s.kind==="auto"?"Slower than hands without upgrades.":s.type==="scanner"?"A manual checkpoint. The operator is the algorithm.":s.type==="facility"&&(s.baseId||s.id)==="mixer"?"Male chicks become revenue here. Do not feed it poop.":s.type==="facility"&&(s.baseId||s.id)==="trash"?"Poop goes in. Sometimes coins come out, for reasons best left unaudited.":s.type==="facility"&&(s.baseId||s.id)==="truck"?"The shipping endpoint. Correct cargo pays; wrong cargo complains.":s.type==="maintenanceRoom"?"A cramped 2\xD72 storage and break room with lockers, spare parts, a bench and one dispatched repairman.":"Factory equipment.":""}return{buildAtCell:v,buildAtPoint:M,eraseAtPoint:Gt,equipmentAtPoint:co,startSelectionBox:Ut.startSelectionBox,updateSelectionBox:Ut.updateSelectionBox,finishSelectionBox:Ut.finishSelectionBox,startGroupDrag:Ut.startGroupDrag,updateGroupDrag:Ut.updateGroupDrag,finishGroupDrag:Ut.finishGroupDrag,selectedObject:N,selectedTitle:j,equipmentPrice:J,selectedUpgradeCost:js,selectedInfoLines:gr,flavorText:al,disconnectedWarningFor:ll,gridExpansionCost:O,buyGridExpansion:se,expansionOfferAtPoint:he,beginConveyorDrag:ao,continueConveyorDrag:d,endConveyorDrag:p,cycleSingleConveyorDirection:Ct,branchSwitcherAtPoint:Mr,cycleBranchModeAtPoint:sl,cycleBranchModeForKey:yo,removeSelected:vr,switchScannerRole:nl,showManualScannerMenu:ln,showAutoScannerMenu:uo,showSelectedMenu:kr,setBuildTool:rl,fail:_,isEquipmentCell:F,equipmentHitBoxes:il,routeFromFarmToScanner:Dt}}function Bs({game:e,ui:t,build:n,startGame:o,beginCardDraft:r,activeQueuedChick:i}){function l(F){return String(F).replace(/[&<>"']/g,U=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[U])}function c(){return Math.round(Xn(e))}function b(){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return!1;let F=!1;for(let U of So)if(F=!0,e.cash>=Oe(U,e))return!1;return F}function C(){T(),I(),ee(),O(),$()}function T(){for(let[U,S]of Object.entries(t.buttons))S?.classList?.contains("tool-button")&&S.classList.toggle("active",e.buildTool===U);for(let U of So){let S=t.buttons[U];if(!S)continue;let g=Oe(U,e),N=S.querySelector("span");N&&(N.textContent=U==="conveyor"||U==="boostConveyor"?`${x(g)} / tile`:x(g));let j=U==="manualScanner"&&e.scanners.filter(pe=>pe.kind==="manual").length>=8,J=e.cashDt(e,j)?.scannerId).length,U=fn(e),S=Math.max(0,Math.floor(e.lastResult?.profit??e.stats?.profit??0)),g=Math.max(1,Number(e.turn)||1),N=_n(e,g,S);t.turnSummary.innerHTML=[`Seed: ${l(e.runSeed||"none")} | Grid box: ${e.gridRows||10}x${e.gridCols||20} | Owned: ${e.gridOwnedCells||e.ownedCells?.size||(e.gridRows||10)*(e.gridCols||20)} cells | Blocked: ${e.blockedCells?.size||0} cells`,`Truck target: ${je(e).toUpperCase()} | Male fine: -${x(Uo(e))}`,`Poop fine: Mixer -${x(pn(e))} / Shipment -${x(yn(e))}`,`Fairies tribute on Next Day: -${x(N.amount)} | base ${x(N.base)} + profit share ${x(N.profitTribute)} | basis net ${x(S)} | exemption ${x(N.profitExemption)}${N.reduction?` | reduction -${x(N.reduction)}`:""}`,`Maintenance: worst ${or(e).worst.percent}% dirty (${or(e).worst.label}) | Repair rooms: ${(e.maintenanceRooms||[]).length} | Repairmen: ${(e.repairmen||[]).length}`,`Manual combo: ${e.manualCombo?.count||0} | Card draft: ${e.cardDraft?.pending?Math.max(1,e.cardDraft.picksRemaining||1)+" pick(s) left":"ready after each day"} | Belt: ${c()}px/s | Farms with scanner route: ${F}/${e.eggFarms.length}`,e.cardEffects?.usedMachineActive?'Procurement: USED MACHINE MODE / no refunds / 60% durability':"",U.length?`Blocked: ${U[0]}`:`${oe.status.allPortsConnected}`].join("
")}function ee(){if(!t.eventPanel)return;let F=e.eventOffer;if(e.phase!=="build"){t.eventPanel.innerHTML=oe.status.eventPanelRunning;return}if(!F){t.eventPanel.className="event-card empty",e.turn+1Event lock active.No irregular events during Days 1-7. First possible forced event: Day ${xt}.`:t.eventPanel.innerHTML="No event.Random forced events can appear later.";return}t.eventPanel.className="event-card accepted",t.eventPanel.innerHTML=` +
FORCED NEXT DAY
+

${F.title}

+
+ Effect: ${F.route} + ${F.targetAmount?`Target: ${F.targetAmount}`:"Target: none"} + ${F.reward?`Reward: ${x(F.reward)}`:"Reward: none"} + Time ${F.daySeconds||60}s / Output x${Number(F.productionMultiplier||1).toFixed(2)} / Poop +${Math.round((F.poopRateAdd||0)*100)}pt +
`}function X(){T(),t.shell.classList.toggle("phase-running",e.phase==="running"),t.shell.classList.toggle("phase-build",e.phase==="build"),t.shell.classList.toggle("phase-gameover",e.phase==="gameover"),t.shell.classList.toggle("phase-title",e.phase==="title"),t.shell.classList.toggle("phase-loanDecision",e.phase==="loanDecision"),t.money.textContent=x(e.cash),t.money.classList.toggle("cash-negative",e.cash<0),t.money.classList.toggle("cash-positive",e.cash>an),t.turn.textContent=e.turn,t.timeLeft.textContent=e.phase==="running"&&e.timeLeft<=0&&e.shutdownTimeLeft>0?`+${e.shutdownTimeLeft.toFixed(1)}s`:`${Math.max(0,e.timeLeft).toFixed(1)}s`,t.timeLeft.closest?.(".hud-card")?.classList.toggle("time-critical",e.phase==="running"&&(e.timeLeft<=10||e.timeLeft<=0&&e.shutdownTimeLeft>0)),t.phase.textContent=he(),t.comboCount&&(t.comboCount.textContent=e.manualCombo?.count||0),ae(),t.turnProfit.textContent=x(e.stats.profit),t.turnProfit.classList.toggle("cash-negative",e.stats.profit<0),t.turnProfit.classList.toggle("cash-positive",e.stats.profit>0),t.mixerCount.textContent=e.stats.mixerCount,t.truckFemaleCount.textContent=e.stats.truckFemale,t.truckMaleCount.textContent=e.stats.truckMale,t.poopCount.textContent=e.stats.poopSpawned,t.buttons.s1Left.disabled=e.phase!=="running"||!i(0),t.buttons.s1Right.disabled=e.phase!=="running"||!i(0),t.buttons.s2Left.disabled=e.phase!=="running"||!i(1),t.buttons.s2Right.disabled=e.phase!=="running"||!i(1);let F=e.scanners.find(N=>N.kind==="manual"&&N.slot===0),U=e.scanners.find(N=>N.kind==="manual"&&N.slot===1);F&&(t.buttons.s1Left.textContent=`S1 ${F.keys?.left?.label||"A"} -> Mixer`,t.buttons.s1Right.textContent=`S1 ${F.keys?.right?.label||"D"} -> S2`),U&&(t.buttons.s2Left.textContent=`S2 ${U.keys?.left?.label||"Left"} -> Waste`,t.buttons.s2Right.textContent=`S2 ${U.keys?.right?.label||"Right"} -> Truck`);let S=Math.max(0,Math.floor(e.lastResult?.profit??e.stats?.profit??0)),g=_n(e,Math.max(1,Number(e.turn)||1),S).amount;t.buttons.nextTurn.textContent=e.phase==="build"&&g>0?`Next Day - Fairies ${x(g)}`:oe.actions.nextDay,t.buttons.nextTurn.disabled=e.phase!=="build"||!!e.cardDraft?.pending||!!e.cardTargetPick?.pending||!yi(e)}function ae(){if(!t.eventBrief||!t.targetBrief||!t.speedBrief)return;let F=je(e).toUpperCase();t.targetBrief.textContent=`TRUCK TARGET: ${F}`,t.speedBrief.textContent=`BELT SPEED: ${c()} px/s`,t.speedBrief.title=`Conveyor speed does not increase by day. Degraded belts reduce speed. Cap: ${Wt}px/s.`;let U=e.eventActive,S=e.eventOffer;U?(t.eventBrief.textContent=`ACTIVE EVENT: ${U.title} | ${U.route}`,t.eventBrief.className="event-brief active"):e.phase==="build"&&S?(t.eventBrief.textContent=`NEXT DAY EVENT: ${S.title} | ${S.route}${S.targetAmount?` | Target ${S.targetAmount}`:""}${S.reward?` | Reward ${x(S.reward)}`:""}`,t.eventBrief.className="event-brief next"):e.phase==="build"&&e.turn+1
\u2642Male->MixerS1: A
\u2640Female->TruckS1: D, then S2: right
\u{1F4A9}Poop->ShredderS1: D, then S2: left

Build phase: connect at least one EGG through a scanner to Mixer, Shredder, or Truck before Next Day. One day is one run.

',t.modalActions.innerHTML="",t.modalActions.appendChild(G(oe.actions.startGame,o,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function se(F){let U=j=>`${j>0?"+":""}${x(j)}`,S=j=>`${j>0?"-":""}${x(j)}`,g=F.profit>=0?"cash-positive":"cash-negative",N=(F.mixerPoopFine||0)+(F.truckPoopFine||0)+(F.maleTruckFine||0)+(F.explosionDamage||0)+(F.cardRerollCost||0);t.modalTitle.textContent=`Day ${F.turn} Settlement`,t.modalBody.innerHTML=` +
Net result${x(F.profit)}
+
+
Chick shipment income${U(F.chickShipmentIncome||0)}
+
Poop shipment income${U(F.poopShipmentIncome||0)}
+
Mixer income${U(F.mixerRevenue||0)}
+
Composter income${U(F.composterIncome||0)}
+
DUD refund income${U(F.dudRefundIncome||0)}
+
Manual combo bonus${U(F.manualComboBonus||0)}
+
Chemical subsidy${U(F.chemicalWeaponSubsidy||0)}
+
Event bonus${U(F.eventBonus||0)}
+
Penalties${S(N)}
+
Fairies fee${S(F.fairiesTribute?.amount||F.fairiesTribute||0)}
+
+

Income ${x(F.revenue)} - losses ${x(F.penalty)} = ${x(F.profit)}

`,t.modalActions.innerHTML="",t.modalActions.appendChild(G("Choose Upgrade Card",r||H,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function ie(F,U){let S=Math.max(0,e.cardEffects?.rescueLoanCharges||0);t.modalTitle.textContent="Emergency Loan Available",t.modalBody.innerHTML=` +

End-of-day cash is below ${x(0)}.

+
+
Current money${x(e.cash)}
+
Emergency Loan+${x(500)}
+
Cards remaining${S}
+
+

Use one Emergency Loan to gain ${x(500)} immediately. If cash is still negative, another decision will be shown if another card remains.

`,t.modalActions.innerHTML="",t.modalActions.appendChild(G("Accept Game Over",U,"facility-action danger")),t.modalActions.appendChild(G("Use Emergency Loan",F,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function P(){let F=e.totals.processed,U=F?Math.round(e.totals.correct/F*100):0,S=_i(e);t.modalTitle.textContent=oe.phases.gameover,t.modalBody.innerHTML=`

Your cash went negative.

+
Final Score${S.score}
Survival${e.totals.turnsCompleted} days
Final Cash${x(e.cash)}
Accuracy${U}%
+
Score breakdown +
Formula
Base = Cash + Total revenue + Factory value \xD70.5 + Event bonus \xD70.5 = ${x(S.base)}
Daily earned = ceil(Base \xF7 Days) = ${x(S.dailyEarned)}
Score = max(0, floor(Base + Daily earned + Correct bonus - Total outflow - Day penalty)) = ${S.score}
+
Factory Value${x(S.factoryValue)}
Total Revenue${x(e.totals.revenue)}
Daily Earned${x(S.dailyEarned)} / day
Total Outflow${x(e.totals.penalty)}
Fairies Tribute${x(e.totals.fairiesTribute||0)}
Correct Sorts${e.totals.correct}
Auto Sorted${e.totals.autoSorted}
Poop Control${e.totals.poopTrash} trashed / ${e.totals.poopTruck} shipped / ${e.totals.poopMixer} mixer
Explosion Penalty${x(e.totals.explosionDamage)}
Event Bonus${x(e.totals.eventBonus)}
Day Penalty-${S.dayPenalty}
Events${e.totals.eventSuccess} success / ${e.totals.eventFailed} failed
+
`,t.modalActions.innerHTML="",t.modalActions.appendChild(G(oe.actions.restart||"Restart",o,"primary-button restart-button")),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible","gameover-modal")}function G(F,U,S="primary-button"){let g=document.createElement("button");return g.type="button",g.className=S,g.textContent=F,g.addEventListener("click",U),g}function H(){t.modal.classList.remove("visible","equipment-popover","gameover-modal"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function be(){}return{updatePanels:C,updateUI:X,showTitle:re,showTurnResult:se,showEmergencyLoanDecision:ie,showGameOver:P,hideModal:H,checkGameOver:be}}function br(e){e.totals.processed+=1}function Zt(e){e.stats.correct+=1,e.totals.correct+=1}function vt(e){e.stats.mistakes+=1,e.totals.mistakes+=1}function Ls(e){e.stats.autoSorted+=1,e.totals.autoSorted+=1}function Os(e){e.stats.poopSpawned+=1}function Ns(e){e.stats.mixerCount+=1,br(e)}function _s(e){e.stats.trashCount+=1,br(e)}function Gs(e,t){t==="female"?e.stats.truckFemale+=1:t==="male"&&(e.stats.truckMale+=1),br(e)}function Zn(e,t){let n=t==="truck"?"poopTruck":t==="trash"?"poopTrash":t==="mixer"?"poopMixer":null;n&&(e.stats[n]+=1,e.totals[n]+=1)}function Us({game:e,currentConveyorSpeed:t,onGameOverCheck:n}){function o(d){return Rt(d)*Yn(d)*fs(e)/ki(e)}function r(d){let p=B(d.col,d.row),v=1+ps(e,d),M=l(d,v);if(!M.length)return i(d,p),!0;let k=0,R=0;for(let D of M){let q=B(D.col,D.row),le=c(q);if(le){le.stoppedTimer=.85,R+=1;continue}let Ne=Is(e,{stage:"belt",scannerId:null,route:[q]});Ne.sex==="poop"&&Os(e),e.chicks.push(Ne),Ji(e,d),k+=1}return k>0?(Ui(e,p.x,p.y),k>1&&K(e,p.x,p.y-28,`x${k}`,y.green),!0):R===0}function i(d,p){(d.noRouteNoticeCooldown||0)<=0&&(K(e,p.x,p.y-24,"NO BELT: PAUSED",y.warn),d.noRouteNoticeCooldown=2.5)}function l(d,p){let M=de.map(k=>({col:d.col+k.dc,row:d.row+k.dr})).filter(k=>Ee(k.col,k.row)&&e.conveyorTiles.has(A(k.col,k.row))).map(k=>({p:k,blocked:$(null,B(k.col,k.row))?1:0,roll:Math.random()}));return M.sort((k,R)=>k.blocked-R.blocked||k.roll-R.roll),M.slice(0,Math.max(1,p||1)).map(k=>k.p)}function c(d){return e.chicks.find(p=>p.stage!=="flying"&&Math.hypot(p.x-d.x,p.y-d.y)0;if(e.timeLeft=Math.max(0,e.timeLeft-d),M&&e.timeLeft<=0&&p(),e.timeLeft<=0){e.shutdownTimeLeft>0&&(e.shutdownTimeLeft=Math.max(0,e.shutdownTimeLeft-d));for(let k of e.eggFarms)k.shutterProgress=Math.min(1,(k.shutterProgress||0)+d*2.8)}if(M&&e.timeLeft>0){for(let k of e.eggFarms)if(k.noRouteNoticeCooldown>0&&(k.noRouteNoticeCooldown=Math.max(0,k.noRouteNoticeCooldown-d)),k.nextSpawn-=d,k.nextSpawn<=0){let R=r(k);k.nextSpawn=R?o(k):.15,k.lastInterval=k.nextSpawn}}for(let k=e.chicks.length-1;k>=0;k-=1){let R=e.chicks[k];R.bob+=d*7,R.stoppedTimer>0&&(R.stoppedTimer=Math.max(0,R.stoppedTimer-d)),R.stage!=="queued"&&T(R,k,d)}_(d),_t(),on(),e.timeLeft<=0&&(e.chicks.length===0?v():e.shutdownTimeLeft<=0&&C())}function C(){if(e.cleanupBlown)return;e.cleanupBlown=!0,e.cleanupTimer=1;let d=[...e.chicks];for(let p of d)qo(e,p.sex,p.x,p.y,-Math.PI/2,!0);e.chicks=[];for(let p of e.scanners)p.queue=[];if(_t(),d.length){let p=d.reduce((M,k)=>M+k.x,0)/d.length,v=d.reduce((M,k)=>M+k.y,0)/d.length;Xe(e,p,v,y.warn,58),K(e,p,v-24,"CLEANUP",y.warn)}}function T(d,p,v){if(I(d)){d.stoppedTimer=.35;return}if(pe(d,v),!(d.route&&d.targetIndex=d.route.length)return!1;let p=d.route[d.targetIndex];return $(d,p)}function $(d,p){if(!p)return!1;for(let v of e.chicks)if(!(d&&v.id===d.id)&&v.stage!=="flying"&&Math.hypot(v.x-p.x,v.y-p.y)1)&&d.push({x:p.x,y:p.y})}function ee(d){let p=e.conveyorMeta?.get?.(d)||{},v=[];Array.isArray(p.outDirs)&&v.push(...p.outDirs),p.dir&&v.push(p.dir);let M=[...new Set(v)].filter(le=>de.some(Ne=>Ne.name===le)),k=te(d),R=de.filter(le=>P(k,le.name)).map(le=>le.name),D=M.filter(le=>R.includes(le)),q=R;return D.length?D:q}function X(d){return de.find(p=>p.name===d)||null}function ae(d,p){return e.scanners.find(v=>v.col<=d&&d<=v.col+1&&v.row-1<=p&&p<=v.row+1)||null}function he(d,p){let v=X(p);if(!v)return null;let M=ae(d.col+v.dc,d.row+v.dr);if(!M)return null;let k=Re(M,"inputA");return k&&k.col===d.col&&k.row===d.row?M:null}function re(d){return Object.entries(e.facilities||{}).find(([,p])=>p?.entry&&p.entry.col===d.col&&p.entry.row===d.row)||null}function se(d){return d?.baseId||d?.id||""}function ie(d,p){return d.side==="left"&&p==="left"||d.side==="right"&&p==="right"||d.side==="top"&&p==="up"||d.side==="bottom"&&p==="down"}function P(d,p){let v=X(p);if(!v)return null;let M={col:d.col+v.dc,row:d.row+v.dr};if(Ee(M.col,M.row)&&e.conveyorTiles.has(A(M.col,M.row)))return{type:"conveyor",dirName:p,target:B(M.col,M.row),nextCell:M};let k=he(d,p);if(k)return{type:"scanner",dirName:p,target:ye(k),scanner:k};let R=re(d);return R&&ie(R[1],p)?{type:"facility",dirName:p,facilityId:R[0],facility:R[1],target:B(d.col,d.row)}:null}function G(d,p){let v=X(p);if(!v)return!1;let M=e.conveyorMeta?.get?.(A(d.col+v.dc,d.row+v.dr));return M?[...new Set([...Array.isArray(M.outDirs)?M.outDirs:[],M.dir].filter(Boolean))].includes(v.opposite):!1}function H(d){return de.filter(p=>Ee(d.col+p.dc,d.row+p.dr)&&e.conveyorTiles.has(A(d.col+p.dc,d.row+p.dr))).map(p=>p.name)}function be(d,p,v="random"){let M=H(d);if(M.length<3)return p;let k=new Set(M.filter(q=>G(d,q))),R=M.filter(q=>!k.has(q)),D=k.size&&R.length>=2?R:[...new Set(p.filter(q=>M.includes(q)))];return D.length<2&&(D=M),v&&v!=="random"&&v!=="pass"&&D.includes(v)?[v]:D}function F(d,p){return p&&(p.type==="facility"||!$(d,p.target))}function U(d,p,v,M="random"){let k=v.map(le=>P(p,le)).filter(Boolean);if(!k.length)return null;let D=k.filter(le=>le.type!=="facility").filter(le=>!$(d,le.target)),q=D.length?D:k.filter(le=>le.type==="facility");return q.length?q[Math.floor(Math.random()*q.length)]:null}function S(d,p){let v=[];O(v,{x:d.x,y:d.y}),O(v,p),d.route=v.length?v:[{x:d.x,y:d.y}],d.targetIndex=d.route.length>1?1:d.route.length}function g(d,p){let v=He(d.x,d.y);if(!v)return Mt(p,"OFF GRID");let M=A(v.col,v.row);if(!e.conveyorTiles.has(M))return Mt(p,"OFF BELT");let k=e.conveyorMeta?.get(M)||{},R=be(v,ee(M),k.branchMode||"random");if(!R.length){d.stoppedTimer=.25;return}let D=U(d,v,R,k.branchMode||"random");if(!D){d.stoppedTimer=.25;return}if(D.type==="facility"){let q=se(D.facility);q==="mixer"?io(p,D.facility):q==="truck"?Mn(p,D.facility):q==="trash"?so(p,D.facility):Mt(p,"DONE");return}D.type==="scanner"&&(d.pendingScannerId=D.scanner.id),d.prevConveyorCell=M,S(d,D.target)}function N(d){let p=He(d.x,d.y);if(!p)return null;let v=A(p.col,p.row);return e.conveyorTiles.has(v)?v:null}function j(d){let p=N(d)||N(d.route?.[d.targetIndex]||d);return t(p)}function J(d,p){let v=N(p);!v||d.lastWearKey===v||(d.lastWearKey=v,Qi(e,v))}function pe(d,p){let v=j(d)*p;for(;v>0&&d.targetIndex=D?(d.x=M.x,d.y=M.y,J(d,M),d.targetIndex+=1,v-=D):(d.x+=k/D*v,d.y+=R/D*v,v=0)}}function xe(d,p,v){d.stage="queued",d.route=null,d.queueRoute=v?v.map(M=>({x:M.x,y:M.y})):[ye(p)],d.scannerId=p.id,p.queue.includes(d.id)||p.queue.push(d.id),Pe(p)}function Pe(d){d.queue=d.queue.filter(v=>e.chicks.some(M=>M.id===v&&M.stage==="queued"));let p=f.cell*.86*ys(e);d.queue.forEach((v,M)=>{let k=e.chicks.find(R=>R.id===v);k&&(Ae(k,k.queueRoute||[ye(d)],M*p),k.queueIndex=M)})}function Ae(d,p,v){if(!p||!p.length)return;if(p.length===1||v<=0){let R=p[p.length-1];d.x=R.x,d.y=R.y;return}let M=v;for(let R=p.length-1;R>0;R-=1){let D=p[R-1],q=p[R],le=Math.hypot(q.x-D.x,q.y-D.y);if(M<=le){let Ne=1-M/le;d.x=D.x+(q.x-D.x)*Ne,d.y=D.y+(q.y-D.y)*Ne;return}M-=le}let k=p[0];d.x=k.x,d.y=k.y}function _(d){for(let p of e.scanners){if(p.cooldown>0&&(p.cooldown=Math.max(0,p.cooldown-d)),p.keyPressTime>0&&(p.keyPressTime=Math.max(0,p.keyPressTime-d)),Pe(p),p.kind!=="auto"||p.cooldown>0||!p.queue.length)continue;let v=p.queue[0],M=e.chicks.findIndex(k=>k.id===v);if(M<0){p.queue.shift();continue}nn(M,Io(p,e.chicks[M]),!0)&&(ji(e,p),p.cooldown=nt(p,e),Ls(e))}}function De(d){let p=Ro(e,d);return!p||!p.queue.length?null:e.chicks.find(v=>v.id===p.queue[0])||null}function Ye(d,p){if(e.phase!=="running")return;let v=Ro(e,d);Ve(v,p)}function Ve(d,p){if(e.phase!=="running"||!d||d.kind!=="manual"||(d.keyPressTime=.18,d.keyPressSide=p,!d.queue.length))return;let v=e.chicks.findIndex(M=>M.id===d.queue[0]);v>=0&&nn(v,p,!1)}function Te(d,p,v){return d.kind==="manual"&&Io(d,p)===v}function kt(d){let p=e.manualCombo?.count||0;if(e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=0,e.manualCombo.lastBonus=0,e.stats.manualComboFailure=(e.stats.manualComboFailure||0)+1,e.totals.manualComboFailure=(e.totals.manualComboFailure||0)+1,p>=10){let v=ye(d);Ft(e,10,.25),K(e,v.x,v.y-36,"COMBO RESET",y.danger)}}function oo(d){e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=Math.max(0,e.manualCombo.count||0)+1,e.stats.manualComboSuccess=(e.stats.manualComboSuccess||0)+1,e.totals.manualComboSuccess=(e.totals.manualComboSuccess||0)+1;let p=e.manualCombo.count;if(e.manualCombo.lastBonus=0,p<10)return 0;let v=Math.max(1,Math.floor(p/10)),M=e.scanners.filter(q=>q.kind==="manual").length,k=Math.min(1,(20+M*10)/100),R=0;for(let q=0;q0){Ge(e,D),e.stats.manualComboBonus=(e.stats.manualComboBonus||0)+D,e.totals.manualComboBonus=(e.totals.manualComboBonus||0)+D,e.manualCombo.lastBonus=D;let q=ye(d);K(e,q.x,q.y-42,`COMBO +${x(D)}`,y.green)}return D}function Cn(d,p){let v=Re(d,p);if(!v)return null;let M=A(v.col,v.row);if(e.conveyorTiles.has(M))return{...v};let R=(_e(e).scannerPorts.get(d.id)?.[p]?.keys||[]).filter(Boolean);if(!R.length)return null;let D=R.map(te);return D.find(le=>le.col===v.col&&le.row===v.row)||D[0]||null}function ro(d,p,v,M){let k=[];O(k,{x:d.x,y:d.y});let R=Re(p,v);return R&&O(k,B(R.col,R.row)),O(k,B(M.col,M.row)),k}function nn(d,p,v){let M=e.chicks[d];if(!M||M.stage!=="queued")return!1;let k=At(e,M.scannerId);if(!k)return!1;let R=Cn(k,p);if(!R)return!v&&k.kind==="manual"&&kt(k),K(e,M.x,M.y-16,p==="left"?"NO LEFT BELT":"NO RIGHT BELT",y.danger),!1;!v&&k.kind==="manual"&&(Te(k,M,p)?oo(k):kt(k)),k.queue=k.queue.filter(q=>q!==M.id),M.stage="belt",M.route=ro(M,k,p,R),M.targetIndex=M.route.length>1?1:M.route.length,M.scannerId=null,M.nextScannerId=null,M.pendingScannerId=null,M.queueRoute=null,M.queueIndex=-1;let D=v?y.green:p==="left"?y.mixerBlue:y.truckPink;return Wi(e,ye(k).x,ye(k).y,D),K(e,M.x,M.y-20,v?"AUTO":p.toUpperCase(),D),!0}function Ct(d){let p=e.chicks[d];return p?(e.chicks.splice(d,1),p):null}function io(d,p=e.facilities.mixer){if(p?.processingCooldown>0){let D=e.chicks[d];D&&(D.stoppedTimer=.25);return}let v=Ct(d);if(!v)return;let{x:M,y:k}=v;if(Ns(e),er(e,p),tr(e,p),v.sex==="poop"){let D=Ii(e);Zn(e,"mixer"),vt(e),Hi(e,M,k),K(e,M,k-18,`-${x(D)}`,y.danger);return}let R=Di(e);v.sex==="male"?Zt(e):vt(e),Ki(e,M,k),K(e,M,k-18,`+${x(R)}`,y.green)}function Mn(d,p=e.facilities.truck){let v=Ct(d);if(!v)return;let{x:M,y:k}=v;lo(v.sex,p),Yi(e,M,k,v.sex),Gs(e,v.sex);let R=je(e),D=Mi(e,v.sex);if(v.sex==="poop"){if(Zn(e,"truck"),D)Zt(e),K(e,M,k-18,`+${x(Fe(e))}`,y.green);else{let q=$i(e);vt(e),K(e,M,k-18,`-${x(q)}`,y.danger)}return}if(v.sex==="female"){D?(Zt(e),K(e,M,k-18,`+${x(Fe(e))}`,y.green)):(vt(e),K(e,M,k-18,R==="male"?"REJECT":"NO SALE",y.warn));return}if(D){Zt(e),K(e,M,k-18,`+${x(Fe(e))}`,y.green);return}if(gi(e)){let q=Fi(e);vt(e),K(e,M,k-18,`-${x(q)}`,y.danger)}else vt(e),K(e,M,k-18,"REJECT",y.warn)}function so(d,p=e.facilities.trash){if(p?.processingCooldown>0){let q=e.chicks[d];q&&(q.stoppedTimer=.25);return}let v=Ct(d);if(!v)return;let{x:M,y:k}=v;qi(e,M,k,v.sex),_s(e),er(e,p),tr(e,p);let R={amount:0},D="";if(v.sex==="poop"){R=Ri(e),D=R.amount>0?` +${x(R.amount)}`:"",Zn(e,"trash"),Zt(e);let q=Math.ceil(Math.max(0,Number(e.cardEffects?.composter)||0)*3*On(e));if(q>0){let le=Ge(e,q);e.stats.composterIncome=(e.stats.composterIncome||0)+le,e.totals.composterIncome=(e.totals.composterIncome||0)+le,K(e,M,k-36,`COMPOST +${x(le)}`,y.green)}K(e,M,k-18,`CLEAN${D}`,R.amount>0?y.green:y.green)}else vt(e),K(e,M,k-18,R.amount>0?`WASTE${D}`:"WASTE",R.amount>0?y.green:y.ink)}function Mt(d,p){let v=Ct(d);v&&K(e,v.x,v.y-12,p,y.muted)}function lo(d,p=e.facilities.truck){let v=p||e.facilities.truck;v&&(e.truckCargo.push({sex:d,x:W(22,v.w-22),y:W(66,v.h-24)}),e.truckCargo.length>45&&e.truckCargo.shift())}function gn(d){let p=He(d.x,d.y);if(p){let R=A(p.col,p.row);if(e.conveyorTiles.has(R))return R}let v=ui(e,d.x,d.y);if(!v)return null;let M=te(v),k=B(M.col,M.row);return Math.hypot(d.x-k.x,d.y-k.y)<=f.cell*.55?v:null}function _t(){let{components:d,cellToComponent:p}=ci(e);for(let v of e.chicks){if(v.stage==="flying")continue;let M=gn(v);if(!M)continue;let k=p.get(M),R=d.get(k);R&&(R.count+=1)}for(let v of d.values())v.ratio=v.count/v.capacity;e.congestion=d,e.componentLookup=p}function on(){for(let d of e.congestion.values()){let p=_o(e),v=xi(e);if(d.ratio>v&&d.ratio=p){let M=rn(d.id);if(!M.length||M.some(D=>D.stage!=="queued"&&D.stoppedTimer<=.2))continue;let k=e.lastExplodedComponent.get(d.id)||0,R=performance.now();R-k>900&&(e.lastExplodedComponent.set(d.id,R),ao(d))}}}function rn(d){return e.chicks.filter(p=>{let v=gn(p);return v&&e.componentLookup?.get(v)===d})}function ao(d){let p=rn(d.id);if(!p.length)return;for(let k of p)qo(e,k.sex,k.x,k.y);e.chicks=e.chicks.filter(k=>!p.some(R=>R.id===k.id));for(let k of e.scanners)k.queue=k.queue.filter(R=>e.chicks.some(D=>D.id===R));for(let k of d.cells){let R=te(k),D=B(R.col,R.row);Xe(e,D.x,D.y,y.danger),Ze(e,D.x,D.y,6),Gn(e,D.x,D.y,4)}Ft(e,18,.75);let v=te(d.cells[0]),M=B(v.col,v.row);e.stats.explosions=(e.stats.explosions||0)+1,e.totals.explosions=(e.totals.explosions||0)+1,K(e,M.x,M.y-22,`${Math.round(_o(e)*100)}% JAM EXPLOSION`,y.danger)}return{activeQueuedChick:De,currentSpawnDelay:o,sortSlot:Ye,updateCongestion:_t,sortScanner:Ve,updateRunning:b}}var fe=document.getElementById("gameCanvas"),kc=fe.getContext("2d"),L={shell:document.getElementById("gameShell"),money:document.getElementById("money"),turn:document.getElementById("turn"),timeLeft:document.getElementById("timeLeft"),phase:document.getElementById("phaseLabel"),comboCount:document.getElementById("comboCount"),eventBrief:document.getElementById("eventBrief"),targetBrief:document.getElementById("targetBrief"),speedBrief:document.getElementById("speedBrief"),turnProfit:document.getElementById("turnProfit"),mixerCount:document.getElementById("mixerCount"),truckFemaleCount:document.getElementById("truckFemaleCount"),truckMaleCount:document.getElementById("truckMaleCount"),poopCount:document.getElementById("poopCount"),buildStatus:document.getElementById("buildStatus"),turnSummary:document.getElementById("turnSummary"),eventPanel:document.getElementById("eventPanel"),modal:document.getElementById("modal"),modalTitle:document.getElementById("modalTitle"),modalBody:document.getElementById("modalBody"),modalActions:document.getElementById("modalActions"),hoverTooltip:document.getElementById("hoverTooltip"),manualScannerMonitor:document.getElementById("manualScannerMonitor"),debug:{panel:document.getElementById("debugPanel"),infiniteCash:document.getElementById("debugInfiniteCash"),dayInput:document.getElementById("debugDayInput"),setDay:document.getElementById("debugSetDayButton"),zeroTimer:document.getElementById("debugZeroTimerButton"),cardSelect:document.getElementById("debugCardSelect"),targetSelect:document.getElementById("debugTargetSelect"),grantCard:document.getElementById("debugGrantCardButton"),grantAllCards:document.getElementById("debugGrantAllCardsButton"),readout:document.getElementById("debugReadout")},buttons:{s1Left:document.getElementById("scanner1MixerButton"),s1Right:document.getElementById("scanner1TruckButton"),s2Left:document.getElementById("scanner2MixerButton"),s2Right:document.getElementById("scanner2TruckButton"),nextTurn:document.getElementById("nextTurnButton"),conveyor:document.getElementById("buildConveyorButton"),boostConveyor:document.getElementById("buildBoostConveyorButton"),eggFarm:document.getElementById("buildEggFarmButton"),autoScanner:document.getElementById("buildAutoScannerButton"),manualScanner:document.getElementById("buildManualScannerButton"),mixer:document.getElementById("buildMixerButton"),trash:document.getElementById("buildTrashButton"),truck:document.getElementById("buildTruckButton"),maintenanceRoom:document.getElementById("buildMaintenanceRoomButton"),erase:document.getElementById("eraseButton"),undo:document.getElementById("undoButton"),redo:document.getElementById("redoButton")}};function Cc(){let e={conveyor:"conveyor",boostConveyor:"boostConveyor",eggFarm:"eggFarm",autoScanner:"autoScanner",manualScanner:"manualScanner",mixer:"mixer",trash:"trash",truck:"truck",maintenanceRoom:"maintenanceRoom"};for(let[t,n]of Object.entries(e))L.buttons[t]&&(L.buttons[t].innerHTML=Or(n))}function Mc(e){let t=new Set(e.tags||[]);return["upgradeEgg","crowdedFarming","hatchingFeed","extraEggOutlet"].includes(e.id)||t.has("EGG")?"Production / EGG":["upgradeTrash","poopRateBooster","composter","chemicalWeaponSubsidy"].includes(e.id)||t.has("POOP")?"Poop / Shredder":["upgradeAutoScanner","autoScannerTuning","scannerQueueSpacing"].includes(e.id)||t.has("SCANNER")?"Scanner":["bearing","dynamite"].includes(e.id)||t.has("CONVEYOR")?"Conveyor / Map":["safetyCover","preventiveMaintenance","durabilityCoating","sparePartsBin","laborExploitation"].includes(e.id)||t.has("MAINTENANCE")?"Maintenance / Risk":["dudFilter","dudRefund","freeReroll","extraCards"].includes(e.id)||t.has("CARD")?"Card Engine":t.has("ULTRA RARE")?"Ultra Rare":t.has("ECONOMY")||["upgradeMixer","upgradeTruck","recyclingSubsidy","usedMachine","newMachine","flattery","legalWork","rescueLoan"].includes(e.id)?"Economy / Shipment":"Other"}function gc(){if(!L.debug?.panel||!L.debug.cardSelect)return;let e=["Production / EGG","Poop / Shredder","Scanner","Conveyor / Map","Maintenance / Risk","Card Engine","Economy / Shipment","Ultra Rare","Other"],t=new Map(e.map(n=>[n,[]]));for(let n of Qt){let o=Mc(n);t.has(o)||t.set(o,[]),t.get(o).push(n)}L.debug.cardSelect.innerHTML="";for(let n of e){let o=t.get(n)||[];if(!o.length)continue;let r=document.createElement("optgroup");r.label=n;for(let i of o){let l=document.createElement("option");l.value=i.id;let c=i.rarity==="ultraRare"?"UR":i.rarity==="rare"?"R":"C";l.textContent=`[${c}] ${i.title}`,r.appendChild(l)}L.debug.cardSelect.appendChild(r)}L.debug.cardSelect.addEventListener("change",Ot),Ot()}function Ot(){if(!L.debug?.targetSelect)return;let e=L.debug.cardSelect?.value,t=Jt(e),n=t?hs(u,t):[];if(L.debug.targetSelect.innerHTML="",!n.length){let r=document.createElement("option");r.value="__none__",r.textContent=t?"No target required":"No card selected",L.debug.targetSelect.appendChild(r),L.debug.targetSelect.disabled=!0;return}let o=document.createElement("option");o.value="__auto__",o.textContent=t?.id==="dynamite"?"Auto: first 3 blocked cells":"Auto: first valid target",L.debug.targetSelect.appendChild(o);for(let r of n){let i=document.createElement("option");i.value=r.key,i.textContent=r.label,L.debug.targetSelect.appendChild(i)}L.debug.targetSelect.disabled=!1}function xc(){let e=Math.max(1,Math.floor(Number(L.debug.dayInput?.value)||1));u.turn=e,L.debug.dayInput&&(L.debug.dayInput.value=String(e)),K(u,fe.width/2-u.view.x,86-u.view.y,`DAY ${e}`,y.green),z.updatePanels(),z.updateUI(),Ot(),Nt(`Day set to ${e}.`)}function Tc(){u.timeLeft=0,u.phase==="running"&&Vs(),K(u,fe.width/2-u.view.x,86-u.view.y,"TIMER 0",y.warn),z.updatePanels(),z.updateUI(),Nt("Timer set to 0.")}function Ec(){let e=L.debug.cardSelect?.value,t=L.debug.targetSelect?.disabled?void 0:L.debug.targetSelect?.value,n=ir(u,e,{targetKey:t});L.debug.grantCard&&(L.debug.grantCard.textContent=n.ok?"Granted":"Failed",window.setTimeout(()=>{L.debug.grantCard&&(L.debug.grantCard.textContent="Grant Selected")},900)),ge?.updateCongestion?.(),z.updatePanels(),z.updateUI(),Ot(),Nt(n.reason)}function Rc(){let t=Qt.map(n=>ir(u,n,{targetKey:"__auto__"})).filter(n=>n.ok).length;ge?.updateCongestion?.(),z.updatePanels(),z.updateUI(),Ot(),Nt(`Granted ${t}/${Qt.length} cards.`)}function Pc(){L.debug?.infiniteCash?.checked&&u.cash<999999&&(u.cash=999999,u.totals.maxCash=Math.max(u.totals.maxCash,u.cash))}function Nt(e=""){L.debug?.readout&&(L.debug.readout.textContent=[e,`D${u.turn}`,x(u.cash),`Combo ${u.manualCombo?.count||0}`,`Event ${u.eventActive?.title||u.eventOffer?.title||"none"}`,`Rescue ${u.cardEffects?.rescueLoanCharges||0}`,`Chem ${u.cardEffects?.chemicalWeaponSubsidy||0}`].filter(Boolean).join(" | "))}var u=To(),V,z,ge,tn;function Ac(e=null){let t=Xn(u,e);return e?t*Xo(u,e):t}function Dc(){Object.assign(u,To()),u.phase="running",u.view={x:0,y:0,scale:1},Eo(u),Xs(),Se(u),z.hideModal(),ge.updateCongestion(),z.updatePanels(),z.updateUI(),Nt()}function Ic(){if(u.phase!=="build")return;if(u.cardDraft?.pending||u.cardTargetPick?.pending){V.fail(u.cardTargetPick?.pending?"Choose upgrade target first.":"Choose an upgrade card first."),z.updatePanels();return}let e=fn(u);if(e.length){V.fail(`Cannot start: ${e[0]}`),z.updatePanels();return}Se(u),ai(u),ns(u);let t=Math.max(0,Math.floor(u.lastResult?.profit??u.stats?.profit??0)),n=Oi(u,Math.max(1,u.turn||1),t);u.lastStartFees={fairiesTribute:n.amount||0,tribute:n},n.amount>0&&K(u,fe.width/2-u.view.x,116-u.view.y,`FAIRIES -${x(n.amount)}`,y.danger),vi(u),u.phase="running",u.turn+=1,u.timeLeft=Si(u),u.shutdownTimeLeft=0,u.cleanupTimer=null,u.cleanupBlown=!1,u.chicks=[],u.effects=[],u.floatingTexts=[],u.shake={time:0,strength:0},u.truckCargo=[],Xs(),u.stats=xo(),u.stats.fairiesTribute=u.lastStartFees?.fairiesTribute||0,u.stats.fairiesTribute>0&&(u.stats.penalty+=u.stats.fairiesTribute,u.stats.profit-=u.stats.fairiesTribute);for(let o of u.scanners)o.queue=[],o.cooldown=0;for(let o of u.eggFarms)o.nextSpawn=ge.currentSpawnDelay(o),o.lastInterval=o.nextSpawn,o.shutterProgress=0,o.shutterSparked=!1;u.buildTool=null,u.selected=null,u.groupDrag=null,u.selectionBox=null,u.pan=null,ge.updateCongestion(),z.updatePanels(),z.updateUI()}function $c(){if(u.phase!=="running")return;let e=Li(u),t=u.eventActive?{...u.eventActive}:null,n=Ei(u),o=Ni(u);if(e.adjusted>0){let i=u.facilities.truck,l=i?i.x+i.w/2:fe.width/2-u.view.x,c=i?i.y+26:96-u.view.y;K(u,l,c,`${e.target==="poop"?"POOP SHIP":"SHIP"} +${x(e.adjusted)}`,y.green)}n?.bonus>0&&K(u,fe.width/2-u.view.x,96-u.view.y,`EVENT +${x(n.bonus)}`,y.green),o.amount>0&&K(u,fe.width/2-u.view.x,116-u.view.y,`CHEM SUBSIDY +${x(o.amount)}`,y.green),wi(u),u.totals.turnsCompleted+=1;let r=Ti(t);if(r!==1&&(u.pendingFairiesTributeMultiplier=r),u.lastResult={...u.stats,ship:e,event:n,chemical:o,rescue:{amount:0,used:0,remaining:u.cardEffects?.rescueLoanCharges||0},fairiesTribute:{amount:u.stats.fairiesTribute||0},tributeMultiplier:r,turn:u.turn,cash:u.cash},u.cash<0){if((u.cardEffects?.rescueLoanCharges||0)>0){u.phase="loanDecision",z.showEmergencyLoanDecision(Ys,eo);return}u.phase="gameover",z.showGameOver();return}qs()}function qs(){u.phase="build",u.truckCargo=[],u.chicks=[],u.shutdownTimeLeft=0,u.cleanupTimer=null,u.cleanupBlown=!1,u.buildSession+=1,u.undoStack=[],u.redoStack=[],u.timeLeft=0;for(let e of u.scanners)e.queue=[];for(let e of u.eggFarms)e.shutterProgress=0,e.shutterSparked=!1;os(u),u.eventOffer=bi(u),tn&&tn.prepareDraft(),u.cardTargetPick=null,u.buildTool=null,u.groupDrag=null,u.selectionBox=null,u.pan=null,z.updatePanels(),z.showTurnResult(u.lastResult)}function Ys(){if((u.cardEffects?.rescueLoanCharges||0)<=0)return eo();u.cardEffects.rescueLoanCharges-=1,u.stats.rescueLoan=(u.stats.rescueLoan||0)+500,u.totals.rescueLoan=(u.totals.rescueLoan||0)+500;let e=Ge(u,500);u.lastResult={...u.lastResult||{},...u.stats,rescue:{amount:(u.lastResult?.rescue?.amount||0)+e,used:(u.lastResult?.rescue?.used||0)+1,remaining:u.cardEffects.rescueLoanCharges},cash:u.cash},K(u,fe.width/2-u.view.x,176-u.view.y,`RESCUE +${x(e)}`,y.green),u.cash>=0?qs():(u.cardEffects?.rescueLoanCharges||0)>0?(u.phase="loanDecision",z.showEmergencyLoanDecision(Ys,eo)):eo()}function eo(){u.phase="gameover",z.showGameOver()}function Vs(){u.shutdownTimeLeft<=0&&(u.shutdownTimeLeft=u.shutdownGraceSeconds||10);for(let e of u.eggFarms){if(e.shutterSparked)continue;e.shutterProgress=.02,e.shutterSparked=!0;let t=B(e.col,e.row);Xe(u,t.x,t.y,y.ink),Ze(u,t.x,t.y+10,10),K(u,t.x,t.y-34,"SHUT +10s",y.ink)}}function zs(e){u.lastTimestamp||(u.lastTimestamp=e);let t=Math.min((e-u.lastTimestamp)/1e3,.05);u.lastTimestamp=e,u.phase==="running"&&ge.updateRunning(t,{closeFarmShutters:Vs,completeTurn:$c}),zi(u,t,fe,V.equipmentHitBoxes),ge.updateCongestion(),Cs(kc,fe,u,{activeQueuedChick:ge.activeQueuedChick,selectedObject:V.selectedObject,selectedTitle:V.selectedTitle}),Pc(),z.updateUI(),Js(),Nt(),requestAnimationFrame(zs)}function to(){return u.view?.scale||1}function kn(){u.view||(u.view={x:0,y:0,scale:1}),u.view.scale==null&&(u.view.scale=1)}function no(e){let t=fe.getBoundingClientRect();return{x:(e.clientX-t.left)*fe.width/t.width,y:(e.clientY-t.top)*fe.height/t.height}}function wt(e){let t=no(e),n=to();return{x:(t.x-(u.view?.x||0))/n,y:(t.y-(u.view?.y||0))/n}}function Fc(e){let t=to();return{x:e.x*t+(u.view?.x||0),y:e.y*t+(u.view?.y||0)}}function Bc(){let e={left:f.x-90,top:f.y-130,right:f.x+f.cols*f.cell+260,bottom:f.y+f.rows*f.cell+220};if(u.phase==="build")for(let t of Tt(u)){let n=Et(t);e.left=Math.min(e.left,n.x-60),e.top=Math.min(e.top,n.y-80),e.right=Math.max(e.right,n.x+n.w+80),e.bottom=Math.max(e.bottom,n.y+n.h+80)}return e}function Ws(e,t){if(e<=t)return[e,t];let n=(e+t)/2;return[n,n]}function St(){kn();let e=to(),t=Bc(),[n,o]=Ws(fe.width-160-t.right*e,110-t.left*e),[r,i]=Ws(fe.height-150-t.bottom*e,150-t.top*e);u.view.x=un(u.view.x,n,o),u.view.y=un(u.view.y,r,i)}function Xs(){kn(),u.view.scale=1;let e=u.eggFarms?.[0],t=e?B(e.col,e.row):{x:f.x,y:f.y};u.view.x=280-t.x,u.view.y=190-t.y,St()}function Lc(e){let t=no(e);kn(),u.pan={start:t,viewX:u.view.x,viewY:u.view.y,moved:!1}}function Oc(e){if(!u.pan)return;let t=no(e);Math.hypot(t.x-u.pan.start.x,t.y-u.pan.start.y)>5&&(u.pan.moved=!0),kn(),u.view.x=u.pan.viewX+t.x-u.pan.start.x,u.view.y=u.pan.viewY+t.y-u.pan.start.y,St()}function Nc(e){e.preventDefault(),kn();let t=no(e),n=wt(e),o=Math.exp(-e.deltaY*.0012),r=un(to()*o,.55,1.8);u.view.scale=r,u.view.x=t.x-n.x*r,u.view.y=t.y-n.y*r,St(),st()}function _c(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:{type:e.type,id:e.ref.id}:null}function Gc(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:e.ref||null:null}function st(){L.hoverTooltip&&(L.hoverTooltip.classList.remove("visible"),L.hoverTooltip.setAttribute("aria-hidden","true"),u.hover=null)}function Uc(e,t){if(!L.hoverTooltip||u.phase!=="build"||u.cardTargetPick?.pending||u.groupDrag||u.selectionBox||u.pan)return st();let n=Gc(t);if(!n)return st();let o=V.selectedTitle(n),r=V.flavorText?V.flavorText(n):"",i=V.disconnectedWarningFor?V.disconnectedWarningFor(n):"",l=V.selectedInfoLines(n).slice(0,7);L.hoverTooltip.innerHTML=`${o}${i?`${i}`:r?`${r}`:""}${l.map(C=>`${C}`).join("")}`;let c=Math.min(window.innerWidth-330,e.clientX+18),b=Math.min(window.innerHeight-220,e.clientY+18);L.hoverTooltip.style.left=`${Math.max(8,c)}px`,L.hoverTooltip.style.top=`${Math.max(8,b)}px`,L.hoverTooltip.classList.add("visible"),L.hoverTooltip.setAttribute("aria-hidden","false"),u.hover={type:t.type,id:t.oldKey||t.ref?.id||null}}function Wc(e){if(u.phase!=="build")return st();Uc(e,V.equipmentAtPoint(wt(e)))}function Qs(e){st();let t=wt(e),n=V.equipmentAtPoint(t),o=_c(n);if(!o){u.selected=null,u.multiSelected=[],z.updatePanels();return}u.selected=o,u.multiSelected=[o],z.updatePanels();let r=V.selectedObject();r?.type==="scanner"&&r.kind==="manual"&&V.showManualScannerMenu(r),r?.type==="scanner"&&r.kind==="auto"&&V.showAutoScannerMenu(r)}function en(){u.buildTool=null,u.selected=null,u.multiSelected=[],u.selectionBox=null,u.cardTargetPick?.mode==="autoScannerMenu"&&(u.cardTargetPick=null),z.hideModal(),st(),z.updatePanels(),z.updateUI()}function Ks(e){return String(e).replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function Kc(e){let t=e?.queue?.[0];return t==null?null:u.chicks.find(n=>n.id===t)||null}function Hc(e){if(!e)return'WAIT';let t=e.sex==="poop"?"\u{1F4A9} POOP":e.sex==="male"?"\u2642 MALE":"\u2640 FEMALE";return`${t}`}function qc(e,t){let n=new Set(u.eggFarms.map(T=>A(T.col,T.row))),o=new Map(u.scanners.map(T=>[A(T.col,T.row),T])),r=Re(e,"inputA"),i=r?A(r.col,r.row):null,l=new Set(Object.values(u.facilities||{}).map(T=>T.entry?A(T.entry.col,T.entry.row):null).filter(Boolean)),c=t?.sex||"",b=c==="poop"?"\u{1F4A9}":c==="male"?"\u2642":c==="female"?"\u2640":"",C=[];for(let T=e.row-2;T<=e.row+2;T+=1)for(let I=e.col-2;I<=e.col+2;I+=1){let $=A(I,T),O=["mini-cell"],ee="";I===e.col&&T===e.row?(O.push("scanner"),c&&O.push(c),ee=b||"S"):$===i?(O.push("input"),ee="IN"):n.has($)?(O.push("egg"),ee="E"):o.has($)?(O.push("scanner-other"),ee="S"):l.has($)?(O.push("port"),ee="P"):u.conveyorTiles.has($)?(O.push("belt"),ee="\u2022"):u.blockedCells?.has?.($)&&(O.push("blocked"),ee="\xD7"),C.push(`${ee}`)}return`
${C.join("")}
`}function Yc(e){let t=Fc(B(e.col,e.row)),n=76;return t.x<-n||t.y<-n||t.x>fe.width+n||t.y>fe.height+n}function Js(){if(!L.manualScannerMonitor)return;if(u.phase!=="running"){L.manualScannerMonitor.classList.remove("visible"),L.manualScannerMonitor.innerHTML="";return}let e=u.scanners.filter(t=>t.kind==="manual"&&Yc(t));if(!e.length){L.manualScannerMonitor.classList.remove("visible"),L.manualScannerMonitor.innerHTML="";return}L.manualScannerMonitor.innerHTML=e.map(t=>{let n=Kc(t),o=t.keys?.left?.label||(t.slot===0?"A":"Left"),r=t.keys?.right?.label||(t.slot===0?"D":"Right"),i=t.role===0?"MIXER":"WASTE",l=t.role===0?"S2":"TRUCK",c=n?"":" disabled";return` +
+
S${(t.slot??0)+1}OFFSCREEN / Q:${t.queue.length}
+
+ IN${Hc(n)}SCANNER +
+ ${qc(t,n)} +
+ + +
+
`}).join(""),L.manualScannerMonitor.classList.add("visible")}L.manualScannerMonitor?.addEventListener("click",e=>{let t=e.target.closest("button[data-scanner-id]");if(!t||t.disabled)return;let n=u.scanners.find(o=>o.id===Number(t.dataset.scannerId));n&&(ge.sortScanner(n,t.dataset.side),Js())});fe.addEventListener("contextmenu",e=>e.preventDefault());fe.addEventListener("wheel",Nc,{passive:!1});fe.addEventListener("pointerdown",e=>{if(u.phase!=="build")return;fe.setPointerCapture(e.pointerId);let t=wt(e);if(e.button===2){Lc(e);return}if(e.button!==0)return;if(u.cardTargetPick?.mode==="autoScannerMenu"){en();return}if(u.cardTargetPick?.pending){tn.chooseTargetAtPoint(t);return}let n=V.expansionOfferAtPoint?.(t);if(n){V.buyGridExpansion(n),St(),z.updatePanels(),z.updateUI();return}if(V.cycleBranchModeAtPoint?.(t)){z.updatePanels(),z.updateUI();return}let o=He(t.x,t.y),r=V.equipmentAtPoint(t);if(!u.buildTool&&r?.type==="conveyor"&&o&&V.cycleSingleConveyorDirection?.(o)){z.updatePanels(),z.updateUI();return}if(u.buildTool==="erase"){if(!V.equipmentAtPoint(t)){en();return}V.eraseAtPoint(t);return}if(u.buildTool){let i=He(t.x,t.y);if(!i&&!["mixer","trash","truck"].includes(u.buildTool)){en();return}if(u.buildTool==="conveyor"||u.buildTool==="boostConveyor"){V.beginConveyorDrag(i);return}if(V.equipmentAtPoint(t)){u.buildTool=null,Qs(e);return}V.buildAtPoint(t);return}V.startGroupDrag(e)||V.startSelectionBox(e)});fe.addEventListener("pointermove",e=>{if(u.phase!=="build"){st();return}Wc(e),u.pan&&e.buttons&2&&Oc(e),u.groupDrag&&e.buttons&1&&V.updateGroupDrag(e),u.selectionBox&&e.buttons&1&&V.updateSelectionBox(e),(u.buildTool==="conveyor"||u.buildTool==="boostConveyor")&&e.buttons&1&&V.continueConveyorDrag(He(wt(e).x,wt(e).y)),u.buildTool==="erase"&&e.buttons&1&&V.eraseAtPoint(wt(e))});fe.addEventListener("pointerup",e=>{u.selectionBox?V.finishSelectionBox():u.groupDrag&&(u.groupDrag.committed||Qs(e),V.finishGroupDrag()),e.button===2&&u.pan&&!u.pan.moved&&u.buildTool&&en(),(u.buildTool==="conveyor"||u.buildTool==="boostConveyor")&&V.endConveyorDrag?.(),u.groupDrag=null,u.pan=null;try{fe.releasePointerCapture(e.pointerId)}catch{}});fe.addEventListener("pointerleave",st);fe.addEventListener("pointercancel",()=>{V?.endConveyorDrag?.(),u.groupDrag=null,u.selectionBox=null,u.pan=null,st()});document.addEventListener("pointerdown",e=>{!L.modal.classList.contains("visible")||!L.modal.classList.contains("equipment-popover")||e.target.closest("#modal .modal-card")||en()},!0);L.buttons.s1Left.addEventListener("click",()=>ge.sortSlot(0,"left"));L.buttons.s1Right.addEventListener("click",()=>ge.sortSlot(0,"right"));L.buttons.s2Left.addEventListener("click",()=>ge.sortSlot(1,"left"));L.buttons.s2Right.addEventListener("click",()=>ge.sortSlot(1,"right"));L.buttons.nextTurn.addEventListener("click",Ic);L.buttons.conveyor.addEventListener("click",()=>V.setBuildTool("conveyor"));L.buttons.boostConveyor.addEventListener("click",()=>V.setBuildTool("boostConveyor"));L.buttons.eggFarm.addEventListener("click",()=>V.setBuildTool("eggFarm"));L.buttons.autoScanner.addEventListener("click",()=>V.setBuildTool("autoScanner"));L.buttons.manualScanner.addEventListener("click",()=>V.setBuildTool("manualScanner"));L.buttons.mixer.addEventListener("click",()=>V.setBuildTool("mixer"));L.buttons.trash.addEventListener("click",()=>V.setBuildTool("trash"));L.buttons.truck.addEventListener("click",()=>V.setBuildTool("truck"));L.buttons.maintenanceRoom.addEventListener("click",()=>V.setBuildTool("maintenanceRoom"));L.buttons.erase.addEventListener("click",()=>V.setBuildTool("erase"));L.debug.setDay?.addEventListener("click",xc);L.debug.zeroTimer?.addEventListener("click",Tc);L.debug.grantCard?.addEventListener("click",Ec);L.debug.grantAllCards?.addEventListener("click",Rc);L.buttons.undo.addEventListener("click",()=>{Ko(u)&&(St(),z.updatePanels(),z.updateUI(),Ot())});L.buttons.redo.addEventListener("click",()=>{Ho(u)&&(St(),z.updatePanels(),z.updateUI(),Ot())});function Hs(e,t,n){let o=e.keys?.[t];return o?o.code&&n.code===o.code||o.key&&n.key.toLowerCase()===o.key:!1}window.addEventListener("keydown",e=>{if(e.repeat)return;let t=e.key.toLowerCase();if(u.phase==="running")for(let n of u.scanners.filter(o=>o.kind==="manual")){if(Hs(n,"left",e)){e.preventDefault(),ge.sortScanner(n,"left");return}if(Hs(n,"right",e)){e.preventDefault(),ge.sortScanner(n,"right");return}}u.phase==="build"&&(e.ctrlKey||e.metaKey)&&t==="z"&&(e.preventDefault(),Ko(u)&&(St(),z.updatePanels(),z.updateUI())),u.phase==="build"&&(e.ctrlKey||e.metaKey)&&(t==="y"||e.shiftKey&&t==="z")&&(e.preventDefault(),Ho(u)&&(St(),z.updatePanels(),z.updateUI())),e.key==="Escape"&&u.cardTargetPick?.pending&&(e.preventDefault(),u.cardTargetPick.mode==="autoScannerMenu"?en():tn.cancelTargetPick())});V=Fs({game:u,ui:L,canvas:fe,canvasPoint:wt,onUpdatePanels:()=>z?.updatePanels()});ge=Us({game:u,currentConveyorSpeed:Ac,onGameOverCheck:()=>z?.checkGameOver()});tn=vs({game:u,ui:L,onUpdatePanels:()=>z?.updatePanels()});z=Bs({game:u,ui:L,build:V,startGame:Dc,beginCardDraft:()=>tn.showDraft(),activeQueuedChick:ge.activeQueuedChick});Cc();gc();Eo(u);Se(u);ge.updateCongestion();z.updatePanels();z.updateUI();z.showTitle();Nt();requestAnimationFrame(zs); diff --git a/dist/game-v27.19.js b/dist/game-v27.19.js new file mode 100644 index 0000000..29d8c43 --- /dev/null +++ b/dist/game-v27.19.js @@ -0,0 +1,51 @@ +var q={version:"v27.19 LAND + UI PATCH",time:{daySeconds:60,farmShutdownGraceSeconds:10},cash:{starting:250},grid:{x:170,y:78,cols:20,rows:10,cell:46,expansion:{colsPerPurchase:10,rowsPerPurchase:10,costBase:1e3,costMultiplier:1.3333333333333333,truncateUnit:100}},map:{blockedRatio:.03,blockedExpansionIncrement:.005,blockedRatioMax:.1},economy:{income:{mixer:5,truck:10},poopFine:10,fairiesTribute:{perDay:10,profitExemption:300,legalWorkExemptionBonus:250,profitRate:.12},incomeUpgradeRate:1.1,explosionDamageDivisor:30,maleTruckFinePerHalfDay:30,shredderBonus:{maxCards:30,incomePerUpgrade:1.25},chemicalWeaponSubsidy:{poopPerBlock:70,yenPerBlock:1200}},production:{poopRate:.08,autoScannerCooldown:3.5,autoScannerUpgradeRate:.95,autoScannerCardUpgradeRate:.95,autoScannerMinCooldown:.5,poopRateCardBonus:.04,eggSpawnRanges:[[1.95,4.35],[1.55,3.45],[1.25,2.8],[1.05,2.35]]},conveyor:{baseSpeed:52,maxSpeed:300,bearingSpeedMultiplier:1.075},cards:{definitions:[{id:"upgradeEgg",title:"EGG Improvement",rarity:"common",type:"equipmentUpgrade",target:"eggFarm",description:"Choose one EGG FARM on the map and raise it by 1 level.",tags:["EGG","ACTIVE"]},{id:"upgradeAutoScanner",title:"AUTO SCANNER Improvement",rarity:"common",type:"equipmentUpgrade",target:"autoScanner",description:"Choose one AUTO SCANNER on the map and raise it by 1 level.",tags:["SCANNER","ACTIVE"]},{id:"autoScannerTuning",title:"AUTO SCANNER Tuning",rarity:"common",type:"instant",description:"All AUTO SCANNER cooldowns use default cooldown x0.95 per copy.",tags:["SCANNER","PASSIVE"]},{id:"upgradeMixer",title:"MIXER Improvement",rarity:"common",type:"equipmentUpgrade",target:"mixer",description:"Choose MIXER on the map and raise it by 1 level.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeTruck",title:"TRUCK Improvement",rarity:"common",type:"equipmentUpgrade",target:"truck",description:"Choose TRUCK on the map and raise it by 1 level.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeTrash",title:"SHREDDER Improvement",rarity:"common",type:"equipmentUpgrade",target:"trash",description:"Shred poops for a little money. Max 30 upgrades.",tags:["POOP","ACTIVE"]},{id:"crowdedFarming",title:"Crowded Farming",rarity:"common",type:"instant",description:"EGG production interval -5%. Equipment deterioration +4%. Max 10 cards.",tags:["EGG","RISK","PASSIVE"]},{id:"hatchingFeed",title:"Hatching Feed",rarity:"common",type:"instant",description:"EGG production interval -4%. Poop rate +3%. No card limit.",tags:["EGG","POOP","PASSIVE"]},{id:"poopRateBooster",title:"Poop Culture",rarity:"common",type:"instant",description:"Base poop rate +4 percentage points. No card limit.",tags:["POOP","PASSIVE"]},{id:"safetyCover",title:"Safety Cover",rarity:"common",type:"instant",description:"Explosion damage -5%. No card limit.",tags:["RISK","PASSIVE"]},{id:"preventiveMaintenance",title:"Preventive Maintenance Manual",rarity:"common",type:"instant",description:"All equipment deterioration speed -5%. No card limit.",tags:["MAINTENANCE","PASSIVE"]},{id:"dudFilter",title:"DUD Filter",rarity:"common",type:"instant",description:"DUD chance -5 percentage points. Stacks until DUD chance reaches 0%.",tags:["CARD","PASSIVE"]},{id:"durabilityCoating",title:"Durability Coating",rarity:"common",type:"instant",description:"All equipment maximum durability +3%. No card limit.",tags:["MAINTENANCE","PASSIVE"]},{id:"bearing",title:"High-Quality Bearing",rarity:"common",type:"instant",description:"Conveyor speed +7.5%.",tags:["CONVEYOR","PASSIVE"]},{id:"sparePartsBin",title:"SPARE PARTS BIN",rarity:"common",type:"instant",description:"Restores 2% durability to every machine. A box of almost-compatible parts.",tags:["MAINTENANCE","ACTIVE"]},{id:"dudRefund",title:"DUD REFUND",rarity:"common",type:"instant",description:"DUDs now come with paperwork. Gain JPY 50 per copy when you pick a DUD.",tags:["CARD","ECONOMY","PASSIVE"]},{id:"freeReroll",title:"FREE REROLL",rarity:"common",type:"instant",description:"The first bad ideas are free.",tags:["CARD","PASSIVE"]},{id:"composter",title:"COMPOSTER",rarity:"common",type:"instant",description:"Turns shredder waste into suspicious fertilizer. Gain JPY 3 per copy when SHREDDER processes poop.",tags:["POOP","ECONOMY","PASSIVE"]},{id:"scannerQueueSpacing",title:"Scanner Queue Spacing",rarity:"common",type:"instant",description:"Manual and Auto Scanner queue spacing -15%. No card limit.",tags:["SCANNER","PASSIVE"]},{id:"extraEggOutlet",title:"Extra Egg Outlet",rarity:"rare",type:"equipmentUpgrade",target:"eggOutlet",description:"Choose one EGG FARM and add +1 output port to that EGG. Max +3 per EGG.",tags:["EGG","RARE","ACTIVE"]},{id:"recyclingSubsidy",title:"Recycling Subsidy",rarity:"rare",type:"instant",description:"SELL refund rate +10 points. Max 3 cards; normal SELL can reach 80%.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"dynamite",title:"Dynamite",rarity:"rare",type:"cellAction",target:"blockedCell",description:"Choose and remove up to 3 unbuildable cells.",tags:["RISK","RARE","ONE-SHOT"]},{id:"usedMachine",title:"Used Machines",rarity:"rare",type:"instant",description:"Future equipment costs half. New purchases have no refund and 60% durability. New Machines cancels it.",tags:["ECONOMY","RISK","RARE"]},{id:"newMachine",title:"New Machines",rarity:"common",type:"instant",description:"Cancel Used Machines and restore normal prices, refunds, and durability.",tags:["ECONOMY","ONE-SHOT"]},{id:"flattery",title:"Flattery",rarity:"rare",type:"instant",description:"Next Fairies tribute -50%.",tags:["ECONOMY","RARE","ONE-SHOT"]},{id:"extraCards",title:"Extra Cards",rarity:"rare",type:"instant",description:"Draw 2 cards now and choose both.",tags:["RARE","ACTIVE"]},{id:"legalWork",title:"Legal Work",rarity:"rare",type:"instant",description:"Fairies tribute profit exemption +JPY 250.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"chemicalWeaponSubsidy",title:"Chemical Weapons Subsidy",rarity:"ultraRare",type:"instant",description:"Each day, gain JPY 1200 per 70 poop shipped by truck. No card limit.",tags:["POOP","ULTRA RARE","PASSIVE"]},{id:"laborExploitation",title:"Motivational Exploitation",rarity:"ultraRare",type:"instant",description:"Repair room work time -30%. The repairman smiles with bloodshot eyes. One time only.",tags:["MAINTENANCE","ULTRA RARE","PASSIVE"]},{id:"rescueLoan",title:"Emergency Loan",rarity:"ultraRare",type:"instant",description:"If cash is below JPY 0 at day-end settlement, gain JPY 500. Consumed on use.",tags:["ECONOMY","ULTRA RARE","ONE-SHOT"]}],defaultEffects:{bearing:0,legalWork:0,fairiesFlatteryNext:0,autoScannerTuning:0,poopRateBooster:0,crowdedFarming:0,hatchingFeed:0,safetyCover:0,recyclingSubsidy:0,chemicalWeaponSubsidy:0,preventiveMaintenance:0,dudFilter:0,durabilityCoating:0,sparePartsBin:0,dudRefund:0,freeReroll:0,composter:0,scannerQueueSpacing:0,laborExploitation:0,usedMachineActive:!1,rescueLoanCharges:0},commonWeight:8,rareWeight:2,ultraRareWeight:.45,baseDraftSize:3,maxDudsPerDraft:2,dudChancePerCard:.3,dudChanceReductionPerFilter:.05,extraCardsAddedPicks:2,rerollCost:{dayDivisor:2,multiplier:100}},events:{eventChance:.1,firstTurn:8},maintenance:{fullPerformanceUntilWear:.5,minimumPerformance:.5,durability:{conveyor:1300,eggFarm:475,autoScanner:850,mixer:775,trash:950},processingDelayMaxSeconds:{mixer:1.2,trash:1},repairman:{secondsPerOnePercent:.5,walkSpeed:90}},facilities:{conveyor:{id:"conveyor",type:"conveyor",name:"Conveyor",shortName:"Belt",price:30,buildable:!0,upgradeable:!1},boostConveyor:{id:"boostConveyor",type:"conveyor",name:"Boost Conveyor",shortName:"BOOST BELT",price:75,buildable:!0,upgradeable:!1,speedMultiplier:2},eggFarm:{id:"eggFarm",type:"eggFarm",name:"Egg Farm",shortName:"EGG",price:250,buildable:!0,upgradeable:!0,maxLevel:4},manualScanner:{id:"manualScanner",type:"scanner",kind:"manual",name:"Manual Scanner",shortName:"Manual Scanner",price:260,buildable:!0,upgradeable:!1},autoScanner:{id:"autoScanner",type:"scanner",kind:"auto",name:"Auto Scanner",shortName:"Auto Scanner",price:180,buildable:!0,upgradeable:!1},mixer:{id:"mixer",type:"facility",name:"Mixer",shortName:"MIXER",price:450,buildable:!0,upgradeable:!0,incomeKey:"mixer",body:{w:164,h:126}},trash:{id:"trash",type:"facility",name:"Waste Shredder",shortName:"SHREDDER",price:240,buildable:!0,upgradeable:!0,body:{w:180,h:100}},truck:{id:"truck",type:"facility",name:"Truck",shortName:"TRUCK",price:450,buildable:!0,upgradeable:!0,incomeKey:"truck",body:{w:176,h:138}},maintenanceRoom:{id:"maintenanceRoom",type:"maintenanceRoom",name:"Maintenance Room",shortName:"REPAIR ROOM",price:220,buildable:!0,upgradeable:!1,footprint:{cols:2,rows:2}}}};var Pr=q.version,xt=q.time.daySeconds,an=q.cash.starting,ke=q.economy,Ar=q.time.farmShutdownGraceSeconds,Tn=q.production.autoScannerCooldown,Ir=q.production.autoScannerUpgradeRate,ho=q.production.autoScannerCardUpgradeRate||q.production.autoScannerUpgradeRate,mo=q.production.autoScannerMinCooldown,Dr=q.events.eventChance,cn=q.events.firstTurn,bo=q.production.poopRate,vo=q.production.poopRateCardBonus||0,En=q.conveyor.baseSpeed,Kt=q.conveyor.maxSpeed,Rn=q.conveyor.bearingSpeedMultiplier,De=q.cards,$r=q.cards.definitions,wo=q.cards.defaultEffects,st=q.production.eggSpawnRanges,f=q.grid,ve=q.facilities,So=["conveyor","boostConveyor","eggFarm","autoScanner","manualScanner","mixer","trash","truck","maintenanceRoom"],un=["mixer","trash","truck"],Fr=["mixer","truck"],lt=Object.fromEntries(Object.entries(ve).map(([e,t])=>[e,t.price])),de=[{name:"right",dc:1,dr:0,angle:0,opposite:"left"},{name:"left",dc:-1,dr:0,angle:Math.PI,opposite:"right"},{name:"down",dc:0,dr:1,angle:Math.PI/2,opposite:"up"},{name:"up",dc:0,dr:-1,angle:-Math.PI/2,opposite:"down"}],y={bg:"#111318",ink:"#090a0d",muted:"#8f9bab",green:"#7bd84f",greenSoft:"#273c24",mixerBlue:"#4aa3ff",truckPink:"#ffb33e",wasteGreen:"#88d35a",danger:"#e34a36",warn:"#ffb827",white:"#e6edf2",poop:"#7b4a23",male:"#4aa3ff",female:"#ff6fae"},Ce={ambient:0,important:1,critical:2};function T(e){let t=Number(e)||0;return`${t<0?"-":""}\uFFE5${Math.ceil(Math.abs(t)).toLocaleString("ja-JP")}`}function I(e,t){return`${e},${t}`}function te(e){let[t,n]=String(e).split(",").map(Number);return{col:t,row:n}}function dn(e,t,n){return Math.max(t,Math.min(n,e))}function K(e,t){return e+Math.random()*(t-e)}function Ee(e,t){return e>=0&&e=0&&tMath.round(dn(r,0,255)).toString(16).padStart(2,"0");return`#${o(e)}${o(t)}${o(n)}`}function Ht(e,t,n){let o=Br(e),r=Br(t);return cl(ko(o.r,r.r,n),ko(o.g,r.g,n),ko(o.b,r.b,n))}var re={appTitle:"Chick Sorter",versionTitle:`Chick Sorter ${Pr}`,currency:"\uFFE5",phases:{title:"Title",build:"Build",running:"Sorting",clearing:"Clearing",loanDecision:"Emergency Loan",gameover:"Game Over"},actions:{startGame:"Start Game",nextDay:"Next Day",buildPhase:"Build Phase",restart:"Restart",close:"Close",remove:"Remove",refund:"Refund",autoMenu:"Auto Menu"},status:{build:e=>`BUILD: ${(e==="erase"?"SELL":e||"SELECT").toUpperCase()} | Right-drag pan | Hover equipment for info`,sorting:"Sorting: use scanner keys. Build after clearing the day.",allPortsConnected:"Start condition met: one EGG route reaches an exit.",equipmentPanelEmpty:"Hover equipment in Build phase."},routeLabels:{mixer:"MIXER",truck:"TRUCK",trash:"WASTE",scanner:"NEXT","scanner-role-1":"NEXT",input:"IN"},fail:{outOfGrid:"Out of grid",cellOccupied:"Cell occupied",notEnoughCash:"Not enough cash",facilityExists:"Facility already exists",facilityOverlap:"Facility overlap",nothingToErase:"Nothing to sell",noUpgrade:"No upgrade available"}};function ct(e){return ve[e]?.name||String(e||"").replace(/^[a-z]/,t=>t.toUpperCase())}function ul(e){let t=ve[e];return t?e==="conveyor"||e==="boostConveyor"?`${T(t.price)} / tile`:e==="autoScanner"?`${T(t.price)} / ${Tn.toFixed(1)}s cooldown`:e==="trash"?T(t.price):T(t.price):""}function dl(e){return{conveyor:"A narrow green belt. Routes decide whether chicks live, ship, or become invoices.",boostConveyor:"Moves chicks twice as fast. Wears down like a normal belt.",eggFarm:"A tiny gatehouse producing questionable eggs on schedule.",autoScanner:"Slower than hands without upgrades.",manualScanner:"A manual checkpoint. The operator is the algorithm.",mixer:"Male chicks become revenue here. Do not feed it poop.",trash:"A polite shredder for poop and other regrets.",truck:"Ships the target cargo. Wrong cargo still leaves a paper trail.",maintenanceRoom:"2\xD72 repair bay. Each room dispatches one repairman during the day."}[e]||""}function Or(e){let t=dl(e);return`${ct(e)}${ul(e)}${t?`${t}`:""}`}function Nr(e){return re.routeLabels[e]||String(e).toUpperCase()}function _r(e){let t=2166136261;for(let n=0;n>>0}function Gr(e){let t=e>>>0;return()=>{t+=1831565813;let n=Math.imul(t^t>>>15,1|t);return n^=n+Math.imul(n^n>>>7,61|n),((n^n>>>14)>>>0)/4294967296}}function Ur(e,{base:t=.03,increment:n=.005,max:o=.1}={}){let r=Math.max(0,Math.floor(Number(e)||0));return Number(Math.min(o,t+r*n).toFixed(6))}function An(){return`RUN-${Date.now().toString(36)}-${Math.floor(Math.random()*1e6).toString(36)}`.toUpperCase()}function Wr({seed:e,targetRatio:t=.2,reserved:n=[]}={}){let o=Gr(_r(e||An())),r=new Set(n.map(c=>typeof c=="string"?c:I(c.col,c.row))),i=[];for(let c=0;c0;c-=1){let b=Math.floor(o()*(c+1));[i[c],i[b]]=[i[b],i[c]]}let l=Math.round(f.cols*f.rows*t+1e-9);return new Set(i.slice(0,Math.min(l,i.length)).map(c=>c.k))}function Kr({seed:e,colStart:t=0,colEnd:n=f.cols,rowStart:o=0,rowEnd:r=f.rows,targetRatio:i=.2,reserved:l=[]}={}){let c=Gr(_r(e||An())),b=new Set(l.map(z=>typeof z=="string"?z:I(z.col,z.row))),C=[],x=Math.max(0,Math.floor(t)),A=Math.max(x,Math.floor(n)),$=Math.max(0,Math.floor(o)),B=Math.max($,Math.floor(r));for(let z=$;z0;z-=1){let ce=Math.floor(c()*(z+1));[C[z],C[ce]]=[C[ce],C[z]]}let j=Math.round((A-x)*(B-$)*i+1e-9);return new Set(C.slice(0,Math.min(j,C.length)).map(z=>z.k))}var qt=10,Hr=2,qr=1;function Yt(e,t){return`${e},${t}`}function fl(e){let[t,n]=String(e).split(",").map(Number);return{chunkX:t,chunkY:n}}function In(e){let t=q.grid.expansion||{},n=Math.max(1,(e.gridExpansionPurchases||0)+1),o=(t.costBase||1e3)*n*(t.costMultiplier||4/3),r=Math.max(1,t.truncateUnit||100);return Math.floor(o/r)*r}function Yr(e){e.ownedCells=new Set,e.ownedChunks=new Set,e.gridChunkOriginY=0,e.gridExpansionPurchases=0,e.gridExpansionPurchasesByDirection={right:0,up:0};for(let t=0;t=0&&t=0&&n0)continue;let C=Yt(b.chunkX,b.chunkY);t.has(C)||n.has(C)||n.set(C,Co(e,b.chunkX,b.chunkY,b.direction))}}return[...n.values()].sort((o,r)=>{let i=o.direction===r.direction?0:o.direction==="right"?-1:1;return i||(o.chunkY!==r.chunkY?o.chunkY-r.chunkY:o.chunkX-r.chunkX)})}function Xr(e,t="right"){let n=Tt(e);return n.find(o=>o.direction===t)||n[0]||null}function Et(e){return{x:f.x+e.colStart*f.cell,y:f.y+e.rowStart*f.cell,w:e.cols*f.cell,h:e.rows*f.cell}}function Mo(e){let t=Et(e);return{x:t.x+t.w/2-116,y:t.y+t.h/2-36,w:232,h:72,cx:t.x+t.w/2,cy:t.y+t.h/2}}function Qr(e,t){let n=Mo(e);return t.x>=n.x&&t.x<=n.x+n.w&&t.y>=n.y&&t.y<=n.y+n.h}function Jr(e){let t=[];for(let n=e.rowStart;nEe(t.col,t.row))}function Sl(e){return[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}].filter(t=>Ee(t.col,t.row))}function kl(e){return[{col:e.col,row:e.row+1},{col:e.col-1,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row-1}].filter(t=>Ee(t.col,t.row))}function oi(e){let t=new Set([...e.conveyorTiles]),n=o=>{o&&Ee(o.col,o.row)&&t.add(I(o.col,o.row))};for(let o of e.scanners){for(let r of Sl(o))n(r);for(let r of wl(o))n(r)}for(let o of e.eggFarms){n(o);for(let r of kl(o))n(r)}for(let o of Object.values(e.facilities))n(o.entry);return t}function ti(e){let t=hl.map(([n,o])=>({col:n,row:o}));for(let{col:n,row:o}of t)ni(e,n,o);for(let n=0;n({...n,keys:n.keys?{left:{...n.keys.left},right:{...n.keys.right}}:null,queue:[]})),e.eggFarms=bl.map(n=>{let o=Rt(n);return{...n,nextSpawn:o,lastInterval:o}});let t=oi(e);e.blockedCells=Wr({seed:e.runSeed,targetRatio:q.map.blockedRatio,reserved:[...t]}),Cl(e),ti(e),e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function Pt(e){return e?[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}]:[]}function ye(e){let t=F(e.col,e.row);return{x:t.x+f.cell/2,y:t.y}}function dt(e,t,n){return e.eggFarms.find(o=>o.col===t&&o.row===n)||null}function ft(e,t,n){return e.scanners.find(o=>Pt(o).some(r=>r.col===t&&r.row===n))||null}function At(e,t){return e.scanners.find(n=>n.id===t)||null}function Ro(e,t){return e.scanners.find(n=>n.kind==="manual"&&n.slot===t)||null}function Bn(e){return e?.baseId||e?.id||""}function Po(e,t){return Object.entries(e.facilities||{}).filter(([,n])=>Bn(n)===t)}function Re(e,t){return{inputA:{col:e.col,row:e.row-2},inputB:null,left:{col:e.col-1,row:e.row},right:{col:e.col+2,row:e.row}}[t]}function si(e){return e?de.map(t=>({col:e.col+t.dc,row:e.row+t.dr})).filter(t=>Ee(t.col,t.row)):[]}function li(e,t,n=[],o=[]){if(!t||!Ee(t.col,t.row))return[];let r=[],i=l=>{!l||!Ee(l.col,l.row)||!e.conveyorTiles.has(I(l.col,l.row))||n.some(c=>c&&Pn(l,c))||r.some(c=>Pn(c,l))||r.push({...l,viaTolerance:!Pn(l,t)})};i(t);for(let l of o)i(l);for(let l of si(t))i(l);return r}function ri(e,t,n=[],o=[]){let r=li(e,t,n,o),i=r.filter(l=>!l.viaTolerance);return i.length?i:r}function Ml(e,t){let n=Re(t,"inputA");return!n||!Ee(n.col,n.row)?[]:e.conveyorTiles.has(I(n.col,n.row))?[{...n,viaTolerance:!1}]:[]}function gl(e,t,n){let o=Re(t,n);return li(e,o,Pt(t))}function xl(e,t){let n=e.facilities[t]||Po(e,t)[0]?.[1];if(!n)return null;if(n.entry)return F(n.entry.col,n.entry.row);let o=Bn(n)||t;return o==="mixer"?{x:n.x+n.w,y:n.y+n.h*.52}:o==="truck"?{x:n.x,y:n.y+n.h*.52}:o==="trash"?{x:n.x+n.w/2,y:n.y+8}:{x:n.x+n.w/2,y:n.y+n.h/2}}function ai(e,t,n){return n==="inputA"?Ml(e,t).length>0:gl(e,t,n).length>0}function be(e){e.branchCounters?.clear?.(),e.routeCache=null,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function $e(e,t){return I(e,t)}function Vt(e){return te(e)}function Tl(e,t){let n=e.conveyorMeta?.get?.(t)||{},o=[];return Array.isArray(n.outDirs)&&o.push(...n.outDirs),n.dir&&o.push(n.dir),[...new Set(o)].filter(r=>de.some(i=>i.name===r))}function El(e,t,n){let o=de.find(l=>l.name===n);if(!o)return!1;let r=e.conveyorMeta?.get?.($e(t.col+o.dc,t.row+o.dr));return r?[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))].includes(o.opposite):!1}function Rl(e,t){let n=Vt(t),o=e.conveyorMeta?.get?.(t)||{},r=de.filter(x=>e.conveyorTiles.has($e(n.col+x.dc,n.row+x.dr))).map(x=>x.name),i=Tl(e,t).filter(x=>r.includes(x)),l=i.length?i:r;if(r.length<3)return l;let c=new Set(r.filter(x=>El(e,n,x))),b=r.filter(x=>!c.has(x)),C=c.size&&b.length>=2?b:[...new Set(l)];return C.length<2&&(C=r),o.branchMode&&o.branchMode!=="random"&&C.includes(o.branchMode)?[o.branchMode]:C}function Pl(e){return{version:e.routingVersion||0,cells:new Set,adjacency:new Map,components:new Map,cellToComponent:new Map,scannerInputs:new Map,scannerPorts:new Map,facilityPorts:new Map,farmOutputs:new Map,pathCache:new Map,metrics:{conveyorCells:0,edges:0,components:0,deadEnds:0,crosses:0,scannerPorts:0,connectedScannerPorts:0,facilityPorts:0,connectedFacilityPorts:0,farmOutputs:0},issues:[]}}function Al(e){let t=Pl(e);for(let o of e.conveyorTiles)t.cells.add(o),t.adjacency.set(o,[]);for(let o of t.cells){let r=Vt(o),i=Rl(e,o),l=de.filter(c=>i.includes(c.name));for(let c of l){let b=$e(r.col+c.dc,r.row+c.dr);t.cells.has(b)&&t.adjacency.get(o).push({key:b,dir:c.name})}}let n=0;for(let[o,r]of t.adjacency.entries()){n+=r.length;let i=new Set(r.map(l=>l.dir));r.length===1&&(t.metrics.deadEnds+=1),r.length===4&&i.has("left")&&i.has("right")&&i.has("up")&&i.has("down")&&(t.metrics.crosses+=1)}return t.metrics.conveyorCells=t.cells.size,t.metrics.edges=Math.floor(n/2),Il(t),Dl(e,t),t.issues=Kl(e,t,{includeRoutes:!1}),t}function Il(e){let t=1;for(let n of e.cells){if(e.cellToComponent.has(n))continue;let o=t++,r=[n],i=[];for(e.cellToComponent.set(n,o);r.length;){let l=r.shift();i.push(l);for(let c of e.adjacency.get(l)||[])e.cellToComponent.has(c.key)||(e.cellToComponent.set(c.key,o),r.push(c.key))}e.components.set(o,{id:o,cells:i,capacity:Math.max(1,i.length),count:0,ratio:0})}e.metrics.components=e.components.size}function Dl(e,t){for(let n of e.scanners){let o={};for(let r of["inputA","left","right"]){let i=Re(n,r),l=r==="inputA"?i&&t.cells.has($e(i.col,i.row))?[{...i}]:[]:ri(e,i,Pt(n)).filter(C=>t.cells.has($e(C.col,C.row))),c=l.map(C=>$e(C.col,C.row)),b=c.length>0;if(o[r]={type:r,cell:i,cells:l,keys:c,key:c[0]||null,connected:b},t.metrics.scannerPorts+=1,b&&(t.metrics.connectedScannerPorts+=1),r==="inputA")for(let C of c)t.scannerInputs.set(C,n.id)}t.scannerPorts.set(n.id,o)}for(let[n,o]of Object.entries(e.facilities)){if(!o.entry)continue;let r=ri(e,o.entry).filter(c=>t.cells.has($e(c.col,c.row))),i=r.map(c=>$e(c.col,c.row)),l=i.length>0;t.facilityPorts.set(n,{id:n,cell:{...o.entry},cells:r,keys:i,key:i[0]||null,connected:l}),t.metrics.facilityPorts+=1,l&&(t.metrics.connectedFacilityPorts+=1)}for(let n of e.eggFarms){let o=si({col:n.col,row:n.row}).map(r=>$e(r.col,r.row)).filter(r=>t.cells.has(r));t.farmOutputs.set(n.id,o),t.metrics.farmOutputs+=o.length}}function _e(e){let t=e.routingVersion||0;return(!e.factoryGraph||e.factoryGraph.version!==t)&&(e.factoryGraph=Al(e)),e.factoryGraph}function ci(e){let t=_e(e);return e.factoryGraphCommittedVersion=t.version,e.factoryGraphSnapshot=$l(t),t}function $l(e){return e?{version:e.version,conveyorCells:e.metrics.conveyorCells,edges:e.metrics.edges,components:e.metrics.components,deadEnds:e.metrics.deadEnds,crosses:e.metrics.crosses,scannerPorts:`${e.metrics.connectedScannerPorts}/${e.metrics.scannerPorts}`,facilityPorts:`${e.metrics.connectedFacilityPorts}/${e.metrics.facilityPorts}`,farmOutputs:e.metrics.farmOutputs,issues:[...e.issues||[]]}:null}function Fl(e,t){let n=t.col-e.col,o=t.row-e.row;return de.find(r=>r.dc===n&&r.dr===o)?.name||null}function Ao(e,t,n){let o=_e(e),r=$e(t.col,t.row);if(!o.cells.has(r))return[];let i=`${r}|${n.cacheKey||"dynamic"}`;if(n.cacheKey&&o.pathCache.has(i))return o.pathCache.get(i).map(le=>le.map(se=>({...se})));let l=`${r}|none`,c=[{key:r,col:t.col,row:t.row,incoming:"none",depth:0}],b=new Map([[l,0]]),C=new Map,x=[],A=1/0,$=8,B=24,j=80;for(;c.length;){let le=c.shift();if(le.depth>A)break;let se=`${le.key}|${le.incoming}`;if(n(le)){if(x.push(se),A=le.depth,x.length>=B)break;continue}for(let R of o.adjacency.get(le.key)||[]){let _=Vt(R.key),Y=Fl(le,_),O=le.depth+1;if(O>A)continue;let W=`${R.key}|${Y}`,U=b.get(W);if(U==null)b.set(W,O),C.set(W,[se]),c.push({key:R.key,col:_.col,row:_.row,incoming:Y,depth:O});else if(U===O){let M=C.get(W)||[];M.length<$&&!M.includes(se)&&M.push(se),C.set(W,M)}}}let z=[],ce=(le,se)=>{if(z.length>=j)return;let[R]=le.split("|"),_=[Vt(R),...se];if(le===l||R===r){z.push(_);return}for(let Y of C.get(le)||[])ce(Y,_)};for(let le of x)ce(le,[]);let he=[],ie=new Set;for(let le of z){let se=le.map(R=>$e(R.col,R.row)).join(">");ie.has(se)||(ie.add(se),he.push(le))}return n.cacheKey&&o.pathCache.set(i,he.map(le=>le.map(se=>({...se})))),he}function ui(e){let t=_e(e),n=new Map;for(let[o,r]of t.components.entries())n.set(o,{id:o,cells:[...r.cells],capacity:r.capacity,count:0,ratio:0});return{components:n,cellToComponent:new Map(t.cellToComponent)}}function di(e,t,n){let o=_e(e),r=null,i=1/0;for(let l of o.cells){let c=te(l),b=F(c.col,c.row),C=Math.hypot(b.x-t,b.y-n);CF(o.col,o.row));return t&&n.push(t),n}function ut(e,t){t&&(!e.length||Lr(e[e.length-1],t)>1)&&e.push(t)}function Bl(e,t,n,o=null){let r=[{x:e.x,y:e.y}];ut(r,F(t.col,t.row));for(let i of Ln(n,o))ut(r,i);return r}function Ll(e,t){let n=Ln(e),o=Re(t,"inputA");return o&&ut(n,F(o.col,o.row)),ut(n,ye(t)),n}function Ol(e,t,n,o){let r=[{x:e.x,y:e.y}];ut(r,F(t.col,t.row));for(let l of Ln(n))ut(r,l);let i=Re(o,"inputA");return i&&ut(r,F(i.col,i.row)),ut(r,ye(o)),r}function Nl(e,t,n=0){let o=F(t.col,t.row),r=0;for(let i of e.chicks||[]){if(i.stage==="flying"||i.stage==="queued")continue;Math.hypot(i.x-o.x,i.y-o.y){let A=C.roleBias??0,$=x.roleBias??0;if(A!==$)return A-$;let B=C.cells?.length??C.route?.length??Number.POSITIVE_INFINITY,j=x.cells?.length??x.route?.length??Number.POSITIVE_INFINITY;if(B!==j)return B-j;let z=C.key||JSON.stringify(C.route||C.cells||C),ce=x.key||JSON.stringify(x.route||x.cells||x);return z.localeCompare(ce)});if(!o||r.length===1)return r[0];let i=r[0].roleBias??0,l=r.filter(C=>(C.roleBias??0)===i),c=Math.min(...l.map(C=>ii(e,C)));l=l.filter(C=>ii(e,C)===c);let b=e.branchCounters.get(t)||0;return e.branchCounters.set(t,b+1),l[Math.floor(Math.random()*l.length)]}function fi(e){return e.role===0?{left:{match:"male",destination:"mixer"},right:{match:"default",destination:"scanner-role-1"}}:{left:{match:"poop",destination:"trash"},right:{match:"default",destination:"truck"}}}function Io(e){let t=fi(e);return{left:t.left.destination,right:t.right.destination}}function Do(e,t){return fi(e).left.match===t.sex?"left":"right"}function $o(e){return Nr(e)}function Fo(e){return{mixer:"#2477ff",truck:"#ff6aa8",trash:"#22b94f","scanner-role-1":"#526456",scanner:"#526456",input:"#526456"}[e]||"#102015"}function It(e,t,n=!1){let o=_e(e),r=(o.farmOutputs.get(t.id)||[]).map(Vt),i=[];for(let b of r){let C=A=>o.scannerInputs.has($e(A.col,A.row));C.cacheKey=`farmInput:${b.col},${b.row}:v${o.version}`;let x=Ao(e,b,C);for(let A of x){let $=A[A.length-1],B=o.scannerInputs.get($e($.col,$.row)),j=At(e,B);j&&i.push({key:`${j.id}:${$.col},${$.row}:${A.length}`,scanner:j,cells:A})}}let l=Fn(e,`farm:${t.id}`,i,n);if(l)return{scannerId:l.scanner.id,route:Ll(l.cells,l.scanner)};let c=Fn(e,`farm:${t.id}:output`,r.map(b=>({key:I(b.col,b.row),cells:[b]})),n);return c?{scannerId:null,route:Ln(c.cells)}:null}function pi(e,t,n,o,r=!1){let i=At(e,o);if(!i)return null;let c=_e(e).scannerPorts.get(i.id)?.[t],b=Re(i,t),C=c?.connected?(c.keys||[c.key]).filter(Boolean).map(Vt):[];if(!b||!C.length)return null;let x=Io(i)[t];return x==="scanner-role-1"?_l(e,i,t,n,b,C,r):Gl(e,i,t,n,b,C,x,r)}function _l(e,t,n,o,r,i,l){let c=_e(e),b=e.scanners.filter(A=>A.id!==t.id&&c.scannerPorts.get(A.id)?.inputA?.connected),C=[];for(let A of i)for(let $ of b){let B=c.scannerPorts.get($.id)?.inputA?.key;if(!B)continue;let j=(c.scannerPorts.get($.id)?.inputA?.keys||[B]).filter(Boolean),z=ie=>j.includes($e(ie.col,ie.row));z.cacheKey=`toScanner:${A.col},${A.row}:${$.id}:v${c.version}`;let ce=Ao(e,A,z),he=$.role===1?0:1;for(let ie of ce)C.push({key:`${he}:start${I(A.col,A.row)}:s${$.id}:${ie.length}:${I(ie[ie.length-1].col,ie[ie.length-1].row)}`,target:$,cells:ie,roleBias:he})}let x=Fn(e,`scanner:${t.id}:${n}:toRole1`,C,l);return x?{destination:"scanner",nextScannerId:x.target.id,route:Ol(o,r,x.cells,x.target)}:null}function Gl(e,t,n,o,r,i,l,c){let b=_e(e),C=[...b.facilityPorts.entries()].filter(([$,B])=>B?.connected&&Bn(e.facilities?.[$])===l);if(!C.length)return null;let x=[];for(let $ of i)for(let[B,j]of C){let z=(j.keys||[j.key]).filter(Boolean);if(!z.length)continue;let ce=ie=>z.includes($e(ie.col,ie.row));ce.cacheKey=`toFacility:${$.col},${$.row}:${B}:v${b.version}`;let he=Ao(e,$,ce);for(let ie of he)x.push({key:`start${I($.col,$.row)}:${B}:${ie.length}:${I(ie[ie.length-1].col,ie[ie.length-1].row)}`,cells:ie,facilityId:B})}let A=Fn(e,`scanner:${t.id}:${n}:${l}`,x,c);return A?{destination:l,facilityId:A.facilityId,route:Bl(o,r,A.cells,xl(e,A.facilityId))}:null}function yi(e,t,n=new Set){if(!t||n.has(t.id))return!1;n.add(t.id);for(let o of["left","right"]){let r=pi(e,o,ye(t),t.id,!1);if(r){if(["mixer","trash","truck"].includes(r.destination))return!0;if(r.destination==="scanner"){let i=At(e,r.nextScannerId);if(yi(e,i,n))return!0}}}return!1}function Ul(e,t){return!!It(e,t,!1)?.scannerId}function On(e){if(e.phase!=="build")return[];let t=[];for(let n of e.eggFarms||[])Ul(e,n)||t.push({type:"eggFarm",id:n.id,ref:n,message:"This Egg will not produce chicks"});for(let n of un)for(let[o,r]of Po(e,n))_e(e).facilityPorts.get(o)?.connected||t.push({type:"facility",id:o,ref:r,message:"This facility cannot receive items"});return t}function Wl(e){let t=_e(e);for(let r of e.eggFarms||[]){let i=It(e,r,!1);if(!i?.scannerId)continue;let l=At(e,i.scannerId);if(yi(e,l))return[]}let n=e.eggFarms?.length||0,o=[...t.facilityPorts.entries()].filter(([r,i])=>i?.connected&&["mixer","trash","truck"].includes(Bn(e.facilities?.[r]))).length;return n?t.metrics.farmOutputs?e.scanners?.length?o?["Connect at least one EGG through a scanner to any valid exit."]:["Connect at least one receiver exit: Mixer, Shredder, or Truck."]:["Build at least one scanner and connect it to an EGG route."]:["Connect at least one EGG to a conveyor."]:["Build at least one EGG before starting the next day."]}function $n(e){return e.kind==="manual"?`S${(e.slot??0)+1}`:`Auto Scanner #${e.id}`}function Kl(e,t=_e(e),n={}){let o=n.includeRoutes!==!1,r=[],i={mixer:"Mixer",trash:"Shredder",truck:"Truck"};for(let l of un){let c=Po(e,l);if(!c.length){r.push(`${i[l]||l} is missing`);continue}for(let[b]of c)t.facilityPorts.get(b)?.connected||r.push(`${i[l]||l} receiver has no conveyor`)}for(let l of e.scanners){let c=t.scannerPorts.get(l.id)||{};if(c.inputA?.connected||r.push(`${$n(l)} input has no conveyor`),c.left?.connected||r.push(`${$n(l)} left output has no conveyor`),c.right?.connected||r.push(`${$n(l)} right output has no conveyor`),!!o)for(let b of["left","right"])c[b]?.connected&&!pi(e,b,ye(l),l.id)&&r.push(`${$n(l)} ${b} route is incomplete`)}if(o)for(let l of e.eggFarms)It(e,l)?.scannerId||r.push(`Egg Farm #${l.id} has no scanner route`);else for(let l of e.eggFarms)(t.farmOutputs.get(l.id)||[]).length||r.push(`Egg Farm #${l.id} has no output conveyor`);return[...new Set(r)]}function pn(e){return Wl(e)}function hi(e){return pn(e).length===0}var mi=[{key:"premiumFemaleShipment",target:"female",truckTarget:"female",title:"Premium Female Shipment",route:"Female -> Truck",note:"Today only: ship female chicks to Truck. Meet the export target for a bonus.",objective:"truckTarget"},{key:"contaminantSampleExport",target:"poop",truckTarget:"poop",title:"Contaminant Sample Export",route:"Poop value x2",note:"Today only: poop is valid Truck cargo and all poop income is doubled.",objective:"truckTarget",poopValueMultiplier:2},{key:"healthInspection",title:"Health Inspection",route:"Poop -> Shredder",note:"Today only: poop mistakes are fined double. Shred enough poop for an inspection bonus.",objective:"poopTrash",poopFineMultiplier:2},{key:"conveyorJamWarning",title:"Conveyor Jam Warning",route:"No explosions",note:"Today only: jam explosions trigger at 85% congestion. Finish with zero explosions for a bonus.",objective:"noExplosion",congestionExplosionThreshold:.85,congestionWarningThreshold:.68},{key:"powerSavingOrder",title:"Power Saving Order",route:"Slow factory subsidy",note:"Today only: conveyors -20% speed and Auto Scanners +20% cooldown. A subsidy is paid at settlement.",objective:"flatBonus",conveyorSpeedMultiplier:.8,autoScannerCooldownMultiplier:1.2},{key:"overtimeDay",title:"Overtime Day",route:"80 second day",note:"Today only: the work day is longer. No extra reward or penalty.",objective:"none",daySeconds:80},{key:"shortShift",title:"Short Shift",route:"40 second day",note:"Today only: the work day is shorter. The next Fairies tribute is reduced by 10%.",objective:"none",daySeconds:40,fairiesTributeMultiplier:.9},{key:"chickBoom",title:"Chick Boom",route:"EGG interval x0.65",note:"Today only: eggs hatch faster and poop rate rises by 5 percentage points.",objective:"none",productionMultiplier:1/.65,poopRateAdd:.05},{key:"rottenFeed",title:"Rotten Feed",route:"Poop surge",note:"Today only: poop rate rises by 20 percentage points and Shredder poop income is multiplied by 1.5.",objective:"none",poopRateAdd:.2,shredderIncomeMultiplier:1.5},{key:"maintenanceAudit",title:"Maintenance Audit",route:"Durability check",note:"Today only: machines below 50% remaining durability fail the audit. Passing with none below 50% pays a bonus.",objective:"maintenanceAudit"}];function we(e,t=0){let n=Number(e);return Number.isFinite(n)?n:t}function Hl(e,t=0,n=1){let o=Math.max(1,Number(e?.turn||1)+1),r=Math.floor(Bo(e)*(.08+Math.random()*.08)),i=Math.floor(Math.max(0,e.cash||0)*.25),l=Math.floor(Math.max(0,t)*Math.max(1,o)*.75);return Math.max(120,Math.ceil(Math.max(r,i,l)*n))}function bi(e){return Math.max(0,Math.ceil(500+Math.max(1,e?.turn||1)*25))}function Bo(e){return[...e.eggFarms.map(t=>t.price||0),...e.scanners.map(t=>t.price||0),...Object.values(e.facilities).map(t=>t.price||0),...[...e.conveyorMeta.values()].map(t=>t.price||0)].reduce((t,n)=>t+n,0)}function ql(e,t=1,n=xt){return e.eggFarms.reduce((o,r)=>{let[i,l]=fn(r),c=Math.max(.1,(i+l)/2);return o+Math.max(1,n)/c*Math.max(.01,t||1)},0)}function Yl(e,t){let n=we(t.productionMultiplier,1),o=we(t.daySeconds,xt),r=ql(e,n,o),i=Math.max(0,Number(e?.cardEffects?.hatchingFeed)||0),l=Math.max(0,Number(e?.cardEffects?.poopRateBooster)||0),c=Math.pow(1.03,i),b=bo+vo*l,C=Math.min(.95,Math.max(0,(b+we(t.poopRateAdd,0))*we(t.poopMultiplier,1)*c));return{estimate:r,poopRate:C}}function vi(e){if(e.turn+1Dr)return null;let n=mi[Math.floor(Math.random()*mi.length)],{estimate:o,poopRate:r}=Yl(e,n),i=0;n.objective==="truckTarget"?i=Math.max(1,Math.ceil(o*.3)):n.objective==="poopTrash"&&(i=Math.max(1,Math.ceil(o*r*.8)));let l=0;return["truckTarget","poopTrash","noExplosion"].includes(n.objective)&&(l=Hl(e,o)),n.objective==="flatBonus"&&(l=bi(e)),n.objective==="maintenanceAudit"&&(l=bi(e)),{id:`event-${e.turn}-${Date.now()}-${Math.floor(Math.random()*9999)}`,...n,target:n.target||null,truckTarget:n.truckTarget||null,forced:!0,productionMultiplier:we(n.productionMultiplier,1),poopMultiplier:we(n.poopMultiplier,1),poopRateAdd:we(n.poopRateAdd,0),daySeconds:we(n.daySeconds,xt),targetAmount:i,estimatedOutput:Math.round(o),reward:l,createdTurn:e.turn,oneTurnOnly:!0}}function wi(e){e.eventActive=e.eventOffer?{...e.eventOffer}:null,e.eventOffer=null}function Si(e){e.eventActive=null}function ki(e){return Math.max(1,we(e.eventActive?.daySeconds,xt))}function Ci(e){return we(e.eventActive?.productionMultiplier,1)}function Mi(e){let t=Math.max(0,Number(e?.cardEffects?.hatchingFeed)||0),n=Math.max(0,Number(e?.cardEffects?.poopRateBooster)||0),o=Math.pow(1.03,t),r=bo+vo*n,i=we(e.eventActive?.poopRateAdd,0);return Math.min(.95,Math.max(0,(r+i)*we(e.eventActive?.poopMultiplier,1)*o))}function pt(e){return e.eventActive?.truckTarget||e.eventActive?.target||"female"}function Lo(e,t){return t==="male"?e.truckMale||0:t==="poop"?e.poopTruck||0:e.truckFemale||0}function gi(e,t){return pt(e)===t}function xi(e){return pt(e)!=="male"}function Oo(e){return Math.max(.01,we(e.eventActive?.poopValueMultiplier,1))}function Nn(e){return Math.max(.01,Oo(e)*we(e.eventActive?.shredderIncomeMultiplier,1))}function No(e){return Math.max(.01,we(e.eventActive?.poopFineMultiplier,1))}function _o(e){return Math.max(.1,Math.min(1,we(e.eventActive?.congestionExplosionThreshold,1)))}function Ti(e){return Math.max(.1,Math.min(1,we(e.eventActive?.congestionWarningThreshold,.8)))}function Ei(e){return Math.max(.01,we(e?.fairiesTributeMultiplier,1))}function Vl(e){let t=0,n=(o,r)=>{let i=Math.max(1,we(r,1)),l=Math.max(0,we(o,0));1-Math.min(1,l/i)<.5&&(t+=1)};for(let o of e.conveyorMeta?.values?.()||[])n(o.uses,o.durability);for(let o of e.eggFarms||[])n(o.maintenance?.uses,o.maintenance?.durability);for(let o of e.scanners||[])o.kind==="auto"&&n(o.maintenance?.uses,o.maintenance?.durability);for(let o of Object.values(e.facilities||{})){let r=o?.baseId||o?.id;(r==="mixer"||r==="trash")&&n(o.maintenance?.uses,o.maintenance?.durability)}return t}function Ri(e){let t=e.eventActive;if(!t)return null;let n=0,o=!0,r=0,i="";t.objective==="truckTarget"?(n=Lo(e.stats,t.target),o=n>=t.targetAmount,r=o?t.reward:0):t.objective==="poopTrash"?(n=e.stats.poopTrash||0,o=n>=t.targetAmount,r=o?t.reward:0):t.objective==="noExplosion"?(n=e.stats.explosions||0,o=n===0,r=o?t.reward:0,i=`${n} explosion(s)`):t.objective==="flatBonus"?(o=!0,r=t.reward):t.objective==="maintenanceAudit"?(n=Vl(e),o=n===0,o&&(r=t.reward),i=`${n} machine(s) below 50%`):o=!0,r>0?(Ge(e,r),e.stats.eventBonus=(e.stats.eventBonus||0)+r,e.totals.eventBonus+=r,e.totals.eventSuccess+=1):t.objective&&t.objective!=="none"&&(e.stats.eventBonus=e.stats.eventBonus||0,e.totals.eventFailed+=o?0:1,o&&(e.totals.eventSuccess+=1));let l={title:t.title,key:t.key,target:t.target,route:t.route,objective:t.objective,targetAmount:t.targetAmount||0,count:n,success:o,bonus:r,reward:t.reward||0,productionMultiplier:t.productionMultiplier,poopMultiplier:t.poopMultiplier,daySeconds:t.daySeconds,detail:i};return e.stats.eventResult=l,l}function Go(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function zl(e){return!!e?.cardEffects?.usedMachineActive}function Xl(e,t){return t?1:Math.min(.8,.5+.1*Math.min(3,Go(e,"recyclingSubsidy")))}function Ql(e){return Math.pow(.95,Go(e,"safetyCover"))}function _n(e){let t=e?.ref||e||{},n=e?.type||t.type;return n==="conveyor"?t.price||ve[t.kind]?.price||ve.conveyor.price:n==="eggFarm"?t.price||ve.eggFarm.price:n==="scanner"?t.price||(t.kind==="auto"?ve.autoScanner.price:ve.manualScanner.price):n==="facility"?t.price||ve[t.id]?.price||0:n==="maintenanceRoom"?t.price||ve.maintenanceRoom.price:ve[t.id]?.price||0}function Oe(e,t=null){let n=ve[e]?.price||0;return zl(t)?Math.ceil(n*.5):n}function Jl(e,t){return e?.facilities?Object.values(e.facilities).filter(n=>(n?.baseId||n?.id)===t).reduce((n,o)=>n+Math.max(0,(o.level||1)-1),0):0}function yt(e,t){return Fr.includes(t)?Math.pow(ke.incomeUpgradeRate,Jl(e,t)):1}function ze(e){return Math.ceil(ke.income.mixer*yt(e,"mixer"))}function Fe(e){return Math.ceil(ke.income.truck*yt(e,"truck"))}function yn(e){return Math.ceil(ke.poopFine*yt(e,"mixer")*No(e))}function hn(e){return Math.ceil(ke.poopFine*yt(e,"truck")*No(e))}function Uo(e){let t=ke.maleTruckFinePerHalfDay*(e.turn/2);return Math.ceil(t*yt(e,"truck"))}function Wo(e){return e?.facilities?Object.values(e.facilities).filter(t=>(t?.baseId||t?.id)==="trash").reduce((t,n)=>t+Math.max(0,(n.level||1)-1),0):0}function Dt(e){return Math.min(ke.shredderBonus.maxCards,Wo(e))}function zt(){return ke.shredderBonus.maxCards}function ht(e){let t=typeof e=="number"?e:Dt(e),n=Math.min(ke.shredderBonus.maxCards,Math.max(0,t));return n>0?Math.ceil(n*(ke.shredderBonus.incomePerUpgrade||1)):0}function jl(e){let t=Dt(e),n=ht(t),o=Math.ceil(n*Nn(e));return{cards:t,chance:o>0?1:0,amount:o,expected:o,baseAmount:n}}function Pi(e){let t=jl(e);return t.amount>0&&(e.stats.shredderBonus=(e.stats.shredderBonus||0)+t.amount,e.totals.shredderBonus=(e.totals.shredderBonus||0)+t.amount,Ge(e,t.amount)),t}function Ko(e,t=e.turn,n=null){let o=Math.max(1,Math.floor(Number(t)||1)),r=ke.fairiesTribute||{perDay:10,profitExemption:300,legalWorkExemptionBonus:250,profitRate:.12},i=Math.ceil(o*(r.perDay||10)),l=Math.max(0,Math.floor(Number(n??e?.lastResult?.profit??e?.stats?.profit??0)||0)),c=Math.max(0,e?.cardEffects?.legalWork||0),b=Math.max(0,(r.profitExemption||0)+c*(r.legalWorkExemptionBonus||0)),C=Math.max(0,l-b),x=Math.ceil(C*Math.max(0,Number(r.profitRate)||0)),A=i+x,$=Math.max(0,e?.cardEffects?.fairiesFlatteryNext||e?.cardEffects?.flattery||0),B=$>0?Math.pow(.5,$):1,j=Math.max(.01,Number(e?.pendingFairiesTributeMultiplier)||1),z=B*j,ce=Math.max(0,Math.ceil(A*z)),he=Math.max(0,A-ce);return{day:o,base:i,profit:l,legalWork:c,profitExemption:b,taxableProfit:C,profitTribute:x,gross:A,flatteryCount:$,eventMultiplier:j,perCardReduction:Math.ceil(A*.5),reduction:he,amount:ce}}function mt(e,t){let n=e?.ref||e||{},o=e?.type==="conveyor"?t?.conveyorMeta?.get(e.oldKey||n.id):n,r=o?.price||_n(e||n),i=o?.builtSession===t?.buildSession;if(o?.noRefund||n?.noRefund)return{amount:0,sameBuild:i,price:r,rate:0,noRefund:!0};let l=Xl(t,i);return{amount:Math.max(0,Math.ceil(r*l)),sameBuild:i,price:r,rate:l,noRefund:!1}}function Zl(e,t=null){let n=Math.max(1,Math.ceil((Number(e)||0)/ke.explosionDamageDivisor));return Math.max(1,Math.ceil(n*Ql(t)))}function ea(e,t){return Math.max(0,Math.ceil(t))}function Ai(e,t){e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,t>=0?(e.stats.revenue+=t,e.totals.revenue+=t):(e.stats.penalty+=Math.abs(t),e.totals.penalty+=Math.abs(t)),e.totals.maxCash=Math.max(e.totals.maxCash,e.cash)}function Ge(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&Ai(e,n),n}function bt(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&Ai(e,-n),n}function $t(e,t){bt(e,t)}function Ii(e,t){t<=0||(e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,e.totals.maxCash=Math.max(e.totals.maxCash,e.cash))}function Di(e){let t=ze(e);return e.stats.mixerRevenue+=t,Ge(e,t),t}function $i(e){let t=yn(e);return e.stats.mixerPoopFine+=t,e.totals.mixerPoopFine+=t,bt(e,t),t}function Fi(e){let t=hn(e);return e.stats.truckPoopFine+=t,e.totals.truckPoopFine+=t,bt(e,t),t}function Bi(e){let t=Uo(e);return e.stats.maleTruckFine+=t,e.totals.maleTruckFine+=t,bt(e,t),t}function Li(e,t){let n=Zl(t,e);return e.stats.explosionDamage+=n,e.totals.explosionDamage+=n,bt(e,n),n}function Oi(e){let t=pt(e),n=Lo(e.stats,t),o=t==="poop"?Math.ceil(Fe(e)*Oo(e)):Fe(e),r=n*o,i=ea(e,r);return e.stats.pendingTruckRevenue=i,e.stats.truckRevenue=i,t==="poop"?e.stats.poopShipmentIncome=i:e.stats.chickShipmentIncome=i,i>0&&Ge(e,i),{base:r,adjusted:i,target:t,targetCount:n,unitPrice:o}}function Ni(e,t=e.turn,n=null,o={}){let r=Ko(e,t,n);return e.cardEffects&&(e.cardEffects.fairiesFlatteryNext=0,e.cardEffects.flattery!=null&&delete e.cardEffects.flattery),e.pendingFairiesTributeMultiplier!=null&&(e.pendingFairiesTributeMultiplier=1),r.amount<=0||(o.recordStats?(e.stats.fairiesTribute=(e.stats.fairiesTribute||0)+r.amount,e.totals.fairiesTribute=(e.totals.fairiesTribute||0)+r.amount,bt(e,r.amount)):(e.totals.fairiesTribute=(e.totals.fairiesTribute||0)+r.amount,e.totals.penalty=(e.totals.penalty||0)+r.amount,e.totals.profit=(e.totals.profit||0)-r.amount,e.cash-=r.amount)),r}function _i(e){let t=Go(e,"chemicalWeaponSubsidy"),n=Math.max(0,e?.stats?.poopTruck||0),o=ke.chemicalWeaponSubsidy||{poopPerBlock:70,yenPerBlock:1200},r=Math.floor(n/Math.max(1,o.poopPerBlock||70)),i=t>0&&r>0?r*Math.max(0,o.yenPerBlock||1200)*t:0;return i>0&&(e.stats.chemicalWeaponSubsidy=(e.stats.chemicalWeaponSubsidy||0)+i,e.totals.chemicalWeaponSubsidy=(e.totals.chemicalWeaponSubsidy||0)+i,Ge(e,i)),{cards:t,poopTruck:n,blocks:r,amount:i}}function Gi(e){let t=Bo(e),n=Math.max(1,e.totals.turnsCompleted||e.turn||1),o=Math.max(0,e.cash+e.totals.revenue+t*.5+e.totals.eventBonus*.5),r=Math.ceil(o/n),i=Math.floor(n*35+Math.max(0,n-5)*15),l=e.totals.correct*5,c=e.totals.explosionDamage;return{score:Math.max(0,Math.floor(o+r+l-e.totals.penalty-i)),factoryValue:t,base:o,dailyEarned:r,dayPenalty:i,correctBonus:l,explosionPenalty:c,days:n}}function ta(e){return{...e,keys:e.keys?{left:{...e.keys.left},right:{...e.keys.right}}:null,queue:[],cooldown:e.cooldown||0}}function mn(e){return JSON.stringify({cash:e.cash,stats:e.stats,totals:e.totals,nextId:e.nextId,gridX:f.x,gridY:f.y,gridCols:e.gridCols||f.cols,gridRows:e.gridRows||f.rows,gridExpansionPurchases:e.gridExpansionPurchases||0,gridExpansionPurchasesByDirection:e.gridExpansionPurchasesByDirection||{right:0,up:0},gridChunkOriginY:e.gridChunkOriginY||0,ownedCells:[...e.ownedCells||[]],ownedChunks:[...e.ownedChunks||[]],blockedCells:[...e.blockedCells||[]],selected:e.selected,multiSelected:e.multiSelected||[],buildTool:e.buildTool,view:e.view,facilities:e.facilities,eggFarms:e.eggFarms,scanners:e.scanners.map(ta),conveyorTiles:[...e.conveyorTiles],conveyorMeta:[...e.conveyorMeta.entries()],branchCounters:[...e.branchCounters.entries()],cardEffects:e.cardEffects,cardDraft:e.cardDraft,cardTargetPick:e.cardTargetPick})}function Ui(e,t){let n=JSON.parse(t);e.cash=n.cash,e.stats=n.stats,e.totals=n.totals,e.nextId=n.nextId,f.x=n.gridX??q.grid.x,f.y=n.gridY??q.grid.y,f.cols=n.gridCols||q.grid.cols,f.rows=n.gridRows||q.grid.rows,e.gridCols=f.cols,e.gridRows=f.rows,e.gridExpansionPurchases=n.gridExpansionPurchases||0,e.gridExpansionPurchasesByDirection=n.gridExpansionPurchasesByDirection||{right:0,up:0},e.gridChunkOriginY=n.gridChunkOriginY||0,e.ownedCells=new Set(n.ownedCells||[]),e.ownedChunks=new Set(n.ownedChunks||[]),e.gridOwnedCells=e.ownedCells.size||f.cols*f.rows,e.blockedCells=new Set(n.blockedCells||[]),e.selected=n.selected,e.multiSelected=n.multiSelected||[],e.buildTool=n.buildTool,e.view=n.view||{x:0,y:0,scale:1},e.view.scale==null&&(e.view.scale=1),e.facilities=n.facilities||{},e.eggFarms=n.eggFarms||[],e.scanners=(n.scanners||[]).map(o=>({...o,queue:[],cooldown:o.cooldown||0})),e.conveyorTiles=new Set(n.conveyorTiles||[]),e.conveyorMeta=new Map(n.conveyorMeta||[]),e.branchCounters=new Map(n.branchCounters||[]),e.cardEffects=n.cardEffects||{bearing:0,legalWork:0,fairiesFlatteryNext:0,scannerQueueSpacing:0},e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft=n.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardTargetPick=n.cardTargetPick||null,e.groupDrag=null,e.selectionBox=null,e.pan=null,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function Be(e){e.phase==="build"&&(e.undoStack.push(mn(e)),e.undoStack.length>80&&e.undoStack.shift(),e.redoStack=[])}function Ho(e){return e.phase!=="build"||!e.undoStack.length?!1:(e.redoStack.push(mn(e)),Ui(e,e.undoStack.pop()),!0)}function qo(e){return e.phase!=="build"||!e.redoStack.length?!1:(e.undoStack.push(mn(e)),Ui(e,e.redoStack.pop()),!0)}function H(e,t,n,o,r=y.ink){e.floatingTexts.push({x:t,y:n,text:o,color:r,life:1,maxLife:1})}function Ft(e,t,n){e.shake.strength=Math.max(e.shake.strength,t),e.shake.time=Math.max(e.shake.time,n)}function Wi(e,t,n){e.effects.push({type:"spawn",priority:Ce.ambient,x:t,y:n,life:.42,maxLife:.42,size:12})}function Ki(e,t,n,o=y.green){e.effects.push({type:"scannerPulse",priority:Ce.important,x:t,y:n,color:o,life:.42,maxLife:.42,size:24})}function Hi(e,t,n){for(let o=0;o<12;o+=1)e.effects.push({type:"meat",priority:Ce.important,x:t+K(-18,18),y:n+K(-12,16),vx:K(-60,60),vy:K(-90,-25),life:K(.45,.85),maxLife:.85,size:K(4,8)})}function qi(e,t,n){for(let o=0;o<16;o+=1)e.effects.push({type:"sludge",priority:Ce.important,x:t+K(-18,18),y:n+K(-12,16),vx:K(-46,46),vy:K(-70,-20),life:K(.45,.9),maxLife:.9,size:K(4,8)})}function Yi(e,t,n,o){let r=o==="poop"?y.poop:o==="male"?y.male:y.female;for(let i=0;i<22;i+=1)e.effects.push({type:"shred",priority:Ce.important,x:t+K(-16,16),y:n+K(-8,8),vx:K(-70,70),vy:K(40,160),color:i%3===0?y.white:r,life:K(.45,.95),maxLife:.95,w:K(3,7),h:K(10,24),rot:K(-Math.PI,Math.PI)});Xe(e,t,n,y.green,34,Ce.important)}function Vi(e,t,n,o){let r=o==="poop"?y.poop:o==="male"?y.danger:y.green;for(let i=0;i<8;i+=1)e.effects.push({type:"load",priority:Ce.important,x:t+K(-18,18),y:n+K(-18,18),vx:K(-42,42),vy:K(-90,-25),color:r,life:K(.35,.65),maxLife:.65,size:8})}function Xe(e,t,n,o=y.danger,r=52,i=Ce.critical){e.effects.push({type:"shockwave",priority:i,x:t,y:n,color:o,life:.55,maxLife:.55,size:8,maxSize:r})}function Ze(e,t,n,o=12,r=y.danger,i=Ce.critical){for(let l=0;l0&&(e.shake.time=Math.max(0,e.shake.time-t),e.shake.time<=0&&(e.shake.strength=0));for(let r of e.effects)if(r.life-=t,["meat","sludge","spark","smoke","shred","load","rage"].includes(r.type))r.x+=(r.vx||0)*t,r.y+=(r.vy||0)*t,r.vy=(r.vy||0)+150*t;else if(r.type==="flyingChick"){r.x+=r.vx*t,r.y+=r.vy*t,r.vy+=360*t,r.noDamage||na(e,r,o);let i=r.x+e.view.x,l=r.y+e.view.y;(i<-100||l<-100||i>n.width+100||l>n.height+100)&&(r.life=0)}e.effects=e.effects.filter(r=>r.life>0);for(let r of e.floatingTexts)r.life-=t,r.y-=34*t;e.floatingTexts=e.floatingTexts.filter(r=>r.life>0)}function na(e,t,n){t.hit||(t.hit=new Set);for(let o of n()){if(t.hit.has(o.id)||t.xo.x+o.w||t.yo.y+o.h)continue;t.hit.add(o.id);let r=Li(e,o.price);H(e,t.x,t.y-10,`-${T(r)}`,y.danger),Xe(e,t.x,t.y,y.danger,30),Ze(e,t.x,t.y,5,y.danger),Ft(e,5,.18)}}var Ue=q.maintenance;function Vo(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function Wn(e){let t=Math.min(1.4,1+.04*Math.min(10,Vo(e,"crowdedFarming"))),n=Math.pow(.95,Vo(e,"preventiveMaintenance"));return t*n}function oa(e){return Math.pow(1.03,Vo(e,"durabilityCoating"))}function Kn(e,t,n=1){let o=Ue.durability[t]||1e3;return Math.max(1,Math.ceil(o*Math.max(.1,n||1)*oa(e)))}function Qi(e){return Math.max(.1,Number(e?.durabilityBaseMultiplier)||1)}function ra(e,t=0){if(!e)return{x:f.x+f.cell*(.5+t*.55),y:f.y+f.rows*f.cell+84};let n=f.x+e.col*f.cell+f.cell,o=f.y+e.row*f.cell+f.cell;return{x:n,y:o}}function ia(e,t=0){let n=(e.maintenanceRooms||[])[t];return ra(n,t)}function Se(e){e.repairman||(e.repairman={active:!1,x:f.x+f.cell*.5,y:f.y+f.rows*f.cell+84,target:null,repairedToday:0}),Array.isArray(e.maintenanceRooms)||(e.maintenanceRooms=[]),Array.isArray(e.repairmen)||(e.repairmen=[]);for(let[t,n]of e.conveyorMeta||[]){n.uses==null&&(n.uses=0),n.maintenanceType==null&&(n.maintenanceType="conveyor"),n.kind||(n.kind="conveyor"),n.speedMultiplier||(n.speedMultiplier=n.kind==="boostConveyor"?2:1),n.branchMode||(n.branchMode="random");let o=Kn(e,"conveyor",Qi(n));(n.durability==null||n.durability0&&(n.processingCooldown=Math.max(0,n.processingCooldown-t))}function wn(e){Se(e);let t=[];for(let[n,o]of e.conveyorMeta||[])t.push({type:"conveyor",key:n,meta:o,label:`${o.kind==="boostConveyor"?"Boost Belt":"Belt"} ${n}`,center:F(te(n).col,te(n).row)});for(let n of e.eggFarms||[])t.push({type:"eggFarm",ref:n,label:`EGG #${n.id}`,center:F(n.col,n.row)});for(let n of(e.scanners||[]).filter(o=>o.kind==="auto"))t.push({type:"autoScanner",ref:n,label:`AUTO #${n.id}`,center:F(n.col,n.row)});for(let n of Object.values(e.facilities||{})){let o=Vn(n);["mixer","trash"].includes(o)&&t.push({type:o,ref:n,label:`${n.shortName||n.name||o} #${n.id}`,center:{x:n.x+n.w/2,y:n.y+n.h/2}})}return t}function Bt(e){return e.meta?Xt(e):Xt(e.ref)}function bn(e){return e.meta?zo(e):zo(e.ref)}function Un(e){return e.meta?Xo(e):Xo(e.ref)}function ts(e,t){sa(e.meta?e:e.ref,Math.max(0,bn(e)-t))}function or(e){return e.type==="conveyor"?`conveyor:${e.key}`:`${e.type}:${e.ref?.id||e.ref?.type||e.type}`}function ns(e,t=.02){Se(e);let n=Math.max(0,Number(t)||0),o=0;for(let r of wn(e)){let i=bn(r);ts(r,Un(r)*n),o+=Math.max(0,i-bn(r))/Un(r)*100}return o}function os(e){Se(e);let t=e.maintenanceRooms||[];e.repairmen=t.map((o,r)=>{let i=ia(e,r);return{id:`room-${o.id}`,roomId:o.id,active:!0,x:i.x,y:i.y,target:null,repairedToday:0}});let n=e.repairmen[0];e.repairman.active=!!n,e.repairman.target=n?.target||null,e.repairman.repairedToday=0,n&&(e.repairman.x=n.x,e.repairman.y=n.y)}function rs(e){Se(e);for(let t of e.repairmen||[])t.active=!1,t.target=null;e.repairmen=[],e.repairman.active=!1,e.repairman.target=null}function aa(e,t){return t&&wn(e).find(o=>or(o)===t.key)||null}function ca(e){let t=null;for(let n of wn(e)){let o=Bt(n);o<=.001||(!t||o>Bt(t))&&(t=n)}return t}function is(e,t){Se(e);let n=e.repairmen?.length?e.repairmen:e.repairman?.active?[e.repairman]:[];if(!n.length||e.phase!=="running")return;let o=new Set(n.map(i=>i.target?.key).filter(Boolean));for(let i of n)ua(e,i,t,o);let r=n[0];r&&e.repairman!==r&&(e.repairman.active=!0,e.repairman.x=r.x,e.repairman.y=r.y,e.repairman.target=r.target,e.repairman.repairedToday=r.repairedToday||0)}function ua(e,t,n,o){if(!t.active)return;let r=aa(e,t.target);if((!r||Bt(r)<=.001)&&(t.target?.key&&o.delete(t.target.key),r=da(e,o)),!r){t.target=null;return}let i=or(r);o.add(i),t.target={key:i,label:r.label};let l=Ue.repairman.walkSpeed,c=r.center.x-t.x,b=r.center.y-t.y,C=Math.hypot(c,b);if(C>8){let z=Math.min(C,l*n);t.x+=c/C*z,t.y+=b/C*z;return}let x=e?.cardEffects?.laborExploitation?.7:1,A=n/(Ue.repairman.secondsPerOnePercent*x*100),$=bn(r),B=A*Un(r);ts(r,B);let j=Math.max(0,($-bn(r))/Un(r)*100);t.repairedToday=(t.repairedToday||0)+j,j>0&&Math.random()<.02&&H(e,t.x,t.y-28,"REPAIR",y.green),Bt(r)<=.001&&(o.delete(i),t.target=null)}function da(e,t=new Set){let n=null;for(let o of wn(e)){if(t.has(or(o)))continue;let r=Bt(o);r<=.001||(!n||r>Bt(n))&&(n=o)}return n||ca(e)}function fa(e){let t=0,n="none";for(let o of wn(e)){let r=Bt(o);r>t&&(t=r,n=o.label)}return{ratio:t,percent:Math.round(t*100),label:n}}function rr(e){let t=fa(e),n=Jo(e);return{worst:t,avgBeltPerformance:n,repairman:e.repairman||null,repairmen:e.repairmen||[],rooms:e.maintenanceRooms||[]}}var pa=De.commonWeight,ya=De.rareWeight,ha=De.ultraRareWeight||.45,Lt=De.baseDraftSize,Jt=$r;function Qt(e,t){let n=Le(e);return Math.max(0,Number(n[t])||0)}function Le(e){e.cardEffects||(e.cardEffects={...wo});for(let[t,n]of Object.entries(wo))e.cardEffects[t]==null&&(e.cardEffects[t]=Array.isArray(n)?[]:n);return e.cardEffects.flattery!=null&&(e.cardEffects.fairiesFlatteryNext=Math.max(0,e.cardEffects.fairiesFlatteryNext||0)+Math.max(0,e.cardEffects.flattery||0),delete e.cardEffects.flattery),e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft||(e.cardDraft={pending:!1,choices:[],rerolls:0,picksRemaining:0}),e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardEffects}function ps(e){let t=Math.max(.5,1-.05*Math.min(10,Qt(e,"crowdedFarming"))),n=Math.pow(.96,Qt(e,"hatchingFeed"));return t*n}function ys(e,t=null){return Math.min(3,Math.max(0,Number(t?.extraEggOutlet)||0))}function hs(e){return Math.pow(.85,Qt(e,"scannerQueueSpacing"))}function Xn(e,t=null){let n=Le(e),o=En*Math.pow(Rn,Math.max(0,n.bearing||0)),r=t?Math.max(.1,Number(e?.conveyorMeta?.get?.(t)?.speedMultiplier)||1):1,i=t?1:Jo(e),l=Math.max(.01,Number(e?.eventActive?.conveyorSpeedMultiplier)||1);return Math.min(Kt,o*i)*r*l}function nt(e,t=null){let n=Math.max(0,(e?.level||1)-1),o=t?Qt(t,"autoScannerTuning"):0,r=Tn*Math.pow(Ir,n)*Math.pow(ho,o),i=Math.max(mo,r),l=t?Math.max(.01,Number(t?.eventActive?.autoScannerCooldownMultiplier)||1):1;return t?Math.max(mo,i*qn(e)*l):i}function ss(e){let t=e.cardDraft||{rerolls:0},n=Math.max(1,(t.rerolls||0)+1);return Math.ceil(Math.max(1,e.turn||1)/De.rerollCost.dayDivisor*n*De.rerollCost.multiplier)}function Ot(e){return Jt.find(t=>t.id===e)||null}function ms(e,t){let n=typeof t=="string"?Ot(t):t;return Le(e),!n||!(n.type==="equipmentUpgrade"||n.type==="cellAction")?[]:We(e,n).map(o=>({key:tt(o),label:lr(e,o),type:o.type}))}function sr(e,t,n={}){let o=typeof t=="string"?Ot(t):t;if(Le(e),!o||o.type==="dud")return{ok:!1,reason:"Card not found."};if(o.id==="extraCards")return e.cardDraft=e.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.choices.push(...zn(e,2)),{ok:!0,reason:`${o.title} added 2 draft cards.`};if(o.type==="instant")return vs(e,o),{ok:!0,reason:`${o.title} granted.`};if(o.type==="equipmentUpgrade"){let r=We(e,o);if(!r.length)return{ok:!1,reason:`No valid target for ${o.title}.`};let i=n.targetKey&&n.targetKey!=="__auto__"?String(n.targetKey):"",l=i?r.find(c=>tt(c)===i):r[0];return l?(bs(e,l),{ok:!0,reason:`${o.title} applied to ${lr(e,l)}.`}):{ok:!1,reason:`Selected target is no longer valid for ${o.title}.`}}if(o.type==="cellAction"&&o.target==="blockedCell"){let r=We(e,o);if(!r.length)return{ok:!1,reason:"No blocked cells to remove."};let i=new Set((Array.isArray(n.targetKeys)?n.targetKeys:[n.targetKey]).filter(c=>c&&c!=="__auto__").map(String)),l=i.size?r.filter(c=>i.has(tt(c))):r.slice(0,3);if(!l.length)return{ok:!1,reason:`Selected target is no longer valid for ${o.title}.`};for(let c of l.slice(0,3)){e.blockedCells.delete(I(c.col,c.row));let b=F(c.col,c.row);et(e,b.x,b.y),Xe(e,b.x,b.y,y.danger,42),Ze(e,b.x,b.y,8,y.warn)}return be(e),{ok:!0,reason:`${o.title} removed ${Math.min(3,l.length)} blocked cell(s).`}}return{ok:!1,reason:`${o.title} cannot be debug-granted.`}}function lr(e,t){if(t.type==="blockedCell")return`Blocked cell ${t.col},${t.row}`;if(t.type==="eggFarm")return`EGG #${t.id} L${t.level} -> L${t.level+1}`;if(t.type==="eggOutlet"){let n=Math.max(0,Number(t.farm?.extraEggOutlet)||0);return`EGG #${t.id} OUTLET ${1+n} -> ${2+n}`}if(t.type==="scanner")return`AUTO #${t.id} L${t.level} -> L${t.level+1} | CD ${nt(t,e).toFixed(1)}s -> ${nt({...t,level:t.level+1},e).toFixed(1)}s`;if(t.type==="facility"&&(t.baseId||t.id)==="mixer"){let n=t.level,o=ze(e);t.level=n+1;let r=ze(e);return t.level=n,`MIXER L${t.level} -> L${t.level+1} | ${T(o)} -> ${T(r)}`}if(t.type==="facility"&&(t.baseId||t.id)==="truck"){let n=t.level,o=Fe(e);t.level=n+1;let r=Fe(e);return t.level=n,`TRUCK L${t.level} -> L${t.level+1} | ${T(o)} -> ${T(r)}`}if(t.type==="facility"&&t.id==="trash"){let n=Dt(e),o=Math.min(zt(),n+1),r=ht(n),i=ht(o);return`SHREDDER L${t.level||1} -> L${(t.level||1)+1} | poop income ${T(r)} -> ${T(i)} per item`}return`${t.name||t.id} L${t.level||1} -> L${(t.level||1)+1}`}function ma(e){return[...e.blockedCells||[]].map(t=>{let[n,o]=String(t).split(",").map(Number);return{type:"blockedCell",id:t,col:n,row:o}}).filter(t=>Number.isFinite(t.col)&&Number.isFinite(t.row))}function We(e,t){let n=typeof t=="string"?Ot(t):t;return Le(e),n?n.target==="blockedCell"?ma(e):n.target==="eggFarm"?e.eggFarms.filter(o=>(o.level||1)<4):n.target==="eggOutlet"?e.eggFarms.filter(o=>Math.max(0,Number(o.extraEggOutlet)||0)<3).map(o=>({type:"eggOutlet",id:o.id,col:o.col,row:o.row,farm:o})):n.target==="autoScanner"?e.scanners.filter(o=>o.kind==="auto"):n.target==="mixer"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="mixer"):n.target==="truck"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="truck"):n.target==="trash"?Wo(e)(o.baseId||o.id)==="trash"):[]:[]:[]}function ba(e,t){let n=Le(e);if(t.id==="crowdedFarming")return(n.crowdedFarming||0)>=10;if(t.id==="recyclingSubsidy")return(n.recyclingSubsidy||0)>=3;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,De.dudChancePerCard||0)),r=Math.max(1e-4,Math.min(1,De.dudChanceReductionPerFilter||.05));return(n.dudFilter||0)>=Math.ceil(o/r)}return t.id==="laborExploitation"?!!n.laborExploitation:t.id==="usedMachine"?!!n.usedMachineActive:t.id==="newMachine"?!n.usedMachineActive:!1}function va(e){return!!((e.maintenanceRooms||[]).length||(e.repairmen||[]).length||e.repairman?.active)}function wa(e){return Jt.filter(t=>!(t.id==="laborExploitation"&&!va(e)||ba(e,t)||(t.type==="equipmentUpgrade"||t.type==="cellAction")&&We(e,t).length<=0))}function ls(e,t){return t.rarity==="ultraRare"?ha:t.rarity==="rare"?ya:pa}function Sa(e,t){let n=t.reduce((r,i)=>r+ls(e,i),0);if(n<=0)return t[Math.floor(Math.random()*t.length)];let o=Math.random()*n;for(let r of t)if(o-=ls(e,r),o<=0)return r;return t[t.length-1]}var as=0;function ka(){return as+=1,{id:`dud:${Date.now()}:${as}`,title:"Dud",rarity:"dud",type:"dud",description:"Click to flick this dud away. It does not consume a pick."}}function Ca(e){let t=Le(e),n=Math.max(0,Math.min(1,De.dudChancePerCard||0)),o=Math.max(0,Math.min(1,De.dudChanceReductionPerFilter||0));return Math.max(0,n-o*Math.max(0,t.dudFilter||0))}function Ma(e,t){let n=[...t],o=0,r=Math.max(0,De.maxDudsPerDraft||0),i=Ca(e);for(let l=0;lc.id===i.id);l>=0&&r.splice(l,1)}return Ma(e,o)}function tt(e){return e?e.type==="blockedCell"?`blockedCell:${e.id}`:e.type==="eggFarm"?`eggFarm:${e.id}`:e.type==="eggOutlet"?`eggOutlet:${e.id}`:e.type==="scanner"?`scanner:${e.id}`:e.type==="facility"?`facility:${e.id}`:`${e.type}:${e.id}`:""}function cs(e){if(!e)return null;if(e.type==="blockedCell"){let t=F(e.col,e.row);return{x:t.x-f.cell*.48,y:t.y-f.cell*.48,w:f.cell*.96,h:f.cell*.96,cx:t.x,cy:t.y}}if(e.type==="eggFarm"||e.type==="eggOutlet"){let t=F(e.col,e.row);return{x:t.x-34,y:t.y-34,w:68,h:68,cx:t.x,cy:t.y}}if(e.type==="scanner"){let t=ye(e);return{x:t.x-54,y:t.y-77,w:108,h:154,cx:t.x,cy:t.y}}return e.type==="facility"?{x:e.x,y:e.y,w:e.w,h:e.h,cx:e.x+e.w/2,cy:e.y+e.h/2}:null}function ar(e){if(!e.cardTargetPick?.pending)return[];if(e.cardTargetPick.mode==="autoScannerMenu"){let n=new Set(e.cardTargetPick.targetKeys||[]);return e.scanners.filter(o=>o.kind==="auto"&&n.has(tt(o))).map(o=>({key:tt(o),label:"AUTO ROUTE SETTINGS",target:o,bounds:cs(o)})).filter(o=>o.bounds)}let t=new Set(e.cardTargetPick.targetKeys||[]);return We(e,e.cardTargetPick.cardId).filter(n=>t.has(tt(n))).map(n=>({key:tt(n),label:lr(e,n),target:n,bounds:cs(n)})).filter(n=>n.bounds)}function ga(e,t){let n=ar(e);for(let o of n){let r=o.bounds;if(t.x>=r.x&&t.x<=r.x+r.w&&t.y>=r.y&&t.y<=r.y+r.h)return o.target}return null}function bs(e,t){if(t.type==="eggOutlet"){let n=t.farm||e.eggFarms.find(r=>r.id===t.id);if(!n)return;n.extraEggOutlet=Math.min(3,Math.max(0,Number(n.extraEggOutlet)||0)+1);let o=F(n.col,n.row);H(e,o.x,o.y-30,`OUTLET ${1+n.extraEggOutlet}`,y.green),be(e);return}if(t.level=(t.level||1)+1,t.type==="eggFarm"){t.nextSpawn=Rt(t),t.lastInterval=t.nextSpawn;let n=F(t.col,t.row);H(e,n.x,n.y-30,`LV ${t.level}`,y.green);return}if(t.type==="scanner"){let n=ye(t);H(e,n.x,n.y-34,`LV ${t.level}`,y.green);return}t.type==="facility"&&H(e,t.x+t.w/2,t.y+18,`LV ${t.level}`,y.green)}function vs(e,t){let n=Le(e),o=r=>{n[r]=Math.max(0,n[r]||0)+1};if(t.id==="bearing"&&o("bearing"),t.id==="autoScannerTuning"&&o("autoScannerTuning"),t.id==="legalWork"&&o("legalWork"),t.id==="crowdedFarming"&&(n.crowdedFarming=Math.min(10,(n.crowdedFarming||0)+1)),t.id==="hatchingFeed"&&o("hatchingFeed"),t.id==="poopRateBooster"&&o("poopRateBooster"),t.id==="safetyCover"&&o("safetyCover"),t.id==="recyclingSubsidy"&&(n.recyclingSubsidy=Math.min(3,(n.recyclingSubsidy||0)+1)),t.id==="chemicalWeaponSubsidy"&&o("chemicalWeaponSubsidy"),t.id==="preventiveMaintenance"&&o("preventiveMaintenance"),t.id==="dudFilter"&&o("dudFilter"),t.id==="durabilityCoating"&&(o("durabilityCoating"),Se(e)),t.id==="sparePartsBin"){o("sparePartsBin");let r=ns(e,.02);e.stats.sparePartsRepair=(e.stats.sparePartsRepair||0)+r,e.totals.sparePartsRepair=(e.totals.sparePartsRepair||0)+r,H(e,f.x+f.cols*f.cell/2,f.y-30,"REPAIR +2%",y.green)}t.id==="dudRefund"&&o("dudRefund"),t.id==="freeReroll"&&o("freeReroll"),t.id==="composter"&&o("composter"),t.id==="scannerQueueSpacing"&&o("scannerQueueSpacing"),t.id==="flattery"&&o("fairiesFlatteryNext"),t.id==="usedMachine"&&(n.usedMachineActive=!0),t.id==="newMachine"&&(n.usedMachineActive=!1),t.id==="laborExploitation"&&(n.laborExploitation=1),t.id==="rescueLoan"&&(o("rescueLoanCharges"),H(e,f.x+f.cols*f.cell/2,f.y-30,"RESCUE HELD",y.green))}function qe(e){return`${Math.round(Number(e||0)*100)}%`}function us(e){let t=st[Math.max(0,Math.min(st.length-1,e-1))]||st[0]||[0,0];return`${t[0].toFixed(2)}-${t[1].toFixed(2)}s`}function ds(e,t){return Math.ceil(e*Math.pow(ke.incomeUpgradeRate,Math.max(0,t-1)))}function fs(e,t,n){let r=We(e,t==="mixer"?"upgradeMixer":"upgradeTruck")[0];if(!r)return{before:ds(n,1),after:ds(n,2)};let i=t==="mixer"?ze(e):Fe(e),l=r.level||1;r.level=l+1;let c=t==="mixer"?ze(e):Fe(e);return r.level=l,{before:i,after:c}}function xa(e,t){let n=Le(e);if(t.id==="upgradeEgg"){let o=We(e,t),r=Math.min(3,Math.max(1,o[0]?.level||1));return`Choose one EGG. Level +1. Production interval ${us(r)} -> ${us(r+1)}.`}if(t.id==="upgradeAutoScanner"){let o=We(e,t)[0]||{level:1},r=nt(o,e),i=nt({...o,level:(o.level||1)+1},e);return`Choose one AUTO SCANNER. Level +1. Cooldown ${r.toFixed(2)}s -> ${i.toFixed(2)}s.`}if(t.id==="upgradeMixer"){let o=fs(e,"mixer",ke.income.mixer);return`Choose one MIXER. Earning +10%. Male-chick income ${T(o.before)} -> ${T(o.after)}.`}if(t.id==="upgradeTruck"){let o=fs(e,"truck",ke.income.truck);return`Choose one TRUCK. Earning +10%. Correct shipment income ${T(o.before)} -> ${T(o.after)}.`}if(t.id==="upgradeTrash"){let o=Dt(e),r=Math.min(zt(),o+1),i=ht(o),l=ht(r);return`SHREDDER level +1. Poop income ${T(i)} -> ${T(l)} per item.`}if(t.id==="bearing"){let o=Math.min(Kt,En*Math.pow(Rn,Math.max(0,n.bearing||0))),r=Math.min(Kt,En*Math.pow(Rn,Math.max(0,(n.bearing||0)+1)));return`Conveyor speed +7.5%. After pick: ${o.toFixed(1)} -> ${r.toFixed(1)} px/s.`}if(t.id==="legalWork"){let o=Math.max(0,n.legalWork||0);return`Fairies tribute profit exemption +${T(250)}. After pick: exemption bonus ${T(250*(o+1))}.`}if(t.id==="crowdedFarming"){let o=Math.min(10,(n.crowdedFarming||0)+1);return`Held ${n.crowdedFarming||0}/10. After pick: EGG interval ${qe(Math.max(.5,1-.05*o))}, deterioration ${qe(Math.min(1.4,1+.04*o))}.`}if(t.id==="extraEggOutlet"){let o=We(e,t),r=Math.max(0,Number(o[0]?.farm?.extraEggOutlet)||0);return`Choose one EGG. Output ports ${1+r} -> ${2+r}. Max 4 ports per EGG.`}if(t.id==="hatchingFeed")return`Held ${n.hatchingFeed||0}. After pick: EGG interval ${qe(Math.pow(.96,(n.hatchingFeed||0)+1))}, poop rate multiplier ${qe(Math.pow(1.03,(n.hatchingFeed||0)+1))}.`;if(t.id==="poopRateBooster")return`Held ${n.poopRateBooster||0}. After pick: base poop rate +${Math.round((n.poopRateBooster||0)+1)*4} percentage points.`;if(t.id==="autoScannerTuning")return`Held ${n.autoScannerTuning||0}. After pick: all AUTO SCANNER default cooldown ${qe(Math.pow(ho,(n.autoScannerTuning||0)+1))}.`;if(t.id==="safetyCover")return`Held ${n.safetyCover||0}. After pick: explosion damage ${qe(Math.pow(.95,(n.safetyCover||0)+1))}.`;if(t.id==="recyclingSubsidy")return`Held ${n.recyclingSubsidy||0}/3. After pick: normal SELL refund ${Math.round(Math.min(.8,.5+.1*((n.recyclingSubsidy||0)+1))*100)}%.`;if(t.id==="chemicalWeaponSubsidy")return`Held ${n.chemicalWeaponSubsidy||0}. After pick: ${T(1200*((n.chemicalWeaponSubsidy||0)+1))} per 70 truck-shipped poop each day.`;if(t.id==="preventiveMaintenance")return`Held ${n.preventiveMaintenance||0}. After pick: deterioration speed ${qe(Math.pow(.95,(n.preventiveMaintenance||0)+1))}.`;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,De.dudChancePerCard||0)),r=Math.max(0,Math.min(1,De.dudChanceReductionPerFilter||.05)),i=Math.max(0,n.dudFilter||0),l=Math.max(0,o-r*i),c=Math.max(0,o-r*(i+1));return`Held ${i}. DUD chance per card ${qe(l)} -> ${qe(c)}.`}return t.id==="durabilityCoating"?`Held ${n.durabilityCoating||0}. After pick: maximum durability ${qe(Math.pow(1.03,(n.durabilityCoating||0)+1))}.`:t.id==="sparePartsBin"?`Held ${n.sparePartsBin||0}. Immediately restores 2% durability to every maintained machine. Common card weight.`:t.id==="dudRefund"?`Held ${n.dudRefund||0}. After pick: DUD clicks award ${T(50*((n.dudRefund||0)+1))}.`:t.id==="freeReroll"?`Held ${n.freeReroll||0}. After pick: each card screen starts with ${(n.freeReroll||0)+1} free reroll${(n.freeReroll||0)+1===1?"":"s"}.`:t.id==="composter"?`Held ${n.composter||0}. After pick: SHREDDER poop grants ${T(3*((n.composter||0)+1))}.`:t.id==="scannerQueueSpacing"?`Held ${n.scannerQueueSpacing||0}. After pick: Manual/Auto Scanner queue spacing ${qe(Math.pow(.85,(n.scannerQueueSpacing||0)+1))}.`:t.id==="flattery"?`Next Fairies tribute -50%. Held for next tribute: ${n.fairiesFlatteryNext||0}.`:t.id==="usedMachine"?"Enable Used Machines: future equipment costs 50%, has no SELL refund, and starts with 60% durability.":t.id==="newMachine"?"Cancel Used Machines. Future equipment returns to normal price, refund, and durability.":t.id==="laborExploitation"?"Repairman dispatch paperwork is streamlined. Repair rooms keep operating; one time only.":t.id==="rescueLoan"?`At day-end bankruptcy check, gain ${T(500)} if cash is below ${T(0)}. Held: ${n.rescueLoanCharges||0}.`:t.id==="dynamite"?"Choose any blocked tiles on the map and destroy up to 3. Empty-space clicks are ignored; press Esc to finish after at least one blast.":t.description}function ir(e,t){let n=e.cardDraft?.choices||[],o=n.findIndex(r=>r.id===t.id);o>=0&&n.splice(o,1)}function ws({game:e,ui:t,onUpdatePanels:n}){function o(){n&&n()}function r(){Le(e),e.cardTargetPick=null,e.cardDraft={pending:!0,choices:zn(e,Lt),rerolls:0,freeRerolls:Qt(e,"freeReroll"),picksRemaining:1}}function i(){Le(e),e.cardDraft.pending=!1,e.cardDraft.choices=[],e.cardDraft.picksRemaining=0,e.cardTargetPick=null,t.modal.classList.remove("visible","equipment-popover"),o()}function l(R=Lt){Le(e),e.cardDraft.choices=zn(e,R)}function c(){Le(e),!e.cardDraft.choices.length&&e.cardDraft.picksRemaining>0&&l(Lt)}function b(R){ir(e,R),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1),e.cardTargetPick=null,c(),e.cardDraft.picksRemaining<=0?i():se()}function C(R){ir(e,R),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1)+De.extraCardsAddedPicks,e.cardDraft.choices.push(...zn(e,2)),se()}function x(R,_){let Y=Qt(e,"dudRefund")*50;if(Y>0){let O=Ge(e,Y);e.stats.dudRefundIncome=(e.stats.dudRefundIncome||0)+O,e.totals.dudRefundIncome=(e.totals.dudRefundIncome||0)+O,H(e,f.x+f.cols*f.cell/2,f.y-30,`DUD REFUND +${T(O)}`,y.green)}Ft(e,34,.62),document.body?.animate&&document.body.animate([{transform:"translate(0, 0)"},{transform:"translate(-10px, 7px)"},{transform:"translate(12px, -8px)"},{transform:"translate(-8px, -5px)"},{transform:"translate(9px, 6px)"},{transform:"translate(0, 0)"}],{duration:260,easing:"steps(5, end)"}),_&&(_.style.setProperty("--fling-x",`${260+Math.random()*260}px`),_.style.setProperty("--fling-y",`${-260-Math.random()*170}px`),_.style.setProperty("--fling-r",`${(Math.random()<.5?-1:1)*(52+Math.random()*38)}deg`),_.classList.add("flung")),window.setTimeout(()=>{ir(e,R),c(),se()},340)}function A(R,_=null){if(R.type==="dud")return x(R,_);if(R.id==="extraCards")return C(R);if(R.type==="equipmentUpgrade"||R.type==="cellAction")return $(R);vs(e,R),b(R)}function $(R){let _=We(e,R);_.length&&(e.cardTargetPick={pending:!0,cardId:R.id,mode:R.target==="blockedCell"?"blockedCell":"equipment",targetKeys:_.map(tt),remaining:R.id==="dynamite"?Math.min(3,_.length):1,used:0},t.modal.classList.remove("visible","equipment-popover"),o())}function B(R){if(!R||R.type!=="blockedCell")return!1;let _=I(R.col,R.row);if(!e.blockedCells?.has(_))return!1;e.blockedCells.delete(_);let Y=F(R.col,R.row);return et(e,Y.x,Y.y),Xe(e,Y.x,Y.y,y.danger,62),Ze(e,Y.x,Y.y,18,y.warn),Gn(e,Y.x,Y.y,8),Ft(e,16,.35),H(e,Y.x,Y.y-18,"BOOM",y.danger),be(e),e.cardTargetPick.remaining=Math.max(0,(e.cardTargetPick.remaining||1)-1),e.cardTargetPick.used=Math.max(0,e.cardTargetPick.used||0)+1,e.cardTargetPick.targetKeys=We(e,"dynamite").map(tt),o(),!0}function j(R){if(!e.cardTargetPick?.pending)return!1;let _=Ot(e.cardTargetPick.cardId),Y=ga(e,R);return _?_.id==="dynamite"?(!Y||!B(Y)||((e.cardTargetPick.remaining||0)<=0||!We(e,"dynamite").length)&&b(_),!0):Y?(bs(e,Y),b(_),!0):(z(),!0):(z(),!0)}function z(){if(!e.cardTargetPick?.pending)return;let R=e.cardTargetPick,_=Ot(R.cardId);if(_?.id==="dynamite"&&(R.used||0)>0){b(_);return}e.cardTargetPick=null,se()}function ce(){let R=Math.max(0,e.cardDraft?.freeRerolls||0);if(R>0){e.cardDraft.freeRerolls=R-1,e.cardDraft.rerolls+=1,l(Lt),se();return}let _=ss(e);e.cash<_||(bt(e,_),e.stats.cardRerollCost=(e.stats.cardRerollCost||0)+_,e.totals.cardRerollCost=(e.totals.cardRerollCost||0)+_,e.cardDraft.rerolls+=1,l(Lt),se())}function he(R){let _=new Set(R.tags||[]),Y={eggFarm:{type:"image",src:"./assets/dark_factory/facilities/machines/egg_farm_16.png",alt:"EGG"},eggOutlet:{type:"image",src:"./assets/dark_factory/facilities/machines/egg_farm_16.png",alt:"EGG"},autoScanner:{type:"image",src:"./assets/dark_factory/facilities/machines/auto_scanner_32x48.png",alt:"SCAN"},mixer:{type:"image",src:"./assets/dark_factory/facilities/machines/mixer_compact_16.png",alt:"MIX"},truck:{type:"image",src:"./assets/dark_factory/facilities/vehicles/truck_compact_16.png",alt:"TRUCK"},trash:{type:"image",src:"./assets/dark_factory/facilities/machines/shredder_compact_16.png",alt:"SHR"},blockedCell:{type:"image",src:"./assets/dark_factory/facilities/utility/obstacle_crate_16.png",alt:"BLOCK"}};return Y[R.target]?Y[R.target]:R.id==="bearing"||_.has("CONVEYOR")?{type:"image",src:"./assets/dark_factory/facilities/conveyor/conveyor_straight_h_16.png",alt:"BELT"}:_.has("SCANNER")?{type:"image",src:"./assets/dark_factory/facilities/machines/auto_scanner_32x48.png",alt:"SCAN"}:_.has("EGG")?{type:"image",src:"./assets/dark_factory/facilities/machines/egg_farm_16.png",alt:"EGG"}:_.has("POOP")?{type:"glyph",text:"\u{1F4A9}"}:_.has("MAINTENANCE")?{type:"image",src:"./assets/dark_factory/facilities/utility/repairman_16.png",alt:"FIX"}:_.has("CARD")?{type:"glyph",text:"\u25A3"}:_.has("ECONOMY")?{type:"glyph",text:"\uFFE5"}:_.has("RISK")?{type:"glyph",text:"!"}:{type:"glyph",text:"\u25C6"}}function ie(R){let _=he(R);return _.type==="image"?`
${_.alt||
`:``}function le(R,_){let Y=document.createElement("button");Y.type="button";let O=R.type==="dud"?"dud":R.rarity==="ultraRare"?"ultra-rare":R.rarity==="rare"?"rare":"common";Y.className=`card-choice ${O}`;let W=R.type==="dud"?"MISS":R.rarity==="ultraRare"?"ULTRA RARE":R.rarity==="rare"?"RARE":"COMMON",U=[W,...(R.tags||[]).filter(M=>M!==W)].slice(0,5);return Y.innerHTML=`${ie(R)}
${R.title}
${U.map(M=>`${M}`).join("")}
${xa(e,R)}
`,Y.addEventListener("click",()=>A(R,Y)),Y.dataset.index=String(_),Y}function se(){Le(e),e.cardTargetPick=null,e.cardDraft?.pending||r(),e.cardDraft.choices?.length||l(Lt);let R=e.cardDraft.choices||[],_=ss(e),Y=Math.max(0,e.cardDraft?.freeRerolls||0),O=Math.max(1,e.cardDraft.picksRemaining||1);t.modalTitle.textContent="Choose Upgrade Card",t.modalBody.innerHTML=`

Choose ${O} card${O===1?"":"s"} before Build phase. Dud cards can be flicked away without consuming a pick. Equipment cards target machines; Dynamite targets blocked cells.

`;let W=t.modalBody.querySelector("#cardChoices");R.forEach((g,G)=>W.appendChild(le(g,G))),t.modalActions.innerHTML="";let U=document.createElement("button");U.type="button",U.className="facility-action warn reroll-button",U.textContent=Y>0?`Reroll (FREE x${Y})`:`Reroll ${T(_)}`,U.disabled=Y<=0&&e.cash<_,U.title=Y>0?`${Y} free reroll${Y===1?"":"s"} remaining.`:U.disabled?"Not enough cash":"",U.addEventListener("click",ce),t.modalActions.appendChild(U);let M=document.createElement("button");M.type="button",M.className="facility-action",M.textContent="No Card",M.title="Skip this upgrade pick and enter Build phase.",M.addEventListener("click",i),t.modalActions.appendChild(M),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible")}return{prepareDraft:r,showDraft:se,finishDraft:i,chooseTargetAtPoint:j,cancelTargetPick:z}}var Ta=!0,Ea={chickMale:"./assets/images/chick_male.png",chickFemale:"./assets/images/chick_female.png",poop:"./assets/images/poop.png",conveyorStraightH:"./assets/dark_factory/facilities/conveyor/conveyor_straight_h_16.png",conveyorStraightV:"./assets/dark_factory/facilities/conveyor/conveyor_straight_v_16.png",conveyorTurnNe:"./assets/dark_factory/facilities/conveyor/conveyor_turn_ne_16.png",conveyorTurnNw:"./assets/dark_factory/facilities/conveyor/conveyor_turn_nw_16.png",conveyorTurnSe:"./assets/dark_factory/facilities/conveyor/conveyor_turn_se_16.png",conveyorTurnSw:"./assets/dark_factory/facilities/conveyor/conveyor_turn_sw_16.png",boostConveyorStraightH:"./assets/dark_factory/facilities/conveyor/boost_conveyor_straight_h_16.png",boostConveyorStraightV:"./assets/dark_factory/facilities/conveyor/boost_conveyor_straight_v_16.png",boostConveyorTurnNe:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_ne_16.png",boostConveyorTurnNw:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_nw_16.png",boostConveyorTurnSe:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_se_16.png",boostConveyorTurnSw:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_sw_16.png",scannerManual:"./assets/dark_factory/facilities/machines/manual_scanner_32x48.png",scannerAuto:"./assets/dark_factory/facilities/machines/auto_scanner_32x48.png",eggFarm:"./assets/dark_factory/facilities/machines/egg_farm_16.png",mixer:"./assets/dark_factory/facilities/machines/mixer_32.png",shredder:"./assets/dark_factory/facilities/machines/shredder_32.png",truck:"./assets/dark_factory/facilities/vehicles/truck_32.png",mixerCompact:"./assets/dark_factory/facilities/machines/mixer_compact_16.png",shredderCompact:"./assets/dark_factory/facilities/machines/shredder_compact_16.png",truckCompact:"./assets/dark_factory/facilities/vehicles/truck_compact_16.png",maintenanceRoom:"./assets/dark_factory/facilities/utility/maintenance_room_32.png",repairman:"./assets/dark_factory/facilities/utility/repairman_16.png",obstacleCrate:"./assets/dark_factory/facilities/utility/obstacle_crate_16.png"},ue={};for(let[e,t]of Object.entries(Ea)){let n=new Image;n.loaded=!1,n.onerror=()=>{n.loaded=!1},Ta&&t&&(n.onload=()=>{n.loaded=!0},n.src=t),ue[e]=n}function Cs(e,t,n,o){e.imageSmoothingEnabled=!1,e.clearRect(0,0,t.width,t.height),$a(e,t),e.save();let r=n.shake.time>0?K(-n.shake.strength,n.shake.strength):0,i=n.shake.time>0?K(-n.shake.strength,n.shake.strength):0,l=n.view?.scale||1;e.translate((n.view?.x||0)+r,(n.view?.y||0)+i),e.scale(l,l),Ba(e,n),La(e,n),Na(e,n),Xa(e,n),oc(e,n),rc(e,n),Qa(e,n),ja(e,n),Pa(e,n),ac(e,n,o.activeQueuedChick),bc(e,n),pc(e,t,n),fc(e,n,o.selectedObject,o.selectedTitle),yc(e,n),hc(e,n),mc(e,n),e.restore(),wc(e,n,t)}function Ra(e){if(e.type==="eggFarm"){let n=F(e.ref.col,e.ref.row);return{x:n.x-34,y:n.y-34,w:68,h:68,cx:n.x,cy:n.y}}let t=e.ref;return{x:t.x,y:t.y,w:t.w,h:t.h,cx:t.x+t.w/2,cy:t.y+t.h/2}}function Pa(e,t){if(t.phase!=="build")return;let n=On(t);for(let o of n){let r=Ra(o);e.save(),e.fillStyle="rgba(196,36,36,.22)",e.strokeStyle=y.danger,e.lineWidth=5,e.setLineDash([10,6]),ee(e,r.x,r.y,r.w,r.h,!0,!0),e.setLineDash([]),e.fillStyle=y.danger,e.strokeStyle=y.white,e.lineWidth=4,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.strokeText("!",r.cx,r.y+24),e.fillText("!",r.cx,r.y+24),e.font="900 11px ui-monospace, monospace",e.strokeText("NO ROUTE",r.cx,r.y+r.h-8),e.fillText("NO ROUTE",r.cx,r.y+r.h-8),e.restore()}}function ee(e,t,n,o,r,i=!0,l=!0){e.beginPath(),e.rect(t,n,o,r),i&&e.fill(),l&&e.stroke()}function ur(e,t,n,o,r=y.ink){e.save(),e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.lineWidth=4,e.strokeStyle=y.white,e.fillStyle=r,e.strokeText(o,t,n),e.fillText(o,t,n),e.restore()}function vt(e,t,n,o,r,i){if(!t?.loaded)return!1;let l=e.imageSmoothingEnabled;return e.imageSmoothingEnabled=!1,e.drawImage(t,Math.round(n),Math.round(o),Math.round(r),Math.round(i)),e.imageSmoothingEnabled=l,!0}function Aa(e,t,n,o,r,i,l=null,c=1){e.fillStyle=i,e.fillRect(Math.round(t),Math.round(n),Math.round(o),Math.round(r)),l&&(e.strokeStyle=l,e.lineWidth=c,e.strokeRect(Math.round(t)+.5,Math.round(n)+.5,Math.round(o)-1,Math.round(r)-1))}function Ia(e,t){let n=(Math.imul(e+37,73856093)^Math.imul(t+71,19349663))>>>0;return n^=n>>>13,n>>>0}function Da(e,t,n,o,r){let i=Ia(o,r);if(i%31!==0)return;let l=10+(i>>>4)%Math.max(1,f.cell-22),c=10+(i>>>9)%Math.max(1,f.cell-22),b=(i>>>14)%16*Math.PI/16;e.save(),e.globalAlpha=.46,e.fillStyle="#4d9638",e.strokeStyle="rgba(30,66,27,.48)",e.lineWidth=1,e.beginPath();for(let x=0;x<8;x+=1){let A=b+x*Math.PI/4,$=3.5+(i>>>x+2&3),B=t+l+Math.cos(A)*$*1.35,j=n+c+Math.sin(A)*$*.75;x===0?e.moveTo(B,j):e.lineTo(B,j)}e.closePath(),e.fill(),e.stroke();let C=3+(i>>>24)%4;for(let x=0;x>>x+8&3)*.18,$=8+(i>>>x+11&7),B=1.1+(i>>>x+17&3)*.45;e.beginPath(),e.arc(t+l+Math.cos(A)*$,n+c+Math.sin(A)*$*.72,B,0,Math.PI*2),e.fill()}e.fillStyle="rgba(151,218,101,.40)",e.beginPath(),e.arc(t+l-2,n+c-2,1.7,0,Math.PI*2),e.fill(),e.restore()}function $a(e,t){e.fillStyle=y.bg,e.fillRect(0,0,t.width,t.height),e.save(),e.globalAlpha=.85;for(let n=0;n=n;for(let r of Tt(t)){let i=Et(r);e.save(),e.fillStyle=o?"rgba(183,245,198,.34)":"rgba(255,255,255,.22)",e.strokeStyle=o?y.green:y.muted,e.lineWidth=5,e.setLineDash([16,10]),ee(e,i.x,i.y,i.w,i.h,!0,!0),e.setLineDash([]);let l=Mo(r),c=l.cx,b=l.cy;e.fillStyle="rgba(255,255,255,.94)",e.strokeStyle=y.ink,e.lineWidth=4,ee(e,l.x,l.y,l.w,l.h,!0,!0),e.fillStyle=o?y.green:y.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText(r.direction==="right"?"BUY RIGHT LOT":"BUY UPPER LOT",c,b-12),e.fillStyle=y.ink,e.font="900 16px ui-monospace, monospace",e.fillText(`${T(n)} / 10\xD710`,c,b+15),e.fillStyle=y.muted,e.font="900 11px ui-monospace, monospace",e.fillText("blocked tiles included",c,b+30),e.restore()}}function ot(e,t,n,o,r,i,l=0){let c=Xt(i);c<.5||(e.save(),e.globalAlpha=Math.min(.62,.12+c*.54),e.fillStyle="#6b4a23",l>0?(e.beginPath(),e.roundRect?.(t,n,o,r,l),e.roundRect?e.fill():ee(e,t,n,o,r,!0,!1)):ee(e,t,n,o,r,!0,!1),e.globalAlpha=Math.min(.9,.25+c*.6),e.strokeStyle="#3a2a16",e.lineWidth=Math.max(2,Math.floor(2+c*5)),e.setLineDash([5,6]),ee(e,t+3,n+3,o-6,r-6,!1,!0),e.restore())}function cr(e,t){let n=e.componentLookup?.get(t);return(n?e.congestion.get(n):null)?.ratio||0}function Oa(e,t,n={}){let o=kn(e,t).sort(),i=n.kind==="boostConveyor"?"boostConveyor":"conveyor",l=c=>o.includes(c);if(o.length===2){if(l("left")&&l("right"))return ue[`${i}StraightH`];if(l("up")&&l("down"))return ue[`${i}StraightV`];if(l("up")&&l("right"))return ue[`${i}TurnNe`];if(l("up")&&l("left"))return ue[`${i}TurnNw`];if(l("down")&&l("right"))return ue[`${i}TurnSe`];if(l("down")&&l("left"))return ue[`${i}TurnSw`]}return o.length===1?l("up")||l("down")?ue[`${i}StraightV`]:ue[`${i}StraightH`]:l("up")||l("down")?ue[`${i}StraightV`]:ue[`${i}StraightH`]}function Na(e,t){let n=[],o=new Set;for(let i of t.conveyorTiles){let{col:l,row:c}=te(i);for(let b of de){let C={col:l+b.dc,row:c+b.dr},x=I(C.col,C.row);if(!t.conveyorTiles.has(x))continue;let A=[i,x].sort().join("|");if(o.has(A))continue;o.add(A);let $=Math.max(cr(t,i),cr(t,x));n.push({a:F(l,c),b:F(C.col,C.row),ratio:$})}}e.save(),e.lineCap="round",e.lineJoin="round";for(let i of[{width:31,color:"#0b0c0f",alpha:1},{width:23,color:"#444b56",alpha:1},{width:15,color:"#171a1f",alpha:1}]){e.globalAlpha=i.alpha,e.strokeStyle=i.color,e.lineWidth=i.width;for(let l of n)e.beginPath(),e.moveTo(l.a.x,l.a.y),e.lineTo(l.b.x,l.b.y),e.stroke()}for(let i of n){let l=Math.max(0,(i.ratio-.5)/.5);e.strokeStyle=Ht(y.green,y.danger,l),e.globalAlpha=i.ratio>.5?.35+l*.55:.8,e.lineWidth=6,e.beginPath(),e.moveTo(i.a.x,i.a.y),e.lineTo(i.b.x,i.b.y),e.stroke()}let r=Ya(t);for(let i of t.conveyorTiles){let l=F(...Object.values(te(i))),c=t.conveyorMeta.get(i)||{},b=cr(t,i),C=Oa(t,i,c),x=b>.5;if(e.fillStyle=x?"rgba(196,36,36,.28)":"rgba(0,0,0,.35)",e.strokeStyle=x?y.danger:"rgba(255,184,39,.34)",e.lineWidth=x?3:1,ee(e,l.x-20,l.y-20,40,40,!0,!0),!vt(e,C,l.x-19,l.y-19,38,38)){let $=c.kind==="boostConveyor"?"#315e92":"#454b55";e.fillStyle=b>.5?Ht($,"#a12c2c",Math.max(0,(b-.5)/.5)):$,e.strokeStyle=y.ink,e.lineWidth=2,ee(e,l.x-18,l.y-18,36,36,!0,!0)}_a(e,l,i,c,b),ot(e,l.x-18,l.y-18,36,36,{meta:c}),rt(e,t,"conveyor",i,l.x,l.y,38,38),Va(e,l,r.get(i)||[]);let A=kn(t,i);Ha(e,l,c,Wa(t,i,A),A),b>.5&&ur(e,l.x,l.y-15,`${Math.floor(b*100)}%`,y.danger)}e.restore()}function _a(e,t,n,o={},r=0){let l=[...new Set([...Array.isArray(o.outDirs)?o.outDirs:[],o.dir].filter(Boolean))][0]||"right",c=l==="up"||l==="down",b=l==="left"||l==="up",C=o.kind==="boostConveyor",x=typeof performance<"u"?performance.now()/(C?70:105):0,A=((b?-x:x)%10+10)%10;e.save(),e.beginPath(),e.rect(t.x-18,t.y-18,36,36),e.clip();let $=C?"rgba(20,126,124,.62)":"rgba(42,47,54,.72)";if(e.fillStyle=$,e.fillRect(t.x-18,t.y-18,36,36),e.strokeStyle=r>.5?"rgba(238,83,61,.90)":"rgba(184,190,198,.92)",e.lineWidth=4,c)for(let B=t.y-28+A;Be.conveyorTiles.has(I(n.col+o.dc,n.row+o.dr))).map(o=>o.name)}function Ga(e,t,n){let o=de.find(l=>l.name===n);if(!o)return!1;let r=e.conveyorMeta?.get?.(I(t.col+o.dc,t.row+o.dr));return r?[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))].includes(o.opposite):!1}function Ms(e,t,n,o=kn(e,t)){if(o.length<3)return n;let r=te(t),i=new Set(o.filter(b=>Ga(e,r,b))),l=o.filter(b=>!i.has(b));if(i.size&&l.length>=2)return l;let c=n.filter(b=>o.includes(b));return c.length>=2?[...new Set(c)]:o}function Ua(e,t,n,o=kn(e,t),r="random"){let i=Ms(e,t,n,o);return o.length>=3&&r&&r!=="random"&&i.includes(r)?[r]:i}function Wa(e,t,n=kn(e,t)){let o=e.conveyorMeta?.get?.(t)||{},r=[...new Set([...Array.isArray(o.outDirs)?o.outDirs:[],o.dir].filter(Boolean))];return n.length<3?[]:Ms(e,t,r,n)}function Ka(e,t,n){let o=te(t),r=de.filter(c=>e.conveyorTiles.has(I(o.col+c.dc,o.row+c.dr))).map(c=>c.name),i=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(c=>r.includes(c)),l=r;return i.length?i:l}function Ha(e,t,n,o,r=o){if(r.length<3||o.length<2)return;e.save();let i=o.includes(n.branchMode)?n.branchMode:"random",l=i!=="random";if(e.lineJoin="round",e.lineCap="round",e.lineWidth=2,e.fillStyle="rgba(18,21,26,.94)",e.strokeStyle=l?y.warn:y.green,e.lineWidth=4,ee(e,t.x-18,t.y-18,36,36,!0,!0),e.strokeStyle="#ffd36a",e.lineWidth=3,e.fillStyle="#020304",i!=="random"){let c=de.find(b=>b.name===i);Sn(e,t.x,t.y,c?.angle||0,9,6)}else e.beginPath(),e.moveTo(t.x-10,t.y),e.lineTo(t.x-2,t.y),e.lineTo(t.x+8,t.y-8),e.moveTo(t.x-2,t.y),e.lineTo(t.x+8,t.y+8),e.stroke(),Sn(e,t.x+9,t.y-9,-Math.PI/4,4,3),Sn(e,t.x+9,t.y+9,Math.PI/4,4,3);e.restore()}function qa(e,t,n){if(!n)return[];let o=te(t),r=de.filter(c=>e.conveyorTiles.has(I(o.col+c.dc,o.row+c.dr))).map(c=>c.name),i=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(c=>r.includes(c));return Ua(e,t,i.length?i:Ka(e,t,n),r,n.branchMode||"random").map(c=>de.find(b=>b.name===c)).filter(Boolean)}function Ya(e){let t=new Map;for(let[n,o]of e.conveyorMeta||[]){let r=qa(e,n,o);r.length&&t.set(n,r)}return t}function Va(e,t,n){let o=n.slice(0,4);o.length&&(e.save(),e.globalAlpha=1,o.forEach(r=>{let i=t.x+r.dc*11,l=t.y+r.dr*11;e.fillStyle="rgba(255,205,83,.96)",Sn(e,i,l,r.angle,9,7),e.fillStyle="#020304",Sn(e,i,l,r.angle,6.5,4.6)}),e.restore())}function Sn(e,t,n,o,r=11,i=8){e.save(),e.translate(t,n),e.rotate(o),e.beginPath(),e.moveTo(r,0),e.lineTo(-r*.72,-i),e.lineTo(-r*.72,i),e.closePath(),e.fill(),e.restore()}function za(e,t,n,o,r){let i=ye(t),l=null;if(n==="inputA"&&(l={x:i.x,y:i.y-67}),n==="left"&&(l={x:i.x-49,y:i.y+14}),n==="right"&&(l={x:i.x+49,y:i.y+14}),!l)return;let c=n==="inputA"?{x:o.x,y:l.y}:{x:l.x,y:o.y};e.save(),e.lineCap="square",e.lineJoin="bevel",e.strokeStyle="#050609",e.lineWidth=15,e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(c.x,c.y),e.lineTo(l.x,l.y),e.stroke(),e.strokeStyle="#596473",e.lineWidth=9,e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(c.x,c.y),e.lineTo(l.x,l.y),e.stroke(),e.strokeStyle=r||"#7b8795",e.lineWidth=3,e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(c.x,c.y),e.lineTo(l.x,l.y),e.stroke(),e.fillStyle=r||"#7b8795",e.strokeStyle="#050609",e.lineWidth=3,ee(e,l.x-9,l.y-7,18,14,!0,!0),e.restore()}function Xa(e,t){e.save(),e.lineWidth=2,e.font="900 12px ui-monospace, monospace",e.textAlign="center";for(let n of t.scanners){let o=Io(n),r=[{type:"inputA",p:Re(n,"inputA"),label:"IN",color:y.green},{type:"left",p:Re(n,"left"),label:$o(o.left),color:Fo(o.left)},{type:"right",p:Re(n,"right"),label:$o(o.right),color:Fo(o.right)}];for(let i of r){if(!i.p)continue;let l=F(i.p.col,i.p.row);za(e,n,i.type,l,i.color);let c=ai(t,n,i.type||(i.label==="IN"?"inputA":null))||t.conveyorTiles.has(I(i.p.col,i.p.row));e.fillStyle=c?Ht("#1a1d23",i.color,.24):"#3a1e22",e.strokeStyle=c?i.color:y.danger,ee(e,l.x-18,l.y-12,36,24,!0,!0),e.fillStyle=y.white,e.fillText(i.label,l.x,l.y+4)}}e.restore()}function Qa(e,t){for(let n of t.eggFarms)Ja(e,n,t)}function Ja(e,t,n){let o=F(t.col,t.row);if(e.save(),vt(e,ue.eggFarm,o.x-29,o.y-29,58,58)){ot(e,o.x-29,o.y-29,58,58,t);let l=1+Math.max(0,Number(t.extraEggOutlet)||0);e.fillStyle="rgba(255,255,255,.92)",e.strokeStyle=y.ink,e.lineWidth=2,ee(e,o.x+9,o.y+12,30,18,!0,!0),e.fillStyle=y.ink,e.font="900 10px ui-monospace, monospace",e.textAlign="center",e.fillText(`O${l}`,o.x+24,o.y+24),rt(e,n,"eggFarm",t.id,o.x,o.y,68,68),e.restore();return}e.fillStyle=y.white,e.strokeStyle=y.ink,e.lineWidth=4,ee(e,o.x-28,o.y-28,56,56,!0,!0),e.fillStyle=y.green,e.font="900 19px ui-monospace, monospace",e.textAlign="center",e.fillText("EGG",o.x,o.y-4);let r=1+Math.max(0,Number(t.extraEggOutlet)||0);e.font="900 11px ui-monospace, monospace",e.fillStyle=y.ink,e.fillText(`L${t.level} O${r}`,o.x,o.y+13),e.fillText(`${t.nextSpawn.toFixed(1)}s`,o.x,o.y+26);let i=Math.max(0,Math.min(1,t.shutterProgress||0));if(i>0){let l=56*i;e.fillStyle=y.ink,ee(e,o.x-28,o.y-28,56,l,!0,!1),e.strokeStyle=y.white,e.lineWidth=2;for(let c=o.y-24;c=1&&(e.fillStyle=y.white,e.font="900 12px ui-monospace, monospace",e.fillText("SHUT",o.x,o.y+4))}ot(e,o.x-28,o.y-28,56,56,t),rt(e,n,"eggFarm",t.id,o.x,o.y,68,68),e.restore()}function ja(e,t){for(let n of t.scanners)Za(e,n,t)}function Za(e,t,n){let o=ye(t);if(e.save(),t.kind==="manual"&&(n.manualCombo?.count||0)>=10){let b=n.manualCombo.count;e.save(),e.globalAlpha=Math.min(.55,.16+b/120),e.strokeStyle=b>=30?y.warn:y.green,e.lineWidth=Math.min(14,5+Math.floor(b/10)),e.shadowColor=e.strokeStyle,e.shadowBlur=Math.min(28,8+b),ee(e,o.x-54,o.y-76,108,152,!1,!0),e.restore()}let r=t.kind==="auto"?ue.scannerAuto:ue.scannerManual;if(vt(e,r,o.x-50,o.y-73,100,146)){t.kind==="auto"?ot(e,o.x-50,o.y-73,100,146,t):Ss(e,t,o),rt(e,n,"scanner",t.id,o.x,o.y,108,154),e.restore();return}e.fillStyle=t.kind==="auto"?"#d8ffe2":y.white,e.strokeStyle=y.ink,e.lineWidth=4,ee(e,o.x-50,o.y-73,100,146,!0,!0),e.fillStyle=t.kind==="auto"?y.green:y.ink,e.font="900 19px ui-monospace, monospace",e.textAlign="center",e.fillText(`${t.kind==="auto"?"AUTO":`S${(t.slot??0)+1}`}`,o.x,o.y-48),e.font="900 11px ui-monospace, monospace";let i=t.keys?.left?.label||(t.slot===0?"A":"Left"),l=t.keys?.right?.label||(t.slot===0?"D":"Right");e.fillText(t.role===0?`${i}:M ${l}:NEXT`:`${i}:WASTE ${l}:TRUCK`,o.x,o.y-28);let c=t.queue.length;t.kind==="manual"?(Ss(e,t,o),e.fillStyle=c>0?y.green:y.muted,e.font="900 10px ui-monospace, monospace",e.fillText(`Q:${c}`,o.x,o.y+54)):(e.fillStyle=c>0?y.green:y.muted,e.font="900 12px ui-monospace, monospace",e.fillText(`Q:${c} CD:${t.cooldown.toFixed(1)}`,o.x,o.y+54),ot(e,o.x-50,o.y-73,100,146,t)),rt(e,n,"scanner",t.id,o.x,o.y,108,154),e.restore()}function Ss(e,t,n){if(t.kind!=="manual")return;let r=(t.slot??0)===0?[{side:"left",text:"A"},{side:"right",text:"D"}]:[{side:"left",text:"\u2190"},{side:"right",text:"\u2192"}];r[0].text=t.keys?.left?.label||r[0].text,r[1].text=t.keys?.right?.label||r[1].text;let i=t.keyPressTime>0?t.keyPressSide:null,l=n.x-30,c=n.y+18;e.save(),e.lineWidth=3,e.fillStyle="#f7fff5",e.strokeStyle=y.ink,ee(e,l-4,c-4,68,25,!0,!0),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let b=0;b.8,i=t.y+Math.sin(t.bob)*(r?5:1.5);if(e.save(),n&&(e.strokeStyle=y.green,e.lineWidth=5,e.beginPath(),e.arc(t.x,i,t.radius+8,0,Math.PI*2),e.stroke()),r&&(e.strokeStyle=y.danger,e.lineWidth=3,e.beginPath(),e.arc(t.x,i,t.radius+12+Math.sin(t.bob*2)*4,0,Math.PI*2),e.stroke()),t.sex==="poop")mr(e,t.x,i,t.radius);else{let l=t.sex==="male"?ue.chickMale:ue.chickFemale;if(!vt(e,l,t.x-t.radius,i-t.radius,t.radius*2,t.radius*2)){let C=t.sex==="male"?y.male:y.female,x=t.sex==="male"?"#164f8f":"#8b2252";e.fillStyle=C,e.strokeStyle=y.ink,e.lineWidth=5,e.beginPath(),e.arc(t.x,i,t.radius,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle="rgba(255,255,255,.24)",e.beginPath(),e.arc(t.x-5,i-7,t.radius*.36,0,Math.PI*2),e.fill(),e.fillStyle=y.ink,e.beginPath(),e.arc(t.x-6,i-5,2.5,0,Math.PI*2),e.arc(t.x+6,i-5,2.5,0,Math.PI*2),e.fill(),e.fillStyle="#ffaa2e",e.beginPath(),e.moveTo(t.x,i+2),e.lineTo(t.x+9,i+6),e.lineTo(t.x,i+10),e.closePath(),e.fill(),e.strokeStyle=x,e.lineWidth=3,t.sex==="male"?(e.beginPath(),e.moveTo(t.x-8,i-t.radius-2),e.lineTo(t.x+8,i-t.radius-2),e.stroke()):(e.beginPath(),e.moveTo(t.x-9,i-t.radius+2),e.lineTo(t.x,i-t.radius-6),e.lineTo(t.x+9,i-t.radius+2),e.stroke())}e.fillStyle=t.sex==="male"?"#dff1ff":"#fff0f7",e.strokeStyle="#050609",e.lineWidth=3,e.font=`900 ${Math.max(10,Math.round(t.radius*.72))}px ui-monospace, monospace`,e.textAlign="center";let b=t.sex==="male"?"\u2642":"\u2640";e.strokeText(b,t.x+t.radius*.54,i+t.radius*.7),e.fillText(b,t.x+t.radius*.54,i+t.radius*.7)}e.restore()}function uc(e,t){let n=null,o=1/0;for(let[r,i]of e.componentLookup.entries()){let l=te(r),c=F(l.col,l.row),b=Math.hypot(t.x-c.x,t.y-c.y);bks(o.type,o.id)===ks(t,n))}function rt(e,t,n,o,r,i,l,c){dc(t,n,o)&&(e.save(),e.fillStyle="rgba(34,185,79,.18)",e.strokeStyle=y.green,e.lineWidth=(t.multiSelected||[]).length>1?6:4,e.setLineDash((t.multiSelected||[]).length>1?[]:[8,5]),ee(e,r-l/2,i-c/2,l,c,!0,!0),e.restore())}function fc(e,t,n,o){if(t.phase==="build"&&(t.multiSelected||[]).length>1){e.save(),e.fillStyle="rgba(255,255,255,.96)",e.strokeStyle=y.ink,e.lineWidth=3,ee(e,54-t.view.x,66-t.view.y,214,42,!0,!0),e.fillStyle=y.ink,e.font="900 11px ui-monospace, monospace",e.fillText(`${t.multiSelected.length} ITEMS SELECTED`,65-t.view.x,83-t.view.y),e.fillStyle=y.muted,e.font="900 11px ui-monospace, monospace",e.fillText("drag any selected item to move group",65-t.view.x,99-t.view.y),e.restore();return}}function pc(e,t,n){if(!n.cardTargetPick?.pending)return;let o=ar(n);e.save(),e.fillStyle="rgba(0,0,0,.66)",e.beginPath();let r=n.view?.scale||1;e.rect(-(n.view?.x||0)/r,-(n.view?.y||0)/r,t.width/r,t.height/r);for(let C of o){let x=C.bounds,A=8;e.rect(x.x-A,x.y-A,x.w+A*2,x.h+A*2)}e.fill("evenodd");let i=n.cardTargetPick?.mode==="blockedCell";if(!o.length){e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=y.ink,e.lineWidth=3,ee(e,(260-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,420/r,42/r,!0,!0),e.fillStyle=y.danger,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(i?"NO BLOCKED CELL. PRESS ESC.":"NO VALID UPGRADE TARGET. PRESS ESC.",(470-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore();return}e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=y.ink,e.lineWidth=3;let l=Math.max(1,n.cardTargetPick?.remaining||1),c=Math.max(0,n.cardTargetPick?.used||0),b=n.cardTargetPick?.mode==="autoScannerMenu"?"AUTO SCANNER ROUTE SETTINGS. CLICK EMPTY AREA TO CLOSE.":i?`DYNAMITE: CLICK ANY BLOCKED TILE (${l} LEFT). ESC ${c>0?"FINISHES":"CANCELS"}.`:"CLICK AN UPGRADEABLE MACHINE. PRESS ESC TO CANCEL.";ee(e,(216-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,560/r,42/r,!0,!0),e.fillStyle=y.ink,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(b,(496-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore()}function yc(e,t){if(t.phase!=="build"||!t.selectionBox)return;let n=t.selectionBox,o=Math.min(n.x1,n.x2),r=Math.min(n.y1,n.y2),i=Math.abs(n.x2-n.x1),l=Math.abs(n.y2-n.y1);e.save(),e.fillStyle="rgba(34,185,79,.12)",e.strokeStyle=y.green,e.lineWidth=2,e.setLineDash([7,4]),ee(e,o,r,i,l,!0,!0),e.restore()}function hc(e,t){let n=[...t.effects].sort((o,r)=>(o.priority??Ce.ambient)-(r.priority??Ce.ambient));for(let o of n){let r=Math.max(0,o.life/o.maxLife);e.save(),e.globalAlpha=r,o.type==="meat"?(e.fillStyle=y.green,ee(e,o.x-o.size/2,o.y-o.size/2,o.size*1.5,o.size,!0,!1)):o.type==="sludge"?(e.fillStyle=y.poop,ee(e,o.x-o.size/2,o.y-o.size/2,o.size*1.4,o.size,!0,!1)):o.type==="spawn"?(e.strokeStyle=y.green,e.lineWidth=3,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*20,0,Math.PI*2),e.stroke()):o.type==="spark"?(e.fillStyle=o.color||y.danger,ee(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!0,!1)):o.type==="smoke"?(e.fillStyle="rgba(16,32,21,.24)",e.beginPath(),e.arc(o.x,o.y,o.size*(1.2-r*.2),0,Math.PI*2),e.fill()):o.type==="shockwave"?(e.strokeStyle=o.color||y.danger,e.lineWidth=4,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*(o.maxSize||44),0,Math.PI*2),e.stroke()):o.type==="scannerPulse"?(e.strokeStyle=o.color||y.green,e.lineWidth=5,e.setLineDash([8,6]),e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*38,0,Math.PI*2),e.stroke()):o.type==="shred"?(e.fillStyle=o.color||y.ink,e.save(),e.translate(o.x,o.y),e.rotate(o.rot||0),ee(e,-o.w/2,-o.h/2,o.w,o.h,!0,!1),e.restore()):o.type==="load"?(e.strokeStyle=o.color||y.green,e.lineWidth=3,e.beginPath(),e.moveTo(o.x-14,o.y),e.lineTo(o.x+14,o.y),e.moveTo(o.x,o.y-14),e.lineTo(o.x,o.y+14),e.stroke()):o.type==="erase"?(e.strokeStyle=y.ink,e.lineWidth=3,e.setLineDash([4,4]),ee(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!1,!0)):o.type==="rage"?(e.fillStyle=o.color||y.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText("!",o.x,o.y)):o.type==="flyingChick"&&(o.sex==="poop"?mr(e,o.x,o.y,o.radius||11):br(e,o.x,o.y,o.sex,o.sex==="male")),e.restore()}}function mc(e,t){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let n of t.floatingTexts){let o=Math.max(0,n.life/n.maxLife);e.globalAlpha=o,e.lineWidth=5,e.strokeStyle=y.white,e.fillStyle=n.color,e.strokeText(n.text,n.x,n.y),e.fillText(n.text,n.x,n.y)}e.restore()}function bc(e,t){let n=t.repairmen&&t.repairmen.length?t.repairmen:t.repairman?[t.repairman]:[];for(let o of n)vc(e,t,o)}function vc(e,t,n){if(!!!n?.active)return;if(e.save(),vt(e,ue.repairman,n.x-18,n.y-18,36,36)){n.target?.label&&ur(e,n.x,n.y-24,n.target.label,y.green),e.restore();return}e.lineWidth=3,e.fillStyle="#fff0d1",e.strokeStyle=y.ink,e.beginPath(),e.arc(n.x,n.y,17,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle="#ffd6e7",e.beginPath(),e.arc(n.x-6,n.y-2,3.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+6,n.y-2,3.2,0,Math.PI*2),e.fill();let r=!!t.cardEffects?.laborExploitation;e.fillStyle=r?y.danger:y.ink,e.beginPath(),e.arc(n.x-5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.strokeStyle=y.ink,e.lineWidth=r?3:2,e.beginPath(),e.arc(n.x,n.y+(r?0:1),r?8:7,.1*Math.PI,.9*Math.PI),e.stroke(),e.fillStyle=y.green,ee(e,n.x-9,n.y+14,18,8,!0,!0),e.strokeStyle=y.ink,e.lineWidth=3,e.beginPath(),e.moveTo(n.x-11,n.y+18),e.lineTo(n.x-20,n.y+24),e.stroke(),e.beginPath(),e.moveTo(n.x+11,n.y+18),e.lineTo(n.x+20,n.y+24),e.stroke(),e.fillStyle=y.ink,e.font="900 11px ui-monospace, monospace",e.textAlign="center",e.fillText("FIX",n.x,n.y+33),n.target?.label&&ur(e,n.x,n.y-24,n.target.label,y.green),e.restore()}function wc(e,t,n){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="left",e.fillStyle=y.ink,e.font="900 19px ui-monospace, monospace",e.fillStyle=y.ink;let o=[];t.phase==="running"&&o.push(t.timeLeft<=0?"TIME UP: FARMS SHUT. CLEAR LINE.":"A/D: S1 \u2190/\u2192: S2"),t.phase==="build"&&o.push(`BUILD: ${t.buildTool||"SELECT"} | connect 1 EGG route to any exit`);let r=76;for(let i of o)e.strokeStyle=y.white,e.lineWidth=4,e.strokeText(i,24,r),e.fillText(i,24,r),r+=20;e.restore()}var Es=[[{key:"a",code:"KeyA",label:"A"},{key:"d",code:"KeyD",label:"D"}],[{key:"arrowleft",code:"ArrowLeft",label:"Left"},{key:"arrowright",code:"ArrowRight",label:"Right"}],[{key:"j",code:"KeyJ",label:"J"},{key:"l",code:"KeyL",label:"L"}],[{key:"f",code:"KeyF",label:"F"},{key:"h",code:"KeyH",label:"H"}],[{key:"q",code:"KeyQ",label:"Q"},{key:"e",code:"KeyE",label:"E"}],[{key:"z",code:"KeyZ",label:"Z"},{key:"x",code:"KeyX",label:"X"}],[{key:"u",code:"KeyU",label:"U"},{key:"o",code:"KeyO",label:"O"}],[{key:"n",code:"KeyN",label:"N"},{key:"m",code:"KeyM",label:"M"}]];function Sc(e){let t=Es[e]||Es[0];return{left:{...t[0]},right:{...t[1]}}}function Rs(e,t,n){let o={type:"eggFarm",id:e.nextId++,col:t,row:n,level:1,nextSpawn:2,lastInterval:2,extraEggOutlet:0,price:lt.eggFarm,builtSession:e.buildSession};return o.nextSpawn=Rt(o),o.lastInterval=o.nextSpawn,o}function Ps(e,t,n,o){let r=o==="auto"?ve.autoScanner.price:ve.manualScanner.price,i=new Set(e.scanners.filter(c=>c.kind==="manual").map(c=>c.slot)),l=0;for(;i.has(l);)l+=1;return{type:"scanner",id:e.nextId++,kind:o,slot:o==="manual"?l:null,role:o==="manual"?l%2:0,col:t,row:n,level:1,queue:[],cooldown:0,price:r,builtSession:e.buildSession,autoMode:"standard",keys:o==="manual"?Sc(l):null}}function Jn(e){let t=(e.x-f.x)/f.cell,n=(e.y-f.y)/f.cell,o=Math.max(0,Math.min(f.cols-1,Math.round(t-.5))),r=Math.max(0,Math.min(f.rows-1,Math.round(n-.5))),i=Math.abs(e.x-f.x),l=Math.abs(e.x-(f.x+f.cols*f.cell)),c=Math.abs(e.y-f.y),b=Math.abs(e.y-(f.y+f.rows*f.cell)),C=[["left",i],["right",l],["top",c],["bottom",b]].sort((x,A)=>x[1]-A[1])[0][0];return C==="left"?{side:C,entry:{col:0,row:r}}:C==="right"?{side:C,entry:{col:f.cols-1,row:r}}:C==="top"?{side:C,entry:{col:o,row:0}}:{side:C,entry:{col:o,row:f.rows-1}}}function jn(e,t,n){let o={x:f.x+t.col*f.cell+f.cell/2,y:f.y+t.row*f.cell+f.cell/2},r={left:f.x,right:f.x+f.cols*f.cell,top:f.y,bottom:f.y+f.rows*f.cell};return e.entry={...t},e.side=n,n==="left"?(e.x=r.left-e.w-18,e.y=o.y-e.h/2):n==="right"?(e.x=r.right+18,e.y=o.y-e.h/2):n==="top"?(e.x=o.x-e.w/2,e.y=r.top-e.h-18):(e.x=o.x-e.w/2,e.y=r.bottom+18),e}function As(e,t,n,o){let{entry:r,side:i}=Jn(n),l=ve[t],c=l?{name:l.name,w:l.body?.w||168,h:l.body?.h||110,price:l.price}:{name:t[0].toUpperCase()+t.slice(1),w:168,h:110,price:o},b={type:"facility",id:t,name:c.name,x:0,y:0,w:c.w,h:c.h,level:1,price:o||c.price,builtSession:e.buildSession};return jn(b,r,i)}function jt(e){return e?[{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}]:[]}function Is(e,t,n){return{type:"maintenanceRoom",id:e.nextId++,col:t,row:n,price:lt.maintenanceRoom,builtSession:e.buildSession,wCells:2,hCells:2}}function kc(e){return Math.random()({x:i.x,y:i.y})),r=o[0];return{id:e.nextId++,sex:n,x:r.x,y:r.y,route:o,targetIndex:o.length>1?1:o.length,stage:t.stage||"belt",scannerId:t.scannerId??null,nextScannerId:null,pendingScannerId:null,radius:n==="poop"?15:17,bob:Math.random()*Math.PI*2,queueIndex:-1,queueRoute:null}}function $s({game:e,canvasPoint:t,updatePanels:n,equipmentAtPoint:o,fail:r,pointInGrid:i,rectOfFacility:l,rectsOverlap:c}){function b(M){return M?M.type==="conveyor"?`conveyor:${M.id||M.oldKey}`:M.type==="facility"?`facility:${M.id||M.ref?.id}`:M.type==="maintenanceRoom"?`maintenanceRoom:${M.id||M.ref?.id}`:`${M.type}:${M.id||M.ref?.id}`:""}function C(M){return M?M.type==="conveyor"?{type:"conveyor",id:M.oldKey}:{type:M.type,id:M.ref.id}:null}function x(M){let g=b(C(M));return(e.multiSelected||[]).some(G=>b(G)===g)}function A(M){return M?M.type==="eggFarm"?e.eggFarms.find(g=>g.id===M.id)||null:M.type==="scanner"?e.scanners.find(g=>g.id===M.id)||null:M.type==="facility"?e.facilities[M.id]||null:M.type==="maintenanceRoom"?(e.maintenanceRooms||[]).find(g=>g.id===M.id)||null:M.type==="conveyor"&&e.conveyorTiles.has(M.id)?{type:"conveyor",id:M.id}:null:null}function $(){let M=[];for(let g of e.conveyorTiles){let G=te(g),oe=F(G.col,G.row);M.push({type:"conveyor",id:g,center:oe,cell:G})}for(let g of e.eggFarms)M.push({type:"eggFarm",id:g.id,ref:g,center:F(g.col,g.row),cell:{col:g.col,row:g.row}});for(let g of e.scanners)M.push({type:"scanner",id:g.id,ref:g,center:ye(g),cell:{col:g.col,row:g.row}});for(let g of e.maintenanceRooms||[]){let G=F(g.col,g.row);M.push({type:"maintenanceRoom",id:g.id,ref:g,center:{x:G.x+f.cell/2,y:G.y+f.cell/2},cell:{col:g.col,row:g.row}})}for(let g of Object.values(e.facilities)){let G={x:g.x+g.w/2,y:g.y+g.h/2},oe=g.entry?F(g.entry.col,g.entry.row):G;M.push({type:"facility",id:g.id,ref:g,center:G,portCenter:oe})}return M}function B(M,g){let G=Math.min(g.x1,g.x2),oe=Math.max(g.x1,g.x2),Z=Math.min(g.y1,g.y2),me=Math.max(g.y1,g.y2);return M.x>=G&&M.x<=oe&&M.y>=Z&&M.y<=me}function j(M){let g=[];for(let G of $())(B(G.center,M)||G.portCenter&&B(G.portCenter,M))&&g.push({type:G.type,id:G.id});return e.multiSelected=g,e.selected=g[0]||null,n(),g.length}function z(){e.multiSelected=[],e.selected=null,n()}function ce(M){let g=t(M);return e.selectionBox={x1:g.x,y1:g.y,x2:g.x,y2:g.y},e.multiSelected=[],e.selected=null,n(),!0}function he(M){if(!e.selectionBox)return;let g=t(M);e.selectionBox.x2=g.x,e.selectionBox.y2=g.y}function ie(){if(!e.selectionBox)return 0;let M=e.selectionBox,g=Math.abs(M.x2-M.x1),G=Math.abs(M.y2-M.y1);return e.selectionBox=null,g<6&&G<6?(z(),0):j(M)}function le(M){let g=C(M);return g?(e.multiSelected||[]).length&&x(M)?[...e.multiSelected]:[g]:[]}function se(M){let g=A(M);if(!g)return null;if(M.type==="conveyor"){let G=te(M.id);return{...M,obj:g,oldKey:M.id,currentKey:M.id,meta:e.conveyorMeta.get(M.id)||{price:Oe("conveyor"),builtSession:null},col:G.col,row:G.row}}return M.type==="eggFarm"||M.type==="scanner"||M.type==="maintenanceRoom"?{...M,obj:g,col:g.col,row:g.row}:M.type==="facility"?{...M,obj:g,x:g.x,y:g.y,w:g.w,h:g.h,entry:g.entry?{...g.entry}:null,side:g.side,center:{x:g.x+g.w/2,y:g.y+g.h/2}}:null}function R(M){let g=t(M),G=o(g);if(!G)return!1;let oe=le(G),Z=oe.map(se).filter(Boolean);return Z.length?(e.groupDrag={start:g,selections:oe,origins:Z,historySnapshot:mn(e),committed:!1,lastDCol:0,lastDRow:0},e.multiSelected=oe,e.selected=oe[0]||null,n(),!0):!1}function _(){!e.groupDrag||e.groupDrag.committed||(e.undoStack.push(e.groupDrag.historySnapshot),e.redoStack=[],e.groupDrag.committed=!0)}function Y(M,g,G){let oe=I(M,g),Z=dt(e,M,g);if(Z&&!G.has(`eggFarm:${Z.id}`))return!0;let me=ft(e,M,g);if(me&&!G.has(`scanner:${me.id}`))return!0;let ge=(e.maintenanceRooms||[]).find(Pe=>jt(Pe).some(Ae=>Ae.col===M&&Ae.row===g));return!!(ge&&!G.has(`maintenanceRoom:${ge.id}`)||e.conveyorTiles.has(oe)&&!G.has(`conveyor:${oe}`))}function O(M,g,G){let oe=[];for(let Z of e.groupDrag.origins){if(Z.type!=="facility")continue;let me={x:Z.center.x+M,y:Z.center.y+g},{entry:ge,side:Pe}=Jn(me);if(!i(ge.col,ge.row)||e.blockedCells?.has?.(I(ge.col,ge.row)))return!0;let Ae={...Z.obj,entry:{...ge},side:Pe};jn(Ae,ge,Pe),oe.push({id:Z.id,rect:l(Ae)})}for(let Z of oe)for(let me of Object.values(e.facilities))if(!G.has(`facility:${me.id}`)&&c(Z.rect,l(me),12))return!0;for(let Z=0;ZN.type==="conveyor");for(let N of Ae){let Ie=N.currentKey||N.oldKey;e.conveyorTiles.delete(Ie),e.conveyorMeta.delete(Ie)}for(let N of Ae){let Ie=I(N.col+Z,N.row+me);e.conveyorTiles.add(Ie),e.conveyorMeta.set(Ie,N.meta||{price:Oe("conveyor"),builtSession:null,uses:0}),N.currentKey=Ie}for(let N of e.groupDrag.origins)if(N.type==="eggFarm")N.obj.col=N.col+Z,N.obj.row=N.row+me;else if(N.type==="scanner")N.obj.col=N.col+Z,N.obj.row=N.row+me;else if(N.type==="maintenanceRoom")N.obj.col=N.col+Z,N.obj.row=N.row+me;else if(N.type==="facility"){let Ie={x:N.center.x+G,y:N.center.y+oe},{entry:Ye,side:Ve}=Jn(Ie);jn(N.obj,Ye,Ve)}e.groupDrag.selections=e.groupDrag.origins.map(N=>N.type==="conveyor"?{type:"conveyor",id:N.currentKey||N.oldKey}:{type:N.type,id:N.id}),e.multiSelected=[...e.groupDrag.selections],e.selected=e.multiSelected[0]||null,be(e),n()}function U(){e.groupDrag&&(be(e),e.groupDrag=null,n())}return{selectionFromHit:C,startSelectionBox:ce,updateSelectionBox:he,finishSelectionBox:ie,startGroupDrag:R,updateGroupDrag:W,finishGroupDrag:U}}function Fs({game:e,ui:t,canvas:n,canvasPoint:o,onUpdatePanels:r}){function i(){r&&r()}let l=null,c=!1,b=null,C=!1,x=["random","up","right","down","left"],A={random:"RND",up:"UP",right:"RT",down:"DN",left:"LF"},$={w:40,h:40,y:0};function B(){return In(e)}function j(){e.gridCols=f.cols,e.gridRows=f.rows,e.gridOwnedCells=zr(e)}function z(s){if(s){f.y-=s*f.cell,f.rows+=s,e.gridChunkOriginY=(e.gridChunkOriginY||0)-Math.floor(s/10),e.ownedCells=Dn(e.ownedCells,s),e.blockedCells=Dn(e.blockedCells,s),e.conveyorTiles=Dn(e.conveyorTiles,s),e.conveyorMeta=jr(e.conveyorMeta,s);for(let a of e.eggFarms||[])a.row+=s;for(let a of e.scanners||[])a.row+=s;for(let a of Object.values(e.facilities||{}))a.entry&&(a.entry.row+=s)}}function ce(s){e.ownedCells=e.ownedCells||new Set;for(let a of Jr(s))e.ownedCells.add(I(a.col,a.row))}function he(s){return e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending?null:Tt(e).find(a=>a&&Qr(a,s))||null}function ie(s="right"){if(s&&typeof s=="object"&&Number.isFinite(s.chunkX)&&Number.isFinite(s.chunkY))return s;let a=["right","up"].includes(s)?s:"right";return Xr(e,a)}function le(s="right"){let a=ie(s);if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return{ok:!1,reason:"Cannot expand now."};if(!a)return{ok:!1,reason:"Invalid expansion lot."};let h=a.direction||"right",m=B();if(e.cashf.cols&&(f.cols=E.colStart+E.cols),E.rowStart+E.rows>f.rows&&(f.rows=E.rowStart+E.rows),ce(E),Zr(e,E.chunkX,E.chunkY),e.gridExpansionPurchases=(e.gridExpansionPurchases||0)+1,e.gridExpansionPurchasesByDirection[h]=(e.gridExpansionPurchasesByDirection[h]||0)+1,j();let ne=Ur(e.gridExpansionPurchases,{base:q.map.blockedRatio??.03,increment:q.map.blockedExpansionIncrement??.005,max:q.map.blockedRatioMax??.1}),J=Kr({seed:`${e.runSeed}:grid-expansion:${E.chunkX},${E.chunkY}:${e.gridExpansionPurchases}`,colStart:E.colStart,colEnd:E.colStart+E.cols,rowStart:E.rowStart,rowEnd:E.rowStart+E.rows,targetRatio:ne});for(let Je of J)e.blockedCells.add(Je);be(e);let pe=E.cols*E.rows,Te=Et(E);return H(e,Te.x+Te.w/2,Te.y+Te.h/2,`${h.toUpperCase()} +${pe} CELLS -${T(m)}`,y.green),i(),{ok:!0,direction:h,cost:m,addedCells:pe,blocked:J.size,blockedRatio:ne,chunkX:E.chunkX,chunkY:E.chunkY}}function se(s,a){return s>=0&&s=0&&a!a.has(m.id)&&Y(h,_(m),12))}function W(s,a,h=null){if(!se(s,a))return!1;if(R(s,a))return!0;let m=I(s,a),w=dt(e,s,a);if(w&&!(h?.type==="eggFarm"&&h.ref?.id===w.id))return!0;let E=ft(e,s,a);if(E&&!(h?.type==="scanner"&&h.ref?.id===E.id))return!0;let ne=U(e,s,a);return!!(ne&&!(h?.type==="maintenanceRoom"&&h.ref?.id===ne.id)||e.conveyorTiles.has(m)&&!(h?.type==="conveyor"&&h.oldKey===m))}function U(s,a,h){return(s.maintenanceRooms||[]).find(m=>jt(m).some(w=>w.col===a&&w.row===h))||null}function M(s,a,h=null){let m={col:s,row:a};for(let w of jt(m)){if(!se(w.col,w.row)||R(w.col,w.row))return!0;let E=I(w.col,w.row);if(dt(e,w.col,w.row)||ft(e,w.col,w.row))return!0;let pe=U(e,w.col,w.row);if(pe&&!(h?.type==="maintenanceRoom"&&h.ref?.id===pe.id)||e.conveyorTiles.has(E))return!0}return!1}function g(s,a,h=null){let m={col:s,row:a};for(let w of Pt(m)){if(!se(w.col,w.row)||R(w.col,w.row))return!0;let E=I(w.col,w.row);if(dt(e,w.col,w.row))return!0;let J=ft(e,w.col,w.row);if(J&&!(h?.type==="scanner"&&h.ref?.id===J.id)||e.conveyorTiles.has(E))return!0}return!1}function G(){return e.selected?e.selected.type==="eggFarm"?e.eggFarms.find(s=>s.id===e.selected.id)||null:e.selected.type==="scanner"?e.scanners.find(s=>s.id===e.selected.id)||null:e.selected.type==="conveyor"?e.conveyorTiles.has(e.selected.id)?{type:"conveyor",id:e.selected.id}:null:e.selected.type==="facility"?e.facilities[e.selected.id]||null:e.selected.type==="maintenanceRoom"&&(e.maintenanceRooms||[]).find(s=>s.id===e.selected.id)||null:null}function oe(s){return s?s.type==="eggFarm"?`${ct("eggFarm")} #${s.id}`:s.type==="scanner"?`${s.kind==="auto"?ct("autoScanner"):ct("manualScanner")} #${s.id}`:s.type==="conveyor"?e.conveyorMeta.get(s.id)?.kind==="boostConveyor"?ct("boostConveyor"):ct("conveyor"):s.type==="facility"?s.name:s.type==="maintenanceRoom"?`${ct("maintenanceRoom")} #${s.id}`:"Equipment":"Equipment"}function Z(s){return s?.type==="conveyor"?e.conveyorMeta?.get(s.oldKey||s.ref?.id)?.price||_n(s):_n(s)}function me(){return!!e.cardEffects?.usedMachineActive}function ge(){return me()?{usedMachine:!0,noRefund:!0,durabilityBaseMultiplier:.6}:{usedMachine:!1,noRefund:!1,durabilityBaseMultiplier:1}}function Pe(s){let a=ge();return Object.assign(s,a),s}function Ae(s){let a=s?.ref||s||{};if(s?.type==="eggFarm"||a.type==="eggFarm")return e.eggFarms.length<=1?"Cannot sell the last EGG FARM.":"";if((s?.type==="facility"||a.type==="facility")&&["mixer","trash","truck"].includes(a.baseId||a.id)){let h=a.baseId||a.id;if(Object.values(e.facilities).filter(w=>(w.baseId||w.id)===h).length<=1)return`Cannot sell the last ${a.shortName||a.name||a.id}.`}return""}function N(s){t.buildStatus.textContent=s,H(e,n.width/2-e.view.x,86-e.view.y,s.toUpperCase(),y.danger)}function Ie(s){if(!s)return null;let a=I(s.col,s.row);return e.conveyorMeta.get(a)||null}function Ye(s){return s?(Array.isArray(s.outDirs)||(s.outDirs=[]),s.outDirs=[...new Set(s.outDirs.filter(a=>["right","left","down","up"].includes(a)))],x.includes(s.branchMode)||(s.branchMode="random"),s.kind||(s.kind="conveyor"),s.speedMultiplier||(s.speedMultiplier=s.kind==="boostConveyor"?2:1),s.outDirs):[]}function Ve(s){return s?de.filter(a=>e.conveyorTiles.has(I(s.col+a.dc,s.row+a.dr))).map(a=>a.name):[]}function xe(s){return Ve(s).length>=3}function Ct(s,a){let h=de.find(J=>J.name===a);if(!s||!h)return!1;let m=I(s.col+h.dc,s.row+h.dr),w=e.conveyorMeta.get(m);if(!w)return!1;let E=h.opposite;return[...new Set([...Array.isArray(w.outDirs)?w.outDirs:[],w.dir].filter(Boolean))].includes(E)}function oo(s){if(!e.conveyorTiles.has(s))return[];let a=te(s),h=e.conveyorMeta.get(s),m=Ye(h),w=Ve(a),E=[...new Set([...m,h?.dir].filter(Boolean))].filter(pe=>w.includes(pe)),ne=w,J=E.length?E:ne;return h&&(h.outDirs=m.filter(pe=>w.includes(pe)),h.dir&&!w.includes(h.dir)&&(h.dir=h.outDirs[0]||null),h.branchMode!=="random"&&!w.includes(h.branchMode)&&(h.branchMode="random")),J}function Mn(s){if(!e.conveyorTiles.has(s))return[];let a=te(s),h=Ve(a);return xe(a)||h.length?h:oo(s)}function ro(s){let a=te(s),h=Mn(s);if(h.length<3)return[];let m=e.conveyorMeta.get(s)||{},w=new Set(h.filter(J=>Ct(a,J))),E=h.filter(J=>!w.has(J));if(w.size&&E.length>=2)return E;let ne=[...new Set([...Array.isArray(m.outDirs)?m.outDirs:[],m.dir].filter(Boolean))].filter(J=>h.includes(J));return ne.length>=2?ne:h}function nn(s,a){let h=at(s,a);if(!h)return!1;let m=I(s.col,s.row),w=I(a.col,a.row),E=e.conveyorMeta.get(m),ne=e.conveyorMeta.get(w);if(!E||!ne)return!1;let J=Ye(E),pe=!J.includes(h)||E.dir!==h||!ne.dir;return J.includes(h)||J.push(h),E.dir=h,ne.dir||(ne.dir=h),pe}function Mt(s){let a=so(s);return a.length<2?io(s):(Be(e),lo(a),be(e),i(),!0)}function io(s){if(!s)return!1;let a=I(s.col,s.row),h=e.conveyorMeta.get(a);if(!h||xe(s))return!1;let m=de.map(ne=>ne.name),w=h.dir&&m.includes(h.dir)?h.dir:null,E=m[(Math.max(-1,m.indexOf(w))+1)%m.length];return Be(e),h.dir=E,h.outDirs=[E],h.branchMode="random",be(e),i(),!0}function gn(s){return s?de.map(a=>({col:s.col+a.dc,row:s.row+a.dr})).filter(a=>e.conveyorTiles.has(I(a.col,a.row))):[]}function so(s){if(!s||!e.conveyorTiles.has(I(s.col,s.row))||xe(s))return[];let a=gn(s);if(!a.length||a.length>2)return[];let h=E=>{let ne=[],J=new Set([I(s.col,s.row)]),pe=s,Te=E,Je=0;for(;Te&&Je<200;){Je+=1;let Tr=I(Te.col,Te.row);if(J.has(Tr)||(J.add(Tr),ne.push(Te),xe(Te)))break;let Er=gn(Te).filter(Rr=>!(Rr.col===pe.col&&Rr.row===pe.row));if(Er.length!==1)break;pe=Te,Te=Er[0]}return ne},m=a[0]?h(a[0]).reverse():[],w=a[1]?h(a[1]):[];return[...m,s,...w]}function gt(s,a){return!!s&&[...new Set([...Array.isArray(s.outDirs)?s.outDirs:[],s.dir].filter(Boolean))].includes(a)}function lo(s){let a=0,h=0;for(let w=0;wh?[...s].reverse():s;for(let w=0;w=Math.abs(m)?{col:s.col+Math.sign(h),row:s.row}:{col:s.col,row:s.row+Math.sign(m)}}function ao(s){c=!1,b=s?{col:s.col,row:s.row}:null,C=!1,l=null,on(s)}function d(s){if(!s)return;if(!l)return on(s);let a=l,h=0;for(;(a.col!==s.col||a.row!==s.row)&&h<64;){let m=rn(a,s);if(on(m),a=l||m,h+=1,!l)break}}function p(){!C&&b&&e.conveyorTiles.has(I(b.col,b.row))&&Mt(b),b=null,C=!1,l=null,c=!1}function v(s){if(!s)return N(re.fail.outOfGrid);let{col:a,row:h}=s;if(e.buildTool==="conveyor"||e.buildTool==="boostConveyor"){let m=Gt(s,null);if(!m.ok)return N(m.reason||re.fail.cellOccupied);be(e);return}if(R(a,h))return N("Cannot build on blocked ground.");if(e.buildTool==="maintenanceRoom")return M(a,h)?N(re.fail.cellOccupied):D(a,h);if(e.buildTool==="manualScanner"||e.buildTool==="autoScanner"?g(a,h):W(a,h))return N(re.fail.cellOccupied);e.buildTool==="eggFarm"?S(a,h):e.buildTool==="manualScanner"?P(a,h,"manual"):e.buildTool==="autoScanner"&&P(a,h,"auto")}function k(s){let a=He(s.x,s.y);if(["conveyor","boostConveyor","eggFarm","manualScanner","autoScanner","maintenanceRoom"].includes(e.buildTool))return v(a);if(un.includes(e.buildTool))return ae(s,e.buildTool)}function S(s,a){let h=Oe("eggFarm",e);if(e.cashE.kind==="manual").length>=8)return N("Manual Scanner limit reached (8 max).");let m=h==="auto"?Oe("autoScanner",e):Oe("manualScanner",e);if(e.cashw.id!==a.ref.id),et(e,m.x,m.y),be(e)}if(a.type==="scanner"){let m=ye(a.ref);Ne(a,m.x,m.y),e.scanners=e.scanners.filter(w=>w.id!==a.ref.id),et(e,m.x,m.y),be(e)}if(a.type==="facility"){let m=a.ref;Ne(a,m.x+m.w/2,m.y+m.h/2),delete e.facilities[m.id],et(e,m.x+m.w/2,m.y+m.h/2),be(e)}if(a.type==="maintenanceRoom"){let m=a.ref,w=V(m);Ne(a,w.x,w.y),e.maintenanceRooms=(e.maintenanceRooms||[]).filter(E=>E.id!==m.id),et(e,w.x,w.y)}e.selected=null,e.multiSelected=[],i()}function co(s){let a=Object.values(e.facilities).find(J=>{if(s.x>=J.x&&s.x<=J.x+J.w&&s.y>=J.y&&s.y<=J.y+J.h)return!0;if(!J.entry)return!1;let Te=F(J.entry.col,J.entry.row);return Math.abs(s.x-Te.x)<=f.cell*.46&&Math.abs(s.y-Te.y)<=f.cell*.46});if(a)return{type:"facility",ref:a};let h=He(s.x,s.y);if(!h)return null;let m=dt(e,h.col,h.row);if(m)return{type:"eggFarm",ref:m};let w=ft(e,h.col,h.row);if(w)return{type:"scanner",ref:w};let E=U(e,h.col,h.row);if(E)return{type:"maintenanceRoom",ref:E};let ne=I(h.col,h.row);return e.conveyorTiles.has(ne)?{type:"conveyor",oldKey:ne,ref:{type:"conveyor",id:ne}}:null}let Wt=$s({game:e,canvasPoint:o,updatePanels:i,equipmentAtPoint:co,fail:N,pointInGrid:se,rectOfFacility:_,rectsOverlap:Y});function js(s){return null}function wr(){let s=G();s&&(s.type==="conveyor"?Ut(F(...Object.values(te(s.id)))):s.type==="eggFarm"?Ut(F(s.col,s.row)):s.type==="scanner"?Ut(ye(s)):s.type==="facility"?Ut({x:s.x+s.w/2,y:s.y+s.h/2}):s.type==="maintenanceRoom"&&Ut(V(s)))}function Ke(s,a,h="primary-button"){let m=document.createElement("button");return m.type="button",m.className=h,m.textContent=s,m.addEventListener("click",a),m}function sn(){e.cardTargetPick?.mode==="autoScannerMenu"&&(e.cardTargetPick=null),t.modal.classList.remove("visible","equipment-popover"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function uo(s){t.modalTitle.textContent="Auto Scanner",e.cardTargetPick={pending:!0,mode:"autoScannerMenu",cardId:null,targetKeys:[`scanner:${s.id}`],remaining:1},t.modalBody.innerHTML=` +
+

Left / right output routing for this AUTO scanner.

+

Current: ${s.role===0?"Male left / others right":"Poop left / others right"}

+

Cooldown: ${nt(s).toFixed(1)}s.

+
`,t.modalActions.innerHTML="";let a=Ke("Male Left / Others Right",()=>{Be(e),s.role=0,sn(),i()},s.role===0?"facility-action warn":"facility-action"),h=Ke("Poop Left / Others Right",()=>{Be(e),s.role=1,sn(),i()},s.role===1?"facility-action warn":"facility-action");t.modalActions.append(a,h,Ke("Close",sn,"facility-action")),fo(s),t.modal.classList.add("visible","equipment-popover"),i()}function Sr(s){return s?.label||s?.key||"?"}function Zs(s){let a=s.key===" "?"Space":s.key.length===1?s.key.toUpperCase():s.key.replace(/^Arrow/,"");return{key:s.key.toLowerCase(),code:s.code,label:a}}function el(s,a,h){for(let m of e.scanners.filter(w=>w.kind==="manual"))for(let w of["left","right"]){if(m.id===s.id&&w===a)continue;let E=m.keys?.[w];if(E&&(E.code===h.code||E.key===h.key))return!0}return!1}function ln(s,a=""){if(!s||s.kind!=="manual")return;t.modalTitle.textContent=`Manual Scanner #${s.id}`;let h=Sr(s.keys?.left),m=Sr(s.keys?.right),w=tl(s);t.modalBody.innerHTML=` +
+

Left route key: ${h}

+

Right route key: ${m}

+ ${a?`

${a}

`:""} + ${w?`

${w}

`:""} +
`,t.modalActions.innerHTML="",t.modalActions.appendChild(Ke("Set Left Key",()=>kr(s,"left"),"facility-action warn")),t.modalActions.appendChild(Ke("Set Right Key",()=>kr(s,"right"),"facility-action warn")),t.modalActions.appendChild(Ke("Close",sn,"facility-action")),fo(s),t.modal.classList.add("visible","equipment-popover")}function tl(s){let a=[{side:"left",binding:s.keys?.left},{side:"right",binding:s.keys?.right}];if(a[0].binding&&a[1].binding&&(a[0].binding.code===a[1].binding.code||a[0].binding.key===a[1].binding.key))return"Left and right keys conflict.";for(let h of a)if(h.binding)for(let m of e.scanners.filter(w=>w.kind==="manual"&&w.id!==s.id)){if(m.keys?.left&&(m.keys.left.code===h.binding.code||m.keys.left.key===h.binding.key))return`Key conflicts with Manual Scanner #${m.id} left.`;if(m.keys?.right&&(m.keys.right.code===h.binding.code||m.keys.right.key===h.binding.key))return`Key conflicts with Manual Scanner #${m.id} right.`}return""}function kr(s,a){t.modalBody.innerHTML=`

Press a key for ${a.toUpperCase()} route.

Esc cancels.

`,t.modalActions.innerHTML="";let h=m=>{if(m.preventDefault(),m.stopPropagation(),window.removeEventListener("keydown",h,!0),m.key==="Escape")return ln(s);let w=Zs(m),E=el(s,a,w);Be(e),s.keys=s.keys||{left:null,right:null},s.keys[a]=w,i(),ln(s,E?`${w.label} assigned, but another scanner already uses it.`:`${a.toUpperCase()} set to ${w.label}.`)};window.addEventListener("keydown",h,!0)}function nl(){let s=G();if(!(!s||s.type!=="scanner"))return s.kind==="auto"?uo(s):ln(s)}function ol(s){if(!s)return{x:80,y:80};if(s.type==="conveyor"){let a=te(s.id);return F(a.col,a.row)}return s.type==="eggFarm"?F(s.col,s.row):s.type==="scanner"?ye(s):s.type==="facility"?{x:s.x+s.w/2,y:s.y+10}:{x:80,y:80}}function fo(s){let a=n.getBoundingClientRect(),h=ol(s),m=e.view?.scale||1,w=a.left+(h.x*m+(e.view?.x||0))/n.width*a.width+18,E=a.top+(h.y*m+(e.view?.y||0))/n.height*a.height-12,ne=Math.max(12,window.innerWidth-274),J=Math.max(12,window.innerHeight-220);t.modal.style.setProperty("--popover-x",`${Math.max(12,Math.min(ne,w))}px`),t.modal.style.setProperty("--popover-y",`${Math.max(12,Math.min(J,E))}px`)}function Cr(){let s=G();if(!s)return;let a=xr(s);if(t.modalTitle.textContent=oe(s),t.modalBody.innerHTML=` +
${a.map(w=>`

${w}

`).join("")}
+ ${["mixer","truck"].includes(s.baseId||s.id)?'

Income/Fine = ceil(base x 1.10^upgrades)

':""}`,t.modalActions.innerHTML="",s.type==="scanner"&&s.kind==="auto"&&t.modalActions.appendChild(Ke("Auto Menu",()=>uo(s),"facility-action warn")),s.type==="scanner"&&s.kind==="manual"&&t.modalActions.appendChild(Ke("Set Keys",()=>ln(s),"facility-action warn")),s.type==="conveyor"&&po(s.id)){let w=e.conveyorMeta.get(s.id)?.branchMode||"random";t.modalActions.appendChild(Ke(`Branch: ${Mr(w)}`,()=>{yo(s.id),e.selected={type:"conveyor",id:s.id},Cr()},"facility-action warn branch-action"))}let h=s.type==="conveyor"?{type:"conveyor",oldKey:s.id,ref:s}:{type:s.type,ref:s},m=Ae(h);if(m){let w=Ke(m,()=>{},"facility-action danger disabled");w.disabled=!0,t.modalActions.appendChild(w)}else{let w=mt(h,e),E=w.sameBuild?`Remove / Refund ${T(w.amount)}`:`Sell ${T(w.amount)}`;t.modalActions.appendChild(Ke(E,()=>{wr(),sn()},"facility-action danger"))}fo(s),t.modal.classList.add("visible","equipment-popover")}function rl(s){e.phase==="build"&&(p(),e.buildTool=e.buildTool===s?null:s,e.selected=null,e.multiSelected=[],e.selectionBox=null,i())}function il(){let s=[];for(let[a,h]of Object.entries(e.facilities))if(s.push({id:`facility:${a}`,price:Z({type:"facility",ref:h}),x:h.x,y:h.y,w:h.w,h:h.h}),h.entry){let m=F(h.entry.col,h.entry.row);s.push({id:`facilityPort:${a}`,price:Z({type:"facility",ref:h}),x:m.x-18,y:m.y-18,w:36,h:36})}for(let a of e.maintenanceRooms||[]){let h=V(a);s.push({id:`maintenanceRoom:${a.id}`,price:Z({type:"maintenanceRoom",ref:a}),x:h.x-f.cell,y:h.y-f.cell,w:f.cell*2,h:f.cell*2})}for(let a of e.eggFarms){let h=F(a.col,a.row);s.push({id:`eggFarm:${a.id}`,price:Z({type:"eggFarm",ref:a}),x:h.x-24,y:h.y-24,w:48,h:48})}for(let a of e.scanners){let h=ye(a);s.push({id:`scanner:${a.id}`,price:Z({type:"scanner",ref:a}),x:h.x-50,y:h.y-73,w:100,h:146})}for(let a of e.conveyorTiles){let h=te(a),m=F(h.col,h.row),w=e.conveyorMeta.get(a)||{};s.push({id:`conveyor:${a}`,price:w.price||Oe(w.kind==="boostConveyor"?"boostConveyor":"conveyor",e),x:m.x-22,y:m.y-22,w:44,h:44})}return s}function Mr(s){return A[s]||A.random}function zc(s){return Mn(s)}function po(s){return e.conveyorTiles.has(s)?xe(te(s)):!1}function gr(s){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return null;for(let a of e.conveyorTiles){if(!po(a))continue;let h=te(a),m=F(h.col,h.row),w=m.x-$.w/2,E=m.y+$.y-$.h/2;if(s.x>=w&&s.x<=w+$.w&&s.y>=E&&s.y<=E+$.h)return a}return null}function sl(s){let a=gr(s);return a?yo(a):!1}function yo(s){let a=e.conveyorMeta.get(s);if(!a)return!1;let h=ro(s);if(h.length<2)return!1;Be(e);let m=x.includes(a.branchMode)?a.branchMode:"random",w=["random",...de.map(E=>E.name).filter(E=>h.includes(E))];return a.branchMode=w[(Math.max(0,w.indexOf(m))+1)%w.length],be(e),e.selected=null,e.multiSelected=[],i(),!0}function xr(s){Se(e);let a=[],h=s?.type==="facility"?s.baseId||s.id:"";if(s.type==="eggFarm"){let[m,w]=fn(s);a.push(`Price: ${T(Z(s))}`);{let E=Ae({type:s.type,ref:s});a.push(E?`Sale: blocked (${E})`:`Sale value: ${T(mt({type:s.type,ref:s},e).amount)}`)}a.push(`Level: ${s.level}/4`),a.push(`Random interval: ${m.toFixed(2)}-${w.toFixed(2)}s`),a.push(`Durability: ${vn(s)}% | Spawn delay x${Yn(s).toFixed(2)}`)}else if(s.type==="scanner")a.push(`Price: ${T(Z(s))}`),a.push(`Sale value: ${T(mt({type:s.type,ref:s},e).amount)}`),a.push(`Type: ${s.kind.toUpperCase()} / Standard`),s.kind==="auto"&&a.push(`Role: ${s.role===0?"Male left / Others right":"Poop left / Others right"}`),a.push(`Queue: ${s.queue.length}`),s.kind==="auto"&&a.push(`Cooldown: ${s.cooldown.toFixed(1)}s / ${nt(s,e).toFixed(1)}s`),s.kind==="auto"&&a.push(`Durability: ${vn(s)}% | Delay x${qn(s).toFixed(2)}`),s.kind==="manual"&&a.push("Durability: none | Always normal");else if(s.type==="conveyor"){let m=e.conveyorMeta.get(s.id),w=e.componentLookup?.get(s.id),E=w?e.congestion.get(w):null;a.push(`Price: ${T(Z({type:"conveyor",oldKey:s.id,ref:s}))}`),a.push(`Cell: ${s.id}`),a.push(`Type: ${m?.kind==="boostConveyor"?"BOOST BELT":"Normal Belt"} | Speed x${Number(m?.speedMultiplier||1).toFixed(1)}`),a.push(`Congestion: ${E?Math.floor(E.ratio*100):0}%`),a.push(`Durability: ${vn({meta:m})}% | Speed x${Hn({meta:m}).toFixed(2)}`),po(s.id)?(a.push(`Branch mode: ${Mr(m?.branchMode||"random")}`),a.push("Click the Branch button or the large on-belt badge to cycle RANDOM / fixed exit.")):a.push("Branch mode: needs 3+ conveyor connections."),a.push(`Sale value: ${T(mt({type:"conveyor",oldKey:s.id,ref:s},e).amount)}`)}else if(s.type==="maintenanceRoom")a.push(`Price: ${T(Z({type:"maintenanceRoom",ref:s}))}`),a.push(`Sale value: ${T(mt({type:"maintenanceRoom",ref:s},e).amount)}`),a.push("Size: 2\xD72 grid cells"),a.push("Dispatch: 1 repairman during each production day");else if(s.type==="facility"){a.push(`Price: ${T(Z(s))}`);{let m=Ae({type:s.type,ref:s});a.push(m?`Sale: blocked (${m})`:`Sale value: ${T(mt({type:s.type,ref:s},e).amount)}`)}if(a.push(["mixer","truck","trash"].includes(s.id)?`Level: ${s.level} / no cap`:`Level: ${s.level}`),h==="truck"&&a.push("Durability: none | Always normal"),["mixer","trash"].includes(h)&&a.push(`Durability: ${vn(s)}% | Extra delay ${er(e,s).toFixed(2)}s`),h==="mixer"&&(a.push(`Income: ${T(ze(e))} per chick | upgrade x${yt(e,"mixer").toFixed(3)}`),a.push(`Poop fine: -${T(yn(e))}`)),h==="truck"&&(a.push(`Income: ${T(Fe(e))} per target cargo | upgrade x${yt(e,"truck").toFixed(3)}`),a.push(`Poop shipment fine: -${T(hn(e))}`)),h==="trash"){let m=Dt(e),w=ht(m);a.push(`Bonus cards: ${m}/${zt()}`),a.push(`Poop income bonus: ${T(w)} per processed poop.`),a.push("With enough upgrades, poop can out-earn male/female routes.")}s.entry&&a.push(`Receiver: edge cell ${s.entry.col},${s.entry.row} (${s.side})`)}return a}function ll(s){if(!s||e.phase!=="build")return"";let a=On(e).find(h=>h.type===s.type&&h.id===s.id);return a?a.message||"Not connected to conveyor route":""}function al(s){return s?s.type==="conveyor"&&e.conveyorMeta.get(s.id)?.kind==="boostConveyor"?"Moves chicks twice as fast. Wears down like a normal belt.":s.type==="conveyor"?"A stubborn belt tile. It only cares about the next cell.":s.type==="eggFarm"?"A tiny gatehouse producing questionable eggs on schedule.":s.type==="scanner"&&s.kind==="auto"?"Slower than hands without upgrades.":s.type==="scanner"?"A manual checkpoint. The operator is the algorithm.":s.type==="facility"&&(s.baseId||s.id)==="mixer"?"Male chicks become revenue here. Do not feed it poop.":s.type==="facility"&&(s.baseId||s.id)==="trash"?"Poop goes in. Sometimes coins come out, for reasons best left unaudited.":s.type==="facility"&&(s.baseId||s.id)==="truck"?"The shipping endpoint. Correct cargo pays; wrong cargo complains.":s.type==="maintenanceRoom"?"A cramped 2\xD72 storage and break room with lockers, spare parts, a bench and one dispatched repairman.":"Factory equipment.":""}return{buildAtCell:v,buildAtPoint:k,eraseAtPoint:Ut,equipmentAtPoint:co,startSelectionBox:Wt.startSelectionBox,updateSelectionBox:Wt.updateSelectionBox,finishSelectionBox:Wt.finishSelectionBox,startGroupDrag:Wt.startGroupDrag,updateGroupDrag:Wt.updateGroupDrag,finishGroupDrag:Wt.finishGroupDrag,selectedObject:G,selectedTitle:oe,equipmentPrice:Z,selectedUpgradeCost:js,selectedInfoLines:xr,flavorText:al,disconnectedWarningFor:ll,gridExpansionCost:B,buyGridExpansion:le,expansionOfferAtPoint:he,beginConveyorDrag:ao,continueConveyorDrag:d,endConveyorDrag:p,cycleSingleConveyorDirection:Mt,branchSwitcherAtPoint:gr,cycleBranchModeAtPoint:sl,cycleBranchModeForKey:yo,removeSelected:wr,switchScannerRole:nl,showManualScannerMenu:ln,showAutoScannerMenu:uo,showSelectedMenu:Cr,setBuildTool:rl,fail:N,isEquipmentCell:W,equipmentHitBoxes:il,routeFromFarmToScanner:It}}function Bs({game:e,ui:t,build:n,startGame:o,beginCardDraft:r,activeQueuedChick:i}){function l(O){return String(O).replace(/[&<>"']/g,W=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[W])}function c(){return Math.round(Xn(e))}function b(){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return!1;let O=!1;for(let W of So)if(O=!0,e.cash>=Oe(W,e))return!1;return O}function C(){x(),A(),B(),$()}function x(){for(let[W,U]of Object.entries(t.buttons))U?.classList?.contains("tool-button")&&U.classList.toggle("active",e.buildTool===W);for(let W of So){let U=t.buttons[W];if(!U)continue;let M=Oe(W,e),g=U.querySelector("span");g&&(g.textContent=W==="conveyor"||W==="boostConveyor"?`${T(M)} / tile`:T(M));let G=W==="manualScanner"&&e.scanners.filter(Z=>Z.kind==="manual").length>=8,oe=e.cashIt(e,U)?.scannerId).length,W=pn(e);t.turnSummary.innerHTML=[`Seed: ${l(e.runSeed||"none")} | Grid box: ${e.gridRows||10}x${e.gridCols||20} | Owned: ${e.gridOwnedCells||e.ownedCells?.size||(e.gridRows||10)*(e.gridCols||20)} cells | Blocked: ${e.blockedCells?.size||0} cells`,`Penalties: wrong shipment -${T(Uo(e))} | Mixer poop -${T(yn(e))} | Shipment poop -${T(hn(e))}`,`Maintenance: worst ${rr(e).worst.percent}% dirty (${rr(e).worst.label}) | Rooms: ${(e.maintenanceRooms||[]).length} | Repairmen: ${(e.repairmen||[]).length}`,`Card draft: ${e.cardDraft?.pending?Math.max(1,e.cardDraft.picksRemaining||1)+" pick(s) left":"ready after each day"} | Farms with scanner route: ${O}/${e.eggFarms.length}`,e.cardEffects?.usedMachineActive?'Procurement: USED MACHINE MODE / no refunds / 60% durability':"",W.length?`Blocked: ${W[0]}`:`${re.status.allPortsConnected}`].filter(Boolean).join("
")}function j(){x(),t.shell.classList.toggle("phase-running",e.phase==="running"),t.shell.classList.toggle("phase-build",e.phase==="build"),t.shell.classList.toggle("phase-gameover",e.phase==="gameover"),t.shell.classList.toggle("phase-title",e.phase==="title"),t.shell.classList.toggle("phase-loanDecision",e.phase==="loanDecision"),t.money.textContent=T(e.cash),t.money.classList.toggle("cash-negative",e.cash<0),t.money.classList.toggle("cash-positive",e.cash>an),t.turn.textContent=e.turn,t.timeLeft.textContent=e.phase==="running"&&e.timeLeft<=0&&e.shutdownTimeLeft>0?`+${e.shutdownTimeLeft.toFixed(1)}s`:`${Math.max(0,e.timeLeft).toFixed(1)}s`,t.timeLeft.closest?.(".hud-card")?.classList.toggle("time-critical",e.phase==="running"&&(e.timeLeft<=10||e.timeLeft<=0&&e.shutdownTimeLeft>0)),t.phase.textContent=ce(),t.comboCount&&(t.comboCount.textContent=e.manualCombo?.count||0),z(),t.turnProfit.textContent=T(e.stats.profit),t.turnProfit.classList.toggle("cash-negative",e.stats.profit<0),t.turnProfit.classList.toggle("cash-positive",e.stats.profit>0),t.mixerCount.textContent=e.stats.mixerCount,t.truckFemaleCount.textContent=e.stats.truckFemale,t.truckMaleCount.textContent=e.stats.truckMale,t.poopCount.textContent=e.stats.poopSpawned,t.buttons.s1Left.disabled=e.phase!=="running"||!i(0),t.buttons.s1Right.disabled=e.phase!=="running"||!i(0),t.buttons.s2Left.disabled=e.phase!=="running"||!i(1),t.buttons.s2Right.disabled=e.phase!=="running"||!i(1);let O=e.scanners.find(g=>g.kind==="manual"&&g.slot===0),W=e.scanners.find(g=>g.kind==="manual"&&g.slot===1);O&&(t.buttons.s1Left.textContent=`S1 ${O.keys?.left?.label||"A"} -> Mixer`,t.buttons.s1Right.textContent=`S1 ${O.keys?.right?.label||"D"} -> S2`),W&&(t.buttons.s2Left.textContent=`S2 ${W.keys?.left?.label||"Left"} -> Waste`,t.buttons.s2Right.textContent=`S2 ${W.keys?.right?.label||"Right"} -> Truck`);let U=Math.max(0,Math.floor(e.lastResult?.profit??e.stats?.profit??0)),M=Ko(e,Math.max(1,Number(e.turn)||1),U).amount;t.buttons.nextTurn.innerHTML=e.phase==="build"&&M>0?`NEXT DAYFAIRIES -${T(M)}`:`${re.actions.nextDay}`,t.buttons.nextTurn.disabled=e.phase!=="build"||!!e.cardDraft?.pending||!!e.cardTargetPick?.pending||!hi(e)}function z(){if(!t.eventBrief||!t.targetBrief||!t.speedBrief)return;let O=pt(e).toUpperCase();t.targetBrief.textContent=`TRUCK TARGET: ${O}`,t.speedBrief.textContent=`BELT SPEED: ${c()} px/s`,t.speedBrief.title=`Conveyor speed does not increase by day. Degraded belts reduce speed. Cap: ${Kt}px/s.`;let W=e.eventActive,U=e.eventOffer;W?(t.eventBrief.textContent=`ACTIVE EVENT: ${W.title} | ${W.route}`,t.eventBrief.className="event-brief active"):e.phase==="build"&&U?(t.eventBrief.textContent=`NEXT DAY EVENT: ${U.title} | ${U.route}${U.targetAmount?` | Target ${U.targetAmount}`:""}${U.reward?` | Reward ${T(U.reward)}`:""}`,t.eventBrief.className="event-brief next"):e.phase==="build"&&e.turn+1
\u2642Male->MixerS1: A
\u2640Female->TruckS1: D, then S2: right
\u{1F4A9}Poop->ShredderS1: D, then S2: left

Build phase: connect at least one EGG through a scanner to Mixer, Shredder, or Truck before Next Day. One day is one run.

',t.modalActions.innerHTML="",t.modalActions.appendChild(R(re.actions.startGame,o,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function ie(O){let W=G=>`${G>0?"+":""}${T(G)}`,U=G=>`${G>0?"-":""}${T(G)}`,M=O.profit>=0?"cash-positive":"cash-negative",g=(O.mixerPoopFine||0)+(O.truckPoopFine||0)+(O.maleTruckFine||0)+(O.explosionDamage||0)+(O.cardRerollCost||0);t.modalTitle.textContent=`Day ${O.turn} Settlement`,t.modalBody.innerHTML=` +
Net result${T(O.profit)}
+
+
Chick shipment income${W(O.chickShipmentIncome||0)}
+
Poop shipment income${W(O.poopShipmentIncome||0)}
+
Mixer income${W(O.mixerRevenue||0)}
+
Composter income${W(O.composterIncome||0)}
+
DUD refund income${W(O.dudRefundIncome||0)}
+
Manual combo bonus${W(O.manualComboBonus||0)}
+
Chemical subsidy${W(O.chemicalWeaponSubsidy||0)}
+
Event bonus${W(O.eventBonus||0)}
+
Penalties${U(g)}
+
Fairies fee${U(O.fairiesTribute?.amount||O.fairiesTribute||0)}
+
+

Income ${T(O.revenue)} - losses ${T(O.penalty)} = ${T(O.profit)}

`,t.modalActions.innerHTML="",t.modalActions.appendChild(R("Choose Upgrade Card",r||_,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function le(O,W){let U=Math.max(0,e.cardEffects?.rescueLoanCharges||0);t.modalTitle.textContent="Emergency Loan Available",t.modalBody.innerHTML=` +

End-of-day cash is below ${T(0)}.

+
+
Current money${T(e.cash)}
+
Emergency Loan+${T(500)}
+
Cards remaining${U}
+
+

Use one Emergency Loan to gain ${T(500)} immediately. If cash is still negative, another decision will be shown if another card remains.

`,t.modalActions.innerHTML="",t.modalActions.appendChild(R("Accept Game Over",W,"facility-action danger")),t.modalActions.appendChild(R("Use Emergency Loan",O,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function se(){let O=e.totals.processed,W=O?Math.round(e.totals.correct/O*100):0,U=Gi(e);t.modalTitle.textContent=re.phases.gameover,t.modalBody.innerHTML=`

Your cash went negative.

+
Final Score${U.score}
Survival${e.totals.turnsCompleted} days
Final Cash${T(e.cash)}
Accuracy${W}%
+
Score breakdown +
Formula
Base = Cash + Total revenue + Factory value \xD70.5 + Event bonus \xD70.5 = ${T(U.base)}
Daily earned = ceil(Base \xF7 Days) = ${T(U.dailyEarned)}
Score = max(0, floor(Base + Daily earned + Correct bonus - Total outflow - Day penalty)) = ${U.score}
+
Factory Value${T(U.factoryValue)}
Total Revenue${T(e.totals.revenue)}
Daily Earned${T(U.dailyEarned)} / day
Total Outflow${T(e.totals.penalty)}
Fairies Tribute${T(e.totals.fairiesTribute||0)}
Correct Sorts${e.totals.correct}
Auto Sorted${e.totals.autoSorted}
Poop Control${e.totals.poopTrash} trashed / ${e.totals.poopTruck} shipped / ${e.totals.poopMixer} mixer
Explosion Penalty${T(e.totals.explosionDamage)}
Event Bonus${T(e.totals.eventBonus)}
Day Penalty-${U.dayPenalty}
Events${e.totals.eventSuccess} success / ${e.totals.eventFailed} failed
+
`,t.modalActions.innerHTML="",t.modalActions.appendChild(R(re.actions.restart||"Restart",o,"primary-button restart-button")),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible","gameover-modal")}function R(O,W,U="primary-button"){let M=document.createElement("button");return M.type="button",M.className=U,M.textContent=O,M.addEventListener("click",W),M}function _(){t.modal.classList.remove("visible","equipment-popover","gameover-modal"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function Y(){}return{updatePanels:C,updateUI:j,showTitle:he,showTurnResult:ie,showEmergencyLoanDecision:le,showGameOver:se,hideModal:_,checkGameOver:Y}}function vr(e){e.totals.processed+=1}function Zt(e){e.stats.correct+=1,e.totals.correct+=1}function wt(e){e.stats.mistakes+=1,e.totals.mistakes+=1}function Ls(e){e.stats.autoSorted+=1,e.totals.autoSorted+=1}function Os(e){e.stats.poopSpawned+=1}function Ns(e){e.stats.mixerCount+=1,vr(e)}function _s(e){e.stats.trashCount+=1,vr(e)}function Gs(e,t){t==="female"?e.stats.truckFemale+=1:t==="male"&&(e.stats.truckMale+=1),vr(e)}function Zn(e,t){let n=t==="truck"?"poopTruck":t==="trash"?"poopTrash":t==="mixer"?"poopMixer":null;n&&(e.stats[n]+=1,e.totals[n]+=1)}function Us({game:e,currentConveyorSpeed:t,onGameOverCheck:n}){function o(d){return Rt(d)*Yn(d)*ps(e)/Ci(e)}function r(d){let p=F(d.col,d.row),v=1+ys(e,d),k=l(d,v);if(!k.length)return i(d,p),!0;let S=0,P=0;for(let D of k){let V=F(D.col,D.row),ae=c(V);if(ae){ae.stoppedTimer=.85,P+=1;continue}let Ne=Ds(e,{stage:"belt",scannerId:null,route:[V]});Ne.sex==="poop"&&Os(e),e.chicks.push(Ne),ji(e,d),S+=1}return S>0?(Wi(e,p.x,p.y),S>1&&H(e,p.x,p.y-28,`x${S}`,y.green),!0):P===0}function i(d,p){(d.noRouteNoticeCooldown||0)<=0&&(H(e,p.x,p.y-24,"NO BELT: PAUSED",y.warn),d.noRouteNoticeCooldown=2.5)}function l(d,p){let k=de.map(S=>({col:d.col+S.dc,row:d.row+S.dr})).filter(S=>Ee(S.col,S.row)&&e.conveyorTiles.has(I(S.col,S.row))).map(S=>({p:S,blocked:$(null,F(S.col,S.row))?1:0,roll:Math.random()}));return k.sort((S,P)=>S.blocked-P.blocked||S.roll-P.roll),k.slice(0,Math.max(1,p||1)).map(S=>S.p)}function c(d){return e.chicks.find(p=>p.stage!=="flying"&&Math.hypot(p.x-d.x,p.y-d.y)0;if(e.timeLeft=Math.max(0,e.timeLeft-d),k&&e.timeLeft<=0&&p(),e.timeLeft<=0){e.shutdownTimeLeft>0&&(e.shutdownTimeLeft=Math.max(0,e.shutdownTimeLeft-d));for(let S of e.eggFarms)S.shutterProgress=Math.min(1,(S.shutterProgress||0)+d*2.8)}if(k&&e.timeLeft>0){for(let S of e.eggFarms)if(S.noRouteNoticeCooldown>0&&(S.noRouteNoticeCooldown=Math.max(0,S.noRouteNoticeCooldown-d)),S.nextSpawn-=d,S.nextSpawn<=0){let P=r(S);S.nextSpawn=P?o(S):.15,S.lastInterval=S.nextSpawn}}for(let S=e.chicks.length-1;S>=0;S-=1){let P=e.chicks[S];P.bob+=d*7,P.stoppedTimer>0&&(P.stoppedTimer=Math.max(0,P.stoppedTimer-d)),P.stage!=="queued"&&x(P,S,d)}N(d),Gt(),on(),e.timeLeft<=0&&(e.chicks.length===0?v():e.shutdownTimeLeft<=0&&C())}function C(){if(e.cleanupBlown)return;e.cleanupBlown=!0,e.cleanupTimer=1;let d=[...e.chicks];for(let p of d)Yo(e,p.sex,p.x,p.y,-Math.PI/2,!0);e.chicks=[];for(let p of e.scanners)p.queue=[];if(Gt(),d.length){let p=d.reduce((k,S)=>k+S.x,0)/d.length,v=d.reduce((k,S)=>k+S.y,0)/d.length;Xe(e,p,v,y.warn,58),H(e,p,v-24,"CLEANUP",y.warn)}}function x(d,p,v){if(A(d)){d.stoppedTimer=.35;return}if(me(d,v),!(d.route&&d.targetIndex=d.route.length)return!1;let p=d.route[d.targetIndex];return $(d,p)}function $(d,p){if(!p)return!1;for(let v of e.chicks)if(!(d&&v.id===d.id)&&v.stage!=="flying"&&Math.hypot(v.x-p.x,v.y-p.y)1)&&d.push({x:p.x,y:p.y})}function j(d){let p=e.conveyorMeta?.get?.(d)||{},v=[];Array.isArray(p.outDirs)&&v.push(...p.outDirs),p.dir&&v.push(p.dir);let k=[...new Set(v)].filter(ae=>de.some(Ne=>Ne.name===ae)),S=te(d),P=de.filter(ae=>R(S,ae.name)).map(ae=>ae.name),D=k.filter(ae=>P.includes(ae)),V=P;return D.length?D:V}function z(d){return de.find(p=>p.name===d)||null}function ce(d,p){return e.scanners.find(v=>v.col<=d&&d<=v.col+1&&v.row-1<=p&&p<=v.row+1)||null}function he(d,p){let v=z(p);if(!v)return null;let k=ce(d.col+v.dc,d.row+v.dr);if(!k)return null;let S=Re(k,"inputA");return S&&S.col===d.col&&S.row===d.row?k:null}function ie(d){return Object.entries(e.facilities||{}).find(([,p])=>p?.entry&&p.entry.col===d.col&&p.entry.row===d.row)||null}function le(d){return d?.baseId||d?.id||""}function se(d,p){return d.side==="left"&&p==="left"||d.side==="right"&&p==="right"||d.side==="top"&&p==="up"||d.side==="bottom"&&p==="down"}function R(d,p){let v=z(p);if(!v)return null;let k={col:d.col+v.dc,row:d.row+v.dr};if(Ee(k.col,k.row)&&e.conveyorTiles.has(I(k.col,k.row)))return{type:"conveyor",dirName:p,target:F(k.col,k.row),nextCell:k};let S=he(d,p);if(S)return{type:"scanner",dirName:p,target:ye(S),scanner:S};let P=ie(d);return P&&se(P[1],p)?{type:"facility",dirName:p,facilityId:P[0],facility:P[1],target:F(d.col,d.row)}:null}function _(d,p){let v=z(p);if(!v)return!1;let k=e.conveyorMeta?.get?.(I(d.col+v.dc,d.row+v.dr));return k?[...new Set([...Array.isArray(k.outDirs)?k.outDirs:[],k.dir].filter(Boolean))].includes(v.opposite):!1}function Y(d){return de.filter(p=>Ee(d.col+p.dc,d.row+p.dr)&&e.conveyorTiles.has(I(d.col+p.dc,d.row+p.dr))).map(p=>p.name)}function O(d,p,v="random"){let k=Y(d);if(k.length<3)return p;let S=new Set(k.filter(V=>_(d,V))),P=k.filter(V=>!S.has(V)),D=S.size&&P.length>=2?P:[...new Set(p.filter(V=>k.includes(V)))];return D.length<2&&(D=k),v&&v!=="random"&&v!=="pass"&&D.includes(v)?[v]:D}function W(d,p){return p&&(p.type==="facility"||!$(d,p.target))}function U(d,p,v,k="random"){let S=v.map(ae=>R(p,ae)).filter(Boolean);if(!S.length)return null;let D=S.filter(ae=>ae.type!=="facility").filter(ae=>!$(d,ae.target)),V=D.length?D:S.filter(ae=>ae.type==="facility");return V.length?V[Math.floor(Math.random()*V.length)]:null}function M(d,p){let v=[];B(v,{x:d.x,y:d.y}),B(v,p),d.route=v.length?v:[{x:d.x,y:d.y}],d.targetIndex=d.route.length>1?1:d.route.length}function g(d,p){let v=He(d.x,d.y);if(!v)return gt(p,"OFF GRID");let k=I(v.col,v.row);if(!e.conveyorTiles.has(k))return gt(p,"OFF BELT");let S=e.conveyorMeta?.get(k)||{},P=O(v,j(k),S.branchMode||"random");if(!P.length){d.stoppedTimer=.25;return}let D=U(d,v,P,S.branchMode||"random");if(!D){d.stoppedTimer=.25;return}if(D.type==="facility"){let V=le(D.facility);V==="mixer"?io(p,D.facility):V==="truck"?gn(p,D.facility):V==="trash"?so(p,D.facility):gt(p,"DONE");return}D.type==="scanner"&&(d.pendingScannerId=D.scanner.id),d.prevConveyorCell=k,M(d,D.target)}function G(d){let p=He(d.x,d.y);if(!p)return null;let v=I(p.col,p.row);return e.conveyorTiles.has(v)?v:null}function oe(d){let p=G(d)||G(d.route?.[d.targetIndex]||d);return t(p)}function Z(d,p){let v=G(p);!v||d.lastWearKey===v||(d.lastWearKey=v,Ji(e,v))}function me(d,p){let v=oe(d)*p;for(;v>0&&d.targetIndex=D?(d.x=k.x,d.y=k.y,Z(d,k),d.targetIndex+=1,v-=D):(d.x+=S/D*v,d.y+=P/D*v,v=0)}}function ge(d,p,v){d.stage="queued",d.route=null,d.queueRoute=v?v.map(k=>({x:k.x,y:k.y})):[ye(p)],d.scannerId=p.id,p.queue.includes(d.id)||p.queue.push(d.id),Pe(p)}function Pe(d){d.queue=d.queue.filter(v=>e.chicks.some(k=>k.id===v&&k.stage==="queued"));let p=f.cell*.86*hs(e);d.queue.forEach((v,k)=>{let S=e.chicks.find(P=>P.id===v);S&&(Ae(S,S.queueRoute||[ye(d)],k*p),S.queueIndex=k)})}function Ae(d,p,v){if(!p||!p.length)return;if(p.length===1||v<=0){let P=p[p.length-1];d.x=P.x,d.y=P.y;return}let k=v;for(let P=p.length-1;P>0;P-=1){let D=p[P-1],V=p[P],ae=Math.hypot(V.x-D.x,V.y-D.y);if(k<=ae){let Ne=1-k/ae;d.x=D.x+(V.x-D.x)*Ne,d.y=D.y+(V.y-D.y)*Ne;return}k-=ae}let S=p[0];d.x=S.x,d.y=S.y}function N(d){for(let p of e.scanners){if(p.cooldown>0&&(p.cooldown=Math.max(0,p.cooldown-d)),p.keyPressTime>0&&(p.keyPressTime=Math.max(0,p.keyPressTime-d)),Pe(p),p.kind!=="auto"||p.cooldown>0||!p.queue.length)continue;let v=p.queue[0],k=e.chicks.findIndex(S=>S.id===v);if(k<0){p.queue.shift();continue}nn(k,Do(p,e.chicks[k]),!0)&&(Zi(e,p),p.cooldown=nt(p,e),Ls(e))}}function Ie(d){let p=Ro(e,d);return!p||!p.queue.length?null:e.chicks.find(v=>v.id===p.queue[0])||null}function Ye(d,p){if(e.phase!=="running")return;let v=Ro(e,d);Ve(v,p)}function Ve(d,p){if(e.phase!=="running"||!d||d.kind!=="manual"||(d.keyPressTime=.18,d.keyPressSide=p,!d.queue.length))return;let v=e.chicks.findIndex(k=>k.id===d.queue[0]);v>=0&&nn(v,p,!1)}function xe(d,p,v){return d.kind==="manual"&&Do(d,p)===v}function Ct(d){let p=e.manualCombo?.count||0;if(e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=0,e.manualCombo.lastBonus=0,e.stats.manualComboFailure=(e.stats.manualComboFailure||0)+1,e.totals.manualComboFailure=(e.totals.manualComboFailure||0)+1,p>=10){let v=ye(d);Ft(e,10,.25),H(e,v.x,v.y-36,"COMBO RESET",y.danger)}}function oo(d){e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=Math.max(0,e.manualCombo.count||0)+1,e.stats.manualComboSuccess=(e.stats.manualComboSuccess||0)+1,e.totals.manualComboSuccess=(e.totals.manualComboSuccess||0)+1;let p=e.manualCombo.count;if(e.manualCombo.lastBonus=0,p<10)return 0;let v=Math.max(1,Math.floor(p/10)),k=e.scanners.filter(V=>V.kind==="manual").length,S=Math.min(1,(20+k*10)/100),P=0;for(let V=0;V0){Ge(e,D),e.stats.manualComboBonus=(e.stats.manualComboBonus||0)+D,e.totals.manualComboBonus=(e.totals.manualComboBonus||0)+D,e.manualCombo.lastBonus=D;let V=ye(d);H(e,V.x,V.y-42,`COMBO +${T(D)}`,y.green)}return D}function Mn(d,p){let v=Re(d,p);if(!v)return null;let k=I(v.col,v.row);if(e.conveyorTiles.has(k))return{...v};let P=(_e(e).scannerPorts.get(d.id)?.[p]?.keys||[]).filter(Boolean);if(!P.length)return null;let D=P.map(te);return D.find(ae=>ae.col===v.col&&ae.row===v.row)||D[0]||null}function ro(d,p,v,k){let S=[];B(S,{x:d.x,y:d.y});let P=Re(p,v);return P&&B(S,F(P.col,P.row)),B(S,F(k.col,k.row)),S}function nn(d,p,v){let k=e.chicks[d];if(!k||k.stage!=="queued")return!1;let S=At(e,k.scannerId);if(!S)return!1;let P=Mn(S,p);if(!P)return!v&&S.kind==="manual"&&Ct(S),H(e,k.x,k.y-16,p==="left"?"NO LEFT BELT":"NO RIGHT BELT",y.danger),!1;!v&&S.kind==="manual"&&(xe(S,k,p)?oo(S):Ct(S)),S.queue=S.queue.filter(V=>V!==k.id),k.stage="belt",k.route=ro(k,S,p,P),k.targetIndex=k.route.length>1?1:k.route.length,k.scannerId=null,k.nextScannerId=null,k.pendingScannerId=null,k.queueRoute=null,k.queueIndex=-1;let D=v?y.green:p==="left"?y.mixerBlue:y.truckPink;return Ki(e,ye(S).x,ye(S).y,D),H(e,k.x,k.y-20,v?"AUTO":p.toUpperCase(),D),!0}function Mt(d){let p=e.chicks[d];return p?(e.chicks.splice(d,1),p):null}function io(d,p=e.facilities.mixer){if(p?.processingCooldown>0){let D=e.chicks[d];D&&(D.stoppedTimer=.25);return}let v=Mt(d);if(!v)return;let{x:k,y:S}=v;if(Ns(e),tr(e,p),nr(e,p),v.sex==="poop"){let D=$i(e);Zn(e,"mixer"),wt(e),qi(e,k,S),H(e,k,S-18,`-${T(D)}`,y.danger);return}let P=Di(e);v.sex==="male"?Zt(e):wt(e),Hi(e,k,S),H(e,k,S-18,`+${T(P)}`,y.green)}function gn(d,p=e.facilities.truck){let v=Mt(d);if(!v)return;let{x:k,y:S}=v;lo(v.sex,p),Vi(e,k,S,v.sex),Gs(e,v.sex);let P=pt(e),D=gi(e,v.sex);if(v.sex==="poop"){if(Zn(e,"truck"),D)Zt(e),H(e,k,S-18,`+${T(Fe(e))}`,y.green);else{let V=Fi(e);wt(e),H(e,k,S-18,`-${T(V)}`,y.danger)}return}if(v.sex==="female"){D?(Zt(e),H(e,k,S-18,`+${T(Fe(e))}`,y.green)):(wt(e),H(e,k,S-18,P==="male"?"REJECT":"NO SALE",y.warn));return}if(D){Zt(e),H(e,k,S-18,`+${T(Fe(e))}`,y.green);return}if(xi(e)){let V=Bi(e);wt(e),H(e,k,S-18,`-${T(V)}`,y.danger)}else wt(e),H(e,k,S-18,"REJECT",y.warn)}function so(d,p=e.facilities.trash){if(p?.processingCooldown>0){let V=e.chicks[d];V&&(V.stoppedTimer=.25);return}let v=Mt(d);if(!v)return;let{x:k,y:S}=v;Yi(e,k,S,v.sex),_s(e),tr(e,p),nr(e,p);let P={amount:0},D="";if(v.sex==="poop"){P=Pi(e),D=P.amount>0?` +${T(P.amount)}`:"",Zn(e,"trash"),Zt(e);let V=Math.ceil(Math.max(0,Number(e.cardEffects?.composter)||0)*3*Nn(e));if(V>0){let ae=Ge(e,V);e.stats.composterIncome=(e.stats.composterIncome||0)+ae,e.totals.composterIncome=(e.totals.composterIncome||0)+ae,H(e,k,S-36,`COMPOST +${T(ae)}`,y.green)}H(e,k,S-18,`CLEAN${D}`,P.amount>0?y.green:y.green)}else wt(e),H(e,k,S-18,P.amount>0?`WASTE${D}`:"WASTE",P.amount>0?y.green:y.ink)}function gt(d,p){let v=Mt(d);v&&H(e,v.x,v.y-12,p,y.muted)}function lo(d,p=e.facilities.truck){let v=p||e.facilities.truck;v&&(e.truckCargo.push({sex:d,x:K(22,v.w-22),y:K(66,v.h-24)}),e.truckCargo.length>45&&e.truckCargo.shift())}function xn(d){let p=He(d.x,d.y);if(p){let P=I(p.col,p.row);if(e.conveyorTiles.has(P))return P}let v=di(e,d.x,d.y);if(!v)return null;let k=te(v),S=F(k.col,k.row);return Math.hypot(d.x-S.x,d.y-S.y)<=f.cell*.55?v:null}function Gt(){let{components:d,cellToComponent:p}=ui(e);for(let v of e.chicks){if(v.stage==="flying")continue;let k=xn(v);if(!k)continue;let S=p.get(k),P=d.get(S);P&&(P.count+=1)}for(let v of d.values())v.ratio=v.count/v.capacity;e.congestion=d,e.componentLookup=p}function on(){for(let d of e.congestion.values()){let p=_o(e),v=Ti(e);if(d.ratio>v&&d.ratio=p){let k=rn(d.id);if(!k.length||k.some(D=>D.stage!=="queued"&&D.stoppedTimer<=.2))continue;let S=e.lastExplodedComponent.get(d.id)||0,P=performance.now();P-S>900&&(e.lastExplodedComponent.set(d.id,P),ao(d))}}}function rn(d){return e.chicks.filter(p=>{let v=xn(p);return v&&e.componentLookup?.get(v)===d})}function ao(d){let p=rn(d.id);if(!p.length)return;for(let S of p)Yo(e,S.sex,S.x,S.y);e.chicks=e.chicks.filter(S=>!p.some(P=>P.id===S.id));for(let S of e.scanners)S.queue=S.queue.filter(P=>e.chicks.some(D=>D.id===P));for(let S of d.cells){let P=te(S),D=F(P.col,P.row);Xe(e,D.x,D.y,y.danger),Ze(e,D.x,D.y,6),Gn(e,D.x,D.y,4)}Ft(e,18,.75);let v=te(d.cells[0]),k=F(v.col,v.row);e.stats.explosions=(e.stats.explosions||0)+1,e.totals.explosions=(e.totals.explosions||0)+1,H(e,k.x,k.y-22,`${Math.round(_o(e)*100)}% JAM EXPLOSION`,y.danger)}return{activeQueuedChick:Ie,currentSpawnDelay:o,sortSlot:Ye,updateCongestion:Gt,sortScanner:Ve,updateRunning:b}}var fe=document.getElementById("gameCanvas"),Cc=fe.getContext("2d"),L={shell:document.getElementById("gameShell"),money:document.getElementById("money"),turn:document.getElementById("turn"),timeLeft:document.getElementById("timeLeft"),phase:document.getElementById("phaseLabel"),comboCount:document.getElementById("comboCount"),eventBrief:document.getElementById("eventBrief"),targetBrief:document.getElementById("targetBrief"),speedBrief:document.getElementById("speedBrief"),turnProfit:document.getElementById("turnProfit"),mixerCount:document.getElementById("mixerCount"),truckFemaleCount:document.getElementById("truckFemaleCount"),truckMaleCount:document.getElementById("truckMaleCount"),poopCount:document.getElementById("poopCount"),buildStatus:document.getElementById("buildStatus"),turnSummary:document.getElementById("turnSummary"),modal:document.getElementById("modal"),modalTitle:document.getElementById("modalTitle"),modalBody:document.getElementById("modalBody"),modalActions:document.getElementById("modalActions"),hoverTooltip:document.getElementById("hoverTooltip"),manualScannerMonitor:document.getElementById("manualScannerMonitor"),debug:{panel:document.getElementById("debugPanel"),infiniteCash:document.getElementById("debugInfiniteCash"),dayInput:document.getElementById("debugDayInput"),setDay:document.getElementById("debugSetDayButton"),zeroTimer:document.getElementById("debugZeroTimerButton"),cardSelect:document.getElementById("debugCardSelect"),targetSelect:document.getElementById("debugTargetSelect"),grantCard:document.getElementById("debugGrantCardButton"),grantAllCards:document.getElementById("debugGrantAllCardsButton"),readout:document.getElementById("debugReadout")},buttons:{s1Left:document.getElementById("scanner1MixerButton"),s1Right:document.getElementById("scanner1TruckButton"),s2Left:document.getElementById("scanner2MixerButton"),s2Right:document.getElementById("scanner2TruckButton"),nextTurn:document.getElementById("nextTurnButton"),conveyor:document.getElementById("buildConveyorButton"),boostConveyor:document.getElementById("buildBoostConveyorButton"),eggFarm:document.getElementById("buildEggFarmButton"),autoScanner:document.getElementById("buildAutoScannerButton"),manualScanner:document.getElementById("buildManualScannerButton"),mixer:document.getElementById("buildMixerButton"),trash:document.getElementById("buildTrashButton"),truck:document.getElementById("buildTruckButton"),maintenanceRoom:document.getElementById("buildMaintenanceRoomButton"),erase:document.getElementById("eraseButton"),undo:document.getElementById("undoButton"),redo:document.getElementById("redoButton")}};function Mc(){let e={conveyor:"conveyor",boostConveyor:"boostConveyor",eggFarm:"eggFarm",autoScanner:"autoScanner",manualScanner:"manualScanner",mixer:"mixer",trash:"trash",truck:"truck",maintenanceRoom:"maintenanceRoom"};for(let[t,n]of Object.entries(e))L.buttons[t]&&(L.buttons[t].innerHTML=Or(n))}function gc(e){let t=new Set(e.tags||[]);return["upgradeEgg","crowdedFarming","hatchingFeed","extraEggOutlet"].includes(e.id)||t.has("EGG")?"Production / EGG":["upgradeTrash","poopRateBooster","composter","chemicalWeaponSubsidy"].includes(e.id)||t.has("POOP")?"Poop / Shredder":["upgradeAutoScanner","autoScannerTuning","scannerQueueSpacing"].includes(e.id)||t.has("SCANNER")?"Scanner":["bearing","dynamite"].includes(e.id)||t.has("CONVEYOR")?"Conveyor / Map":["safetyCover","preventiveMaintenance","durabilityCoating","sparePartsBin","laborExploitation"].includes(e.id)||t.has("MAINTENANCE")?"Maintenance / Risk":["dudFilter","dudRefund","freeReroll","extraCards"].includes(e.id)||t.has("CARD")?"Card Engine":t.has("ULTRA RARE")?"Ultra Rare":t.has("ECONOMY")||["upgradeMixer","upgradeTruck","recyclingSubsidy","usedMachine","newMachine","flattery","legalWork","rescueLoan"].includes(e.id)?"Economy / Shipment":"Other"}function xc(){if(!L.debug?.panel||!L.debug.cardSelect)return;let e=["Production / EGG","Poop / Shredder","Scanner","Conveyor / Map","Maintenance / Risk","Card Engine","Economy / Shipment","Ultra Rare","Other"],t=new Map(e.map(n=>[n,[]]));for(let n of Jt){let o=gc(n);t.has(o)||t.set(o,[]),t.get(o).push(n)}L.debug.cardSelect.innerHTML="";for(let n of e){let o=t.get(n)||[];if(!o.length)continue;let r=document.createElement("optgroup");r.label=n;for(let i of o){let l=document.createElement("option");l.value=i.id;let c=i.rarity==="ultraRare"?"UR":i.rarity==="rare"?"R":"C";l.textContent=`[${c}] ${i.title}`,r.appendChild(l)}L.debug.cardSelect.appendChild(r)}L.debug.cardSelect.addEventListener("change",Nt),Nt()}function Nt(){if(!L.debug?.targetSelect)return;let e=L.debug.cardSelect?.value,t=Ot(e),n=t?ms(u,t):[];if(L.debug.targetSelect.innerHTML="",!n.length){let r=document.createElement("option");r.value="__none__",r.textContent=t?"No target required":"No card selected",L.debug.targetSelect.appendChild(r),L.debug.targetSelect.disabled=!0;return}let o=document.createElement("option");o.value="__auto__",o.textContent=t?.id==="dynamite"?"Auto: first 3 blocked cells":"Auto: first valid target",L.debug.targetSelect.appendChild(o);for(let r of n){let i=document.createElement("option");i.value=r.key,i.textContent=r.label,L.debug.targetSelect.appendChild(i)}L.debug.targetSelect.disabled=!1}function Tc(){let e=Math.max(1,Math.floor(Number(L.debug.dayInput?.value)||1));u.turn=e,L.debug.dayInput&&(L.debug.dayInput.value=String(e)),H(u,fe.width/2-u.view.x,86-u.view.y,`DAY ${e}`,y.green),Q.updatePanels(),Q.updateUI(),Nt(),_t(`Day set to ${e}.`)}function Ec(){u.timeLeft=0,u.phase==="running"&&Vs(),H(u,fe.width/2-u.view.x,86-u.view.y,"TIMER 0",y.warn),Q.updatePanels(),Q.updateUI(),_t("Timer set to 0.")}function Rc(){let e=L.debug.cardSelect?.value,t=L.debug.targetSelect?.disabled?void 0:L.debug.targetSelect?.value,n=sr(u,e,{targetKey:t});L.debug.grantCard&&(L.debug.grantCard.textContent=n.ok?"Granted":"Failed",window.setTimeout(()=>{L.debug.grantCard&&(L.debug.grantCard.textContent="Grant Selected")},900)),Me?.updateCongestion?.(),Q.updatePanels(),Q.updateUI(),Nt(),_t(n.reason)}function Pc(){let t=Jt.map(n=>sr(u,n,{targetKey:"__auto__"})).filter(n=>n.ok).length;Me?.updateCongestion?.(),Q.updatePanels(),Q.updateUI(),Nt(),_t(`Granted ${t}/${Jt.length} cards.`)}function Ac(){L.debug?.infiniteCash?.checked&&u.cash<999999&&(u.cash=999999,u.totals.maxCash=Math.max(u.totals.maxCash,u.cash))}function _t(e=""){L.debug?.readout&&(L.debug.readout.textContent=[e,`D${u.turn}`,T(u.cash),`Combo ${u.manualCombo?.count||0}`,`Event ${u.eventActive?.title||u.eventOffer?.title||"none"}`,`Rescue ${u.cardEffects?.rescueLoanCharges||0}`,`Chem ${u.cardEffects?.chemicalWeaponSubsidy||0}`].filter(Boolean).join(" | "))}var u=To(),X,Q,Me,tn;function Ic(e=null){let t=Xn(u,e);return e?t*Qo(u,e):t}function Dc(){Object.assign(u,To()),u.phase="running",u.view={x:0,y:0,scale:1},Eo(u),Xs(),Se(u),Q.hideModal(),Me.updateCongestion(),Q.updatePanels(),Q.updateUI(),_t()}function $c(){if(u.phase!=="build")return;if(u.cardDraft?.pending||u.cardTargetPick?.pending){X.fail(u.cardTargetPick?.pending?"Choose upgrade target first.":"Choose an upgrade card first."),Q.updatePanels();return}let e=pn(u);if(e.length){X.fail(`Cannot start: ${e[0]}`),Q.updatePanels();return}Se(u),ci(u),os(u);let t=Math.max(0,Math.floor(u.lastResult?.profit??u.stats?.profit??0)),n=Ni(u,Math.max(1,u.turn||1),t);u.lastStartFees={fairiesTribute:n.amount||0,tribute:n},n.amount>0&&H(u,fe.width/2-u.view.x,116-u.view.y,`FAIRIES -${T(n.amount)}`,y.danger),wi(u),u.phase="running",u.turn+=1,u.timeLeft=ki(u),u.shutdownTimeLeft=0,u.cleanupTimer=null,u.cleanupBlown=!1,u.chicks=[],u.effects=[],u.floatingTexts=[],u.shake={time:0,strength:0},u.truckCargo=[],Xs(),u.stats=xo(),u.stats.fairiesTribute=u.lastStartFees?.fairiesTribute||0,u.stats.fairiesTribute>0&&(u.stats.penalty+=u.stats.fairiesTribute,u.stats.profit-=u.stats.fairiesTribute);for(let o of u.scanners)o.queue=[],o.cooldown=0;for(let o of u.eggFarms)o.nextSpawn=Me.currentSpawnDelay(o),o.lastInterval=o.nextSpawn,o.shutterProgress=0,o.shutterSparked=!1;u.buildTool=null,u.selected=null,u.groupDrag=null,u.selectionBox=null,u.pan=null,Me.updateCongestion(),Q.updatePanels(),Q.updateUI()}function Fc(){if(u.phase!=="running")return;let e=Oi(u),t=u.eventActive?{...u.eventActive}:null,n=Ri(u),o=_i(u);if(e.adjusted>0){let i=u.facilities.truck,l=i?i.x+i.w/2:fe.width/2-u.view.x,c=i?i.y+26:96-u.view.y;H(u,l,c,`${e.target==="poop"?"POOP SHIP":"SHIP"} +${T(e.adjusted)}`,y.green)}n?.bonus>0&&H(u,fe.width/2-u.view.x,96-u.view.y,`EVENT +${T(n.bonus)}`,y.green),o.amount>0&&H(u,fe.width/2-u.view.x,116-u.view.y,`CHEM SUBSIDY +${T(o.amount)}`,y.green),Si(u),u.totals.turnsCompleted+=1;let r=Ei(t);if(r!==1&&(u.pendingFairiesTributeMultiplier=r),u.lastResult={...u.stats,ship:e,event:n,chemical:o,rescue:{amount:0,used:0,remaining:u.cardEffects?.rescueLoanCharges||0},fairiesTribute:{amount:u.stats.fairiesTribute||0},tributeMultiplier:r,turn:u.turn,cash:u.cash},u.cash<0){if((u.cardEffects?.rescueLoanCharges||0)>0){u.phase="loanDecision",Q.showEmergencyLoanDecision(Ys,eo);return}u.phase="gameover",Q.showGameOver();return}qs()}function qs(){u.phase="build",u.truckCargo=[],u.chicks=[],u.shutdownTimeLeft=0,u.cleanupTimer=null,u.cleanupBlown=!1,u.buildSession+=1,u.undoStack=[],u.redoStack=[],u.timeLeft=0;for(let e of u.scanners)e.queue=[];for(let e of u.eggFarms)e.shutterProgress=0,e.shutterSparked=!1;rs(u),u.eventOffer=vi(u),tn&&tn.prepareDraft(),u.cardTargetPick=null,u.buildTool=null,u.groupDrag=null,u.selectionBox=null,u.pan=null,Q.updatePanels(),Q.showTurnResult(u.lastResult)}function Ys(){if((u.cardEffects?.rescueLoanCharges||0)<=0)return eo();u.cardEffects.rescueLoanCharges-=1,u.stats.rescueLoan=(u.stats.rescueLoan||0)+500,u.totals.rescueLoan=(u.totals.rescueLoan||0)+500;let e=Ge(u,500);u.lastResult={...u.lastResult||{},...u.stats,rescue:{amount:(u.lastResult?.rescue?.amount||0)+e,used:(u.lastResult?.rescue?.used||0)+1,remaining:u.cardEffects.rescueLoanCharges},cash:u.cash},H(u,fe.width/2-u.view.x,176-u.view.y,`RESCUE +${T(e)}`,y.green),u.cash>=0?qs():(u.cardEffects?.rescueLoanCharges||0)>0?(u.phase="loanDecision",Q.showEmergencyLoanDecision(Ys,eo)):eo()}function eo(){u.phase="gameover",Q.showGameOver()}function Vs(){u.shutdownTimeLeft<=0&&(u.shutdownTimeLeft=u.shutdownGraceSeconds||10);for(let e of u.eggFarms){if(e.shutterSparked)continue;e.shutterProgress=.02,e.shutterSparked=!0;let t=F(e.col,e.row);Xe(u,t.x,t.y,y.ink),Ze(u,t.x,t.y+10,10),H(u,t.x,t.y-34,"SHUT +10s",y.ink)}}function zs(e){u.lastTimestamp||(u.lastTimestamp=e);let t=Math.min((e-u.lastTimestamp)/1e3,.05);u.lastTimestamp=e,u.phase==="running"&&Me.updateRunning(t,{closeFarmShutters:Vs,completeTurn:Fc}),Xi(u,t,fe,X.equipmentHitBoxes),Me.updateCongestion(),Cs(Cc,fe,u,{activeQueuedChick:Me.activeQueuedChick,selectedObject:X.selectedObject,selectedTitle:X.selectedTitle}),Ac(),Q.updateUI(),Js(),_t(),requestAnimationFrame(zs)}function to(){return u.view?.scale||1}function Cn(){u.view||(u.view={x:0,y:0,scale:1}),u.view.scale==null&&(u.view.scale=1)}function no(e){let t=fe.getBoundingClientRect();return{x:(e.clientX-t.left)*fe.width/t.width,y:(e.clientY-t.top)*fe.height/t.height}}function St(e){let t=no(e),n=to();return{x:(t.x-(u.view?.x||0))/n,y:(t.y-(u.view?.y||0))/n}}function Bc(e){let t=to();return{x:e.x*t+(u.view?.x||0),y:e.y*t+(u.view?.y||0)}}function Lc(){let e={left:f.x-90,top:f.y-130,right:f.x+f.cols*f.cell+260,bottom:f.y+f.rows*f.cell+220};if(u.phase==="build")for(let t of Tt(u)){let n=Et(t);e.left=Math.min(e.left,n.x-60),e.top=Math.min(e.top,n.y-80),e.right=Math.max(e.right,n.x+n.w+80),e.bottom=Math.max(e.bottom,n.y+n.h+80)}return e}function Ws(e,t){if(e<=t)return[e,t];let n=(e+t)/2;return[n,n]}function kt(){Cn();let e=to(),t=Lc(),[n,o]=Ws(fe.width-160-t.right*e,110-t.left*e),[r,i]=Ws(fe.height-150-t.bottom*e,150-t.top*e);u.view.x=dn(u.view.x,n,o),u.view.y=dn(u.view.y,r,i)}function Xs(){Cn(),u.view.scale=1;let e=u.eggFarms?.[0],t=e?F(e.col,e.row):{x:f.x,y:f.y};u.view.x=280-t.x,u.view.y=190-t.y,kt()}function Oc(e){let t=no(e);Cn(),u.pan={start:t,viewX:u.view.x,viewY:u.view.y,moved:!1}}function Nc(e){if(!u.pan)return;let t=no(e);Math.hypot(t.x-u.pan.start.x,t.y-u.pan.start.y)>5&&(u.pan.moved=!0),Cn(),u.view.x=u.pan.viewX+t.x-u.pan.start.x,u.view.y=u.pan.viewY+t.y-u.pan.start.y,kt()}function _c(e){e.preventDefault(),Cn();let t=no(e),n=St(e),o=Math.exp(-e.deltaY*.0012),r=dn(to()*o,.55,1.8);u.view.scale=r,u.view.x=t.x-n.x*r,u.view.y=t.y-n.y*r,kt(),it()}function Gc(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:{type:e.type,id:e.ref.id}:null}function Uc(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:e.ref||null:null}function it(){L.hoverTooltip&&(L.hoverTooltip.classList.remove("visible"),L.hoverTooltip.setAttribute("aria-hidden","true"),u.hover=null)}function Wc(e,t){if(!L.hoverTooltip||u.phase!=="build"||u.cardTargetPick?.pending||u.groupDrag||u.selectionBox||u.pan)return it();let n=Uc(t);if(!n)return it();let o=X.selectedTitle(n),r=X.flavorText?X.flavorText(n):"",i=X.disconnectedWarningFor?X.disconnectedWarningFor(n):"",l=X.selectedInfoLines(n).slice(0,7);L.hoverTooltip.innerHTML=`${o}${i?`${i}`:r?`${r}`:""}${l.map(C=>`${C}`).join("")}`;let c=Math.min(window.innerWidth-330,e.clientX+18),b=Math.min(window.innerHeight-220,e.clientY+18);L.hoverTooltip.style.left=`${Math.max(8,c)}px`,L.hoverTooltip.style.top=`${Math.max(8,b)}px`,L.hoverTooltip.classList.add("visible"),L.hoverTooltip.setAttribute("aria-hidden","false"),u.hover={type:t.type,id:t.oldKey||t.ref?.id||null}}function Kc(e){if(u.phase!=="build")return it();Wc(e,X.equipmentAtPoint(St(e)))}function Qs(e){it();let t=St(e),n=X.equipmentAtPoint(t),o=Gc(n);if(!o){u.selected=null,u.multiSelected=[],Q.updatePanels();return}u.selected=o,u.multiSelected=[o],Q.updatePanels();let r=X.selectedObject();r?.type==="scanner"&&r.kind==="manual"&&X.showManualScannerMenu(r),r?.type==="scanner"&&r.kind==="auto"&&X.showAutoScannerMenu(r)}function en(){u.buildTool=null,u.selected=null,u.multiSelected=[],u.selectionBox=null,u.cardTargetPick?.mode==="autoScannerMenu"&&(u.cardTargetPick=null),Q.hideModal(),it(),Q.updatePanels(),Q.updateUI()}function Ks(e){return String(e).replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function Hc(e){let t=e?.queue?.[0];return t==null?null:u.chicks.find(n=>n.id===t)||null}function qc(e){if(!e)return'WAIT';let t=e.sex==="poop"?"\u{1F4A9} POOP":e.sex==="male"?"\u2642 MALE":"\u2640 FEMALE";return`${t}`}function Yc(e,t){let n=new Set(u.eggFarms.map(x=>I(x.col,x.row))),o=new Map(u.scanners.map(x=>[I(x.col,x.row),x])),r=Re(e,"inputA"),i=r?I(r.col,r.row):null,l=new Set(Object.values(u.facilities||{}).map(x=>x.entry?I(x.entry.col,x.entry.row):null).filter(Boolean)),c=t?.sex||"",b=c==="poop"?"\u{1F4A9}":c==="male"?"\u2642":c==="female"?"\u2640":"",C=[];for(let x=e.row-2;x<=e.row+2;x+=1)for(let A=e.col-2;A<=e.col+2;A+=1){let $=I(A,x),B=["mini-cell"],j="";A===e.col&&x===e.row?(B.push("scanner"),c&&B.push(c),j=b||"S"):$===i?(B.push("input"),j="IN"):n.has($)?(B.push("egg"),j="E"):o.has($)?(B.push("scanner-other"),j="S"):l.has($)?(B.push("port"),j="P"):u.conveyorTiles.has($)?(B.push("belt"),j="\u2022"):u.blockedCells?.has?.($)&&(B.push("blocked"),j="\xD7"),C.push(`${j}`)}return`
${C.join("")}
`}function Vc(e){let t=Bc(F(e.col,e.row)),n=76;return t.x<-n||t.y<-n||t.x>fe.width+n||t.y>fe.height+n}function Js(){if(!L.manualScannerMonitor)return;if(u.phase!=="running"){L.manualScannerMonitor.classList.remove("visible"),L.manualScannerMonitor.innerHTML="";return}let e=u.scanners.filter(t=>t.kind==="manual"&&Vc(t));if(!e.length){L.manualScannerMonitor.classList.remove("visible"),L.manualScannerMonitor.innerHTML="";return}L.manualScannerMonitor.innerHTML=e.map(t=>{let n=Hc(t),o=t.keys?.left?.label||(t.slot===0?"A":"Left"),r=t.keys?.right?.label||(t.slot===0?"D":"Right"),i=t.role===0?"MIXER":"WASTE",l=t.role===0?"S2":"TRUCK",c=n?"":" disabled";return` +
+
S${(t.slot??0)+1}OFFSCREEN / Q:${t.queue.length}
+
+ IN${qc(n)}SCANNER +
+ ${Yc(t,n)} +
+ + +
+
`}).join(""),L.manualScannerMonitor.classList.add("visible")}L.manualScannerMonitor?.addEventListener("click",e=>{let t=e.target.closest("button[data-scanner-id]");if(!t||t.disabled)return;let n=u.scanners.find(o=>o.id===Number(t.dataset.scannerId));n&&(Me.sortScanner(n,t.dataset.side),Js())});fe.addEventListener("contextmenu",e=>e.preventDefault());fe.addEventListener("wheel",_c,{passive:!1});fe.addEventListener("pointerdown",e=>{if(u.phase!=="build")return;fe.setPointerCapture(e.pointerId);let t=St(e);if(e.button===2){Oc(e);return}if(e.button!==0)return;if(u.cardTargetPick?.mode==="autoScannerMenu"){en();return}if(u.cardTargetPick?.pending){tn.chooseTargetAtPoint(t);return}let n=X.expansionOfferAtPoint?.(t);if(n){X.buyGridExpansion(n),kt(),Q.updatePanels(),Q.updateUI();return}if(X.cycleBranchModeAtPoint?.(t)){Q.updatePanels(),Q.updateUI();return}let o=He(t.x,t.y),r=X.equipmentAtPoint(t);if(!u.buildTool&&r?.type==="conveyor"&&o&&X.cycleSingleConveyorDirection?.(o)){Q.updatePanels(),Q.updateUI();return}if(u.buildTool==="erase"){if(!X.equipmentAtPoint(t)){en();return}X.eraseAtPoint(t);return}if(u.buildTool){let i=He(t.x,t.y);if(!i&&!["mixer","trash","truck"].includes(u.buildTool)){en();return}if(u.buildTool==="conveyor"||u.buildTool==="boostConveyor"){X.beginConveyorDrag(i);return}if(X.equipmentAtPoint(t)){u.buildTool=null,Qs(e);return}X.buildAtPoint(t);return}X.startGroupDrag(e)||X.startSelectionBox(e)});fe.addEventListener("pointermove",e=>{if(u.phase!=="build"){it();return}Kc(e),u.pan&&e.buttons&2&&Nc(e),u.groupDrag&&e.buttons&1&&X.updateGroupDrag(e),u.selectionBox&&e.buttons&1&&X.updateSelectionBox(e),(u.buildTool==="conveyor"||u.buildTool==="boostConveyor")&&e.buttons&1&&X.continueConveyorDrag(He(St(e).x,St(e).y)),u.buildTool==="erase"&&e.buttons&1&&X.eraseAtPoint(St(e))});fe.addEventListener("pointerup",e=>{u.selectionBox?X.finishSelectionBox():u.groupDrag&&(u.groupDrag.committed||Qs(e),X.finishGroupDrag()),e.button===2&&u.pan&&!u.pan.moved&&u.buildTool&&en(),(u.buildTool==="conveyor"||u.buildTool==="boostConveyor")&&X.endConveyorDrag?.(),u.groupDrag=null,u.pan=null;try{fe.releasePointerCapture(e.pointerId)}catch{}});fe.addEventListener("pointerleave",it);fe.addEventListener("pointercancel",()=>{X?.endConveyorDrag?.(),u.groupDrag=null,u.selectionBox=null,u.pan=null,it()});document.addEventListener("pointerdown",e=>{!L.modal.classList.contains("visible")||!L.modal.classList.contains("equipment-popover")||e.target.closest("#modal .modal-card")||en()},!0);L.buttons.s1Left.addEventListener("click",()=>Me.sortSlot(0,"left"));L.buttons.s1Right.addEventListener("click",()=>Me.sortSlot(0,"right"));L.buttons.s2Left.addEventListener("click",()=>Me.sortSlot(1,"left"));L.buttons.s2Right.addEventListener("click",()=>Me.sortSlot(1,"right"));L.buttons.nextTurn.addEventListener("click",$c);L.buttons.conveyor.addEventListener("click",()=>X.setBuildTool("conveyor"));L.buttons.boostConveyor.addEventListener("click",()=>X.setBuildTool("boostConveyor"));L.buttons.eggFarm.addEventListener("click",()=>X.setBuildTool("eggFarm"));L.buttons.autoScanner.addEventListener("click",()=>X.setBuildTool("autoScanner"));L.buttons.manualScanner.addEventListener("click",()=>X.setBuildTool("manualScanner"));L.buttons.mixer.addEventListener("click",()=>X.setBuildTool("mixer"));L.buttons.trash.addEventListener("click",()=>X.setBuildTool("trash"));L.buttons.truck.addEventListener("click",()=>X.setBuildTool("truck"));L.buttons.maintenanceRoom.addEventListener("click",()=>X.setBuildTool("maintenanceRoom"));L.buttons.erase.addEventListener("click",()=>X.setBuildTool("erase"));L.debug.setDay?.addEventListener("click",Tc);L.debug.zeroTimer?.addEventListener("click",Ec);L.debug.grantCard?.addEventListener("click",Rc);L.debug.grantAllCards?.addEventListener("click",Pc);L.buttons.undo.addEventListener("click",()=>{Ho(u)&&(kt(),Q.updatePanels(),Q.updateUI(),Nt())});L.buttons.redo.addEventListener("click",()=>{qo(u)&&(kt(),Q.updatePanels(),Q.updateUI(),Nt())});function Hs(e,t,n){let o=e.keys?.[t];return o?o.code&&n.code===o.code||o.key&&n.key.toLowerCase()===o.key:!1}window.addEventListener("keydown",e=>{if(e.repeat)return;let t=e.key.toLowerCase();if(u.phase==="running")for(let n of u.scanners.filter(o=>o.kind==="manual")){if(Hs(n,"left",e)){e.preventDefault(),Me.sortScanner(n,"left");return}if(Hs(n,"right",e)){e.preventDefault(),Me.sortScanner(n,"right");return}}u.phase==="build"&&(e.ctrlKey||e.metaKey)&&t==="z"&&(e.preventDefault(),Ho(u)&&(kt(),Q.updatePanels(),Q.updateUI())),u.phase==="build"&&(e.ctrlKey||e.metaKey)&&(t==="y"||e.shiftKey&&t==="z")&&(e.preventDefault(),qo(u)&&(kt(),Q.updatePanels(),Q.updateUI())),e.key==="Escape"&&u.cardTargetPick?.pending&&(e.preventDefault(),u.cardTargetPick.mode==="autoScannerMenu"?en():tn.cancelTargetPick())});X=Fs({game:u,ui:L,canvas:fe,canvasPoint:St,onUpdatePanels:()=>Q?.updatePanels()});Me=Us({game:u,currentConveyorSpeed:Ic,onGameOverCheck:()=>Q?.checkGameOver()});tn=ws({game:u,ui:L,onUpdatePanels:()=>Q?.updatePanels()});Q=Bs({game:u,ui:L,build:X,startGame:Dc,beginCardDraft:()=>tn.showDraft(),activeQueuedChick:Me.activeQueuedChick});Mc();xc();Eo(u);Se(u);Me.updateCongestion();Q.updatePanels();Q.updateUI();Q.showTitle();_t();requestAnimationFrame(zs); diff --git a/dist/game.js b/dist/game.js index c6ea3cf..0bd90d6 100644 --- a/dist/game.js +++ b/dist/game.js @@ -1,60 +1,60 @@ -var q={version:"v27.14 debug restore consistency patch",time:{daySeconds:60,farmShutdownGraceSeconds:10},cash:{starting:250},grid:{x:170,y:78,cols:20,rows:10,cell:46,expansion:{colsPerPurchase:10,rowsPerPurchase:10,costBase:1e3,costMultiplier:1.3333333333333333,truncateUnit:100}},map:{blockedRatio:.075},economy:{income:{mixer:5,truck:10},poopFine:10,fairiesTribute:{perDay:10,profitExemption:300,legalWorkExemptionBonus:250,profitRate:.12},incomeUpgradeRate:1.1,explosionDamageDivisor:30,maleTruckFinePerHalfDay:30,shredderBonus:{maxCards:30,incomePerUpgrade:1.25},chemicalWeaponSubsidy:{poopPerBlock:70,yenPerBlock:1200}},production:{poopRate:.08,autoScannerCooldown:3.5,autoScannerUpgradeRate:.95,autoScannerCardUpgradeRate:.95,autoScannerMinCooldown:.5,poopRateCardBonus:.04,eggSpawnRanges:[[1.95,4.35],[1.55,3.45],[1.25,2.8],[1.05,2.35]]},conveyor:{baseSpeed:52,maxSpeed:300,bearingSpeedMultiplier:1.075},cards:{definitions:[{id:"upgradeEgg",title:"EGG Improvement",rarity:"common",type:"equipmentUpgrade",target:"eggFarm",description:"Choose one EGG FARM on the map and raise it by 1 level.",tags:["EGG","ACTIVE"]},{id:"upgradeAutoScanner",title:"AUTO SCANNER Improvement",rarity:"common",type:"equipmentUpgrade",target:"autoScanner",description:"Choose one AUTO SCANNER on the map and raise it by 1 level.",tags:["SCANNER","ACTIVE"]},{id:"autoScannerTuning",title:"AUTO SCANNER Tuning",rarity:"common",type:"instant",description:"All AUTO SCANNER cooldowns use default cooldown x0.95 per copy.",tags:["SCANNER","PASSIVE"]},{id:"upgradeMixer",title:"MIXER Improvement",rarity:"common",type:"equipmentUpgrade",target:"mixer",description:"Choose MIXER on the map and raise it by 1 level.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeTruck",title:"TRUCK Improvement",rarity:"common",type:"equipmentUpgrade",target:"truck",description:"Choose TRUCK on the map and raise it by 1 level.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeTrash",title:"SHREDDER Improvement",rarity:"common",type:"equipmentUpgrade",target:"trash",description:"Shred poops for a little money. Max 30 upgrades.",tags:["POOP","ACTIVE"]},{id:"crowdedFarming",title:"Crowded Farming",rarity:"common",type:"instant",description:"EGG production interval -5%. Equipment deterioration +4%. Max 10 cards.",tags:["EGG","RISK","PASSIVE"]},{id:"hatchingFeed",title:"Hatching Feed",rarity:"common",type:"instant",description:"EGG production interval -4%. Poop rate +3%. No card limit.",tags:["EGG","POOP","PASSIVE"]},{id:"poopRateBooster",title:"Poop Culture",rarity:"common",type:"instant",description:"Base poop rate +4 percentage points. No card limit.",tags:["POOP","PASSIVE"]},{id:"safetyCover",title:"Safety Cover",rarity:"common",type:"instant",description:"Explosion damage -5%. No card limit.",tags:["RISK","PASSIVE"]},{id:"preventiveMaintenance",title:"Preventive Maintenance Manual",rarity:"common",type:"instant",description:"All equipment deterioration speed -5%. No card limit.",tags:["MAINTENANCE","PASSIVE"]},{id:"dudFilter",title:"DUD Filter",rarity:"common",type:"instant",description:"DUD chance -5 percentage points. Stacks until DUD chance reaches 0%.",tags:["CARD","PASSIVE"]},{id:"durabilityCoating",title:"Durability Coating",rarity:"common",type:"instant",description:"All equipment maximum durability +3%. No card limit.",tags:["MAINTENANCE","PASSIVE"]},{id:"bearing",title:"High-Quality Bearing",rarity:"common",type:"instant",description:"Conveyor speed +7.5%.",tags:["CONVEYOR","PASSIVE"]},{id:"sparePartsBin",title:"SPARE PARTS BIN",rarity:"common",type:"instant",description:"Restores 2% durability to every machine. A box of almost-compatible parts.",tags:["MAINTENANCE","ACTIVE"]},{id:"dudRefund",title:"DUD REFUND",rarity:"common",type:"instant",description:"DUDs now come with paperwork. Gain JPY 50 per copy when you pick a DUD.",tags:["CARD","ECONOMY","PASSIVE"]},{id:"freeReroll",title:"FREE REROLL",rarity:"common",type:"instant",description:"The first bad ideas are free.",tags:["CARD","PASSIVE"]},{id:"composter",title:"COMPOSTER",rarity:"common",type:"instant",description:"Turns shredder waste into suspicious fertilizer. Gain JPY 3 per copy when SHREDDER processes poop.",tags:["POOP","ECONOMY","PASSIVE"]},{id:"scannerQueueSpacing",title:"Scanner Queue Spacing",rarity:"common",type:"instant",description:"Manual and Auto Scanner queue spacing -15%. No card limit.",tags:["SCANNER","PASSIVE"]},{id:"extraEggOutlet",title:"Extra Egg Outlet",rarity:"rare",type:"equipmentUpgrade",target:"eggOutlet",description:"Choose one EGG FARM and add +1 output port to that EGG. Max +3 per EGG.",tags:["EGG","RARE","ACTIVE"]},{id:"recyclingSubsidy",title:"Recycling Subsidy",rarity:"rare",type:"instant",description:"SELL refund rate +10 points. Max 3 cards; normal SELL can reach 80%.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"dynamite",title:"Dynamite",rarity:"rare",type:"cellAction",target:"blockedCell",description:"Remove any 3 unbuildable cells",tags:["RISK","RARE","ONE-SHOT"]},{id:"usedMachine",title:"Used Machines",rarity:"rare",type:"instant",description:"Future equipment costs half. New purchases have no refund and 60% durability. New Machines cancels it.",tags:["ECONOMY","RISK","RARE"]},{id:"newMachine",title:"New Machines",rarity:"common",type:"instant",description:"Cancel Used Machines and restore normal prices, refunds, and durability.",tags:["ECONOMY","ONE-SHOT"]},{id:"flattery",title:"Flattery",rarity:"rare",type:"instant",description:"Next Fairies tribute -50%.",tags:["ECONOMY","RARE","ONE-SHOT"]},{id:"extraCards",title:"Extra Cards",rarity:"rare",type:"instant",description:"Draw 2 cards now and choose both.",tags:["RARE","ACTIVE"]},{id:"legalWork",title:"Legal Work",rarity:"rare",type:"instant",description:"Fairies tribute profit exemption +JPY 250.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"chemicalWeaponSubsidy",title:"Chemical Weapons Subsidy",rarity:"ultraRare",type:"instant",description:"Each day, gain JPY 1200 per 70 poop shipped by truck. No card limit.",tags:["POOP","ULTRA RARE","PASSIVE"]},{id:"laborExploitation",title:"Motivational Exploitation",rarity:"ultraRare",type:"instant",description:"Repairman labor cost -30%. The repairman smiles with bloodshot eyes. One time only.",tags:["MAINTENANCE","ULTRA RARE","PASSIVE"]},{id:"rescueLoan",title:"Emergency Loan",rarity:"ultraRare",type:"instant",description:"If cash is below JPY 0 at day-end settlement, gain JPY 500. Consumed on use.",tags:["ECONOMY","ULTRA RARE","ONE-SHOT"]}],defaultEffects:{bearing:0,legalWork:0,fairiesFlatteryNext:0,autoScannerTuning:0,poopRateBooster:0,crowdedFarming:0,hatchingFeed:0,safetyCover:0,recyclingSubsidy:0,chemicalWeaponSubsidy:0,preventiveMaintenance:0,dudFilter:0,durabilityCoating:0,sparePartsBin:0,dudRefund:0,freeReroll:0,composter:0,scannerQueueSpacing:0,laborExploitation:0,usedMachineActive:!1,rescueLoanCharges:0},commonWeight:8,rareWeight:2,ultraRareWeight:.45,baseDraftSize:3,maxDudsPerDraft:2,dudChancePerCard:.3,dudChanceReductionPerFilter:.05,extraCardsAddedPicks:2,rerollCost:{dayDivisor:2,multiplier:100}},events:{eventChance:.1,firstTurn:8},maintenance:{fullPerformanceUntilWear:.5,minimumPerformance:.5,durability:{conveyor:1300,eggFarm:475,autoScanner:850,mixer:775,trash:950},processingDelayMaxSeconds:{mixer:1.2,trash:1},repairman:{dailyCost:100,secondsPerOnePercent:.5,walkSpeed:90}},facilities:{conveyor:{id:"conveyor",type:"conveyor",name:"Conveyor",shortName:"Belt",price:30,buildable:!0,upgradeable:!1},boostConveyor:{id:"boostConveyor",type:"conveyor",name:"Boost Conveyor",shortName:"BOOST BELT",price:75,buildable:!0,upgradeable:!1,speedMultiplier:2},eggFarm:{id:"eggFarm",type:"eggFarm",name:"Egg Farm",shortName:"EGG",price:250,buildable:!0,upgradeable:!0,maxLevel:4},manualScanner:{id:"manualScanner",type:"scanner",kind:"manual",name:"Manual Scanner",shortName:"Manual Scanner",price:260,buildable:!0,upgradeable:!1},autoScanner:{id:"autoScanner",type:"scanner",kind:"auto",name:"Auto Scanner",shortName:"Auto Scanner",price:180,buildable:!0,upgradeable:!1},mixer:{id:"mixer",type:"facility",name:"Mixer",shortName:"MIXER",price:450,buildable:!0,upgradeable:!0,incomeKey:"mixer",body:{w:164,h:126}},trash:{id:"trash",type:"facility",name:"Waste Shredder",shortName:"SHREDDER",price:240,buildable:!0,upgradeable:!0,body:{w:180,h:100}},truck:{id:"truck",type:"facility",name:"Truck",shortName:"TRUCK",price:450,buildable:!0,upgradeable:!0,incomeKey:"truck",body:{w:176,h:138}}}};var wn=q.version,vt=q.time.daySeconds,tn=q.cash.starting,xe=q.economy,xr=q.time.farmShutdownGraceSeconds,Sn=q.production.autoScannerCooldown,kr=q.production.autoScannerUpgradeRate,so=q.production.autoScannerCardUpgradeRate||q.production.autoScannerUpgradeRate,lo=q.production.autoScannerMinCooldown,Cr=q.events.eventChance,wt=q.events.firstTurn,ao=q.production.poopRate,co=q.production.poopRateCardBonus||0,xn=q.conveyor.baseSpeed,Gt=q.conveyor.maxSpeed,kn=q.conveyor.bearingSpeedMultiplier,Re=q.cards,Mr=q.cards.definitions,uo=q.cards.defaultEffects,st=q.production.eggSpawnRanges,y=q.grid,Se=q.facilities,fo=["conveyor","boostConveyor","eggFarm","autoScanner","manualScanner","mixer","trash","truck"],nn=["mixer","trash","truck"],gr=["mixer","truck"],St=Object.fromEntries(Object.entries(Se).map(([e,t])=>[e,t.price])),ue=[{name:"right",dc:1,dr:0,angle:0,opposite:"left"},{name:"left",dc:-1,dr:0,angle:Math.PI,opposite:"right"},{name:"down",dc:0,dr:1,angle:Math.PI/2,opposite:"up"},{name:"up",dc:0,dr:-1,angle:-Math.PI/2,opposite:"down"}],f={bg:"#eefbea",ink:"#102015",muted:"#526456",green:"#22b94f",greenSoft:"#b7f5c6",mixerBlue:"#2477ff",truckPink:"#ff6aa8",wasteGreen:"#22b94f",danger:"#c42424",warn:"#f0a020",white:"#ffffff",poop:"#7b4a23",male:"#62a9ff",female:"#ff8bc6"},ke={ambient:0,important:1,critical:2};function M(e){let t=Number(e)||0;return`${t<0?"-":""}\uFFE5${Math.ceil(Math.abs(t)).toLocaleString("ja-JP")}`}function $(e,t){return`${e},${t}`}function Q(e){let[t,n]=String(e).split(",").map(Number);return{col:t,row:n}}function on(e,t,n){return Math.max(t,Math.min(n,e))}function U(e,t){return e+Math.random()*(t-e)}function Te(e,t){return e>=0&&e=0&&tMath.round(on(r,0,255)).toString(16).padStart(2,"0");return`#${o(e)}${o(t)}${o(n)}`}function yo(e,t,n){let o=Tr(e),r=Tr(t);return tl(po(o.r,r.r,n),po(o.g,r.g,n),po(o.b,r.b,n))}var re={appTitle:"Chick Sorter",versionTitle:`Chick Sorter ${wn}`,currency:"\uFFE5",phases:{title:"Title",build:"Build",running:"Sorting",clearing:"Clearing",loanDecision:"Emergency Loan",gameover:"Game Over"},actions:{startGame:"Start Game",nextDay:"Next Day",buildPhase:"Build Phase",restart:"Restart",close:"Close",remove:"Remove",refund:"Refund",autoMenu:"Auto Menu"},status:{build:e=>`BUILD: ${(e==="erase"?"SELL":e||"SELECT").toUpperCase()} | Right-drag pan | Hover equipment for info`,sorting:"Sorting: use scanner keys. Build after clearing the day.",allPortsConnected:"Start condition met: one EGG route reaches an exit.",equipmentPanelEmpty:"Hover equipment in Build phase.",eventPanelRunning:"Forced events appear in Build phase."},routeLabels:{mixer:"MIXER",truck:"TRUCK",trash:"WASTE",scanner:"NEXT","scanner-role-1":"NEXT",input:"IN"},fail:{outOfGrid:"Out of grid",cellOccupied:"Cell occupied",notEnoughCash:"Not enough cash",facilityExists:"Facility already exists",facilityOverlap:"Facility overlap",nothingToErase:"Nothing to sell",noUpgrade:"No upgrade available"}};function xt(e){return Se[e]?.name||String(e||"").replace(/^[a-z]/,t=>t.toUpperCase())}function nl(e){let t=Se[e];return t?e==="conveyor"||e==="boostConveyor"?`${M(t.price)} / tile`:e==="autoScanner"?`${M(t.price)} / ${Sn.toFixed(1)}s cooldown`:e==="trash"?M(t.price):M(t.price):""}function ol(e){return{conveyor:"A narrow green belt. Routes decide whether chicks live, ship, or become invoices.",boostConveyor:"Moves chicks twice as fast. Wears down like a normal belt.",eggFarm:"A tiny gatehouse producing questionable eggs on schedule.",autoScanner:"Slower than hands without upgrades.",manualScanner:"A manual checkpoint. The operator is the algorithm.",mixer:"Male chicks become revenue here. Do not feed it poop.",trash:"A polite shredder for poop and other regrets.",truck:"Ships the target cargo. Wrong cargo still leaves a paper trail."}[e]||""}function Pr(e){let t=ol(e);return`${xt(e)}${nl(e)}${t?`${t}`:""}`}function Rr(e){return re.routeLabels[e]||String(e).toUpperCase()}function Ar(e){let t=2166136261;for(let n=0;n>>0}function Dr(e){let t=e>>>0;return()=>{t+=1831565813;let n=Math.imul(t^t>>>15,1|t);return n^=n+Math.imul(n^n>>>7,61|n),((n^n>>>14)>>>0)/4294967296}}function Mn(){return`RUN-${Date.now().toString(36)}-${Math.floor(Math.random()*1e6).toString(36)}`.toUpperCase()}function Ir({seed:e,targetRatio:t=.2,reserved:n=[]}={}){let o=Dr(Ar(e||Mn())),r=new Set(n.map(d=>typeof d=="string"?d:$(d.col,d.row))),s=[];for(let d=0;d0;d-=1){let v=Math.floor(o()*(d+1));[s[d],s[v]]=[s[v],s[d]]}let l=Math.round(y.cols*y.rows*t);return new Set(s.slice(0,Math.min(l,s.length)).map(d=>d.k))}function $r({seed:e,colStart:t=0,colEnd:n=y.cols,rowStart:o=0,rowEnd:r=y.rows,targetRatio:s=.2,reserved:l=[]}={}){let d=Dr(Ar(e||Mn())),v=new Set(l.map(z=>typeof z=="string"?z:$(z.col,z.row))),C=[],P=Math.max(0,Math.floor(t)),A=Math.max(P,Math.floor(n)),L=Math.max(0,Math.floor(o)),V=Math.max(L,Math.floor(r));for(let z=L;z0;z-=1){let se=Math.floor(d()*(z+1));[C[z],C[se]]=[C[se],C[z]]}let ne=Math.round((A-P)*(V-L)*s);return new Set(C.slice(0,Math.min(ne,C.length)).map(z=>z.k))}var Ut=10,Fr=2,Br=1;function Wt(e,t){return`${e},${t}`}function rl(e){let[t,n]=String(e).split(",").map(Number);return{chunkX:t,chunkY:n}}function gn(e){let t=q.grid.expansion||{},n=Math.max(1,(e.gridExpansionPurchases||0)+1),o=(t.costBase||1e3)*n*(t.costMultiplier||4/3),r=Math.max(1,t.truncateUnit||100);return Math.floor(o/r)*r}function Lr(e){e.ownedCells=new Set,e.ownedChunks=new Set,e.gridChunkOriginY=0,e.gridExpansionPurchases=0,e.gridExpansionPurchasesByDirection={right:0,up:0};for(let t=0;t=0&&t=0&&n0)continue;let C=Wt(v.chunkX,v.chunkY);t.has(C)||n.has(C)||n.set(C,ho(e,v.chunkX,v.chunkY,v.direction))}}return[...n.values()].sort((o,r)=>{let s=o.direction===r.direction?0:o.direction==="right"?-1:1;return s||(o.chunkY!==r.chunkY?o.chunkY-r.chunkY:o.chunkX-r.chunkX)})}function Gr(e,t="right"){let n=kt(e);return n.find(o=>o.direction===t)||n[0]||null}function Ct(e){return{x:y.x+e.colStart*y.cell,y:y.y+e.rowStart*y.cell,w:e.cols*y.cell,h:e.rows*y.cell}}function mo(e){let t=Ct(e);return{x:t.x+t.w/2-116,y:t.y+t.h/2-36,w:232,h:72,cx:t.x+t.w/2,cy:t.y+t.h/2}}function Ur(e,t){let n=mo(e);return t.x>=n.x&&t.x<=n.x+n.w&&t.y>=n.y&&t.y<=n.y+n.h}function Wr(e){let t=[];for(let n=e.rowStart;nTe(t.col,t.row))}function fl(e){return[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}].filter(t=>Te(t.col,t.row))}function pl(e){return[{col:e.col,row:e.row+1},{col:e.col-1,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row-1}].filter(t=>Te(t.col,t.row))}function Vr(e){let t=new Set([...e.conveyorTiles]),n=o=>{o&&Te(o.col,o.row)&&t.add($(o.col,o.row))};for(let o of e.scanners){for(let r of fl(o))n(r);for(let r of dl(o))n(r)}for(let o of e.eggFarms){n(o);for(let r of pl(o))n(r)}for(let o of Object.values(e.facilities))n(o.entry);return t}function qr(e){let t=ll.map(([n,o])=>({col:n,row:o}));for(let{col:n,row:o}of t)Yr(e,n,o);for(let n=0;n({...n,keys:n.keys?{left:{...n.keys.left},right:{...n.keys.right}}:null,queue:[]})),e.eggFarms=cl.map(n=>{let o=Mt(n);return{...n,nextSpawn:o,lastInterval:o}});let t=Vr(e);e.blockedCells=Ir({seed:e.runSeed,targetRatio:q.map.blockedRatio,reserved:[...t]}),yl(e),qr(e),e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function gt(e){return e?[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}]:[]}function pe(e){let t=F(e.col,e.row);return{x:t.x+y.cell/2,y:t.y}}function Tt(e,t,n){return e.eggFarms.find(o=>o.col===t&&o.row===n)||null}function Et(e,t,n){return e.scanners.find(o=>gt(o).some(r=>r.col===t&&r.row===n))||null}function Pt(e,t){return e.scanners.find(n=>n.id===t)||null}function xo(e,t){return e.scanners.find(n=>n.kind==="manual"&&n.slot===t)||null}function Rn(e){return e?.baseId||e?.id||""}function ko(e,t){return Object.entries(e.facilities||{}).filter(([,n])=>Rn(n)===t)}function Ee(e,t){return{inputA:{col:e.col,row:e.row-2},inputB:null,left:{col:e.col-1,row:e.row},right:{col:e.col+2,row:e.row}}[t]}function Qr(e){return e?ue.map(t=>({col:e.col+t.dc,row:e.row+t.dr})).filter(t=>Te(t.col,t.row)):[]}function Jr(e,t,n=[],o=[]){if(!t||!Te(t.col,t.row))return[];let r=[],s=l=>{!l||!Te(l.col,l.row)||!e.conveyorTiles.has($(l.col,l.row))||n.some(d=>d&&Cn(l,d))||r.some(d=>Cn(d,l))||r.push({...l,viaTolerance:!Cn(l,t)})};s(t);for(let l of o)s(l);for(let l of Qr(t))s(l);return r}function zr(e,t,n=[],o=[]){let r=Jr(e,t,n,o),s=r.filter(l=>!l.viaTolerance);return s.length?s:r}function hl(e,t){let n=Ee(t,"inputA");return!n||!Te(n.col,n.row)?[]:e.conveyorTiles.has($(n.col,n.row))?[{...n,viaTolerance:!1}]:[]}function ml(e,t,n){let o=Ee(t,n);return Jr(e,o,gt(t))}function bl(e,t){let n=e.facilities[t]||ko(e,t)[0]?.[1];if(!n)return null;if(n.entry)return F(n.entry.col,n.entry.row);let o=Rn(n)||t;return o==="mixer"?{x:n.x+n.w,y:n.y+n.h*.52}:o==="truck"?{x:n.x,y:n.y+n.h*.52}:o==="trash"?{x:n.x+n.w/2,y:n.y+8}:{x:n.x+n.w/2,y:n.y+n.h/2}}function jr(e,t,n){return n==="inputA"?hl(e,t).length>0:ml(e,t,n).length>0}function be(e){e.branchCounters?.clear?.(),e.routeCache=null,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function Ae(e,t){return $(e,t)}function _t(e){return Q(e)}function vl(e,t){let n=e.conveyorMeta?.get?.(t)||{},o=[];return Array.isArray(n.outDirs)&&o.push(...n.outDirs),n.dir&&o.push(n.dir),[...new Set(o)].filter(r=>ue.some(s=>s.name===r))}function wl(e,t,n){let o=ue.find(l=>l.name===n);if(!o)return!1;let r=e.conveyorMeta?.get?.(Ae(t.col+o.dc,t.row+o.dr));return r?[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))].includes(o.opposite):!1}function Sl(e,t){let n=_t(t),o=e.conveyorMeta?.get?.(t)||{},r=ue.filter(A=>e.conveyorTiles.has(Ae(n.col+A.dc,n.row+A.dr))).map(A=>A.name),s=vl(e,t).filter(A=>r.includes(A)),l=r,d=s.length?s:l;if(r.length<3)return d;let v=new Set(r.filter(A=>wl(e,n,A)));if(o.branchMode&&o.branchMode!=="random"&&r.includes(o.branchMode)){let A=new Set(v);A.add(o.branchMode),r.filter(L=>!A.has(L)).length>=2&&v.add(o.branchMode)}let C=r.filter(A=>!v.has(A));if(C.length)return C;let P=d.filter(A=>!v.has(A));return P.length?P:d}function xl(e){return{version:e.routingVersion||0,cells:new Set,adjacency:new Map,components:new Map,cellToComponent:new Map,scannerInputs:new Map,scannerPorts:new Map,facilityPorts:new Map,farmOutputs:new Map,pathCache:new Map,metrics:{conveyorCells:0,edges:0,components:0,deadEnds:0,crosses:0,scannerPorts:0,connectedScannerPorts:0,facilityPorts:0,connectedFacilityPorts:0,farmOutputs:0},issues:[]}}function kl(e){let t=xl(e);for(let o of e.conveyorTiles)t.cells.add(o),t.adjacency.set(o,[]);for(let o of t.cells){let r=_t(o),s=Sl(e,o),l=ue.filter(d=>s.includes(d.name));for(let d of l){let v=Ae(r.col+d.dc,r.row+d.dr);t.cells.has(v)&&t.adjacency.get(o).push({key:v,dir:d.name})}}let n=0;for(let[o,r]of t.adjacency.entries()){n+=r.length;let s=new Set(r.map(l=>l.dir));r.length===1&&(t.metrics.deadEnds+=1),r.length===4&&s.has("left")&&s.has("right")&&s.has("up")&&s.has("down")&&(t.metrics.crosses+=1)}return t.metrics.conveyorCells=t.cells.size,t.metrics.edges=Math.floor(n/2),Cl(t),Ml(e,t),t.issues=Bl(e,t,{includeRoutes:!1}),t}function Cl(e){let t=1;for(let n of e.cells){if(e.cellToComponent.has(n))continue;let o=t++,r=[n],s=[];for(e.cellToComponent.set(n,o);r.length;){let l=r.shift();s.push(l);for(let d of e.adjacency.get(l)||[])e.cellToComponent.has(d.key)||(e.cellToComponent.set(d.key,o),r.push(d.key))}e.components.set(o,{id:o,cells:s,capacity:Math.max(1,s.length),count:0,ratio:0})}e.metrics.components=e.components.size}function Ml(e,t){for(let n of e.scanners){let o={};for(let r of["inputA","left","right"]){let s=Ee(n,r),l=r==="inputA"?s&&t.cells.has(Ae(s.col,s.row))?[{...s}]:[]:zr(e,s,gt(n)).filter(C=>t.cells.has(Ae(C.col,C.row))),d=l.map(C=>Ae(C.col,C.row)),v=d.length>0;if(o[r]={type:r,cell:s,cells:l,keys:d,key:d[0]||null,connected:v},t.metrics.scannerPorts+=1,v&&(t.metrics.connectedScannerPorts+=1),r==="inputA")for(let C of d)t.scannerInputs.set(C,n.id)}t.scannerPorts.set(n.id,o)}for(let[n,o]of Object.entries(e.facilities)){if(!o.entry)continue;let r=zr(e,o.entry).filter(d=>t.cells.has(Ae(d.col,d.row))),s=r.map(d=>Ae(d.col,d.row)),l=s.length>0;t.facilityPorts.set(n,{id:n,cell:{...o.entry},cells:r,keys:s,key:s[0]||null,connected:l}),t.metrics.facilityPorts+=1,l&&(t.metrics.connectedFacilityPorts+=1)}for(let n of e.eggFarms){let o=Qr({col:n.col,row:n.row}).map(r=>Ae(r.col,r.row)).filter(r=>t.cells.has(r));t.farmOutputs.set(n.id,o),t.metrics.farmOutputs+=o.length}}function Le(e){let t=e.routingVersion||0;return(!e.factoryGraph||e.factoryGraph.version!==t)&&(e.factoryGraph=kl(e)),e.factoryGraph}function Zr(e){let t=Le(e);return e.factoryGraphCommittedVersion=t.version,e.factoryGraphSnapshot=gl(t),t}function gl(e){return e?{version:e.version,conveyorCells:e.metrics.conveyorCells,edges:e.metrics.edges,components:e.metrics.components,deadEnds:e.metrics.deadEnds,crosses:e.metrics.crosses,scannerPorts:`${e.metrics.connectedScannerPorts}/${e.metrics.scannerPorts}`,facilityPorts:`${e.metrics.connectedFacilityPorts}/${e.metrics.facilityPorts}`,farmOutputs:e.metrics.farmOutputs,issues:[...e.issues||[]]}:null}function Tl(e,t){let n=t.col-e.col,o=t.row-e.row;return ue.find(r=>r.dc===n&&r.dr===o)?.name||null}function Co(e,t,n){let o=Le(e),r=Ae(t.col,t.row);if(!o.cells.has(r))return[];let s=`${r}|${n.cacheKey||"dynamic"}`;if(n.cacheKey&&o.pathCache.has(s))return o.pathCache.get(s).map(I=>I.map(W=>({...W})));let l=`${r}|none`,d=[{key:r,col:t.col,row:t.row,incoming:"none",depth:0}],v=new Map([[l,0]]),C=new Map,P=[],A=1/0,L=8,V=24,ne=80;for(;d.length;){let I=d.shift();if(I.depth>A)break;let W=`${I.key}|${I.incoming}`;if(n(I)){if(P.push(W),A=I.depth,P.length>=V)break;continue}for(let N of o.adjacency.get(I.key)||[]){let le=_t(N.key),we=Tl(I,le),he=I.depth+1;if(he>A)continue;let R=`${N.key}|${we}`,G=v.get(R);if(G==null)v.set(R,he),C.set(R,[W]),d.push({key:N.key,col:le.col,row:le.row,incoming:we,depth:he});else if(G===he){let x=C.get(R)||[];x.length{if(z.length>=ne)return;let[N]=I.split("|"),le=[_t(N),...W];if(I===l||N===r){z.push(le);return}for(let we of C.get(I)||[])se(we,le)};for(let I of P)se(I,[]);let ye=[],Z=new Set;for(let I of z){let W=I.map(N=>Ae(N.col,N.row)).join(">");Z.has(W)||(Z.add(W),ye.push(I))}return n.cacheKey&&o.pathCache.set(s,ye.map(I=>I.map(W=>({...W})))),ye}function ei(e){let t=Le(e),n=new Map;for(let[o,r]of t.components.entries())n.set(o,{id:o,cells:[...r.cells],capacity:r.capacity,count:0,ratio:0});return{components:n,cellToComponent:new Map(t.cellToComponent)}}function ti(e,t,n){let o=Le(e),r=null,s=1/0;for(let l of o.cells){let d=Q(l),v=F(d.col,d.row),C=Math.hypot(v.x-t,v.y-n);CF(o.col,o.row));return t&&n.push(t),n}function at(e,t){t&&(!e.length||Er(e[e.length-1],t)>1)&&e.push(t)}function El(e,t,n,o=null){let r=[{x:e.x,y:e.y}];at(r,F(t.col,t.row));for(let s of An(n,o))at(r,s);return r}function Pl(e,t){let n=An(e),o=Ee(t,"inputA");return o&&at(n,F(o.col,o.row)),at(n,pe(t)),n}function Rl(e,t,n,o){let r=[{x:e.x,y:e.y}];at(r,F(t.col,t.row));for(let l of An(n))at(r,l);let s=Ee(o,"inputA");return s&&at(r,F(s.col,s.row)),at(r,pe(o)),r}function Al(e,t,n=0){let o=F(t.col,t.row),r=0;for(let s of e.chicks||[]){if(s.stage==="flying"||s.stage==="queued")continue;Math.hypot(s.x-o.x,s.y-o.y){let A=C.roleBias??0,L=P.roleBias??0;if(A!==L)return A-L;let V=C.cells?.length??C.route?.length??Number.POSITIVE_INFINITY,ne=P.cells?.length??P.route?.length??Number.POSITIVE_INFINITY;if(V!==ne)return V-ne;let z=C.key||JSON.stringify(C.route||C.cells||C),se=P.key||JSON.stringify(P.route||P.cells||P);return z.localeCompare(se)});if(!o||r.length===1)return r[0];let s=r[0].roleBias??0,l=r.filter(C=>(C.roleBias??0)===s),d=Math.min(...l.map(C=>Xr(e,C)));l=l.filter(C=>Xr(e,C)===d);let v=e.branchCounters.get(t)||0;return e.branchCounters.set(t,v+1),l[Math.floor(Math.random()*l.length)]}function ni(e){return e.role===0?{left:{match:"male",destination:"mixer"},right:{match:"default",destination:"scanner-role-1"}}:{left:{match:"poop",destination:"trash"},right:{match:"default",destination:"truck"}}}function Mo(e){let t=ni(e);return{left:t.left.destination,right:t.right.destination}}function go(e,t){return ni(e).left.match===t.sex?"left":"right"}function To(e){return Rr(e)}function Eo(e){return{mixer:"#2477ff",truck:"#ff6aa8",trash:"#22b94f","scanner-role-1":"#526456",scanner:"#526456",input:"#526456"}[e]||"#102015"}function Rt(e,t,n=!1){let o=Le(e),r=(o.farmOutputs.get(t.id)||[]).map(_t),s=[];for(let v of r){let C=A=>o.scannerInputs.has(Ae(A.col,A.row));C.cacheKey=`farmInput:${v.col},${v.row}:v${o.version}`;let P=Co(e,v,C);for(let A of P){let L=A[A.length-1],V=o.scannerInputs.get(Ae(L.col,L.row)),ne=Pt(e,V);ne&&s.push({key:`${ne.id}:${L.col},${L.row}:${A.length}`,scanner:ne,cells:A})}}let l=Pn(e,`farm:${t.id}`,s,n);if(l)return{scannerId:l.scanner.id,route:Pl(l.cells,l.scanner)};let d=Pn(e,`farm:${t.id}:output`,r.map(v=>({key:$(v.col,v.row),cells:[v]})),n);return d?{scannerId:null,route:An(d.cells)}:null}function oi(e,t,n,o,r=!1){let s=Pt(e,o);if(!s)return null;let d=Le(e).scannerPorts.get(s.id)?.[t],v=Ee(s,t),C=d?.connected?(d.keys||[d.key]).filter(Boolean).map(_t):[];if(!v||!C.length)return null;let P=Mo(s)[t];return P==="scanner-role-1"?Dl(e,s,t,n,v,C,r):Il(e,s,t,n,v,C,P,r)}function Dl(e,t,n,o,r,s,l){let d=Le(e),v=e.scanners.filter(A=>A.id!==t.id&&d.scannerPorts.get(A.id)?.inputA?.connected),C=[];for(let A of s)for(let L of v){let V=d.scannerPorts.get(L.id)?.inputA?.key;if(!V)continue;let ne=(d.scannerPorts.get(L.id)?.inputA?.keys||[V]).filter(Boolean),z=Z=>ne.includes(Ae(Z.col,Z.row));z.cacheKey=`toScanner:${A.col},${A.row}:${L.id}:v${d.version}`;let se=Co(e,A,z),ye=L.role===1?0:1;for(let Z of se)C.push({key:`${ye}:start${$(A.col,A.row)}:s${L.id}:${Z.length}:${$(Z[Z.length-1].col,Z[Z.length-1].row)}`,target:L,cells:Z,roleBias:ye})}let P=Pn(e,`scanner:${t.id}:${n}:toRole1`,C,l);return P?{destination:"scanner",nextScannerId:P.target.id,route:Rl(o,r,P.cells,P.target)}:null}function Il(e,t,n,o,r,s,l,d){let v=Le(e),C=[...v.facilityPorts.entries()].filter(([L,V])=>V?.connected&&Rn(e.facilities?.[L])===l);if(!C.length)return null;let P=[];for(let L of s)for(let[V,ne]of C){let z=(ne.keys||[ne.key]).filter(Boolean);if(!z.length)continue;let se=Z=>z.includes(Ae(Z.col,Z.row));se.cacheKey=`toFacility:${L.col},${L.row}:${V}:v${v.version}`;let ye=Co(e,L,se);for(let Z of ye)P.push({key:`start${$(L.col,L.row)}:${V}:${Z.length}:${$(Z[Z.length-1].col,Z[Z.length-1].row)}`,cells:Z,facilityId:V})}let A=Pn(e,`scanner:${t.id}:${n}:${l}`,P,d);return A?{destination:l,facilityId:A.facilityId,route:El(o,r,A.cells,bl(e,A.facilityId))}:null}function ri(e,t,n=new Set){if(!t||n.has(t.id))return!1;n.add(t.id);for(let o of["left","right"]){let r=oi(e,o,pe(t),t.id,!1);if(r){if(["mixer","trash","truck"].includes(r.destination))return!0;if(r.destination==="scanner"){let s=Pt(e,r.nextScannerId);if(ri(e,s,n))return!0}}}return!1}function $l(e,t){return!!Rt(e,t,!1)?.scannerId}function Dn(e){if(e.phase!=="build")return[];let t=[];for(let n of e.eggFarms||[])$l(e,n)||t.push({type:"eggFarm",id:n.id,ref:n,message:"This Egg will not produce chicks"});for(let n of nn)for(let[o,r]of ko(e,n))Le(e).facilityPorts.get(o)?.connected||t.push({type:"facility",id:o,ref:r,message:"This facility cannot receive items"});return t}function Fl(e){let t=Le(e);for(let r of e.eggFarms||[]){let s=Rt(e,r,!1);if(!s?.scannerId)continue;let l=Pt(e,s.scannerId);if(ri(e,l))return[]}let n=e.eggFarms?.length||0,o=[...t.facilityPorts.entries()].filter(([r,s])=>s?.connected&&["mixer","trash","truck"].includes(Rn(e.facilities?.[r]))).length;return n?t.metrics.farmOutputs?e.scanners?.length?o?["Connect at least one EGG through a scanner to any valid exit."]:["Connect at least one receiver exit: Mixer, Shredder, or Truck."]:["Build at least one scanner and connect it to an EGG route."]:["Connect at least one EGG to a conveyor."]:["Build at least one EGG before starting the next day."]}function En(e){return e.kind==="manual"?`S${(e.slot??0)+1}`:`Auto Scanner #${e.id}`}function Bl(e,t=Le(e),n={}){let o=n.includeRoutes!==!1,r=[],s={mixer:"Mixer",trash:"Shredder",truck:"Truck"};for(let l of nn){let d=ko(e,l);if(!d.length){r.push(`${s[l]||l} is missing`);continue}for(let[v]of d)t.facilityPorts.get(v)?.connected||r.push(`${s[l]||l} receiver has no conveyor`)}for(let l of e.scanners){let d=t.scannerPorts.get(l.id)||{};if(d.inputA?.connected||r.push(`${En(l)} input has no conveyor`),d.left?.connected||r.push(`${En(l)} left output has no conveyor`),d.right?.connected||r.push(`${En(l)} right output has no conveyor`),!!o)for(let v of["left","right"])d[v]?.connected&&!oi(e,v,pe(l),l.id)&&r.push(`${En(l)} ${v} route is incomplete`)}if(o)for(let l of e.eggFarms)Rt(e,l)?.scannerId||r.push(`Egg Farm #${l.id} has no scanner route`);else for(let l of e.eggFarms)(t.farmOutputs.get(l.id)||[]).length||r.push(`Egg Farm #${l.id} has no output conveyor`);return[...new Set(r)]}function sn(e){return Fl(e)}function ii(e){return sn(e).length===0}var si=[{key:"premiumFemaleShipment",target:"female",truckTarget:"female",title:"Premium Female Shipment",route:"Female -> Truck",note:"Today only: ship female chicks to Truck. Meet the export target for a bonus.",objective:"truckTarget"},{key:"contaminantSampleExport",target:"poop",truckTarget:"poop",title:"Contaminant Sample Export",route:"Poop value x2",note:"Today only: poop is valid Truck cargo and all poop income is doubled.",objective:"truckTarget",poopValueMultiplier:2},{key:"healthInspection",title:"Health Inspection",route:"Poop -> Shredder",note:"Today only: poop mistakes are fined double. Shred enough poop for an inspection bonus.",objective:"poopTrash",poopFineMultiplier:2},{key:"conveyorJamWarning",title:"Conveyor Jam Warning",route:"No explosions",note:"Today only: jam explosions trigger at 85% congestion. Finish with zero explosions for a bonus.",objective:"noExplosion",congestionExplosionThreshold:.85,congestionWarningThreshold:.68},{key:"powerSavingOrder",title:"Power Saving Order",route:"Slow factory subsidy",note:"Today only: conveyors -20% speed and Auto Scanners +20% cooldown. A subsidy is paid at settlement.",objective:"flatBonus",conveyorSpeedMultiplier:.8,autoScannerCooldownMultiplier:1.2},{key:"overtimeDay",title:"Overtime Day",route:"80 second day",note:"Today only: the work day is longer. No extra reward or penalty.",objective:"none",daySeconds:80},{key:"shortShift",title:"Short Shift",route:"40 second day",note:"Today only: the work day is shorter. The next Fairies tribute is reduced by 10%.",objective:"none",daySeconds:40,fairiesTributeMultiplier:.9},{key:"chickBoom",title:"Chick Boom",route:"EGG interval x0.65",note:"Today only: eggs hatch faster and poop rate rises by 5 percentage points.",objective:"none",productionMultiplier:1/.65,poopRateAdd:.05},{key:"rottenFeed",title:"Rotten Feed",route:"Poop surge",note:"Today only: poop rate rises by 20 percentage points and Shredder poop income is multiplied by 1.5.",objective:"none",poopRateAdd:.2,shredderIncomeMultiplier:1.5},{key:"maintenanceAudit",title:"Maintenance Audit",route:"Durability check",note:"Today only: machines below 50% remaining durability fail the audit. Passing with none below 50% pays a bonus.",objective:"maintenanceAudit"}];function ve(e,t=0){let n=Number(e);return Number.isFinite(n)?n:t}function Ll(e,t=0,n=1){let o=Math.max(1,Number(e?.turn||1)+1),r=Math.floor(Po(e)*(.08+Math.random()*.08)),s=Math.floor(Math.max(0,e.cash||0)*.25),l=Math.floor(Math.max(0,t)*Math.max(1,o)*.75);return Math.max(120,Math.ceil(Math.max(r,s,l)*n))}function li(e){return Math.max(0,Math.ceil(500+Math.max(1,e?.turn||1)*25))}function Po(e){return[...e.eggFarms.map(t=>t.price||0),...e.scanners.map(t=>t.price||0),...Object.values(e.facilities).map(t=>t.price||0),...[...e.conveyorMeta.values()].map(t=>t.price||0)].reduce((t,n)=>t+n,0)}function Ol(e,t=1,n=vt){return e.eggFarms.reduce((o,r)=>{let[s,l]=rn(r),d=Math.max(.1,(s+l)/2);return o+Math.max(1,n)/d*Math.max(.01,t||1)},0)}function Nl(e,t){let n=ve(t.productionMultiplier,1),o=ve(t.daySeconds,vt),r=Ol(e,n,o),s=Math.max(0,Number(e?.cardEffects?.hatchingFeed)||0),l=Math.max(0,Number(e?.cardEffects?.poopRateBooster)||0),d=Math.pow(1.03,s),v=ao+co*l,C=Math.min(.95,Math.max(0,(v+ve(t.poopRateAdd,0))*ve(t.poopMultiplier,1)*d));return{estimate:r,poopRate:C}}function ai(e){if(e.turn+1Cr)return null;let n=si[Math.floor(Math.random()*si.length)],{estimate:o,poopRate:r}=Nl(e,n),s=0;n.objective==="truckTarget"?s=Math.max(1,Math.ceil(o*.3)):n.objective==="poopTrash"&&(s=Math.max(1,Math.ceil(o*r*.8)));let l=0;return["truckTarget","poopTrash","noExplosion"].includes(n.objective)&&(l=Ll(e,o)),n.objective==="flatBonus"&&(l=li(e)),n.objective==="maintenanceAudit"&&(l=li(e)),{id:`event-${e.turn}-${Date.now()}-${Math.floor(Math.random()*9999)}`,...n,target:n.target||null,truckTarget:n.truckTarget||null,forced:!0,productionMultiplier:ve(n.productionMultiplier,1),poopMultiplier:ve(n.poopMultiplier,1),poopRateAdd:ve(n.poopRateAdd,0),daySeconds:ve(n.daySeconds,vt),targetAmount:s,estimatedOutput:Math.round(o),reward:l,createdTurn:e.turn,oneTurnOnly:!0}}function ci(e){e.eventActive=e.eventOffer?{...e.eventOffer}:null,e.eventOffer=null}function ui(e){e.eventActive=null}function di(e){return Math.max(1,ve(e.eventActive?.daySeconds,vt))}function fi(e){return ve(e.eventActive?.productionMultiplier,1)}function pi(e){let t=Math.max(0,Number(e?.cardEffects?.hatchingFeed)||0),n=Math.max(0,Number(e?.cardEffects?.poopRateBooster)||0),o=Math.pow(1.03,t),r=ao+co*n,s=ve(e.eventActive?.poopRateAdd,0);return Math.min(.95,Math.max(0,(r+s)*ve(e.eventActive?.poopMultiplier,1)*o))}function Je(e){return e.eventActive?.truckTarget||e.eventActive?.target||"female"}function Ro(e,t){return t==="male"?e.truckMale||0:t==="poop"?e.poopTruck||0:e.truckFemale||0}function yi(e,t){return Je(e)===t}function hi(e){return Je(e)!=="male"}function Ao(e){return Math.max(.01,ve(e.eventActive?.poopValueMultiplier,1))}function In(e){return Math.max(.01,Ao(e)*ve(e.eventActive?.shredderIncomeMultiplier,1))}function Do(e){return Math.max(.01,ve(e.eventActive?.poopFineMultiplier,1))}function Io(e){return Math.max(.1,Math.min(1,ve(e.eventActive?.congestionExplosionThreshold,1)))}function mi(e){return Math.max(.1,Math.min(1,ve(e.eventActive?.congestionWarningThreshold,.8)))}function bi(e){return Math.max(.01,ve(e?.fairiesTributeMultiplier,1))}function Gl(e){let t=0,n=(o,r)=>{let s=Math.max(1,ve(r,1)),l=Math.max(0,ve(o,0));1-Math.min(1,l/s)<.5&&(t+=1)};for(let o of e.conveyorMeta?.values?.()||[])n(o.uses,o.durability);for(let o of e.eggFarms||[])n(o.maintenance?.uses,o.maintenance?.durability);for(let o of e.scanners||[])o.kind==="auto"&&n(o.maintenance?.uses,o.maintenance?.durability);for(let o of Object.values(e.facilities||{})){let r=o?.baseId||o?.id;(r==="mixer"||r==="trash")&&n(o.maintenance?.uses,o.maintenance?.durability)}return t}function vi(e){let t=e.eventActive;if(!t)return null;let n=0,o=!0,r=0,s="";t.objective==="truckTarget"?(n=Ro(e.stats,t.target),o=n>=t.targetAmount,r=o?t.reward:0):t.objective==="poopTrash"?(n=e.stats.poopTrash||0,o=n>=t.targetAmount,r=o?t.reward:0):t.objective==="noExplosion"?(n=e.stats.explosions||0,o=n===0,r=o?t.reward:0,s=`${n} explosion(s)`):t.objective==="flatBonus"?(o=!0,r=t.reward):t.objective==="maintenanceAudit"?(n=Gl(e),o=n===0,o&&(r=t.reward),s=`${n} machine(s) below 50%`):o=!0,r>0?(Oe(e,r),e.stats.eventBonus=(e.stats.eventBonus||0)+r,e.totals.eventBonus+=r,e.totals.eventSuccess+=1):t.objective&&t.objective!=="none"&&(e.stats.eventBonus=e.stats.eventBonus||0,e.totals.eventFailed+=o?0:1,o&&(e.totals.eventSuccess+=1));let l={title:t.title,key:t.key,target:t.target,route:t.route,objective:t.objective,targetAmount:t.targetAmount||0,count:n,success:o,bonus:r,reward:t.reward||0,productionMultiplier:t.productionMultiplier,poopMultiplier:t.poopMultiplier,daySeconds:t.daySeconds,detail:s};return e.stats.eventResult=l,l}function $o(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function Ul(e){return!!e?.cardEffects?.usedMachineActive}function Wl(e,t){return t?1:Math.min(.8,.5+.1*Math.min(3,$o(e,"recyclingSubsidy")))}function _l(e){return Math.pow(.95,$o(e,"safetyCover"))}function $n(e){let t=e?.ref||e||{},n=e?.type||t.type;return n==="conveyor"?t.price||Se[t.kind]?.price||Se.conveyor.price:n==="eggFarm"?t.price||Se.eggFarm.price:n==="scanner"?t.price||(t.kind==="auto"?Se.autoScanner.price:Se.manualScanner.price):n==="facility"?t.price||Se[t.id]?.price||0:Se[t.id]?.price||0}function Ne(e,t=null){let n=Se[e]?.price||0;return Ul(t)?Math.ceil(n*.5):n}function Kl(e,t){return e?.facilities?Object.values(e.facilities).filter(n=>(n?.baseId||n?.id)===t).reduce((n,o)=>n+Math.max(0,(o.level||1)-1),0):0}function ct(e,t){return gr.includes(t)?Math.pow(xe.incomeUpgradeRate,Kl(e,t)):1}function qe(e){return Math.ceil(xe.income.mixer*ct(e,"mixer"))}function De(e){return Math.ceil(xe.income.truck*ct(e,"truck"))}function ln(e){return Math.ceil(xe.poopFine*ct(e,"mixer")*Do(e))}function an(e){return Math.ceil(xe.poopFine*ct(e,"truck")*Do(e))}function Fo(e){let t=xe.maleTruckFinePerHalfDay*(e.turn/2);return Math.ceil(t*ct(e,"truck"))}function Bo(e){return e?.facilities?Object.values(e.facilities).filter(t=>(t?.baseId||t?.id)==="trash").reduce((t,n)=>t+Math.max(0,(n.level||1)-1),0):0}function At(e){return Math.min(xe.shredderBonus.maxCards,Bo(e))}function Kt(){return xe.shredderBonus.maxCards}function ut(e){let t=typeof e=="number"?e:At(e),n=Math.min(xe.shredderBonus.maxCards,Math.max(0,t));return n>0?Math.ceil(n*(xe.shredderBonus.incomePerUpgrade||1)):0}function Hl(e){let t=At(e),n=ut(t),o=Math.ceil(n*In(e));return{cards:t,chance:o>0?1:0,amount:o,expected:o,baseAmount:n}}function wi(e){let t=Hl(e);return t.amount>0&&(e.stats.shredderBonus=(e.stats.shredderBonus||0)+t.amount,e.totals.shredderBonus=(e.totals.shredderBonus||0)+t.amount,Oe(e,t.amount)),t}function Fn(e,t=e.turn,n=null){let o=Math.max(1,Math.floor(Number(t)||1)),r=xe.fairiesTribute||{perDay:10,profitExemption:300,legalWorkExemptionBonus:250,profitRate:.12},s=Math.ceil(o*(r.perDay||10)),l=Math.max(0,Math.floor(Number(n??e?.lastResult?.profit??e?.stats?.profit??0)||0)),d=Math.max(0,e?.cardEffects?.legalWork||0),v=Math.max(0,(r.profitExemption||0)+d*(r.legalWorkExemptionBonus||0)),C=Math.max(0,l-v),P=Math.ceil(C*Math.max(0,Number(r.profitRate)||0)),A=s+P,L=Math.max(0,e?.cardEffects?.fairiesFlatteryNext||e?.cardEffects?.flattery||0),V=L>0?Math.pow(.5,L):1,ne=Math.max(.01,Number(e?.pendingFairiesTributeMultiplier)||1),z=V*ne,se=Math.max(0,Math.ceil(A*z)),ye=Math.max(0,A-se);return{day:o,base:s,profit:l,legalWork:d,profitExemption:v,taxableProfit:C,profitTribute:P,gross:A,flatteryCount:L,eventMultiplier:ne,perCardReduction:Math.ceil(A*.5),reduction:ye,amount:se}}function Dt(e,t){let n=e?.ref||e||{},o=e?.type==="conveyor"?t?.conveyorMeta?.get(e.oldKey||n.id):n,r=o?.price||$n(e||n),s=o?.builtSession===t?.buildSession;if(o?.noRefund||n?.noRefund)return{amount:0,sameBuild:s,price:r,rate:0,noRefund:!0};let l=Wl(t,s);return{amount:Math.max(0,Math.ceil(r*l)),sameBuild:s,price:r,rate:l,noRefund:!1}}function ql(e,t=null){let n=Math.max(1,Math.ceil((Number(e)||0)/xe.explosionDamageDivisor));return Math.max(1,Math.ceil(n*_l(t)))}function Yl(e,t){return Math.max(0,Math.ceil(t))}function Si(e,t){e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,t>=0?(e.stats.revenue+=t,e.totals.revenue+=t):(e.stats.penalty+=Math.abs(t),e.totals.penalty+=Math.abs(t)),e.totals.maxCash=Math.max(e.totals.maxCash,e.cash)}function Oe(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&Si(e,n),n}function dt(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&Si(e,-n),n}function ft(e,t){dt(e,t)}function xi(e,t){t<=0||(e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,e.totals.maxCash=Math.max(e.totals.maxCash,e.cash))}function ki(e){let t=qe(e);return e.stats.mixerRevenue+=t,Oe(e,t),t}function Ci(e){let t=ln(e);return e.stats.mixerPoopFine+=t,e.totals.mixerPoopFine+=t,dt(e,t),t}function Mi(e){let t=an(e);return e.stats.truckPoopFine+=t,e.totals.truckPoopFine+=t,dt(e,t),t}function gi(e){let t=Fo(e);return e.stats.maleTruckFine+=t,e.totals.maleTruckFine+=t,dt(e,t),t}function Ti(e,t){let n=ql(t,e);return e.stats.explosionDamage+=n,e.totals.explosionDamage+=n,dt(e,n),n}function Ei(e){let t=Je(e),n=Ro(e.stats,t),o=t==="poop"?Math.ceil(De(e)*Ao(e)):De(e),r=n*o,s=Yl(e,r);return e.stats.pendingTruckRevenue=s,e.stats.truckRevenue=s,t==="poop"?e.stats.poopShipmentIncome=s:e.stats.chickShipmentIncome=s,s>0&&Oe(e,s),{base:r,adjusted:s,target:t,targetCount:n,unitPrice:o}}function Pi(e,t=e.turn,n=null,o={}){let r=Fn(e,t,n);return e.cardEffects&&(e.cardEffects.fairiesFlatteryNext=0,e.cardEffects.flattery!=null&&delete e.cardEffects.flattery),e.pendingFairiesTributeMultiplier!=null&&(e.pendingFairiesTributeMultiplier=1),r.amount<=0||(o.recordStats?(e.stats.fairiesTribute=(e.stats.fairiesTribute||0)+r.amount,e.totals.fairiesTribute=(e.totals.fairiesTribute||0)+r.amount,dt(e,r.amount)):(e.totals.fairiesTribute=(e.totals.fairiesTribute||0)+r.amount,e.totals.penalty=(e.totals.penalty||0)+r.amount,e.totals.profit=(e.totals.profit||0)-r.amount,e.cash-=r.amount)),r}function Ri(e){let t=$o(e,"chemicalWeaponSubsidy"),n=Math.max(0,e?.stats?.poopTruck||0),o=xe.chemicalWeaponSubsidy||{poopPerBlock:70,yenPerBlock:1200},r=Math.floor(n/Math.max(1,o.poopPerBlock||70)),s=t>0&&r>0?r*Math.max(0,o.yenPerBlock||1200)*t:0;return s>0&&(e.stats.chemicalWeaponSubsidy=(e.stats.chemicalWeaponSubsidy||0)+s,e.totals.chemicalWeaponSubsidy=(e.totals.chemicalWeaponSubsidy||0)+s,Oe(e,s)),{cards:t,poopTruck:n,blocks:r,amount:s}}function Ai(e){let t=Po(e),n=Math.max(1,e.totals.turnsCompleted||e.turn||1),o=Math.max(0,e.cash+e.totals.revenue+t*.5+e.totals.eventBonus*.5),r=Math.ceil(o/n),s=Math.floor(n*35+Math.max(0,n-5)*15),l=e.totals.correct*5,d=e.totals.explosionDamage;return{score:Math.max(0,Math.floor(o+r+l-e.totals.penalty-s)),factoryValue:t,base:o,dailyEarned:r,dayPenalty:s,correctBonus:l,explosionPenalty:d,days:n}}function Vl(e){return{...e,keys:e.keys?{left:{...e.keys.left},right:{...e.keys.right}}:null,queue:[],cooldown:e.cooldown||0}}function cn(e){return JSON.stringify({cash:e.cash,stats:e.stats,totals:e.totals,nextId:e.nextId,gridX:y.x,gridY:y.y,gridCols:e.gridCols||y.cols,gridRows:e.gridRows||y.rows,gridExpansionPurchases:e.gridExpansionPurchases||0,gridExpansionPurchasesByDirection:e.gridExpansionPurchasesByDirection||{right:0,up:0},gridChunkOriginY:e.gridChunkOriginY||0,ownedCells:[...e.ownedCells||[]],ownedChunks:[...e.ownedChunks||[]],blockedCells:[...e.blockedCells||[]],selected:e.selected,multiSelected:e.multiSelected||[],buildTool:e.buildTool,view:e.view,facilities:e.facilities,eggFarms:e.eggFarms,scanners:e.scanners.map(Vl),conveyorTiles:[...e.conveyorTiles],conveyorMeta:[...e.conveyorMeta.entries()],branchCounters:[...e.branchCounters.entries()],cardEffects:e.cardEffects,cardDraft:e.cardDraft,cardTargetPick:e.cardTargetPick})}function Di(e,t){let n=JSON.parse(t);e.cash=n.cash,e.stats=n.stats,e.totals=n.totals,e.nextId=n.nextId,y.x=n.gridX??q.grid.x,y.y=n.gridY??q.grid.y,y.cols=n.gridCols||q.grid.cols,y.rows=n.gridRows||q.grid.rows,e.gridCols=y.cols,e.gridRows=y.rows,e.gridExpansionPurchases=n.gridExpansionPurchases||0,e.gridExpansionPurchasesByDirection=n.gridExpansionPurchasesByDirection||{right:0,up:0},e.gridChunkOriginY=n.gridChunkOriginY||0,e.ownedCells=new Set(n.ownedCells||[]),e.ownedChunks=new Set(n.ownedChunks||[]),e.gridOwnedCells=e.ownedCells.size||y.cols*y.rows,e.blockedCells=new Set(n.blockedCells||[]),e.selected=n.selected,e.multiSelected=n.multiSelected||[],e.buildTool=n.buildTool,e.view=n.view||{x:0,y:0,scale:1},e.view.scale==null&&(e.view.scale=1),e.facilities=n.facilities||{},e.eggFarms=n.eggFarms||[],e.scanners=(n.scanners||[]).map(o=>({...o,queue:[],cooldown:o.cooldown||0})),e.conveyorTiles=new Set(n.conveyorTiles||[]),e.conveyorMeta=new Map(n.conveyorMeta||[]),e.branchCounters=new Map(n.branchCounters||[]),e.cardEffects=n.cardEffects||{bearing:0,legalWork:0,fairiesFlatteryNext:0,scannerQueueSpacing:0},e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft=n.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardTargetPick=n.cardTargetPick||null,e.groupDrag=null,e.selectionBox=null,e.pan=null,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function $e(e){e.phase==="build"&&(e.undoStack.push(cn(e)),e.undoStack.length>80&&e.undoStack.shift(),e.redoStack=[])}function Lo(e){return e.phase!=="build"||!e.undoStack.length?!1:(e.redoStack.push(cn(e)),Di(e,e.undoStack.pop()),!0)}function Oo(e){return e.phase!=="build"||!e.redoStack.length?!1:(e.undoStack.push(cn(e)),Di(e,e.redoStack.pop()),!0)}function _(e,t,n,o,r=f.ink){e.floatingTexts.push({x:t,y:n,text:o,color:r,life:1,maxLife:1})}function It(e,t,n){e.shake.strength=Math.max(e.shake.strength,t),e.shake.time=Math.max(e.shake.time,n)}function Ii(e,t,n){e.effects.push({type:"spawn",priority:ke.ambient,x:t,y:n,life:.42,maxLife:.42,size:12})}function $i(e,t,n,o=f.green){e.effects.push({type:"scannerPulse",priority:ke.important,x:t,y:n,color:o,life:.42,maxLife:.42,size:24})}function Fi(e,t,n){for(let o=0;o<12;o+=1)e.effects.push({type:"meat",priority:ke.important,x:t+U(-18,18),y:n+U(-12,16),vx:U(-60,60),vy:U(-90,-25),life:U(.45,.85),maxLife:.85,size:U(4,8)})}function Bi(e,t,n){for(let o=0;o<16;o+=1)e.effects.push({type:"sludge",priority:ke.important,x:t+U(-18,18),y:n+U(-12,16),vx:U(-46,46),vy:U(-70,-20),life:U(.45,.9),maxLife:.9,size:U(4,8)})}function Li(e,t,n,o){let r=o==="poop"?f.poop:o==="male"?f.male:f.female;for(let s=0;s<22;s+=1)e.effects.push({type:"shred",priority:ke.important,x:t+U(-16,16),y:n+U(-8,8),vx:U(-70,70),vy:U(40,160),color:s%3===0?f.white:r,life:U(.45,.95),maxLife:.95,w:U(3,7),h:U(10,24),rot:U(-Math.PI,Math.PI)});Ye(e,t,n,f.green,34,ke.important)}function Oi(e,t,n,o){let r=o==="poop"?f.poop:o==="male"?f.danger:f.green;for(let s=0;s<8;s+=1)e.effects.push({type:"load",priority:ke.important,x:t+U(-18,18),y:n+U(-18,18),vx:U(-42,42),vy:U(-90,-25),color:r,life:U(.35,.65),maxLife:.65,size:8})}function Ye(e,t,n,o=f.danger,r=52,s=ke.critical){e.effects.push({type:"shockwave",priority:s,x:t,y:n,color:o,life:.55,maxLife:.55,size:8,maxSize:r})}function je(e,t,n,o=12,r=f.danger,s=ke.critical){for(let l=0;l0&&(e.shake.time=Math.max(0,e.shake.time-t),e.shake.time<=0&&(e.shake.strength=0));for(let r of e.effects)if(r.life-=t,["meat","sludge","spark","smoke","shred","load","rage"].includes(r.type))r.x+=(r.vx||0)*t,r.y+=(r.vy||0)*t,r.vy=(r.vy||0)+150*t;else if(r.type==="flyingChick"){r.x+=r.vx*t,r.y+=r.vy*t,r.vy+=360*t,r.noDamage||zl(e,r,o);let s=r.x+e.view.x,l=r.y+e.view.y;(s<-100||l<-100||s>n.width+100||l>n.height+100)&&(r.life=0)}e.effects=e.effects.filter(r=>r.life>0);for(let r of e.floatingTexts)r.life-=t,r.y-=34*t;e.floatingTexts=e.floatingTexts.filter(r=>r.life>0)}function zl(e,t,n){t.hit||(t.hit=new Set);for(let o of n()){if(t.hit.has(o.id)||t.xo.x+o.w||t.yo.y+o.h)continue;t.hit.add(o.id);let r=Ti(e,o.price);_(e,t.x,t.y-10,`-${M(r)}`,f.danger),Ye(e,t.x,t.y,f.danger,30),je(e,t.x,t.y,5,f.danger),It(e,5,.18)}}var Fe=q.maintenance;function Go(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function Nn(e){let t=Math.min(1.4,1+.04*Math.min(10,Go(e,"crowdedFarming"))),n=Math.pow(.95,Go(e,"preventiveMaintenance"));return t*n}function Xl(e){return Math.pow(1.03,Go(e,"durabilityCoating"))}function Gn(e,t,n=1){let o=Fe.durability[t]||1e3;return Math.max(1,Math.ceil(o*Math.max(.1,n||1)*Xl(e)))}function _o(e){let t=Fe.repairman.dailyCost;return e?.cardEffects?.laborExploitation?Math.ceil(t*.7):t}function Ui(e){return Math.max(.1,Number(e?.durabilityBaseMultiplier)||1)}function me(e){e.repairman||(e.repairman={hiredForNextDay:!1,active:!1,x:y.x+y.cell*.5,y:y.y+y.rows*y.cell+84,target:null,repairedToday:0});for(let[t,n]of e.conveyorMeta||[]){n.uses==null&&(n.uses=0),n.maintenanceType==null&&(n.maintenanceType="conveyor"),n.kind||(n.kind="conveyor"),n.speedMultiplier||(n.speedMultiplier=n.kind==="boostConveyor"?2:1),n.branchMode||(n.branchMode="random");let o=Gn(e,"conveyor",Ui(n));(n.durability==null||n.durability0&&(n.processingCooldown=Math.max(0,n.processingCooldown-t))}function Hn(e){me(e);let t=[];for(let[n,o]of e.conveyorMeta||[])t.push({type:"conveyor",key:n,meta:o,label:`${o.kind==="boostConveyor"?"Boost Belt":"Belt"} ${n}`,center:F(Q(n).col,Q(n).row)});for(let n of e.eggFarms||[])t.push({type:"eggFarm",ref:n,label:`EGG #${n.id}`,center:F(n.col,n.row)});for(let n of(e.scanners||[]).filter(o=>o.kind==="auto"))t.push({type:"autoScanner",ref:n,label:`AUTO #${n.id}`,center:F(n.col,n.row)});for(let n of Object.values(e.facilities||{})){let o=Kn(n);["mixer","trash"].includes(o)&&t.push({type:o,ref:n,label:`${n.shortName||n.name||o} #${n.id}`,center:{x:n.x+n.w/2,y:n.y+n.h/2}})}return t}function Ln(e){return e.meta?Ht(e):Ht(e.ref)}function un(e){return e.meta?Uo(e):Uo(e.ref)}function On(e){return e.meta?Wo(e):Wo(e.ref)}function qi(e,t){Ql(e.meta?e:e.ref,Math.max(0,un(e)-t))}function Yi(e){return e.type==="conveyor"?`conveyor:${e.key}`:`${e.type}:${e.ref?.id||e.ref?.type||e.type}`}function Vi(e,t=.02){me(e);let n=Math.max(0,Number(t)||0),o=0;for(let r of Hn(e)){let s=un(r);qi(r,On(r)*n),o+=Math.max(0,s-un(r))/On(r)*100}return o}function zi(e){if(me(e),e.repairman.hiredForNextDay)return{ok:!1,reason:"Repairman already hired."};let t=_o(e);return e.cashYi(o)===t.key)||null}function Zl(e){let t=null;for(let n of Hn(e)){let o=Ln(n);o<=.001||(!t||o>Ln(t))&&(t=n)}return t}function Ji(e,t){me(e);let n=e.repairman;if(!n.active||e.phase!=="running")return;let o=jl(e,n.target)||Zl(e);if(!o){n.target=null;return}n.target={key:Yi(o),label:o.label};let r=Fe.repairman.walkSpeed,s=o.center.x-n.x,l=o.center.y-n.y,d=Math.hypot(s,l);if(d>8){let L=Math.min(d,r*t);n.x+=s/d*L,n.y+=l/d*L;return}let v=t/(Fe.repairman.secondsPerOnePercent*100),C=un(o),P=v*On(o);qi(o,P);let A=Math.max(0,(C-un(o))/On(o)*100);n.repairedToday=(n.repairedToday||0)+A,A>0&&Math.random()<.02&&_(e,n.x,n.y-28,"REPAIR",f.green),Ln(o)<=.001&&(n.target=null)}function ea(e){let t=0,n="none";for(let o of Hn(e)){let r=Ln(o);r>t&&(t=r,n=o.label)}return{ratio:t,percent:Math.round(t*100),label:n}}function Qo(e){let t=ea(e),n=Ho(e);return{worst:t,avgBeltPerformance:n,repairman:e.repairman||null}}var ta=Re.commonWeight,na=Re.rareWeight,oa=Re.ultraRareWeight||.45,$t=Re.baseDraftSize,Yt=Mr;function qt(e,t){let n=Ie(e);return Math.max(0,Number(n[t])||0)}function Ie(e){e.cardEffects||(e.cardEffects={...uo});for(let[t,n]of Object.entries(uo))e.cardEffects[t]==null&&(e.cardEffects[t]=Array.isArray(n)?[]:n);return e.cardEffects.flattery!=null&&(e.cardEffects.fairiesFlatteryNext=Math.max(0,e.cardEffects.fairiesFlatteryNext||0)+Math.max(0,e.cardEffects.flattery||0),delete e.cardEffects.flattery),e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft||(e.cardDraft={pending:!1,choices:[],rerolls:0,picksRemaining:0}),e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardEffects}function is(e){let t=Math.max(.5,1-.05*Math.min(10,qt(e,"crowdedFarming"))),n=Math.pow(.96,qt(e,"hatchingFeed"));return t*n}function ss(e,t=null){return Math.min(3,Math.max(0,Number(t?.extraEggOutlet)||0))}function ls(e){return Math.pow(.85,qt(e,"scannerQueueSpacing"))}function Yn(e,t=null){let n=Ie(e),o=xn*Math.pow(kn,Math.max(0,n.bearing||0)),r=t?Math.max(.1,Number(e?.conveyorMeta?.get?.(t)?.speedMultiplier)||1):1,s=t?1:Ho(e),l=Math.max(.01,Number(e?.eventActive?.conveyorSpeedMultiplier)||1);return Math.min(Gt,o*s)*r*l}function et(e,t=null){let n=Math.max(0,(e?.level||1)-1),o=t?qt(t,"autoScannerTuning"):0,r=Sn*Math.pow(kr,n)*Math.pow(so,o),s=Math.max(lo,r),l=t?Math.max(.01,Number(t?.eventActive?.autoScannerCooldownMultiplier)||1):1;return t?Math.max(lo,s*Wn(e)*l):s}function ji(e){let t=e.cardDraft||{rerolls:0},n=Math.max(1,(t.rerolls||0)+1);return Math.ceil(Math.max(1,e.turn||1)/Re.rerollCost.dayDivisor*n*Re.rerollCost.multiplier)}function Vt(e){return Yt.find(t=>t.id===e)||null}function as(e,t){let n=typeof t=="string"?Vt(t):t;return Ie(e),!n||!(n.type==="equipmentUpgrade"||n.type==="cellAction")?[]:Ue(e,n).map(o=>({key:Ze(o),label:Zo(e,o),type:o.type}))}function jo(e,t,n={}){let o=typeof t=="string"?Vt(t):t;if(Ie(e),!o||o.type==="dud")return{ok:!1,reason:"Card not found."};if(o.id==="extraCards")return e.cardDraft=e.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.choices.push(...qn(e,2)),{ok:!0,reason:`${o.title} added 2 draft cards.`};if(o.type==="instant")return us(e,o),{ok:!0,reason:`${o.title} granted.`};if(o.type==="equipmentUpgrade"){let r=Ue(e,o);if(!r.length)return{ok:!1,reason:`No valid target for ${o.title}.`};let s=n.targetKey&&n.targetKey!=="__auto__"?String(n.targetKey):"",l=s?r.find(d=>Ze(d)===s):r[0];return l?(cs(e,l),{ok:!0,reason:`${o.title} applied to ${Zo(e,l)}.`}):{ok:!1,reason:`Selected target is no longer valid for ${o.title}.`}}if(o.type==="cellAction"&&o.target==="blockedCell"){let r=Ue(e,o);if(!r.length)return{ok:!1,reason:"No blocked cells to remove."};let s=new Set((Array.isArray(n.targetKeys)?n.targetKeys:[n.targetKey]).filter(d=>d&&d!=="__auto__").map(String)),l=s.size?r.filter(d=>s.has(Ze(d))):r.slice(0,3);if(!l.length)return{ok:!1,reason:`Selected target is no longer valid for ${o.title}.`};for(let d of l.slice(0,3)){e.blockedCells.delete($(d.col,d.row));let v=F(d.col,d.row);pt(e,v.x,v.y),Ye(e,v.x,v.y,f.danger,42),je(e,v.x,v.y,8,f.warn)}return be(e),{ok:!0,reason:`${o.title} removed ${Math.min(3,l.length)} blocked cell(s).`}}return{ok:!1,reason:`${o.title} cannot be debug-granted.`}}function Zo(e,t){if(t.type==="blockedCell")return`Blocked cell ${t.col},${t.row}`;if(t.type==="eggFarm")return`EGG #${t.id} L${t.level} -> L${t.level+1}`;if(t.type==="eggOutlet"){let n=Math.max(0,Number(t.farm?.extraEggOutlet)||0);return`EGG #${t.id} OUTLET ${1+n} -> ${2+n}`}if(t.type==="scanner")return`AUTO #${t.id} L${t.level} -> L${t.level+1} | CD ${et(t,e).toFixed(1)}s -> ${et({...t,level:t.level+1},e).toFixed(1)}s`;if(t.type==="facility"&&(t.baseId||t.id)==="mixer"){let n=t.level,o=qe(e);t.level=n+1;let r=qe(e);return t.level=n,`MIXER L${t.level} -> L${t.level+1} | ${M(o)} -> ${M(r)}`}if(t.type==="facility"&&(t.baseId||t.id)==="truck"){let n=t.level,o=De(e);t.level=n+1;let r=De(e);return t.level=n,`TRUCK L${t.level} -> L${t.level+1} | ${M(o)} -> ${M(r)}`}if(t.type==="facility"&&t.id==="trash"){let n=At(e),o=Math.min(Kt(),n+1),r=ut(n),s=ut(o);return`SHREDDER L${t.level||1} -> L${(t.level||1)+1} | poop income ${M(r)} -> ${M(s)} per item`}return`${t.name||t.id} L${t.level||1} -> L${(t.level||1)+1}`}function ra(e){return[...e.blockedCells||[]].map(t=>{let[n,o]=String(t).split(",").map(Number);return{type:"blockedCell",id:t,col:n,row:o}}).filter(t=>Number.isFinite(t.col)&&Number.isFinite(t.row))}function Ue(e,t){let n=typeof t=="string"?Vt(t):t;return Ie(e),n?n.target==="blockedCell"?ra(e):n.target==="eggFarm"?e.eggFarms.filter(o=>(o.level||1)<4):n.target==="eggOutlet"?e.eggFarms.filter(o=>Math.max(0,Number(o.extraEggOutlet)||0)<3).map(o=>({type:"eggOutlet",id:o.id,col:o.col,row:o.row,farm:o})):n.target==="autoScanner"?e.scanners.filter(o=>o.kind==="auto"):n.target==="mixer"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="mixer"):n.target==="truck"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="truck"):n.target==="trash"?Bo(e)(o.baseId||o.id)==="trash"):[]:[]:[]}function ia(e,t){let n=Ie(e);if(t.id==="crowdedFarming")return(n.crowdedFarming||0)>=10;if(t.id==="recyclingSubsidy")return(n.recyclingSubsidy||0)>=3;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,Re.dudChancePerCard||0)),r=Math.max(1e-4,Math.min(1,Re.dudChanceReductionPerFilter||.05));return(n.dudFilter||0)>=Math.ceil(o/r)}return t.id==="laborExploitation"?!!n.laborExploitation:t.id==="usedMachine"?!!n.usedMachineActive:t.id==="newMachine"?!n.usedMachineActive:!1}function sa(e){let t=e.repairman||{};return!!(t.active||t.hiredForNextDay||e.pendingRepairWorkerWages>0)}function la(e){return Yt.filter(t=>!(t.id==="laborExploitation"&&!sa(e)||ia(e,t)||(t.type==="equipmentUpgrade"||t.type==="cellAction")&&Ue(e,t).length<=0))}function Zi(e,t){return t.rarity==="ultraRare"?oa:t.rarity==="rare"?na:ta}function aa(e,t){let n=t.reduce((r,s)=>r+Zi(e,s),0);if(n<=0)return t[Math.floor(Math.random()*t.length)];let o=Math.random()*n;for(let r of t)if(o-=Zi(e,r),o<=0)return r;return t[t.length-1]}var es=0;function ca(){return es+=1,{id:`dud:${Date.now()}:${es}`,title:"Dud",rarity:"dud",type:"dud",description:"Click to flick this dud away. It does not consume a pick."}}function ua(e){let t=Ie(e),n=Math.max(0,Math.min(1,Re.dudChancePerCard||0)),o=Math.max(0,Math.min(1,Re.dudChanceReductionPerFilter||0));return Math.max(0,n-o*Math.max(0,t.dudFilter||0))}function da(e,t){let n=[...t],o=0,r=Math.max(0,Re.maxDudsPerDraft||0),s=ua(e);for(let l=0;ld.id===s.id);l>=0&&r.splice(l,1)}return da(e,o)}function Ze(e){return e?e.type==="blockedCell"?`blockedCell:${e.id}`:e.type==="eggFarm"?`eggFarm:${e.id}`:e.type==="eggOutlet"?`eggOutlet:${e.id}`:e.type==="scanner"?`scanner:${e.id}`:e.type==="facility"?`facility:${e.id}`:`${e.type}:${e.id}`:""}function ts(e){if(!e)return null;if(e.type==="blockedCell"){let t=F(e.col,e.row);return{x:t.x-y.cell*.48,y:t.y-y.cell*.48,w:y.cell*.96,h:y.cell*.96,cx:t.x,cy:t.y}}if(e.type==="eggFarm"||e.type==="eggOutlet"){let t=F(e.col,e.row);return{x:t.x-34,y:t.y-34,w:68,h:68,cx:t.x,cy:t.y}}if(e.type==="scanner"){let t=pe(e);return{x:t.x-54,y:t.y-77,w:108,h:154,cx:t.x,cy:t.y}}return e.type==="facility"?{x:e.x,y:e.y,w:e.w,h:e.h,cx:e.x+e.w/2,cy:e.y+e.h/2}:null}function er(e){if(!e.cardTargetPick?.pending)return[];if(e.cardTargetPick.mode==="autoScannerMenu"){let n=new Set(e.cardTargetPick.targetKeys||[]);return e.scanners.filter(o=>o.kind==="auto"&&n.has(Ze(o))).map(o=>({key:Ze(o),label:"AUTO ROUTE SETTINGS",target:o,bounds:ts(o)})).filter(o=>o.bounds)}let t=new Set(e.cardTargetPick.targetKeys||[]);return Ue(e,e.cardTargetPick.cardId).filter(n=>t.has(Ze(n))).map(n=>({key:Ze(n),label:Zo(e,n),target:n,bounds:ts(n)})).filter(n=>n.bounds)}function fa(e,t){let n=er(e);for(let o of n){let r=o.bounds;if(t.x>=r.x&&t.x<=r.x+r.w&&t.y>=r.y&&t.y<=r.y+r.h)return o.target}return null}function cs(e,t){if(t.type==="eggOutlet"){let n=t.farm||e.eggFarms.find(r=>r.id===t.id);if(!n)return;n.extraEggOutlet=Math.min(3,Math.max(0,Number(n.extraEggOutlet)||0)+1);let o=F(n.col,n.row);_(e,o.x,o.y-30,`OUTLET ${1+n.extraEggOutlet}`,f.green),be(e);return}if(t.level=(t.level||1)+1,t.type==="eggFarm"){t.nextSpawn=Mt(t),t.lastInterval=t.nextSpawn;let n=F(t.col,t.row);_(e,n.x,n.y-30,`LV ${t.level}`,f.green);return}if(t.type==="scanner"){let n=pe(t);_(e,n.x,n.y-34,`LV ${t.level}`,f.green);return}t.type==="facility"&&_(e,t.x+t.w/2,t.y+18,`LV ${t.level}`,f.green)}function us(e,t){let n=Ie(e),o=r=>{n[r]=Math.max(0,n[r]||0)+1};if(t.id==="bearing"&&o("bearing"),t.id==="autoScannerTuning"&&o("autoScannerTuning"),t.id==="legalWork"&&o("legalWork"),t.id==="crowdedFarming"&&(n.crowdedFarming=Math.min(10,(n.crowdedFarming||0)+1)),t.id==="hatchingFeed"&&o("hatchingFeed"),t.id==="poopRateBooster"&&o("poopRateBooster"),t.id==="safetyCover"&&o("safetyCover"),t.id==="recyclingSubsidy"&&(n.recyclingSubsidy=Math.min(3,(n.recyclingSubsidy||0)+1)),t.id==="chemicalWeaponSubsidy"&&o("chemicalWeaponSubsidy"),t.id==="preventiveMaintenance"&&o("preventiveMaintenance"),t.id==="dudFilter"&&o("dudFilter"),t.id==="durabilityCoating"&&(o("durabilityCoating"),me(e)),t.id==="sparePartsBin"){o("sparePartsBin");let r=Vi(e,.02);e.stats.sparePartsRepair=(e.stats.sparePartsRepair||0)+r,e.totals.sparePartsRepair=(e.totals.sparePartsRepair||0)+r,_(e,y.x+y.cols*y.cell/2,y.y-30,"REPAIR +2%",f.green)}t.id==="dudRefund"&&o("dudRefund"),t.id==="freeReroll"&&o("freeReroll"),t.id==="composter"&&o("composter"),t.id==="scannerQueueSpacing"&&o("scannerQueueSpacing"),t.id==="flattery"&&o("fairiesFlatteryNext"),t.id==="usedMachine"&&(n.usedMachineActive=!0),t.id==="newMachine"&&(n.usedMachineActive=!1),t.id==="laborExploitation"&&(n.laborExploitation=1),t.id==="rescueLoan"&&(o("rescueLoanCharges"),_(e,y.x+y.cols*y.cell/2,y.y-30,"RESCUE HELD",f.green))}function _e(e){return`${Math.round(Number(e||0)*100)}%`}function ns(e){let t=st[Math.max(0,Math.min(st.length-1,e-1))]||st[0]||[0,0];return`${t[0].toFixed(2)}-${t[1].toFixed(2)}s`}function os(e,t){return Math.ceil(e*Math.pow(xe.incomeUpgradeRate,Math.max(0,t-1)))}function rs(e,t,n){let r=Ue(e,t==="mixer"?"upgradeMixer":"upgradeTruck")[0];if(!r)return{before:os(n,1),after:os(n,2)};let s=t==="mixer"?qe(e):De(e),l=r.level||1;r.level=l+1;let d=t==="mixer"?qe(e):De(e);return r.level=l,{before:s,after:d}}function pa(e,t){let n=Ie(e);if(t.id==="upgradeEgg"){let o=Ue(e,t),r=Math.min(3,Math.max(1,o[0]?.level||1));return`Choose one EGG. Level +1. Production interval ${ns(r)} -> ${ns(r+1)}.`}if(t.id==="upgradeAutoScanner"){let o=Ue(e,t)[0]||{level:1},r=et(o,e),s=et({...o,level:(o.level||1)+1},e);return`Choose one AUTO SCANNER. Level +1. Cooldown ${r.toFixed(2)}s -> ${s.toFixed(2)}s.`}if(t.id==="upgradeMixer"){let o=rs(e,"mixer",xe.income.mixer);return`Choose one MIXER. Earning +10%. Male-chick income ${M(o.before)} -> ${M(o.after)}.`}if(t.id==="upgradeTruck"){let o=rs(e,"truck",xe.income.truck);return`Choose one TRUCK. Earning +10%. Correct shipment income ${M(o.before)} -> ${M(o.after)}.`}if(t.id==="upgradeTrash"){let o=At(e),r=Math.min(Kt(),o+1),s=ut(o),l=ut(r);return`SHREDDER level +1. Poop income ${M(s)} -> ${M(l)} per item.`}if(t.id==="bearing"){let o=Math.min(Gt,xn*Math.pow(kn,Math.max(0,n.bearing||0))),r=Math.min(Gt,xn*Math.pow(kn,Math.max(0,(n.bearing||0)+1)));return`Conveyor speed +7.5%. After pick: ${o.toFixed(1)} -> ${r.toFixed(1)} px/s.`}if(t.id==="legalWork"){let o=Math.max(0,n.legalWork||0);return`Fairies tribute profit exemption +${M(250)}. After pick: exemption bonus ${M(250*(o+1))}.`}if(t.id==="crowdedFarming"){let o=Math.min(10,(n.crowdedFarming||0)+1);return`Held ${n.crowdedFarming||0}/10. After pick: EGG interval ${_e(Math.max(.5,1-.05*o))}, deterioration ${_e(Math.min(1.4,1+.04*o))}.`}if(t.id==="extraEggOutlet"){let o=Ue(e,t),r=Math.max(0,Number(o[0]?.farm?.extraEggOutlet)||0);return`Choose one EGG. Output ports ${1+r} -> ${2+r}. Max 4 ports per EGG.`}if(t.id==="hatchingFeed")return`Held ${n.hatchingFeed||0}. After pick: EGG interval ${_e(Math.pow(.96,(n.hatchingFeed||0)+1))}, poop rate multiplier ${_e(Math.pow(1.03,(n.hatchingFeed||0)+1))}.`;if(t.id==="poopRateBooster")return`Held ${n.poopRateBooster||0}. After pick: base poop rate +${Math.round((n.poopRateBooster||0)+1)*4} percentage points.`;if(t.id==="autoScannerTuning")return`Held ${n.autoScannerTuning||0}. After pick: all AUTO SCANNER default cooldown ${_e(Math.pow(so,(n.autoScannerTuning||0)+1))}.`;if(t.id==="safetyCover")return`Held ${n.safetyCover||0}. After pick: explosion damage ${_e(Math.pow(.95,(n.safetyCover||0)+1))}.`;if(t.id==="recyclingSubsidy")return`Held ${n.recyclingSubsidy||0}/3. After pick: normal SELL refund ${Math.round(Math.min(.8,.5+.1*((n.recyclingSubsidy||0)+1))*100)}%.`;if(t.id==="chemicalWeaponSubsidy")return`Held ${n.chemicalWeaponSubsidy||0}. After pick: ${M(1200*((n.chemicalWeaponSubsidy||0)+1))} per 70 truck-shipped poop each day.`;if(t.id==="preventiveMaintenance")return`Held ${n.preventiveMaintenance||0}. After pick: deterioration speed ${_e(Math.pow(.95,(n.preventiveMaintenance||0)+1))}.`;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,Re.dudChancePerCard||0)),r=Math.max(0,Math.min(1,Re.dudChanceReductionPerFilter||.05)),s=Math.max(0,n.dudFilter||0),l=Math.max(0,o-r*s),d=Math.max(0,o-r*(s+1));return`Held ${s}. DUD chance per card ${_e(l)} -> ${_e(d)}.`}return t.id==="durabilityCoating"?`Held ${n.durabilityCoating||0}. After pick: maximum durability ${_e(Math.pow(1.03,(n.durabilityCoating||0)+1))}.`:t.id==="sparePartsBin"?`Held ${n.sparePartsBin||0}. Immediately restores 2% durability to every maintained machine. Common card weight.`:t.id==="dudRefund"?`Held ${n.dudRefund||0}. After pick: DUD clicks award ${M(50*((n.dudRefund||0)+1))}.`:t.id==="freeReroll"?`Held ${n.freeReroll||0}. After pick: each card screen starts with ${(n.freeReroll||0)+1} free reroll${(n.freeReroll||0)+1===1?"":"s"}.`:t.id==="composter"?`Held ${n.composter||0}. After pick: SHREDDER poop grants ${M(3*((n.composter||0)+1))}.`:t.id==="scannerQueueSpacing"?`Held ${n.scannerQueueSpacing||0}. After pick: Manual/Auto Scanner queue spacing ${_e(Math.pow(.85,(n.scannerQueueSpacing||0)+1))}.`:t.id==="flattery"?`Next Fairies tribute -50%. Held for next tribute: ${n.fairiesFlatteryNext||0}.`:t.id==="usedMachine"?"Enable Used Machines: future equipment costs 50%, has no SELL refund, and starts with 60% durability.":t.id==="newMachine"?"Cancel Used Machines. Future equipment returns to normal price, refund, and durability.":t.id==="laborExploitation"?"Repairman labor cost -30% permanently. One time only.":t.id==="rescueLoan"?`At day-end bankruptcy check, gain ${M(500)} if cash is below ${M(0)}. Held: ${n.rescueLoanCharges||0}.`:t.description}function Jo(e,t){let n=e.cardDraft?.choices||[],o=n.findIndex(r=>r.id===t.id);o>=0&&n.splice(o,1)}function ds({game:e,ui:t,onUpdatePanels:n}){function o(){n&&n()}function r(){Ie(e),e.cardTargetPick=null,e.cardDraft={pending:!0,choices:qn(e,$t),rerolls:0,freeRerolls:qt(e,"freeReroll"),picksRemaining:1}}function s(){Ie(e),e.cardDraft.pending=!1,e.cardDraft.choices=[],e.cardDraft.picksRemaining=0,e.cardTargetPick=null,t.modal.classList.remove("visible","equipment-popover"),o()}function l(I=$t){Ie(e),e.cardDraft.choices=qn(e,I)}function d(){Ie(e),!e.cardDraft.choices.length&&e.cardDraft.picksRemaining>0&&l($t)}function v(I){Jo(e,I),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1),e.cardTargetPick=null,d(),e.cardDraft.picksRemaining<=0?s():Z()}function C(I){Jo(e,I),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1)+Re.extraCardsAddedPicks,e.cardDraft.choices.push(...qn(e,2)),Z()}function P(I,W){let N=qt(e,"dudRefund")*50;if(N>0){let le=Oe(e,N);e.stats.dudRefundIncome=(e.stats.dudRefundIncome||0)+le,e.totals.dudRefundIncome=(e.totals.dudRefundIncome||0)+le,_(e,y.x+y.cols*y.cell/2,y.y-30,`DUD REFUND +${M(le)}`,f.green)}It(e,34,.62),document.body?.animate&&document.body.animate([{transform:"translate(0, 0)"},{transform:"translate(-10px, 7px)"},{transform:"translate(12px, -8px)"},{transform:"translate(-8px, -5px)"},{transform:"translate(9px, 6px)"},{transform:"translate(0, 0)"}],{duration:260,easing:"steps(5, end)"}),W&&(W.style.setProperty("--fling-x",`${260+Math.random()*260}px`),W.style.setProperty("--fling-y",`${-260-Math.random()*170}px`),W.style.setProperty("--fling-r",`${(Math.random()<.5?-1:1)*(52+Math.random()*38)}deg`),W.classList.add("flung")),window.setTimeout(()=>{Jo(e,I),d(),Z()},340)}function A(I,W=null){if(I.type==="dud")return P(I,W);if(I.id==="extraCards")return C(I);if(I.type==="equipmentUpgrade"||I.type==="cellAction")return L(I);us(e,I),v(I)}function L(I){let W=Ue(e,I);W.length&&(e.cardTargetPick={pending:!0,cardId:I.id,mode:I.target==="blockedCell"?"blockedCell":"equipment",targetKeys:W.map(Ze),remaining:I.id==="dynamite"?Math.min(3,W.length):1},t.modal.classList.remove("visible","equipment-popover"),o())}function V(I){if(!I||I.type!=="blockedCell")return!1;let W=$(I.col,I.row);if(!e.blockedCells?.has(W))return!1;e.blockedCells.delete(W);let N=F(I.col,I.row);return pt(e,N.x,N.y),Ye(e,N.x,N.y,f.danger,62),je(e,N.x,N.y,18,f.warn),Bn(e,N.x,N.y,8),It(e,16,.35),_(e,N.x,N.y-18,"BOOM",f.danger),be(e),e.cardTargetPick.remaining=Math.max(0,(e.cardTargetPick.remaining||1)-1),e.cardTargetPick.targetKeys=Ue(e,"dynamite").map(Ze),o(),!0}function ne(I){if(!e.cardTargetPick?.pending)return!1;let W=Vt(e.cardTargetPick.cardId),N=fa(e,I);return!W||!N?(z(),!0):W.id==="dynamite"?(V(N)&&((e.cardTargetPick.remaining||0)<=0||!Ue(e,"dynamite").length)&&v(W),!0):(cs(e,N),v(W),!0)}function z(){e.cardTargetPick?.pending&&(e.cardTargetPick=null,Z())}function se(){let I=Math.max(0,e.cardDraft?.freeRerolls||0);if(I>0){e.cardDraft.freeRerolls=I-1,e.cardDraft.rerolls+=1,l($t),Z();return}let W=ji(e);e.cashR!==we)].slice(0,5);return N.innerHTML=`${I.title}
${he.map(R=>`${R}`).join("")}
${pa(e,I)}`,N.addEventListener("click",()=>A(I,N)),N.dataset.index=String(W),N}function Z(){Ie(e),e.cardTargetPick=null,e.cardDraft?.pending||r(),e.cardDraft.choices?.length||l($t);let I=e.cardDraft.choices||[],W=ji(e),N=Math.max(0,e.cardDraft?.freeRerolls||0),le=Math.max(1,e.cardDraft.picksRemaining||1);t.modalTitle.textContent="Choose Upgrade Card",t.modalBody.innerHTML=`

Choose ${le} card${le===1?"":"s"} before Build phase. Dud cards can be flicked away without consuming a pick. Equipment cards target machines; Dynamite targets blocked cells.

`;let we=t.modalBody.querySelector("#cardChoices");I.forEach((G,x)=>we.appendChild(ye(G,x))),t.modalActions.innerHTML="";let he=document.createElement("button");he.type="button",he.className="facility-action warn reroll-button",he.textContent=N>0?`Reroll (FREE x${N})`:`Reroll ${M(W)}`,he.disabled=N<=0&&e.cash0?`${N} free reroll${N===1?"":"s"} remaining.`:he.disabled?"Not enough cash":"",he.addEventListener("click",se),t.modalActions.appendChild(he);let R=document.createElement("button");R.type="button",R.className="facility-action",R.textContent="No Card",R.title="Skip this upgrade pick and enter Build phase.",R.addEventListener("click",s),t.modalActions.appendChild(R),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible")}return{prepareDraft:r,showDraft:Z,finishDraft:s,chooseTargetAtPoint:ne,cancelTargetPick:z}}var ya=!1,ha={chickMale:"./assets/images/chick_male.png",chickFemale:"./assets/images/chick_female.png",poop:new URL("../../assets/images/poop.png",import.meta.url).href,conveyor:"./assets/images/conveyor.png",scannerManual:"./assets/images/scanner_manual.png",scannerAuto:"./assets/images/scanner_auto.png",eggFarm:"./assets/images/egg_farm.png",mixer:"./assets/images/mixer.png",shredder:"./assets/images/shredder.png",truck:"./assets/images/truck.png"},ze={};for(let[e,t]of Object.entries(ha)){let n=new Image;n.loaded=!1,n.onerror=()=>{n.loaded=!1},(ya||e==="poop")&&t&&(n.onload=()=>{n.loaded=!0},n.src=t),ze[e]=n}function ys(e,t,n,o){e.clearRect(0,0,t.width,t.height),va(e,t),e.save();let r=n.shake.time>0?U(-n.shake.strength,n.shake.strength):0,s=n.shake.time>0?U(-n.shake.strength,n.shake.strength):0,l=n.view?.scale||1;e.translate((n.view?.x||0)+r,(n.view?.y||0)+s),e.scale(l,l),Sa(e,n),xa(e,n),ka(e,n),Aa(e,n),Oa(e,n),Da(e,n),$a(e,n),ba(e,n),Wa(e,n,o.activeQueuedChick),Qa(e,n),Ya(e,t,n),qa(e,n,o.selectedObject,o.selectedTitle),Va(e,n),za(e,n),Xa(e,n),e.restore(),Ja(e,n,t)}function ma(e){if(e.type==="eggFarm"){let n=F(e.ref.col,e.ref.row);return{x:n.x-34,y:n.y-34,w:68,h:68,cx:n.x,cy:n.y}}let t=e.ref;return{x:t.x,y:t.y,w:t.w,h:t.h,cx:t.x+t.w/2,cy:t.y+t.h/2}}function ba(e,t){if(t.phase!=="build")return;let n=Dn(t);for(let o of n){let r=ma(o);e.save(),e.fillStyle="rgba(196,36,36,.22)",e.strokeStyle=f.danger,e.lineWidth=5,e.setLineDash([10,6]),te(e,r.x,r.y,r.w,r.h,!0,!0),e.setLineDash([]),e.fillStyle=f.danger,e.strokeStyle=f.white,e.lineWidth=4,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.strokeText("!",r.cx,r.y+24),e.fillText("!",r.cx,r.y+24),e.font="900 11px ui-monospace, monospace",e.strokeText("NO ROUTE",r.cx,r.y+r.h-8),e.fillText("NO ROUTE",r.cx,r.y+r.h-8),e.restore()}}function te(e,t,n,o,r,s=!0,l=!0){e.beginPath(),e.rect(t,n,o,r),s&&e.fill(),l&&e.stroke()}function nr(e,t,n,o,r=f.ink){e.save(),e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.lineWidth=4,e.strokeStyle=f.white,e.fillStyle=r,e.strokeText(o,t,n),e.fillText(o,t,n),e.restore()}function Ft(e,t,n,o,r,s){return t?.loaded?(e.drawImage(t,n,o,r,s),!0):!1}function va(e,t){e.fillStyle=f.bg,e.fillRect(0,0,t.width,t.height),e.save(),e.strokeStyle="rgba(16, 32, 21, 0.035)",e.lineWidth=1;for(let n=0;n=n;for(let r of kt(t)){let s=Ct(r);e.save(),e.fillStyle=o?"rgba(183,245,198,.34)":"rgba(255,255,255,.22)",e.strokeStyle=o?f.green:f.muted,e.lineWidth=5,e.setLineDash([16,10]),te(e,s.x,s.y,s.w,s.h,!0,!0),e.setLineDash([]);let l=mo(r),d=l.cx,v=l.cy;e.fillStyle="rgba(255,255,255,.94)",e.strokeStyle=f.ink,e.lineWidth=4,te(e,l.x,l.y,l.w,l.h,!0,!0),e.fillStyle=o?f.green:f.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText(r.direction==="right"?"BUY RIGHT LOT":"BUY UPPER LOT",d,v-12),e.fillStyle=f.ink,e.font="900 16px ui-monospace, monospace",e.fillText(`${M(n)} / 10\xD710`,d,v+15),e.fillStyle=f.muted,e.font="900 11px ui-monospace, monospace",e.fillText("blocked tiles included",d,v+30),e.restore()}}function tt(e,t,n,o,r,s,l=0){let d=Ht(s);d<.5||(e.save(),e.globalAlpha=Math.min(.62,.12+d*.54),e.fillStyle="#6b4a23",l>0?(e.beginPath(),e.roundRect?.(t,n,o,r,l),e.roundRect?e.fill():te(e,t,n,o,r,!0,!1)):te(e,t,n,o,r,!0,!1),e.globalAlpha=Math.min(.9,.25+d*.6),e.strokeStyle="#3a2a16",e.lineWidth=Math.max(2,Math.floor(2+d*5)),e.setLineDash([5,6]),te(e,t+3,n+3,o-6,r-6,!1,!0),e.restore())}function tr(e,t){let n=e.componentLookup?.get(t);return(n?e.congestion.get(n):null)?.ratio||0}function ka(e,t){let n=[],o=new Set;for(let s of t.conveyorTiles){let{col:l,row:d}=Q(s);for(let v of ue){let C={col:l+v.dc,row:d+v.dr},P=$(C.col,C.row);if(!t.conveyorTiles.has(P))continue;let A=[s,P].sort().join("|");if(o.has(A))continue;o.add(A);let L=Math.max(tr(t,s),tr(t,P));n.push({a:F(l,d),b:F(C.col,C.row),ratio:L})}}e.save(),e.lineCap="round",e.lineJoin="round";for(let s of[{width:33,color:f.ink,alpha:1},{width:25,color:f.white,alpha:1},{width:17,color:f.greenSoft,alpha:1}]){e.globalAlpha=s.alpha,e.strokeStyle=s.color,e.lineWidth=s.width;for(let l of n)e.beginPath(),e.moveTo(l.a.x,l.a.y),e.lineTo(l.b.x,l.b.y),e.stroke()}for(let s of n){let l=Math.max(0,(s.ratio-.5)/.5);e.strokeStyle=yo(f.green,f.danger,l),e.globalAlpha=s.ratio>.5?.35+l*.55:.8,e.lineWidth=6,e.beginPath(),e.moveTo(s.a.x,s.a.y),e.lineTo(s.b.x,s.b.y),e.stroke()}let r=Pa(t);for(let s of t.conveyorTiles){let l=F(...Object.values(Q(s))),d=t.conveyorMeta.get(s)||{},v=tr(t,s),C=d.kind==="boostConveyor"?"#fff2b8":f.white;e.fillStyle=v>.5?yo(C,"#ffd6d6",Math.max(0,(v-.5)/.5)):C,e.strokeStyle=f.ink,e.lineWidth=2,te(e,l.x-8,l.y-8,16,16,!0,!0),d.kind==="boostConveyor"&&(e.save(),e.strokeStyle=f.warn,e.lineWidth=3,e.beginPath(),e.moveTo(l.x-15,l.y+13),e.lineTo(l.x-3,l.y-13),e.lineTo(l.x+2,l.y-2),e.lineTo(l.x+15,l.y-13),e.stroke(),e.restore()),tt(e,l.x-14,l.y-14,28,28,{meta:d}),Ke(e,t,"conveyor",s,l.x,l.y,38,38),Ra(e,l,r.get(s)||[]);let P=rr(t,s);Ta(e,l,d,Ma(t,s,P),P),v>.5&&nr(e,l.x,l.y-15,`${Math.floor(v*100)}%`,f.danger)}e.restore()}function rr(e,t){let n=Q(t);return ue.filter(o=>e.conveyorTiles.has($(n.col+o.dc,n.row+o.dr))).map(o=>o.name)}function hs(e,t,n){let o=ue.find(l=>l.name===n);if(!o)return!1;let r=e.conveyorMeta?.get?.($(t.col+o.dc,t.row+o.dr));return r?[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))].includes(o.opposite):!1}function Ca(e,t,n,o=rr(e,t),r="random"){if(o.length<3)return n;let s=Q(t),l=new Set(o.filter(C=>hs(e,s,C)));if(r&&r!=="random"&&o.includes(r)){let C=new Set(l);C.add(r),o.filter(P=>!C.has(P)).length>=2&&l.add(r)}let d=o.filter(C=>!l.has(C));if(d.length)return d;let v=n.filter(C=>!l.has(C));return v.length?v:n}function Ma(e,t,n=rr(e,t)){if(n.length<3)return[];let o=Q(t),r=new Set(n.filter(s=>hs(e,o,s)));return n.filter(s=>{let l=new Set(r);return l.add(s),n.filter(d=>!l.has(d)).length>=2})}function ga(e,t,n){let o=Q(t),r=ue.filter(d=>e.conveyorTiles.has($(o.col+d.dc,o.row+d.dr))).map(d=>d.name),s=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(d=>r.includes(d)),l=r;return s.length?s:l}function Ta(e,t,n,o,r=o){if(r.length<3||o.length<2)return;e.save();let s=o.includes(n.branchMode)?n.branchMode:"random",l=s!=="random";if(e.lineJoin="round",e.lineCap="round",e.lineWidth=2,e.fillStyle="rgba(255,255,255,.9)",e.strokeStyle=l?f.warn:f.green,te(e,t.x-17,t.y-17,34,34,!0,!0),e.strokeStyle=f.ink,e.lineWidth=2,e.fillStyle=f.ink,s!=="random"){let d=ue.find(v=>v.name===s);Vn(e,t.x,t.y,d?.angle||0,9,6)}else e.beginPath(),e.moveTo(t.x-10,t.y),e.lineTo(t.x-2,t.y),e.lineTo(t.x+8,t.y-8),e.moveTo(t.x-2,t.y),e.lineTo(t.x+8,t.y+8),e.stroke(),Vn(e,t.x+9,t.y-9,-Math.PI/4,4,3),Vn(e,t.x+9,t.y+9,Math.PI/4,4,3);e.restore()}function Ea(e,t,n){if(!n)return[];let o=Q(t),r=ue.filter(d=>e.conveyorTiles.has($(o.col+d.dc,o.row+d.dr))).map(d=>d.name),s=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(d=>r.includes(d));return Ca(e,t,s.length?s:ga(e,t,n),r,n.branchMode||"random").map(d=>ue.find(v=>v.name===d)).filter(Boolean)}function Pa(e){let t=new Map;for(let[n,o]of e.conveyorMeta||[]){let r=Ea(e,n,o);r.length&&t.set(n,r)}return t}function Ra(e,t,n){let o=n.slice(0,4);o.length&&(e.save(),e.fillStyle=f.ink,e.globalAlpha=.86,o.forEach(r=>{Vn(e,t.x+r.dc*12,t.y+r.dr*12,r.angle,6,5)}),e.restore())}function Vn(e,t,n,o,r=11,s=8){e.save(),e.translate(t,n),e.rotate(o),e.beginPath(),e.moveTo(r,0),e.lineTo(-r*.72,-s),e.lineTo(-r*.72,s),e.closePath(),e.fill(),e.restore()}function Aa(e,t){e.save(),e.lineWidth=2,e.font="900 12px ui-monospace, monospace",e.textAlign="center";for(let n of t.scanners){let o=Mo(n),r=[{type:"inputA",p:Ee(n,"inputA"),label:"IN",color:f.green},{type:"left",p:Ee(n,"left"),label:To(o.left),color:Eo(o.left)},{type:"right",p:Ee(n,"right"),label:To(o.right),color:Eo(o.right)}];for(let s of r){if(!s.p)continue;let l=F(s.p.col,s.p.row),d=jr(t,n,s.type||(s.label==="IN"?"inputA":null))||t.conveyorTiles.has($(s.p.col,s.p.row));e.fillStyle=d?s.color:"#f4c2c2",e.strokeStyle=f.ink,te(e,l.x-18,l.y-12,36,24,!0,!0),e.fillStyle=d&&s.color===f.white?f.ink:f.white,e.fillText(s.label,l.x,l.y+4)}}e.restore()}function Da(e,t){for(let n of t.eggFarms)Ia(e,n,t)}function Ia(e,t,n){let o=F(t.col,t.row);if(e.save(),Ft(e,ze.eggFarm,o.x-29,o.y-29,58,58)){tt(e,o.x-29,o.y-29,58,58,t);let l=1+Math.max(0,Number(t.extraEggOutlet)||0);e.fillStyle="rgba(255,255,255,.92)",e.strokeStyle=f.ink,e.lineWidth=2,te(e,o.x+9,o.y+12,30,18,!0,!0),e.fillStyle=f.ink,e.font="900 10px ui-monospace, monospace",e.textAlign="center",e.fillText(`O${l}`,o.x+24,o.y+24),Ke(e,n,"eggFarm",t.id,o.x,o.y,68,68),e.restore();return}e.fillStyle=f.white,e.strokeStyle=f.ink,e.lineWidth=4,te(e,o.x-28,o.y-28,56,56,!0,!0),e.fillStyle=f.green,e.font="900 19px ui-monospace, monospace",e.textAlign="center",e.fillText("EGG",o.x,o.y-4);let r=1+Math.max(0,Number(t.extraEggOutlet)||0);e.font="900 11px ui-monospace, monospace",e.fillStyle=f.ink,e.fillText(`L${t.level} O${r}`,o.x,o.y+13),e.fillText(`${t.nextSpawn.toFixed(1)}s`,o.x,o.y+26);let s=Math.max(0,Math.min(1,t.shutterProgress||0));if(s>0){let l=56*s;e.fillStyle=f.ink,te(e,o.x-28,o.y-28,56,l,!0,!1),e.strokeStyle=f.white,e.lineWidth=2;for(let d=o.y-24;d=1&&(e.fillStyle=f.white,e.font="900 12px ui-monospace, monospace",e.fillText("SHUT",o.x,o.y+4))}tt(e,o.x-28,o.y-28,56,56,t),Ke(e,n,"eggFarm",t.id,o.x,o.y,68,68),e.restore()}function $a(e,t){for(let n of t.scanners)Fa(e,n,t)}function Fa(e,t,n){let o=pe(t);if(e.save(),t.kind==="manual"&&(n.manualCombo?.count||0)>=10){let v=n.manualCombo.count;e.save(),e.globalAlpha=Math.min(.55,.16+v/120),e.strokeStyle=v>=30?f.warn:f.green,e.lineWidth=Math.min(14,5+Math.floor(v/10)),e.shadowColor=e.strokeStyle,e.shadowBlur=Math.min(28,8+v),te(e,o.x-54,o.y-76,108,152,!1,!0),e.restore()}let r=t.kind==="auto"?ze.scannerAuto:ze.scannerManual;if(Ft(e,r,o.x-50,o.y-73,100,146)){t.kind==="auto"?tt(e,o.x-50,o.y-73,100,146,t):fs(e,t,o),Ke(e,n,"scanner",t.id,o.x,o.y,108,154),e.restore();return}e.fillStyle=t.kind==="auto"?"#d8ffe2":f.white,e.strokeStyle=f.ink,e.lineWidth=4,te(e,o.x-50,o.y-73,100,146,!0,!0),e.fillStyle=t.kind==="auto"?f.green:f.ink,e.font="900 19px ui-monospace, monospace",e.textAlign="center",e.fillText(`${t.kind==="auto"?"AUTO":`S${(t.slot??0)+1}`}`,o.x,o.y-48),e.font="900 11px ui-monospace, monospace";let s=t.keys?.left?.label||(t.slot===0?"A":"Left"),l=t.keys?.right?.label||(t.slot===0?"D":"Right");e.fillText(t.role===0?`${s}:M ${l}:NEXT`:`${s}:WASTE ${l}:TRUCK`,o.x,o.y-28);let d=t.queue.length;t.kind==="manual"?(fs(e,t,o),e.fillStyle=d>0?f.green:f.muted,e.font="900 10px ui-monospace, monospace",e.fillText(`Q:${d}`,o.x,o.y+54)):(e.fillStyle=d>0?f.green:f.muted,e.font="900 12px ui-monospace, monospace",e.fillText(`Q:${d} CD:${t.cooldown.toFixed(1)}`,o.x,o.y+54),tt(e,o.x-50,o.y-73,100,146,t)),Ke(e,n,"scanner",t.id,o.x,o.y,108,154),e.restore()}function fs(e,t,n){if(t.kind!=="manual")return;let r=(t.slot??0)===0?[{side:"left",text:"A"},{side:"right",text:"D"}]:[{side:"left",text:"\u2190"},{side:"right",text:"\u2192"}];r[0].text=t.keys?.left?.label||r[0].text,r[1].text=t.keys?.right?.label||r[1].text;let s=t.keyPressTime>0?t.keyPressSide:null,l=n.x-30,d=n.y+18;e.save(),e.lineWidth=3,e.fillStyle="#f7fff5",e.strokeStyle=f.ink,te(e,l-4,d-4,68,25,!0,!0),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let v=0;v.8,s=t.y+Math.sin(t.bob)*(r?5:1.5);if(e.save(),n&&(e.strokeStyle=f.green,e.lineWidth=5,e.beginPath(),e.arc(t.x,s,t.radius+8,0,Math.PI*2),e.stroke()),r&&(e.strokeStyle=f.danger,e.lineWidth=3,e.beginPath(),e.arc(t.x,s,t.radius+12+Math.sin(t.bob*2)*4,0,Math.PI*2),e.stroke()),t.sex==="poop")lr(e,t.x,s,t.radius);else{let l=t.sex==="male"?ze.chickMale:ze.chickFemale;Ft(e,l,t.x-t.radius,s-t.radius,t.radius*2,t.radius*2)||(e.fillStyle=t.sex==="male"?f.male:f.female,e.strokeStyle=f.ink,e.lineWidth=5,e.beginPath(),e.arc(t.x,s,t.radius,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle=f.ink,e.beginPath(),e.arc(t.x-6,s-5,2.5,0,Math.PI*2),e.arc(t.x+6,s-5,2.5,0,Math.PI*2),e.fill(),e.fillStyle="#ffaa2e",e.beginPath(),e.moveTo(t.x,s+2),e.lineTo(t.x+9,s+6),e.lineTo(t.x,s+10),e.closePath(),e.fill())}e.restore()}function Ka(e,t){let n=null,o=1/0;for(let[r,s]of e.componentLookup.entries()){let l=Q(r),d=F(l.col,l.row),v=Math.hypot(t.x-d.x,t.y-d.y);vps(o.type,o.id)===ps(t,n))}function Ke(e,t,n,o,r,s,l,d){Ha(t,n,o)&&(e.save(),e.fillStyle="rgba(34,185,79,.18)",e.strokeStyle=f.green,e.lineWidth=(t.multiSelected||[]).length>1?6:4,e.setLineDash((t.multiSelected||[]).length>1?[]:[8,5]),te(e,r-l/2,s-d/2,l,d,!0,!0),e.restore())}function qa(e,t,n,o){if(t.phase==="build"&&(t.multiSelected||[]).length>1){e.save(),e.fillStyle="rgba(255,255,255,.96)",e.strokeStyle=f.ink,e.lineWidth=3,te(e,54-t.view.x,66-t.view.y,214,42,!0,!0),e.fillStyle=f.ink,e.font="900 11px ui-monospace, monospace",e.fillText(`${t.multiSelected.length} ITEMS SELECTED`,65-t.view.x,83-t.view.y),e.fillStyle=f.muted,e.font="900 11px ui-monospace, monospace",e.fillText("drag any selected item to move group",65-t.view.x,99-t.view.y),e.restore();return}}function Ya(e,t,n){if(!n.cardTargetPick?.pending)return;let o=er(n);e.save(),e.fillStyle="rgba(0,0,0,.66)",e.beginPath();let r=n.view?.scale||1;e.rect(-(n.view?.x||0)/r,-(n.view?.y||0)/r,t.width/r,t.height/r);for(let v of o){let C=v.bounds,P=8;e.rect(C.x-P,C.y-P,C.w+P*2,C.h+P*2)}e.fill("evenodd");let s=n.cardTargetPick?.mode==="blockedCell";if(!o.length){e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=f.ink,e.lineWidth=3,te(e,(260-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,420/r,42/r,!0,!0),e.fillStyle=f.danger,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(s?"NO BLOCKED CELL. PRESS ESC.":"NO VALID UPGRADE TARGET. PRESS ESC.",(470-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore();return}e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=f.ink,e.lineWidth=3;let l=Math.max(1,n.cardTargetPick?.remaining||1),d=n.cardTargetPick?.mode==="autoScannerMenu"?"AUTO SCANNER ROUTE SETTINGS. CLICK EMPTY AREA TO CLOSE.":s?`CLICK BLOCKED CELL: ${l} LEFT. PRESS ESC TO CANCEL.`:"CLICK AN UPGRADEABLE MACHINE. PRESS ESC TO CANCEL.";te(e,(216-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,560/r,42/r,!0,!0),e.fillStyle=f.ink,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(d,(496-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore()}function Va(e,t){if(t.phase!=="build"||!t.selectionBox)return;let n=t.selectionBox,o=Math.min(n.x1,n.x2),r=Math.min(n.y1,n.y2),s=Math.abs(n.x2-n.x1),l=Math.abs(n.y2-n.y1);e.save(),e.fillStyle="rgba(34,185,79,.12)",e.strokeStyle=f.green,e.lineWidth=2,e.setLineDash([7,4]),te(e,o,r,s,l,!0,!0),e.restore()}function za(e,t){let n=[...t.effects].sort((o,r)=>(o.priority??ke.ambient)-(r.priority??ke.ambient));for(let o of n){let r=Math.max(0,o.life/o.maxLife);e.save(),e.globalAlpha=r,o.type==="meat"?(e.fillStyle=f.green,te(e,o.x-o.size/2,o.y-o.size/2,o.size*1.5,o.size,!0,!1)):o.type==="sludge"?(e.fillStyle=f.poop,te(e,o.x-o.size/2,o.y-o.size/2,o.size*1.4,o.size,!0,!1)):o.type==="spawn"?(e.strokeStyle=f.green,e.lineWidth=3,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*20,0,Math.PI*2),e.stroke()):o.type==="spark"?(e.fillStyle=o.color||f.danger,te(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!0,!1)):o.type==="smoke"?(e.fillStyle="rgba(16,32,21,.24)",e.beginPath(),e.arc(o.x,o.y,o.size*(1.2-r*.2),0,Math.PI*2),e.fill()):o.type==="shockwave"?(e.strokeStyle=o.color||f.danger,e.lineWidth=4,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*(o.maxSize||44),0,Math.PI*2),e.stroke()):o.type==="scannerPulse"?(e.strokeStyle=o.color||f.green,e.lineWidth=5,e.setLineDash([8,6]),e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*38,0,Math.PI*2),e.stroke()):o.type==="shred"?(e.fillStyle=o.color||f.ink,e.save(),e.translate(o.x,o.y),e.rotate(o.rot||0),te(e,-o.w/2,-o.h/2,o.w,o.h,!0,!1),e.restore()):o.type==="load"?(e.strokeStyle=o.color||f.green,e.lineWidth=3,e.beginPath(),e.moveTo(o.x-14,o.y),e.lineTo(o.x+14,o.y),e.moveTo(o.x,o.y-14),e.lineTo(o.x,o.y+14),e.stroke()):o.type==="erase"?(e.strokeStyle=f.ink,e.lineWidth=3,e.setLineDash([4,4]),te(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!1,!0)):o.type==="rage"?(e.fillStyle=o.color||f.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText("!",o.x,o.y)):o.type==="flyingChick"&&(o.sex==="poop"?lr(e,o.x,o.y,o.radius||11):ar(e,o.x,o.y,o.sex,o.sex==="male")),e.restore()}}function Xa(e,t){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let n of t.floatingTexts){let o=Math.max(0,n.life/n.maxLife);e.globalAlpha=o,e.lineWidth=5,e.strokeStyle=f.white,e.fillStyle=n.color,e.strokeText(n.text,n.x,n.y),e.fillText(n.text,n.x,n.y)}e.restore()}function Qa(e,t){let n=t.repairman;if(!(!!n?.active||t.phase==="build"&&!!n?.hiredForNextDay))return;e.save(),e.lineWidth=3,e.fillStyle="#fff0d1",e.strokeStyle=f.ink,e.beginPath(),e.arc(n.x,n.y,17,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle="#ffd6e7",e.beginPath(),e.arc(n.x-6,n.y-2,3.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+6,n.y-2,3.2,0,Math.PI*2),e.fill();let r=!!t.cardEffects?.laborExploitation;e.fillStyle=r?f.danger:f.ink,e.beginPath(),e.arc(n.x-5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.strokeStyle=f.ink,e.lineWidth=r?3:2,e.beginPath(),e.arc(n.x,n.y+(r?0:1),r?8:7,.1*Math.PI,.9*Math.PI),e.stroke(),e.fillStyle=f.green,te(e,n.x-9,n.y+14,18,8,!0,!0),e.strokeStyle=f.ink,e.lineWidth=3,e.beginPath(),e.moveTo(n.x-11,n.y+18),e.lineTo(n.x-20,n.y+24),e.stroke(),e.beginPath(),e.moveTo(n.x+11,n.y+18),e.lineTo(n.x+20,n.y+24),e.stroke(),e.fillStyle=f.ink,e.font="900 11px ui-monospace, monospace",e.textAlign="center",e.fillText(n.active?"FIX":"HIRED",n.x,n.y+33),n.target?.label?nr(e,n.x,n.y-24,n.target.label,f.green):!n.active&&n.hiredForNextDay&&nr(e,n.x,n.y-24,"NEXT DAY",f.green),e.restore()}function Ja(e,t,n){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="left",e.fillStyle=f.ink,e.fillStyle="rgba(255,255,255,.92)",e.strokeStyle=f.ink,e.lineWidth=3,te(e,n.width-284,18,260,34,!0,!0),e.fillStyle=f.green,e.font="900 12px ui-monospace, monospace",e.fillText(wn,n.width-270,40),e.font="900 19px ui-monospace, monospace",e.fillStyle=f.ink;let o=[];t.phase==="running"&&o.push(t.timeLeft<=0?"TIME UP: FARMS SHUT. CLEAR LINE.":"A/D: S1 \u2190/\u2192: S2"),t.phase==="build"&&o.push(`BUILD: ${t.buildTool||"SELECT"} | connect 1 EGG route to any exit`);let r=76;for(let s of o)e.strokeStyle=f.white,e.lineWidth=4,e.strokeText(s,24,r),e.fillText(s,24,r),r+=20;e.restore()}var ws=[[{key:"a",code:"KeyA",label:"A"},{key:"d",code:"KeyD",label:"D"}],[{key:"arrowleft",code:"ArrowLeft",label:"Left"},{key:"arrowright",code:"ArrowRight",label:"Right"}],[{key:"j",code:"KeyJ",label:"J"},{key:"l",code:"KeyL",label:"L"}],[{key:"f",code:"KeyF",label:"F"},{key:"h",code:"KeyH",label:"H"}],[{key:"q",code:"KeyQ",label:"Q"},{key:"e",code:"KeyE",label:"E"}],[{key:"z",code:"KeyZ",label:"Z"},{key:"x",code:"KeyX",label:"X"}],[{key:"u",code:"KeyU",label:"U"},{key:"o",code:"KeyO",label:"O"}],[{key:"n",code:"KeyN",label:"N"},{key:"m",code:"KeyM",label:"M"}]];function ja(e){let t=ws[e]||ws[0];return{left:{...t[0]},right:{...t[1]}}}function Ss(e,t,n){let o={type:"eggFarm",id:e.nextId++,col:t,row:n,level:1,nextSpawn:2,lastInterval:2,extraEggOutlet:0,price:St.eggFarm,builtSession:e.buildSession};return o.nextSpawn=Mt(o),o.lastInterval=o.nextSpawn,o}function xs(e,t,n,o){let r=o==="auto"?Se.autoScanner.price:Se.manualScanner.price,s=new Set(e.scanners.filter(d=>d.kind==="manual").map(d=>d.slot)),l=0;for(;s.has(l);)l+=1;return{type:"scanner",id:e.nextId++,kind:o,slot:o==="manual"?l:null,role:o==="manual"?l%2:0,col:t,row:n,level:1,queue:[],cooldown:0,price:r,builtSession:e.buildSession,autoMode:"standard",keys:o==="manual"?ja(l):null}}function zn(e){let t=(e.x-y.x)/y.cell,n=(e.y-y.y)/y.cell,o=Math.max(0,Math.min(y.cols-1,Math.round(t-.5))),r=Math.max(0,Math.min(y.rows-1,Math.round(n-.5))),s=Math.abs(e.x-y.x),l=Math.abs(e.x-(y.x+y.cols*y.cell)),d=Math.abs(e.y-y.y),v=Math.abs(e.y-(y.y+y.rows*y.cell)),C=[["left",s],["right",l],["top",d],["bottom",v]].sort((P,A)=>P[1]-A[1])[0][0];return C==="left"?{side:C,entry:{col:0,row:r}}:C==="right"?{side:C,entry:{col:y.cols-1,row:r}}:C==="top"?{side:C,entry:{col:o,row:0}}:{side:C,entry:{col:o,row:y.rows-1}}}function Xn(e,t,n){let o={x:y.x+t.col*y.cell+y.cell/2,y:y.y+t.row*y.cell+y.cell/2},r={left:y.x,right:y.x+y.cols*y.cell,top:y.y,bottom:y.y+y.rows*y.cell};return e.entry={...t},e.side=n,n==="left"?(e.x=r.left-e.w-18,e.y=o.y-e.h/2):n==="right"?(e.x=r.right+18,e.y=o.y-e.h/2):n==="top"?(e.x=o.x-e.w/2,e.y=r.top-e.h-18):(e.x=o.x-e.w/2,e.y=r.bottom+18),e}function ks(e,t,n,o){let{entry:r,side:s}=zn(n),l=Se[t],d=l?{name:l.name,w:l.body?.w||168,h:l.body?.h||110,price:l.price}:{name:t[0].toUpperCase()+t.slice(1),w:168,h:110,price:o},v={type:"facility",id:t,name:d.name,x:0,y:0,w:d.w,h:d.h,level:1,price:o||d.price,builtSession:e.buildSession};return Xn(v,r,s)}function Za(e){return Math.random()({x:s.x,y:s.y})),r=o[0];return{id:e.nextId++,sex:n,x:r.x,y:r.y,route:o,targetIndex:o.length>1?1:o.length,stage:t.stage||"belt",scannerId:t.scannerId??null,nextScannerId:null,pendingScannerId:null,radius:n==="poop"?15:17,bob:Math.random()*Math.PI*2,queueIndex:-1,queueRoute:null}}function Ms({game:e,canvasPoint:t,updatePanels:n,equipmentAtPoint:o,fail:r,pointInGrid:s,rectOfFacility:l,rectsOverlap:d}){function v(x){return x?x.type==="conveyor"?`conveyor:${x.id||x.oldKey}`:x.type==="facility"?`facility:${x.id||x.ref?.id}`:`${x.type}:${x.id||x.ref?.id}`:""}function C(x){return x?x.type==="conveyor"?{type:"conveyor",id:x.oldKey}:{type:x.type,id:x.ref.id}:null}function P(x){let g=v(C(x));return(e.multiSelected||[]).some(O=>v(O)===g)}function A(x){return x?x.type==="eggFarm"?e.eggFarms.find(g=>g.id===x.id)||null:x.type==="scanner"?e.scanners.find(g=>g.id===x.id)||null:x.type==="facility"?e.facilities[x.id]||null:x.type==="conveyor"&&e.conveyorTiles.has(x.id)?{type:"conveyor",id:x.id}:null:null}function L(){let x=[];for(let g of e.conveyorTiles){let O=Q(g),X=F(O.col,O.row);x.push({type:"conveyor",id:g,center:X,cell:O})}for(let g of e.eggFarms)x.push({type:"eggFarm",id:g.id,ref:g,center:F(g.col,g.row),cell:{col:g.col,row:g.row}});for(let g of e.scanners)x.push({type:"scanner",id:g.id,ref:g,center:pe(g),cell:{col:g.col,row:g.row}});for(let g of Object.values(e.facilities)){let O={x:g.x+g.w/2,y:g.y+g.h/2},X=g.entry?F(g.entry.col,g.entry.row):O;x.push({type:"facility",id:g.id,ref:g,center:O,portCenter:X})}return x}function V(x,g){let O=Math.min(g.x1,g.x2),X=Math.max(g.x1,g.x2),oe=Math.min(g.y1,g.y2),de=Math.max(g.y1,g.y2);return x.x>=O&&x.x<=X&&x.y>=oe&&x.y<=de}function ne(x){let g=[];for(let O of L())(V(O.center,x)||O.portCenter&&V(O.portCenter,x))&&g.push({type:O.type,id:O.id});return e.multiSelected=g,e.selected=g[0]||null,n(),g.length}function z(){e.multiSelected=[],e.selected=null,n()}function se(x){let g=t(x);return e.selectionBox={x1:g.x,y1:g.y,x2:g.x,y2:g.y},e.multiSelected=[],e.selected=null,n(),!0}function ye(x){if(!e.selectionBox)return;let g=t(x);e.selectionBox.x2=g.x,e.selectionBox.y2=g.y}function Z(){if(!e.selectionBox)return 0;let x=e.selectionBox,g=Math.abs(x.x2-x.x1),O=Math.abs(x.y2-x.y1);return e.selectionBox=null,g<6&&O<6?(z(),0):ne(x)}function I(x){let g=C(x);return g?(e.multiSelected||[]).length&&P(x)?[...e.multiSelected]:[g]:[]}function W(x){let g=A(x);if(!g)return null;if(x.type==="conveyor"){let O=Q(x.id);return{...x,obj:g,oldKey:x.id,currentKey:x.id,meta:e.conveyorMeta.get(x.id)||{price:Ne("conveyor"),builtSession:null},col:O.col,row:O.row}}return x.type==="eggFarm"||x.type==="scanner"?{...x,obj:g,col:g.col,row:g.row}:x.type==="facility"?{...x,obj:g,x:g.x,y:g.y,w:g.w,h:g.h,entry:g.entry?{...g.entry}:null,side:g.side,center:{x:g.x+g.w/2,y:g.y+g.h/2}}:null}function N(x){let g=t(x),O=o(g);if(!O)return!1;let X=I(O),oe=X.map(W).filter(Boolean);return oe.length?(e.groupDrag={start:g,selections:X,origins:oe,historySnapshot:cn(e),committed:!1,lastDCol:0,lastDRow:0},e.multiSelected=X,e.selected=X[0]||null,n(),!0):!1}function le(){!e.groupDrag||e.groupDrag.committed||(e.undoStack.push(e.groupDrag.historySnapshot),e.redoStack=[],e.groupDrag.committed=!0)}function we(x,g,O){let X=$(x,g),oe=Tt(e,x,g);if(oe&&!O.has(`eggFarm:${oe.id}`))return!0;let de=Et(e,x,g);return!!(de&&!O.has(`scanner:${de.id}`)||e.conveyorTiles.has(X)&&!O.has(`conveyor:${X}`))}function he(x,g,O){let X=[];for(let oe of e.groupDrag.origins){if(oe.type!=="facility")continue;let de={x:oe.center.x+x,y:oe.center.y+g},{entry:ge,side:ce}=zn(de);if(!s(ge.col,ge.row)||e.blockedCells?.has?.($(ge.col,ge.row)))return!0;let ot={...oe.obj,entry:{...ge},side:ce};Xn(ot,ge,ce),X.push({id:oe.id,rect:l(ot)})}for(let oe of X)for(let de of Object.values(e.facilities))if(!O.has(`facility:${de.id}`)&&d(oe.rect,l(de),12))return!0;for(let oe=0;oeJ.type==="conveyor");for(let J of ot){let Me=J.currentKey||J.oldKey;e.conveyorTiles.delete(Me),e.conveyorMeta.delete(Me)}for(let J of ot){let Me=$(J.col+oe,J.row+de);e.conveyorTiles.add(Me),e.conveyorMeta.set(Me,J.meta||{price:Ne("conveyor"),builtSession:null,uses:0}),J.currentKey=Me}for(let J of e.groupDrag.origins)if(J.type==="eggFarm")J.obj.col=J.col+oe,J.obj.row=J.row+de;else if(J.type==="scanner")J.obj.col=J.col+oe,J.obj.row=J.row+de;else if(J.type==="facility"){let Me={x:J.center.x+O,y:J.center.y+X},{entry:Be,side:rt}=zn(Me);Xn(J.obj,Be,rt)}e.groupDrag.selections=e.groupDrag.origins.map(J=>J.type==="conveyor"?{type:"conveyor",id:J.currentKey||J.oldKey}:{type:J.type,id:J.id}),e.multiSelected=[...e.groupDrag.selections],e.selected=e.multiSelected[0]||null,be(e),n()}function G(){e.groupDrag&&(be(e),e.groupDrag=null,n())}return{selectionFromHit:C,startSelectionBox:se,updateSelectionBox:ye,finishSelectionBox:Z,startGroupDrag:N,updateGroupDrag:R,finishGroupDrag:G}}function gs({game:e,ui:t,canvas:n,canvasPoint:o,onUpdatePanels:r}){function s(){r&&r()}let l=null,d=!1,v=null,C=!1,P=["random","up","right","down","left"],A={random:"RND",up:"UP",right:"RT",down:"DN",left:"LF"},L={w:40,h:40,y:0};function V(){return gn(e)}function ne(){e.gridCols=y.cols,e.gridRows=y.rows,e.gridOwnedCells=Nr(e)}function z(i){if(i){y.y-=i*y.cell,y.rows+=i,e.gridChunkOriginY=(e.gridChunkOriginY||0)-Math.floor(i/10),e.ownedCells=Tn(e.ownedCells,i),e.blockedCells=Tn(e.blockedCells,i),e.conveyorTiles=Tn(e.conveyorTiles,i),e.conveyorMeta=_r(e.conveyorMeta,i);for(let c of e.eggFarms||[])c.row+=i;for(let c of e.scanners||[])c.row+=i;for(let c of Object.values(e.facilities||{}))c.entry&&(c.entry.row+=i)}}function se(i){e.ownedCells=e.ownedCells||new Set;for(let c of Wr(i))e.ownedCells.add($(c.col,c.row))}function ye(i){return e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending?null:kt(e).find(c=>c&&Ur(c,i))||null}function Z(i="right"){if(i&&typeof i=="object"&&Number.isFinite(i.chunkX)&&Number.isFinite(i.chunkY))return i;let c=["right","up"].includes(i)?i:"right";return Gr(e,c)}function I(i="right"){let c=Z(i);if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return{ok:!1,reason:"Cannot expand now."};if(!c)return{ok:!1,reason:"Invalid expansion lot."};let h=c.direction||"right",m=V();if(e.cashy.cols&&(y.cols=T.colStart+T.cols),T.rowStart+T.rows>y.rows&&(y.rows=T.rowStart+T.rows),se(T),Kr(e,T.chunkX,T.chunkY),e.gridExpansionPurchases=(e.gridExpansionPurchases||0)+1,e.gridExpansionPurchasesByDirection[h]=(e.gridExpansionPurchasesByDirection[h]||0)+1,ne();let j=$r({seed:`${e.runSeed}:grid-expansion:${T.chunkX},${T.chunkY}:${e.gridExpansionPurchases}`,colStart:T.colStart,colEnd:T.colStart+T.cols,rowStart:T.rowStart,rowEnd:T.rowStart+T.rows,targetRatio:q.map.blockedRatio});for(let Pe of j)e.blockedCells.add(Pe);be(e);let ie=T.cols*T.rows,fe=Ct(T);return _(e,fe.x+fe.w/2,fe.y+fe.h/2,`${h.toUpperCase()} +${ie} CELLS -${M(m)}`,f.green),s(),{ok:!0,direction:h,cost:m,addedCells:ie,blocked:j.size,chunkX:T.chunkX,chunkY:T.chunkY}}function W(i,c){return i>=0&&i=0&&c!c.has(m.id)&&we(h,le(m),12))}function R(i,c,h=null){if(!W(i,c))return!1;if(N(i,c))return!0;let m=$(i,c),k=Tt(e,i,c);if(k&&!(h?.type==="eggFarm"&&h.ref?.id===k.id))return!0;let T=Et(e,i,c);return!!(T&&!(h?.type==="scanner"&&h.ref?.id===T.id)||e.conveyorTiles.has(m)&&!(h?.type==="conveyor"&&h.oldKey===m))}function G(i,c,h=null){let m={col:i,row:c};for(let k of gt(m)){if(!W(k.col,k.row)||N(k.col,k.row))return!0;let T=$(k.col,k.row);if(Tt(e,k.col,k.row))return!0;let ie=Et(e,k.col,k.row);if(ie&&!(h?.type==="scanner"&&h.ref?.id===ie.id)||e.conveyorTiles.has(T))return!0}return!1}function x(){return e.selected?e.selected.type==="eggFarm"?e.eggFarms.find(i=>i.id===e.selected.id)||null:e.selected.type==="scanner"?e.scanners.find(i=>i.id===e.selected.id)||null:e.selected.type==="conveyor"?e.conveyorTiles.has(e.selected.id)?{type:"conveyor",id:e.selected.id}:null:e.selected.type==="facility"&&e.facilities[e.selected.id]||null:null}function g(i){return i?i.type==="eggFarm"?`${xt("eggFarm")} #${i.id}`:i.type==="scanner"?`${i.kind==="auto"?xt("autoScanner"):xt("manualScanner")} #${i.id}`:i.type==="conveyor"?e.conveyorMeta.get(i.id)?.kind==="boostConveyor"?xt("boostConveyor"):xt("conveyor"):i.type==="facility"?i.name:"Equipment":"Equipment"}function O(i){return i?.type==="conveyor"?e.conveyorMeta?.get(i.oldKey||i.ref?.id)?.price||$n(i):$n(i)}function X(){return!!e.cardEffects?.usedMachineActive}function oe(){return X()?{usedMachine:!0,noRefund:!0,durabilityBaseMultiplier:.6}:{usedMachine:!1,noRefund:!1,durabilityBaseMultiplier:1}}function de(i){let c=oe();return Object.assign(i,c),i}function ge(i){let c=i?.ref||i||{};if(i?.type==="eggFarm"||c.type==="eggFarm")return e.eggFarms.length<=1?"Cannot sell the last EGG FARM.":"";if((i?.type==="facility"||c.type==="facility")&&["mixer","trash","truck"].includes(c.baseId||c.id)){let h=c.baseId||c.id;if(Object.values(e.facilities).filter(k=>(k.baseId||k.id)===h).length<=1)return`Cannot sell the last ${c.shortName||c.name||c.id}.`}return""}function ce(i){t.buildStatus.textContent=i,_(e,n.width/2-e.view.x,86-e.view.y,i.toUpperCase(),f.danger)}function ot(i){if(!i)return null;let c=$(i.col,i.row);return e.conveyorMeta.get(c)||null}function J(i){return i?(Array.isArray(i.outDirs)||(i.outDirs=[]),i.outDirs=[...new Set(i.outDirs.filter(c=>["right","left","down","up"].includes(c)))],P.includes(i.branchMode)||(i.branchMode="random"),i.kind||(i.kind="conveyor"),i.speedMultiplier||(i.speedMultiplier=i.kind==="boostConveyor"?2:1),i.outDirs):[]}function Me(i){return i?ue.filter(c=>e.conveyorTiles.has($(i.col+c.dc,i.row+c.dr))).map(c=>c.name):[]}function Be(i){return Me(i).length>=3}function rt(i,c){let h=ue.find(ie=>ie.name===c);if(!i||!h)return!1;let m=$(i.col+h.dc,i.row+h.dr),k=e.conveyorMeta.get(m);if(!k)return!1;let T=h.opposite;return[...new Set([...Array.isArray(k.outDirs)?k.outDirs:[],k.dir].filter(Boolean))].includes(T)}function Ge(i){if(!e.conveyorTiles.has(i))return[];let c=Q(i),h=e.conveyorMeta.get(i),m=J(h),k=Me(c),T=[...new Set([...m,h?.dir].filter(Boolean))].filter(fe=>k.includes(fe)),j=k,ie=T.length?T:j;return h&&(h.outDirs=m.filter(fe=>k.includes(fe)),h.dir&&!k.includes(h.dir)&&(h.dir=h.outDirs[0]||null),h.branchMode!=="random"&&!k.includes(h.branchMode)&&(h.branchMode="random")),ie}function it(i){if(!e.conveyorTiles.has(i))return[];let c=Q(i),h=Me(c);return Be(c)||h.length?h:Ge(i)}function eo(i){let c=Q(i),h=it(i);if(h.length<3)return[];let m=new Set(h.filter(k=>rt(c,k)));return h.filter(k=>{let T=new Set(m);return T.add(k),h.filter(j=>!T.has(j)).length>=2})}function pn(i,c){let h=lt(i,c);if(!h)return!1;let m=$(i.col,i.row),k=$(c.col,c.row),T=e.conveyorMeta.get(m),j=e.conveyorMeta.get(k);if(!T||!j)return!1;let ie=J(T),fe=!ie.includes(h)||T.dir!==h||!j.dir;return ie.includes(h)||ie.push(h),T.dir=h,j.dir||(j.dir=h),fe}function yn(i){let c=to(i);return c.length<2?hn(i):($e(e),no(c),be(e),s(),!0)}function hn(i){if(!i)return!1;let c=$(i.col,i.row),h=e.conveyorMeta.get(c);if(!h||Be(i))return!1;let m=ue.map(j=>j.name),k=h.dir&&m.includes(h.dir)?h.dir:null,T=m[(Math.max(-1,m.indexOf(k))+1)%m.length];return $e(e),h.dir=T,h.outDirs=[T],h.branchMode="random",be(e),s(),!0}function bt(i){return i?ue.map(c=>({col:i.col+c.dc,row:i.row+c.dr})).filter(c=>e.conveyorTiles.has($(c.col,c.row))):[]}function to(i){if(!i||!e.conveyorTiles.has($(i.col,i.row))||Be(i))return[];let c=bt(i);if(!c.length||c.length>2)return[];let h=T=>{let j=[],ie=new Set([$(i.col,i.row)]),fe=i,Pe=T,br=0;for(;Pe&&br<200;){br+=1;let vr=$(Pe.col,Pe.row);if(ie.has(vr)||(ie.add(vr),j.push(Pe),Be(Pe)))break;let wr=bt(Pe).filter(Sr=>!(Sr.col===fe.col&&Sr.row===fe.row));if(wr.length!==1)break;fe=Pe,Pe=wr[0]}return j},m=c[0]?h(c[0]).reverse():[],k=c[1]?h(c[1]):[];return[...m,i,...k]}function mn(i,c){return!!i&&[...new Set([...Array.isArray(i.outDirs)?i.outDirs:[],i.dir].filter(Boolean))].includes(c)}function no(i){let c=0,h=0;for(let k=0;kh?[...i].reverse():i;for(let k=0;k=Math.abs(m)?{col:i.col+Math.sign(h),row:i.row}:{col:i.col,row:i.row+Math.sign(m)}}function oo(i){d=!1,v=i?{col:i.col,row:i.row}:null,C=!1,l=null,Nt(i)}function jt(i){if(!i)return;if(!l)return Nt(i);let c=l,h=0;for(;(c.col!==i.col||c.row!==i.row)&&h<64;){let m=Jt(c,i);if(Nt(m),c=l||m,h+=1,!l)break}}function vn(){!C&&v&&e.conveyorTiles.has($(v.col,v.row))&&yn(v),v=null,C=!1,l=null,d=!1}function u(i){if(!i)return ce(re.fail.outOfGrid);let{col:c,row:h}=i;if(e.buildTool==="conveyor"||e.buildTool==="boostConveyor"){let m=bn(i,null);if(!m.ok)return ce(m.reason||re.fail.cellOccupied);be(e);return}if(N(c,h))return ce("Cannot build on blocked ground.");if(e.buildTool==="manualScanner"||e.buildTool==="autoScanner"?G(c,h):R(c,h))return ce(re.fail.cellOccupied);e.buildTool==="eggFarm"?b(c,h):e.buildTool==="manualScanner"?S(c,h,"manual"):e.buildTool==="autoScanner"&&S(c,h,"auto")}function p(i){let c=We(i.x,i.y);if(["conveyor","boostConveyor","eggFarm","manualScanner","autoScanner"].includes(e.buildTool))return u(c);if(nn.includes(e.buildTool))return w(i,e.buildTool)}function b(i,c){let h=Ne("eggFarm",e);if(e.cashT.kind==="manual").length>=8)return ce("Manual Scanner limit reached (8 max).");let m=h==="auto"?Ne("autoScanner",e):Ne("manualScanner",e);if(e.cashk.id!==c.ref.id),pt(e,m.x,m.y),be(e)}if(c.type==="scanner"){let m=pe(c.ref);E(c,m.x,m.y),e.scanners=e.scanners.filter(k=>k.id!==c.ref.id),pt(e,m.x,m.y),be(e)}if(c.type==="facility"){let m=c.ref;E(c,m.x+m.w/2,m.y+m.h/2),delete e.facilities[m.id],pt(e,m.x+m.w/2,m.y+m.h/2),be(e)}e.selected=null,e.multiSelected=[],s()}function K(i){let c=Object.values(e.facilities).find(j=>{if(i.x>=j.x&&i.x<=j.x+j.w&&i.y>=j.y&&i.y<=j.y+j.h)return!0;if(!j.entry)return!1;let fe=F(j.entry.col,j.entry.row);return Math.abs(i.x-fe.x)<=y.cell*.46&&Math.abs(i.y-fe.y)<=y.cell*.46});if(c)return{type:"facility",ref:c};let h=We(i.x,i.y);if(!h)return null;let m=Tt(e,h.col,h.row);if(m)return{type:"eggFarm",ref:m};let k=Et(e,h.col,h.row);if(k)return{type:"scanner",ref:k};let T=$(h.col,h.row);return e.conveyorTiles.has(T)?{type:"conveyor",oldKey:T,ref:{type:"conveyor",id:T}}:null}let ee=Ms({game:e,canvasPoint:o,updatePanels:s,equipmentAtPoint:K,fail:ce,pointInGrid:W,rectOfFacility:le,rectsOverlap:we});function Xe(i){return null}function ur(){let i=x();i&&(i.type==="conveyor"?D(F(...Object.values(Q(i.id)))):i.type==="eggFarm"?D(F(i.col,i.row)):i.type==="scanner"?D(pe(i)):i.type==="facility"&&D({x:i.x+i.w/2,y:i.y+i.h/2}))}function He(i,c,h="primary-button"){let m=document.createElement("button");return m.type="button",m.className=h,m.textContent=i,m.addEventListener("click",c),m}function Zt(){e.cardTargetPick?.mode==="autoScannerMenu"&&(e.cardTargetPick=null),t.modal.classList.remove("visible","equipment-popover"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function ro(i){t.modalTitle.textContent="Auto Scanner",e.cardTargetPick={pending:!0,mode:"autoScannerMenu",cardId:null,targetKeys:[`scanner:${i.id}`],remaining:1},t.modalBody.innerHTML=` +var q={version:"v27.15 dark factory visual patch",time:{daySeconds:60,farmShutdownGraceSeconds:10},cash:{starting:250},grid:{x:170,y:78,cols:20,rows:10,cell:46,expansion:{colsPerPurchase:10,rowsPerPurchase:10,costBase:1e3,costMultiplier:1.3333333333333333,truncateUnit:100}},map:{blockedRatio:.075},economy:{income:{mixer:5,truck:10},poopFine:10,fairiesTribute:{perDay:10,profitExemption:300,legalWorkExemptionBonus:250,profitRate:.12},incomeUpgradeRate:1.1,explosionDamageDivisor:30,maleTruckFinePerHalfDay:30,shredderBonus:{maxCards:30,incomePerUpgrade:1.25},chemicalWeaponSubsidy:{poopPerBlock:70,yenPerBlock:1200}},production:{poopRate:.08,autoScannerCooldown:3.5,autoScannerUpgradeRate:.95,autoScannerCardUpgradeRate:.95,autoScannerMinCooldown:.5,poopRateCardBonus:.04,eggSpawnRanges:[[1.95,4.35],[1.55,3.45],[1.25,2.8],[1.05,2.35]]},conveyor:{baseSpeed:52,maxSpeed:300,bearingSpeedMultiplier:1.075},cards:{definitions:[{id:"upgradeEgg",title:"EGG Improvement",rarity:"common",type:"equipmentUpgrade",target:"eggFarm",description:"Choose one EGG FARM on the map and raise it by 1 level.",tags:["EGG","ACTIVE"]},{id:"upgradeAutoScanner",title:"AUTO SCANNER Improvement",rarity:"common",type:"equipmentUpgrade",target:"autoScanner",description:"Choose one AUTO SCANNER on the map and raise it by 1 level.",tags:["SCANNER","ACTIVE"]},{id:"autoScannerTuning",title:"AUTO SCANNER Tuning",rarity:"common",type:"instant",description:"All AUTO SCANNER cooldowns use default cooldown x0.95 per copy.",tags:["SCANNER","PASSIVE"]},{id:"upgradeMixer",title:"MIXER Improvement",rarity:"common",type:"equipmentUpgrade",target:"mixer",description:"Choose MIXER on the map and raise it by 1 level.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeTruck",title:"TRUCK Improvement",rarity:"common",type:"equipmentUpgrade",target:"truck",description:"Choose TRUCK on the map and raise it by 1 level.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeTrash",title:"SHREDDER Improvement",rarity:"common",type:"equipmentUpgrade",target:"trash",description:"Shred poops for a little money. Max 30 upgrades.",tags:["POOP","ACTIVE"]},{id:"crowdedFarming",title:"Crowded Farming",rarity:"common",type:"instant",description:"EGG production interval -5%. Equipment deterioration +4%. Max 10 cards.",tags:["EGG","RISK","PASSIVE"]},{id:"hatchingFeed",title:"Hatching Feed",rarity:"common",type:"instant",description:"EGG production interval -4%. Poop rate +3%. No card limit.",tags:["EGG","POOP","PASSIVE"]},{id:"poopRateBooster",title:"Poop Culture",rarity:"common",type:"instant",description:"Base poop rate +4 percentage points. No card limit.",tags:["POOP","PASSIVE"]},{id:"safetyCover",title:"Safety Cover",rarity:"common",type:"instant",description:"Explosion damage -5%. No card limit.",tags:["RISK","PASSIVE"]},{id:"preventiveMaintenance",title:"Preventive Maintenance Manual",rarity:"common",type:"instant",description:"All equipment deterioration speed -5%. No card limit.",tags:["MAINTENANCE","PASSIVE"]},{id:"dudFilter",title:"DUD Filter",rarity:"common",type:"instant",description:"DUD chance -5 percentage points. Stacks until DUD chance reaches 0%.",tags:["CARD","PASSIVE"]},{id:"durabilityCoating",title:"Durability Coating",rarity:"common",type:"instant",description:"All equipment maximum durability +3%. No card limit.",tags:["MAINTENANCE","PASSIVE"]},{id:"bearing",title:"High-Quality Bearing",rarity:"common",type:"instant",description:"Conveyor speed +7.5%.",tags:["CONVEYOR","PASSIVE"]},{id:"sparePartsBin",title:"SPARE PARTS BIN",rarity:"common",type:"instant",description:"Restores 2% durability to every machine. A box of almost-compatible parts.",tags:["MAINTENANCE","ACTIVE"]},{id:"dudRefund",title:"DUD REFUND",rarity:"common",type:"instant",description:"DUDs now come with paperwork. Gain JPY 50 per copy when you pick a DUD.",tags:["CARD","ECONOMY","PASSIVE"]},{id:"freeReroll",title:"FREE REROLL",rarity:"common",type:"instant",description:"The first bad ideas are free.",tags:["CARD","PASSIVE"]},{id:"composter",title:"COMPOSTER",rarity:"common",type:"instant",description:"Turns shredder waste into suspicious fertilizer. Gain JPY 3 per copy when SHREDDER processes poop.",tags:["POOP","ECONOMY","PASSIVE"]},{id:"scannerQueueSpacing",title:"Scanner Queue Spacing",rarity:"common",type:"instant",description:"Manual and Auto Scanner queue spacing -15%. No card limit.",tags:["SCANNER","PASSIVE"]},{id:"extraEggOutlet",title:"Extra Egg Outlet",rarity:"rare",type:"equipmentUpgrade",target:"eggOutlet",description:"Choose one EGG FARM and add +1 output port to that EGG. Max +3 per EGG.",tags:["EGG","RARE","ACTIVE"]},{id:"recyclingSubsidy",title:"Recycling Subsidy",rarity:"rare",type:"instant",description:"SELL refund rate +10 points. Max 3 cards; normal SELL can reach 80%.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"dynamite",title:"Dynamite",rarity:"rare",type:"cellAction",target:"blockedCell",description:"Remove any 3 unbuildable cells",tags:["RISK","RARE","ONE-SHOT"]},{id:"usedMachine",title:"Used Machines",rarity:"rare",type:"instant",description:"Future equipment costs half. New purchases have no refund and 60% durability. New Machines cancels it.",tags:["ECONOMY","RISK","RARE"]},{id:"newMachine",title:"New Machines",rarity:"common",type:"instant",description:"Cancel Used Machines and restore normal prices, refunds, and durability.",tags:["ECONOMY","ONE-SHOT"]},{id:"flattery",title:"Flattery",rarity:"rare",type:"instant",description:"Next Fairies tribute -50%.",tags:["ECONOMY","RARE","ONE-SHOT"]},{id:"extraCards",title:"Extra Cards",rarity:"rare",type:"instant",description:"Draw 2 cards now and choose both.",tags:["RARE","ACTIVE"]},{id:"legalWork",title:"Legal Work",rarity:"rare",type:"instant",description:"Fairies tribute profit exemption +JPY 250.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"chemicalWeaponSubsidy",title:"Chemical Weapons Subsidy",rarity:"ultraRare",type:"instant",description:"Each day, gain JPY 1200 per 70 poop shipped by truck. No card limit.",tags:["POOP","ULTRA RARE","PASSIVE"]},{id:"laborExploitation",title:"Motivational Exploitation",rarity:"ultraRare",type:"instant",description:"Repairman labor cost -30%. The repairman smiles with bloodshot eyes. One time only.",tags:["MAINTENANCE","ULTRA RARE","PASSIVE"]},{id:"rescueLoan",title:"Emergency Loan",rarity:"ultraRare",type:"instant",description:"If cash is below JPY 0 at day-end settlement, gain JPY 500. Consumed on use.",tags:["ECONOMY","ULTRA RARE","ONE-SHOT"]}],defaultEffects:{bearing:0,legalWork:0,fairiesFlatteryNext:0,autoScannerTuning:0,poopRateBooster:0,crowdedFarming:0,hatchingFeed:0,safetyCover:0,recyclingSubsidy:0,chemicalWeaponSubsidy:0,preventiveMaintenance:0,dudFilter:0,durabilityCoating:0,sparePartsBin:0,dudRefund:0,freeReroll:0,composter:0,scannerQueueSpacing:0,laborExploitation:0,usedMachineActive:!1,rescueLoanCharges:0},commonWeight:8,rareWeight:2,ultraRareWeight:.45,baseDraftSize:3,maxDudsPerDraft:2,dudChancePerCard:.3,dudChanceReductionPerFilter:.05,extraCardsAddedPicks:2,rerollCost:{dayDivisor:2,multiplier:100}},events:{eventChance:.1,firstTurn:8},maintenance:{fullPerformanceUntilWear:.5,minimumPerformance:.5,durability:{conveyor:1300,eggFarm:475,autoScanner:850,mixer:775,trash:950},processingDelayMaxSeconds:{mixer:1.2,trash:1},repairman:{dailyCost:100,secondsPerOnePercent:.5,walkSpeed:90}},facilities:{conveyor:{id:"conveyor",type:"conveyor",name:"Conveyor",shortName:"Belt",price:30,buildable:!0,upgradeable:!1},boostConveyor:{id:"boostConveyor",type:"conveyor",name:"Boost Conveyor",shortName:"BOOST BELT",price:75,buildable:!0,upgradeable:!1,speedMultiplier:2},eggFarm:{id:"eggFarm",type:"eggFarm",name:"Egg Farm",shortName:"EGG",price:250,buildable:!0,upgradeable:!0,maxLevel:4},manualScanner:{id:"manualScanner",type:"scanner",kind:"manual",name:"Manual Scanner",shortName:"Manual Scanner",price:260,buildable:!0,upgradeable:!1},autoScanner:{id:"autoScanner",type:"scanner",kind:"auto",name:"Auto Scanner",shortName:"Auto Scanner",price:180,buildable:!0,upgradeable:!1},mixer:{id:"mixer",type:"facility",name:"Mixer",shortName:"MIXER",price:450,buildable:!0,upgradeable:!0,incomeKey:"mixer",body:{w:164,h:126}},trash:{id:"trash",type:"facility",name:"Waste Shredder",shortName:"SHREDDER",price:240,buildable:!0,upgradeable:!0,body:{w:180,h:100}},truck:{id:"truck",type:"facility",name:"Truck",shortName:"TRUCK",price:450,buildable:!0,upgradeable:!0,incomeKey:"truck",body:{w:176,h:138}}}};var Sn=q.version,wt=q.time.daySeconds,tn=q.cash.starting,xe=q.economy,kr=q.time.farmShutdownGraceSeconds,kn=q.production.autoScannerCooldown,xr=q.production.autoScannerUpgradeRate,co=q.production.autoScannerCardUpgradeRate||q.production.autoScannerUpgradeRate,uo=q.production.autoScannerMinCooldown,Cr=q.events.eventChance,St=q.events.firstTurn,fo=q.production.poopRate,po=q.production.poopRateCardBonus||0,xn=q.conveyor.baseSpeed,_t=q.conveyor.maxSpeed,Cn=q.conveyor.bearingSpeedMultiplier,Ae=q.cards,Mr=q.cards.definitions,yo=q.cards.defaultEffects,lt=q.production.eggSpawnRanges,y=q.grid,ke=q.facilities,ho=["conveyor","boostConveyor","eggFarm","autoScanner","manualScanner","mixer","trash","truck"],nn=["mixer","trash","truck"],gr=["mixer","truck"],kt=Object.fromEntries(Object.entries(ke).map(([e,t])=>[e,t.price])),ue=[{name:"right",dc:1,dr:0,angle:0,opposite:"left"},{name:"left",dc:-1,dr:0,angle:Math.PI,opposite:"right"},{name:"down",dc:0,dr:1,angle:Math.PI/2,opposite:"up"},{name:"up",dc:0,dr:-1,angle:-Math.PI/2,opposite:"down"}],p={bg:"#111318",ink:"#090a0d",muted:"#8f9bab",green:"#7bd84f",greenSoft:"#273c24",mixerBlue:"#4aa3ff",truckPink:"#ffb33e",wasteGreen:"#88d35a",danger:"#e34a36",warn:"#ffb827",white:"#e6edf2",poop:"#7b4a23",male:"#ffd23d",female:"#ffdf69"},Ce={ambient:0,important:1,critical:2};function M(e){let t=Number(e)||0;return`${t<0?"-":""}\uFFE5${Math.ceil(Math.abs(t)).toLocaleString("ja-JP")}`}function I(e,t){return`${e},${t}`}function Q(e){let[t,n]=String(e).split(",").map(Number);return{col:t,row:n}}function on(e,t,n){return Math.max(t,Math.min(n,e))}function G(e,t){return e+Math.random()*(t-e)}function Ee(e,t){return e>=0&&e=0&&tMath.round(on(r,0,255)).toString(16).padStart(2,"0");return`#${o(e)}${o(t)}${o(n)}`}function gn(e,t,n){let o=Tr(e),r=Tr(t);return nl(mo(o.r,r.r,n),mo(o.g,r.g,n),mo(o.b,r.b,n))}var re={appTitle:"Chick Sorter",versionTitle:`Chick Sorter ${Sn}`,currency:"\uFFE5",phases:{title:"Title",build:"Build",running:"Sorting",clearing:"Clearing",loanDecision:"Emergency Loan",gameover:"Game Over"},actions:{startGame:"Start Game",nextDay:"Next Day",buildPhase:"Build Phase",restart:"Restart",close:"Close",remove:"Remove",refund:"Refund",autoMenu:"Auto Menu"},status:{build:e=>`BUILD: ${(e==="erase"?"SELL":e||"SELECT").toUpperCase()} | Right-drag pan | Hover equipment for info`,sorting:"Sorting: use scanner keys. Build after clearing the day.",allPortsConnected:"Start condition met: one EGG route reaches an exit.",equipmentPanelEmpty:"Hover equipment in Build phase.",eventPanelRunning:"Forced events appear in Build phase."},routeLabels:{mixer:"MIXER",truck:"TRUCK",trash:"WASTE",scanner:"NEXT","scanner-role-1":"NEXT",input:"IN"},fail:{outOfGrid:"Out of grid",cellOccupied:"Cell occupied",notEnoughCash:"Not enough cash",facilityExists:"Facility already exists",facilityOverlap:"Facility overlap",nothingToErase:"Nothing to sell",noUpgrade:"No upgrade available"}};function xt(e){return ke[e]?.name||String(e||"").replace(/^[a-z]/,t=>t.toUpperCase())}function ol(e){let t=ke[e];return t?e==="conveyor"||e==="boostConveyor"?`${M(t.price)} / tile`:e==="autoScanner"?`${M(t.price)} / ${kn.toFixed(1)}s cooldown`:e==="trash"?M(t.price):M(t.price):""}function rl(e){return{conveyor:"A narrow green belt. Routes decide whether chicks live, ship, or become invoices.",boostConveyor:"Moves chicks twice as fast. Wears down like a normal belt.",eggFarm:"A tiny gatehouse producing questionable eggs on schedule.",autoScanner:"Slower than hands without upgrades.",manualScanner:"A manual checkpoint. The operator is the algorithm.",mixer:"Male chicks become revenue here. Do not feed it poop.",trash:"A polite shredder for poop and other regrets.",truck:"Ships the target cargo. Wrong cargo still leaves a paper trail."}[e]||""}function Pr(e){let t=rl(e);return`${xt(e)}${ol(e)}${t?`${t}`:""}`}function Rr(e){return re.routeLabels[e]||String(e).toUpperCase()}function Ar(e){let t=2166136261;for(let n=0;n>>0}function Dr(e){let t=e>>>0;return()=>{t+=1831565813;let n=Math.imul(t^t>>>15,1|t);return n^=n+Math.imul(n^n>>>7,61|n),((n^n>>>14)>>>0)/4294967296}}function Tn(){return`RUN-${Date.now().toString(36)}-${Math.floor(Math.random()*1e6).toString(36)}`.toUpperCase()}function $r({seed:e,targetRatio:t=.2,reserved:n=[]}={}){let o=Dr(Ar(e||Tn())),r=new Set(n.map(d=>typeof d=="string"?d:I(d.col,d.row))),s=[];for(let d=0;d0;d-=1){let v=Math.floor(o()*(d+1));[s[d],s[v]]=[s[v],s[d]]}let l=Math.round(y.cols*y.rows*t);return new Set(s.slice(0,Math.min(l,s.length)).map(d=>d.k))}function Ir({seed:e,colStart:t=0,colEnd:n=y.cols,rowStart:o=0,rowEnd:r=y.rows,targetRatio:s=.2,reserved:l=[]}={}){let d=Dr(Ar(e||Tn())),v=new Set(l.map(z=>typeof z=="string"?z:I(z.col,z.row))),C=[],P=Math.max(0,Math.floor(t)),R=Math.max(P,Math.floor(n)),L=Math.max(0,Math.floor(o)),V=Math.max(L,Math.floor(r));for(let z=L;z0;z-=1){let se=Math.floor(d()*(z+1));[C[z],C[se]]=[C[se],C[z]]}let te=Math.round((R-P)*(V-L)*s);return new Set(C.slice(0,Math.min(te,C.length)).map(z=>z.k))}var Gt=10,Fr=2,Br=1;function Ut(e,t){return`${e},${t}`}function il(e){let[t,n]=String(e).split(",").map(Number);return{chunkX:t,chunkY:n}}function En(e){let t=q.grid.expansion||{},n=Math.max(1,(e.gridExpansionPurchases||0)+1),o=(t.costBase||1e3)*n*(t.costMultiplier||4/3),r=Math.max(1,t.truncateUnit||100);return Math.floor(o/r)*r}function Lr(e){e.ownedCells=new Set,e.ownedChunks=new Set,e.gridChunkOriginY=0,e.gridExpansionPurchases=0,e.gridExpansionPurchasesByDirection={right:0,up:0};for(let t=0;t=0&&t=0&&n0)continue;let C=Ut(v.chunkX,v.chunkY);t.has(C)||n.has(C)||n.set(C,bo(e,v.chunkX,v.chunkY,v.direction))}}return[...n.values()].sort((o,r)=>{let s=o.direction===r.direction?0:o.direction==="right"?-1:1;return s||(o.chunkY!==r.chunkY?o.chunkY-r.chunkY:o.chunkX-r.chunkX)})}function _r(e,t="right"){let n=Ct(e);return n.find(o=>o.direction===t)||n[0]||null}function Mt(e){return{x:y.x+e.colStart*y.cell,y:y.y+e.rowStart*y.cell,w:e.cols*y.cell,h:e.rows*y.cell}}function vo(e){let t=Mt(e);return{x:t.x+t.w/2-116,y:t.y+t.h/2-36,w:232,h:72,cx:t.x+t.w/2,cy:t.y+t.h/2}}function Gr(e,t){let n=vo(e);return t.x>=n.x&&t.x<=n.x+n.w&&t.y>=n.y&&t.y<=n.y+n.h}function Ur(e){let t=[];for(let n=e.rowStart;nEe(t.col,t.row))}function pl(e){return[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}].filter(t=>Ee(t.col,t.row))}function yl(e){return[{col:e.col,row:e.row+1},{col:e.col-1,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row-1}].filter(t=>Ee(t.col,t.row))}function Vr(e){let t=new Set([...e.conveyorTiles]),n=o=>{o&&Ee(o.col,o.row)&&t.add(I(o.col,o.row))};for(let o of e.scanners){for(let r of pl(o))n(r);for(let r of fl(o))n(r)}for(let o of e.eggFarms){n(o);for(let r of yl(o))n(r)}for(let o of Object.values(e.facilities))n(o.entry);return t}function qr(e){let t=al.map(([n,o])=>({col:n,row:o}));for(let{col:n,row:o}of t)Yr(e,n,o);for(let n=0;n({...n,keys:n.keys?{left:{...n.keys.left},right:{...n.keys.right}}:null,queue:[]})),e.eggFarms=ul.map(n=>{let o=gt(n);return{...n,nextSpawn:o,lastInterval:o}});let t=Vr(e);e.blockedCells=$r({seed:e.runSeed,targetRatio:q.map.blockedRatio,reserved:[...t]}),hl(e),qr(e),e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function Tt(e){return e?[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}]:[]}function pe(e){let t=F(e.col,e.row);return{x:t.x+y.cell/2,y:t.y}}function Et(e,t,n){return e.eggFarms.find(o=>o.col===t&&o.row===n)||null}function Pt(e,t,n){return e.scanners.find(o=>Tt(o).some(r=>r.col===t&&r.row===n))||null}function Rt(e,t){return e.scanners.find(n=>n.id===t)||null}function Co(e,t){return e.scanners.find(n=>n.kind==="manual"&&n.slot===t)||null}function Dn(e){return e?.baseId||e?.id||""}function Mo(e,t){return Object.entries(e.facilities||{}).filter(([,n])=>Dn(n)===t)}function Pe(e,t){return{inputA:{col:e.col,row:e.row-2},inputB:null,left:{col:e.col-1,row:e.row},right:{col:e.col+2,row:e.row}}[t]}function Qr(e){return e?ue.map(t=>({col:e.col+t.dc,row:e.row+t.dr})).filter(t=>Ee(t.col,t.row)):[]}function Jr(e,t,n=[],o=[]){if(!t||!Ee(t.col,t.row))return[];let r=[],s=l=>{!l||!Ee(l.col,l.row)||!e.conveyorTiles.has(I(l.col,l.row))||n.some(d=>d&&Mn(l,d))||r.some(d=>Mn(d,l))||r.push({...l,viaTolerance:!Mn(l,t)})};s(t);for(let l of o)s(l);for(let l of Qr(t))s(l);return r}function zr(e,t,n=[],o=[]){let r=Jr(e,t,n,o),s=r.filter(l=>!l.viaTolerance);return s.length?s:r}function ml(e,t){let n=Pe(t,"inputA");return!n||!Ee(n.col,n.row)?[]:e.conveyorTiles.has(I(n.col,n.row))?[{...n,viaTolerance:!1}]:[]}function bl(e,t,n){let o=Pe(t,n);return Jr(e,o,Tt(t))}function vl(e,t){let n=e.facilities[t]||Mo(e,t)[0]?.[1];if(!n)return null;if(n.entry)return F(n.entry.col,n.entry.row);let o=Dn(n)||t;return o==="mixer"?{x:n.x+n.w,y:n.y+n.h*.52}:o==="truck"?{x:n.x,y:n.y+n.h*.52}:o==="trash"?{x:n.x+n.w/2,y:n.y+8}:{x:n.x+n.w/2,y:n.y+n.h/2}}function jr(e,t,n){return n==="inputA"?ml(e,t).length>0:bl(e,t,n).length>0}function ve(e){e.branchCounters?.clear?.(),e.routeCache=null,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function De(e,t){return I(e,t)}function Wt(e){return Q(e)}function wl(e,t){let n=e.conveyorMeta?.get?.(t)||{},o=[];return Array.isArray(n.outDirs)&&o.push(...n.outDirs),n.dir&&o.push(n.dir),[...new Set(o)].filter(r=>ue.some(s=>s.name===r))}function Sl(e,t,n){let o=ue.find(l=>l.name===n);if(!o)return!1;let r=e.conveyorMeta?.get?.(De(t.col+o.dc,t.row+o.dr));return r?[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))].includes(o.opposite):!1}function kl(e,t){let n=Wt(t),o=e.conveyorMeta?.get?.(t)||{},r=ue.filter(R=>e.conveyorTiles.has(De(n.col+R.dc,n.row+R.dr))).map(R=>R.name),s=wl(e,t).filter(R=>r.includes(R)),l=r,d=s.length?s:l;if(r.length<3)return d;let v=new Set(r.filter(R=>Sl(e,n,R)));if(o.branchMode&&o.branchMode!=="random"&&r.includes(o.branchMode)){let R=new Set(v);R.add(o.branchMode),r.filter(L=>!R.has(L)).length>=2&&v.add(o.branchMode)}let C=r.filter(R=>!v.has(R));if(C.length)return C;let P=d.filter(R=>!v.has(R));return P.length?P:d}function xl(e){return{version:e.routingVersion||0,cells:new Set,adjacency:new Map,components:new Map,cellToComponent:new Map,scannerInputs:new Map,scannerPorts:new Map,facilityPorts:new Map,farmOutputs:new Map,pathCache:new Map,metrics:{conveyorCells:0,edges:0,components:0,deadEnds:0,crosses:0,scannerPorts:0,connectedScannerPorts:0,facilityPorts:0,connectedFacilityPorts:0,farmOutputs:0},issues:[]}}function Cl(e){let t=xl(e);for(let o of e.conveyorTiles)t.cells.add(o),t.adjacency.set(o,[]);for(let o of t.cells){let r=Wt(o),s=kl(e,o),l=ue.filter(d=>s.includes(d.name));for(let d of l){let v=De(r.col+d.dc,r.row+d.dr);t.cells.has(v)&&t.adjacency.get(o).push({key:v,dir:d.name})}}let n=0;for(let[o,r]of t.adjacency.entries()){n+=r.length;let s=new Set(r.map(l=>l.dir));r.length===1&&(t.metrics.deadEnds+=1),r.length===4&&s.has("left")&&s.has("right")&&s.has("up")&&s.has("down")&&(t.metrics.crosses+=1)}return t.metrics.conveyorCells=t.cells.size,t.metrics.edges=Math.floor(n/2),Ml(t),gl(e,t),t.issues=Ll(e,t,{includeRoutes:!1}),t}function Ml(e){let t=1;for(let n of e.cells){if(e.cellToComponent.has(n))continue;let o=t++,r=[n],s=[];for(e.cellToComponent.set(n,o);r.length;){let l=r.shift();s.push(l);for(let d of e.adjacency.get(l)||[])e.cellToComponent.has(d.key)||(e.cellToComponent.set(d.key,o),r.push(d.key))}e.components.set(o,{id:o,cells:s,capacity:Math.max(1,s.length),count:0,ratio:0})}e.metrics.components=e.components.size}function gl(e,t){for(let n of e.scanners){let o={};for(let r of["inputA","left","right"]){let s=Pe(n,r),l=r==="inputA"?s&&t.cells.has(De(s.col,s.row))?[{...s}]:[]:zr(e,s,Tt(n)).filter(C=>t.cells.has(De(C.col,C.row))),d=l.map(C=>De(C.col,C.row)),v=d.length>0;if(o[r]={type:r,cell:s,cells:l,keys:d,key:d[0]||null,connected:v},t.metrics.scannerPorts+=1,v&&(t.metrics.connectedScannerPorts+=1),r==="inputA")for(let C of d)t.scannerInputs.set(C,n.id)}t.scannerPorts.set(n.id,o)}for(let[n,o]of Object.entries(e.facilities)){if(!o.entry)continue;let r=zr(e,o.entry).filter(d=>t.cells.has(De(d.col,d.row))),s=r.map(d=>De(d.col,d.row)),l=s.length>0;t.facilityPorts.set(n,{id:n,cell:{...o.entry},cells:r,keys:s,key:s[0]||null,connected:l}),t.metrics.facilityPorts+=1,l&&(t.metrics.connectedFacilityPorts+=1)}for(let n of e.eggFarms){let o=Qr({col:n.col,row:n.row}).map(r=>De(r.col,r.row)).filter(r=>t.cells.has(r));t.farmOutputs.set(n.id,o),t.metrics.farmOutputs+=o.length}}function Oe(e){let t=e.routingVersion||0;return(!e.factoryGraph||e.factoryGraph.version!==t)&&(e.factoryGraph=Cl(e)),e.factoryGraph}function Zr(e){let t=Oe(e);return e.factoryGraphCommittedVersion=t.version,e.factoryGraphSnapshot=Tl(t),t}function Tl(e){return e?{version:e.version,conveyorCells:e.metrics.conveyorCells,edges:e.metrics.edges,components:e.metrics.components,deadEnds:e.metrics.deadEnds,crosses:e.metrics.crosses,scannerPorts:`${e.metrics.connectedScannerPorts}/${e.metrics.scannerPorts}`,facilityPorts:`${e.metrics.connectedFacilityPorts}/${e.metrics.facilityPorts}`,farmOutputs:e.metrics.farmOutputs,issues:[...e.issues||[]]}:null}function El(e,t){let n=t.col-e.col,o=t.row-e.row;return ue.find(r=>r.dc===n&&r.dr===o)?.name||null}function go(e,t,n){let o=Oe(e),r=De(t.col,t.row);if(!o.cells.has(r))return[];let s=`${r}|${n.cacheKey||"dynamic"}`;if(n.cacheKey&&o.pathCache.has(s))return o.pathCache.get(s).map($=>$.map(U=>({...U})));let l=`${r}|none`,d=[{key:r,col:t.col,row:t.row,incoming:"none",depth:0}],v=new Map([[l,0]]),C=new Map,P=[],R=1/0,L=8,V=24,te=80;for(;d.length;){let $=d.shift();if($.depth>R)break;let U=`${$.key}|${$.incoming}`;if(n($)){if(P.push(U),R=$.depth,P.length>=V)break;continue}for(let N of o.adjacency.get($.key)||[]){let le=Wt(N.key),Se=El($,le),he=$.depth+1;if(he>R)continue;let A=`${N.key}|${Se}`,_=v.get(A);if(_==null)v.set(A,he),C.set(A,[U]),d.push({key:N.key,col:le.col,row:le.row,incoming:Se,depth:he});else if(_===he){let k=C.get(A)||[];k.length{if(z.length>=te)return;let[N]=$.split("|"),le=[Wt(N),...U];if($===l||N===r){z.push(le);return}for(let Se of C.get($)||[])se(Se,le)};for(let $ of P)se($,[]);let ye=[],Z=new Set;for(let $ of z){let U=$.map(N=>De(N.col,N.row)).join(">");Z.has(U)||(Z.add(U),ye.push($))}return n.cacheKey&&o.pathCache.set(s,ye.map($=>$.map(U=>({...U})))),ye}function ei(e){let t=Oe(e),n=new Map;for(let[o,r]of t.components.entries())n.set(o,{id:o,cells:[...r.cells],capacity:r.capacity,count:0,ratio:0});return{components:n,cellToComponent:new Map(t.cellToComponent)}}function ti(e,t,n){let o=Oe(e),r=null,s=1/0;for(let l of o.cells){let d=Q(l),v=F(d.col,d.row),C=Math.hypot(v.x-t,v.y-n);CF(o.col,o.row));return t&&n.push(t),n}function ct(e,t){t&&(!e.length||Er(e[e.length-1],t)>1)&&e.push(t)}function Pl(e,t,n,o=null){let r=[{x:e.x,y:e.y}];ct(r,F(t.col,t.row));for(let s of $n(n,o))ct(r,s);return r}function Rl(e,t){let n=$n(e),o=Pe(t,"inputA");return o&&ct(n,F(o.col,o.row)),ct(n,pe(t)),n}function Al(e,t,n,o){let r=[{x:e.x,y:e.y}];ct(r,F(t.col,t.row));for(let l of $n(n))ct(r,l);let s=Pe(o,"inputA");return s&&ct(r,F(s.col,s.row)),ct(r,pe(o)),r}function Dl(e,t,n=0){let o=F(t.col,t.row),r=0;for(let s of e.chicks||[]){if(s.stage==="flying"||s.stage==="queued")continue;Math.hypot(s.x-o.x,s.y-o.y){let R=C.roleBias??0,L=P.roleBias??0;if(R!==L)return R-L;let V=C.cells?.length??C.route?.length??Number.POSITIVE_INFINITY,te=P.cells?.length??P.route?.length??Number.POSITIVE_INFINITY;if(V!==te)return V-te;let z=C.key||JSON.stringify(C.route||C.cells||C),se=P.key||JSON.stringify(P.route||P.cells||P);return z.localeCompare(se)});if(!o||r.length===1)return r[0];let s=r[0].roleBias??0,l=r.filter(C=>(C.roleBias??0)===s),d=Math.min(...l.map(C=>Xr(e,C)));l=l.filter(C=>Xr(e,C)===d);let v=e.branchCounters.get(t)||0;return e.branchCounters.set(t,v+1),l[Math.floor(Math.random()*l.length)]}function ni(e){return e.role===0?{left:{match:"male",destination:"mixer"},right:{match:"default",destination:"scanner-role-1"}}:{left:{match:"poop",destination:"trash"},right:{match:"default",destination:"truck"}}}function To(e){let t=ni(e);return{left:t.left.destination,right:t.right.destination}}function Eo(e,t){return ni(e).left.match===t.sex?"left":"right"}function Po(e){return Rr(e)}function Ro(e){return{mixer:"#2477ff",truck:"#ff6aa8",trash:"#22b94f","scanner-role-1":"#526456",scanner:"#526456",input:"#526456"}[e]||"#102015"}function At(e,t,n=!1){let o=Oe(e),r=(o.farmOutputs.get(t.id)||[]).map(Wt),s=[];for(let v of r){let C=R=>o.scannerInputs.has(De(R.col,R.row));C.cacheKey=`farmInput:${v.col},${v.row}:v${o.version}`;let P=go(e,v,C);for(let R of P){let L=R[R.length-1],V=o.scannerInputs.get(De(L.col,L.row)),te=Rt(e,V);te&&s.push({key:`${te.id}:${L.col},${L.row}:${R.length}`,scanner:te,cells:R})}}let l=An(e,`farm:${t.id}`,s,n);if(l)return{scannerId:l.scanner.id,route:Rl(l.cells,l.scanner)};let d=An(e,`farm:${t.id}:output`,r.map(v=>({key:I(v.col,v.row),cells:[v]})),n);return d?{scannerId:null,route:$n(d.cells)}:null}function oi(e,t,n,o,r=!1){let s=Rt(e,o);if(!s)return null;let d=Oe(e).scannerPorts.get(s.id)?.[t],v=Pe(s,t),C=d?.connected?(d.keys||[d.key]).filter(Boolean).map(Wt):[];if(!v||!C.length)return null;let P=To(s)[t];return P==="scanner-role-1"?$l(e,s,t,n,v,C,r):Il(e,s,t,n,v,C,P,r)}function $l(e,t,n,o,r,s,l){let d=Oe(e),v=e.scanners.filter(R=>R.id!==t.id&&d.scannerPorts.get(R.id)?.inputA?.connected),C=[];for(let R of s)for(let L of v){let V=d.scannerPorts.get(L.id)?.inputA?.key;if(!V)continue;let te=(d.scannerPorts.get(L.id)?.inputA?.keys||[V]).filter(Boolean),z=Z=>te.includes(De(Z.col,Z.row));z.cacheKey=`toScanner:${R.col},${R.row}:${L.id}:v${d.version}`;let se=go(e,R,z),ye=L.role===1?0:1;for(let Z of se)C.push({key:`${ye}:start${I(R.col,R.row)}:s${L.id}:${Z.length}:${I(Z[Z.length-1].col,Z[Z.length-1].row)}`,target:L,cells:Z,roleBias:ye})}let P=An(e,`scanner:${t.id}:${n}:toRole1`,C,l);return P?{destination:"scanner",nextScannerId:P.target.id,route:Al(o,r,P.cells,P.target)}:null}function Il(e,t,n,o,r,s,l,d){let v=Oe(e),C=[...v.facilityPorts.entries()].filter(([L,V])=>V?.connected&&Dn(e.facilities?.[L])===l);if(!C.length)return null;let P=[];for(let L of s)for(let[V,te]of C){let z=(te.keys||[te.key]).filter(Boolean);if(!z.length)continue;let se=Z=>z.includes(De(Z.col,Z.row));se.cacheKey=`toFacility:${L.col},${L.row}:${V}:v${v.version}`;let ye=go(e,L,se);for(let Z of ye)P.push({key:`start${I(L.col,L.row)}:${V}:${Z.length}:${I(Z[Z.length-1].col,Z[Z.length-1].row)}`,cells:Z,facilityId:V})}let R=An(e,`scanner:${t.id}:${n}:${l}`,P,d);return R?{destination:l,facilityId:R.facilityId,route:Pl(o,r,R.cells,vl(e,R.facilityId))}:null}function ri(e,t,n=new Set){if(!t||n.has(t.id))return!1;n.add(t.id);for(let o of["left","right"]){let r=oi(e,o,pe(t),t.id,!1);if(r){if(["mixer","trash","truck"].includes(r.destination))return!0;if(r.destination==="scanner"){let s=Rt(e,r.nextScannerId);if(ri(e,s,n))return!0}}}return!1}function Fl(e,t){return!!At(e,t,!1)?.scannerId}function In(e){if(e.phase!=="build")return[];let t=[];for(let n of e.eggFarms||[])Fl(e,n)||t.push({type:"eggFarm",id:n.id,ref:n,message:"This Egg will not produce chicks"});for(let n of nn)for(let[o,r]of Mo(e,n))Oe(e).facilityPorts.get(o)?.connected||t.push({type:"facility",id:o,ref:r,message:"This facility cannot receive items"});return t}function Bl(e){let t=Oe(e);for(let r of e.eggFarms||[]){let s=At(e,r,!1);if(!s?.scannerId)continue;let l=Rt(e,s.scannerId);if(ri(e,l))return[]}let n=e.eggFarms?.length||0,o=[...t.facilityPorts.entries()].filter(([r,s])=>s?.connected&&["mixer","trash","truck"].includes(Dn(e.facilities?.[r]))).length;return n?t.metrics.farmOutputs?e.scanners?.length?o?["Connect at least one EGG through a scanner to any valid exit."]:["Connect at least one receiver exit: Mixer, Shredder, or Truck."]:["Build at least one scanner and connect it to an EGG route."]:["Connect at least one EGG to a conveyor."]:["Build at least one EGG before starting the next day."]}function Rn(e){return e.kind==="manual"?`S${(e.slot??0)+1}`:`Auto Scanner #${e.id}`}function Ll(e,t=Oe(e),n={}){let o=n.includeRoutes!==!1,r=[],s={mixer:"Mixer",trash:"Shredder",truck:"Truck"};for(let l of nn){let d=Mo(e,l);if(!d.length){r.push(`${s[l]||l} is missing`);continue}for(let[v]of d)t.facilityPorts.get(v)?.connected||r.push(`${s[l]||l} receiver has no conveyor`)}for(let l of e.scanners){let d=t.scannerPorts.get(l.id)||{};if(d.inputA?.connected||r.push(`${Rn(l)} input has no conveyor`),d.left?.connected||r.push(`${Rn(l)} left output has no conveyor`),d.right?.connected||r.push(`${Rn(l)} right output has no conveyor`),!!o)for(let v of["left","right"])d[v]?.connected&&!oi(e,v,pe(l),l.id)&&r.push(`${Rn(l)} ${v} route is incomplete`)}if(o)for(let l of e.eggFarms)At(e,l)?.scannerId||r.push(`Egg Farm #${l.id} has no scanner route`);else for(let l of e.eggFarms)(t.farmOutputs.get(l.id)||[]).length||r.push(`Egg Farm #${l.id} has no output conveyor`);return[...new Set(r)]}function sn(e){return Bl(e)}function ii(e){return sn(e).length===0}var si=[{key:"premiumFemaleShipment",target:"female",truckTarget:"female",title:"Premium Female Shipment",route:"Female -> Truck",note:"Today only: ship female chicks to Truck. Meet the export target for a bonus.",objective:"truckTarget"},{key:"contaminantSampleExport",target:"poop",truckTarget:"poop",title:"Contaminant Sample Export",route:"Poop value x2",note:"Today only: poop is valid Truck cargo and all poop income is doubled.",objective:"truckTarget",poopValueMultiplier:2},{key:"healthInspection",title:"Health Inspection",route:"Poop -> Shredder",note:"Today only: poop mistakes are fined double. Shred enough poop for an inspection bonus.",objective:"poopTrash",poopFineMultiplier:2},{key:"conveyorJamWarning",title:"Conveyor Jam Warning",route:"No explosions",note:"Today only: jam explosions trigger at 85% congestion. Finish with zero explosions for a bonus.",objective:"noExplosion",congestionExplosionThreshold:.85,congestionWarningThreshold:.68},{key:"powerSavingOrder",title:"Power Saving Order",route:"Slow factory subsidy",note:"Today only: conveyors -20% speed and Auto Scanners +20% cooldown. A subsidy is paid at settlement.",objective:"flatBonus",conveyorSpeedMultiplier:.8,autoScannerCooldownMultiplier:1.2},{key:"overtimeDay",title:"Overtime Day",route:"80 second day",note:"Today only: the work day is longer. No extra reward or penalty.",objective:"none",daySeconds:80},{key:"shortShift",title:"Short Shift",route:"40 second day",note:"Today only: the work day is shorter. The next Fairies tribute is reduced by 10%.",objective:"none",daySeconds:40,fairiesTributeMultiplier:.9},{key:"chickBoom",title:"Chick Boom",route:"EGG interval x0.65",note:"Today only: eggs hatch faster and poop rate rises by 5 percentage points.",objective:"none",productionMultiplier:1/.65,poopRateAdd:.05},{key:"rottenFeed",title:"Rotten Feed",route:"Poop surge",note:"Today only: poop rate rises by 20 percentage points and Shredder poop income is multiplied by 1.5.",objective:"none",poopRateAdd:.2,shredderIncomeMultiplier:1.5},{key:"maintenanceAudit",title:"Maintenance Audit",route:"Durability check",note:"Today only: machines below 50% remaining durability fail the audit. Passing with none below 50% pays a bonus.",objective:"maintenanceAudit"}];function we(e,t=0){let n=Number(e);return Number.isFinite(n)?n:t}function Ol(e,t=0,n=1){let o=Math.max(1,Number(e?.turn||1)+1),r=Math.floor(Ao(e)*(.08+Math.random()*.08)),s=Math.floor(Math.max(0,e.cash||0)*.25),l=Math.floor(Math.max(0,t)*Math.max(1,o)*.75);return Math.max(120,Math.ceil(Math.max(r,s,l)*n))}function li(e){return Math.max(0,Math.ceil(500+Math.max(1,e?.turn||1)*25))}function Ao(e){return[...e.eggFarms.map(t=>t.price||0),...e.scanners.map(t=>t.price||0),...Object.values(e.facilities).map(t=>t.price||0),...[...e.conveyorMeta.values()].map(t=>t.price||0)].reduce((t,n)=>t+n,0)}function Nl(e,t=1,n=wt){return e.eggFarms.reduce((o,r)=>{let[s,l]=rn(r),d=Math.max(.1,(s+l)/2);return o+Math.max(1,n)/d*Math.max(.01,t||1)},0)}function _l(e,t){let n=we(t.productionMultiplier,1),o=we(t.daySeconds,wt),r=Nl(e,n,o),s=Math.max(0,Number(e?.cardEffects?.hatchingFeed)||0),l=Math.max(0,Number(e?.cardEffects?.poopRateBooster)||0),d=Math.pow(1.03,s),v=fo+po*l,C=Math.min(.95,Math.max(0,(v+we(t.poopRateAdd,0))*we(t.poopMultiplier,1)*d));return{estimate:r,poopRate:C}}function ai(e){if(e.turn+1Cr)return null;let n=si[Math.floor(Math.random()*si.length)],{estimate:o,poopRate:r}=_l(e,n),s=0;n.objective==="truckTarget"?s=Math.max(1,Math.ceil(o*.3)):n.objective==="poopTrash"&&(s=Math.max(1,Math.ceil(o*r*.8)));let l=0;return["truckTarget","poopTrash","noExplosion"].includes(n.objective)&&(l=Ol(e,o)),n.objective==="flatBonus"&&(l=li(e)),n.objective==="maintenanceAudit"&&(l=li(e)),{id:`event-${e.turn}-${Date.now()}-${Math.floor(Math.random()*9999)}`,...n,target:n.target||null,truckTarget:n.truckTarget||null,forced:!0,productionMultiplier:we(n.productionMultiplier,1),poopMultiplier:we(n.poopMultiplier,1),poopRateAdd:we(n.poopRateAdd,0),daySeconds:we(n.daySeconds,wt),targetAmount:s,estimatedOutput:Math.round(o),reward:l,createdTurn:e.turn,oneTurnOnly:!0}}function ci(e){e.eventActive=e.eventOffer?{...e.eventOffer}:null,e.eventOffer=null}function ui(e){e.eventActive=null}function di(e){return Math.max(1,we(e.eventActive?.daySeconds,wt))}function fi(e){return we(e.eventActive?.productionMultiplier,1)}function pi(e){let t=Math.max(0,Number(e?.cardEffects?.hatchingFeed)||0),n=Math.max(0,Number(e?.cardEffects?.poopRateBooster)||0),o=Math.pow(1.03,t),r=fo+po*n,s=we(e.eventActive?.poopRateAdd,0);return Math.min(.95,Math.max(0,(r+s)*we(e.eventActive?.poopMultiplier,1)*o))}function je(e){return e.eventActive?.truckTarget||e.eventActive?.target||"female"}function Do(e,t){return t==="male"?e.truckMale||0:t==="poop"?e.poopTruck||0:e.truckFemale||0}function yi(e,t){return je(e)===t}function hi(e){return je(e)!=="male"}function $o(e){return Math.max(.01,we(e.eventActive?.poopValueMultiplier,1))}function Fn(e){return Math.max(.01,$o(e)*we(e.eventActive?.shredderIncomeMultiplier,1))}function Io(e){return Math.max(.01,we(e.eventActive?.poopFineMultiplier,1))}function Fo(e){return Math.max(.1,Math.min(1,we(e.eventActive?.congestionExplosionThreshold,1)))}function mi(e){return Math.max(.1,Math.min(1,we(e.eventActive?.congestionWarningThreshold,.8)))}function bi(e){return Math.max(.01,we(e?.fairiesTributeMultiplier,1))}function Gl(e){let t=0,n=(o,r)=>{let s=Math.max(1,we(r,1)),l=Math.max(0,we(o,0));1-Math.min(1,l/s)<.5&&(t+=1)};for(let o of e.conveyorMeta?.values?.()||[])n(o.uses,o.durability);for(let o of e.eggFarms||[])n(o.maintenance?.uses,o.maintenance?.durability);for(let o of e.scanners||[])o.kind==="auto"&&n(o.maintenance?.uses,o.maintenance?.durability);for(let o of Object.values(e.facilities||{})){let r=o?.baseId||o?.id;(r==="mixer"||r==="trash")&&n(o.maintenance?.uses,o.maintenance?.durability)}return t}function vi(e){let t=e.eventActive;if(!t)return null;let n=0,o=!0,r=0,s="";t.objective==="truckTarget"?(n=Do(e.stats,t.target),o=n>=t.targetAmount,r=o?t.reward:0):t.objective==="poopTrash"?(n=e.stats.poopTrash||0,o=n>=t.targetAmount,r=o?t.reward:0):t.objective==="noExplosion"?(n=e.stats.explosions||0,o=n===0,r=o?t.reward:0,s=`${n} explosion(s)`):t.objective==="flatBonus"?(o=!0,r=t.reward):t.objective==="maintenanceAudit"?(n=Gl(e),o=n===0,o&&(r=t.reward),s=`${n} machine(s) below 50%`):o=!0,r>0?(Ne(e,r),e.stats.eventBonus=(e.stats.eventBonus||0)+r,e.totals.eventBonus+=r,e.totals.eventSuccess+=1):t.objective&&t.objective!=="none"&&(e.stats.eventBonus=e.stats.eventBonus||0,e.totals.eventFailed+=o?0:1,o&&(e.totals.eventSuccess+=1));let l={title:t.title,key:t.key,target:t.target,route:t.route,objective:t.objective,targetAmount:t.targetAmount||0,count:n,success:o,bonus:r,reward:t.reward||0,productionMultiplier:t.productionMultiplier,poopMultiplier:t.poopMultiplier,daySeconds:t.daySeconds,detail:s};return e.stats.eventResult=l,l}function Bo(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function Ul(e){return!!e?.cardEffects?.usedMachineActive}function Wl(e,t){return t?1:Math.min(.8,.5+.1*Math.min(3,Bo(e,"recyclingSubsidy")))}function Kl(e){return Math.pow(.95,Bo(e,"safetyCover"))}function Bn(e){let t=e?.ref||e||{},n=e?.type||t.type;return n==="conveyor"?t.price||ke[t.kind]?.price||ke.conveyor.price:n==="eggFarm"?t.price||ke.eggFarm.price:n==="scanner"?t.price||(t.kind==="auto"?ke.autoScanner.price:ke.manualScanner.price):n==="facility"?t.price||ke[t.id]?.price||0:ke[t.id]?.price||0}function _e(e,t=null){let n=ke[e]?.price||0;return Ul(t)?Math.ceil(n*.5):n}function Hl(e,t){return e?.facilities?Object.values(e.facilities).filter(n=>(n?.baseId||n?.id)===t).reduce((n,o)=>n+Math.max(0,(o.level||1)-1),0):0}function ut(e,t){return gr.includes(t)?Math.pow(xe.incomeUpgradeRate,Hl(e,t)):1}function Ye(e){return Math.ceil(xe.income.mixer*ut(e,"mixer"))}function $e(e){return Math.ceil(xe.income.truck*ut(e,"truck"))}function ln(e){return Math.ceil(xe.poopFine*ut(e,"mixer")*Io(e))}function an(e){return Math.ceil(xe.poopFine*ut(e,"truck")*Io(e))}function Lo(e){let t=xe.maleTruckFinePerHalfDay*(e.turn/2);return Math.ceil(t*ut(e,"truck"))}function Oo(e){return e?.facilities?Object.values(e.facilities).filter(t=>(t?.baseId||t?.id)==="trash").reduce((t,n)=>t+Math.max(0,(n.level||1)-1),0):0}function Dt(e){return Math.min(xe.shredderBonus.maxCards,Oo(e))}function Kt(){return xe.shredderBonus.maxCards}function dt(e){let t=typeof e=="number"?e:Dt(e),n=Math.min(xe.shredderBonus.maxCards,Math.max(0,t));return n>0?Math.ceil(n*(xe.shredderBonus.incomePerUpgrade||1)):0}function ql(e){let t=Dt(e),n=dt(t),o=Math.ceil(n*Fn(e));return{cards:t,chance:o>0?1:0,amount:o,expected:o,baseAmount:n}}function wi(e){let t=ql(e);return t.amount>0&&(e.stats.shredderBonus=(e.stats.shredderBonus||0)+t.amount,e.totals.shredderBonus=(e.totals.shredderBonus||0)+t.amount,Ne(e,t.amount)),t}function Ln(e,t=e.turn,n=null){let o=Math.max(1,Math.floor(Number(t)||1)),r=xe.fairiesTribute||{perDay:10,profitExemption:300,legalWorkExemptionBonus:250,profitRate:.12},s=Math.ceil(o*(r.perDay||10)),l=Math.max(0,Math.floor(Number(n??e?.lastResult?.profit??e?.stats?.profit??0)||0)),d=Math.max(0,e?.cardEffects?.legalWork||0),v=Math.max(0,(r.profitExemption||0)+d*(r.legalWorkExemptionBonus||0)),C=Math.max(0,l-v),P=Math.ceil(C*Math.max(0,Number(r.profitRate)||0)),R=s+P,L=Math.max(0,e?.cardEffects?.fairiesFlatteryNext||e?.cardEffects?.flattery||0),V=L>0?Math.pow(.5,L):1,te=Math.max(.01,Number(e?.pendingFairiesTributeMultiplier)||1),z=V*te,se=Math.max(0,Math.ceil(R*z)),ye=Math.max(0,R-se);return{day:o,base:s,profit:l,legalWork:d,profitExemption:v,taxableProfit:C,profitTribute:P,gross:R,flatteryCount:L,eventMultiplier:te,perCardReduction:Math.ceil(R*.5),reduction:ye,amount:se}}function $t(e,t){let n=e?.ref||e||{},o=e?.type==="conveyor"?t?.conveyorMeta?.get(e.oldKey||n.id):n,r=o?.price||Bn(e||n),s=o?.builtSession===t?.buildSession;if(o?.noRefund||n?.noRefund)return{amount:0,sameBuild:s,price:r,rate:0,noRefund:!0};let l=Wl(t,s);return{amount:Math.max(0,Math.ceil(r*l)),sameBuild:s,price:r,rate:l,noRefund:!1}}function Yl(e,t=null){let n=Math.max(1,Math.ceil((Number(e)||0)/xe.explosionDamageDivisor));return Math.max(1,Math.ceil(n*Kl(t)))}function Vl(e,t){return Math.max(0,Math.ceil(t))}function Si(e,t){e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,t>=0?(e.stats.revenue+=t,e.totals.revenue+=t):(e.stats.penalty+=Math.abs(t),e.totals.penalty+=Math.abs(t)),e.totals.maxCash=Math.max(e.totals.maxCash,e.cash)}function Ne(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&Si(e,n),n}function ft(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&Si(e,-n),n}function pt(e,t){ft(e,t)}function ki(e,t){t<=0||(e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,e.totals.maxCash=Math.max(e.totals.maxCash,e.cash))}function xi(e){let t=Ye(e);return e.stats.mixerRevenue+=t,Ne(e,t),t}function Ci(e){let t=ln(e);return e.stats.mixerPoopFine+=t,e.totals.mixerPoopFine+=t,ft(e,t),t}function Mi(e){let t=an(e);return e.stats.truckPoopFine+=t,e.totals.truckPoopFine+=t,ft(e,t),t}function gi(e){let t=Lo(e);return e.stats.maleTruckFine+=t,e.totals.maleTruckFine+=t,ft(e,t),t}function Ti(e,t){let n=Yl(t,e);return e.stats.explosionDamage+=n,e.totals.explosionDamage+=n,ft(e,n),n}function Ei(e){let t=je(e),n=Do(e.stats,t),o=t==="poop"?Math.ceil($e(e)*$o(e)):$e(e),r=n*o,s=Vl(e,r);return e.stats.pendingTruckRevenue=s,e.stats.truckRevenue=s,t==="poop"?e.stats.poopShipmentIncome=s:e.stats.chickShipmentIncome=s,s>0&&Ne(e,s),{base:r,adjusted:s,target:t,targetCount:n,unitPrice:o}}function Pi(e,t=e.turn,n=null,o={}){let r=Ln(e,t,n);return e.cardEffects&&(e.cardEffects.fairiesFlatteryNext=0,e.cardEffects.flattery!=null&&delete e.cardEffects.flattery),e.pendingFairiesTributeMultiplier!=null&&(e.pendingFairiesTributeMultiplier=1),r.amount<=0||(o.recordStats?(e.stats.fairiesTribute=(e.stats.fairiesTribute||0)+r.amount,e.totals.fairiesTribute=(e.totals.fairiesTribute||0)+r.amount,ft(e,r.amount)):(e.totals.fairiesTribute=(e.totals.fairiesTribute||0)+r.amount,e.totals.penalty=(e.totals.penalty||0)+r.amount,e.totals.profit=(e.totals.profit||0)-r.amount,e.cash-=r.amount)),r}function Ri(e){let t=Bo(e,"chemicalWeaponSubsidy"),n=Math.max(0,e?.stats?.poopTruck||0),o=xe.chemicalWeaponSubsidy||{poopPerBlock:70,yenPerBlock:1200},r=Math.floor(n/Math.max(1,o.poopPerBlock||70)),s=t>0&&r>0?r*Math.max(0,o.yenPerBlock||1200)*t:0;return s>0&&(e.stats.chemicalWeaponSubsidy=(e.stats.chemicalWeaponSubsidy||0)+s,e.totals.chemicalWeaponSubsidy=(e.totals.chemicalWeaponSubsidy||0)+s,Ne(e,s)),{cards:t,poopTruck:n,blocks:r,amount:s}}function Ai(e){let t=Ao(e),n=Math.max(1,e.totals.turnsCompleted||e.turn||1),o=Math.max(0,e.cash+e.totals.revenue+t*.5+e.totals.eventBonus*.5),r=Math.ceil(o/n),s=Math.floor(n*35+Math.max(0,n-5)*15),l=e.totals.correct*5,d=e.totals.explosionDamage;return{score:Math.max(0,Math.floor(o+r+l-e.totals.penalty-s)),factoryValue:t,base:o,dailyEarned:r,dayPenalty:s,correctBonus:l,explosionPenalty:d,days:n}}function zl(e){return{...e,keys:e.keys?{left:{...e.keys.left},right:{...e.keys.right}}:null,queue:[],cooldown:e.cooldown||0}}function cn(e){return JSON.stringify({cash:e.cash,stats:e.stats,totals:e.totals,nextId:e.nextId,gridX:y.x,gridY:y.y,gridCols:e.gridCols||y.cols,gridRows:e.gridRows||y.rows,gridExpansionPurchases:e.gridExpansionPurchases||0,gridExpansionPurchasesByDirection:e.gridExpansionPurchasesByDirection||{right:0,up:0},gridChunkOriginY:e.gridChunkOriginY||0,ownedCells:[...e.ownedCells||[]],ownedChunks:[...e.ownedChunks||[]],blockedCells:[...e.blockedCells||[]],selected:e.selected,multiSelected:e.multiSelected||[],buildTool:e.buildTool,view:e.view,facilities:e.facilities,eggFarms:e.eggFarms,scanners:e.scanners.map(zl),conveyorTiles:[...e.conveyorTiles],conveyorMeta:[...e.conveyorMeta.entries()],branchCounters:[...e.branchCounters.entries()],cardEffects:e.cardEffects,cardDraft:e.cardDraft,cardTargetPick:e.cardTargetPick})}function Di(e,t){let n=JSON.parse(t);e.cash=n.cash,e.stats=n.stats,e.totals=n.totals,e.nextId=n.nextId,y.x=n.gridX??q.grid.x,y.y=n.gridY??q.grid.y,y.cols=n.gridCols||q.grid.cols,y.rows=n.gridRows||q.grid.rows,e.gridCols=y.cols,e.gridRows=y.rows,e.gridExpansionPurchases=n.gridExpansionPurchases||0,e.gridExpansionPurchasesByDirection=n.gridExpansionPurchasesByDirection||{right:0,up:0},e.gridChunkOriginY=n.gridChunkOriginY||0,e.ownedCells=new Set(n.ownedCells||[]),e.ownedChunks=new Set(n.ownedChunks||[]),e.gridOwnedCells=e.ownedCells.size||y.cols*y.rows,e.blockedCells=new Set(n.blockedCells||[]),e.selected=n.selected,e.multiSelected=n.multiSelected||[],e.buildTool=n.buildTool,e.view=n.view||{x:0,y:0,scale:1},e.view.scale==null&&(e.view.scale=1),e.facilities=n.facilities||{},e.eggFarms=n.eggFarms||[],e.scanners=(n.scanners||[]).map(o=>({...o,queue:[],cooldown:o.cooldown||0})),e.conveyorTiles=new Set(n.conveyorTiles||[]),e.conveyorMeta=new Map(n.conveyorMeta||[]),e.branchCounters=new Map(n.branchCounters||[]),e.cardEffects=n.cardEffects||{bearing:0,legalWork:0,fairiesFlatteryNext:0,scannerQueueSpacing:0},e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft=n.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardTargetPick=n.cardTargetPick||null,e.groupDrag=null,e.selectionBox=null,e.pan=null,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function Fe(e){e.phase==="build"&&(e.undoStack.push(cn(e)),e.undoStack.length>80&&e.undoStack.shift(),e.redoStack=[])}function No(e){return e.phase!=="build"||!e.undoStack.length?!1:(e.redoStack.push(cn(e)),Di(e,e.undoStack.pop()),!0)}function _o(e){return e.phase!=="build"||!e.redoStack.length?!1:(e.undoStack.push(cn(e)),Di(e,e.redoStack.pop()),!0)}function W(e,t,n,o,r=p.ink){e.floatingTexts.push({x:t,y:n,text:o,color:r,life:1,maxLife:1})}function It(e,t,n){e.shake.strength=Math.max(e.shake.strength,t),e.shake.time=Math.max(e.shake.time,n)}function $i(e,t,n){e.effects.push({type:"spawn",priority:Ce.ambient,x:t,y:n,life:.42,maxLife:.42,size:12})}function Ii(e,t,n,o=p.green){e.effects.push({type:"scannerPulse",priority:Ce.important,x:t,y:n,color:o,life:.42,maxLife:.42,size:24})}function Fi(e,t,n){for(let o=0;o<12;o+=1)e.effects.push({type:"meat",priority:Ce.important,x:t+G(-18,18),y:n+G(-12,16),vx:G(-60,60),vy:G(-90,-25),life:G(.45,.85),maxLife:.85,size:G(4,8)})}function Bi(e,t,n){for(let o=0;o<16;o+=1)e.effects.push({type:"sludge",priority:Ce.important,x:t+G(-18,18),y:n+G(-12,16),vx:G(-46,46),vy:G(-70,-20),life:G(.45,.9),maxLife:.9,size:G(4,8)})}function Li(e,t,n,o){let r=o==="poop"?p.poop:o==="male"?p.male:p.female;for(let s=0;s<22;s+=1)e.effects.push({type:"shred",priority:Ce.important,x:t+G(-16,16),y:n+G(-8,8),vx:G(-70,70),vy:G(40,160),color:s%3===0?p.white:r,life:G(.45,.95),maxLife:.95,w:G(3,7),h:G(10,24),rot:G(-Math.PI,Math.PI)});Ve(e,t,n,p.green,34,Ce.important)}function Oi(e,t,n,o){let r=o==="poop"?p.poop:o==="male"?p.danger:p.green;for(let s=0;s<8;s+=1)e.effects.push({type:"load",priority:Ce.important,x:t+G(-18,18),y:n+G(-18,18),vx:G(-42,42),vy:G(-90,-25),color:r,life:G(.35,.65),maxLife:.65,size:8})}function Ve(e,t,n,o=p.danger,r=52,s=Ce.critical){e.effects.push({type:"shockwave",priority:s,x:t,y:n,color:o,life:.55,maxLife:.55,size:8,maxSize:r})}function Ze(e,t,n,o=12,r=p.danger,s=Ce.critical){for(let l=0;l0&&(e.shake.time=Math.max(0,e.shake.time-t),e.shake.time<=0&&(e.shake.strength=0));for(let r of e.effects)if(r.life-=t,["meat","sludge","spark","smoke","shred","load","rage"].includes(r.type))r.x+=(r.vx||0)*t,r.y+=(r.vy||0)*t,r.vy=(r.vy||0)+150*t;else if(r.type==="flyingChick"){r.x+=r.vx*t,r.y+=r.vy*t,r.vy+=360*t,r.noDamage||Xl(e,r,o);let s=r.x+e.view.x,l=r.y+e.view.y;(s<-100||l<-100||s>n.width+100||l>n.height+100)&&(r.life=0)}e.effects=e.effects.filter(r=>r.life>0);for(let r of e.floatingTexts)r.life-=t,r.y-=34*t;e.floatingTexts=e.floatingTexts.filter(r=>r.life>0)}function Xl(e,t,n){t.hit||(t.hit=new Set);for(let o of n()){if(t.hit.has(o.id)||t.xo.x+o.w||t.yo.y+o.h)continue;t.hit.add(o.id);let r=Ti(e,o.price);W(e,t.x,t.y-10,`-${M(r)}`,p.danger),Ve(e,t.x,t.y,p.danger,30),Ze(e,t.x,t.y,5,p.danger),It(e,5,.18)}}var Be=q.maintenance;function Uo(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function Gn(e){let t=Math.min(1.4,1+.04*Math.min(10,Uo(e,"crowdedFarming"))),n=Math.pow(.95,Uo(e,"preventiveMaintenance"));return t*n}function Ql(e){return Math.pow(1.03,Uo(e,"durabilityCoating"))}function Un(e,t,n=1){let o=Be.durability[t]||1e3;return Math.max(1,Math.ceil(o*Math.max(.1,n||1)*Ql(e)))}function Ho(e){let t=Be.repairman.dailyCost;return e?.cardEffects?.laborExploitation?Math.ceil(t*.7):t}function Gi(e){return Math.max(.1,Number(e?.durabilityBaseMultiplier)||1)}function me(e){e.repairman||(e.repairman={hiredForNextDay:!1,active:!1,x:y.x+y.cell*.5,y:y.y+y.rows*y.cell+84,target:null,repairedToday:0});for(let[t,n]of e.conveyorMeta||[]){n.uses==null&&(n.uses=0),n.maintenanceType==null&&(n.maintenanceType="conveyor"),n.kind||(n.kind="conveyor"),n.speedMultiplier||(n.speedMultiplier=n.kind==="boostConveyor"?2:1),n.branchMode||(n.branchMode="random");let o=Un(e,"conveyor",Gi(n));(n.durability==null||n.durability0&&(n.processingCooldown=Math.max(0,n.processingCooldown-t))}function Yn(e){me(e);let t=[];for(let[n,o]of e.conveyorMeta||[])t.push({type:"conveyor",key:n,meta:o,label:`${o.kind==="boostConveyor"?"Boost Belt":"Belt"} ${n}`,center:F(Q(n).col,Q(n).row)});for(let n of e.eggFarms||[])t.push({type:"eggFarm",ref:n,label:`EGG #${n.id}`,center:F(n.col,n.row)});for(let n of(e.scanners||[]).filter(o=>o.kind==="auto"))t.push({type:"autoScanner",ref:n,label:`AUTO #${n.id}`,center:F(n.col,n.row)});for(let n of Object.values(e.facilities||{})){let o=qn(n);["mixer","trash"].includes(o)&&t.push({type:o,ref:n,label:`${n.shortName||n.name||o} #${n.id}`,center:{x:n.x+n.w/2,y:n.y+n.h/2}})}return t}function Nn(e){return e.meta?Ht(e):Ht(e.ref)}function un(e){return e.meta?Wo(e):Wo(e.ref)}function _n(e){return e.meta?Ko(e):Ko(e.ref)}function qi(e,t){Jl(e.meta?e:e.ref,Math.max(0,un(e)-t))}function Yi(e){return e.type==="conveyor"?`conveyor:${e.key}`:`${e.type}:${e.ref?.id||e.ref?.type||e.type}`}function Vi(e,t=.02){me(e);let n=Math.max(0,Number(t)||0),o=0;for(let r of Yn(e)){let s=un(r);qi(r,_n(r)*n),o+=Math.max(0,s-un(r))/_n(r)*100}return o}function zi(e){if(me(e),e.repairman.hiredForNextDay)return{ok:!1,reason:"Repairman already hired."};let t=Ho(e);return e.cashYi(o)===t.key)||null}function ea(e){let t=null;for(let n of Yn(e)){let o=Nn(n);o<=.001||(!t||o>Nn(t))&&(t=n)}return t}function Ji(e,t){me(e);let n=e.repairman;if(!n.active||e.phase!=="running")return;let o=Zl(e,n.target)||ea(e);if(!o){n.target=null;return}n.target={key:Yi(o),label:o.label};let r=Be.repairman.walkSpeed,s=o.center.x-n.x,l=o.center.y-n.y,d=Math.hypot(s,l);if(d>8){let L=Math.min(d,r*t);n.x+=s/d*L,n.y+=l/d*L;return}let v=t/(Be.repairman.secondsPerOnePercent*100),C=un(o),P=v*_n(o);qi(o,P);let R=Math.max(0,(C-un(o))/_n(o)*100);n.repairedToday=(n.repairedToday||0)+R,R>0&&Math.random()<.02&&W(e,n.x,n.y-28,"REPAIR",p.green),Nn(o)<=.001&&(n.target=null)}function ta(e){let t=0,n="none";for(let o of Yn(e)){let r=Nn(o);r>t&&(t=r,n=o.label)}return{ratio:t,percent:Math.round(t*100),label:n}}function jo(e){let t=ta(e),n=Yo(e);return{worst:t,avgBeltPerformance:n,repairman:e.repairman||null}}var na=Ae.commonWeight,oa=Ae.rareWeight,ra=Ae.ultraRareWeight||.45,Ft=Ae.baseDraftSize,Yt=Mr;function qt(e,t){let n=Ie(e);return Math.max(0,Number(n[t])||0)}function Ie(e){e.cardEffects||(e.cardEffects={...yo});for(let[t,n]of Object.entries(yo))e.cardEffects[t]==null&&(e.cardEffects[t]=Array.isArray(n)?[]:n);return e.cardEffects.flattery!=null&&(e.cardEffects.fairiesFlatteryNext=Math.max(0,e.cardEffects.fairiesFlatteryNext||0)+Math.max(0,e.cardEffects.flattery||0),delete e.cardEffects.flattery),e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft||(e.cardDraft={pending:!1,choices:[],rerolls:0,picksRemaining:0}),e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardEffects}function is(e){let t=Math.max(.5,1-.05*Math.min(10,qt(e,"crowdedFarming"))),n=Math.pow(.96,qt(e,"hatchingFeed"));return t*n}function ss(e,t=null){return Math.min(3,Math.max(0,Number(t?.extraEggOutlet)||0))}function ls(e){return Math.pow(.85,qt(e,"scannerQueueSpacing"))}function zn(e,t=null){let n=Ie(e),o=xn*Math.pow(Cn,Math.max(0,n.bearing||0)),r=t?Math.max(.1,Number(e?.conveyorMeta?.get?.(t)?.speedMultiplier)||1):1,s=t?1:Yo(e),l=Math.max(.01,Number(e?.eventActive?.conveyorSpeedMultiplier)||1);return Math.min(_t,o*s)*r*l}function tt(e,t=null){let n=Math.max(0,(e?.level||1)-1),o=t?qt(t,"autoScannerTuning"):0,r=kn*Math.pow(xr,n)*Math.pow(co,o),s=Math.max(uo,r),l=t?Math.max(.01,Number(t?.eventActive?.autoScannerCooldownMultiplier)||1):1;return t?Math.max(uo,s*Kn(e)*l):s}function ji(e){let t=e.cardDraft||{rerolls:0},n=Math.max(1,(t.rerolls||0)+1);return Math.ceil(Math.max(1,e.turn||1)/Ae.rerollCost.dayDivisor*n*Ae.rerollCost.multiplier)}function Vt(e){return Yt.find(t=>t.id===e)||null}function as(e,t){let n=typeof t=="string"?Vt(t):t;return Ie(e),!n||!(n.type==="equipmentUpgrade"||n.type==="cellAction")?[]:Ue(e,n).map(o=>({key:et(o),label:tr(e,o),type:o.type}))}function er(e,t,n={}){let o=typeof t=="string"?Vt(t):t;if(Ie(e),!o||o.type==="dud")return{ok:!1,reason:"Card not found."};if(o.id==="extraCards")return e.cardDraft=e.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.choices.push(...Vn(e,2)),{ok:!0,reason:`${o.title} added 2 draft cards.`};if(o.type==="instant")return us(e,o),{ok:!0,reason:`${o.title} granted.`};if(o.type==="equipmentUpgrade"){let r=Ue(e,o);if(!r.length)return{ok:!1,reason:`No valid target for ${o.title}.`};let s=n.targetKey&&n.targetKey!=="__auto__"?String(n.targetKey):"",l=s?r.find(d=>et(d)===s):r[0];return l?(cs(e,l),{ok:!0,reason:`${o.title} applied to ${tr(e,l)}.`}):{ok:!1,reason:`Selected target is no longer valid for ${o.title}.`}}if(o.type==="cellAction"&&o.target==="blockedCell"){let r=Ue(e,o);if(!r.length)return{ok:!1,reason:"No blocked cells to remove."};let s=new Set((Array.isArray(n.targetKeys)?n.targetKeys:[n.targetKey]).filter(d=>d&&d!=="__auto__").map(String)),l=s.size?r.filter(d=>s.has(et(d))):r.slice(0,3);if(!l.length)return{ok:!1,reason:`Selected target is no longer valid for ${o.title}.`};for(let d of l.slice(0,3)){e.blockedCells.delete(I(d.col,d.row));let v=F(d.col,d.row);yt(e,v.x,v.y),Ve(e,v.x,v.y,p.danger,42),Ze(e,v.x,v.y,8,p.warn)}return ve(e),{ok:!0,reason:`${o.title} removed ${Math.min(3,l.length)} blocked cell(s).`}}return{ok:!1,reason:`${o.title} cannot be debug-granted.`}}function tr(e,t){if(t.type==="blockedCell")return`Blocked cell ${t.col},${t.row}`;if(t.type==="eggFarm")return`EGG #${t.id} L${t.level} -> L${t.level+1}`;if(t.type==="eggOutlet"){let n=Math.max(0,Number(t.farm?.extraEggOutlet)||0);return`EGG #${t.id} OUTLET ${1+n} -> ${2+n}`}if(t.type==="scanner")return`AUTO #${t.id} L${t.level} -> L${t.level+1} | CD ${tt(t,e).toFixed(1)}s -> ${tt({...t,level:t.level+1},e).toFixed(1)}s`;if(t.type==="facility"&&(t.baseId||t.id)==="mixer"){let n=t.level,o=Ye(e);t.level=n+1;let r=Ye(e);return t.level=n,`MIXER L${t.level} -> L${t.level+1} | ${M(o)} -> ${M(r)}`}if(t.type==="facility"&&(t.baseId||t.id)==="truck"){let n=t.level,o=$e(e);t.level=n+1;let r=$e(e);return t.level=n,`TRUCK L${t.level} -> L${t.level+1} | ${M(o)} -> ${M(r)}`}if(t.type==="facility"&&t.id==="trash"){let n=Dt(e),o=Math.min(Kt(),n+1),r=dt(n),s=dt(o);return`SHREDDER L${t.level||1} -> L${(t.level||1)+1} | poop income ${M(r)} -> ${M(s)} per item`}return`${t.name||t.id} L${t.level||1} -> L${(t.level||1)+1}`}function ia(e){return[...e.blockedCells||[]].map(t=>{let[n,o]=String(t).split(",").map(Number);return{type:"blockedCell",id:t,col:n,row:o}}).filter(t=>Number.isFinite(t.col)&&Number.isFinite(t.row))}function Ue(e,t){let n=typeof t=="string"?Vt(t):t;return Ie(e),n?n.target==="blockedCell"?ia(e):n.target==="eggFarm"?e.eggFarms.filter(o=>(o.level||1)<4):n.target==="eggOutlet"?e.eggFarms.filter(o=>Math.max(0,Number(o.extraEggOutlet)||0)<3).map(o=>({type:"eggOutlet",id:o.id,col:o.col,row:o.row,farm:o})):n.target==="autoScanner"?e.scanners.filter(o=>o.kind==="auto"):n.target==="mixer"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="mixer"):n.target==="truck"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="truck"):n.target==="trash"?Oo(e)(o.baseId||o.id)==="trash"):[]:[]:[]}function sa(e,t){let n=Ie(e);if(t.id==="crowdedFarming")return(n.crowdedFarming||0)>=10;if(t.id==="recyclingSubsidy")return(n.recyclingSubsidy||0)>=3;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,Ae.dudChancePerCard||0)),r=Math.max(1e-4,Math.min(1,Ae.dudChanceReductionPerFilter||.05));return(n.dudFilter||0)>=Math.ceil(o/r)}return t.id==="laborExploitation"?!!n.laborExploitation:t.id==="usedMachine"?!!n.usedMachineActive:t.id==="newMachine"?!n.usedMachineActive:!1}function la(e){let t=e.repairman||{};return!!(t.active||t.hiredForNextDay||e.pendingRepairWorkerWages>0)}function aa(e){return Yt.filter(t=>!(t.id==="laborExploitation"&&!la(e)||sa(e,t)||(t.type==="equipmentUpgrade"||t.type==="cellAction")&&Ue(e,t).length<=0))}function Zi(e,t){return t.rarity==="ultraRare"?ra:t.rarity==="rare"?oa:na}function ca(e,t){let n=t.reduce((r,s)=>r+Zi(e,s),0);if(n<=0)return t[Math.floor(Math.random()*t.length)];let o=Math.random()*n;for(let r of t)if(o-=Zi(e,r),o<=0)return r;return t[t.length-1]}var es=0;function ua(){return es+=1,{id:`dud:${Date.now()}:${es}`,title:"Dud",rarity:"dud",type:"dud",description:"Click to flick this dud away. It does not consume a pick."}}function da(e){let t=Ie(e),n=Math.max(0,Math.min(1,Ae.dudChancePerCard||0)),o=Math.max(0,Math.min(1,Ae.dudChanceReductionPerFilter||0));return Math.max(0,n-o*Math.max(0,t.dudFilter||0))}function fa(e,t){let n=[...t],o=0,r=Math.max(0,Ae.maxDudsPerDraft||0),s=da(e);for(let l=0;ld.id===s.id);l>=0&&r.splice(l,1)}return fa(e,o)}function et(e){return e?e.type==="blockedCell"?`blockedCell:${e.id}`:e.type==="eggFarm"?`eggFarm:${e.id}`:e.type==="eggOutlet"?`eggOutlet:${e.id}`:e.type==="scanner"?`scanner:${e.id}`:e.type==="facility"?`facility:${e.id}`:`${e.type}:${e.id}`:""}function ts(e){if(!e)return null;if(e.type==="blockedCell"){let t=F(e.col,e.row);return{x:t.x-y.cell*.48,y:t.y-y.cell*.48,w:y.cell*.96,h:y.cell*.96,cx:t.x,cy:t.y}}if(e.type==="eggFarm"||e.type==="eggOutlet"){let t=F(e.col,e.row);return{x:t.x-34,y:t.y-34,w:68,h:68,cx:t.x,cy:t.y}}if(e.type==="scanner"){let t=pe(e);return{x:t.x-54,y:t.y-77,w:108,h:154,cx:t.x,cy:t.y}}return e.type==="facility"?{x:e.x,y:e.y,w:e.w,h:e.h,cx:e.x+e.w/2,cy:e.y+e.h/2}:null}function nr(e){if(!e.cardTargetPick?.pending)return[];if(e.cardTargetPick.mode==="autoScannerMenu"){let n=new Set(e.cardTargetPick.targetKeys||[]);return e.scanners.filter(o=>o.kind==="auto"&&n.has(et(o))).map(o=>({key:et(o),label:"AUTO ROUTE SETTINGS",target:o,bounds:ts(o)})).filter(o=>o.bounds)}let t=new Set(e.cardTargetPick.targetKeys||[]);return Ue(e,e.cardTargetPick.cardId).filter(n=>t.has(et(n))).map(n=>({key:et(n),label:tr(e,n),target:n,bounds:ts(n)})).filter(n=>n.bounds)}function pa(e,t){let n=nr(e);for(let o of n){let r=o.bounds;if(t.x>=r.x&&t.x<=r.x+r.w&&t.y>=r.y&&t.y<=r.y+r.h)return o.target}return null}function cs(e,t){if(t.type==="eggOutlet"){let n=t.farm||e.eggFarms.find(r=>r.id===t.id);if(!n)return;n.extraEggOutlet=Math.min(3,Math.max(0,Number(n.extraEggOutlet)||0)+1);let o=F(n.col,n.row);W(e,o.x,o.y-30,`OUTLET ${1+n.extraEggOutlet}`,p.green),ve(e);return}if(t.level=(t.level||1)+1,t.type==="eggFarm"){t.nextSpawn=gt(t),t.lastInterval=t.nextSpawn;let n=F(t.col,t.row);W(e,n.x,n.y-30,`LV ${t.level}`,p.green);return}if(t.type==="scanner"){let n=pe(t);W(e,n.x,n.y-34,`LV ${t.level}`,p.green);return}t.type==="facility"&&W(e,t.x+t.w/2,t.y+18,`LV ${t.level}`,p.green)}function us(e,t){let n=Ie(e),o=r=>{n[r]=Math.max(0,n[r]||0)+1};if(t.id==="bearing"&&o("bearing"),t.id==="autoScannerTuning"&&o("autoScannerTuning"),t.id==="legalWork"&&o("legalWork"),t.id==="crowdedFarming"&&(n.crowdedFarming=Math.min(10,(n.crowdedFarming||0)+1)),t.id==="hatchingFeed"&&o("hatchingFeed"),t.id==="poopRateBooster"&&o("poopRateBooster"),t.id==="safetyCover"&&o("safetyCover"),t.id==="recyclingSubsidy"&&(n.recyclingSubsidy=Math.min(3,(n.recyclingSubsidy||0)+1)),t.id==="chemicalWeaponSubsidy"&&o("chemicalWeaponSubsidy"),t.id==="preventiveMaintenance"&&o("preventiveMaintenance"),t.id==="dudFilter"&&o("dudFilter"),t.id==="durabilityCoating"&&(o("durabilityCoating"),me(e)),t.id==="sparePartsBin"){o("sparePartsBin");let r=Vi(e,.02);e.stats.sparePartsRepair=(e.stats.sparePartsRepair||0)+r,e.totals.sparePartsRepair=(e.totals.sparePartsRepair||0)+r,W(e,y.x+y.cols*y.cell/2,y.y-30,"REPAIR +2%",p.green)}t.id==="dudRefund"&&o("dudRefund"),t.id==="freeReroll"&&o("freeReroll"),t.id==="composter"&&o("composter"),t.id==="scannerQueueSpacing"&&o("scannerQueueSpacing"),t.id==="flattery"&&o("fairiesFlatteryNext"),t.id==="usedMachine"&&(n.usedMachineActive=!0),t.id==="newMachine"&&(n.usedMachineActive=!1),t.id==="laborExploitation"&&(n.laborExploitation=1),t.id==="rescueLoan"&&(o("rescueLoanCharges"),W(e,y.x+y.cols*y.cell/2,y.y-30,"RESCUE HELD",p.green))}function Ke(e){return`${Math.round(Number(e||0)*100)}%`}function ns(e){let t=lt[Math.max(0,Math.min(lt.length-1,e-1))]||lt[0]||[0,0];return`${t[0].toFixed(2)}-${t[1].toFixed(2)}s`}function os(e,t){return Math.ceil(e*Math.pow(xe.incomeUpgradeRate,Math.max(0,t-1)))}function rs(e,t,n){let r=Ue(e,t==="mixer"?"upgradeMixer":"upgradeTruck")[0];if(!r)return{before:os(n,1),after:os(n,2)};let s=t==="mixer"?Ye(e):$e(e),l=r.level||1;r.level=l+1;let d=t==="mixer"?Ye(e):$e(e);return r.level=l,{before:s,after:d}}function ya(e,t){let n=Ie(e);if(t.id==="upgradeEgg"){let o=Ue(e,t),r=Math.min(3,Math.max(1,o[0]?.level||1));return`Choose one EGG. Level +1. Production interval ${ns(r)} -> ${ns(r+1)}.`}if(t.id==="upgradeAutoScanner"){let o=Ue(e,t)[0]||{level:1},r=tt(o,e),s=tt({...o,level:(o.level||1)+1},e);return`Choose one AUTO SCANNER. Level +1. Cooldown ${r.toFixed(2)}s -> ${s.toFixed(2)}s.`}if(t.id==="upgradeMixer"){let o=rs(e,"mixer",xe.income.mixer);return`Choose one MIXER. Earning +10%. Male-chick income ${M(o.before)} -> ${M(o.after)}.`}if(t.id==="upgradeTruck"){let o=rs(e,"truck",xe.income.truck);return`Choose one TRUCK. Earning +10%. Correct shipment income ${M(o.before)} -> ${M(o.after)}.`}if(t.id==="upgradeTrash"){let o=Dt(e),r=Math.min(Kt(),o+1),s=dt(o),l=dt(r);return`SHREDDER level +1. Poop income ${M(s)} -> ${M(l)} per item.`}if(t.id==="bearing"){let o=Math.min(_t,xn*Math.pow(Cn,Math.max(0,n.bearing||0))),r=Math.min(_t,xn*Math.pow(Cn,Math.max(0,(n.bearing||0)+1)));return`Conveyor speed +7.5%. After pick: ${o.toFixed(1)} -> ${r.toFixed(1)} px/s.`}if(t.id==="legalWork"){let o=Math.max(0,n.legalWork||0);return`Fairies tribute profit exemption +${M(250)}. After pick: exemption bonus ${M(250*(o+1))}.`}if(t.id==="crowdedFarming"){let o=Math.min(10,(n.crowdedFarming||0)+1);return`Held ${n.crowdedFarming||0}/10. After pick: EGG interval ${Ke(Math.max(.5,1-.05*o))}, deterioration ${Ke(Math.min(1.4,1+.04*o))}.`}if(t.id==="extraEggOutlet"){let o=Ue(e,t),r=Math.max(0,Number(o[0]?.farm?.extraEggOutlet)||0);return`Choose one EGG. Output ports ${1+r} -> ${2+r}. Max 4 ports per EGG.`}if(t.id==="hatchingFeed")return`Held ${n.hatchingFeed||0}. After pick: EGG interval ${Ke(Math.pow(.96,(n.hatchingFeed||0)+1))}, poop rate multiplier ${Ke(Math.pow(1.03,(n.hatchingFeed||0)+1))}.`;if(t.id==="poopRateBooster")return`Held ${n.poopRateBooster||0}. After pick: base poop rate +${Math.round((n.poopRateBooster||0)+1)*4} percentage points.`;if(t.id==="autoScannerTuning")return`Held ${n.autoScannerTuning||0}. After pick: all AUTO SCANNER default cooldown ${Ke(Math.pow(co,(n.autoScannerTuning||0)+1))}.`;if(t.id==="safetyCover")return`Held ${n.safetyCover||0}. After pick: explosion damage ${Ke(Math.pow(.95,(n.safetyCover||0)+1))}.`;if(t.id==="recyclingSubsidy")return`Held ${n.recyclingSubsidy||0}/3. After pick: normal SELL refund ${Math.round(Math.min(.8,.5+.1*((n.recyclingSubsidy||0)+1))*100)}%.`;if(t.id==="chemicalWeaponSubsidy")return`Held ${n.chemicalWeaponSubsidy||0}. After pick: ${M(1200*((n.chemicalWeaponSubsidy||0)+1))} per 70 truck-shipped poop each day.`;if(t.id==="preventiveMaintenance")return`Held ${n.preventiveMaintenance||0}. After pick: deterioration speed ${Ke(Math.pow(.95,(n.preventiveMaintenance||0)+1))}.`;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,Ae.dudChancePerCard||0)),r=Math.max(0,Math.min(1,Ae.dudChanceReductionPerFilter||.05)),s=Math.max(0,n.dudFilter||0),l=Math.max(0,o-r*s),d=Math.max(0,o-r*(s+1));return`Held ${s}. DUD chance per card ${Ke(l)} -> ${Ke(d)}.`}return t.id==="durabilityCoating"?`Held ${n.durabilityCoating||0}. After pick: maximum durability ${Ke(Math.pow(1.03,(n.durabilityCoating||0)+1))}.`:t.id==="sparePartsBin"?`Held ${n.sparePartsBin||0}. Immediately restores 2% durability to every maintained machine. Common card weight.`:t.id==="dudRefund"?`Held ${n.dudRefund||0}. After pick: DUD clicks award ${M(50*((n.dudRefund||0)+1))}.`:t.id==="freeReroll"?`Held ${n.freeReroll||0}. After pick: each card screen starts with ${(n.freeReroll||0)+1} free reroll${(n.freeReroll||0)+1===1?"":"s"}.`:t.id==="composter"?`Held ${n.composter||0}. After pick: SHREDDER poop grants ${M(3*((n.composter||0)+1))}.`:t.id==="scannerQueueSpacing"?`Held ${n.scannerQueueSpacing||0}. After pick: Manual/Auto Scanner queue spacing ${Ke(Math.pow(.85,(n.scannerQueueSpacing||0)+1))}.`:t.id==="flattery"?`Next Fairies tribute -50%. Held for next tribute: ${n.fairiesFlatteryNext||0}.`:t.id==="usedMachine"?"Enable Used Machines: future equipment costs 50%, has no SELL refund, and starts with 60% durability.":t.id==="newMachine"?"Cancel Used Machines. Future equipment returns to normal price, refund, and durability.":t.id==="laborExploitation"?"Repairman labor cost -30% permanently. One time only.":t.id==="rescueLoan"?`At day-end bankruptcy check, gain ${M(500)} if cash is below ${M(0)}. Held: ${n.rescueLoanCharges||0}.`:t.description}function Zo(e,t){let n=e.cardDraft?.choices||[],o=n.findIndex(r=>r.id===t.id);o>=0&&n.splice(o,1)}function ds({game:e,ui:t,onUpdatePanels:n}){function o(){n&&n()}function r(){Ie(e),e.cardTargetPick=null,e.cardDraft={pending:!0,choices:Vn(e,Ft),rerolls:0,freeRerolls:qt(e,"freeReroll"),picksRemaining:1}}function s(){Ie(e),e.cardDraft.pending=!1,e.cardDraft.choices=[],e.cardDraft.picksRemaining=0,e.cardTargetPick=null,t.modal.classList.remove("visible","equipment-popover"),o()}function l($=Ft){Ie(e),e.cardDraft.choices=Vn(e,$)}function d(){Ie(e),!e.cardDraft.choices.length&&e.cardDraft.picksRemaining>0&&l(Ft)}function v($){Zo(e,$),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1),e.cardTargetPick=null,d(),e.cardDraft.picksRemaining<=0?s():Z()}function C($){Zo(e,$),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1)+Ae.extraCardsAddedPicks,e.cardDraft.choices.push(...Vn(e,2)),Z()}function P($,U){let N=qt(e,"dudRefund")*50;if(N>0){let le=Ne(e,N);e.stats.dudRefundIncome=(e.stats.dudRefundIncome||0)+le,e.totals.dudRefundIncome=(e.totals.dudRefundIncome||0)+le,W(e,y.x+y.cols*y.cell/2,y.y-30,`DUD REFUND +${M(le)}`,p.green)}It(e,34,.62),document.body?.animate&&document.body.animate([{transform:"translate(0, 0)"},{transform:"translate(-10px, 7px)"},{transform:"translate(12px, -8px)"},{transform:"translate(-8px, -5px)"},{transform:"translate(9px, 6px)"},{transform:"translate(0, 0)"}],{duration:260,easing:"steps(5, end)"}),U&&(U.style.setProperty("--fling-x",`${260+Math.random()*260}px`),U.style.setProperty("--fling-y",`${-260-Math.random()*170}px`),U.style.setProperty("--fling-r",`${(Math.random()<.5?-1:1)*(52+Math.random()*38)}deg`),U.classList.add("flung")),window.setTimeout(()=>{Zo(e,$),d(),Z()},340)}function R($,U=null){if($.type==="dud")return P($,U);if($.id==="extraCards")return C($);if($.type==="equipmentUpgrade"||$.type==="cellAction")return L($);us(e,$),v($)}function L($){let U=Ue(e,$);U.length&&(e.cardTargetPick={pending:!0,cardId:$.id,mode:$.target==="blockedCell"?"blockedCell":"equipment",targetKeys:U.map(et),remaining:$.id==="dynamite"?Math.min(3,U.length):1},t.modal.classList.remove("visible","equipment-popover"),o())}function V($){if(!$||$.type!=="blockedCell")return!1;let U=I($.col,$.row);if(!e.blockedCells?.has(U))return!1;e.blockedCells.delete(U);let N=F($.col,$.row);return yt(e,N.x,N.y),Ve(e,N.x,N.y,p.danger,62),Ze(e,N.x,N.y,18,p.warn),On(e,N.x,N.y,8),It(e,16,.35),W(e,N.x,N.y-18,"BOOM",p.danger),ve(e),e.cardTargetPick.remaining=Math.max(0,(e.cardTargetPick.remaining||1)-1),e.cardTargetPick.targetKeys=Ue(e,"dynamite").map(et),o(),!0}function te($){if(!e.cardTargetPick?.pending)return!1;let U=Vt(e.cardTargetPick.cardId),N=pa(e,$);return!U||!N?(z(),!0):U.id==="dynamite"?(V(N)&&((e.cardTargetPick.remaining||0)<=0||!Ue(e,"dynamite").length)&&v(U),!0):(cs(e,N),v(U),!0)}function z(){e.cardTargetPick?.pending&&(e.cardTargetPick=null,Z())}function se(){let $=Math.max(0,e.cardDraft?.freeRerolls||0);if($>0){e.cardDraft.freeRerolls=$-1,e.cardDraft.rerolls+=1,l(Ft),Z();return}let U=ji(e);e.cashA!==Se)].slice(0,5);return N.innerHTML=`${$.title}
${he.map(A=>`${A}`).join("")}
${ya(e,$)}`,N.addEventListener("click",()=>R($,N)),N.dataset.index=String(U),N}function Z(){Ie(e),e.cardTargetPick=null,e.cardDraft?.pending||r(),e.cardDraft.choices?.length||l(Ft);let $=e.cardDraft.choices||[],U=ji(e),N=Math.max(0,e.cardDraft?.freeRerolls||0),le=Math.max(1,e.cardDraft.picksRemaining||1);t.modalTitle.textContent="Choose Upgrade Card",t.modalBody.innerHTML=`

Choose ${le} card${le===1?"":"s"} before Build phase. Dud cards can be flicked away without consuming a pick. Equipment cards target machines; Dynamite targets blocked cells.

`;let Se=t.modalBody.querySelector("#cardChoices");$.forEach((_,k)=>Se.appendChild(ye(_,k))),t.modalActions.innerHTML="";let he=document.createElement("button");he.type="button",he.className="facility-action warn reroll-button",he.textContent=N>0?`Reroll (FREE x${N})`:`Reroll ${M(U)}`,he.disabled=N<=0&&e.cash0?`${N} free reroll${N===1?"":"s"} remaining.`:he.disabled?"Not enough cash":"",he.addEventListener("click",se),t.modalActions.appendChild(he);let A=document.createElement("button");A.type="button",A.className="facility-action",A.textContent="No Card",A.title="Skip this upgrade pick and enter Build phase.",A.addEventListener("click",s),t.modalActions.appendChild(A),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible")}return{prepareDraft:r,showDraft:Z,finishDraft:s,chooseTargetAtPoint:te,cancelTargetPick:z}}var ha=!0,ma={chickMale:"./assets/images/chick_male.png",chickFemale:"./assets/images/chick_female.png",poop:"./assets/images/poop.png",conveyorStraightH:"./assets/dark_factory/facilities/conveyor/conveyor_straight_h_16.png",conveyorStraightV:"./assets/dark_factory/facilities/conveyor/conveyor_straight_v_16.png",conveyorTurnNe:"./assets/dark_factory/facilities/conveyor/conveyor_turn_ne_16.png",conveyorTurnNw:"./assets/dark_factory/facilities/conveyor/conveyor_turn_nw_16.png",conveyorTurnSe:"./assets/dark_factory/facilities/conveyor/conveyor_turn_se_16.png",conveyorTurnSw:"./assets/dark_factory/facilities/conveyor/conveyor_turn_sw_16.png",boostConveyorStraightH:"./assets/dark_factory/facilities/conveyor/boost_conveyor_straight_h_16.png",boostConveyorStraightV:"./assets/dark_factory/facilities/conveyor/boost_conveyor_straight_v_16.png",boostConveyorTurnNe:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_ne_16.png",boostConveyorTurnNw:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_nw_16.png",boostConveyorTurnSe:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_se_16.png",boostConveyorTurnSw:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_sw_16.png",scannerManual:"./assets/dark_factory/facilities/machines/manual_scanner_32x48.png",scannerAuto:"./assets/dark_factory/facilities/machines/auto_scanner_32x48.png",eggFarm:"./assets/dark_factory/facilities/machines/egg_farm_16.png",mixer:"./assets/dark_factory/facilities/machines/mixer_32.png",shredder:"./assets/dark_factory/facilities/machines/shredder_32.png",truck:"./assets/dark_factory/facilities/vehicles/truck_32.png",repairman:"./assets/dark_factory/facilities/utility/repairman_16.png",obstacleCrate:"./assets/dark_factory/facilities/utility/obstacle_crate_16.png"},be={};for(let[e,t]of Object.entries(ma)){let n=new Image;n.loaded=!1,n.onerror=()=>{n.loaded=!1},(ha&&e!=="chickMale"&&e!=="chickFemale"||e==="poop")&&t&&(n.onload=()=>{n.loaded=!0},n.src=t),be[e]=n}function hs(e,t,n,o){e.imageSmoothingEnabled=!1,e.clearRect(0,0,t.width,t.height),wa(e,t),e.save();let r=n.shake.time>0?G(-n.shake.strength,n.shake.strength):0,s=n.shake.time>0?G(-n.shake.strength,n.shake.strength):0,l=n.view?.scale||1;e.translate((n.view?.x||0)+r,(n.view?.y||0)+s),e.scale(l,l),ka(e,n),xa(e,n),Ma(e,n),$a(e,n),_a(e,n),Ia(e,n),Ba(e,n),va(e,n),Ka(e,n,o.activeQueuedChick),ja(e,n),za(e,t,n),Va(e,n,o.selectedObject,o.selectedTitle),Xa(e,n),Qa(e,n),Ja(e,n),e.restore(),Za(e,n,t)}function ba(e){if(e.type==="eggFarm"){let n=F(e.ref.col,e.ref.row);return{x:n.x-34,y:n.y-34,w:68,h:68,cx:n.x,cy:n.y}}let t=e.ref;return{x:t.x,y:t.y,w:t.w,h:t.h,cx:t.x+t.w/2,cy:t.y+t.h/2}}function va(e,t){if(t.phase!=="build")return;let n=In(t);for(let o of n){let r=ba(o);e.save(),e.fillStyle="rgba(196,36,36,.22)",e.strokeStyle=p.danger,e.lineWidth=5,e.setLineDash([10,6]),ne(e,r.x,r.y,r.w,r.h,!0,!0),e.setLineDash([]),e.fillStyle=p.danger,e.strokeStyle=p.white,e.lineWidth=4,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.strokeText("!",r.cx,r.y+24),e.fillText("!",r.cx,r.y+24),e.font="900 11px ui-monospace, monospace",e.strokeText("NO ROUTE",r.cx,r.y+r.h-8),e.fillText("NO ROUTE",r.cx,r.y+r.h-8),e.restore()}}function ne(e,t,n,o,r,s=!0,l=!0){e.beginPath(),e.rect(t,n,o,r),s&&e.fill(),l&&e.stroke()}function fn(e,t,n,o,r=p.ink){e.save(),e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.lineWidth=4,e.strokeStyle=p.white,e.fillStyle=r,e.strokeText(o,t,n),e.fillText(o,t,n),e.restore()}function Xe(e,t,n,o,r,s){if(!t?.loaded)return!1;let l=e.imageSmoothingEnabled;return e.imageSmoothingEnabled=!1,e.drawImage(t,Math.round(n),Math.round(o),Math.round(r),Math.round(s)),e.imageSmoothingEnabled=l,!0}function fs(e,t,n,o,r,s,l=null,d=1){e.fillStyle=s,e.fillRect(Math.round(t),Math.round(n),Math.round(o),Math.round(r)),l&&(e.strokeStyle=l,e.lineWidth=d,e.strokeRect(Math.round(t)+.5,Math.round(n)+.5,Math.round(o)-1,Math.round(r)-1))}function wa(e,t){e.fillStyle=p.bg,e.fillRect(0,0,t.width,t.height),e.save(),e.globalAlpha=.85;for(let n=0;n=n;for(let r of Ct(t)){let s=Mt(r);e.save(),e.fillStyle=o?"rgba(183,245,198,.34)":"rgba(255,255,255,.22)",e.strokeStyle=o?p.green:p.muted,e.lineWidth=5,e.setLineDash([16,10]),ne(e,s.x,s.y,s.w,s.h,!0,!0),e.setLineDash([]);let l=vo(r),d=l.cx,v=l.cy;e.fillStyle="rgba(255,255,255,.94)",e.strokeStyle=p.ink,e.lineWidth=4,ne(e,l.x,l.y,l.w,l.h,!0,!0),e.fillStyle=o?p.green:p.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText(r.direction==="right"?"BUY RIGHT LOT":"BUY UPPER LOT",d,v-12),e.fillStyle=p.ink,e.font="900 16px ui-monospace, monospace",e.fillText(`${M(n)} / 10\xD710`,d,v+15),e.fillStyle=p.muted,e.font="900 11px ui-monospace, monospace",e.fillText("blocked tiles included",d,v+30),e.restore()}}function nt(e,t,n,o,r,s,l=0){let d=Ht(s);d<.5||(e.save(),e.globalAlpha=Math.min(.62,.12+d*.54),e.fillStyle="#6b4a23",l>0?(e.beginPath(),e.roundRect?.(t,n,o,r,l),e.roundRect?e.fill():ne(e,t,n,o,r,!0,!1)):ne(e,t,n,o,r,!0,!1),e.globalAlpha=Math.min(.9,.25+d*.6),e.strokeStyle="#3a2a16",e.lineWidth=Math.max(2,Math.floor(2+d*5)),e.setLineDash([5,6]),ne(e,t+3,n+3,o-6,r-6,!1,!0),e.restore())}function or(e,t){let n=e.componentLookup?.get(t);return(n?e.congestion.get(n):null)?.ratio||0}function Ca(e,t,n={}){let o=Qn(e,t).sort(),s=n.kind==="boostConveyor"?"boostConveyor":"conveyor",l=d=>o.includes(d);if(o.length===2){if(l("left")&&l("right"))return be[`${s}StraightH`];if(l("up")&&l("down"))return be[`${s}StraightV`];if(l("up")&&l("right"))return be[`${s}TurnNe`];if(l("up")&&l("left"))return be[`${s}TurnNw`];if(l("down")&&l("right"))return be[`${s}TurnSe`];if(l("down")&&l("left"))return be[`${s}TurnSw`]}return o.length===1?l("up")||l("down")?be[`${s}StraightV`]:be[`${s}StraightH`]:l("up")||l("down")?be[`${s}StraightV`]:be[`${s}StraightH`]}function Ma(e,t){let n=[],o=new Set;for(let s of t.conveyorTiles){let{col:l,row:d}=Q(s);for(let v of ue){let C={col:l+v.dc,row:d+v.dr},P=I(C.col,C.row);if(!t.conveyorTiles.has(P))continue;let R=[s,P].sort().join("|");if(o.has(R))continue;o.add(R);let L=Math.max(or(t,s),or(t,P));n.push({a:F(l,d),b:F(C.col,C.row),ratio:L})}}e.save(),e.lineCap="round",e.lineJoin="round";for(let s of[{width:31,color:"#0b0c0f",alpha:1},{width:23,color:"#444b56",alpha:1},{width:15,color:"#171a1f",alpha:1}]){e.globalAlpha=s.alpha,e.strokeStyle=s.color,e.lineWidth=s.width;for(let l of n)e.beginPath(),e.moveTo(l.a.x,l.a.y),e.lineTo(l.b.x,l.b.y),e.stroke()}for(let s of n){let l=Math.max(0,(s.ratio-.5)/.5);e.strokeStyle=gn(p.green,p.danger,l),e.globalAlpha=s.ratio>.5?.35+l*.55:.8,e.lineWidth=6,e.beginPath(),e.moveTo(s.a.x,s.a.y),e.lineTo(s.b.x,s.b.y),e.stroke()}let r=Aa(t);for(let s of t.conveyorTiles){let l=F(...Object.values(Q(s))),d=t.conveyorMeta.get(s)||{},v=or(t,s),C=Ca(t,s,d),P=v>.5;if(e.fillStyle=P?"rgba(196,36,36,.28)":"rgba(0,0,0,.35)",e.strokeStyle=P?p.danger:"rgba(255,184,39,.34)",e.lineWidth=P?3:1,ne(e,l.x-20,l.y-20,40,40,!0,!0),!Xe(e,C,l.x-19,l.y-19,38,38)){let L=d.kind==="boostConveyor"?"#315e92":"#454b55";e.fillStyle=v>.5?gn(L,"#a12c2c",Math.max(0,(v-.5)/.5)):L,e.strokeStyle=p.ink,e.lineWidth=2,ne(e,l.x-18,l.y-18,36,36,!0,!0)}nt(e,l.x-18,l.y-18,36,36,{meta:d}),He(e,t,"conveyor",s,l.x,l.y,38,38),Da(e,l,r.get(s)||[]);let R=Qn(t,s);Pa(e,l,d,Ta(t,s,R),R),v>.5&&fn(e,l.x,l.y-15,`${Math.floor(v*100)}%`,p.danger)}e.restore()}function Qn(e,t){let n=Q(t);return ue.filter(o=>e.conveyorTiles.has(I(n.col+o.dc,n.row+o.dr))).map(o=>o.name)}function ms(e,t,n){let o=ue.find(l=>l.name===n);if(!o)return!1;let r=e.conveyorMeta?.get?.(I(t.col+o.dc,t.row+o.dr));return r?[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))].includes(o.opposite):!1}function ga(e,t,n,o=Qn(e,t),r="random"){if(o.length<3)return n;let s=Q(t),l=new Set(o.filter(C=>ms(e,s,C)));if(r&&r!=="random"&&o.includes(r)){let C=new Set(l);C.add(r),o.filter(P=>!C.has(P)).length>=2&&l.add(r)}let d=o.filter(C=>!l.has(C));if(d.length)return d;let v=n.filter(C=>!l.has(C));return v.length?v:n}function Ta(e,t,n=Qn(e,t)){if(n.length<3)return[];let o=Q(t),r=new Set(n.filter(s=>ms(e,o,s)));return n.filter(s=>{let l=new Set(r);return l.add(s),n.filter(d=>!l.has(d)).length>=2})}function Ea(e,t,n){let o=Q(t),r=ue.filter(d=>e.conveyorTiles.has(I(o.col+d.dc,o.row+d.dr))).map(d=>d.name),s=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(d=>r.includes(d)),l=r;return s.length?s:l}function Pa(e,t,n,o,r=o){if(r.length<3||o.length<2)return;e.save();let s=o.includes(n.branchMode)?n.branchMode:"random",l=s!=="random";if(e.lineJoin="round",e.lineCap="round",e.lineWidth=2,e.fillStyle="rgba(255,255,255,.9)",e.strokeStyle=l?p.warn:p.green,ne(e,t.x-17,t.y-17,34,34,!0,!0),e.strokeStyle=p.ink,e.lineWidth=2,e.fillStyle=p.ink,s!=="random"){let d=ue.find(v=>v.name===s);Xn(e,t.x,t.y,d?.angle||0,9,6)}else e.beginPath(),e.moveTo(t.x-10,t.y),e.lineTo(t.x-2,t.y),e.lineTo(t.x+8,t.y-8),e.moveTo(t.x-2,t.y),e.lineTo(t.x+8,t.y+8),e.stroke(),Xn(e,t.x+9,t.y-9,-Math.PI/4,4,3),Xn(e,t.x+9,t.y+9,Math.PI/4,4,3);e.restore()}function Ra(e,t,n){if(!n)return[];let o=Q(t),r=ue.filter(d=>e.conveyorTiles.has(I(o.col+d.dc,o.row+d.dr))).map(d=>d.name),s=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(d=>r.includes(d));return ga(e,t,s.length?s:Ea(e,t,n),r,n.branchMode||"random").map(d=>ue.find(v=>v.name===d)).filter(Boolean)}function Aa(e){let t=new Map;for(let[n,o]of e.conveyorMeta||[]){let r=Ra(e,n,o);r.length&&t.set(n,r)}return t}function Da(e,t,n){let o=n.slice(0,4);o.length&&(e.save(),e.fillStyle=p.ink,e.globalAlpha=.86,o.forEach(r=>{Xn(e,t.x+r.dc*12,t.y+r.dr*12,r.angle,6,5)}),e.restore())}function Xn(e,t,n,o,r=11,s=8){e.save(),e.translate(t,n),e.rotate(o),e.beginPath(),e.moveTo(r,0),e.lineTo(-r*.72,-s),e.lineTo(-r*.72,s),e.closePath(),e.fill(),e.restore()}function $a(e,t){e.save(),e.lineWidth=2,e.font="900 12px ui-monospace, monospace",e.textAlign="center";for(let n of t.scanners){let o=To(n),r=[{type:"inputA",p:Pe(n,"inputA"),label:"IN",color:p.green},{type:"left",p:Pe(n,"left"),label:Po(o.left),color:Ro(o.left)},{type:"right",p:Pe(n,"right"),label:Po(o.right),color:Ro(o.right)}];for(let s of r){if(!s.p)continue;let l=F(s.p.col,s.p.row),d=jr(t,n,s.type||(s.label==="IN"?"inputA":null))||t.conveyorTiles.has(I(s.p.col,s.p.row));e.fillStyle=d?gn("#1a1d23",s.color,.24):"#3a1e22",e.strokeStyle=d?s.color:p.danger,ne(e,l.x-18,l.y-12,36,24,!0,!0),e.fillStyle=p.white,e.fillText(s.label,l.x,l.y+4)}}e.restore()}function Ia(e,t){for(let n of t.eggFarms)Fa(e,n,t)}function Fa(e,t,n){let o=F(t.col,t.row);if(e.save(),Xe(e,be.eggFarm,o.x-29,o.y-29,58,58)){nt(e,o.x-29,o.y-29,58,58,t);let l=1+Math.max(0,Number(t.extraEggOutlet)||0);e.fillStyle="rgba(255,255,255,.92)",e.strokeStyle=p.ink,e.lineWidth=2,ne(e,o.x+9,o.y+12,30,18,!0,!0),e.fillStyle=p.ink,e.font="900 10px ui-monospace, monospace",e.textAlign="center",e.fillText(`O${l}`,o.x+24,o.y+24),He(e,n,"eggFarm",t.id,o.x,o.y,68,68),e.restore();return}e.fillStyle=p.white,e.strokeStyle=p.ink,e.lineWidth=4,ne(e,o.x-28,o.y-28,56,56,!0,!0),e.fillStyle=p.green,e.font="900 19px ui-monospace, monospace",e.textAlign="center",e.fillText("EGG",o.x,o.y-4);let r=1+Math.max(0,Number(t.extraEggOutlet)||0);e.font="900 11px ui-monospace, monospace",e.fillStyle=p.ink,e.fillText(`L${t.level} O${r}`,o.x,o.y+13),e.fillText(`${t.nextSpawn.toFixed(1)}s`,o.x,o.y+26);let s=Math.max(0,Math.min(1,t.shutterProgress||0));if(s>0){let l=56*s;e.fillStyle=p.ink,ne(e,o.x-28,o.y-28,56,l,!0,!1),e.strokeStyle=p.white,e.lineWidth=2;for(let d=o.y-24;d=1&&(e.fillStyle=p.white,e.font="900 12px ui-monospace, monospace",e.fillText("SHUT",o.x,o.y+4))}nt(e,o.x-28,o.y-28,56,56,t),He(e,n,"eggFarm",t.id,o.x,o.y,68,68),e.restore()}function Ba(e,t){for(let n of t.scanners)La(e,n,t)}function La(e,t,n){let o=pe(t);if(e.save(),t.kind==="manual"&&(n.manualCombo?.count||0)>=10){let v=n.manualCombo.count;e.save(),e.globalAlpha=Math.min(.55,.16+v/120),e.strokeStyle=v>=30?p.warn:p.green,e.lineWidth=Math.min(14,5+Math.floor(v/10)),e.shadowColor=e.strokeStyle,e.shadowBlur=Math.min(28,8+v),ne(e,o.x-54,o.y-76,108,152,!1,!0),e.restore()}let r=t.kind==="auto"?be.scannerAuto:be.scannerManual;if(Xe(e,r,o.x-50,o.y-73,100,146)){t.kind==="auto"?nt(e,o.x-50,o.y-73,100,146,t):ps(e,t,o),He(e,n,"scanner",t.id,o.x,o.y,108,154),e.restore();return}e.fillStyle=t.kind==="auto"?"#d8ffe2":p.white,e.strokeStyle=p.ink,e.lineWidth=4,ne(e,o.x-50,o.y-73,100,146,!0,!0),e.fillStyle=t.kind==="auto"?p.green:p.ink,e.font="900 19px ui-monospace, monospace",e.textAlign="center",e.fillText(`${t.kind==="auto"?"AUTO":`S${(t.slot??0)+1}`}`,o.x,o.y-48),e.font="900 11px ui-monospace, monospace";let s=t.keys?.left?.label||(t.slot===0?"A":"Left"),l=t.keys?.right?.label||(t.slot===0?"D":"Right");e.fillText(t.role===0?`${s}:M ${l}:NEXT`:`${s}:WASTE ${l}:TRUCK`,o.x,o.y-28);let d=t.queue.length;t.kind==="manual"?(ps(e,t,o),e.fillStyle=d>0?p.green:p.muted,e.font="900 10px ui-monospace, monospace",e.fillText(`Q:${d}`,o.x,o.y+54)):(e.fillStyle=d>0?p.green:p.muted,e.font="900 12px ui-monospace, monospace",e.fillText(`Q:${d} CD:${t.cooldown.toFixed(1)}`,o.x,o.y+54),nt(e,o.x-50,o.y-73,100,146,t)),He(e,n,"scanner",t.id,o.x,o.y,108,154),e.restore()}function ps(e,t,n){if(t.kind!=="manual")return;let r=(t.slot??0)===0?[{side:"left",text:"A"},{side:"right",text:"D"}]:[{side:"left",text:"\u2190"},{side:"right",text:"\u2192"}];r[0].text=t.keys?.left?.label||r[0].text,r[1].text=t.keys?.right?.label||r[1].text;let s=t.keyPressTime>0?t.keyPressSide:null,l=n.x-30,d=n.y+18;e.save(),e.lineWidth=3,e.fillStyle="#f7fff5",e.strokeStyle=p.ink,ne(e,l-4,d-4,68,25,!0,!0),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let v=0;v.8,s=t.y+Math.sin(t.bob)*(r?5:1.5);if(e.save(),n&&(e.strokeStyle=p.green,e.lineWidth=5,e.beginPath(),e.arc(t.x,s,t.radius+8,0,Math.PI*2),e.stroke()),r&&(e.strokeStyle=p.danger,e.lineWidth=3,e.beginPath(),e.arc(t.x,s,t.radius+12+Math.sin(t.bob*2)*4,0,Math.PI*2),e.stroke()),t.sex==="poop")lr(e,t.x,s,t.radius);else{let l=t.sex==="male"?be.chickMale:be.chickFemale;Xe(e,l,t.x-t.radius,s-t.radius,t.radius*2,t.radius*2)||(e.fillStyle=t.sex==="male"?p.male:p.female,e.strokeStyle=p.ink,e.lineWidth=5,e.beginPath(),e.arc(t.x,s,t.radius,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle=p.ink,e.beginPath(),e.arc(t.x-6,s-5,2.5,0,Math.PI*2),e.arc(t.x+6,s-5,2.5,0,Math.PI*2),e.fill(),e.fillStyle="#ffaa2e",e.beginPath(),e.moveTo(t.x,s+2),e.lineTo(t.x+9,s+6),e.lineTo(t.x,s+10),e.closePath(),e.fill())}e.restore()}function qa(e,t){let n=null,o=1/0;for(let[r,s]of e.componentLookup.entries()){let l=Q(r),d=F(l.col,l.row),v=Math.hypot(t.x-d.x,t.y-d.y);vys(o.type,o.id)===ys(t,n))}function He(e,t,n,o,r,s,l,d){Ya(t,n,o)&&(e.save(),e.fillStyle="rgba(34,185,79,.18)",e.strokeStyle=p.green,e.lineWidth=(t.multiSelected||[]).length>1?6:4,e.setLineDash((t.multiSelected||[]).length>1?[]:[8,5]),ne(e,r-l/2,s-d/2,l,d,!0,!0),e.restore())}function Va(e,t,n,o){if(t.phase==="build"&&(t.multiSelected||[]).length>1){e.save(),e.fillStyle="rgba(255,255,255,.96)",e.strokeStyle=p.ink,e.lineWidth=3,ne(e,54-t.view.x,66-t.view.y,214,42,!0,!0),e.fillStyle=p.ink,e.font="900 11px ui-monospace, monospace",e.fillText(`${t.multiSelected.length} ITEMS SELECTED`,65-t.view.x,83-t.view.y),e.fillStyle=p.muted,e.font="900 11px ui-monospace, monospace",e.fillText("drag any selected item to move group",65-t.view.x,99-t.view.y),e.restore();return}}function za(e,t,n){if(!n.cardTargetPick?.pending)return;let o=nr(n);e.save(),e.fillStyle="rgba(0,0,0,.66)",e.beginPath();let r=n.view?.scale||1;e.rect(-(n.view?.x||0)/r,-(n.view?.y||0)/r,t.width/r,t.height/r);for(let v of o){let C=v.bounds,P=8;e.rect(C.x-P,C.y-P,C.w+P*2,C.h+P*2)}e.fill("evenodd");let s=n.cardTargetPick?.mode==="blockedCell";if(!o.length){e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=p.ink,e.lineWidth=3,ne(e,(260-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,420/r,42/r,!0,!0),e.fillStyle=p.danger,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(s?"NO BLOCKED CELL. PRESS ESC.":"NO VALID UPGRADE TARGET. PRESS ESC.",(470-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore();return}e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=p.ink,e.lineWidth=3;let l=Math.max(1,n.cardTargetPick?.remaining||1),d=n.cardTargetPick?.mode==="autoScannerMenu"?"AUTO SCANNER ROUTE SETTINGS. CLICK EMPTY AREA TO CLOSE.":s?`CLICK BLOCKED CELL: ${l} LEFT. PRESS ESC TO CANCEL.`:"CLICK AN UPGRADEABLE MACHINE. PRESS ESC TO CANCEL.";ne(e,(216-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,560/r,42/r,!0,!0),e.fillStyle=p.ink,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(d,(496-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore()}function Xa(e,t){if(t.phase!=="build"||!t.selectionBox)return;let n=t.selectionBox,o=Math.min(n.x1,n.x2),r=Math.min(n.y1,n.y2),s=Math.abs(n.x2-n.x1),l=Math.abs(n.y2-n.y1);e.save(),e.fillStyle="rgba(34,185,79,.12)",e.strokeStyle=p.green,e.lineWidth=2,e.setLineDash([7,4]),ne(e,o,r,s,l,!0,!0),e.restore()}function Qa(e,t){let n=[...t.effects].sort((o,r)=>(o.priority??Ce.ambient)-(r.priority??Ce.ambient));for(let o of n){let r=Math.max(0,o.life/o.maxLife);e.save(),e.globalAlpha=r,o.type==="meat"?(e.fillStyle=p.green,ne(e,o.x-o.size/2,o.y-o.size/2,o.size*1.5,o.size,!0,!1)):o.type==="sludge"?(e.fillStyle=p.poop,ne(e,o.x-o.size/2,o.y-o.size/2,o.size*1.4,o.size,!0,!1)):o.type==="spawn"?(e.strokeStyle=p.green,e.lineWidth=3,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*20,0,Math.PI*2),e.stroke()):o.type==="spark"?(e.fillStyle=o.color||p.danger,ne(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!0,!1)):o.type==="smoke"?(e.fillStyle="rgba(16,32,21,.24)",e.beginPath(),e.arc(o.x,o.y,o.size*(1.2-r*.2),0,Math.PI*2),e.fill()):o.type==="shockwave"?(e.strokeStyle=o.color||p.danger,e.lineWidth=4,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*(o.maxSize||44),0,Math.PI*2),e.stroke()):o.type==="scannerPulse"?(e.strokeStyle=o.color||p.green,e.lineWidth=5,e.setLineDash([8,6]),e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*38,0,Math.PI*2),e.stroke()):o.type==="shred"?(e.fillStyle=o.color||p.ink,e.save(),e.translate(o.x,o.y),e.rotate(o.rot||0),ne(e,-o.w/2,-o.h/2,o.w,o.h,!0,!1),e.restore()):o.type==="load"?(e.strokeStyle=o.color||p.green,e.lineWidth=3,e.beginPath(),e.moveTo(o.x-14,o.y),e.lineTo(o.x+14,o.y),e.moveTo(o.x,o.y-14),e.lineTo(o.x,o.y+14),e.stroke()):o.type==="erase"?(e.strokeStyle=p.ink,e.lineWidth=3,e.setLineDash([4,4]),ne(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!1,!0)):o.type==="rage"?(e.fillStyle=o.color||p.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText("!",o.x,o.y)):o.type==="flyingChick"&&(o.sex==="poop"?lr(e,o.x,o.y,o.radius||11):ar(e,o.x,o.y,o.sex,o.sex==="male")),e.restore()}}function Ja(e,t){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let n of t.floatingTexts){let o=Math.max(0,n.life/n.maxLife);e.globalAlpha=o,e.lineWidth=5,e.strokeStyle=p.white,e.fillStyle=n.color,e.strokeText(n.text,n.x,n.y),e.fillText(n.text,n.x,n.y)}e.restore()}function ja(e,t){let n=t.repairman;if(!(!!n?.active||t.phase==="build"&&!!n?.hiredForNextDay))return;if(e.save(),Xe(e,be.repairman,n.x-18,n.y-18,36,36)){n.target?.label?fn(e,n.x,n.y-24,n.target.label,p.green):!n.active&&n.hiredForNextDay&&fn(e,n.x,n.y-24,"NEXT DAY",p.green),e.restore();return}e.lineWidth=3,e.fillStyle="#fff0d1",e.strokeStyle=p.ink,e.beginPath(),e.arc(n.x,n.y,17,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle="#ffd6e7",e.beginPath(),e.arc(n.x-6,n.y-2,3.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+6,n.y-2,3.2,0,Math.PI*2),e.fill();let r=!!t.cardEffects?.laborExploitation;e.fillStyle=r?p.danger:p.ink,e.beginPath(),e.arc(n.x-5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.strokeStyle=p.ink,e.lineWidth=r?3:2,e.beginPath(),e.arc(n.x,n.y+(r?0:1),r?8:7,.1*Math.PI,.9*Math.PI),e.stroke(),e.fillStyle=p.green,ne(e,n.x-9,n.y+14,18,8,!0,!0),e.strokeStyle=p.ink,e.lineWidth=3,e.beginPath(),e.moveTo(n.x-11,n.y+18),e.lineTo(n.x-20,n.y+24),e.stroke(),e.beginPath(),e.moveTo(n.x+11,n.y+18),e.lineTo(n.x+20,n.y+24),e.stroke(),e.fillStyle=p.ink,e.font="900 11px ui-monospace, monospace",e.textAlign="center",e.fillText(n.active?"FIX":"HIRED",n.x,n.y+33),n.target?.label?fn(e,n.x,n.y-24,n.target.label,p.green):!n.active&&n.hiredForNextDay&&fn(e,n.x,n.y-24,"NEXT DAY",p.green),e.restore()}function Za(e,t,n){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="left",e.fillStyle=p.ink,e.fillStyle="rgba(255,255,255,.92)",e.strokeStyle=p.ink,e.lineWidth=3,ne(e,n.width-284,18,260,34,!0,!0),e.fillStyle=p.green,e.font="900 12px ui-monospace, monospace",e.fillText(Sn,n.width-270,40),e.font="900 19px ui-monospace, monospace",e.fillStyle=p.ink;let o=[];t.phase==="running"&&o.push(t.timeLeft<=0?"TIME UP: FARMS SHUT. CLEAR LINE.":"A/D: S1 \u2190/\u2192: S2"),t.phase==="build"&&o.push(`BUILD: ${t.buildTool||"SELECT"} | connect 1 EGG route to any exit`);let r=76;for(let s of o)e.strokeStyle=p.white,e.lineWidth=4,e.strokeText(s,24,r),e.fillText(s,24,r),r+=20;e.restore()}var Ss=[[{key:"a",code:"KeyA",label:"A"},{key:"d",code:"KeyD",label:"D"}],[{key:"arrowleft",code:"ArrowLeft",label:"Left"},{key:"arrowright",code:"ArrowRight",label:"Right"}],[{key:"j",code:"KeyJ",label:"J"},{key:"l",code:"KeyL",label:"L"}],[{key:"f",code:"KeyF",label:"F"},{key:"h",code:"KeyH",label:"H"}],[{key:"q",code:"KeyQ",label:"Q"},{key:"e",code:"KeyE",label:"E"}],[{key:"z",code:"KeyZ",label:"Z"},{key:"x",code:"KeyX",label:"X"}],[{key:"u",code:"KeyU",label:"U"},{key:"o",code:"KeyO",label:"O"}],[{key:"n",code:"KeyN",label:"N"},{key:"m",code:"KeyM",label:"M"}]];function ec(e){let t=Ss[e]||Ss[0];return{left:{...t[0]},right:{...t[1]}}}function ks(e,t,n){let o={type:"eggFarm",id:e.nextId++,col:t,row:n,level:1,nextSpawn:2,lastInterval:2,extraEggOutlet:0,price:kt.eggFarm,builtSession:e.buildSession};return o.nextSpawn=gt(o),o.lastInterval=o.nextSpawn,o}function xs(e,t,n,o){let r=o==="auto"?ke.autoScanner.price:ke.manualScanner.price,s=new Set(e.scanners.filter(d=>d.kind==="manual").map(d=>d.slot)),l=0;for(;s.has(l);)l+=1;return{type:"scanner",id:e.nextId++,kind:o,slot:o==="manual"?l:null,role:o==="manual"?l%2:0,col:t,row:n,level:1,queue:[],cooldown:0,price:r,builtSession:e.buildSession,autoMode:"standard",keys:o==="manual"?ec(l):null}}function Jn(e){let t=(e.x-y.x)/y.cell,n=(e.y-y.y)/y.cell,o=Math.max(0,Math.min(y.cols-1,Math.round(t-.5))),r=Math.max(0,Math.min(y.rows-1,Math.round(n-.5))),s=Math.abs(e.x-y.x),l=Math.abs(e.x-(y.x+y.cols*y.cell)),d=Math.abs(e.y-y.y),v=Math.abs(e.y-(y.y+y.rows*y.cell)),C=[["left",s],["right",l],["top",d],["bottom",v]].sort((P,R)=>P[1]-R[1])[0][0];return C==="left"?{side:C,entry:{col:0,row:r}}:C==="right"?{side:C,entry:{col:y.cols-1,row:r}}:C==="top"?{side:C,entry:{col:o,row:0}}:{side:C,entry:{col:o,row:y.rows-1}}}function jn(e,t,n){let o={x:y.x+t.col*y.cell+y.cell/2,y:y.y+t.row*y.cell+y.cell/2},r={left:y.x,right:y.x+y.cols*y.cell,top:y.y,bottom:y.y+y.rows*y.cell};return e.entry={...t},e.side=n,n==="left"?(e.x=r.left-e.w-18,e.y=o.y-e.h/2):n==="right"?(e.x=r.right+18,e.y=o.y-e.h/2):n==="top"?(e.x=o.x-e.w/2,e.y=r.top-e.h-18):(e.x=o.x-e.w/2,e.y=r.bottom+18),e}function Cs(e,t,n,o){let{entry:r,side:s}=Jn(n),l=ke[t],d=l?{name:l.name,w:l.body?.w||168,h:l.body?.h||110,price:l.price}:{name:t[0].toUpperCase()+t.slice(1),w:168,h:110,price:o},v={type:"facility",id:t,name:d.name,x:0,y:0,w:d.w,h:d.h,level:1,price:o||d.price,builtSession:e.buildSession};return jn(v,r,s)}function tc(e){return Math.random()({x:s.x,y:s.y})),r=o[0];return{id:e.nextId++,sex:n,x:r.x,y:r.y,route:o,targetIndex:o.length>1?1:o.length,stage:t.stage||"belt",scannerId:t.scannerId??null,nextScannerId:null,pendingScannerId:null,radius:n==="poop"?15:17,bob:Math.random()*Math.PI*2,queueIndex:-1,queueRoute:null}}function gs({game:e,canvasPoint:t,updatePanels:n,equipmentAtPoint:o,fail:r,pointInGrid:s,rectOfFacility:l,rectsOverlap:d}){function v(k){return k?k.type==="conveyor"?`conveyor:${k.id||k.oldKey}`:k.type==="facility"?`facility:${k.id||k.ref?.id}`:`${k.type}:${k.id||k.ref?.id}`:""}function C(k){return k?k.type==="conveyor"?{type:"conveyor",id:k.oldKey}:{type:k.type,id:k.ref.id}:null}function P(k){let g=v(C(k));return(e.multiSelected||[]).some(O=>v(O)===g)}function R(k){return k?k.type==="eggFarm"?e.eggFarms.find(g=>g.id===k.id)||null:k.type==="scanner"?e.scanners.find(g=>g.id===k.id)||null:k.type==="facility"?e.facilities[k.id]||null:k.type==="conveyor"&&e.conveyorTiles.has(k.id)?{type:"conveyor",id:k.id}:null:null}function L(){let k=[];for(let g of e.conveyorTiles){let O=Q(g),X=F(O.col,O.row);k.push({type:"conveyor",id:g,center:X,cell:O})}for(let g of e.eggFarms)k.push({type:"eggFarm",id:g.id,ref:g,center:F(g.col,g.row),cell:{col:g.col,row:g.row}});for(let g of e.scanners)k.push({type:"scanner",id:g.id,ref:g,center:pe(g),cell:{col:g.col,row:g.row}});for(let g of Object.values(e.facilities)){let O={x:g.x+g.w/2,y:g.y+g.h/2},X=g.entry?F(g.entry.col,g.entry.row):O;k.push({type:"facility",id:g.id,ref:g,center:O,portCenter:X})}return k}function V(k,g){let O=Math.min(g.x1,g.x2),X=Math.max(g.x1,g.x2),oe=Math.min(g.y1,g.y2),de=Math.max(g.y1,g.y2);return k.x>=O&&k.x<=X&&k.y>=oe&&k.y<=de}function te(k){let g=[];for(let O of L())(V(O.center,k)||O.portCenter&&V(O.portCenter,k))&&g.push({type:O.type,id:O.id});return e.multiSelected=g,e.selected=g[0]||null,n(),g.length}function z(){e.multiSelected=[],e.selected=null,n()}function se(k){let g=t(k);return e.selectionBox={x1:g.x,y1:g.y,x2:g.x,y2:g.y},e.multiSelected=[],e.selected=null,n(),!0}function ye(k){if(!e.selectionBox)return;let g=t(k);e.selectionBox.x2=g.x,e.selectionBox.y2=g.y}function Z(){if(!e.selectionBox)return 0;let k=e.selectionBox,g=Math.abs(k.x2-k.x1),O=Math.abs(k.y2-k.y1);return e.selectionBox=null,g<6&&O<6?(z(),0):te(k)}function $(k){let g=C(k);return g?(e.multiSelected||[]).length&&P(k)?[...e.multiSelected]:[g]:[]}function U(k){let g=R(k);if(!g)return null;if(k.type==="conveyor"){let O=Q(k.id);return{...k,obj:g,oldKey:k.id,currentKey:k.id,meta:e.conveyorMeta.get(k.id)||{price:_e("conveyor"),builtSession:null},col:O.col,row:O.row}}return k.type==="eggFarm"||k.type==="scanner"?{...k,obj:g,col:g.col,row:g.row}:k.type==="facility"?{...k,obj:g,x:g.x,y:g.y,w:g.w,h:g.h,entry:g.entry?{...g.entry}:null,side:g.side,center:{x:g.x+g.w/2,y:g.y+g.h/2}}:null}function N(k){let g=t(k),O=o(g);if(!O)return!1;let X=$(O),oe=X.map(U).filter(Boolean);return oe.length?(e.groupDrag={start:g,selections:X,origins:oe,historySnapshot:cn(e),committed:!1,lastDCol:0,lastDRow:0},e.multiSelected=X,e.selected=X[0]||null,n(),!0):!1}function le(){!e.groupDrag||e.groupDrag.committed||(e.undoStack.push(e.groupDrag.historySnapshot),e.redoStack=[],e.groupDrag.committed=!0)}function Se(k,g,O){let X=I(k,g),oe=Et(e,k,g);if(oe&&!O.has(`eggFarm:${oe.id}`))return!0;let de=Pt(e,k,g);return!!(de&&!O.has(`scanner:${de.id}`)||e.conveyorTiles.has(X)&&!O.has(`conveyor:${X}`))}function he(k,g,O){let X=[];for(let oe of e.groupDrag.origins){if(oe.type!=="facility")continue;let de={x:oe.center.x+k,y:oe.center.y+g},{entry:Te,side:ce}=Jn(de);if(!s(Te.col,Te.row)||e.blockedCells?.has?.(I(Te.col,Te.row)))return!0;let rt={...oe.obj,entry:{...Te},side:ce};jn(rt,Te,ce),X.push({id:oe.id,rect:l(rt)})}for(let oe of X)for(let de of Object.values(e.facilities))if(!O.has(`facility:${de.id}`)&&d(oe.rect,l(de),12))return!0;for(let oe=0;oeJ.type==="conveyor");for(let J of rt){let ge=J.currentKey||J.oldKey;e.conveyorTiles.delete(ge),e.conveyorMeta.delete(ge)}for(let J of rt){let ge=I(J.col+oe,J.row+de);e.conveyorTiles.add(ge),e.conveyorMeta.set(ge,J.meta||{price:_e("conveyor"),builtSession:null,uses:0}),J.currentKey=ge}for(let J of e.groupDrag.origins)if(J.type==="eggFarm")J.obj.col=J.col+oe,J.obj.row=J.row+de;else if(J.type==="scanner")J.obj.col=J.col+oe,J.obj.row=J.row+de;else if(J.type==="facility"){let ge={x:J.center.x+O,y:J.center.y+X},{entry:Le,side:it}=Jn(ge);jn(J.obj,Le,it)}e.groupDrag.selections=e.groupDrag.origins.map(J=>J.type==="conveyor"?{type:"conveyor",id:J.currentKey||J.oldKey}:{type:J.type,id:J.id}),e.multiSelected=[...e.groupDrag.selections],e.selected=e.multiSelected[0]||null,ve(e),n()}function _(){e.groupDrag&&(ve(e),e.groupDrag=null,n())}return{selectionFromHit:C,startSelectionBox:se,updateSelectionBox:ye,finishSelectionBox:Z,startGroupDrag:N,updateGroupDrag:A,finishGroupDrag:_}}function Ts({game:e,ui:t,canvas:n,canvasPoint:o,onUpdatePanels:r}){function s(){r&&r()}let l=null,d=!1,v=null,C=!1,P=["random","up","right","down","left"],R={random:"RND",up:"UP",right:"RT",down:"DN",left:"LF"},L={w:40,h:40,y:0};function V(){return En(e)}function te(){e.gridCols=y.cols,e.gridRows=y.rows,e.gridOwnedCells=Nr(e)}function z(i){if(i){y.y-=i*y.cell,y.rows+=i,e.gridChunkOriginY=(e.gridChunkOriginY||0)-Math.floor(i/10),e.ownedCells=Pn(e.ownedCells,i),e.blockedCells=Pn(e.blockedCells,i),e.conveyorTiles=Pn(e.conveyorTiles,i),e.conveyorMeta=Wr(e.conveyorMeta,i);for(let c of e.eggFarms||[])c.row+=i;for(let c of e.scanners||[])c.row+=i;for(let c of Object.values(e.facilities||{}))c.entry&&(c.entry.row+=i)}}function se(i){e.ownedCells=e.ownedCells||new Set;for(let c of Ur(i))e.ownedCells.add(I(c.col,c.row))}function ye(i){return e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending?null:Ct(e).find(c=>c&&Gr(c,i))||null}function Z(i="right"){if(i&&typeof i=="object"&&Number.isFinite(i.chunkX)&&Number.isFinite(i.chunkY))return i;let c=["right","up"].includes(i)?i:"right";return _r(e,c)}function $(i="right"){let c=Z(i);if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return{ok:!1,reason:"Cannot expand now."};if(!c)return{ok:!1,reason:"Invalid expansion lot."};let h=c.direction||"right",m=V();if(e.cashy.cols&&(y.cols=T.colStart+T.cols),T.rowStart+T.rows>y.rows&&(y.rows=T.rowStart+T.rows),se(T),Kr(e,T.chunkX,T.chunkY),e.gridExpansionPurchases=(e.gridExpansionPurchases||0)+1,e.gridExpansionPurchasesByDirection[h]=(e.gridExpansionPurchasesByDirection[h]||0)+1,te();let j=Ir({seed:`${e.runSeed}:grid-expansion:${T.chunkX},${T.chunkY}:${e.gridExpansionPurchases}`,colStart:T.colStart,colEnd:T.colStart+T.cols,rowStart:T.rowStart,rowEnd:T.rowStart+T.rows,targetRatio:q.map.blockedRatio});for(let Re of j)e.blockedCells.add(Re);ve(e);let ie=T.cols*T.rows,fe=Mt(T);return W(e,fe.x+fe.w/2,fe.y+fe.h/2,`${h.toUpperCase()} +${ie} CELLS -${M(m)}`,p.green),s(),{ok:!0,direction:h,cost:m,addedCells:ie,blocked:j.size,chunkX:T.chunkX,chunkY:T.chunkY}}function U(i,c){return i>=0&&i=0&&c!c.has(m.id)&&Se(h,le(m),12))}function A(i,c,h=null){if(!U(i,c))return!1;if(N(i,c))return!0;let m=I(i,c),x=Et(e,i,c);if(x&&!(h?.type==="eggFarm"&&h.ref?.id===x.id))return!0;let T=Pt(e,i,c);return!!(T&&!(h?.type==="scanner"&&h.ref?.id===T.id)||e.conveyorTiles.has(m)&&!(h?.type==="conveyor"&&h.oldKey===m))}function _(i,c,h=null){let m={col:i,row:c};for(let x of Tt(m)){if(!U(x.col,x.row)||N(x.col,x.row))return!0;let T=I(x.col,x.row);if(Et(e,x.col,x.row))return!0;let ie=Pt(e,x.col,x.row);if(ie&&!(h?.type==="scanner"&&h.ref?.id===ie.id)||e.conveyorTiles.has(T))return!0}return!1}function k(){return e.selected?e.selected.type==="eggFarm"?e.eggFarms.find(i=>i.id===e.selected.id)||null:e.selected.type==="scanner"?e.scanners.find(i=>i.id===e.selected.id)||null:e.selected.type==="conveyor"?e.conveyorTiles.has(e.selected.id)?{type:"conveyor",id:e.selected.id}:null:e.selected.type==="facility"&&e.facilities[e.selected.id]||null:null}function g(i){return i?i.type==="eggFarm"?`${xt("eggFarm")} #${i.id}`:i.type==="scanner"?`${i.kind==="auto"?xt("autoScanner"):xt("manualScanner")} #${i.id}`:i.type==="conveyor"?e.conveyorMeta.get(i.id)?.kind==="boostConveyor"?xt("boostConveyor"):xt("conveyor"):i.type==="facility"?i.name:"Equipment":"Equipment"}function O(i){return i?.type==="conveyor"?e.conveyorMeta?.get(i.oldKey||i.ref?.id)?.price||Bn(i):Bn(i)}function X(){return!!e.cardEffects?.usedMachineActive}function oe(){return X()?{usedMachine:!0,noRefund:!0,durabilityBaseMultiplier:.6}:{usedMachine:!1,noRefund:!1,durabilityBaseMultiplier:1}}function de(i){let c=oe();return Object.assign(i,c),i}function Te(i){let c=i?.ref||i||{};if(i?.type==="eggFarm"||c.type==="eggFarm")return e.eggFarms.length<=1?"Cannot sell the last EGG FARM.":"";if((i?.type==="facility"||c.type==="facility")&&["mixer","trash","truck"].includes(c.baseId||c.id)){let h=c.baseId||c.id;if(Object.values(e.facilities).filter(x=>(x.baseId||x.id)===h).length<=1)return`Cannot sell the last ${c.shortName||c.name||c.id}.`}return""}function ce(i){t.buildStatus.textContent=i,W(e,n.width/2-e.view.x,86-e.view.y,i.toUpperCase(),p.danger)}function rt(i){if(!i)return null;let c=I(i.col,i.row);return e.conveyorMeta.get(c)||null}function J(i){return i?(Array.isArray(i.outDirs)||(i.outDirs=[]),i.outDirs=[...new Set(i.outDirs.filter(c=>["right","left","down","up"].includes(c)))],P.includes(i.branchMode)||(i.branchMode="random"),i.kind||(i.kind="conveyor"),i.speedMultiplier||(i.speedMultiplier=i.kind==="boostConveyor"?2:1),i.outDirs):[]}function ge(i){return i?ue.filter(c=>e.conveyorTiles.has(I(i.col+c.dc,i.row+c.dr))).map(c=>c.name):[]}function Le(i){return ge(i).length>=3}function it(i,c){let h=ue.find(ie=>ie.name===c);if(!i||!h)return!1;let m=I(i.col+h.dc,i.row+h.dr),x=e.conveyorMeta.get(m);if(!x)return!1;let T=h.opposite;return[...new Set([...Array.isArray(x.outDirs)?x.outDirs:[],x.dir].filter(Boolean))].includes(T)}function Ge(i){if(!e.conveyorTiles.has(i))return[];let c=Q(i),h=e.conveyorMeta.get(i),m=J(h),x=ge(c),T=[...new Set([...m,h?.dir].filter(Boolean))].filter(fe=>x.includes(fe)),j=x,ie=T.length?T:j;return h&&(h.outDirs=m.filter(fe=>x.includes(fe)),h.dir&&!x.includes(h.dir)&&(h.dir=h.outDirs[0]||null),h.branchMode!=="random"&&!x.includes(h.branchMode)&&(h.branchMode="random")),ie}function st(i){if(!e.conveyorTiles.has(i))return[];let c=Q(i),h=ge(c);return Le(c)||h.length?h:Ge(i)}function oo(i){let c=Q(i),h=st(i);if(h.length<3)return[];let m=new Set(h.filter(x=>it(c,x)));return h.filter(x=>{let T=new Set(m);return T.add(x),h.filter(j=>!T.has(j)).length>=2})}function yn(i,c){let h=at(i,c);if(!h)return!1;let m=I(i.col,i.row),x=I(c.col,c.row),T=e.conveyorMeta.get(m),j=e.conveyorMeta.get(x);if(!T||!j)return!1;let ie=J(T),fe=!ie.includes(h)||T.dir!==h||!j.dir;return ie.includes(h)||ie.push(h),T.dir=h,j.dir||(j.dir=h),fe}function hn(i){let c=ro(i);return c.length<2?mn(i):(Fe(e),io(c),ve(e),s(),!0)}function mn(i){if(!i)return!1;let c=I(i.col,i.row),h=e.conveyorMeta.get(c);if(!h||Le(i))return!1;let m=ue.map(j=>j.name),x=h.dir&&m.includes(h.dir)?h.dir:null,T=m[(Math.max(-1,m.indexOf(x))+1)%m.length];return Fe(e),h.dir=T,h.outDirs=[T],h.branchMode="random",ve(e),s(),!0}function vt(i){return i?ue.map(c=>({col:i.col+c.dc,row:i.row+c.dr})).filter(c=>e.conveyorTiles.has(I(c.col,c.row))):[]}function ro(i){if(!i||!e.conveyorTiles.has(I(i.col,i.row))||Le(i))return[];let c=vt(i);if(!c.length||c.length>2)return[];let h=T=>{let j=[],ie=new Set([I(i.col,i.row)]),fe=i,Re=T,br=0;for(;Re&&br<200;){br+=1;let vr=I(Re.col,Re.row);if(ie.has(vr)||(ie.add(vr),j.push(Re),Le(Re)))break;let wr=vt(Re).filter(Sr=>!(Sr.col===fe.col&&Sr.row===fe.row));if(wr.length!==1)break;fe=Re,Re=wr[0]}return j},m=c[0]?h(c[0]).reverse():[],x=c[1]?h(c[1]):[];return[...m,i,...x]}function bn(i,c){return!!i&&[...new Set([...Array.isArray(i.outDirs)?i.outDirs:[],i.dir].filter(Boolean))].includes(c)}function io(i){let c=0,h=0;for(let x=0;xh?[...i].reverse():i;for(let x=0;x=Math.abs(m)?{col:i.col+Math.sign(h),row:i.row}:{col:i.col,row:i.row+Math.sign(m)}}function so(i){d=!1,v=i?{col:i.col,row:i.row}:null,C=!1,l=null,Nt(i)}function jt(i){if(!i)return;if(!l)return Nt(i);let c=l,h=0;for(;(c.col!==i.col||c.row!==i.row)&&h<64;){let m=Jt(c,i);if(Nt(m),c=l||m,h+=1,!l)break}}function wn(){!C&&v&&e.conveyorTiles.has(I(v.col,v.row))&&hn(v),v=null,C=!1,l=null,d=!1}function u(i){if(!i)return ce(re.fail.outOfGrid);let{col:c,row:h}=i;if(e.buildTool==="conveyor"||e.buildTool==="boostConveyor"){let m=vn(i,null);if(!m.ok)return ce(m.reason||re.fail.cellOccupied);ve(e);return}if(N(c,h))return ce("Cannot build on blocked ground.");if(e.buildTool==="manualScanner"||e.buildTool==="autoScanner"?_(c,h):A(c,h))return ce(re.fail.cellOccupied);e.buildTool==="eggFarm"?b(c,h):e.buildTool==="manualScanner"?S(c,h,"manual"):e.buildTool==="autoScanner"&&S(c,h,"auto")}function f(i){let c=We(i.x,i.y);if(["conveyor","boostConveyor","eggFarm","manualScanner","autoScanner"].includes(e.buildTool))return u(c);if(nn.includes(e.buildTool))return w(i,e.buildTool)}function b(i,c){let h=_e("eggFarm",e);if(e.cashT.kind==="manual").length>=8)return ce("Manual Scanner limit reached (8 max).");let m=h==="auto"?_e("autoScanner",e):_e("manualScanner",e);if(e.cashx.id!==c.ref.id),yt(e,m.x,m.y),ve(e)}if(c.type==="scanner"){let m=pe(c.ref);E(c,m.x,m.y),e.scanners=e.scanners.filter(x=>x.id!==c.ref.id),yt(e,m.x,m.y),ve(e)}if(c.type==="facility"){let m=c.ref;E(c,m.x+m.w/2,m.y+m.h/2),delete e.facilities[m.id],yt(e,m.x+m.w/2,m.y+m.h/2),ve(e)}e.selected=null,e.multiSelected=[],s()}function K(i){let c=Object.values(e.facilities).find(j=>{if(i.x>=j.x&&i.x<=j.x+j.w&&i.y>=j.y&&i.y<=j.y+j.h)return!0;if(!j.entry)return!1;let fe=F(j.entry.col,j.entry.row);return Math.abs(i.x-fe.x)<=y.cell*.46&&Math.abs(i.y-fe.y)<=y.cell*.46});if(c)return{type:"facility",ref:c};let h=We(i.x,i.y);if(!h)return null;let m=Et(e,h.col,h.row);if(m)return{type:"eggFarm",ref:m};let x=Pt(e,h.col,h.row);if(x)return{type:"scanner",ref:x};let T=I(h.col,h.row);return e.conveyorTiles.has(T)?{type:"conveyor",oldKey:T,ref:{type:"conveyor",id:T}}:null}let ee=gs({game:e,canvasPoint:o,updatePanels:s,equipmentAtPoint:K,fail:ce,pointInGrid:U,rectOfFacility:le,rectsOverlap:Se});function Qe(i){return null}function ur(){let i=k();i&&(i.type==="conveyor"?D(F(...Object.values(Q(i.id)))):i.type==="eggFarm"?D(F(i.col,i.row)):i.type==="scanner"?D(pe(i)):i.type==="facility"&&D({x:i.x+i.w/2,y:i.y+i.h/2}))}function qe(i,c,h="primary-button"){let m=document.createElement("button");return m.type="button",m.className=h,m.textContent=i,m.addEventListener("click",c),m}function Zt(){e.cardTargetPick?.mode==="autoScannerMenu"&&(e.cardTargetPick=null),t.modal.classList.remove("visible","equipment-popover"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function lo(i){t.modalTitle.textContent="Auto Scanner",e.cardTargetPick={pending:!0,mode:"autoScannerMenu",cardId:null,targetKeys:[`scanner:${i.id}`],remaining:1},t.modalBody.innerHTML=`

Left / right output routing for this AUTO scanner.

Current: ${i.role===0?"Male left / others right":"Poop left / others right"}

-

Cooldown: ${et(i).toFixed(1)}s.

-
`,t.modalActions.innerHTML="";let c=He("Male Left / Others Right",()=>{$e(e),i.role=0,Zt(),s()},i.role===0?"facility-action warn":"facility-action"),h=He("Poop Left / Others Right",()=>{$e(e),i.role=1,Zt(),s()},i.role===1?"facility-action warn":"facility-action");t.modalActions.append(c,h,He("Close",Zt,"facility-action")),io(i),t.modal.classList.add("visible","equipment-popover"),s()}function dr(i){return i?.label||i?.key||"?"}function Ks(i){let c=i.key===" "?"Space":i.key.length===1?i.key.toUpperCase():i.key.replace(/^Arrow/,"");return{key:i.key.toLowerCase(),code:i.code,label:c}}function Hs(i,c,h){for(let m of e.scanners.filter(k=>k.kind==="manual"))for(let k of["left","right"]){if(m.id===i.id&&k===c)continue;let T=m.keys?.[k];if(T&&(T.code===h.code||T.key===h.key))return!0}return!1}function en(i,c=""){if(!i||i.kind!=="manual")return;t.modalTitle.textContent=`Manual Scanner #${i.id}`;let h=dr(i.keys?.left),m=dr(i.keys?.right),k=qs(i);t.modalBody.innerHTML=` +

Cooldown: ${tt(i).toFixed(1)}s.

+ `,t.modalActions.innerHTML="";let c=qe("Male Left / Others Right",()=>{Fe(e),i.role=0,Zt(),s()},i.role===0?"facility-action warn":"facility-action"),h=qe("Poop Left / Others Right",()=>{Fe(e),i.role=1,Zt(),s()},i.role===1?"facility-action warn":"facility-action");t.modalActions.append(c,h,qe("Close",Zt,"facility-action")),ao(i),t.modal.classList.add("visible","equipment-popover"),s()}function dr(i){return i?.label||i?.key||"?"}function Hs(i){let c=i.key===" "?"Space":i.key.length===1?i.key.toUpperCase():i.key.replace(/^Arrow/,"");return{key:i.key.toLowerCase(),code:i.code,label:c}}function qs(i,c,h){for(let m of e.scanners.filter(x=>x.kind==="manual"))for(let x of["left","right"]){if(m.id===i.id&&x===c)continue;let T=m.keys?.[x];if(T&&(T.code===h.code||T.key===h.key))return!0}return!1}function en(i,c=""){if(!i||i.kind!=="manual")return;t.modalTitle.textContent=`Manual Scanner #${i.id}`;let h=dr(i.keys?.left),m=dr(i.keys?.right),x=Ys(i);t.modalBody.innerHTML=`

Left route key: ${h}

Right route key: ${m}

${c?`

${c}

`:""} - ${k?`

${k}

`:""} -
`,t.modalActions.innerHTML="",t.modalActions.appendChild(He("Set Left Key",()=>fr(i,"left"),"facility-action warn")),t.modalActions.appendChild(He("Set Right Key",()=>fr(i,"right"),"facility-action warn")),t.modalActions.appendChild(He("Close",Zt,"facility-action")),io(i),t.modal.classList.add("visible","equipment-popover")}function qs(i){let c=[{side:"left",binding:i.keys?.left},{side:"right",binding:i.keys?.right}];if(c[0].binding&&c[1].binding&&(c[0].binding.code===c[1].binding.code||c[0].binding.key===c[1].binding.key))return"Left and right keys conflict.";for(let h of c)if(h.binding)for(let m of e.scanners.filter(k=>k.kind==="manual"&&k.id!==i.id)){if(m.keys?.left&&(m.keys.left.code===h.binding.code||m.keys.left.key===h.binding.key))return`Key conflicts with Manual Scanner #${m.id} left.`;if(m.keys?.right&&(m.keys.right.code===h.binding.code||m.keys.right.key===h.binding.key))return`Key conflicts with Manual Scanner #${m.id} right.`}return""}function fr(i,c){t.modalBody.innerHTML=`

Press a key for ${c.toUpperCase()} route.

Esc cancels.

`,t.modalActions.innerHTML="";let h=m=>{if(m.preventDefault(),m.stopPropagation(),window.removeEventListener("keydown",h,!0),m.key==="Escape")return en(i);let k=Ks(m),T=Hs(i,c,k);$e(e),i.keys=i.keys||{left:null,right:null},i.keys[c]=k,s(),en(i,T?`${k.label} assigned, but another scanner already uses it.`:`${c.toUpperCase()} set to ${k.label}.`)};window.addEventListener("keydown",h,!0)}function Ys(){let i=x();if(!(!i||i.type!=="scanner"))return i.kind==="auto"?ro(i):en(i)}function Vs(i){if(!i)return{x:80,y:80};if(i.type==="conveyor"){let c=Q(i.id);return F(c.col,c.row)}return i.type==="eggFarm"?F(i.col,i.row):i.type==="scanner"?pe(i):i.type==="facility"?{x:i.x+i.w/2,y:i.y+10}:{x:80,y:80}}function io(i){let c=n.getBoundingClientRect(),h=Vs(i),m=e.view?.scale||1,k=c.left+(h.x*m+(e.view?.x||0))/n.width*c.width+18,T=c.top+(h.y*m+(e.view?.y||0))/n.height*c.height-12,j=Math.max(12,window.innerWidth-274),ie=Math.max(12,window.innerHeight-220);t.modal.style.setProperty("--popover-x",`${Math.max(12,Math.min(j,k))}px`),t.modal.style.setProperty("--popover-y",`${Math.max(12,Math.min(ie,T))}px`)}function zs(){let i=x();if(!i)return;let c=mr(i);t.modalTitle.textContent=g(i),t.modalBody.innerHTML=` -
${c.map(k=>`

${k}

`).join("")}
- ${["mixer","truck"].includes(i.baseId||i.id)?'

Income/Fine = ceil(base x 1.10^upgrades)

':""}`,t.modalActions.innerHTML="",i.type==="scanner"&&i.kind==="auto"&&t.modalActions.appendChild(He("Auto Menu",()=>ro(i),"facility-action warn")),i.type==="scanner"&&i.kind==="manual"&&t.modalActions.appendChild(He("Set Keys",()=>en(i),"facility-action warn"));let h=i.type==="conveyor"?{type:"conveyor",oldKey:i.id,ref:i}:{type:i.type,ref:i},m=ge(h);if(m){let k=He(m,()=>{},"facility-action danger disabled");k.disabled=!0,t.modalActions.appendChild(k)}else{let k=Dt(h,e),T=k.sameBuild?`Remove / Refund ${M(k.amount)}`:`Sell ${M(k.amount)}`;t.modalActions.appendChild(He(T,()=>{ur(),Zt()},"facility-action danger"))}io(i),t.modal.classList.add("visible","equipment-popover")}function Xs(i){e.phase==="build"&&(vn(),e.buildTool=e.buildTool===i?null:i,e.selected=null,e.multiSelected=[],e.selectionBox=null,s())}function Qs(){let i=[];for(let[c,h]of Object.entries(e.facilities))if(i.push({id:`facility:${c}`,price:O({type:"facility",ref:h}),x:h.x,y:h.y,w:h.w,h:h.h}),h.entry){let m=F(h.entry.col,h.entry.row);i.push({id:`facilityPort:${c}`,price:O({type:"facility",ref:h}),x:m.x-18,y:m.y-18,w:36,h:36})}for(let c of e.eggFarms){let h=F(c.col,c.row);i.push({id:`eggFarm:${c.id}`,price:O({type:"eggFarm",ref:c}),x:h.x-24,y:h.y-24,w:48,h:48})}for(let c of e.scanners){let h=pe(c);i.push({id:`scanner:${c.id}`,price:O({type:"scanner",ref:c}),x:h.x-50,y:h.y-73,w:100,h:146})}for(let c of e.conveyorTiles){let h=Q(c),m=F(h.col,h.row),k=e.conveyorMeta.get(c)||{};i.push({id:`conveyor:${c}`,price:k.price||Ne(k.kind==="boostConveyor"?"boostConveyor":"conveyor",e),x:m.x-22,y:m.y-22,w:44,h:44})}return i}function Js(i){return A[i]||A.random}function Ec(i){return it(i)}function pr(i){return e.conveyorTiles.has(i)?Be(Q(i)):!1}function yr(i){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return null;for(let c of e.conveyorTiles){if(!pr(c))continue;let h=Q(c),m=F(h.col,h.row),k=m.x-L.w/2,T=m.y+L.y-L.h/2;if(i.x>=k&&i.x<=k+L.w&&i.y>=T&&i.y<=T+L.h)return c}return null}function js(i){let c=yr(i);return c?(hr(c),!0):!1}function hr(i){let c=e.conveyorMeta.get(i);if(!c)return!1;let h=eo(i);if(h.length<2)return!1;$e(e);let m=P.includes(c.branchMode)?c.branchMode:"random",k=["random",...ue.map(T=>T.name).filter(T=>h.includes(T))];return c.branchMode=k[(Math.max(0,k.indexOf(m))+1)%k.length],e.selected=null,e.multiSelected=[],s(),!0}function mr(i){me(e);let c=[],h=i?.type==="facility"?i.baseId||i.id:"";if(i.type==="eggFarm"){let[m,k]=rn(i);c.push(`Price: ${M(O(i))}`);{let T=ge({type:i.type,ref:i});c.push(T?`Sale: blocked (${T})`:`Sale value: ${M(Dt({type:i.type,ref:i},e).amount)}`)}c.push(`Level: ${i.level}/4`),c.push(`Random interval: ${m.toFixed(2)}-${k.toFixed(2)}s`),c.push(`Durability: ${dn(i)}% | Spawn delay x${_n(i).toFixed(2)}`)}else if(i.type==="scanner")c.push(`Price: ${M(O(i))}`),c.push(`Sale value: ${M(Dt({type:i.type,ref:i},e).amount)}`),c.push(`Type: ${i.kind.toUpperCase()} / Standard`),i.kind==="auto"&&c.push(`Role: ${i.role===0?"Male left / Others right":"Poop left / Others right"}`),c.push(`Queue: ${i.queue.length}`),i.kind==="auto"&&c.push(`Cooldown: ${i.cooldown.toFixed(1)}s / ${et(i,e).toFixed(1)}s`),i.kind==="auto"&&c.push(`Durability: ${dn(i)}% | Delay x${Wn(i).toFixed(2)}`),i.kind==="manual"&&c.push("Durability: none | Always normal");else if(i.type==="conveyor"){let m=e.conveyorMeta.get(i.id),k=e.componentLookup?.get(i.id),T=k?e.congestion.get(k):null;c.push(`Price: ${M(O({type:"conveyor",oldKey:i.id,ref:i}))}`),c.push(`Cell: ${i.id}`),c.push(`Type: ${m?.kind==="boostConveyor"?"BOOST BELT":"Normal Belt"} | Speed x${Number(m?.speedMultiplier||1).toFixed(1)}`),c.push(`Congestion: ${T?Math.floor(T.ratio*100):0}%`),c.push(`Durability: ${dn({meta:m})}% | Speed x${Un({meta:m}).toFixed(2)}`),pr(i.id)?(c.push(`Branch mode: ${Js(m?.branchMode||"random")}`),c.push("Use the Branch button below or the on-belt branch badge.")):c.push("Branch mode: needs 3+ conveyor connections."),c.push(`Sale value: ${M(Dt({type:"conveyor",oldKey:i.id,ref:i},e).amount)}`)}else if(i.type==="facility"){c.push(`Price: ${M(O(i))}`);{let m=ge({type:i.type,ref:i});c.push(m?`Sale: blocked (${m})`:`Sale value: ${M(Dt({type:i.type,ref:i},e).amount)}`)}if(c.push(["mixer","truck","trash"].includes(i.id)?`Level: ${i.level} / no cap`:`Level: ${i.level}`),h==="truck"&&c.push("Durability: none | Always normal"),["mixer","trash"].includes(h)&&c.push(`Durability: ${dn(i)}% | Extra delay ${Vo(e,i).toFixed(2)}s`),h==="mixer"&&(c.push(`Income: ${M(qe(e))} per chick | upgrade x${ct(e,"mixer").toFixed(3)}`),c.push(`Poop fine: -${M(ln(e))}`)),h==="truck"&&(c.push(`Income: ${M(De(e))} per target cargo | upgrade x${ct(e,"truck").toFixed(3)}`),c.push(`Poop shipment fine: -${M(an(e))}`)),h==="trash"){let m=At(e),k=ut(m);c.push(`Bonus cards: ${m}/${Kt()}`),c.push(`Poop income bonus: ${M(k)} per processed poop.`),c.push("With enough upgrades, poop can out-earn male/female routes.")}i.entry&&c.push(`Receiver: edge cell ${i.entry.col},${i.entry.row} (${i.side})`)}return c}function Zs(i){if(!i||e.phase!=="build")return"";let c=Dn(e).find(h=>h.type===i.type&&h.id===i.id);return c?c.message||"Not connected to conveyor route":""}function el(i){return i?i.type==="conveyor"&&e.conveyorMeta.get(i.id)?.kind==="boostConveyor"?"Moves chicks twice as fast. Wears down like a normal belt.":i.type==="conveyor"?"A stubborn belt tile. It only cares about the next cell.":i.type==="eggFarm"?"A tiny gatehouse producing questionable eggs on schedule.":i.type==="scanner"&&i.kind==="auto"?"Slower than hands without upgrades.":i.type==="scanner"?"A manual checkpoint. The operator is the algorithm.":i.type==="facility"&&(i.baseId||i.id)==="mixer"?"Male chicks become revenue here. Do not feed it poop.":i.type==="facility"&&(i.baseId||i.id)==="trash"?"Poop goes in. Sometimes coins come out, for reasons best left unaudited.":i.type==="facility"&&(i.baseId||i.id)==="truck"?"The shipping endpoint. Correct cargo pays; wrong cargo complains.":"Factory equipment.":""}return{buildAtCell:u,buildAtPoint:p,eraseAtPoint:D,equipmentAtPoint:K,startSelectionBox:ee.startSelectionBox,updateSelectionBox:ee.updateSelectionBox,finishSelectionBox:ee.finishSelectionBox,startGroupDrag:ee.startGroupDrag,updateGroupDrag:ee.updateGroupDrag,finishGroupDrag:ee.finishGroupDrag,selectedObject:x,selectedTitle:g,equipmentPrice:O,selectedUpgradeCost:Xe,selectedInfoLines:mr,flavorText:el,disconnectedWarningFor:Zs,gridExpansionCost:V,buyGridExpansion:I,expansionOfferAtPoint:ye,beginConveyorDrag:oo,continueConveyorDrag:jt,endConveyorDrag:vn,cycleSingleConveyorDirection:yn,branchSwitcherAtPoint:yr,cycleBranchModeAtPoint:js,cycleBranchModeForKey:hr,removeSelected:ur,switchScannerRole:Ys,showManualScannerMenu:en,showAutoScannerMenu:ro,showSelectedMenu:zs,setBuildTool:Xs,fail:ce,isEquipmentCell:R,equipmentHitBoxes:Qs,routeFromFarmToScanner:Rt}}function Ts({game:e,ui:t,build:n,startGame:o,beginCardDraft:r,activeQueuedChick:s}){function l(R){return String(R).replace(/[&<>"']/g,G=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[G])}function d(){return Math.round(Yn(e))}function v(){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return!1;let R=!1;for(let G of fo)if(R=!0,e.cash>=Ne(G,e))return!1;return R}function C(){P(),A(),ne(),V(),L()}function P(){for(let[G,x]of Object.entries(t.buttons))x?.classList?.contains("tool-button")&&x.classList.toggle("active",e.buildTool===G);for(let G of fo){let x=t.buttons[G];if(!x)continue;let g=Ne(G,e),O=x.querySelector("span");O&&(O.textContent=G==="conveyor"||G==="boostConveyor"?`${M(g)} / tile`:M(g));let X=G==="manualScanner"&&e.scanners.filter(de=>de.kind==="manual").length>=8,oe=e.cashRt(e,X)?.scannerId).length,G=sn(e),x=Math.max(0,Math.floor(e.lastResult?.profit??e.stats?.profit??0)),g=Math.max(1,Number(e.turn)||1),O=Fn(e,g,x);t.turnSummary.innerHTML=[`Seed: ${l(e.runSeed||"none")} | Grid box: ${e.gridRows||10}x${e.gridCols||20} | Owned: ${e.gridOwnedCells||e.ownedCells?.size||(e.gridRows||10)*(e.gridCols||20)} cells | Blocked: ${e.blockedCells?.size||0} cells`,`Truck target: ${Je(e).toUpperCase()} | Male fine: -${M(Fo(e))}`,`Poop fine: Mixer -${M(ln(e))} / Shipment -${M(an(e))}`,`Fairies tribute on Next Day: -${M(O.amount)} | base ${M(O.base)} + profit share ${M(O.profitTribute)} | basis net ${M(x)} | exemption ${M(O.profitExemption)}${O.reduction?` | reduction -${M(O.reduction)}`:""}`,`Maintenance: worst ${Qo(e).worst.percent}% dirty (${Qo(e).worst.label}) | Repairman: ${e.repairman?.hiredForNextDay?"hired next day":e.repairman?.active?"working":"none"}`,`Manual combo: ${e.manualCombo?.count||0} | Card draft: ${e.cardDraft?.pending?Math.max(1,e.cardDraft.picksRemaining||1)+" pick(s) left":"ready after each day"} | Belt: ${d()}px/s | Farms with scanner route: ${R}/${e.eggFarms.length}`,e.cardEffects?.usedMachineActive?'Procurement: USED MACHINE MODE / no refunds / 60% durability':"",G.length?`Blocked: ${G[0]}`:`${re.status.allPortsConnected}`].join("
")}function ne(){if(!t.eventPanel)return;let R=e.eventOffer;if(e.phase!=="build"){t.eventPanel.innerHTML=re.status.eventPanelRunning;return}if(!R){t.eventPanel.className="event-card empty",e.turn+1Event lock active.No irregular events during Days 1-7. First possible forced event: Day ${wt}.`:t.eventPanel.innerHTML="No event.Random forced events can appear later.";return}t.eventPanel.className="event-card accepted",t.eventPanel.innerHTML=` + ${x?`

${x}

`:""} + `,t.modalActions.innerHTML="",t.modalActions.appendChild(qe("Set Left Key",()=>fr(i,"left"),"facility-action warn")),t.modalActions.appendChild(qe("Set Right Key",()=>fr(i,"right"),"facility-action warn")),t.modalActions.appendChild(qe("Close",Zt,"facility-action")),ao(i),t.modal.classList.add("visible","equipment-popover")}function Ys(i){let c=[{side:"left",binding:i.keys?.left},{side:"right",binding:i.keys?.right}];if(c[0].binding&&c[1].binding&&(c[0].binding.code===c[1].binding.code||c[0].binding.key===c[1].binding.key))return"Left and right keys conflict.";for(let h of c)if(h.binding)for(let m of e.scanners.filter(x=>x.kind==="manual"&&x.id!==i.id)){if(m.keys?.left&&(m.keys.left.code===h.binding.code||m.keys.left.key===h.binding.key))return`Key conflicts with Manual Scanner #${m.id} left.`;if(m.keys?.right&&(m.keys.right.code===h.binding.code||m.keys.right.key===h.binding.key))return`Key conflicts with Manual Scanner #${m.id} right.`}return""}function fr(i,c){t.modalBody.innerHTML=`

Press a key for ${c.toUpperCase()} route.

Esc cancels.

`,t.modalActions.innerHTML="";let h=m=>{if(m.preventDefault(),m.stopPropagation(),window.removeEventListener("keydown",h,!0),m.key==="Escape")return en(i);let x=Hs(m),T=qs(i,c,x);Fe(e),i.keys=i.keys||{left:null,right:null},i.keys[c]=x,s(),en(i,T?`${x.label} assigned, but another scanner already uses it.`:`${c.toUpperCase()} set to ${x.label}.`)};window.addEventListener("keydown",h,!0)}function Vs(){let i=k();if(!(!i||i.type!=="scanner"))return i.kind==="auto"?lo(i):en(i)}function zs(i){if(!i)return{x:80,y:80};if(i.type==="conveyor"){let c=Q(i.id);return F(c.col,c.row)}return i.type==="eggFarm"?F(i.col,i.row):i.type==="scanner"?pe(i):i.type==="facility"?{x:i.x+i.w/2,y:i.y+10}:{x:80,y:80}}function ao(i){let c=n.getBoundingClientRect(),h=zs(i),m=e.view?.scale||1,x=c.left+(h.x*m+(e.view?.x||0))/n.width*c.width+18,T=c.top+(h.y*m+(e.view?.y||0))/n.height*c.height-12,j=Math.max(12,window.innerWidth-274),ie=Math.max(12,window.innerHeight-220);t.modal.style.setProperty("--popover-x",`${Math.max(12,Math.min(j,x))}px`),t.modal.style.setProperty("--popover-y",`${Math.max(12,Math.min(ie,T))}px`)}function Xs(){let i=k();if(!i)return;let c=mr(i);t.modalTitle.textContent=g(i),t.modalBody.innerHTML=` +
${c.map(x=>`

${x}

`).join("")}
+ ${["mixer","truck"].includes(i.baseId||i.id)?'

Income/Fine = ceil(base x 1.10^upgrades)

':""}`,t.modalActions.innerHTML="",i.type==="scanner"&&i.kind==="auto"&&t.modalActions.appendChild(qe("Auto Menu",()=>lo(i),"facility-action warn")),i.type==="scanner"&&i.kind==="manual"&&t.modalActions.appendChild(qe("Set Keys",()=>en(i),"facility-action warn"));let h=i.type==="conveyor"?{type:"conveyor",oldKey:i.id,ref:i}:{type:i.type,ref:i},m=Te(h);if(m){let x=qe(m,()=>{},"facility-action danger disabled");x.disabled=!0,t.modalActions.appendChild(x)}else{let x=$t(h,e),T=x.sameBuild?`Remove / Refund ${M(x.amount)}`:`Sell ${M(x.amount)}`;t.modalActions.appendChild(qe(T,()=>{ur(),Zt()},"facility-action danger"))}ao(i),t.modal.classList.add("visible","equipment-popover")}function Qs(i){e.phase==="build"&&(wn(),e.buildTool=e.buildTool===i?null:i,e.selected=null,e.multiSelected=[],e.selectionBox=null,s())}function Js(){let i=[];for(let[c,h]of Object.entries(e.facilities))if(i.push({id:`facility:${c}`,price:O({type:"facility",ref:h}),x:h.x,y:h.y,w:h.w,h:h.h}),h.entry){let m=F(h.entry.col,h.entry.row);i.push({id:`facilityPort:${c}`,price:O({type:"facility",ref:h}),x:m.x-18,y:m.y-18,w:36,h:36})}for(let c of e.eggFarms){let h=F(c.col,c.row);i.push({id:`eggFarm:${c.id}`,price:O({type:"eggFarm",ref:c}),x:h.x-24,y:h.y-24,w:48,h:48})}for(let c of e.scanners){let h=pe(c);i.push({id:`scanner:${c.id}`,price:O({type:"scanner",ref:c}),x:h.x-50,y:h.y-73,w:100,h:146})}for(let c of e.conveyorTiles){let h=Q(c),m=F(h.col,h.row),x=e.conveyorMeta.get(c)||{};i.push({id:`conveyor:${c}`,price:x.price||_e(x.kind==="boostConveyor"?"boostConveyor":"conveyor",e),x:m.x-22,y:m.y-22,w:44,h:44})}return i}function js(i){return R[i]||R.random}function Rc(i){return st(i)}function pr(i){return e.conveyorTiles.has(i)?Le(Q(i)):!1}function yr(i){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return null;for(let c of e.conveyorTiles){if(!pr(c))continue;let h=Q(c),m=F(h.col,h.row),x=m.x-L.w/2,T=m.y+L.y-L.h/2;if(i.x>=x&&i.x<=x+L.w&&i.y>=T&&i.y<=T+L.h)return c}return null}function Zs(i){let c=yr(i);return c?(hr(c),!0):!1}function hr(i){let c=e.conveyorMeta.get(i);if(!c)return!1;let h=oo(i);if(h.length<2)return!1;Fe(e);let m=P.includes(c.branchMode)?c.branchMode:"random",x=["random",...ue.map(T=>T.name).filter(T=>h.includes(T))];return c.branchMode=x[(Math.max(0,x.indexOf(m))+1)%x.length],e.selected=null,e.multiSelected=[],s(),!0}function mr(i){me(e);let c=[],h=i?.type==="facility"?i.baseId||i.id:"";if(i.type==="eggFarm"){let[m,x]=rn(i);c.push(`Price: ${M(O(i))}`);{let T=Te({type:i.type,ref:i});c.push(T?`Sale: blocked (${T})`:`Sale value: ${M($t({type:i.type,ref:i},e).amount)}`)}c.push(`Level: ${i.level}/4`),c.push(`Random interval: ${m.toFixed(2)}-${x.toFixed(2)}s`),c.push(`Durability: ${dn(i)}% | Spawn delay x${Hn(i).toFixed(2)}`)}else if(i.type==="scanner")c.push(`Price: ${M(O(i))}`),c.push(`Sale value: ${M($t({type:i.type,ref:i},e).amount)}`),c.push(`Type: ${i.kind.toUpperCase()} / Standard`),i.kind==="auto"&&c.push(`Role: ${i.role===0?"Male left / Others right":"Poop left / Others right"}`),c.push(`Queue: ${i.queue.length}`),i.kind==="auto"&&c.push(`Cooldown: ${i.cooldown.toFixed(1)}s / ${tt(i,e).toFixed(1)}s`),i.kind==="auto"&&c.push(`Durability: ${dn(i)}% | Delay x${Kn(i).toFixed(2)}`),i.kind==="manual"&&c.push("Durability: none | Always normal");else if(i.type==="conveyor"){let m=e.conveyorMeta.get(i.id),x=e.componentLookup?.get(i.id),T=x?e.congestion.get(x):null;c.push(`Price: ${M(O({type:"conveyor",oldKey:i.id,ref:i}))}`),c.push(`Cell: ${i.id}`),c.push(`Type: ${m?.kind==="boostConveyor"?"BOOST BELT":"Normal Belt"} | Speed x${Number(m?.speedMultiplier||1).toFixed(1)}`),c.push(`Congestion: ${T?Math.floor(T.ratio*100):0}%`),c.push(`Durability: ${dn({meta:m})}% | Speed x${Wn({meta:m}).toFixed(2)}`),pr(i.id)?(c.push(`Branch mode: ${js(m?.branchMode||"random")}`),c.push("Use the Branch button below or the on-belt branch badge.")):c.push("Branch mode: needs 3+ conveyor connections."),c.push(`Sale value: ${M($t({type:"conveyor",oldKey:i.id,ref:i},e).amount)}`)}else if(i.type==="facility"){c.push(`Price: ${M(O(i))}`);{let m=Te({type:i.type,ref:i});c.push(m?`Sale: blocked (${m})`:`Sale value: ${M($t({type:i.type,ref:i},e).amount)}`)}if(c.push(["mixer","truck","trash"].includes(i.id)?`Level: ${i.level} / no cap`:`Level: ${i.level}`),h==="truck"&&c.push("Durability: none | Always normal"),["mixer","trash"].includes(h)&&c.push(`Durability: ${dn(i)}% | Extra delay ${Xo(e,i).toFixed(2)}s`),h==="mixer"&&(c.push(`Income: ${M(Ye(e))} per chick | upgrade x${ut(e,"mixer").toFixed(3)}`),c.push(`Poop fine: -${M(ln(e))}`)),h==="truck"&&(c.push(`Income: ${M($e(e))} per target cargo | upgrade x${ut(e,"truck").toFixed(3)}`),c.push(`Poop shipment fine: -${M(an(e))}`)),h==="trash"){let m=Dt(e),x=dt(m);c.push(`Bonus cards: ${m}/${Kt()}`),c.push(`Poop income bonus: ${M(x)} per processed poop.`),c.push("With enough upgrades, poop can out-earn male/female routes.")}i.entry&&c.push(`Receiver: edge cell ${i.entry.col},${i.entry.row} (${i.side})`)}return c}function el(i){if(!i||e.phase!=="build")return"";let c=In(e).find(h=>h.type===i.type&&h.id===i.id);return c?c.message||"Not connected to conveyor route":""}function tl(i){return i?i.type==="conveyor"&&e.conveyorMeta.get(i.id)?.kind==="boostConveyor"?"Moves chicks twice as fast. Wears down like a normal belt.":i.type==="conveyor"?"A stubborn belt tile. It only cares about the next cell.":i.type==="eggFarm"?"A tiny gatehouse producing questionable eggs on schedule.":i.type==="scanner"&&i.kind==="auto"?"Slower than hands without upgrades.":i.type==="scanner"?"A manual checkpoint. The operator is the algorithm.":i.type==="facility"&&(i.baseId||i.id)==="mixer"?"Male chicks become revenue here. Do not feed it poop.":i.type==="facility"&&(i.baseId||i.id)==="trash"?"Poop goes in. Sometimes coins come out, for reasons best left unaudited.":i.type==="facility"&&(i.baseId||i.id)==="truck"?"The shipping endpoint. Correct cargo pays; wrong cargo complains.":"Factory equipment.":""}return{buildAtCell:u,buildAtPoint:f,eraseAtPoint:D,equipmentAtPoint:K,startSelectionBox:ee.startSelectionBox,updateSelectionBox:ee.updateSelectionBox,finishSelectionBox:ee.finishSelectionBox,startGroupDrag:ee.startGroupDrag,updateGroupDrag:ee.updateGroupDrag,finishGroupDrag:ee.finishGroupDrag,selectedObject:k,selectedTitle:g,equipmentPrice:O,selectedUpgradeCost:Qe,selectedInfoLines:mr,flavorText:tl,disconnectedWarningFor:el,gridExpansionCost:V,buyGridExpansion:$,expansionOfferAtPoint:ye,beginConveyorDrag:so,continueConveyorDrag:jt,endConveyorDrag:wn,cycleSingleConveyorDirection:hn,branchSwitcherAtPoint:yr,cycleBranchModeAtPoint:Zs,cycleBranchModeForKey:hr,removeSelected:ur,switchScannerRole:Vs,showManualScannerMenu:en,showAutoScannerMenu:lo,showSelectedMenu:Xs,setBuildTool:Qs,fail:ce,isEquipmentCell:A,equipmentHitBoxes:Js,routeFromFarmToScanner:At}}function Es({game:e,ui:t,build:n,startGame:o,beginCardDraft:r,activeQueuedChick:s}){function l(A){return String(A).replace(/[&<>"']/g,_=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[_])}function d(){return Math.round(zn(e))}function v(){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return!1;let A=!1;for(let _ of ho)if(A=!0,e.cash>=_e(_,e))return!1;return A}function C(){P(),R(),te(),V(),L()}function P(){for(let[_,k]of Object.entries(t.buttons))k?.classList?.contains("tool-button")&&k.classList.toggle("active",e.buildTool===_);for(let _ of ho){let k=t.buttons[_];if(!k)continue;let g=_e(_,e),O=k.querySelector("span");O&&(O.textContent=_==="conveyor"||_==="boostConveyor"?`${M(g)} / tile`:M(g));let X=_==="manualScanner"&&e.scanners.filter(de=>de.kind==="manual").length>=8,oe=e.cashAt(e,X)?.scannerId).length,_=sn(e),k=Math.max(0,Math.floor(e.lastResult?.profit??e.stats?.profit??0)),g=Math.max(1,Number(e.turn)||1),O=Ln(e,g,k);t.turnSummary.innerHTML=[`Seed: ${l(e.runSeed||"none")} | Grid box: ${e.gridRows||10}x${e.gridCols||20} | Owned: ${e.gridOwnedCells||e.ownedCells?.size||(e.gridRows||10)*(e.gridCols||20)} cells | Blocked: ${e.blockedCells?.size||0} cells`,`Truck target: ${je(e).toUpperCase()} | Male fine: -${M(Lo(e))}`,`Poop fine: Mixer -${M(ln(e))} / Shipment -${M(an(e))}`,`Fairies tribute on Next Day: -${M(O.amount)} | base ${M(O.base)} + profit share ${M(O.profitTribute)} | basis net ${M(k)} | exemption ${M(O.profitExemption)}${O.reduction?` | reduction -${M(O.reduction)}`:""}`,`Maintenance: worst ${jo(e).worst.percent}% dirty (${jo(e).worst.label}) | Repairman: ${e.repairman?.hiredForNextDay?"hired next day":e.repairman?.active?"working":"none"}`,`Manual combo: ${e.manualCombo?.count||0} | Card draft: ${e.cardDraft?.pending?Math.max(1,e.cardDraft.picksRemaining||1)+" pick(s) left":"ready after each day"} | Belt: ${d()}px/s | Farms with scanner route: ${A}/${e.eggFarms.length}`,e.cardEffects?.usedMachineActive?'Procurement: USED MACHINE MODE / no refunds / 60% durability':"",_.length?`Blocked: ${_[0]}`:`${re.status.allPortsConnected}`].join("
")}function te(){if(!t.eventPanel)return;let A=e.eventOffer;if(e.phase!=="build"){t.eventPanel.innerHTML=re.status.eventPanelRunning;return}if(!A){t.eventPanel.className="event-card empty",e.turn+1Event lock active.No irregular events during Days 1-7. First possible forced event: Day ${St}.`:t.eventPanel.innerHTML="No event.Random forced events can appear later.";return}t.eventPanel.className="event-card accepted",t.eventPanel.innerHTML=`
FORCED NEXT DAY
-

${R.title}

+

${A.title}

- Effect: ${R.route} - ${R.targetAmount?`Target: ${R.targetAmount}`:"Target: none"} - ${R.reward?`Reward: ${M(R.reward)}`:"Reward: none"} - Time ${R.daySeconds||60}s / Output x${Number(R.productionMultiplier||1).toFixed(2)} / Poop +${Math.round((R.poopRateAdd||0)*100)}pt -
`}function z(){P(),t.shell.classList.toggle("phase-running",e.phase==="running"),t.shell.classList.toggle("phase-build",e.phase==="build"),t.shell.classList.toggle("phase-gameover",e.phase==="gameover"),t.shell.classList.toggle("phase-title",e.phase==="title"),t.shell.classList.toggle("phase-loanDecision",e.phase==="loanDecision"),t.money.textContent=M(e.cash),t.money.classList.toggle("cash-negative",e.cash<0),t.money.classList.toggle("cash-positive",e.cash>tn),t.turn.textContent=e.turn,t.timeLeft.textContent=e.phase==="running"&&e.timeLeft<=0&&e.shutdownTimeLeft>0?`+${e.shutdownTimeLeft.toFixed(1)}s`:`${Math.max(0,e.timeLeft).toFixed(1)}s`,t.timeLeft.closest?.(".hud-card")?.classList.toggle("time-critical",e.phase==="running"&&(e.timeLeft<=10||e.timeLeft<=0&&e.shutdownTimeLeft>0)),t.phase.textContent=ye(),t.comboCount&&(t.comboCount.textContent=e.manualCombo?.count||0),se(),t.turnProfit.textContent=M(e.stats.profit),t.turnProfit.classList.toggle("cash-negative",e.stats.profit<0),t.turnProfit.classList.toggle("cash-positive",e.stats.profit>0),t.mixerCount.textContent=e.stats.mixerCount,t.truckFemaleCount.textContent=e.stats.truckFemale,t.truckMaleCount.textContent=e.stats.truckMale,t.poopCount.textContent=e.stats.poopSpawned,t.buttons.s1Left.disabled=e.phase!=="running"||!s(0),t.buttons.s1Right.disabled=e.phase!=="running"||!s(0),t.buttons.s2Left.disabled=e.phase!=="running"||!s(1),t.buttons.s2Right.disabled=e.phase!=="running"||!s(1);let R=e.scanners.find(O=>O.kind==="manual"&&O.slot===0),G=e.scanners.find(O=>O.kind==="manual"&&O.slot===1);R&&(t.buttons.s1Left.textContent=`S1 ${R.keys?.left?.label||"A"} -> Mixer`,t.buttons.s1Right.textContent=`S1 ${R.keys?.right?.label||"D"} -> S2`),G&&(t.buttons.s2Left.textContent=`S2 ${G.keys?.left?.label||"Left"} -> Waste`,t.buttons.s2Right.textContent=`S2 ${G.keys?.right?.label||"Right"} -> Truck`);let x=Math.max(0,Math.floor(e.lastResult?.profit??e.stats?.profit??0)),g=Fn(e,Math.max(1,Number(e.turn)||1),x).amount;t.buttons.nextTurn.textContent=e.phase==="build"&&g>0?`Next Day - Fairies ${M(g)}`:re.actions.nextDay,t.buttons.nextTurn.disabled=e.phase!=="build"||!!e.cardDraft?.pending||!!e.cardTargetPick?.pending||!ii(e)}function se(){if(!t.eventBrief||!t.targetBrief||!t.speedBrief)return;let R=Je(e).toUpperCase();t.targetBrief.textContent=`TRUCK TARGET: ${R}`,t.speedBrief.textContent=`BELT: ${d()} px/s | COMBO: ${e.manualCombo?.count||0}`,t.speedBrief.title=`Conveyor speed does not increase by day. Degraded belts reduce speed. Cap: ${Gt}px/s.`;let G=e.eventActive,x=e.eventOffer;G?(t.eventBrief.textContent=`ACTIVE EVENT: ${G.title} | ${G.route}`,t.eventBrief.className="event-brief active"):e.phase==="build"&&x?(t.eventBrief.textContent=`NEXT DAY EVENT: ${x.title} | ${x.route}${x.targetAmount?` | Target ${x.targetAmount}`:""}${x.reward?` | Reward ${M(x.reward)}`:""}`,t.eventBrief.className="event-brief next"):e.phase==="build"&&e.turn+1
\u2642Male->MixerS1: A
\u2640Female->TruckS1: D, then S2: right
\u{1F4A9}Poop->ShredderS1: D, then S2: left

Build phase: connect at least one EGG through a scanner to Mixer, Shredder, or Truck before Next Day. One day is one run.

',t.modalActions.innerHTML="",t.modalActions.appendChild(le(re.actions.startGame,o,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function I(R){let G=X=>`${X>0?"+":""}${M(X)}`,x=X=>`${X>0?"-":""}${M(X)}`,g=R.profit>=0?"cash-positive":"cash-negative",O=(R.mixerPoopFine||0)+(R.truckPoopFine||0)+(R.maleTruckFine||0)+(R.explosionDamage||0)+(R.cardRerollCost||0);t.modalTitle.textContent=`Day ${R.turn} Settlement`,t.modalBody.innerHTML=` -
Net result${M(R.profit)}
+ Effect: ${A.route} + ${A.targetAmount?`Target: ${A.targetAmount}`:"Target: none"} + ${A.reward?`Reward: ${M(A.reward)}`:"Reward: none"} + Time ${A.daySeconds||60}s / Output x${Number(A.productionMultiplier||1).toFixed(2)} / Poop +${Math.round((A.poopRateAdd||0)*100)}pt + `}function z(){P(),t.shell.classList.toggle("phase-running",e.phase==="running"),t.shell.classList.toggle("phase-build",e.phase==="build"),t.shell.classList.toggle("phase-gameover",e.phase==="gameover"),t.shell.classList.toggle("phase-title",e.phase==="title"),t.shell.classList.toggle("phase-loanDecision",e.phase==="loanDecision"),t.money.textContent=M(e.cash),t.money.classList.toggle("cash-negative",e.cash<0),t.money.classList.toggle("cash-positive",e.cash>tn),t.turn.textContent=e.turn,t.timeLeft.textContent=e.phase==="running"&&e.timeLeft<=0&&e.shutdownTimeLeft>0?`+${e.shutdownTimeLeft.toFixed(1)}s`:`${Math.max(0,e.timeLeft).toFixed(1)}s`,t.timeLeft.closest?.(".hud-card")?.classList.toggle("time-critical",e.phase==="running"&&(e.timeLeft<=10||e.timeLeft<=0&&e.shutdownTimeLeft>0)),t.phase.textContent=ye(),t.comboCount&&(t.comboCount.textContent=e.manualCombo?.count||0),se(),t.turnProfit.textContent=M(e.stats.profit),t.turnProfit.classList.toggle("cash-negative",e.stats.profit<0),t.turnProfit.classList.toggle("cash-positive",e.stats.profit>0),t.mixerCount.textContent=e.stats.mixerCount,t.truckFemaleCount.textContent=e.stats.truckFemale,t.truckMaleCount.textContent=e.stats.truckMale,t.poopCount.textContent=e.stats.poopSpawned,t.buttons.s1Left.disabled=e.phase!=="running"||!s(0),t.buttons.s1Right.disabled=e.phase!=="running"||!s(0),t.buttons.s2Left.disabled=e.phase!=="running"||!s(1),t.buttons.s2Right.disabled=e.phase!=="running"||!s(1);let A=e.scanners.find(O=>O.kind==="manual"&&O.slot===0),_=e.scanners.find(O=>O.kind==="manual"&&O.slot===1);A&&(t.buttons.s1Left.textContent=`S1 ${A.keys?.left?.label||"A"} -> Mixer`,t.buttons.s1Right.textContent=`S1 ${A.keys?.right?.label||"D"} -> S2`),_&&(t.buttons.s2Left.textContent=`S2 ${_.keys?.left?.label||"Left"} -> Waste`,t.buttons.s2Right.textContent=`S2 ${_.keys?.right?.label||"Right"} -> Truck`);let k=Math.max(0,Math.floor(e.lastResult?.profit??e.stats?.profit??0)),g=Ln(e,Math.max(1,Number(e.turn)||1),k).amount;t.buttons.nextTurn.textContent=e.phase==="build"&&g>0?`Next Day - Fairies ${M(g)}`:re.actions.nextDay,t.buttons.nextTurn.disabled=e.phase!=="build"||!!e.cardDraft?.pending||!!e.cardTargetPick?.pending||!ii(e)}function se(){if(!t.eventBrief||!t.targetBrief||!t.speedBrief)return;let A=je(e).toUpperCase();t.targetBrief.textContent=`TRUCK TARGET: ${A}`,t.speedBrief.textContent=`BELT: ${d()} px/s | COMBO: ${e.manualCombo?.count||0}`,t.speedBrief.title=`Conveyor speed does not increase by day. Degraded belts reduce speed. Cap: ${_t}px/s.`;let _=e.eventActive,k=e.eventOffer;_?(t.eventBrief.textContent=`ACTIVE EVENT: ${_.title} | ${_.route}`,t.eventBrief.className="event-brief active"):e.phase==="build"&&k?(t.eventBrief.textContent=`NEXT DAY EVENT: ${k.title} | ${k.route}${k.targetAmount?` | Target ${k.targetAmount}`:""}${k.reward?` | Reward ${M(k.reward)}`:""}`,t.eventBrief.className="event-brief next"):e.phase==="build"&&e.turn+1
\u2642Male->MixerS1: A
\u2640Female->TruckS1: D, then S2: right
\u{1F4A9}Poop->ShredderS1: D, then S2: left

Build phase: connect at least one EGG through a scanner to Mixer, Shredder, or Truck before Next Day. One day is one run.

',t.modalActions.innerHTML="",t.modalActions.appendChild(le(re.actions.startGame,o,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function $(A){let _=X=>`${X>0?"+":""}${M(X)}`,k=X=>`${X>0?"-":""}${M(X)}`,g=A.profit>=0?"cash-positive":"cash-negative",O=(A.mixerPoopFine||0)+(A.truckPoopFine||0)+(A.maleTruckFine||0)+(A.explosionDamage||0)+(A.cardRerollCost||0);t.modalTitle.textContent=`Day ${A.turn} Settlement`,t.modalBody.innerHTML=` +
Net result${M(A.profit)}
-
Chick shipment income${G(R.chickShipmentIncome||0)}
-
Poop shipment income${G(R.poopShipmentIncome||0)}
-
Mixer income${G(R.mixerRevenue||0)}
-
Composter income${G(R.composterIncome||0)}
-
DUD refund income${G(R.dudRefundIncome||0)}
-
Manual combo bonus${G(R.manualComboBonus||0)}
-
Chemical subsidy${G(R.chemicalWeaponSubsidy||0)}
-
Event bonus${G(R.eventBonus||0)}
-
Penalties${x(O)}
-
Fairies fee${x(R.fairiesTribute?.amount||R.fairiesTribute||0)}
-
Repair worker wages${x(R.repairWorkerWages||0)}
+
Chick shipment income${_(A.chickShipmentIncome||0)}
+
Poop shipment income${_(A.poopShipmentIncome||0)}
+
Mixer income${_(A.mixerRevenue||0)}
+
Composter income${_(A.composterIncome||0)}
+
DUD refund income${_(A.dudRefundIncome||0)}
+
Manual combo bonus${_(A.manualComboBonus||0)}
+
Chemical subsidy${_(A.chemicalWeaponSubsidy||0)}
+
Event bonus${_(A.eventBonus||0)}
+
Penalties${k(O)}
+
Fairies fee${k(A.fairiesTribute?.amount||A.fairiesTribute||0)}
+
Repair worker wages${k(A.repairWorkerWages||0)}
-

Income ${M(R.revenue)} - losses ${M(R.penalty)} = ${M(R.profit)}

`,t.modalActions.innerHTML="",t.modalActions.appendChild(le("Choose Upgrade Card",r||we,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function W(R,G){let x=Math.max(0,e.cardEffects?.rescueLoanCharges||0);t.modalTitle.textContent="Emergency Loan Available",t.modalBody.innerHTML=` +

Income ${M(A.revenue)} - losses ${M(A.penalty)} = ${M(A.profit)}

`,t.modalActions.innerHTML="",t.modalActions.appendChild(le("Choose Upgrade Card",r||Se,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function U(A,_){let k=Math.max(0,e.cardEffects?.rescueLoanCharges||0);t.modalTitle.textContent="Emergency Loan Available",t.modalBody.innerHTML=`

End-of-day cash is below ${M(0)}.

Current money${M(e.cash)}
Emergency Loan+${M(500)}
-
Cards remaining${x}
+
Cards remaining${k}
-

Use one Emergency Loan to gain ${M(500)} immediately. If cash is still negative, another decision will be shown if another card remains.

`,t.modalActions.innerHTML="",t.modalActions.appendChild(le("Accept Game Over",G,"facility-action danger")),t.modalActions.appendChild(le("Use Emergency Loan",R,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function N(){let R=e.totals.processed,G=R?Math.round(e.totals.correct/R*100):0,x=Ai(e);t.modalTitle.textContent=re.phases.gameover,t.modalBody.innerHTML=`

Your cash went negative.

-
Final Score${x.score}
Survival${e.totals.turnsCompleted} days
Final Cash${M(e.cash)}
Accuracy${G}%
+

Use one Emergency Loan to gain ${M(500)} immediately. If cash is still negative, another decision will be shown if another card remains.

`,t.modalActions.innerHTML="",t.modalActions.appendChild(le("Accept Game Over",_,"facility-action danger")),t.modalActions.appendChild(le("Use Emergency Loan",A,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function N(){let A=e.totals.processed,_=A?Math.round(e.totals.correct/A*100):0,k=Ai(e);t.modalTitle.textContent=re.phases.gameover,t.modalBody.innerHTML=`

Your cash went negative.

+
Final Score${k.score}
Survival${e.totals.turnsCompleted} days
Final Cash${M(e.cash)}
Accuracy${_}%
Score breakdown -
Formula
Base = Cash + Total revenue + Factory value \xD70.5 + Event bonus \xD70.5 = ${M(x.base)}
Daily earned = ceil(Base \xF7 Days) = ${M(x.dailyEarned)}
Score = max(0, floor(Base + Daily earned + Correct bonus - Total outflow - Day penalty)) = ${x.score}
-
Factory Value${M(x.factoryValue)}
Total Revenue${M(e.totals.revenue)}
Daily Earned${M(x.dailyEarned)} / day
Total Outflow${M(e.totals.penalty)}
Fairies Tribute${M(e.totals.fairiesTribute||0)}
Correct Sorts${e.totals.correct}
Auto Sorted${e.totals.autoSorted}
Poop Control${e.totals.poopTrash} trashed / ${e.totals.poopTruck} shipped / ${e.totals.poopMixer} mixer
Explosion Penalty${M(e.totals.explosionDamage)}
Event Bonus${M(e.totals.eventBonus)}
Day Penalty-${x.dayPenalty}
Events${e.totals.eventSuccess} success / ${e.totals.eventFailed} failed
-
`,t.modalActions.innerHTML="",t.modalActions.appendChild(le(re.actions.restart||"Restart",o,"primary-button restart-button")),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible","gameover-modal")}function le(R,G,x="primary-button"){let g=document.createElement("button");return g.type="button",g.className=x,g.textContent=R,g.addEventListener("click",G),g}function we(){t.modal.classList.remove("visible","equipment-popover","gameover-modal"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function he(){}return{updatePanels:C,updateUI:z,showTitle:Z,showTurnResult:I,showEmergencyLoanDecision:W,showGameOver:N,hideModal:we,checkGameOver:he}}function cr(e){e.totals.processed+=1}function zt(e){e.stats.correct+=1,e.totals.correct+=1}function yt(e){e.stats.mistakes+=1,e.totals.mistakes+=1}function Es(e){e.stats.autoSorted+=1,e.totals.autoSorted+=1}function Ps(e){e.stats.poopSpawned+=1}function Rs(e){e.stats.mixerCount+=1,cr(e)}function As(e){e.stats.trashCount+=1,cr(e)}function Ds(e,t){t==="female"?e.stats.truckFemale+=1:t==="male"&&(e.stats.truckMale+=1),cr(e)}function Qn(e,t){let n=t==="truck"?"poopTruck":t==="trash"?"poopTrash":t==="mixer"?"poopMixer":null;n&&(e.stats[n]+=1,e.totals[n]+=1)}function Is({game:e,currentConveyorSpeed:t,onGameOverCheck:n}){function o(u){return Mt(u)*_n(u)*is(e)/fi(e)}function r(u){let p=F(u.col,u.row),b=1+ss(e,u),S=l(u,b);if(!S.length)return s(u,p),!0;let w=0,E=0;for(let D of S){let K=F(D.col,D.row),ee=d(K);if(ee){ee.stoppedTimer=.85,E+=1;continue}let Xe=Cs(e,{stage:"belt",scannerId:null,route:[K]});Xe.sex==="poop"&&Ps(e),e.chicks.push(Xe),_i(e,u),w+=1}return w>0?(Ii(e,p.x,p.y),w>1&&_(e,p.x,p.y-28,`x${w}`,f.green),!0):E===0}function s(u,p){(u.noRouteNoticeCooldown||0)<=0&&(_(e,p.x,p.y-24,"NO BELT: PAUSED",f.warn),u.noRouteNoticeCooldown=2.5)}function l(u,p){let S=ue.map(w=>({col:u.col+w.dc,row:u.row+w.dr})).filter(w=>Te(w.col,w.row)&&e.conveyorTiles.has($(w.col,w.row))).map(w=>({p:w,blocked:L(null,F(w.col,w.row))?1:0,roll:Math.random()}));return S.sort((w,E)=>w.blocked-E.blocked||w.roll-E.roll),S.slice(0,Math.max(1,p||1)).map(w=>w.p)}function d(u){return e.chicks.find(p=>p.stage!=="flying"&&Math.hypot(p.x-u.x,p.y-u.y)0;if(e.timeLeft=Math.max(0,e.timeLeft-u),S&&e.timeLeft<=0&&p(),e.timeLeft<=0){e.shutdownTimeLeft>0&&(e.shutdownTimeLeft=Math.max(0,e.shutdownTimeLeft-u));for(let w of e.eggFarms)w.shutterProgress=Math.min(1,(w.shutterProgress||0)+u*2.8)}if(S&&e.timeLeft>0){for(let w of e.eggFarms)if(w.noRouteNoticeCooldown>0&&(w.noRouteNoticeCooldown=Math.max(0,w.noRouteNoticeCooldown-u)),w.nextSpawn-=u,w.nextSpawn<=0){let E=r(w);w.nextSpawn=E?o(w):.15,w.lastInterval=w.nextSpawn}}for(let w=e.chicks.length-1;w>=0;w-=1){let E=e.chicks[w];E.bob+=u*7,E.stoppedTimer>0&&(E.stoppedTimer=Math.max(0,E.stoppedTimer-u)),E.stage!=="queued"&&P(E,w,u)}J(u),Jt(),oo(),e.timeLeft<=0&&(e.chicks.length===0?b():e.shutdownTimeLeft<=0&&C())}function C(){if(e.cleanupBlown)return;e.cleanupBlown=!0,e.cleanupTimer=1;let u=[...e.chicks];for(let p of u)No(e,p.sex,p.x,p.y,-Math.PI/2,!0);e.chicks=[];for(let p of e.scanners)p.queue=[];if(Jt(),u.length){let p=u.reduce((S,w)=>S+w.x,0)/u.length,b=u.reduce((S,w)=>S+w.y,0)/u.length;Ye(e,p,b,f.warn,58),_(e,p,b-24,"CLEANUP",f.warn)}}function P(u,p,b){if(A(u)){u.stoppedTimer=.35;return}if(de(u,b),!(u.route&&u.targetIndex=u.route.length)return!1;let p=u.route[u.targetIndex];return L(u,p)}function L(u,p){if(!p)return!1;for(let b of e.chicks)if(!(u&&b.id===u.id)&&b.stage!=="flying"&&Math.hypot(b.x-p.x,b.y-p.y)1)&&u.push({x:p.x,y:p.y})}function ne(u){let p=e.conveyorMeta?.get?.(u)||{},b=[];Array.isArray(p.outDirs)&&b.push(...p.outDirs),p.dir&&b.push(p.dir);let S=[...new Set(b)].filter(ee=>ue.some(Xe=>Xe.name===ee)),w=Q(u),E=ue.filter(ee=>N(w,ee.name)).map(ee=>ee.name),D=S.filter(ee=>E.includes(ee)),K=E;return D.length?D:K}function z(u){return ue.find(p=>p.name===u)||null}function se(u,p){return e.scanners.find(b=>b.col<=u&&u<=b.col+1&&b.row-1<=p&&p<=b.row+1)||null}function ye(u,p){let b=z(p);if(!b)return null;let S=se(u.col+b.dc,u.row+b.dr);if(!S)return null;let w=Ee(S,"inputA");return w&&w.col===u.col&&w.row===u.row?S:null}function Z(u){return Object.entries(e.facilities||{}).find(([,p])=>p?.entry&&p.entry.col===u.col&&p.entry.row===u.row)||null}function I(u){return u?.baseId||u?.id||""}function W(u,p){return u.side==="left"&&p==="left"||u.side==="right"&&p==="right"||u.side==="top"&&p==="up"||u.side==="bottom"&&p==="down"}function N(u,p){let b=z(p);if(!b)return null;let S={col:u.col+b.dc,row:u.row+b.dr};if(Te(S.col,S.row)&&e.conveyorTiles.has($(S.col,S.row)))return{type:"conveyor",dirName:p,target:F(S.col,S.row),nextCell:S};let w=ye(u,p);if(w)return{type:"scanner",dirName:p,target:pe(w),scanner:w};let E=Z(u);return E&&W(E[1],p)?{type:"facility",dirName:p,facilityId:E[0],facility:E[1],target:F(u.col,u.row)}:null}function le(u,p){let b=z(p);if(!b)return!1;let S=e.conveyorMeta?.get?.($(u.col+b.dc,u.row+b.dr));return S?[...new Set([...Array.isArray(S.outDirs)?S.outDirs:[],S.dir].filter(Boolean))].includes(b.opposite):!1}function we(u){return ue.filter(p=>Te(u.col+p.dc,u.row+p.dr)&&e.conveyorTiles.has($(u.col+p.dc,u.row+p.dr))).map(p=>p.name)}function he(u,p,b="random"){let S=we(u);if(S.length<3)return p;let w=new Set(S.filter(K=>le(u,K)));if(b&&b!=="random"&&b!=="pass"&&S.includes(b)){let K=new Set(w);K.add(b),S.filter(ee=>!K.has(ee)).length>=2&&w.add(b)}let E=S.filter(K=>!w.has(K));if(E.length)return E;let D=p.filter(K=>!w.has(K));return D.length?D:p}function R(u,p){return p&&(p.type==="facility"||!L(u,p.target))}function G(u,p,b,S="random"){let w=b.map(ee=>N(p,ee)).filter(Boolean);if(!w.length)return null;let D=w.filter(ee=>ee.type!=="facility").filter(ee=>!L(u,ee.target)),K=D.length?D:w.filter(ee=>ee.type==="facility");return K.length?K[Math.floor(Math.random()*K.length)]:null}function x(u,p){let b=[];V(b,{x:u.x,y:u.y}),V(b,p),u.route=b.length?b:[{x:u.x,y:u.y}],u.targetIndex=u.route.length>1?1:u.route.length}function g(u,p){let b=We(u.x,u.y);if(!b)return Ot(p,"OFF GRID");let S=$(b.col,b.row);if(!e.conveyorTiles.has(S))return Ot(p,"OFF BELT");let w=e.conveyorMeta?.get(S)||{},E=he(b,ne(S),w.branchMode||"random");if(!E.length){u.stoppedTimer=.25;return}let D=G(u,b,E,w.branchMode||"random");if(!D){u.stoppedTimer=.25;return}if(D.type==="facility"){let K=I(D.facility);K==="mixer"?to(p,D.facility):K==="truck"?mn(p,D.facility):K==="trash"?no(p,D.facility):Ot(p,"DONE");return}D.type==="scanner"&&(u.pendingScannerId=D.scanner.id),u.prevConveyorCell=S,x(u,D.target)}function O(u){let p=We(u.x,u.y);if(!p)return null;let b=$(p.col,p.row);return e.conveyorTiles.has(b)?b:null}function X(u){let p=O(u)||O(u.route?.[u.targetIndex]||u);return t(p)}function oe(u,p){let b=O(p);!b||u.lastWearKey===b||(u.lastWearKey=b,Wi(e,b))}function de(u,p){let b=X(u)*p;for(;b>0&&u.targetIndex=D?(u.x=S.x,u.y=S.y,oe(u,S),u.targetIndex+=1,b-=D):(u.x+=w/D*b,u.y+=E/D*b,b=0)}}function ge(u,p,b){u.stage="queued",u.route=null,u.queueRoute=b?b.map(S=>({x:S.x,y:S.y})):[pe(p)],u.scannerId=p.id,p.queue.includes(u.id)||p.queue.push(u.id),ce(p)}function ce(u){u.queue=u.queue.filter(b=>e.chicks.some(S=>S.id===b&&S.stage==="queued"));let p=y.cell*.86*ls(e);u.queue.forEach((b,S)=>{let w=e.chicks.find(E=>E.id===b);w&&(ot(w,w.queueRoute||[pe(u)],S*p),w.queueIndex=S)})}function ot(u,p,b){if(!p||!p.length)return;if(p.length===1||b<=0){let E=p[p.length-1];u.x=E.x,u.y=E.y;return}let S=b;for(let E=p.length-1;E>0;E-=1){let D=p[E-1],K=p[E],ee=Math.hypot(K.x-D.x,K.y-D.y);if(S<=ee){let Xe=1-S/ee;u.x=D.x+(K.x-D.x)*Xe,u.y=D.y+(K.y-D.y)*Xe;return}S-=ee}let w=p[0];u.x=w.x,u.y=w.y}function J(u){for(let p of e.scanners){if(p.cooldown>0&&(p.cooldown=Math.max(0,p.cooldown-u)),p.keyPressTime>0&&(p.keyPressTime=Math.max(0,p.keyPressTime-u)),ce(p),p.kind!=="auto"||p.cooldown>0||!p.queue.length)continue;let b=p.queue[0],S=e.chicks.findIndex(w=>w.id===b);if(S<0){p.queue.shift();continue}hn(S,go(p,e.chicks[S]),!0)&&(Ki(e,p),p.cooldown=et(p,e),Es(e))}}function Me(u){let p=xo(e,u);return!p||!p.queue.length?null:e.chicks.find(b=>b.id===p.queue[0])||null}function Be(u,p){if(e.phase!=="running")return;let b=xo(e,u);rt(b,p)}function rt(u,p){if(e.phase!=="running"||!u||u.kind!=="manual"||(u.keyPressTime=.18,u.keyPressSide=p,!u.queue.length))return;let b=e.chicks.findIndex(S=>S.id===u.queue[0]);b>=0&&hn(b,p,!1)}function Ge(u,p,b){return u.kind==="manual"&&go(u,p)===b}function it(u){let p=e.manualCombo?.count||0;if(e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=0,e.manualCombo.lastBonus=0,e.stats.manualComboFailure=(e.stats.manualComboFailure||0)+1,e.totals.manualComboFailure=(e.totals.manualComboFailure||0)+1,p>=10){let b=pe(u);It(e,10,.25),_(e,b.x,b.y-36,"COMBO RESET",f.danger)}}function eo(u){e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=Math.max(0,e.manualCombo.count||0)+1,e.stats.manualComboSuccess=(e.stats.manualComboSuccess||0)+1,e.totals.manualComboSuccess=(e.totals.manualComboSuccess||0)+1;let p=e.manualCombo.count;if(e.manualCombo.lastBonus=0,p<10)return 0;let b=Math.max(1,Math.floor(p/10)),S=e.scanners.filter(K=>K.kind==="manual").length,w=Math.min(1,(20+S*10)/100),E=0;for(let K=0;K0){Oe(e,D),e.stats.manualComboBonus=(e.stats.manualComboBonus||0)+D,e.totals.manualComboBonus=(e.totals.manualComboBonus||0)+D,e.manualCombo.lastBonus=D;let K=pe(u);_(e,K.x,K.y-42,`COMBO +${M(D)}`,f.green)}return D}function pn(u,p){let b=Ee(u,p);if(!b)return null;let S=$(b.col,b.row);if(e.conveyorTiles.has(S))return{...b};let E=(Le(e).scannerPorts.get(u.id)?.[p]?.keys||[]).filter(Boolean);if(!E.length)return null;let D=E.map(Q);return D.find(ee=>ee.col===b.col&&ee.row===b.row)||D[0]||null}function yn(u,p,b,S){let w=[];V(w,{x:u.x,y:u.y});let E=Ee(p,b);return E&&V(w,F(E.col,E.row)),V(w,F(S.col,S.row)),w}function hn(u,p,b){let S=e.chicks[u];if(!S||S.stage!=="queued")return!1;let w=Pt(e,S.scannerId);if(!w)return!1;let E=pn(w,p);if(!E)return!b&&w.kind==="manual"&&it(w),_(e,S.x,S.y-16,p==="left"?"NO LEFT BELT":"NO RIGHT BELT",f.danger),!1;!b&&w.kind==="manual"&&(Ge(w,S,p)?eo(w):it(w)),w.queue=w.queue.filter(K=>K!==S.id),S.stage="belt",S.route=yn(S,w,p,E),S.targetIndex=S.route.length>1?1:S.route.length,S.scannerId=null,S.nextScannerId=null,S.pendingScannerId=null,S.queueRoute=null,S.queueIndex=-1;let D=b?f.green:p==="left"?f.mixerBlue:f.truckPink;return $i(e,pe(w).x,pe(w).y,D),_(e,S.x,S.y-20,b?"AUTO":p.toUpperCase(),D),!0}function bt(u){let p=e.chicks[u];return p?(e.chicks.splice(u,1),p):null}function to(u,p=e.facilities.mixer){if(p?.processingCooldown>0){let D=e.chicks[u];D&&(D.stoppedTimer=.25);return}let b=bt(u);if(!b)return;let{x:S,y:w}=b;if(Rs(e),zo(e,p),Xo(e,p),b.sex==="poop"){let D=Ci(e);Qn(e,"mixer"),yt(e),Bi(e,S,w),_(e,S,w-18,`-${M(D)}`,f.danger);return}let E=ki(e);b.sex==="male"?zt(e):yt(e),Fi(e,S,w),_(e,S,w-18,`+${M(E)}`,f.green)}function mn(u,p=e.facilities.truck){let b=bt(u);if(!b)return;let{x:S,y:w}=b;bn(b.sex,p),Oi(e,S,w,b.sex),Ds(e,b.sex);let E=Je(e),D=yi(e,b.sex);if(b.sex==="poop"){if(Qn(e,"truck"),D)zt(e),_(e,S,w-18,`+${M(De(e))}`,f.green);else{let K=Mi(e);yt(e),_(e,S,w-18,`-${M(K)}`,f.danger)}return}if(b.sex==="female"){D?(zt(e),_(e,S,w-18,`+${M(De(e))}`,f.green)):(yt(e),_(e,S,w-18,E==="male"?"REJECT":"NO SALE",f.warn));return}if(D){zt(e),_(e,S,w-18,`+${M(De(e))}`,f.green);return}if(hi(e)){let K=gi(e);yt(e),_(e,S,w-18,`-${M(K)}`,f.danger)}else yt(e),_(e,S,w-18,"REJECT",f.warn)}function no(u,p=e.facilities.trash){if(p?.processingCooldown>0){let K=e.chicks[u];K&&(K.stoppedTimer=.25);return}let b=bt(u);if(!b)return;let{x:S,y:w}=b;Li(e,S,w,b.sex),As(e),zo(e,p),Xo(e,p);let E={amount:0},D="";if(b.sex==="poop"){E=wi(e),D=E.amount>0?` +${M(E.amount)}`:"",Qn(e,"trash"),zt(e);let K=Math.ceil(Math.max(0,Number(e.cardEffects?.composter)||0)*3*In(e));if(K>0){let ee=Oe(e,K);e.stats.composterIncome=(e.stats.composterIncome||0)+ee,e.totals.composterIncome=(e.totals.composterIncome||0)+ee,_(e,S,w-36,`COMPOST +${M(ee)}`,f.green)}_(e,S,w-18,`CLEAN${D}`,E.amount>0?f.green:f.green)}else yt(e),_(e,S,w-18,E.amount>0?`WASTE${D}`:"WASTE",E.amount>0?f.green:f.ink)}function Ot(u,p){let b=bt(u);b&&_(e,b.x,b.y-12,p,f.muted)}function bn(u,p=e.facilities.truck){let b=p||e.facilities.truck;b&&(e.truckCargo.push({sex:u,x:U(22,b.w-22),y:U(66,b.h-24)}),e.truckCargo.length>45&&e.truckCargo.shift())}function Nt(u){let p=We(u.x,u.y);if(p){let E=$(p.col,p.row);if(e.conveyorTiles.has(E))return E}let b=ti(e,u.x,u.y);if(!b)return null;let S=Q(b),w=F(S.col,S.row);return Math.hypot(u.x-w.x,u.y-w.y)<=y.cell*.55?b:null}function Jt(){let{components:u,cellToComponent:p}=ei(e);for(let b of e.chicks){if(b.stage==="flying")continue;let S=Nt(b);if(!S)continue;let w=p.get(S),E=u.get(w);E&&(E.count+=1)}for(let b of u.values())b.ratio=b.count/b.capacity;e.congestion=u,e.componentLookup=p}function oo(){for(let u of e.congestion.values()){let p=Io(e),b=mi(e);if(u.ratio>b&&u.ratio=p){let S=jt(u.id);if(!S.length||S.some(D=>D.stage!=="queued"&&D.stoppedTimer<=.2))continue;let w=e.lastExplodedComponent.get(u.id)||0,E=performance.now();E-w>900&&(e.lastExplodedComponent.set(u.id,E),vn(u))}}}function jt(u){return e.chicks.filter(p=>{let b=Nt(p);return b&&e.componentLookup?.get(b)===u})}function vn(u){let p=jt(u.id);if(!p.length)return;for(let w of p)No(e,w.sex,w.x,w.y);e.chicks=e.chicks.filter(w=>!p.some(E=>E.id===w.id));for(let w of e.scanners)w.queue=w.queue.filter(E=>e.chicks.some(D=>D.id===E));for(let w of u.cells){let E=Q(w),D=F(E.col,E.row);Ye(e,D.x,D.y,f.danger),je(e,D.x,D.y,6),Bn(e,D.x,D.y,4)}It(e,18,.75);let b=Q(u.cells[0]),S=F(b.col,b.row);e.stats.explosions=(e.stats.explosions||0)+1,e.totals.explosions=(e.totals.explosions||0)+1,_(e,S.x,S.y-22,`${Math.round(Io(e)*100)}% JAM EXPLOSION`,f.danger)}return{activeQueuedChick:Me,currentSpawnDelay:o,sortSlot:Be,updateCongestion:Jt,sortScanner:rt,updateRunning:v}}var ae=document.getElementById("gameCanvas"),ec=ae.getContext("2d"),B={shell:document.getElementById("gameShell"),money:document.getElementById("money"),turn:document.getElementById("turn"),timeLeft:document.getElementById("timeLeft"),phase:document.getElementById("phaseLabel"),comboCount:document.getElementById("comboCount"),eventBrief:document.getElementById("eventBrief"),targetBrief:document.getElementById("targetBrief"),speedBrief:document.getElementById("speedBrief"),turnProfit:document.getElementById("turnProfit"),mixerCount:document.getElementById("mixerCount"),truckFemaleCount:document.getElementById("truckFemaleCount"),truckMaleCount:document.getElementById("truckMaleCount"),poopCount:document.getElementById("poopCount"),buildStatus:document.getElementById("buildStatus"),turnSummary:document.getElementById("turnSummary"),eventPanel:document.getElementById("eventPanel"),modal:document.getElementById("modal"),modalTitle:document.getElementById("modalTitle"),modalBody:document.getElementById("modalBody"),modalActions:document.getElementById("modalActions"),hoverTooltip:document.getElementById("hoverTooltip"),manualScannerMonitor:document.getElementById("manualScannerMonitor"),hireRepairmanButton:document.getElementById("hireRepairmanButton"),debug:{panel:document.getElementById("debugPanel"),infiniteCash:document.getElementById("debugInfiniteCash"),dayInput:document.getElementById("debugDayInput"),setDay:document.getElementById("debugSetDayButton"),zeroTimer:document.getElementById("debugZeroTimerButton"),cardSelect:document.getElementById("debugCardSelect"),targetSelect:document.getElementById("debugTargetSelect"),grantCard:document.getElementById("debugGrantCardButton"),grantAllCards:document.getElementById("debugGrantAllCardsButton"),readout:document.getElementById("debugReadout")},buttons:{s1Left:document.getElementById("scanner1MixerButton"),s1Right:document.getElementById("scanner1TruckButton"),s2Left:document.getElementById("scanner2MixerButton"),s2Right:document.getElementById("scanner2TruckButton"),nextTurn:document.getElementById("nextTurnButton"),conveyor:document.getElementById("buildConveyorButton"),boostConveyor:document.getElementById("buildBoostConveyorButton"),eggFarm:document.getElementById("buildEggFarmButton"),autoScanner:document.getElementById("buildAutoScannerButton"),manualScanner:document.getElementById("buildManualScannerButton"),mixer:document.getElementById("buildMixerButton"),trash:document.getElementById("buildTrashButton"),truck:document.getElementById("buildTruckButton"),erase:document.getElementById("eraseButton"),undo:document.getElementById("undoButton"),redo:document.getElementById("redoButton")}};function tc(){let e={conveyor:"conveyor",boostConveyor:"boostConveyor",eggFarm:"eggFarm",autoScanner:"autoScanner",manualScanner:"manualScanner",mixer:"mixer",trash:"trash",truck:"truck"};for(let[t,n]of Object.entries(e))B.buttons[t]&&(B.buttons[t].innerHTML=Pr(n))}function nc(e){let t=new Set(e.tags||[]);return["upgradeEgg","crowdedFarming","hatchingFeed","extraEggOutlet"].includes(e.id)||t.has("EGG")?"Production / EGG":["upgradeTrash","poopRateBooster","composter","chemicalWeaponSubsidy"].includes(e.id)||t.has("POOP")?"Poop / Shredder":["upgradeAutoScanner","autoScannerTuning","scannerQueueSpacing"].includes(e.id)||t.has("SCANNER")?"Scanner":["bearing","dynamite"].includes(e.id)||t.has("CONVEYOR")?"Conveyor / Map":["safetyCover","preventiveMaintenance","durabilityCoating","sparePartsBin","laborExploitation"].includes(e.id)||t.has("MAINTENANCE")?"Maintenance / Risk":["dudFilter","dudRefund","freeReroll","extraCards"].includes(e.id)||t.has("CARD")?"Card Engine":t.has("ULTRA RARE")?"Ultra Rare":t.has("ECONOMY")||["upgradeMixer","upgradeTruck","recyclingSubsidy","usedMachine","newMachine","flattery","legalWork","rescueLoan"].includes(e.id)?"Economy / Shipment":"Other"}function oc(){if(!B.debug?.panel||!B.debug.cardSelect)return;let e=["Production / EGG","Poop / Shredder","Scanner","Conveyor / Map","Maintenance / Risk","Card Engine","Economy / Shipment","Ultra Rare","Other"],t=new Map(e.map(n=>[n,[]]));for(let n of Yt){let o=nc(n);t.has(o)||t.set(o,[]),t.get(o).push(n)}B.debug.cardSelect.innerHTML="";for(let n of e){let o=t.get(n)||[];if(!o.length)continue;let r=document.createElement("optgroup");r.label=n;for(let s of o){let l=document.createElement("option");l.value=s.id;let d=s.rarity==="ultraRare"?"UR":s.rarity==="rare"?"R":"C";l.textContent=`[${d}] ${s.title}`,r.appendChild(l)}B.debug.cardSelect.appendChild(r)}B.debug.cardSelect.addEventListener("change",Bt),Bt()}function Bt(){if(!B.debug?.targetSelect)return;let e=B.debug.cardSelect?.value,t=Vt(e),n=t?as(a,t):[];if(B.debug.targetSelect.innerHTML="",!n.length){let r=document.createElement("option");r.value="__none__",r.textContent=t?"No target required":"No card selected",B.debug.targetSelect.appendChild(r),B.debug.targetSelect.disabled=!0;return}let o=document.createElement("option");o.value="__auto__",o.textContent=t?.id==="dynamite"?"Auto: first 3 blocked cells":"Auto: first valid target",B.debug.targetSelect.appendChild(o);for(let r of n){let s=document.createElement("option");s.value=r.key,s.textContent=r.label,B.debug.targetSelect.appendChild(s)}B.debug.targetSelect.disabled=!1}function rc(){let e=Math.max(1,Math.floor(Number(B.debug.dayInput?.value)||1));a.turn=e,B.debug.dayInput&&(B.debug.dayInput.value=String(e)),_(a,ae.width/2-a.view.x,86-a.view.y,`DAY ${e}`,f.green),H.updatePanels(),H.updateUI(),Bt(),Lt(`Day set to ${e}.`)}function ic(){a.timeLeft=0,a.phase==="running"&&Ns(),_(a,ae.width/2-a.view.x,86-a.view.y,"TIMER 0",f.warn),H.updatePanels(),H.updateUI(),Lt("Timer set to 0.")}function sc(){let e=B.debug.cardSelect?.value,t=B.debug.targetSelect?.disabled?void 0:B.debug.targetSelect?.value,n=jo(a,e,{targetKey:t});B.debug.grantCard&&(B.debug.grantCard.textContent=n.ok?"Granted":"Failed",window.setTimeout(()=>{B.debug.grantCard&&(B.debug.grantCard.textContent="Grant Selected")},900)),Ce?.updateCongestion?.(),H.updatePanels(),H.updateUI(),Bt(),Lt(n.reason)}function lc(){let t=Yt.map(n=>jo(a,n,{targetKey:"__auto__"})).filter(n=>n.ok).length;Ce?.updateCongestion?.(),H.updatePanels(),H.updateUI(),Bt(),Lt(`Granted ${t}/${Yt.length} cards.`)}function ac(){B.debug?.infiniteCash?.checked&&a.cash<999999&&(a.cash=999999,a.totals.maxCash=Math.max(a.totals.maxCash,a.cash))}function Lt(e=""){B.debug?.readout&&(B.debug.readout.textContent=[e,`D${a.turn}`,M(a.cash),`Combo ${a.manualCombo?.count||0}`,`Event ${a.eventActive?.title||a.eventOffer?.title||"none"}`,`Rescue ${a.cardEffects?.rescueLoanCharges||0}`,`Chem ${a.cardEffects?.chemicalWeaponSubsidy||0}`].filter(Boolean).join(" | "))}var a=wo(),Y,H,Ce,Qt;function cc(e=null){let t=Yn(a,e);return e?t*Ko(a,e):t}function uc(){Object.assign(a,wo()),a.phase="running",a.view={x:0,y:0,scale:1},So(a),Us(),me(a),H.hideModal(),Ce.updateCongestion(),H.updatePanels(),H.updateUI(),Lt()}function dc(){if(a.phase!=="build")return;if(a.cardDraft?.pending||a.cardTargetPick?.pending){Y.fail(a.cardTargetPick?.pending?"Choose upgrade target first.":"Choose an upgrade card first."),H.updatePanels();return}let e=sn(a);if(e.length){Y.fail(`Cannot start: ${e[0]}`),H.updatePanels();return}me(a),Zr(a),Xi(a);let t=Math.max(0,Math.floor(a.lastResult?.profit??a.stats?.profit??0)),n=Pi(a,Math.max(1,a.turn||1),t);a.lastStartFees={fairiesTribute:n.amount||0,tribute:n},n.amount>0&&_(a,ae.width/2-a.view.x,116-a.view.y,`FAIRIES -${M(n.amount)}`,f.danger),ci(a),a.phase="running",a.turn+=1,a.timeLeft=di(a),a.shutdownTimeLeft=0,a.cleanupTimer=null,a.cleanupBlown=!1,a.chicks=[],a.effects=[],a.floatingTexts=[],a.shake={time:0,strength:0},a.truckCargo=[],Us(),a.stats=vo(),a.stats.fairiesTribute=a.lastStartFees?.fairiesTribute||0,a.stats.repairWorkerWages=a.pendingRepairWorkerWages||0;let o=a.stats.fairiesTribute+a.stats.repairWorkerWages;o>0&&(a.stats.penalty+=o,a.stats.profit-=o),a.pendingRepairWorkerWages=0;for(let r of a.scanners)r.queue=[],r.cooldown=0;for(let r of a.eggFarms)r.nextSpawn=Ce.currentSpawnDelay(r),r.lastInterval=r.nextSpawn,r.shutterProgress=0,r.shutterSparked=!1;a.buildTool=null,a.selected=null,a.groupDrag=null,a.selectionBox=null,a.pan=null,Ce.updateCongestion(),H.updatePanels(),H.updateUI()}function fc(){me(a);let e=zi(a);e.ok?_(a,ae.width/2-a.view.x,96-a.view.y,`Repairman hired -${M(e.cost)}`,f.green):(_(a,ae.width/2-a.view.x,96-a.view.y,e.reason||"Cannot hire repairman.",f.danger),Y?.fail?.(e.reason||"Cannot hire repairman.")),H.updatePanels(),H.updateUI()}function pc(){if(a.phase!=="running")return;let e=Ei(a),t=a.eventActive?{...a.eventActive}:null,n=vi(a),o=Ri(a);if(e.adjusted>0){let s=a.facilities.truck,l=s?s.x+s.w/2:ae.width/2-a.view.x,d=s?s.y+26:96-a.view.y;_(a,l,d,`${e.target==="poop"?"POOP SHIP":"SHIP"} +${M(e.adjusted)}`,f.green)}n?.bonus>0&&_(a,ae.width/2-a.view.x,96-a.view.y,`EVENT +${M(n.bonus)}`,f.green),o.amount>0&&_(a,ae.width/2-a.view.x,116-a.view.y,`CHEM SUBSIDY +${M(o.amount)}`,f.green),ui(a),a.totals.turnsCompleted+=1;let r=bi(t);if(r!==1&&(a.pendingFairiesTributeMultiplier=r),a.lastResult={...a.stats,ship:e,event:n,chemical:o,rescue:{amount:0,used:0,remaining:a.cardEffects?.rescueLoanCharges||0},fairiesTribute:{amount:a.stats.fairiesTribute||0},tributeMultiplier:r,turn:a.turn,cash:a.cash},a.cash<0){if((a.cardEffects?.rescueLoanCharges||0)>0){a.phase="loanDecision",H.showEmergencyLoanDecision(Os,Jn);return}a.phase="gameover",H.showGameOver();return}Ls()}function Ls(){a.phase="build",a.truckCargo=[],a.chicks=[],a.shutdownTimeLeft=0,a.cleanupTimer=null,a.cleanupBlown=!1,a.buildSession+=1,a.undoStack=[],a.redoStack=[],a.timeLeft=0;for(let e of a.scanners)e.queue=[];for(let e of a.eggFarms)e.shutterProgress=0,e.shutterSparked=!1;Qi(a),a.eventOffer=ai(a),Qt&&Qt.prepareDraft(),a.cardTargetPick=null,a.buildTool=null,a.groupDrag=null,a.selectionBox=null,a.pan=null,H.updatePanels(),H.showTurnResult(a.lastResult)}function Os(){if((a.cardEffects?.rescueLoanCharges||0)<=0)return Jn();a.cardEffects.rescueLoanCharges-=1,a.stats.rescueLoan=(a.stats.rescueLoan||0)+500,a.totals.rescueLoan=(a.totals.rescueLoan||0)+500;let e=Oe(a,500);a.lastResult={...a.lastResult||{},...a.stats,rescue:{amount:(a.lastResult?.rescue?.amount||0)+e,used:(a.lastResult?.rescue?.used||0)+1,remaining:a.cardEffects.rescueLoanCharges},cash:a.cash},_(a,ae.width/2-a.view.x,176-a.view.y,`RESCUE +${M(e)}`,f.green),a.cash>=0?Ls():(a.cardEffects?.rescueLoanCharges||0)>0?(a.phase="loanDecision",H.showEmergencyLoanDecision(Os,Jn)):Jn()}function Jn(){a.phase="gameover",H.showGameOver()}function Ns(){a.shutdownTimeLeft<=0&&(a.shutdownTimeLeft=a.shutdownGraceSeconds||10);for(let e of a.eggFarms){if(e.shutterSparked)continue;e.shutterProgress=.02,e.shutterSparked=!0;let t=F(e.col,e.row);Ye(a,t.x,t.y,f.ink),je(a,t.x,t.y+10,10),_(a,t.x,t.y-34,"SHUT +10s",f.ink)}}function Gs(e){a.lastTimestamp||(a.lastTimestamp=e);let t=Math.min((e-a.lastTimestamp)/1e3,.05);a.lastTimestamp=e,a.phase==="running"&&Ce.updateRunning(t,{closeFarmShutters:Ns,completeTurn:pc}),Gi(a,t,ae,Y.equipmentHitBoxes),Ce.updateCongestion(),ys(ec,ae,a,{activeQueuedChick:Ce.activeQueuedChick,selectedObject:Y.selectedObject,selectedTitle:Y.selectedTitle}),ac(),H.updateUI(),_s(),Lt(),requestAnimationFrame(Gs)}function jn(){return a.view?.scale||1}function fn(){a.view||(a.view={x:0,y:0,scale:1}),a.view.scale==null&&(a.view.scale=1)}function Zn(e){let t=ae.getBoundingClientRect();return{x:(e.clientX-t.left)*ae.width/t.width,y:(e.clientY-t.top)*ae.height/t.height}}function ht(e){let t=Zn(e),n=jn();return{x:(t.x-(a.view?.x||0))/n,y:(t.y-(a.view?.y||0))/n}}function yc(e){let t=jn();return{x:e.x*t+(a.view?.x||0),y:e.y*t+(a.view?.y||0)}}function hc(){let e={left:y.x-90,top:y.y-130,right:y.x+y.cols*y.cell+260,bottom:y.y+y.rows*y.cell+220};if(a.phase==="build")for(let t of kt(a)){let n=Ct(t);e.left=Math.min(e.left,n.x-60),e.top=Math.min(e.top,n.y-80),e.right=Math.max(e.right,n.x+n.w+80),e.bottom=Math.max(e.bottom,n.y+n.h+80)}return e}function $s(e,t){if(e<=t)return[e,t];let n=(e+t)/2;return[n,n]}function mt(){fn();let e=jn(),t=hc(),[n,o]=$s(ae.width-160-t.right*e,110-t.left*e),[r,s]=$s(ae.height-150-t.bottom*e,150-t.top*e);a.view.x=on(a.view.x,n,o),a.view.y=on(a.view.y,r,s)}function Us(){fn(),a.view.scale=1;let e=a.eggFarms?.[0],t=e?F(e.col,e.row):{x:y.x,y:y.y};a.view.x=280-t.x,a.view.y=190-t.y,mt()}function mc(e){let t=Zn(e);fn(),a.pan={start:t,viewX:a.view.x,viewY:a.view.y,moved:!1}}function bc(e){if(!a.pan)return;let t=Zn(e);Math.hypot(t.x-a.pan.start.x,t.y-a.pan.start.y)>5&&(a.pan.moved=!0),fn(),a.view.x=a.pan.viewX+t.x-a.pan.start.x,a.view.y=a.pan.viewY+t.y-a.pan.start.y,mt()}function vc(e){e.preventDefault(),fn();let t=Zn(e),n=ht(e),o=Math.exp(-e.deltaY*.0012),r=on(jn()*o,.55,1.8);a.view.scale=r,a.view.x=t.x-n.x*r,a.view.y=t.y-n.y*r,mt(),nt()}function wc(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:{type:e.type,id:e.ref.id}:null}function Sc(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:e.ref||null:null}function nt(){B.hoverTooltip&&(B.hoverTooltip.classList.remove("visible"),B.hoverTooltip.setAttribute("aria-hidden","true"),a.hover=null)}function xc(e,t){if(!B.hoverTooltip||a.phase!=="build"||a.cardTargetPick?.pending||a.groupDrag||a.selectionBox||a.pan)return nt();let n=Sc(t);if(!n)return nt();let o=Y.selectedTitle(n),r=Y.flavorText?Y.flavorText(n):"",s=Y.disconnectedWarningFor?Y.disconnectedWarningFor(n):"",l=Y.selectedInfoLines(n).slice(0,7);B.hoverTooltip.innerHTML=`${o}${s?`${s}`:r?`${r}`:""}${l.map(C=>`${C}`).join("")}`;let d=Math.min(window.innerWidth-330,e.clientX+18),v=Math.min(window.innerHeight-220,e.clientY+18);B.hoverTooltip.style.left=`${Math.max(8,d)}px`,B.hoverTooltip.style.top=`${Math.max(8,v)}px`,B.hoverTooltip.classList.add("visible"),B.hoverTooltip.setAttribute("aria-hidden","false"),a.hover={type:t.type,id:t.oldKey||t.ref?.id||null}}function kc(e){if(a.phase!=="build")return nt();xc(e,Y.equipmentAtPoint(ht(e)))}function Ws(e){nt();let t=ht(e),n=Y.equipmentAtPoint(t),o=wc(n);if(!o){a.selected=null,a.multiSelected=[],H.updatePanels();return}a.selected=o,a.multiSelected=[o],H.updatePanels();let r=Y.selectedObject();r?.type==="scanner"&&r.kind==="manual"&&Y.showManualScannerMenu(r),r?.type==="scanner"&&r.kind==="auto"&&Y.showAutoScannerMenu(r)}function Xt(){a.buildTool=null,a.selected=null,a.multiSelected=[],a.selectionBox=null,a.cardTargetPick?.mode==="autoScannerMenu"&&(a.cardTargetPick=null),H.hideModal(),nt(),H.updatePanels(),H.updateUI()}function Fs(e){return String(e).replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function Cc(e){let t=e?.queue?.[0];return t==null?null:a.chicks.find(n=>n.id===t)||null}function Mc(e){if(!e)return'WAIT';let t=e.sex==="poop"?"\u{1F4A9} POOP":e.sex==="male"?"\u2642 MALE":"\u2640 FEMALE";return`${t}`}function gc(e,t){let n=new Set(a.eggFarms.map(P=>$(P.col,P.row))),o=new Map(a.scanners.map(P=>[$(P.col,P.row),P])),r=Ee(e,"inputA"),s=r?$(r.col,r.row):null,l=new Set(Object.values(a.facilities||{}).map(P=>P.entry?$(P.entry.col,P.entry.row):null).filter(Boolean)),d=t?.sex||"",v=d==="poop"?"\u{1F4A9}":d==="male"?"\u2642":d==="female"?"\u2640":"",C=[];for(let P=e.row-2;P<=e.row+2;P+=1)for(let A=e.col-2;A<=e.col+2;A+=1){let L=$(A,P),V=["mini-cell"],ne="";A===e.col&&P===e.row?(V.push("scanner"),d&&V.push(d),ne=v||"S"):L===s?(V.push("input"),ne="IN"):n.has(L)?(V.push("egg"),ne="E"):o.has(L)?(V.push("scanner-other"),ne="S"):l.has(L)?(V.push("port"),ne="P"):a.conveyorTiles.has(L)?(V.push("belt"),ne="\u2022"):a.blockedCells?.has?.(L)&&(V.push("blocked"),ne="\xD7"),C.push(`${ne}`)}return`
${C.join("")}
`}function Tc(e){let t=yc(F(e.col,e.row)),n=76;return t.x<-n||t.y<-n||t.x>ae.width+n||t.y>ae.height+n}function _s(){if(!B.manualScannerMonitor)return;if(a.phase!=="running"){B.manualScannerMonitor.classList.remove("visible"),B.manualScannerMonitor.innerHTML="";return}let e=a.scanners.filter(t=>t.kind==="manual"&&Tc(t));if(!e.length){B.manualScannerMonitor.classList.remove("visible"),B.manualScannerMonitor.innerHTML="";return}B.manualScannerMonitor.innerHTML=e.map(t=>{let n=Cc(t),o=t.keys?.left?.label||(t.slot===0?"A":"Left"),r=t.keys?.right?.label||(t.slot===0?"D":"Right"),s=t.role===0?"MIXER":"WASTE",l=t.role===0?"S2":"TRUCK",d=n?"":" disabled";return` +
Formula
Base = Cash + Total revenue + Factory value \xD70.5 + Event bonus \xD70.5 = ${M(k.base)}
Daily earned = ceil(Base \xF7 Days) = ${M(k.dailyEarned)}
Score = max(0, floor(Base + Daily earned + Correct bonus - Total outflow - Day penalty)) = ${k.score}
+
Factory Value${M(k.factoryValue)}
Total Revenue${M(e.totals.revenue)}
Daily Earned${M(k.dailyEarned)} / day
Total Outflow${M(e.totals.penalty)}
Fairies Tribute${M(e.totals.fairiesTribute||0)}
Correct Sorts${e.totals.correct}
Auto Sorted${e.totals.autoSorted}
Poop Control${e.totals.poopTrash} trashed / ${e.totals.poopTruck} shipped / ${e.totals.poopMixer} mixer
Explosion Penalty${M(e.totals.explosionDamage)}
Event Bonus${M(e.totals.eventBonus)}
Day Penalty-${k.dayPenalty}
Events${e.totals.eventSuccess} success / ${e.totals.eventFailed} failed
+ `,t.modalActions.innerHTML="",t.modalActions.appendChild(le(re.actions.restart||"Restart",o,"primary-button restart-button")),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible","gameover-modal")}function le(A,_,k="primary-button"){let g=document.createElement("button");return g.type="button",g.className=k,g.textContent=A,g.addEventListener("click",_),g}function Se(){t.modal.classList.remove("visible","equipment-popover","gameover-modal"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function he(){}return{updatePanels:C,updateUI:z,showTitle:Z,showTurnResult:$,showEmergencyLoanDecision:U,showGameOver:N,hideModal:Se,checkGameOver:he}}function cr(e){e.totals.processed+=1}function zt(e){e.stats.correct+=1,e.totals.correct+=1}function ht(e){e.stats.mistakes+=1,e.totals.mistakes+=1}function Ps(e){e.stats.autoSorted+=1,e.totals.autoSorted+=1}function Rs(e){e.stats.poopSpawned+=1}function As(e){e.stats.mixerCount+=1,cr(e)}function Ds(e){e.stats.trashCount+=1,cr(e)}function $s(e,t){t==="female"?e.stats.truckFemale+=1:t==="male"&&(e.stats.truckMale+=1),cr(e)}function Zn(e,t){let n=t==="truck"?"poopTruck":t==="trash"?"poopTrash":t==="mixer"?"poopMixer":null;n&&(e.stats[n]+=1,e.totals[n]+=1)}function Is({game:e,currentConveyorSpeed:t,onGameOverCheck:n}){function o(u){return gt(u)*Hn(u)*is(e)/fi(e)}function r(u){let f=F(u.col,u.row),b=1+ss(e,u),S=l(u,b);if(!S.length)return s(u,f),!0;let w=0,E=0;for(let D of S){let K=F(D.col,D.row),ee=d(K);if(ee){ee.stoppedTimer=.85,E+=1;continue}let Qe=Ms(e,{stage:"belt",scannerId:null,route:[K]});Qe.sex==="poop"&&Rs(e),e.chicks.push(Qe),Wi(e,u),w+=1}return w>0?($i(e,f.x,f.y),w>1&&W(e,f.x,f.y-28,`x${w}`,p.green),!0):E===0}function s(u,f){(u.noRouteNoticeCooldown||0)<=0&&(W(e,f.x,f.y-24,"NO BELT: PAUSED",p.warn),u.noRouteNoticeCooldown=2.5)}function l(u,f){let S=ue.map(w=>({col:u.col+w.dc,row:u.row+w.dr})).filter(w=>Ee(w.col,w.row)&&e.conveyorTiles.has(I(w.col,w.row))).map(w=>({p:w,blocked:L(null,F(w.col,w.row))?1:0,roll:Math.random()}));return S.sort((w,E)=>w.blocked-E.blocked||w.roll-E.roll),S.slice(0,Math.max(1,f||1)).map(w=>w.p)}function d(u){return e.chicks.find(f=>f.stage!=="flying"&&Math.hypot(f.x-u.x,f.y-u.y)0;if(e.timeLeft=Math.max(0,e.timeLeft-u),S&&e.timeLeft<=0&&f(),e.timeLeft<=0){e.shutdownTimeLeft>0&&(e.shutdownTimeLeft=Math.max(0,e.shutdownTimeLeft-u));for(let w of e.eggFarms)w.shutterProgress=Math.min(1,(w.shutterProgress||0)+u*2.8)}if(S&&e.timeLeft>0){for(let w of e.eggFarms)if(w.noRouteNoticeCooldown>0&&(w.noRouteNoticeCooldown=Math.max(0,w.noRouteNoticeCooldown-u)),w.nextSpawn-=u,w.nextSpawn<=0){let E=r(w);w.nextSpawn=E?o(w):.15,w.lastInterval=w.nextSpawn}}for(let w=e.chicks.length-1;w>=0;w-=1){let E=e.chicks[w];E.bob+=u*7,E.stoppedTimer>0&&(E.stoppedTimer=Math.max(0,E.stoppedTimer-u)),E.stage!=="queued"&&P(E,w,u)}J(u),Jt(),so(),e.timeLeft<=0&&(e.chicks.length===0?b():e.shutdownTimeLeft<=0&&C())}function C(){if(e.cleanupBlown)return;e.cleanupBlown=!0,e.cleanupTimer=1;let u=[...e.chicks];for(let f of u)Go(e,f.sex,f.x,f.y,-Math.PI/2,!0);e.chicks=[];for(let f of e.scanners)f.queue=[];if(Jt(),u.length){let f=u.reduce((S,w)=>S+w.x,0)/u.length,b=u.reduce((S,w)=>S+w.y,0)/u.length;Ve(e,f,b,p.warn,58),W(e,f,b-24,"CLEANUP",p.warn)}}function P(u,f,b){if(R(u)){u.stoppedTimer=.35;return}if(de(u,b),!(u.route&&u.targetIndex=u.route.length)return!1;let f=u.route[u.targetIndex];return L(u,f)}function L(u,f){if(!f)return!1;for(let b of e.chicks)if(!(u&&b.id===u.id)&&b.stage!=="flying"&&Math.hypot(b.x-f.x,b.y-f.y)1)&&u.push({x:f.x,y:f.y})}function te(u){let f=e.conveyorMeta?.get?.(u)||{},b=[];Array.isArray(f.outDirs)&&b.push(...f.outDirs),f.dir&&b.push(f.dir);let S=[...new Set(b)].filter(ee=>ue.some(Qe=>Qe.name===ee)),w=Q(u),E=ue.filter(ee=>N(w,ee.name)).map(ee=>ee.name),D=S.filter(ee=>E.includes(ee)),K=E;return D.length?D:K}function z(u){return ue.find(f=>f.name===u)||null}function se(u,f){return e.scanners.find(b=>b.col<=u&&u<=b.col+1&&b.row-1<=f&&f<=b.row+1)||null}function ye(u,f){let b=z(f);if(!b)return null;let S=se(u.col+b.dc,u.row+b.dr);if(!S)return null;let w=Pe(S,"inputA");return w&&w.col===u.col&&w.row===u.row?S:null}function Z(u){return Object.entries(e.facilities||{}).find(([,f])=>f?.entry&&f.entry.col===u.col&&f.entry.row===u.row)||null}function $(u){return u?.baseId||u?.id||""}function U(u,f){return u.side==="left"&&f==="left"||u.side==="right"&&f==="right"||u.side==="top"&&f==="up"||u.side==="bottom"&&f==="down"}function N(u,f){let b=z(f);if(!b)return null;let S={col:u.col+b.dc,row:u.row+b.dr};if(Ee(S.col,S.row)&&e.conveyorTiles.has(I(S.col,S.row)))return{type:"conveyor",dirName:f,target:F(S.col,S.row),nextCell:S};let w=ye(u,f);if(w)return{type:"scanner",dirName:f,target:pe(w),scanner:w};let E=Z(u);return E&&U(E[1],f)?{type:"facility",dirName:f,facilityId:E[0],facility:E[1],target:F(u.col,u.row)}:null}function le(u,f){let b=z(f);if(!b)return!1;let S=e.conveyorMeta?.get?.(I(u.col+b.dc,u.row+b.dr));return S?[...new Set([...Array.isArray(S.outDirs)?S.outDirs:[],S.dir].filter(Boolean))].includes(b.opposite):!1}function Se(u){return ue.filter(f=>Ee(u.col+f.dc,u.row+f.dr)&&e.conveyorTiles.has(I(u.col+f.dc,u.row+f.dr))).map(f=>f.name)}function he(u,f,b="random"){let S=Se(u);if(S.length<3)return f;let w=new Set(S.filter(K=>le(u,K)));if(b&&b!=="random"&&b!=="pass"&&S.includes(b)){let K=new Set(w);K.add(b),S.filter(ee=>!K.has(ee)).length>=2&&w.add(b)}let E=S.filter(K=>!w.has(K));if(E.length)return E;let D=f.filter(K=>!w.has(K));return D.length?D:f}function A(u,f){return f&&(f.type==="facility"||!L(u,f.target))}function _(u,f,b,S="random"){let w=b.map(ee=>N(f,ee)).filter(Boolean);if(!w.length)return null;let D=w.filter(ee=>ee.type!=="facility").filter(ee=>!L(u,ee.target)),K=D.length?D:w.filter(ee=>ee.type==="facility");return K.length?K[Math.floor(Math.random()*K.length)]:null}function k(u,f){let b=[];V(b,{x:u.x,y:u.y}),V(b,f),u.route=b.length?b:[{x:u.x,y:u.y}],u.targetIndex=u.route.length>1?1:u.route.length}function g(u,f){let b=We(u.x,u.y);if(!b)return Ot(f,"OFF GRID");let S=I(b.col,b.row);if(!e.conveyorTiles.has(S))return Ot(f,"OFF BELT");let w=e.conveyorMeta?.get(S)||{},E=he(b,te(S),w.branchMode||"random");if(!E.length){u.stoppedTimer=.25;return}let D=_(u,b,E,w.branchMode||"random");if(!D){u.stoppedTimer=.25;return}if(D.type==="facility"){let K=$(D.facility);K==="mixer"?ro(f,D.facility):K==="truck"?bn(f,D.facility):K==="trash"?io(f,D.facility):Ot(f,"DONE");return}D.type==="scanner"&&(u.pendingScannerId=D.scanner.id),u.prevConveyorCell=S,k(u,D.target)}function O(u){let f=We(u.x,u.y);if(!f)return null;let b=I(f.col,f.row);return e.conveyorTiles.has(b)?b:null}function X(u){let f=O(u)||O(u.route?.[u.targetIndex]||u);return t(f)}function oe(u,f){let b=O(f);!b||u.lastWearKey===b||(u.lastWearKey=b,Ui(e,b))}function de(u,f){let b=X(u)*f;for(;b>0&&u.targetIndex=D?(u.x=S.x,u.y=S.y,oe(u,S),u.targetIndex+=1,b-=D):(u.x+=w/D*b,u.y+=E/D*b,b=0)}}function Te(u,f,b){u.stage="queued",u.route=null,u.queueRoute=b?b.map(S=>({x:S.x,y:S.y})):[pe(f)],u.scannerId=f.id,f.queue.includes(u.id)||f.queue.push(u.id),ce(f)}function ce(u){u.queue=u.queue.filter(b=>e.chicks.some(S=>S.id===b&&S.stage==="queued"));let f=y.cell*.86*ls(e);u.queue.forEach((b,S)=>{let w=e.chicks.find(E=>E.id===b);w&&(rt(w,w.queueRoute||[pe(u)],S*f),w.queueIndex=S)})}function rt(u,f,b){if(!f||!f.length)return;if(f.length===1||b<=0){let E=f[f.length-1];u.x=E.x,u.y=E.y;return}let S=b;for(let E=f.length-1;E>0;E-=1){let D=f[E-1],K=f[E],ee=Math.hypot(K.x-D.x,K.y-D.y);if(S<=ee){let Qe=1-S/ee;u.x=D.x+(K.x-D.x)*Qe,u.y=D.y+(K.y-D.y)*Qe;return}S-=ee}let w=f[0];u.x=w.x,u.y=w.y}function J(u){for(let f of e.scanners){if(f.cooldown>0&&(f.cooldown=Math.max(0,f.cooldown-u)),f.keyPressTime>0&&(f.keyPressTime=Math.max(0,f.keyPressTime-u)),ce(f),f.kind!=="auto"||f.cooldown>0||!f.queue.length)continue;let b=f.queue[0],S=e.chicks.findIndex(w=>w.id===b);if(S<0){f.queue.shift();continue}mn(S,Eo(f,e.chicks[S]),!0)&&(Ki(e,f),f.cooldown=tt(f,e),Ps(e))}}function ge(u){let f=Co(e,u);return!f||!f.queue.length?null:e.chicks.find(b=>b.id===f.queue[0])||null}function Le(u,f){if(e.phase!=="running")return;let b=Co(e,u);it(b,f)}function it(u,f){if(e.phase!=="running"||!u||u.kind!=="manual"||(u.keyPressTime=.18,u.keyPressSide=f,!u.queue.length))return;let b=e.chicks.findIndex(S=>S.id===u.queue[0]);b>=0&&mn(b,f,!1)}function Ge(u,f,b){return u.kind==="manual"&&Eo(u,f)===b}function st(u){let f=e.manualCombo?.count||0;if(e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=0,e.manualCombo.lastBonus=0,e.stats.manualComboFailure=(e.stats.manualComboFailure||0)+1,e.totals.manualComboFailure=(e.totals.manualComboFailure||0)+1,f>=10){let b=pe(u);It(e,10,.25),W(e,b.x,b.y-36,"COMBO RESET",p.danger)}}function oo(u){e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=Math.max(0,e.manualCombo.count||0)+1,e.stats.manualComboSuccess=(e.stats.manualComboSuccess||0)+1,e.totals.manualComboSuccess=(e.totals.manualComboSuccess||0)+1;let f=e.manualCombo.count;if(e.manualCombo.lastBonus=0,f<10)return 0;let b=Math.max(1,Math.floor(f/10)),S=e.scanners.filter(K=>K.kind==="manual").length,w=Math.min(1,(20+S*10)/100),E=0;for(let K=0;K0){Ne(e,D),e.stats.manualComboBonus=(e.stats.manualComboBonus||0)+D,e.totals.manualComboBonus=(e.totals.manualComboBonus||0)+D,e.manualCombo.lastBonus=D;let K=pe(u);W(e,K.x,K.y-42,`COMBO +${M(D)}`,p.green)}return D}function yn(u,f){let b=Pe(u,f);if(!b)return null;let S=I(b.col,b.row);if(e.conveyorTiles.has(S))return{...b};let E=(Oe(e).scannerPorts.get(u.id)?.[f]?.keys||[]).filter(Boolean);if(!E.length)return null;let D=E.map(Q);return D.find(ee=>ee.col===b.col&&ee.row===b.row)||D[0]||null}function hn(u,f,b,S){let w=[];V(w,{x:u.x,y:u.y});let E=Pe(f,b);return E&&V(w,F(E.col,E.row)),V(w,F(S.col,S.row)),w}function mn(u,f,b){let S=e.chicks[u];if(!S||S.stage!=="queued")return!1;let w=Rt(e,S.scannerId);if(!w)return!1;let E=yn(w,f);if(!E)return!b&&w.kind==="manual"&&st(w),W(e,S.x,S.y-16,f==="left"?"NO LEFT BELT":"NO RIGHT BELT",p.danger),!1;!b&&w.kind==="manual"&&(Ge(w,S,f)?oo(w):st(w)),w.queue=w.queue.filter(K=>K!==S.id),S.stage="belt",S.route=hn(S,w,f,E),S.targetIndex=S.route.length>1?1:S.route.length,S.scannerId=null,S.nextScannerId=null,S.pendingScannerId=null,S.queueRoute=null,S.queueIndex=-1;let D=b?p.green:f==="left"?p.mixerBlue:p.truckPink;return Ii(e,pe(w).x,pe(w).y,D),W(e,S.x,S.y-20,b?"AUTO":f.toUpperCase(),D),!0}function vt(u){let f=e.chicks[u];return f?(e.chicks.splice(u,1),f):null}function ro(u,f=e.facilities.mixer){if(f?.processingCooldown>0){let D=e.chicks[u];D&&(D.stoppedTimer=.25);return}let b=vt(u);if(!b)return;let{x:S,y:w}=b;if(As(e),Qo(e,f),Jo(e,f),b.sex==="poop"){let D=Ci(e);Zn(e,"mixer"),ht(e),Bi(e,S,w),W(e,S,w-18,`-${M(D)}`,p.danger);return}let E=xi(e);b.sex==="male"?zt(e):ht(e),Fi(e,S,w),W(e,S,w-18,`+${M(E)}`,p.green)}function bn(u,f=e.facilities.truck){let b=vt(u);if(!b)return;let{x:S,y:w}=b;vn(b.sex,f),Oi(e,S,w,b.sex),$s(e,b.sex);let E=je(e),D=yi(e,b.sex);if(b.sex==="poop"){if(Zn(e,"truck"),D)zt(e),W(e,S,w-18,`+${M($e(e))}`,p.green);else{let K=Mi(e);ht(e),W(e,S,w-18,`-${M(K)}`,p.danger)}return}if(b.sex==="female"){D?(zt(e),W(e,S,w-18,`+${M($e(e))}`,p.green)):(ht(e),W(e,S,w-18,E==="male"?"REJECT":"NO SALE",p.warn));return}if(D){zt(e),W(e,S,w-18,`+${M($e(e))}`,p.green);return}if(hi(e)){let K=gi(e);ht(e),W(e,S,w-18,`-${M(K)}`,p.danger)}else ht(e),W(e,S,w-18,"REJECT",p.warn)}function io(u,f=e.facilities.trash){if(f?.processingCooldown>0){let K=e.chicks[u];K&&(K.stoppedTimer=.25);return}let b=vt(u);if(!b)return;let{x:S,y:w}=b;Li(e,S,w,b.sex),Ds(e),Qo(e,f),Jo(e,f);let E={amount:0},D="";if(b.sex==="poop"){E=wi(e),D=E.amount>0?` +${M(E.amount)}`:"",Zn(e,"trash"),zt(e);let K=Math.ceil(Math.max(0,Number(e.cardEffects?.composter)||0)*3*Fn(e));if(K>0){let ee=Ne(e,K);e.stats.composterIncome=(e.stats.composterIncome||0)+ee,e.totals.composterIncome=(e.totals.composterIncome||0)+ee,W(e,S,w-36,`COMPOST +${M(ee)}`,p.green)}W(e,S,w-18,`CLEAN${D}`,E.amount>0?p.green:p.green)}else ht(e),W(e,S,w-18,E.amount>0?`WASTE${D}`:"WASTE",E.amount>0?p.green:p.ink)}function Ot(u,f){let b=vt(u);b&&W(e,b.x,b.y-12,f,p.muted)}function vn(u,f=e.facilities.truck){let b=f||e.facilities.truck;b&&(e.truckCargo.push({sex:u,x:G(22,b.w-22),y:G(66,b.h-24)}),e.truckCargo.length>45&&e.truckCargo.shift())}function Nt(u){let f=We(u.x,u.y);if(f){let E=I(f.col,f.row);if(e.conveyorTiles.has(E))return E}let b=ti(e,u.x,u.y);if(!b)return null;let S=Q(b),w=F(S.col,S.row);return Math.hypot(u.x-w.x,u.y-w.y)<=y.cell*.55?b:null}function Jt(){let{components:u,cellToComponent:f}=ei(e);for(let b of e.chicks){if(b.stage==="flying")continue;let S=Nt(b);if(!S)continue;let w=f.get(S),E=u.get(w);E&&(E.count+=1)}for(let b of u.values())b.ratio=b.count/b.capacity;e.congestion=u,e.componentLookup=f}function so(){for(let u of e.congestion.values()){let f=Fo(e),b=mi(e);if(u.ratio>b&&u.ratio=f){let S=jt(u.id);if(!S.length||S.some(D=>D.stage!=="queued"&&D.stoppedTimer<=.2))continue;let w=e.lastExplodedComponent.get(u.id)||0,E=performance.now();E-w>900&&(e.lastExplodedComponent.set(u.id,E),wn(u))}}}function jt(u){return e.chicks.filter(f=>{let b=Nt(f);return b&&e.componentLookup?.get(b)===u})}function wn(u){let f=jt(u.id);if(!f.length)return;for(let w of f)Go(e,w.sex,w.x,w.y);e.chicks=e.chicks.filter(w=>!f.some(E=>E.id===w.id));for(let w of e.scanners)w.queue=w.queue.filter(E=>e.chicks.some(D=>D.id===E));for(let w of u.cells){let E=Q(w),D=F(E.col,E.row);Ve(e,D.x,D.y,p.danger),Ze(e,D.x,D.y,6),On(e,D.x,D.y,4)}It(e,18,.75);let b=Q(u.cells[0]),S=F(b.col,b.row);e.stats.explosions=(e.stats.explosions||0)+1,e.totals.explosions=(e.totals.explosions||0)+1,W(e,S.x,S.y-22,`${Math.round(Fo(e)*100)}% JAM EXPLOSION`,p.danger)}return{activeQueuedChick:ge,currentSpawnDelay:o,sortSlot:Le,updateCongestion:Jt,sortScanner:it,updateRunning:v}}var ae=document.getElementById("gameCanvas"),nc=ae.getContext("2d"),B={shell:document.getElementById("gameShell"),money:document.getElementById("money"),turn:document.getElementById("turn"),timeLeft:document.getElementById("timeLeft"),phase:document.getElementById("phaseLabel"),comboCount:document.getElementById("comboCount"),eventBrief:document.getElementById("eventBrief"),targetBrief:document.getElementById("targetBrief"),speedBrief:document.getElementById("speedBrief"),turnProfit:document.getElementById("turnProfit"),mixerCount:document.getElementById("mixerCount"),truckFemaleCount:document.getElementById("truckFemaleCount"),truckMaleCount:document.getElementById("truckMaleCount"),poopCount:document.getElementById("poopCount"),buildStatus:document.getElementById("buildStatus"),turnSummary:document.getElementById("turnSummary"),eventPanel:document.getElementById("eventPanel"),modal:document.getElementById("modal"),modalTitle:document.getElementById("modalTitle"),modalBody:document.getElementById("modalBody"),modalActions:document.getElementById("modalActions"),hoverTooltip:document.getElementById("hoverTooltip"),manualScannerMonitor:document.getElementById("manualScannerMonitor"),hireRepairmanButton:document.getElementById("hireRepairmanButton"),debug:{panel:document.getElementById("debugPanel"),infiniteCash:document.getElementById("debugInfiniteCash"),dayInput:document.getElementById("debugDayInput"),setDay:document.getElementById("debugSetDayButton"),zeroTimer:document.getElementById("debugZeroTimerButton"),cardSelect:document.getElementById("debugCardSelect"),targetSelect:document.getElementById("debugTargetSelect"),grantCard:document.getElementById("debugGrantCardButton"),grantAllCards:document.getElementById("debugGrantAllCardsButton"),readout:document.getElementById("debugReadout")},buttons:{s1Left:document.getElementById("scanner1MixerButton"),s1Right:document.getElementById("scanner1TruckButton"),s2Left:document.getElementById("scanner2MixerButton"),s2Right:document.getElementById("scanner2TruckButton"),nextTurn:document.getElementById("nextTurnButton"),conveyor:document.getElementById("buildConveyorButton"),boostConveyor:document.getElementById("buildBoostConveyorButton"),eggFarm:document.getElementById("buildEggFarmButton"),autoScanner:document.getElementById("buildAutoScannerButton"),manualScanner:document.getElementById("buildManualScannerButton"),mixer:document.getElementById("buildMixerButton"),trash:document.getElementById("buildTrashButton"),truck:document.getElementById("buildTruckButton"),erase:document.getElementById("eraseButton"),undo:document.getElementById("undoButton"),redo:document.getElementById("redoButton")}};function oc(){let e={conveyor:"conveyor",boostConveyor:"boostConveyor",eggFarm:"eggFarm",autoScanner:"autoScanner",manualScanner:"manualScanner",mixer:"mixer",trash:"trash",truck:"truck"};for(let[t,n]of Object.entries(e))B.buttons[t]&&(B.buttons[t].innerHTML=Pr(n))}function rc(e){let t=new Set(e.tags||[]);return["upgradeEgg","crowdedFarming","hatchingFeed","extraEggOutlet"].includes(e.id)||t.has("EGG")?"Production / EGG":["upgradeTrash","poopRateBooster","composter","chemicalWeaponSubsidy"].includes(e.id)||t.has("POOP")?"Poop / Shredder":["upgradeAutoScanner","autoScannerTuning","scannerQueueSpacing"].includes(e.id)||t.has("SCANNER")?"Scanner":["bearing","dynamite"].includes(e.id)||t.has("CONVEYOR")?"Conveyor / Map":["safetyCover","preventiveMaintenance","durabilityCoating","sparePartsBin","laborExploitation"].includes(e.id)||t.has("MAINTENANCE")?"Maintenance / Risk":["dudFilter","dudRefund","freeReroll","extraCards"].includes(e.id)||t.has("CARD")?"Card Engine":t.has("ULTRA RARE")?"Ultra Rare":t.has("ECONOMY")||["upgradeMixer","upgradeTruck","recyclingSubsidy","usedMachine","newMachine","flattery","legalWork","rescueLoan"].includes(e.id)?"Economy / Shipment":"Other"}function ic(){if(!B.debug?.panel||!B.debug.cardSelect)return;let e=["Production / EGG","Poop / Shredder","Scanner","Conveyor / Map","Maintenance / Risk","Card Engine","Economy / Shipment","Ultra Rare","Other"],t=new Map(e.map(n=>[n,[]]));for(let n of Yt){let o=rc(n);t.has(o)||t.set(o,[]),t.get(o).push(n)}B.debug.cardSelect.innerHTML="";for(let n of e){let o=t.get(n)||[];if(!o.length)continue;let r=document.createElement("optgroup");r.label=n;for(let s of o){let l=document.createElement("option");l.value=s.id;let d=s.rarity==="ultraRare"?"UR":s.rarity==="rare"?"R":"C";l.textContent=`[${d}] ${s.title}`,r.appendChild(l)}B.debug.cardSelect.appendChild(r)}B.debug.cardSelect.addEventListener("change",Bt),Bt()}function Bt(){if(!B.debug?.targetSelect)return;let e=B.debug.cardSelect?.value,t=Vt(e),n=t?as(a,t):[];if(B.debug.targetSelect.innerHTML="",!n.length){let r=document.createElement("option");r.value="__none__",r.textContent=t?"No target required":"No card selected",B.debug.targetSelect.appendChild(r),B.debug.targetSelect.disabled=!0;return}let o=document.createElement("option");o.value="__auto__",o.textContent=t?.id==="dynamite"?"Auto: first 3 blocked cells":"Auto: first valid target",B.debug.targetSelect.appendChild(o);for(let r of n){let s=document.createElement("option");s.value=r.key,s.textContent=r.label,B.debug.targetSelect.appendChild(s)}B.debug.targetSelect.disabled=!1}function sc(){let e=Math.max(1,Math.floor(Number(B.debug.dayInput?.value)||1));a.turn=e,B.debug.dayInput&&(B.debug.dayInput.value=String(e)),W(a,ae.width/2-a.view.x,86-a.view.y,`DAY ${e}`,p.green),H.updatePanels(),H.updateUI(),Bt(),Lt(`Day set to ${e}.`)}function lc(){a.timeLeft=0,a.phase==="running"&&_s(),W(a,ae.width/2-a.view.x,86-a.view.y,"TIMER 0",p.warn),H.updatePanels(),H.updateUI(),Lt("Timer set to 0.")}function ac(){let e=B.debug.cardSelect?.value,t=B.debug.targetSelect?.disabled?void 0:B.debug.targetSelect?.value,n=er(a,e,{targetKey:t});B.debug.grantCard&&(B.debug.grantCard.textContent=n.ok?"Granted":"Failed",window.setTimeout(()=>{B.debug.grantCard&&(B.debug.grantCard.textContent="Grant Selected")},900)),Me?.updateCongestion?.(),H.updatePanels(),H.updateUI(),Bt(),Lt(n.reason)}function cc(){let t=Yt.map(n=>er(a,n,{targetKey:"__auto__"})).filter(n=>n.ok).length;Me?.updateCongestion?.(),H.updatePanels(),H.updateUI(),Bt(),Lt(`Granted ${t}/${Yt.length} cards.`)}function uc(){B.debug?.infiniteCash?.checked&&a.cash<999999&&(a.cash=999999,a.totals.maxCash=Math.max(a.totals.maxCash,a.cash))}function Lt(e=""){B.debug?.readout&&(B.debug.readout.textContent=[e,`D${a.turn}`,M(a.cash),`Combo ${a.manualCombo?.count||0}`,`Event ${a.eventActive?.title||a.eventOffer?.title||"none"}`,`Rescue ${a.cardEffects?.rescueLoanCharges||0}`,`Chem ${a.cardEffects?.chemicalWeaponSubsidy||0}`].filter(Boolean).join(" | "))}var a=ko(),Y,H,Me,Qt;function dc(e=null){let t=zn(a,e);return e?t*qo(a,e):t}function fc(){Object.assign(a,ko()),a.phase="running",a.view={x:0,y:0,scale:1},xo(a),Us(),me(a),H.hideModal(),Me.updateCongestion(),H.updatePanels(),H.updateUI(),Lt()}function pc(){if(a.phase!=="build")return;if(a.cardDraft?.pending||a.cardTargetPick?.pending){Y.fail(a.cardTargetPick?.pending?"Choose upgrade target first.":"Choose an upgrade card first."),H.updatePanels();return}let e=sn(a);if(e.length){Y.fail(`Cannot start: ${e[0]}`),H.updatePanels();return}me(a),Zr(a),Xi(a);let t=Math.max(0,Math.floor(a.lastResult?.profit??a.stats?.profit??0)),n=Pi(a,Math.max(1,a.turn||1),t);a.lastStartFees={fairiesTribute:n.amount||0,tribute:n},n.amount>0&&W(a,ae.width/2-a.view.x,116-a.view.y,`FAIRIES -${M(n.amount)}`,p.danger),ci(a),a.phase="running",a.turn+=1,a.timeLeft=di(a),a.shutdownTimeLeft=0,a.cleanupTimer=null,a.cleanupBlown=!1,a.chicks=[],a.effects=[],a.floatingTexts=[],a.shake={time:0,strength:0},a.truckCargo=[],Us(),a.stats=So(),a.stats.fairiesTribute=a.lastStartFees?.fairiesTribute||0,a.stats.repairWorkerWages=a.pendingRepairWorkerWages||0;let o=a.stats.fairiesTribute+a.stats.repairWorkerWages;o>0&&(a.stats.penalty+=o,a.stats.profit-=o),a.pendingRepairWorkerWages=0;for(let r of a.scanners)r.queue=[],r.cooldown=0;for(let r of a.eggFarms)r.nextSpawn=Me.currentSpawnDelay(r),r.lastInterval=r.nextSpawn,r.shutterProgress=0,r.shutterSparked=!1;a.buildTool=null,a.selected=null,a.groupDrag=null,a.selectionBox=null,a.pan=null,Me.updateCongestion(),H.updatePanels(),H.updateUI()}function yc(){me(a);let e=zi(a);e.ok?W(a,ae.width/2-a.view.x,96-a.view.y,`Repairman hired -${M(e.cost)}`,p.green):(W(a,ae.width/2-a.view.x,96-a.view.y,e.reason||"Cannot hire repairman.",p.danger),Y?.fail?.(e.reason||"Cannot hire repairman.")),H.updatePanels(),H.updateUI()}function hc(){if(a.phase!=="running")return;let e=Ei(a),t=a.eventActive?{...a.eventActive}:null,n=vi(a),o=Ri(a);if(e.adjusted>0){let s=a.facilities.truck,l=s?s.x+s.w/2:ae.width/2-a.view.x,d=s?s.y+26:96-a.view.y;W(a,l,d,`${e.target==="poop"?"POOP SHIP":"SHIP"} +${M(e.adjusted)}`,p.green)}n?.bonus>0&&W(a,ae.width/2-a.view.x,96-a.view.y,`EVENT +${M(n.bonus)}`,p.green),o.amount>0&&W(a,ae.width/2-a.view.x,116-a.view.y,`CHEM SUBSIDY +${M(o.amount)}`,p.green),ui(a),a.totals.turnsCompleted+=1;let r=bi(t);if(r!==1&&(a.pendingFairiesTributeMultiplier=r),a.lastResult={...a.stats,ship:e,event:n,chemical:o,rescue:{amount:0,used:0,remaining:a.cardEffects?.rescueLoanCharges||0},fairiesTribute:{amount:a.stats.fairiesTribute||0},tributeMultiplier:r,turn:a.turn,cash:a.cash},a.cash<0){if((a.cardEffects?.rescueLoanCharges||0)>0){a.phase="loanDecision",H.showEmergencyLoanDecision(Ns,eo);return}a.phase="gameover",H.showGameOver();return}Os()}function Os(){a.phase="build",a.truckCargo=[],a.chicks=[],a.shutdownTimeLeft=0,a.cleanupTimer=null,a.cleanupBlown=!1,a.buildSession+=1,a.undoStack=[],a.redoStack=[],a.timeLeft=0;for(let e of a.scanners)e.queue=[];for(let e of a.eggFarms)e.shutterProgress=0,e.shutterSparked=!1;Qi(a),a.eventOffer=ai(a),Qt&&Qt.prepareDraft(),a.cardTargetPick=null,a.buildTool=null,a.groupDrag=null,a.selectionBox=null,a.pan=null,H.updatePanels(),H.showTurnResult(a.lastResult)}function Ns(){if((a.cardEffects?.rescueLoanCharges||0)<=0)return eo();a.cardEffects.rescueLoanCharges-=1,a.stats.rescueLoan=(a.stats.rescueLoan||0)+500,a.totals.rescueLoan=(a.totals.rescueLoan||0)+500;let e=Ne(a,500);a.lastResult={...a.lastResult||{},...a.stats,rescue:{amount:(a.lastResult?.rescue?.amount||0)+e,used:(a.lastResult?.rescue?.used||0)+1,remaining:a.cardEffects.rescueLoanCharges},cash:a.cash},W(a,ae.width/2-a.view.x,176-a.view.y,`RESCUE +${M(e)}`,p.green),a.cash>=0?Os():(a.cardEffects?.rescueLoanCharges||0)>0?(a.phase="loanDecision",H.showEmergencyLoanDecision(Ns,eo)):eo()}function eo(){a.phase="gameover",H.showGameOver()}function _s(){a.shutdownTimeLeft<=0&&(a.shutdownTimeLeft=a.shutdownGraceSeconds||10);for(let e of a.eggFarms){if(e.shutterSparked)continue;e.shutterProgress=.02,e.shutterSparked=!0;let t=F(e.col,e.row);Ve(a,t.x,t.y,p.ink),Ze(a,t.x,t.y+10,10),W(a,t.x,t.y-34,"SHUT +10s",p.ink)}}function Gs(e){a.lastTimestamp||(a.lastTimestamp=e);let t=Math.min((e-a.lastTimestamp)/1e3,.05);a.lastTimestamp=e,a.phase==="running"&&Me.updateRunning(t,{closeFarmShutters:_s,completeTurn:hc}),_i(a,t,ae,Y.equipmentHitBoxes),Me.updateCongestion(),hs(nc,ae,a,{activeQueuedChick:Me.activeQueuedChick,selectedObject:Y.selectedObject,selectedTitle:Y.selectedTitle}),uc(),H.updateUI(),Ks(),Lt(),requestAnimationFrame(Gs)}function to(){return a.view?.scale||1}function pn(){a.view||(a.view={x:0,y:0,scale:1}),a.view.scale==null&&(a.view.scale=1)}function no(e){let t=ae.getBoundingClientRect();return{x:(e.clientX-t.left)*ae.width/t.width,y:(e.clientY-t.top)*ae.height/t.height}}function mt(e){let t=no(e),n=to();return{x:(t.x-(a.view?.x||0))/n,y:(t.y-(a.view?.y||0))/n}}function mc(e){let t=to();return{x:e.x*t+(a.view?.x||0),y:e.y*t+(a.view?.y||0)}}function bc(){let e={left:y.x-90,top:y.y-130,right:y.x+y.cols*y.cell+260,bottom:y.y+y.rows*y.cell+220};if(a.phase==="build")for(let t of Ct(a)){let n=Mt(t);e.left=Math.min(e.left,n.x-60),e.top=Math.min(e.top,n.y-80),e.right=Math.max(e.right,n.x+n.w+80),e.bottom=Math.max(e.bottom,n.y+n.h+80)}return e}function Fs(e,t){if(e<=t)return[e,t];let n=(e+t)/2;return[n,n]}function bt(){pn();let e=to(),t=bc(),[n,o]=Fs(ae.width-160-t.right*e,110-t.left*e),[r,s]=Fs(ae.height-150-t.bottom*e,150-t.top*e);a.view.x=on(a.view.x,n,o),a.view.y=on(a.view.y,r,s)}function Us(){pn(),a.view.scale=1;let e=a.eggFarms?.[0],t=e?F(e.col,e.row):{x:y.x,y:y.y};a.view.x=280-t.x,a.view.y=190-t.y,bt()}function vc(e){let t=no(e);pn(),a.pan={start:t,viewX:a.view.x,viewY:a.view.y,moved:!1}}function wc(e){if(!a.pan)return;let t=no(e);Math.hypot(t.x-a.pan.start.x,t.y-a.pan.start.y)>5&&(a.pan.moved=!0),pn(),a.view.x=a.pan.viewX+t.x-a.pan.start.x,a.view.y=a.pan.viewY+t.y-a.pan.start.y,bt()}function Sc(e){e.preventDefault(),pn();let t=no(e),n=mt(e),o=Math.exp(-e.deltaY*.0012),r=on(to()*o,.55,1.8);a.view.scale=r,a.view.x=t.x-n.x*r,a.view.y=t.y-n.y*r,bt(),ot()}function kc(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:{type:e.type,id:e.ref.id}:null}function xc(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:e.ref||null:null}function ot(){B.hoverTooltip&&(B.hoverTooltip.classList.remove("visible"),B.hoverTooltip.setAttribute("aria-hidden","true"),a.hover=null)}function Cc(e,t){if(!B.hoverTooltip||a.phase!=="build"||a.cardTargetPick?.pending||a.groupDrag||a.selectionBox||a.pan)return ot();let n=xc(t);if(!n)return ot();let o=Y.selectedTitle(n),r=Y.flavorText?Y.flavorText(n):"",s=Y.disconnectedWarningFor?Y.disconnectedWarningFor(n):"",l=Y.selectedInfoLines(n).slice(0,7);B.hoverTooltip.innerHTML=`${o}${s?`${s}`:r?`${r}`:""}${l.map(C=>`${C}`).join("")}`;let d=Math.min(window.innerWidth-330,e.clientX+18),v=Math.min(window.innerHeight-220,e.clientY+18);B.hoverTooltip.style.left=`${Math.max(8,d)}px`,B.hoverTooltip.style.top=`${Math.max(8,v)}px`,B.hoverTooltip.classList.add("visible"),B.hoverTooltip.setAttribute("aria-hidden","false"),a.hover={type:t.type,id:t.oldKey||t.ref?.id||null}}function Mc(e){if(a.phase!=="build")return ot();Cc(e,Y.equipmentAtPoint(mt(e)))}function Ws(e){ot();let t=mt(e),n=Y.equipmentAtPoint(t),o=kc(n);if(!o){a.selected=null,a.multiSelected=[],H.updatePanels();return}a.selected=o,a.multiSelected=[o],H.updatePanels();let r=Y.selectedObject();r?.type==="scanner"&&r.kind==="manual"&&Y.showManualScannerMenu(r),r?.type==="scanner"&&r.kind==="auto"&&Y.showAutoScannerMenu(r)}function Xt(){a.buildTool=null,a.selected=null,a.multiSelected=[],a.selectionBox=null,a.cardTargetPick?.mode==="autoScannerMenu"&&(a.cardTargetPick=null),H.hideModal(),ot(),H.updatePanels(),H.updateUI()}function Bs(e){return String(e).replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function gc(e){let t=e?.queue?.[0];return t==null?null:a.chicks.find(n=>n.id===t)||null}function Tc(e){if(!e)return'WAIT';let t=e.sex==="poop"?"\u{1F4A9} POOP":e.sex==="male"?"\u2642 MALE":"\u2640 FEMALE";return`${t}`}function Ec(e,t){let n=new Set(a.eggFarms.map(P=>I(P.col,P.row))),o=new Map(a.scanners.map(P=>[I(P.col,P.row),P])),r=Pe(e,"inputA"),s=r?I(r.col,r.row):null,l=new Set(Object.values(a.facilities||{}).map(P=>P.entry?I(P.entry.col,P.entry.row):null).filter(Boolean)),d=t?.sex||"",v=d==="poop"?"\u{1F4A9}":d==="male"?"\u2642":d==="female"?"\u2640":"",C=[];for(let P=e.row-2;P<=e.row+2;P+=1)for(let R=e.col-2;R<=e.col+2;R+=1){let L=I(R,P),V=["mini-cell"],te="";R===e.col&&P===e.row?(V.push("scanner"),d&&V.push(d),te=v||"S"):L===s?(V.push("input"),te="IN"):n.has(L)?(V.push("egg"),te="E"):o.has(L)?(V.push("scanner-other"),te="S"):l.has(L)?(V.push("port"),te="P"):a.conveyorTiles.has(L)?(V.push("belt"),te="\u2022"):a.blockedCells?.has?.(L)&&(V.push("blocked"),te="\xD7"),C.push(`${te}`)}return`
${C.join("")}
`}function Pc(e){let t=mc(F(e.col,e.row)),n=76;return t.x<-n||t.y<-n||t.x>ae.width+n||t.y>ae.height+n}function Ks(){if(!B.manualScannerMonitor)return;if(a.phase!=="running"){B.manualScannerMonitor.classList.remove("visible"),B.manualScannerMonitor.innerHTML="";return}let e=a.scanners.filter(t=>t.kind==="manual"&&Pc(t));if(!e.length){B.manualScannerMonitor.classList.remove("visible"),B.manualScannerMonitor.innerHTML="";return}B.manualScannerMonitor.innerHTML=e.map(t=>{let n=gc(t),o=t.keys?.left?.label||(t.slot===0?"A":"Left"),r=t.keys?.right?.label||(t.slot===0?"D":"Right"),s=t.role===0?"MIXER":"WASTE",l=t.role===0?"S2":"TRUCK",d=n?"":" disabled";return`
S${(t.slot??0)+1}OFFSCREEN / Q:${t.queue.length}
- IN${Mc(n)}SCANNER + IN${Tc(n)}SCANNER
- ${gc(t,n)} + ${Ec(t,n)}
- - + +
-
`}).join(""),B.manualScannerMonitor.classList.add("visible")}B.manualScannerMonitor?.addEventListener("click",e=>{let t=e.target.closest("button[data-scanner-id]");if(!t||t.disabled)return;let n=a.scanners.find(o=>o.id===Number(t.dataset.scannerId));n&&(Ce.sortScanner(n,t.dataset.side),_s())});ae.addEventListener("contextmenu",e=>e.preventDefault());ae.addEventListener("wheel",vc,{passive:!1});ae.addEventListener("pointerdown",e=>{if(a.phase!=="build")return;ae.setPointerCapture(e.pointerId);let t=ht(e);if(e.button===2){mc(e);return}if(e.button!==0)return;if(a.cardTargetPick?.mode==="autoScannerMenu"){Xt();return}if(a.cardTargetPick?.pending){Qt.chooseTargetAtPoint(t);return}let n=Y.expansionOfferAtPoint?.(t);if(n){Y.buyGridExpansion(n),mt(),H.updatePanels(),H.updateUI();return}if(Y.cycleBranchModeAtPoint?.(t)){H.updatePanels(),H.updateUI();return}let o=We(t.x,t.y),r=Y.equipmentAtPoint(t);if(!a.buildTool&&r?.type==="conveyor"&&o&&Y.cycleSingleConveyorDirection?.(o)){H.updatePanels(),H.updateUI();return}if(a.buildTool==="erase"){if(!Y.equipmentAtPoint(t)){Xt();return}Y.eraseAtPoint(t);return}if(a.buildTool){let s=We(t.x,t.y);if(!s&&!["mixer","trash","truck"].includes(a.buildTool)){Xt();return}if(a.buildTool==="conveyor"||a.buildTool==="boostConveyor"){Y.beginConveyorDrag(s);return}if(Y.equipmentAtPoint(t)){a.buildTool=null,Ws(e);return}Y.buildAtPoint(t);return}Y.startGroupDrag(e)||Y.startSelectionBox(e)});ae.addEventListener("pointermove",e=>{if(a.phase!=="build"){nt();return}kc(e),a.pan&&e.buttons&2&&bc(e),a.groupDrag&&e.buttons&1&&Y.updateGroupDrag(e),a.selectionBox&&e.buttons&1&&Y.updateSelectionBox(e),(a.buildTool==="conveyor"||a.buildTool==="boostConveyor")&&e.buttons&1&&Y.continueConveyorDrag(We(ht(e).x,ht(e).y)),a.buildTool==="erase"&&e.buttons&1&&Y.eraseAtPoint(ht(e))});ae.addEventListener("pointerup",e=>{a.selectionBox?Y.finishSelectionBox():a.groupDrag&&(a.groupDrag.committed||Ws(e),Y.finishGroupDrag()),e.button===2&&a.pan&&!a.pan.moved&&a.buildTool&&Xt(),(a.buildTool==="conveyor"||a.buildTool==="boostConveyor")&&Y.endConveyorDrag?.(),a.groupDrag=null,a.pan=null;try{ae.releasePointerCapture(e.pointerId)}catch{}});ae.addEventListener("pointerleave",nt);ae.addEventListener("pointercancel",()=>{Y?.endConveyorDrag?.(),a.groupDrag=null,a.selectionBox=null,a.pan=null,nt()});document.addEventListener("pointerdown",e=>{!B.modal.classList.contains("visible")||!B.modal.classList.contains("equipment-popover")||e.target.closest("#modal .modal-card")||Xt()},!0);B.buttons.s1Left.addEventListener("click",()=>Ce.sortSlot(0,"left"));B.buttons.s1Right.addEventListener("click",()=>Ce.sortSlot(0,"right"));B.buttons.s2Left.addEventListener("click",()=>Ce.sortSlot(1,"left"));B.buttons.s2Right.addEventListener("click",()=>Ce.sortSlot(1,"right"));B.buttons.nextTurn.addEventListener("click",dc);B.buttons.conveyor.addEventListener("click",()=>Y.setBuildTool("conveyor"));B.buttons.boostConveyor.addEventListener("click",()=>Y.setBuildTool("boostConveyor"));B.buttons.eggFarm.addEventListener("click",()=>Y.setBuildTool("eggFarm"));B.buttons.autoScanner.addEventListener("click",()=>Y.setBuildTool("autoScanner"));B.buttons.manualScanner.addEventListener("click",()=>Y.setBuildTool("manualScanner"));B.buttons.mixer.addEventListener("click",()=>Y.setBuildTool("mixer"));B.buttons.trash.addEventListener("click",()=>Y.setBuildTool("trash"));B.buttons.truck.addEventListener("click",()=>Y.setBuildTool("truck"));B.buttons.erase.addEventListener("click",()=>Y.setBuildTool("erase"));B.hireRepairmanButton?.addEventListener("click",fc);B.debug.setDay?.addEventListener("click",rc);B.debug.zeroTimer?.addEventListener("click",ic);B.debug.grantCard?.addEventListener("click",sc);B.debug.grantAllCards?.addEventListener("click",lc);B.buttons.undo.addEventListener("click",()=>{Lo(a)&&(mt(),H.updatePanels(),H.updateUI(),Bt())});B.buttons.redo.addEventListener("click",()=>{Oo(a)&&(mt(),H.updatePanels(),H.updateUI(),Bt())});function Bs(e,t,n){let o=e.keys?.[t];return o?o.code&&n.code===o.code||o.key&&n.key.toLowerCase()===o.key:!1}window.addEventListener("keydown",e=>{if(e.repeat)return;let t=e.key.toLowerCase();if(a.phase==="running")for(let n of a.scanners.filter(o=>o.kind==="manual")){if(Bs(n,"left",e)){e.preventDefault(),Ce.sortScanner(n,"left");return}if(Bs(n,"right",e)){e.preventDefault(),Ce.sortScanner(n,"right");return}}a.phase==="build"&&(e.ctrlKey||e.metaKey)&&t==="z"&&(e.preventDefault(),Lo(a)&&(mt(),H.updatePanels(),H.updateUI())),a.phase==="build"&&(e.ctrlKey||e.metaKey)&&(t==="y"||e.shiftKey&&t==="z")&&(e.preventDefault(),Oo(a)&&(mt(),H.updatePanels(),H.updateUI())),e.key==="Escape"&&a.cardTargetPick?.pending&&(e.preventDefault(),a.cardTargetPick.mode==="autoScannerMenu"?Xt():Qt.cancelTargetPick())});Y=gs({game:a,ui:B,canvas:ae,canvasPoint:ht,onUpdatePanels:()=>H?.updatePanels()});Ce=Is({game:a,currentConveyorSpeed:cc,onGameOverCheck:()=>H?.checkGameOver()});Qt=ds({game:a,ui:B,onUpdatePanels:()=>H?.updatePanels()});H=Ts({game:a,ui:B,build:Y,startGame:uc,beginCardDraft:()=>Qt.showDraft(),activeQueuedChick:Ce.activeQueuedChick});tc();oc();So(a);me(a);Ce.updateCongestion();H.updatePanels();H.updateUI();H.showTitle();Lt();requestAnimationFrame(Gs); + `}).join(""),B.manualScannerMonitor.classList.add("visible")}B.manualScannerMonitor?.addEventListener("click",e=>{let t=e.target.closest("button[data-scanner-id]");if(!t||t.disabled)return;let n=a.scanners.find(o=>o.id===Number(t.dataset.scannerId));n&&(Me.sortScanner(n,t.dataset.side),Ks())});ae.addEventListener("contextmenu",e=>e.preventDefault());ae.addEventListener("wheel",Sc,{passive:!1});ae.addEventListener("pointerdown",e=>{if(a.phase!=="build")return;ae.setPointerCapture(e.pointerId);let t=mt(e);if(e.button===2){vc(e);return}if(e.button!==0)return;if(a.cardTargetPick?.mode==="autoScannerMenu"){Xt();return}if(a.cardTargetPick?.pending){Qt.chooseTargetAtPoint(t);return}let n=Y.expansionOfferAtPoint?.(t);if(n){Y.buyGridExpansion(n),bt(),H.updatePanels(),H.updateUI();return}if(Y.cycleBranchModeAtPoint?.(t)){H.updatePanels(),H.updateUI();return}let o=We(t.x,t.y),r=Y.equipmentAtPoint(t);if(!a.buildTool&&r?.type==="conveyor"&&o&&Y.cycleSingleConveyorDirection?.(o)){H.updatePanels(),H.updateUI();return}if(a.buildTool==="erase"){if(!Y.equipmentAtPoint(t)){Xt();return}Y.eraseAtPoint(t);return}if(a.buildTool){let s=We(t.x,t.y);if(!s&&!["mixer","trash","truck"].includes(a.buildTool)){Xt();return}if(a.buildTool==="conveyor"||a.buildTool==="boostConveyor"){Y.beginConveyorDrag(s);return}if(Y.equipmentAtPoint(t)){a.buildTool=null,Ws(e);return}Y.buildAtPoint(t);return}Y.startGroupDrag(e)||Y.startSelectionBox(e)});ae.addEventListener("pointermove",e=>{if(a.phase!=="build"){ot();return}Mc(e),a.pan&&e.buttons&2&&wc(e),a.groupDrag&&e.buttons&1&&Y.updateGroupDrag(e),a.selectionBox&&e.buttons&1&&Y.updateSelectionBox(e),(a.buildTool==="conveyor"||a.buildTool==="boostConveyor")&&e.buttons&1&&Y.continueConveyorDrag(We(mt(e).x,mt(e).y)),a.buildTool==="erase"&&e.buttons&1&&Y.eraseAtPoint(mt(e))});ae.addEventListener("pointerup",e=>{a.selectionBox?Y.finishSelectionBox():a.groupDrag&&(a.groupDrag.committed||Ws(e),Y.finishGroupDrag()),e.button===2&&a.pan&&!a.pan.moved&&a.buildTool&&Xt(),(a.buildTool==="conveyor"||a.buildTool==="boostConveyor")&&Y.endConveyorDrag?.(),a.groupDrag=null,a.pan=null;try{ae.releasePointerCapture(e.pointerId)}catch{}});ae.addEventListener("pointerleave",ot);ae.addEventListener("pointercancel",()=>{Y?.endConveyorDrag?.(),a.groupDrag=null,a.selectionBox=null,a.pan=null,ot()});document.addEventListener("pointerdown",e=>{!B.modal.classList.contains("visible")||!B.modal.classList.contains("equipment-popover")||e.target.closest("#modal .modal-card")||Xt()},!0);B.buttons.s1Left.addEventListener("click",()=>Me.sortSlot(0,"left"));B.buttons.s1Right.addEventListener("click",()=>Me.sortSlot(0,"right"));B.buttons.s2Left.addEventListener("click",()=>Me.sortSlot(1,"left"));B.buttons.s2Right.addEventListener("click",()=>Me.sortSlot(1,"right"));B.buttons.nextTurn.addEventListener("click",pc);B.buttons.conveyor.addEventListener("click",()=>Y.setBuildTool("conveyor"));B.buttons.boostConveyor.addEventListener("click",()=>Y.setBuildTool("boostConveyor"));B.buttons.eggFarm.addEventListener("click",()=>Y.setBuildTool("eggFarm"));B.buttons.autoScanner.addEventListener("click",()=>Y.setBuildTool("autoScanner"));B.buttons.manualScanner.addEventListener("click",()=>Y.setBuildTool("manualScanner"));B.buttons.mixer.addEventListener("click",()=>Y.setBuildTool("mixer"));B.buttons.trash.addEventListener("click",()=>Y.setBuildTool("trash"));B.buttons.truck.addEventListener("click",()=>Y.setBuildTool("truck"));B.buttons.erase.addEventListener("click",()=>Y.setBuildTool("erase"));B.hireRepairmanButton?.addEventListener("click",yc);B.debug.setDay?.addEventListener("click",sc);B.debug.zeroTimer?.addEventListener("click",lc);B.debug.grantCard?.addEventListener("click",ac);B.debug.grantAllCards?.addEventListener("click",cc);B.buttons.undo.addEventListener("click",()=>{No(a)&&(bt(),H.updatePanels(),H.updateUI(),Bt())});B.buttons.redo.addEventListener("click",()=>{_o(a)&&(bt(),H.updatePanels(),H.updateUI(),Bt())});function Ls(e,t,n){let o=e.keys?.[t];return o?o.code&&n.code===o.code||o.key&&n.key.toLowerCase()===o.key:!1}window.addEventListener("keydown",e=>{if(e.repeat)return;let t=e.key.toLowerCase();if(a.phase==="running")for(let n of a.scanners.filter(o=>o.kind==="manual")){if(Ls(n,"left",e)){e.preventDefault(),Me.sortScanner(n,"left");return}if(Ls(n,"right",e)){e.preventDefault(),Me.sortScanner(n,"right");return}}a.phase==="build"&&(e.ctrlKey||e.metaKey)&&t==="z"&&(e.preventDefault(),No(a)&&(bt(),H.updatePanels(),H.updateUI())),a.phase==="build"&&(e.ctrlKey||e.metaKey)&&(t==="y"||e.shiftKey&&t==="z")&&(e.preventDefault(),_o(a)&&(bt(),H.updatePanels(),H.updateUI())),e.key==="Escape"&&a.cardTargetPick?.pending&&(e.preventDefault(),a.cardTargetPick.mode==="autoScannerMenu"?Xt():Qt.cancelTargetPick())});Y=Ts({game:a,ui:B,canvas:ae,canvasPoint:mt,onUpdatePanels:()=>H?.updatePanels()});Me=Is({game:a,currentConveyorSpeed:dc,onGameOverCheck:()=>H?.checkGameOver()});Qt=ds({game:a,ui:B,onUpdatePanels:()=>H?.updatePanels()});H=Es({game:a,ui:B,build:Y,startGame:fc,beginCardDraft:()=>Qt.showDraft(),activeQueuedChick:Me.activeQueuedChick});oc();ic();xo(a);me(a);Me.updateCongestion();H.updatePanels();H.updateUI();H.showTitle();Lt();requestAnimationFrame(Gs); diff --git a/index.html b/index.html index c4d8f27..ee5d73e 100644 --- a/index.html +++ b/index.html @@ -3,12 +3,16 @@ - Chick Sorter v27.14 - + + + + Chick Sorter v27.19 — Land and UI Patch +
-
+
+
v27.19 VERIFIED
@@ -17,7 +21,6 @@
NET¥0
DAY1
PHASETitle
-
COMBO0
@@ -27,16 +30,17 @@
POOP0
-
-
NO ACTIVE EVENT
-
TRUCK TARGET: FEMALE
-
BELT: 52 px/s
+
+
NO ACTIVE EVENT
+
BELT: 52 px/s
+
COMBO0
+
TRUCK TARGET: FEMALE
-

CHICK SORTER v27.14

+

CHICK SORTER v27.19

Build, expand, connect at least one valid EGG route, then start the next day.

@@ -55,7 +59,7 @@ - +
Build tools unlock after each day.
@@ -64,10 +68,6 @@

Status

-
-

Next Event

-
-
@@ -110,6 +110,6 @@ - + diff --git a/package-lock.json b/package-lock.json index 8ba8995..8035d10 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,19 @@ { "name": "zunda-shiwake", - "version": "27.13.0", + "version": "27.19.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "zunda-shiwake", - "version": "27.13.0", + "version": "27.19.0", "devDependencies": { "esbuild": "^0.25.0" } }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.12", - "resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", "cpu": [ "ppc64" @@ -30,7 +30,7 @@ }, "node_modules/@esbuild/android-arm": { "version": "0.25.12", - "resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", "cpu": [ "arm" @@ -47,7 +47,7 @@ }, "node_modules/@esbuild/android-arm64": { "version": "0.25.12", - "resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", "cpu": [ "arm64" @@ -64,7 +64,7 @@ }, "node_modules/@esbuild/android-x64": { "version": "0.25.12", - "resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", "cpu": [ "x64" @@ -81,7 +81,7 @@ }, "node_modules/@esbuild/darwin-arm64": { "version": "0.25.12", - "resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", "cpu": [ "arm64" @@ -98,7 +98,7 @@ }, "node_modules/@esbuild/darwin-x64": { "version": "0.25.12", - "resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", "cpu": [ "x64" @@ -114,7 +114,7 @@ }, "node_modules/@esbuild/freebsd-arm64": { "version": "0.25.12", - "resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", "cpu": [ "arm64" @@ -131,7 +131,7 @@ }, "node_modules/@esbuild/freebsd-x64": { "version": "0.25.12", - "resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", "cpu": [ "x64" @@ -148,7 +148,7 @@ }, "node_modules/@esbuild/linux-arm": { "version": "0.25.12", - "resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", "cpu": [ "arm" @@ -165,7 +165,7 @@ }, "node_modules/@esbuild/linux-arm64": { "version": "0.25.12", - "resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", "cpu": [ "arm64" @@ -182,7 +182,7 @@ }, "node_modules/@esbuild/linux-ia32": { "version": "0.25.12", - "resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", "cpu": [ "ia32" @@ -199,7 +199,7 @@ }, "node_modules/@esbuild/linux-loong64": { "version": "0.25.12", - "resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", "cpu": [ "loong64" @@ -216,7 +216,7 @@ }, "node_modules/@esbuild/linux-mips64el": { "version": "0.25.12", - "resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", "cpu": [ "mips64el" @@ -233,7 +233,7 @@ }, "node_modules/@esbuild/linux-ppc64": { "version": "0.25.12", - "resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", "cpu": [ "ppc64" @@ -250,7 +250,7 @@ }, "node_modules/@esbuild/linux-riscv64": { "version": "0.25.12", - "resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", "cpu": [ "riscv64" @@ -267,7 +267,7 @@ }, "node_modules/@esbuild/linux-s390x": { "version": "0.25.12", - "resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", "cpu": [ "s390x" @@ -284,7 +284,7 @@ }, "node_modules/@esbuild/linux-x64": { "version": "0.25.12", - "resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", "cpu": [ "x64" @@ -301,7 +301,7 @@ }, "node_modules/@esbuild/netbsd-arm64": { "version": "0.25.12", - "resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", "cpu": [ "arm64" @@ -318,7 +318,7 @@ }, "node_modules/@esbuild/netbsd-x64": { "version": "0.25.12", - "resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", "cpu": [ "x64" @@ -335,7 +335,7 @@ }, "node_modules/@esbuild/openbsd-arm64": { "version": "0.25.12", - "resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", "cpu": [ "arm64" @@ -352,7 +352,7 @@ }, "node_modules/@esbuild/openbsd-x64": { "version": "0.25.12", - "resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", "cpu": [ "x64" @@ -369,7 +369,7 @@ }, "node_modules/@esbuild/openharmony-arm64": { "version": "0.25.12", - "resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", "cpu": [ "arm64" @@ -386,7 +386,7 @@ }, "node_modules/@esbuild/sunos-x64": { "version": "0.25.12", - "resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", "cpu": [ "x64" @@ -403,7 +403,7 @@ }, "node_modules/@esbuild/win32-arm64": { "version": "0.25.12", - "resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", "cpu": [ "arm64" @@ -420,7 +420,7 @@ }, "node_modules/@esbuild/win32-ia32": { "version": "0.25.12", - "resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", "cpu": [ "ia32" @@ -437,7 +437,7 @@ }, "node_modules/@esbuild/win32-x64": { "version": "0.25.12", - "resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", "cpu": [ "x64" @@ -453,7 +453,7 @@ }, "node_modules/esbuild": { "version": "0.25.12", - "resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/esbuild/-/esbuild-0.25.12.tgz", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", "dev": true, "hasInstallScript": true, diff --git a/package.json b/package.json index 94483f5..8ff31e7 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { "name": "zunda-shiwake", - "version": "27.14.0", + "version": "27.19.0", "private": true, "type": "module", "scripts": { "clean": "node -e \"require('fs').rmSync('dist', { recursive: true, force: true })\"", - "build": "npm run clean && esbuild src/game.js --bundle --format=esm --target=es2020 --minify --outfile=dist/game.js" + "build": "npm run clean && node -e \"require('fs').copyFileSync('styles.css', 'styles-v27.19.css')\" && esbuild src/game.js --bundle --format=esm --target=es2020 --minify --outfile=dist/game-v27.19.js" }, "devDependencies": { "esbuild": "^0.25.0" diff --git a/src/core/balance.js b/src/core/balance.js index 6135bd5..58adddb 100644 --- a/src/core/balance.js +++ b/src/core/balance.js @@ -1,7 +1,7 @@ // Central balance sheet for tuning gameplay. // Edit this file first when adjusting prices, income, penalties, timing, card rates, or caps. export const BALANCE = { - version: 'v27.14 debug restore consistency patch', + version: 'v27.19 LAND + UI PATCH', time: { daySeconds: 60, farmShutdownGraceSeconds: 10 @@ -24,7 +24,9 @@ export const BALANCE = { } }, map: { - blockedRatio: 0.075 + blockedRatio: 0.03, + blockedExpansionIncrement: 0.005, + blockedRatioMax: 0.10 }, economy: { income: { @@ -251,7 +253,7 @@ export const BALANCE = { rarity: 'rare', type: 'cellAction', target: 'blockedCell', - description: 'Remove any 3 unbuildable cells', + description: 'Choose and remove up to 3 unbuildable cells.', tags: ['RISK', 'RARE', 'ONE-SHOT'] }, { @@ -307,7 +309,7 @@ export const BALANCE = { title: 'Motivational Exploitation', rarity: 'ultraRare', type: 'instant', - description: 'Repairman labor cost -30%. The repairman smiles with bloodshot eyes. One time only.', + description: 'Repair room work time -30%. The repairman smiles with bloodshot eyes. One time only.', tags: ['MAINTENANCE', 'ULTRA RARE', 'PASSIVE'] }, { @@ -374,7 +376,6 @@ export const BALANCE = { trash: 1.00 }, repairman: { - dailyCost: 100, secondsPerOnePercent: 0.5, walkSpeed: 90 } @@ -411,6 +412,10 @@ export const BALANCE = { truck: { id: 'truck', type: 'facility', name: 'Truck', shortName: 'TRUCK', price: 450, buildable: true, upgradeable: true, incomeKey: 'truck', body: { w: 176, h: 138 } + }, + maintenanceRoom: { + id: 'maintenanceRoom', type: 'maintenanceRoom', name: 'Maintenance Room', shortName: 'REPAIR ROOM', price: 220, + buildable: true, upgradeable: false, footprint: { cols: 2, rows: 2 } } } }; diff --git a/src/core/config.js b/src/core/config.js index 595dcb9..dfa135f 100644 --- a/src/core/config.js +++ b/src/core/config.js @@ -26,7 +26,7 @@ export const EGG_SPAWN_RANGES = BALANCE.production.eggSpawnRanges; export const GRID = BALANCE.grid; export const FACILITY_DEFS = BALANCE.facilities; -export const BUILD_TOOL_IDS = ['conveyor', 'boostConveyor', 'eggFarm', 'autoScanner', 'manualScanner', 'mixer', 'trash', 'truck']; +export const BUILD_TOOL_IDS = ['conveyor', 'boostConveyor', 'eggFarm', 'autoScanner', 'manualScanner', 'mixer', 'trash', 'truck', 'maintenanceRoom']; export const MACHINE_FACILITY_IDS = ['mixer', 'trash', 'truck']; export const INCOME_FACILITY_IDS = ['mixer', 'truck']; @@ -40,20 +40,20 @@ export const DIRS = [ ]; export const THEME = { - bg: '#eefbea', - ink: '#102015', - muted: '#526456', - green: '#22b94f', - greenSoft: '#b7f5c6', - mixerBlue: '#2477ff', - truckPink: '#ff6aa8', - wasteGreen: '#22b94f', - danger: '#c42424', - warn: '#f0a020', - white: '#ffffff', + bg: '#111318', + ink: '#090a0d', + muted: '#8f9bab', + green: '#7bd84f', + greenSoft: '#273c24', + mixerBlue: '#4aa3ff', + truckPink: '#ffb33e', + wasteGreen: '#88d35a', + danger: '#e34a36', + warn: '#ffb827', + white: '#e6edf2', poop: '#7b4a23', - male: '#62a9ff', - female: '#ff8bc6' + male: '#4aa3ff', + female: '#ff6fae' }; export const EFFECT_PRIORITY = { diff --git a/src/core/entities.js b/src/core/entities.js index 71e9c7a..75d699e 100644 --- a/src/core/entities.js +++ b/src/core/entities.js @@ -94,6 +94,26 @@ export function createFacility(game, id, p, price) { return layoutFacilityOnEdge(f, entry, side); } + +export function maintenanceRoomFootprint(room) { + if (!room) return []; + return [ + { col: room.col, row: room.row }, + { col: room.col + 1, row: room.row }, + { col: room.col, row: room.row + 1 }, + { col: room.col + 1, row: room.row + 1 } + ]; +} + +export function createMaintenanceRoom(game, col, row) { + return { + type: 'maintenanceRoom', id: game.nextId++, col, row, + price: BUILD_COSTS.maintenanceRoom, + builtSession: game.buildSession, + wCells: 2, hCells: 2 + }; +} + export function rollChickSex(game) { return Math.random() < currentPoopRate(game) ? 'poop' : (Math.random() < 0.5 ? 'male' : 'female'); } diff --git a/src/core/mapGen.js b/src/core/mapGen.js index 15712ad..dde8d4f 100644 --- a/src/core/mapGen.js +++ b/src/core/mapGen.js @@ -20,6 +20,12 @@ function mulberry32(seed) { }; } + +export function blockedRatioForExpansionPurchase(purchaseCount, { base = 0.03, increment = 0.005, max = 0.10 } = {}) { + const count = Math.max(0, Math.floor(Number(purchaseCount) || 0)); + return Number(Math.min(max, base + count * increment).toFixed(6)); +} + export function createRunSeed() { return `RUN-${Date.now().toString(36)}-${Math.floor(Math.random() * 1e6).toString(36)}`.toUpperCase(); } @@ -38,7 +44,7 @@ export function generateBlockedCells({ seed, targetRatio = 0.20, reserved = [] } const j = Math.floor(rng() * (i + 1)); [candidates[i], candidates[j]] = [candidates[j], candidates[i]]; } - const target = Math.round(GRID.cols * GRID.rows * targetRatio); + const target = Math.round(GRID.cols * GRID.rows * targetRatio + 1e-9); return new Set(candidates.slice(0, Math.min(target, candidates.length)).map(c => c.k)); } @@ -60,6 +66,6 @@ export function generateBlockedCellsInRect({ seed, colStart = 0, colEnd = GRID.c const j = Math.floor(rng() * (i + 1)); [candidates[i], candidates[j]] = [candidates[j], candidates[i]]; } - const target = Math.round((c1 - c0) * (r1 - r0) * targetRatio); + const target = Math.round((c1 - c0) * (r1 - r0) * targetRatio + 1e-9); return new Set(candidates.slice(0, Math.min(target, candidates.length)).map(c => c.k)); } diff --git a/src/core/state.js b/src/core/state.js index d44b5ac..783cd54 100644 --- a/src/core/state.js +++ b/src/core/state.js @@ -26,7 +26,6 @@ export function newTurnStats() { manualComboBonus: 0, manualComboSuccess: 0, manualComboFailure: 0, - repairWorkerWages: 0, fairiesTribute: 0, chemicalWeaponSubsidy: 0, rescueLoan: 0, @@ -73,7 +72,6 @@ export function newTotalStats() { manualComboBonus: 0, manualComboSuccess: 0, manualComboFailure: 0, - repairWorkerWages: 0, cardRerollCost: 0, dudRefundIncome: 0, composterIncome: 0, @@ -129,6 +127,8 @@ export function createGame() { eggFarms: [], scanners: [], facilities: {}, + maintenanceRooms: [], + repairmen: [], branchCounters: new Map(), routingVersion: 0, factoryGraph: null, @@ -144,8 +144,7 @@ export function createGame() { cardDraft: { pending: false, choices: [], rerolls: 0, picksRemaining: 0 }, cardTargetPick: null, manualCombo: { count: 0, lastBonus: 0 }, - pendingRepairWorkerWages: 0, - repairman: { hiredForNextDay: false, active: false, x: GRID.x + GRID.cell * 0.5, y: GRID.y + BALANCE.grid.rows * GRID.cell + 84, target: null, repairedToday: 0 }, + repairman: { active: false, x: GRID.x + GRID.cell * 0.5, y: GRID.y + BALANCE.grid.rows * GRID.cell + 84, target: null, repairedToday: 0 }, stats: newTurnStats(), lastResult: null, totals: newTotalStats() @@ -319,10 +318,11 @@ export function resetLayout(game) { game.repairman.y = GRID.y + GRID.rows * GRID.cell + 84; game.repairman.target = null; game.repairman.active = false; - game.repairman.hiredForNextDay = false; } game.conveyorTiles.clear(); game.conveyorMeta.clear(); + game.maintenanceRooms = []; + game.repairmen = []; game.blockedCells = new Set(); installInitialConveyorBackbone(game); game.facilities = defaultFacilities(); @@ -336,7 +336,7 @@ export function resetLayout(game) { // installed. The protected footprint includes every default conveyor segment, // scanner body/ports, farm output, and machine receiver. This guarantees that // the starter line is always continuous from Egg Farm -> S1 -> S2 -> exits even - // when roughly 20% of the map is blocked. + // when roughly 3% of the initial map is blocked. const reserved = protectedInitialCells(game); game.blockedCells = generateBlockedCells({ seed: game.runSeed, targetRatio: BALANCE.map.blockedRatio, reserved: [...reserved] }); scrubBlockedCellsFromInitialBackbone(game); diff --git a/src/core/text.js b/src/core/text.js index 065f9a3..fb14317 100644 --- a/src/core/text.js +++ b/src/core/text.js @@ -28,7 +28,6 @@ export const TEXT = { sorting: 'Sorting: use scanner keys. Build after clearing the day.', allPortsConnected: 'Start condition met: one EGG route reaches an exit.', equipmentPanelEmpty: 'Hover equipment in Build phase.', - eventPanelRunning: 'Forced events appear in Build phase.' }, routeLabels: { mixer: 'MIXER', @@ -71,7 +70,8 @@ export function buildToolFlavorText(id) { manualScanner: 'A manual checkpoint. The operator is the algorithm.', mixer: 'Male chicks become revenue here. Do not feed it poop.', trash: 'A polite shredder for poop and other regrets.', - truck: 'Ships the target cargo. Wrong cargo still leaves a paper trail.' + truck: 'Ships the target cargo. Wrong cargo still leaves a paper trail.', + maintenanceRoom: '2×2 repair bay. Each room dispatches one repairman during the day.' }; return flavors[id] || ''; } diff --git a/src/game.js b/src/game.js index de630df..254230d 100644 --- a/src/game.js +++ b/src/game.js @@ -13,7 +13,7 @@ import { createChickSystem } from './systems/chickSystem.js'; import { CARD_DEFS, cardById, conveyorSpeedForGame, createCardSystem, debugCardTargets, debugGrantCard } from './systems/cards.js'; import { floating, shockwave, sparkBurst, updateEffects } from './systems/effects.js'; import { rollEventOffer, activateEventOffer, clearActiveEvent, resolveEvent, eventDaySeconds, fairiesTributeMultiplierFromEvent } from './systems/events.js'; -import { ensureMaintenanceState, hireRepairmanForNextDay, activateRepairmanForDay, deactivateRepairman, conveyorSpeedFactorForKey } from './systems/maintenance.js'; +import { ensureMaintenanceState, activateRepairmanForDay, deactivateRepairman, conveyorSpeedFactorForKey } from './systems/maintenance.js'; const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); @@ -23,11 +23,10 @@ const ui = { money: document.getElementById('money'), turn: document.getElementById('turn'), timeLeft: document.getElementById('timeLeft'), phase: document.getElementById('phaseLabel'), comboCount: document.getElementById('comboCount'), eventBrief: document.getElementById('eventBrief'), targetBrief: document.getElementById('targetBrief'), speedBrief: document.getElementById('speedBrief'), turnProfit: document.getElementById('turnProfit'), mixerCount: document.getElementById('mixerCount'), truckFemaleCount: document.getElementById('truckFemaleCount'), truckMaleCount: document.getElementById('truckMaleCount'), poopCount: document.getElementById('poopCount'), - buildStatus: document.getElementById('buildStatus'), turnSummary: document.getElementById('turnSummary'), eventPanel: document.getElementById('eventPanel'), + buildStatus: document.getElementById('buildStatus'), turnSummary: document.getElementById('turnSummary'), modal: document.getElementById('modal'), modalTitle: document.getElementById('modalTitle'), modalBody: document.getElementById('modalBody'), modalActions: document.getElementById('modalActions'), hoverTooltip: document.getElementById('hoverTooltip'), manualScannerMonitor: document.getElementById('manualScannerMonitor'), - hireRepairmanButton: document.getElementById('hireRepairmanButton'), debug: { panel: document.getElementById('debugPanel'), infiniteCash: document.getElementById('debugInfiniteCash'), @@ -42,7 +41,7 @@ const ui = { }, buttons: { s1Left: document.getElementById('scanner1MixerButton'), s1Right: document.getElementById('scanner1TruckButton'), s2Left: document.getElementById('scanner2MixerButton'), s2Right: document.getElementById('scanner2TruckButton'), - nextTurn: document.getElementById('nextTurnButton'), conveyor: document.getElementById('buildConveyorButton'), boostConveyor: document.getElementById('buildBoostConveyorButton'), eggFarm: document.getElementById('buildEggFarmButton'), autoScanner: document.getElementById('buildAutoScannerButton'), manualScanner: document.getElementById('buildManualScannerButton'), mixer: document.getElementById('buildMixerButton'), trash: document.getElementById('buildTrashButton'), truck: document.getElementById('buildTruckButton'), erase: document.getElementById('eraseButton'), undo: document.getElementById('undoButton'), redo: document.getElementById('redoButton') + nextTurn: document.getElementById('nextTurnButton'), conveyor: document.getElementById('buildConveyorButton'), boostConveyor: document.getElementById('buildBoostConveyorButton'), eggFarm: document.getElementById('buildEggFarmButton'), autoScanner: document.getElementById('buildAutoScannerButton'), manualScanner: document.getElementById('buildManualScannerButton'), mixer: document.getElementById('buildMixerButton'), trash: document.getElementById('buildTrashButton'), truck: document.getElementById('buildTruckButton'), maintenanceRoom: document.getElementById('buildMaintenanceRoomButton'), erase: document.getElementById('eraseButton'), undo: document.getElementById('undoButton'), redo: document.getElementById('redoButton') } }; @@ -56,7 +55,8 @@ function initializeStaticText() { manualScanner: 'manualScanner', mixer: 'mixer', trash: 'trash', - truck: 'truck' + truck: 'truck', + maintenanceRoom: 'maintenanceRoom' }; for (const [buttonKey, toolId] of Object.entries(buttonToolMap)) { if (ui.buttons[buttonKey]) ui.buttons[buttonKey].innerHTML = buildToolButtonHtml(toolId); @@ -259,13 +259,10 @@ function startNextTurn() { resetCameraToFactoryStart(); game.stats = newTurnStats(); game.stats.fairiesTribute = game.lastStartFees?.fairiesTribute || 0; - game.stats.repairWorkerWages = game.pendingRepairWorkerWages || 0; - const carriedStartCosts = game.stats.fairiesTribute + game.stats.repairWorkerWages; - if (carriedStartCosts > 0) { - game.stats.penalty += carriedStartCosts; - game.stats.profit -= carriedStartCosts; + if (game.stats.fairiesTribute > 0) { + game.stats.penalty += game.stats.fairiesTribute; + game.stats.profit -= game.stats.fairiesTribute; } - game.pendingRepairWorkerWages = 0; for (const scanner of game.scanners) { scanner.queue = []; scanner.cooldown = 0; } for (const farm of game.eggFarms) { farm.nextSpawn = chicks.currentSpawnDelay(farm); farm.lastInterval = farm.nextSpawn; farm.shutterProgress = 0; farm.shutterSparked = false; } game.buildTool = null; @@ -279,19 +276,6 @@ function startNextTurn() { } -function hireRepairman() { - ensureMaintenanceState(game); - const result = hireRepairmanForNextDay(game); - if (!result.ok) { - floating(game, canvas.width / 2 - game.view.x, 96 - game.view.y, result.reason || 'Cannot hire repairman.', THEME.danger); - build?.fail?.(result.reason || 'Cannot hire repairman.'); - } else { - floating(game, canvas.width / 2 - game.view.x, 96 - game.view.y, `Repairman hired -${yen(result.cost)}`, THEME.green); - } - uiSystem.updatePanels(); - uiSystem.updateUI(); -} - function completeTurn() { if (game.phase !== 'running') return; const ship = settleTruckRevenue(game); @@ -713,8 +697,7 @@ document.addEventListener('pointerdown', event => { }, true); ui.buttons.s1Left.addEventListener('click', () => chicks.sortSlot(0, 'left')); ui.buttons.s1Right.addEventListener('click', () => chicks.sortSlot(0, 'right')); ui.buttons.s2Left.addEventListener('click', () => chicks.sortSlot(1, 'left')); ui.buttons.s2Right.addEventListener('click', () => chicks.sortSlot(1, 'right')); -ui.buttons.nextTurn.addEventListener('click', startNextTurn); ui.buttons.conveyor.addEventListener('click', () => build.setBuildTool('conveyor')); ui.buttons.boostConveyor.addEventListener('click', () => build.setBuildTool('boostConveyor')); ui.buttons.eggFarm.addEventListener('click', () => build.setBuildTool('eggFarm')); ui.buttons.autoScanner.addEventListener('click', () => build.setBuildTool('autoScanner')); ui.buttons.manualScanner.addEventListener('click', () => build.setBuildTool('manualScanner')); ui.buttons.mixer.addEventListener('click', () => build.setBuildTool('mixer')); ui.buttons.trash.addEventListener('click', () => build.setBuildTool('trash')); ui.buttons.truck.addEventListener('click', () => build.setBuildTool('truck')); ui.buttons.erase.addEventListener('click', () => build.setBuildTool('erase')); -ui.hireRepairmanButton?.addEventListener('click', hireRepairman); +ui.buttons.nextTurn.addEventListener('click', startNextTurn); ui.buttons.conveyor.addEventListener('click', () => build.setBuildTool('conveyor')); ui.buttons.boostConveyor.addEventListener('click', () => build.setBuildTool('boostConveyor')); ui.buttons.eggFarm.addEventListener('click', () => build.setBuildTool('eggFarm')); ui.buttons.autoScanner.addEventListener('click', () => build.setBuildTool('autoScanner')); ui.buttons.manualScanner.addEventListener('click', () => build.setBuildTool('manualScanner')); ui.buttons.mixer.addEventListener('click', () => build.setBuildTool('mixer')); ui.buttons.trash.addEventListener('click', () => build.setBuildTool('trash')); ui.buttons.truck.addEventListener('click', () => build.setBuildTool('truck')); ui.buttons.maintenanceRoom.addEventListener('click', () => build.setBuildTool('maintenanceRoom')); ui.buttons.erase.addEventListener('click', () => build.setBuildTool('erase')); ui.debug.setDay?.addEventListener('click', debugSetDay); ui.debug.zeroTimer?.addEventListener('click', debugZeroTimer); ui.debug.grantCard?.addEventListener('click', debugGrantSelectedCard); diff --git a/src/render/draw.js b/src/render/draw.js index 93a274d..dd7c62b 100644 --- a/src/render/draw.js +++ b/src/render/draw.js @@ -9,18 +9,36 @@ import { wearRatio } from '../systems/maintenance.js'; // Optional art overlay hook. // Keep external art probing disabled by default so a clean checkout does not emit 404s for missing PNGs. // To use replacement art, set ENABLE_EXTERNAL_ART_ASSETS to true and place files under assets/images/. -const ENABLE_EXTERNAL_ART_ASSETS = false; +const ENABLE_EXTERNAL_ART_ASSETS = true; const ASSET_PATHS = { + // User-supplied chick/poop assets remain optional. Facility/UI art is wired below. chickMale: './assets/images/chick_male.png', chickFemale: './assets/images/chick_female.png', - poop: new URL('../../assets/images/poop.png', import.meta.url).href, - conveyor: './assets/images/conveyor.png', - scannerManual: './assets/images/scanner_manual.png', - scannerAuto: './assets/images/scanner_auto.png', - eggFarm: './assets/images/egg_farm.png', - mixer: './assets/images/mixer.png', - shredder: './assets/images/shredder.png', - truck: './assets/images/truck.png' + poop: './assets/images/poop.png', + conveyorStraightH: './assets/dark_factory/facilities/conveyor/conveyor_straight_h_16.png', + conveyorStraightV: './assets/dark_factory/facilities/conveyor/conveyor_straight_v_16.png', + conveyorTurnNe: './assets/dark_factory/facilities/conveyor/conveyor_turn_ne_16.png', + conveyorTurnNw: './assets/dark_factory/facilities/conveyor/conveyor_turn_nw_16.png', + conveyorTurnSe: './assets/dark_factory/facilities/conveyor/conveyor_turn_se_16.png', + conveyorTurnSw: './assets/dark_factory/facilities/conveyor/conveyor_turn_sw_16.png', + boostConveyorStraightH: './assets/dark_factory/facilities/conveyor/boost_conveyor_straight_h_16.png', + boostConveyorStraightV: './assets/dark_factory/facilities/conveyor/boost_conveyor_straight_v_16.png', + boostConveyorTurnNe: './assets/dark_factory/facilities/conveyor/boost_conveyor_turn_ne_16.png', + boostConveyorTurnNw: './assets/dark_factory/facilities/conveyor/boost_conveyor_turn_nw_16.png', + boostConveyorTurnSe: './assets/dark_factory/facilities/conveyor/boost_conveyor_turn_se_16.png', + boostConveyorTurnSw: './assets/dark_factory/facilities/conveyor/boost_conveyor_turn_sw_16.png', + scannerManual: './assets/dark_factory/facilities/machines/manual_scanner_32x48.png', + scannerAuto: './assets/dark_factory/facilities/machines/auto_scanner_32x48.png', + eggFarm: './assets/dark_factory/facilities/machines/egg_farm_16.png', + mixer: './assets/dark_factory/facilities/machines/mixer_32.png', + shredder: './assets/dark_factory/facilities/machines/shredder_32.png', + truck: './assets/dark_factory/facilities/vehicles/truck_32.png', + mixerCompact: './assets/dark_factory/facilities/machines/mixer_compact_16.png', + shredderCompact: './assets/dark_factory/facilities/machines/shredder_compact_16.png', + truckCompact: './assets/dark_factory/facilities/vehicles/truck_compact_16.png', + maintenanceRoom: './assets/dark_factory/facilities/utility/maintenance_room_32.png', + repairman: './assets/dark_factory/facilities/utility/repairman_16.png', + obstacleCrate: './assets/dark_factory/facilities/utility/obstacle_crate_16.png' }; export const assets = {}; @@ -28,7 +46,7 @@ for (const [name, src] of Object.entries(ASSET_PATHS)) { const img = new Image(); img.loaded = false; img.onerror = () => { img.loaded = false; }; - if ((ENABLE_EXTERNAL_ART_ASSETS || name === 'poop') && src) { + if (ENABLE_EXTERNAL_ART_ASSETS && src) { img.onload = () => { img.loaded = true; }; img.src = src; } @@ -38,6 +56,7 @@ for (const [name, src] of Object.entries(ASSET_PATHS)) { // Each draw* function first checks whether an image loaded; if not, it falls back to simple canvas shapes. export function drawAll(ctx, canvas, game, helpers) { + ctx.imageSmoothingEnabled = false; ctx.clearRect(0, 0, canvas.width, canvas.height); drawBackground(ctx, canvas); ctx.save(); @@ -50,6 +69,7 @@ export function drawAll(ctx, canvas, game, helpers) { drawExpansionOffers(ctx, game); drawConveyors(ctx, game); drawScannerConnectors(ctx, game); + drawMaintenanceRooms(ctx, game); drawFacilities(ctx, game); drawEggFarms(ctx, game); drawScanners(ctx, game); @@ -108,17 +128,84 @@ function label(ctx, x, y, text, color = THEME.ink) { } function drawImageIfLoaded(ctx, image, x, y, w, h) { if (!image?.loaded) return false; - ctx.drawImage(image, x, y, w, h); + const previous = ctx.imageSmoothingEnabled; + ctx.imageSmoothingEnabled = false; + ctx.drawImage(image, Math.round(x), Math.round(y), Math.round(w), Math.round(h)); + ctx.imageSmoothingEnabled = previous; return true; } +function pixelRect(ctx, x, y, w, h, fill, stroke = null, lineWidth = 1) { + ctx.fillStyle = fill; + ctx.fillRect(Math.round(x), Math.round(y), Math.round(w), Math.round(h)); + if (stroke) { + ctx.strokeStyle = stroke; + ctx.lineWidth = lineWidth; + ctx.strokeRect(Math.round(x) + 0.5, Math.round(y) + 0.5, Math.round(w) - 1, Math.round(h) - 1); + } +} +function floorCellHash(col, row) { + let n = (Math.imul(col + 37, 73856093) ^ Math.imul(row + 71, 19349663)) >>> 0; + n ^= n >>> 13; + return n >>> 0; +} +function drawFloorSlime(ctx, x, y, col, row) { + const h = floorCellHash(col, row); + // Sparse, deterministic splashes: about 3% of owned floor cells. + if (h % 31 !== 0) return; + const ox = 10 + ((h >>> 4) % Math.max(1, GRID.cell - 22)); + const oy = 10 + ((h >>> 9) % Math.max(1, GRID.cell - 22)); + const angle = ((h >>> 14) % 16) * Math.PI / 16; + ctx.save(); + ctx.globalAlpha = 0.46; + ctx.fillStyle = '#4d9638'; + ctx.strokeStyle = 'rgba(30,66,27,.48)'; + ctx.lineWidth = 1; + + // Small irregular core rather than a large puddle. + ctx.beginPath(); + for (let i = 0; i < 8; i += 1) { + const a = angle + i * Math.PI / 4; + const r = 3.5 + ((h >>> (i + 2)) & 3); + const px = x + ox + Math.cos(a) * r * 1.35; + const py = y + oy + Math.sin(a) * r * .75; + if (i === 0) ctx.moveTo(px, py); else ctx.lineTo(px, py); + } + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + + // Several separated droplets produce a splattered silhouette. + const droplets = 3 + ((h >>> 24) % 4); + for (let i = 0; i < droplets; i += 1) { + const a = angle + i * 2.17 + ((h >>> (i + 8)) & 3) * .18; + const dist = 8 + ((h >>> (i + 11)) & 7); + const radius = 1.1 + ((h >>> (i + 17)) & 3) * .45; + ctx.beginPath(); + ctx.arc(x + ox + Math.cos(a) * dist, y + oy + Math.sin(a) * dist * .72, radius, 0, Math.PI * 2); + ctx.fill(); + } + ctx.fillStyle = 'rgba(151,218,101,.40)'; + ctx.beginPath(); + ctx.arc(x + ox - 2, y + oy - 2, 1.7, 0, Math.PI * 2); + ctx.fill(); + ctx.restore(); +} function drawBackground(ctx, canvas) { ctx.fillStyle = THEME.bg; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.save(); - ctx.strokeStyle = 'rgba(16, 32, 21, 0.035)'; + ctx.globalAlpha = 0.85; + for (let y = 0; y < canvas.height; y += 16) { + for (let x = 0; x < canvas.width; x += 16) { + const even = ((x / 16 + y / 16) | 0) % 2 === 0; + ctx.fillStyle = even ? '#181b20' : '#20242b'; + ctx.fillRect(x, y, 16, 16); + } + } + ctx.strokeStyle = 'rgba(255,184,39,.08)'; ctx.lineWidth = 1; - for (let x = 0; x < canvas.width; x += 32) { ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, canvas.height); ctx.stroke(); } - for (let y = 0; y < canvas.height; y += 32) { ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(canvas.width, y); ctx.stroke(); } + for (let x = 0; x < canvas.width; x += 64) { ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, canvas.height); ctx.stroke(); } + for (let y = 0; y < canvas.height; y += 64) { ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(canvas.width, y); ctx.stroke(); } ctx.restore(); } function ownedCellKeys(game) { @@ -131,15 +218,20 @@ function ownedCellKeys(game) { function drawGrid(ctx, game) { ctx.save(); const cells = ownedCellKeys(game); - ctx.fillStyle = 'rgba(255,255,255,.46)'; - ctx.strokeStyle = 'rgba(16,32,21,.055)'; - ctx.lineWidth = 1; for (const k of cells) { const p = parseKey(k); const c = cellCenter(p.col, p.row); - rect(ctx, c.x - GRID.cell / 2, c.y - GRID.cell / 2, GRID.cell, GRID.cell, true, true); + const x = c.x - GRID.cell / 2; + const y = c.y - GRID.cell / 2; + const tone = ((p.col + p.row) % 2 === 0) ? '#59616d' : '#505965'; + pixelRect(ctx, x, y, GRID.cell, GRID.cell, tone, 'rgba(190,199,210,.28)', 1); + ctx.fillStyle = 'rgba(255,255,255,.055)'; + ctx.fillRect(Math.round(x + 2), Math.round(y + 2), Math.round(GRID.cell - 4), 2); + ctx.fillStyle = 'rgba(0,0,0,.18)'; + ctx.fillRect(Math.round(x + 1), Math.round(y + GRID.cell - 3), Math.round(GRID.cell - 2), 2); + drawFloorSlime(ctx, x, y, p.col, p.row); } - ctx.strokeStyle = 'rgba(16,32,21,.16)'; + ctx.strokeStyle = 'rgba(255,184,39,.32)'; ctx.lineWidth = 3; for (const k of cells) { const p = parseKey(k); @@ -154,14 +246,41 @@ function drawGrid(ctx, game) { const p = parseKey(k); if (!isOwnedCell(game, p.col, p.row)) continue; const c = cellCenter(p.col, p.row); - ctx.fillStyle = 'rgba(16,32,21,.30)'; - ctx.strokeStyle = 'rgba(16,32,21,.60)'; + const x = c.x - GRID.cell / 2; + const y = c.y - GRID.cell / 2; + // Muted floor-level hazard striping. It remains readable without dominating machines. + ctx.save(); + ctx.beginPath(); + ctx.rect(Math.round(x + 1), Math.round(y + 1), GRID.cell - 2, GRID.cell - 2); + ctx.clip(); + ctx.fillStyle = 'rgba(42,45,48,.42)'; + ctx.fillRect(Math.round(x), Math.round(y), GRID.cell, GRID.cell); + ctx.lineWidth = 8; + ctx.strokeStyle = 'rgba(196,163,79,.38)'; + for (let stripe = -GRID.cell; stripe < GRID.cell * 2; stripe += 16) { + ctx.beginPath(); + ctx.moveTo(x + stripe, y + GRID.cell); + ctx.lineTo(x + stripe + GRID.cell, y); + ctx.stroke(); + } + ctx.lineWidth = 8; + ctx.strokeStyle = 'rgba(20,23,26,.32)'; + for (let stripe = -GRID.cell + 8; stripe < GRID.cell * 2; stripe += 16) { + ctx.beginPath(); + ctx.moveTo(x + stripe, y + GRID.cell); + ctx.lineTo(x + stripe + GRID.cell, y); + ctx.stroke(); + } + ctx.restore(); + ctx.strokeStyle = 'rgba(17,19,22,.72)'; ctx.lineWidth = 2; - rect(ctx, c.x - GRID.cell / 2 + 4, c.y - GRID.cell / 2 + 4, GRID.cell - 8, GRID.cell - 8, true, true); + ctx.strokeRect(Math.round(x) + 1, Math.round(y) + 1, GRID.cell - 2, GRID.cell - 2); + ctx.strokeStyle = 'rgba(224,194,112,.24)'; + ctx.lineWidth = 1; + ctx.strokeRect(Math.round(x) + 4, Math.round(y) + 4, GRID.cell - 8, GRID.cell - 8); } ctx.restore(); } - function drawExpansionOffers(ctx, game) { if (game.phase !== 'build' || game.cardDraft?.pending || game.cardTargetPick?.pending) return; const cost = expansionCost(game); @@ -220,6 +339,22 @@ function componentRatio(game, k) { const data = id ? game.congestion.get(id) : null; return data?.ratio || 0; } +function conveyorAssetForTile(game, k, meta = {}) { + const dirs = connectedConveyorDirs(game, k).sort(); + const boost = meta.kind === 'boostConveyor'; + const prefix = boost ? 'boostConveyor' : 'conveyor'; + const has = name => dirs.includes(name); + if (dirs.length === 2) { + if (has('left') && has('right')) return assets[`${prefix}StraightH`]; + if (has('up') && has('down')) return assets[`${prefix}StraightV`]; + if (has('up') && has('right')) return assets[`${prefix}TurnNe`]; + if (has('up') && has('left')) return assets[`${prefix}TurnNw`]; + if (has('down') && has('right')) return assets[`${prefix}TurnSe`]; + if (has('down') && has('left')) return assets[`${prefix}TurnSw`]; + } + if (dirs.length === 1) return has('up') || has('down') ? assets[`${prefix}StraightV`] : assets[`${prefix}StraightH`]; + return has('up') || has('down') ? assets[`${prefix}StraightV`] : assets[`${prefix}StraightH`]; +} function drawConveyors(ctx, game) { const edges = []; const seen = new Set(); @@ -239,9 +374,9 @@ function drawConveyors(ctx, game) { ctx.save(); ctx.lineCap = 'round'; ctx.lineJoin = 'round'; for (const layer of [ - { width: 33, color: THEME.ink, alpha: 1 }, - { width: 25, color: THEME.white, alpha: 1 }, - { width: 17, color: THEME.greenSoft, alpha: 1 } + { width: 31, color: '#0b0c0f', alpha: 1 }, + { width: 23, color: '#444b56', alpha: 1 }, + { width: 15, color: '#171a1f', alpha: 1 } ]) { ctx.globalAlpha = layer.alpha; ctx.strokeStyle = layer.color; ctx.lineWidth = layer.width; for (const e of edges) { ctx.beginPath(); ctx.moveTo(e.a.x, e.a.y); ctx.lineTo(e.b.x, e.b.y); ctx.stroke(); } @@ -258,27 +393,80 @@ function drawConveyors(ctx, game) { const c = cellCenter(...Object.values(parseKey(k))); const meta = game.conveyorMeta.get(k) || {}; const ratio = componentRatio(game, k); - const baseFill = meta.kind === 'boostConveyor' ? '#fff2b8' : THEME.white; - ctx.fillStyle = ratio > 0.5 ? mixHex(baseFill, '#ffd6d6', Math.max(0, (ratio - .5) / .5)) : baseFill; - ctx.strokeStyle = THEME.ink; ctx.lineWidth = 2; - rect(ctx, c.x - 8, c.y - 8, 16, 16, true, true); - if (meta.kind === 'boostConveyor') { - ctx.save(); - ctx.strokeStyle = THEME.warn; - ctx.lineWidth = 3; - ctx.beginPath(); ctx.moveTo(c.x - 15, c.y + 13); ctx.lineTo(c.x - 3, c.y - 13); ctx.lineTo(c.x + 2, c.y - 2); ctx.lineTo(c.x + 15, c.y - 13); ctx.stroke(); - ctx.restore(); + const sprite = conveyorAssetForTile(game, k, meta); + const congested = ratio > 0.5; + ctx.fillStyle = congested ? 'rgba(196,36,36,.28)' : 'rgba(0,0,0,.35)'; + ctx.strokeStyle = congested ? THEME.danger : 'rgba(255,184,39,.34)'; + ctx.lineWidth = congested ? 3 : 1; + rect(ctx, c.x - 20, c.y - 20, 40, 40, true, true); + if (!drawImageIfLoaded(ctx, sprite, c.x - 19, c.y - 19, 38, 38)) { + const baseFill = meta.kind === 'boostConveyor' ? '#315e92' : '#454b55'; + ctx.fillStyle = ratio > 0.5 ? mixHex(baseFill, '#a12c2c', Math.max(0, (ratio - .5) / .5)) : baseFill; + ctx.strokeStyle = THEME.ink; ctx.lineWidth = 2; + rect(ctx, c.x - 18, c.y - 18, 36, 36, true, true); } - drawDirtOverlay(ctx, c.x - 14, c.y - 14, 28, 28, { meta }); + drawAnimatedConveyorStripes(ctx, c, k, meta, ratio); + drawDirtOverlay(ctx, c.x - 18, c.y - 18, 36, 36, { meta }); drawSelection(ctx, game, 'conveyor', k, c.x, c.y, 38, 38); drawConveyorDirectionMarkers(ctx, c, directionMarkers.get(k) || []); const connectedDirs = connectedConveyorDirs(game, k); - drawBranchModeIcon(ctx, c, meta, branchSelectableEntranceDirs(game, k, connectedDirs), connectedDirs); + drawBranchModeIcon(ctx, c, meta, branchSelectableExitDirs(game, k, connectedDirs), connectedDirs); if (ratio > 0.5) label(ctx, c.x, c.y - 15, `${Math.floor(ratio * 100)}%`, THEME.danger); } ctx.restore(); } + +function drawAnimatedConveyorStripes(ctx, center, tileKey, meta = {}, ratio = 0) { + const names = [...new Set([...(Array.isArray(meta.outDirs) ? meta.outDirs : []), meta.dir].filter(Boolean))]; + const primary = names[0] || 'right'; + const verticalTravel = primary === 'up' || primary === 'down'; + const reverse = primary === 'left' || primary === 'up'; + const boost = meta.kind === 'boostConveyor'; + const t = typeof performance !== 'undefined' ? performance.now() / (boost ? 70 : 105) : 0; + const phase = ((reverse ? -t : t) % 10 + 10) % 10; + ctx.save(); + ctx.beginPath(); + ctx.rect(center.x - 18, center.y - 18, 36, 36); + ctx.clip(); + + // Blue-green rubber for boost belts; dark steel/rubber for standard belts. + const rubber = boost ? 'rgba(20,126,124,.62)' : 'rgba(42,47,54,.72)'; + ctx.fillStyle = rubber; + ctx.fillRect(center.x - 18, center.y - 18, 36, 36); + + // Slats are always perpendicular to travel and move in the travel direction. + ctx.strokeStyle = ratio > 0.5 ? 'rgba(238,83,61,.90)' : 'rgba(184,190,198,.92)'; + ctx.lineWidth = 4; + if (verticalTravel) { + for (let yy = center.y - 28 + phase; yy < center.y + 28; yy += 10) { + ctx.beginPath(); ctx.moveTo(center.x - 17, yy); ctx.lineTo(center.x + 17, yy); ctx.stroke(); + } + } else { + for (let xx = center.x - 28 + phase; xx < center.x + 28; xx += 10) { + ctx.beginPath(); ctx.moveTo(xx, center.y - 17); ctx.lineTo(xx, center.y + 17); ctx.stroke(); + } + } + + ctx.globalAlpha = 0.55; + ctx.strokeStyle = '#050609'; + ctx.lineWidth = 1; + if (verticalTravel) { + for (let yy = center.y - 23 + phase; yy < center.y + 28; yy += 10) { + ctx.beginPath(); ctx.moveTo(center.x - 17, yy); ctx.lineTo(center.x + 17, yy); ctx.stroke(); + } + } else { + for (let xx = center.x - 23 + phase; xx < center.x + 28; xx += 10) { + ctx.beginPath(); ctx.moveTo(xx, center.y - 17); ctx.lineTo(xx, center.y + 17); ctx.stroke(); + } + } + ctx.globalAlpha = 1; + ctx.strokeStyle = 'rgba(8,9,12,.92)'; + ctx.lineWidth = 2; + rect(ctx, center.x - 18, center.y - 18, 36, 36, false, true); + ctx.restore(); +} + function reachableConveyorDirs(game, k, meta) { const p = parseKey(k); const neighborNames = DIRS @@ -306,30 +494,27 @@ function neighborPointsIntoCell(game, p, dirName) { return names.includes(d.opposite); } -function branchExitDirs(game, k, dirs, connectedDirs = connectedConveyorDirs(game, k), branchMode = 'random') { +function branchExitCandidates(game, k, dirs, connectedDirs = connectedConveyorDirs(game, k)) { if (connectedDirs.length < 3) return dirs; const p = parseKey(k); - const entrances = new Set(connectedDirs.filter(dir => neighborPointsIntoCell(game, p, dir))); - if (branchMode && branchMode !== 'random' && connectedDirs.includes(branchMode)) { - const selectedEntrances = new Set(entrances); - selectedEntrances.add(branchMode); - if (connectedDirs.filter(dir => !selectedEntrances.has(dir)).length >= 2) entrances.add(branchMode); - } - const exits = connectedDirs.filter(dir => !entrances.has(dir)); - if (exits.length) return exits; - const fallback = dirs.filter(dir => !entrances.has(dir)); - return fallback.length ? fallback : dirs; + const physicalEntrances = new Set(connectedDirs.filter(dir => neighborPointsIntoCell(game, p, dir))); + const physicalExits = connectedDirs.filter(dir => !physicalEntrances.has(dir)); + if (physicalEntrances.size && physicalExits.length >= 2) return physicalExits; + const explicit = dirs.filter(dir => connectedDirs.includes(dir)); + if (explicit.length >= 2) return [...new Set(explicit)]; + return connectedDirs; } -function branchSelectableEntranceDirs(game, k, connectedDirs = connectedConveyorDirs(game, k)) { - if (connectedDirs.length < 3) return []; - const p = parseKey(k); - const physicalEntrances = new Set(connectedDirs.filter(dir => neighborPointsIntoCell(game, p, dir))); - return connectedDirs.filter(dir => { - const entrances = new Set(physicalEntrances); - entrances.add(dir); - return connectedDirs.filter(item => !entrances.has(item)).length >= 2; - }); +function branchExitDirs(game, k, dirs, connectedDirs = connectedConveyorDirs(game, k), branchMode = 'random') { + const candidates = branchExitCandidates(game, k, dirs, connectedDirs); + if (connectedDirs.length >= 3 && branchMode && branchMode !== 'random' && candidates.includes(branchMode)) return [branchMode]; + return candidates; +} + +function branchSelectableExitDirs(game, k, connectedDirs = connectedConveyorDirs(game, k)) { + const meta = game.conveyorMeta?.get?.(k) || {}; + const explicit = [...new Set([...(Array.isArray(meta.outDirs) ? meta.outDirs : []), meta.dir].filter(Boolean))]; + return connectedDirs.length < 3 ? [] : branchExitCandidates(game, k, explicit, connectedDirs); } function effectiveConveyorDirs(game, k, meta) { @@ -351,12 +536,13 @@ function drawBranchModeIcon(ctx, center, meta, dirs, connectedDirs = dirs) { ctx.lineJoin = 'round'; ctx.lineCap = 'round'; ctx.lineWidth = 2; - ctx.fillStyle = 'rgba(255,255,255,.9)'; + ctx.fillStyle = 'rgba(18,21,26,.94)'; ctx.strokeStyle = isFixed ? THEME.warn : THEME.green; - rect(ctx, center.x - 17, center.y - 17, 34, 34, true, true); - ctx.strokeStyle = THEME.ink; - ctx.lineWidth = 2; - ctx.fillStyle = THEME.ink; + ctx.lineWidth = 4; + rect(ctx, center.x - 18, center.y - 18, 36, 36, true, true); + ctx.strokeStyle = '#ffd36a'; + ctx.lineWidth = 3; + ctx.fillStyle = '#020304'; if (mode !== 'random') { const d = DIRS.find(item => item.name === mode); drawDirectionTriangle(ctx, center.x, center.y, d?.angle || 0, 9, 6); @@ -400,10 +586,14 @@ function drawConveyorDirectionMarkers(ctx, center, dirs) { const limited = dirs.slice(0, 4); if (!limited.length) return; ctx.save(); - ctx.fillStyle = THEME.ink; - ctx.globalAlpha = 0.86; + ctx.globalAlpha = 1; limited.forEach(d => { - drawDirectionTriangle(ctx, center.x + d.dc * 12, center.y + d.dr * 12, d.angle, 6, 5); + const x = center.x + d.dc * 11; + const y = center.y + d.dr * 11; + ctx.fillStyle = 'rgba(255,205,83,.96)'; + drawDirectionTriangle(ctx, x, y, d.angle, 9, 7); + ctx.fillStyle = '#020304'; + drawDirectionTriangle(ctx, x, y, d.angle, 6.5, 4.6); }); ctx.restore(); } @@ -413,6 +603,36 @@ function drawDirectionTriangle(ctx, x, y, angle, length = 11, halfWidth = 8) { ctx.beginPath(); ctx.moveTo(length, 0); ctx.lineTo(-length * 0.72, -halfWidth); ctx.lineTo(-length * 0.72, halfWidth); ctx.closePath(); ctx.fill(); ctx.restore(); } + +function drawScannerPortDuct(ctx, scanner, type, p, color) { + const c = scannerCenter(scanner); + let target = null; + if (type === 'inputA') target = { x: c.x, y: c.y - 67 }; + if (type === 'left') target = { x: c.x - 49, y: c.y + 14 }; + if (type === 'right') target = { x: c.x + 49, y: c.y + 14 }; + if (!target) return; + const elbow = type === 'inputA' + ? { x: p.x, y: target.y } + : { x: target.x, y: p.y }; + ctx.save(); + ctx.lineCap = 'square'; + ctx.lineJoin = 'bevel'; + ctx.strokeStyle = '#050609'; + ctx.lineWidth = 15; + ctx.beginPath(); ctx.moveTo(p.x, p.y); ctx.lineTo(elbow.x, elbow.y); ctx.lineTo(target.x, target.y); ctx.stroke(); + ctx.strokeStyle = '#596473'; + ctx.lineWidth = 9; + ctx.beginPath(); ctx.moveTo(p.x, p.y); ctx.lineTo(elbow.x, elbow.y); ctx.lineTo(target.x, target.y); ctx.stroke(); + ctx.strokeStyle = color || '#7b8795'; + ctx.lineWidth = 3; + ctx.beginPath(); ctx.moveTo(p.x, p.y); ctx.lineTo(elbow.x, elbow.y); ctx.lineTo(target.x, target.y); ctx.stroke(); + ctx.fillStyle = color || '#7b8795'; + ctx.strokeStyle = '#050609'; + ctx.lineWidth = 3; + rect(ctx, target.x - 9, target.y - 7, 18, 14, true, true); + ctx.restore(); +} + function drawScannerConnectors(ctx, game) { ctx.save(); ctx.lineWidth = 2; @@ -428,11 +648,12 @@ function drawScannerConnectors(ctx, game) { for (const item of items) { if (!item.p) continue; const p = cellCenter(item.p.col, item.p.row); + drawScannerPortDuct(ctx, scanner, item.type, p, item.color); const connected = scannerPortHasConveyor(game, scanner, item.type || (item.label === 'IN' ? 'inputA' : null)) || game.conveyorTiles.has(key(item.p.col, item.p.row)); - ctx.fillStyle = connected ? item.color : '#f4c2c2'; - ctx.strokeStyle = THEME.ink; + ctx.fillStyle = connected ? mixHex('#1a1d23', item.color, 0.24) : '#3a1e22'; + ctx.strokeStyle = connected ? item.color : THEME.danger; rect(ctx, p.x - 18, p.y - 12, 36, 24, true, true); - ctx.fillStyle = connected && item.color === THEME.white ? THEME.ink : THEME.white; + ctx.fillStyle = THEME.white; ctx.fillText(item.label, p.x, p.y + 4); } } @@ -598,7 +819,7 @@ function drawFacilityReceiver(ctx, game, facility) { const c = cellCenter(f.entry.col, f.entry.row); const info = receiverTitle(id, game); ctx.save(); - ctx.fillStyle = THEME.white; + ctx.fillStyle = '#191c22'; ctx.strokeStyle = info.color; ctx.lineWidth = 5; rect(ctx, c.x - 22, c.y - 22, 44, 44, true, true); @@ -612,6 +833,90 @@ function drawFacilityReceiver(ctx, game, facility) { ctx.fillText(info.title, c.x, c.y + 20); ctx.restore(); } + + +function drawMetalPanel(ctx, x, y, w, h, fill = '#252b34', stroke = '#08090c', accent = '#606a78') { + ctx.save(); + const g = ctx.createLinearGradient(x, y, x, y + h); + g.addColorStop(0, mixHex(fill, '#ffffff', 0.12)); + g.addColorStop(0.55, fill); + g.addColorStop(1, mixHex(fill, '#000000', 0.28)); + ctx.fillStyle = g; + ctx.strokeStyle = stroke; + ctx.lineWidth = 4; + rect(ctx, x, y, w, h, true, true); + ctx.fillStyle = 'rgba(255,255,255,.08)'; + ctx.fillRect(x + 5, y + 5, Math.max(0, w - 10), 3); + ctx.strokeStyle = 'rgba(0,0,0,.34)'; + ctx.lineWidth = 1; + for (let yy = y + 11; yy < y + h - 8; yy += 13) { ctx.beginPath(); ctx.moveTo(x + 6, yy); ctx.lineTo(x + w - 6, yy); ctx.stroke(); } + ctx.fillStyle = accent; + for (const [rx, ry] of [[x + 8, y + 8], [x + w - 8, y + 8], [x + 8, y + h - 8], [x + w - 8, y + h - 8]]) { + ctx.beginPath(); ctx.arc(rx, ry, 2.2, 0, Math.PI * 2); ctx.fill(); + } + ctx.restore(); +} + +function drawFacilityDetails(ctx, f, accent = THEME.green) { + ctx.save(); + ctx.strokeStyle = '#06070a'; ctx.lineWidth = 4; + ctx.beginPath(); ctx.moveTo(f.x + 12, f.y + f.h - 18); ctx.lineTo(f.x + f.w - 12, f.y + f.h - 18); ctx.stroke(); + ctx.strokeStyle = accent; ctx.lineWidth = 2; + ctx.beginPath(); ctx.moveTo(f.x + 16, f.y + 22); ctx.lineTo(f.x + f.w - 18, f.y + 22); ctx.stroke(); + ctx.fillStyle = '#20242b'; ctx.strokeStyle = '#07080a'; ctx.lineWidth = 2; + rect(ctx, f.x + f.w - 44, f.y + 12, 30, 22, true, true); + ctx.fillStyle = accent; ctx.fillRect(f.x + f.w - 38, f.y + 18, 6, 6); + ctx.fillStyle = THEME.danger; ctx.fillRect(f.x + f.w - 27, f.y + 18, 6, 6); + ctx.strokeStyle = '#47515f'; ctx.lineWidth = 3; + ctx.beginPath(); ctx.moveTo(f.x + 12, f.y + f.h - 35); ctx.bezierCurveTo(f.x + 42, f.y + f.h - 52, f.x + 60, f.y + f.h - 20, f.x + 88, f.y + f.h - 38); ctx.stroke(); + ctx.restore(); +} + +function drawFacilityTexture(ctx, image, f, maxCells = 1.45) { + if (!image?.loaded) return false; + // Keep external-machine sprites at roughly the same pixel density as a grid object. + const maxSize = GRID.cell * Math.min(1.45, maxCells); + const size = Math.max(42, Math.min(maxSize, f.w - 34, f.h - 42)); + const x = f.x + Math.round((f.w - size) / 2); + const y = f.y + Math.round((f.h - size) / 2) + 2; + return drawImageIfLoaded(ctx, image, x, y, size, size); +} + +function roomBounds(room) { + const first = cellCenter(room.col, room.row); + return { x: first.x - GRID.cell / 2, y: first.y - GRID.cell / 2, w: GRID.cell * 2, h: GRID.cell * 2, cx: first.x + GRID.cell / 2, cy: first.y + GRID.cell / 2 }; +} +function drawMaintenanceRooms(ctx, game) { + for (const room of game.maintenanceRooms || []) { + const b = roomBounds(room); + ctx.save(); + drawMetalPanel(ctx, b.x + 2, b.y + 2, b.w - 4, b.h - 4, '#343b45', '#0a0b0e', '#7a6750'); + if (!drawImageIfLoaded(ctx, assets.maintenanceRoom, b.x + 5, b.y + 5, b.w - 10, b.h - 10)) { + ctx.fillStyle = '#414a55'; ctx.strokeStyle = THEME.ink; ctx.lineWidth = 3; + rect(ctx, b.x + 8, b.y + 8, b.w - 16, b.h - 16, true, true); + // Storage shelves, spare-parts crates, a workbench, lockers and a small break stool. + ctx.fillStyle = '#6e573e'; ctx.strokeStyle = '#111318'; ctx.lineWidth = 2; + rect(ctx, b.x + 13, b.y + 14, 24, 51, true, true); + ctx.strokeStyle = '#b58a52'; + for (const yy of [b.y + 29, b.y + 44, b.y + 59]) { ctx.beginPath(); ctx.moveTo(b.x + 14, yy); ctx.lineTo(b.x + 36, yy); ctx.stroke(); } + ctx.fillStyle = '#515b68'; ctx.strokeStyle = '#111318'; + rect(ctx, b.x + b.w - 34, b.y + 13, 20, 43, true, true); + ctx.fillStyle = '#d49d28'; ctx.fillRect(b.x + b.w - 21, b.y + 32, 3, 3); + ctx.fillStyle = '#735431'; ctx.strokeStyle = '#111318'; + rect(ctx, b.x + 41, b.y + b.h - 31, 34, 14, true, true); + ctx.fillStyle = '#1b2027'; ctx.fillRect(b.x + 46, b.y + b.h - 39, 24, 8); + ctx.fillStyle = '#7b8795'; ctx.fillRect(b.x + 51, b.y + b.h - 37, 4, 5); + ctx.fillStyle = '#805b35'; ctx.strokeStyle = '#111318'; + rect(ctx, b.x + b.w - 32, b.y + b.h - 28, 16, 12, true, true); + ctx.fillStyle = '#222831'; ctx.beginPath(); ctx.arc(b.x + b.w - 46, b.y + b.h - 20, 7, 0, Math.PI * 2); ctx.fill(); + ctx.fillStyle = '#ddd0ad'; ctx.font = '900 8px ui-monospace, monospace'; ctx.textAlign = 'center'; ctx.fillText('STORE / REST', b.cx, b.y + 11); + } + drawDirtOverlay(ctx, b.x + 5, b.y + 5, b.w - 10, b.h - 10, room); + drawSelection(ctx, game, 'maintenanceRoom', room.id, b.cx, b.cy, b.w + 6, b.h + 6); + ctx.restore(); + } +} + function drawFacilities(ctx, game) { for (const f of Object.values(game.facilities || {})) { const kind = facilityKind(f); @@ -630,24 +935,29 @@ function drawExternalDuct(ctx, f) { else if (f.side === 'top') { bx = c.x; by = f.y + f.h; } else if (f.side === 'bottom') { bx = c.x; by = f.y; } ctx.save(); - ctx.strokeStyle = THEME.ink; - ctx.lineWidth = 9; + ctx.strokeStyle = '#07080a'; + ctx.lineWidth = 11; ctx.lineCap = 'round'; ctx.beginPath(); ctx.moveTo(c.x, c.y); ctx.lineTo(bx, by); ctx.stroke(); - ctx.strokeStyle = THEME.white; ctx.lineWidth = 5; + ctx.strokeStyle = '#555f70'; ctx.lineWidth = 5; ctx.beginPath(); ctx.moveTo(c.x, c.y); ctx.lineTo(bx, by); ctx.stroke(); ctx.restore(); } function drawMixer(ctx, game, m = game.facilities.mixer) { ctx.save(); drawExternalDuct(ctx, m); - if (drawImageIfLoaded(ctx, assets.mixer, m.x, m.y, m.w, m.h)) { drawDirtOverlay(ctx, m.x, m.y, m.w, m.h, m); drawSelection(ctx, game, 'facility', m.id, m.x + m.w / 2, m.y + m.h / 2, m.w + 12, m.h + 12); ctx.restore(); return; } - ctx.fillStyle = THEME.white; ctx.strokeStyle = THEME.ink; ctx.lineWidth = 4; rect(ctx, m.x, m.y, m.w, m.h, true, true); - ctx.fillStyle = THEME.ink; ctx.font = '900 19px ui-monospace, monospace'; ctx.textAlign = 'center'; ctx.fillText(`MIXER L${m.level}`, m.x + m.w / 2, m.y + 28); - ctx.font = '900 12px ui-monospace, monospace'; ctx.fillText(`PAY ${yen(upgradedMixerPrice(game))}`, m.x + m.w / 2, m.y + 48); + drawMetalPanel(ctx, m.x, m.y, m.w, m.h, '#2b333d', THEME.ink, THEME.mixerBlue); + drawFacilityDetails(ctx, m, THEME.mixerBlue); + ctx.fillStyle = THEME.white; ctx.font = '900 14px ui-monospace, monospace'; ctx.textAlign = 'left'; + ctx.fillText(`MIXER L${m.level}`, m.x + 14, m.y + 18); + ctx.fillStyle = THEME.muted; ctx.font = '900 10px ui-monospace, monospace'; + ctx.fillText(`PAY ${yen(upgradedMixerPrice(game))}`, m.x + 14, m.y + 34); + const drew = drawFacilityTexture(ctx, assets.mixerCompact.loaded ? assets.mixerCompact : assets.mixer, m, 2.05); + if (!drew) { + ctx.strokeStyle = THEME.green; ctx.lineWidth = 5; + for (let i = 0; i < 3; i += 1) { ctx.beginPath(); ctx.arc(m.x + m.w / 2, m.y + m.h / 2 + 6, 11 + i * 8, 0, Math.PI * 1.5); ctx.stroke(); } + } drawTargetBadge(ctx, m.x + 14, m.y + m.h - 40, m.w - 28, 'SEND MALE', 'male', 'safe meat route'); - ctx.strokeStyle = THEME.green; ctx.lineWidth = 5; - for (let i = 0; i < 3; i += 1) { ctx.beginPath(); ctx.arc(m.x + m.w / 2, m.y + 78, 16 + i * 8, 0, Math.PI * 1.5); ctx.stroke(); } drawDirtOverlay(ctx, m.x, m.y, m.w, m.h, m); drawSelection(ctx, game, 'facility', m.id, m.x + m.w / 2, m.y + m.h / 2, m.w + 12, m.h + 12); ctx.restore(); @@ -655,10 +965,15 @@ function drawMixer(ctx, game, m = game.facilities.mixer) { function drawTrash(ctx, game, t = game.facilities.trash) { ctx.save(); drawExternalDuct(ctx, t); - if (drawImageIfLoaded(ctx, assets.shredder, t.x, t.y, t.w, t.h)) { drawDirtOverlay(ctx, t.x, t.y, t.w, t.h, t); drawSelection(ctx, game, 'facility', t.id, t.x + t.w / 2, t.y + t.h / 2, t.w + 12, t.h + 12); ctx.restore(); return; } - ctx.fillStyle = THEME.white; ctx.strokeStyle = THEME.ink; ctx.lineWidth = 4; rect(ctx, t.x, t.y, t.w, t.h, true, true); - ctx.fillStyle = THEME.ink; ctx.font = '900 19px ui-monospace, monospace'; ctx.textAlign = 'center'; ctx.fillText(`SHREDDER L${t.level}`, t.x + t.w / 2, t.y + 25); - for (let i = 0; i < 7; i += 1) { ctx.fillRect(t.x + 34 + i * 16, t.y + 48, 7, t.h - 66); } + drawMetalPanel(ctx, t.x, t.y, t.w, t.h, '#29342d', THEME.ink, THEME.wasteGreen); + drawFacilityDetails(ctx, t, THEME.wasteGreen); + ctx.fillStyle = THEME.white; ctx.font = '900 14px ui-monospace, monospace'; ctx.textAlign = 'left'; + ctx.fillText(`SHREDDER L${t.level}`, t.x + 14, t.y + 18); + const drew = drawFacilityTexture(ctx, assets.shredderCompact.loaded ? assets.shredderCompact : assets.shredder, t, 1.85); + if (!drew) { + ctx.fillStyle = '#0a0b0e'; + for (let i = 0; i < 7; i += 1) ctx.fillRect(t.x + 40 + i * 12, t.y + 42, 6, Math.max(20, t.h - 72)); + } drawTargetBadge(ctx, t.x + 14, t.y + t.h - 42, t.w - 28, 'SEND POOP', 'poop', 'shredder'); drawDirtOverlay(ctx, t.x, t.y, t.w, t.h, t); drawSelection(ctx, game, 'facility', t.id, t.x + t.w / 2, t.y + t.h / 2, t.w + 12, t.h + 12); @@ -667,14 +982,18 @@ function drawTrash(ctx, game, t = game.facilities.trash) { function drawTruck(ctx, game, t = game.facilities.truck) { ctx.save(); drawExternalDuct(ctx, t); - if (drawImageIfLoaded(ctx, assets.truck, t.x, t.y, t.w, t.h)) { drawSelection(ctx, game, 'facility', t.id, t.x + t.w / 2, t.y + t.h / 2, t.w + 12, t.h + 12); ctx.restore(); return; } - ctx.fillStyle = THEME.white; ctx.strokeStyle = THEME.ink; ctx.lineWidth = 4; rect(ctx, t.x, t.y, t.w, t.h, true, true); - ctx.fillStyle = THEME.ink; ctx.font = '900 19px ui-monospace, monospace'; ctx.textAlign = 'center'; ctx.fillText(`TRUCK L${t.level}`, t.x + t.w / 2, t.y + 24); - ctx.font = '900 11px ui-monospace, monospace'; ctx.fillText(`UNIT ${yen(upgradedTruckPrice(game))}`, t.x + t.w / 2, t.y + 42); + drawMetalPanel(ctx, t.x, t.y, t.w, t.h, '#343128', THEME.ink, THEME.truckPink); + drawFacilityDetails(ctx, t, THEME.truckPink); + ctx.fillStyle = THEME.white; ctx.font = '900 14px ui-monospace, monospace'; ctx.textAlign = 'left'; + ctx.fillText(`TRUCK L${t.level}`, t.x + 14, t.y + 18); + ctx.fillStyle = THEME.muted; ctx.font = '900 10px ui-monospace, monospace'; + ctx.fillText(`UNIT ${yen(upgradedTruckPrice(game))}`, t.x + 14, t.y + 34); + drawFacilityTexture(ctx, assets.truckCompact.loaded ? assets.truckCompact : assets.truck, t, 2.0); const truckTargetType = targetForTruck(game); drawTargetBadge(ctx, t.x + 15, t.y + 50, t.w - 30, `SEND ${truckTargetType.toUpperCase()}`, truckTargetType, game.eventOffer && !game.eventActive ? 'next event' : 'truck cargo'); - ctx.fillStyle = THEME.greenSoft; rect(ctx, t.x + 13, t.y + 88, t.w - 26, t.h - 103, true, false); + ctx.fillStyle = 'rgba(39,60,36,.9)'; rect(ctx, t.x + 13, t.y + 88, t.w - 26, Math.max(18, t.h - 103), true, false); for (const cargo of game.truckCargo) cargo.sex === 'poop' ? drawTinyPoop(ctx, t.x + cargo.x, t.y + cargo.y) : drawTinyChick(ctx, t.x + cargo.x, t.y + cargo.y, cargo.sex, cargo.sex === 'male'); + drawDirtOverlay(ctx, t.x, t.y, t.w, t.h, t); drawSelection(ctx, game, 'facility', t.id, t.x + t.w / 2, t.y + t.h / 2, t.w + 12, t.h + 12); ctx.restore(); } @@ -695,13 +1014,32 @@ function drawChick(ctx, chick, active, game) { if (chick.sex === 'poop') drawPoop(ctx, chick.x, y, chick.radius); else { const img = chick.sex === 'male' ? assets.chickMale : assets.chickFemale; - if (!drawImageIfLoaded(ctx, img, chick.x - chick.radius, y - chick.radius, chick.radius * 2, chick.radius * 2)) { - ctx.fillStyle = chick.sex === 'male' ? THEME.male : THEME.female; + const spriteDrawn = drawImageIfLoaded(ctx, img, chick.x - chick.radius, y - chick.radius, chick.radius * 2, chick.radius * 2); + if (!spriteDrawn) { + const bodyColor = chick.sex === 'male' ? THEME.male : THEME.female; + const accent = chick.sex === 'male' ? '#164f8f' : '#8b2252'; + ctx.fillStyle = bodyColor; ctx.strokeStyle = THEME.ink; ctx.lineWidth = 5; ctx.beginPath(); ctx.arc(chick.x, y, chick.radius, 0, Math.PI * 2); ctx.fill(); ctx.stroke(); + ctx.fillStyle = 'rgba(255,255,255,.24)'; ctx.beginPath(); ctx.arc(chick.x - 5, y - 7, chick.radius * .36, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = THEME.ink; ctx.beginPath(); ctx.arc(chick.x - 6, y - 5, 2.5, 0, Math.PI * 2); ctx.arc(chick.x + 6, y - 5, 2.5, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = '#ffaa2e'; ctx.beginPath(); ctx.moveTo(chick.x, y + 2); ctx.lineTo(chick.x + 9, y + 6); ctx.lineTo(chick.x, y + 10); ctx.closePath(); ctx.fill(); + ctx.strokeStyle = accent; ctx.lineWidth = 3; + if (chick.sex === 'male') { + ctx.beginPath(); ctx.moveTo(chick.x - 8, y - chick.radius - 2); ctx.lineTo(chick.x + 8, y - chick.radius - 2); ctx.stroke(); + } else { + ctx.beginPath(); ctx.moveTo(chick.x - 9, y - chick.radius + 2); ctx.lineTo(chick.x, y - chick.radius - 6); ctx.lineTo(chick.x + 9, y - chick.radius + 2); ctx.stroke(); + } } + // Symbols remain legible even when custom sprites are replaced. + ctx.fillStyle = chick.sex === 'male' ? '#dff1ff' : '#fff0f7'; + ctx.strokeStyle = '#050609'; + ctx.lineWidth = 3; + ctx.font = `900 ${Math.max(10, Math.round(chick.radius * .72))}px ui-monospace, monospace`; + ctx.textAlign = 'center'; + const sexMark = chick.sex === 'male' ? '♂' : '♀'; + ctx.strokeText(sexMark, chick.x + chick.radius * .54, y + chick.radius * .70); + ctx.fillText(sexMark, chick.x + chick.radius * .54, y + chick.radius * .70); } ctx.restore(); } @@ -721,8 +1059,14 @@ function drawPoop(ctx, x, y, radius) { } function drawTinyPoop(ctx, x, y) { drawPoop(ctx, x, y, 7); } function drawTinyChick(ctx, x, y, sex, warning = false) { - ctx.save(); ctx.fillStyle = sex === 'male' ? THEME.male : THEME.female; ctx.strokeStyle = THEME.ink; ctx.lineWidth = 2; + ctx.save(); + const bodyColor = sex === 'male' ? THEME.male : THEME.female; + const accent = sex === 'male' ? '#164f8f' : '#8b2252'; + ctx.fillStyle = bodyColor; ctx.strokeStyle = THEME.ink; ctx.lineWidth = 2; ctx.beginPath(); ctx.arc(x, y, 7, 0, Math.PI * 2); ctx.fill(); ctx.stroke(); + ctx.strokeStyle = accent; ctx.lineWidth = 2; + if (sex === 'male') { ctx.beginPath(); ctx.moveTo(x - 4, y - 8); ctx.lineTo(x + 4, y - 8); ctx.stroke(); } + else { ctx.beginPath(); ctx.moveTo(x - 5, y - 7); ctx.lineTo(x, y - 11); ctx.lineTo(x + 5, y - 7); ctx.stroke(); } if (warning) { ctx.fillStyle = THEME.danger; ctx.font = '900 12px ui-monospace, monospace'; ctx.textAlign = 'center'; ctx.fillText('!', x, y + 15); } ctx.restore(); } @@ -784,9 +1128,12 @@ function drawCardTargetOverlay(ctx, canvas, game) { ctx.strokeStyle = THEME.ink; ctx.lineWidth = 3; const remaining = Math.max(1, game.cardTargetPick?.remaining || 1); + const dynamiteUsed = Math.max(0, game.cardTargetPick?.used || 0); const msg = game.cardTargetPick?.mode === 'autoScannerMenu' ? 'AUTO SCANNER ROUTE SETTINGS. CLICK EMPTY AREA TO CLOSE.' - : isBlockedCellMode ? `CLICK BLOCKED CELL: ${remaining} LEFT. PRESS ESC TO CANCEL.` : 'CLICK AN UPGRADEABLE MACHINE. PRESS ESC TO CANCEL.'; + : isBlockedCellMode + ? `DYNAMITE: CLICK ANY BLOCKED TILE (${remaining} LEFT). ESC ${dynamiteUsed > 0 ? 'FINISHES' : 'CANCELS'}.` + : 'CLICK AN UPGRADEABLE MACHINE. PRESS ESC TO CANCEL.'; rect(ctx, (216 - (game.view?.x || 0)) / scale, (96 - (game.view?.y || 0)) / scale, 560 / scale, 42 / scale, true, true); ctx.fillStyle = THEME.ink; ctx.font = '900 12px ui-monospace, monospace'; @@ -835,10 +1182,19 @@ function drawFloatingTexts(ctx, game) { } function drawRepairman(ctx, game) { - const r = game.repairman; - const visible = !!r?.active || (game.phase === 'build' && !!r?.hiredForNextDay); + const list = (game.repairmen && game.repairmen.length) ? game.repairmen : (game.repairman ? [game.repairman] : []); + for (const r of list) drawSingleRepairman(ctx, game, r); +} + +function drawSingleRepairman(ctx, game, r) { + const visible = !!r?.active; if (!visible) return; ctx.save(); + if (drawImageIfLoaded(ctx, assets.repairman, r.x - 18, r.y - 18, 36, 36)) { + if (r.target?.label) label(ctx, r.x, r.y - 24, r.target.label, THEME.green); + ctx.restore(); + return; + } ctx.lineWidth = 3; ctx.fillStyle = '#fff0d1'; ctx.strokeStyle = THEME.ink; @@ -862,19 +1218,15 @@ function drawRepairman(ctx, game) { ctx.fillStyle = THEME.ink; ctx.font = '900 11px ui-monospace, monospace'; ctx.textAlign = 'center'; - ctx.fillText(r.active ? 'FIX' : 'HIRED', r.x, r.y + 33); + ctx.fillText('FIX', r.x, r.y + 33); if (r.target?.label) label(ctx, r.x, r.y - 24, r.target.label, THEME.green); - else if (!r.active && r.hiredForNextDay) label(ctx, r.x, r.y - 24, 'NEXT DAY', THEME.green); ctx.restore(); } + function drawCanvasHints(ctx, game, canvas) { ctx.save(); ctx.font = '900 19px ui-monospace, monospace'; ctx.textAlign = 'left'; ctx.fillStyle = THEME.ink; - // Visible version marker helps avoid browser/file-cache confusion when testing zips. - ctx.fillStyle = 'rgba(255,255,255,.92)'; ctx.strokeStyle = THEME.ink; ctx.lineWidth = 3; - rect(ctx, canvas.width - 284, 18, 260, 34, true, true); - ctx.fillStyle = THEME.green; ctx.font = '900 12px ui-monospace, monospace'; ctx.fillText(VERSION, canvas.width - 270, 40); ctx.font = '900 19px ui-monospace, monospace'; ctx.fillStyle = THEME.ink; const lines = []; if (game.phase === 'running') lines.push(game.timeLeft <= 0 ? 'TIME UP: FARMS SHUT. CLEAR LINE.' : 'A/D: S1 ←/→: S2'); diff --git a/src/systems/buildSystem.js b/src/systems/buildSystem.js index c10bc6f..6a94566 100644 --- a/src/systems/buildSystem.js +++ b/src/systems/buildSystem.js @@ -1,8 +1,8 @@ import { BALANCE } from '../core/balance.js'; import { DIRS, MACHINE_FACILITY_IDS, GRID, THEME } from '../core/config.js'; import { getSpawnRange } from '../core/state.js'; -import { createEggFarm, createScanner, createFacility } from '../core/entities.js'; -import { generateBlockedCellsInRect } from '../core/mapGen.js'; +import { createEggFarm, createScanner, createFacility, createMaintenanceRoom, maintenanceRoomFootprint } from '../core/entities.js'; +import { generateBlockedCellsInRect, blockedRatioForExpansionPurchase } from '../core/mapGen.js'; import { expansionCost, expansionLot, expansionLots, lotFromChunk, lotBounds, lotContainsPoint, cellsInLot, isOwnedCell, countOwnedCells, shiftRowIndexedSet, shiftRowIndexedMap, ownChunk } from '../core/gridExpansion.js'; import { key, parseKey, pointToCell, cellCenter, yen, directionNameBetweenCells } from '../core/utils.js'; import { TEXT, equipmentName } from '../core/text.js'; @@ -92,13 +92,18 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel game.gridExpansionPurchases = (game.gridExpansionPurchases || 0) + 1; game.gridExpansionPurchasesByDirection[direction] = (game.gridExpansionPurchasesByDirection[direction] || 0) + 1; syncGridSizeToGame(); + const blockedRatio = blockedRatioForExpansionPurchase(game.gridExpansionPurchases, { + base: BALANCE.map.blockedRatio ?? 0.03, + increment: BALANCE.map.blockedExpansionIncrement ?? 0.005, + max: BALANCE.map.blockedRatioMax ?? 0.10 + }); const blocked = generateBlockedCellsInRect({ seed: `${game.runSeed}:grid-expansion:${lot.chunkX},${lot.chunkY}:${game.gridExpansionPurchases}`, colStart: lot.colStart, colEnd: lot.colStart + lot.cols, rowStart: lot.rowStart, rowEnd: lot.rowStart + lot.rows, - targetRatio: BALANCE.map.blockedRatio + targetRatio: blockedRatio }); for (const k of blocked) game.blockedCells.add(k); refreshRoutingAfterEdit(game); @@ -106,7 +111,7 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel const b = lotBounds(lot); floating(game, b.x + b.w / 2, b.y + b.h / 2, `${direction.toUpperCase()} +${addedCells} CELLS -${yen(cost)}`, THEME.green); updatePanels(); - return { ok: true, direction, cost, addedCells, blocked: blocked.size, chunkX: lot.chunkX, chunkY: lot.chunkY }; + return { ok: true, direction, cost, addedCells, blocked: blocked.size, blockedRatio, chunkX: lot.chunkX, chunkY: lot.chunkY }; } function pointInGrid(col, row) { return col >= 0 && col < GRID.cols && row >= 0 && row < GRID.rows && isOwnedCell(game, col, row); } @@ -129,10 +134,32 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel if (existingFarm && !(moving?.type === 'eggFarm' && moving.ref?.id === existingFarm.id)) return true; const existingScanner = scannerAt(game, col, row); if (existingScanner && !(moving?.type === 'scanner' && moving.ref?.id === existingScanner.id)) return true; + const existingRoom = maintenanceRoomAt(game, col, row); + if (existingRoom && !(moving?.type === 'maintenanceRoom' && moving.ref?.id === existingRoom.id)) return true; if (game.conveyorTiles.has(k) && !(moving?.type === 'conveyor' && moving.oldKey === k)) return true; return false; } + function maintenanceRoomAt(gameRef, col, row) { + return (gameRef.maintenanceRooms || []).find(room => maintenanceRoomFootprint(room).some(cell => cell.col === col && cell.row === row)) || null; + } + + function maintenanceRoomPlacementBlocked(col, row, moving = null) { + const draft = { col, row }; + for (const cell of maintenanceRoomFootprint(draft)) { + if (!pointInGrid(cell.col, cell.row) || isBlockedCell(cell.col, cell.row)) return true; + const k = key(cell.col, cell.row); + const existingFarm = farmAt(game, cell.col, cell.row); + if (existingFarm) return true; + const existingScanner = scannerAt(game, cell.col, cell.row); + if (existingScanner) return true; + const existingRoom = maintenanceRoomAt(game, cell.col, cell.row); + if (existingRoom && !(moving?.type === 'maintenanceRoom' && moving.ref?.id === existingRoom.id)) return true; + if (game.conveyorTiles.has(k)) return true; + } + return false; + } + function scannerPlacementBlocked(col, row, moving = null) { const draft = { col, row }; for (const cell of scannerFootprintCells(draft)) { @@ -153,6 +180,7 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel if (game.selected.type === 'scanner') return game.scanners.find(s => s.id === game.selected.id) || null; if (game.selected.type === 'conveyor') return game.conveyorTiles.has(game.selected.id) ? { type: 'conveyor', id: game.selected.id } : null; if (game.selected.type === 'facility') return game.facilities[game.selected.id] || null; + if (game.selected.type === 'maintenanceRoom') return (game.maintenanceRooms || []).find(r => r.id === game.selected.id) || null; return null; } @@ -162,6 +190,7 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel if (obj.type === 'scanner') return `${obj.kind === 'auto' ? equipmentName('autoScanner') : equipmentName('manualScanner')} #${obj.id}`; if (obj.type === 'conveyor') return game.conveyorMeta.get(obj.id)?.kind === 'boostConveyor' ? equipmentName('boostConveyor') : equipmentName('conveyor'); if (obj.type === 'facility') return obj.name; + if (obj.type === 'maintenanceRoom') return `${equipmentName('maintenanceRoom')} #${obj.id}`; return 'Equipment'; } @@ -266,16 +295,18 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel return connected; } - function branchSelectableEntranceDirsForKey(k) { + function branchSelectableExitDirsForKey(k) { const cell = parseKey(k); const connected = branchExitDirsForKey(k); if (connected.length < 3) return []; + const meta = game.conveyorMeta.get(k) || {}; const physicalEntrances = new Set(connected.filter(dir => neighborPointsIntoCell(cell, dir))); - return connected.filter(dir => { - const entrances = new Set(physicalEntrances); - entrances.add(dir); - return connected.filter(item => !entrances.has(item)).length >= 2; - }); + const physicalExits = connected.filter(dir => !physicalEntrances.has(dir)); + if (physicalEntrances.size && physicalExits.length >= 2) return physicalExits; + const explicit = [...new Set([...(Array.isArray(meta.outDirs) ? meta.outDirs : []), meta.dir].filter(Boolean))] + .filter(dir => connected.includes(dir)); + if (explicit.length >= 2) return explicit; + return connected; } function markConveyorDirection(from, to) { @@ -502,6 +533,10 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel return; } if (isBlockedCell(col, row)) return fail('Cannot build on blocked ground.'); + if (game.buildTool === 'maintenanceRoom') { + if (maintenanceRoomPlacementBlocked(col, row)) return fail(TEXT.fail.cellOccupied); + return buildMaintenanceRoom(col, row); + } if ((game.buildTool === 'manualScanner' || game.buildTool === 'autoScanner') ? scannerPlacementBlocked(col, row) : isEquipmentCell(col, row)) return fail(TEXT.fail.cellOccupied); if (game.buildTool === 'eggFarm') buildFarm(col, row); else if (game.buildTool === 'manualScanner') buildScanner(col, row, 'manual'); @@ -510,7 +545,7 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel function buildAtPoint(p) { const cell = pointToCell(p.x, p.y); - if (['conveyor', 'boostConveyor', 'eggFarm', 'manualScanner', 'autoScanner'].includes(game.buildTool)) return buildAtCell(cell); + if (['conveyor', 'boostConveyor', 'eggFarm', 'manualScanner', 'autoScanner', 'maintenanceRoom'].includes(game.buildTool)) return buildAtCell(cell); if (MACHINE_FACILITY_IDS.includes(game.buildTool)) return buildFacility(p, game.buildTool); } @@ -542,6 +577,26 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel floating(game, cellCenter(col, row).x, cellCenter(col, row).y, `-${yen(cost)}`, THEME.ink); } + function buildMaintenanceRoom(col, row) { + const cost = buildPrice('maintenanceRoom', game); + if (game.cash < cost) return fail(TEXT.fail.notEnoughCash); + if (maintenanceRoomPlacementBlocked(col, row)) return fail(TEXT.fail.cellOccupied); + record(game); + spendCash(game, cost); + const room = applyBuildQuality(createMaintenanceRoom(game, col, row)); + room.price = cost; + game.maintenanceRooms = game.maintenanceRooms || []; + game.maintenanceRooms.push(room); + game.selected = { type: 'maintenanceRoom', id: room.id }; + const center = roomCenter(room); + floating(game, center.x, center.y, `-${yen(cost)}`, THEME.ink); + } + + function roomCenter(room) { + const first = cellCenter(room.col, room.row); + return { x: first.x + GRID.cell / 2, y: first.y + GRID.cell / 2 }; + } + function buildFacility(p, id) { const cost = buildPrice(id, game); if (game.cash < cost) return fail(TEXT.fail.notEnoughCash); @@ -603,6 +658,13 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel eraseEffect(game, f.x + f.w / 2, f.y + f.h / 2); refreshRoutingAfterEdit(game); } + if (hit.type === 'maintenanceRoom') { + const room = hit.ref; + const center = roomCenter(room); + refundOrSell(hit, center.x, center.y); + game.maintenanceRooms = (game.maintenanceRooms || []).filter(r => r.id !== room.id); + eraseEffect(game, center.x, center.y); + } game.selected = null; game.multiSelected = []; updatePanels(); @@ -623,6 +685,8 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel if (farm) return { type: 'eggFarm', ref: farm }; const scanner = scannerAt(game, cell.col, cell.row); if (scanner) return { type: 'scanner', ref: scanner }; + const room = maintenanceRoomAt(game, cell.col, cell.row); + if (room) return { type: 'maintenanceRoom', ref: room }; const k = key(cell.col, cell.row); if (game.conveyorTiles.has(k)) return { type: 'conveyor', oldKey: k, ref: { type: 'conveyor', id: k } }; return null; @@ -641,6 +705,7 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel else if (obj.type === 'eggFarm') eraseAtPoint(cellCenter(obj.col, obj.row)); else if (obj.type === 'scanner') eraseAtPoint(scannerCenter(obj)); else if (obj.type === 'facility') eraseAtPoint({ x: obj.x + obj.w / 2, y: obj.y + obj.h / 2 }); + else if (obj.type === 'maintenanceRoom') eraseAtPoint(roomCenter(obj)); } function modalButton(text, onClick, className = 'primary-button') { @@ -798,6 +863,14 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel ui.modalActions.innerHTML = ''; if (obj.type === 'scanner' && obj.kind === 'auto') ui.modalActions.appendChild(modalButton('Auto Menu', () => showAutoScannerMenu(obj), 'facility-action warn')); if (obj.type === 'scanner' && obj.kind === 'manual') ui.modalActions.appendChild(modalButton('Set Keys', () => showManualScannerMenu(obj), 'facility-action warn')); + if (obj.type === 'conveyor' && isBranchKey(obj.id)) { + const mode = game.conveyorMeta.get(obj.id)?.branchMode || 'random'; + ui.modalActions.appendChild(modalButton(`Branch: ${branchModeLabel(mode)}`, () => { + cycleBranchModeForKey(obj.id); + game.selected = { type: 'conveyor', id: obj.id }; + showSelectedMenu(); + }, 'facility-action warn branch-action')); + } const hit = obj.type === 'conveyor' ? { type: 'conveyor', oldKey: obj.id, ref: obj } : { type: obj.type, ref: obj }; const saleReason = lastProtectedSaleReason(hit); if (saleReason) { @@ -829,6 +902,7 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel boxes.push({ id: `facility:${id}`, price: equipmentPrice({ type: 'facility', ref: f }), x: f.x, y: f.y, w: f.w, h: f.h }); if (f.entry) { const c = cellCenter(f.entry.col, f.entry.row); boxes.push({ id: `facilityPort:${id}`, price: equipmentPrice({ type: 'facility', ref: f }), x: c.x - 18, y: c.y - 18, w: 36, h: 36 }); } } + for (const room of game.maintenanceRooms || []) { const c = roomCenter(room); boxes.push({ id: `maintenanceRoom:${room.id}`, price: equipmentPrice({ type: 'maintenanceRoom', ref: room }), x: c.x - GRID.cell, y: c.y - GRID.cell, w: GRID.cell * 2, h: GRID.cell * 2 }); } for (const farm of game.eggFarms) { const c = cellCenter(farm.col, farm.row); boxes.push({ id: `eggFarm:${farm.id}`, price: equipmentPrice({ type: 'eggFarm', ref: farm }), x: c.x - 24, y: c.y - 24, w: 48, h: 48 }); } for (const scanner of game.scanners) { const c = scannerCenter(scanner); boxes.push({ id: `scanner:${scanner.id}`, price: equipmentPrice({ type: 'scanner', ref: scanner }), x: c.x - 50, y: c.y - 73, w: 100, h: 146 }); } for (const k of game.conveyorTiles) { @@ -869,19 +943,19 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel function cycleBranchModeAtPoint(p) { const k = branchSwitcherAtPoint(p); if (!k) return false; - cycleBranchModeForKey(k); - return true; + return cycleBranchModeForKey(k); } function cycleBranchModeForKey(k) { const meta = game.conveyorMeta.get(k); if (!meta) return false; - const reachable = branchSelectableEntranceDirsForKey(k); + const reachable = branchSelectableExitDirsForKey(k); if (reachable.length < 2) return false; record(game); const current = BRANCH_MODES.includes(meta.branchMode) ? meta.branchMode : 'random'; const modes = ['random', ...DIRS.map(d => d.name).filter(mode => reachable.includes(mode))]; meta.branchMode = modes[(Math.max(0, modes.indexOf(current)) + 1) % modes.length]; + refreshRoutingAfterEdit(game); game.selected = null; game.multiSelected = []; updatePanels(); @@ -920,11 +994,16 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel lines.push(`Durability: ${remainingPercent({ meta })}% | Speed x${performanceFactor({ meta }).toFixed(2)}`); if (isBranchKey(obj.id)) { lines.push(`Branch mode: ${branchModeLabel(meta?.branchMode || 'random')}`); - lines.push('Use the Branch button below or the on-belt branch badge.'); + lines.push('Click the Branch button or the large on-belt badge to cycle RANDOM / fixed exit.'); } else { lines.push('Branch mode: needs 3+ conveyor connections.'); } lines.push(`Sale value: ${yen(resaleValueFor({ type: 'conveyor', oldKey: obj.id, ref: obj }, game).amount)}`); + } else if (obj.type === 'maintenanceRoom') { + lines.push(`Price: ${yen(equipmentPrice({ type: 'maintenanceRoom', ref: obj }))}`); + lines.push(`Sale value: ${yen(resaleValueFor({ type: 'maintenanceRoom', ref: obj }, game).amount)}`); + lines.push('Size: 2×2 grid cells'); + lines.push('Dispatch: 1 repairman during each production day'); } else if (obj.type === 'facility') { lines.push(`Price: ${yen(equipmentPrice(obj))}`); { const reason = lastProtectedSaleReason({ type: obj.type, ref: obj }); lines.push(reason ? `Sale: blocked (${reason})` : `Sale value: ${yen(resaleValueFor({ type: obj.type, ref: obj }, game).amount)}`); } @@ -969,6 +1048,7 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel if (obj.type === 'facility' && (obj.baseId || obj.id) === 'mixer') return 'Male chicks become revenue here. Do not feed it poop.'; if (obj.type === 'facility' && (obj.baseId || obj.id) === 'trash') return 'Poop goes in. Sometimes coins come out, for reasons best left unaudited.'; if (obj.type === 'facility' && (obj.baseId || obj.id) === 'truck') return 'The shipping endpoint. Correct cargo pays; wrong cargo complains.'; + if (obj.type === 'maintenanceRoom') return 'A cramped 2×2 storage and break room with lockers, spare parts, a bench and one dispatched repairman.'; return 'Factory equipment.'; } diff --git a/src/systems/cards.js b/src/systems/cards.js index 091504a..098cfb0 100644 --- a/src/systems/cards.js +++ b/src/systems/cards.js @@ -213,8 +213,7 @@ function cardAtCap(game, card) { } function repairmanCardVisible(game) { - const r = game.repairman || {}; - return !!(r.active || r.hiredForNextDay || game.pendingRepairWorkerWages > 0); + return !!((game.maintenanceRooms || []).length || (game.repairmen || []).length || game.repairman?.active); } function availableCards(game) { @@ -506,8 +505,9 @@ function cardDescription(game, card) { if (card.id === 'flattery') return `Next Fairies tribute -50%. Held for next tribute: ${e.fairiesFlatteryNext || 0}.`; if (card.id === 'usedMachine') return 'Enable Used Machines: future equipment costs 50%, has no SELL refund, and starts with 60% durability.'; if (card.id === 'newMachine') return 'Cancel Used Machines. Future equipment returns to normal price, refund, and durability.'; - if (card.id === 'laborExploitation') return 'Repairman labor cost -30% permanently. One time only.'; + if (card.id === 'laborExploitation') return 'Repairman dispatch paperwork is streamlined. Repair rooms keep operating; one time only.'; if (card.id === 'rescueLoan') return `At day-end bankruptcy check, gain ${yen(500)} if cash is below ${yen(0)}. Held: ${e.rescueLoanCharges || 0}.`; + if (card.id === 'dynamite') return 'Choose any blocked tiles on the map and destroy up to 3. Empty-space clicks are ignored; press Esc to finish after at least one blast.'; return card.description; } @@ -610,7 +610,8 @@ export function createCardSystem({ game, ui, onUpdatePanels }) { cardId: card.id, mode: card.target === 'blockedCell' ? 'blockedCell' : 'equipment', targetKeys: targets.map(targetKey), - remaining: card.id === 'dynamite' ? Math.min(3, targets.length) : 1 + remaining: card.id === 'dynamite' ? Math.min(3, targets.length) : 1, + used: 0 }; ui.modal.classList.remove('visible', 'equipment-popover'); updatePanels(); @@ -630,6 +631,7 @@ export function createCardSystem({ game, ui, onUpdatePanels }) { floating(game, c.x, c.y - 18, 'BOOM', THEME.danger); refreshRoutingAfterEdit(game); game.cardTargetPick.remaining = Math.max(0, (game.cardTargetPick.remaining || 1) - 1); + game.cardTargetPick.used = Math.max(0, game.cardTargetPick.used || 0) + 1; game.cardTargetPick.targetKeys = targetsForCard(game, 'dynamite').map(targetKey); updatePanels(); return true; @@ -639,15 +641,21 @@ export function createCardSystem({ game, ui, onUpdatePanels }) { if (!game.cardTargetPick?.pending) return false; const card = cardById(game.cardTargetPick.cardId); const target = targetAtPoint(game, p); - if (!card || !target) { + if (!card) { cancelTargetPick(); return true; } if (card.id === 'dynamite') { + // Empty-space clicks do nothing: the player may freely choose any highlighted tile. + if (!target) return true; if (!applyDynamiteTarget(target)) return true; if ((game.cardTargetPick.remaining || 0) <= 0 || !targetsForCard(game, 'dynamite').length) completePickedCard(card); return true; } + if (!target) { + cancelTargetPick(); + return true; + } applyEquipmentUpgrade(game, target); completePickedCard(card); return true; @@ -655,6 +663,15 @@ export function createCardSystem({ game, ui, onUpdatePanels }) { function cancelTargetPick() { if (!game.cardTargetPick?.pending) return; + const activePick = game.cardTargetPick; + const card = cardById(activePick.cardId); + // Once a dynamite charge has been used, Escape finishes the card instead of + // returning a partially consumed card to the draft. Before the first blast, + // Escape still cancels normally. + if (card?.id === 'dynamite' && (activePick.used || 0) > 0) { + completePickedCard(card); + return; + } game.cardTargetPick = null; showDraft(); } @@ -678,6 +695,36 @@ export function createCardSystem({ game, ui, onUpdatePanels }) { showDraft(); } + + function cardIconFor(card) { + const tags = new Set(card.tags || []); + const byTarget = { + eggFarm: { type: 'image', src: './assets/dark_factory/facilities/machines/egg_farm_16.png', alt: 'EGG' }, + eggOutlet: { type: 'image', src: './assets/dark_factory/facilities/machines/egg_farm_16.png', alt: 'EGG' }, + autoScanner: { type: 'image', src: './assets/dark_factory/facilities/machines/auto_scanner_32x48.png', alt: 'SCAN' }, + mixer: { type: 'image', src: './assets/dark_factory/facilities/machines/mixer_compact_16.png', alt: 'MIX' }, + truck: { type: 'image', src: './assets/dark_factory/facilities/vehicles/truck_compact_16.png', alt: 'TRUCK' }, + trash: { type: 'image', src: './assets/dark_factory/facilities/machines/shredder_compact_16.png', alt: 'SHR' }, + blockedCell: { type: 'image', src: './assets/dark_factory/facilities/utility/obstacle_crate_16.png', alt: 'BLOCK' } + }; + if (byTarget[card.target]) return byTarget[card.target]; + if (card.id === 'bearing' || tags.has('CONVEYOR')) return { type: 'image', src: './assets/dark_factory/facilities/conveyor/conveyor_straight_h_16.png', alt: 'BELT' }; + if (tags.has('SCANNER')) return { type: 'image', src: './assets/dark_factory/facilities/machines/auto_scanner_32x48.png', alt: 'SCAN' }; + if (tags.has('EGG')) return { type: 'image', src: './assets/dark_factory/facilities/machines/egg_farm_16.png', alt: 'EGG' }; + if (tags.has('POOP')) return { type: 'glyph', text: '💩' }; + if (tags.has('MAINTENANCE')) return { type: 'image', src: './assets/dark_factory/facilities/utility/repairman_16.png', alt: 'FIX' }; + if (tags.has('CARD')) return { type: 'glyph', text: '▣' }; + if (tags.has('ECONOMY')) return { type: 'glyph', text: '¥' }; + if (tags.has('RISK')) return { type: 'glyph', text: '!' }; + return { type: 'glyph', text: '◆' }; + } + + function cardIconHtml(card) { + const icon = cardIconFor(card); + if (icon.type === 'image') return `
${icon.alt || ''}
`; + return ``; + } + function cardButton(card, index) { const b = document.createElement('button'); b.type = 'button'; @@ -685,7 +732,7 @@ export function createCardSystem({ game, ui, onUpdatePanels }) { b.className = `card-choice ${kind}`; const rarity = card.type === 'dud' ? 'MISS' : (card.rarity === 'ultraRare' ? 'ULTRA RARE' : (card.rarity === 'rare' ? 'RARE' : 'COMMON')); const tags = [rarity, ...(card.tags || []).filter(tag => tag !== rarity)].slice(0, 5); - b.innerHTML = `${card.title}
${tags.map(tag => `${tag}`).join('')}
${cardDescription(game, card)}`; + b.innerHTML = `${cardIconHtml(card)}
${card.title}
${tags.map(tag => `${tag}`).join('')}
${cardDescription(game, card)}
`; b.addEventListener('click', () => chooseCard(card, b)); b.dataset.index = String(index); return b; diff --git a/src/systems/chickSystem.js b/src/systems/chickSystem.js index 0282165..1662557 100644 --- a/src/systems/chickSystem.js +++ b/src/systems/chickSystem.js @@ -249,15 +249,13 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck const connected = conveyorNeighborDirNames(cell); if (connected.length < 3) return dirs; const entrances = new Set(connected.filter(dir => neighborPointsIntoCell(cell, dir))); - if (branchMode && branchMode !== 'random' && branchMode !== 'pass' && connected.includes(branchMode)) { - const selectedEntrances = new Set(entrances); - selectedEntrances.add(branchMode); - if (connected.filter(dir => !selectedEntrances.has(dir)).length >= 2) entrances.add(branchMode); - } - const exits = connected.filter(dir => !entrances.has(dir)); - if (exits.length) return exits; - const fallback = dirs.filter(dir => !entrances.has(dir)); - return fallback.length ? fallback : dirs; + const physicalExits = connected.filter(dir => !entrances.has(dir)); + let candidates = entrances.size && physicalExits.length >= 2 + ? physicalExits + : [...new Set(dirs.filter(dir => connected.includes(dir)))]; + if (candidates.length < 2) candidates = connected; + if (branchMode && branchMode !== 'random' && branchMode !== 'pass' && candidates.includes(branchMode)) return [branchMode]; + return candidates; } function optionAvailableForBranch(chick, opt) { diff --git a/src/systems/economy.js b/src/systems/economy.js index 8dd772d..89a094a 100644 --- a/src/systems/economy.js +++ b/src/systems/economy.js @@ -25,6 +25,7 @@ export function equipmentBasePrice(objOrHit) { if (type === 'eggFarm') return obj.price || FACILITY_DEFS.eggFarm.price; if (type === 'scanner') return obj.price || (obj.kind === 'auto' ? FACILITY_DEFS.autoScanner.price : FACILITY_DEFS.manualScanner.price); if (type === 'facility') return obj.price || FACILITY_DEFS[obj.id]?.price || 0; + if (type === 'maintenanceRoom') return obj.price || FACILITY_DEFS.maintenanceRoom.price; return FACILITY_DEFS[obj.id]?.price || 0; } diff --git a/src/systems/maintenance.js b/src/systems/maintenance.js index 2c9ffaa..6321b38 100644 --- a/src/systems/maintenance.js +++ b/src/systems/maintenance.js @@ -1,7 +1,6 @@ import { BALANCE } from '../core/balance.js'; import { GRID, THEME } from '../core/config.js'; -import { cellCenter, parseKey, key, yen } from '../core/utils.js'; -import { spendCash } from './economy.js'; +import { cellCenter, parseKey, key } from '../core/utils.js'; import { floating } from './effects.js'; const RULES = BALANCE.maintenance; @@ -25,19 +24,25 @@ export function durabilityCapFor(game, type, qualityMultiplier = 1) { return Math.max(1, Math.ceil(base * Math.max(0.1, qualityMultiplier || 1) * durabilityMultiplier(game))); } -export function repairmanDailyCost(game) { - const base = RULES.repairman.dailyCost; - return game?.cardEffects?.laborExploitation ? Math.ceil(base * 0.7) : base; -} - function qualityMultiplierOf(objOrMeta) { return Math.max(0.1, Number(objOrMeta?.durabilityBaseMultiplier) || 1); } +function maintenanceRoomCenter(room, index = 0) { + if (!room) return { x: GRID.x + GRID.cell * (0.5 + index * 0.55), y: GRID.y + GRID.rows * GRID.cell + 84 }; + const x = GRID.x + room.col * GRID.cell + GRID.cell; + const y = GRID.y + room.row * GRID.cell + GRID.cell; + return { x, y }; +} + +function repairmanHome(game, index = 0) { + const room = (game.maintenanceRooms || [])[index]; + return maintenanceRoomCenter(room, index); +} + export function ensureMaintenanceState(game) { if (!game.repairman) { game.repairman = { - hiredForNextDay: false, active: false, x: GRID.x + GRID.cell * 0.5, y: GRID.y + GRID.rows * GRID.cell + 84, @@ -45,6 +50,8 @@ export function ensureMaintenanceState(game) { repairedToday: 0 }; } + if (!Array.isArray(game.maintenanceRooms)) game.maintenanceRooms = []; + if (!Array.isArray(game.repairmen)) game.repairmen = []; for (const [k, meta] of game.conveyorMeta || []) { if (meta.uses == null) meta.uses = 0; if (meta.maintenanceType == null) meta.maintenanceType = 'conveyor'; @@ -240,28 +247,32 @@ export function repairAllEquipment(game, percent = 0.02) { return repaired; } -export function hireRepairmanForNextDay(game) { - ensureMaintenanceState(game); - if (game.repairman.hiredForNextDay) return { ok: false, reason: 'Repairman already hired.' }; - const cost = repairmanDailyCost(game); - if (game.cash < cost) return { ok: false, reason: `Need ${yen(cost - game.cash)} more.` }; - spendCash(game, cost); - game.pendingRepairWorkerWages = (game.pendingRepairWorkerWages || 0) + cost; - game.totals.repairWorkerWages = (game.totals.repairWorkerWages || 0) + cost; - game.repairman.hiredForNextDay = true; - return { ok: true, cost }; -} - export function activateRepairmanForDay(game) { ensureMaintenanceState(game); - game.repairman.active = !!game.repairman.hiredForNextDay; - game.repairman.hiredForNextDay = false; - game.repairman.target = null; + const rooms = game.maintenanceRooms || []; + game.repairmen = rooms.map((room, index) => { + const home = repairmanHome(game, index); + return { + id: `room-${room.id}`, + roomId: room.id, + active: true, + x: home.x, + y: home.y, + target: null, + repairedToday: 0 + }; + }); + const first = game.repairmen[0]; + game.repairman.active = !!first; + game.repairman.target = first?.target || null; game.repairman.repairedToday = 0; + if (first) { game.repairman.x = first.x; game.repairman.y = first.y; } } export function deactivateRepairman(game) { ensureMaintenanceState(game); + for (const r of game.repairmen || []) { r.active = false; r.target = null; } + game.repairmen = []; game.repairman.active = false; game.repairman.target = null; } @@ -284,14 +295,34 @@ function chooseRepairTarget(game) { export function updateRepairman(game, dt) { ensureMaintenanceState(game); - const r = game.repairman; - if (!r.active || game.phase !== 'running') return; - let target = resolveStoredTarget(game, r.target) || chooseRepairTarget(game); + const repairmen = game.repairmen?.length ? game.repairmen : (game.repairman?.active ? [game.repairman] : []); + if (!repairmen.length || game.phase !== 'running') return; + const assigned = new Set(repairmen.map(r => r.target?.key).filter(Boolean)); + for (const r of repairmen) updateSingleRepairman(game, r, dt, assigned); + const first = repairmen[0]; + if (first && game.repairman !== first) { + game.repairman.active = true; + game.repairman.x = first.x; + game.repairman.y = first.y; + game.repairman.target = first.target; + game.repairman.repairedToday = first.repairedToday || 0; + } +} + +function updateSingleRepairman(game, r, dt, assigned) { + if (!r.active) return; + let target = resolveStoredTarget(game, r.target); + if (!target || targetWear(target) <= 0.001) { + if (r.target?.key) assigned.delete(r.target.key); + target = chooseRepairTargetAvoiding(game, assigned); + } if (!target) { r.target = null; return; } - r.target = { key: targetKey(target), label: target.label }; + const tKey = targetKey(target); + assigned.add(tKey); + r.target = { key: tKey, label: target.label }; const speed = RULES.repairman.walkSpeed; const dx = target.center.x - r.x; const dy = target.center.y - r.y; @@ -302,16 +333,32 @@ export function updateRepairman(game, dt) { r.y += dy / dist * step; return; } - const repairWear = dt / (RULES.repairman.secondsPerOnePercent * 100); + const workTimeMultiplier = game?.cardEffects?.laborExploitation ? 0.7 : 1; + const repairWear = dt / (RULES.repairman.secondsPerOnePercent * workTimeMultiplier * 100); const usesBefore = targetUses(target); const usesDelta = repairWear * targetDurability(target); reduceTargetUses(target, usesDelta); const repairedPct = Math.max(0, (usesBefore - targetUses(target)) / targetDurability(target) * 100); r.repairedToday = (r.repairedToday || 0) + repairedPct; if (repairedPct > 0 && Math.random() < 0.02) floating(game, r.x, r.y - 28, 'REPAIR', THEME.green); - if (targetWear(target) <= 0.001) r.target = null; + if (targetWear(target) <= 0.001) { + assigned.delete(tKey); + r.target = null; + } } +function chooseRepairTargetAvoiding(game, assigned = new Set()) { + let best = null; + for (const t of equipmentMaintenanceTargets(game)) { + if (assigned.has(targetKey(t))) continue; + const w = targetWear(t); + if (w <= 0.001) continue; + if (!best || w > targetWear(best)) best = t; + } + return best || chooseRepairTarget(game); +} + + function worstDegradation(game) { let worst = 0; let label = 'none'; @@ -325,5 +372,5 @@ function worstDegradation(game) { export function maintenanceSummary(game) { const worst = worstDegradation(game); const avgBeltPerformance = averageConveyorPerformance(game); - return { worst, avgBeltPerformance, repairman: game.repairman || null }; + return { worst, avgBeltPerformance, repairman: game.repairman || null, repairmen: game.repairmen || [], rooms: game.maintenanceRooms || [] }; } diff --git a/src/systems/routing.js b/src/systems/routing.js index a7f9a52..99a74c2 100644 --- a/src/systems/routing.js +++ b/src/systems/routing.js @@ -138,19 +138,14 @@ function inferredConveyorOutDirNames(game, cellKey) { .filter(d => game.conveyorTiles.has(graphNodeKey(p.col + d.dc, p.row + d.dr))) .map(d => d.name); const explicit = conveyorOutDirNames(game, cellKey).filter(dir => neighbors.includes(dir)); - const inferred = neighbors; - const dirs = explicit.length ? explicit : inferred; + const dirs = explicit.length ? explicit : neighbors; if (neighbors.length < 3) return dirs; const entrances = new Set(neighbors.filter(dir => neighborPointsIntoCell(game, p, dir))); - if (meta.branchMode && meta.branchMode !== 'random' && neighbors.includes(meta.branchMode)) { - const selectedEntrances = new Set(entrances); - selectedEntrances.add(meta.branchMode); - if (neighbors.filter(dir => !selectedEntrances.has(dir)).length >= 2) entrances.add(meta.branchMode); - } - const exits = neighbors.filter(dir => !entrances.has(dir)); - if (exits.length) return exits; - const fallback = dirs.filter(dir => !entrances.has(dir)); - return fallback.length ? fallback : dirs; + const physicalExits = neighbors.filter(dir => !entrances.has(dir)); + let candidates = entrances.size && physicalExits.length >= 2 ? physicalExits : [...new Set(dirs)]; + if (candidates.length < 2) candidates = neighbors; + if (meta.branchMode && meta.branchMode !== 'random' && candidates.includes(meta.branchMode)) return [meta.branchMode]; + return candidates; } function emptyFactoryGraph(game) { diff --git a/src/systems/selectionSystem.js b/src/systems/selectionSystem.js index 505a729..0aaab89 100644 --- a/src/systems/selectionSystem.js +++ b/src/systems/selectionSystem.js @@ -1,6 +1,6 @@ import { GRID } from '../core/config.js'; import { key, parseKey, cellCenter } from '../core/utils.js'; -import { nearestGridEdge, layoutFacilityOnEdge } from '../core/entities.js'; +import { nearestGridEdge, layoutFacilityOnEdge, maintenanceRoomFootprint } from '../core/entities.js'; import { farmAt, scannerAt, scannerCenter, scannerFootprintCells, refreshRoutingAfterEdit } from './routing.js'; import { snapshot } from './history.js'; import { buildPrice } from './economy.js'; @@ -10,6 +10,7 @@ export function createSelectionSystem({ game, canvasPoint, updatePanels, equipme if (!item) return ''; if (item.type === 'conveyor') return `conveyor:${item.id || item.oldKey}`; if (item.type === 'facility') return `facility:${item.id || item.ref?.id}`; + if (item.type === 'maintenanceRoom') return `maintenanceRoom:${item.id || item.ref?.id}`; return `${item.type}:${item.id || item.ref?.id}`; } @@ -29,6 +30,7 @@ export function createSelectionSystem({ game, canvasPoint, updatePanels, equipme if (sel.type === 'eggFarm') return game.eggFarms.find(f => f.id === sel.id) || null; if (sel.type === 'scanner') return game.scanners.find(sc => sc.id === sel.id) || null; if (sel.type === 'facility') return game.facilities[sel.id] || null; + if (sel.type === 'maintenanceRoom') return (game.maintenanceRooms || []).find(r => r.id === sel.id) || null; if (sel.type === 'conveyor') return game.conveyorTiles.has(sel.id) ? { type: 'conveyor', id: sel.id } : null; return null; } @@ -42,6 +44,10 @@ export function createSelectionSystem({ game, canvasPoint, updatePanels, equipme } for (const farm of game.eggFarms) items.push({ type: 'eggFarm', id: farm.id, ref: farm, center: cellCenter(farm.col, farm.row), cell: { col: farm.col, row: farm.row } }); for (const scanner of game.scanners) items.push({ type: 'scanner', id: scanner.id, ref: scanner, center: scannerCenter(scanner), cell: { col: scanner.col, row: scanner.row } }); + for (const room of game.maintenanceRooms || []) { + const c = cellCenter(room.col, room.row); + items.push({ type: 'maintenanceRoom', id: room.id, ref: room, center: { x: c.x + GRID.cell / 2, y: c.y + GRID.cell / 2 }, cell: { col: room.col, row: room.row } }); + } for (const f of Object.values(game.facilities)) { const bodyCenter = { x: f.x + f.w / 2, y: f.y + f.h / 2 }; const portCenter = f.entry ? cellCenter(f.entry.col, f.entry.row) : bodyCenter; @@ -117,7 +123,7 @@ export function createSelectionSystem({ game, canvasPoint, updatePanels, equipme const cell = parseKey(sel.id); return { ...sel, obj, oldKey: sel.id, currentKey: sel.id, meta: game.conveyorMeta.get(sel.id) || { price: buildPrice('conveyor'), builtSession: null }, col: cell.col, row: cell.row }; } - if (sel.type === 'eggFarm' || sel.type === 'scanner') return { ...sel, obj, col: obj.col, row: obj.row }; + if (sel.type === 'eggFarm' || sel.type === 'scanner' || sel.type === 'maintenanceRoom') return { ...sel, obj, col: obj.col, row: obj.row }; if (sel.type === 'facility') return { ...sel, obj, x: obj.x, y: obj.y, w: obj.w, h: obj.h, entry: obj.entry ? { ...obj.entry } : null, side: obj.side, center: { x: obj.x + obj.w / 2, y: obj.y + obj.h / 2 } }; return null; } @@ -149,6 +155,8 @@ export function createSelectionSystem({ game, canvasPoint, updatePanels, equipme if (farm && !selectedTokens.has(`eggFarm:${farm.id}`)) return true; const scanner = scannerAt(game, col, row); if (scanner && !selectedTokens.has(`scanner:${scanner.id}`)) return true; + const room = (game.maintenanceRooms || []).find(item => maintenanceRoomFootprint(item).some(cell => cell.col === col && cell.row === row)); + if (room && !selectedTokens.has(`maintenanceRoom:${room.id}`)) return true; if (game.conveyorTiles.has(k) && !selectedTokens.has(`conveyor:${k}`)) return true; return false; } @@ -192,7 +200,7 @@ export function createSelectionSystem({ game, canvasPoint, updatePanels, equipme for (const origin of game.groupDrag.origins) { if (origin.type === 'facility') continue; const col = origin.col + dcol, row = origin.row + drow; - const cells = origin.type === 'scanner' ? scannerFootprintCells({ col, row }) : [{ col, row }]; + const cells = origin.type === 'scanner' ? scannerFootprintCells({ col, row }) : (origin.type === 'maintenanceRoom' ? maintenanceRoomFootprint({ col, row }) : [{ col, row }]); for (const cell of cells) { if (!pointInGrid(cell.col, cell.row)) return fail('Selection outside grid'); if (game.blockedCells?.has?.(key(cell.col, cell.row))) return fail('Selection hits blocked ground'); @@ -224,6 +232,9 @@ export function createSelectionSystem({ game, canvasPoint, updatePanels, equipme } else if (origin.type === 'scanner') { origin.obj.col = origin.col + dcol; origin.obj.row = origin.row + drow; + } else if (origin.type === 'maintenanceRoom') { + origin.obj.col = origin.col + dcol; + origin.obj.row = origin.row + drow; } else if (origin.type === 'facility') { const nextCenter = { x: origin.center.x + dx, y: origin.center.y + dy }; const { entry, side } = nearestGridEdge(nextCenter); diff --git a/src/systems/uiSystem.js b/src/systems/uiSystem.js index 0c57b2a..ebe08c6 100644 --- a/src/systems/uiSystem.js +++ b/src/systems/uiSystem.js @@ -5,7 +5,7 @@ import { routeFromFarmToScanner, factoryReady, facilityConnectionIssues } from ' import { buildPrice, fairiesTributeInfo, finalScore, maleTruckPenalty, mixerPoopPenalty, truckPoopPenalty } from './economy.js'; import { truckTarget } from './events.js'; import { conveyorSpeedForGame } from './cards.js'; -import { maintenanceSummary, repairmanDailyCost } from './maintenance.js'; +import { maintenanceSummary } from './maintenance.js'; export function createUISystem({ game, ui, build, startGame, beginCardDraft, activeQueuedChick }) { function escapeHtml(value) { @@ -27,7 +27,6 @@ export function createUISystem({ game, ui, build, startGame, beginCardDraft, act function updatePanels() { updateToolButtons(); updateBuildStatus(); - updateEventPanel(); updateTurnSummary(); updateHistoryButtons(); } @@ -56,15 +55,6 @@ export function createUISystem({ game, ui, build, startGame, beginCardDraft, act : ''; } if (ui.buttons.erase) ui.buttons.erase.disabled = game.phase !== 'build' || !!game.cardDraft?.pending || !!game.cardTargetPick?.pending; - if (ui.hireRepairmanButton) { - const hired = !!game.repairman?.hiredForNextDay; - const cost = repairmanDailyCost(game); - const blocked = game.phase !== 'build' || !!game.cardDraft?.pending || !!game.cardTargetPick?.pending || hired || game.cash < cost; - ui.hireRepairmanButton.disabled = blocked; - ui.hireRepairmanButton.classList.toggle('active', hired); - ui.hireRepairmanButton.classList.toggle('unaffordable', game.cash < cost); - ui.hireRepairmanButton.title = hired ? 'Repairman is hired for the next production phase.' : `Hire for ${yen(cost)} for one day. Repairs 2% durability per second.`; - } const cashout = noAffordableBuildTools(); ui.buttons.nextTurn?.classList.toggle('cashout-emphasis', cashout); ui.buttons.erase?.classList.toggle('cashout-emphasis', cashout); @@ -89,47 +79,14 @@ export function createUISystem({ game, ui, build, startGame, beginCardDraft, act function updateTurnSummary() { const connected = game.eggFarms.filter(f => routeFromFarmToScanner(game, f)?.scannerId).length; const issues = facilityConnectionIssues(game); - const tributeBasisProfit = Math.max(0, Math.floor(game.lastResult?.profit ?? game.stats?.profit ?? 0)); - const tributeDay = Math.max(1, Number(game.turn) || 1); - const tribute = fairiesTributeInfo(game, tributeDay, tributeBasisProfit); ui.turnSummary.innerHTML = [ `Seed: ${escapeHtml(game.runSeed || 'none')} | Grid box: ${game.gridRows || 10}x${game.gridCols || 20} | Owned: ${game.gridOwnedCells || game.ownedCells?.size || ((game.gridRows || 10) * (game.gridCols || 20))} cells | Blocked: ${game.blockedCells?.size || 0} cells`, - `Truck target: ${truckTarget(game).toUpperCase()} | Male fine: -${yen(maleTruckPenalty(game))}`, - `Poop fine: Mixer -${yen(mixerPoopPenalty(game))} / Shipment -${yen(truckPoopPenalty(game))}`, - `Fairies tribute on Next Day: -${yen(tribute.amount)} | base ${yen(tribute.base)} + profit share ${yen(tribute.profitTribute)} | basis net ${yen(tributeBasisProfit)} | exemption ${yen(tribute.profitExemption)}${tribute.reduction ? ` | reduction -${yen(tribute.reduction)}` : ''}`, - `Maintenance: worst ${maintenanceSummary(game).worst.percent}% dirty (${maintenanceSummary(game).worst.label}) | Repairman: ${game.repairman?.hiredForNextDay ? 'hired next day' : game.repairman?.active ? 'working' : 'none'}`, - `Manual combo: ${game.manualCombo?.count || 0} | Card draft: ${game.cardDraft?.pending ? Math.max(1, game.cardDraft.picksRemaining || 1) + ' pick(s) left' : 'ready after each day'} | Belt: ${displaySpeed()}px/s | Farms with scanner route: ${connected}/${game.eggFarms.length}`, + `Penalties: wrong shipment -${yen(maleTruckPenalty(game))} | Mixer poop -${yen(mixerPoopPenalty(game))} | Shipment poop -${yen(truckPoopPenalty(game))}`, + `Maintenance: worst ${maintenanceSummary(game).worst.percent}% dirty (${maintenanceSummary(game).worst.label}) | Rooms: ${(game.maintenanceRooms || []).length} | Repairmen: ${(game.repairmen || []).length}`, + `Card draft: ${game.cardDraft?.pending ? Math.max(1, game.cardDraft.picksRemaining || 1) + ' pick(s) left' : 'ready after each day'} | Farms with scanner route: ${connected}/${game.eggFarms.length}`, game.cardEffects?.usedMachineActive ? 'Procurement: USED MACHINE MODE / no refunds / 60% durability' : '', issues.length ? `Blocked: ${issues[0]}` : `${TEXT.status.allPortsConnected}` - ].join('
'); - } - function updateEventPanel() { - if (!ui.eventPanel) return; - const offer = game.eventOffer; - if (game.phase !== 'build') { - ui.eventPanel.innerHTML = TEXT.status.eventPanelRunning; - return; - } - if (!offer) { - ui.eventPanel.className = 'event-card empty'; - const nextTurn = game.turn + 1; - if (nextTurn < DAILY_EVENT_FIRST_TURN) { - ui.eventPanel.innerHTML = `Event lock active.No irregular events during Days 1-7. First possible forced event: Day ${DAILY_EVENT_FIRST_TURN}.`; - } else { - ui.eventPanel.innerHTML = 'No event.Random forced events can appear later.'; - } - return; - } - ui.eventPanel.className = 'event-card accepted'; - ui.eventPanel.innerHTML = ` -
FORCED NEXT DAY
-

${offer.title}

-
- Effect: ${offer.route} - ${offer.targetAmount ? `Target: ${offer.targetAmount}` : 'Target: none'} - ${offer.reward ? `Reward: ${yen(offer.reward)}` : 'Reward: none'} - Time ${offer.daySeconds || 60}s / Output x${Number(offer.productionMultiplier || 1).toFixed(2)} / Poop +${Math.round((offer.poopRateAdd || 0) * 100)}pt -
`; + ].filter(Boolean).join('
'); } function updateUI() { updateToolButtons(); @@ -172,7 +129,9 @@ export function createUISystem({ game, ui, build, startGame, beginCardDraft, act } const nextTributeBasis = Math.max(0, Math.floor(game.lastResult?.profit ?? game.stats?.profit ?? 0)); const nextTribute = fairiesTributeInfo(game, Math.max(1, Number(game.turn) || 1), nextTributeBasis).amount; - ui.buttons.nextTurn.textContent = game.phase === 'build' && nextTribute > 0 ? `Next Day - Fairies ${yen(nextTribute)}` : TEXT.actions.nextDay; + ui.buttons.nextTurn.innerHTML = game.phase === 'build' && nextTribute > 0 + ? `NEXT DAYFAIRIES -${yen(nextTribute)}` + : `${TEXT.actions.nextDay}`; ui.buttons.nextTurn.disabled = game.phase !== 'build' || !!game.cardDraft?.pending || !!game.cardTargetPick?.pending || !factoryReady(game); } @@ -180,7 +139,7 @@ export function createUISystem({ game, ui, build, startGame, beginCardDraft, act if (!ui.eventBrief || !ui.targetBrief || !ui.speedBrief) return; const target = truckTarget(game).toUpperCase(); ui.targetBrief.textContent = `TRUCK TARGET: ${target}`; - ui.speedBrief.textContent = `BELT: ${displaySpeed()} px/s | COMBO: ${game.manualCombo?.count || 0}`; + ui.speedBrief.textContent = `BELT SPEED: ${displaySpeed()} px/s`; ui.speedBrief.title = `Conveyor speed does not increase by day. Degraded belts reduce speed. Cap: ${CONVEYOR_SPEED_MAX}px/s.`; const active = game.eventActive; const offer = game.eventOffer; @@ -235,7 +194,6 @@ export function createUISystem({ game, ui, build, startGame, beginCardDraft, act
Event bonus${positive(r.eventBonus || 0)}
Penalties${negative(penalties)}
Fairies fee${negative(r.fairiesTribute?.amount || r.fairiesTribute || 0)}
-
Repair worker wages${negative(r.repairWorkerWages || 0)}

Income ${yen(r.revenue)} - losses ${yen(r.penalty)} = ${yen(r.profit)}

`; ui.modalActions.innerHTML = ''; diff --git a/styles-v27.17.css b/styles-v27.17.css new file mode 100644 index 0000000..1219389 --- /dev/null +++ b/styles-v27.17.css @@ -0,0 +1,1130 @@ +:root { + --bg: #f2fff0; + --screen: #eefbea; + --panel: rgba(245, 255, 242, 0.96); + --ink: #102015; + --muted: #526456; + --line: #102015; + --green: #22b94f; + --green-soft: #b7f5c6; + --white: #ffffff; + --danger: #c42424; + --shadow: 8px 8px 0 rgba(16, 32, 21, 0.22); +} +* { box-sizing: border-box; } +html, body { min-height: 100%; } +body { margin: 0; background: var(--bg); color: var(--ink); font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; overflow-x: hidden; } +button { font: inherit; } +h1, h2, p { margin: 0; } +#app { width: min(100vw, 1680px); margin: 0 auto; padding: 0 8px 12px; } +.game-shell { position: relative; width: 100%; min-height: min(100vh, 920px); border: 4px solid var(--line); border-top: 0; background: var(--screen); overflow: hidden; box-shadow: var(--shadow); } +#gameCanvas { display: block; width: 100%; height: min(calc(100vh - 10px), 900px); min-height: 720px; background: var(--screen); touch-action: none; } +.hud { position: absolute; z-index: 4; display: grid; gap: 6px; pointer-events: none; } +.hud-top-left { top: 10px; left: 10px; grid-template-columns: repeat(6, minmax(82px, auto)); } +.hud-top-right { top: 10px; right: 10px; grid-template-columns: repeat(4, minmax(78px, auto)); } +.hud-card { min-width: 82px; padding: 7px 9px; border: 3px solid var(--line); background: rgba(255,255,255,.88); box-shadow: 4px 4px 0 rgba(16,32,21,.16); } +.hud-card.primary { min-width: 116px; padding: 10px 12px; background: rgba(255,255,255,.96); } +.hud-card.primary span { font-size: 9px; } +.hud-card.primary strong { font-size: clamp(22px, 2vw, 32px); } +.hud-card.time-critical { background: #fff0d1; box-shadow: inset 0 0 0 4px var(--danger), 4px 4px 0 rgba(16,32,21,.16); } +.hud-card span { display: block; font-size: 9px; letter-spacing: .1em; color: var(--muted); margin-bottom: 4px; } +.hud-card strong { font-size: clamp(15px, 1.3vw, 22px); line-height: 1; color: var(--ink); } +.hud-card.cash strong, .hud-card.profit strong, .hud-card.combo strong, .cash-positive { color: var(--green) !important; } +.cash-negative { color: var(--danger) !important; } + +.priority-strip { position: absolute; z-index: 5; top: 76px; left: 10px; display: grid; grid-template-columns: minmax(280px, 1.2fr) minmax(170px, .75fr) minmax(130px, .55fr); gap: 8px; max-width: calc(100% - 420px); pointer-events: none; } +.priority-strip > div { border: 3px solid var(--line); background: rgba(255,255,255,.94); padding: 8px 10px; font-weight: 900; text-transform: uppercase; box-shadow: 4px 4px 0 rgba(16,32,21,.14); font-size: 12px; letter-spacing: .03em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.event-brief.active { background: #fff0d1; box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(16,32,21,.14); } +.event-brief.next { background: var(--green-soft); box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(16,32,21,.14); } +.event-brief.locked { background: #edf3ec; color: var(--muted); } +.target-brief { color: var(--green); } +.speed-brief { color: var(--ink); } + +.build-panel { position: absolute; z-index: 6; top: 118px; right: 12px; bottom: 12px; width: clamp(278px, 23vw, 360px); min-height: 0; padding: 10px; border: 4px solid var(--line); background: var(--panel); box-shadow: var(--shadow); overflow: auto; } +.panel-head { display: grid; gap: 8px; margin-bottom: 10px; } +.panel-head h1 { font-size: 15px; letter-spacing: .06em; } +.panel-head h1 span { font-size: 9px; color: var(--white); background: var(--green); border: 2px solid var(--line); padding: 1px 6px; } +.panel-head p { color: var(--muted); margin-top: 4px; font-size: 9px; line-height: 1.25; } +.panel-grid { display: grid; grid-template-columns: 1fr; gap: 10px; } +.build-panel h2 { font-size: 11px; text-transform: uppercase; letter-spacing: .1em; margin-bottom: 7px; } +.large-tools { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; } +.history-tools { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; grid-column: 1 / -1; } +.tool-button.small { min-height: 40px; padding: 6px; } +.tool-button, .primary-button, .sort-button, .facility-action { border: 3px solid var(--line); background: var(--white); color: var(--ink); font-weight: 900; text-transform: uppercase; cursor: pointer; box-shadow: 4px 4px 0 rgba(16,32,21,.18); } +.tool-button { min-height: 50px; text-align: left; padding: 8px; } +.tool-button strong { display: block; font-size: 12px; } +.tool-button span { display: block; margin-top: 4px; font-size: 9px; color: var(--muted); } +.tool-button.active { background: var(--green-soft); box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(16,32,21,.18); } +.tool-button.danger.active { background: #ffdada; box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(16,32,21,.18); } +.primary-button { padding: 10px 12px; background: var(--green); color: var(--white); white-space: nowrap; } +.primary-button:disabled, .tool-button:disabled, .sort-button:disabled, .facility-action:disabled { opacity: .42; cursor: not-allowed; } +.mini-box { border: 3px solid var(--line); background: var(--white); padding: 12px; line-height: 1.45; color: var(--muted); font-size: 11px; } +.facility-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; } +.facility-action { padding: 7px 9px; font-size: 9px; } +.facility-action.good { background: var(--green-soft); } +.facility-action.warn { background: #fff0d1; } +.facility-action.danger { background: #ffdada; } +.control-dock { position: absolute; z-index: 7; left: 50%; bottom: 12px; transform: translateX(-50%); display: grid; grid-template-columns: repeat(4, 150px); gap: 8px; padding: 7px; border: 3px solid var(--line); background: rgba(255,255,255,.90); } +.sort-button { min-height: 46px; font-size: 12px; } +/* Debug UI is intentionally kept for active balancing builds. Do not remove during cleanup/audit passes unless explicitly requested. */ +.debug-panel { + position: absolute; + z-index: 9; + left: 10px; + bottom: 10px; + width: min(410px, calc(100% - 20px)); + border: 3px solid var(--line); + background: rgba(255,255,255,.96); + box-shadow: 4px 4px 0 rgba(16,32,21,.16); + font-weight: 900; +} +.debug-panel summary { + cursor: pointer; + padding: 5px 8px; + color: var(--danger); + font-size: 14px; + line-height: 1.1; +} +.debug-body { + display: grid; + grid-template-columns: 1fr 92px; + gap: 6px; + padding: 7px; + border-top: 3px solid var(--line); + font-size: 12px; + line-height: 1.15; +} +.debug-body label, +.debug-body button, +.debug-body select, +.debug-body input { + min-width: 0; + font: inherit; +} +.debug-check, +.debug-card, +.debug-target, +.debug-readout { + grid-column: 1 / -1; +} +.debug-row { + display: grid; + grid-template-columns: 1fr 92px; + gap: 6px; + grid-column: 1 / -1; +} +.debug-day { + display: grid; + grid-template-columns: 38px 1fr; + align-items: center; + gap: 4px; +} +.debug-body button { + border: 2px solid var(--line); + background: var(--white); + cursor: pointer; + font-weight: 900; + padding: 5px 6px; + line-height: 1.05; +} +.debug-body input[type="number"], +.debug-body select { + width: 100%; + border: 2px solid var(--line); + background: var(--white); + padding: 4px 5px; + min-height: 29px; +} +.debug-target select:disabled { + opacity: .55; +} +.debug-readout { + border: 2px solid var(--line); + background: #f7fff5; + color: var(--muted); + padding: 5px; + line-height: 1.25; + max-height: 64px; + overflow: auto; +} +.modal { position: fixed; inset: 0; z-index: 20; display: none; align-items: center; justify-content: center; padding: 22px; background: rgba(16,32,21,.45); } +.modal.visible { display: flex; } +.modal-card { width: min(860px, 96vw); border: 4px solid var(--line); padding: 24px; background: var(--white); box-shadow: var(--shadow); } +.modal-card h2 { font-size: 26px; text-transform: uppercase; margin-bottom: 12px; } +.modal-card p { line-height: 1.55; } +.modal-card ul { margin: 12px 0 0; padding-left: 22px; line-height: 1.55; color: var(--muted); } +.modal-actions { margin-top: 18px; display: flex; justify-content: flex-end; gap: 10px; flex-wrap: wrap; } +.route-cards { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; margin: 14px 0; } +.route-card { border: 3px solid var(--line); background: #f7fff5; padding: 14px; display: grid; grid-template-columns: 44px 1fr 28px 1fr; align-items: center; gap: 4px 8px; } +.route-card .route-icon { grid-row: 1 / span 2; font-size: 30px; text-align: center; } +.route-card strong, .route-card em { font-style: normal; font-weight: 900; text-transform: uppercase; } +.route-card b { font-size: 24px; color: var(--green); text-align: center; } +.route-card small { grid-column: 2 / span 3; color: var(--muted); font-weight: 900; } +.result-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin-top: 12px; } +.result-grid div { border: 3px solid var(--line); padding: 10px; background: #f7fff5; } +.result-grid strong { display: block; font-size: 11px; color: var(--muted); text-transform: uppercase; margin-bottom: 6px; } +.result-grid span { font-size: 16px; font-weight: 900; color: var(--ink); } +.game-shell:not(.phase-build) .build-panel { display: none; } +.game-shell.phase-running .hud-top-right { display: none; } +.game-shell:not(.phase-running) .control-dock { display: none; } +@media (max-width: 1180px) { + #app { padding: 0; } + .game-shell { min-height: 100vh; } + #gameCanvas { height: 100vh; } + .hud-top-left, .hud-top-right { grid-template-columns: repeat(2, minmax(76px, auto)); } + .priority-strip { top: 150px; left: 8px; right: 8px; max-width: none; grid-template-columns: 1fr; } + .build-panel { top: auto; left: 8px; right: 8px; bottom: 8px; width: auto; max-height: 42vh; } + .large-tools { grid-template-columns: 1fr 1fr; } + .control-dock { grid-template-columns: repeat(2, 150px); } + .route-cards, .result-grid { grid-template-columns: 1fr; } +} + +.event-card { border: 3px solid var(--line); background: #f7fff5; padding: 12px; line-height: 1.35; color: var(--ink); font-size: 11px; box-shadow: 4px 4px 0 rgba(16,32,21,.14); } +.event-card.empty { color: var(--muted); background: rgba(255,255,255,.72); } +.event-card.empty strong { display: block; color: var(--ink); margin-bottom: 4px; } +.event-card h3 { margin: 2px 0 7px; font-size: 14px; text-transform: uppercase; letter-spacing: .04em; } +.event-card p { margin: 5px 0; } +.event-card.accepted { background: var(--green-soft); box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(16,32,21,.14); } +.event-card.declined { background: #f1f1f1; color: var(--muted); } +.event-status { display: inline-block; padding: 2px 7px; border: 2px solid var(--line); background: var(--white); font-size: 9px; font-weight: 900; letter-spacing: .1em; margin-bottom: 4px; } +.event-metrics { display: grid; grid-template-columns: 1fr; gap: 4px; margin: 8px 0; } +.event-metrics span { display: block; border: 2px solid rgba(16,32,21,.55); background: rgba(255,255,255,.82); padding: 5px; font-weight: 900; color: var(--ink); } +.event-actions { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; } +.result-section-title { margin: 16px 0 8px; font-size: 12px; font-weight: 900; text-transform: uppercase; letter-spacing: .12em; color: var(--green); } +.result-section-title:first-child { margin-top: 0; } +.muted-title { color: var(--muted); border: 3px solid var(--line); padding: 10px; background: #f7fff5; } + +.compact-rules .mini-box { padding: 8px; font-size: 9px; } +.primary-button:disabled { filter: grayscale(1); background: #c9d2ca; color: #526456; } +.formula-box { + border: 3px solid var(--line); + background: #f7fff5; + padding: 10px; + margin: 10px 0; + line-height: 1.5; + color: var(--ink); + font-size: 12px; + font-weight: 700; +} +.equipment-menu-lines { + border: 3px solid var(--line); + background: #ffffff; + padding: 10px; + margin: 8px 0; + color: var(--muted); + line-height: 1.45; +} +.equipment-menu-lines p { margin: 4px 0; } + +/* v11 compact clicked-equipment bubble */ +.modal.equipment-popover { + background: transparent; + align-items: flex-start; + justify-content: flex-start; + padding: 0; + pointer-events: none; +} +.modal.equipment-popover .modal-card { + position: absolute; + left: var(--popover-x, 16px); + top: var(--popover-y, 16px); + width: min(250px, calc(100vw - 24px)); + max-height: min(280px, calc(100vh - 24px)); + overflow: auto; + padding: 8px; + border-width: 3px; + pointer-events: auto; + box-shadow: 6px 6px 0 rgba(16,32,21,.18); +} +.modal.equipment-popover .modal-card h2 { + font-size: 14px; + margin-bottom: 6px; +} +.modal.equipment-popover .modal-actions { + margin-top: 8px; + gap: 6px; + justify-content: flex-start; +} +.modal.equipment-popover .modal-actions button { + padding: 5px 7px; + font-size: 9px; +} +.equipment-menu-lines.compact { + padding: 7px; + margin: 6px 0; + font-size: 9px; +} +.formula-box.compact { + padding: 7px; + margin: 6px 0; + font-size: 9px; +} + +/* v15 pre-build card draft */ +.card-choices { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(190px, 220px)); + justify-content: center; + align-items: stretch; + gap: 10px; + margin-top: 14px; +} +.card-choice { + min-height: 132px; + border: 3px solid var(--line); + background: #f7fff5; + color: var(--ink); + box-shadow: 5px 5px 0 rgba(16,32,21,.16); + padding: 12px; + text-align: left; + cursor: pointer; + font-weight: 900; +} +.card-choice:hover { transform: translate(-1px, -1px); box-shadow: 6px 6px 0 rgba(16,32,21,.18); } +.card-choice strong { display: block; font-size: 14px; text-transform: uppercase; line-height: 1.2; } +.card-choice span { display: inline-block; margin: 8px 0; padding: 2px 7px; border: 2px solid var(--line); background: var(--white); font-size: 9px; letter-spacing: .1em; } +.card-tags { display: flex; flex-wrap: wrap; gap: 4px; margin: 7px 0; } +.card-tags span { margin: 0; padding: 2px 5px; font-size: 8px; line-height: 1.1; letter-spacing: .04em; } +.card-choice small { display: block; color: var(--muted); font-size: 11px; line-height: 1.35; } +.card-choice.rare { background: #fff0d1; box-shadow: inset 0 0 0 3px #f0a020, 5px 5px 0 rgba(16,32,21,.16); } +.card-choice.ultra-rare { background: #ffe6f0; box-shadow: inset 0 0 0 3px #c42424, 5px 5px 0 rgba(16,32,21,.18); } +.card-choice.ultra-rare span { background: #c42424; color: #fff; } +.muted-card-note { color: var(--muted); font-weight: 700; } +.card-targets { display: grid; gap: 8px; margin-top: 14px; } +.card-target-button { border: 3px solid var(--line); background: #f7fff5; padding: 10px 12px; text-align: left; cursor: pointer; font-weight: 900; box-shadow: 4px 4px 0 rgba(16,32,21,.14); } +.card-target-button:hover { background: var(--green-soft); } + +/* v19 readability pass */ +body { font-size: 16px; } +.hud-card span { font-size: 11px; } +.hud-card strong { font-size: clamp(18px, 1.5vw, 25px); } +.priority-strip > div { font-size: 14px; } +.panel-head h1 { font-size: 18px; } +.panel-head p { font-size: 11px; } +.build-panel h2 { font-size: 13px; } +.tool-button strong { font-size: 14px; } +.tool-button span { font-size: 11px; } +.mini-box, .event-card { font-size: 12px; } +.sort-button { font-size: 14px; } +.modal-card h2 { font-size: 29px; } +.card-choice strong { font-size: 16px; } +.card-choice small { font-size: 13px; } + +.tool-button.unaffordable, .tool-button.already-built { opacity: .42; filter: grayscale(.7); } + +.hover-tooltip { + position: fixed; + z-index: 30; + width: min(320px, calc(100vw - 20px)); + display: none; + border: 3px solid var(--line); + background: rgba(255,255,255,.96); + color: var(--ink); + box-shadow: 6px 6px 0 rgba(16,32,21,.18); + padding: 10px; + pointer-events: none; + line-height: 1.35; +} +.hover-tooltip.visible { display: block; } +.hover-tooltip strong { display: block; font-size: 15px; text-transform: uppercase; margin-bottom: 5px; } +.hover-tooltip em { display: block; font-style: normal; color: var(--green); font-weight: 900; margin-bottom: 7px; } +.hover-tooltip em.warning { color: var(--danger); } +.hover-tooltip span { display: block; color: var(--muted); font-size: 12px; } + + +.card-choice.dud { + background: #eeeeee; + color: #777; + filter: grayscale(1); + border-style: dashed; + box-shadow: 5px 5px 0 rgba(16,32,21,.10); +} +.card-choice.dud span { background: #f8f8f8; } +.card-choice.flung { + pointer-events: none; + transform: translate(var(--fling-x, 480px), var(--fling-y, -320px)) rotate(var(--fling-r, 68deg)) scale(.68); + opacity: 0; + transition: transform .34s cubic-bezier(.18,.84,.26,.99), opacity .28s ease-in; +} + + + +.route-card .route-icon.male, +.route-card .route-icon.female, +.route-card .route-icon.poop { + display: inline-grid; + place-items: center; + width: 38px; + height: 38px; + border-radius: 999px; + border: 3px solid var(--line, #102015); + background: var(--white, #fff); + line-height: 1; +} +.route-card .route-icon.male { color: #2477ff; background: #d9ecff; } +.route-card .route-icon.female { color: #d62a85; background: #ffe0f0; } +.route-card .route-icon.poop { color: #7b4a23; background: #fff0d1; font-size: 24px; } +.restart-button { min-width: 160px; } +.restart-fallback-note { margin-top: 12px; color: var(--muted, #526456); font-weight: 700; } + +/* v24.4 hover-only build-button flavor / cashout guidance / compact game-over */ +.tool-button .tool-flavor { + display: block; + max-height: 0; + opacity: 0; + overflow: hidden; + margin-top: 0; + color: var(--muted); + font-size: 8px; + line-height: 1.22; + text-transform: none; + letter-spacing: 0; + transition: max-height .12s ease, opacity .12s ease, margin-top .12s ease; +} +.tool-button:hover .tool-flavor { + max-height: 42px; + opacity: 1; + margin-top: 5px; +} +.large-tools .tool-button { min-height: 58px; } +.large-tools .tool-button:hover { min-height: 78px; } +.history-tools .tool-button.small { min-height: 40px; } +.primary-button.cashout-emphasis, +.tool-button.cashout-emphasis { + opacity: 1 !important; + filter: none !important; + animation: cashoutPulse 0.9s ease-in-out infinite alternate; +} +.primary-button.cashout-emphasis { + box-shadow: inset 0 0 0 4px #fff0d1, 6px 6px 0 rgba(16,32,21,.22); +} +.tool-button.cashout-emphasis { + background: #fff0d1; + box-shadow: inset 0 0 0 3px var(--danger), 6px 6px 0 rgba(16,32,21,.20); +} +@keyframes cashoutPulse { + from { transform: translate(0, 0); } + to { transform: translate(-1px, -1px); } +} +.modal.gameover-modal { padding: 12px; } +.modal.gameover-modal .modal-card { + width: min(640px, 92vw); + max-height: min(82vh, 720px); + overflow: auto; + padding: 16px; +} +.modal.gameover-modal .modal-card h2 { + font-size: 22px; + margin-bottom: 8px; +} +.gameover-reason { font-weight: 900; color: var(--danger); margin-bottom: 8px; } +.settlement-net { + border: 3px solid var(--line); + background: #f7fff5; + padding: 10px 12px; + margin-bottom: 10px; + display: flex; + justify-content: space-between; + align-items: center; + gap: 12px; + font-weight: 900; + text-transform: uppercase; +} +.settlement-net strong { font-size: 24px; } +.settlement-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; } +.settlement-grid div { padding: 8px; } +.settlement-grid span { display: block; font-size: 14px; } +.gameover-summary { + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 6px; + margin-top: 8px; +} +.gameover-breakdown { + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 6px; + margin-top: 8px; +} +.modal.gameover-modal .result-grid div { padding: 7px; } +.modal.gameover-modal .result-grid strong { font-size: 9px; margin-bottom: 3px; } +.modal.gameover-modal .result-grid span { font-size: 12px; } +.gameover-details { + margin-top: 10px; + border: 3px solid var(--line); + background: #f7fff5; + padding: 8px; +} +.gameover-details summary { + cursor: pointer; + font-weight: 900; + text-transform: uppercase; +} +.modal.gameover-modal .formula-box.compact { font-size: 9px; line-height: 1.35; } +@media (max-width: 720px) { + .gameover-summary, .gameover-breakdown { grid-template-columns: 1fr 1fr; } +} + +/* v27.0 cleanup and stable build-menu tooltip pass */ +body { font-size: 18px; } +.build-panel { width: clamp(330px, 26vw, 420px); } +.panel-head h1 { font-size: 20px; } +.panel-head h1 span { font-size: 12px; } +.panel-head p { font-size: 13px; line-height: 1.35; } +.build-panel h2 { font-size: 14px; } +.priority-strip > div { font-size: 15px; } +.hud-card span { font-size: 12px; } +.hud-card strong { font-size: clamp(20px, 1.7vw, 28px); } +.mini-box, .event-card { font-size: 14px; line-height: 1.45; } +.compact-rules .mini-box { font-size: 13px; } +.tool-button { + position: relative; + overflow: visible; + min-height: 62px; + padding: 10px; +} +.large-tools .tool-button { min-height: 62px; } +.large-tools .tool-button:hover { min-height: 62px; } +.tool-button strong { font-size: 15px; line-height: 1.15; } +.tool-button span { font-size: 12px; } +.tool-button .tool-flavor { + display: none; + position: absolute; + z-index: 60; + left: 0; + top: calc(100% + 7px); + width: min(300px, calc(100vw - 40px)); + max-height: none; + opacity: 1; + overflow: visible; + margin: 0; + padding: 10px 12px; + border: 3px solid var(--line); + background: rgba(255,255,255,.98); + color: var(--ink); + box-shadow: 5px 5px 0 rgba(16,32,21,.18); + font-size: 13px; + line-height: 1.35; + text-transform: none; + letter-spacing: 0; + pointer-events: none; + transition: none; +} +.tool-button .tool-flavor::before { + content: ''; + position: absolute; + left: 16px; + top: -10px; + width: 16px; + height: 16px; + border-left: 3px solid var(--line); + border-top: 3px solid var(--line); + background: rgba(255,255,255,.98); + transform: rotate(45deg); +} +.tool-button:hover .tool-flavor { + display: block; + max-height: none; + opacity: 1; + margin: 0; +} +.primary-button { font-size: 16px; padding: 13px 16px; } +#nextTurnButton { min-height: 56px; font-size: 18px; } +@keyframes cashoutPulse { + from { box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(16,32,21,.18); filter: brightness(1); } + to { box-shadow: inset 0 0 0 5px #fff0d1, 4px 4px 0 rgba(16,32,21,.20); filter: brightness(1.08); } +} +.card-choices { grid-template-columns: repeat(auto-fill, minmax(230px, 270px)); gap: 14px; } +.card-choice { min-height: 164px; padding: 15px; } +.card-choice strong { font-size: 18px; } +.card-choice span { font-size: 11px; } +.card-choice small { font-size: 15px; line-height: 1.4; } +.muted-card-note { font-size: 15px; line-height: 1.45; } +.modal-card { width: min(980px, 96vw); } +.modal-card p, .modal-card li { font-size: 16px; } +.modal-actions .reroll-button { + order: 99; + flex: 1 1 100%; + min-height: 64px; + margin-top: 8px; + font-size: 20px; + text-align: center; + justify-content: center; + background: #fff0d1; + box-shadow: inset 0 0 0 4px var(--green), 6px 6px 0 rgba(16,32,21,.20); +} +.modal-actions .reroll-button:disabled { box-shadow: 4px 4px 0 rgba(16,32,21,.12); } +.hover-tooltip strong { font-size: 17px; } +.hover-tooltip span { font-size: 14px; } +.sort-button { font-size: 16px; min-height: 56px; } +.control-dock { grid-template-columns: repeat(4, 172px); } +@media (max-width: 1180px) { + .build-panel { width: auto; } + .control-dock { grid-template-columns: repeat(2, 172px); } +} + +/* v27.1 expansion/readability pass */ +body { font-size: 20px; } +.panel-head h1 { font-size: 22px; } +.panel-head h1 span { font-size: 13px; } +.panel-head p { font-size: 14px; line-height: 1.35; } +.build-panel h2 { font-size: 15px; } +.priority-strip > div { font-size: 16px; } +.hud-card span { font-size: 13px; } +.hud-card strong { font-size: clamp(22px, 1.8vw, 30px); } +.mini-box, .event-card { font-size: 15px; line-height: 1.5; } +.compact-rules .mini-box { font-size: 14px; } +.tool-button strong { font-size: 16px; line-height: 1.15; } +.tool-button span { font-size: 13px; line-height: 1.2; } +.tool-button .tool-flavor { + left: auto; + right: 0; + width: min(320px, calc(100vw - 40px)); + font-size: 14px; + line-height: 1.4; + overflow-wrap: anywhere; +} +.tool-button .tool-flavor::before { left: auto; right: 18px; } +.tool-button.unaffordable .tool-flavor, +.tool-button.unaffordable:hover .tool-flavor, +.tool-button:disabled .tool-flavor, +.tool-button:disabled:hover .tool-flavor { display: none; } +.facility-action { font-size: 12px; } +.primary-button { font-size: 17px; } +#nextTurnButton { font-size: 19px; } +.card-choice strong { font-size: 19px; } +.card-choice span { font-size: 12px; } +.card-choice small { font-size: 16px; line-height: 1.45; } +.muted-card-note { font-size: 16px; } +.modal-card p, .modal-card li { font-size: 17px; } +.modal.equipment-popover .modal-card h2 { font-size: 16px; } +.modal.equipment-popover .modal-actions button { font-size: 11px; } +.equipment-menu-lines.compact, .formula-box.compact { font-size: 11px; } +.hover-tooltip strong { font-size: 18px; } + +/* Keep construction flavor text readable as a hover bubble, not button content. */ +.large-tools .tool-button { + min-height: 62px; + position: relative; + overflow: visible; +} +.large-tools .tool-button:hover { + min-height: 62px; +} +.large-tools .tool-button .tool-flavor { + display: none; + position: absolute; + z-index: 90; + right: 0; + top: calc(100% + 8px); + width: min(320px, calc(100vw - 40px)); + max-height: none; + opacity: 1; + overflow: visible; + margin: 0; + padding: 10px 12px; + border: 3px solid var(--line); + background: rgba(255,255,255,.98); + color: var(--ink); + box-shadow: 5px 5px 0 rgba(16,32,21,.18); + font-size: 14px; + line-height: 1.35; + pointer-events: none; + overflow-wrap: anywhere; +} +.large-tools .tool-button:hover .tool-flavor { + display: block; +} +.large-tools .tool-button .tool-flavor::before { + content: ''; + position: absolute; + right: 18px; + top: -10px; + width: 16px; + height: 16px; + border-left: 3px solid var(--line); + border-top: 3px solid var(--line); + background: rgba(255,255,255,.98); + transform: rotate(45deg); +} +.hover-tooltip span { font-size: 15px; } +.sort-button { font-size: 17px; } + +/* v27.3 offscreen scanner monitor / expansion UI pass */ +.scanner-monitor { + position: absolute; + z-index: 8; + left: 12px; + bottom: 92px; + display: none; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 8px; + width: min(560px, calc(100% - 24px)); + pointer-events: auto; +} +.scanner-monitor.visible { display: grid; } +.scanner-monitor-card { + border: 3px solid var(--line); + background: rgba(255,255,255,.95); + box-shadow: 5px 5px 0 rgba(16,32,21,.18); + padding: 9px; + font-weight: 900; +} +.scanner-monitor-card header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + margin-bottom: 7px; + text-transform: uppercase; +} +.scanner-monitor-card header strong { font-size: 20px; color: var(--green); } +.scanner-monitor-card header span { font-size: 12px; color: var(--muted); } +.scanner-mini-map { + display: grid; + grid-template-columns: 42px 1fr 82px; + align-items: center; + gap: 6px; + margin-bottom: 8px; +} +.scanner-mini-map > span, +.scanner-mini-map > b { + border: 2px solid var(--line); + background: #f7fff5; + padding: 7px 6px; + text-align: center; + font-size: 13px; + min-height: 36px; +} +.scanner-current { display: block; color: var(--ink); } +.scanner-current.male { color: #2477ff; } +.scanner-current.female { color: #d62a85; } +.scanner-current.poop { color: #7b4a23; } +.scanner-current.empty { color: var(--muted); } + +.scanner-mini-grid { + display: grid; + grid-template-columns: repeat(5, 27px); + gap: 3px; + justify-content: center; + align-items: center; + padding: 6px; + margin: 0 0 8px; + border: 2px solid var(--line); + background: #f6f1df; +} +.scanner-mini-grid .mini-cell { + width: 27px; + height: 27px; + display: grid; + place-items: center; + border: 1px solid rgba(22,38,25,.28); + background: #fffdfa; + color: var(--muted); + font-size: 11px; + font-weight: 900; + line-height: 1; +} +.scanner-mini-grid .mini-cell.belt { background: #e7f7e4; color: var(--green-dark); } +.scanner-mini-grid .mini-cell.input { background: #fff3bf; color: var(--ink); font-size: 9px; } +.scanner-mini-grid .mini-cell.scanner { background: var(--green); color: #fff; border-color: var(--line); font-size: 16px; } +.scanner-mini-grid .mini-cell.scanner.male { background: #2477ff; } +.scanner-mini-grid .mini-cell.scanner.female { background: #d62a85; } +.scanner-mini-grid .mini-cell.scanner.poop { background: #7b4a23; } +.scanner-mini-grid .mini-cell.scanner-other { background: #b7f5c6; color: var(--ink); } +.scanner-mini-grid .mini-cell.egg { background: #fff7c4; color: #7a5a00; } +.scanner-mini-grid .mini-cell.port { background: #dbe7ff; color: #27427d; } +.scanner-mini-grid .mini-cell.blocked { background: #d7cfc1; color: #6d4d35; } + +.scanner-monitor-actions { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 7px; +} +.scanner-monitor-actions button { + border: 3px solid var(--line); + background: var(--green-soft); + color: var(--ink); + cursor: pointer; + font: inherit; + font-size: 14px; + font-weight: 900; + min-height: 44px; + box-shadow: 3px 3px 0 rgba(16,32,21,.18); +} +.scanner-monitor-actions button:disabled { + background: #edf3ec; + color: var(--muted); + opacity: .62; + cursor: not-allowed; +} +@media (max-width: 1180px) { + .scanner-monitor { bottom: 132px; width: min(520px, calc(100% - 16px)); left: 8px; } +} + +/* ------------------------------------------------------------------ + DARK FACTORY VISUAL PASS + - Facility sprites are now loaded from assets/dark_factory/. + - Debug UI is intentionally retained for balancing builds. Do not remove. + ------------------------------------------------------------------ */ +:root { + --bg: #0b0c0f; + --screen: #111318; + --panel: rgba(24, 27, 34, 0.96); + --panel-2: #20242b; + --panel-3: #2a303a; + --ink: #e6edf2; + --muted: #8f9bab; + --line: #050609; + --green: #7bd84f; + --green-soft: #273c24; + --white: #e6edf2; + --danger: #e34a36; + --warn: #ffb827; + --cyan: #4aa3ff; + --orange: #c86a2b; + --shadow: 6px 6px 0 rgba(0, 0, 0, 0.62); +} +html, body { background: #050609; color: var(--ink); } +body { + background: + linear-gradient(90deg, rgba(255,184,39,.035) 1px, transparent 1px) 0 0 / 32px 32px, + linear-gradient(rgba(255,184,39,.028) 1px, transparent 1px) 0 0 / 32px 32px, + #050609; +} +#app { width: min(100vw, 1720px); padding: 0; } +.game-shell { + min-height: 100vh; + border: 0; + background: var(--screen); + box-shadow: inset 0 0 0 4px #050609, inset 0 0 0 8px #303744; +} +#gameCanvas { + height: 100vh; + min-height: 720px; + background: var(--screen); + image-rendering: pixelated; + image-rendering: crisp-edges; +} +.hud { gap: 4px; } +.hud-top-left { + top: 8px; + left: 8px; + right: 420px; + grid-template-columns: 1.25fr repeat(5, minmax(92px, .65fr)); +} +.hud-top-right { + top: 8px; + right: 8px; + grid-template-columns: repeat(4, minmax(74px, auto)); +} +.hud-card { + min-width: 74px; + padding: 7px 9px; + border: 3px solid var(--line); + background: linear-gradient(#242a33, #171a20); + box-shadow: 4px 4px 0 rgba(0,0,0,.7), inset 0 0 0 2px rgba(255,184,39,.10); + color: var(--ink); +} +.hud-card span { color: var(--warn); font-size: 9px; letter-spacing: .12em; } +.hud-card strong { color: var(--ink); text-shadow: 2px 2px 0 #050609; } +.hud-card.cash strong, .hud-card.profit strong, .hud-card.combo strong, .cash-positive { color: var(--green) !important; } +.hud-card.time-critical { background: #3a1f1f; box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(0,0,0,.7); } +.priority-strip { + top: 74px; + left: 10px; + width: clamp(250px, 21vw, 330px); + max-width: none; + grid-template-columns: 1fr; + gap: 6px; +} +.priority-strip > div { + border: 3px solid var(--line); + background: linear-gradient(#222832, #15181e); + color: var(--ink); + box-shadow: 4px 4px 0 rgba(0,0,0,.66), inset 0 0 0 2px rgba(255,184,39,.12); +} +.event-brief.active { background: #38251a; box-shadow: inset 0 0 0 3px var(--orange), 4px 4px 0 rgba(0,0,0,.66); } +.event-brief.next { background: #1c2c20; box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(0,0,0,.66); } +.event-brief.locked { background: #181b20; color: var(--muted); } +.target-brief { color: var(--warn); } +.speed-brief { color: var(--cyan); } +.build-panel { + top: 82px; + right: 8px; + bottom: 8px; + width: clamp(320px, 24vw, 410px); + padding: 9px; + border: 4px solid var(--line); + background: linear-gradient(#222832, #14171d); + box-shadow: 6px 6px 0 rgba(0,0,0,.72), inset 0 0 0 3px rgba(255,184,39,.10); + scrollbar-color: var(--warn) #111318; +} +.panel-head { + display: grid; + grid-template-columns: 1fr 126px; + align-items: stretch; + gap: 8px; + margin-bottom: 8px; +} +.panel-head h1 { color: var(--warn); text-shadow: 2px 2px 0 #050609; font-size: 17px; } +.panel-head h1 span { color: #050609; background: var(--warn); border-color: var(--line); } +.panel-head p { color: var(--muted); } +.panel-grid { + display: grid; + grid-template-columns: 1fr; + gap: 8px; +} +.build-panel h2, .result-section-title { color: var(--warn); } +.large-tools { + grid-template-columns: 1fr 1fr; + gap: 6px; +} +.tool-button, .primary-button, .sort-button, .facility-action { + border: 3px solid var(--line); + background: linear-gradient(#2a303a, #171a20); + color: var(--ink); + box-shadow: 4px 4px 0 rgba(0,0,0,.70), inset 0 0 0 2px rgba(255,184,39,.08); + text-shadow: 1px 1px 0 #050609; +} +.tool-button { min-height: 48px; padding: 8px; } +.tool-button strong { color: var(--ink); } +.tool-button span { color: var(--muted); } +.tool-button.active { + background: linear-gradient(#33311d, #1e2117); + box-shadow: inset 0 0 0 3px var(--warn), 4px 4px 0 rgba(0,0,0,.70); +} +.tool-button.danger.active { background: linear-gradient(#4b1f1c, #241014); box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(0,0,0,.70); } +.primary-button { background: linear-gradient(#8b2d23, #4b1714); color: #fff3d2; } +.primary-button:not(:disabled) { box-shadow: inset 0 0 0 3px #ffb827, 5px 5px 0 rgba(0,0,0,.72); } +.primary-button:disabled, .tool-button:disabled, .sort-button:disabled, .facility-action:disabled { opacity: .42; filter: grayscale(1); } +.mini-box, .event-card, .formula-box, .equipment-menu-lines, .route-card, .result-grid div, .muted-title { + border: 3px solid var(--line); + background: #15181e; + color: var(--muted); + box-shadow: inset 0 0 0 2px rgba(255,184,39,.08); +} +.event-card h3, .event-card strong, .event-metrics span { color: var(--ink); } +.event-card.accepted { background: #1c2c20; box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(0,0,0,.66); } +.event-card.empty { background: #15181e; color: var(--muted); } +.event-metrics span { border-color: #3d4654; background: #20242b; } +.event-status { background: #2a303a; color: var(--warn); border-color: var(--line); } +.control-dock { + left: 50%; + right: auto; + bottom: 8px; + transform: translateX(-50%); + grid-template-columns: repeat(4, minmax(135px, 160px)); + gap: 6px; + padding: 6px; + border: 4px solid var(--line); + background: rgba(13,15,19,.96); + box-shadow: 5px 5px 0 rgba(0,0,0,.72), inset 0 0 0 2px rgba(255,184,39,.10); +} +.sort-button { min-height: 44px; font-size: 12px; } +.scanner-monitor { + position: absolute; + z-index: 5; + left: 10px; + top: 198px; + width: clamp(250px, 21vw, 330px); +} +.scanner-monitor-card { + border: 3px solid var(--line) !important; + background: linear-gradient(#222832, #15181e) !important; + color: var(--ink) !important; + box-shadow: 4px 4px 0 rgba(0,0,0,.66), inset 0 0 0 2px rgba(255,184,39,.10) !important; +} +.scanner-monitor-card strong { color: var(--warn); } +.debug-panel { + left: auto; + right: 12px; + bottom: 10px; + width: min(420px, calc(100% - 24px)); + border-color: var(--line); + background: rgba(16,18,23,.97); + box-shadow: 5px 5px 0 rgba(0,0,0,.72), inset 0 0 0 2px rgba(227,74,54,.18); + color: var(--ink); +} +.debug-panel summary { color: var(--danger); } +.debug-body { border-top-color: var(--line); } +.debug-body button, .debug-body input[type="number"], .debug-body select, .debug-readout { + border-color: var(--line); + background: #20242b; + color: var(--ink); +} +.debug-readout { color: var(--muted); } +.modal { background: rgba(3,4,6,.72); } +.modal-card { + border-color: var(--line); + background: linear-gradient(#242a33, #15181e); + color: var(--ink); + box-shadow: 8px 8px 0 rgba(0,0,0,.72), inset 0 0 0 3px rgba(255,184,39,.12); +} +.modal-card h2 { color: var(--warn); text-shadow: 2px 2px 0 #050609; } +.modal-card ul, .modal-card p { color: var(--muted); } +.hover-tooltip { + border-color: var(--line) !important; + background: rgba(20,23,29,.98) !important; + color: var(--ink) !important; + box-shadow: 5px 5px 0 rgba(0,0,0,.72) !important; +} +::-webkit-scrollbar { width: 14px; height: 14px; } +::-webkit-scrollbar-track { background: #111318; } +::-webkit-scrollbar-thumb { background: #333b48; border: 3px solid #111318; } +::-webkit-scrollbar-thumb:hover { background: #ffb827; } +@media (max-width: 1180px) { + .hud-top-left { right: 8px; grid-template-columns: repeat(3, minmax(80px, 1fr)); } + .hud-top-right { top: 132px; left: 8px; right: auto; grid-template-columns: repeat(2, minmax(82px, auto)); } + .priority-strip { top: 226px; } + .scanner-monitor { top: 348px; } + .build-panel { left: 8px; right: 8px; bottom: 8px; width: auto; max-height: 46vh; } + .control-dock { grid-template-columns: repeat(2, 150px); } +} + +/* v27.16: compact collapsed debug panel + icon card layout */ +.debug-panel:not([open]) { + width: 104px !important; + min-width: 0; + overflow: hidden; +} +.debug-panel:not([open]) summary { + display: block; + width: 100%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.debug-panel[open] { + width: min(420px, calc(100% - 24px)); +} + +.card-choice { + position: relative; + display: grid; + grid-template-columns: 54px minmax(0, 1fr); + gap: 10px; + align-items: start; + min-height: 150px; + overflow: hidden; + background: + linear-gradient(135deg, rgba(255,255,255,.08), rgba(0,0,0,.20)), + #20242b; + border-color: var(--line); +} +.card-choice::before { + content: ""; + position: absolute; + inset: 5px; + border: 1px solid rgba(255,184,39,.18); + pointer-events: none; +} +.card-icon { + position: relative; + z-index: 1; + width: 46px; + height: 46px; + display: grid; + place-items: center; + border: 3px solid var(--line); + background: #15181e; + box-shadow: inset 0 0 0 2px rgba(255,184,39,.10), 3px 3px 0 rgba(0,0,0,.35); + image-rendering: pixelated; +} +.card-icon img { + width: 36px; + height: 36px; + object-fit: contain; + image-rendering: pixelated; +} +.card-icon.glyph { + color: var(--warn, #ffb827); + font-size: 24px; + font-weight: 900; + text-align: center; + line-height: 1; +} +.card-copy { + position: relative; + z-index: 1; + min-width: 0; +} +.card-choice strong { + color: var(--warn, #ffb827); + text-shadow: 1px 1px 0 #050609; +} +.card-choice small { color: var(--muted); } +.card-tags span { + background: #15181e; + color: var(--white); + border-color: var(--line); +} +.card-choice.common { background: linear-gradient(145deg, #262c35, #171a20); } +.card-choice.rare { + background: linear-gradient(145deg, #3b3020, #191b20); + box-shadow: inset 0 0 0 3px #f0a020, 5px 5px 0 rgba(0,0,0,.50); +} +.card-choice.ultra-rare { + background: linear-gradient(145deg, #401d2a, #171a20); + box-shadow: inset 0 0 0 3px #c42424, 5px 5px 0 rgba(0,0,0,.55); +} +.card-choice.dud { + background: linear-gradient(145deg, #2b2b2b, #191919); + color: #878787; +} +.card-choice.dud .card-tags span { background: #222; color: #aaa; } + +@media (max-width: 1180px) { + .debug-panel:not([open]) { + width: 92px !important; + right: 8px; + bottom: 8px; + } +} + + +/* v27.17 verified visual patch: cache-proof identity and final UI overrides */ +.build-stamp { + position: absolute; + z-index: 12; + right: 14px; + top: 76px; + padding: 5px 9px; + border: 2px solid #ffb827; + background: rgba(14, 17, 22, .94); + color: #80e067; + box-shadow: 3px 3px 0 rgba(0,0,0,.7); + font: 900 11px/1 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; + letter-spacing: .04em; + pointer-events: none; +} +.debug-panel:not([open]) { + width: 58px !important; + max-width: 58px !important; + height: 30px; + min-height: 0; +} +.debug-panel:not([open]) summary { + box-sizing: border-box; + width: 58px; + height: 27px; + padding: 5px 7px; + text-align: center; + overflow: hidden; + text-overflow: clip; +} +.debug-panel[open] { + width: min(390px, calc(100% - 24px)) !important; + height: auto; +} +.card-choice { + border-width: 3px; + box-shadow: 4px 4px 0 rgba(0,0,0,.55), inset 0 0 0 1px rgba(255,184,39,.14); +} +.card-choice:hover { + transform: translateY(-2px); + box-shadow: 4px 6px 0 rgba(0,0,0,.65), inset 0 0 0 2px rgba(128,224,103,.24); +} +.card-icon img { + image-rendering: pixelated; + filter: drop-shadow(2px 2px 0 rgba(0,0,0,.7)); +} +#gameCanvas { image-rendering: pixelated; } diff --git a/styles-v27.18.css b/styles-v27.18.css new file mode 100644 index 0000000..8bb1b90 --- /dev/null +++ b/styles-v27.18.css @@ -0,0 +1,1253 @@ +:root { + --bg: #f2fff0; + --screen: #eefbea; + --panel: rgba(245, 255, 242, 0.96); + --ink: #102015; + --muted: #526456; + --line: #102015; + --green: #22b94f; + --green-soft: #b7f5c6; + --white: #ffffff; + --danger: #c42424; + --shadow: 8px 8px 0 rgba(16, 32, 21, 0.22); +} +* { box-sizing: border-box; } +html, body { min-height: 100%; } +body { margin: 0; background: var(--bg); color: var(--ink); font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; overflow-x: hidden; } +button { font: inherit; } +h1, h2, p { margin: 0; } +#app { width: min(100vw, 1680px); margin: 0 auto; padding: 0 8px 12px; } +.game-shell { position: relative; width: 100%; min-height: min(100vh, 920px); border: 4px solid var(--line); border-top: 0; background: var(--screen); overflow: hidden; box-shadow: var(--shadow); } +#gameCanvas { display: block; width: 100%; height: min(calc(100vh - 10px), 900px); min-height: 720px; background: var(--screen); touch-action: none; } +.hud { position: absolute; z-index: 4; display: grid; gap: 6px; pointer-events: none; } +.hud-top-left { top: 10px; left: 10px; grid-template-columns: repeat(6, minmax(82px, auto)); } +.hud-top-right { top: 10px; right: 10px; grid-template-columns: repeat(4, minmax(78px, auto)); } +.hud-card { min-width: 82px; padding: 7px 9px; border: 3px solid var(--line); background: rgba(255,255,255,.88); box-shadow: 4px 4px 0 rgba(16,32,21,.16); } +.hud-card.primary { min-width: 116px; padding: 10px 12px; background: rgba(255,255,255,.96); } +.hud-card.primary span { font-size: 9px; } +.hud-card.primary strong { font-size: clamp(22px, 2vw, 32px); } +.hud-card.time-critical { background: #fff0d1; box-shadow: inset 0 0 0 4px var(--danger), 4px 4px 0 rgba(16,32,21,.16); } +.hud-card span { display: block; font-size: 9px; letter-spacing: .1em; color: var(--muted); margin-bottom: 4px; } +.hud-card strong { font-size: clamp(15px, 1.3vw, 22px); line-height: 1; color: var(--ink); } +.hud-card.cash strong, .hud-card.profit strong, .hud-card.combo strong, .cash-positive { color: var(--green) !important; } +.cash-negative { color: var(--danger) !important; } + +.priority-strip { position: absolute; z-index: 5; top: 76px; left: 10px; display: grid; grid-template-columns: minmax(280px, 1.2fr) minmax(170px, .75fr) minmax(130px, .55fr); gap: 8px; max-width: calc(100% - 420px); pointer-events: none; } +.priority-strip > div { border: 3px solid var(--line); background: rgba(255,255,255,.94); padding: 8px 10px; font-weight: 900; text-transform: uppercase; box-shadow: 4px 4px 0 rgba(16,32,21,.14); font-size: 12px; letter-spacing: .03em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.event-brief.active { background: #fff0d1; box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(16,32,21,.14); } +.event-brief.next { background: var(--green-soft); box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(16,32,21,.14); } +.event-brief.locked { background: #edf3ec; color: var(--muted); } +.target-brief { color: var(--green); } +.speed-brief { color: var(--ink); } + +.build-panel { position: absolute; z-index: 6; top: 118px; right: 12px; bottom: 12px; width: clamp(278px, 23vw, 360px); min-height: 0; padding: 10px; border: 4px solid var(--line); background: var(--panel); box-shadow: var(--shadow); overflow: auto; } +.panel-head { display: grid; gap: 8px; margin-bottom: 10px; } +.panel-head h1 { font-size: 15px; letter-spacing: .06em; } +.panel-head h1 span { font-size: 9px; color: var(--white); background: var(--green); border: 2px solid var(--line); padding: 1px 6px; } +.panel-head p { color: var(--muted); margin-top: 4px; font-size: 9px; line-height: 1.25; } +.panel-grid { display: grid; grid-template-columns: 1fr; gap: 10px; } +.build-panel h2 { font-size: 11px; text-transform: uppercase; letter-spacing: .1em; margin-bottom: 7px; } +.large-tools { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; } +.history-tools { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; grid-column: 1 / -1; } +.tool-button.small { min-height: 40px; padding: 6px; } +.tool-button, .primary-button, .sort-button, .facility-action { border: 3px solid var(--line); background: var(--white); color: var(--ink); font-weight: 900; text-transform: uppercase; cursor: pointer; box-shadow: 4px 4px 0 rgba(16,32,21,.18); } +.tool-button { min-height: 50px; text-align: left; padding: 8px; } +.tool-button strong { display: block; font-size: 12px; } +.tool-button span { display: block; margin-top: 4px; font-size: 9px; color: var(--muted); } +.tool-button.active { background: var(--green-soft); box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(16,32,21,.18); } +.tool-button.danger.active { background: #ffdada; box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(16,32,21,.18); } +.primary-button { padding: 10px 12px; background: var(--green); color: var(--white); white-space: nowrap; } +.primary-button:disabled, .tool-button:disabled, .sort-button:disabled, .facility-action:disabled { opacity: .42; cursor: not-allowed; } +.mini-box { border: 3px solid var(--line); background: var(--white); padding: 12px; line-height: 1.45; color: var(--muted); font-size: 11px; } +.facility-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; } +.facility-action { padding: 7px 9px; font-size: 9px; } +.facility-action.good { background: var(--green-soft); } +.facility-action.warn { background: #fff0d1; } +.facility-action.danger { background: #ffdada; } +.control-dock { position: absolute; z-index: 7; left: 50%; bottom: 12px; transform: translateX(-50%); display: grid; grid-template-columns: repeat(4, 150px); gap: 8px; padding: 7px; border: 3px solid var(--line); background: rgba(255,255,255,.90); } +.sort-button { min-height: 46px; font-size: 12px; } +/* Debug UI is intentionally kept for active balancing builds. Do not remove during cleanup/audit passes unless explicitly requested. */ +.debug-panel { + position: absolute; + z-index: 9; + left: 10px; + bottom: 10px; + width: min(410px, calc(100% - 20px)); + border: 3px solid var(--line); + background: rgba(255,255,255,.96); + box-shadow: 4px 4px 0 rgba(16,32,21,.16); + font-weight: 900; +} +.debug-panel summary { + cursor: pointer; + padding: 5px 8px; + color: var(--danger); + font-size: 14px; + line-height: 1.1; +} +.debug-body { + display: grid; + grid-template-columns: 1fr 92px; + gap: 6px; + padding: 7px; + border-top: 3px solid var(--line); + font-size: 12px; + line-height: 1.15; +} +.debug-body label, +.debug-body button, +.debug-body select, +.debug-body input { + min-width: 0; + font: inherit; +} +.debug-check, +.debug-card, +.debug-target, +.debug-readout { + grid-column: 1 / -1; +} +.debug-row { + display: grid; + grid-template-columns: 1fr 92px; + gap: 6px; + grid-column: 1 / -1; +} +.debug-day { + display: grid; + grid-template-columns: 38px 1fr; + align-items: center; + gap: 4px; +} +.debug-body button { + border: 2px solid var(--line); + background: var(--white); + cursor: pointer; + font-weight: 900; + padding: 5px 6px; + line-height: 1.05; +} +.debug-body input[type="number"], +.debug-body select { + width: 100%; + border: 2px solid var(--line); + background: var(--white); + padding: 4px 5px; + min-height: 29px; +} +.debug-target select:disabled { + opacity: .55; +} +.debug-readout { + border: 2px solid var(--line); + background: #f7fff5; + color: var(--muted); + padding: 5px; + line-height: 1.25; + max-height: 64px; + overflow: auto; +} +.modal { position: fixed; inset: 0; z-index: 20; display: none; align-items: center; justify-content: center; padding: 22px; background: rgba(16,32,21,.45); } +.modal.visible { display: flex; } +.modal-card { width: min(860px, 96vw); border: 4px solid var(--line); padding: 24px; background: var(--white); box-shadow: var(--shadow); } +.modal-card h2 { font-size: 26px; text-transform: uppercase; margin-bottom: 12px; } +.modal-card p { line-height: 1.55; } +.modal-card ul { margin: 12px 0 0; padding-left: 22px; line-height: 1.55; color: var(--muted); } +.modal-actions { margin-top: 18px; display: flex; justify-content: flex-end; gap: 10px; flex-wrap: wrap; } +.route-cards { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; margin: 14px 0; } +.route-card { border: 3px solid var(--line); background: #f7fff5; padding: 14px; display: grid; grid-template-columns: 44px 1fr 28px 1fr; align-items: center; gap: 4px 8px; } +.route-card .route-icon { grid-row: 1 / span 2; font-size: 30px; text-align: center; } +.route-card strong, .route-card em { font-style: normal; font-weight: 900; text-transform: uppercase; } +.route-card b { font-size: 24px; color: var(--green); text-align: center; } +.route-card small { grid-column: 2 / span 3; color: var(--muted); font-weight: 900; } +.result-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin-top: 12px; } +.result-grid div { border: 3px solid var(--line); padding: 10px; background: #f7fff5; } +.result-grid strong { display: block; font-size: 11px; color: var(--muted); text-transform: uppercase; margin-bottom: 6px; } +.result-grid span { font-size: 16px; font-weight: 900; color: var(--ink); } +.game-shell:not(.phase-build) .build-panel { display: none; } +.game-shell.phase-running .hud-top-right { display: none; } +.game-shell:not(.phase-running) .control-dock { display: none; } +@media (max-width: 1180px) { + #app { padding: 0; } + .game-shell { min-height: 100vh; } + #gameCanvas { height: 100vh; } + .hud-top-left, .hud-top-right { grid-template-columns: repeat(2, minmax(76px, auto)); } + .priority-strip { top: 150px; left: 8px; right: 8px; max-width: none; grid-template-columns: 1fr; } + .build-panel { top: auto; left: 8px; right: 8px; bottom: 8px; width: auto; max-height: 42vh; } + .large-tools { grid-template-columns: 1fr 1fr; } + .control-dock { grid-template-columns: repeat(2, 150px); } + .route-cards, .result-grid { grid-template-columns: 1fr; } +} + +.event-card { border: 3px solid var(--line); background: #f7fff5; padding: 12px; line-height: 1.35; color: var(--ink); font-size: 11px; box-shadow: 4px 4px 0 rgba(16,32,21,.14); } +.event-card.empty { color: var(--muted); background: rgba(255,255,255,.72); } +.event-card.empty strong { display: block; color: var(--ink); margin-bottom: 4px; } +.event-card h3 { margin: 2px 0 7px; font-size: 14px; text-transform: uppercase; letter-spacing: .04em; } +.event-card p { margin: 5px 0; } +.event-card.accepted { background: var(--green-soft); box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(16,32,21,.14); } +.event-card.declined { background: #f1f1f1; color: var(--muted); } +.event-status { display: inline-block; padding: 2px 7px; border: 2px solid var(--line); background: var(--white); font-size: 9px; font-weight: 900; letter-spacing: .1em; margin-bottom: 4px; } +.event-metrics { display: grid; grid-template-columns: 1fr; gap: 4px; margin: 8px 0; } +.event-metrics span { display: block; border: 2px solid rgba(16,32,21,.55); background: rgba(255,255,255,.82); padding: 5px; font-weight: 900; color: var(--ink); } +.event-actions { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; } +.result-section-title { margin: 16px 0 8px; font-size: 12px; font-weight: 900; text-transform: uppercase; letter-spacing: .12em; color: var(--green); } +.result-section-title:first-child { margin-top: 0; } +.muted-title { color: var(--muted); border: 3px solid var(--line); padding: 10px; background: #f7fff5; } + +.compact-rules .mini-box { padding: 8px; font-size: 9px; } +.primary-button:disabled { filter: grayscale(1); background: #c9d2ca; color: #526456; } +.formula-box { + border: 3px solid var(--line); + background: #f7fff5; + padding: 10px; + margin: 10px 0; + line-height: 1.5; + color: var(--ink); + font-size: 12px; + font-weight: 700; +} +.equipment-menu-lines { + border: 3px solid var(--line); + background: #ffffff; + padding: 10px; + margin: 8px 0; + color: var(--muted); + line-height: 1.45; +} +.equipment-menu-lines p { margin: 4px 0; } + +/* v11 compact clicked-equipment bubble */ +.modal.equipment-popover { + background: transparent; + align-items: flex-start; + justify-content: flex-start; + padding: 0; + pointer-events: none; +} +.modal.equipment-popover .modal-card { + position: absolute; + left: var(--popover-x, 16px); + top: var(--popover-y, 16px); + width: min(250px, calc(100vw - 24px)); + max-height: min(280px, calc(100vh - 24px)); + overflow: auto; + padding: 8px; + border-width: 3px; + pointer-events: auto; + box-shadow: 6px 6px 0 rgba(16,32,21,.18); +} +.modal.equipment-popover .modal-card h2 { + font-size: 14px; + margin-bottom: 6px; +} +.modal.equipment-popover .modal-actions { + margin-top: 8px; + gap: 6px; + justify-content: flex-start; +} +.modal.equipment-popover .modal-actions button { + padding: 5px 7px; + font-size: 9px; +} +.equipment-menu-lines.compact { + padding: 7px; + margin: 6px 0; + font-size: 9px; +} +.formula-box.compact { + padding: 7px; + margin: 6px 0; + font-size: 9px; +} + +/* v15 pre-build card draft */ +.card-choices { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(190px, 220px)); + justify-content: center; + align-items: stretch; + gap: 10px; + margin-top: 14px; +} +.card-choice { + min-height: 132px; + border: 3px solid var(--line); + background: #f7fff5; + color: var(--ink); + box-shadow: 5px 5px 0 rgba(16,32,21,.16); + padding: 12px; + text-align: left; + cursor: pointer; + font-weight: 900; +} +.card-choice:hover { transform: translate(-1px, -1px); box-shadow: 6px 6px 0 rgba(16,32,21,.18); } +.card-choice strong { display: block; font-size: 14px; text-transform: uppercase; line-height: 1.2; } +.card-choice span { display: inline-block; margin: 8px 0; padding: 2px 7px; border: 2px solid var(--line); background: var(--white); font-size: 9px; letter-spacing: .1em; } +.card-tags { display: flex; flex-wrap: wrap; gap: 4px; margin: 7px 0; } +.card-tags span { margin: 0; padding: 2px 5px; font-size: 8px; line-height: 1.1; letter-spacing: .04em; } +.card-choice small { display: block; color: var(--muted); font-size: 11px; line-height: 1.35; } +.card-choice.rare { background: #fff0d1; box-shadow: inset 0 0 0 3px #f0a020, 5px 5px 0 rgba(16,32,21,.16); } +.card-choice.ultra-rare { background: #ffe6f0; box-shadow: inset 0 0 0 3px #c42424, 5px 5px 0 rgba(16,32,21,.18); } +.card-choice.ultra-rare span { background: #c42424; color: #fff; } +.muted-card-note { color: var(--muted); font-weight: 700; } +.card-targets { display: grid; gap: 8px; margin-top: 14px; } +.card-target-button { border: 3px solid var(--line); background: #f7fff5; padding: 10px 12px; text-align: left; cursor: pointer; font-weight: 900; box-shadow: 4px 4px 0 rgba(16,32,21,.14); } +.card-target-button:hover { background: var(--green-soft); } + +/* v19 readability pass */ +body { font-size: 16px; } +.hud-card span { font-size: 11px; } +.hud-card strong { font-size: clamp(18px, 1.5vw, 25px); } +.priority-strip > div { font-size: 14px; } +.panel-head h1 { font-size: 18px; } +.panel-head p { font-size: 11px; } +.build-panel h2 { font-size: 13px; } +.tool-button strong { font-size: 14px; } +.tool-button span { font-size: 11px; } +.mini-box, .event-card { font-size: 12px; } +.sort-button { font-size: 14px; } +.modal-card h2 { font-size: 29px; } +.card-choice strong { font-size: 16px; } +.card-choice small { font-size: 13px; } + +.tool-button.unaffordable, .tool-button.already-built { opacity: .42; filter: grayscale(.7); } + +.hover-tooltip { + position: fixed; + z-index: 30; + width: min(320px, calc(100vw - 20px)); + display: none; + border: 3px solid var(--line); + background: rgba(255,255,255,.96); + color: var(--ink); + box-shadow: 6px 6px 0 rgba(16,32,21,.18); + padding: 10px; + pointer-events: none; + line-height: 1.35; +} +.hover-tooltip.visible { display: block; } +.hover-tooltip strong { display: block; font-size: 15px; text-transform: uppercase; margin-bottom: 5px; } +.hover-tooltip em { display: block; font-style: normal; color: var(--green); font-weight: 900; margin-bottom: 7px; } +.hover-tooltip em.warning { color: var(--danger); } +.hover-tooltip span { display: block; color: var(--muted); font-size: 12px; } + + +.card-choice.dud { + background: #eeeeee; + color: #777; + filter: grayscale(1); + border-style: dashed; + box-shadow: 5px 5px 0 rgba(16,32,21,.10); +} +.card-choice.dud span { background: #f8f8f8; } +.card-choice.flung { + pointer-events: none; + transform: translate(var(--fling-x, 480px), var(--fling-y, -320px)) rotate(var(--fling-r, 68deg)) scale(.68); + opacity: 0; + transition: transform .34s cubic-bezier(.18,.84,.26,.99), opacity .28s ease-in; +} + + + +.route-card .route-icon.male, +.route-card .route-icon.female, +.route-card .route-icon.poop { + display: inline-grid; + place-items: center; + width: 38px; + height: 38px; + border-radius: 999px; + border: 3px solid var(--line, #102015); + background: var(--white, #fff); + line-height: 1; +} +.route-card .route-icon.male { color: #2477ff; background: #d9ecff; } +.route-card .route-icon.female { color: #d62a85; background: #ffe0f0; } +.route-card .route-icon.poop { color: #7b4a23; background: #fff0d1; font-size: 24px; } +.restart-button { min-width: 160px; } +.restart-fallback-note { margin-top: 12px; color: var(--muted, #526456); font-weight: 700; } + +/* v24.4 hover-only build-button flavor / cashout guidance / compact game-over */ +.tool-button .tool-flavor { + display: block; + max-height: 0; + opacity: 0; + overflow: hidden; + margin-top: 0; + color: var(--muted); + font-size: 8px; + line-height: 1.22; + text-transform: none; + letter-spacing: 0; + transition: max-height .12s ease, opacity .12s ease, margin-top .12s ease; +} +.tool-button:hover .tool-flavor { + max-height: 42px; + opacity: 1; + margin-top: 5px; +} +.large-tools .tool-button { min-height: 58px; } +.large-tools .tool-button:hover { min-height: 78px; } +.history-tools .tool-button.small { min-height: 40px; } +.primary-button.cashout-emphasis, +.tool-button.cashout-emphasis { + opacity: 1 !important; + filter: none !important; + animation: cashoutPulse 0.9s ease-in-out infinite alternate; +} +.primary-button.cashout-emphasis { + box-shadow: inset 0 0 0 4px #fff0d1, 6px 6px 0 rgba(16,32,21,.22); +} +.tool-button.cashout-emphasis { + background: #fff0d1; + box-shadow: inset 0 0 0 3px var(--danger), 6px 6px 0 rgba(16,32,21,.20); +} +@keyframes cashoutPulse { + from { transform: translate(0, 0); } + to { transform: translate(-1px, -1px); } +} +.modal.gameover-modal { padding: 12px; } +.modal.gameover-modal .modal-card { + width: min(640px, 92vw); + max-height: min(82vh, 720px); + overflow: auto; + padding: 16px; +} +.modal.gameover-modal .modal-card h2 { + font-size: 22px; + margin-bottom: 8px; +} +.gameover-reason { font-weight: 900; color: var(--danger); margin-bottom: 8px; } +.settlement-net { + border: 3px solid var(--line); + background: #f7fff5; + padding: 10px 12px; + margin-bottom: 10px; + display: flex; + justify-content: space-between; + align-items: center; + gap: 12px; + font-weight: 900; + text-transform: uppercase; +} +.settlement-net strong { font-size: 24px; } +.settlement-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; } +.settlement-grid div { padding: 8px; } +.settlement-grid span { display: block; font-size: 14px; } +.gameover-summary { + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 6px; + margin-top: 8px; +} +.gameover-breakdown { + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 6px; + margin-top: 8px; +} +.modal.gameover-modal .result-grid div { padding: 7px; } +.modal.gameover-modal .result-grid strong { font-size: 9px; margin-bottom: 3px; } +.modal.gameover-modal .result-grid span { font-size: 12px; } +.gameover-details { + margin-top: 10px; + border: 3px solid var(--line); + background: #f7fff5; + padding: 8px; +} +.gameover-details summary { + cursor: pointer; + font-weight: 900; + text-transform: uppercase; +} +.modal.gameover-modal .formula-box.compact { font-size: 9px; line-height: 1.35; } +@media (max-width: 720px) { + .gameover-summary, .gameover-breakdown { grid-template-columns: 1fr 1fr; } +} + +/* v27.0 cleanup and stable build-menu tooltip pass */ +body { font-size: 18px; } +.build-panel { width: clamp(330px, 26vw, 420px); } +.panel-head h1 { font-size: 20px; } +.panel-head h1 span { font-size: 12px; } +.panel-head p { font-size: 13px; line-height: 1.35; } +.build-panel h2 { font-size: 14px; } +.priority-strip > div { font-size: 15px; } +.hud-card span { font-size: 12px; } +.hud-card strong { font-size: clamp(20px, 1.7vw, 28px); } +.mini-box, .event-card { font-size: 14px; line-height: 1.45; } +.compact-rules .mini-box { font-size: 13px; } +.tool-button { + position: relative; + overflow: visible; + min-height: 62px; + padding: 10px; +} +.large-tools .tool-button { min-height: 62px; } +.large-tools .tool-button:hover { min-height: 62px; } +.tool-button strong { font-size: 15px; line-height: 1.15; } +.tool-button span { font-size: 12px; } +.tool-button .tool-flavor { + display: none; + position: absolute; + z-index: 60; + left: 0; + top: calc(100% + 7px); + width: min(300px, calc(100vw - 40px)); + max-height: none; + opacity: 1; + overflow: visible; + margin: 0; + padding: 10px 12px; + border: 3px solid var(--line); + background: rgba(255,255,255,.98); + color: var(--ink); + box-shadow: 5px 5px 0 rgba(16,32,21,.18); + font-size: 13px; + line-height: 1.35; + text-transform: none; + letter-spacing: 0; + pointer-events: none; + transition: none; +} +.tool-button .tool-flavor::before { + content: ''; + position: absolute; + left: 16px; + top: -10px; + width: 16px; + height: 16px; + border-left: 3px solid var(--line); + border-top: 3px solid var(--line); + background: rgba(255,255,255,.98); + transform: rotate(45deg); +} +.tool-button:hover .tool-flavor { + display: block; + max-height: none; + opacity: 1; + margin: 0; +} +.primary-button { font-size: 16px; padding: 13px 16px; } +#nextTurnButton { min-height: 56px; font-size: 18px; } +@keyframes cashoutPulse { + from { box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(16,32,21,.18); filter: brightness(1); } + to { box-shadow: inset 0 0 0 5px #fff0d1, 4px 4px 0 rgba(16,32,21,.20); filter: brightness(1.08); } +} +.card-choices { grid-template-columns: repeat(auto-fill, minmax(230px, 270px)); gap: 14px; } +.card-choice { min-height: 164px; padding: 15px; } +.card-choice strong { font-size: 18px; } +.card-choice span { font-size: 11px; } +.card-choice small { font-size: 15px; line-height: 1.4; } +.muted-card-note { font-size: 15px; line-height: 1.45; } +.modal-card { width: min(980px, 96vw); } +.modal-card p, .modal-card li { font-size: 16px; } +.modal-actions .reroll-button { + order: 99; + flex: 1 1 100%; + min-height: 64px; + margin-top: 8px; + font-size: 20px; + text-align: center; + justify-content: center; + background: #fff0d1; + box-shadow: inset 0 0 0 4px var(--green), 6px 6px 0 rgba(16,32,21,.20); +} +.modal-actions .reroll-button:disabled { box-shadow: 4px 4px 0 rgba(16,32,21,.12); } +.hover-tooltip strong { font-size: 17px; } +.hover-tooltip span { font-size: 14px; } +.sort-button { font-size: 16px; min-height: 56px; } +.control-dock { grid-template-columns: repeat(4, 172px); } +@media (max-width: 1180px) { + .build-panel { width: auto; } + .control-dock { grid-template-columns: repeat(2, 172px); } +} + +/* v27.1 expansion/readability pass */ +body { font-size: 20px; } +.panel-head h1 { font-size: 22px; } +.panel-head h1 span { font-size: 13px; } +.panel-head p { font-size: 14px; line-height: 1.35; } +.build-panel h2 { font-size: 15px; } +.priority-strip > div { font-size: 16px; } +.hud-card span { font-size: 13px; } +.hud-card strong { font-size: clamp(22px, 1.8vw, 30px); } +.mini-box, .event-card { font-size: 15px; line-height: 1.5; } +.compact-rules .mini-box { font-size: 14px; } +.tool-button strong { font-size: 16px; line-height: 1.15; } +.tool-button span { font-size: 13px; line-height: 1.2; } +.tool-button .tool-flavor { + left: auto; + right: 0; + width: min(320px, calc(100vw - 40px)); + font-size: 14px; + line-height: 1.4; + overflow-wrap: anywhere; +} +.tool-button .tool-flavor::before { left: auto; right: 18px; } +.tool-button.unaffordable .tool-flavor, +.tool-button.unaffordable:hover .tool-flavor, +.tool-button:disabled .tool-flavor, +.tool-button:disabled:hover .tool-flavor { display: none; } +.facility-action { font-size: 12px; } +.primary-button { font-size: 17px; } +#nextTurnButton { font-size: 19px; } +.card-choice strong { font-size: 19px; } +.card-choice span { font-size: 12px; } +.card-choice small { font-size: 16px; line-height: 1.45; } +.muted-card-note { font-size: 16px; } +.modal-card p, .modal-card li { font-size: 17px; } +.modal.equipment-popover .modal-card h2 { font-size: 16px; } +.modal.equipment-popover .modal-actions button { font-size: 11px; } +.equipment-menu-lines.compact, .formula-box.compact { font-size: 11px; } +.hover-tooltip strong { font-size: 18px; } + +/* Keep construction flavor text readable as a hover bubble, not button content. */ +.large-tools .tool-button { + min-height: 62px; + position: relative; + overflow: visible; +} +.large-tools .tool-button:hover { + min-height: 62px; +} +.large-tools .tool-button .tool-flavor { + display: none; + position: absolute; + z-index: 90; + right: 0; + top: calc(100% + 8px); + width: min(320px, calc(100vw - 40px)); + max-height: none; + opacity: 1; + overflow: visible; + margin: 0; + padding: 10px 12px; + border: 3px solid var(--line); + background: rgba(255,255,255,.98); + color: var(--ink); + box-shadow: 5px 5px 0 rgba(16,32,21,.18); + font-size: 14px; + line-height: 1.35; + pointer-events: none; + overflow-wrap: anywhere; +} +.large-tools .tool-button:hover .tool-flavor { + display: block; +} +.large-tools .tool-button .tool-flavor::before { + content: ''; + position: absolute; + right: 18px; + top: -10px; + width: 16px; + height: 16px; + border-left: 3px solid var(--line); + border-top: 3px solid var(--line); + background: rgba(255,255,255,.98); + transform: rotate(45deg); +} +.hover-tooltip span { font-size: 15px; } +.sort-button { font-size: 17px; } + +/* v27.3 offscreen scanner monitor / expansion UI pass */ +.scanner-monitor { + position: absolute; + z-index: 8; + left: 12px; + bottom: 92px; + display: none; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 8px; + width: min(560px, calc(100% - 24px)); + pointer-events: auto; +} +.scanner-monitor.visible { display: grid; } +.scanner-monitor-card { + border: 3px solid var(--line); + background: rgba(255,255,255,.95); + box-shadow: 5px 5px 0 rgba(16,32,21,.18); + padding: 9px; + font-weight: 900; +} +.scanner-monitor-card header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + margin-bottom: 7px; + text-transform: uppercase; +} +.scanner-monitor-card header strong { font-size: 20px; color: var(--green); } +.scanner-monitor-card header span { font-size: 12px; color: var(--muted); } +.scanner-mini-map { + display: grid; + grid-template-columns: 42px 1fr 82px; + align-items: center; + gap: 6px; + margin-bottom: 8px; +} +.scanner-mini-map > span, +.scanner-mini-map > b { + border: 2px solid var(--line); + background: #f7fff5; + padding: 7px 6px; + text-align: center; + font-size: 13px; + min-height: 36px; +} +.scanner-current { display: block; color: var(--ink); } +.scanner-current.male { color: #2477ff; } +.scanner-current.female { color: #d62a85; } +.scanner-current.poop { color: #7b4a23; } +.scanner-current.empty { color: var(--muted); } + +.scanner-mini-grid { + display: grid; + grid-template-columns: repeat(5, 27px); + gap: 3px; + justify-content: center; + align-items: center; + padding: 6px; + margin: 0 0 8px; + border: 2px solid var(--line); + background: #f6f1df; +} +.scanner-mini-grid .mini-cell { + width: 27px; + height: 27px; + display: grid; + place-items: center; + border: 1px solid rgba(22,38,25,.28); + background: #fffdfa; + color: var(--muted); + font-size: 11px; + font-weight: 900; + line-height: 1; +} +.scanner-mini-grid .mini-cell.belt { background: #e7f7e4; color: var(--green-dark); } +.scanner-mini-grid .mini-cell.input { background: #fff3bf; color: var(--ink); font-size: 9px; } +.scanner-mini-grid .mini-cell.scanner { background: var(--green); color: #fff; border-color: var(--line); font-size: 16px; } +.scanner-mini-grid .mini-cell.scanner.male { background: #2477ff; } +.scanner-mini-grid .mini-cell.scanner.female { background: #d62a85; } +.scanner-mini-grid .mini-cell.scanner.poop { background: #7b4a23; } +.scanner-mini-grid .mini-cell.scanner-other { background: #b7f5c6; color: var(--ink); } +.scanner-mini-grid .mini-cell.egg { background: #fff7c4; color: #7a5a00; } +.scanner-mini-grid .mini-cell.port { background: #dbe7ff; color: #27427d; } +.scanner-mini-grid .mini-cell.blocked { background: #d7cfc1; color: #6d4d35; } + +.scanner-monitor-actions { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 7px; +} +.scanner-monitor-actions button { + border: 3px solid var(--line); + background: var(--green-soft); + color: var(--ink); + cursor: pointer; + font: inherit; + font-size: 14px; + font-weight: 900; + min-height: 44px; + box-shadow: 3px 3px 0 rgba(16,32,21,.18); +} +.scanner-monitor-actions button:disabled { + background: #edf3ec; + color: var(--muted); + opacity: .62; + cursor: not-allowed; +} +@media (max-width: 1180px) { + .scanner-monitor { bottom: 132px; width: min(520px, calc(100% - 16px)); left: 8px; } +} + +/* ------------------------------------------------------------------ + DARK FACTORY VISUAL PASS + - Facility sprites are now loaded from assets/dark_factory/. + - Debug UI is intentionally retained for balancing builds. Do not remove. + ------------------------------------------------------------------ */ +:root { + --bg: #0b0c0f; + --screen: #111318; + --panel: rgba(24, 27, 34, 0.96); + --panel-2: #20242b; + --panel-3: #2a303a; + --ink: #e6edf2; + --muted: #8f9bab; + --line: #050609; + --green: #7bd84f; + --green-soft: #273c24; + --white: #e6edf2; + --danger: #e34a36; + --warn: #ffb827; + --cyan: #4aa3ff; + --orange: #c86a2b; + --shadow: 6px 6px 0 rgba(0, 0, 0, 0.62); +} +html, body { background: #050609; color: var(--ink); } +body { + background: + linear-gradient(90deg, rgba(255,184,39,.035) 1px, transparent 1px) 0 0 / 32px 32px, + linear-gradient(rgba(255,184,39,.028) 1px, transparent 1px) 0 0 / 32px 32px, + #050609; +} +#app { width: min(100vw, 1720px); padding: 0; } +.game-shell { + min-height: 100vh; + border: 0; + background: var(--screen); + box-shadow: inset 0 0 0 4px #050609, inset 0 0 0 8px #303744; +} +#gameCanvas { + height: 100vh; + min-height: 720px; + background: var(--screen); + image-rendering: pixelated; + image-rendering: crisp-edges; +} +.hud { gap: 4px; } +.hud-top-left { + top: 8px; + left: 8px; + right: 420px; + grid-template-columns: 1.25fr repeat(5, minmax(92px, .65fr)); +} +.hud-top-right { + top: 8px; + right: 8px; + grid-template-columns: repeat(4, minmax(74px, auto)); +} +.hud-card { + min-width: 74px; + padding: 7px 9px; + border: 3px solid var(--line); + background: linear-gradient(#242a33, #171a20); + box-shadow: 4px 4px 0 rgba(0,0,0,.7), inset 0 0 0 2px rgba(255,184,39,.10); + color: var(--ink); +} +.hud-card span { color: var(--warn); font-size: 9px; letter-spacing: .12em; } +.hud-card strong { color: var(--ink); text-shadow: 2px 2px 0 #050609; } +.hud-card.cash strong, .hud-card.profit strong, .hud-card.combo strong, .cash-positive { color: var(--green) !important; } +.hud-card.time-critical { background: #3a1f1f; box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(0,0,0,.7); } +.priority-strip { + top: 74px; + left: 10px; + width: clamp(250px, 21vw, 330px); + max-width: none; + grid-template-columns: 1fr; + gap: 6px; +} +.priority-strip > div { + border: 3px solid var(--line); + background: linear-gradient(#222832, #15181e); + color: var(--ink); + box-shadow: 4px 4px 0 rgba(0,0,0,.66), inset 0 0 0 2px rgba(255,184,39,.12); +} +.event-brief.active { background: #38251a; box-shadow: inset 0 0 0 3px var(--orange), 4px 4px 0 rgba(0,0,0,.66); } +.event-brief.next { background: #1c2c20; box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(0,0,0,.66); } +.event-brief.locked { background: #181b20; color: var(--muted); } +.target-brief { color: var(--warn); } +.speed-brief { color: var(--cyan); } +.build-panel { + top: 82px; + right: 8px; + bottom: 8px; + width: clamp(320px, 24vw, 410px); + padding: 9px; + border: 4px solid var(--line); + background: linear-gradient(#222832, #14171d); + box-shadow: 6px 6px 0 rgba(0,0,0,.72), inset 0 0 0 3px rgba(255,184,39,.10); + scrollbar-color: var(--warn) #111318; +} +.panel-head { + display: grid; + grid-template-columns: 1fr 126px; + align-items: stretch; + gap: 8px; + margin-bottom: 8px; +} +.panel-head h1 { color: var(--warn); text-shadow: 2px 2px 0 #050609; font-size: 17px; } +.panel-head h1 span { color: #050609; background: var(--warn); border-color: var(--line); } +.panel-head p { color: var(--muted); } +.panel-grid { + display: grid; + grid-template-columns: 1fr; + gap: 8px; +} +.build-panel h2, .result-section-title { color: var(--warn); } +.large-tools { + grid-template-columns: 1fr 1fr; + gap: 6px; +} +.tool-button, .primary-button, .sort-button, .facility-action { + border: 3px solid var(--line); + background: linear-gradient(#2a303a, #171a20); + color: var(--ink); + box-shadow: 4px 4px 0 rgba(0,0,0,.70), inset 0 0 0 2px rgba(255,184,39,.08); + text-shadow: 1px 1px 0 #050609; +} +.tool-button { min-height: 48px; padding: 8px; } +.tool-button strong { color: var(--ink); } +.tool-button span { color: var(--muted); } +.tool-button.active { + background: linear-gradient(#33311d, #1e2117); + box-shadow: inset 0 0 0 3px var(--warn), 4px 4px 0 rgba(0,0,0,.70); +} +.tool-button.danger.active { background: linear-gradient(#4b1f1c, #241014); box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(0,0,0,.70); } +.primary-button { background: linear-gradient(#8b2d23, #4b1714); color: #fff3d2; } +.primary-button:not(:disabled) { box-shadow: inset 0 0 0 3px #ffb827, 5px 5px 0 rgba(0,0,0,.72); } +.primary-button:disabled, .tool-button:disabled, .sort-button:disabled, .facility-action:disabled { opacity: .42; filter: grayscale(1); } +.mini-box, .event-card, .formula-box, .equipment-menu-lines, .route-card, .result-grid div, .muted-title { + border: 3px solid var(--line); + background: #15181e; + color: var(--muted); + box-shadow: inset 0 0 0 2px rgba(255,184,39,.08); +} +.event-card h3, .event-card strong, .event-metrics span { color: var(--ink); } +.event-card.accepted { background: #1c2c20; box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(0,0,0,.66); } +.event-card.empty { background: #15181e; color: var(--muted); } +.event-metrics span { border-color: #3d4654; background: #20242b; } +.event-status { background: #2a303a; color: var(--warn); border-color: var(--line); } +.control-dock { + left: 50%; + right: auto; + bottom: 8px; + transform: translateX(-50%); + grid-template-columns: repeat(4, minmax(135px, 160px)); + gap: 6px; + padding: 6px; + border: 4px solid var(--line); + background: rgba(13,15,19,.96); + box-shadow: 5px 5px 0 rgba(0,0,0,.72), inset 0 0 0 2px rgba(255,184,39,.10); +} +.sort-button { min-height: 44px; font-size: 12px; } +.scanner-monitor { + position: absolute; + z-index: 5; + left: 10px; + top: 198px; + width: clamp(250px, 21vw, 330px); +} +.scanner-monitor-card { + border: 3px solid var(--line) !important; + background: linear-gradient(#222832, #15181e) !important; + color: var(--ink) !important; + box-shadow: 4px 4px 0 rgba(0,0,0,.66), inset 0 0 0 2px rgba(255,184,39,.10) !important; +} +.scanner-monitor-card strong { color: var(--warn); } +.debug-panel { + left: auto; + right: 12px; + bottom: 10px; + width: min(420px, calc(100% - 24px)); + border-color: var(--line); + background: rgba(16,18,23,.97); + box-shadow: 5px 5px 0 rgba(0,0,0,.72), inset 0 0 0 2px rgba(227,74,54,.18); + color: var(--ink); +} +.debug-panel summary { color: var(--danger); } +.debug-body { border-top-color: var(--line); } +.debug-body button, .debug-body input[type="number"], .debug-body select, .debug-readout { + border-color: var(--line); + background: #20242b; + color: var(--ink); +} +.debug-readout { color: var(--muted); } +.modal { background: rgba(3,4,6,.72); } +.modal-card { + border-color: var(--line); + background: linear-gradient(#242a33, #15181e); + color: var(--ink); + box-shadow: 8px 8px 0 rgba(0,0,0,.72), inset 0 0 0 3px rgba(255,184,39,.12); +} +.modal-card h2 { color: var(--warn); text-shadow: 2px 2px 0 #050609; } +.modal-card ul, .modal-card p { color: var(--muted); } +.hover-tooltip { + border-color: var(--line) !important; + background: rgba(20,23,29,.98) !important; + color: var(--ink) !important; + box-shadow: 5px 5px 0 rgba(0,0,0,.72) !important; +} +::-webkit-scrollbar { width: 14px; height: 14px; } +::-webkit-scrollbar-track { background: #111318; } +::-webkit-scrollbar-thumb { background: #333b48; border: 3px solid #111318; } +::-webkit-scrollbar-thumb:hover { background: #ffb827; } +@media (max-width: 1180px) { + .hud-top-left { right: 8px; grid-template-columns: repeat(3, minmax(80px, 1fr)); } + .hud-top-right { top: 132px; left: 8px; right: auto; grid-template-columns: repeat(2, minmax(82px, auto)); } + .priority-strip { top: 226px; } + .scanner-monitor { top: 348px; } + .build-panel { left: 8px; right: 8px; bottom: 8px; width: auto; max-height: 46vh; } + .control-dock { grid-template-columns: repeat(2, 150px); } +} + +/* v27.16: compact collapsed debug panel + icon card layout */ +.debug-panel:not([open]) { + width: 104px !important; + min-width: 0; + overflow: hidden; +} +.debug-panel:not([open]) summary { + display: block; + width: 100%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.debug-panel[open] { + width: min(420px, calc(100% - 24px)); +} + +.card-choice { + position: relative; + display: grid; + grid-template-columns: 54px minmax(0, 1fr); + gap: 10px; + align-items: start; + min-height: 150px; + overflow: hidden; + background: + linear-gradient(135deg, rgba(255,255,255,.08), rgba(0,0,0,.20)), + #20242b; + border-color: var(--line); +} +.card-choice::before { + content: ""; + position: absolute; + inset: 5px; + border: 1px solid rgba(255,184,39,.18); + pointer-events: none; +} +.card-icon { + position: relative; + z-index: 1; + width: 46px; + height: 46px; + display: grid; + place-items: center; + border: 3px solid var(--line); + background: #15181e; + box-shadow: inset 0 0 0 2px rgba(255,184,39,.10), 3px 3px 0 rgba(0,0,0,.35); + image-rendering: pixelated; +} +.card-icon img { + width: 36px; + height: 36px; + object-fit: contain; + image-rendering: pixelated; +} +.card-icon.glyph { + color: var(--warn, #ffb827); + font-size: 24px; + font-weight: 900; + text-align: center; + line-height: 1; +} +.card-copy { + position: relative; + z-index: 1; + min-width: 0; +} +.card-choice strong { + color: var(--warn, #ffb827); + text-shadow: 1px 1px 0 #050609; +} +.card-choice small { color: var(--muted); } +.card-tags span { + background: #15181e; + color: var(--white); + border-color: var(--line); +} +.card-choice.common { background: linear-gradient(145deg, #262c35, #171a20); } +.card-choice.rare { + background: linear-gradient(145deg, #3b3020, #191b20); + box-shadow: inset 0 0 0 3px #f0a020, 5px 5px 0 rgba(0,0,0,.50); +} +.card-choice.ultra-rare { + background: linear-gradient(145deg, #401d2a, #171a20); + box-shadow: inset 0 0 0 3px #c42424, 5px 5px 0 rgba(0,0,0,.55); +} +.card-choice.dud { + background: linear-gradient(145deg, #2b2b2b, #191919); + color: #878787; +} +.card-choice.dud .card-tags span { background: #222; color: #aaa; } + +@media (max-width: 1180px) { + .debug-panel:not([open]) { + width: 92px !important; + right: 8px; + bottom: 8px; + } +} + + +/* v27.18 inherited cache-proof identity and final UI overrides */ +.build-stamp { + position: absolute; + z-index: 12; + right: 14px; + top: 76px; + padding: 5px 9px; + border: 2px solid #ffb827; + background: rgba(14, 17, 22, .94); + color: #80e067; + box-shadow: 3px 3px 0 rgba(0,0,0,.7); + font: 900 11px/1 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; + letter-spacing: .04em; + pointer-events: none; +} +.debug-panel:not([open]) { + width: 58px !important; + max-width: 58px !important; + height: 30px; + min-height: 0; +} +.debug-panel:not([open]) summary { + box-sizing: border-box; + width: 58px; + height: 27px; + padding: 5px 7px; + text-align: center; + overflow: hidden; + text-overflow: clip; +} +.debug-panel[open] { + width: min(390px, calc(100% - 24px)) !important; + height: auto; +} +.card-choice { + border-width: 3px; + box-shadow: 4px 4px 0 rgba(0,0,0,.55), inset 0 0 0 1px rgba(255,184,39,.14); +} +.card-choice:hover { + transform: translateY(-2px); + box-shadow: 4px 6px 0 rgba(0,0,0,.65), inset 0 0 0 2px rgba(128,224,103,.24); +} +.card-icon img { + image-rendering: pixelated; + filter: drop-shadow(2px 2px 0 rgba(0,0,0,.7)); +} +#gameCanvas { image-rendering: pixelated; } + +/* v27.18: status relocation, consistent industrial controls, card watermarks */ +.hud-top-left { grid-template-columns: repeat(5, minmax(82px, auto)); } + +.left-bottom-status { + position: absolute; + z-index: 6; + left: 10px; + bottom: 10px; + width: min(310px, calc(100% - 20px)); + display: grid; + grid-template-columns: 1fr 1fr; + gap: 6px; + pointer-events: none; +} +.left-bottom-status > div { + min-width: 0; + border: 3px solid var(--line); + background: rgba(22, 26, 32, .95); + color: var(--ink); + padding: 8px 10px; + box-shadow: 4px 4px 0 rgba(0,0,0,.68), inset 0 0 0 1px rgba(255,184,39,.10); + font-size: 12px; + line-height: 1.2; + font-weight: 900; + text-transform: uppercase; + letter-spacing: .025em; + overflow: hidden; + text-overflow: ellipsis; +} +.left-bottom-status .event-brief { grid-column: 1 / -1; white-space: normal; min-height: 39px; } +.left-bottom-status .event-brief.active { background: #35221c; box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(0,0,0,.68); } +.left-bottom-status .event-brief.next { background: #22301f; box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(0,0,0,.68); } +.left-bottom-status .event-brief.locked { background: #1c2027; color: var(--muted); } +.left-bottom-status .speed-brief { color: #d9e2e8; } +.left-bottom-status .target-brief { color: #ffcf68; } +.left-bottom-status .combo-brief { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; } +.left-bottom-status .combo-brief span { color: var(--muted); font-size: 10px; } +.left-bottom-status .combo-brief strong { color: var(--green); font-size: 22px; line-height: 1; } + +/* Remove the remaining bright green/white control styling from modal actions. */ +.modal-actions button, +.facility-action, +.card-target-button { + border: 3px solid #07080a; + background: linear-gradient(#353d48, #1b1f25); + color: #e6edf2; + box-shadow: inset 0 0 0 1px rgba(255,184,39,.14), 4px 4px 0 rgba(0,0,0,.68); +} +.modal-actions button:hover:not(:disabled), +.facility-action:hover:not(:disabled), +.card-target-button:hover:not(:disabled) { + background: linear-gradient(#424b58, #242930); + color: #fff0c9; + box-shadow: inset 0 0 0 2px rgba(255,184,39,.42), 4px 4px 0 rgba(0,0,0,.72); +} +.facility-action.warn, +.modal-actions .reroll-button { + background: linear-gradient(#554221, #2b2419); + color: #ffd36a; + box-shadow: inset 0 0 0 3px #b97810, 5px 5px 0 rgba(0,0,0,.72); +} +.modal-actions .reroll-button:hover:not(:disabled) { + background: linear-gradient(#6b5227, #342919); + color: #fff0bd; + box-shadow: inset 0 0 0 3px #ffb827, 5px 5px 0 rgba(0,0,0,.76); +} +.facility-action.good { background: linear-gradient(#29422a, #19271a); color: #a9ed91; } +.facility-action.danger { background: linear-gradient(#57251f, #2d1715); color: #ffb1a3; } +.modal-actions button:disabled, +.facility-action:disabled, +.card-target-button:disabled { opacity: .42; filter: grayscale(.85); box-shadow: 3px 3px 0 rgba(0,0,0,.45); } + +/* Icons are now translucent background art rather than separate foreground badges. */ +.card-choice { + display: block; + min-height: 170px; + padding: 16px; + isolation: isolate; +} +.card-choice::before { z-index: 1; } +.card-copy { position: relative; z-index: 3; padding-right: 6px; } +.card-icon { + position: absolute; + z-index: 0; + right: -9px; + bottom: -12px; + width: 124px; + height: 124px; + border: 0; + background: transparent; + box-shadow: none; + opacity: .14; + transform: rotate(-7deg); + pointer-events: none; + overflow: visible; +} +.card-icon img { + width: 100%; + height: 100%; + object-fit: contain; + filter: grayscale(.12) contrast(1.2) drop-shadow(3px 3px 0 rgba(0,0,0,.55)); +} +.card-icon.glyph { + display: grid; + place-items: center; + color: #f0b437; + font-size: 88px; + line-height: 1; + text-shadow: 4px 4px 0 rgba(0,0,0,.55); +} +.card-choice.rare .card-icon { opacity: .16; } +.card-choice.ultra-rare .card-icon { opacity: .17; } +.card-choice.dud .card-icon { opacity: .08; filter: grayscale(1); } + +@media (max-width: 1180px) { + .hud-top-left { grid-template-columns: repeat(3, minmax(80px, 1fr)); } + .left-bottom-status { width: 290px; left: 8px; bottom: 8px; } +} +@media (max-width: 760px) { + .left-bottom-status { width: min(270px, calc(100% - 16px)); grid-template-columns: 1fr; } + .left-bottom-status .event-brief { grid-column: auto; } +} diff --git a/styles-v27.19.css b/styles-v27.19.css new file mode 100644 index 0000000..3ddf905 --- /dev/null +++ b/styles-v27.19.css @@ -0,0 +1,1279 @@ +:root { + --bg: #f2fff0; + --screen: #eefbea; + --panel: rgba(245, 255, 242, 0.96); + --ink: #102015; + --muted: #526456; + --line: #102015; + --green: #22b94f; + --green-soft: #b7f5c6; + --white: #ffffff; + --danger: #c42424; + --shadow: 8px 8px 0 rgba(16, 32, 21, 0.22); +} +* { box-sizing: border-box; } +html, body { min-height: 100%; } +body { margin: 0; background: var(--bg); color: var(--ink); font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; overflow-x: hidden; } +button { font: inherit; } +h1, h2, p { margin: 0; } +#app { width: min(100vw, 1680px); margin: 0 auto; padding: 0 8px 12px; } +.game-shell { position: relative; width: 100%; min-height: min(100vh, 920px); border: 4px solid var(--line); border-top: 0; background: var(--screen); overflow: hidden; box-shadow: var(--shadow); } +#gameCanvas { display: block; width: 100%; height: min(calc(100vh - 10px), 900px); min-height: 720px; background: var(--screen); touch-action: none; } +.hud { position: absolute; z-index: 4; display: grid; gap: 6px; pointer-events: none; } +.hud-top-left { top: 10px; left: 10px; grid-template-columns: repeat(6, minmax(82px, auto)); } +.hud-top-right { top: 10px; right: 10px; grid-template-columns: repeat(4, minmax(78px, auto)); } +.hud-card { min-width: 82px; padding: 7px 9px; border: 3px solid var(--line); background: rgba(255,255,255,.88); box-shadow: 4px 4px 0 rgba(16,32,21,.16); } +.hud-card.primary { min-width: 116px; padding: 10px 12px; background: rgba(255,255,255,.96); } +.hud-card.primary span { font-size: 9px; } +.hud-card.primary strong { font-size: clamp(22px, 2vw, 32px); } +.hud-card.time-critical { background: #fff0d1; box-shadow: inset 0 0 0 4px var(--danger), 4px 4px 0 rgba(16,32,21,.16); } +.hud-card span { display: block; font-size: 9px; letter-spacing: .1em; color: var(--muted); margin-bottom: 4px; } +.hud-card strong { font-size: clamp(15px, 1.3vw, 22px); line-height: 1; color: var(--ink); } +.hud-card.cash strong, .hud-card.profit strong, .hud-card.combo strong, .cash-positive { color: var(--green) !important; } +.cash-negative { color: var(--danger) !important; } + +.priority-strip { position: absolute; z-index: 5; top: 76px; left: 10px; display: grid; grid-template-columns: minmax(280px, 1.2fr) minmax(170px, .75fr) minmax(130px, .55fr); gap: 8px; max-width: calc(100% - 420px); pointer-events: none; } +.priority-strip > div { border: 3px solid var(--line); background: rgba(255,255,255,.94); padding: 8px 10px; font-weight: 900; text-transform: uppercase; box-shadow: 4px 4px 0 rgba(16,32,21,.14); font-size: 12px; letter-spacing: .03em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.event-brief.active { background: #fff0d1; box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(16,32,21,.14); } +.event-brief.next { background: var(--green-soft); box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(16,32,21,.14); } +.event-brief.locked { background: #edf3ec; color: var(--muted); } +.target-brief { color: var(--green); } +.speed-brief { color: var(--ink); } + +.build-panel { position: absolute; z-index: 6; top: 118px; right: 12px; bottom: 12px; width: clamp(278px, 23vw, 360px); min-height: 0; padding: 10px; border: 4px solid var(--line); background: var(--panel); box-shadow: var(--shadow); overflow: auto; } +.panel-head { display: grid; gap: 8px; margin-bottom: 10px; } +.panel-head h1 { font-size: 15px; letter-spacing: .06em; } +.panel-head h1 span { font-size: 9px; color: var(--white); background: var(--green); border: 2px solid var(--line); padding: 1px 6px; } +.panel-head p { color: var(--muted); margin-top: 4px; font-size: 9px; line-height: 1.25; } +.panel-grid { display: grid; grid-template-columns: 1fr; gap: 10px; } +.build-panel h2 { font-size: 11px; text-transform: uppercase; letter-spacing: .1em; margin-bottom: 7px; } +.large-tools { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; } +.history-tools { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; grid-column: 1 / -1; } +.tool-button.small { min-height: 40px; padding: 6px; } +.tool-button, .primary-button, .sort-button, .facility-action { border: 3px solid var(--line); background: var(--white); color: var(--ink); font-weight: 900; text-transform: uppercase; cursor: pointer; box-shadow: 4px 4px 0 rgba(16,32,21,.18); } +.tool-button { min-height: 50px; text-align: left; padding: 8px; } +.tool-button strong { display: block; font-size: 12px; } +.tool-button span { display: block; margin-top: 4px; font-size: 9px; color: var(--muted); } +.tool-button.active { background: var(--green-soft); box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(16,32,21,.18); } +.tool-button.danger.active { background: #ffdada; box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(16,32,21,.18); } +.primary-button { padding: 10px 12px; background: var(--green); color: var(--white); white-space: nowrap; } +.primary-button:disabled, .tool-button:disabled, .sort-button:disabled, .facility-action:disabled { opacity: .42; cursor: not-allowed; } +.mini-box { border: 3px solid var(--line); background: var(--white); padding: 12px; line-height: 1.45; color: var(--muted); font-size: 11px; } +.facility-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; } +.facility-action { padding: 7px 9px; font-size: 9px; } +.facility-action.good { background: var(--green-soft); } +.facility-action.warn { background: #fff0d1; } +.facility-action.danger { background: #ffdada; } +.control-dock { position: absolute; z-index: 7; left: 50%; bottom: 12px; transform: translateX(-50%); display: grid; grid-template-columns: repeat(4, 150px); gap: 8px; padding: 7px; border: 3px solid var(--line); background: rgba(255,255,255,.90); } +.sort-button { min-height: 46px; font-size: 12px; } +/* Debug UI is intentionally kept for active balancing builds. Do not remove during cleanup/audit passes unless explicitly requested. */ +.debug-panel { + position: absolute; + z-index: 9; + left: 10px; + bottom: 10px; + width: min(410px, calc(100% - 20px)); + border: 3px solid var(--line); + background: rgba(255,255,255,.96); + box-shadow: 4px 4px 0 rgba(16,32,21,.16); + font-weight: 900; +} +.debug-panel summary { + cursor: pointer; + padding: 5px 8px; + color: var(--danger); + font-size: 14px; + line-height: 1.1; +} +.debug-body { + display: grid; + grid-template-columns: 1fr 92px; + gap: 6px; + padding: 7px; + border-top: 3px solid var(--line); + font-size: 12px; + line-height: 1.15; +} +.debug-body label, +.debug-body button, +.debug-body select, +.debug-body input { + min-width: 0; + font: inherit; +} +.debug-check, +.debug-card, +.debug-target, +.debug-readout { + grid-column: 1 / -1; +} +.debug-row { + display: grid; + grid-template-columns: 1fr 92px; + gap: 6px; + grid-column: 1 / -1; +} +.debug-day { + display: grid; + grid-template-columns: 38px 1fr; + align-items: center; + gap: 4px; +} +.debug-body button { + border: 2px solid var(--line); + background: var(--white); + cursor: pointer; + font-weight: 900; + padding: 5px 6px; + line-height: 1.05; +} +.debug-body input[type="number"], +.debug-body select { + width: 100%; + border: 2px solid var(--line); + background: var(--white); + padding: 4px 5px; + min-height: 29px; +} +.debug-target select:disabled { + opacity: .55; +} +.debug-readout { + border: 2px solid var(--line); + background: #f7fff5; + color: var(--muted); + padding: 5px; + line-height: 1.25; + max-height: 64px; + overflow: auto; +} +.modal { position: fixed; inset: 0; z-index: 20; display: none; align-items: center; justify-content: center; padding: 22px; background: rgba(16,32,21,.45); } +.modal.visible { display: flex; } +.modal-card { width: min(860px, 96vw); border: 4px solid var(--line); padding: 24px; background: var(--white); box-shadow: var(--shadow); } +.modal-card h2 { font-size: 26px; text-transform: uppercase; margin-bottom: 12px; } +.modal-card p { line-height: 1.55; } +.modal-card ul { margin: 12px 0 0; padding-left: 22px; line-height: 1.55; color: var(--muted); } +.modal-actions { margin-top: 18px; display: flex; justify-content: flex-end; gap: 10px; flex-wrap: wrap; } +.route-cards { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; margin: 14px 0; } +.route-card { border: 3px solid var(--line); background: #f7fff5; padding: 14px; display: grid; grid-template-columns: 44px 1fr 28px 1fr; align-items: center; gap: 4px 8px; } +.route-card .route-icon { grid-row: 1 / span 2; font-size: 30px; text-align: center; } +.route-card strong, .route-card em { font-style: normal; font-weight: 900; text-transform: uppercase; } +.route-card b { font-size: 24px; color: var(--green); text-align: center; } +.route-card small { grid-column: 2 / span 3; color: var(--muted); font-weight: 900; } +.result-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin-top: 12px; } +.result-grid div { border: 3px solid var(--line); padding: 10px; background: #f7fff5; } +.result-grid strong { display: block; font-size: 11px; color: var(--muted); text-transform: uppercase; margin-bottom: 6px; } +.result-grid span { font-size: 16px; font-weight: 900; color: var(--ink); } +.game-shell:not(.phase-build) .build-panel { display: none; } +.game-shell.phase-running .hud-top-right { display: none; } +.game-shell:not(.phase-running) .control-dock { display: none; } +@media (max-width: 1180px) { + #app { padding: 0; } + .game-shell { min-height: 100vh; } + #gameCanvas { height: 100vh; } + .hud-top-left, .hud-top-right { grid-template-columns: repeat(2, minmax(76px, auto)); } + .priority-strip { top: 150px; left: 8px; right: 8px; max-width: none; grid-template-columns: 1fr; } + .build-panel { top: auto; left: 8px; right: 8px; bottom: 8px; width: auto; max-height: 42vh; } + .large-tools { grid-template-columns: 1fr 1fr; } + .control-dock { grid-template-columns: repeat(2, 150px); } + .route-cards, .result-grid { grid-template-columns: 1fr; } +} + +.event-card { border: 3px solid var(--line); background: #f7fff5; padding: 12px; line-height: 1.35; color: var(--ink); font-size: 11px; box-shadow: 4px 4px 0 rgba(16,32,21,.14); } +.event-card.empty { color: var(--muted); background: rgba(255,255,255,.72); } +.event-card.empty strong { display: block; color: var(--ink); margin-bottom: 4px; } +.event-card h3 { margin: 2px 0 7px; font-size: 14px; text-transform: uppercase; letter-spacing: .04em; } +.event-card p { margin: 5px 0; } +.event-card.accepted { background: var(--green-soft); box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(16,32,21,.14); } +.event-card.declined { background: #f1f1f1; color: var(--muted); } +.event-status { display: inline-block; padding: 2px 7px; border: 2px solid var(--line); background: var(--white); font-size: 9px; font-weight: 900; letter-spacing: .1em; margin-bottom: 4px; } +.event-metrics { display: grid; grid-template-columns: 1fr; gap: 4px; margin: 8px 0; } +.event-metrics span { display: block; border: 2px solid rgba(16,32,21,.55); background: rgba(255,255,255,.82); padding: 5px; font-weight: 900; color: var(--ink); } +.event-actions { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; } +.result-section-title { margin: 16px 0 8px; font-size: 12px; font-weight: 900; text-transform: uppercase; letter-spacing: .12em; color: var(--green); } +.result-section-title:first-child { margin-top: 0; } +.muted-title { color: var(--muted); border: 3px solid var(--line); padding: 10px; background: #f7fff5; } + +.compact-rules .mini-box { padding: 8px; font-size: 9px; } +.primary-button:disabled { filter: grayscale(1); background: #c9d2ca; color: #526456; } +.formula-box { + border: 3px solid var(--line); + background: #f7fff5; + padding: 10px; + margin: 10px 0; + line-height: 1.5; + color: var(--ink); + font-size: 12px; + font-weight: 700; +} +.equipment-menu-lines { + border: 3px solid var(--line); + background: #ffffff; + padding: 10px; + margin: 8px 0; + color: var(--muted); + line-height: 1.45; +} +.equipment-menu-lines p { margin: 4px 0; } + +/* v11 compact clicked-equipment bubble */ +.modal.equipment-popover { + background: transparent; + align-items: flex-start; + justify-content: flex-start; + padding: 0; + pointer-events: none; +} +.modal.equipment-popover .modal-card { + position: absolute; + left: var(--popover-x, 16px); + top: var(--popover-y, 16px); + width: min(250px, calc(100vw - 24px)); + max-height: min(280px, calc(100vh - 24px)); + overflow: auto; + padding: 8px; + border-width: 3px; + pointer-events: auto; + box-shadow: 6px 6px 0 rgba(16,32,21,.18); +} +.modal.equipment-popover .modal-card h2 { + font-size: 14px; + margin-bottom: 6px; +} +.modal.equipment-popover .modal-actions { + margin-top: 8px; + gap: 6px; + justify-content: flex-start; +} +.modal.equipment-popover .modal-actions button { + padding: 5px 7px; + font-size: 9px; +} +.equipment-menu-lines.compact { + padding: 7px; + margin: 6px 0; + font-size: 9px; +} +.formula-box.compact { + padding: 7px; + margin: 6px 0; + font-size: 9px; +} + +/* v15 pre-build card draft */ +.card-choices { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(190px, 220px)); + justify-content: center; + align-items: stretch; + gap: 10px; + margin-top: 14px; +} +.card-choice { + min-height: 132px; + border: 3px solid var(--line); + background: #f7fff5; + color: var(--ink); + box-shadow: 5px 5px 0 rgba(16,32,21,.16); + padding: 12px; + text-align: left; + cursor: pointer; + font-weight: 900; +} +.card-choice:hover { transform: translate(-1px, -1px); box-shadow: 6px 6px 0 rgba(16,32,21,.18); } +.card-choice strong { display: block; font-size: 14px; text-transform: uppercase; line-height: 1.2; } +.card-choice span { display: inline-block; margin: 8px 0; padding: 2px 7px; border: 2px solid var(--line); background: var(--white); font-size: 9px; letter-spacing: .1em; } +.card-tags { display: flex; flex-wrap: wrap; gap: 4px; margin: 7px 0; } +.card-tags span { margin: 0; padding: 2px 5px; font-size: 8px; line-height: 1.1; letter-spacing: .04em; } +.card-choice small { display: block; color: var(--muted); font-size: 11px; line-height: 1.35; } +.card-choice.rare { background: #fff0d1; box-shadow: inset 0 0 0 3px #f0a020, 5px 5px 0 rgba(16,32,21,.16); } +.card-choice.ultra-rare { background: #ffe6f0; box-shadow: inset 0 0 0 3px #c42424, 5px 5px 0 rgba(16,32,21,.18); } +.card-choice.ultra-rare span { background: #c42424; color: #fff; } +.muted-card-note { color: var(--muted); font-weight: 700; } +.card-targets { display: grid; gap: 8px; margin-top: 14px; } +.card-target-button { border: 3px solid var(--line); background: #f7fff5; padding: 10px 12px; text-align: left; cursor: pointer; font-weight: 900; box-shadow: 4px 4px 0 rgba(16,32,21,.14); } +.card-target-button:hover { background: var(--green-soft); } + +/* v19 readability pass */ +body { font-size: 16px; } +.hud-card span { font-size: 11px; } +.hud-card strong { font-size: clamp(18px, 1.5vw, 25px); } +.priority-strip > div { font-size: 14px; } +.panel-head h1 { font-size: 18px; } +.panel-head p { font-size: 11px; } +.build-panel h2 { font-size: 13px; } +.tool-button strong { font-size: 14px; } +.tool-button span { font-size: 11px; } +.mini-box, .event-card { font-size: 12px; } +.sort-button { font-size: 14px; } +.modal-card h2 { font-size: 29px; } +.card-choice strong { font-size: 16px; } +.card-choice small { font-size: 13px; } + +.tool-button.unaffordable, .tool-button.already-built { opacity: .42; filter: grayscale(.7); } + +.hover-tooltip { + position: fixed; + z-index: 30; + width: min(320px, calc(100vw - 20px)); + display: none; + border: 3px solid var(--line); + background: rgba(255,255,255,.96); + color: var(--ink); + box-shadow: 6px 6px 0 rgba(16,32,21,.18); + padding: 10px; + pointer-events: none; + line-height: 1.35; +} +.hover-tooltip.visible { display: block; } +.hover-tooltip strong { display: block; font-size: 15px; text-transform: uppercase; margin-bottom: 5px; } +.hover-tooltip em { display: block; font-style: normal; color: var(--green); font-weight: 900; margin-bottom: 7px; } +.hover-tooltip em.warning { color: var(--danger); } +.hover-tooltip span { display: block; color: var(--muted); font-size: 12px; } + + +.card-choice.dud { + background: #eeeeee; + color: #777; + filter: grayscale(1); + border-style: dashed; + box-shadow: 5px 5px 0 rgba(16,32,21,.10); +} +.card-choice.dud span { background: #f8f8f8; } +.card-choice.flung { + pointer-events: none; + transform: translate(var(--fling-x, 480px), var(--fling-y, -320px)) rotate(var(--fling-r, 68deg)) scale(.68); + opacity: 0; + transition: transform .34s cubic-bezier(.18,.84,.26,.99), opacity .28s ease-in; +} + + + +.route-card .route-icon.male, +.route-card .route-icon.female, +.route-card .route-icon.poop { + display: inline-grid; + place-items: center; + width: 38px; + height: 38px; + border-radius: 999px; + border: 3px solid var(--line, #102015); + background: var(--white, #fff); + line-height: 1; +} +.route-card .route-icon.male { color: #2477ff; background: #d9ecff; } +.route-card .route-icon.female { color: #d62a85; background: #ffe0f0; } +.route-card .route-icon.poop { color: #7b4a23; background: #fff0d1; font-size: 24px; } +.restart-button { min-width: 160px; } +.restart-fallback-note { margin-top: 12px; color: var(--muted, #526456); font-weight: 700; } + +/* v24.4 hover-only build-button flavor / cashout guidance / compact game-over */ +.tool-button .tool-flavor { + display: block; + max-height: 0; + opacity: 0; + overflow: hidden; + margin-top: 0; + color: var(--muted); + font-size: 8px; + line-height: 1.22; + text-transform: none; + letter-spacing: 0; + transition: max-height .12s ease, opacity .12s ease, margin-top .12s ease; +} +.tool-button:hover .tool-flavor { + max-height: 42px; + opacity: 1; + margin-top: 5px; +} +.large-tools .tool-button { min-height: 58px; } +.large-tools .tool-button:hover { min-height: 78px; } +.history-tools .tool-button.small { min-height: 40px; } +.primary-button.cashout-emphasis, +.tool-button.cashout-emphasis { + opacity: 1 !important; + filter: none !important; + animation: cashoutPulse 0.9s ease-in-out infinite alternate; +} +.primary-button.cashout-emphasis { + box-shadow: inset 0 0 0 4px #fff0d1, 6px 6px 0 rgba(16,32,21,.22); +} +.tool-button.cashout-emphasis { + background: #fff0d1; + box-shadow: inset 0 0 0 3px var(--danger), 6px 6px 0 rgba(16,32,21,.20); +} +@keyframes cashoutPulse { + from { transform: translate(0, 0); } + to { transform: translate(-1px, -1px); } +} +.modal.gameover-modal { padding: 12px; } +.modal.gameover-modal .modal-card { + width: min(640px, 92vw); + max-height: min(82vh, 720px); + overflow: auto; + padding: 16px; +} +.modal.gameover-modal .modal-card h2 { + font-size: 22px; + margin-bottom: 8px; +} +.gameover-reason { font-weight: 900; color: var(--danger); margin-bottom: 8px; } +.settlement-net { + border: 3px solid var(--line); + background: #f7fff5; + padding: 10px 12px; + margin-bottom: 10px; + display: flex; + justify-content: space-between; + align-items: center; + gap: 12px; + font-weight: 900; + text-transform: uppercase; +} +.settlement-net strong { font-size: 24px; } +.settlement-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; } +.settlement-grid div { padding: 8px; } +.settlement-grid span { display: block; font-size: 14px; } +.gameover-summary { + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 6px; + margin-top: 8px; +} +.gameover-breakdown { + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 6px; + margin-top: 8px; +} +.modal.gameover-modal .result-grid div { padding: 7px; } +.modal.gameover-modal .result-grid strong { font-size: 9px; margin-bottom: 3px; } +.modal.gameover-modal .result-grid span { font-size: 12px; } +.gameover-details { + margin-top: 10px; + border: 3px solid var(--line); + background: #f7fff5; + padding: 8px; +} +.gameover-details summary { + cursor: pointer; + font-weight: 900; + text-transform: uppercase; +} +.modal.gameover-modal .formula-box.compact { font-size: 9px; line-height: 1.35; } +@media (max-width: 720px) { + .gameover-summary, .gameover-breakdown { grid-template-columns: 1fr 1fr; } +} + +/* v27.0 cleanup and stable build-menu tooltip pass */ +body { font-size: 18px; } +.build-panel { width: clamp(330px, 26vw, 420px); } +.panel-head h1 { font-size: 20px; } +.panel-head h1 span { font-size: 12px; } +.panel-head p { font-size: 13px; line-height: 1.35; } +.build-panel h2 { font-size: 14px; } +.priority-strip > div { font-size: 15px; } +.hud-card span { font-size: 12px; } +.hud-card strong { font-size: clamp(20px, 1.7vw, 28px); } +.mini-box, .event-card { font-size: 14px; line-height: 1.45; } +.compact-rules .mini-box { font-size: 13px; } +.tool-button { + position: relative; + overflow: visible; + min-height: 62px; + padding: 10px; +} +.large-tools .tool-button { min-height: 62px; } +.large-tools .tool-button:hover { min-height: 62px; } +.tool-button strong { font-size: 15px; line-height: 1.15; } +.tool-button span { font-size: 12px; } +.tool-button .tool-flavor { + display: none; + position: absolute; + z-index: 60; + left: 0; + top: calc(100% + 7px); + width: min(300px, calc(100vw - 40px)); + max-height: none; + opacity: 1; + overflow: visible; + margin: 0; + padding: 10px 12px; + border: 3px solid var(--line); + background: rgba(255,255,255,.98); + color: var(--ink); + box-shadow: 5px 5px 0 rgba(16,32,21,.18); + font-size: 13px; + line-height: 1.35; + text-transform: none; + letter-spacing: 0; + pointer-events: none; + transition: none; +} +.tool-button .tool-flavor::before { + content: ''; + position: absolute; + left: 16px; + top: -10px; + width: 16px; + height: 16px; + border-left: 3px solid var(--line); + border-top: 3px solid var(--line); + background: rgba(255,255,255,.98); + transform: rotate(45deg); +} +.tool-button:hover .tool-flavor { + display: block; + max-height: none; + opacity: 1; + margin: 0; +} +.primary-button { font-size: 16px; padding: 13px 16px; } +#nextTurnButton { min-height: 56px; font-size: 18px; } +@keyframes cashoutPulse { + from { box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(16,32,21,.18); filter: brightness(1); } + to { box-shadow: inset 0 0 0 5px #fff0d1, 4px 4px 0 rgba(16,32,21,.20); filter: brightness(1.08); } +} +.card-choices { grid-template-columns: repeat(auto-fill, minmax(230px, 270px)); gap: 14px; } +.card-choice { min-height: 164px; padding: 15px; } +.card-choice strong { font-size: 18px; } +.card-choice span { font-size: 11px; } +.card-choice small { font-size: 15px; line-height: 1.4; } +.muted-card-note { font-size: 15px; line-height: 1.45; } +.modal-card { width: min(980px, 96vw); } +.modal-card p, .modal-card li { font-size: 16px; } +.modal-actions .reroll-button { + order: 99; + flex: 1 1 100%; + min-height: 64px; + margin-top: 8px; + font-size: 20px; + text-align: center; + justify-content: center; + background: #fff0d1; + box-shadow: inset 0 0 0 4px var(--green), 6px 6px 0 rgba(16,32,21,.20); +} +.modal-actions .reroll-button:disabled { box-shadow: 4px 4px 0 rgba(16,32,21,.12); } +.hover-tooltip strong { font-size: 17px; } +.hover-tooltip span { font-size: 14px; } +.sort-button { font-size: 16px; min-height: 56px; } +.control-dock { grid-template-columns: repeat(4, 172px); } +@media (max-width: 1180px) { + .build-panel { width: auto; } + .control-dock { grid-template-columns: repeat(2, 172px); } +} + +/* v27.1 expansion/readability pass */ +body { font-size: 20px; } +.panel-head h1 { font-size: 22px; } +.panel-head h1 span { font-size: 13px; } +.panel-head p { font-size: 14px; line-height: 1.35; } +.build-panel h2 { font-size: 15px; } +.priority-strip > div { font-size: 16px; } +.hud-card span { font-size: 13px; } +.hud-card strong { font-size: clamp(22px, 1.8vw, 30px); } +.mini-box, .event-card { font-size: 15px; line-height: 1.5; } +.compact-rules .mini-box { font-size: 14px; } +.tool-button strong { font-size: 16px; line-height: 1.15; } +.tool-button span { font-size: 13px; line-height: 1.2; } +.tool-button .tool-flavor { + left: auto; + right: 0; + width: min(320px, calc(100vw - 40px)); + font-size: 14px; + line-height: 1.4; + overflow-wrap: anywhere; +} +.tool-button .tool-flavor::before { left: auto; right: 18px; } +.tool-button.unaffordable .tool-flavor, +.tool-button.unaffordable:hover .tool-flavor, +.tool-button:disabled .tool-flavor, +.tool-button:disabled:hover .tool-flavor { display: none; } +.facility-action { font-size: 12px; } +.primary-button { font-size: 17px; } +#nextTurnButton { font-size: 19px; } +.card-choice strong { font-size: 19px; } +.card-choice span { font-size: 12px; } +.card-choice small { font-size: 16px; line-height: 1.45; } +.muted-card-note { font-size: 16px; } +.modal-card p, .modal-card li { font-size: 17px; } +.modal.equipment-popover .modal-card h2 { font-size: 16px; } +.modal.equipment-popover .modal-actions button { font-size: 11px; } +.equipment-menu-lines.compact, .formula-box.compact { font-size: 11px; } +.hover-tooltip strong { font-size: 18px; } + +/* Keep construction flavor text readable as a hover bubble, not button content. */ +.large-tools .tool-button { + min-height: 62px; + position: relative; + overflow: visible; +} +.large-tools .tool-button:hover { + min-height: 62px; +} +.large-tools .tool-button .tool-flavor { + display: none; + position: absolute; + z-index: 90; + right: 0; + top: calc(100% + 8px); + width: min(320px, calc(100vw - 40px)); + max-height: none; + opacity: 1; + overflow: visible; + margin: 0; + padding: 10px 12px; + border: 3px solid var(--line); + background: rgba(255,255,255,.98); + color: var(--ink); + box-shadow: 5px 5px 0 rgba(16,32,21,.18); + font-size: 14px; + line-height: 1.35; + pointer-events: none; + overflow-wrap: anywhere; +} +.large-tools .tool-button:hover .tool-flavor { + display: block; +} +.large-tools .tool-button .tool-flavor::before { + content: ''; + position: absolute; + right: 18px; + top: -10px; + width: 16px; + height: 16px; + border-left: 3px solid var(--line); + border-top: 3px solid var(--line); + background: rgba(255,255,255,.98); + transform: rotate(45deg); +} +.hover-tooltip span { font-size: 15px; } +.sort-button { font-size: 17px; } + +/* v27.3 offscreen scanner monitor / expansion UI pass */ +.scanner-monitor { + position: absolute; + z-index: 8; + left: 12px; + bottom: 92px; + display: none; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 8px; + width: min(560px, calc(100% - 24px)); + pointer-events: auto; +} +.scanner-monitor.visible { display: grid; } +.scanner-monitor-card { + border: 3px solid var(--line); + background: rgba(255,255,255,.95); + box-shadow: 5px 5px 0 rgba(16,32,21,.18); + padding: 9px; + font-weight: 900; +} +.scanner-monitor-card header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + margin-bottom: 7px; + text-transform: uppercase; +} +.scanner-monitor-card header strong { font-size: 20px; color: var(--green); } +.scanner-monitor-card header span { font-size: 12px; color: var(--muted); } +.scanner-mini-map { + display: grid; + grid-template-columns: 42px 1fr 82px; + align-items: center; + gap: 6px; + margin-bottom: 8px; +} +.scanner-mini-map > span, +.scanner-mini-map > b { + border: 2px solid var(--line); + background: #f7fff5; + padding: 7px 6px; + text-align: center; + font-size: 13px; + min-height: 36px; +} +.scanner-current { display: block; color: var(--ink); } +.scanner-current.male { color: #2477ff; } +.scanner-current.female { color: #d62a85; } +.scanner-current.poop { color: #7b4a23; } +.scanner-current.empty { color: var(--muted); } + +.scanner-mini-grid { + display: grid; + grid-template-columns: repeat(5, 27px); + gap: 3px; + justify-content: center; + align-items: center; + padding: 6px; + margin: 0 0 8px; + border: 2px solid var(--line); + background: #f6f1df; +} +.scanner-mini-grid .mini-cell { + width: 27px; + height: 27px; + display: grid; + place-items: center; + border: 1px solid rgba(22,38,25,.28); + background: #fffdfa; + color: var(--muted); + font-size: 11px; + font-weight: 900; + line-height: 1; +} +.scanner-mini-grid .mini-cell.belt { background: #e7f7e4; color: var(--green-dark); } +.scanner-mini-grid .mini-cell.input { background: #fff3bf; color: var(--ink); font-size: 9px; } +.scanner-mini-grid .mini-cell.scanner { background: var(--green); color: #fff; border-color: var(--line); font-size: 16px; } +.scanner-mini-grid .mini-cell.scanner.male { background: #2477ff; } +.scanner-mini-grid .mini-cell.scanner.female { background: #d62a85; } +.scanner-mini-grid .mini-cell.scanner.poop { background: #7b4a23; } +.scanner-mini-grid .mini-cell.scanner-other { background: #b7f5c6; color: var(--ink); } +.scanner-mini-grid .mini-cell.egg { background: #fff7c4; color: #7a5a00; } +.scanner-mini-grid .mini-cell.port { background: #dbe7ff; color: #27427d; } +.scanner-mini-grid .mini-cell.blocked { background: #d7cfc1; color: #6d4d35; } + +.scanner-monitor-actions { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 7px; +} +.scanner-monitor-actions button { + border: 3px solid var(--line); + background: var(--green-soft); + color: var(--ink); + cursor: pointer; + font: inherit; + font-size: 14px; + font-weight: 900; + min-height: 44px; + box-shadow: 3px 3px 0 rgba(16,32,21,.18); +} +.scanner-monitor-actions button:disabled { + background: #edf3ec; + color: var(--muted); + opacity: .62; + cursor: not-allowed; +} +@media (max-width: 1180px) { + .scanner-monitor { bottom: 132px; width: min(520px, calc(100% - 16px)); left: 8px; } +} + +/* ------------------------------------------------------------------ + DARK FACTORY VISUAL PASS + - Facility sprites are now loaded from assets/dark_factory/. + - Debug UI is intentionally retained for balancing builds. Do not remove. + ------------------------------------------------------------------ */ +:root { + --bg: #0b0c0f; + --screen: #111318; + --panel: rgba(24, 27, 34, 0.96); + --panel-2: #20242b; + --panel-3: #2a303a; + --ink: #e6edf2; + --muted: #8f9bab; + --line: #050609; + --green: #7bd84f; + --green-soft: #273c24; + --white: #e6edf2; + --danger: #e34a36; + --warn: #ffb827; + --cyan: #4aa3ff; + --orange: #c86a2b; + --shadow: 6px 6px 0 rgba(0, 0, 0, 0.62); +} +html, body { background: #050609; color: var(--ink); } +body { + background: + linear-gradient(90deg, rgba(255,184,39,.035) 1px, transparent 1px) 0 0 / 32px 32px, + linear-gradient(rgba(255,184,39,.028) 1px, transparent 1px) 0 0 / 32px 32px, + #050609; +} +#app { width: min(100vw, 1720px); padding: 0; } +.game-shell { + min-height: 100vh; + border: 0; + background: var(--screen); + box-shadow: inset 0 0 0 4px #050609, inset 0 0 0 8px #303744; +} +#gameCanvas { + height: 100vh; + min-height: 720px; + background: var(--screen); + image-rendering: pixelated; + image-rendering: crisp-edges; +} +.hud { gap: 4px; } +.hud-top-left { + top: 8px; + left: 8px; + right: 420px; + grid-template-columns: 1.25fr repeat(5, minmax(92px, .65fr)); +} +.hud-top-right { + top: 8px; + right: 8px; + grid-template-columns: repeat(4, minmax(74px, auto)); +} +.hud-card { + min-width: 74px; + padding: 7px 9px; + border: 3px solid var(--line); + background: linear-gradient(#242a33, #171a20); + box-shadow: 4px 4px 0 rgba(0,0,0,.7), inset 0 0 0 2px rgba(255,184,39,.10); + color: var(--ink); +} +.hud-card span { color: var(--warn); font-size: 9px; letter-spacing: .12em; } +.hud-card strong { color: var(--ink); text-shadow: 2px 2px 0 #050609; } +.hud-card.cash strong, .hud-card.profit strong, .hud-card.combo strong, .cash-positive { color: var(--green) !important; } +.hud-card.time-critical { background: #3a1f1f; box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(0,0,0,.7); } +.priority-strip { + top: 74px; + left: 10px; + width: clamp(250px, 21vw, 330px); + max-width: none; + grid-template-columns: 1fr; + gap: 6px; +} +.priority-strip > div { + border: 3px solid var(--line); + background: linear-gradient(#222832, #15181e); + color: var(--ink); + box-shadow: 4px 4px 0 rgba(0,0,0,.66), inset 0 0 0 2px rgba(255,184,39,.12); +} +.event-brief.active { background: #38251a; box-shadow: inset 0 0 0 3px var(--orange), 4px 4px 0 rgba(0,0,0,.66); } +.event-brief.next { background: #1c2c20; box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(0,0,0,.66); } +.event-brief.locked { background: #181b20; color: var(--muted); } +.target-brief { color: var(--warn); } +.speed-brief { color: var(--cyan); } +.build-panel { + top: 82px; + right: 8px; + bottom: 8px; + width: clamp(320px, 24vw, 410px); + padding: 9px; + border: 4px solid var(--line); + background: linear-gradient(#222832, #14171d); + box-shadow: 6px 6px 0 rgba(0,0,0,.72), inset 0 0 0 3px rgba(255,184,39,.10); + scrollbar-color: var(--warn) #111318; +} +.panel-head { + display: grid; + grid-template-columns: 1fr 126px; + align-items: stretch; + gap: 8px; + margin-bottom: 8px; +} +.panel-head h1 { color: var(--warn); text-shadow: 2px 2px 0 #050609; font-size: 17px; } +.panel-head h1 span { color: #050609; background: var(--warn); border-color: var(--line); } +.panel-head p { color: var(--muted); } +.panel-grid { + display: grid; + grid-template-columns: 1fr; + gap: 8px; +} +.build-panel h2, .result-section-title { color: var(--warn); } +.large-tools { + grid-template-columns: 1fr 1fr; + gap: 6px; +} +.tool-button, .primary-button, .sort-button, .facility-action { + border: 3px solid var(--line); + background: linear-gradient(#2a303a, #171a20); + color: var(--ink); + box-shadow: 4px 4px 0 rgba(0,0,0,.70), inset 0 0 0 2px rgba(255,184,39,.08); + text-shadow: 1px 1px 0 #050609; +} +.tool-button { min-height: 48px; padding: 8px; } +.tool-button strong { color: var(--ink); } +.tool-button span { color: var(--muted); } +.tool-button.active { + background: linear-gradient(#33311d, #1e2117); + box-shadow: inset 0 0 0 3px var(--warn), 4px 4px 0 rgba(0,0,0,.70); +} +.tool-button.danger.active { background: linear-gradient(#4b1f1c, #241014); box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(0,0,0,.70); } +.primary-button { background: linear-gradient(#8b2d23, #4b1714); color: #fff3d2; } +.primary-button:not(:disabled) { box-shadow: inset 0 0 0 3px #ffb827, 5px 5px 0 rgba(0,0,0,.72); } +.primary-button:disabled, .tool-button:disabled, .sort-button:disabled, .facility-action:disabled { opacity: .42; filter: grayscale(1); } +.mini-box, .event-card, .formula-box, .equipment-menu-lines, .route-card, .result-grid div, .muted-title { + border: 3px solid var(--line); + background: #15181e; + color: var(--muted); + box-shadow: inset 0 0 0 2px rgba(255,184,39,.08); +} +.event-card h3, .event-card strong, .event-metrics span { color: var(--ink); } +.event-card.accepted { background: #1c2c20; box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(0,0,0,.66); } +.event-card.empty { background: #15181e; color: var(--muted); } +.event-metrics span { border-color: #3d4654; background: #20242b; } +.event-status { background: #2a303a; color: var(--warn); border-color: var(--line); } +.control-dock { + left: 50%; + right: auto; + bottom: 8px; + transform: translateX(-50%); + grid-template-columns: repeat(4, minmax(135px, 160px)); + gap: 6px; + padding: 6px; + border: 4px solid var(--line); + background: rgba(13,15,19,.96); + box-shadow: 5px 5px 0 rgba(0,0,0,.72), inset 0 0 0 2px rgba(255,184,39,.10); +} +.sort-button { min-height: 44px; font-size: 12px; } +.scanner-monitor { + position: absolute; + z-index: 5; + left: 10px; + top: 198px; + width: clamp(250px, 21vw, 330px); +} +.scanner-monitor-card { + border: 3px solid var(--line) !important; + background: linear-gradient(#222832, #15181e) !important; + color: var(--ink) !important; + box-shadow: 4px 4px 0 rgba(0,0,0,.66), inset 0 0 0 2px rgba(255,184,39,.10) !important; +} +.scanner-monitor-card strong { color: var(--warn); } +.debug-panel { + left: auto; + right: 12px; + bottom: 10px; + width: min(420px, calc(100% - 24px)); + border-color: var(--line); + background: rgba(16,18,23,.97); + box-shadow: 5px 5px 0 rgba(0,0,0,.72), inset 0 0 0 2px rgba(227,74,54,.18); + color: var(--ink); +} +.debug-panel summary { color: var(--danger); } +.debug-body { border-top-color: var(--line); } +.debug-body button, .debug-body input[type="number"], .debug-body select, .debug-readout { + border-color: var(--line); + background: #20242b; + color: var(--ink); +} +.debug-readout { color: var(--muted); } +.modal { background: rgba(3,4,6,.72); } +.modal-card { + border-color: var(--line); + background: linear-gradient(#242a33, #15181e); + color: var(--ink); + box-shadow: 8px 8px 0 rgba(0,0,0,.72), inset 0 0 0 3px rgba(255,184,39,.12); +} +.modal-card h2 { color: var(--warn); text-shadow: 2px 2px 0 #050609; } +.modal-card ul, .modal-card p { color: var(--muted); } +.hover-tooltip { + border-color: var(--line) !important; + background: rgba(20,23,29,.98) !important; + color: var(--ink) !important; + box-shadow: 5px 5px 0 rgba(0,0,0,.72) !important; +} +::-webkit-scrollbar { width: 14px; height: 14px; } +::-webkit-scrollbar-track { background: #111318; } +::-webkit-scrollbar-thumb { background: #333b48; border: 3px solid #111318; } +::-webkit-scrollbar-thumb:hover { background: #ffb827; } +@media (max-width: 1180px) { + .hud-top-left { right: 8px; grid-template-columns: repeat(3, minmax(80px, 1fr)); } + .hud-top-right { top: 132px; left: 8px; right: auto; grid-template-columns: repeat(2, minmax(82px, auto)); } + .priority-strip { top: 226px; } + .scanner-monitor { top: 348px; } + .build-panel { left: 8px; right: 8px; bottom: 8px; width: auto; max-height: 46vh; } + .control-dock { grid-template-columns: repeat(2, 150px); } +} + +/* v27.16: compact collapsed debug panel + icon card layout */ +.debug-panel:not([open]) { + width: 104px !important; + min-width: 0; + overflow: hidden; +} +.debug-panel:not([open]) summary { + display: block; + width: 100%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.debug-panel[open] { + width: min(420px, calc(100% - 24px)); +} + +.card-choice { + position: relative; + display: grid; + grid-template-columns: 54px minmax(0, 1fr); + gap: 10px; + align-items: start; + min-height: 150px; + overflow: hidden; + background: + linear-gradient(135deg, rgba(255,255,255,.08), rgba(0,0,0,.20)), + #20242b; + border-color: var(--line); +} +.card-choice::before { + content: ""; + position: absolute; + inset: 5px; + border: 1px solid rgba(255,184,39,.18); + pointer-events: none; +} +.card-icon { + position: relative; + z-index: 1; + width: 46px; + height: 46px; + display: grid; + place-items: center; + border: 3px solid var(--line); + background: #15181e; + box-shadow: inset 0 0 0 2px rgba(255,184,39,.10), 3px 3px 0 rgba(0,0,0,.35); + image-rendering: pixelated; +} +.card-icon img { + width: 36px; + height: 36px; + object-fit: contain; + image-rendering: pixelated; +} +.card-icon.glyph { + color: var(--warn, #ffb827); + font-size: 24px; + font-weight: 900; + text-align: center; + line-height: 1; +} +.card-copy { + position: relative; + z-index: 1; + min-width: 0; +} +.card-choice strong { + color: var(--warn, #ffb827); + text-shadow: 1px 1px 0 #050609; +} +.card-choice small { color: var(--muted); } +.card-tags span { + background: #15181e; + color: var(--white); + border-color: var(--line); +} +.card-choice.common { background: linear-gradient(145deg, #262c35, #171a20); } +.card-choice.rare { + background: linear-gradient(145deg, #3b3020, #191b20); + box-shadow: inset 0 0 0 3px #f0a020, 5px 5px 0 rgba(0,0,0,.50); +} +.card-choice.ultra-rare { + background: linear-gradient(145deg, #401d2a, #171a20); + box-shadow: inset 0 0 0 3px #c42424, 5px 5px 0 rgba(0,0,0,.55); +} +.card-choice.dud { + background: linear-gradient(145deg, #2b2b2b, #191919); + color: #878787; +} +.card-choice.dud .card-tags span { background: #222; color: #aaa; } + +@media (max-width: 1180px) { + .debug-panel:not([open]) { + width: 92px !important; + right: 8px; + bottom: 8px; + } +} + + +/* v27.18 inherited cache-proof identity and final UI overrides */ +.build-stamp { + position: absolute; + z-index: 12; + right: 14px; + top: 76px; + padding: 5px 9px; + border: 2px solid #ffb827; + background: rgba(14, 17, 22, .94); + color: #80e067; + box-shadow: 3px 3px 0 rgba(0,0,0,.7); + font: 900 11px/1 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; + letter-spacing: .04em; + pointer-events: none; +} +.debug-panel:not([open]) { + width: 58px !important; + max-width: 58px !important; + height: 30px; + min-height: 0; +} +.debug-panel:not([open]) summary { + box-sizing: border-box; + width: 58px; + height: 27px; + padding: 5px 7px; + text-align: center; + overflow: hidden; + text-overflow: clip; +} +.debug-panel[open] { + width: min(390px, calc(100% - 24px)) !important; + height: auto; +} +.card-choice { + border-width: 3px; + box-shadow: 4px 4px 0 rgba(0,0,0,.55), inset 0 0 0 1px rgba(255,184,39,.14); +} +.card-choice:hover { + transform: translateY(-2px); + box-shadow: 4px 6px 0 rgba(0,0,0,.65), inset 0 0 0 2px rgba(128,224,103,.24); +} +.card-icon img { + image-rendering: pixelated; + filter: drop-shadow(2px 2px 0 rgba(0,0,0,.7)); +} +#gameCanvas { image-rendering: pixelated; } + +/* v27.18: status relocation, consistent industrial controls, card watermarks */ +.hud-top-left { grid-template-columns: repeat(5, minmax(82px, auto)); } + +.left-bottom-status { + position: absolute; + z-index: 6; + left: 10px; + bottom: 10px; + width: min(310px, calc(100% - 20px)); + display: grid; + grid-template-columns: 1fr 1fr; + gap: 6px; + pointer-events: none; +} +.left-bottom-status > div { + min-width: 0; + border: 3px solid var(--line); + background: rgba(22, 26, 32, .95); + color: var(--ink); + padding: 8px 10px; + box-shadow: 4px 4px 0 rgba(0,0,0,.68), inset 0 0 0 1px rgba(255,184,39,.10); + font-size: 12px; + line-height: 1.2; + font-weight: 900; + text-transform: uppercase; + letter-spacing: .025em; + overflow: hidden; + text-overflow: ellipsis; +} +.left-bottom-status .event-brief { grid-column: 1 / -1; white-space: normal; min-height: 39px; } +.left-bottom-status .event-brief.active { background: #35221c; box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(0,0,0,.68); } +.left-bottom-status .event-brief.next { background: #22301f; box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(0,0,0,.68); } +.left-bottom-status .event-brief.locked { background: #1c2027; color: var(--muted); } +.left-bottom-status .speed-brief { color: #d9e2e8; } +.left-bottom-status .target-brief { color: #ffcf68; } +.left-bottom-status .combo-brief { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; } +.left-bottom-status .combo-brief span { color: var(--muted); font-size: 10px; } +.left-bottom-status .combo-brief strong { color: var(--green); font-size: 22px; line-height: 1; } + +/* Remove the remaining bright green/white control styling from modal actions. */ +.modal-actions button, +.facility-action, +.card-target-button { + border: 3px solid #07080a; + background: linear-gradient(#353d48, #1b1f25); + color: #e6edf2; + box-shadow: inset 0 0 0 1px rgba(255,184,39,.14), 4px 4px 0 rgba(0,0,0,.68); +} +.modal-actions button:hover:not(:disabled), +.facility-action:hover:not(:disabled), +.card-target-button:hover:not(:disabled) { + background: linear-gradient(#424b58, #242930); + color: #fff0c9; + box-shadow: inset 0 0 0 2px rgba(255,184,39,.42), 4px 4px 0 rgba(0,0,0,.72); +} +.facility-action.warn, +.modal-actions .reroll-button { + background: linear-gradient(#554221, #2b2419); + color: #ffd36a; + box-shadow: inset 0 0 0 3px #b97810, 5px 5px 0 rgba(0,0,0,.72); +} +.modal-actions .reroll-button:hover:not(:disabled) { + background: linear-gradient(#6b5227, #342919); + color: #fff0bd; + box-shadow: inset 0 0 0 3px #ffb827, 5px 5px 0 rgba(0,0,0,.76); +} +.facility-action.good { background: linear-gradient(#29422a, #19271a); color: #a9ed91; } +.facility-action.danger { background: linear-gradient(#57251f, #2d1715); color: #ffb1a3; } +.modal-actions button:disabled, +.facility-action:disabled, +.card-target-button:disabled { opacity: .42; filter: grayscale(.85); box-shadow: 3px 3px 0 rgba(0,0,0,.45); } + +/* Icons are now translucent background art rather than separate foreground badges. */ +.card-choice { + display: block; + min-height: 170px; + padding: 16px; + isolation: isolate; +} +.card-choice::before { z-index: 1; } +.card-copy { position: relative; z-index: 3; padding-right: 6px; } +.card-icon { + position: absolute; + z-index: 0; + right: -9px; + bottom: -12px; + width: 124px; + height: 124px; + border: 0; + background: transparent; + box-shadow: none; + opacity: .14; + transform: rotate(-7deg); + pointer-events: none; + overflow: visible; +} +.card-icon img { + width: 100%; + height: 100%; + object-fit: contain; + filter: grayscale(.12) contrast(1.2) drop-shadow(3px 3px 0 rgba(0,0,0,.55)); +} +.card-icon.glyph { + display: grid; + place-items: center; + color: #f0b437; + font-size: 88px; + line-height: 1; + text-shadow: 4px 4px 0 rgba(0,0,0,.55); +} +.card-choice.rare .card-icon { opacity: .16; } +.card-choice.ultra-rare .card-icon { opacity: .17; } +.card-choice.dud .card-icon { opacity: .08; filter: grayscale(1); } + +@media (max-width: 1180px) { + .hud-top-left { grid-template-columns: repeat(3, minmax(80px, 1fr)); } + .left-bottom-status { width: 290px; left: 8px; bottom: 8px; } +} +@media (max-width: 760px) { + .left-bottom-status { width: min(270px, calc(100% - 16px)); grid-template-columns: 1fr; } + .left-bottom-status .event-brief { grid-column: auto; } +} + + +/* v27.19: compact Next Day fee label and deduplicated side panel */ +.panel-head { grid-template-columns: minmax(0, 1fr) minmax(112px, 126px); } +.primary-button#nextTurnButton { + min-width: 0; + max-width: 126px; + padding: 8px 7px; + white-space: normal; + overflow: hidden; + line-height: 1.08; + display: grid; + place-content: center; + gap: 4px; + text-align: center; +} +#nextTurnButton .next-day-main { display: block; font-size: 15px; letter-spacing: .035em; } +#nextTurnButton .next-day-fee { + display: block; + max-width: 100%; + color: #ffd36a; + font-size: 9px; + line-height: 1.15; + letter-spacing: 0; + overflow-wrap: anywhere; +} diff --git a/styles.css b/styles.css index 83b96a5..3ddf905 100644 --- a/styles.css +++ b/styles.css @@ -759,3 +759,521 @@ body { font-size: 20px; } @media (max-width: 1180px) { .scanner-monitor { bottom: 132px; width: min(520px, calc(100% - 16px)); left: 8px; } } + +/* ------------------------------------------------------------------ + DARK FACTORY VISUAL PASS + - Facility sprites are now loaded from assets/dark_factory/. + - Debug UI is intentionally retained for balancing builds. Do not remove. + ------------------------------------------------------------------ */ +:root { + --bg: #0b0c0f; + --screen: #111318; + --panel: rgba(24, 27, 34, 0.96); + --panel-2: #20242b; + --panel-3: #2a303a; + --ink: #e6edf2; + --muted: #8f9bab; + --line: #050609; + --green: #7bd84f; + --green-soft: #273c24; + --white: #e6edf2; + --danger: #e34a36; + --warn: #ffb827; + --cyan: #4aa3ff; + --orange: #c86a2b; + --shadow: 6px 6px 0 rgba(0, 0, 0, 0.62); +} +html, body { background: #050609; color: var(--ink); } +body { + background: + linear-gradient(90deg, rgba(255,184,39,.035) 1px, transparent 1px) 0 0 / 32px 32px, + linear-gradient(rgba(255,184,39,.028) 1px, transparent 1px) 0 0 / 32px 32px, + #050609; +} +#app { width: min(100vw, 1720px); padding: 0; } +.game-shell { + min-height: 100vh; + border: 0; + background: var(--screen); + box-shadow: inset 0 0 0 4px #050609, inset 0 0 0 8px #303744; +} +#gameCanvas { + height: 100vh; + min-height: 720px; + background: var(--screen); + image-rendering: pixelated; + image-rendering: crisp-edges; +} +.hud { gap: 4px; } +.hud-top-left { + top: 8px; + left: 8px; + right: 420px; + grid-template-columns: 1.25fr repeat(5, minmax(92px, .65fr)); +} +.hud-top-right { + top: 8px; + right: 8px; + grid-template-columns: repeat(4, minmax(74px, auto)); +} +.hud-card { + min-width: 74px; + padding: 7px 9px; + border: 3px solid var(--line); + background: linear-gradient(#242a33, #171a20); + box-shadow: 4px 4px 0 rgba(0,0,0,.7), inset 0 0 0 2px rgba(255,184,39,.10); + color: var(--ink); +} +.hud-card span { color: var(--warn); font-size: 9px; letter-spacing: .12em; } +.hud-card strong { color: var(--ink); text-shadow: 2px 2px 0 #050609; } +.hud-card.cash strong, .hud-card.profit strong, .hud-card.combo strong, .cash-positive { color: var(--green) !important; } +.hud-card.time-critical { background: #3a1f1f; box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(0,0,0,.7); } +.priority-strip { + top: 74px; + left: 10px; + width: clamp(250px, 21vw, 330px); + max-width: none; + grid-template-columns: 1fr; + gap: 6px; +} +.priority-strip > div { + border: 3px solid var(--line); + background: linear-gradient(#222832, #15181e); + color: var(--ink); + box-shadow: 4px 4px 0 rgba(0,0,0,.66), inset 0 0 0 2px rgba(255,184,39,.12); +} +.event-brief.active { background: #38251a; box-shadow: inset 0 0 0 3px var(--orange), 4px 4px 0 rgba(0,0,0,.66); } +.event-brief.next { background: #1c2c20; box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(0,0,0,.66); } +.event-brief.locked { background: #181b20; color: var(--muted); } +.target-brief { color: var(--warn); } +.speed-brief { color: var(--cyan); } +.build-panel { + top: 82px; + right: 8px; + bottom: 8px; + width: clamp(320px, 24vw, 410px); + padding: 9px; + border: 4px solid var(--line); + background: linear-gradient(#222832, #14171d); + box-shadow: 6px 6px 0 rgba(0,0,0,.72), inset 0 0 0 3px rgba(255,184,39,.10); + scrollbar-color: var(--warn) #111318; +} +.panel-head { + display: grid; + grid-template-columns: 1fr 126px; + align-items: stretch; + gap: 8px; + margin-bottom: 8px; +} +.panel-head h1 { color: var(--warn); text-shadow: 2px 2px 0 #050609; font-size: 17px; } +.panel-head h1 span { color: #050609; background: var(--warn); border-color: var(--line); } +.panel-head p { color: var(--muted); } +.panel-grid { + display: grid; + grid-template-columns: 1fr; + gap: 8px; +} +.build-panel h2, .result-section-title { color: var(--warn); } +.large-tools { + grid-template-columns: 1fr 1fr; + gap: 6px; +} +.tool-button, .primary-button, .sort-button, .facility-action { + border: 3px solid var(--line); + background: linear-gradient(#2a303a, #171a20); + color: var(--ink); + box-shadow: 4px 4px 0 rgba(0,0,0,.70), inset 0 0 0 2px rgba(255,184,39,.08); + text-shadow: 1px 1px 0 #050609; +} +.tool-button { min-height: 48px; padding: 8px; } +.tool-button strong { color: var(--ink); } +.tool-button span { color: var(--muted); } +.tool-button.active { + background: linear-gradient(#33311d, #1e2117); + box-shadow: inset 0 0 0 3px var(--warn), 4px 4px 0 rgba(0,0,0,.70); +} +.tool-button.danger.active { background: linear-gradient(#4b1f1c, #241014); box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(0,0,0,.70); } +.primary-button { background: linear-gradient(#8b2d23, #4b1714); color: #fff3d2; } +.primary-button:not(:disabled) { box-shadow: inset 0 0 0 3px #ffb827, 5px 5px 0 rgba(0,0,0,.72); } +.primary-button:disabled, .tool-button:disabled, .sort-button:disabled, .facility-action:disabled { opacity: .42; filter: grayscale(1); } +.mini-box, .event-card, .formula-box, .equipment-menu-lines, .route-card, .result-grid div, .muted-title { + border: 3px solid var(--line); + background: #15181e; + color: var(--muted); + box-shadow: inset 0 0 0 2px rgba(255,184,39,.08); +} +.event-card h3, .event-card strong, .event-metrics span { color: var(--ink); } +.event-card.accepted { background: #1c2c20; box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(0,0,0,.66); } +.event-card.empty { background: #15181e; color: var(--muted); } +.event-metrics span { border-color: #3d4654; background: #20242b; } +.event-status { background: #2a303a; color: var(--warn); border-color: var(--line); } +.control-dock { + left: 50%; + right: auto; + bottom: 8px; + transform: translateX(-50%); + grid-template-columns: repeat(4, minmax(135px, 160px)); + gap: 6px; + padding: 6px; + border: 4px solid var(--line); + background: rgba(13,15,19,.96); + box-shadow: 5px 5px 0 rgba(0,0,0,.72), inset 0 0 0 2px rgba(255,184,39,.10); +} +.sort-button { min-height: 44px; font-size: 12px; } +.scanner-monitor { + position: absolute; + z-index: 5; + left: 10px; + top: 198px; + width: clamp(250px, 21vw, 330px); +} +.scanner-monitor-card { + border: 3px solid var(--line) !important; + background: linear-gradient(#222832, #15181e) !important; + color: var(--ink) !important; + box-shadow: 4px 4px 0 rgba(0,0,0,.66), inset 0 0 0 2px rgba(255,184,39,.10) !important; +} +.scanner-monitor-card strong { color: var(--warn); } +.debug-panel { + left: auto; + right: 12px; + bottom: 10px; + width: min(420px, calc(100% - 24px)); + border-color: var(--line); + background: rgba(16,18,23,.97); + box-shadow: 5px 5px 0 rgba(0,0,0,.72), inset 0 0 0 2px rgba(227,74,54,.18); + color: var(--ink); +} +.debug-panel summary { color: var(--danger); } +.debug-body { border-top-color: var(--line); } +.debug-body button, .debug-body input[type="number"], .debug-body select, .debug-readout { + border-color: var(--line); + background: #20242b; + color: var(--ink); +} +.debug-readout { color: var(--muted); } +.modal { background: rgba(3,4,6,.72); } +.modal-card { + border-color: var(--line); + background: linear-gradient(#242a33, #15181e); + color: var(--ink); + box-shadow: 8px 8px 0 rgba(0,0,0,.72), inset 0 0 0 3px rgba(255,184,39,.12); +} +.modal-card h2 { color: var(--warn); text-shadow: 2px 2px 0 #050609; } +.modal-card ul, .modal-card p { color: var(--muted); } +.hover-tooltip { + border-color: var(--line) !important; + background: rgba(20,23,29,.98) !important; + color: var(--ink) !important; + box-shadow: 5px 5px 0 rgba(0,0,0,.72) !important; +} +::-webkit-scrollbar { width: 14px; height: 14px; } +::-webkit-scrollbar-track { background: #111318; } +::-webkit-scrollbar-thumb { background: #333b48; border: 3px solid #111318; } +::-webkit-scrollbar-thumb:hover { background: #ffb827; } +@media (max-width: 1180px) { + .hud-top-left { right: 8px; grid-template-columns: repeat(3, minmax(80px, 1fr)); } + .hud-top-right { top: 132px; left: 8px; right: auto; grid-template-columns: repeat(2, minmax(82px, auto)); } + .priority-strip { top: 226px; } + .scanner-monitor { top: 348px; } + .build-panel { left: 8px; right: 8px; bottom: 8px; width: auto; max-height: 46vh; } + .control-dock { grid-template-columns: repeat(2, 150px); } +} + +/* v27.16: compact collapsed debug panel + icon card layout */ +.debug-panel:not([open]) { + width: 104px !important; + min-width: 0; + overflow: hidden; +} +.debug-panel:not([open]) summary { + display: block; + width: 100%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.debug-panel[open] { + width: min(420px, calc(100% - 24px)); +} + +.card-choice { + position: relative; + display: grid; + grid-template-columns: 54px minmax(0, 1fr); + gap: 10px; + align-items: start; + min-height: 150px; + overflow: hidden; + background: + linear-gradient(135deg, rgba(255,255,255,.08), rgba(0,0,0,.20)), + #20242b; + border-color: var(--line); +} +.card-choice::before { + content: ""; + position: absolute; + inset: 5px; + border: 1px solid rgba(255,184,39,.18); + pointer-events: none; +} +.card-icon { + position: relative; + z-index: 1; + width: 46px; + height: 46px; + display: grid; + place-items: center; + border: 3px solid var(--line); + background: #15181e; + box-shadow: inset 0 0 0 2px rgba(255,184,39,.10), 3px 3px 0 rgba(0,0,0,.35); + image-rendering: pixelated; +} +.card-icon img { + width: 36px; + height: 36px; + object-fit: contain; + image-rendering: pixelated; +} +.card-icon.glyph { + color: var(--warn, #ffb827); + font-size: 24px; + font-weight: 900; + text-align: center; + line-height: 1; +} +.card-copy { + position: relative; + z-index: 1; + min-width: 0; +} +.card-choice strong { + color: var(--warn, #ffb827); + text-shadow: 1px 1px 0 #050609; +} +.card-choice small { color: var(--muted); } +.card-tags span { + background: #15181e; + color: var(--white); + border-color: var(--line); +} +.card-choice.common { background: linear-gradient(145deg, #262c35, #171a20); } +.card-choice.rare { + background: linear-gradient(145deg, #3b3020, #191b20); + box-shadow: inset 0 0 0 3px #f0a020, 5px 5px 0 rgba(0,0,0,.50); +} +.card-choice.ultra-rare { + background: linear-gradient(145deg, #401d2a, #171a20); + box-shadow: inset 0 0 0 3px #c42424, 5px 5px 0 rgba(0,0,0,.55); +} +.card-choice.dud { + background: linear-gradient(145deg, #2b2b2b, #191919); + color: #878787; +} +.card-choice.dud .card-tags span { background: #222; color: #aaa; } + +@media (max-width: 1180px) { + .debug-panel:not([open]) { + width: 92px !important; + right: 8px; + bottom: 8px; + } +} + + +/* v27.18 inherited cache-proof identity and final UI overrides */ +.build-stamp { + position: absolute; + z-index: 12; + right: 14px; + top: 76px; + padding: 5px 9px; + border: 2px solid #ffb827; + background: rgba(14, 17, 22, .94); + color: #80e067; + box-shadow: 3px 3px 0 rgba(0,0,0,.7); + font: 900 11px/1 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; + letter-spacing: .04em; + pointer-events: none; +} +.debug-panel:not([open]) { + width: 58px !important; + max-width: 58px !important; + height: 30px; + min-height: 0; +} +.debug-panel:not([open]) summary { + box-sizing: border-box; + width: 58px; + height: 27px; + padding: 5px 7px; + text-align: center; + overflow: hidden; + text-overflow: clip; +} +.debug-panel[open] { + width: min(390px, calc(100% - 24px)) !important; + height: auto; +} +.card-choice { + border-width: 3px; + box-shadow: 4px 4px 0 rgba(0,0,0,.55), inset 0 0 0 1px rgba(255,184,39,.14); +} +.card-choice:hover { + transform: translateY(-2px); + box-shadow: 4px 6px 0 rgba(0,0,0,.65), inset 0 0 0 2px rgba(128,224,103,.24); +} +.card-icon img { + image-rendering: pixelated; + filter: drop-shadow(2px 2px 0 rgba(0,0,0,.7)); +} +#gameCanvas { image-rendering: pixelated; } + +/* v27.18: status relocation, consistent industrial controls, card watermarks */ +.hud-top-left { grid-template-columns: repeat(5, minmax(82px, auto)); } + +.left-bottom-status { + position: absolute; + z-index: 6; + left: 10px; + bottom: 10px; + width: min(310px, calc(100% - 20px)); + display: grid; + grid-template-columns: 1fr 1fr; + gap: 6px; + pointer-events: none; +} +.left-bottom-status > div { + min-width: 0; + border: 3px solid var(--line); + background: rgba(22, 26, 32, .95); + color: var(--ink); + padding: 8px 10px; + box-shadow: 4px 4px 0 rgba(0,0,0,.68), inset 0 0 0 1px rgba(255,184,39,.10); + font-size: 12px; + line-height: 1.2; + font-weight: 900; + text-transform: uppercase; + letter-spacing: .025em; + overflow: hidden; + text-overflow: ellipsis; +} +.left-bottom-status .event-brief { grid-column: 1 / -1; white-space: normal; min-height: 39px; } +.left-bottom-status .event-brief.active { background: #35221c; box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(0,0,0,.68); } +.left-bottom-status .event-brief.next { background: #22301f; box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(0,0,0,.68); } +.left-bottom-status .event-brief.locked { background: #1c2027; color: var(--muted); } +.left-bottom-status .speed-brief { color: #d9e2e8; } +.left-bottom-status .target-brief { color: #ffcf68; } +.left-bottom-status .combo-brief { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; } +.left-bottom-status .combo-brief span { color: var(--muted); font-size: 10px; } +.left-bottom-status .combo-brief strong { color: var(--green); font-size: 22px; line-height: 1; } + +/* Remove the remaining bright green/white control styling from modal actions. */ +.modal-actions button, +.facility-action, +.card-target-button { + border: 3px solid #07080a; + background: linear-gradient(#353d48, #1b1f25); + color: #e6edf2; + box-shadow: inset 0 0 0 1px rgba(255,184,39,.14), 4px 4px 0 rgba(0,0,0,.68); +} +.modal-actions button:hover:not(:disabled), +.facility-action:hover:not(:disabled), +.card-target-button:hover:not(:disabled) { + background: linear-gradient(#424b58, #242930); + color: #fff0c9; + box-shadow: inset 0 0 0 2px rgba(255,184,39,.42), 4px 4px 0 rgba(0,0,0,.72); +} +.facility-action.warn, +.modal-actions .reroll-button { + background: linear-gradient(#554221, #2b2419); + color: #ffd36a; + box-shadow: inset 0 0 0 3px #b97810, 5px 5px 0 rgba(0,0,0,.72); +} +.modal-actions .reroll-button:hover:not(:disabled) { + background: linear-gradient(#6b5227, #342919); + color: #fff0bd; + box-shadow: inset 0 0 0 3px #ffb827, 5px 5px 0 rgba(0,0,0,.76); +} +.facility-action.good { background: linear-gradient(#29422a, #19271a); color: #a9ed91; } +.facility-action.danger { background: linear-gradient(#57251f, #2d1715); color: #ffb1a3; } +.modal-actions button:disabled, +.facility-action:disabled, +.card-target-button:disabled { opacity: .42; filter: grayscale(.85); box-shadow: 3px 3px 0 rgba(0,0,0,.45); } + +/* Icons are now translucent background art rather than separate foreground badges. */ +.card-choice { + display: block; + min-height: 170px; + padding: 16px; + isolation: isolate; +} +.card-choice::before { z-index: 1; } +.card-copy { position: relative; z-index: 3; padding-right: 6px; } +.card-icon { + position: absolute; + z-index: 0; + right: -9px; + bottom: -12px; + width: 124px; + height: 124px; + border: 0; + background: transparent; + box-shadow: none; + opacity: .14; + transform: rotate(-7deg); + pointer-events: none; + overflow: visible; +} +.card-icon img { + width: 100%; + height: 100%; + object-fit: contain; + filter: grayscale(.12) contrast(1.2) drop-shadow(3px 3px 0 rgba(0,0,0,.55)); +} +.card-icon.glyph { + display: grid; + place-items: center; + color: #f0b437; + font-size: 88px; + line-height: 1; + text-shadow: 4px 4px 0 rgba(0,0,0,.55); +} +.card-choice.rare .card-icon { opacity: .16; } +.card-choice.ultra-rare .card-icon { opacity: .17; } +.card-choice.dud .card-icon { opacity: .08; filter: grayscale(1); } + +@media (max-width: 1180px) { + .hud-top-left { grid-template-columns: repeat(3, minmax(80px, 1fr)); } + .left-bottom-status { width: 290px; left: 8px; bottom: 8px; } +} +@media (max-width: 760px) { + .left-bottom-status { width: min(270px, calc(100% - 16px)); grid-template-columns: 1fr; } + .left-bottom-status .event-brief { grid-column: auto; } +} + + +/* v27.19: compact Next Day fee label and deduplicated side panel */ +.panel-head { grid-template-columns: minmax(0, 1fr) minmax(112px, 126px); } +.primary-button#nextTurnButton { + min-width: 0; + max-width: 126px; + padding: 8px 7px; + white-space: normal; + overflow: hidden; + line-height: 1.08; + display: grid; + place-content: center; + gap: 4px; + text-align: center; +} +#nextTurnButton .next-day-main { display: block; font-size: 15px; letter-spacing: .035em; } +#nextTurnButton .next-day-fee { + display: block; + max-width: 100%; + color: #ffd36a; + font-size: 9px; + line-height: 1.15; + letter-spacing: 0; + overflow-wrap: anywhere; +} From b13e07a074206b0e23f777ee186f330508d25eac Mon Sep 17 00:00:00 2001 From: 33333-33333 Date: Thu, 11 Jun 2026 14:54:21 +0900 Subject: [PATCH 3/5] tweak --- BALANCE_PATCH_NOTES.md | 114 --- PATCH_VERIFICATION.md | 20 - README.md | 14 +- assets/README_ASSETS_DARK_FACTORY.md | 5 +- assets/_legacy/images/README.md | 3 - assets/_legacy/images/poop.png | Bin 1211 -> 0 bytes assets/chicks/README.md | 1 - assets/poop/README.md | 1 - assets/poop/poop.png | Bin 378 -> 0 bytes assets/ui/README.md | 1 - dist/game-v27.17.js | 59 -- dist/game-v27.18.js | 59 -- dist/game-v27.19.js | 51 - dist/game.js | 61 +- index.html | 12 +- package-lock.json | 4 +- package.json | 4 +- src/core/balance.js | 10 +- src/core/gridExpansion.js | 10 +- src/core/mapGen.js | 2 +- src/game.js | 2 +- src/render/draw.js | 132 ++- src/systems/buildSystem.js | 10 +- src/systems/cards.js | 14 +- src/systems/contracts.js | 143 --- styles-v27.17.css | 1130 ----------------------- styles-v27.18.css | 1253 ------------------------- styles-v27.19.css | 1279 -------------------------- styles.css | 48 +- 29 files changed, 166 insertions(+), 4276 deletions(-) delete mode 100644 BALANCE_PATCH_NOTES.md delete mode 100644 PATCH_VERIFICATION.md delete mode 100644 assets/_legacy/images/README.md delete mode 100644 assets/_legacy/images/poop.png delete mode 100644 assets/chicks/README.md delete mode 100644 assets/poop/README.md delete mode 100644 assets/poop/poop.png delete mode 100644 assets/ui/README.md delete mode 100644 dist/game-v27.17.js delete mode 100644 dist/game-v27.18.js delete mode 100644 dist/game-v27.19.js delete mode 100644 src/systems/contracts.js delete mode 100644 styles-v27.17.css delete mode 100644 styles-v27.18.css delete mode 100644 styles-v27.19.css diff --git a/BALANCE_PATCH_NOTES.md b/BALANCE_PATCH_NOTES.md deleted file mode 100644 index b00bc7f..0000000 --- a/BALANCE_PATCH_NOTES.md +++ /dev/null @@ -1,114 +0,0 @@ -# Balance Patch Notes v27.14 - -## Event system - -The old shipment-goal terminology has been replaced by one-day Events in player-facing UI and balance notes. Internal names are mostly event-based; a few generic helper concepts are preserved only where they are not player-facing. - -Events start appearing from Day 8 with a 10% chance. An offered event is forced and applies only to the next running day. - -Implemented events: - -1. Premium Female Shipment - - Female -> Truck event. - - Target = estimated total production x 0.3. - - Success pays an event bonus. - -2. Contaminant Sample Export - - Poop is valid Truck cargo. - - All poop income is doubled. - - Target = estimated total production x 0.3. - - Success pays an event bonus. - -3. Health Inspection - - Poop mistake fines are doubled. - - Shredding enough poop pays an event bonus. - -4. Conveyor Jam Warning - - Jam explosion threshold becomes 85% congestion. - - Finishing with zero explosions pays an event bonus. - -5. Power Saving Order - - Conveyor speed x0.8. - - Auto Scanner cooldown x1.2. - - Settlement pays a flat subsidy. - -6. Overtime Day - - Day length becomes 80 seconds. - - No extra effect. - -7. Short Shift - - Day length becomes 40 seconds. - - Next Fairies tribute is reduced by 10%. - -8. Chick Boom - - Egg interval x0.65. - - Poop rate +5 percentage points. - -9. Rotten Feed - - Poop rate +20 percentage points. - - Shredder poop payout x1.5. - -10. Maintenance Audit - - No penalty. - - If no maintained machine is below 50% remaining durability, settlement pays a bonus. - -## Related balance behavior - -- Shredder Upgrade payout is affected by Event poop/shredder multipliers. -- COMPOSTER payout is also affected by Event shredder payout multipliers. -- Poop target Truck events no longer fine poop when poop is the valid cargo. -- Chemical Weapons Subsidy remains 70 poop / 1200 yen. -- Fairies tribute is paid on Next Day press. -- Normal Loan card and repayment state are removed. Emergency Loan remains. -- The old tax system is removed. Fairies tribute is the only recurring day-start levy. - -## v27.14 consistency/debug changes - -- Debug UI restored intentionally for balancing builds. HTML/CSS/JS include comments stating it should not be removed during cleanup unless explicitly requested. -- Debug card selector is grouped by gameplay genre. -- Debug single-card grant supports selecting the target for target-consuming build-phase cards. -- Debug All Cards still uses automatic valid targets. -- Removed unused special weight logic left over from old SPARE PARTS BIN behavior. -- Removed unused Egg Farm cash upgrade cost data; Egg upgrades are card-based. -- Shredder Upgrade now sums upgrades across all Shredder facilities, not only the original primary Shredder. -- Maintenance and repair target collection now includes additional Mixer/Shredder facilities. -- Maintenance Audit low-durability checks now include additional Mixer/Shredder facilities. -- Fixed duplicate Emergency Loan button in the bankruptcy decision modal. -- Fixed stale debug-removal CSS fragments left from the previous audit pass. -- Fixed corrupted score-breakdown formula text. - -## v27.15 dark factory visual patch - -- Wired `assets/dark_factory/facilities/` sprites into canvas rendering. -- Added pixelated rendering for facility sprites and dark factory grid/floor colors. -- Changed CSS theme from green/white panels to dark industrial panels with amber/red/blue accents. -- Moved UI emphasis: status HUD across the top, event/status strip down the left, build/equipment panel on the right, sorting controls at the bottom. -- Kept user-supplied chick/poop slots unmodified. Chick art is not auto-requested; existing poop compatibility path remains. -- Debug UI remains intentionally present for balancing builds. - - -## v27.17 verified visual patch - -- Versioned CSS and JavaScript launch filenames prevent the old visual bundle from being reused from cache. -- Removed all player-facing remnants of wage-based Repairman hiring. -- Maintenance Room remains a 2×2 buildable object and dispatches one Repairman per room. -- Conveyor slats now animate perpendicular to travel, with blue-green rubber on Boost Conveyors. -- DEBUG collapsed width reduced to 58 px. -- Facility sprite scale aligned to grid-object pixel density. -- Scanner ducts, blocked-cell coverage, chick sex colors/symbols, metal/grime decoration, and card texture icons verified in browser. - -## v27.18 UI and routing patch - -- Moved event, belt speed, combo, and truck target indicators to a non-overlapping lower-left group. -- Reworked T-junction branch mode as explicit output selection: random or a valid fixed exit. -- Lightened floor tiles, added deterministic green-fluid stains, increased conveyor arrow contrast, and centered blocked-cell X marks. -- Converted card icons into translucent background watermarks and normalized modal button styling. -- Replaced Maintenance Room art with storage/break-room pixel art. - - -## v27.19 land/UI/dynamite patch - -- Starting blocked ratio: 3%. -- Purchased-lot blocked ratio: base 3% + 0.5 percentage points per purchase, max 10%. -- Dynamite target selection is map-driven and consumes the card correctly after any blast. -- Duplicate event/status information removed. diff --git a/PATCH_VERIFICATION.md b/PATCH_VERIFICATION.md deleted file mode 100644 index 180730f..0000000 --- a/PATCH_VERIFICATION.md +++ /dev/null @@ -1,20 +0,0 @@ -# v27.19 verification - -## Automated checks - -- All source JavaScript files pass `node --check`. -- Production bundle `dist/game-v27.19.js` builds successfully. -- Initial blocked-cell generation: 6 / 200 cells = 3%. -- Purchased-lot ratios: purchase 1 = 3.5%, purchase 2 = 4.0%, purchase 14+ = 10% cap. -- A 10x10 lot at the cap generates 10 blocked cells. -- Dynamite empty-space click leaves target mode active. -- Clicking a chosen blocked cell removes that exact cell and consumes one charge. -- Escape after at least one blast finishes and consumes the card, preventing reuse. -- Browser check: no console/page errors, duplicate right-side event panel absent, Status contains no event/belt/combo/truck-target duplicates. -- Browser check: NEXT DAY Fairies fee remains inside the button. - -## Visual checks - -- Green floor residue is sparse and splattered. -- Blocked cells use subdued black/yellow hazard striping. -- Initial Status reports 6 blocked cells. diff --git a/README.md b/README.md index 5ffb72b..a761a09 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,17 @@ -# Chick Sorter v27.19 — Land and UI Patch +# Chick Sorter Serve this folder with a static HTTP server and open `index.html`. -The launch page uses cache-busted files: +The launch page uses the unversioned app assets: -- `styles-v27.19.css?build=2719` -- `dist/game-v27.19.js?build=2719` - -A `v27.19 VERIFIED` badge appears near the upper-right when the current build is loaded. +- `styles.css` +- `dist/game.js` ## Build -Run `npm install` once, then `npm run build` after editing JavaScript or `styles.css`. +Run `npm install` once, then `npm run build` after editing JavaScript or `styles.css`. Without a local Node/npm toolchain, `dist/game.js` remains a source-module wrapper for local static serving. -## v27.19 changes +## Current changes - Initial no-build tiles are 3% of the starting 20x10 land. - Each purchased 10x10 lot increases its own no-build ratio by 0.5 percentage points, capped at 10%. diff --git a/assets/README_ASSETS_DARK_FACTORY.md b/assets/README_ASSETS_DARK_FACTORY.md index 1e49cb5..5057cf3 100644 --- a/assets/README_ASSETS_DARK_FACTORY.md +++ b/assets/README_ASSETS_DARK_FACTORY.md @@ -5,10 +5,7 @@ This patch adds a **dark factory** art set without changing runtime references y ## Folder guide - `assets/dark_factory/facilities/` : new factory equipment sprites - `assets/dark_factory/previews/` : visual overview sheet -- `assets/ui/` : future UI asset buckets (buttons / panels / icons / debug) -- `assets/chicks/` : reserved for user-supplied chick sprites -- `assets/poop/` : reserved for user-supplied poop sprites -- `assets/_legacy/` : copied backup of older loose files +- `assets/images/` : user-supplied chick and poop sprites used by the renderer - `assets/images/` : left untouched for compatibility with the current build ## Notes diff --git a/assets/_legacy/images/README.md b/assets/_legacy/images/README.md deleted file mode 100644 index 0e29b23..0000000 --- a/assets/_legacy/images/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Image assets - -`poop.png` is bundled and loaded by default. Other equipment/chick art is optional and currently falls back to canvas drawing unless external art loading is enabled in `src/render/draw.js`. diff --git a/assets/_legacy/images/poop.png b/assets/_legacy/images/poop.png deleted file mode 100644 index 75fde9d97f6e0e8e3cec842c7b2d3c52709ed5f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1211 zcmV;s1VsCZP) zO>Wdc5Jn5c8ihr&P9#=bg`;oH5A%qY@2qAR;mVN1n^Eu6$wg| zvfgBT`tbJb&%S>D({=3Z!$Ioc7g_|^OZqulWXLW+`XRt7`K_PJJ`|)Dz%uzgpU*5o zY5^`Wntbhc5J@Y*rK?UmX_wl|S_RSyu!q$ZTd@+96o9moQUKI)iyGG+DFxWWx=dFa z2FeLQ`k(-lLjfj-0!$7Cm>dc)IpqZC{XQS9eQ#0Z#$X36iOq&(UUqV!O_oWkpR9_X`M)`RlzMF z4+*e=iP&95n)?D;L6rb9D3SijUc?N&_qd1>K+XY<%=En%Y8*K(;=BOPNRhGi{vMTJ z;Qwy#VV;*yH`fi=RE-KMYR-t=o^L)NP>1|4GW$zBkaffxWY5niPS{^jZL5Ev;R|Q^vPNR^ErUlj^7OT|7*1RWIZPce-hY} z*enuc>XT`Cv0UtdI3!s1$7(1D6Tox3w>2Jpu@WHtqR{op_mm;JbZcQIK*aNHYZ)Sw zesz2OWKjjoh5)ob_%QPD#uM*hApH=~N|lnWP55mfiG>184h5K;5CIVG-4Tg6FJ=ND zEP1Yk)%oNQFgalYa2R+=)cG(K;8NM51pkQKJsds+%q~H6|IGzxu{Zi8L@~vRAQ4J% z3WVf~fUgR!$h5117ouMM8V%~(#Zv4H$}9rVnmIUm{=?WmzJDRhEGBALj*U+&Aj{P-%O)jh!^QIEU1eZkAUz~V4go?w zB{d|-jsj%gW8>4@0n`FR%K^m3FDdDOXa}Gh3QP64_{2JbCz*;Z%z( zPmCjo%Cj(o&@EPyk;1SXU7k?6KrjSgmNy3~;8ll9o=_+d3;}cpL{C1(z`(%3ur${S zt9oSl+Vu|@7#Q%Ejx2;6fDUk3OsqUQ7~JIma{R%9lURVP9$z}Z=>Tk+h;;-ub+{aX zHE|#-E_M`WU|?Wi=-vMkMGdx8k8UwGz32%NuLEEPzyP`<@Bv(U(H%fiF2EHU_$(#_ zh>ikE0KO=|nh22viN8j@5Qkpl=-MkKe2iE#|MeT0z- Y0JdI?It5RF8~^|S07*qoM6N<$f>6DX4FCWD diff --git a/assets/ui/README.md b/assets/ui/README.md deleted file mode 100644 index 94d658a..0000000 --- a/assets/ui/README.md +++ /dev/null @@ -1 +0,0 @@ -Future UI asset buckets. Nothing is wired yet. Use 32x32 as the base size for non-grid UI objects.\n \ No newline at end of file diff --git a/dist/game-v27.17.js b/dist/game-v27.17.js deleted file mode 100644 index 1863d48..0000000 --- a/dist/game-v27.17.js +++ /dev/null @@ -1,59 +0,0 @@ -var Y={version:"v27.17 VERIFIED VISUAL PATCH",time:{daySeconds:60,farmShutdownGraceSeconds:10},cash:{starting:250},grid:{x:170,y:78,cols:20,rows:10,cell:46,expansion:{colsPerPurchase:10,rowsPerPurchase:10,costBase:1e3,costMultiplier:1.3333333333333333,truncateUnit:100}},map:{blockedRatio:.075},economy:{income:{mixer:5,truck:10},poopFine:10,fairiesTribute:{perDay:10,profitExemption:300,legalWorkExemptionBonus:250,profitRate:.12},incomeUpgradeRate:1.1,explosionDamageDivisor:30,maleTruckFinePerHalfDay:30,shredderBonus:{maxCards:30,incomePerUpgrade:1.25},chemicalWeaponSubsidy:{poopPerBlock:70,yenPerBlock:1200}},production:{poopRate:.08,autoScannerCooldown:3.5,autoScannerUpgradeRate:.95,autoScannerCardUpgradeRate:.95,autoScannerMinCooldown:.5,poopRateCardBonus:.04,eggSpawnRanges:[[1.95,4.35],[1.55,3.45],[1.25,2.8],[1.05,2.35]]},conveyor:{baseSpeed:52,maxSpeed:300,bearingSpeedMultiplier:1.075},cards:{definitions:[{id:"upgradeEgg",title:"EGG Improvement",rarity:"common",type:"equipmentUpgrade",target:"eggFarm",description:"Choose one EGG FARM on the map and raise it by 1 level.",tags:["EGG","ACTIVE"]},{id:"upgradeAutoScanner",title:"AUTO SCANNER Improvement",rarity:"common",type:"equipmentUpgrade",target:"autoScanner",description:"Choose one AUTO SCANNER on the map and raise it by 1 level.",tags:["SCANNER","ACTIVE"]},{id:"autoScannerTuning",title:"AUTO SCANNER Tuning",rarity:"common",type:"instant",description:"All AUTO SCANNER cooldowns use default cooldown x0.95 per copy.",tags:["SCANNER","PASSIVE"]},{id:"upgradeMixer",title:"MIXER Improvement",rarity:"common",type:"equipmentUpgrade",target:"mixer",description:"Choose MIXER on the map and raise it by 1 level.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeTruck",title:"TRUCK Improvement",rarity:"common",type:"equipmentUpgrade",target:"truck",description:"Choose TRUCK on the map and raise it by 1 level.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeTrash",title:"SHREDDER Improvement",rarity:"common",type:"equipmentUpgrade",target:"trash",description:"Shred poops for a little money. Max 30 upgrades.",tags:["POOP","ACTIVE"]},{id:"crowdedFarming",title:"Crowded Farming",rarity:"common",type:"instant",description:"EGG production interval -5%. Equipment deterioration +4%. Max 10 cards.",tags:["EGG","RISK","PASSIVE"]},{id:"hatchingFeed",title:"Hatching Feed",rarity:"common",type:"instant",description:"EGG production interval -4%. Poop rate +3%. No card limit.",tags:["EGG","POOP","PASSIVE"]},{id:"poopRateBooster",title:"Poop Culture",rarity:"common",type:"instant",description:"Base poop rate +4 percentage points. No card limit.",tags:["POOP","PASSIVE"]},{id:"safetyCover",title:"Safety Cover",rarity:"common",type:"instant",description:"Explosion damage -5%. No card limit.",tags:["RISK","PASSIVE"]},{id:"preventiveMaintenance",title:"Preventive Maintenance Manual",rarity:"common",type:"instant",description:"All equipment deterioration speed -5%. No card limit.",tags:["MAINTENANCE","PASSIVE"]},{id:"dudFilter",title:"DUD Filter",rarity:"common",type:"instant",description:"DUD chance -5 percentage points. Stacks until DUD chance reaches 0%.",tags:["CARD","PASSIVE"]},{id:"durabilityCoating",title:"Durability Coating",rarity:"common",type:"instant",description:"All equipment maximum durability +3%. No card limit.",tags:["MAINTENANCE","PASSIVE"]},{id:"bearing",title:"High-Quality Bearing",rarity:"common",type:"instant",description:"Conveyor speed +7.5%.",tags:["CONVEYOR","PASSIVE"]},{id:"sparePartsBin",title:"SPARE PARTS BIN",rarity:"common",type:"instant",description:"Restores 2% durability to every machine. A box of almost-compatible parts.",tags:["MAINTENANCE","ACTIVE"]},{id:"dudRefund",title:"DUD REFUND",rarity:"common",type:"instant",description:"DUDs now come with paperwork. Gain JPY 50 per copy when you pick a DUD.",tags:["CARD","ECONOMY","PASSIVE"]},{id:"freeReroll",title:"FREE REROLL",rarity:"common",type:"instant",description:"The first bad ideas are free.",tags:["CARD","PASSIVE"]},{id:"composter",title:"COMPOSTER",rarity:"common",type:"instant",description:"Turns shredder waste into suspicious fertilizer. Gain JPY 3 per copy when SHREDDER processes poop.",tags:["POOP","ECONOMY","PASSIVE"]},{id:"scannerQueueSpacing",title:"Scanner Queue Spacing",rarity:"common",type:"instant",description:"Manual and Auto Scanner queue spacing -15%. No card limit.",tags:["SCANNER","PASSIVE"]},{id:"extraEggOutlet",title:"Extra Egg Outlet",rarity:"rare",type:"equipmentUpgrade",target:"eggOutlet",description:"Choose one EGG FARM and add +1 output port to that EGG. Max +3 per EGG.",tags:["EGG","RARE","ACTIVE"]},{id:"recyclingSubsidy",title:"Recycling Subsidy",rarity:"rare",type:"instant",description:"SELL refund rate +10 points. Max 3 cards; normal SELL can reach 80%.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"dynamite",title:"Dynamite",rarity:"rare",type:"cellAction",target:"blockedCell",description:"Remove any 3 unbuildable cells",tags:["RISK","RARE","ONE-SHOT"]},{id:"usedMachine",title:"Used Machines",rarity:"rare",type:"instant",description:"Future equipment costs half. New purchases have no refund and 60% durability. New Machines cancels it.",tags:["ECONOMY","RISK","RARE"]},{id:"newMachine",title:"New Machines",rarity:"common",type:"instant",description:"Cancel Used Machines and restore normal prices, refunds, and durability.",tags:["ECONOMY","ONE-SHOT"]},{id:"flattery",title:"Flattery",rarity:"rare",type:"instant",description:"Next Fairies tribute -50%.",tags:["ECONOMY","RARE","ONE-SHOT"]},{id:"extraCards",title:"Extra Cards",rarity:"rare",type:"instant",description:"Draw 2 cards now and choose both.",tags:["RARE","ACTIVE"]},{id:"legalWork",title:"Legal Work",rarity:"rare",type:"instant",description:"Fairies tribute profit exemption +JPY 250.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"chemicalWeaponSubsidy",title:"Chemical Weapons Subsidy",rarity:"ultraRare",type:"instant",description:"Each day, gain JPY 1200 per 70 poop shipped by truck. No card limit.",tags:["POOP","ULTRA RARE","PASSIVE"]},{id:"laborExploitation",title:"Motivational Exploitation",rarity:"ultraRare",type:"instant",description:"Repair room work time -30%. The repairman smiles with bloodshot eyes. One time only.",tags:["MAINTENANCE","ULTRA RARE","PASSIVE"]},{id:"rescueLoan",title:"Emergency Loan",rarity:"ultraRare",type:"instant",description:"If cash is below JPY 0 at day-end settlement, gain JPY 500. Consumed on use.",tags:["ECONOMY","ULTRA RARE","ONE-SHOT"]}],defaultEffects:{bearing:0,legalWork:0,fairiesFlatteryNext:0,autoScannerTuning:0,poopRateBooster:0,crowdedFarming:0,hatchingFeed:0,safetyCover:0,recyclingSubsidy:0,chemicalWeaponSubsidy:0,preventiveMaintenance:0,dudFilter:0,durabilityCoating:0,sparePartsBin:0,dudRefund:0,freeReroll:0,composter:0,scannerQueueSpacing:0,laborExploitation:0,usedMachineActive:!1,rescueLoanCharges:0},commonWeight:8,rareWeight:2,ultraRareWeight:.45,baseDraftSize:3,maxDudsPerDraft:2,dudChancePerCard:.3,dudChanceReductionPerFilter:.05,extraCardsAddedPicks:2,rerollCost:{dayDivisor:2,multiplier:100}},events:{eventChance:.1,firstTurn:8},maintenance:{fullPerformanceUntilWear:.5,minimumPerformance:.5,durability:{conveyor:1300,eggFarm:475,autoScanner:850,mixer:775,trash:950},processingDelayMaxSeconds:{mixer:1.2,trash:1},repairman:{secondsPerOnePercent:.5,walkSpeed:90}},facilities:{conveyor:{id:"conveyor",type:"conveyor",name:"Conveyor",shortName:"Belt",price:30,buildable:!0,upgradeable:!1},boostConveyor:{id:"boostConveyor",type:"conveyor",name:"Boost Conveyor",shortName:"BOOST BELT",price:75,buildable:!0,upgradeable:!1,speedMultiplier:2},eggFarm:{id:"eggFarm",type:"eggFarm",name:"Egg Farm",shortName:"EGG",price:250,buildable:!0,upgradeable:!0,maxLevel:4},manualScanner:{id:"manualScanner",type:"scanner",kind:"manual",name:"Manual Scanner",shortName:"Manual Scanner",price:260,buildable:!0,upgradeable:!1},autoScanner:{id:"autoScanner",type:"scanner",kind:"auto",name:"Auto Scanner",shortName:"Auto Scanner",price:180,buildable:!0,upgradeable:!1},mixer:{id:"mixer",type:"facility",name:"Mixer",shortName:"MIXER",price:450,buildable:!0,upgradeable:!0,incomeKey:"mixer",body:{w:164,h:126}},trash:{id:"trash",type:"facility",name:"Waste Shredder",shortName:"SHREDDER",price:240,buildable:!0,upgradeable:!0,body:{w:180,h:100}},truck:{id:"truck",type:"facility",name:"Truck",shortName:"TRUCK",price:450,buildable:!0,upgradeable:!0,incomeKey:"truck",body:{w:176,h:138}},maintenanceRoom:{id:"maintenanceRoom",type:"maintenanceRoom",name:"Maintenance Room",shortName:"REPAIR ROOM",price:220,buildable:!0,upgradeable:!1,footprint:{cols:2,rows:2}}}};var Er=Y.version,Mt=Y.time.daySeconds,an=Y.cash.starting,Ce=Y.economy,Rr=Y.time.farmShutdownGraceSeconds,xn=Y.production.autoScannerCooldown,Pr=Y.production.autoScannerUpgradeRate,po=Y.production.autoScannerCardUpgradeRate||Y.production.autoScannerUpgradeRate,yo=Y.production.autoScannerMinCooldown,Ar=Y.events.eventChance,gt=Y.events.firstTurn,ho=Y.production.poopRate,mo=Y.production.poopRateCardBonus||0,Mn=Y.conveyor.baseSpeed,Wt=Y.conveyor.maxSpeed,gn=Y.conveyor.bearingSpeedMultiplier,$e=Y.cards,Ir=Y.cards.definitions,bo=Y.cards.defaultEffects,st=Y.production.eggSpawnRanges,f=Y.grid,ve=Y.facilities,vo=["conveyor","boostConveyor","eggFarm","autoScanner","manualScanner","mixer","trash","truck","maintenanceRoom"],cn=["mixer","trash","truck"],$r=["mixer","truck"],lt=Object.fromEntries(Object.entries(ve).map(([e,t])=>[e,t.price])),de=[{name:"right",dc:1,dr:0,angle:0,opposite:"left"},{name:"left",dc:-1,dr:0,angle:Math.PI,opposite:"right"},{name:"down",dc:0,dr:1,angle:Math.PI/2,opposite:"up"},{name:"up",dc:0,dr:-1,angle:-Math.PI/2,opposite:"down"}],p={bg:"#111318",ink:"#090a0d",muted:"#8f9bab",green:"#7bd84f",greenSoft:"#273c24",mixerBlue:"#4aa3ff",truckPink:"#ffb33e",wasteGreen:"#88d35a",danger:"#e34a36",warn:"#ffb827",white:"#e6edf2",poop:"#7b4a23",male:"#4aa3ff",female:"#ff6fae"},xe={ambient:0,important:1,critical:2};function g(e){let t=Number(e)||0;return`${t<0?"-":""}\uFFE5${Math.ceil(Math.abs(t)).toLocaleString("ja-JP")}`}function I(e,t){return`${e},${t}`}function Z(e){let[t,n]=String(e).split(",").map(Number);return{col:t,row:n}}function un(e,t,n){return Math.max(t,Math.min(n,e))}function W(e,t){return e+Math.random()*(t-e)}function Ee(e,t){return e>=0&&e=0&&tMath.round(un(r,0,255)).toString(16).padStart(2,"0");return`#${o(e)}${o(t)}${o(n)}`}function Kt(e,t,n){let o=Dr(e),r=Dr(t);return cl(wo(o.r,r.r,n),wo(o.g,r.g,n),wo(o.b,r.b,n))}var oe={appTitle:"Chick Sorter",versionTitle:`Chick Sorter ${Er}`,currency:"\uFFE5",phases:{title:"Title",build:"Build",running:"Sorting",clearing:"Clearing",loanDecision:"Emergency Loan",gameover:"Game Over"},actions:{startGame:"Start Game",nextDay:"Next Day",buildPhase:"Build Phase",restart:"Restart",close:"Close",remove:"Remove",refund:"Refund",autoMenu:"Auto Menu"},status:{build:e=>`BUILD: ${(e==="erase"?"SELL":e||"SELECT").toUpperCase()} | Right-drag pan | Hover equipment for info`,sorting:"Sorting: use scanner keys. Build after clearing the day.",allPortsConnected:"Start condition met: one EGG route reaches an exit.",equipmentPanelEmpty:"Hover equipment in Build phase.",eventPanelRunning:"Forced events appear in Build phase."},routeLabels:{mixer:"MIXER",truck:"TRUCK",trash:"WASTE",scanner:"NEXT","scanner-role-1":"NEXT",input:"IN"},fail:{outOfGrid:"Out of grid",cellOccupied:"Cell occupied",notEnoughCash:"Not enough cash",facilityExists:"Facility already exists",facilityOverlap:"Facility overlap",nothingToErase:"Nothing to sell",noUpgrade:"No upgrade available"}};function ct(e){return ve[e]?.name||String(e||"").replace(/^[a-z]/,t=>t.toUpperCase())}function ul(e){let t=ve[e];return t?e==="conveyor"||e==="boostConveyor"?`${g(t.price)} / tile`:e==="autoScanner"?`${g(t.price)} / ${xn.toFixed(1)}s cooldown`:e==="trash"?g(t.price):g(t.price):""}function dl(e){return{conveyor:"A narrow green belt. Routes decide whether chicks live, ship, or become invoices.",boostConveyor:"Moves chicks twice as fast. Wears down like a normal belt.",eggFarm:"A tiny gatehouse producing questionable eggs on schedule.",autoScanner:"Slower than hands without upgrades.",manualScanner:"A manual checkpoint. The operator is the algorithm.",mixer:"Male chicks become revenue here. Do not feed it poop.",trash:"A polite shredder for poop and other regrets.",truck:"Ships the target cargo. Wrong cargo still leaves a paper trail.",maintenanceRoom:"2\xD72 repair bay. Each room dispatches one repairman during the day."}[e]||""}function Br(e){let t=dl(e);return`${ct(e)}${ul(e)}${t?`${t}`:""}`}function Lr(e){return oe.routeLabels[e]||String(e).toUpperCase()}function Or(e){let t=2166136261;for(let n=0;n>>0}function Nr(e){let t=e>>>0;return()=>{t+=1831565813;let n=Math.imul(t^t>>>15,1|t);return n^=n+Math.imul(n^n>>>7,61|n),((n^n>>>14)>>>0)/4294967296}}function En(){return`RUN-${Date.now().toString(36)}-${Math.floor(Math.random()*1e6).toString(36)}`.toUpperCase()}function _r({seed:e,targetRatio:t=.2,reserved:n=[]}={}){let o=Nr(Or(e||En())),r=new Set(n.map(c=>typeof c=="string"?c:I(c.col,c.row))),i=[];for(let c=0;c0;c-=1){let v=Math.floor(o()*(c+1));[i[c],i[v]]=[i[v],i[c]]}let l=Math.round(f.cols*f.rows*t);return new Set(i.slice(0,Math.min(l,i.length)).map(c=>c.k))}function Gr({seed:e,colStart:t=0,colEnd:n=f.cols,rowStart:o=0,rowEnd:r=f.rows,targetRatio:i=.2,reserved:l=[]}={}){let c=Nr(Or(e||En())),v=new Set(l.map(X=>typeof X=="string"?X:I(X.col,X.row))),x=[],E=Math.max(0,Math.floor(t)),R=Math.max(E,Math.floor(n)),B=Math.max(0,Math.floor(o)),O=Math.max(B,Math.floor(r));for(let X=B;X0;X-=1){let ae=Math.floor(c()*(X+1));[x[X],x[ae]]=[x[ae],x[X]]}let ee=Math.round((R-E)*(O-B)*i);return new Set(x.slice(0,Math.min(ee,x.length)).map(X=>X.k))}var Ht=10,Ur=2,Wr=1;function qt(e,t){return`${e},${t}`}function fl(e){let[t,n]=String(e).split(",").map(Number);return{chunkX:t,chunkY:n}}function Rn(e){let t=Y.grid.expansion||{},n=Math.max(1,(e.gridExpansionPurchases||0)+1),o=(t.costBase||1e3)*n*(t.costMultiplier||4/3),r=Math.max(1,t.truncateUnit||100);return Math.floor(o/r)*r}function Kr(e){e.ownedCells=new Set,e.ownedChunks=new Set,e.gridChunkOriginY=0,e.gridExpansionPurchases=0,e.gridExpansionPurchasesByDirection={right:0,up:0};for(let t=0;t=0&&t=0&&n0)continue;let x=qt(v.chunkX,v.chunkY);t.has(x)||n.has(x)||n.set(x,So(e,v.chunkX,v.chunkY,v.direction))}}return[...n.values()].sort((o,r)=>{let i=o.direction===r.direction?0:o.direction==="right"?-1:1;return i||(o.chunkY!==r.chunkY?o.chunkY-r.chunkY:o.chunkX-r.chunkX)})}function Yr(e,t="right"){let n=Tt(e);return n.find(o=>o.direction===t)||n[0]||null}function Et(e){return{x:f.x+e.colStart*f.cell,y:f.y+e.rowStart*f.cell,w:e.cols*f.cell,h:e.rows*f.cell}}function ko(e){let t=Et(e);return{x:t.x+t.w/2-116,y:t.y+t.h/2-36,w:232,h:72,cx:t.x+t.w/2,cy:t.y+t.h/2}}function Vr(e,t){let n=ko(e);return t.x>=n.x&&t.x<=n.x+n.w&&t.y>=n.y&&t.y<=n.y+n.h}function zr(e){let t=[];for(let n=e.rowStart;nEe(t.col,t.row))}function Sl(e){return[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}].filter(t=>Ee(t.col,t.row))}function kl(e){return[{col:e.col,row:e.row+1},{col:e.col-1,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row-1}].filter(t=>Ee(t.col,t.row))}function ei(e){let t=new Set([...e.conveyorTiles]),n=o=>{o&&Ee(o.col,o.row)&&t.add(I(o.col,o.row))};for(let o of e.scanners){for(let r of Sl(o))n(r);for(let r of wl(o))n(r)}for(let o of e.eggFarms){n(o);for(let r of kl(o))n(r)}for(let o of Object.values(e.facilities))n(o.entry);return t}function jr(e){let t=hl.map(([n,o])=>({col:n,row:o}));for(let{col:n,row:o}of t)Zr(e,n,o);for(let n=0;n({...n,keys:n.keys?{left:{...n.keys.left},right:{...n.keys.right}}:null,queue:[]})),e.eggFarms=bl.map(n=>{let o=Rt(n);return{...n,nextSpawn:o,lastInterval:o}});let t=ei(e);e.blockedCells=_r({seed:e.runSeed,targetRatio:Y.map.blockedRatio,reserved:[...t]}),Cl(e),jr(e),e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function Pt(e){return e?[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}]:[]}function ye(e){let t=F(e.col,e.row);return{x:t.x+f.cell/2,y:t.y}}function dt(e,t,n){return e.eggFarms.find(o=>o.col===t&&o.row===n)||null}function ft(e,t,n){return e.scanners.find(o=>Pt(o).some(r=>r.col===t&&r.row===n))||null}function At(e,t){return e.scanners.find(n=>n.id===t)||null}function To(e,t){return e.scanners.find(n=>n.kind==="manual"&&n.slot===t)||null}function $n(e){return e?.baseId||e?.id||""}function Eo(e,t){return Object.entries(e.facilities||{}).filter(([,n])=>$n(n)===t)}function Re(e,t){return{inputA:{col:e.col,row:e.row-2},inputB:null,left:{col:e.col-1,row:e.row},right:{col:e.col+2,row:e.row}}[t]}function oi(e){return e?de.map(t=>({col:e.col+t.dc,row:e.row+t.dr})).filter(t=>Ee(t.col,t.row)):[]}function ri(e,t,n=[],o=[]){if(!t||!Ee(t.col,t.row))return[];let r=[],i=l=>{!l||!Ee(l.col,l.row)||!e.conveyorTiles.has(I(l.col,l.row))||n.some(c=>c&&Tn(l,c))||r.some(c=>Tn(c,l))||r.push({...l,viaTolerance:!Tn(l,t)})};i(t);for(let l of o)i(l);for(let l of oi(t))i(l);return r}function ti(e,t,n=[],o=[]){let r=ri(e,t,n,o),i=r.filter(l=>!l.viaTolerance);return i.length?i:r}function xl(e,t){let n=Re(t,"inputA");return!n||!Ee(n.col,n.row)?[]:e.conveyorTiles.has(I(n.col,n.row))?[{...n,viaTolerance:!1}]:[]}function Ml(e,t,n){let o=Re(t,n);return ri(e,o,Pt(t))}function gl(e,t){let n=e.facilities[t]||Eo(e,t)[0]?.[1];if(!n)return null;if(n.entry)return F(n.entry.col,n.entry.row);let o=$n(n)||t;return o==="mixer"?{x:n.x+n.w,y:n.y+n.h*.52}:o==="truck"?{x:n.x,y:n.y+n.h*.52}:o==="trash"?{x:n.x+n.w/2,y:n.y+8}:{x:n.x+n.w/2,y:n.y+n.h/2}}function ii(e,t,n){return n==="inputA"?xl(e,t).length>0:Ml(e,t,n).length>0}function be(e){e.branchCounters?.clear?.(),e.routeCache=null,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function De(e,t){return I(e,t)}function Yt(e){return Z(e)}function Tl(e,t){let n=e.conveyorMeta?.get?.(t)||{},o=[];return Array.isArray(n.outDirs)&&o.push(...n.outDirs),n.dir&&o.push(n.dir),[...new Set(o)].filter(r=>de.some(i=>i.name===r))}function El(e,t,n){let o=de.find(l=>l.name===n);if(!o)return!1;let r=e.conveyorMeta?.get?.(De(t.col+o.dc,t.row+o.dr));return r?[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))].includes(o.opposite):!1}function Rl(e,t){let n=Yt(t),o=e.conveyorMeta?.get?.(t)||{},r=de.filter(R=>e.conveyorTiles.has(De(n.col+R.dc,n.row+R.dr))).map(R=>R.name),i=Tl(e,t).filter(R=>r.includes(R)),l=r,c=i.length?i:l;if(r.length<3)return c;let v=new Set(r.filter(R=>El(e,n,R)));if(o.branchMode&&o.branchMode!=="random"&&r.includes(o.branchMode)){let R=new Set(v);R.add(o.branchMode),r.filter(B=>!R.has(B)).length>=2&&v.add(o.branchMode)}let x=r.filter(R=>!v.has(R));if(x.length)return x;let E=c.filter(R=>!v.has(R));return E.length?E:c}function Pl(e){return{version:e.routingVersion||0,cells:new Set,adjacency:new Map,components:new Map,cellToComponent:new Map,scannerInputs:new Map,scannerPorts:new Map,facilityPorts:new Map,farmOutputs:new Map,pathCache:new Map,metrics:{conveyorCells:0,edges:0,components:0,deadEnds:0,crosses:0,scannerPorts:0,connectedScannerPorts:0,facilityPorts:0,connectedFacilityPorts:0,farmOutputs:0},issues:[]}}function Al(e){let t=Pl(e);for(let o of e.conveyorTiles)t.cells.add(o),t.adjacency.set(o,[]);for(let o of t.cells){let r=Yt(o),i=Rl(e,o),l=de.filter(c=>i.includes(c.name));for(let c of l){let v=De(r.col+c.dc,r.row+c.dr);t.cells.has(v)&&t.adjacency.get(o).push({key:v,dir:c.name})}}let n=0;for(let[o,r]of t.adjacency.entries()){n+=r.length;let i=new Set(r.map(l=>l.dir));r.length===1&&(t.metrics.deadEnds+=1),r.length===4&&i.has("left")&&i.has("right")&&i.has("up")&&i.has("down")&&(t.metrics.crosses+=1)}return t.metrics.conveyorCells=t.cells.size,t.metrics.edges=Math.floor(n/2),Il(t),$l(e,t),t.issues=Kl(e,t,{includeRoutes:!1}),t}function Il(e){let t=1;for(let n of e.cells){if(e.cellToComponent.has(n))continue;let o=t++,r=[n],i=[];for(e.cellToComponent.set(n,o);r.length;){let l=r.shift();i.push(l);for(let c of e.adjacency.get(l)||[])e.cellToComponent.has(c.key)||(e.cellToComponent.set(c.key,o),r.push(c.key))}e.components.set(o,{id:o,cells:i,capacity:Math.max(1,i.length),count:0,ratio:0})}e.metrics.components=e.components.size}function $l(e,t){for(let n of e.scanners){let o={};for(let r of["inputA","left","right"]){let i=Re(n,r),l=r==="inputA"?i&&t.cells.has(De(i.col,i.row))?[{...i}]:[]:ti(e,i,Pt(n)).filter(x=>t.cells.has(De(x.col,x.row))),c=l.map(x=>De(x.col,x.row)),v=c.length>0;if(o[r]={type:r,cell:i,cells:l,keys:c,key:c[0]||null,connected:v},t.metrics.scannerPorts+=1,v&&(t.metrics.connectedScannerPorts+=1),r==="inputA")for(let x of c)t.scannerInputs.set(x,n.id)}t.scannerPorts.set(n.id,o)}for(let[n,o]of Object.entries(e.facilities)){if(!o.entry)continue;let r=ti(e,o.entry).filter(c=>t.cells.has(De(c.col,c.row))),i=r.map(c=>De(c.col,c.row)),l=i.length>0;t.facilityPorts.set(n,{id:n,cell:{...o.entry},cells:r,keys:i,key:i[0]||null,connected:l}),t.metrics.facilityPorts+=1,l&&(t.metrics.connectedFacilityPorts+=1)}for(let n of e.eggFarms){let o=oi({col:n.col,row:n.row}).map(r=>De(r.col,r.row)).filter(r=>t.cells.has(r));t.farmOutputs.set(n.id,o),t.metrics.farmOutputs+=o.length}}function _e(e){let t=e.routingVersion||0;return(!e.factoryGraph||e.factoryGraph.version!==t)&&(e.factoryGraph=Al(e)),e.factoryGraph}function si(e){let t=_e(e);return e.factoryGraphCommittedVersion=t.version,e.factoryGraphSnapshot=Dl(t),t}function Dl(e){return e?{version:e.version,conveyorCells:e.metrics.conveyorCells,edges:e.metrics.edges,components:e.metrics.components,deadEnds:e.metrics.deadEnds,crosses:e.metrics.crosses,scannerPorts:`${e.metrics.connectedScannerPorts}/${e.metrics.scannerPorts}`,facilityPorts:`${e.metrics.connectedFacilityPorts}/${e.metrics.facilityPorts}`,farmOutputs:e.metrics.farmOutputs,issues:[...e.issues||[]]}:null}function Fl(e,t){let n=t.col-e.col,o=t.row-e.row;return de.find(r=>r.dc===n&&r.dr===o)?.name||null}function Ro(e,t,n){let o=_e(e),r=De(t.col,t.row);if(!o.cells.has(r))return[];let i=`${r}|${n.cacheKey||"dynamic"}`;if(n.cacheKey&&o.pathCache.has(i))return o.pathCache.get(i).map(le=>le.map(se=>({...se})));let l=`${r}|none`,c=[{key:r,col:t.col,row:t.row,incoming:"none",depth:0}],v=new Map([[l,0]]),x=new Map,E=[],R=1/0,B=8,O=24,ee=80;for(;c.length;){let le=c.shift();if(le.depth>R)break;let se=`${le.key}|${le.incoming}`;if(n(le)){if(E.push(se),R=le.depth,E.length>=O)break;continue}for(let A of o.adjacency.get(le.key)||[]){let G=Yt(A.key),q=Fl(le,G),me=le.depth+1;if(me>R)continue;let D=`${A.key}|${q}`,U=v.get(D);if(U==null)v.set(D,me),x.set(D,[se]),c.push({key:A.key,col:G.col,row:G.row,incoming:q,depth:me});else if(U===me){let S=x.get(D)||[];S.length{if(X.length>=ee)return;let[A]=le.split("|"),G=[Yt(A),...se];if(le===l||A===r){X.push(G);return}for(let q of x.get(le)||[])ae(q,G)};for(let le of E)ae(le,[]);let he=[],ie=new Set;for(let le of X){let se=le.map(A=>De(A.col,A.row)).join(">");ie.has(se)||(ie.add(se),he.push(le))}return n.cacheKey&&o.pathCache.set(i,he.map(le=>le.map(se=>({...se})))),he}function li(e){let t=_e(e),n=new Map;for(let[o,r]of t.components.entries())n.set(o,{id:o,cells:[...r.cells],capacity:r.capacity,count:0,ratio:0});return{components:n,cellToComponent:new Map(t.cellToComponent)}}function ai(e,t,n){let o=_e(e),r=null,i=1/0;for(let l of o.cells){let c=Z(l),v=F(c.col,c.row),x=Math.hypot(v.x-t,v.y-n);xF(o.col,o.row));return t&&n.push(t),n}function ut(e,t){t&&(!e.length||Fr(e[e.length-1],t)>1)&&e.push(t)}function Bl(e,t,n,o=null){let r=[{x:e.x,y:e.y}];ut(r,F(t.col,t.row));for(let i of Dn(n,o))ut(r,i);return r}function Ll(e,t){let n=Dn(e),o=Re(t,"inputA");return o&&ut(n,F(o.col,o.row)),ut(n,ye(t)),n}function Ol(e,t,n,o){let r=[{x:e.x,y:e.y}];ut(r,F(t.col,t.row));for(let l of Dn(n))ut(r,l);let i=Re(o,"inputA");return i&&ut(r,F(i.col,i.row)),ut(r,ye(o)),r}function Nl(e,t,n=0){let o=F(t.col,t.row),r=0;for(let i of e.chicks||[]){if(i.stage==="flying"||i.stage==="queued")continue;Math.hypot(i.x-o.x,i.y-o.y){let R=x.roleBias??0,B=E.roleBias??0;if(R!==B)return R-B;let O=x.cells?.length??x.route?.length??Number.POSITIVE_INFINITY,ee=E.cells?.length??E.route?.length??Number.POSITIVE_INFINITY;if(O!==ee)return O-ee;let X=x.key||JSON.stringify(x.route||x.cells||x),ae=E.key||JSON.stringify(E.route||E.cells||E);return X.localeCompare(ae)});if(!o||r.length===1)return r[0];let i=r[0].roleBias??0,l=r.filter(x=>(x.roleBias??0)===i),c=Math.min(...l.map(x=>ni(e,x)));l=l.filter(x=>ni(e,x)===c);let v=e.branchCounters.get(t)||0;return e.branchCounters.set(t,v+1),l[Math.floor(Math.random()*l.length)]}function ci(e){return e.role===0?{left:{match:"male",destination:"mixer"},right:{match:"default",destination:"scanner-role-1"}}:{left:{match:"poop",destination:"trash"},right:{match:"default",destination:"truck"}}}function Po(e){let t=ci(e);return{left:t.left.destination,right:t.right.destination}}function Ao(e,t){return ci(e).left.match===t.sex?"left":"right"}function Io(e){return Lr(e)}function $o(e){return{mixer:"#2477ff",truck:"#ff6aa8",trash:"#22b94f","scanner-role-1":"#526456",scanner:"#526456",input:"#526456"}[e]||"#102015"}function It(e,t,n=!1){let o=_e(e),r=(o.farmOutputs.get(t.id)||[]).map(Yt),i=[];for(let v of r){let x=R=>o.scannerInputs.has(De(R.col,R.row));x.cacheKey=`farmInput:${v.col},${v.row}:v${o.version}`;let E=Ro(e,v,x);for(let R of E){let B=R[R.length-1],O=o.scannerInputs.get(De(B.col,B.row)),ee=At(e,O);ee&&i.push({key:`${ee.id}:${B.col},${B.row}:${R.length}`,scanner:ee,cells:R})}}let l=In(e,`farm:${t.id}`,i,n);if(l)return{scannerId:l.scanner.id,route:Ll(l.cells,l.scanner)};let c=In(e,`farm:${t.id}:output`,r.map(v=>({key:I(v.col,v.row),cells:[v]})),n);return c?{scannerId:null,route:Dn(c.cells)}:null}function ui(e,t,n,o,r=!1){let i=At(e,o);if(!i)return null;let c=_e(e).scannerPorts.get(i.id)?.[t],v=Re(i,t),x=c?.connected?(c.keys||[c.key]).filter(Boolean).map(Yt):[];if(!v||!x.length)return null;let E=Po(i)[t];return E==="scanner-role-1"?_l(e,i,t,n,v,x,r):Gl(e,i,t,n,v,x,E,r)}function _l(e,t,n,o,r,i,l){let c=_e(e),v=e.scanners.filter(R=>R.id!==t.id&&c.scannerPorts.get(R.id)?.inputA?.connected),x=[];for(let R of i)for(let B of v){let O=c.scannerPorts.get(B.id)?.inputA?.key;if(!O)continue;let ee=(c.scannerPorts.get(B.id)?.inputA?.keys||[O]).filter(Boolean),X=ie=>ee.includes(De(ie.col,ie.row));X.cacheKey=`toScanner:${R.col},${R.row}:${B.id}:v${c.version}`;let ae=Ro(e,R,X),he=B.role===1?0:1;for(let ie of ae)x.push({key:`${he}:start${I(R.col,R.row)}:s${B.id}:${ie.length}:${I(ie[ie.length-1].col,ie[ie.length-1].row)}`,target:B,cells:ie,roleBias:he})}let E=In(e,`scanner:${t.id}:${n}:toRole1`,x,l);return E?{destination:"scanner",nextScannerId:E.target.id,route:Ol(o,r,E.cells,E.target)}:null}function Gl(e,t,n,o,r,i,l,c){let v=_e(e),x=[...v.facilityPorts.entries()].filter(([B,O])=>O?.connected&&$n(e.facilities?.[B])===l);if(!x.length)return null;let E=[];for(let B of i)for(let[O,ee]of x){let X=(ee.keys||[ee.key]).filter(Boolean);if(!X.length)continue;let ae=ie=>X.includes(De(ie.col,ie.row));ae.cacheKey=`toFacility:${B.col},${B.row}:${O}:v${v.version}`;let he=Ro(e,B,ae);for(let ie of he)E.push({key:`start${I(B.col,B.row)}:${O}:${ie.length}:${I(ie[ie.length-1].col,ie[ie.length-1].row)}`,cells:ie,facilityId:O})}let R=In(e,`scanner:${t.id}:${n}:${l}`,E,c);return R?{destination:l,facilityId:R.facilityId,route:Bl(o,r,R.cells,gl(e,R.facilityId))}:null}function di(e,t,n=new Set){if(!t||n.has(t.id))return!1;n.add(t.id);for(let o of["left","right"]){let r=ui(e,o,ye(t),t.id,!1);if(r){if(["mixer","trash","truck"].includes(r.destination))return!0;if(r.destination==="scanner"){let i=At(e,r.nextScannerId);if(di(e,i,n))return!0}}}return!1}function Ul(e,t){return!!It(e,t,!1)?.scannerId}function Fn(e){if(e.phase!=="build")return[];let t=[];for(let n of e.eggFarms||[])Ul(e,n)||t.push({type:"eggFarm",id:n.id,ref:n,message:"This Egg will not produce chicks"});for(let n of cn)for(let[o,r]of Eo(e,n))_e(e).facilityPorts.get(o)?.connected||t.push({type:"facility",id:o,ref:r,message:"This facility cannot receive items"});return t}function Wl(e){let t=_e(e);for(let r of e.eggFarms||[]){let i=It(e,r,!1);if(!i?.scannerId)continue;let l=At(e,i.scannerId);if(di(e,l))return[]}let n=e.eggFarms?.length||0,o=[...t.facilityPorts.entries()].filter(([r,i])=>i?.connected&&["mixer","trash","truck"].includes($n(e.facilities?.[r]))).length;return n?t.metrics.farmOutputs?e.scanners?.length?o?["Connect at least one EGG through a scanner to any valid exit."]:["Connect at least one receiver exit: Mixer, Shredder, or Truck."]:["Build at least one scanner and connect it to an EGG route."]:["Connect at least one EGG to a conveyor."]:["Build at least one EGG before starting the next day."]}function An(e){return e.kind==="manual"?`S${(e.slot??0)+1}`:`Auto Scanner #${e.id}`}function Kl(e,t=_e(e),n={}){let o=n.includeRoutes!==!1,r=[],i={mixer:"Mixer",trash:"Shredder",truck:"Truck"};for(let l of cn){let c=Eo(e,l);if(!c.length){r.push(`${i[l]||l} is missing`);continue}for(let[v]of c)t.facilityPorts.get(v)?.connected||r.push(`${i[l]||l} receiver has no conveyor`)}for(let l of e.scanners){let c=t.scannerPorts.get(l.id)||{};if(c.inputA?.connected||r.push(`${An(l)} input has no conveyor`),c.left?.connected||r.push(`${An(l)} left output has no conveyor`),c.right?.connected||r.push(`${An(l)} right output has no conveyor`),!!o)for(let v of["left","right"])c[v]?.connected&&!ui(e,v,ye(l),l.id)&&r.push(`${An(l)} ${v} route is incomplete`)}if(o)for(let l of e.eggFarms)It(e,l)?.scannerId||r.push(`Egg Farm #${l.id} has no scanner route`);else for(let l of e.eggFarms)(t.farmOutputs.get(l.id)||[]).length||r.push(`Egg Farm #${l.id} has no output conveyor`);return[...new Set(r)]}function fn(e){return Wl(e)}function fi(e){return fn(e).length===0}var pi=[{key:"premiumFemaleShipment",target:"female",truckTarget:"female",title:"Premium Female Shipment",route:"Female -> Truck",note:"Today only: ship female chicks to Truck. Meet the export target for a bonus.",objective:"truckTarget"},{key:"contaminantSampleExport",target:"poop",truckTarget:"poop",title:"Contaminant Sample Export",route:"Poop value x2",note:"Today only: poop is valid Truck cargo and all poop income is doubled.",objective:"truckTarget",poopValueMultiplier:2},{key:"healthInspection",title:"Health Inspection",route:"Poop -> Shredder",note:"Today only: poop mistakes are fined double. Shred enough poop for an inspection bonus.",objective:"poopTrash",poopFineMultiplier:2},{key:"conveyorJamWarning",title:"Conveyor Jam Warning",route:"No explosions",note:"Today only: jam explosions trigger at 85% congestion. Finish with zero explosions for a bonus.",objective:"noExplosion",congestionExplosionThreshold:.85,congestionWarningThreshold:.68},{key:"powerSavingOrder",title:"Power Saving Order",route:"Slow factory subsidy",note:"Today only: conveyors -20% speed and Auto Scanners +20% cooldown. A subsidy is paid at settlement.",objective:"flatBonus",conveyorSpeedMultiplier:.8,autoScannerCooldownMultiplier:1.2},{key:"overtimeDay",title:"Overtime Day",route:"80 second day",note:"Today only: the work day is longer. No extra reward or penalty.",objective:"none",daySeconds:80},{key:"shortShift",title:"Short Shift",route:"40 second day",note:"Today only: the work day is shorter. The next Fairies tribute is reduced by 10%.",objective:"none",daySeconds:40,fairiesTributeMultiplier:.9},{key:"chickBoom",title:"Chick Boom",route:"EGG interval x0.65",note:"Today only: eggs hatch faster and poop rate rises by 5 percentage points.",objective:"none",productionMultiplier:1/.65,poopRateAdd:.05},{key:"rottenFeed",title:"Rotten Feed",route:"Poop surge",note:"Today only: poop rate rises by 20 percentage points and Shredder poop income is multiplied by 1.5.",objective:"none",poopRateAdd:.2,shredderIncomeMultiplier:1.5},{key:"maintenanceAudit",title:"Maintenance Audit",route:"Durability check",note:"Today only: machines below 50% remaining durability fail the audit. Passing with none below 50% pays a bonus.",objective:"maintenanceAudit"}];function we(e,t=0){let n=Number(e);return Number.isFinite(n)?n:t}function Hl(e,t=0,n=1){let o=Math.max(1,Number(e?.turn||1)+1),r=Math.floor(Do(e)*(.08+Math.random()*.08)),i=Math.floor(Math.max(0,e.cash||0)*.25),l=Math.floor(Math.max(0,t)*Math.max(1,o)*.75);return Math.max(120,Math.ceil(Math.max(r,i,l)*n))}function yi(e){return Math.max(0,Math.ceil(500+Math.max(1,e?.turn||1)*25))}function Do(e){return[...e.eggFarms.map(t=>t.price||0),...e.scanners.map(t=>t.price||0),...Object.values(e.facilities).map(t=>t.price||0),...[...e.conveyorMeta.values()].map(t=>t.price||0)].reduce((t,n)=>t+n,0)}function ql(e,t=1,n=Mt){return e.eggFarms.reduce((o,r)=>{let[i,l]=dn(r),c=Math.max(.1,(i+l)/2);return o+Math.max(1,n)/c*Math.max(.01,t||1)},0)}function Yl(e,t){let n=we(t.productionMultiplier,1),o=we(t.daySeconds,Mt),r=ql(e,n,o),i=Math.max(0,Number(e?.cardEffects?.hatchingFeed)||0),l=Math.max(0,Number(e?.cardEffects?.poopRateBooster)||0),c=Math.pow(1.03,i),v=ho+mo*l,x=Math.min(.95,Math.max(0,(v+we(t.poopRateAdd,0))*we(t.poopMultiplier,1)*c));return{estimate:r,poopRate:x}}function hi(e){if(e.turn+1Ar)return null;let n=pi[Math.floor(Math.random()*pi.length)],{estimate:o,poopRate:r}=Yl(e,n),i=0;n.objective==="truckTarget"?i=Math.max(1,Math.ceil(o*.3)):n.objective==="poopTrash"&&(i=Math.max(1,Math.ceil(o*r*.8)));let l=0;return["truckTarget","poopTrash","noExplosion"].includes(n.objective)&&(l=Hl(e,o)),n.objective==="flatBonus"&&(l=yi(e)),n.objective==="maintenanceAudit"&&(l=yi(e)),{id:`event-${e.turn}-${Date.now()}-${Math.floor(Math.random()*9999)}`,...n,target:n.target||null,truckTarget:n.truckTarget||null,forced:!0,productionMultiplier:we(n.productionMultiplier,1),poopMultiplier:we(n.poopMultiplier,1),poopRateAdd:we(n.poopRateAdd,0),daySeconds:we(n.daySeconds,Mt),targetAmount:i,estimatedOutput:Math.round(o),reward:l,createdTurn:e.turn,oneTurnOnly:!0}}function mi(e){e.eventActive=e.eventOffer?{...e.eventOffer}:null,e.eventOffer=null}function bi(e){e.eventActive=null}function vi(e){return Math.max(1,we(e.eventActive?.daySeconds,Mt))}function wi(e){return we(e.eventActive?.productionMultiplier,1)}function Si(e){let t=Math.max(0,Number(e?.cardEffects?.hatchingFeed)||0),n=Math.max(0,Number(e?.cardEffects?.poopRateBooster)||0),o=Math.pow(1.03,t),r=ho+mo*n,i=we(e.eventActive?.poopRateAdd,0);return Math.min(.95,Math.max(0,(r+i)*we(e.eventActive?.poopMultiplier,1)*o))}function je(e){return e.eventActive?.truckTarget||e.eventActive?.target||"female"}function Fo(e,t){return t==="male"?e.truckMale||0:t==="poop"?e.poopTruck||0:e.truckFemale||0}function ki(e,t){return je(e)===t}function Ci(e){return je(e)!=="male"}function Bo(e){return Math.max(.01,we(e.eventActive?.poopValueMultiplier,1))}function Bn(e){return Math.max(.01,Bo(e)*we(e.eventActive?.shredderIncomeMultiplier,1))}function Lo(e){return Math.max(.01,we(e.eventActive?.poopFineMultiplier,1))}function Oo(e){return Math.max(.1,Math.min(1,we(e.eventActive?.congestionExplosionThreshold,1)))}function xi(e){return Math.max(.1,Math.min(1,we(e.eventActive?.congestionWarningThreshold,.8)))}function Mi(e){return Math.max(.01,we(e?.fairiesTributeMultiplier,1))}function Vl(e){let t=0,n=(o,r)=>{let i=Math.max(1,we(r,1)),l=Math.max(0,we(o,0));1-Math.min(1,l/i)<.5&&(t+=1)};for(let o of e.conveyorMeta?.values?.()||[])n(o.uses,o.durability);for(let o of e.eggFarms||[])n(o.maintenance?.uses,o.maintenance?.durability);for(let o of e.scanners||[])o.kind==="auto"&&n(o.maintenance?.uses,o.maintenance?.durability);for(let o of Object.values(e.facilities||{})){let r=o?.baseId||o?.id;(r==="mixer"||r==="trash")&&n(o.maintenance?.uses,o.maintenance?.durability)}return t}function gi(e){let t=e.eventActive;if(!t)return null;let n=0,o=!0,r=0,i="";t.objective==="truckTarget"?(n=Fo(e.stats,t.target),o=n>=t.targetAmount,r=o?t.reward:0):t.objective==="poopTrash"?(n=e.stats.poopTrash||0,o=n>=t.targetAmount,r=o?t.reward:0):t.objective==="noExplosion"?(n=e.stats.explosions||0,o=n===0,r=o?t.reward:0,i=`${n} explosion(s)`):t.objective==="flatBonus"?(o=!0,r=t.reward):t.objective==="maintenanceAudit"?(n=Vl(e),o=n===0,o&&(r=t.reward),i=`${n} machine(s) below 50%`):o=!0,r>0?(Ge(e,r),e.stats.eventBonus=(e.stats.eventBonus||0)+r,e.totals.eventBonus+=r,e.totals.eventSuccess+=1):t.objective&&t.objective!=="none"&&(e.stats.eventBonus=e.stats.eventBonus||0,e.totals.eventFailed+=o?0:1,o&&(e.totals.eventSuccess+=1));let l={title:t.title,key:t.key,target:t.target,route:t.route,objective:t.objective,targetAmount:t.targetAmount||0,count:n,success:o,bonus:r,reward:t.reward||0,productionMultiplier:t.productionMultiplier,poopMultiplier:t.poopMultiplier,daySeconds:t.daySeconds,detail:i};return e.stats.eventResult=l,l}function No(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function zl(e){return!!e?.cardEffects?.usedMachineActive}function Xl(e,t){return t?1:Math.min(.8,.5+.1*Math.min(3,No(e,"recyclingSubsidy")))}function Ql(e){return Math.pow(.95,No(e,"safetyCover"))}function Ln(e){let t=e?.ref||e||{},n=e?.type||t.type;return n==="conveyor"?t.price||ve[t.kind]?.price||ve.conveyor.price:n==="eggFarm"?t.price||ve.eggFarm.price:n==="scanner"?t.price||(t.kind==="auto"?ve.autoScanner.price:ve.manualScanner.price):n==="facility"?t.price||ve[t.id]?.price||0:n==="maintenanceRoom"?t.price||ve.maintenanceRoom.price:ve[t.id]?.price||0}function Oe(e,t=null){let n=ve[e]?.price||0;return zl(t)?Math.ceil(n*.5):n}function Jl(e,t){return e?.facilities?Object.values(e.facilities).filter(n=>(n?.baseId||n?.id)===t).reduce((n,o)=>n+Math.max(0,(o.level||1)-1),0):0}function pt(e,t){return $r.includes(t)?Math.pow(Ce.incomeUpgradeRate,Jl(e,t)):1}function ze(e){return Math.ceil(Ce.income.mixer*pt(e,"mixer"))}function Fe(e){return Math.ceil(Ce.income.truck*pt(e,"truck"))}function pn(e){return Math.ceil(Ce.poopFine*pt(e,"mixer")*Lo(e))}function yn(e){return Math.ceil(Ce.poopFine*pt(e,"truck")*Lo(e))}function _o(e){let t=Ce.maleTruckFinePerHalfDay*(e.turn/2);return Math.ceil(t*pt(e,"truck"))}function Go(e){return e?.facilities?Object.values(e.facilities).filter(t=>(t?.baseId||t?.id)==="trash").reduce((t,n)=>t+Math.max(0,(n.level||1)-1),0):0}function $t(e){return Math.min(Ce.shredderBonus.maxCards,Go(e))}function Vt(){return Ce.shredderBonus.maxCards}function yt(e){let t=typeof e=="number"?e:$t(e),n=Math.min(Ce.shredderBonus.maxCards,Math.max(0,t));return n>0?Math.ceil(n*(Ce.shredderBonus.incomePerUpgrade||1)):0}function jl(e){let t=$t(e),n=yt(t),o=Math.ceil(n*Bn(e));return{cards:t,chance:o>0?1:0,amount:o,expected:o,baseAmount:n}}function Ti(e){let t=jl(e);return t.amount>0&&(e.stats.shredderBonus=(e.stats.shredderBonus||0)+t.amount,e.totals.shredderBonus=(e.totals.shredderBonus||0)+t.amount,Ge(e,t.amount)),t}function On(e,t=e.turn,n=null){let o=Math.max(1,Math.floor(Number(t)||1)),r=Ce.fairiesTribute||{perDay:10,profitExemption:300,legalWorkExemptionBonus:250,profitRate:.12},i=Math.ceil(o*(r.perDay||10)),l=Math.max(0,Math.floor(Number(n??e?.lastResult?.profit??e?.stats?.profit??0)||0)),c=Math.max(0,e?.cardEffects?.legalWork||0),v=Math.max(0,(r.profitExemption||0)+c*(r.legalWorkExemptionBonus||0)),x=Math.max(0,l-v),E=Math.ceil(x*Math.max(0,Number(r.profitRate)||0)),R=i+E,B=Math.max(0,e?.cardEffects?.fairiesFlatteryNext||e?.cardEffects?.flattery||0),O=B>0?Math.pow(.5,B):1,ee=Math.max(.01,Number(e?.pendingFairiesTributeMultiplier)||1),X=O*ee,ae=Math.max(0,Math.ceil(R*X)),he=Math.max(0,R-ae);return{day:o,base:i,profit:l,legalWork:c,profitExemption:v,taxableProfit:x,profitTribute:E,gross:R,flatteryCount:B,eventMultiplier:ee,perCardReduction:Math.ceil(R*.5),reduction:he,amount:ae}}function ht(e,t){let n=e?.ref||e||{},o=e?.type==="conveyor"?t?.conveyorMeta?.get(e.oldKey||n.id):n,r=o?.price||Ln(e||n),i=o?.builtSession===t?.buildSession;if(o?.noRefund||n?.noRefund)return{amount:0,sameBuild:i,price:r,rate:0,noRefund:!0};let l=Xl(t,i);return{amount:Math.max(0,Math.ceil(r*l)),sameBuild:i,price:r,rate:l,noRefund:!1}}function Zl(e,t=null){let n=Math.max(1,Math.ceil((Number(e)||0)/Ce.explosionDamageDivisor));return Math.max(1,Math.ceil(n*Ql(t)))}function ea(e,t){return Math.max(0,Math.ceil(t))}function Ei(e,t){e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,t>=0?(e.stats.revenue+=t,e.totals.revenue+=t):(e.stats.penalty+=Math.abs(t),e.totals.penalty+=Math.abs(t)),e.totals.maxCash=Math.max(e.totals.maxCash,e.cash)}function Ge(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&Ei(e,n),n}function mt(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&Ei(e,-n),n}function Dt(e,t){mt(e,t)}function Ri(e,t){t<=0||(e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,e.totals.maxCash=Math.max(e.totals.maxCash,e.cash))}function Pi(e){let t=ze(e);return e.stats.mixerRevenue+=t,Ge(e,t),t}function Ai(e){let t=pn(e);return e.stats.mixerPoopFine+=t,e.totals.mixerPoopFine+=t,mt(e,t),t}function Ii(e){let t=yn(e);return e.stats.truckPoopFine+=t,e.totals.truckPoopFine+=t,mt(e,t),t}function $i(e){let t=_o(e);return e.stats.maleTruckFine+=t,e.totals.maleTruckFine+=t,mt(e,t),t}function Di(e,t){let n=Zl(t,e);return e.stats.explosionDamage+=n,e.totals.explosionDamage+=n,mt(e,n),n}function Fi(e){let t=je(e),n=Fo(e.stats,t),o=t==="poop"?Math.ceil(Fe(e)*Bo(e)):Fe(e),r=n*o,i=ea(e,r);return e.stats.pendingTruckRevenue=i,e.stats.truckRevenue=i,t==="poop"?e.stats.poopShipmentIncome=i:e.stats.chickShipmentIncome=i,i>0&&Ge(e,i),{base:r,adjusted:i,target:t,targetCount:n,unitPrice:o}}function Bi(e,t=e.turn,n=null,o={}){let r=On(e,t,n);return e.cardEffects&&(e.cardEffects.fairiesFlatteryNext=0,e.cardEffects.flattery!=null&&delete e.cardEffects.flattery),e.pendingFairiesTributeMultiplier!=null&&(e.pendingFairiesTributeMultiplier=1),r.amount<=0||(o.recordStats?(e.stats.fairiesTribute=(e.stats.fairiesTribute||0)+r.amount,e.totals.fairiesTribute=(e.totals.fairiesTribute||0)+r.amount,mt(e,r.amount)):(e.totals.fairiesTribute=(e.totals.fairiesTribute||0)+r.amount,e.totals.penalty=(e.totals.penalty||0)+r.amount,e.totals.profit=(e.totals.profit||0)-r.amount,e.cash-=r.amount)),r}function Li(e){let t=No(e,"chemicalWeaponSubsidy"),n=Math.max(0,e?.stats?.poopTruck||0),o=Ce.chemicalWeaponSubsidy||{poopPerBlock:70,yenPerBlock:1200},r=Math.floor(n/Math.max(1,o.poopPerBlock||70)),i=t>0&&r>0?r*Math.max(0,o.yenPerBlock||1200)*t:0;return i>0&&(e.stats.chemicalWeaponSubsidy=(e.stats.chemicalWeaponSubsidy||0)+i,e.totals.chemicalWeaponSubsidy=(e.totals.chemicalWeaponSubsidy||0)+i,Ge(e,i)),{cards:t,poopTruck:n,blocks:r,amount:i}}function Oi(e){let t=Do(e),n=Math.max(1,e.totals.turnsCompleted||e.turn||1),o=Math.max(0,e.cash+e.totals.revenue+t*.5+e.totals.eventBonus*.5),r=Math.ceil(o/n),i=Math.floor(n*35+Math.max(0,n-5)*15),l=e.totals.correct*5,c=e.totals.explosionDamage;return{score:Math.max(0,Math.floor(o+r+l-e.totals.penalty-i)),factoryValue:t,base:o,dailyEarned:r,dayPenalty:i,correctBonus:l,explosionPenalty:c,days:n}}function ta(e){return{...e,keys:e.keys?{left:{...e.keys.left},right:{...e.keys.right}}:null,queue:[],cooldown:e.cooldown||0}}function hn(e){return JSON.stringify({cash:e.cash,stats:e.stats,totals:e.totals,nextId:e.nextId,gridX:f.x,gridY:f.y,gridCols:e.gridCols||f.cols,gridRows:e.gridRows||f.rows,gridExpansionPurchases:e.gridExpansionPurchases||0,gridExpansionPurchasesByDirection:e.gridExpansionPurchasesByDirection||{right:0,up:0},gridChunkOriginY:e.gridChunkOriginY||0,ownedCells:[...e.ownedCells||[]],ownedChunks:[...e.ownedChunks||[]],blockedCells:[...e.blockedCells||[]],selected:e.selected,multiSelected:e.multiSelected||[],buildTool:e.buildTool,view:e.view,facilities:e.facilities,eggFarms:e.eggFarms,scanners:e.scanners.map(ta),conveyorTiles:[...e.conveyorTiles],conveyorMeta:[...e.conveyorMeta.entries()],branchCounters:[...e.branchCounters.entries()],cardEffects:e.cardEffects,cardDraft:e.cardDraft,cardTargetPick:e.cardTargetPick})}function Ni(e,t){let n=JSON.parse(t);e.cash=n.cash,e.stats=n.stats,e.totals=n.totals,e.nextId=n.nextId,f.x=n.gridX??Y.grid.x,f.y=n.gridY??Y.grid.y,f.cols=n.gridCols||Y.grid.cols,f.rows=n.gridRows||Y.grid.rows,e.gridCols=f.cols,e.gridRows=f.rows,e.gridExpansionPurchases=n.gridExpansionPurchases||0,e.gridExpansionPurchasesByDirection=n.gridExpansionPurchasesByDirection||{right:0,up:0},e.gridChunkOriginY=n.gridChunkOriginY||0,e.ownedCells=new Set(n.ownedCells||[]),e.ownedChunks=new Set(n.ownedChunks||[]),e.gridOwnedCells=e.ownedCells.size||f.cols*f.rows,e.blockedCells=new Set(n.blockedCells||[]),e.selected=n.selected,e.multiSelected=n.multiSelected||[],e.buildTool=n.buildTool,e.view=n.view||{x:0,y:0,scale:1},e.view.scale==null&&(e.view.scale=1),e.facilities=n.facilities||{},e.eggFarms=n.eggFarms||[],e.scanners=(n.scanners||[]).map(o=>({...o,queue:[],cooldown:o.cooldown||0})),e.conveyorTiles=new Set(n.conveyorTiles||[]),e.conveyorMeta=new Map(n.conveyorMeta||[]),e.branchCounters=new Map(n.branchCounters||[]),e.cardEffects=n.cardEffects||{bearing:0,legalWork:0,fairiesFlatteryNext:0,scannerQueueSpacing:0},e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft=n.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardTargetPick=n.cardTargetPick||null,e.groupDrag=null,e.selectionBox=null,e.pan=null,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function Be(e){e.phase==="build"&&(e.undoStack.push(hn(e)),e.undoStack.length>80&&e.undoStack.shift(),e.redoStack=[])}function Uo(e){return e.phase!=="build"||!e.undoStack.length?!1:(e.redoStack.push(hn(e)),Ni(e,e.undoStack.pop()),!0)}function Wo(e){return e.phase!=="build"||!e.redoStack.length?!1:(e.undoStack.push(hn(e)),Ni(e,e.redoStack.pop()),!0)}function H(e,t,n,o,r=p.ink){e.floatingTexts.push({x:t,y:n,text:o,color:r,life:1,maxLife:1})}function Ft(e,t,n){e.shake.strength=Math.max(e.shake.strength,t),e.shake.time=Math.max(e.shake.time,n)}function _i(e,t,n){e.effects.push({type:"spawn",priority:xe.ambient,x:t,y:n,life:.42,maxLife:.42,size:12})}function Gi(e,t,n,o=p.green){e.effects.push({type:"scannerPulse",priority:xe.important,x:t,y:n,color:o,life:.42,maxLife:.42,size:24})}function Ui(e,t,n){for(let o=0;o<12;o+=1)e.effects.push({type:"meat",priority:xe.important,x:t+W(-18,18),y:n+W(-12,16),vx:W(-60,60),vy:W(-90,-25),life:W(.45,.85),maxLife:.85,size:W(4,8)})}function Wi(e,t,n){for(let o=0;o<16;o+=1)e.effects.push({type:"sludge",priority:xe.important,x:t+W(-18,18),y:n+W(-12,16),vx:W(-46,46),vy:W(-70,-20),life:W(.45,.9),maxLife:.9,size:W(4,8)})}function Ki(e,t,n,o){let r=o==="poop"?p.poop:o==="male"?p.male:p.female;for(let i=0;i<22;i+=1)e.effects.push({type:"shred",priority:xe.important,x:t+W(-16,16),y:n+W(-8,8),vx:W(-70,70),vy:W(40,160),color:i%3===0?p.white:r,life:W(.45,.95),maxLife:.95,w:W(3,7),h:W(10,24),rot:W(-Math.PI,Math.PI)});Xe(e,t,n,p.green,34,xe.important)}function Hi(e,t,n,o){let r=o==="poop"?p.poop:o==="male"?p.danger:p.green;for(let i=0;i<8;i+=1)e.effects.push({type:"load",priority:xe.important,x:t+W(-18,18),y:n+W(-18,18),vx:W(-42,42),vy:W(-90,-25),color:r,life:W(.35,.65),maxLife:.65,size:8})}function Xe(e,t,n,o=p.danger,r=52,i=xe.critical){e.effects.push({type:"shockwave",priority:i,x:t,y:n,color:o,life:.55,maxLife:.55,size:8,maxSize:r})}function Ze(e,t,n,o=12,r=p.danger,i=xe.critical){for(let l=0;l0&&(e.shake.time=Math.max(0,e.shake.time-t),e.shake.time<=0&&(e.shake.strength=0));for(let r of e.effects)if(r.life-=t,["meat","sludge","spark","smoke","shred","load","rage"].includes(r.type))r.x+=(r.vx||0)*t,r.y+=(r.vy||0)*t,r.vy=(r.vy||0)+150*t;else if(r.type==="flyingChick"){r.x+=r.vx*t,r.y+=r.vy*t,r.vy+=360*t,r.noDamage||na(e,r,o);let i=r.x+e.view.x,l=r.y+e.view.y;(i<-100||l<-100||i>n.width+100||l>n.height+100)&&(r.life=0)}e.effects=e.effects.filter(r=>r.life>0);for(let r of e.floatingTexts)r.life-=t,r.y-=34*t;e.floatingTexts=e.floatingTexts.filter(r=>r.life>0)}function na(e,t,n){t.hit||(t.hit=new Set);for(let o of n()){if(t.hit.has(o.id)||t.xo.x+o.w||t.yo.y+o.h)continue;t.hit.add(o.id);let r=Di(e,o.price);H(e,t.x,t.y-10,`-${g(r)}`,p.danger),Xe(e,t.x,t.y,p.danger,30),Ze(e,t.x,t.y,5,p.danger),Ft(e,5,.18)}}var Ue=Y.maintenance;function Ho(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function Gn(e){let t=Math.min(1.4,1+.04*Math.min(10,Ho(e,"crowdedFarming"))),n=Math.pow(.95,Ho(e,"preventiveMaintenance"));return t*n}function oa(e){return Math.pow(1.03,Ho(e,"durabilityCoating"))}function Un(e,t,n=1){let o=Ue.durability[t]||1e3;return Math.max(1,Math.ceil(o*Math.max(.1,n||1)*oa(e)))}function Vi(e){return Math.max(.1,Number(e?.durabilityBaseMultiplier)||1)}function ra(e,t=0){if(!e)return{x:f.x+f.cell*(.5+t*.55),y:f.y+f.rows*f.cell+84};let n=f.x+e.col*f.cell+f.cell,o=f.y+e.row*f.cell+f.cell;return{x:n,y:o}}function ia(e,t=0){let n=(e.maintenanceRooms||[])[t];return ra(n,t)}function Se(e){e.repairman||(e.repairman={active:!1,x:f.x+f.cell*.5,y:f.y+f.rows*f.cell+84,target:null,repairedToday:0}),Array.isArray(e.maintenanceRooms)||(e.maintenanceRooms=[]),Array.isArray(e.repairmen)||(e.repairmen=[]);for(let[t,n]of e.conveyorMeta||[]){n.uses==null&&(n.uses=0),n.maintenanceType==null&&(n.maintenanceType="conveyor"),n.kind||(n.kind="conveyor"),n.speedMultiplier||(n.speedMultiplier=n.kind==="boostConveyor"?2:1),n.branchMode||(n.branchMode="random");let o=Un(e,"conveyor",Vi(n));(n.durability==null||n.durability0&&(n.processingCooldown=Math.max(0,n.processingCooldown-t))}function vn(e){Se(e);let t=[];for(let[n,o]of e.conveyorMeta||[])t.push({type:"conveyor",key:n,meta:o,label:`${o.kind==="boostConveyor"?"Boost Belt":"Belt"} ${n}`,center:F(Z(n).col,Z(n).row)});for(let n of e.eggFarms||[])t.push({type:"eggFarm",ref:n,label:`EGG #${n.id}`,center:F(n.col,n.row)});for(let n of(e.scanners||[]).filter(o=>o.kind==="auto"))t.push({type:"autoScanner",ref:n,label:`AUTO #${n.id}`,center:F(n.col,n.row)});for(let n of Object.values(e.facilities||{})){let o=qn(n);["mixer","trash"].includes(o)&&t.push({type:o,ref:n,label:`${n.shortName||n.name||o} #${n.id}`,center:{x:n.x+n.w/2,y:n.y+n.h/2}})}return t}function Bt(e){return e.meta?zt(e):zt(e.ref)}function mn(e){return e.meta?qo(e):qo(e.ref)}function _n(e){return e.meta?Yo(e):Yo(e.ref)}function ji(e,t){sa(e.meta?e:e.ref,Math.max(0,mn(e)-t))}function er(e){return e.type==="conveyor"?`conveyor:${e.key}`:`${e.type}:${e.ref?.id||e.ref?.type||e.type}`}function Zi(e,t=.02){Se(e);let n=Math.max(0,Number(t)||0),o=0;for(let r of vn(e)){let i=mn(r);ji(r,_n(r)*n),o+=Math.max(0,i-mn(r))/_n(r)*100}return o}function es(e){Se(e);let t=e.maintenanceRooms||[];e.repairmen=t.map((o,r)=>{let i=ia(e,r);return{id:`room-${o.id}`,roomId:o.id,active:!0,x:i.x,y:i.y,target:null,repairedToday:0}});let n=e.repairmen[0];e.repairman.active=!!n,e.repairman.target=n?.target||null,e.repairman.repairedToday=0,n&&(e.repairman.x=n.x,e.repairman.y=n.y)}function ts(e){Se(e);for(let t of e.repairmen||[])t.active=!1,t.target=null;e.repairmen=[],e.repairman.active=!1,e.repairman.target=null}function aa(e,t){return t&&vn(e).find(o=>er(o)===t.key)||null}function ca(e){let t=null;for(let n of vn(e)){let o=Bt(n);o<=.001||(!t||o>Bt(t))&&(t=n)}return t}function ns(e,t){Se(e);let n=e.repairmen?.length?e.repairmen:e.repairman?.active?[e.repairman]:[];if(!n.length||e.phase!=="running")return;let o=new Set(n.map(i=>i.target?.key).filter(Boolean));for(let i of n)ua(e,i,t,o);let r=n[0];r&&e.repairman!==r&&(e.repairman.active=!0,e.repairman.x=r.x,e.repairman.y=r.y,e.repairman.target=r.target,e.repairman.repairedToday=r.repairedToday||0)}function ua(e,t,n,o){if(!t.active)return;let r=aa(e,t.target);if((!r||Bt(r)<=.001)&&(t.target?.key&&o.delete(t.target.key),r=da(e,o)),!r){t.target=null;return}let i=er(r);o.add(i),t.target={key:i,label:r.label};let l=Ue.repairman.walkSpeed,c=r.center.x-t.x,v=r.center.y-t.y,x=Math.hypot(c,v);if(x>8){let X=Math.min(x,l*n);t.x+=c/x*X,t.y+=v/x*X;return}let E=e?.cardEffects?.laborExploitation?.7:1,R=n/(Ue.repairman.secondsPerOnePercent*E*100),B=mn(r),O=R*_n(r);ji(r,O);let ee=Math.max(0,(B-mn(r))/_n(r)*100);t.repairedToday=(t.repairedToday||0)+ee,ee>0&&Math.random()<.02&&H(e,t.x,t.y-28,"REPAIR",p.green),Bt(r)<=.001&&(o.delete(i),t.target=null)}function da(e,t=new Set){let n=null;for(let o of vn(e)){if(t.has(er(o)))continue;let r=Bt(o);r<=.001||(!n||r>Bt(n))&&(n=o)}return n||ca(e)}function fa(e){let t=0,n="none";for(let o of vn(e)){let r=Bt(o);r>t&&(t=r,n=o.label)}return{ratio:t,percent:Math.round(t*100),label:n}}function tr(e){let t=fa(e),n=zo(e);return{worst:t,avgBeltPerformance:n,repairman:e.repairman||null,repairmen:e.repairmen||[],rooms:e.maintenanceRooms||[]}}var pa=$e.commonWeight,ya=$e.rareWeight,ha=$e.ultraRareWeight||.45,Lt=$e.baseDraftSize,Qt=Ir;function Xt(e,t){let n=Le(e);return Math.max(0,Number(n[t])||0)}function Le(e){e.cardEffects||(e.cardEffects={...bo});for(let[t,n]of Object.entries(bo))e.cardEffects[t]==null&&(e.cardEffects[t]=Array.isArray(n)?[]:n);return e.cardEffects.flattery!=null&&(e.cardEffects.fairiesFlatteryNext=Math.max(0,e.cardEffects.fairiesFlatteryNext||0)+Math.max(0,e.cardEffects.flattery||0),delete e.cardEffects.flattery),e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft||(e.cardDraft={pending:!1,choices:[],rerolls:0,picksRemaining:0}),e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardEffects}function us(e){let t=Math.max(.5,1-.05*Math.min(10,Xt(e,"crowdedFarming"))),n=Math.pow(.96,Xt(e,"hatchingFeed"));return t*n}function ds(e,t=null){return Math.min(3,Math.max(0,Number(t?.extraEggOutlet)||0))}function fs(e){return Math.pow(.85,Xt(e,"scannerQueueSpacing"))}function Vn(e,t=null){let n=Le(e),o=Mn*Math.pow(gn,Math.max(0,n.bearing||0)),r=t?Math.max(.1,Number(e?.conveyorMeta?.get?.(t)?.speedMultiplier)||1):1,i=t?1:zo(e),l=Math.max(.01,Number(e?.eventActive?.conveyorSpeedMultiplier)||1);return Math.min(Wt,o*i)*r*l}function nt(e,t=null){let n=Math.max(0,(e?.level||1)-1),o=t?Xt(t,"autoScannerTuning"):0,r=xn*Math.pow(Pr,n)*Math.pow(po,o),i=Math.max(yo,r),l=t?Math.max(.01,Number(t?.eventActive?.autoScannerCooldownMultiplier)||1):1;return t?Math.max(yo,i*Kn(e)*l):i}function os(e){let t=e.cardDraft||{rerolls:0},n=Math.max(1,(t.rerolls||0)+1);return Math.ceil(Math.max(1,e.turn||1)/$e.rerollCost.dayDivisor*n*$e.rerollCost.multiplier)}function Jt(e){return Qt.find(t=>t.id===e)||null}function ps(e,t){let n=typeof t=="string"?Jt(t):t;return Le(e),!n||!(n.type==="equipmentUpgrade"||n.type==="cellAction")?[]:We(e,n).map(o=>({key:tt(o),label:rr(e,o),type:o.type}))}function or(e,t,n={}){let o=typeof t=="string"?Jt(t):t;if(Le(e),!o||o.type==="dud")return{ok:!1,reason:"Card not found."};if(o.id==="extraCards")return e.cardDraft=e.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.choices.push(...Yn(e,2)),{ok:!0,reason:`${o.title} added 2 draft cards.`};if(o.type==="instant")return hs(e,o),{ok:!0,reason:`${o.title} granted.`};if(o.type==="equipmentUpgrade"){let r=We(e,o);if(!r.length)return{ok:!1,reason:`No valid target for ${o.title}.`};let i=n.targetKey&&n.targetKey!=="__auto__"?String(n.targetKey):"",l=i?r.find(c=>tt(c)===i):r[0];return l?(ys(e,l),{ok:!0,reason:`${o.title} applied to ${rr(e,l)}.`}):{ok:!1,reason:`Selected target is no longer valid for ${o.title}.`}}if(o.type==="cellAction"&&o.target==="blockedCell"){let r=We(e,o);if(!r.length)return{ok:!1,reason:"No blocked cells to remove."};let i=new Set((Array.isArray(n.targetKeys)?n.targetKeys:[n.targetKey]).filter(c=>c&&c!=="__auto__").map(String)),l=i.size?r.filter(c=>i.has(tt(c))):r.slice(0,3);if(!l.length)return{ok:!1,reason:`Selected target is no longer valid for ${o.title}.`};for(let c of l.slice(0,3)){e.blockedCells.delete(I(c.col,c.row));let v=F(c.col,c.row);et(e,v.x,v.y),Xe(e,v.x,v.y,p.danger,42),Ze(e,v.x,v.y,8,p.warn)}return be(e),{ok:!0,reason:`${o.title} removed ${Math.min(3,l.length)} blocked cell(s).`}}return{ok:!1,reason:`${o.title} cannot be debug-granted.`}}function rr(e,t){if(t.type==="blockedCell")return`Blocked cell ${t.col},${t.row}`;if(t.type==="eggFarm")return`EGG #${t.id} L${t.level} -> L${t.level+1}`;if(t.type==="eggOutlet"){let n=Math.max(0,Number(t.farm?.extraEggOutlet)||0);return`EGG #${t.id} OUTLET ${1+n} -> ${2+n}`}if(t.type==="scanner")return`AUTO #${t.id} L${t.level} -> L${t.level+1} | CD ${nt(t,e).toFixed(1)}s -> ${nt({...t,level:t.level+1},e).toFixed(1)}s`;if(t.type==="facility"&&(t.baseId||t.id)==="mixer"){let n=t.level,o=ze(e);t.level=n+1;let r=ze(e);return t.level=n,`MIXER L${t.level} -> L${t.level+1} | ${g(o)} -> ${g(r)}`}if(t.type==="facility"&&(t.baseId||t.id)==="truck"){let n=t.level,o=Fe(e);t.level=n+1;let r=Fe(e);return t.level=n,`TRUCK L${t.level} -> L${t.level+1} | ${g(o)} -> ${g(r)}`}if(t.type==="facility"&&t.id==="trash"){let n=$t(e),o=Math.min(Vt(),n+1),r=yt(n),i=yt(o);return`SHREDDER L${t.level||1} -> L${(t.level||1)+1} | poop income ${g(r)} -> ${g(i)} per item`}return`${t.name||t.id} L${t.level||1} -> L${(t.level||1)+1}`}function ma(e){return[...e.blockedCells||[]].map(t=>{let[n,o]=String(t).split(",").map(Number);return{type:"blockedCell",id:t,col:n,row:o}}).filter(t=>Number.isFinite(t.col)&&Number.isFinite(t.row))}function We(e,t){let n=typeof t=="string"?Jt(t):t;return Le(e),n?n.target==="blockedCell"?ma(e):n.target==="eggFarm"?e.eggFarms.filter(o=>(o.level||1)<4):n.target==="eggOutlet"?e.eggFarms.filter(o=>Math.max(0,Number(o.extraEggOutlet)||0)<3).map(o=>({type:"eggOutlet",id:o.id,col:o.col,row:o.row,farm:o})):n.target==="autoScanner"?e.scanners.filter(o=>o.kind==="auto"):n.target==="mixer"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="mixer"):n.target==="truck"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="truck"):n.target==="trash"?Go(e)(o.baseId||o.id)==="trash"):[]:[]:[]}function ba(e,t){let n=Le(e);if(t.id==="crowdedFarming")return(n.crowdedFarming||0)>=10;if(t.id==="recyclingSubsidy")return(n.recyclingSubsidy||0)>=3;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,$e.dudChancePerCard||0)),r=Math.max(1e-4,Math.min(1,$e.dudChanceReductionPerFilter||.05));return(n.dudFilter||0)>=Math.ceil(o/r)}return t.id==="laborExploitation"?!!n.laborExploitation:t.id==="usedMachine"?!!n.usedMachineActive:t.id==="newMachine"?!n.usedMachineActive:!1}function va(e){return!!((e.maintenanceRooms||[]).length||(e.repairmen||[]).length||e.repairman?.active)}function wa(e){return Qt.filter(t=>!(t.id==="laborExploitation"&&!va(e)||ba(e,t)||(t.type==="equipmentUpgrade"||t.type==="cellAction")&&We(e,t).length<=0))}function rs(e,t){return t.rarity==="ultraRare"?ha:t.rarity==="rare"?ya:pa}function Sa(e,t){let n=t.reduce((r,i)=>r+rs(e,i),0);if(n<=0)return t[Math.floor(Math.random()*t.length)];let o=Math.random()*n;for(let r of t)if(o-=rs(e,r),o<=0)return r;return t[t.length-1]}var is=0;function ka(){return is+=1,{id:`dud:${Date.now()}:${is}`,title:"Dud",rarity:"dud",type:"dud",description:"Click to flick this dud away. It does not consume a pick."}}function Ca(e){let t=Le(e),n=Math.max(0,Math.min(1,$e.dudChancePerCard||0)),o=Math.max(0,Math.min(1,$e.dudChanceReductionPerFilter||0));return Math.max(0,n-o*Math.max(0,t.dudFilter||0))}function xa(e,t){let n=[...t],o=0,r=Math.max(0,$e.maxDudsPerDraft||0),i=Ca(e);for(let l=0;lc.id===i.id);l>=0&&r.splice(l,1)}return xa(e,o)}function tt(e){return e?e.type==="blockedCell"?`blockedCell:${e.id}`:e.type==="eggFarm"?`eggFarm:${e.id}`:e.type==="eggOutlet"?`eggOutlet:${e.id}`:e.type==="scanner"?`scanner:${e.id}`:e.type==="facility"?`facility:${e.id}`:`${e.type}:${e.id}`:""}function ss(e){if(!e)return null;if(e.type==="blockedCell"){let t=F(e.col,e.row);return{x:t.x-f.cell*.48,y:t.y-f.cell*.48,w:f.cell*.96,h:f.cell*.96,cx:t.x,cy:t.y}}if(e.type==="eggFarm"||e.type==="eggOutlet"){let t=F(e.col,e.row);return{x:t.x-34,y:t.y-34,w:68,h:68,cx:t.x,cy:t.y}}if(e.type==="scanner"){let t=ye(e);return{x:t.x-54,y:t.y-77,w:108,h:154,cx:t.x,cy:t.y}}return e.type==="facility"?{x:e.x,y:e.y,w:e.w,h:e.h,cx:e.x+e.w/2,cy:e.y+e.h/2}:null}function ir(e){if(!e.cardTargetPick?.pending)return[];if(e.cardTargetPick.mode==="autoScannerMenu"){let n=new Set(e.cardTargetPick.targetKeys||[]);return e.scanners.filter(o=>o.kind==="auto"&&n.has(tt(o))).map(o=>({key:tt(o),label:"AUTO ROUTE SETTINGS",target:o,bounds:ss(o)})).filter(o=>o.bounds)}let t=new Set(e.cardTargetPick.targetKeys||[]);return We(e,e.cardTargetPick.cardId).filter(n=>t.has(tt(n))).map(n=>({key:tt(n),label:rr(e,n),target:n,bounds:ss(n)})).filter(n=>n.bounds)}function Ma(e,t){let n=ir(e);for(let o of n){let r=o.bounds;if(t.x>=r.x&&t.x<=r.x+r.w&&t.y>=r.y&&t.y<=r.y+r.h)return o.target}return null}function ys(e,t){if(t.type==="eggOutlet"){let n=t.farm||e.eggFarms.find(r=>r.id===t.id);if(!n)return;n.extraEggOutlet=Math.min(3,Math.max(0,Number(n.extraEggOutlet)||0)+1);let o=F(n.col,n.row);H(e,o.x,o.y-30,`OUTLET ${1+n.extraEggOutlet}`,p.green),be(e);return}if(t.level=(t.level||1)+1,t.type==="eggFarm"){t.nextSpawn=Rt(t),t.lastInterval=t.nextSpawn;let n=F(t.col,t.row);H(e,n.x,n.y-30,`LV ${t.level}`,p.green);return}if(t.type==="scanner"){let n=ye(t);H(e,n.x,n.y-34,`LV ${t.level}`,p.green);return}t.type==="facility"&&H(e,t.x+t.w/2,t.y+18,`LV ${t.level}`,p.green)}function hs(e,t){let n=Le(e),o=r=>{n[r]=Math.max(0,n[r]||0)+1};if(t.id==="bearing"&&o("bearing"),t.id==="autoScannerTuning"&&o("autoScannerTuning"),t.id==="legalWork"&&o("legalWork"),t.id==="crowdedFarming"&&(n.crowdedFarming=Math.min(10,(n.crowdedFarming||0)+1)),t.id==="hatchingFeed"&&o("hatchingFeed"),t.id==="poopRateBooster"&&o("poopRateBooster"),t.id==="safetyCover"&&o("safetyCover"),t.id==="recyclingSubsidy"&&(n.recyclingSubsidy=Math.min(3,(n.recyclingSubsidy||0)+1)),t.id==="chemicalWeaponSubsidy"&&o("chemicalWeaponSubsidy"),t.id==="preventiveMaintenance"&&o("preventiveMaintenance"),t.id==="dudFilter"&&o("dudFilter"),t.id==="durabilityCoating"&&(o("durabilityCoating"),Se(e)),t.id==="sparePartsBin"){o("sparePartsBin");let r=Zi(e,.02);e.stats.sparePartsRepair=(e.stats.sparePartsRepair||0)+r,e.totals.sparePartsRepair=(e.totals.sparePartsRepair||0)+r,H(e,f.x+f.cols*f.cell/2,f.y-30,"REPAIR +2%",p.green)}t.id==="dudRefund"&&o("dudRefund"),t.id==="freeReroll"&&o("freeReroll"),t.id==="composter"&&o("composter"),t.id==="scannerQueueSpacing"&&o("scannerQueueSpacing"),t.id==="flattery"&&o("fairiesFlatteryNext"),t.id==="usedMachine"&&(n.usedMachineActive=!0),t.id==="newMachine"&&(n.usedMachineActive=!1),t.id==="laborExploitation"&&(n.laborExploitation=1),t.id==="rescueLoan"&&(o("rescueLoanCharges"),H(e,f.x+f.cols*f.cell/2,f.y-30,"RESCUE HELD",p.green))}function He(e){return`${Math.round(Number(e||0)*100)}%`}function ls(e){let t=st[Math.max(0,Math.min(st.length-1,e-1))]||st[0]||[0,0];return`${t[0].toFixed(2)}-${t[1].toFixed(2)}s`}function as(e,t){return Math.ceil(e*Math.pow(Ce.incomeUpgradeRate,Math.max(0,t-1)))}function cs(e,t,n){let r=We(e,t==="mixer"?"upgradeMixer":"upgradeTruck")[0];if(!r)return{before:as(n,1),after:as(n,2)};let i=t==="mixer"?ze(e):Fe(e),l=r.level||1;r.level=l+1;let c=t==="mixer"?ze(e):Fe(e);return r.level=l,{before:i,after:c}}function ga(e,t){let n=Le(e);if(t.id==="upgradeEgg"){let o=We(e,t),r=Math.min(3,Math.max(1,o[0]?.level||1));return`Choose one EGG. Level +1. Production interval ${ls(r)} -> ${ls(r+1)}.`}if(t.id==="upgradeAutoScanner"){let o=We(e,t)[0]||{level:1},r=nt(o,e),i=nt({...o,level:(o.level||1)+1},e);return`Choose one AUTO SCANNER. Level +1. Cooldown ${r.toFixed(2)}s -> ${i.toFixed(2)}s.`}if(t.id==="upgradeMixer"){let o=cs(e,"mixer",Ce.income.mixer);return`Choose one MIXER. Earning +10%. Male-chick income ${g(o.before)} -> ${g(o.after)}.`}if(t.id==="upgradeTruck"){let o=cs(e,"truck",Ce.income.truck);return`Choose one TRUCK. Earning +10%. Correct shipment income ${g(o.before)} -> ${g(o.after)}.`}if(t.id==="upgradeTrash"){let o=$t(e),r=Math.min(Vt(),o+1),i=yt(o),l=yt(r);return`SHREDDER level +1. Poop income ${g(i)} -> ${g(l)} per item.`}if(t.id==="bearing"){let o=Math.min(Wt,Mn*Math.pow(gn,Math.max(0,n.bearing||0))),r=Math.min(Wt,Mn*Math.pow(gn,Math.max(0,(n.bearing||0)+1)));return`Conveyor speed +7.5%. After pick: ${o.toFixed(1)} -> ${r.toFixed(1)} px/s.`}if(t.id==="legalWork"){let o=Math.max(0,n.legalWork||0);return`Fairies tribute profit exemption +${g(250)}. After pick: exemption bonus ${g(250*(o+1))}.`}if(t.id==="crowdedFarming"){let o=Math.min(10,(n.crowdedFarming||0)+1);return`Held ${n.crowdedFarming||0}/10. After pick: EGG interval ${He(Math.max(.5,1-.05*o))}, deterioration ${He(Math.min(1.4,1+.04*o))}.`}if(t.id==="extraEggOutlet"){let o=We(e,t),r=Math.max(0,Number(o[0]?.farm?.extraEggOutlet)||0);return`Choose one EGG. Output ports ${1+r} -> ${2+r}. Max 4 ports per EGG.`}if(t.id==="hatchingFeed")return`Held ${n.hatchingFeed||0}. After pick: EGG interval ${He(Math.pow(.96,(n.hatchingFeed||0)+1))}, poop rate multiplier ${He(Math.pow(1.03,(n.hatchingFeed||0)+1))}.`;if(t.id==="poopRateBooster")return`Held ${n.poopRateBooster||0}. After pick: base poop rate +${Math.round((n.poopRateBooster||0)+1)*4} percentage points.`;if(t.id==="autoScannerTuning")return`Held ${n.autoScannerTuning||0}. After pick: all AUTO SCANNER default cooldown ${He(Math.pow(po,(n.autoScannerTuning||0)+1))}.`;if(t.id==="safetyCover")return`Held ${n.safetyCover||0}. After pick: explosion damage ${He(Math.pow(.95,(n.safetyCover||0)+1))}.`;if(t.id==="recyclingSubsidy")return`Held ${n.recyclingSubsidy||0}/3. After pick: normal SELL refund ${Math.round(Math.min(.8,.5+.1*((n.recyclingSubsidy||0)+1))*100)}%.`;if(t.id==="chemicalWeaponSubsidy")return`Held ${n.chemicalWeaponSubsidy||0}. After pick: ${g(1200*((n.chemicalWeaponSubsidy||0)+1))} per 70 truck-shipped poop each day.`;if(t.id==="preventiveMaintenance")return`Held ${n.preventiveMaintenance||0}. After pick: deterioration speed ${He(Math.pow(.95,(n.preventiveMaintenance||0)+1))}.`;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,$e.dudChancePerCard||0)),r=Math.max(0,Math.min(1,$e.dudChanceReductionPerFilter||.05)),i=Math.max(0,n.dudFilter||0),l=Math.max(0,o-r*i),c=Math.max(0,o-r*(i+1));return`Held ${i}. DUD chance per card ${He(l)} -> ${He(c)}.`}return t.id==="durabilityCoating"?`Held ${n.durabilityCoating||0}. After pick: maximum durability ${He(Math.pow(1.03,(n.durabilityCoating||0)+1))}.`:t.id==="sparePartsBin"?`Held ${n.sparePartsBin||0}. Immediately restores 2% durability to every maintained machine. Common card weight.`:t.id==="dudRefund"?`Held ${n.dudRefund||0}. After pick: DUD clicks award ${g(50*((n.dudRefund||0)+1))}.`:t.id==="freeReroll"?`Held ${n.freeReroll||0}. After pick: each card screen starts with ${(n.freeReroll||0)+1} free reroll${(n.freeReroll||0)+1===1?"":"s"}.`:t.id==="composter"?`Held ${n.composter||0}. After pick: SHREDDER poop grants ${g(3*((n.composter||0)+1))}.`:t.id==="scannerQueueSpacing"?`Held ${n.scannerQueueSpacing||0}. After pick: Manual/Auto Scanner queue spacing ${He(Math.pow(.85,(n.scannerQueueSpacing||0)+1))}.`:t.id==="flattery"?`Next Fairies tribute -50%. Held for next tribute: ${n.fairiesFlatteryNext||0}.`:t.id==="usedMachine"?"Enable Used Machines: future equipment costs 50%, has no SELL refund, and starts with 60% durability.":t.id==="newMachine"?"Cancel Used Machines. Future equipment returns to normal price, refund, and durability.":t.id==="laborExploitation"?"Repairman dispatch paperwork is streamlined. Repair rooms keep operating; one time only.":t.id==="rescueLoan"?`At day-end bankruptcy check, gain ${g(500)} if cash is below ${g(0)}. Held: ${n.rescueLoanCharges||0}.`:t.description}function nr(e,t){let n=e.cardDraft?.choices||[],o=n.findIndex(r=>r.id===t.id);o>=0&&n.splice(o,1)}function ms({game:e,ui:t,onUpdatePanels:n}){function o(){n&&n()}function r(){Le(e),e.cardTargetPick=null,e.cardDraft={pending:!0,choices:Yn(e,Lt),rerolls:0,freeRerolls:Xt(e,"freeReroll"),picksRemaining:1}}function i(){Le(e),e.cardDraft.pending=!1,e.cardDraft.choices=[],e.cardDraft.picksRemaining=0,e.cardTargetPick=null,t.modal.classList.remove("visible","equipment-popover"),o()}function l(A=Lt){Le(e),e.cardDraft.choices=Yn(e,A)}function c(){Le(e),!e.cardDraft.choices.length&&e.cardDraft.picksRemaining>0&&l(Lt)}function v(A){nr(e,A),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1),e.cardTargetPick=null,c(),e.cardDraft.picksRemaining<=0?i():se()}function x(A){nr(e,A),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1)+$e.extraCardsAddedPicks,e.cardDraft.choices.push(...Yn(e,2)),se()}function E(A,G){let q=Xt(e,"dudRefund")*50;if(q>0){let me=Ge(e,q);e.stats.dudRefundIncome=(e.stats.dudRefundIncome||0)+me,e.totals.dudRefundIncome=(e.totals.dudRefundIncome||0)+me,H(e,f.x+f.cols*f.cell/2,f.y-30,`DUD REFUND +${g(me)}`,p.green)}Ft(e,34,.62),document.body?.animate&&document.body.animate([{transform:"translate(0, 0)"},{transform:"translate(-10px, 7px)"},{transform:"translate(12px, -8px)"},{transform:"translate(-8px, -5px)"},{transform:"translate(9px, 6px)"},{transform:"translate(0, 0)"}],{duration:260,easing:"steps(5, end)"}),G&&(G.style.setProperty("--fling-x",`${260+Math.random()*260}px`),G.style.setProperty("--fling-y",`${-260-Math.random()*170}px`),G.style.setProperty("--fling-r",`${(Math.random()<.5?-1:1)*(52+Math.random()*38)}deg`),G.classList.add("flung")),window.setTimeout(()=>{nr(e,A),c(),se()},340)}function R(A,G=null){if(A.type==="dud")return E(A,G);if(A.id==="extraCards")return x(A);if(A.type==="equipmentUpgrade"||A.type==="cellAction")return B(A);hs(e,A),v(A)}function B(A){let G=We(e,A);G.length&&(e.cardTargetPick={pending:!0,cardId:A.id,mode:A.target==="blockedCell"?"blockedCell":"equipment",targetKeys:G.map(tt),remaining:A.id==="dynamite"?Math.min(3,G.length):1},t.modal.classList.remove("visible","equipment-popover"),o())}function O(A){if(!A||A.type!=="blockedCell")return!1;let G=I(A.col,A.row);if(!e.blockedCells?.has(G))return!1;e.blockedCells.delete(G);let q=F(A.col,A.row);return et(e,q.x,q.y),Xe(e,q.x,q.y,p.danger,62),Ze(e,q.x,q.y,18,p.warn),Nn(e,q.x,q.y,8),Ft(e,16,.35),H(e,q.x,q.y-18,"BOOM",p.danger),be(e),e.cardTargetPick.remaining=Math.max(0,(e.cardTargetPick.remaining||1)-1),e.cardTargetPick.targetKeys=We(e,"dynamite").map(tt),o(),!0}function ee(A){if(!e.cardTargetPick?.pending)return!1;let G=Jt(e.cardTargetPick.cardId),q=Ma(e,A);return!G||!q?(X(),!0):G.id==="dynamite"?(O(q)&&((e.cardTargetPick.remaining||0)<=0||!We(e,"dynamite").length)&&v(G),!0):(ys(e,q),v(G),!0)}function X(){e.cardTargetPick?.pending&&(e.cardTargetPick=null,se())}function ae(){let A=Math.max(0,e.cardDraft?.freeRerolls||0);if(A>0){e.cardDraft.freeRerolls=A-1,e.cardDraft.rerolls+=1,l(Lt),se();return}let G=os(e);e.cash${G.alt||`:``}function le(A,G){let q=document.createElement("button");q.type="button";let me=A.type==="dud"?"dud":A.rarity==="ultraRare"?"ultra-rare":A.rarity==="rare"?"rare":"common";q.className=`card-choice ${me}`;let D=A.type==="dud"?"MISS":A.rarity==="ultraRare"?"ULTRA RARE":A.rarity==="rare"?"RARE":"COMMON",U=[D,...(A.tags||[]).filter(S=>S!==D)].slice(0,5);return q.innerHTML=`${ie(A)}
${A.title}
${U.map(S=>`${S}`).join("")}
${ga(e,A)}
`,q.addEventListener("click",()=>R(A,q)),q.dataset.index=String(G),q}function se(){Le(e),e.cardTargetPick=null,e.cardDraft?.pending||r(),e.cardDraft.choices?.length||l(Lt);let A=e.cardDraft.choices||[],G=os(e),q=Math.max(0,e.cardDraft?.freeRerolls||0),me=Math.max(1,e.cardDraft.picksRemaining||1);t.modalTitle.textContent="Choose Upgrade Card",t.modalBody.innerHTML=`

Choose ${me} card${me===1?"":"s"} before Build phase. Dud cards can be flicked away without consuming a pick. Equipment cards target machines; Dynamite targets blocked cells.

`;let D=t.modalBody.querySelector("#cardChoices");A.forEach((M,N)=>D.appendChild(le(M,N))),t.modalActions.innerHTML="";let U=document.createElement("button");U.type="button",U.className="facility-action warn reroll-button",U.textContent=q>0?`Reroll (FREE x${q})`:`Reroll ${g(G)}`,U.disabled=q<=0&&e.cash0?`${q} free reroll${q===1?"":"s"} remaining.`:U.disabled?"Not enough cash":"",U.addEventListener("click",ae),t.modalActions.appendChild(U);let S=document.createElement("button");S.type="button",S.className="facility-action",S.textContent="No Card",S.title="Skip this upgrade pick and enter Build phase.",S.addEventListener("click",i),t.modalActions.appendChild(S),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible")}return{prepareDraft:r,showDraft:se,finishDraft:i,chooseTargetAtPoint:ee,cancelTargetPick:X}}var Ta=!0,Ea={chickMale:"./assets/images/chick_male.png",chickFemale:"./assets/images/chick_female.png",poop:"./assets/images/poop.png",conveyorStraightH:"./assets/dark_factory/facilities/conveyor/conveyor_straight_h_16.png",conveyorStraightV:"./assets/dark_factory/facilities/conveyor/conveyor_straight_v_16.png",conveyorTurnNe:"./assets/dark_factory/facilities/conveyor/conveyor_turn_ne_16.png",conveyorTurnNw:"./assets/dark_factory/facilities/conveyor/conveyor_turn_nw_16.png",conveyorTurnSe:"./assets/dark_factory/facilities/conveyor/conveyor_turn_se_16.png",conveyorTurnSw:"./assets/dark_factory/facilities/conveyor/conveyor_turn_sw_16.png",boostConveyorStraightH:"./assets/dark_factory/facilities/conveyor/boost_conveyor_straight_h_16.png",boostConveyorStraightV:"./assets/dark_factory/facilities/conveyor/boost_conveyor_straight_v_16.png",boostConveyorTurnNe:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_ne_16.png",boostConveyorTurnNw:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_nw_16.png",boostConveyorTurnSe:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_se_16.png",boostConveyorTurnSw:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_sw_16.png",scannerManual:"./assets/dark_factory/facilities/machines/manual_scanner_32x48.png",scannerAuto:"./assets/dark_factory/facilities/machines/auto_scanner_32x48.png",eggFarm:"./assets/dark_factory/facilities/machines/egg_farm_16.png",mixer:"./assets/dark_factory/facilities/machines/mixer_32.png",shredder:"./assets/dark_factory/facilities/machines/shredder_32.png",truck:"./assets/dark_factory/facilities/vehicles/truck_32.png",mixerCompact:"./assets/dark_factory/facilities/machines/mixer_compact_16.png",shredderCompact:"./assets/dark_factory/facilities/machines/shredder_compact_16.png",truckCompact:"./assets/dark_factory/facilities/vehicles/truck_compact_16.png",maintenanceRoom:"./assets/dark_factory/facilities/utility/maintenance_room_32.png",repairman:"./assets/dark_factory/facilities/utility/repairman_16.png",obstacleCrate:"./assets/dark_factory/facilities/utility/obstacle_crate_16.png"},ce={};for(let[e,t]of Object.entries(Ea)){let n=new Image;n.loaded=!1,n.onerror=()=>{n.loaded=!1},Ta&&t&&(n.onload=()=>{n.loaded=!0},n.src=t),ce[e]=n}function Ss(e,t,n,o){e.imageSmoothingEnabled=!1,e.clearRect(0,0,t.width,t.height),Aa(e,t),e.save();let r=n.shake.time>0?W(-n.shake.strength,n.shake.strength):0,i=n.shake.time>0?W(-n.shake.strength,n.shake.strength):0,l=n.view?.scale||1;e.translate((n.view?.x||0)+r,(n.view?.y||0)+i),e.scale(l,l),$a(e,n),Da(e,n),Ba(e,n),qa(e,n),Za(e,n),ec(e,n),Ya(e,n),za(e,n),Pa(e,n),rc(e,n,o.activeQueuedChick),pc(e,n),cc(e,t,n),ac(e,n,o.selectedObject,o.selectedTitle),uc(e,n),dc(e,n),fc(e,n),e.restore(),hc(e,n,t)}function Ra(e){if(e.type==="eggFarm"){let n=F(e.ref.col,e.ref.row);return{x:n.x-34,y:n.y-34,w:68,h:68,cx:n.x,cy:n.y}}let t=e.ref;return{x:t.x,y:t.y,w:t.w,h:t.h,cx:t.x+t.w/2,cy:t.y+t.h/2}}function Pa(e,t){if(t.phase!=="build")return;let n=Fn(t);for(let o of n){let r=Ra(o);e.save(),e.fillStyle="rgba(196,36,36,.22)",e.strokeStyle=p.danger,e.lineWidth=5,e.setLineDash([10,6]),ne(e,r.x,r.y,r.w,r.h,!0,!0),e.setLineDash([]),e.fillStyle=p.danger,e.strokeStyle=p.white,e.lineWidth=4,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.strokeText("!",r.cx,r.y+24),e.fillText("!",r.cx,r.y+24),e.font="900 11px ui-monospace, monospace",e.strokeText("NO ROUTE",r.cx,r.y+r.h-8),e.fillText("NO ROUTE",r.cx,r.y+r.h-8),e.restore()}}function ne(e,t,n,o,r,i=!0,l=!0){e.beginPath(),e.rect(t,n,o,r),i&&e.fill(),l&&e.stroke()}function lr(e,t,n,o,r=p.ink){e.save(),e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.lineWidth=4,e.strokeStyle=p.white,e.fillStyle=r,e.strokeText(o,t,n),e.fillText(o,t,n),e.restore()}function rt(e,t,n,o,r,i){if(!t?.loaded)return!1;let l=e.imageSmoothingEnabled;return e.imageSmoothingEnabled=!1,e.drawImage(t,Math.round(n),Math.round(o),Math.round(r),Math.round(i)),e.imageSmoothingEnabled=l,!0}function bs(e,t,n,o,r,i,l=null,c=1){e.fillStyle=i,e.fillRect(Math.round(t),Math.round(n),Math.round(o),Math.round(r)),l&&(e.strokeStyle=l,e.lineWidth=c,e.strokeRect(Math.round(t)+.5,Math.round(n)+.5,Math.round(o)-1,Math.round(r)-1))}function Aa(e,t){e.fillStyle=p.bg,e.fillRect(0,0,t.width,t.height),e.save(),e.globalAlpha=.85;for(let n=0;n=n;for(let r of Tt(t)){let i=Et(r);e.save(),e.fillStyle=o?"rgba(183,245,198,.34)":"rgba(255,255,255,.22)",e.strokeStyle=o?p.green:p.muted,e.lineWidth=5,e.setLineDash([16,10]),ne(e,i.x,i.y,i.w,i.h,!0,!0),e.setLineDash([]);let l=ko(r),c=l.cx,v=l.cy;e.fillStyle="rgba(255,255,255,.94)",e.strokeStyle=p.ink,e.lineWidth=4,ne(e,l.x,l.y,l.w,l.h,!0,!0),e.fillStyle=o?p.green:p.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText(r.direction==="right"?"BUY RIGHT LOT":"BUY UPPER LOT",c,v-12),e.fillStyle=p.ink,e.font="900 16px ui-monospace, monospace",e.fillText(`${g(n)} / 10\xD710`,c,v+15),e.fillStyle=p.muted,e.font="900 11px ui-monospace, monospace",e.fillText("blocked tiles included",c,v+30),e.restore()}}function bt(e,t,n,o,r,i,l=0){let c=zt(i);c<.5||(e.save(),e.globalAlpha=Math.min(.62,.12+c*.54),e.fillStyle="#6b4a23",l>0?(e.beginPath(),e.roundRect?.(t,n,o,r,l),e.roundRect?e.fill():ne(e,t,n,o,r,!0,!1)):ne(e,t,n,o,r,!0,!1),e.globalAlpha=Math.min(.9,.25+c*.6),e.strokeStyle="#3a2a16",e.lineWidth=Math.max(2,Math.floor(2+c*5)),e.setLineDash([5,6]),ne(e,t+3,n+3,o-6,r-6,!1,!0),e.restore())}function sr(e,t){let n=e.componentLookup?.get(t);return(n?e.congestion.get(n):null)?.ratio||0}function Fa(e,t,n={}){let o=Xn(e,t).sort(),i=n.kind==="boostConveyor"?"boostConveyor":"conveyor",l=c=>o.includes(c);if(o.length===2){if(l("left")&&l("right"))return ce[`${i}StraightH`];if(l("up")&&l("down"))return ce[`${i}StraightV`];if(l("up")&&l("right"))return ce[`${i}TurnNe`];if(l("up")&&l("left"))return ce[`${i}TurnNw`];if(l("down")&&l("right"))return ce[`${i}TurnSe`];if(l("down")&&l("left"))return ce[`${i}TurnSw`]}return o.length===1?l("up")||l("down")?ce[`${i}StraightV`]:ce[`${i}StraightH`]:l("up")||l("down")?ce[`${i}StraightV`]:ce[`${i}StraightH`]}function Ba(e,t){let n=[],o=new Set;for(let i of t.conveyorTiles){let{col:l,row:c}=Z(i);for(let v of de){let x={col:l+v.dc,row:c+v.dr},E=I(x.col,x.row);if(!t.conveyorTiles.has(E))continue;let R=[i,E].sort().join("|");if(o.has(R))continue;o.add(R);let B=Math.max(sr(t,i),sr(t,E));n.push({a:F(l,c),b:F(x.col,x.row),ratio:B})}}e.save(),e.lineCap="round",e.lineJoin="round";for(let i of[{width:31,color:"#0b0c0f",alpha:1},{width:23,color:"#444b56",alpha:1},{width:15,color:"#171a1f",alpha:1}]){e.globalAlpha=i.alpha,e.strokeStyle=i.color,e.lineWidth=i.width;for(let l of n)e.beginPath(),e.moveTo(l.a.x,l.a.y),e.lineTo(l.b.x,l.b.y),e.stroke()}for(let i of n){let l=Math.max(0,(i.ratio-.5)/.5);e.strokeStyle=Kt(p.green,p.danger,l),e.globalAlpha=i.ratio>.5?.35+l*.55:.8,e.lineWidth=6,e.beginPath(),e.moveTo(i.a.x,i.a.y),e.lineTo(i.b.x,i.b.y),e.stroke()}let r=Wa(t);for(let i of t.conveyorTiles){let l=F(...Object.values(Z(i))),c=t.conveyorMeta.get(i)||{},v=sr(t,i),x=Fa(t,i,c),E=v>.5;if(e.fillStyle=E?"rgba(196,36,36,.28)":"rgba(0,0,0,.35)",e.strokeStyle=E?p.danger:"rgba(255,184,39,.34)",e.lineWidth=E?3:1,ne(e,l.x-20,l.y-20,40,40,!0,!0),!rt(e,x,l.x-19,l.y-19,38,38)){let B=c.kind==="boostConveyor"?"#315e92":"#454b55";e.fillStyle=v>.5?Kt(B,"#a12c2c",Math.max(0,(v-.5)/.5)):B,e.strokeStyle=p.ink,e.lineWidth=2,ne(e,l.x-18,l.y-18,36,36,!0,!0)}La(e,l,i,c,v),bt(e,l.x-18,l.y-18,36,36,{meta:c}),ot(e,t,"conveyor",i,l.x,l.y,38,38),Ka(e,l,r.get(i)||[]);let R=Xn(t,i);Ga(e,l,c,Na(t,i,R),R),v>.5&&lr(e,l.x,l.y-15,`${Math.floor(v*100)}%`,p.danger)}e.restore()}function La(e,t,n,o={},r=0){let l=[...new Set([...Array.isArray(o.outDirs)?o.outDirs:[],o.dir].filter(Boolean))][0]||"right",c=l==="up"||l==="down",v=l==="left"||l==="up",x=o.kind==="boostConveyor",E=typeof performance<"u"?performance.now()/(x?70:105):0,R=((v?-E:E)%10+10)%10;e.save(),e.beginPath(),e.rect(t.x-18,t.y-18,36,36),e.clip();let B=x?"rgba(20,126,124,.62)":"rgba(42,47,54,.72)";if(e.fillStyle=B,e.fillRect(t.x-18,t.y-18,36,36),e.strokeStyle=r>.5?"rgba(238,83,61,.90)":"rgba(184,190,198,.92)",e.lineWidth=4,c)for(let O=t.y-28+R;Oe.conveyorTiles.has(I(n.col+o.dc,n.row+o.dr))).map(o=>o.name)}function ks(e,t,n){let o=de.find(l=>l.name===n);if(!o)return!1;let r=e.conveyorMeta?.get?.(I(t.col+o.dc,t.row+o.dr));return r?[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))].includes(o.opposite):!1}function Oa(e,t,n,o=Xn(e,t),r="random"){if(o.length<3)return n;let i=Z(t),l=new Set(o.filter(x=>ks(e,i,x)));if(r&&r!=="random"&&o.includes(r)){let x=new Set(l);x.add(r),o.filter(E=>!x.has(E)).length>=2&&l.add(r)}let c=o.filter(x=>!l.has(x));if(c.length)return c;let v=n.filter(x=>!l.has(x));return v.length?v:n}function Na(e,t,n=Xn(e,t)){if(n.length<3)return[];let o=Z(t),r=new Set(n.filter(i=>ks(e,o,i)));return n.filter(i=>{let l=new Set(r);return l.add(i),n.filter(c=>!l.has(c)).length>=2})}function _a(e,t,n){let o=Z(t),r=de.filter(c=>e.conveyorTiles.has(I(o.col+c.dc,o.row+c.dr))).map(c=>c.name),i=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(c=>r.includes(c)),l=r;return i.length?i:l}function Ga(e,t,n,o,r=o){if(r.length<3||o.length<2)return;e.save();let i=o.includes(n.branchMode)?n.branchMode:"random",l=i!=="random";if(e.lineJoin="round",e.lineCap="round",e.lineWidth=2,e.fillStyle="rgba(255,255,255,.9)",e.strokeStyle=l?p.warn:p.green,ne(e,t.x-17,t.y-17,34,34,!0,!0),e.strokeStyle=p.ink,e.lineWidth=2,e.fillStyle=p.ink,i!=="random"){let c=de.find(v=>v.name===i);zn(e,t.x,t.y,c?.angle||0,9,6)}else e.beginPath(),e.moveTo(t.x-10,t.y),e.lineTo(t.x-2,t.y),e.lineTo(t.x+8,t.y-8),e.moveTo(t.x-2,t.y),e.lineTo(t.x+8,t.y+8),e.stroke(),zn(e,t.x+9,t.y-9,-Math.PI/4,4,3),zn(e,t.x+9,t.y+9,Math.PI/4,4,3);e.restore()}function Ua(e,t,n){if(!n)return[];let o=Z(t),r=de.filter(c=>e.conveyorTiles.has(I(o.col+c.dc,o.row+c.dr))).map(c=>c.name),i=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(c=>r.includes(c));return Oa(e,t,i.length?i:_a(e,t,n),r,n.branchMode||"random").map(c=>de.find(v=>v.name===c)).filter(Boolean)}function Wa(e){let t=new Map;for(let[n,o]of e.conveyorMeta||[]){let r=Ua(e,n,o);r.length&&t.set(n,r)}return t}function Ka(e,t,n){let o=n.slice(0,4);o.length&&(e.save(),e.fillStyle=p.ink,e.globalAlpha=.86,o.forEach(r=>{zn(e,t.x+r.dc*12,t.y+r.dr*12,r.angle,6,5)}),e.restore())}function zn(e,t,n,o,r=11,i=8){e.save(),e.translate(t,n),e.rotate(o),e.beginPath(),e.moveTo(r,0),e.lineTo(-r*.72,-i),e.lineTo(-r*.72,i),e.closePath(),e.fill(),e.restore()}function Ha(e,t,n,o,r){let i=ye(t),l=null;if(n==="inputA"&&(l={x:i.x,y:i.y-67}),n==="left"&&(l={x:i.x-49,y:i.y+14}),n==="right"&&(l={x:i.x+49,y:i.y+14}),!l)return;let c=n==="inputA"?{x:o.x,y:l.y}:{x:l.x,y:o.y};e.save(),e.lineCap="square",e.lineJoin="bevel",e.strokeStyle="#050609",e.lineWidth=15,e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(c.x,c.y),e.lineTo(l.x,l.y),e.stroke(),e.strokeStyle="#596473",e.lineWidth=9,e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(c.x,c.y),e.lineTo(l.x,l.y),e.stroke(),e.strokeStyle=r||"#7b8795",e.lineWidth=3,e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(c.x,c.y),e.lineTo(l.x,l.y),e.stroke(),e.fillStyle=r||"#7b8795",e.strokeStyle="#050609",e.lineWidth=3,ne(e,l.x-9,l.y-7,18,14,!0,!0),e.restore()}function qa(e,t){e.save(),e.lineWidth=2,e.font="900 12px ui-monospace, monospace",e.textAlign="center";for(let n of t.scanners){let o=Po(n),r=[{type:"inputA",p:Re(n,"inputA"),label:"IN",color:p.green},{type:"left",p:Re(n,"left"),label:Io(o.left),color:$o(o.left)},{type:"right",p:Re(n,"right"),label:Io(o.right),color:$o(o.right)}];for(let i of r){if(!i.p)continue;let l=F(i.p.col,i.p.row);Ha(e,n,i.type,l,i.color);let c=ii(t,n,i.type||(i.label==="IN"?"inputA":null))||t.conveyorTiles.has(I(i.p.col,i.p.row));e.fillStyle=c?Kt("#1a1d23",i.color,.24):"#3a1e22",e.strokeStyle=c?i.color:p.danger,ne(e,l.x-18,l.y-12,36,24,!0,!0),e.fillStyle=p.white,e.fillText(i.label,l.x,l.y+4)}}e.restore()}function Ya(e,t){for(let n of t.eggFarms)Va(e,n,t)}function Va(e,t,n){let o=F(t.col,t.row);if(e.save(),rt(e,ce.eggFarm,o.x-29,o.y-29,58,58)){bt(e,o.x-29,o.y-29,58,58,t);let l=1+Math.max(0,Number(t.extraEggOutlet)||0);e.fillStyle="rgba(255,255,255,.92)",e.strokeStyle=p.ink,e.lineWidth=2,ne(e,o.x+9,o.y+12,30,18,!0,!0),e.fillStyle=p.ink,e.font="900 10px ui-monospace, monospace",e.textAlign="center",e.fillText(`O${l}`,o.x+24,o.y+24),ot(e,n,"eggFarm",t.id,o.x,o.y,68,68),e.restore();return}e.fillStyle=p.white,e.strokeStyle=p.ink,e.lineWidth=4,ne(e,o.x-28,o.y-28,56,56,!0,!0),e.fillStyle=p.green,e.font="900 19px ui-monospace, monospace",e.textAlign="center",e.fillText("EGG",o.x,o.y-4);let r=1+Math.max(0,Number(t.extraEggOutlet)||0);e.font="900 11px ui-monospace, monospace",e.fillStyle=p.ink,e.fillText(`L${t.level} O${r}`,o.x,o.y+13),e.fillText(`${t.nextSpawn.toFixed(1)}s`,o.x,o.y+26);let i=Math.max(0,Math.min(1,t.shutterProgress||0));if(i>0){let l=56*i;e.fillStyle=p.ink,ne(e,o.x-28,o.y-28,56,l,!0,!1),e.strokeStyle=p.white,e.lineWidth=2;for(let c=o.y-24;c=1&&(e.fillStyle=p.white,e.font="900 12px ui-monospace, monospace",e.fillText("SHUT",o.x,o.y+4))}bt(e,o.x-28,o.y-28,56,56,t),ot(e,n,"eggFarm",t.id,o.x,o.y,68,68),e.restore()}function za(e,t){for(let n of t.scanners)Xa(e,n,t)}function Xa(e,t,n){let o=ye(t);if(e.save(),t.kind==="manual"&&(n.manualCombo?.count||0)>=10){let v=n.manualCombo.count;e.save(),e.globalAlpha=Math.min(.55,.16+v/120),e.strokeStyle=v>=30?p.warn:p.green,e.lineWidth=Math.min(14,5+Math.floor(v/10)),e.shadowColor=e.strokeStyle,e.shadowBlur=Math.min(28,8+v),ne(e,o.x-54,o.y-76,108,152,!1,!0),e.restore()}let r=t.kind==="auto"?ce.scannerAuto:ce.scannerManual;if(rt(e,r,o.x-50,o.y-73,100,146)){t.kind==="auto"?bt(e,o.x-50,o.y-73,100,146,t):vs(e,t,o),ot(e,n,"scanner",t.id,o.x,o.y,108,154),e.restore();return}e.fillStyle=t.kind==="auto"?"#d8ffe2":p.white,e.strokeStyle=p.ink,e.lineWidth=4,ne(e,o.x-50,o.y-73,100,146,!0,!0),e.fillStyle=t.kind==="auto"?p.green:p.ink,e.font="900 19px ui-monospace, monospace",e.textAlign="center",e.fillText(`${t.kind==="auto"?"AUTO":`S${(t.slot??0)+1}`}`,o.x,o.y-48),e.font="900 11px ui-monospace, monospace";let i=t.keys?.left?.label||(t.slot===0?"A":"Left"),l=t.keys?.right?.label||(t.slot===0?"D":"Right");e.fillText(t.role===0?`${i}:M ${l}:NEXT`:`${i}:WASTE ${l}:TRUCK`,o.x,o.y-28);let c=t.queue.length;t.kind==="manual"?(vs(e,t,o),e.fillStyle=c>0?p.green:p.muted,e.font="900 10px ui-monospace, monospace",e.fillText(`Q:${c}`,o.x,o.y+54)):(e.fillStyle=c>0?p.green:p.muted,e.font="900 12px ui-monospace, monospace",e.fillText(`Q:${c} CD:${t.cooldown.toFixed(1)}`,o.x,o.y+54),bt(e,o.x-50,o.y-73,100,146,t)),ot(e,n,"scanner",t.id,o.x,o.y,108,154),e.restore()}function vs(e,t,n){if(t.kind!=="manual")return;let r=(t.slot??0)===0?[{side:"left",text:"A"},{side:"right",text:"D"}]:[{side:"left",text:"\u2190"},{side:"right",text:"\u2192"}];r[0].text=t.keys?.left?.label||r[0].text,r[1].text=t.keys?.right?.label||r[1].text;let i=t.keyPressTime>0?t.keyPressSide:null,l=n.x-30,c=n.y+18;e.save(),e.lineWidth=3,e.fillStyle="#f7fff5",e.strokeStyle=p.ink,ne(e,l-4,c-4,68,25,!0,!0),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let v=0;v.8,i=t.y+Math.sin(t.bob)*(r?5:1.5);if(e.save(),n&&(e.strokeStyle=p.green,e.lineWidth=5,e.beginPath(),e.arc(t.x,i,t.radius+8,0,Math.PI*2),e.stroke()),r&&(e.strokeStyle=p.danger,e.lineWidth=3,e.beginPath(),e.arc(t.x,i,t.radius+12+Math.sin(t.bob*2)*4,0,Math.PI*2),e.stroke()),t.sex==="poop")pr(e,t.x,i,t.radius);else{let l=t.sex==="male"?ce.chickMale:ce.chickFemale;if(!rt(e,l,t.x-t.radius,i-t.radius,t.radius*2,t.radius*2)){let x=t.sex==="male"?p.male:p.female,E=t.sex==="male"?"#164f8f":"#8b2252";e.fillStyle=x,e.strokeStyle=p.ink,e.lineWidth=5,e.beginPath(),e.arc(t.x,i,t.radius,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle="rgba(255,255,255,.24)",e.beginPath(),e.arc(t.x-5,i-7,t.radius*.36,0,Math.PI*2),e.fill(),e.fillStyle=p.ink,e.beginPath(),e.arc(t.x-6,i-5,2.5,0,Math.PI*2),e.arc(t.x+6,i-5,2.5,0,Math.PI*2),e.fill(),e.fillStyle="#ffaa2e",e.beginPath(),e.moveTo(t.x,i+2),e.lineTo(t.x+9,i+6),e.lineTo(t.x,i+10),e.closePath(),e.fill(),e.strokeStyle=E,e.lineWidth=3,t.sex==="male"?(e.beginPath(),e.moveTo(t.x-8,i-t.radius-2),e.lineTo(t.x+8,i-t.radius-2),e.stroke()):(e.beginPath(),e.moveTo(t.x-9,i-t.radius+2),e.lineTo(t.x,i-t.radius-6),e.lineTo(t.x+9,i-t.radius+2),e.stroke())}e.fillStyle=t.sex==="male"?"#dff1ff":"#fff0f7",e.strokeStyle="#050609",e.lineWidth=3,e.font=`900 ${Math.max(10,Math.round(t.radius*.72))}px ui-monospace, monospace`,e.textAlign="center";let v=t.sex==="male"?"\u2642":"\u2640";e.strokeText(v,t.x+t.radius*.54,i+t.radius*.7),e.fillText(v,t.x+t.radius*.54,i+t.radius*.7)}e.restore()}function sc(e,t){let n=null,o=1/0;for(let[r,i]of e.componentLookup.entries()){let l=Z(r),c=F(l.col,l.row),v=Math.hypot(t.x-c.x,t.y-c.y);vws(o.type,o.id)===ws(t,n))}function ot(e,t,n,o,r,i,l,c){lc(t,n,o)&&(e.save(),e.fillStyle="rgba(34,185,79,.18)",e.strokeStyle=p.green,e.lineWidth=(t.multiSelected||[]).length>1?6:4,e.setLineDash((t.multiSelected||[]).length>1?[]:[8,5]),ne(e,r-l/2,i-c/2,l,c,!0,!0),e.restore())}function ac(e,t,n,o){if(t.phase==="build"&&(t.multiSelected||[]).length>1){e.save(),e.fillStyle="rgba(255,255,255,.96)",e.strokeStyle=p.ink,e.lineWidth=3,ne(e,54-t.view.x,66-t.view.y,214,42,!0,!0),e.fillStyle=p.ink,e.font="900 11px ui-monospace, monospace",e.fillText(`${t.multiSelected.length} ITEMS SELECTED`,65-t.view.x,83-t.view.y),e.fillStyle=p.muted,e.font="900 11px ui-monospace, monospace",e.fillText("drag any selected item to move group",65-t.view.x,99-t.view.y),e.restore();return}}function cc(e,t,n){if(!n.cardTargetPick?.pending)return;let o=ir(n);e.save(),e.fillStyle="rgba(0,0,0,.66)",e.beginPath();let r=n.view?.scale||1;e.rect(-(n.view?.x||0)/r,-(n.view?.y||0)/r,t.width/r,t.height/r);for(let v of o){let x=v.bounds,E=8;e.rect(x.x-E,x.y-E,x.w+E*2,x.h+E*2)}e.fill("evenodd");let i=n.cardTargetPick?.mode==="blockedCell";if(!o.length){e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=p.ink,e.lineWidth=3,ne(e,(260-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,420/r,42/r,!0,!0),e.fillStyle=p.danger,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(i?"NO BLOCKED CELL. PRESS ESC.":"NO VALID UPGRADE TARGET. PRESS ESC.",(470-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore();return}e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=p.ink,e.lineWidth=3;let l=Math.max(1,n.cardTargetPick?.remaining||1),c=n.cardTargetPick?.mode==="autoScannerMenu"?"AUTO SCANNER ROUTE SETTINGS. CLICK EMPTY AREA TO CLOSE.":i?`CLICK BLOCKED CELL: ${l} LEFT. PRESS ESC TO CANCEL.`:"CLICK AN UPGRADEABLE MACHINE. PRESS ESC TO CANCEL.";ne(e,(216-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,560/r,42/r,!0,!0),e.fillStyle=p.ink,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(c,(496-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore()}function uc(e,t){if(t.phase!=="build"||!t.selectionBox)return;let n=t.selectionBox,o=Math.min(n.x1,n.x2),r=Math.min(n.y1,n.y2),i=Math.abs(n.x2-n.x1),l=Math.abs(n.y2-n.y1);e.save(),e.fillStyle="rgba(34,185,79,.12)",e.strokeStyle=p.green,e.lineWidth=2,e.setLineDash([7,4]),ne(e,o,r,i,l,!0,!0),e.restore()}function dc(e,t){let n=[...t.effects].sort((o,r)=>(o.priority??xe.ambient)-(r.priority??xe.ambient));for(let o of n){let r=Math.max(0,o.life/o.maxLife);e.save(),e.globalAlpha=r,o.type==="meat"?(e.fillStyle=p.green,ne(e,o.x-o.size/2,o.y-o.size/2,o.size*1.5,o.size,!0,!1)):o.type==="sludge"?(e.fillStyle=p.poop,ne(e,o.x-o.size/2,o.y-o.size/2,o.size*1.4,o.size,!0,!1)):o.type==="spawn"?(e.strokeStyle=p.green,e.lineWidth=3,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*20,0,Math.PI*2),e.stroke()):o.type==="spark"?(e.fillStyle=o.color||p.danger,ne(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!0,!1)):o.type==="smoke"?(e.fillStyle="rgba(16,32,21,.24)",e.beginPath(),e.arc(o.x,o.y,o.size*(1.2-r*.2),0,Math.PI*2),e.fill()):o.type==="shockwave"?(e.strokeStyle=o.color||p.danger,e.lineWidth=4,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*(o.maxSize||44),0,Math.PI*2),e.stroke()):o.type==="scannerPulse"?(e.strokeStyle=o.color||p.green,e.lineWidth=5,e.setLineDash([8,6]),e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*38,0,Math.PI*2),e.stroke()):o.type==="shred"?(e.fillStyle=o.color||p.ink,e.save(),e.translate(o.x,o.y),e.rotate(o.rot||0),ne(e,-o.w/2,-o.h/2,o.w,o.h,!0,!1),e.restore()):o.type==="load"?(e.strokeStyle=o.color||p.green,e.lineWidth=3,e.beginPath(),e.moveTo(o.x-14,o.y),e.lineTo(o.x+14,o.y),e.moveTo(o.x,o.y-14),e.lineTo(o.x,o.y+14),e.stroke()):o.type==="erase"?(e.strokeStyle=p.ink,e.lineWidth=3,e.setLineDash([4,4]),ne(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!1,!0)):o.type==="rage"?(e.fillStyle=o.color||p.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText("!",o.x,o.y)):o.type==="flyingChick"&&(o.sex==="poop"?pr(e,o.x,o.y,o.radius||11):yr(e,o.x,o.y,o.sex,o.sex==="male")),e.restore()}}function fc(e,t){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let n of t.floatingTexts){let o=Math.max(0,n.life/n.maxLife);e.globalAlpha=o,e.lineWidth=5,e.strokeStyle=p.white,e.fillStyle=n.color,e.strokeText(n.text,n.x,n.y),e.fillText(n.text,n.x,n.y)}e.restore()}function pc(e,t){let n=t.repairmen&&t.repairmen.length?t.repairmen:t.repairman?[t.repairman]:[];for(let o of n)yc(e,t,o)}function yc(e,t,n){if(!!!n?.active)return;if(e.save(),rt(e,ce.repairman,n.x-18,n.y-18,36,36)){n.target?.label&&lr(e,n.x,n.y-24,n.target.label,p.green),e.restore();return}e.lineWidth=3,e.fillStyle="#fff0d1",e.strokeStyle=p.ink,e.beginPath(),e.arc(n.x,n.y,17,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle="#ffd6e7",e.beginPath(),e.arc(n.x-6,n.y-2,3.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+6,n.y-2,3.2,0,Math.PI*2),e.fill();let r=!!t.cardEffects?.laborExploitation;e.fillStyle=r?p.danger:p.ink,e.beginPath(),e.arc(n.x-5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.strokeStyle=p.ink,e.lineWidth=r?3:2,e.beginPath(),e.arc(n.x,n.y+(r?0:1),r?8:7,.1*Math.PI,.9*Math.PI),e.stroke(),e.fillStyle=p.green,ne(e,n.x-9,n.y+14,18,8,!0,!0),e.strokeStyle=p.ink,e.lineWidth=3,e.beginPath(),e.moveTo(n.x-11,n.y+18),e.lineTo(n.x-20,n.y+24),e.stroke(),e.beginPath(),e.moveTo(n.x+11,n.y+18),e.lineTo(n.x+20,n.y+24),e.stroke(),e.fillStyle=p.ink,e.font="900 11px ui-monospace, monospace",e.textAlign="center",e.fillText("FIX",n.x,n.y+33),n.target?.label&&lr(e,n.x,n.y-24,n.target.label,p.green),e.restore()}function hc(e,t,n){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="left",e.fillStyle=p.ink,e.font="900 19px ui-monospace, monospace",e.fillStyle=p.ink;let o=[];t.phase==="running"&&o.push(t.timeLeft<=0?"TIME UP: FARMS SHUT. CLEAR LINE.":"A/D: S1 \u2190/\u2192: S2"),t.phase==="build"&&o.push(`BUILD: ${t.buildTool||"SELECT"} | connect 1 EGG route to any exit`);let r=76;for(let i of o)e.strokeStyle=p.white,e.lineWidth=4,e.strokeText(i,24,r),e.fillText(i,24,r),r+=20;e.restore()}var gs=[[{key:"a",code:"KeyA",label:"A"},{key:"d",code:"KeyD",label:"D"}],[{key:"arrowleft",code:"ArrowLeft",label:"Left"},{key:"arrowright",code:"ArrowRight",label:"Right"}],[{key:"j",code:"KeyJ",label:"J"},{key:"l",code:"KeyL",label:"L"}],[{key:"f",code:"KeyF",label:"F"},{key:"h",code:"KeyH",label:"H"}],[{key:"q",code:"KeyQ",label:"Q"},{key:"e",code:"KeyE",label:"E"}],[{key:"z",code:"KeyZ",label:"Z"},{key:"x",code:"KeyX",label:"X"}],[{key:"u",code:"KeyU",label:"U"},{key:"o",code:"KeyO",label:"O"}],[{key:"n",code:"KeyN",label:"N"},{key:"m",code:"KeyM",label:"M"}]];function mc(e){let t=gs[e]||gs[0];return{left:{...t[0]},right:{...t[1]}}}function Ts(e,t,n){let o={type:"eggFarm",id:e.nextId++,col:t,row:n,level:1,nextSpawn:2,lastInterval:2,extraEggOutlet:0,price:lt.eggFarm,builtSession:e.buildSession};return o.nextSpawn=Rt(o),o.lastInterval=o.nextSpawn,o}function Es(e,t,n,o){let r=o==="auto"?ve.autoScanner.price:ve.manualScanner.price,i=new Set(e.scanners.filter(c=>c.kind==="manual").map(c=>c.slot)),l=0;for(;i.has(l);)l+=1;return{type:"scanner",id:e.nextId++,kind:o,slot:o==="manual"?l:null,role:o==="manual"?l%2:0,col:t,row:n,level:1,queue:[],cooldown:0,price:r,builtSession:e.buildSession,autoMode:"standard",keys:o==="manual"?mc(l):null}}function Jn(e){let t=(e.x-f.x)/f.cell,n=(e.y-f.y)/f.cell,o=Math.max(0,Math.min(f.cols-1,Math.round(t-.5))),r=Math.max(0,Math.min(f.rows-1,Math.round(n-.5))),i=Math.abs(e.x-f.x),l=Math.abs(e.x-(f.x+f.cols*f.cell)),c=Math.abs(e.y-f.y),v=Math.abs(e.y-(f.y+f.rows*f.cell)),x=[["left",i],["right",l],["top",c],["bottom",v]].sort((E,R)=>E[1]-R[1])[0][0];return x==="left"?{side:x,entry:{col:0,row:r}}:x==="right"?{side:x,entry:{col:f.cols-1,row:r}}:x==="top"?{side:x,entry:{col:o,row:0}}:{side:x,entry:{col:o,row:f.rows-1}}}function jn(e,t,n){let o={x:f.x+t.col*f.cell+f.cell/2,y:f.y+t.row*f.cell+f.cell/2},r={left:f.x,right:f.x+f.cols*f.cell,top:f.y,bottom:f.y+f.rows*f.cell};return e.entry={...t},e.side=n,n==="left"?(e.x=r.left-e.w-18,e.y=o.y-e.h/2):n==="right"?(e.x=r.right+18,e.y=o.y-e.h/2):n==="top"?(e.x=o.x-e.w/2,e.y=r.top-e.h-18):(e.x=o.x-e.w/2,e.y=r.bottom+18),e}function Rs(e,t,n,o){let{entry:r,side:i}=Jn(n),l=ve[t],c=l?{name:l.name,w:l.body?.w||168,h:l.body?.h||110,price:l.price}:{name:t[0].toUpperCase()+t.slice(1),w:168,h:110,price:o},v={type:"facility",id:t,name:c.name,x:0,y:0,w:c.w,h:c.h,level:1,price:o||c.price,builtSession:e.buildSession};return jn(v,r,i)}function jt(e){return e?[{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}]:[]}function Ps(e,t,n){return{type:"maintenanceRoom",id:e.nextId++,col:t,row:n,price:lt.maintenanceRoom,builtSession:e.buildSession,wCells:2,hCells:2}}function bc(e){return Math.random()({x:i.x,y:i.y})),r=o[0];return{id:e.nextId++,sex:n,x:r.x,y:r.y,route:o,targetIndex:o.length>1?1:o.length,stage:t.stage||"belt",scannerId:t.scannerId??null,nextScannerId:null,pendingScannerId:null,radius:n==="poop"?15:17,bob:Math.random()*Math.PI*2,queueIndex:-1,queueRoute:null}}function Is({game:e,canvasPoint:t,updatePanels:n,equipmentAtPoint:o,fail:r,pointInGrid:i,rectOfFacility:l,rectsOverlap:c}){function v(S){return S?S.type==="conveyor"?`conveyor:${S.id||S.oldKey}`:S.type==="facility"?`facility:${S.id||S.ref?.id}`:S.type==="maintenanceRoom"?`maintenanceRoom:${S.id||S.ref?.id}`:`${S.type}:${S.id||S.ref?.id}`:""}function x(S){return S?S.type==="conveyor"?{type:"conveyor",id:S.oldKey}:{type:S.type,id:S.ref.id}:null}function E(S){let M=v(x(S));return(e.multiSelected||[]).some(N=>v(N)===M)}function R(S){return S?S.type==="eggFarm"?e.eggFarms.find(M=>M.id===S.id)||null:S.type==="scanner"?e.scanners.find(M=>M.id===S.id)||null:S.type==="facility"?e.facilities[S.id]||null:S.type==="maintenanceRoom"?(e.maintenanceRooms||[]).find(M=>M.id===S.id)||null:S.type==="conveyor"&&e.conveyorTiles.has(S.id)?{type:"conveyor",id:S.id}:null:null}function B(){let S=[];for(let M of e.conveyorTiles){let N=Z(M),J=F(N.col,N.row);S.push({type:"conveyor",id:M,center:J,cell:N})}for(let M of e.eggFarms)S.push({type:"eggFarm",id:M.id,ref:M,center:F(M.col,M.row),cell:{col:M.col,row:M.row}});for(let M of e.scanners)S.push({type:"scanner",id:M.id,ref:M,center:ye(M),cell:{col:M.col,row:M.row}});for(let M of e.maintenanceRooms||[]){let N=F(M.col,M.row);S.push({type:"maintenanceRoom",id:M.id,ref:M,center:{x:N.x+f.cell/2,y:N.y+f.cell/2},cell:{col:M.col,row:M.row}})}for(let M of Object.values(e.facilities)){let N={x:M.x+M.w/2,y:M.y+M.h/2},J=M.entry?F(M.entry.col,M.entry.row):N;S.push({type:"facility",id:M.id,ref:M,center:N,portCenter:J})}return S}function O(S,M){let N=Math.min(M.x1,M.x2),J=Math.max(M.x1,M.x2),Q=Math.min(M.y1,M.y2),pe=Math.max(M.y1,M.y2);return S.x>=N&&S.x<=J&&S.y>=Q&&S.y<=pe}function ee(S){let M=[];for(let N of B())(O(N.center,S)||N.portCenter&&O(N.portCenter,S))&&M.push({type:N.type,id:N.id});return e.multiSelected=M,e.selected=M[0]||null,n(),M.length}function X(){e.multiSelected=[],e.selected=null,n()}function ae(S){let M=t(S);return e.selectionBox={x1:M.x,y1:M.y,x2:M.x,y2:M.y},e.multiSelected=[],e.selected=null,n(),!0}function he(S){if(!e.selectionBox)return;let M=t(S);e.selectionBox.x2=M.x,e.selectionBox.y2=M.y}function ie(){if(!e.selectionBox)return 0;let S=e.selectionBox,M=Math.abs(S.x2-S.x1),N=Math.abs(S.y2-S.y1);return e.selectionBox=null,M<6&&N<6?(X(),0):ee(S)}function le(S){let M=x(S);return M?(e.multiSelected||[]).length&&E(S)?[...e.multiSelected]:[M]:[]}function se(S){let M=R(S);if(!M)return null;if(S.type==="conveyor"){let N=Z(S.id);return{...S,obj:M,oldKey:S.id,currentKey:S.id,meta:e.conveyorMeta.get(S.id)||{price:Oe("conveyor"),builtSession:null},col:N.col,row:N.row}}return S.type==="eggFarm"||S.type==="scanner"||S.type==="maintenanceRoom"?{...S,obj:M,col:M.col,row:M.row}:S.type==="facility"?{...S,obj:M,x:M.x,y:M.y,w:M.w,h:M.h,entry:M.entry?{...M.entry}:null,side:M.side,center:{x:M.x+M.w/2,y:M.y+M.h/2}}:null}function A(S){let M=t(S),N=o(M);if(!N)return!1;let J=le(N),Q=J.map(se).filter(Boolean);return Q.length?(e.groupDrag={start:M,selections:J,origins:Q,historySnapshot:hn(e),committed:!1,lastDCol:0,lastDRow:0},e.multiSelected=J,e.selected=J[0]||null,n(),!0):!1}function G(){!e.groupDrag||e.groupDrag.committed||(e.undoStack.push(e.groupDrag.historySnapshot),e.redoStack=[],e.groupDrag.committed=!0)}function q(S,M,N){let J=I(S,M),Q=dt(e,S,M);if(Q&&!N.has(`eggFarm:${Q.id}`))return!0;let pe=ft(e,S,M);if(pe&&!N.has(`scanner:${pe.id}`))return!0;let ge=(e.maintenanceRooms||[]).find(Pe=>jt(Pe).some(Ae=>Ae.col===S&&Ae.row===M));return!!(ge&&!N.has(`maintenanceRoom:${ge.id}`)||e.conveyorTiles.has(J)&&!N.has(`conveyor:${J}`))}function me(S,M,N){let J=[];for(let Q of e.groupDrag.origins){if(Q.type!=="facility")continue;let pe={x:Q.center.x+S,y:Q.center.y+M},{entry:ge,side:Pe}=Jn(pe);if(!i(ge.col,ge.row)||e.blockedCells?.has?.(I(ge.col,ge.row)))return!0;let Ae={...Q.obj,entry:{...ge},side:Pe};jn(Ae,ge,Pe),J.push({id:Q.id,rect:l(Ae)})}for(let Q of J)for(let pe of Object.values(e.facilities))if(!N.has(`facility:${pe.id}`)&&c(Q.rect,l(pe),12))return!0;for(let Q=0;Q_.type==="conveyor");for(let _ of Ae){let Ie=_.currentKey||_.oldKey;e.conveyorTiles.delete(Ie),e.conveyorMeta.delete(Ie)}for(let _ of Ae){let Ie=I(_.col+Q,_.row+pe);e.conveyorTiles.add(Ie),e.conveyorMeta.set(Ie,_.meta||{price:Oe("conveyor"),builtSession:null,uses:0}),_.currentKey=Ie}for(let _ of e.groupDrag.origins)if(_.type==="eggFarm")_.obj.col=_.col+Q,_.obj.row=_.row+pe;else if(_.type==="scanner")_.obj.col=_.col+Q,_.obj.row=_.row+pe;else if(_.type==="maintenanceRoom")_.obj.col=_.col+Q,_.obj.row=_.row+pe;else if(_.type==="facility"){let Ie={x:_.center.x+N,y:_.center.y+J},{entry:qe,side:Ye}=Jn(Ie);jn(_.obj,qe,Ye)}e.groupDrag.selections=e.groupDrag.origins.map(_=>_.type==="conveyor"?{type:"conveyor",id:_.currentKey||_.oldKey}:{type:_.type,id:_.id}),e.multiSelected=[...e.groupDrag.selections],e.selected=e.multiSelected[0]||null,be(e),n()}function U(){e.groupDrag&&(be(e),e.groupDrag=null,n())}return{selectionFromHit:x,startSelectionBox:ae,updateSelectionBox:he,finishSelectionBox:ie,startGroupDrag:A,updateGroupDrag:D,finishGroupDrag:U}}function $s({game:e,ui:t,canvas:n,canvasPoint:o,onUpdatePanels:r}){function i(){r&&r()}let l=null,c=!1,v=null,x=!1,E=["random","up","right","down","left"],R={random:"RND",up:"UP",right:"RT",down:"DN",left:"LF"},B={w:40,h:40,y:0};function O(){return Rn(e)}function ee(){e.gridCols=f.cols,e.gridRows=f.rows,e.gridOwnedCells=qr(e)}function X(s){if(s){f.y-=s*f.cell,f.rows+=s,e.gridChunkOriginY=(e.gridChunkOriginY||0)-Math.floor(s/10),e.ownedCells=Pn(e.ownedCells,s),e.blockedCells=Pn(e.blockedCells,s),e.conveyorTiles=Pn(e.conveyorTiles,s),e.conveyorMeta=Xr(e.conveyorMeta,s);for(let a of e.eggFarms||[])a.row+=s;for(let a of e.scanners||[])a.row+=s;for(let a of Object.values(e.facilities||{}))a.entry&&(a.entry.row+=s)}}function ae(s){e.ownedCells=e.ownedCells||new Set;for(let a of zr(s))e.ownedCells.add(I(a.col,a.row))}function he(s){return e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending?null:Tt(e).find(a=>a&&Vr(a,s))||null}function ie(s="right"){if(s&&typeof s=="object"&&Number.isFinite(s.chunkX)&&Number.isFinite(s.chunkY))return s;let a=["right","up"].includes(s)?s:"right";return Yr(e,a)}function le(s="right"){let a=ie(s);if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return{ok:!1,reason:"Cannot expand now."};if(!a)return{ok:!1,reason:"Invalid expansion lot."};let h=a.direction||"right",m=O();if(e.cashf.cols&&(f.cols=T.colStart+T.cols),T.rowStart+T.rows>f.rows&&(f.rows=T.rowStart+T.rows),ae(T),Qr(e,T.chunkX,T.chunkY),e.gridExpansionPurchases=(e.gridExpansionPurchases||0)+1,e.gridExpansionPurchasesByDirection[h]=(e.gridExpansionPurchasesByDirection[h]||0)+1,ee();let te=Gr({seed:`${e.runSeed}:grid-expansion:${T.chunkX},${T.chunkY}:${e.gridExpansionPurchases}`,colStart:T.colStart,colEnd:T.colStart+T.cols,rowStart:T.rowStart,rowEnd:T.rowStart+T.rows,targetRatio:Y.map.blockedRatio});for(let ke of te)e.blockedCells.add(ke);be(e);let j=T.cols*T.rows,ue=Et(T);return H(e,ue.x+ue.w/2,ue.y+ue.h/2,`${h.toUpperCase()} +${j} CELLS -${g(m)}`,p.green),i(),{ok:!0,direction:h,cost:m,addedCells:j,blocked:te.size,chunkX:T.chunkX,chunkY:T.chunkY}}function se(s,a){return s>=0&&s=0&&a!a.has(m.id)&&q(h,G(m),12))}function D(s,a,h=null){if(!se(s,a))return!1;if(A(s,a))return!0;let m=I(s,a),w=dt(e,s,a);if(w&&!(h?.type==="eggFarm"&&h.ref?.id===w.id))return!0;let T=ft(e,s,a);if(T&&!(h?.type==="scanner"&&h.ref?.id===T.id))return!0;let te=U(e,s,a);return!!(te&&!(h?.type==="maintenanceRoom"&&h.ref?.id===te.id)||e.conveyorTiles.has(m)&&!(h?.type==="conveyor"&&h.oldKey===m))}function U(s,a,h){return(s.maintenanceRooms||[]).find(m=>jt(m).some(w=>w.col===a&&w.row===h))||null}function S(s,a,h=null){let m={col:s,row:a};for(let w of jt(m)){if(!se(w.col,w.row)||A(w.col,w.row))return!0;let T=I(w.col,w.row);if(dt(e,w.col,w.row)||ft(e,w.col,w.row))return!0;let ue=U(e,w.col,w.row);if(ue&&!(h?.type==="maintenanceRoom"&&h.ref?.id===ue.id)||e.conveyorTiles.has(T))return!0}return!1}function M(s,a,h=null){let m={col:s,row:a};for(let w of Pt(m)){if(!se(w.col,w.row)||A(w.col,w.row))return!0;let T=I(w.col,w.row);if(dt(e,w.col,w.row))return!0;let j=ft(e,w.col,w.row);if(j&&!(h?.type==="scanner"&&h.ref?.id===j.id)||e.conveyorTiles.has(T))return!0}return!1}function N(){return e.selected?e.selected.type==="eggFarm"?e.eggFarms.find(s=>s.id===e.selected.id)||null:e.selected.type==="scanner"?e.scanners.find(s=>s.id===e.selected.id)||null:e.selected.type==="conveyor"?e.conveyorTiles.has(e.selected.id)?{type:"conveyor",id:e.selected.id}:null:e.selected.type==="facility"?e.facilities[e.selected.id]||null:e.selected.type==="maintenanceRoom"&&(e.maintenanceRooms||[]).find(s=>s.id===e.selected.id)||null:null}function J(s){return s?s.type==="eggFarm"?`${ct("eggFarm")} #${s.id}`:s.type==="scanner"?`${s.kind==="auto"?ct("autoScanner"):ct("manualScanner")} #${s.id}`:s.type==="conveyor"?e.conveyorMeta.get(s.id)?.kind==="boostConveyor"?ct("boostConveyor"):ct("conveyor"):s.type==="facility"?s.name:s.type==="maintenanceRoom"?`${ct("maintenanceRoom")} #${s.id}`:"Equipment":"Equipment"}function Q(s){return s?.type==="conveyor"?e.conveyorMeta?.get(s.oldKey||s.ref?.id)?.price||Ln(s):Ln(s)}function pe(){return!!e.cardEffects?.usedMachineActive}function ge(){return pe()?{usedMachine:!0,noRefund:!0,durabilityBaseMultiplier:.6}:{usedMachine:!1,noRefund:!1,durabilityBaseMultiplier:1}}function Pe(s){let a=ge();return Object.assign(s,a),s}function Ae(s){let a=s?.ref||s||{};if(s?.type==="eggFarm"||a.type==="eggFarm")return e.eggFarms.length<=1?"Cannot sell the last EGG FARM.":"";if((s?.type==="facility"||a.type==="facility")&&["mixer","trash","truck"].includes(a.baseId||a.id)){let h=a.baseId||a.id;if(Object.values(e.facilities).filter(w=>(w.baseId||w.id)===h).length<=1)return`Cannot sell the last ${a.shortName||a.name||a.id}.`}return""}function _(s){t.buildStatus.textContent=s,H(e,n.width/2-e.view.x,86-e.view.y,s.toUpperCase(),p.danger)}function Ie(s){if(!s)return null;let a=I(s.col,s.row);return e.conveyorMeta.get(a)||null}function qe(s){return s?(Array.isArray(s.outDirs)||(s.outDirs=[]),s.outDirs=[...new Set(s.outDirs.filter(a=>["right","left","down","up"].includes(a)))],E.includes(s.branchMode)||(s.branchMode="random"),s.kind||(s.kind="conveyor"),s.speedMultiplier||(s.speedMultiplier=s.kind==="boostConveyor"?2:1),s.outDirs):[]}function Ye(s){return s?de.filter(a=>e.conveyorTiles.has(I(s.col+a.dc,s.row+a.dr))).map(a=>a.name):[]}function Te(s){return Ye(s).length>=3}function kt(s,a){let h=de.find(j=>j.name===a);if(!s||!h)return!1;let m=I(s.col+h.dc,s.row+h.dr),w=e.conveyorMeta.get(m);if(!w)return!1;let T=h.opposite;return[...new Set([...Array.isArray(w.outDirs)?w.outDirs:[],w.dir].filter(Boolean))].includes(T)}function oo(s){if(!e.conveyorTiles.has(s))return[];let a=Z(s),h=e.conveyorMeta.get(s),m=qe(h),w=Ye(a),T=[...new Set([...m,h?.dir].filter(Boolean))].filter(ue=>w.includes(ue)),te=w,j=T.length?T:te;return h&&(h.outDirs=m.filter(ue=>w.includes(ue)),h.dir&&!w.includes(h.dir)&&(h.dir=h.outDirs[0]||null),h.branchMode!=="random"&&!w.includes(h.branchMode)&&(h.branchMode="random")),j}function Sn(s){if(!e.conveyorTiles.has(s))return[];let a=Z(s),h=Ye(a);return Te(a)||h.length?h:oo(s)}function ro(s){let a=Z(s),h=Sn(s);if(h.length<3)return[];let m=new Set(h.filter(w=>kt(a,w)));return h.filter(w=>{let T=new Set(m);return T.add(w),h.filter(te=>!T.has(te)).length>=2})}function nn(s,a){let h=at(s,a);if(!h)return!1;let m=I(s.col,s.row),w=I(a.col,a.row),T=e.conveyorMeta.get(m),te=e.conveyorMeta.get(w);if(!T||!te)return!1;let j=qe(T),ue=!j.includes(h)||T.dir!==h||!te.dir;return j.includes(h)||j.push(h),T.dir=h,te.dir||(te.dir=h),ue}function Ct(s){let a=so(s);return a.length<2?io(s):(Be(e),lo(a),be(e),i(),!0)}function io(s){if(!s)return!1;let a=I(s.col,s.row),h=e.conveyorMeta.get(a);if(!h||Te(s))return!1;let m=de.map(te=>te.name),w=h.dir&&m.includes(h.dir)?h.dir:null,T=m[(Math.max(-1,m.indexOf(w))+1)%m.length];return Be(e),h.dir=T,h.outDirs=[T],h.branchMode="random",be(e),i(),!0}function kn(s){return s?de.map(a=>({col:s.col+a.dc,row:s.row+a.dr})).filter(a=>e.conveyorTiles.has(I(a.col,a.row))):[]}function so(s){if(!s||!e.conveyorTiles.has(I(s.col,s.row))||Te(s))return[];let a=kn(s);if(!a.length||a.length>2)return[];let h=T=>{let te=[],j=new Set([I(s.col,s.row)]),ue=s,ke=T,xr=0;for(;ke&&xr<200;){xr+=1;let Mr=I(ke.col,ke.row);if(j.has(Mr)||(j.add(Mr),te.push(ke),Te(ke)))break;let gr=kn(ke).filter(Tr=>!(Tr.col===ue.col&&Tr.row===ue.row));if(gr.length!==1)break;ue=ke,ke=gr[0]}return te},m=a[0]?h(a[0]).reverse():[],w=a[1]?h(a[1]):[];return[...m,s,...w]}function xt(s,a){return!!s&&[...new Set([...Array.isArray(s.outDirs)?s.outDirs:[],s.dir].filter(Boolean))].includes(a)}function lo(s){let a=0,h=0;for(let w=0;wh?[...s].reverse():s;for(let w=0;w=Math.abs(m)?{col:s.col+Math.sign(h),row:s.row}:{col:s.col,row:s.row+Math.sign(m)}}function ao(s){c=!1,v=s?{col:s.col,row:s.row}:null,x=!1,l=null,on(s)}function d(s){if(!s)return;if(!l)return on(s);let a=l,h=0;for(;(a.col!==s.col||a.row!==s.row)&&h<64;){let m=rn(a,s);if(on(m),a=l||m,h+=1,!l)break}}function y(){!x&&v&&e.conveyorTiles.has(I(v.col,v.row))&&Ct(v),v=null,x=!1,l=null,c=!1}function b(s){if(!s)return _(oe.fail.outOfGrid);let{col:a,row:h}=s;if(e.buildTool==="conveyor"||e.buildTool==="boostConveyor"){let m=_t(s,null);if(!m.ok)return _(m.reason||oe.fail.cellOccupied);be(e);return}if(A(a,h))return _("Cannot build on blocked ground.");if(e.buildTool==="maintenanceRoom")return S(a,h)?_(oe.fail.cellOccupied):$(a,h);if(e.buildTool==="manualScanner"||e.buildTool==="autoScanner"?M(a,h):D(a,h))return _(oe.fail.cellOccupied);e.buildTool==="eggFarm"?k(a,h):e.buildTool==="manualScanner"?P(a,h,"manual"):e.buildTool==="autoScanner"&&P(a,h,"auto")}function C(s){let a=Ke(s.x,s.y);if(["conveyor","boostConveyor","eggFarm","manualScanner","autoScanner","maintenanceRoom"].includes(e.buildTool))return b(a);if(cn.includes(e.buildTool))return re(s,e.buildTool)}function k(s,a){let h=Oe("eggFarm",e);if(e.cashT.kind==="manual").length>=8)return _("Manual Scanner limit reached (8 max).");let m=h==="auto"?Oe("autoScanner",e):Oe("manualScanner",e);if(e.cashw.id!==a.ref.id),et(e,m.x,m.y),be(e)}if(a.type==="scanner"){let m=ye(a.ref);Ne(a,m.x,m.y),e.scanners=e.scanners.filter(w=>w.id!==a.ref.id),et(e,m.x,m.y),be(e)}if(a.type==="facility"){let m=a.ref;Ne(a,m.x+m.w/2,m.y+m.h/2),delete e.facilities[m.id],et(e,m.x+m.w/2,m.y+m.h/2),be(e)}if(a.type==="maintenanceRoom"){let m=a.ref,w=K(m);Ne(a,w.x,w.y),e.maintenanceRooms=(e.maintenanceRooms||[]).filter(T=>T.id!==m.id),et(e,w.x,w.y)}e.selected=null,e.multiSelected=[],i()}function co(s){let a=Object.values(e.facilities).find(j=>{if(s.x>=j.x&&s.x<=j.x+j.w&&s.y>=j.y&&s.y<=j.y+j.h)return!0;if(!j.entry)return!1;let ke=F(j.entry.col,j.entry.row);return Math.abs(s.x-ke.x)<=f.cell*.46&&Math.abs(s.y-ke.y)<=f.cell*.46});if(a)return{type:"facility",ref:a};let h=Ke(s.x,s.y);if(!h)return null;let m=dt(e,h.col,h.row);if(m)return{type:"eggFarm",ref:m};let w=ft(e,h.col,h.row);if(w)return{type:"scanner",ref:w};let T=U(e,h.col,h.row);if(T)return{type:"maintenanceRoom",ref:T};let te=I(h.col,h.row);return e.conveyorTiles.has(te)?{type:"conveyor",oldKey:te,ref:{type:"conveyor",id:te}}:null}let Ut=Is({game:e,canvasPoint:o,updatePanels:i,equipmentAtPoint:co,fail:_,pointInGrid:se,rectOfFacility:G,rectsOverlap:q});function Qs(s){return null}function mr(){let s=N();s&&(s.type==="conveyor"?Gt(F(...Object.values(Z(s.id)))):s.type==="eggFarm"?Gt(F(s.col,s.row)):s.type==="scanner"?Gt(ye(s)):s.type==="facility"?Gt({x:s.x+s.w/2,y:s.y+s.h/2}):s.type==="maintenanceRoom"&&Gt(K(s)))}function Ve(s,a,h="primary-button"){let m=document.createElement("button");return m.type="button",m.className=h,m.textContent=s,m.addEventListener("click",a),m}function sn(){e.cardTargetPick?.mode==="autoScannerMenu"&&(e.cardTargetPick=null),t.modal.classList.remove("visible","equipment-popover"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function uo(s){t.modalTitle.textContent="Auto Scanner",e.cardTargetPick={pending:!0,mode:"autoScannerMenu",cardId:null,targetKeys:[`scanner:${s.id}`],remaining:1},t.modalBody.innerHTML=` -
-

Left / right output routing for this AUTO scanner.

-

Current: ${s.role===0?"Male left / others right":"Poop left / others right"}

-

Cooldown: ${nt(s).toFixed(1)}s.

-
`,t.modalActions.innerHTML="";let a=Ve("Male Left / Others Right",()=>{Be(e),s.role=0,sn(),i()},s.role===0?"facility-action warn":"facility-action"),h=Ve("Poop Left / Others Right",()=>{Be(e),s.role=1,sn(),i()},s.role===1?"facility-action warn":"facility-action");t.modalActions.append(a,h,Ve("Close",sn,"facility-action")),fo(s),t.modal.classList.add("visible","equipment-popover"),i()}function br(s){return s?.label||s?.key||"?"}function Js(s){let a=s.key===" "?"Space":s.key.length===1?s.key.toUpperCase():s.key.replace(/^Arrow/,"");return{key:s.key.toLowerCase(),code:s.code,label:a}}function js(s,a,h){for(let m of e.scanners.filter(w=>w.kind==="manual"))for(let w of["left","right"]){if(m.id===s.id&&w===a)continue;let T=m.keys?.[w];if(T&&(T.code===h.code||T.key===h.key))return!0}return!1}function ln(s,a=""){if(!s||s.kind!=="manual")return;t.modalTitle.textContent=`Manual Scanner #${s.id}`;let h=br(s.keys?.left),m=br(s.keys?.right),w=Zs(s);t.modalBody.innerHTML=` -
-

Left route key: ${h}

-

Right route key: ${m}

- ${a?`

${a}

`:""} - ${w?`

${w}

`:""} -
`,t.modalActions.innerHTML="",t.modalActions.appendChild(Ve("Set Left Key",()=>vr(s,"left"),"facility-action warn")),t.modalActions.appendChild(Ve("Set Right Key",()=>vr(s,"right"),"facility-action warn")),t.modalActions.appendChild(Ve("Close",sn,"facility-action")),fo(s),t.modal.classList.add("visible","equipment-popover")}function Zs(s){let a=[{side:"left",binding:s.keys?.left},{side:"right",binding:s.keys?.right}];if(a[0].binding&&a[1].binding&&(a[0].binding.code===a[1].binding.code||a[0].binding.key===a[1].binding.key))return"Left and right keys conflict.";for(let h of a)if(h.binding)for(let m of e.scanners.filter(w=>w.kind==="manual"&&w.id!==s.id)){if(m.keys?.left&&(m.keys.left.code===h.binding.code||m.keys.left.key===h.binding.key))return`Key conflicts with Manual Scanner #${m.id} left.`;if(m.keys?.right&&(m.keys.right.code===h.binding.code||m.keys.right.key===h.binding.key))return`Key conflicts with Manual Scanner #${m.id} right.`}return""}function vr(s,a){t.modalBody.innerHTML=`

Press a key for ${a.toUpperCase()} route.

Esc cancels.

`,t.modalActions.innerHTML="";let h=m=>{if(m.preventDefault(),m.stopPropagation(),window.removeEventListener("keydown",h,!0),m.key==="Escape")return ln(s);let w=Js(m),T=js(s,a,w);Be(e),s.keys=s.keys||{left:null,right:null},s.keys[a]=w,i(),ln(s,T?`${w.label} assigned, but another scanner already uses it.`:`${a.toUpperCase()} set to ${w.label}.`)};window.addEventListener("keydown",h,!0)}function el(){let s=N();if(!(!s||s.type!=="scanner"))return s.kind==="auto"?uo(s):ln(s)}function tl(s){if(!s)return{x:80,y:80};if(s.type==="conveyor"){let a=Z(s.id);return F(a.col,a.row)}return s.type==="eggFarm"?F(s.col,s.row):s.type==="scanner"?ye(s):s.type==="facility"?{x:s.x+s.w/2,y:s.y+10}:{x:80,y:80}}function fo(s){let a=n.getBoundingClientRect(),h=tl(s),m=e.view?.scale||1,w=a.left+(h.x*m+(e.view?.x||0))/n.width*a.width+18,T=a.top+(h.y*m+(e.view?.y||0))/n.height*a.height-12,te=Math.max(12,window.innerWidth-274),j=Math.max(12,window.innerHeight-220);t.modal.style.setProperty("--popover-x",`${Math.max(12,Math.min(te,w))}px`),t.modal.style.setProperty("--popover-y",`${Math.max(12,Math.min(j,T))}px`)}function nl(){let s=N();if(!s)return;let a=Cr(s);t.modalTitle.textContent=J(s),t.modalBody.innerHTML=` -
${a.map(w=>`

${w}

`).join("")}
- ${["mixer","truck"].includes(s.baseId||s.id)?'

Income/Fine = ceil(base x 1.10^upgrades)

':""}`,t.modalActions.innerHTML="",s.type==="scanner"&&s.kind==="auto"&&t.modalActions.appendChild(Ve("Auto Menu",()=>uo(s),"facility-action warn")),s.type==="scanner"&&s.kind==="manual"&&t.modalActions.appendChild(Ve("Set Keys",()=>ln(s),"facility-action warn"));let h=s.type==="conveyor"?{type:"conveyor",oldKey:s.id,ref:s}:{type:s.type,ref:s},m=Ae(h);if(m){let w=Ve(m,()=>{},"facility-action danger disabled");w.disabled=!0,t.modalActions.appendChild(w)}else{let w=ht(h,e),T=w.sameBuild?`Remove / Refund ${g(w.amount)}`:`Sell ${g(w.amount)}`;t.modalActions.appendChild(Ve(T,()=>{mr(),sn()},"facility-action danger"))}fo(s),t.modal.classList.add("visible","equipment-popover")}function ol(s){e.phase==="build"&&(y(),e.buildTool=e.buildTool===s?null:s,e.selected=null,e.multiSelected=[],e.selectionBox=null,i())}function rl(){let s=[];for(let[a,h]of Object.entries(e.facilities))if(s.push({id:`facility:${a}`,price:Q({type:"facility",ref:h}),x:h.x,y:h.y,w:h.w,h:h.h}),h.entry){let m=F(h.entry.col,h.entry.row);s.push({id:`facilityPort:${a}`,price:Q({type:"facility",ref:h}),x:m.x-18,y:m.y-18,w:36,h:36})}for(let a of e.maintenanceRooms||[]){let h=K(a);s.push({id:`maintenanceRoom:${a.id}`,price:Q({type:"maintenanceRoom",ref:a}),x:h.x-f.cell,y:h.y-f.cell,w:f.cell*2,h:f.cell*2})}for(let a of e.eggFarms){let h=F(a.col,a.row);s.push({id:`eggFarm:${a.id}`,price:Q({type:"eggFarm",ref:a}),x:h.x-24,y:h.y-24,w:48,h:48})}for(let a of e.scanners){let h=ye(a);s.push({id:`scanner:${a.id}`,price:Q({type:"scanner",ref:a}),x:h.x-50,y:h.y-73,w:100,h:146})}for(let a of e.conveyorTiles){let h=Z(a),m=F(h.col,h.row),w=e.conveyorMeta.get(a)||{};s.push({id:`conveyor:${a}`,price:w.price||Oe(w.kind==="boostConveyor"?"boostConveyor":"conveyor",e),x:m.x-22,y:m.y-22,w:44,h:44})}return s}function il(s){return R[s]||R.random}function Hc(s){return Sn(s)}function wr(s){return e.conveyorTiles.has(s)?Te(Z(s)):!1}function Sr(s){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return null;for(let a of e.conveyorTiles){if(!wr(a))continue;let h=Z(a),m=F(h.col,h.row),w=m.x-B.w/2,T=m.y+B.y-B.h/2;if(s.x>=w&&s.x<=w+B.w&&s.y>=T&&s.y<=T+B.h)return a}return null}function sl(s){let a=Sr(s);return a?(kr(a),!0):!1}function kr(s){let a=e.conveyorMeta.get(s);if(!a)return!1;let h=ro(s);if(h.length<2)return!1;Be(e);let m=E.includes(a.branchMode)?a.branchMode:"random",w=["random",...de.map(T=>T.name).filter(T=>h.includes(T))];return a.branchMode=w[(Math.max(0,w.indexOf(m))+1)%w.length],e.selected=null,e.multiSelected=[],i(),!0}function Cr(s){Se(e);let a=[],h=s?.type==="facility"?s.baseId||s.id:"";if(s.type==="eggFarm"){let[m,w]=dn(s);a.push(`Price: ${g(Q(s))}`);{let T=Ae({type:s.type,ref:s});a.push(T?`Sale: blocked (${T})`:`Sale value: ${g(ht({type:s.type,ref:s},e).amount)}`)}a.push(`Level: ${s.level}/4`),a.push(`Random interval: ${m.toFixed(2)}-${w.toFixed(2)}s`),a.push(`Durability: ${bn(s)}% | Spawn delay x${Hn(s).toFixed(2)}`)}else if(s.type==="scanner")a.push(`Price: ${g(Q(s))}`),a.push(`Sale value: ${g(ht({type:s.type,ref:s},e).amount)}`),a.push(`Type: ${s.kind.toUpperCase()} / Standard`),s.kind==="auto"&&a.push(`Role: ${s.role===0?"Male left / Others right":"Poop left / Others right"}`),a.push(`Queue: ${s.queue.length}`),s.kind==="auto"&&a.push(`Cooldown: ${s.cooldown.toFixed(1)}s / ${nt(s,e).toFixed(1)}s`),s.kind==="auto"&&a.push(`Durability: ${bn(s)}% | Delay x${Kn(s).toFixed(2)}`),s.kind==="manual"&&a.push("Durability: none | Always normal");else if(s.type==="conveyor"){let m=e.conveyorMeta.get(s.id),w=e.componentLookup?.get(s.id),T=w?e.congestion.get(w):null;a.push(`Price: ${g(Q({type:"conveyor",oldKey:s.id,ref:s}))}`),a.push(`Cell: ${s.id}`),a.push(`Type: ${m?.kind==="boostConveyor"?"BOOST BELT":"Normal Belt"} | Speed x${Number(m?.speedMultiplier||1).toFixed(1)}`),a.push(`Congestion: ${T?Math.floor(T.ratio*100):0}%`),a.push(`Durability: ${bn({meta:m})}% | Speed x${Wn({meta:m}).toFixed(2)}`),wr(s.id)?(a.push(`Branch mode: ${il(m?.branchMode||"random")}`),a.push("Use the Branch button below or the on-belt branch badge.")):a.push("Branch mode: needs 3+ conveyor connections."),a.push(`Sale value: ${g(ht({type:"conveyor",oldKey:s.id,ref:s},e).amount)}`)}else if(s.type==="maintenanceRoom")a.push(`Price: ${g(Q({type:"maintenanceRoom",ref:s}))}`),a.push(`Sale value: ${g(ht({type:"maintenanceRoom",ref:s},e).amount)}`),a.push("Size: 2\xD72 grid cells"),a.push("Dispatch: 1 repairman during each production day");else if(s.type==="facility"){a.push(`Price: ${g(Q(s))}`);{let m=Ae({type:s.type,ref:s});a.push(m?`Sale: blocked (${m})`:`Sale value: ${g(ht({type:s.type,ref:s},e).amount)}`)}if(a.push(["mixer","truck","trash"].includes(s.id)?`Level: ${s.level} / no cap`:`Level: ${s.level}`),h==="truck"&&a.push("Durability: none | Always normal"),["mixer","trash"].includes(h)&&a.push(`Durability: ${bn(s)}% | Extra delay ${Jo(e,s).toFixed(2)}s`),h==="mixer"&&(a.push(`Income: ${g(ze(e))} per chick | upgrade x${pt(e,"mixer").toFixed(3)}`),a.push(`Poop fine: -${g(pn(e))}`)),h==="truck"&&(a.push(`Income: ${g(Fe(e))} per target cargo | upgrade x${pt(e,"truck").toFixed(3)}`),a.push(`Poop shipment fine: -${g(yn(e))}`)),h==="trash"){let m=$t(e),w=yt(m);a.push(`Bonus cards: ${m}/${Vt()}`),a.push(`Poop income bonus: ${g(w)} per processed poop.`),a.push("With enough upgrades, poop can out-earn male/female routes.")}s.entry&&a.push(`Receiver: edge cell ${s.entry.col},${s.entry.row} (${s.side})`)}return a}function ll(s){if(!s||e.phase!=="build")return"";let a=Fn(e).find(h=>h.type===s.type&&h.id===s.id);return a?a.message||"Not connected to conveyor route":""}function al(s){return s?s.type==="conveyor"&&e.conveyorMeta.get(s.id)?.kind==="boostConveyor"?"Moves chicks twice as fast. Wears down like a normal belt.":s.type==="conveyor"?"A stubborn belt tile. It only cares about the next cell.":s.type==="eggFarm"?"A tiny gatehouse producing questionable eggs on schedule.":s.type==="scanner"&&s.kind==="auto"?"Slower than hands without upgrades.":s.type==="scanner"?"A manual checkpoint. The operator is the algorithm.":s.type==="facility"&&(s.baseId||s.id)==="mixer"?"Male chicks become revenue here. Do not feed it poop.":s.type==="facility"&&(s.baseId||s.id)==="trash"?"Poop goes in. Sometimes coins come out, for reasons best left unaudited.":s.type==="facility"&&(s.baseId||s.id)==="truck"?"The shipping endpoint. Correct cargo pays; wrong cargo complains.":s.type==="maintenanceRoom"?"A 2\xD72 repair bay. One room dispatches one repairman per day.":"Factory equipment.":""}return{buildAtCell:b,buildAtPoint:C,eraseAtPoint:Gt,equipmentAtPoint:co,startSelectionBox:Ut.startSelectionBox,updateSelectionBox:Ut.updateSelectionBox,finishSelectionBox:Ut.finishSelectionBox,startGroupDrag:Ut.startGroupDrag,updateGroupDrag:Ut.updateGroupDrag,finishGroupDrag:Ut.finishGroupDrag,selectedObject:N,selectedTitle:J,equipmentPrice:Q,selectedUpgradeCost:Qs,selectedInfoLines:Cr,flavorText:al,disconnectedWarningFor:ll,gridExpansionCost:O,buyGridExpansion:le,expansionOfferAtPoint:he,beginConveyorDrag:ao,continueConveyorDrag:d,endConveyorDrag:y,cycleSingleConveyorDirection:Ct,branchSwitcherAtPoint:Sr,cycleBranchModeAtPoint:sl,cycleBranchModeForKey:kr,removeSelected:mr,switchScannerRole:el,showManualScannerMenu:ln,showAutoScannerMenu:uo,showSelectedMenu:nl,setBuildTool:ol,fail:_,isEquipmentCell:D,equipmentHitBoxes:rl,routeFromFarmToScanner:It}}function Ds({game:e,ui:t,build:n,startGame:o,beginCardDraft:r,activeQueuedChick:i}){function l(D){return String(D).replace(/[&<>"']/g,U=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[U])}function c(){return Math.round(Vn(e))}function v(){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return!1;let D=!1;for(let U of vo)if(D=!0,e.cash>=Oe(U,e))return!1;return D}function x(){E(),R(),ee(),O(),B()}function E(){for(let[U,S]of Object.entries(t.buttons))S?.classList?.contains("tool-button")&&S.classList.toggle("active",e.buildTool===U);for(let U of vo){let S=t.buttons[U];if(!S)continue;let M=Oe(U,e),N=S.querySelector("span");N&&(N.textContent=U==="conveyor"||U==="boostConveyor"?`${g(M)} / tile`:g(M));let J=U==="manualScanner"&&e.scanners.filter(pe=>pe.kind==="manual").length>=8,Q=e.cashIt(e,J)?.scannerId).length,U=fn(e),S=Math.max(0,Math.floor(e.lastResult?.profit??e.stats?.profit??0)),M=Math.max(1,Number(e.turn)||1),N=On(e,M,S);t.turnSummary.innerHTML=[`Seed: ${l(e.runSeed||"none")} | Grid box: ${e.gridRows||10}x${e.gridCols||20} | Owned: ${e.gridOwnedCells||e.ownedCells?.size||(e.gridRows||10)*(e.gridCols||20)} cells | Blocked: ${e.blockedCells?.size||0} cells`,`Truck target: ${je(e).toUpperCase()} | Male fine: -${g(_o(e))}`,`Poop fine: Mixer -${g(pn(e))} / Shipment -${g(yn(e))}`,`Fairies tribute on Next Day: -${g(N.amount)} | base ${g(N.base)} + profit share ${g(N.profitTribute)} | basis net ${g(S)} | exemption ${g(N.profitExemption)}${N.reduction?` | reduction -${g(N.reduction)}`:""}`,`Maintenance: worst ${tr(e).worst.percent}% dirty (${tr(e).worst.label}) | Repair rooms: ${(e.maintenanceRooms||[]).length} | Repairmen: ${(e.repairmen||[]).length}`,`Manual combo: ${e.manualCombo?.count||0} | Card draft: ${e.cardDraft?.pending?Math.max(1,e.cardDraft.picksRemaining||1)+" pick(s) left":"ready after each day"} | Belt: ${c()}px/s | Farms with scanner route: ${D}/${e.eggFarms.length}`,e.cardEffects?.usedMachineActive?'Procurement: USED MACHINE MODE / no refunds / 60% durability':"",U.length?`Blocked: ${U[0]}`:`${oe.status.allPortsConnected}`].join("
")}function ee(){if(!t.eventPanel)return;let D=e.eventOffer;if(e.phase!=="build"){t.eventPanel.innerHTML=oe.status.eventPanelRunning;return}if(!D){t.eventPanel.className="event-card empty",e.turn+1Event lock active.No irregular events during Days 1-7. First possible forced event: Day ${gt}.`:t.eventPanel.innerHTML="No event.Random forced events can appear later.";return}t.eventPanel.className="event-card accepted",t.eventPanel.innerHTML=` -
FORCED NEXT DAY
-

${D.title}

-
- Effect: ${D.route} - ${D.targetAmount?`Target: ${D.targetAmount}`:"Target: none"} - ${D.reward?`Reward: ${g(D.reward)}`:"Reward: none"} - Time ${D.daySeconds||60}s / Output x${Number(D.productionMultiplier||1).toFixed(2)} / Poop +${Math.round((D.poopRateAdd||0)*100)}pt -
`}function X(){E(),t.shell.classList.toggle("phase-running",e.phase==="running"),t.shell.classList.toggle("phase-build",e.phase==="build"),t.shell.classList.toggle("phase-gameover",e.phase==="gameover"),t.shell.classList.toggle("phase-title",e.phase==="title"),t.shell.classList.toggle("phase-loanDecision",e.phase==="loanDecision"),t.money.textContent=g(e.cash),t.money.classList.toggle("cash-negative",e.cash<0),t.money.classList.toggle("cash-positive",e.cash>an),t.turn.textContent=e.turn,t.timeLeft.textContent=e.phase==="running"&&e.timeLeft<=0&&e.shutdownTimeLeft>0?`+${e.shutdownTimeLeft.toFixed(1)}s`:`${Math.max(0,e.timeLeft).toFixed(1)}s`,t.timeLeft.closest?.(".hud-card")?.classList.toggle("time-critical",e.phase==="running"&&(e.timeLeft<=10||e.timeLeft<=0&&e.shutdownTimeLeft>0)),t.phase.textContent=he(),t.comboCount&&(t.comboCount.textContent=e.manualCombo?.count||0),ae(),t.turnProfit.textContent=g(e.stats.profit),t.turnProfit.classList.toggle("cash-negative",e.stats.profit<0),t.turnProfit.classList.toggle("cash-positive",e.stats.profit>0),t.mixerCount.textContent=e.stats.mixerCount,t.truckFemaleCount.textContent=e.stats.truckFemale,t.truckMaleCount.textContent=e.stats.truckMale,t.poopCount.textContent=e.stats.poopSpawned,t.buttons.s1Left.disabled=e.phase!=="running"||!i(0),t.buttons.s1Right.disabled=e.phase!=="running"||!i(0),t.buttons.s2Left.disabled=e.phase!=="running"||!i(1),t.buttons.s2Right.disabled=e.phase!=="running"||!i(1);let D=e.scanners.find(N=>N.kind==="manual"&&N.slot===0),U=e.scanners.find(N=>N.kind==="manual"&&N.slot===1);D&&(t.buttons.s1Left.textContent=`S1 ${D.keys?.left?.label||"A"} -> Mixer`,t.buttons.s1Right.textContent=`S1 ${D.keys?.right?.label||"D"} -> S2`),U&&(t.buttons.s2Left.textContent=`S2 ${U.keys?.left?.label||"Left"} -> Waste`,t.buttons.s2Right.textContent=`S2 ${U.keys?.right?.label||"Right"} -> Truck`);let S=Math.max(0,Math.floor(e.lastResult?.profit??e.stats?.profit??0)),M=On(e,Math.max(1,Number(e.turn)||1),S).amount;t.buttons.nextTurn.textContent=e.phase==="build"&&M>0?`Next Day - Fairies ${g(M)}`:oe.actions.nextDay,t.buttons.nextTurn.disabled=e.phase!=="build"||!!e.cardDraft?.pending||!!e.cardTargetPick?.pending||!fi(e)}function ae(){if(!t.eventBrief||!t.targetBrief||!t.speedBrief)return;let D=je(e).toUpperCase();t.targetBrief.textContent=`TRUCK TARGET: ${D}`,t.speedBrief.textContent=`BELT: ${c()} px/s | COMBO: ${e.manualCombo?.count||0}`,t.speedBrief.title=`Conveyor speed does not increase by day. Degraded belts reduce speed. Cap: ${Wt}px/s.`;let U=e.eventActive,S=e.eventOffer;U?(t.eventBrief.textContent=`ACTIVE EVENT: ${U.title} | ${U.route}`,t.eventBrief.className="event-brief active"):e.phase==="build"&&S?(t.eventBrief.textContent=`NEXT DAY EVENT: ${S.title} | ${S.route}${S.targetAmount?` | Target ${S.targetAmount}`:""}${S.reward?` | Reward ${g(S.reward)}`:""}`,t.eventBrief.className="event-brief next"):e.phase==="build"&&e.turn+1
\u2642Male->MixerS1: A
\u2640Female->TruckS1: D, then S2: right
\u{1F4A9}Poop->ShredderS1: D, then S2: left

Build phase: connect at least one EGG through a scanner to Mixer, Shredder, or Truck before Next Day. One day is one run.

',t.modalActions.innerHTML="",t.modalActions.appendChild(G(oe.actions.startGame,o,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function le(D){let U=J=>`${J>0?"+":""}${g(J)}`,S=J=>`${J>0?"-":""}${g(J)}`,M=D.profit>=0?"cash-positive":"cash-negative",N=(D.mixerPoopFine||0)+(D.truckPoopFine||0)+(D.maleTruckFine||0)+(D.explosionDamage||0)+(D.cardRerollCost||0);t.modalTitle.textContent=`Day ${D.turn} Settlement`,t.modalBody.innerHTML=` -
Net result${g(D.profit)}
-
-
Chick shipment income${U(D.chickShipmentIncome||0)}
-
Poop shipment income${U(D.poopShipmentIncome||0)}
-
Mixer income${U(D.mixerRevenue||0)}
-
Composter income${U(D.composterIncome||0)}
-
DUD refund income${U(D.dudRefundIncome||0)}
-
Manual combo bonus${U(D.manualComboBonus||0)}
-
Chemical subsidy${U(D.chemicalWeaponSubsidy||0)}
-
Event bonus${U(D.eventBonus||0)}
-
Penalties${S(N)}
-
Fairies fee${S(D.fairiesTribute?.amount||D.fairiesTribute||0)}
-
-

Income ${g(D.revenue)} - losses ${g(D.penalty)} = ${g(D.profit)}

`,t.modalActions.innerHTML="",t.modalActions.appendChild(G("Choose Upgrade Card",r||q,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function se(D,U){let S=Math.max(0,e.cardEffects?.rescueLoanCharges||0);t.modalTitle.textContent="Emergency Loan Available",t.modalBody.innerHTML=` -

End-of-day cash is below ${g(0)}.

-
-
Current money${g(e.cash)}
-
Emergency Loan+${g(500)}
-
Cards remaining${S}
-
-

Use one Emergency Loan to gain ${g(500)} immediately. If cash is still negative, another decision will be shown if another card remains.

`,t.modalActions.innerHTML="",t.modalActions.appendChild(G("Accept Game Over",U,"facility-action danger")),t.modalActions.appendChild(G("Use Emergency Loan",D,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function A(){let D=e.totals.processed,U=D?Math.round(e.totals.correct/D*100):0,S=Oi(e);t.modalTitle.textContent=oe.phases.gameover,t.modalBody.innerHTML=`

Your cash went negative.

-
Final Score${S.score}
Survival${e.totals.turnsCompleted} days
Final Cash${g(e.cash)}
Accuracy${U}%
-
Score breakdown -
Formula
Base = Cash + Total revenue + Factory value \xD70.5 + Event bonus \xD70.5 = ${g(S.base)}
Daily earned = ceil(Base \xF7 Days) = ${g(S.dailyEarned)}
Score = max(0, floor(Base + Daily earned + Correct bonus - Total outflow - Day penalty)) = ${S.score}
-
Factory Value${g(S.factoryValue)}
Total Revenue${g(e.totals.revenue)}
Daily Earned${g(S.dailyEarned)} / day
Total Outflow${g(e.totals.penalty)}
Fairies Tribute${g(e.totals.fairiesTribute||0)}
Correct Sorts${e.totals.correct}
Auto Sorted${e.totals.autoSorted}
Poop Control${e.totals.poopTrash} trashed / ${e.totals.poopTruck} shipped / ${e.totals.poopMixer} mixer
Explosion Penalty${g(e.totals.explosionDamage)}
Event Bonus${g(e.totals.eventBonus)}
Day Penalty-${S.dayPenalty}
Events${e.totals.eventSuccess} success / ${e.totals.eventFailed} failed
-
`,t.modalActions.innerHTML="",t.modalActions.appendChild(G(oe.actions.restart||"Restart",o,"primary-button restart-button")),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible","gameover-modal")}function G(D,U,S="primary-button"){let M=document.createElement("button");return M.type="button",M.className=S,M.textContent=D,M.addEventListener("click",U),M}function q(){t.modal.classList.remove("visible","equipment-popover","gameover-modal"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function me(){}return{updatePanels:x,updateUI:X,showTitle:ie,showTurnResult:le,showEmergencyLoanDecision:se,showGameOver:A,hideModal:q,checkGameOver:me}}function hr(e){e.totals.processed+=1}function Zt(e){e.stats.correct+=1,e.totals.correct+=1}function vt(e){e.stats.mistakes+=1,e.totals.mistakes+=1}function Fs(e){e.stats.autoSorted+=1,e.totals.autoSorted+=1}function Bs(e){e.stats.poopSpawned+=1}function Ls(e){e.stats.mixerCount+=1,hr(e)}function Os(e){e.stats.trashCount+=1,hr(e)}function Ns(e,t){t==="female"?e.stats.truckFemale+=1:t==="male"&&(e.stats.truckMale+=1),hr(e)}function Zn(e,t){let n=t==="truck"?"poopTruck":t==="trash"?"poopTrash":t==="mixer"?"poopMixer":null;n&&(e.stats[n]+=1,e.totals[n]+=1)}function _s({game:e,currentConveyorSpeed:t,onGameOverCheck:n}){function o(d){return Rt(d)*Hn(d)*us(e)/wi(e)}function r(d){let y=F(d.col,d.row),b=1+ds(e,d),C=l(d,b);if(!C.length)return i(d,y),!0;let k=0,P=0;for(let $ of C){let K=F($.col,$.row),re=c(K);if(re){re.stoppedTimer=.85,P+=1;continue}let Ne=As(e,{stage:"belt",scannerId:null,route:[K]});Ne.sex==="poop"&&Bs(e),e.chicks.push(Ne),Xi(e,d),k+=1}return k>0?(_i(e,y.x,y.y),k>1&&H(e,y.x,y.y-28,`x${k}`,p.green),!0):P===0}function i(d,y){(d.noRouteNoticeCooldown||0)<=0&&(H(e,y.x,y.y-24,"NO BELT: PAUSED",p.warn),d.noRouteNoticeCooldown=2.5)}function l(d,y){let C=de.map(k=>({col:d.col+k.dc,row:d.row+k.dr})).filter(k=>Ee(k.col,k.row)&&e.conveyorTiles.has(I(k.col,k.row))).map(k=>({p:k,blocked:B(null,F(k.col,k.row))?1:0,roll:Math.random()}));return C.sort((k,P)=>k.blocked-P.blocked||k.roll-P.roll),C.slice(0,Math.max(1,y||1)).map(k=>k.p)}function c(d){return e.chicks.find(y=>y.stage!=="flying"&&Math.hypot(y.x-d.x,y.y-d.y)0;if(e.timeLeft=Math.max(0,e.timeLeft-d),C&&e.timeLeft<=0&&y(),e.timeLeft<=0){e.shutdownTimeLeft>0&&(e.shutdownTimeLeft=Math.max(0,e.shutdownTimeLeft-d));for(let k of e.eggFarms)k.shutterProgress=Math.min(1,(k.shutterProgress||0)+d*2.8)}if(C&&e.timeLeft>0){for(let k of e.eggFarms)if(k.noRouteNoticeCooldown>0&&(k.noRouteNoticeCooldown=Math.max(0,k.noRouteNoticeCooldown-d)),k.nextSpawn-=d,k.nextSpawn<=0){let P=r(k);k.nextSpawn=P?o(k):.15,k.lastInterval=k.nextSpawn}}for(let k=e.chicks.length-1;k>=0;k-=1){let P=e.chicks[k];P.bob+=d*7,P.stoppedTimer>0&&(P.stoppedTimer=Math.max(0,P.stoppedTimer-d)),P.stage!=="queued"&&E(P,k,d)}_(d),_t(),on(),e.timeLeft<=0&&(e.chicks.length===0?b():e.shutdownTimeLeft<=0&&x())}function x(){if(e.cleanupBlown)return;e.cleanupBlown=!0,e.cleanupTimer=1;let d=[...e.chicks];for(let y of d)Ko(e,y.sex,y.x,y.y,-Math.PI/2,!0);e.chicks=[];for(let y of e.scanners)y.queue=[];if(_t(),d.length){let y=d.reduce((C,k)=>C+k.x,0)/d.length,b=d.reduce((C,k)=>C+k.y,0)/d.length;Xe(e,y,b,p.warn,58),H(e,y,b-24,"CLEANUP",p.warn)}}function E(d,y,b){if(R(d)){d.stoppedTimer=.35;return}if(pe(d,b),!(d.route&&d.targetIndex=d.route.length)return!1;let y=d.route[d.targetIndex];return B(d,y)}function B(d,y){if(!y)return!1;for(let b of e.chicks)if(!(d&&b.id===d.id)&&b.stage!=="flying"&&Math.hypot(b.x-y.x,b.y-y.y)1)&&d.push({x:y.x,y:y.y})}function ee(d){let y=e.conveyorMeta?.get?.(d)||{},b=[];Array.isArray(y.outDirs)&&b.push(...y.outDirs),y.dir&&b.push(y.dir);let C=[...new Set(b)].filter(re=>de.some(Ne=>Ne.name===re)),k=Z(d),P=de.filter(re=>A(k,re.name)).map(re=>re.name),$=C.filter(re=>P.includes(re)),K=P;return $.length?$:K}function X(d){return de.find(y=>y.name===d)||null}function ae(d,y){return e.scanners.find(b=>b.col<=d&&d<=b.col+1&&b.row-1<=y&&y<=b.row+1)||null}function he(d,y){let b=X(y);if(!b)return null;let C=ae(d.col+b.dc,d.row+b.dr);if(!C)return null;let k=Re(C,"inputA");return k&&k.col===d.col&&k.row===d.row?C:null}function ie(d){return Object.entries(e.facilities||{}).find(([,y])=>y?.entry&&y.entry.col===d.col&&y.entry.row===d.row)||null}function le(d){return d?.baseId||d?.id||""}function se(d,y){return d.side==="left"&&y==="left"||d.side==="right"&&y==="right"||d.side==="top"&&y==="up"||d.side==="bottom"&&y==="down"}function A(d,y){let b=X(y);if(!b)return null;let C={col:d.col+b.dc,row:d.row+b.dr};if(Ee(C.col,C.row)&&e.conveyorTiles.has(I(C.col,C.row)))return{type:"conveyor",dirName:y,target:F(C.col,C.row),nextCell:C};let k=he(d,y);if(k)return{type:"scanner",dirName:y,target:ye(k),scanner:k};let P=ie(d);return P&&se(P[1],y)?{type:"facility",dirName:y,facilityId:P[0],facility:P[1],target:F(d.col,d.row)}:null}function G(d,y){let b=X(y);if(!b)return!1;let C=e.conveyorMeta?.get?.(I(d.col+b.dc,d.row+b.dr));return C?[...new Set([...Array.isArray(C.outDirs)?C.outDirs:[],C.dir].filter(Boolean))].includes(b.opposite):!1}function q(d){return de.filter(y=>Ee(d.col+y.dc,d.row+y.dr)&&e.conveyorTiles.has(I(d.col+y.dc,d.row+y.dr))).map(y=>y.name)}function me(d,y,b="random"){let C=q(d);if(C.length<3)return y;let k=new Set(C.filter(K=>G(d,K)));if(b&&b!=="random"&&b!=="pass"&&C.includes(b)){let K=new Set(k);K.add(b),C.filter(re=>!K.has(re)).length>=2&&k.add(b)}let P=C.filter(K=>!k.has(K));if(P.length)return P;let $=y.filter(K=>!k.has(K));return $.length?$:y}function D(d,y){return y&&(y.type==="facility"||!B(d,y.target))}function U(d,y,b,C="random"){let k=b.map(re=>A(y,re)).filter(Boolean);if(!k.length)return null;let $=k.filter(re=>re.type!=="facility").filter(re=>!B(d,re.target)),K=$.length?$:k.filter(re=>re.type==="facility");return K.length?K[Math.floor(Math.random()*K.length)]:null}function S(d,y){let b=[];O(b,{x:d.x,y:d.y}),O(b,y),d.route=b.length?b:[{x:d.x,y:d.y}],d.targetIndex=d.route.length>1?1:d.route.length}function M(d,y){let b=Ke(d.x,d.y);if(!b)return xt(y,"OFF GRID");let C=I(b.col,b.row);if(!e.conveyorTiles.has(C))return xt(y,"OFF BELT");let k=e.conveyorMeta?.get(C)||{},P=me(b,ee(C),k.branchMode||"random");if(!P.length){d.stoppedTimer=.25;return}let $=U(d,b,P,k.branchMode||"random");if(!$){d.stoppedTimer=.25;return}if($.type==="facility"){let K=le($.facility);K==="mixer"?io(y,$.facility):K==="truck"?kn(y,$.facility):K==="trash"?so(y,$.facility):xt(y,"DONE");return}$.type==="scanner"&&(d.pendingScannerId=$.scanner.id),d.prevConveyorCell=C,S(d,$.target)}function N(d){let y=Ke(d.x,d.y);if(!y)return null;let b=I(y.col,y.row);return e.conveyorTiles.has(b)?b:null}function J(d){let y=N(d)||N(d.route?.[d.targetIndex]||d);return t(y)}function Q(d,y){let b=N(y);!b||d.lastWearKey===b||(d.lastWearKey=b,zi(e,b))}function pe(d,y){let b=J(d)*y;for(;b>0&&d.targetIndex=$?(d.x=C.x,d.y=C.y,Q(d,C),d.targetIndex+=1,b-=$):(d.x+=k/$*b,d.y+=P/$*b,b=0)}}function ge(d,y,b){d.stage="queued",d.route=null,d.queueRoute=b?b.map(C=>({x:C.x,y:C.y})):[ye(y)],d.scannerId=y.id,y.queue.includes(d.id)||y.queue.push(d.id),Pe(y)}function Pe(d){d.queue=d.queue.filter(b=>e.chicks.some(C=>C.id===b&&C.stage==="queued"));let y=f.cell*.86*fs(e);d.queue.forEach((b,C)=>{let k=e.chicks.find(P=>P.id===b);k&&(Ae(k,k.queueRoute||[ye(d)],C*y),k.queueIndex=C)})}function Ae(d,y,b){if(!y||!y.length)return;if(y.length===1||b<=0){let P=y[y.length-1];d.x=P.x,d.y=P.y;return}let C=b;for(let P=y.length-1;P>0;P-=1){let $=y[P-1],K=y[P],re=Math.hypot(K.x-$.x,K.y-$.y);if(C<=re){let Ne=1-C/re;d.x=$.x+(K.x-$.x)*Ne,d.y=$.y+(K.y-$.y)*Ne;return}C-=re}let k=y[0];d.x=k.x,d.y=k.y}function _(d){for(let y of e.scanners){if(y.cooldown>0&&(y.cooldown=Math.max(0,y.cooldown-d)),y.keyPressTime>0&&(y.keyPressTime=Math.max(0,y.keyPressTime-d)),Pe(y),y.kind!=="auto"||y.cooldown>0||!y.queue.length)continue;let b=y.queue[0],C=e.chicks.findIndex(k=>k.id===b);if(C<0){y.queue.shift();continue}nn(C,Ao(y,e.chicks[C]),!0)&&(Qi(e,y),y.cooldown=nt(y,e),Fs(e))}}function Ie(d){let y=To(e,d);return!y||!y.queue.length?null:e.chicks.find(b=>b.id===y.queue[0])||null}function qe(d,y){if(e.phase!=="running")return;let b=To(e,d);Ye(b,y)}function Ye(d,y){if(e.phase!=="running"||!d||d.kind!=="manual"||(d.keyPressTime=.18,d.keyPressSide=y,!d.queue.length))return;let b=e.chicks.findIndex(C=>C.id===d.queue[0]);b>=0&&nn(b,y,!1)}function Te(d,y,b){return d.kind==="manual"&&Ao(d,y)===b}function kt(d){let y=e.manualCombo?.count||0;if(e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=0,e.manualCombo.lastBonus=0,e.stats.manualComboFailure=(e.stats.manualComboFailure||0)+1,e.totals.manualComboFailure=(e.totals.manualComboFailure||0)+1,y>=10){let b=ye(d);Ft(e,10,.25),H(e,b.x,b.y-36,"COMBO RESET",p.danger)}}function oo(d){e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=Math.max(0,e.manualCombo.count||0)+1,e.stats.manualComboSuccess=(e.stats.manualComboSuccess||0)+1,e.totals.manualComboSuccess=(e.totals.manualComboSuccess||0)+1;let y=e.manualCombo.count;if(e.manualCombo.lastBonus=0,y<10)return 0;let b=Math.max(1,Math.floor(y/10)),C=e.scanners.filter(K=>K.kind==="manual").length,k=Math.min(1,(20+C*10)/100),P=0;for(let K=0;K0){Ge(e,$),e.stats.manualComboBonus=(e.stats.manualComboBonus||0)+$,e.totals.manualComboBonus=(e.totals.manualComboBonus||0)+$,e.manualCombo.lastBonus=$;let K=ye(d);H(e,K.x,K.y-42,`COMBO +${g($)}`,p.green)}return $}function Sn(d,y){let b=Re(d,y);if(!b)return null;let C=I(b.col,b.row);if(e.conveyorTiles.has(C))return{...b};let P=(_e(e).scannerPorts.get(d.id)?.[y]?.keys||[]).filter(Boolean);if(!P.length)return null;let $=P.map(Z);return $.find(re=>re.col===b.col&&re.row===b.row)||$[0]||null}function ro(d,y,b,C){let k=[];O(k,{x:d.x,y:d.y});let P=Re(y,b);return P&&O(k,F(P.col,P.row)),O(k,F(C.col,C.row)),k}function nn(d,y,b){let C=e.chicks[d];if(!C||C.stage!=="queued")return!1;let k=At(e,C.scannerId);if(!k)return!1;let P=Sn(k,y);if(!P)return!b&&k.kind==="manual"&&kt(k),H(e,C.x,C.y-16,y==="left"?"NO LEFT BELT":"NO RIGHT BELT",p.danger),!1;!b&&k.kind==="manual"&&(Te(k,C,y)?oo(k):kt(k)),k.queue=k.queue.filter(K=>K!==C.id),C.stage="belt",C.route=ro(C,k,y,P),C.targetIndex=C.route.length>1?1:C.route.length,C.scannerId=null,C.nextScannerId=null,C.pendingScannerId=null,C.queueRoute=null,C.queueIndex=-1;let $=b?p.green:y==="left"?p.mixerBlue:p.truckPink;return Gi(e,ye(k).x,ye(k).y,$),H(e,C.x,C.y-20,b?"AUTO":y.toUpperCase(),$),!0}function Ct(d){let y=e.chicks[d];return y?(e.chicks.splice(d,1),y):null}function io(d,y=e.facilities.mixer){if(y?.processingCooldown>0){let $=e.chicks[d];$&&($.stoppedTimer=.25);return}let b=Ct(d);if(!b)return;let{x:C,y:k}=b;if(Ls(e),jo(e,y),Zo(e,y),b.sex==="poop"){let $=Ai(e);Zn(e,"mixer"),vt(e),Wi(e,C,k),H(e,C,k-18,`-${g($)}`,p.danger);return}let P=Pi(e);b.sex==="male"?Zt(e):vt(e),Ui(e,C,k),H(e,C,k-18,`+${g(P)}`,p.green)}function kn(d,y=e.facilities.truck){let b=Ct(d);if(!b)return;let{x:C,y:k}=b;lo(b.sex,y),Hi(e,C,k,b.sex),Ns(e,b.sex);let P=je(e),$=ki(e,b.sex);if(b.sex==="poop"){if(Zn(e,"truck"),$)Zt(e),H(e,C,k-18,`+${g(Fe(e))}`,p.green);else{let K=Ii(e);vt(e),H(e,C,k-18,`-${g(K)}`,p.danger)}return}if(b.sex==="female"){$?(Zt(e),H(e,C,k-18,`+${g(Fe(e))}`,p.green)):(vt(e),H(e,C,k-18,P==="male"?"REJECT":"NO SALE",p.warn));return}if($){Zt(e),H(e,C,k-18,`+${g(Fe(e))}`,p.green);return}if(Ci(e)){let K=$i(e);vt(e),H(e,C,k-18,`-${g(K)}`,p.danger)}else vt(e),H(e,C,k-18,"REJECT",p.warn)}function so(d,y=e.facilities.trash){if(y?.processingCooldown>0){let K=e.chicks[d];K&&(K.stoppedTimer=.25);return}let b=Ct(d);if(!b)return;let{x:C,y:k}=b;Ki(e,C,k,b.sex),Os(e),jo(e,y),Zo(e,y);let P={amount:0},$="";if(b.sex==="poop"){P=Ti(e),$=P.amount>0?` +${g(P.amount)}`:"",Zn(e,"trash"),Zt(e);let K=Math.ceil(Math.max(0,Number(e.cardEffects?.composter)||0)*3*Bn(e));if(K>0){let re=Ge(e,K);e.stats.composterIncome=(e.stats.composterIncome||0)+re,e.totals.composterIncome=(e.totals.composterIncome||0)+re,H(e,C,k-36,`COMPOST +${g(re)}`,p.green)}H(e,C,k-18,`CLEAN${$}`,P.amount>0?p.green:p.green)}else vt(e),H(e,C,k-18,P.amount>0?`WASTE${$}`:"WASTE",P.amount>0?p.green:p.ink)}function xt(d,y){let b=Ct(d);b&&H(e,b.x,b.y-12,y,p.muted)}function lo(d,y=e.facilities.truck){let b=y||e.facilities.truck;b&&(e.truckCargo.push({sex:d,x:W(22,b.w-22),y:W(66,b.h-24)}),e.truckCargo.length>45&&e.truckCargo.shift())}function Cn(d){let y=Ke(d.x,d.y);if(y){let P=I(y.col,y.row);if(e.conveyorTiles.has(P))return P}let b=ai(e,d.x,d.y);if(!b)return null;let C=Z(b),k=F(C.col,C.row);return Math.hypot(d.x-k.x,d.y-k.y)<=f.cell*.55?b:null}function _t(){let{components:d,cellToComponent:y}=li(e);for(let b of e.chicks){if(b.stage==="flying")continue;let C=Cn(b);if(!C)continue;let k=y.get(C),P=d.get(k);P&&(P.count+=1)}for(let b of d.values())b.ratio=b.count/b.capacity;e.congestion=d,e.componentLookup=y}function on(){for(let d of e.congestion.values()){let y=Oo(e),b=xi(e);if(d.ratio>b&&d.ratio=y){let C=rn(d.id);if(!C.length||C.some($=>$.stage!=="queued"&&$.stoppedTimer<=.2))continue;let k=e.lastExplodedComponent.get(d.id)||0,P=performance.now();P-k>900&&(e.lastExplodedComponent.set(d.id,P),ao(d))}}}function rn(d){return e.chicks.filter(y=>{let b=Cn(y);return b&&e.componentLookup?.get(b)===d})}function ao(d){let y=rn(d.id);if(!y.length)return;for(let k of y)Ko(e,k.sex,k.x,k.y);e.chicks=e.chicks.filter(k=>!y.some(P=>P.id===k.id));for(let k of e.scanners)k.queue=k.queue.filter(P=>e.chicks.some($=>$.id===P));for(let k of d.cells){let P=Z(k),$=F(P.col,P.row);Xe(e,$.x,$.y,p.danger),Ze(e,$.x,$.y,6),Nn(e,$.x,$.y,4)}Ft(e,18,.75);let b=Z(d.cells[0]),C=F(b.col,b.row);e.stats.explosions=(e.stats.explosions||0)+1,e.totals.explosions=(e.totals.explosions||0)+1,H(e,C.x,C.y-22,`${Math.round(Oo(e)*100)}% JAM EXPLOSION`,p.danger)}return{activeQueuedChick:Ie,currentSpawnDelay:o,sortSlot:qe,updateCongestion:_t,sortScanner:Ye,updateRunning:v}}var fe=document.getElementById("gameCanvas"),vc=fe.getContext("2d"),L={shell:document.getElementById("gameShell"),money:document.getElementById("money"),turn:document.getElementById("turn"),timeLeft:document.getElementById("timeLeft"),phase:document.getElementById("phaseLabel"),comboCount:document.getElementById("comboCount"),eventBrief:document.getElementById("eventBrief"),targetBrief:document.getElementById("targetBrief"),speedBrief:document.getElementById("speedBrief"),turnProfit:document.getElementById("turnProfit"),mixerCount:document.getElementById("mixerCount"),truckFemaleCount:document.getElementById("truckFemaleCount"),truckMaleCount:document.getElementById("truckMaleCount"),poopCount:document.getElementById("poopCount"),buildStatus:document.getElementById("buildStatus"),turnSummary:document.getElementById("turnSummary"),eventPanel:document.getElementById("eventPanel"),modal:document.getElementById("modal"),modalTitle:document.getElementById("modalTitle"),modalBody:document.getElementById("modalBody"),modalActions:document.getElementById("modalActions"),hoverTooltip:document.getElementById("hoverTooltip"),manualScannerMonitor:document.getElementById("manualScannerMonitor"),debug:{panel:document.getElementById("debugPanel"),infiniteCash:document.getElementById("debugInfiniteCash"),dayInput:document.getElementById("debugDayInput"),setDay:document.getElementById("debugSetDayButton"),zeroTimer:document.getElementById("debugZeroTimerButton"),cardSelect:document.getElementById("debugCardSelect"),targetSelect:document.getElementById("debugTargetSelect"),grantCard:document.getElementById("debugGrantCardButton"),grantAllCards:document.getElementById("debugGrantAllCardsButton"),readout:document.getElementById("debugReadout")},buttons:{s1Left:document.getElementById("scanner1MixerButton"),s1Right:document.getElementById("scanner1TruckButton"),s2Left:document.getElementById("scanner2MixerButton"),s2Right:document.getElementById("scanner2TruckButton"),nextTurn:document.getElementById("nextTurnButton"),conveyor:document.getElementById("buildConveyorButton"),boostConveyor:document.getElementById("buildBoostConveyorButton"),eggFarm:document.getElementById("buildEggFarmButton"),autoScanner:document.getElementById("buildAutoScannerButton"),manualScanner:document.getElementById("buildManualScannerButton"),mixer:document.getElementById("buildMixerButton"),trash:document.getElementById("buildTrashButton"),truck:document.getElementById("buildTruckButton"),maintenanceRoom:document.getElementById("buildMaintenanceRoomButton"),erase:document.getElementById("eraseButton"),undo:document.getElementById("undoButton"),redo:document.getElementById("redoButton")}};function wc(){let e={conveyor:"conveyor",boostConveyor:"boostConveyor",eggFarm:"eggFarm",autoScanner:"autoScanner",manualScanner:"manualScanner",mixer:"mixer",trash:"trash",truck:"truck",maintenanceRoom:"maintenanceRoom"};for(let[t,n]of Object.entries(e))L.buttons[t]&&(L.buttons[t].innerHTML=Br(n))}function Sc(e){let t=new Set(e.tags||[]);return["upgradeEgg","crowdedFarming","hatchingFeed","extraEggOutlet"].includes(e.id)||t.has("EGG")?"Production / EGG":["upgradeTrash","poopRateBooster","composter","chemicalWeaponSubsidy"].includes(e.id)||t.has("POOP")?"Poop / Shredder":["upgradeAutoScanner","autoScannerTuning","scannerQueueSpacing"].includes(e.id)||t.has("SCANNER")?"Scanner":["bearing","dynamite"].includes(e.id)||t.has("CONVEYOR")?"Conveyor / Map":["safetyCover","preventiveMaintenance","durabilityCoating","sparePartsBin","laborExploitation"].includes(e.id)||t.has("MAINTENANCE")?"Maintenance / Risk":["dudFilter","dudRefund","freeReroll","extraCards"].includes(e.id)||t.has("CARD")?"Card Engine":t.has("ULTRA RARE")?"Ultra Rare":t.has("ECONOMY")||["upgradeMixer","upgradeTruck","recyclingSubsidy","usedMachine","newMachine","flattery","legalWork","rescueLoan"].includes(e.id)?"Economy / Shipment":"Other"}function kc(){if(!L.debug?.panel||!L.debug.cardSelect)return;let e=["Production / EGG","Poop / Shredder","Scanner","Conveyor / Map","Maintenance / Risk","Card Engine","Economy / Shipment","Ultra Rare","Other"],t=new Map(e.map(n=>[n,[]]));for(let n of Qt){let o=Sc(n);t.has(o)||t.set(o,[]),t.get(o).push(n)}L.debug.cardSelect.innerHTML="";for(let n of e){let o=t.get(n)||[];if(!o.length)continue;let r=document.createElement("optgroup");r.label=n;for(let i of o){let l=document.createElement("option");l.value=i.id;let c=i.rarity==="ultraRare"?"UR":i.rarity==="rare"?"R":"C";l.textContent=`[${c}] ${i.title}`,r.appendChild(l)}L.debug.cardSelect.appendChild(r)}L.debug.cardSelect.addEventListener("change",Ot),Ot()}function Ot(){if(!L.debug?.targetSelect)return;let e=L.debug.cardSelect?.value,t=Jt(e),n=t?ps(u,t):[];if(L.debug.targetSelect.innerHTML="",!n.length){let r=document.createElement("option");r.value="__none__",r.textContent=t?"No target required":"No card selected",L.debug.targetSelect.appendChild(r),L.debug.targetSelect.disabled=!0;return}let o=document.createElement("option");o.value="__auto__",o.textContent=t?.id==="dynamite"?"Auto: first 3 blocked cells":"Auto: first valid target",L.debug.targetSelect.appendChild(o);for(let r of n){let i=document.createElement("option");i.value=r.key,i.textContent=r.label,L.debug.targetSelect.appendChild(i)}L.debug.targetSelect.disabled=!1}function Cc(){let e=Math.max(1,Math.floor(Number(L.debug.dayInput?.value)||1));u.turn=e,L.debug.dayInput&&(L.debug.dayInput.value=String(e)),H(u,fe.width/2-u.view.x,86-u.view.y,`DAY ${e}`,p.green),z.updatePanels(),z.updateUI(),Ot(),Nt(`Day set to ${e}.`)}function xc(){u.timeLeft=0,u.phase==="running"&&qs(),H(u,fe.width/2-u.view.x,86-u.view.y,"TIMER 0",p.warn),z.updatePanels(),z.updateUI(),Nt("Timer set to 0.")}function Mc(){let e=L.debug.cardSelect?.value,t=L.debug.targetSelect?.disabled?void 0:L.debug.targetSelect?.value,n=or(u,e,{targetKey:t});L.debug.grantCard&&(L.debug.grantCard.textContent=n.ok?"Granted":"Failed",window.setTimeout(()=>{L.debug.grantCard&&(L.debug.grantCard.textContent="Grant Selected")},900)),Me?.updateCongestion?.(),z.updatePanels(),z.updateUI(),Ot(),Nt(n.reason)}function gc(){let t=Qt.map(n=>or(u,n,{targetKey:"__auto__"})).filter(n=>n.ok).length;Me?.updateCongestion?.(),z.updatePanels(),z.updateUI(),Ot(),Nt(`Granted ${t}/${Qt.length} cards.`)}function Tc(){L.debug?.infiniteCash?.checked&&u.cash<999999&&(u.cash=999999,u.totals.maxCash=Math.max(u.totals.maxCash,u.cash))}function Nt(e=""){L.debug?.readout&&(L.debug.readout.textContent=[e,`D${u.turn}`,g(u.cash),`Combo ${u.manualCombo?.count||0}`,`Event ${u.eventActive?.title||u.eventOffer?.title||"none"}`,`Rescue ${u.cardEffects?.rescueLoanCharges||0}`,`Chem ${u.cardEffects?.chemicalWeaponSubsidy||0}`].filter(Boolean).join(" | "))}var u=Mo(),V,z,Me,tn;function Ec(e=null){let t=Vn(u,e);return e?t*Vo(u,e):t}function Rc(){Object.assign(u,Mo()),u.phase="running",u.view={x:0,y:0,scale:1},go(u),Vs(),Se(u),z.hideModal(),Me.updateCongestion(),z.updatePanels(),z.updateUI(),Nt()}function Pc(){if(u.phase!=="build")return;if(u.cardDraft?.pending||u.cardTargetPick?.pending){V.fail(u.cardTargetPick?.pending?"Choose upgrade target first.":"Choose an upgrade card first."),z.updatePanels();return}let e=fn(u);if(e.length){V.fail(`Cannot start: ${e[0]}`),z.updatePanels();return}Se(u),si(u),es(u);let t=Math.max(0,Math.floor(u.lastResult?.profit??u.stats?.profit??0)),n=Bi(u,Math.max(1,u.turn||1),t);u.lastStartFees={fairiesTribute:n.amount||0,tribute:n},n.amount>0&&H(u,fe.width/2-u.view.x,116-u.view.y,`FAIRIES -${g(n.amount)}`,p.danger),mi(u),u.phase="running",u.turn+=1,u.timeLeft=vi(u),u.shutdownTimeLeft=0,u.cleanupTimer=null,u.cleanupBlown=!1,u.chicks=[],u.effects=[],u.floatingTexts=[],u.shake={time:0,strength:0},u.truckCargo=[],Vs(),u.stats=xo(),u.stats.fairiesTribute=u.lastStartFees?.fairiesTribute||0,u.stats.fairiesTribute>0&&(u.stats.penalty+=u.stats.fairiesTribute,u.stats.profit-=u.stats.fairiesTribute);for(let o of u.scanners)o.queue=[],o.cooldown=0;for(let o of u.eggFarms)o.nextSpawn=Me.currentSpawnDelay(o),o.lastInterval=o.nextSpawn,o.shutterProgress=0,o.shutterSparked=!1;u.buildTool=null,u.selected=null,u.groupDrag=null,u.selectionBox=null,u.pan=null,Me.updateCongestion(),z.updatePanels(),z.updateUI()}function Ac(){if(u.phase!=="running")return;let e=Fi(u),t=u.eventActive?{...u.eventActive}:null,n=gi(u),o=Li(u);if(e.adjusted>0){let i=u.facilities.truck,l=i?i.x+i.w/2:fe.width/2-u.view.x,c=i?i.y+26:96-u.view.y;H(u,l,c,`${e.target==="poop"?"POOP SHIP":"SHIP"} +${g(e.adjusted)}`,p.green)}n?.bonus>0&&H(u,fe.width/2-u.view.x,96-u.view.y,`EVENT +${g(n.bonus)}`,p.green),o.amount>0&&H(u,fe.width/2-u.view.x,116-u.view.y,`CHEM SUBSIDY +${g(o.amount)}`,p.green),bi(u),u.totals.turnsCompleted+=1;let r=Mi(t);if(r!==1&&(u.pendingFairiesTributeMultiplier=r),u.lastResult={...u.stats,ship:e,event:n,chemical:o,rescue:{amount:0,used:0,remaining:u.cardEffects?.rescueLoanCharges||0},fairiesTribute:{amount:u.stats.fairiesTribute||0},tributeMultiplier:r,turn:u.turn,cash:u.cash},u.cash<0){if((u.cardEffects?.rescueLoanCharges||0)>0){u.phase="loanDecision",z.showEmergencyLoanDecision(Hs,eo);return}u.phase="gameover",z.showGameOver();return}Ks()}function Ks(){u.phase="build",u.truckCargo=[],u.chicks=[],u.shutdownTimeLeft=0,u.cleanupTimer=null,u.cleanupBlown=!1,u.buildSession+=1,u.undoStack=[],u.redoStack=[],u.timeLeft=0;for(let e of u.scanners)e.queue=[];for(let e of u.eggFarms)e.shutterProgress=0,e.shutterSparked=!1;ts(u),u.eventOffer=hi(u),tn&&tn.prepareDraft(),u.cardTargetPick=null,u.buildTool=null,u.groupDrag=null,u.selectionBox=null,u.pan=null,z.updatePanels(),z.showTurnResult(u.lastResult)}function Hs(){if((u.cardEffects?.rescueLoanCharges||0)<=0)return eo();u.cardEffects.rescueLoanCharges-=1,u.stats.rescueLoan=(u.stats.rescueLoan||0)+500,u.totals.rescueLoan=(u.totals.rescueLoan||0)+500;let e=Ge(u,500);u.lastResult={...u.lastResult||{},...u.stats,rescue:{amount:(u.lastResult?.rescue?.amount||0)+e,used:(u.lastResult?.rescue?.used||0)+1,remaining:u.cardEffects.rescueLoanCharges},cash:u.cash},H(u,fe.width/2-u.view.x,176-u.view.y,`RESCUE +${g(e)}`,p.green),u.cash>=0?Ks():(u.cardEffects?.rescueLoanCharges||0)>0?(u.phase="loanDecision",z.showEmergencyLoanDecision(Hs,eo)):eo()}function eo(){u.phase="gameover",z.showGameOver()}function qs(){u.shutdownTimeLeft<=0&&(u.shutdownTimeLeft=u.shutdownGraceSeconds||10);for(let e of u.eggFarms){if(e.shutterSparked)continue;e.shutterProgress=.02,e.shutterSparked=!0;let t=F(e.col,e.row);Xe(u,t.x,t.y,p.ink),Ze(u,t.x,t.y+10,10),H(u,t.x,t.y-34,"SHUT +10s",p.ink)}}function Ys(e){u.lastTimestamp||(u.lastTimestamp=e);let t=Math.min((e-u.lastTimestamp)/1e3,.05);u.lastTimestamp=e,u.phase==="running"&&Me.updateRunning(t,{closeFarmShutters:qs,completeTurn:Ac}),Yi(u,t,fe,V.equipmentHitBoxes),Me.updateCongestion(),Ss(vc,fe,u,{activeQueuedChick:Me.activeQueuedChick,selectedObject:V.selectedObject,selectedTitle:V.selectedTitle}),Tc(),z.updateUI(),Xs(),Nt(),requestAnimationFrame(Ys)}function to(){return u.view?.scale||1}function wn(){u.view||(u.view={x:0,y:0,scale:1}),u.view.scale==null&&(u.view.scale=1)}function no(e){let t=fe.getBoundingClientRect();return{x:(e.clientX-t.left)*fe.width/t.width,y:(e.clientY-t.top)*fe.height/t.height}}function wt(e){let t=no(e),n=to();return{x:(t.x-(u.view?.x||0))/n,y:(t.y-(u.view?.y||0))/n}}function Ic(e){let t=to();return{x:e.x*t+(u.view?.x||0),y:e.y*t+(u.view?.y||0)}}function $c(){let e={left:f.x-90,top:f.y-130,right:f.x+f.cols*f.cell+260,bottom:f.y+f.rows*f.cell+220};if(u.phase==="build")for(let t of Tt(u)){let n=Et(t);e.left=Math.min(e.left,n.x-60),e.top=Math.min(e.top,n.y-80),e.right=Math.max(e.right,n.x+n.w+80),e.bottom=Math.max(e.bottom,n.y+n.h+80)}return e}function Gs(e,t){if(e<=t)return[e,t];let n=(e+t)/2;return[n,n]}function St(){wn();let e=to(),t=$c(),[n,o]=Gs(fe.width-160-t.right*e,110-t.left*e),[r,i]=Gs(fe.height-150-t.bottom*e,150-t.top*e);u.view.x=un(u.view.x,n,o),u.view.y=un(u.view.y,r,i)}function Vs(){wn(),u.view.scale=1;let e=u.eggFarms?.[0],t=e?F(e.col,e.row):{x:f.x,y:f.y};u.view.x=280-t.x,u.view.y=190-t.y,St()}function Dc(e){let t=no(e);wn(),u.pan={start:t,viewX:u.view.x,viewY:u.view.y,moved:!1}}function Fc(e){if(!u.pan)return;let t=no(e);Math.hypot(t.x-u.pan.start.x,t.y-u.pan.start.y)>5&&(u.pan.moved=!0),wn(),u.view.x=u.pan.viewX+t.x-u.pan.start.x,u.view.y=u.pan.viewY+t.y-u.pan.start.y,St()}function Bc(e){e.preventDefault(),wn();let t=no(e),n=wt(e),o=Math.exp(-e.deltaY*.0012),r=un(to()*o,.55,1.8);u.view.scale=r,u.view.x=t.x-n.x*r,u.view.y=t.y-n.y*r,St(),it()}function Lc(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:{type:e.type,id:e.ref.id}:null}function Oc(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:e.ref||null:null}function it(){L.hoverTooltip&&(L.hoverTooltip.classList.remove("visible"),L.hoverTooltip.setAttribute("aria-hidden","true"),u.hover=null)}function Nc(e,t){if(!L.hoverTooltip||u.phase!=="build"||u.cardTargetPick?.pending||u.groupDrag||u.selectionBox||u.pan)return it();let n=Oc(t);if(!n)return it();let o=V.selectedTitle(n),r=V.flavorText?V.flavorText(n):"",i=V.disconnectedWarningFor?V.disconnectedWarningFor(n):"",l=V.selectedInfoLines(n).slice(0,7);L.hoverTooltip.innerHTML=`${o}${i?`${i}`:r?`${r}`:""}${l.map(x=>`${x}`).join("")}`;let c=Math.min(window.innerWidth-330,e.clientX+18),v=Math.min(window.innerHeight-220,e.clientY+18);L.hoverTooltip.style.left=`${Math.max(8,c)}px`,L.hoverTooltip.style.top=`${Math.max(8,v)}px`,L.hoverTooltip.classList.add("visible"),L.hoverTooltip.setAttribute("aria-hidden","false"),u.hover={type:t.type,id:t.oldKey||t.ref?.id||null}}function _c(e){if(u.phase!=="build")return it();Nc(e,V.equipmentAtPoint(wt(e)))}function zs(e){it();let t=wt(e),n=V.equipmentAtPoint(t),o=Lc(n);if(!o){u.selected=null,u.multiSelected=[],z.updatePanels();return}u.selected=o,u.multiSelected=[o],z.updatePanels();let r=V.selectedObject();r?.type==="scanner"&&r.kind==="manual"&&V.showManualScannerMenu(r),r?.type==="scanner"&&r.kind==="auto"&&V.showAutoScannerMenu(r)}function en(){u.buildTool=null,u.selected=null,u.multiSelected=[],u.selectionBox=null,u.cardTargetPick?.mode==="autoScannerMenu"&&(u.cardTargetPick=null),z.hideModal(),it(),z.updatePanels(),z.updateUI()}function Us(e){return String(e).replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function Gc(e){let t=e?.queue?.[0];return t==null?null:u.chicks.find(n=>n.id===t)||null}function Uc(e){if(!e)return'WAIT';let t=e.sex==="poop"?"\u{1F4A9} POOP":e.sex==="male"?"\u2642 MALE":"\u2640 FEMALE";return`${t}`}function Wc(e,t){let n=new Set(u.eggFarms.map(E=>I(E.col,E.row))),o=new Map(u.scanners.map(E=>[I(E.col,E.row),E])),r=Re(e,"inputA"),i=r?I(r.col,r.row):null,l=new Set(Object.values(u.facilities||{}).map(E=>E.entry?I(E.entry.col,E.entry.row):null).filter(Boolean)),c=t?.sex||"",v=c==="poop"?"\u{1F4A9}":c==="male"?"\u2642":c==="female"?"\u2640":"",x=[];for(let E=e.row-2;E<=e.row+2;E+=1)for(let R=e.col-2;R<=e.col+2;R+=1){let B=I(R,E),O=["mini-cell"],ee="";R===e.col&&E===e.row?(O.push("scanner"),c&&O.push(c),ee=v||"S"):B===i?(O.push("input"),ee="IN"):n.has(B)?(O.push("egg"),ee="E"):o.has(B)?(O.push("scanner-other"),ee="S"):l.has(B)?(O.push("port"),ee="P"):u.conveyorTiles.has(B)?(O.push("belt"),ee="\u2022"):u.blockedCells?.has?.(B)&&(O.push("blocked"),ee="\xD7"),x.push(`${ee}`)}return`
${x.join("")}
`}function Kc(e){let t=Ic(F(e.col,e.row)),n=76;return t.x<-n||t.y<-n||t.x>fe.width+n||t.y>fe.height+n}function Xs(){if(!L.manualScannerMonitor)return;if(u.phase!=="running"){L.manualScannerMonitor.classList.remove("visible"),L.manualScannerMonitor.innerHTML="";return}let e=u.scanners.filter(t=>t.kind==="manual"&&Kc(t));if(!e.length){L.manualScannerMonitor.classList.remove("visible"),L.manualScannerMonitor.innerHTML="";return}L.manualScannerMonitor.innerHTML=e.map(t=>{let n=Gc(t),o=t.keys?.left?.label||(t.slot===0?"A":"Left"),r=t.keys?.right?.label||(t.slot===0?"D":"Right"),i=t.role===0?"MIXER":"WASTE",l=t.role===0?"S2":"TRUCK",c=n?"":" disabled";return` -
-
S${(t.slot??0)+1}OFFSCREEN / Q:${t.queue.length}
-
- IN${Uc(n)}SCANNER -
- ${Wc(t,n)} -
- - -
-
`}).join(""),L.manualScannerMonitor.classList.add("visible")}L.manualScannerMonitor?.addEventListener("click",e=>{let t=e.target.closest("button[data-scanner-id]");if(!t||t.disabled)return;let n=u.scanners.find(o=>o.id===Number(t.dataset.scannerId));n&&(Me.sortScanner(n,t.dataset.side),Xs())});fe.addEventListener("contextmenu",e=>e.preventDefault());fe.addEventListener("wheel",Bc,{passive:!1});fe.addEventListener("pointerdown",e=>{if(u.phase!=="build")return;fe.setPointerCapture(e.pointerId);let t=wt(e);if(e.button===2){Dc(e);return}if(e.button!==0)return;if(u.cardTargetPick?.mode==="autoScannerMenu"){en();return}if(u.cardTargetPick?.pending){tn.chooseTargetAtPoint(t);return}let n=V.expansionOfferAtPoint?.(t);if(n){V.buyGridExpansion(n),St(),z.updatePanels(),z.updateUI();return}if(V.cycleBranchModeAtPoint?.(t)){z.updatePanels(),z.updateUI();return}let o=Ke(t.x,t.y),r=V.equipmentAtPoint(t);if(!u.buildTool&&r?.type==="conveyor"&&o&&V.cycleSingleConveyorDirection?.(o)){z.updatePanels(),z.updateUI();return}if(u.buildTool==="erase"){if(!V.equipmentAtPoint(t)){en();return}V.eraseAtPoint(t);return}if(u.buildTool){let i=Ke(t.x,t.y);if(!i&&!["mixer","trash","truck"].includes(u.buildTool)){en();return}if(u.buildTool==="conveyor"||u.buildTool==="boostConveyor"){V.beginConveyorDrag(i);return}if(V.equipmentAtPoint(t)){u.buildTool=null,zs(e);return}V.buildAtPoint(t);return}V.startGroupDrag(e)||V.startSelectionBox(e)});fe.addEventListener("pointermove",e=>{if(u.phase!=="build"){it();return}_c(e),u.pan&&e.buttons&2&&Fc(e),u.groupDrag&&e.buttons&1&&V.updateGroupDrag(e),u.selectionBox&&e.buttons&1&&V.updateSelectionBox(e),(u.buildTool==="conveyor"||u.buildTool==="boostConveyor")&&e.buttons&1&&V.continueConveyorDrag(Ke(wt(e).x,wt(e).y)),u.buildTool==="erase"&&e.buttons&1&&V.eraseAtPoint(wt(e))});fe.addEventListener("pointerup",e=>{u.selectionBox?V.finishSelectionBox():u.groupDrag&&(u.groupDrag.committed||zs(e),V.finishGroupDrag()),e.button===2&&u.pan&&!u.pan.moved&&u.buildTool&&en(),(u.buildTool==="conveyor"||u.buildTool==="boostConveyor")&&V.endConveyorDrag?.(),u.groupDrag=null,u.pan=null;try{fe.releasePointerCapture(e.pointerId)}catch{}});fe.addEventListener("pointerleave",it);fe.addEventListener("pointercancel",()=>{V?.endConveyorDrag?.(),u.groupDrag=null,u.selectionBox=null,u.pan=null,it()});document.addEventListener("pointerdown",e=>{!L.modal.classList.contains("visible")||!L.modal.classList.contains("equipment-popover")||e.target.closest("#modal .modal-card")||en()},!0);L.buttons.s1Left.addEventListener("click",()=>Me.sortSlot(0,"left"));L.buttons.s1Right.addEventListener("click",()=>Me.sortSlot(0,"right"));L.buttons.s2Left.addEventListener("click",()=>Me.sortSlot(1,"left"));L.buttons.s2Right.addEventListener("click",()=>Me.sortSlot(1,"right"));L.buttons.nextTurn.addEventListener("click",Pc);L.buttons.conveyor.addEventListener("click",()=>V.setBuildTool("conveyor"));L.buttons.boostConveyor.addEventListener("click",()=>V.setBuildTool("boostConveyor"));L.buttons.eggFarm.addEventListener("click",()=>V.setBuildTool("eggFarm"));L.buttons.autoScanner.addEventListener("click",()=>V.setBuildTool("autoScanner"));L.buttons.manualScanner.addEventListener("click",()=>V.setBuildTool("manualScanner"));L.buttons.mixer.addEventListener("click",()=>V.setBuildTool("mixer"));L.buttons.trash.addEventListener("click",()=>V.setBuildTool("trash"));L.buttons.truck.addEventListener("click",()=>V.setBuildTool("truck"));L.buttons.maintenanceRoom.addEventListener("click",()=>V.setBuildTool("maintenanceRoom"));L.buttons.erase.addEventListener("click",()=>V.setBuildTool("erase"));L.debug.setDay?.addEventListener("click",Cc);L.debug.zeroTimer?.addEventListener("click",xc);L.debug.grantCard?.addEventListener("click",Mc);L.debug.grantAllCards?.addEventListener("click",gc);L.buttons.undo.addEventListener("click",()=>{Uo(u)&&(St(),z.updatePanels(),z.updateUI(),Ot())});L.buttons.redo.addEventListener("click",()=>{Wo(u)&&(St(),z.updatePanels(),z.updateUI(),Ot())});function Ws(e,t,n){let o=e.keys?.[t];return o?o.code&&n.code===o.code||o.key&&n.key.toLowerCase()===o.key:!1}window.addEventListener("keydown",e=>{if(e.repeat)return;let t=e.key.toLowerCase();if(u.phase==="running")for(let n of u.scanners.filter(o=>o.kind==="manual")){if(Ws(n,"left",e)){e.preventDefault(),Me.sortScanner(n,"left");return}if(Ws(n,"right",e)){e.preventDefault(),Me.sortScanner(n,"right");return}}u.phase==="build"&&(e.ctrlKey||e.metaKey)&&t==="z"&&(e.preventDefault(),Uo(u)&&(St(),z.updatePanels(),z.updateUI())),u.phase==="build"&&(e.ctrlKey||e.metaKey)&&(t==="y"||e.shiftKey&&t==="z")&&(e.preventDefault(),Wo(u)&&(St(),z.updatePanels(),z.updateUI())),e.key==="Escape"&&u.cardTargetPick?.pending&&(e.preventDefault(),u.cardTargetPick.mode==="autoScannerMenu"?en():tn.cancelTargetPick())});V=$s({game:u,ui:L,canvas:fe,canvasPoint:wt,onUpdatePanels:()=>z?.updatePanels()});Me=_s({game:u,currentConveyorSpeed:Ec,onGameOverCheck:()=>z?.checkGameOver()});tn=ms({game:u,ui:L,onUpdatePanels:()=>z?.updatePanels()});z=Ds({game:u,ui:L,build:V,startGame:Rc,beginCardDraft:()=>tn.showDraft(),activeQueuedChick:Me.activeQueuedChick});wc();kc();go(u);Se(u);Me.updateCongestion();z.updatePanels();z.updateUI();z.showTitle();Nt();requestAnimationFrame(Ys); diff --git a/dist/game-v27.18.js b/dist/game-v27.18.js deleted file mode 100644 index b796070..0000000 --- a/dist/game-v27.18.js +++ /dev/null @@ -1,59 +0,0 @@ -var Y={version:"v27.18 UI + ROUTING PATCH",time:{daySeconds:60,farmShutdownGraceSeconds:10},cash:{starting:250},grid:{x:170,y:78,cols:20,rows:10,cell:46,expansion:{colsPerPurchase:10,rowsPerPurchase:10,costBase:1e3,costMultiplier:1.3333333333333333,truncateUnit:100}},map:{blockedRatio:.075},economy:{income:{mixer:5,truck:10},poopFine:10,fairiesTribute:{perDay:10,profitExemption:300,legalWorkExemptionBonus:250,profitRate:.12},incomeUpgradeRate:1.1,explosionDamageDivisor:30,maleTruckFinePerHalfDay:30,shredderBonus:{maxCards:30,incomePerUpgrade:1.25},chemicalWeaponSubsidy:{poopPerBlock:70,yenPerBlock:1200}},production:{poopRate:.08,autoScannerCooldown:3.5,autoScannerUpgradeRate:.95,autoScannerCardUpgradeRate:.95,autoScannerMinCooldown:.5,poopRateCardBonus:.04,eggSpawnRanges:[[1.95,4.35],[1.55,3.45],[1.25,2.8],[1.05,2.35]]},conveyor:{baseSpeed:52,maxSpeed:300,bearingSpeedMultiplier:1.075},cards:{definitions:[{id:"upgradeEgg",title:"EGG Improvement",rarity:"common",type:"equipmentUpgrade",target:"eggFarm",description:"Choose one EGG FARM on the map and raise it by 1 level.",tags:["EGG","ACTIVE"]},{id:"upgradeAutoScanner",title:"AUTO SCANNER Improvement",rarity:"common",type:"equipmentUpgrade",target:"autoScanner",description:"Choose one AUTO SCANNER on the map and raise it by 1 level.",tags:["SCANNER","ACTIVE"]},{id:"autoScannerTuning",title:"AUTO SCANNER Tuning",rarity:"common",type:"instant",description:"All AUTO SCANNER cooldowns use default cooldown x0.95 per copy.",tags:["SCANNER","PASSIVE"]},{id:"upgradeMixer",title:"MIXER Improvement",rarity:"common",type:"equipmentUpgrade",target:"mixer",description:"Choose MIXER on the map and raise it by 1 level.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeTruck",title:"TRUCK Improvement",rarity:"common",type:"equipmentUpgrade",target:"truck",description:"Choose TRUCK on the map and raise it by 1 level.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeTrash",title:"SHREDDER Improvement",rarity:"common",type:"equipmentUpgrade",target:"trash",description:"Shred poops for a little money. Max 30 upgrades.",tags:["POOP","ACTIVE"]},{id:"crowdedFarming",title:"Crowded Farming",rarity:"common",type:"instant",description:"EGG production interval -5%. Equipment deterioration +4%. Max 10 cards.",tags:["EGG","RISK","PASSIVE"]},{id:"hatchingFeed",title:"Hatching Feed",rarity:"common",type:"instant",description:"EGG production interval -4%. Poop rate +3%. No card limit.",tags:["EGG","POOP","PASSIVE"]},{id:"poopRateBooster",title:"Poop Culture",rarity:"common",type:"instant",description:"Base poop rate +4 percentage points. No card limit.",tags:["POOP","PASSIVE"]},{id:"safetyCover",title:"Safety Cover",rarity:"common",type:"instant",description:"Explosion damage -5%. No card limit.",tags:["RISK","PASSIVE"]},{id:"preventiveMaintenance",title:"Preventive Maintenance Manual",rarity:"common",type:"instant",description:"All equipment deterioration speed -5%. No card limit.",tags:["MAINTENANCE","PASSIVE"]},{id:"dudFilter",title:"DUD Filter",rarity:"common",type:"instant",description:"DUD chance -5 percentage points. Stacks until DUD chance reaches 0%.",tags:["CARD","PASSIVE"]},{id:"durabilityCoating",title:"Durability Coating",rarity:"common",type:"instant",description:"All equipment maximum durability +3%. No card limit.",tags:["MAINTENANCE","PASSIVE"]},{id:"bearing",title:"High-Quality Bearing",rarity:"common",type:"instant",description:"Conveyor speed +7.5%.",tags:["CONVEYOR","PASSIVE"]},{id:"sparePartsBin",title:"SPARE PARTS BIN",rarity:"common",type:"instant",description:"Restores 2% durability to every machine. A box of almost-compatible parts.",tags:["MAINTENANCE","ACTIVE"]},{id:"dudRefund",title:"DUD REFUND",rarity:"common",type:"instant",description:"DUDs now come with paperwork. Gain JPY 50 per copy when you pick a DUD.",tags:["CARD","ECONOMY","PASSIVE"]},{id:"freeReroll",title:"FREE REROLL",rarity:"common",type:"instant",description:"The first bad ideas are free.",tags:["CARD","PASSIVE"]},{id:"composter",title:"COMPOSTER",rarity:"common",type:"instant",description:"Turns shredder waste into suspicious fertilizer. Gain JPY 3 per copy when SHREDDER processes poop.",tags:["POOP","ECONOMY","PASSIVE"]},{id:"scannerQueueSpacing",title:"Scanner Queue Spacing",rarity:"common",type:"instant",description:"Manual and Auto Scanner queue spacing -15%. No card limit.",tags:["SCANNER","PASSIVE"]},{id:"extraEggOutlet",title:"Extra Egg Outlet",rarity:"rare",type:"equipmentUpgrade",target:"eggOutlet",description:"Choose one EGG FARM and add +1 output port to that EGG. Max +3 per EGG.",tags:["EGG","RARE","ACTIVE"]},{id:"recyclingSubsidy",title:"Recycling Subsidy",rarity:"rare",type:"instant",description:"SELL refund rate +10 points. Max 3 cards; normal SELL can reach 80%.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"dynamite",title:"Dynamite",rarity:"rare",type:"cellAction",target:"blockedCell",description:"Remove any 3 unbuildable cells",tags:["RISK","RARE","ONE-SHOT"]},{id:"usedMachine",title:"Used Machines",rarity:"rare",type:"instant",description:"Future equipment costs half. New purchases have no refund and 60% durability. New Machines cancels it.",tags:["ECONOMY","RISK","RARE"]},{id:"newMachine",title:"New Machines",rarity:"common",type:"instant",description:"Cancel Used Machines and restore normal prices, refunds, and durability.",tags:["ECONOMY","ONE-SHOT"]},{id:"flattery",title:"Flattery",rarity:"rare",type:"instant",description:"Next Fairies tribute -50%.",tags:["ECONOMY","RARE","ONE-SHOT"]},{id:"extraCards",title:"Extra Cards",rarity:"rare",type:"instant",description:"Draw 2 cards now and choose both.",tags:["RARE","ACTIVE"]},{id:"legalWork",title:"Legal Work",rarity:"rare",type:"instant",description:"Fairies tribute profit exemption +JPY 250.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"chemicalWeaponSubsidy",title:"Chemical Weapons Subsidy",rarity:"ultraRare",type:"instant",description:"Each day, gain JPY 1200 per 70 poop shipped by truck. No card limit.",tags:["POOP","ULTRA RARE","PASSIVE"]},{id:"laborExploitation",title:"Motivational Exploitation",rarity:"ultraRare",type:"instant",description:"Repair room work time -30%. The repairman smiles with bloodshot eyes. One time only.",tags:["MAINTENANCE","ULTRA RARE","PASSIVE"]},{id:"rescueLoan",title:"Emergency Loan",rarity:"ultraRare",type:"instant",description:"If cash is below JPY 0 at day-end settlement, gain JPY 500. Consumed on use.",tags:["ECONOMY","ULTRA RARE","ONE-SHOT"]}],defaultEffects:{bearing:0,legalWork:0,fairiesFlatteryNext:0,autoScannerTuning:0,poopRateBooster:0,crowdedFarming:0,hatchingFeed:0,safetyCover:0,recyclingSubsidy:0,chemicalWeaponSubsidy:0,preventiveMaintenance:0,dudFilter:0,durabilityCoating:0,sparePartsBin:0,dudRefund:0,freeReroll:0,composter:0,scannerQueueSpacing:0,laborExploitation:0,usedMachineActive:!1,rescueLoanCharges:0},commonWeight:8,rareWeight:2,ultraRareWeight:.45,baseDraftSize:3,maxDudsPerDraft:2,dudChancePerCard:.3,dudChanceReductionPerFilter:.05,extraCardsAddedPicks:2,rerollCost:{dayDivisor:2,multiplier:100}},events:{eventChance:.1,firstTurn:8},maintenance:{fullPerformanceUntilWear:.5,minimumPerformance:.5,durability:{conveyor:1300,eggFarm:475,autoScanner:850,mixer:775,trash:950},processingDelayMaxSeconds:{mixer:1.2,trash:1},repairman:{secondsPerOnePercent:.5,walkSpeed:90}},facilities:{conveyor:{id:"conveyor",type:"conveyor",name:"Conveyor",shortName:"Belt",price:30,buildable:!0,upgradeable:!1},boostConveyor:{id:"boostConveyor",type:"conveyor",name:"Boost Conveyor",shortName:"BOOST BELT",price:75,buildable:!0,upgradeable:!1,speedMultiplier:2},eggFarm:{id:"eggFarm",type:"eggFarm",name:"Egg Farm",shortName:"EGG",price:250,buildable:!0,upgradeable:!0,maxLevel:4},manualScanner:{id:"manualScanner",type:"scanner",kind:"manual",name:"Manual Scanner",shortName:"Manual Scanner",price:260,buildable:!0,upgradeable:!1},autoScanner:{id:"autoScanner",type:"scanner",kind:"auto",name:"Auto Scanner",shortName:"Auto Scanner",price:180,buildable:!0,upgradeable:!1},mixer:{id:"mixer",type:"facility",name:"Mixer",shortName:"MIXER",price:450,buildable:!0,upgradeable:!0,incomeKey:"mixer",body:{w:164,h:126}},trash:{id:"trash",type:"facility",name:"Waste Shredder",shortName:"SHREDDER",price:240,buildable:!0,upgradeable:!0,body:{w:180,h:100}},truck:{id:"truck",type:"facility",name:"Truck",shortName:"TRUCK",price:450,buildable:!0,upgradeable:!0,incomeKey:"truck",body:{w:176,h:138}},maintenanceRoom:{id:"maintenanceRoom",type:"maintenanceRoom",name:"Maintenance Room",shortName:"REPAIR ROOM",price:220,buildable:!0,upgradeable:!1,footprint:{cols:2,rows:2}}}};var Pr=Y.version,gt=Y.time.daySeconds,an=Y.cash.starting,Ce=Y.economy,Ar=Y.time.farmShutdownGraceSeconds,xn=Y.production.autoScannerCooldown,Dr=Y.production.autoScannerUpgradeRate,ho=Y.production.autoScannerCardUpgradeRate||Y.production.autoScannerUpgradeRate,mo=Y.production.autoScannerMinCooldown,Ir=Y.events.eventChance,xt=Y.events.firstTurn,bo=Y.production.poopRate,vo=Y.production.poopRateCardBonus||0,Tn=Y.conveyor.baseSpeed,Wt=Y.conveyor.maxSpeed,En=Y.conveyor.bearingSpeedMultiplier,Ie=Y.cards,$r=Y.cards.definitions,wo=Y.cards.defaultEffects,lt=Y.production.eggSpawnRanges,f=Y.grid,ve=Y.facilities,So=["conveyor","boostConveyor","eggFarm","autoScanner","manualScanner","mixer","trash","truck","maintenanceRoom"],cn=["mixer","trash","truck"],Fr=["mixer","truck"],at=Object.fromEntries(Object.entries(ve).map(([e,t])=>[e,t.price])),de=[{name:"right",dc:1,dr:0,angle:0,opposite:"left"},{name:"left",dc:-1,dr:0,angle:Math.PI,opposite:"right"},{name:"down",dc:0,dr:1,angle:Math.PI/2,opposite:"up"},{name:"up",dc:0,dr:-1,angle:-Math.PI/2,opposite:"down"}],y={bg:"#111318",ink:"#090a0d",muted:"#8f9bab",green:"#7bd84f",greenSoft:"#273c24",mixerBlue:"#4aa3ff",truckPink:"#ffb33e",wasteGreen:"#88d35a",danger:"#e34a36",warn:"#ffb827",white:"#e6edf2",poop:"#7b4a23",male:"#4aa3ff",female:"#ff6fae"},Me={ambient:0,important:1,critical:2};function x(e){let t=Number(e)||0;return`${t<0?"-":""}\uFFE5${Math.ceil(Math.abs(t)).toLocaleString("ja-JP")}`}function A(e,t){return`${e},${t}`}function te(e){let[t,n]=String(e).split(",").map(Number);return{col:t,row:n}}function un(e,t,n){return Math.max(t,Math.min(n,e))}function W(e,t){return e+Math.random()*(t-e)}function Ee(e,t){return e>=0&&e=0&&tMath.round(un(r,0,255)).toString(16).padStart(2,"0");return`#${o(e)}${o(t)}${o(n)}`}function Kt(e,t,n){let o=Br(e),r=Br(t);return cl(ko(o.r,r.r,n),ko(o.g,r.g,n),ko(o.b,r.b,n))}var oe={appTitle:"Chick Sorter",versionTitle:`Chick Sorter ${Pr}`,currency:"\uFFE5",phases:{title:"Title",build:"Build",running:"Sorting",clearing:"Clearing",loanDecision:"Emergency Loan",gameover:"Game Over"},actions:{startGame:"Start Game",nextDay:"Next Day",buildPhase:"Build Phase",restart:"Restart",close:"Close",remove:"Remove",refund:"Refund",autoMenu:"Auto Menu"},status:{build:e=>`BUILD: ${(e==="erase"?"SELL":e||"SELECT").toUpperCase()} | Right-drag pan | Hover equipment for info`,sorting:"Sorting: use scanner keys. Build after clearing the day.",allPortsConnected:"Start condition met: one EGG route reaches an exit.",equipmentPanelEmpty:"Hover equipment in Build phase.",eventPanelRunning:"Forced events appear in Build phase."},routeLabels:{mixer:"MIXER",truck:"TRUCK",trash:"WASTE",scanner:"NEXT","scanner-role-1":"NEXT",input:"IN"},fail:{outOfGrid:"Out of grid",cellOccupied:"Cell occupied",notEnoughCash:"Not enough cash",facilityExists:"Facility already exists",facilityOverlap:"Facility overlap",nothingToErase:"Nothing to sell",noUpgrade:"No upgrade available"}};function ut(e){return ve[e]?.name||String(e||"").replace(/^[a-z]/,t=>t.toUpperCase())}function ul(e){let t=ve[e];return t?e==="conveyor"||e==="boostConveyor"?`${x(t.price)} / tile`:e==="autoScanner"?`${x(t.price)} / ${xn.toFixed(1)}s cooldown`:e==="trash"?x(t.price):x(t.price):""}function dl(e){return{conveyor:"A narrow green belt. Routes decide whether chicks live, ship, or become invoices.",boostConveyor:"Moves chicks twice as fast. Wears down like a normal belt.",eggFarm:"A tiny gatehouse producing questionable eggs on schedule.",autoScanner:"Slower than hands without upgrades.",manualScanner:"A manual checkpoint. The operator is the algorithm.",mixer:"Male chicks become revenue here. Do not feed it poop.",trash:"A polite shredder for poop and other regrets.",truck:"Ships the target cargo. Wrong cargo still leaves a paper trail.",maintenanceRoom:"2\xD72 repair bay. Each room dispatches one repairman during the day."}[e]||""}function Or(e){let t=dl(e);return`${ut(e)}${ul(e)}${t?`${t}`:""}`}function Nr(e){return oe.routeLabels[e]||String(e).toUpperCase()}function _r(e){let t=2166136261;for(let n=0;n>>0}function Gr(e){let t=e>>>0;return()=>{t+=1831565813;let n=Math.imul(t^t>>>15,1|t);return n^=n+Math.imul(n^n>>>7,61|n),((n^n>>>14)>>>0)/4294967296}}function Pn(){return`RUN-${Date.now().toString(36)}-${Math.floor(Math.random()*1e6).toString(36)}`.toUpperCase()}function Ur({seed:e,targetRatio:t=.2,reserved:n=[]}={}){let o=Gr(_r(e||Pn())),r=new Set(n.map(c=>typeof c=="string"?c:A(c.col,c.row))),i=[];for(let c=0;c0;c-=1){let b=Math.floor(o()*(c+1));[i[c],i[b]]=[i[b],i[c]]}let l=Math.round(f.cols*f.rows*t);return new Set(i.slice(0,Math.min(l,i.length)).map(c=>c.k))}function Wr({seed:e,colStart:t=0,colEnd:n=f.cols,rowStart:o=0,rowEnd:r=f.rows,targetRatio:i=.2,reserved:l=[]}={}){let c=Gr(_r(e||Pn())),b=new Set(l.map(X=>typeof X=="string"?X:A(X.col,X.row))),C=[],T=Math.max(0,Math.floor(t)),I=Math.max(T,Math.floor(n)),$=Math.max(0,Math.floor(o)),O=Math.max($,Math.floor(r));for(let X=$;X0;X-=1){let ae=Math.floor(c()*(X+1));[C[X],C[ae]]=[C[ae],C[X]]}let ee=Math.round((I-T)*(O-$)*i);return new Set(C.slice(0,Math.min(ee,C.length)).map(X=>X.k))}var Ht=10,Kr=2,Hr=1;function qt(e,t){return`${e},${t}`}function fl(e){let[t,n]=String(e).split(",").map(Number);return{chunkX:t,chunkY:n}}function An(e){let t=Y.grid.expansion||{},n=Math.max(1,(e.gridExpansionPurchases||0)+1),o=(t.costBase||1e3)*n*(t.costMultiplier||4/3),r=Math.max(1,t.truncateUnit||100);return Math.floor(o/r)*r}function qr(e){e.ownedCells=new Set,e.ownedChunks=new Set,e.gridChunkOriginY=0,e.gridExpansionPurchases=0,e.gridExpansionPurchasesByDirection={right:0,up:0};for(let t=0;t=0&&t=0&&n0)continue;let C=qt(b.chunkX,b.chunkY);t.has(C)||n.has(C)||n.set(C,Co(e,b.chunkX,b.chunkY,b.direction))}}return[...n.values()].sort((o,r)=>{let i=o.direction===r.direction?0:o.direction==="right"?-1:1;return i||(o.chunkY!==r.chunkY?o.chunkY-r.chunkY:o.chunkX-r.chunkX)})}function zr(e,t="right"){let n=Tt(e);return n.find(o=>o.direction===t)||n[0]||null}function Et(e){return{x:f.x+e.colStart*f.cell,y:f.y+e.rowStart*f.cell,w:e.cols*f.cell,h:e.rows*f.cell}}function Mo(e){let t=Et(e);return{x:t.x+t.w/2-116,y:t.y+t.h/2-36,w:232,h:72,cx:t.x+t.w/2,cy:t.y+t.h/2}}function Xr(e,t){let n=Mo(e);return t.x>=n.x&&t.x<=n.x+n.w&&t.y>=n.y&&t.y<=n.y+n.h}function Qr(e){let t=[];for(let n=e.rowStart;nEe(t.col,t.row))}function Sl(e){return[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}].filter(t=>Ee(t.col,t.row))}function kl(e){return[{col:e.col,row:e.row+1},{col:e.col-1,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row-1}].filter(t=>Ee(t.col,t.row))}function ni(e){let t=new Set([...e.conveyorTiles]),n=o=>{o&&Ee(o.col,o.row)&&t.add(A(o.col,o.row))};for(let o of e.scanners){for(let r of Sl(o))n(r);for(let r of wl(o))n(r)}for(let o of e.eggFarms){n(o);for(let r of kl(o))n(r)}for(let o of Object.values(e.facilities))n(o.entry);return t}function ei(e){let t=hl.map(([n,o])=>({col:n,row:o}));for(let{col:n,row:o}of t)ti(e,n,o);for(let n=0;n({...n,keys:n.keys?{left:{...n.keys.left},right:{...n.keys.right}}:null,queue:[]})),e.eggFarms=bl.map(n=>{let o=Rt(n);return{...n,nextSpawn:o,lastInterval:o}});let t=ni(e);e.blockedCells=Ur({seed:e.runSeed,targetRatio:Y.map.blockedRatio,reserved:[...t]}),Cl(e),ei(e),e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function Pt(e){return e?[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}]:[]}function ye(e){let t=B(e.col,e.row);return{x:t.x+f.cell/2,y:t.y}}function ft(e,t,n){return e.eggFarms.find(o=>o.col===t&&o.row===n)||null}function pt(e,t,n){return e.scanners.find(o=>Pt(o).some(r=>r.col===t&&r.row===n))||null}function At(e,t){return e.scanners.find(n=>n.id===t)||null}function Ro(e,t){return e.scanners.find(n=>n.kind==="manual"&&n.slot===t)||null}function Fn(e){return e?.baseId||e?.id||""}function Po(e,t){return Object.entries(e.facilities||{}).filter(([,n])=>Fn(n)===t)}function Re(e,t){return{inputA:{col:e.col,row:e.row-2},inputB:null,left:{col:e.col-1,row:e.row},right:{col:e.col+2,row:e.row}}[t]}function ii(e){return e?de.map(t=>({col:e.col+t.dc,row:e.row+t.dr})).filter(t=>Ee(t.col,t.row)):[]}function si(e,t,n=[],o=[]){if(!t||!Ee(t.col,t.row))return[];let r=[],i=l=>{!l||!Ee(l.col,l.row)||!e.conveyorTiles.has(A(l.col,l.row))||n.some(c=>c&&Rn(l,c))||r.some(c=>Rn(c,l))||r.push({...l,viaTolerance:!Rn(l,t)})};i(t);for(let l of o)i(l);for(let l of ii(t))i(l);return r}function oi(e,t,n=[],o=[]){let r=si(e,t,n,o),i=r.filter(l=>!l.viaTolerance);return i.length?i:r}function Ml(e,t){let n=Re(t,"inputA");return!n||!Ee(n.col,n.row)?[]:e.conveyorTiles.has(A(n.col,n.row))?[{...n,viaTolerance:!1}]:[]}function gl(e,t,n){let o=Re(t,n);return si(e,o,Pt(t))}function xl(e,t){let n=e.facilities[t]||Po(e,t)[0]?.[1];if(!n)return null;if(n.entry)return B(n.entry.col,n.entry.row);let o=Fn(n)||t;return o==="mixer"?{x:n.x+n.w,y:n.y+n.h*.52}:o==="truck"?{x:n.x,y:n.y+n.h*.52}:o==="trash"?{x:n.x+n.w/2,y:n.y+8}:{x:n.x+n.w/2,y:n.y+n.h/2}}function li(e,t,n){return n==="inputA"?Ml(e,t).length>0:gl(e,t,n).length>0}function me(e){e.branchCounters?.clear?.(),e.routeCache=null,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function $e(e,t){return A(e,t)}function Yt(e){return te(e)}function Tl(e,t){let n=e.conveyorMeta?.get?.(t)||{},o=[];return Array.isArray(n.outDirs)&&o.push(...n.outDirs),n.dir&&o.push(n.dir),[...new Set(o)].filter(r=>de.some(i=>i.name===r))}function El(e,t,n){let o=de.find(l=>l.name===n);if(!o)return!1;let r=e.conveyorMeta?.get?.($e(t.col+o.dc,t.row+o.dr));return r?[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))].includes(o.opposite):!1}function Rl(e,t){let n=Yt(t),o=e.conveyorMeta?.get?.(t)||{},r=de.filter(T=>e.conveyorTiles.has($e(n.col+T.dc,n.row+T.dr))).map(T=>T.name),i=Tl(e,t).filter(T=>r.includes(T)),l=i.length?i:r;if(r.length<3)return l;let c=new Set(r.filter(T=>El(e,n,T))),b=r.filter(T=>!c.has(T)),C=c.size&&b.length>=2?b:[...new Set(l)];return C.length<2&&(C=r),o.branchMode&&o.branchMode!=="random"&&C.includes(o.branchMode)?[o.branchMode]:C}function Pl(e){return{version:e.routingVersion||0,cells:new Set,adjacency:new Map,components:new Map,cellToComponent:new Map,scannerInputs:new Map,scannerPorts:new Map,facilityPorts:new Map,farmOutputs:new Map,pathCache:new Map,metrics:{conveyorCells:0,edges:0,components:0,deadEnds:0,crosses:0,scannerPorts:0,connectedScannerPorts:0,facilityPorts:0,connectedFacilityPorts:0,farmOutputs:0},issues:[]}}function Al(e){let t=Pl(e);for(let o of e.conveyorTiles)t.cells.add(o),t.adjacency.set(o,[]);for(let o of t.cells){let r=Yt(o),i=Rl(e,o),l=de.filter(c=>i.includes(c.name));for(let c of l){let b=$e(r.col+c.dc,r.row+c.dr);t.cells.has(b)&&t.adjacency.get(o).push({key:b,dir:c.name})}}let n=0;for(let[o,r]of t.adjacency.entries()){n+=r.length;let i=new Set(r.map(l=>l.dir));r.length===1&&(t.metrics.deadEnds+=1),r.length===4&&i.has("left")&&i.has("right")&&i.has("up")&&i.has("down")&&(t.metrics.crosses+=1)}return t.metrics.conveyorCells=t.cells.size,t.metrics.edges=Math.floor(n/2),Dl(t),Il(e,t),t.issues=Kl(e,t,{includeRoutes:!1}),t}function Dl(e){let t=1;for(let n of e.cells){if(e.cellToComponent.has(n))continue;let o=t++,r=[n],i=[];for(e.cellToComponent.set(n,o);r.length;){let l=r.shift();i.push(l);for(let c of e.adjacency.get(l)||[])e.cellToComponent.has(c.key)||(e.cellToComponent.set(c.key,o),r.push(c.key))}e.components.set(o,{id:o,cells:i,capacity:Math.max(1,i.length),count:0,ratio:0})}e.metrics.components=e.components.size}function Il(e,t){for(let n of e.scanners){let o={};for(let r of["inputA","left","right"]){let i=Re(n,r),l=r==="inputA"?i&&t.cells.has($e(i.col,i.row))?[{...i}]:[]:oi(e,i,Pt(n)).filter(C=>t.cells.has($e(C.col,C.row))),c=l.map(C=>$e(C.col,C.row)),b=c.length>0;if(o[r]={type:r,cell:i,cells:l,keys:c,key:c[0]||null,connected:b},t.metrics.scannerPorts+=1,b&&(t.metrics.connectedScannerPorts+=1),r==="inputA")for(let C of c)t.scannerInputs.set(C,n.id)}t.scannerPorts.set(n.id,o)}for(let[n,o]of Object.entries(e.facilities)){if(!o.entry)continue;let r=oi(e,o.entry).filter(c=>t.cells.has($e(c.col,c.row))),i=r.map(c=>$e(c.col,c.row)),l=i.length>0;t.facilityPorts.set(n,{id:n,cell:{...o.entry},cells:r,keys:i,key:i[0]||null,connected:l}),t.metrics.facilityPorts+=1,l&&(t.metrics.connectedFacilityPorts+=1)}for(let n of e.eggFarms){let o=ii({col:n.col,row:n.row}).map(r=>$e(r.col,r.row)).filter(r=>t.cells.has(r));t.farmOutputs.set(n.id,o),t.metrics.farmOutputs+=o.length}}function _e(e){let t=e.routingVersion||0;return(!e.factoryGraph||e.factoryGraph.version!==t)&&(e.factoryGraph=Al(e)),e.factoryGraph}function ai(e){let t=_e(e);return e.factoryGraphCommittedVersion=t.version,e.factoryGraphSnapshot=$l(t),t}function $l(e){return e?{version:e.version,conveyorCells:e.metrics.conveyorCells,edges:e.metrics.edges,components:e.metrics.components,deadEnds:e.metrics.deadEnds,crosses:e.metrics.crosses,scannerPorts:`${e.metrics.connectedScannerPorts}/${e.metrics.scannerPorts}`,facilityPorts:`${e.metrics.connectedFacilityPorts}/${e.metrics.facilityPorts}`,farmOutputs:e.metrics.farmOutputs,issues:[...e.issues||[]]}:null}function Fl(e,t){let n=t.col-e.col,o=t.row-e.row;return de.find(r=>r.dc===n&&r.dr===o)?.name||null}function Ao(e,t,n){let o=_e(e),r=$e(t.col,t.row);if(!o.cells.has(r))return[];let i=`${r}|${n.cacheKey||"dynamic"}`;if(n.cacheKey&&o.pathCache.has(i))return o.pathCache.get(i).map(se=>se.map(ie=>({...ie})));let l=`${r}|none`,c=[{key:r,col:t.col,row:t.row,incoming:"none",depth:0}],b=new Map([[l,0]]),C=new Map,T=[],I=1/0,$=8,O=24,ee=80;for(;c.length;){let se=c.shift();if(se.depth>I)break;let ie=`${se.key}|${se.incoming}`;if(n(se)){if(T.push(ie),I=se.depth,T.length>=O)break;continue}for(let P of o.adjacency.get(se.key)||[]){let G=Yt(P.key),H=Fl(se,G),be=se.depth+1;if(be>I)continue;let F=`${P.key}|${H}`,U=b.get(F);if(U==null)b.set(F,be),C.set(F,[ie]),c.push({key:P.key,col:G.col,row:G.row,incoming:H,depth:be});else if(U===be){let S=C.get(F)||[];S.length<$&&!S.includes(ie)&&S.push(ie),C.set(F,S)}}}let X=[],ae=(se,ie)=>{if(X.length>=ee)return;let[P]=se.split("|"),G=[Yt(P),...ie];if(se===l||P===r){X.push(G);return}for(let H of C.get(se)||[])ae(H,G)};for(let se of T)ae(se,[]);let he=[],re=new Set;for(let se of X){let ie=se.map(P=>$e(P.col,P.row)).join(">");re.has(ie)||(re.add(ie),he.push(se))}return n.cacheKey&&o.pathCache.set(i,he.map(se=>se.map(ie=>({...ie})))),he}function ci(e){let t=_e(e),n=new Map;for(let[o,r]of t.components.entries())n.set(o,{id:o,cells:[...r.cells],capacity:r.capacity,count:0,ratio:0});return{components:n,cellToComponent:new Map(t.cellToComponent)}}function ui(e,t,n){let o=_e(e),r=null,i=1/0;for(let l of o.cells){let c=te(l),b=B(c.col,c.row),C=Math.hypot(b.x-t,b.y-n);CB(o.col,o.row));return t&&n.push(t),n}function dt(e,t){t&&(!e.length||Lr(e[e.length-1],t)>1)&&e.push(t)}function Bl(e,t,n,o=null){let r=[{x:e.x,y:e.y}];dt(r,B(t.col,t.row));for(let i of Bn(n,o))dt(r,i);return r}function Ll(e,t){let n=Bn(e),o=Re(t,"inputA");return o&&dt(n,B(o.col,o.row)),dt(n,ye(t)),n}function Ol(e,t,n,o){let r=[{x:e.x,y:e.y}];dt(r,B(t.col,t.row));for(let l of Bn(n))dt(r,l);let i=Re(o,"inputA");return i&&dt(r,B(i.col,i.row)),dt(r,ye(o)),r}function Nl(e,t,n=0){let o=B(t.col,t.row),r=0;for(let i of e.chicks||[]){if(i.stage==="flying"||i.stage==="queued")continue;Math.hypot(i.x-o.x,i.y-o.y){let I=C.roleBias??0,$=T.roleBias??0;if(I!==$)return I-$;let O=C.cells?.length??C.route?.length??Number.POSITIVE_INFINITY,ee=T.cells?.length??T.route?.length??Number.POSITIVE_INFINITY;if(O!==ee)return O-ee;let X=C.key||JSON.stringify(C.route||C.cells||C),ae=T.key||JSON.stringify(T.route||T.cells||T);return X.localeCompare(ae)});if(!o||r.length===1)return r[0];let i=r[0].roleBias??0,l=r.filter(C=>(C.roleBias??0)===i),c=Math.min(...l.map(C=>ri(e,C)));l=l.filter(C=>ri(e,C)===c);let b=e.branchCounters.get(t)||0;return e.branchCounters.set(t,b+1),l[Math.floor(Math.random()*l.length)]}function di(e){return e.role===0?{left:{match:"male",destination:"mixer"},right:{match:"default",destination:"scanner-role-1"}}:{left:{match:"poop",destination:"trash"},right:{match:"default",destination:"truck"}}}function Do(e){let t=di(e);return{left:t.left.destination,right:t.right.destination}}function Io(e,t){return di(e).left.match===t.sex?"left":"right"}function $o(e){return Nr(e)}function Fo(e){return{mixer:"#2477ff",truck:"#ff6aa8",trash:"#22b94f","scanner-role-1":"#526456",scanner:"#526456",input:"#526456"}[e]||"#102015"}function Dt(e,t,n=!1){let o=_e(e),r=(o.farmOutputs.get(t.id)||[]).map(Yt),i=[];for(let b of r){let C=I=>o.scannerInputs.has($e(I.col,I.row));C.cacheKey=`farmInput:${b.col},${b.row}:v${o.version}`;let T=Ao(e,b,C);for(let I of T){let $=I[I.length-1],O=o.scannerInputs.get($e($.col,$.row)),ee=At(e,O);ee&&i.push({key:`${ee.id}:${$.col},${$.row}:${I.length}`,scanner:ee,cells:I})}}let l=$n(e,`farm:${t.id}`,i,n);if(l)return{scannerId:l.scanner.id,route:Ll(l.cells,l.scanner)};let c=$n(e,`farm:${t.id}:output`,r.map(b=>({key:A(b.col,b.row),cells:[b]})),n);return c?{scannerId:null,route:Bn(c.cells)}:null}function fi(e,t,n,o,r=!1){let i=At(e,o);if(!i)return null;let c=_e(e).scannerPorts.get(i.id)?.[t],b=Re(i,t),C=c?.connected?(c.keys||[c.key]).filter(Boolean).map(Yt):[];if(!b||!C.length)return null;let T=Do(i)[t];return T==="scanner-role-1"?_l(e,i,t,n,b,C,r):Gl(e,i,t,n,b,C,T,r)}function _l(e,t,n,o,r,i,l){let c=_e(e),b=e.scanners.filter(I=>I.id!==t.id&&c.scannerPorts.get(I.id)?.inputA?.connected),C=[];for(let I of i)for(let $ of b){let O=c.scannerPorts.get($.id)?.inputA?.key;if(!O)continue;let ee=(c.scannerPorts.get($.id)?.inputA?.keys||[O]).filter(Boolean),X=re=>ee.includes($e(re.col,re.row));X.cacheKey=`toScanner:${I.col},${I.row}:${$.id}:v${c.version}`;let ae=Ao(e,I,X),he=$.role===1?0:1;for(let re of ae)C.push({key:`${he}:start${A(I.col,I.row)}:s${$.id}:${re.length}:${A(re[re.length-1].col,re[re.length-1].row)}`,target:$,cells:re,roleBias:he})}let T=$n(e,`scanner:${t.id}:${n}:toRole1`,C,l);return T?{destination:"scanner",nextScannerId:T.target.id,route:Ol(o,r,T.cells,T.target)}:null}function Gl(e,t,n,o,r,i,l,c){let b=_e(e),C=[...b.facilityPorts.entries()].filter(([$,O])=>O?.connected&&Fn(e.facilities?.[$])===l);if(!C.length)return null;let T=[];for(let $ of i)for(let[O,ee]of C){let X=(ee.keys||[ee.key]).filter(Boolean);if(!X.length)continue;let ae=re=>X.includes($e(re.col,re.row));ae.cacheKey=`toFacility:${$.col},${$.row}:${O}:v${b.version}`;let he=Ao(e,$,ae);for(let re of he)T.push({key:`start${A($.col,$.row)}:${O}:${re.length}:${A(re[re.length-1].col,re[re.length-1].row)}`,cells:re,facilityId:O})}let I=$n(e,`scanner:${t.id}:${n}:${l}`,T,c);return I?{destination:l,facilityId:I.facilityId,route:Bl(o,r,I.cells,xl(e,I.facilityId))}:null}function pi(e,t,n=new Set){if(!t||n.has(t.id))return!1;n.add(t.id);for(let o of["left","right"]){let r=fi(e,o,ye(t),t.id,!1);if(r){if(["mixer","trash","truck"].includes(r.destination))return!0;if(r.destination==="scanner"){let i=At(e,r.nextScannerId);if(pi(e,i,n))return!0}}}return!1}function Ul(e,t){return!!Dt(e,t,!1)?.scannerId}function Ln(e){if(e.phase!=="build")return[];let t=[];for(let n of e.eggFarms||[])Ul(e,n)||t.push({type:"eggFarm",id:n.id,ref:n,message:"This Egg will not produce chicks"});for(let n of cn)for(let[o,r]of Po(e,n))_e(e).facilityPorts.get(o)?.connected||t.push({type:"facility",id:o,ref:r,message:"This facility cannot receive items"});return t}function Wl(e){let t=_e(e);for(let r of e.eggFarms||[]){let i=Dt(e,r,!1);if(!i?.scannerId)continue;let l=At(e,i.scannerId);if(pi(e,l))return[]}let n=e.eggFarms?.length||0,o=[...t.facilityPorts.entries()].filter(([r,i])=>i?.connected&&["mixer","trash","truck"].includes(Fn(e.facilities?.[r]))).length;return n?t.metrics.farmOutputs?e.scanners?.length?o?["Connect at least one EGG through a scanner to any valid exit."]:["Connect at least one receiver exit: Mixer, Shredder, or Truck."]:["Build at least one scanner and connect it to an EGG route."]:["Connect at least one EGG to a conveyor."]:["Build at least one EGG before starting the next day."]}function In(e){return e.kind==="manual"?`S${(e.slot??0)+1}`:`Auto Scanner #${e.id}`}function Kl(e,t=_e(e),n={}){let o=n.includeRoutes!==!1,r=[],i={mixer:"Mixer",trash:"Shredder",truck:"Truck"};for(let l of cn){let c=Po(e,l);if(!c.length){r.push(`${i[l]||l} is missing`);continue}for(let[b]of c)t.facilityPorts.get(b)?.connected||r.push(`${i[l]||l} receiver has no conveyor`)}for(let l of e.scanners){let c=t.scannerPorts.get(l.id)||{};if(c.inputA?.connected||r.push(`${In(l)} input has no conveyor`),c.left?.connected||r.push(`${In(l)} left output has no conveyor`),c.right?.connected||r.push(`${In(l)} right output has no conveyor`),!!o)for(let b of["left","right"])c[b]?.connected&&!fi(e,b,ye(l),l.id)&&r.push(`${In(l)} ${b} route is incomplete`)}if(o)for(let l of e.eggFarms)Dt(e,l)?.scannerId||r.push(`Egg Farm #${l.id} has no scanner route`);else for(let l of e.eggFarms)(t.farmOutputs.get(l.id)||[]).length||r.push(`Egg Farm #${l.id} has no output conveyor`);return[...new Set(r)]}function fn(e){return Wl(e)}function yi(e){return fn(e).length===0}var hi=[{key:"premiumFemaleShipment",target:"female",truckTarget:"female",title:"Premium Female Shipment",route:"Female -> Truck",note:"Today only: ship female chicks to Truck. Meet the export target for a bonus.",objective:"truckTarget"},{key:"contaminantSampleExport",target:"poop",truckTarget:"poop",title:"Contaminant Sample Export",route:"Poop value x2",note:"Today only: poop is valid Truck cargo and all poop income is doubled.",objective:"truckTarget",poopValueMultiplier:2},{key:"healthInspection",title:"Health Inspection",route:"Poop -> Shredder",note:"Today only: poop mistakes are fined double. Shred enough poop for an inspection bonus.",objective:"poopTrash",poopFineMultiplier:2},{key:"conveyorJamWarning",title:"Conveyor Jam Warning",route:"No explosions",note:"Today only: jam explosions trigger at 85% congestion. Finish with zero explosions for a bonus.",objective:"noExplosion",congestionExplosionThreshold:.85,congestionWarningThreshold:.68},{key:"powerSavingOrder",title:"Power Saving Order",route:"Slow factory subsidy",note:"Today only: conveyors -20% speed and Auto Scanners +20% cooldown. A subsidy is paid at settlement.",objective:"flatBonus",conveyorSpeedMultiplier:.8,autoScannerCooldownMultiplier:1.2},{key:"overtimeDay",title:"Overtime Day",route:"80 second day",note:"Today only: the work day is longer. No extra reward or penalty.",objective:"none",daySeconds:80},{key:"shortShift",title:"Short Shift",route:"40 second day",note:"Today only: the work day is shorter. The next Fairies tribute is reduced by 10%.",objective:"none",daySeconds:40,fairiesTributeMultiplier:.9},{key:"chickBoom",title:"Chick Boom",route:"EGG interval x0.65",note:"Today only: eggs hatch faster and poop rate rises by 5 percentage points.",objective:"none",productionMultiplier:1/.65,poopRateAdd:.05},{key:"rottenFeed",title:"Rotten Feed",route:"Poop surge",note:"Today only: poop rate rises by 20 percentage points and Shredder poop income is multiplied by 1.5.",objective:"none",poopRateAdd:.2,shredderIncomeMultiplier:1.5},{key:"maintenanceAudit",title:"Maintenance Audit",route:"Durability check",note:"Today only: machines below 50% remaining durability fail the audit. Passing with none below 50% pays a bonus.",objective:"maintenanceAudit"}];function we(e,t=0){let n=Number(e);return Number.isFinite(n)?n:t}function Hl(e,t=0,n=1){let o=Math.max(1,Number(e?.turn||1)+1),r=Math.floor(Bo(e)*(.08+Math.random()*.08)),i=Math.floor(Math.max(0,e.cash||0)*.25),l=Math.floor(Math.max(0,t)*Math.max(1,o)*.75);return Math.max(120,Math.ceil(Math.max(r,i,l)*n))}function mi(e){return Math.max(0,Math.ceil(500+Math.max(1,e?.turn||1)*25))}function Bo(e){return[...e.eggFarms.map(t=>t.price||0),...e.scanners.map(t=>t.price||0),...Object.values(e.facilities).map(t=>t.price||0),...[...e.conveyorMeta.values()].map(t=>t.price||0)].reduce((t,n)=>t+n,0)}function ql(e,t=1,n=gt){return e.eggFarms.reduce((o,r)=>{let[i,l]=dn(r),c=Math.max(.1,(i+l)/2);return o+Math.max(1,n)/c*Math.max(.01,t||1)},0)}function Yl(e,t){let n=we(t.productionMultiplier,1),o=we(t.daySeconds,gt),r=ql(e,n,o),i=Math.max(0,Number(e?.cardEffects?.hatchingFeed)||0),l=Math.max(0,Number(e?.cardEffects?.poopRateBooster)||0),c=Math.pow(1.03,i),b=bo+vo*l,C=Math.min(.95,Math.max(0,(b+we(t.poopRateAdd,0))*we(t.poopMultiplier,1)*c));return{estimate:r,poopRate:C}}function bi(e){if(e.turn+1Ir)return null;let n=hi[Math.floor(Math.random()*hi.length)],{estimate:o,poopRate:r}=Yl(e,n),i=0;n.objective==="truckTarget"?i=Math.max(1,Math.ceil(o*.3)):n.objective==="poopTrash"&&(i=Math.max(1,Math.ceil(o*r*.8)));let l=0;return["truckTarget","poopTrash","noExplosion"].includes(n.objective)&&(l=Hl(e,o)),n.objective==="flatBonus"&&(l=mi(e)),n.objective==="maintenanceAudit"&&(l=mi(e)),{id:`event-${e.turn}-${Date.now()}-${Math.floor(Math.random()*9999)}`,...n,target:n.target||null,truckTarget:n.truckTarget||null,forced:!0,productionMultiplier:we(n.productionMultiplier,1),poopMultiplier:we(n.poopMultiplier,1),poopRateAdd:we(n.poopRateAdd,0),daySeconds:we(n.daySeconds,gt),targetAmount:i,estimatedOutput:Math.round(o),reward:l,createdTurn:e.turn,oneTurnOnly:!0}}function vi(e){e.eventActive=e.eventOffer?{...e.eventOffer}:null,e.eventOffer=null}function wi(e){e.eventActive=null}function Si(e){return Math.max(1,we(e.eventActive?.daySeconds,gt))}function ki(e){return we(e.eventActive?.productionMultiplier,1)}function Ci(e){let t=Math.max(0,Number(e?.cardEffects?.hatchingFeed)||0),n=Math.max(0,Number(e?.cardEffects?.poopRateBooster)||0),o=Math.pow(1.03,t),r=bo+vo*n,i=we(e.eventActive?.poopRateAdd,0);return Math.min(.95,Math.max(0,(r+i)*we(e.eventActive?.poopMultiplier,1)*o))}function je(e){return e.eventActive?.truckTarget||e.eventActive?.target||"female"}function Lo(e,t){return t==="male"?e.truckMale||0:t==="poop"?e.poopTruck||0:e.truckFemale||0}function Mi(e,t){return je(e)===t}function gi(e){return je(e)!=="male"}function Oo(e){return Math.max(.01,we(e.eventActive?.poopValueMultiplier,1))}function On(e){return Math.max(.01,Oo(e)*we(e.eventActive?.shredderIncomeMultiplier,1))}function No(e){return Math.max(.01,we(e.eventActive?.poopFineMultiplier,1))}function _o(e){return Math.max(.1,Math.min(1,we(e.eventActive?.congestionExplosionThreshold,1)))}function xi(e){return Math.max(.1,Math.min(1,we(e.eventActive?.congestionWarningThreshold,.8)))}function Ti(e){return Math.max(.01,we(e?.fairiesTributeMultiplier,1))}function Vl(e){let t=0,n=(o,r)=>{let i=Math.max(1,we(r,1)),l=Math.max(0,we(o,0));1-Math.min(1,l/i)<.5&&(t+=1)};for(let o of e.conveyorMeta?.values?.()||[])n(o.uses,o.durability);for(let o of e.eggFarms||[])n(o.maintenance?.uses,o.maintenance?.durability);for(let o of e.scanners||[])o.kind==="auto"&&n(o.maintenance?.uses,o.maintenance?.durability);for(let o of Object.values(e.facilities||{})){let r=o?.baseId||o?.id;(r==="mixer"||r==="trash")&&n(o.maintenance?.uses,o.maintenance?.durability)}return t}function Ei(e){let t=e.eventActive;if(!t)return null;let n=0,o=!0,r=0,i="";t.objective==="truckTarget"?(n=Lo(e.stats,t.target),o=n>=t.targetAmount,r=o?t.reward:0):t.objective==="poopTrash"?(n=e.stats.poopTrash||0,o=n>=t.targetAmount,r=o?t.reward:0):t.objective==="noExplosion"?(n=e.stats.explosions||0,o=n===0,r=o?t.reward:0,i=`${n} explosion(s)`):t.objective==="flatBonus"?(o=!0,r=t.reward):t.objective==="maintenanceAudit"?(n=Vl(e),o=n===0,o&&(r=t.reward),i=`${n} machine(s) below 50%`):o=!0,r>0?(Ge(e,r),e.stats.eventBonus=(e.stats.eventBonus||0)+r,e.totals.eventBonus+=r,e.totals.eventSuccess+=1):t.objective&&t.objective!=="none"&&(e.stats.eventBonus=e.stats.eventBonus||0,e.totals.eventFailed+=o?0:1,o&&(e.totals.eventSuccess+=1));let l={title:t.title,key:t.key,target:t.target,route:t.route,objective:t.objective,targetAmount:t.targetAmount||0,count:n,success:o,bonus:r,reward:t.reward||0,productionMultiplier:t.productionMultiplier,poopMultiplier:t.poopMultiplier,daySeconds:t.daySeconds,detail:i};return e.stats.eventResult=l,l}function Go(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function zl(e){return!!e?.cardEffects?.usedMachineActive}function Xl(e,t){return t?1:Math.min(.8,.5+.1*Math.min(3,Go(e,"recyclingSubsidy")))}function Ql(e){return Math.pow(.95,Go(e,"safetyCover"))}function Nn(e){let t=e?.ref||e||{},n=e?.type||t.type;return n==="conveyor"?t.price||ve[t.kind]?.price||ve.conveyor.price:n==="eggFarm"?t.price||ve.eggFarm.price:n==="scanner"?t.price||(t.kind==="auto"?ve.autoScanner.price:ve.manualScanner.price):n==="facility"?t.price||ve[t.id]?.price||0:n==="maintenanceRoom"?t.price||ve.maintenanceRoom.price:ve[t.id]?.price||0}function Oe(e,t=null){let n=ve[e]?.price||0;return zl(t)?Math.ceil(n*.5):n}function Jl(e,t){return e?.facilities?Object.values(e.facilities).filter(n=>(n?.baseId||n?.id)===t).reduce((n,o)=>n+Math.max(0,(o.level||1)-1),0):0}function yt(e,t){return Fr.includes(t)?Math.pow(Ce.incomeUpgradeRate,Jl(e,t)):1}function ze(e){return Math.ceil(Ce.income.mixer*yt(e,"mixer"))}function Fe(e){return Math.ceil(Ce.income.truck*yt(e,"truck"))}function pn(e){return Math.ceil(Ce.poopFine*yt(e,"mixer")*No(e))}function yn(e){return Math.ceil(Ce.poopFine*yt(e,"truck")*No(e))}function Uo(e){let t=Ce.maleTruckFinePerHalfDay*(e.turn/2);return Math.ceil(t*yt(e,"truck"))}function Wo(e){return e?.facilities?Object.values(e.facilities).filter(t=>(t?.baseId||t?.id)==="trash").reduce((t,n)=>t+Math.max(0,(n.level||1)-1),0):0}function It(e){return Math.min(Ce.shredderBonus.maxCards,Wo(e))}function Vt(){return Ce.shredderBonus.maxCards}function ht(e){let t=typeof e=="number"?e:It(e),n=Math.min(Ce.shredderBonus.maxCards,Math.max(0,t));return n>0?Math.ceil(n*(Ce.shredderBonus.incomePerUpgrade||1)):0}function jl(e){let t=It(e),n=ht(t),o=Math.ceil(n*On(e));return{cards:t,chance:o>0?1:0,amount:o,expected:o,baseAmount:n}}function Ri(e){let t=jl(e);return t.amount>0&&(e.stats.shredderBonus=(e.stats.shredderBonus||0)+t.amount,e.totals.shredderBonus=(e.totals.shredderBonus||0)+t.amount,Ge(e,t.amount)),t}function _n(e,t=e.turn,n=null){let o=Math.max(1,Math.floor(Number(t)||1)),r=Ce.fairiesTribute||{perDay:10,profitExemption:300,legalWorkExemptionBonus:250,profitRate:.12},i=Math.ceil(o*(r.perDay||10)),l=Math.max(0,Math.floor(Number(n??e?.lastResult?.profit??e?.stats?.profit??0)||0)),c=Math.max(0,e?.cardEffects?.legalWork||0),b=Math.max(0,(r.profitExemption||0)+c*(r.legalWorkExemptionBonus||0)),C=Math.max(0,l-b),T=Math.ceil(C*Math.max(0,Number(r.profitRate)||0)),I=i+T,$=Math.max(0,e?.cardEffects?.fairiesFlatteryNext||e?.cardEffects?.flattery||0),O=$>0?Math.pow(.5,$):1,ee=Math.max(.01,Number(e?.pendingFairiesTributeMultiplier)||1),X=O*ee,ae=Math.max(0,Math.ceil(I*X)),he=Math.max(0,I-ae);return{day:o,base:i,profit:l,legalWork:c,profitExemption:b,taxableProfit:C,profitTribute:T,gross:I,flatteryCount:$,eventMultiplier:ee,perCardReduction:Math.ceil(I*.5),reduction:he,amount:ae}}function mt(e,t){let n=e?.ref||e||{},o=e?.type==="conveyor"?t?.conveyorMeta?.get(e.oldKey||n.id):n,r=o?.price||Nn(e||n),i=o?.builtSession===t?.buildSession;if(o?.noRefund||n?.noRefund)return{amount:0,sameBuild:i,price:r,rate:0,noRefund:!0};let l=Xl(t,i);return{amount:Math.max(0,Math.ceil(r*l)),sameBuild:i,price:r,rate:l,noRefund:!1}}function Zl(e,t=null){let n=Math.max(1,Math.ceil((Number(e)||0)/Ce.explosionDamageDivisor));return Math.max(1,Math.ceil(n*Ql(t)))}function ea(e,t){return Math.max(0,Math.ceil(t))}function Pi(e,t){e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,t>=0?(e.stats.revenue+=t,e.totals.revenue+=t):(e.stats.penalty+=Math.abs(t),e.totals.penalty+=Math.abs(t)),e.totals.maxCash=Math.max(e.totals.maxCash,e.cash)}function Ge(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&Pi(e,n),n}function bt(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&Pi(e,-n),n}function $t(e,t){bt(e,t)}function Ai(e,t){t<=0||(e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,e.totals.maxCash=Math.max(e.totals.maxCash,e.cash))}function Di(e){let t=ze(e);return e.stats.mixerRevenue+=t,Ge(e,t),t}function Ii(e){let t=pn(e);return e.stats.mixerPoopFine+=t,e.totals.mixerPoopFine+=t,bt(e,t),t}function $i(e){let t=yn(e);return e.stats.truckPoopFine+=t,e.totals.truckPoopFine+=t,bt(e,t),t}function Fi(e){let t=Uo(e);return e.stats.maleTruckFine+=t,e.totals.maleTruckFine+=t,bt(e,t),t}function Bi(e,t){let n=Zl(t,e);return e.stats.explosionDamage+=n,e.totals.explosionDamage+=n,bt(e,n),n}function Li(e){let t=je(e),n=Lo(e.stats,t),o=t==="poop"?Math.ceil(Fe(e)*Oo(e)):Fe(e),r=n*o,i=ea(e,r);return e.stats.pendingTruckRevenue=i,e.stats.truckRevenue=i,t==="poop"?e.stats.poopShipmentIncome=i:e.stats.chickShipmentIncome=i,i>0&&Ge(e,i),{base:r,adjusted:i,target:t,targetCount:n,unitPrice:o}}function Oi(e,t=e.turn,n=null,o={}){let r=_n(e,t,n);return e.cardEffects&&(e.cardEffects.fairiesFlatteryNext=0,e.cardEffects.flattery!=null&&delete e.cardEffects.flattery),e.pendingFairiesTributeMultiplier!=null&&(e.pendingFairiesTributeMultiplier=1),r.amount<=0||(o.recordStats?(e.stats.fairiesTribute=(e.stats.fairiesTribute||0)+r.amount,e.totals.fairiesTribute=(e.totals.fairiesTribute||0)+r.amount,bt(e,r.amount)):(e.totals.fairiesTribute=(e.totals.fairiesTribute||0)+r.amount,e.totals.penalty=(e.totals.penalty||0)+r.amount,e.totals.profit=(e.totals.profit||0)-r.amount,e.cash-=r.amount)),r}function Ni(e){let t=Go(e,"chemicalWeaponSubsidy"),n=Math.max(0,e?.stats?.poopTruck||0),o=Ce.chemicalWeaponSubsidy||{poopPerBlock:70,yenPerBlock:1200},r=Math.floor(n/Math.max(1,o.poopPerBlock||70)),i=t>0&&r>0?r*Math.max(0,o.yenPerBlock||1200)*t:0;return i>0&&(e.stats.chemicalWeaponSubsidy=(e.stats.chemicalWeaponSubsidy||0)+i,e.totals.chemicalWeaponSubsidy=(e.totals.chemicalWeaponSubsidy||0)+i,Ge(e,i)),{cards:t,poopTruck:n,blocks:r,amount:i}}function _i(e){let t=Bo(e),n=Math.max(1,e.totals.turnsCompleted||e.turn||1),o=Math.max(0,e.cash+e.totals.revenue+t*.5+e.totals.eventBonus*.5),r=Math.ceil(o/n),i=Math.floor(n*35+Math.max(0,n-5)*15),l=e.totals.correct*5,c=e.totals.explosionDamage;return{score:Math.max(0,Math.floor(o+r+l-e.totals.penalty-i)),factoryValue:t,base:o,dailyEarned:r,dayPenalty:i,correctBonus:l,explosionPenalty:c,days:n}}function ta(e){return{...e,keys:e.keys?{left:{...e.keys.left},right:{...e.keys.right}}:null,queue:[],cooldown:e.cooldown||0}}function hn(e){return JSON.stringify({cash:e.cash,stats:e.stats,totals:e.totals,nextId:e.nextId,gridX:f.x,gridY:f.y,gridCols:e.gridCols||f.cols,gridRows:e.gridRows||f.rows,gridExpansionPurchases:e.gridExpansionPurchases||0,gridExpansionPurchasesByDirection:e.gridExpansionPurchasesByDirection||{right:0,up:0},gridChunkOriginY:e.gridChunkOriginY||0,ownedCells:[...e.ownedCells||[]],ownedChunks:[...e.ownedChunks||[]],blockedCells:[...e.blockedCells||[]],selected:e.selected,multiSelected:e.multiSelected||[],buildTool:e.buildTool,view:e.view,facilities:e.facilities,eggFarms:e.eggFarms,scanners:e.scanners.map(ta),conveyorTiles:[...e.conveyorTiles],conveyorMeta:[...e.conveyorMeta.entries()],branchCounters:[...e.branchCounters.entries()],cardEffects:e.cardEffects,cardDraft:e.cardDraft,cardTargetPick:e.cardTargetPick})}function Gi(e,t){let n=JSON.parse(t);e.cash=n.cash,e.stats=n.stats,e.totals=n.totals,e.nextId=n.nextId,f.x=n.gridX??Y.grid.x,f.y=n.gridY??Y.grid.y,f.cols=n.gridCols||Y.grid.cols,f.rows=n.gridRows||Y.grid.rows,e.gridCols=f.cols,e.gridRows=f.rows,e.gridExpansionPurchases=n.gridExpansionPurchases||0,e.gridExpansionPurchasesByDirection=n.gridExpansionPurchasesByDirection||{right:0,up:0},e.gridChunkOriginY=n.gridChunkOriginY||0,e.ownedCells=new Set(n.ownedCells||[]),e.ownedChunks=new Set(n.ownedChunks||[]),e.gridOwnedCells=e.ownedCells.size||f.cols*f.rows,e.blockedCells=new Set(n.blockedCells||[]),e.selected=n.selected,e.multiSelected=n.multiSelected||[],e.buildTool=n.buildTool,e.view=n.view||{x:0,y:0,scale:1},e.view.scale==null&&(e.view.scale=1),e.facilities=n.facilities||{},e.eggFarms=n.eggFarms||[],e.scanners=(n.scanners||[]).map(o=>({...o,queue:[],cooldown:o.cooldown||0})),e.conveyorTiles=new Set(n.conveyorTiles||[]),e.conveyorMeta=new Map(n.conveyorMeta||[]),e.branchCounters=new Map(n.branchCounters||[]),e.cardEffects=n.cardEffects||{bearing:0,legalWork:0,fairiesFlatteryNext:0,scannerQueueSpacing:0},e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft=n.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardTargetPick=n.cardTargetPick||null,e.groupDrag=null,e.selectionBox=null,e.pan=null,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function Be(e){e.phase==="build"&&(e.undoStack.push(hn(e)),e.undoStack.length>80&&e.undoStack.shift(),e.redoStack=[])}function Ko(e){return e.phase!=="build"||!e.undoStack.length?!1:(e.redoStack.push(hn(e)),Gi(e,e.undoStack.pop()),!0)}function Ho(e){return e.phase!=="build"||!e.redoStack.length?!1:(e.undoStack.push(hn(e)),Gi(e,e.redoStack.pop()),!0)}function K(e,t,n,o,r=y.ink){e.floatingTexts.push({x:t,y:n,text:o,color:r,life:1,maxLife:1})}function Ft(e,t,n){e.shake.strength=Math.max(e.shake.strength,t),e.shake.time=Math.max(e.shake.time,n)}function Ui(e,t,n){e.effects.push({type:"spawn",priority:Me.ambient,x:t,y:n,life:.42,maxLife:.42,size:12})}function Wi(e,t,n,o=y.green){e.effects.push({type:"scannerPulse",priority:Me.important,x:t,y:n,color:o,life:.42,maxLife:.42,size:24})}function Ki(e,t,n){for(let o=0;o<12;o+=1)e.effects.push({type:"meat",priority:Me.important,x:t+W(-18,18),y:n+W(-12,16),vx:W(-60,60),vy:W(-90,-25),life:W(.45,.85),maxLife:.85,size:W(4,8)})}function Hi(e,t,n){for(let o=0;o<16;o+=1)e.effects.push({type:"sludge",priority:Me.important,x:t+W(-18,18),y:n+W(-12,16),vx:W(-46,46),vy:W(-70,-20),life:W(.45,.9),maxLife:.9,size:W(4,8)})}function qi(e,t,n,o){let r=o==="poop"?y.poop:o==="male"?y.male:y.female;for(let i=0;i<22;i+=1)e.effects.push({type:"shred",priority:Me.important,x:t+W(-16,16),y:n+W(-8,8),vx:W(-70,70),vy:W(40,160),color:i%3===0?y.white:r,life:W(.45,.95),maxLife:.95,w:W(3,7),h:W(10,24),rot:W(-Math.PI,Math.PI)});Xe(e,t,n,y.green,34,Me.important)}function Yi(e,t,n,o){let r=o==="poop"?y.poop:o==="male"?y.danger:y.green;for(let i=0;i<8;i+=1)e.effects.push({type:"load",priority:Me.important,x:t+W(-18,18),y:n+W(-18,18),vx:W(-42,42),vy:W(-90,-25),color:r,life:W(.35,.65),maxLife:.65,size:8})}function Xe(e,t,n,o=y.danger,r=52,i=Me.critical){e.effects.push({type:"shockwave",priority:i,x:t,y:n,color:o,life:.55,maxLife:.55,size:8,maxSize:r})}function Ze(e,t,n,o=12,r=y.danger,i=Me.critical){for(let l=0;l0&&(e.shake.time=Math.max(0,e.shake.time-t),e.shake.time<=0&&(e.shake.strength=0));for(let r of e.effects)if(r.life-=t,["meat","sludge","spark","smoke","shred","load","rage"].includes(r.type))r.x+=(r.vx||0)*t,r.y+=(r.vy||0)*t,r.vy=(r.vy||0)+150*t;else if(r.type==="flyingChick"){r.x+=r.vx*t,r.y+=r.vy*t,r.vy+=360*t,r.noDamage||na(e,r,o);let i=r.x+e.view.x,l=r.y+e.view.y;(i<-100||l<-100||i>n.width+100||l>n.height+100)&&(r.life=0)}e.effects=e.effects.filter(r=>r.life>0);for(let r of e.floatingTexts)r.life-=t,r.y-=34*t;e.floatingTexts=e.floatingTexts.filter(r=>r.life>0)}function na(e,t,n){t.hit||(t.hit=new Set);for(let o of n()){if(t.hit.has(o.id)||t.xo.x+o.w||t.yo.y+o.h)continue;t.hit.add(o.id);let r=Bi(e,o.price);K(e,t.x,t.y-10,`-${x(r)}`,y.danger),Xe(e,t.x,t.y,y.danger,30),Ze(e,t.x,t.y,5,y.danger),Ft(e,5,.18)}}var Ue=Y.maintenance;function Yo(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function Wn(e){let t=Math.min(1.4,1+.04*Math.min(10,Yo(e,"crowdedFarming"))),n=Math.pow(.95,Yo(e,"preventiveMaintenance"));return t*n}function oa(e){return Math.pow(1.03,Yo(e,"durabilityCoating"))}function Kn(e,t,n=1){let o=Ue.durability[t]||1e3;return Math.max(1,Math.ceil(o*Math.max(.1,n||1)*oa(e)))}function Xi(e){return Math.max(.1,Number(e?.durabilityBaseMultiplier)||1)}function ra(e,t=0){if(!e)return{x:f.x+f.cell*(.5+t*.55),y:f.y+f.rows*f.cell+84};let n=f.x+e.col*f.cell+f.cell,o=f.y+e.row*f.cell+f.cell;return{x:n,y:o}}function ia(e,t=0){let n=(e.maintenanceRooms||[])[t];return ra(n,t)}function Se(e){e.repairman||(e.repairman={active:!1,x:f.x+f.cell*.5,y:f.y+f.rows*f.cell+84,target:null,repairedToday:0}),Array.isArray(e.maintenanceRooms)||(e.maintenanceRooms=[]),Array.isArray(e.repairmen)||(e.repairmen=[]);for(let[t,n]of e.conveyorMeta||[]){n.uses==null&&(n.uses=0),n.maintenanceType==null&&(n.maintenanceType="conveyor"),n.kind||(n.kind="conveyor"),n.speedMultiplier||(n.speedMultiplier=n.kind==="boostConveyor"?2:1),n.branchMode||(n.branchMode="random");let o=Kn(e,"conveyor",Xi(n));(n.durability==null||n.durability0&&(n.processingCooldown=Math.max(0,n.processingCooldown-t))}function vn(e){Se(e);let t=[];for(let[n,o]of e.conveyorMeta||[])t.push({type:"conveyor",key:n,meta:o,label:`${o.kind==="boostConveyor"?"Boost Belt":"Belt"} ${n}`,center:B(te(n).col,te(n).row)});for(let n of e.eggFarms||[])t.push({type:"eggFarm",ref:n,label:`EGG #${n.id}`,center:B(n.col,n.row)});for(let n of(e.scanners||[]).filter(o=>o.kind==="auto"))t.push({type:"autoScanner",ref:n,label:`AUTO #${n.id}`,center:B(n.col,n.row)});for(let n of Object.values(e.facilities||{})){let o=Vn(n);["mixer","trash"].includes(o)&&t.push({type:o,ref:n,label:`${n.shortName||n.name||o} #${n.id}`,center:{x:n.x+n.w/2,y:n.y+n.h/2}})}return t}function Bt(e){return e.meta?zt(e):zt(e.ref)}function mn(e){return e.meta?Vo(e):Vo(e.ref)}function Un(e){return e.meta?zo(e):zo(e.ref)}function es(e,t){sa(e.meta?e:e.ref,Math.max(0,mn(e)-t))}function nr(e){return e.type==="conveyor"?`conveyor:${e.key}`:`${e.type}:${e.ref?.id||e.ref?.type||e.type}`}function ts(e,t=.02){Se(e);let n=Math.max(0,Number(t)||0),o=0;for(let r of vn(e)){let i=mn(r);es(r,Un(r)*n),o+=Math.max(0,i-mn(r))/Un(r)*100}return o}function ns(e){Se(e);let t=e.maintenanceRooms||[];e.repairmen=t.map((o,r)=>{let i=ia(e,r);return{id:`room-${o.id}`,roomId:o.id,active:!0,x:i.x,y:i.y,target:null,repairedToday:0}});let n=e.repairmen[0];e.repairman.active=!!n,e.repairman.target=n?.target||null,e.repairman.repairedToday=0,n&&(e.repairman.x=n.x,e.repairman.y=n.y)}function os(e){Se(e);for(let t of e.repairmen||[])t.active=!1,t.target=null;e.repairmen=[],e.repairman.active=!1,e.repairman.target=null}function aa(e,t){return t&&vn(e).find(o=>nr(o)===t.key)||null}function ca(e){let t=null;for(let n of vn(e)){let o=Bt(n);o<=.001||(!t||o>Bt(t))&&(t=n)}return t}function rs(e,t){Se(e);let n=e.repairmen?.length?e.repairmen:e.repairman?.active?[e.repairman]:[];if(!n.length||e.phase!=="running")return;let o=new Set(n.map(i=>i.target?.key).filter(Boolean));for(let i of n)ua(e,i,t,o);let r=n[0];r&&e.repairman!==r&&(e.repairman.active=!0,e.repairman.x=r.x,e.repairman.y=r.y,e.repairman.target=r.target,e.repairman.repairedToday=r.repairedToday||0)}function ua(e,t,n,o){if(!t.active)return;let r=aa(e,t.target);if((!r||Bt(r)<=.001)&&(t.target?.key&&o.delete(t.target.key),r=da(e,o)),!r){t.target=null;return}let i=nr(r);o.add(i),t.target={key:i,label:r.label};let l=Ue.repairman.walkSpeed,c=r.center.x-t.x,b=r.center.y-t.y,C=Math.hypot(c,b);if(C>8){let X=Math.min(C,l*n);t.x+=c/C*X,t.y+=b/C*X;return}let T=e?.cardEffects?.laborExploitation?.7:1,I=n/(Ue.repairman.secondsPerOnePercent*T*100),$=mn(r),O=I*Un(r);es(r,O);let ee=Math.max(0,($-mn(r))/Un(r)*100);t.repairedToday=(t.repairedToday||0)+ee,ee>0&&Math.random()<.02&&K(e,t.x,t.y-28,"REPAIR",y.green),Bt(r)<=.001&&(o.delete(i),t.target=null)}function da(e,t=new Set){let n=null;for(let o of vn(e)){if(t.has(nr(o)))continue;let r=Bt(o);r<=.001||(!n||r>Bt(n))&&(n=o)}return n||ca(e)}function fa(e){let t=0,n="none";for(let o of vn(e)){let r=Bt(o);r>t&&(t=r,n=o.label)}return{ratio:t,percent:Math.round(t*100),label:n}}function or(e){let t=fa(e),n=Qo(e);return{worst:t,avgBeltPerformance:n,repairman:e.repairman||null,repairmen:e.repairmen||[],rooms:e.maintenanceRooms||[]}}var pa=Ie.commonWeight,ya=Ie.rareWeight,ha=Ie.ultraRareWeight||.45,Lt=Ie.baseDraftSize,Qt=$r;function Xt(e,t){let n=Le(e);return Math.max(0,Number(n[t])||0)}function Le(e){e.cardEffects||(e.cardEffects={...wo});for(let[t,n]of Object.entries(wo))e.cardEffects[t]==null&&(e.cardEffects[t]=Array.isArray(n)?[]:n);return e.cardEffects.flattery!=null&&(e.cardEffects.fairiesFlatteryNext=Math.max(0,e.cardEffects.fairiesFlatteryNext||0)+Math.max(0,e.cardEffects.flattery||0),delete e.cardEffects.flattery),e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft||(e.cardDraft={pending:!1,choices:[],rerolls:0,picksRemaining:0}),e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardEffects}function fs(e){let t=Math.max(.5,1-.05*Math.min(10,Xt(e,"crowdedFarming"))),n=Math.pow(.96,Xt(e,"hatchingFeed"));return t*n}function ps(e,t=null){return Math.min(3,Math.max(0,Number(t?.extraEggOutlet)||0))}function ys(e){return Math.pow(.85,Xt(e,"scannerQueueSpacing"))}function Xn(e,t=null){let n=Le(e),o=Tn*Math.pow(En,Math.max(0,n.bearing||0)),r=t?Math.max(.1,Number(e?.conveyorMeta?.get?.(t)?.speedMultiplier)||1):1,i=t?1:Qo(e),l=Math.max(.01,Number(e?.eventActive?.conveyorSpeedMultiplier)||1);return Math.min(Wt,o*i)*r*l}function nt(e,t=null){let n=Math.max(0,(e?.level||1)-1),o=t?Xt(t,"autoScannerTuning"):0,r=xn*Math.pow(Dr,n)*Math.pow(ho,o),i=Math.max(mo,r),l=t?Math.max(.01,Number(t?.eventActive?.autoScannerCooldownMultiplier)||1):1;return t?Math.max(mo,i*qn(e)*l):i}function is(e){let t=e.cardDraft||{rerolls:0},n=Math.max(1,(t.rerolls||0)+1);return Math.ceil(Math.max(1,e.turn||1)/Ie.rerollCost.dayDivisor*n*Ie.rerollCost.multiplier)}function Jt(e){return Qt.find(t=>t.id===e)||null}function hs(e,t){let n=typeof t=="string"?Jt(t):t;return Le(e),!n||!(n.type==="equipmentUpgrade"||n.type==="cellAction")?[]:We(e,n).map(o=>({key:tt(o),label:sr(e,o),type:o.type}))}function ir(e,t,n={}){let o=typeof t=="string"?Jt(t):t;if(Le(e),!o||o.type==="dud")return{ok:!1,reason:"Card not found."};if(o.id==="extraCards")return e.cardDraft=e.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.choices.push(...zn(e,2)),{ok:!0,reason:`${o.title} added 2 draft cards.`};if(o.type==="instant")return bs(e,o),{ok:!0,reason:`${o.title} granted.`};if(o.type==="equipmentUpgrade"){let r=We(e,o);if(!r.length)return{ok:!1,reason:`No valid target for ${o.title}.`};let i=n.targetKey&&n.targetKey!=="__auto__"?String(n.targetKey):"",l=i?r.find(c=>tt(c)===i):r[0];return l?(ms(e,l),{ok:!0,reason:`${o.title} applied to ${sr(e,l)}.`}):{ok:!1,reason:`Selected target is no longer valid for ${o.title}.`}}if(o.type==="cellAction"&&o.target==="blockedCell"){let r=We(e,o);if(!r.length)return{ok:!1,reason:"No blocked cells to remove."};let i=new Set((Array.isArray(n.targetKeys)?n.targetKeys:[n.targetKey]).filter(c=>c&&c!=="__auto__").map(String)),l=i.size?r.filter(c=>i.has(tt(c))):r.slice(0,3);if(!l.length)return{ok:!1,reason:`Selected target is no longer valid for ${o.title}.`};for(let c of l.slice(0,3)){e.blockedCells.delete(A(c.col,c.row));let b=B(c.col,c.row);et(e,b.x,b.y),Xe(e,b.x,b.y,y.danger,42),Ze(e,b.x,b.y,8,y.warn)}return me(e),{ok:!0,reason:`${o.title} removed ${Math.min(3,l.length)} blocked cell(s).`}}return{ok:!1,reason:`${o.title} cannot be debug-granted.`}}function sr(e,t){if(t.type==="blockedCell")return`Blocked cell ${t.col},${t.row}`;if(t.type==="eggFarm")return`EGG #${t.id} L${t.level} -> L${t.level+1}`;if(t.type==="eggOutlet"){let n=Math.max(0,Number(t.farm?.extraEggOutlet)||0);return`EGG #${t.id} OUTLET ${1+n} -> ${2+n}`}if(t.type==="scanner")return`AUTO #${t.id} L${t.level} -> L${t.level+1} | CD ${nt(t,e).toFixed(1)}s -> ${nt({...t,level:t.level+1},e).toFixed(1)}s`;if(t.type==="facility"&&(t.baseId||t.id)==="mixer"){let n=t.level,o=ze(e);t.level=n+1;let r=ze(e);return t.level=n,`MIXER L${t.level} -> L${t.level+1} | ${x(o)} -> ${x(r)}`}if(t.type==="facility"&&(t.baseId||t.id)==="truck"){let n=t.level,o=Fe(e);t.level=n+1;let r=Fe(e);return t.level=n,`TRUCK L${t.level} -> L${t.level+1} | ${x(o)} -> ${x(r)}`}if(t.type==="facility"&&t.id==="trash"){let n=It(e),o=Math.min(Vt(),n+1),r=ht(n),i=ht(o);return`SHREDDER L${t.level||1} -> L${(t.level||1)+1} | poop income ${x(r)} -> ${x(i)} per item`}return`${t.name||t.id} L${t.level||1} -> L${(t.level||1)+1}`}function ma(e){return[...e.blockedCells||[]].map(t=>{let[n,o]=String(t).split(",").map(Number);return{type:"blockedCell",id:t,col:n,row:o}}).filter(t=>Number.isFinite(t.col)&&Number.isFinite(t.row))}function We(e,t){let n=typeof t=="string"?Jt(t):t;return Le(e),n?n.target==="blockedCell"?ma(e):n.target==="eggFarm"?e.eggFarms.filter(o=>(o.level||1)<4):n.target==="eggOutlet"?e.eggFarms.filter(o=>Math.max(0,Number(o.extraEggOutlet)||0)<3).map(o=>({type:"eggOutlet",id:o.id,col:o.col,row:o.row,farm:o})):n.target==="autoScanner"?e.scanners.filter(o=>o.kind==="auto"):n.target==="mixer"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="mixer"):n.target==="truck"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="truck"):n.target==="trash"?Wo(e)(o.baseId||o.id)==="trash"):[]:[]:[]}function ba(e,t){let n=Le(e);if(t.id==="crowdedFarming")return(n.crowdedFarming||0)>=10;if(t.id==="recyclingSubsidy")return(n.recyclingSubsidy||0)>=3;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,Ie.dudChancePerCard||0)),r=Math.max(1e-4,Math.min(1,Ie.dudChanceReductionPerFilter||.05));return(n.dudFilter||0)>=Math.ceil(o/r)}return t.id==="laborExploitation"?!!n.laborExploitation:t.id==="usedMachine"?!!n.usedMachineActive:t.id==="newMachine"?!n.usedMachineActive:!1}function va(e){return!!((e.maintenanceRooms||[]).length||(e.repairmen||[]).length||e.repairman?.active)}function wa(e){return Qt.filter(t=>!(t.id==="laborExploitation"&&!va(e)||ba(e,t)||(t.type==="equipmentUpgrade"||t.type==="cellAction")&&We(e,t).length<=0))}function ss(e,t){return t.rarity==="ultraRare"?ha:t.rarity==="rare"?ya:pa}function Sa(e,t){let n=t.reduce((r,i)=>r+ss(e,i),0);if(n<=0)return t[Math.floor(Math.random()*t.length)];let o=Math.random()*n;for(let r of t)if(o-=ss(e,r),o<=0)return r;return t[t.length-1]}var ls=0;function ka(){return ls+=1,{id:`dud:${Date.now()}:${ls}`,title:"Dud",rarity:"dud",type:"dud",description:"Click to flick this dud away. It does not consume a pick."}}function Ca(e){let t=Le(e),n=Math.max(0,Math.min(1,Ie.dudChancePerCard||0)),o=Math.max(0,Math.min(1,Ie.dudChanceReductionPerFilter||0));return Math.max(0,n-o*Math.max(0,t.dudFilter||0))}function Ma(e,t){let n=[...t],o=0,r=Math.max(0,Ie.maxDudsPerDraft||0),i=Ca(e);for(let l=0;lc.id===i.id);l>=0&&r.splice(l,1)}return Ma(e,o)}function tt(e){return e?e.type==="blockedCell"?`blockedCell:${e.id}`:e.type==="eggFarm"?`eggFarm:${e.id}`:e.type==="eggOutlet"?`eggOutlet:${e.id}`:e.type==="scanner"?`scanner:${e.id}`:e.type==="facility"?`facility:${e.id}`:`${e.type}:${e.id}`:""}function as(e){if(!e)return null;if(e.type==="blockedCell"){let t=B(e.col,e.row);return{x:t.x-f.cell*.48,y:t.y-f.cell*.48,w:f.cell*.96,h:f.cell*.96,cx:t.x,cy:t.y}}if(e.type==="eggFarm"||e.type==="eggOutlet"){let t=B(e.col,e.row);return{x:t.x-34,y:t.y-34,w:68,h:68,cx:t.x,cy:t.y}}if(e.type==="scanner"){let t=ye(e);return{x:t.x-54,y:t.y-77,w:108,h:154,cx:t.x,cy:t.y}}return e.type==="facility"?{x:e.x,y:e.y,w:e.w,h:e.h,cx:e.x+e.w/2,cy:e.y+e.h/2}:null}function lr(e){if(!e.cardTargetPick?.pending)return[];if(e.cardTargetPick.mode==="autoScannerMenu"){let n=new Set(e.cardTargetPick.targetKeys||[]);return e.scanners.filter(o=>o.kind==="auto"&&n.has(tt(o))).map(o=>({key:tt(o),label:"AUTO ROUTE SETTINGS",target:o,bounds:as(o)})).filter(o=>o.bounds)}let t=new Set(e.cardTargetPick.targetKeys||[]);return We(e,e.cardTargetPick.cardId).filter(n=>t.has(tt(n))).map(n=>({key:tt(n),label:sr(e,n),target:n,bounds:as(n)})).filter(n=>n.bounds)}function ga(e,t){let n=lr(e);for(let o of n){let r=o.bounds;if(t.x>=r.x&&t.x<=r.x+r.w&&t.y>=r.y&&t.y<=r.y+r.h)return o.target}return null}function ms(e,t){if(t.type==="eggOutlet"){let n=t.farm||e.eggFarms.find(r=>r.id===t.id);if(!n)return;n.extraEggOutlet=Math.min(3,Math.max(0,Number(n.extraEggOutlet)||0)+1);let o=B(n.col,n.row);K(e,o.x,o.y-30,`OUTLET ${1+n.extraEggOutlet}`,y.green),me(e);return}if(t.level=(t.level||1)+1,t.type==="eggFarm"){t.nextSpawn=Rt(t),t.lastInterval=t.nextSpawn;let n=B(t.col,t.row);K(e,n.x,n.y-30,`LV ${t.level}`,y.green);return}if(t.type==="scanner"){let n=ye(t);K(e,n.x,n.y-34,`LV ${t.level}`,y.green);return}t.type==="facility"&&K(e,t.x+t.w/2,t.y+18,`LV ${t.level}`,y.green)}function bs(e,t){let n=Le(e),o=r=>{n[r]=Math.max(0,n[r]||0)+1};if(t.id==="bearing"&&o("bearing"),t.id==="autoScannerTuning"&&o("autoScannerTuning"),t.id==="legalWork"&&o("legalWork"),t.id==="crowdedFarming"&&(n.crowdedFarming=Math.min(10,(n.crowdedFarming||0)+1)),t.id==="hatchingFeed"&&o("hatchingFeed"),t.id==="poopRateBooster"&&o("poopRateBooster"),t.id==="safetyCover"&&o("safetyCover"),t.id==="recyclingSubsidy"&&(n.recyclingSubsidy=Math.min(3,(n.recyclingSubsidy||0)+1)),t.id==="chemicalWeaponSubsidy"&&o("chemicalWeaponSubsidy"),t.id==="preventiveMaintenance"&&o("preventiveMaintenance"),t.id==="dudFilter"&&o("dudFilter"),t.id==="durabilityCoating"&&(o("durabilityCoating"),Se(e)),t.id==="sparePartsBin"){o("sparePartsBin");let r=ts(e,.02);e.stats.sparePartsRepair=(e.stats.sparePartsRepair||0)+r,e.totals.sparePartsRepair=(e.totals.sparePartsRepair||0)+r,K(e,f.x+f.cols*f.cell/2,f.y-30,"REPAIR +2%",y.green)}t.id==="dudRefund"&&o("dudRefund"),t.id==="freeReroll"&&o("freeReroll"),t.id==="composter"&&o("composter"),t.id==="scannerQueueSpacing"&&o("scannerQueueSpacing"),t.id==="flattery"&&o("fairiesFlatteryNext"),t.id==="usedMachine"&&(n.usedMachineActive=!0),t.id==="newMachine"&&(n.usedMachineActive=!1),t.id==="laborExploitation"&&(n.laborExploitation=1),t.id==="rescueLoan"&&(o("rescueLoanCharges"),K(e,f.x+f.cols*f.cell/2,f.y-30,"RESCUE HELD",y.green))}function qe(e){return`${Math.round(Number(e||0)*100)}%`}function cs(e){let t=lt[Math.max(0,Math.min(lt.length-1,e-1))]||lt[0]||[0,0];return`${t[0].toFixed(2)}-${t[1].toFixed(2)}s`}function us(e,t){return Math.ceil(e*Math.pow(Ce.incomeUpgradeRate,Math.max(0,t-1)))}function ds(e,t,n){let r=We(e,t==="mixer"?"upgradeMixer":"upgradeTruck")[0];if(!r)return{before:us(n,1),after:us(n,2)};let i=t==="mixer"?ze(e):Fe(e),l=r.level||1;r.level=l+1;let c=t==="mixer"?ze(e):Fe(e);return r.level=l,{before:i,after:c}}function xa(e,t){let n=Le(e);if(t.id==="upgradeEgg"){let o=We(e,t),r=Math.min(3,Math.max(1,o[0]?.level||1));return`Choose one EGG. Level +1. Production interval ${cs(r)} -> ${cs(r+1)}.`}if(t.id==="upgradeAutoScanner"){let o=We(e,t)[0]||{level:1},r=nt(o,e),i=nt({...o,level:(o.level||1)+1},e);return`Choose one AUTO SCANNER. Level +1. Cooldown ${r.toFixed(2)}s -> ${i.toFixed(2)}s.`}if(t.id==="upgradeMixer"){let o=ds(e,"mixer",Ce.income.mixer);return`Choose one MIXER. Earning +10%. Male-chick income ${x(o.before)} -> ${x(o.after)}.`}if(t.id==="upgradeTruck"){let o=ds(e,"truck",Ce.income.truck);return`Choose one TRUCK. Earning +10%. Correct shipment income ${x(o.before)} -> ${x(o.after)}.`}if(t.id==="upgradeTrash"){let o=It(e),r=Math.min(Vt(),o+1),i=ht(o),l=ht(r);return`SHREDDER level +1. Poop income ${x(i)} -> ${x(l)} per item.`}if(t.id==="bearing"){let o=Math.min(Wt,Tn*Math.pow(En,Math.max(0,n.bearing||0))),r=Math.min(Wt,Tn*Math.pow(En,Math.max(0,(n.bearing||0)+1)));return`Conveyor speed +7.5%. After pick: ${o.toFixed(1)} -> ${r.toFixed(1)} px/s.`}if(t.id==="legalWork"){let o=Math.max(0,n.legalWork||0);return`Fairies tribute profit exemption +${x(250)}. After pick: exemption bonus ${x(250*(o+1))}.`}if(t.id==="crowdedFarming"){let o=Math.min(10,(n.crowdedFarming||0)+1);return`Held ${n.crowdedFarming||0}/10. After pick: EGG interval ${qe(Math.max(.5,1-.05*o))}, deterioration ${qe(Math.min(1.4,1+.04*o))}.`}if(t.id==="extraEggOutlet"){let o=We(e,t),r=Math.max(0,Number(o[0]?.farm?.extraEggOutlet)||0);return`Choose one EGG. Output ports ${1+r} -> ${2+r}. Max 4 ports per EGG.`}if(t.id==="hatchingFeed")return`Held ${n.hatchingFeed||0}. After pick: EGG interval ${qe(Math.pow(.96,(n.hatchingFeed||0)+1))}, poop rate multiplier ${qe(Math.pow(1.03,(n.hatchingFeed||0)+1))}.`;if(t.id==="poopRateBooster")return`Held ${n.poopRateBooster||0}. After pick: base poop rate +${Math.round((n.poopRateBooster||0)+1)*4} percentage points.`;if(t.id==="autoScannerTuning")return`Held ${n.autoScannerTuning||0}. After pick: all AUTO SCANNER default cooldown ${qe(Math.pow(ho,(n.autoScannerTuning||0)+1))}.`;if(t.id==="safetyCover")return`Held ${n.safetyCover||0}. After pick: explosion damage ${qe(Math.pow(.95,(n.safetyCover||0)+1))}.`;if(t.id==="recyclingSubsidy")return`Held ${n.recyclingSubsidy||0}/3. After pick: normal SELL refund ${Math.round(Math.min(.8,.5+.1*((n.recyclingSubsidy||0)+1))*100)}%.`;if(t.id==="chemicalWeaponSubsidy")return`Held ${n.chemicalWeaponSubsidy||0}. After pick: ${x(1200*((n.chemicalWeaponSubsidy||0)+1))} per 70 truck-shipped poop each day.`;if(t.id==="preventiveMaintenance")return`Held ${n.preventiveMaintenance||0}. After pick: deterioration speed ${qe(Math.pow(.95,(n.preventiveMaintenance||0)+1))}.`;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,Ie.dudChancePerCard||0)),r=Math.max(0,Math.min(1,Ie.dudChanceReductionPerFilter||.05)),i=Math.max(0,n.dudFilter||0),l=Math.max(0,o-r*i),c=Math.max(0,o-r*(i+1));return`Held ${i}. DUD chance per card ${qe(l)} -> ${qe(c)}.`}return t.id==="durabilityCoating"?`Held ${n.durabilityCoating||0}. After pick: maximum durability ${qe(Math.pow(1.03,(n.durabilityCoating||0)+1))}.`:t.id==="sparePartsBin"?`Held ${n.sparePartsBin||0}. Immediately restores 2% durability to every maintained machine. Common card weight.`:t.id==="dudRefund"?`Held ${n.dudRefund||0}. After pick: DUD clicks award ${x(50*((n.dudRefund||0)+1))}.`:t.id==="freeReroll"?`Held ${n.freeReroll||0}. After pick: each card screen starts with ${(n.freeReroll||0)+1} free reroll${(n.freeReroll||0)+1===1?"":"s"}.`:t.id==="composter"?`Held ${n.composter||0}. After pick: SHREDDER poop grants ${x(3*((n.composter||0)+1))}.`:t.id==="scannerQueueSpacing"?`Held ${n.scannerQueueSpacing||0}. After pick: Manual/Auto Scanner queue spacing ${qe(Math.pow(.85,(n.scannerQueueSpacing||0)+1))}.`:t.id==="flattery"?`Next Fairies tribute -50%. Held for next tribute: ${n.fairiesFlatteryNext||0}.`:t.id==="usedMachine"?"Enable Used Machines: future equipment costs 50%, has no SELL refund, and starts with 60% durability.":t.id==="newMachine"?"Cancel Used Machines. Future equipment returns to normal price, refund, and durability.":t.id==="laborExploitation"?"Repairman dispatch paperwork is streamlined. Repair rooms keep operating; one time only.":t.id==="rescueLoan"?`At day-end bankruptcy check, gain ${x(500)} if cash is below ${x(0)}. Held: ${n.rescueLoanCharges||0}.`:t.description}function rr(e,t){let n=e.cardDraft?.choices||[],o=n.findIndex(r=>r.id===t.id);o>=0&&n.splice(o,1)}function vs({game:e,ui:t,onUpdatePanels:n}){function o(){n&&n()}function r(){Le(e),e.cardTargetPick=null,e.cardDraft={pending:!0,choices:zn(e,Lt),rerolls:0,freeRerolls:Xt(e,"freeReroll"),picksRemaining:1}}function i(){Le(e),e.cardDraft.pending=!1,e.cardDraft.choices=[],e.cardDraft.picksRemaining=0,e.cardTargetPick=null,t.modal.classList.remove("visible","equipment-popover"),o()}function l(P=Lt){Le(e),e.cardDraft.choices=zn(e,P)}function c(){Le(e),!e.cardDraft.choices.length&&e.cardDraft.picksRemaining>0&&l(Lt)}function b(P){rr(e,P),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1),e.cardTargetPick=null,c(),e.cardDraft.picksRemaining<=0?i():ie()}function C(P){rr(e,P),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1)+Ie.extraCardsAddedPicks,e.cardDraft.choices.push(...zn(e,2)),ie()}function T(P,G){let H=Xt(e,"dudRefund")*50;if(H>0){let be=Ge(e,H);e.stats.dudRefundIncome=(e.stats.dudRefundIncome||0)+be,e.totals.dudRefundIncome=(e.totals.dudRefundIncome||0)+be,K(e,f.x+f.cols*f.cell/2,f.y-30,`DUD REFUND +${x(be)}`,y.green)}Ft(e,34,.62),document.body?.animate&&document.body.animate([{transform:"translate(0, 0)"},{transform:"translate(-10px, 7px)"},{transform:"translate(12px, -8px)"},{transform:"translate(-8px, -5px)"},{transform:"translate(9px, 6px)"},{transform:"translate(0, 0)"}],{duration:260,easing:"steps(5, end)"}),G&&(G.style.setProperty("--fling-x",`${260+Math.random()*260}px`),G.style.setProperty("--fling-y",`${-260-Math.random()*170}px`),G.style.setProperty("--fling-r",`${(Math.random()<.5?-1:1)*(52+Math.random()*38)}deg`),G.classList.add("flung")),window.setTimeout(()=>{rr(e,P),c(),ie()},340)}function I(P,G=null){if(P.type==="dud")return T(P,G);if(P.id==="extraCards")return C(P);if(P.type==="equipmentUpgrade"||P.type==="cellAction")return $(P);bs(e,P),b(P)}function $(P){let G=We(e,P);G.length&&(e.cardTargetPick={pending:!0,cardId:P.id,mode:P.target==="blockedCell"?"blockedCell":"equipment",targetKeys:G.map(tt),remaining:P.id==="dynamite"?Math.min(3,G.length):1},t.modal.classList.remove("visible","equipment-popover"),o())}function O(P){if(!P||P.type!=="blockedCell")return!1;let G=A(P.col,P.row);if(!e.blockedCells?.has(G))return!1;e.blockedCells.delete(G);let H=B(P.col,P.row);return et(e,H.x,H.y),Xe(e,H.x,H.y,y.danger,62),Ze(e,H.x,H.y,18,y.warn),Gn(e,H.x,H.y,8),Ft(e,16,.35),K(e,H.x,H.y-18,"BOOM",y.danger),me(e),e.cardTargetPick.remaining=Math.max(0,(e.cardTargetPick.remaining||1)-1),e.cardTargetPick.targetKeys=We(e,"dynamite").map(tt),o(),!0}function ee(P){if(!e.cardTargetPick?.pending)return!1;let G=Jt(e.cardTargetPick.cardId),H=ga(e,P);return!G||!H?(X(),!0):G.id==="dynamite"?(O(H)&&((e.cardTargetPick.remaining||0)<=0||!We(e,"dynamite").length)&&b(G),!0):(ms(e,H),b(G),!0)}function X(){e.cardTargetPick?.pending&&(e.cardTargetPick=null,ie())}function ae(){let P=Math.max(0,e.cardDraft?.freeRerolls||0);if(P>0){e.cardDraft.freeRerolls=P-1,e.cardDraft.rerolls+=1,l(Lt),ie();return}let G=is(e);e.cash${G.alt||`:``}function se(P,G){let H=document.createElement("button");H.type="button";let be=P.type==="dud"?"dud":P.rarity==="ultraRare"?"ultra-rare":P.rarity==="rare"?"rare":"common";H.className=`card-choice ${be}`;let F=P.type==="dud"?"MISS":P.rarity==="ultraRare"?"ULTRA RARE":P.rarity==="rare"?"RARE":"COMMON",U=[F,...(P.tags||[]).filter(S=>S!==F)].slice(0,5);return H.innerHTML=`${re(P)}
${P.title}
${U.map(S=>`${S}`).join("")}
${xa(e,P)}
`,H.addEventListener("click",()=>I(P,H)),H.dataset.index=String(G),H}function ie(){Le(e),e.cardTargetPick=null,e.cardDraft?.pending||r(),e.cardDraft.choices?.length||l(Lt);let P=e.cardDraft.choices||[],G=is(e),H=Math.max(0,e.cardDraft?.freeRerolls||0),be=Math.max(1,e.cardDraft.picksRemaining||1);t.modalTitle.textContent="Choose Upgrade Card",t.modalBody.innerHTML=`

Choose ${be} card${be===1?"":"s"} before Build phase. Dud cards can be flicked away without consuming a pick. Equipment cards target machines; Dynamite targets blocked cells.

`;let F=t.modalBody.querySelector("#cardChoices");P.forEach((g,N)=>F.appendChild(se(g,N))),t.modalActions.innerHTML="";let U=document.createElement("button");U.type="button",U.className="facility-action warn reroll-button",U.textContent=H>0?`Reroll (FREE x${H})`:`Reroll ${x(G)}`,U.disabled=H<=0&&e.cash0?`${H} free reroll${H===1?"":"s"} remaining.`:U.disabled?"Not enough cash":"",U.addEventListener("click",ae),t.modalActions.appendChild(U);let S=document.createElement("button");S.type="button",S.className="facility-action",S.textContent="No Card",S.title="Skip this upgrade pick and enter Build phase.",S.addEventListener("click",i),t.modalActions.appendChild(S),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible")}return{prepareDraft:r,showDraft:ie,finishDraft:i,chooseTargetAtPoint:ee,cancelTargetPick:X}}var Ta=!0,Ea={chickMale:"./assets/images/chick_male.png",chickFemale:"./assets/images/chick_female.png",poop:"./assets/images/poop.png",conveyorStraightH:"./assets/dark_factory/facilities/conveyor/conveyor_straight_h_16.png",conveyorStraightV:"./assets/dark_factory/facilities/conveyor/conveyor_straight_v_16.png",conveyorTurnNe:"./assets/dark_factory/facilities/conveyor/conveyor_turn_ne_16.png",conveyorTurnNw:"./assets/dark_factory/facilities/conveyor/conveyor_turn_nw_16.png",conveyorTurnSe:"./assets/dark_factory/facilities/conveyor/conveyor_turn_se_16.png",conveyorTurnSw:"./assets/dark_factory/facilities/conveyor/conveyor_turn_sw_16.png",boostConveyorStraightH:"./assets/dark_factory/facilities/conveyor/boost_conveyor_straight_h_16.png",boostConveyorStraightV:"./assets/dark_factory/facilities/conveyor/boost_conveyor_straight_v_16.png",boostConveyorTurnNe:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_ne_16.png",boostConveyorTurnNw:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_nw_16.png",boostConveyorTurnSe:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_se_16.png",boostConveyorTurnSw:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_sw_16.png",scannerManual:"./assets/dark_factory/facilities/machines/manual_scanner_32x48.png",scannerAuto:"./assets/dark_factory/facilities/machines/auto_scanner_32x48.png",eggFarm:"./assets/dark_factory/facilities/machines/egg_farm_16.png",mixer:"./assets/dark_factory/facilities/machines/mixer_32.png",shredder:"./assets/dark_factory/facilities/machines/shredder_32.png",truck:"./assets/dark_factory/facilities/vehicles/truck_32.png",mixerCompact:"./assets/dark_factory/facilities/machines/mixer_compact_16.png",shredderCompact:"./assets/dark_factory/facilities/machines/shredder_compact_16.png",truckCompact:"./assets/dark_factory/facilities/vehicles/truck_compact_16.png",maintenanceRoom:"./assets/dark_factory/facilities/utility/maintenance_room_32.png",repairman:"./assets/dark_factory/facilities/utility/repairman_16.png",obstacleCrate:"./assets/dark_factory/facilities/utility/obstacle_crate_16.png"},ce={};for(let[e,t]of Object.entries(Ea)){let n=new Image;n.loaded=!1,n.onerror=()=>{n.loaded=!1},Ta&&t&&(n.onload=()=>{n.loaded=!0},n.src=t),ce[e]=n}function Cs(e,t,n,o){e.imageSmoothingEnabled=!1,e.clearRect(0,0,t.width,t.height),Ia(e,t),e.save();let r=n.shake.time>0?W(-n.shake.strength,n.shake.strength):0,i=n.shake.time>0?W(-n.shake.strength,n.shake.strength):0,l=n.view?.scale||1;e.translate((n.view?.x||0)+r,(n.view?.y||0)+i),e.scale(l,l),Fa(e,n),Ba(e,n),Oa(e,n),za(e,n),nc(e,n),oc(e,n),Xa(e,n),Ja(e,n),Pa(e,n),lc(e,n,o.activeQueuedChick),mc(e,n),fc(e,t,n),dc(e,n,o.selectedObject,o.selectedTitle),pc(e,n),yc(e,n),hc(e,n),e.restore(),vc(e,n,t)}function Ra(e){if(e.type==="eggFarm"){let n=B(e.ref.col,e.ref.row);return{x:n.x-34,y:n.y-34,w:68,h:68,cx:n.x,cy:n.y}}let t=e.ref;return{x:t.x,y:t.y,w:t.w,h:t.h,cx:t.x+t.w/2,cy:t.y+t.h/2}}function Pa(e,t){if(t.phase!=="build")return;let n=Ln(t);for(let o of n){let r=Ra(o);e.save(),e.fillStyle="rgba(196,36,36,.22)",e.strokeStyle=y.danger,e.lineWidth=5,e.setLineDash([10,6]),Z(e,r.x,r.y,r.w,r.h,!0,!0),e.setLineDash([]),e.fillStyle=y.danger,e.strokeStyle=y.white,e.lineWidth=4,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.strokeText("!",r.cx,r.y+24),e.fillText("!",r.cx,r.y+24),e.font="900 11px ui-monospace, monospace",e.strokeText("NO ROUTE",r.cx,r.y+r.h-8),e.fillText("NO ROUTE",r.cx,r.y+r.h-8),e.restore()}}function Z(e,t,n,o,r,i=!0,l=!0){e.beginPath(),e.rect(t,n,o,r),i&&e.fill(),l&&e.stroke()}function cr(e,t,n,o,r=y.ink){e.save(),e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.lineWidth=4,e.strokeStyle=y.white,e.fillStyle=r,e.strokeText(o,t,n),e.fillText(o,t,n),e.restore()}function it(e,t,n,o,r,i){if(!t?.loaded)return!1;let l=e.imageSmoothingEnabled;return e.imageSmoothingEnabled=!1,e.drawImage(t,Math.round(n),Math.round(o),Math.round(r),Math.round(i)),e.imageSmoothingEnabled=l,!0}function ws(e,t,n,o,r,i,l=null,c=1){e.fillStyle=i,e.fillRect(Math.round(t),Math.round(n),Math.round(o),Math.round(r)),l&&(e.strokeStyle=l,e.lineWidth=c,e.strokeRect(Math.round(t)+.5,Math.round(n)+.5,Math.round(o)-1,Math.round(r)-1))}function Aa(e,t){let n=(Math.imul(e+37,73856093)^Math.imul(t+71,19349663))>>>0;return n^=n>>>13,n>>>0}function Da(e,t,n,o,r){let i=Aa(o,r);if(i%11>1)return;let l=8+(i>>>4)%Math.max(1,f.cell-20),c=9+(i>>>9)%Math.max(1,f.cell-20),b=7+(i>>>14)%7,C=4+(i>>>18)%5;e.save(),e.globalAlpha=.72,e.fillStyle="#4f9e39",e.strokeStyle="rgba(21,55,21,.72)",e.lineWidth=1.5,e.beginPath(),e.ellipse(t+l,n+c,b,C,(i>>>22)%8*Math.PI/16,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle="rgba(135,214,83,.58)",e.beginPath(),e.ellipse(t+l-b*.22,n+c-C*.28,Math.max(2,b*.34),Math.max(1.5,C*.26),0,0,Math.PI*2),e.fill(),i%3===0&&(e.fillStyle="rgba(55,132,42,.72)",e.beginPath(),e.arc(t+l+b+3,n+c+(i>>>27)%5-2,2.2,0,Math.PI*2),e.fill()),e.restore()}function Ia(e,t){e.fillStyle=y.bg,e.fillRect(0,0,t.width,t.height),e.save(),e.globalAlpha=.85;for(let n=0;n=n;for(let r of Tt(t)){let i=Et(r);e.save(),e.fillStyle=o?"rgba(183,245,198,.34)":"rgba(255,255,255,.22)",e.strokeStyle=o?y.green:y.muted,e.lineWidth=5,e.setLineDash([16,10]),Z(e,i.x,i.y,i.w,i.h,!0,!0),e.setLineDash([]);let l=Mo(r),c=l.cx,b=l.cy;e.fillStyle="rgba(255,255,255,.94)",e.strokeStyle=y.ink,e.lineWidth=4,Z(e,l.x,l.y,l.w,l.h,!0,!0),e.fillStyle=o?y.green:y.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText(r.direction==="right"?"BUY RIGHT LOT":"BUY UPPER LOT",c,b-12),e.fillStyle=y.ink,e.font="900 16px ui-monospace, monospace",e.fillText(`${x(n)} / 10\xD710`,c,b+15),e.fillStyle=y.muted,e.font="900 11px ui-monospace, monospace",e.fillText("blocked tiles included",c,b+30),e.restore()}}function ot(e,t,n,o,r,i,l=0){let c=zt(i);c<.5||(e.save(),e.globalAlpha=Math.min(.62,.12+c*.54),e.fillStyle="#6b4a23",l>0?(e.beginPath(),e.roundRect?.(t,n,o,r,l),e.roundRect?e.fill():Z(e,t,n,o,r,!0,!1)):Z(e,t,n,o,r,!0,!1),e.globalAlpha=Math.min(.9,.25+c*.6),e.strokeStyle="#3a2a16",e.lineWidth=Math.max(2,Math.floor(2+c*5)),e.setLineDash([5,6]),Z(e,t+3,n+3,o-6,r-6,!1,!0),e.restore())}function ar(e,t){let n=e.componentLookup?.get(t);return(n?e.congestion.get(n):null)?.ratio||0}function La(e,t,n={}){let o=Sn(e,t).sort(),i=n.kind==="boostConveyor"?"boostConveyor":"conveyor",l=c=>o.includes(c);if(o.length===2){if(l("left")&&l("right"))return ce[`${i}StraightH`];if(l("up")&&l("down"))return ce[`${i}StraightV`];if(l("up")&&l("right"))return ce[`${i}TurnNe`];if(l("up")&&l("left"))return ce[`${i}TurnNw`];if(l("down")&&l("right"))return ce[`${i}TurnSe`];if(l("down")&&l("left"))return ce[`${i}TurnSw`]}return o.length===1?l("up")||l("down")?ce[`${i}StraightV`]:ce[`${i}StraightH`]:l("up")||l("down")?ce[`${i}StraightV`]:ce[`${i}StraightH`]}function Oa(e,t){let n=[],o=new Set;for(let i of t.conveyorTiles){let{col:l,row:c}=te(i);for(let b of de){let C={col:l+b.dc,row:c+b.dr},T=A(C.col,C.row);if(!t.conveyorTiles.has(T))continue;let I=[i,T].sort().join("|");if(o.has(I))continue;o.add(I);let $=Math.max(ar(t,i),ar(t,T));n.push({a:B(l,c),b:B(C.col,C.row),ratio:$})}}e.save(),e.lineCap="round",e.lineJoin="round";for(let i of[{width:31,color:"#0b0c0f",alpha:1},{width:23,color:"#444b56",alpha:1},{width:15,color:"#171a1f",alpha:1}]){e.globalAlpha=i.alpha,e.strokeStyle=i.color,e.lineWidth=i.width;for(let l of n)e.beginPath(),e.moveTo(l.a.x,l.a.y),e.lineTo(l.b.x,l.b.y),e.stroke()}for(let i of n){let l=Math.max(0,(i.ratio-.5)/.5);e.strokeStyle=Kt(y.green,y.danger,l),e.globalAlpha=i.ratio>.5?.35+l*.55:.8,e.lineWidth=6,e.beginPath(),e.moveTo(i.a.x,i.a.y),e.lineTo(i.b.x,i.b.y),e.stroke()}let r=qa(t);for(let i of t.conveyorTiles){let l=B(...Object.values(te(i))),c=t.conveyorMeta.get(i)||{},b=ar(t,i),C=La(t,i,c),T=b>.5;if(e.fillStyle=T?"rgba(196,36,36,.28)":"rgba(0,0,0,.35)",e.strokeStyle=T?y.danger:"rgba(255,184,39,.34)",e.lineWidth=T?3:1,Z(e,l.x-20,l.y-20,40,40,!0,!0),!it(e,C,l.x-19,l.y-19,38,38)){let $=c.kind==="boostConveyor"?"#315e92":"#454b55";e.fillStyle=b>.5?Kt($,"#a12c2c",Math.max(0,(b-.5)/.5)):$,e.strokeStyle=y.ink,e.lineWidth=2,Z(e,l.x-18,l.y-18,36,36,!0,!0)}Na(e,l,i,c,b),ot(e,l.x-18,l.y-18,36,36,{meta:c}),rt(e,t,"conveyor",i,l.x,l.y,38,38),Ya(e,l,r.get(i)||[]);let I=Sn(t,i);Ka(e,l,c,Ua(t,i,I),I),b>.5&&cr(e,l.x,l.y-15,`${Math.floor(b*100)}%`,y.danger)}e.restore()}function Na(e,t,n,o={},r=0){let l=[...new Set([...Array.isArray(o.outDirs)?o.outDirs:[],o.dir].filter(Boolean))][0]||"right",c=l==="up"||l==="down",b=l==="left"||l==="up",C=o.kind==="boostConveyor",T=typeof performance<"u"?performance.now()/(C?70:105):0,I=((b?-T:T)%10+10)%10;e.save(),e.beginPath(),e.rect(t.x-18,t.y-18,36,36),e.clip();let $=C?"rgba(20,126,124,.62)":"rgba(42,47,54,.72)";if(e.fillStyle=$,e.fillRect(t.x-18,t.y-18,36,36),e.strokeStyle=r>.5?"rgba(238,83,61,.90)":"rgba(184,190,198,.92)",e.lineWidth=4,c)for(let O=t.y-28+I;Oe.conveyorTiles.has(A(n.col+o.dc,n.row+o.dr))).map(o=>o.name)}function _a(e,t,n){let o=de.find(l=>l.name===n);if(!o)return!1;let r=e.conveyorMeta?.get?.(A(t.col+o.dc,t.row+o.dr));return r?[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))].includes(o.opposite):!1}function Ms(e,t,n,o=Sn(e,t)){if(o.length<3)return n;let r=te(t),i=new Set(o.filter(b=>_a(e,r,b))),l=o.filter(b=>!i.has(b));if(i.size&&l.length>=2)return l;let c=n.filter(b=>o.includes(b));return c.length>=2?[...new Set(c)]:o}function Ga(e,t,n,o=Sn(e,t),r="random"){let i=Ms(e,t,n,o);return o.length>=3&&r&&r!=="random"&&i.includes(r)?[r]:i}function Ua(e,t,n=Sn(e,t)){let o=e.conveyorMeta?.get?.(t)||{},r=[...new Set([...Array.isArray(o.outDirs)?o.outDirs:[],o.dir].filter(Boolean))];return n.length<3?[]:Ms(e,t,r,n)}function Wa(e,t,n){let o=te(t),r=de.filter(c=>e.conveyorTiles.has(A(o.col+c.dc,o.row+c.dr))).map(c=>c.name),i=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(c=>r.includes(c)),l=r;return i.length?i:l}function Ka(e,t,n,o,r=o){if(r.length<3||o.length<2)return;e.save();let i=o.includes(n.branchMode)?n.branchMode:"random",l=i!=="random";if(e.lineJoin="round",e.lineCap="round",e.lineWidth=2,e.fillStyle="rgba(18,21,26,.94)",e.strokeStyle=l?y.warn:y.green,e.lineWidth=4,Z(e,t.x-18,t.y-18,36,36,!0,!0),e.strokeStyle="#ffd36a",e.lineWidth=3,e.fillStyle="#020304",i!=="random"){let c=de.find(b=>b.name===i);wn(e,t.x,t.y,c?.angle||0,9,6)}else e.beginPath(),e.moveTo(t.x-10,t.y),e.lineTo(t.x-2,t.y),e.lineTo(t.x+8,t.y-8),e.moveTo(t.x-2,t.y),e.lineTo(t.x+8,t.y+8),e.stroke(),wn(e,t.x+9,t.y-9,-Math.PI/4,4,3),wn(e,t.x+9,t.y+9,Math.PI/4,4,3);e.restore()}function Ha(e,t,n){if(!n)return[];let o=te(t),r=de.filter(c=>e.conveyorTiles.has(A(o.col+c.dc,o.row+c.dr))).map(c=>c.name),i=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(c=>r.includes(c));return Ga(e,t,i.length?i:Wa(e,t,n),r,n.branchMode||"random").map(c=>de.find(b=>b.name===c)).filter(Boolean)}function qa(e){let t=new Map;for(let[n,o]of e.conveyorMeta||[]){let r=Ha(e,n,o);r.length&&t.set(n,r)}return t}function Ya(e,t,n){let o=n.slice(0,4);o.length&&(e.save(),e.globalAlpha=1,o.forEach(r=>{let i=t.x+r.dc*11,l=t.y+r.dr*11;e.fillStyle="rgba(255,205,83,.96)",wn(e,i,l,r.angle,9,7),e.fillStyle="#020304",wn(e,i,l,r.angle,6.5,4.6)}),e.restore())}function wn(e,t,n,o,r=11,i=8){e.save(),e.translate(t,n),e.rotate(o),e.beginPath(),e.moveTo(r,0),e.lineTo(-r*.72,-i),e.lineTo(-r*.72,i),e.closePath(),e.fill(),e.restore()}function Va(e,t,n,o,r){let i=ye(t),l=null;if(n==="inputA"&&(l={x:i.x,y:i.y-67}),n==="left"&&(l={x:i.x-49,y:i.y+14}),n==="right"&&(l={x:i.x+49,y:i.y+14}),!l)return;let c=n==="inputA"?{x:o.x,y:l.y}:{x:l.x,y:o.y};e.save(),e.lineCap="square",e.lineJoin="bevel",e.strokeStyle="#050609",e.lineWidth=15,e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(c.x,c.y),e.lineTo(l.x,l.y),e.stroke(),e.strokeStyle="#596473",e.lineWidth=9,e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(c.x,c.y),e.lineTo(l.x,l.y),e.stroke(),e.strokeStyle=r||"#7b8795",e.lineWidth=3,e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(c.x,c.y),e.lineTo(l.x,l.y),e.stroke(),e.fillStyle=r||"#7b8795",e.strokeStyle="#050609",e.lineWidth=3,Z(e,l.x-9,l.y-7,18,14,!0,!0),e.restore()}function za(e,t){e.save(),e.lineWidth=2,e.font="900 12px ui-monospace, monospace",e.textAlign="center";for(let n of t.scanners){let o=Do(n),r=[{type:"inputA",p:Re(n,"inputA"),label:"IN",color:y.green},{type:"left",p:Re(n,"left"),label:$o(o.left),color:Fo(o.left)},{type:"right",p:Re(n,"right"),label:$o(o.right),color:Fo(o.right)}];for(let i of r){if(!i.p)continue;let l=B(i.p.col,i.p.row);Va(e,n,i.type,l,i.color);let c=li(t,n,i.type||(i.label==="IN"?"inputA":null))||t.conveyorTiles.has(A(i.p.col,i.p.row));e.fillStyle=c?Kt("#1a1d23",i.color,.24):"#3a1e22",e.strokeStyle=c?i.color:y.danger,Z(e,l.x-18,l.y-12,36,24,!0,!0),e.fillStyle=y.white,e.fillText(i.label,l.x,l.y+4)}}e.restore()}function Xa(e,t){for(let n of t.eggFarms)Qa(e,n,t)}function Qa(e,t,n){let o=B(t.col,t.row);if(e.save(),it(e,ce.eggFarm,o.x-29,o.y-29,58,58)){ot(e,o.x-29,o.y-29,58,58,t);let l=1+Math.max(0,Number(t.extraEggOutlet)||0);e.fillStyle="rgba(255,255,255,.92)",e.strokeStyle=y.ink,e.lineWidth=2,Z(e,o.x+9,o.y+12,30,18,!0,!0),e.fillStyle=y.ink,e.font="900 10px ui-monospace, monospace",e.textAlign="center",e.fillText(`O${l}`,o.x+24,o.y+24),rt(e,n,"eggFarm",t.id,o.x,o.y,68,68),e.restore();return}e.fillStyle=y.white,e.strokeStyle=y.ink,e.lineWidth=4,Z(e,o.x-28,o.y-28,56,56,!0,!0),e.fillStyle=y.green,e.font="900 19px ui-monospace, monospace",e.textAlign="center",e.fillText("EGG",o.x,o.y-4);let r=1+Math.max(0,Number(t.extraEggOutlet)||0);e.font="900 11px ui-monospace, monospace",e.fillStyle=y.ink,e.fillText(`L${t.level} O${r}`,o.x,o.y+13),e.fillText(`${t.nextSpawn.toFixed(1)}s`,o.x,o.y+26);let i=Math.max(0,Math.min(1,t.shutterProgress||0));if(i>0){let l=56*i;e.fillStyle=y.ink,Z(e,o.x-28,o.y-28,56,l,!0,!1),e.strokeStyle=y.white,e.lineWidth=2;for(let c=o.y-24;c=1&&(e.fillStyle=y.white,e.font="900 12px ui-monospace, monospace",e.fillText("SHUT",o.x,o.y+4))}ot(e,o.x-28,o.y-28,56,56,t),rt(e,n,"eggFarm",t.id,o.x,o.y,68,68),e.restore()}function Ja(e,t){for(let n of t.scanners)ja(e,n,t)}function ja(e,t,n){let o=ye(t);if(e.save(),t.kind==="manual"&&(n.manualCombo?.count||0)>=10){let b=n.manualCombo.count;e.save(),e.globalAlpha=Math.min(.55,.16+b/120),e.strokeStyle=b>=30?y.warn:y.green,e.lineWidth=Math.min(14,5+Math.floor(b/10)),e.shadowColor=e.strokeStyle,e.shadowBlur=Math.min(28,8+b),Z(e,o.x-54,o.y-76,108,152,!1,!0),e.restore()}let r=t.kind==="auto"?ce.scannerAuto:ce.scannerManual;if(it(e,r,o.x-50,o.y-73,100,146)){t.kind==="auto"?ot(e,o.x-50,o.y-73,100,146,t):Ss(e,t,o),rt(e,n,"scanner",t.id,o.x,o.y,108,154),e.restore();return}e.fillStyle=t.kind==="auto"?"#d8ffe2":y.white,e.strokeStyle=y.ink,e.lineWidth=4,Z(e,o.x-50,o.y-73,100,146,!0,!0),e.fillStyle=t.kind==="auto"?y.green:y.ink,e.font="900 19px ui-monospace, monospace",e.textAlign="center",e.fillText(`${t.kind==="auto"?"AUTO":`S${(t.slot??0)+1}`}`,o.x,o.y-48),e.font="900 11px ui-monospace, monospace";let i=t.keys?.left?.label||(t.slot===0?"A":"Left"),l=t.keys?.right?.label||(t.slot===0?"D":"Right");e.fillText(t.role===0?`${i}:M ${l}:NEXT`:`${i}:WASTE ${l}:TRUCK`,o.x,o.y-28);let c=t.queue.length;t.kind==="manual"?(Ss(e,t,o),e.fillStyle=c>0?y.green:y.muted,e.font="900 10px ui-monospace, monospace",e.fillText(`Q:${c}`,o.x,o.y+54)):(e.fillStyle=c>0?y.green:y.muted,e.font="900 12px ui-monospace, monospace",e.fillText(`Q:${c} CD:${t.cooldown.toFixed(1)}`,o.x,o.y+54),ot(e,o.x-50,o.y-73,100,146,t)),rt(e,n,"scanner",t.id,o.x,o.y,108,154),e.restore()}function Ss(e,t,n){if(t.kind!=="manual")return;let r=(t.slot??0)===0?[{side:"left",text:"A"},{side:"right",text:"D"}]:[{side:"left",text:"\u2190"},{side:"right",text:"\u2192"}];r[0].text=t.keys?.left?.label||r[0].text,r[1].text=t.keys?.right?.label||r[1].text;let i=t.keyPressTime>0?t.keyPressSide:null,l=n.x-30,c=n.y+18;e.save(),e.lineWidth=3,e.fillStyle="#f7fff5",e.strokeStyle=y.ink,Z(e,l-4,c-4,68,25,!0,!0),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let b=0;b.8,i=t.y+Math.sin(t.bob)*(r?5:1.5);if(e.save(),n&&(e.strokeStyle=y.green,e.lineWidth=5,e.beginPath(),e.arc(t.x,i,t.radius+8,0,Math.PI*2),e.stroke()),r&&(e.strokeStyle=y.danger,e.lineWidth=3,e.beginPath(),e.arc(t.x,i,t.radius+12+Math.sin(t.bob*2)*4,0,Math.PI*2),e.stroke()),t.sex==="poop")hr(e,t.x,i,t.radius);else{let l=t.sex==="male"?ce.chickMale:ce.chickFemale;if(!it(e,l,t.x-t.radius,i-t.radius,t.radius*2,t.radius*2)){let C=t.sex==="male"?y.male:y.female,T=t.sex==="male"?"#164f8f":"#8b2252";e.fillStyle=C,e.strokeStyle=y.ink,e.lineWidth=5,e.beginPath(),e.arc(t.x,i,t.radius,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle="rgba(255,255,255,.24)",e.beginPath(),e.arc(t.x-5,i-7,t.radius*.36,0,Math.PI*2),e.fill(),e.fillStyle=y.ink,e.beginPath(),e.arc(t.x-6,i-5,2.5,0,Math.PI*2),e.arc(t.x+6,i-5,2.5,0,Math.PI*2),e.fill(),e.fillStyle="#ffaa2e",e.beginPath(),e.moveTo(t.x,i+2),e.lineTo(t.x+9,i+6),e.lineTo(t.x,i+10),e.closePath(),e.fill(),e.strokeStyle=T,e.lineWidth=3,t.sex==="male"?(e.beginPath(),e.moveTo(t.x-8,i-t.radius-2),e.lineTo(t.x+8,i-t.radius-2),e.stroke()):(e.beginPath(),e.moveTo(t.x-9,i-t.radius+2),e.lineTo(t.x,i-t.radius-6),e.lineTo(t.x+9,i-t.radius+2),e.stroke())}e.fillStyle=t.sex==="male"?"#dff1ff":"#fff0f7",e.strokeStyle="#050609",e.lineWidth=3,e.font=`900 ${Math.max(10,Math.round(t.radius*.72))}px ui-monospace, monospace`,e.textAlign="center";let b=t.sex==="male"?"\u2642":"\u2640";e.strokeText(b,t.x+t.radius*.54,i+t.radius*.7),e.fillText(b,t.x+t.radius*.54,i+t.radius*.7)}e.restore()}function cc(e,t){let n=null,o=1/0;for(let[r,i]of e.componentLookup.entries()){let l=te(r),c=B(l.col,l.row),b=Math.hypot(t.x-c.x,t.y-c.y);bks(o.type,o.id)===ks(t,n))}function rt(e,t,n,o,r,i,l,c){uc(t,n,o)&&(e.save(),e.fillStyle="rgba(34,185,79,.18)",e.strokeStyle=y.green,e.lineWidth=(t.multiSelected||[]).length>1?6:4,e.setLineDash((t.multiSelected||[]).length>1?[]:[8,5]),Z(e,r-l/2,i-c/2,l,c,!0,!0),e.restore())}function dc(e,t,n,o){if(t.phase==="build"&&(t.multiSelected||[]).length>1){e.save(),e.fillStyle="rgba(255,255,255,.96)",e.strokeStyle=y.ink,e.lineWidth=3,Z(e,54-t.view.x,66-t.view.y,214,42,!0,!0),e.fillStyle=y.ink,e.font="900 11px ui-monospace, monospace",e.fillText(`${t.multiSelected.length} ITEMS SELECTED`,65-t.view.x,83-t.view.y),e.fillStyle=y.muted,e.font="900 11px ui-monospace, monospace",e.fillText("drag any selected item to move group",65-t.view.x,99-t.view.y),e.restore();return}}function fc(e,t,n){if(!n.cardTargetPick?.pending)return;let o=lr(n);e.save(),e.fillStyle="rgba(0,0,0,.66)",e.beginPath();let r=n.view?.scale||1;e.rect(-(n.view?.x||0)/r,-(n.view?.y||0)/r,t.width/r,t.height/r);for(let b of o){let C=b.bounds,T=8;e.rect(C.x-T,C.y-T,C.w+T*2,C.h+T*2)}e.fill("evenodd");let i=n.cardTargetPick?.mode==="blockedCell";if(!o.length){e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=y.ink,e.lineWidth=3,Z(e,(260-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,420/r,42/r,!0,!0),e.fillStyle=y.danger,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(i?"NO BLOCKED CELL. PRESS ESC.":"NO VALID UPGRADE TARGET. PRESS ESC.",(470-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore();return}e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=y.ink,e.lineWidth=3;let l=Math.max(1,n.cardTargetPick?.remaining||1),c=n.cardTargetPick?.mode==="autoScannerMenu"?"AUTO SCANNER ROUTE SETTINGS. CLICK EMPTY AREA TO CLOSE.":i?`CLICK BLOCKED CELL: ${l} LEFT. PRESS ESC TO CANCEL.`:"CLICK AN UPGRADEABLE MACHINE. PRESS ESC TO CANCEL.";Z(e,(216-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,560/r,42/r,!0,!0),e.fillStyle=y.ink,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(c,(496-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore()}function pc(e,t){if(t.phase!=="build"||!t.selectionBox)return;let n=t.selectionBox,o=Math.min(n.x1,n.x2),r=Math.min(n.y1,n.y2),i=Math.abs(n.x2-n.x1),l=Math.abs(n.y2-n.y1);e.save(),e.fillStyle="rgba(34,185,79,.12)",e.strokeStyle=y.green,e.lineWidth=2,e.setLineDash([7,4]),Z(e,o,r,i,l,!0,!0),e.restore()}function yc(e,t){let n=[...t.effects].sort((o,r)=>(o.priority??Me.ambient)-(r.priority??Me.ambient));for(let o of n){let r=Math.max(0,o.life/o.maxLife);e.save(),e.globalAlpha=r,o.type==="meat"?(e.fillStyle=y.green,Z(e,o.x-o.size/2,o.y-o.size/2,o.size*1.5,o.size,!0,!1)):o.type==="sludge"?(e.fillStyle=y.poop,Z(e,o.x-o.size/2,o.y-o.size/2,o.size*1.4,o.size,!0,!1)):o.type==="spawn"?(e.strokeStyle=y.green,e.lineWidth=3,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*20,0,Math.PI*2),e.stroke()):o.type==="spark"?(e.fillStyle=o.color||y.danger,Z(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!0,!1)):o.type==="smoke"?(e.fillStyle="rgba(16,32,21,.24)",e.beginPath(),e.arc(o.x,o.y,o.size*(1.2-r*.2),0,Math.PI*2),e.fill()):o.type==="shockwave"?(e.strokeStyle=o.color||y.danger,e.lineWidth=4,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*(o.maxSize||44),0,Math.PI*2),e.stroke()):o.type==="scannerPulse"?(e.strokeStyle=o.color||y.green,e.lineWidth=5,e.setLineDash([8,6]),e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*38,0,Math.PI*2),e.stroke()):o.type==="shred"?(e.fillStyle=o.color||y.ink,e.save(),e.translate(o.x,o.y),e.rotate(o.rot||0),Z(e,-o.w/2,-o.h/2,o.w,o.h,!0,!1),e.restore()):o.type==="load"?(e.strokeStyle=o.color||y.green,e.lineWidth=3,e.beginPath(),e.moveTo(o.x-14,o.y),e.lineTo(o.x+14,o.y),e.moveTo(o.x,o.y-14),e.lineTo(o.x,o.y+14),e.stroke()):o.type==="erase"?(e.strokeStyle=y.ink,e.lineWidth=3,e.setLineDash([4,4]),Z(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!1,!0)):o.type==="rage"?(e.fillStyle=o.color||y.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText("!",o.x,o.y)):o.type==="flyingChick"&&(o.sex==="poop"?hr(e,o.x,o.y,o.radius||11):mr(e,o.x,o.y,o.sex,o.sex==="male")),e.restore()}}function hc(e,t){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let n of t.floatingTexts){let o=Math.max(0,n.life/n.maxLife);e.globalAlpha=o,e.lineWidth=5,e.strokeStyle=y.white,e.fillStyle=n.color,e.strokeText(n.text,n.x,n.y),e.fillText(n.text,n.x,n.y)}e.restore()}function mc(e,t){let n=t.repairmen&&t.repairmen.length?t.repairmen:t.repairman?[t.repairman]:[];for(let o of n)bc(e,t,o)}function bc(e,t,n){if(!!!n?.active)return;if(e.save(),it(e,ce.repairman,n.x-18,n.y-18,36,36)){n.target?.label&&cr(e,n.x,n.y-24,n.target.label,y.green),e.restore();return}e.lineWidth=3,e.fillStyle="#fff0d1",e.strokeStyle=y.ink,e.beginPath(),e.arc(n.x,n.y,17,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle="#ffd6e7",e.beginPath(),e.arc(n.x-6,n.y-2,3.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+6,n.y-2,3.2,0,Math.PI*2),e.fill();let r=!!t.cardEffects?.laborExploitation;e.fillStyle=r?y.danger:y.ink,e.beginPath(),e.arc(n.x-5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.strokeStyle=y.ink,e.lineWidth=r?3:2,e.beginPath(),e.arc(n.x,n.y+(r?0:1),r?8:7,.1*Math.PI,.9*Math.PI),e.stroke(),e.fillStyle=y.green,Z(e,n.x-9,n.y+14,18,8,!0,!0),e.strokeStyle=y.ink,e.lineWidth=3,e.beginPath(),e.moveTo(n.x-11,n.y+18),e.lineTo(n.x-20,n.y+24),e.stroke(),e.beginPath(),e.moveTo(n.x+11,n.y+18),e.lineTo(n.x+20,n.y+24),e.stroke(),e.fillStyle=y.ink,e.font="900 11px ui-monospace, monospace",e.textAlign="center",e.fillText("FIX",n.x,n.y+33),n.target?.label&&cr(e,n.x,n.y-24,n.target.label,y.green),e.restore()}function vc(e,t,n){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="left",e.fillStyle=y.ink,e.font="900 19px ui-monospace, monospace",e.fillStyle=y.ink;let o=[];t.phase==="running"&&o.push(t.timeLeft<=0?"TIME UP: FARMS SHUT. CLEAR LINE.":"A/D: S1 \u2190/\u2192: S2"),t.phase==="build"&&o.push(`BUILD: ${t.buildTool||"SELECT"} | connect 1 EGG route to any exit`);let r=76;for(let i of o)e.strokeStyle=y.white,e.lineWidth=4,e.strokeText(i,24,r),e.fillText(i,24,r),r+=20;e.restore()}var Es=[[{key:"a",code:"KeyA",label:"A"},{key:"d",code:"KeyD",label:"D"}],[{key:"arrowleft",code:"ArrowLeft",label:"Left"},{key:"arrowright",code:"ArrowRight",label:"Right"}],[{key:"j",code:"KeyJ",label:"J"},{key:"l",code:"KeyL",label:"L"}],[{key:"f",code:"KeyF",label:"F"},{key:"h",code:"KeyH",label:"H"}],[{key:"q",code:"KeyQ",label:"Q"},{key:"e",code:"KeyE",label:"E"}],[{key:"z",code:"KeyZ",label:"Z"},{key:"x",code:"KeyX",label:"X"}],[{key:"u",code:"KeyU",label:"U"},{key:"o",code:"KeyO",label:"O"}],[{key:"n",code:"KeyN",label:"N"},{key:"m",code:"KeyM",label:"M"}]];function wc(e){let t=Es[e]||Es[0];return{left:{...t[0]},right:{...t[1]}}}function Rs(e,t,n){let o={type:"eggFarm",id:e.nextId++,col:t,row:n,level:1,nextSpawn:2,lastInterval:2,extraEggOutlet:0,price:at.eggFarm,builtSession:e.buildSession};return o.nextSpawn=Rt(o),o.lastInterval=o.nextSpawn,o}function Ps(e,t,n,o){let r=o==="auto"?ve.autoScanner.price:ve.manualScanner.price,i=new Set(e.scanners.filter(c=>c.kind==="manual").map(c=>c.slot)),l=0;for(;i.has(l);)l+=1;return{type:"scanner",id:e.nextId++,kind:o,slot:o==="manual"?l:null,role:o==="manual"?l%2:0,col:t,row:n,level:1,queue:[],cooldown:0,price:r,builtSession:e.buildSession,autoMode:"standard",keys:o==="manual"?wc(l):null}}function Jn(e){let t=(e.x-f.x)/f.cell,n=(e.y-f.y)/f.cell,o=Math.max(0,Math.min(f.cols-1,Math.round(t-.5))),r=Math.max(0,Math.min(f.rows-1,Math.round(n-.5))),i=Math.abs(e.x-f.x),l=Math.abs(e.x-(f.x+f.cols*f.cell)),c=Math.abs(e.y-f.y),b=Math.abs(e.y-(f.y+f.rows*f.cell)),C=[["left",i],["right",l],["top",c],["bottom",b]].sort((T,I)=>T[1]-I[1])[0][0];return C==="left"?{side:C,entry:{col:0,row:r}}:C==="right"?{side:C,entry:{col:f.cols-1,row:r}}:C==="top"?{side:C,entry:{col:o,row:0}}:{side:C,entry:{col:o,row:f.rows-1}}}function jn(e,t,n){let o={x:f.x+t.col*f.cell+f.cell/2,y:f.y+t.row*f.cell+f.cell/2},r={left:f.x,right:f.x+f.cols*f.cell,top:f.y,bottom:f.y+f.rows*f.cell};return e.entry={...t},e.side=n,n==="left"?(e.x=r.left-e.w-18,e.y=o.y-e.h/2):n==="right"?(e.x=r.right+18,e.y=o.y-e.h/2):n==="top"?(e.x=o.x-e.w/2,e.y=r.top-e.h-18):(e.x=o.x-e.w/2,e.y=r.bottom+18),e}function As(e,t,n,o){let{entry:r,side:i}=Jn(n),l=ve[t],c=l?{name:l.name,w:l.body?.w||168,h:l.body?.h||110,price:l.price}:{name:t[0].toUpperCase()+t.slice(1),w:168,h:110,price:o},b={type:"facility",id:t,name:c.name,x:0,y:0,w:c.w,h:c.h,level:1,price:o||c.price,builtSession:e.buildSession};return jn(b,r,i)}function jt(e){return e?[{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}]:[]}function Ds(e,t,n){return{type:"maintenanceRoom",id:e.nextId++,col:t,row:n,price:at.maintenanceRoom,builtSession:e.buildSession,wCells:2,hCells:2}}function Sc(e){return Math.random()({x:i.x,y:i.y})),r=o[0];return{id:e.nextId++,sex:n,x:r.x,y:r.y,route:o,targetIndex:o.length>1?1:o.length,stage:t.stage||"belt",scannerId:t.scannerId??null,nextScannerId:null,pendingScannerId:null,radius:n==="poop"?15:17,bob:Math.random()*Math.PI*2,queueIndex:-1,queueRoute:null}}function $s({game:e,canvasPoint:t,updatePanels:n,equipmentAtPoint:o,fail:r,pointInGrid:i,rectOfFacility:l,rectsOverlap:c}){function b(S){return S?S.type==="conveyor"?`conveyor:${S.id||S.oldKey}`:S.type==="facility"?`facility:${S.id||S.ref?.id}`:S.type==="maintenanceRoom"?`maintenanceRoom:${S.id||S.ref?.id}`:`${S.type}:${S.id||S.ref?.id}`:""}function C(S){return S?S.type==="conveyor"?{type:"conveyor",id:S.oldKey}:{type:S.type,id:S.ref.id}:null}function T(S){let g=b(C(S));return(e.multiSelected||[]).some(N=>b(N)===g)}function I(S){return S?S.type==="eggFarm"?e.eggFarms.find(g=>g.id===S.id)||null:S.type==="scanner"?e.scanners.find(g=>g.id===S.id)||null:S.type==="facility"?e.facilities[S.id]||null:S.type==="maintenanceRoom"?(e.maintenanceRooms||[]).find(g=>g.id===S.id)||null:S.type==="conveyor"&&e.conveyorTiles.has(S.id)?{type:"conveyor",id:S.id}:null:null}function $(){let S=[];for(let g of e.conveyorTiles){let N=te(g),j=B(N.col,N.row);S.push({type:"conveyor",id:g,center:j,cell:N})}for(let g of e.eggFarms)S.push({type:"eggFarm",id:g.id,ref:g,center:B(g.col,g.row),cell:{col:g.col,row:g.row}});for(let g of e.scanners)S.push({type:"scanner",id:g.id,ref:g,center:ye(g),cell:{col:g.col,row:g.row}});for(let g of e.maintenanceRooms||[]){let N=B(g.col,g.row);S.push({type:"maintenanceRoom",id:g.id,ref:g,center:{x:N.x+f.cell/2,y:N.y+f.cell/2},cell:{col:g.col,row:g.row}})}for(let g of Object.values(e.facilities)){let N={x:g.x+g.w/2,y:g.y+g.h/2},j=g.entry?B(g.entry.col,g.entry.row):N;S.push({type:"facility",id:g.id,ref:g,center:N,portCenter:j})}return S}function O(S,g){let N=Math.min(g.x1,g.x2),j=Math.max(g.x1,g.x2),J=Math.min(g.y1,g.y2),pe=Math.max(g.y1,g.y2);return S.x>=N&&S.x<=j&&S.y>=J&&S.y<=pe}function ee(S){let g=[];for(let N of $())(O(N.center,S)||N.portCenter&&O(N.portCenter,S))&&g.push({type:N.type,id:N.id});return e.multiSelected=g,e.selected=g[0]||null,n(),g.length}function X(){e.multiSelected=[],e.selected=null,n()}function ae(S){let g=t(S);return e.selectionBox={x1:g.x,y1:g.y,x2:g.x,y2:g.y},e.multiSelected=[],e.selected=null,n(),!0}function he(S){if(!e.selectionBox)return;let g=t(S);e.selectionBox.x2=g.x,e.selectionBox.y2=g.y}function re(){if(!e.selectionBox)return 0;let S=e.selectionBox,g=Math.abs(S.x2-S.x1),N=Math.abs(S.y2-S.y1);return e.selectionBox=null,g<6&&N<6?(X(),0):ee(S)}function se(S){let g=C(S);return g?(e.multiSelected||[]).length&&T(S)?[...e.multiSelected]:[g]:[]}function ie(S){let g=I(S);if(!g)return null;if(S.type==="conveyor"){let N=te(S.id);return{...S,obj:g,oldKey:S.id,currentKey:S.id,meta:e.conveyorMeta.get(S.id)||{price:Oe("conveyor"),builtSession:null},col:N.col,row:N.row}}return S.type==="eggFarm"||S.type==="scanner"||S.type==="maintenanceRoom"?{...S,obj:g,col:g.col,row:g.row}:S.type==="facility"?{...S,obj:g,x:g.x,y:g.y,w:g.w,h:g.h,entry:g.entry?{...g.entry}:null,side:g.side,center:{x:g.x+g.w/2,y:g.y+g.h/2}}:null}function P(S){let g=t(S),N=o(g);if(!N)return!1;let j=se(N),J=j.map(ie).filter(Boolean);return J.length?(e.groupDrag={start:g,selections:j,origins:J,historySnapshot:hn(e),committed:!1,lastDCol:0,lastDRow:0},e.multiSelected=j,e.selected=j[0]||null,n(),!0):!1}function G(){!e.groupDrag||e.groupDrag.committed||(e.undoStack.push(e.groupDrag.historySnapshot),e.redoStack=[],e.groupDrag.committed=!0)}function H(S,g,N){let j=A(S,g),J=ft(e,S,g);if(J&&!N.has(`eggFarm:${J.id}`))return!0;let pe=pt(e,S,g);if(pe&&!N.has(`scanner:${pe.id}`))return!0;let xe=(e.maintenanceRooms||[]).find(Pe=>jt(Pe).some(Ae=>Ae.col===S&&Ae.row===g));return!!(xe&&!N.has(`maintenanceRoom:${xe.id}`)||e.conveyorTiles.has(j)&&!N.has(`conveyor:${j}`))}function be(S,g,N){let j=[];for(let J of e.groupDrag.origins){if(J.type!=="facility")continue;let pe={x:J.center.x+S,y:J.center.y+g},{entry:xe,side:Pe}=Jn(pe);if(!i(xe.col,xe.row)||e.blockedCells?.has?.(A(xe.col,xe.row)))return!0;let Ae={...J.obj,entry:{...xe},side:Pe};jn(Ae,xe,Pe),j.push({id:J.id,rect:l(Ae)})}for(let J of j)for(let pe of Object.values(e.facilities))if(!N.has(`facility:${pe.id}`)&&c(J.rect,l(pe),12))return!0;for(let J=0;J_.type==="conveyor");for(let _ of Ae){let De=_.currentKey||_.oldKey;e.conveyorTiles.delete(De),e.conveyorMeta.delete(De)}for(let _ of Ae){let De=A(_.col+J,_.row+pe);e.conveyorTiles.add(De),e.conveyorMeta.set(De,_.meta||{price:Oe("conveyor"),builtSession:null,uses:0}),_.currentKey=De}for(let _ of e.groupDrag.origins)if(_.type==="eggFarm")_.obj.col=_.col+J,_.obj.row=_.row+pe;else if(_.type==="scanner")_.obj.col=_.col+J,_.obj.row=_.row+pe;else if(_.type==="maintenanceRoom")_.obj.col=_.col+J,_.obj.row=_.row+pe;else if(_.type==="facility"){let De={x:_.center.x+N,y:_.center.y+j},{entry:Ye,side:Ve}=Jn(De);jn(_.obj,Ye,Ve)}e.groupDrag.selections=e.groupDrag.origins.map(_=>_.type==="conveyor"?{type:"conveyor",id:_.currentKey||_.oldKey}:{type:_.type,id:_.id}),e.multiSelected=[...e.groupDrag.selections],e.selected=e.multiSelected[0]||null,me(e),n()}function U(){e.groupDrag&&(me(e),e.groupDrag=null,n())}return{selectionFromHit:C,startSelectionBox:ae,updateSelectionBox:he,finishSelectionBox:re,startGroupDrag:P,updateGroupDrag:F,finishGroupDrag:U}}function Fs({game:e,ui:t,canvas:n,canvasPoint:o,onUpdatePanels:r}){function i(){r&&r()}let l=null,c=!1,b=null,C=!1,T=["random","up","right","down","left"],I={random:"RND",up:"UP",right:"RT",down:"DN",left:"LF"},$={w:40,h:40,y:0};function O(){return An(e)}function ee(){e.gridCols=f.cols,e.gridRows=f.rows,e.gridOwnedCells=Vr(e)}function X(s){if(s){f.y-=s*f.cell,f.rows+=s,e.gridChunkOriginY=(e.gridChunkOriginY||0)-Math.floor(s/10),e.ownedCells=Dn(e.ownedCells,s),e.blockedCells=Dn(e.blockedCells,s),e.conveyorTiles=Dn(e.conveyorTiles,s),e.conveyorMeta=Jr(e.conveyorMeta,s);for(let a of e.eggFarms||[])a.row+=s;for(let a of e.scanners||[])a.row+=s;for(let a of Object.values(e.facilities||{}))a.entry&&(a.entry.row+=s)}}function ae(s){e.ownedCells=e.ownedCells||new Set;for(let a of Qr(s))e.ownedCells.add(A(a.col,a.row))}function he(s){return e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending?null:Tt(e).find(a=>a&&Xr(a,s))||null}function re(s="right"){if(s&&typeof s=="object"&&Number.isFinite(s.chunkX)&&Number.isFinite(s.chunkY))return s;let a=["right","up"].includes(s)?s:"right";return zr(e,a)}function se(s="right"){let a=re(s);if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return{ok:!1,reason:"Cannot expand now."};if(!a)return{ok:!1,reason:"Invalid expansion lot."};let h=a.direction||"right",m=O();if(e.cashf.cols&&(f.cols=E.colStart+E.cols),E.rowStart+E.rows>f.rows&&(f.rows=E.rowStart+E.rows),ae(E),jr(e,E.chunkX,E.chunkY),e.gridExpansionPurchases=(e.gridExpansionPurchases||0)+1,e.gridExpansionPurchasesByDirection[h]=(e.gridExpansionPurchasesByDirection[h]||0)+1,ee();let ne=Wr({seed:`${e.runSeed}:grid-expansion:${E.chunkX},${E.chunkY}:${e.gridExpansionPurchases}`,colStart:E.colStart,colEnd:E.colStart+E.cols,rowStart:E.rowStart,rowEnd:E.rowStart+E.rows,targetRatio:Y.map.blockedRatio});for(let ke of ne)e.blockedCells.add(ke);me(e);let Q=E.cols*E.rows,ue=Et(E);return K(e,ue.x+ue.w/2,ue.y+ue.h/2,`${h.toUpperCase()} +${Q} CELLS -${x(m)}`,y.green),i(),{ok:!0,direction:h,cost:m,addedCells:Q,blocked:ne.size,chunkX:E.chunkX,chunkY:E.chunkY}}function ie(s,a){return s>=0&&s=0&&a!a.has(m.id)&&H(h,G(m),12))}function F(s,a,h=null){if(!ie(s,a))return!1;if(P(s,a))return!0;let m=A(s,a),w=ft(e,s,a);if(w&&!(h?.type==="eggFarm"&&h.ref?.id===w.id))return!0;let E=pt(e,s,a);if(E&&!(h?.type==="scanner"&&h.ref?.id===E.id))return!0;let ne=U(e,s,a);return!!(ne&&!(h?.type==="maintenanceRoom"&&h.ref?.id===ne.id)||e.conveyorTiles.has(m)&&!(h?.type==="conveyor"&&h.oldKey===m))}function U(s,a,h){return(s.maintenanceRooms||[]).find(m=>jt(m).some(w=>w.col===a&&w.row===h))||null}function S(s,a,h=null){let m={col:s,row:a};for(let w of jt(m)){if(!ie(w.col,w.row)||P(w.col,w.row))return!0;let E=A(w.col,w.row);if(ft(e,w.col,w.row)||pt(e,w.col,w.row))return!0;let ue=U(e,w.col,w.row);if(ue&&!(h?.type==="maintenanceRoom"&&h.ref?.id===ue.id)||e.conveyorTiles.has(E))return!0}return!1}function g(s,a,h=null){let m={col:s,row:a};for(let w of Pt(m)){if(!ie(w.col,w.row)||P(w.col,w.row))return!0;let E=A(w.col,w.row);if(ft(e,w.col,w.row))return!0;let Q=pt(e,w.col,w.row);if(Q&&!(h?.type==="scanner"&&h.ref?.id===Q.id)||e.conveyorTiles.has(E))return!0}return!1}function N(){return e.selected?e.selected.type==="eggFarm"?e.eggFarms.find(s=>s.id===e.selected.id)||null:e.selected.type==="scanner"?e.scanners.find(s=>s.id===e.selected.id)||null:e.selected.type==="conveyor"?e.conveyorTiles.has(e.selected.id)?{type:"conveyor",id:e.selected.id}:null:e.selected.type==="facility"?e.facilities[e.selected.id]||null:e.selected.type==="maintenanceRoom"&&(e.maintenanceRooms||[]).find(s=>s.id===e.selected.id)||null:null}function j(s){return s?s.type==="eggFarm"?`${ut("eggFarm")} #${s.id}`:s.type==="scanner"?`${s.kind==="auto"?ut("autoScanner"):ut("manualScanner")} #${s.id}`:s.type==="conveyor"?e.conveyorMeta.get(s.id)?.kind==="boostConveyor"?ut("boostConveyor"):ut("conveyor"):s.type==="facility"?s.name:s.type==="maintenanceRoom"?`${ut("maintenanceRoom")} #${s.id}`:"Equipment":"Equipment"}function J(s){return s?.type==="conveyor"?e.conveyorMeta?.get(s.oldKey||s.ref?.id)?.price||Nn(s):Nn(s)}function pe(){return!!e.cardEffects?.usedMachineActive}function xe(){return pe()?{usedMachine:!0,noRefund:!0,durabilityBaseMultiplier:.6}:{usedMachine:!1,noRefund:!1,durabilityBaseMultiplier:1}}function Pe(s){let a=xe();return Object.assign(s,a),s}function Ae(s){let a=s?.ref||s||{};if(s?.type==="eggFarm"||a.type==="eggFarm")return e.eggFarms.length<=1?"Cannot sell the last EGG FARM.":"";if((s?.type==="facility"||a.type==="facility")&&["mixer","trash","truck"].includes(a.baseId||a.id)){let h=a.baseId||a.id;if(Object.values(e.facilities).filter(w=>(w.baseId||w.id)===h).length<=1)return`Cannot sell the last ${a.shortName||a.name||a.id}.`}return""}function _(s){t.buildStatus.textContent=s,K(e,n.width/2-e.view.x,86-e.view.y,s.toUpperCase(),y.danger)}function De(s){if(!s)return null;let a=A(s.col,s.row);return e.conveyorMeta.get(a)||null}function Ye(s){return s?(Array.isArray(s.outDirs)||(s.outDirs=[]),s.outDirs=[...new Set(s.outDirs.filter(a=>["right","left","down","up"].includes(a)))],T.includes(s.branchMode)||(s.branchMode="random"),s.kind||(s.kind="conveyor"),s.speedMultiplier||(s.speedMultiplier=s.kind==="boostConveyor"?2:1),s.outDirs):[]}function Ve(s){return s?de.filter(a=>e.conveyorTiles.has(A(s.col+a.dc,s.row+a.dr))).map(a=>a.name):[]}function Te(s){return Ve(s).length>=3}function kt(s,a){let h=de.find(Q=>Q.name===a);if(!s||!h)return!1;let m=A(s.col+h.dc,s.row+h.dr),w=e.conveyorMeta.get(m);if(!w)return!1;let E=h.opposite;return[...new Set([...Array.isArray(w.outDirs)?w.outDirs:[],w.dir].filter(Boolean))].includes(E)}function oo(s){if(!e.conveyorTiles.has(s))return[];let a=te(s),h=e.conveyorMeta.get(s),m=Ye(h),w=Ve(a),E=[...new Set([...m,h?.dir].filter(Boolean))].filter(ue=>w.includes(ue)),ne=w,Q=E.length?E:ne;return h&&(h.outDirs=m.filter(ue=>w.includes(ue)),h.dir&&!w.includes(h.dir)&&(h.dir=h.outDirs[0]||null),h.branchMode!=="random"&&!w.includes(h.branchMode)&&(h.branchMode="random")),Q}function Cn(s){if(!e.conveyorTiles.has(s))return[];let a=te(s),h=Ve(a);return Te(a)||h.length?h:oo(s)}function ro(s){let a=te(s),h=Cn(s);if(h.length<3)return[];let m=e.conveyorMeta.get(s)||{},w=new Set(h.filter(Q=>kt(a,Q))),E=h.filter(Q=>!w.has(Q));if(w.size&&E.length>=2)return E;let ne=[...new Set([...Array.isArray(m.outDirs)?m.outDirs:[],m.dir].filter(Boolean))].filter(Q=>h.includes(Q));return ne.length>=2?ne:h}function nn(s,a){let h=ct(s,a);if(!h)return!1;let m=A(s.col,s.row),w=A(a.col,a.row),E=e.conveyorMeta.get(m),ne=e.conveyorMeta.get(w);if(!E||!ne)return!1;let Q=Ye(E),ue=!Q.includes(h)||E.dir!==h||!ne.dir;return Q.includes(h)||Q.push(h),E.dir=h,ne.dir||(ne.dir=h),ue}function Ct(s){let a=so(s);return a.length<2?io(s):(Be(e),lo(a),me(e),i(),!0)}function io(s){if(!s)return!1;let a=A(s.col,s.row),h=e.conveyorMeta.get(a);if(!h||Te(s))return!1;let m=de.map(ne=>ne.name),w=h.dir&&m.includes(h.dir)?h.dir:null,E=m[(Math.max(-1,m.indexOf(w))+1)%m.length];return Be(e),h.dir=E,h.outDirs=[E],h.branchMode="random",me(e),i(),!0}function Mn(s){return s?de.map(a=>({col:s.col+a.dc,row:s.row+a.dr})).filter(a=>e.conveyorTiles.has(A(a.col,a.row))):[]}function so(s){if(!s||!e.conveyorTiles.has(A(s.col,s.row))||Te(s))return[];let a=Mn(s);if(!a.length||a.length>2)return[];let h=E=>{let ne=[],Q=new Set([A(s.col,s.row)]),ue=s,ke=E,xr=0;for(;ke&&xr<200;){xr+=1;let Tr=A(ke.col,ke.row);if(Q.has(Tr)||(Q.add(Tr),ne.push(ke),Te(ke)))break;let Er=Mn(ke).filter(Rr=>!(Rr.col===ue.col&&Rr.row===ue.row));if(Er.length!==1)break;ue=ke,ke=Er[0]}return ne},m=a[0]?h(a[0]).reverse():[],w=a[1]?h(a[1]):[];return[...m,s,...w]}function Mt(s,a){return!!s&&[...new Set([...Array.isArray(s.outDirs)?s.outDirs:[],s.dir].filter(Boolean))].includes(a)}function lo(s){let a=0,h=0;for(let w=0;wh?[...s].reverse():s;for(let w=0;w=Math.abs(m)?{col:s.col+Math.sign(h),row:s.row}:{col:s.col,row:s.row+Math.sign(m)}}function ao(s){c=!1,b=s?{col:s.col,row:s.row}:null,C=!1,l=null,on(s)}function d(s){if(!s)return;if(!l)return on(s);let a=l,h=0;for(;(a.col!==s.col||a.row!==s.row)&&h<64;){let m=rn(a,s);if(on(m),a=l||m,h+=1,!l)break}}function p(){!C&&b&&e.conveyorTiles.has(A(b.col,b.row))&&Ct(b),b=null,C=!1,l=null,c=!1}function v(s){if(!s)return _(oe.fail.outOfGrid);let{col:a,row:h}=s;if(e.buildTool==="conveyor"||e.buildTool==="boostConveyor"){let m=_t(s,null);if(!m.ok)return _(m.reason||oe.fail.cellOccupied);me(e);return}if(P(a,h))return _("Cannot build on blocked ground.");if(e.buildTool==="maintenanceRoom")return S(a,h)?_(oe.fail.cellOccupied):D(a,h);if(e.buildTool==="manualScanner"||e.buildTool==="autoScanner"?g(a,h):F(a,h))return _(oe.fail.cellOccupied);e.buildTool==="eggFarm"?k(a,h):e.buildTool==="manualScanner"?R(a,h,"manual"):e.buildTool==="autoScanner"&&R(a,h,"auto")}function M(s){let a=He(s.x,s.y);if(["conveyor","boostConveyor","eggFarm","manualScanner","autoScanner","maintenanceRoom"].includes(e.buildTool))return v(a);if(cn.includes(e.buildTool))return le(s,e.buildTool)}function k(s,a){let h=Oe("eggFarm",e);if(e.cashE.kind==="manual").length>=8)return _("Manual Scanner limit reached (8 max).");let m=h==="auto"?Oe("autoScanner",e):Oe("manualScanner",e);if(e.cashw.id!==a.ref.id),et(e,m.x,m.y),me(e)}if(a.type==="scanner"){let m=ye(a.ref);Ne(a,m.x,m.y),e.scanners=e.scanners.filter(w=>w.id!==a.ref.id),et(e,m.x,m.y),me(e)}if(a.type==="facility"){let m=a.ref;Ne(a,m.x+m.w/2,m.y+m.h/2),delete e.facilities[m.id],et(e,m.x+m.w/2,m.y+m.h/2),me(e)}if(a.type==="maintenanceRoom"){let m=a.ref,w=q(m);Ne(a,w.x,w.y),e.maintenanceRooms=(e.maintenanceRooms||[]).filter(E=>E.id!==m.id),et(e,w.x,w.y)}e.selected=null,e.multiSelected=[],i()}function co(s){let a=Object.values(e.facilities).find(Q=>{if(s.x>=Q.x&&s.x<=Q.x+Q.w&&s.y>=Q.y&&s.y<=Q.y+Q.h)return!0;if(!Q.entry)return!1;let ke=B(Q.entry.col,Q.entry.row);return Math.abs(s.x-ke.x)<=f.cell*.46&&Math.abs(s.y-ke.y)<=f.cell*.46});if(a)return{type:"facility",ref:a};let h=He(s.x,s.y);if(!h)return null;let m=ft(e,h.col,h.row);if(m)return{type:"eggFarm",ref:m};let w=pt(e,h.col,h.row);if(w)return{type:"scanner",ref:w};let E=U(e,h.col,h.row);if(E)return{type:"maintenanceRoom",ref:E};let ne=A(h.col,h.row);return e.conveyorTiles.has(ne)?{type:"conveyor",oldKey:ne,ref:{type:"conveyor",id:ne}}:null}let Ut=$s({game:e,canvasPoint:o,updatePanels:i,equipmentAtPoint:co,fail:_,pointInGrid:ie,rectOfFacility:G,rectsOverlap:H});function js(s){return null}function vr(){let s=N();s&&(s.type==="conveyor"?Gt(B(...Object.values(te(s.id)))):s.type==="eggFarm"?Gt(B(s.col,s.row)):s.type==="scanner"?Gt(ye(s)):s.type==="facility"?Gt({x:s.x+s.w/2,y:s.y+s.h/2}):s.type==="maintenanceRoom"&&Gt(q(s)))}function Ke(s,a,h="primary-button"){let m=document.createElement("button");return m.type="button",m.className=h,m.textContent=s,m.addEventListener("click",a),m}function sn(){e.cardTargetPick?.mode==="autoScannerMenu"&&(e.cardTargetPick=null),t.modal.classList.remove("visible","equipment-popover"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function uo(s){t.modalTitle.textContent="Auto Scanner",e.cardTargetPick={pending:!0,mode:"autoScannerMenu",cardId:null,targetKeys:[`scanner:${s.id}`],remaining:1},t.modalBody.innerHTML=` -
-

Left / right output routing for this AUTO scanner.

-

Current: ${s.role===0?"Male left / others right":"Poop left / others right"}

-

Cooldown: ${nt(s).toFixed(1)}s.

-
`,t.modalActions.innerHTML="";let a=Ke("Male Left / Others Right",()=>{Be(e),s.role=0,sn(),i()},s.role===0?"facility-action warn":"facility-action"),h=Ke("Poop Left / Others Right",()=>{Be(e),s.role=1,sn(),i()},s.role===1?"facility-action warn":"facility-action");t.modalActions.append(a,h,Ke("Close",sn,"facility-action")),fo(s),t.modal.classList.add("visible","equipment-popover"),i()}function wr(s){return s?.label||s?.key||"?"}function Zs(s){let a=s.key===" "?"Space":s.key.length===1?s.key.toUpperCase():s.key.replace(/^Arrow/,"");return{key:s.key.toLowerCase(),code:s.code,label:a}}function el(s,a,h){for(let m of e.scanners.filter(w=>w.kind==="manual"))for(let w of["left","right"]){if(m.id===s.id&&w===a)continue;let E=m.keys?.[w];if(E&&(E.code===h.code||E.key===h.key))return!0}return!1}function ln(s,a=""){if(!s||s.kind!=="manual")return;t.modalTitle.textContent=`Manual Scanner #${s.id}`;let h=wr(s.keys?.left),m=wr(s.keys?.right),w=tl(s);t.modalBody.innerHTML=` -
-

Left route key: ${h}

-

Right route key: ${m}

- ${a?`

${a}

`:""} - ${w?`

${w}

`:""} -
`,t.modalActions.innerHTML="",t.modalActions.appendChild(Ke("Set Left Key",()=>Sr(s,"left"),"facility-action warn")),t.modalActions.appendChild(Ke("Set Right Key",()=>Sr(s,"right"),"facility-action warn")),t.modalActions.appendChild(Ke("Close",sn,"facility-action")),fo(s),t.modal.classList.add("visible","equipment-popover")}function tl(s){let a=[{side:"left",binding:s.keys?.left},{side:"right",binding:s.keys?.right}];if(a[0].binding&&a[1].binding&&(a[0].binding.code===a[1].binding.code||a[0].binding.key===a[1].binding.key))return"Left and right keys conflict.";for(let h of a)if(h.binding)for(let m of e.scanners.filter(w=>w.kind==="manual"&&w.id!==s.id)){if(m.keys?.left&&(m.keys.left.code===h.binding.code||m.keys.left.key===h.binding.key))return`Key conflicts with Manual Scanner #${m.id} left.`;if(m.keys?.right&&(m.keys.right.code===h.binding.code||m.keys.right.key===h.binding.key))return`Key conflicts with Manual Scanner #${m.id} right.`}return""}function Sr(s,a){t.modalBody.innerHTML=`

Press a key for ${a.toUpperCase()} route.

Esc cancels.

`,t.modalActions.innerHTML="";let h=m=>{if(m.preventDefault(),m.stopPropagation(),window.removeEventListener("keydown",h,!0),m.key==="Escape")return ln(s);let w=Zs(m),E=el(s,a,w);Be(e),s.keys=s.keys||{left:null,right:null},s.keys[a]=w,i(),ln(s,E?`${w.label} assigned, but another scanner already uses it.`:`${a.toUpperCase()} set to ${w.label}.`)};window.addEventListener("keydown",h,!0)}function nl(){let s=N();if(!(!s||s.type!=="scanner"))return s.kind==="auto"?uo(s):ln(s)}function ol(s){if(!s)return{x:80,y:80};if(s.type==="conveyor"){let a=te(s.id);return B(a.col,a.row)}return s.type==="eggFarm"?B(s.col,s.row):s.type==="scanner"?ye(s):s.type==="facility"?{x:s.x+s.w/2,y:s.y+10}:{x:80,y:80}}function fo(s){let a=n.getBoundingClientRect(),h=ol(s),m=e.view?.scale||1,w=a.left+(h.x*m+(e.view?.x||0))/n.width*a.width+18,E=a.top+(h.y*m+(e.view?.y||0))/n.height*a.height-12,ne=Math.max(12,window.innerWidth-274),Q=Math.max(12,window.innerHeight-220);t.modal.style.setProperty("--popover-x",`${Math.max(12,Math.min(ne,w))}px`),t.modal.style.setProperty("--popover-y",`${Math.max(12,Math.min(Q,E))}px`)}function kr(){let s=N();if(!s)return;let a=gr(s);if(t.modalTitle.textContent=j(s),t.modalBody.innerHTML=` -
${a.map(w=>`

${w}

`).join("")}
- ${["mixer","truck"].includes(s.baseId||s.id)?'

Income/Fine = ceil(base x 1.10^upgrades)

':""}`,t.modalActions.innerHTML="",s.type==="scanner"&&s.kind==="auto"&&t.modalActions.appendChild(Ke("Auto Menu",()=>uo(s),"facility-action warn")),s.type==="scanner"&&s.kind==="manual"&&t.modalActions.appendChild(Ke("Set Keys",()=>ln(s),"facility-action warn")),s.type==="conveyor"&&po(s.id)){let w=e.conveyorMeta.get(s.id)?.branchMode||"random";t.modalActions.appendChild(Ke(`Branch: ${Cr(w)}`,()=>{yo(s.id),e.selected={type:"conveyor",id:s.id},kr()},"facility-action warn branch-action"))}let h=s.type==="conveyor"?{type:"conveyor",oldKey:s.id,ref:s}:{type:s.type,ref:s},m=Ae(h);if(m){let w=Ke(m,()=>{},"facility-action danger disabled");w.disabled=!0,t.modalActions.appendChild(w)}else{let w=mt(h,e),E=w.sameBuild?`Remove / Refund ${x(w.amount)}`:`Sell ${x(w.amount)}`;t.modalActions.appendChild(Ke(E,()=>{vr(),sn()},"facility-action danger"))}fo(s),t.modal.classList.add("visible","equipment-popover")}function rl(s){e.phase==="build"&&(p(),e.buildTool=e.buildTool===s?null:s,e.selected=null,e.multiSelected=[],e.selectionBox=null,i())}function il(){let s=[];for(let[a,h]of Object.entries(e.facilities))if(s.push({id:`facility:${a}`,price:J({type:"facility",ref:h}),x:h.x,y:h.y,w:h.w,h:h.h}),h.entry){let m=B(h.entry.col,h.entry.row);s.push({id:`facilityPort:${a}`,price:J({type:"facility",ref:h}),x:m.x-18,y:m.y-18,w:36,h:36})}for(let a of e.maintenanceRooms||[]){let h=q(a);s.push({id:`maintenanceRoom:${a.id}`,price:J({type:"maintenanceRoom",ref:a}),x:h.x-f.cell,y:h.y-f.cell,w:f.cell*2,h:f.cell*2})}for(let a of e.eggFarms){let h=B(a.col,a.row);s.push({id:`eggFarm:${a.id}`,price:J({type:"eggFarm",ref:a}),x:h.x-24,y:h.y-24,w:48,h:48})}for(let a of e.scanners){let h=ye(a);s.push({id:`scanner:${a.id}`,price:J({type:"scanner",ref:a}),x:h.x-50,y:h.y-73,w:100,h:146})}for(let a of e.conveyorTiles){let h=te(a),m=B(h.col,h.row),w=e.conveyorMeta.get(a)||{};s.push({id:`conveyor:${a}`,price:w.price||Oe(w.kind==="boostConveyor"?"boostConveyor":"conveyor",e),x:m.x-22,y:m.y-22,w:44,h:44})}return s}function Cr(s){return I[s]||I.random}function Vc(s){return Cn(s)}function po(s){return e.conveyorTiles.has(s)?Te(te(s)):!1}function Mr(s){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return null;for(let a of e.conveyorTiles){if(!po(a))continue;let h=te(a),m=B(h.col,h.row),w=m.x-$.w/2,E=m.y+$.y-$.h/2;if(s.x>=w&&s.x<=w+$.w&&s.y>=E&&s.y<=E+$.h)return a}return null}function sl(s){let a=Mr(s);return a?yo(a):!1}function yo(s){let a=e.conveyorMeta.get(s);if(!a)return!1;let h=ro(s);if(h.length<2)return!1;Be(e);let m=T.includes(a.branchMode)?a.branchMode:"random",w=["random",...de.map(E=>E.name).filter(E=>h.includes(E))];return a.branchMode=w[(Math.max(0,w.indexOf(m))+1)%w.length],me(e),e.selected=null,e.multiSelected=[],i(),!0}function gr(s){Se(e);let a=[],h=s?.type==="facility"?s.baseId||s.id:"";if(s.type==="eggFarm"){let[m,w]=dn(s);a.push(`Price: ${x(J(s))}`);{let E=Ae({type:s.type,ref:s});a.push(E?`Sale: blocked (${E})`:`Sale value: ${x(mt({type:s.type,ref:s},e).amount)}`)}a.push(`Level: ${s.level}/4`),a.push(`Random interval: ${m.toFixed(2)}-${w.toFixed(2)}s`),a.push(`Durability: ${bn(s)}% | Spawn delay x${Yn(s).toFixed(2)}`)}else if(s.type==="scanner")a.push(`Price: ${x(J(s))}`),a.push(`Sale value: ${x(mt({type:s.type,ref:s},e).amount)}`),a.push(`Type: ${s.kind.toUpperCase()} / Standard`),s.kind==="auto"&&a.push(`Role: ${s.role===0?"Male left / Others right":"Poop left / Others right"}`),a.push(`Queue: ${s.queue.length}`),s.kind==="auto"&&a.push(`Cooldown: ${s.cooldown.toFixed(1)}s / ${nt(s,e).toFixed(1)}s`),s.kind==="auto"&&a.push(`Durability: ${bn(s)}% | Delay x${qn(s).toFixed(2)}`),s.kind==="manual"&&a.push("Durability: none | Always normal");else if(s.type==="conveyor"){let m=e.conveyorMeta.get(s.id),w=e.componentLookup?.get(s.id),E=w?e.congestion.get(w):null;a.push(`Price: ${x(J({type:"conveyor",oldKey:s.id,ref:s}))}`),a.push(`Cell: ${s.id}`),a.push(`Type: ${m?.kind==="boostConveyor"?"BOOST BELT":"Normal Belt"} | Speed x${Number(m?.speedMultiplier||1).toFixed(1)}`),a.push(`Congestion: ${E?Math.floor(E.ratio*100):0}%`),a.push(`Durability: ${bn({meta:m})}% | Speed x${Hn({meta:m}).toFixed(2)}`),po(s.id)?(a.push(`Branch mode: ${Cr(m?.branchMode||"random")}`),a.push("Click the Branch button or the large on-belt badge to cycle RANDOM / fixed exit.")):a.push("Branch mode: needs 3+ conveyor connections."),a.push(`Sale value: ${x(mt({type:"conveyor",oldKey:s.id,ref:s},e).amount)}`)}else if(s.type==="maintenanceRoom")a.push(`Price: ${x(J({type:"maintenanceRoom",ref:s}))}`),a.push(`Sale value: ${x(mt({type:"maintenanceRoom",ref:s},e).amount)}`),a.push("Size: 2\xD72 grid cells"),a.push("Dispatch: 1 repairman during each production day");else if(s.type==="facility"){a.push(`Price: ${x(J(s))}`);{let m=Ae({type:s.type,ref:s});a.push(m?`Sale: blocked (${m})`:`Sale value: ${x(mt({type:s.type,ref:s},e).amount)}`)}if(a.push(["mixer","truck","trash"].includes(s.id)?`Level: ${s.level} / no cap`:`Level: ${s.level}`),h==="truck"&&a.push("Durability: none | Always normal"),["mixer","trash"].includes(h)&&a.push(`Durability: ${bn(s)}% | Extra delay ${Zo(e,s).toFixed(2)}s`),h==="mixer"&&(a.push(`Income: ${x(ze(e))} per chick | upgrade x${yt(e,"mixer").toFixed(3)}`),a.push(`Poop fine: -${x(pn(e))}`)),h==="truck"&&(a.push(`Income: ${x(Fe(e))} per target cargo | upgrade x${yt(e,"truck").toFixed(3)}`),a.push(`Poop shipment fine: -${x(yn(e))}`)),h==="trash"){let m=It(e),w=ht(m);a.push(`Bonus cards: ${m}/${Vt()}`),a.push(`Poop income bonus: ${x(w)} per processed poop.`),a.push("With enough upgrades, poop can out-earn male/female routes.")}s.entry&&a.push(`Receiver: edge cell ${s.entry.col},${s.entry.row} (${s.side})`)}return a}function ll(s){if(!s||e.phase!=="build")return"";let a=Ln(e).find(h=>h.type===s.type&&h.id===s.id);return a?a.message||"Not connected to conveyor route":""}function al(s){return s?s.type==="conveyor"&&e.conveyorMeta.get(s.id)?.kind==="boostConveyor"?"Moves chicks twice as fast. Wears down like a normal belt.":s.type==="conveyor"?"A stubborn belt tile. It only cares about the next cell.":s.type==="eggFarm"?"A tiny gatehouse producing questionable eggs on schedule.":s.type==="scanner"&&s.kind==="auto"?"Slower than hands without upgrades.":s.type==="scanner"?"A manual checkpoint. The operator is the algorithm.":s.type==="facility"&&(s.baseId||s.id)==="mixer"?"Male chicks become revenue here. Do not feed it poop.":s.type==="facility"&&(s.baseId||s.id)==="trash"?"Poop goes in. Sometimes coins come out, for reasons best left unaudited.":s.type==="facility"&&(s.baseId||s.id)==="truck"?"The shipping endpoint. Correct cargo pays; wrong cargo complains.":s.type==="maintenanceRoom"?"A cramped 2\xD72 storage and break room with lockers, spare parts, a bench and one dispatched repairman.":"Factory equipment.":""}return{buildAtCell:v,buildAtPoint:M,eraseAtPoint:Gt,equipmentAtPoint:co,startSelectionBox:Ut.startSelectionBox,updateSelectionBox:Ut.updateSelectionBox,finishSelectionBox:Ut.finishSelectionBox,startGroupDrag:Ut.startGroupDrag,updateGroupDrag:Ut.updateGroupDrag,finishGroupDrag:Ut.finishGroupDrag,selectedObject:N,selectedTitle:j,equipmentPrice:J,selectedUpgradeCost:js,selectedInfoLines:gr,flavorText:al,disconnectedWarningFor:ll,gridExpansionCost:O,buyGridExpansion:se,expansionOfferAtPoint:he,beginConveyorDrag:ao,continueConveyorDrag:d,endConveyorDrag:p,cycleSingleConveyorDirection:Ct,branchSwitcherAtPoint:Mr,cycleBranchModeAtPoint:sl,cycleBranchModeForKey:yo,removeSelected:vr,switchScannerRole:nl,showManualScannerMenu:ln,showAutoScannerMenu:uo,showSelectedMenu:kr,setBuildTool:rl,fail:_,isEquipmentCell:F,equipmentHitBoxes:il,routeFromFarmToScanner:Dt}}function Bs({game:e,ui:t,build:n,startGame:o,beginCardDraft:r,activeQueuedChick:i}){function l(F){return String(F).replace(/[&<>"']/g,U=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[U])}function c(){return Math.round(Xn(e))}function b(){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return!1;let F=!1;for(let U of So)if(F=!0,e.cash>=Oe(U,e))return!1;return F}function C(){T(),I(),ee(),O(),$()}function T(){for(let[U,S]of Object.entries(t.buttons))S?.classList?.contains("tool-button")&&S.classList.toggle("active",e.buildTool===U);for(let U of So){let S=t.buttons[U];if(!S)continue;let g=Oe(U,e),N=S.querySelector("span");N&&(N.textContent=U==="conveyor"||U==="boostConveyor"?`${x(g)} / tile`:x(g));let j=U==="manualScanner"&&e.scanners.filter(pe=>pe.kind==="manual").length>=8,J=e.cashDt(e,j)?.scannerId).length,U=fn(e),S=Math.max(0,Math.floor(e.lastResult?.profit??e.stats?.profit??0)),g=Math.max(1,Number(e.turn)||1),N=_n(e,g,S);t.turnSummary.innerHTML=[`Seed: ${l(e.runSeed||"none")} | Grid box: ${e.gridRows||10}x${e.gridCols||20} | Owned: ${e.gridOwnedCells||e.ownedCells?.size||(e.gridRows||10)*(e.gridCols||20)} cells | Blocked: ${e.blockedCells?.size||0} cells`,`Truck target: ${je(e).toUpperCase()} | Male fine: -${x(Uo(e))}`,`Poop fine: Mixer -${x(pn(e))} / Shipment -${x(yn(e))}`,`Fairies tribute on Next Day: -${x(N.amount)} | base ${x(N.base)} + profit share ${x(N.profitTribute)} | basis net ${x(S)} | exemption ${x(N.profitExemption)}${N.reduction?` | reduction -${x(N.reduction)}`:""}`,`Maintenance: worst ${or(e).worst.percent}% dirty (${or(e).worst.label}) | Repair rooms: ${(e.maintenanceRooms||[]).length} | Repairmen: ${(e.repairmen||[]).length}`,`Manual combo: ${e.manualCombo?.count||0} | Card draft: ${e.cardDraft?.pending?Math.max(1,e.cardDraft.picksRemaining||1)+" pick(s) left":"ready after each day"} | Belt: ${c()}px/s | Farms with scanner route: ${F}/${e.eggFarms.length}`,e.cardEffects?.usedMachineActive?'Procurement: USED MACHINE MODE / no refunds / 60% durability':"",U.length?`Blocked: ${U[0]}`:`${oe.status.allPortsConnected}`].join("
")}function ee(){if(!t.eventPanel)return;let F=e.eventOffer;if(e.phase!=="build"){t.eventPanel.innerHTML=oe.status.eventPanelRunning;return}if(!F){t.eventPanel.className="event-card empty",e.turn+1Event lock active.No irregular events during Days 1-7. First possible forced event: Day ${xt}.`:t.eventPanel.innerHTML="No event.Random forced events can appear later.";return}t.eventPanel.className="event-card accepted",t.eventPanel.innerHTML=` -
FORCED NEXT DAY
-

${F.title}

-
- Effect: ${F.route} - ${F.targetAmount?`Target: ${F.targetAmount}`:"Target: none"} - ${F.reward?`Reward: ${x(F.reward)}`:"Reward: none"} - Time ${F.daySeconds||60}s / Output x${Number(F.productionMultiplier||1).toFixed(2)} / Poop +${Math.round((F.poopRateAdd||0)*100)}pt -
`}function X(){T(),t.shell.classList.toggle("phase-running",e.phase==="running"),t.shell.classList.toggle("phase-build",e.phase==="build"),t.shell.classList.toggle("phase-gameover",e.phase==="gameover"),t.shell.classList.toggle("phase-title",e.phase==="title"),t.shell.classList.toggle("phase-loanDecision",e.phase==="loanDecision"),t.money.textContent=x(e.cash),t.money.classList.toggle("cash-negative",e.cash<0),t.money.classList.toggle("cash-positive",e.cash>an),t.turn.textContent=e.turn,t.timeLeft.textContent=e.phase==="running"&&e.timeLeft<=0&&e.shutdownTimeLeft>0?`+${e.shutdownTimeLeft.toFixed(1)}s`:`${Math.max(0,e.timeLeft).toFixed(1)}s`,t.timeLeft.closest?.(".hud-card")?.classList.toggle("time-critical",e.phase==="running"&&(e.timeLeft<=10||e.timeLeft<=0&&e.shutdownTimeLeft>0)),t.phase.textContent=he(),t.comboCount&&(t.comboCount.textContent=e.manualCombo?.count||0),ae(),t.turnProfit.textContent=x(e.stats.profit),t.turnProfit.classList.toggle("cash-negative",e.stats.profit<0),t.turnProfit.classList.toggle("cash-positive",e.stats.profit>0),t.mixerCount.textContent=e.stats.mixerCount,t.truckFemaleCount.textContent=e.stats.truckFemale,t.truckMaleCount.textContent=e.stats.truckMale,t.poopCount.textContent=e.stats.poopSpawned,t.buttons.s1Left.disabled=e.phase!=="running"||!i(0),t.buttons.s1Right.disabled=e.phase!=="running"||!i(0),t.buttons.s2Left.disabled=e.phase!=="running"||!i(1),t.buttons.s2Right.disabled=e.phase!=="running"||!i(1);let F=e.scanners.find(N=>N.kind==="manual"&&N.slot===0),U=e.scanners.find(N=>N.kind==="manual"&&N.slot===1);F&&(t.buttons.s1Left.textContent=`S1 ${F.keys?.left?.label||"A"} -> Mixer`,t.buttons.s1Right.textContent=`S1 ${F.keys?.right?.label||"D"} -> S2`),U&&(t.buttons.s2Left.textContent=`S2 ${U.keys?.left?.label||"Left"} -> Waste`,t.buttons.s2Right.textContent=`S2 ${U.keys?.right?.label||"Right"} -> Truck`);let S=Math.max(0,Math.floor(e.lastResult?.profit??e.stats?.profit??0)),g=_n(e,Math.max(1,Number(e.turn)||1),S).amount;t.buttons.nextTurn.textContent=e.phase==="build"&&g>0?`Next Day - Fairies ${x(g)}`:oe.actions.nextDay,t.buttons.nextTurn.disabled=e.phase!=="build"||!!e.cardDraft?.pending||!!e.cardTargetPick?.pending||!yi(e)}function ae(){if(!t.eventBrief||!t.targetBrief||!t.speedBrief)return;let F=je(e).toUpperCase();t.targetBrief.textContent=`TRUCK TARGET: ${F}`,t.speedBrief.textContent=`BELT SPEED: ${c()} px/s`,t.speedBrief.title=`Conveyor speed does not increase by day. Degraded belts reduce speed. Cap: ${Wt}px/s.`;let U=e.eventActive,S=e.eventOffer;U?(t.eventBrief.textContent=`ACTIVE EVENT: ${U.title} | ${U.route}`,t.eventBrief.className="event-brief active"):e.phase==="build"&&S?(t.eventBrief.textContent=`NEXT DAY EVENT: ${S.title} | ${S.route}${S.targetAmount?` | Target ${S.targetAmount}`:""}${S.reward?` | Reward ${x(S.reward)}`:""}`,t.eventBrief.className="event-brief next"):e.phase==="build"&&e.turn+1
\u2642Male->MixerS1: A
\u2640Female->TruckS1: D, then S2: right
\u{1F4A9}Poop->ShredderS1: D, then S2: left

Build phase: connect at least one EGG through a scanner to Mixer, Shredder, or Truck before Next Day. One day is one run.

',t.modalActions.innerHTML="",t.modalActions.appendChild(G(oe.actions.startGame,o,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function se(F){let U=j=>`${j>0?"+":""}${x(j)}`,S=j=>`${j>0?"-":""}${x(j)}`,g=F.profit>=0?"cash-positive":"cash-negative",N=(F.mixerPoopFine||0)+(F.truckPoopFine||0)+(F.maleTruckFine||0)+(F.explosionDamage||0)+(F.cardRerollCost||0);t.modalTitle.textContent=`Day ${F.turn} Settlement`,t.modalBody.innerHTML=` -
Net result${x(F.profit)}
-
-
Chick shipment income${U(F.chickShipmentIncome||0)}
-
Poop shipment income${U(F.poopShipmentIncome||0)}
-
Mixer income${U(F.mixerRevenue||0)}
-
Composter income${U(F.composterIncome||0)}
-
DUD refund income${U(F.dudRefundIncome||0)}
-
Manual combo bonus${U(F.manualComboBonus||0)}
-
Chemical subsidy${U(F.chemicalWeaponSubsidy||0)}
-
Event bonus${U(F.eventBonus||0)}
-
Penalties${S(N)}
-
Fairies fee${S(F.fairiesTribute?.amount||F.fairiesTribute||0)}
-
-

Income ${x(F.revenue)} - losses ${x(F.penalty)} = ${x(F.profit)}

`,t.modalActions.innerHTML="",t.modalActions.appendChild(G("Choose Upgrade Card",r||H,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function ie(F,U){let S=Math.max(0,e.cardEffects?.rescueLoanCharges||0);t.modalTitle.textContent="Emergency Loan Available",t.modalBody.innerHTML=` -

End-of-day cash is below ${x(0)}.

-
-
Current money${x(e.cash)}
-
Emergency Loan+${x(500)}
-
Cards remaining${S}
-
-

Use one Emergency Loan to gain ${x(500)} immediately. If cash is still negative, another decision will be shown if another card remains.

`,t.modalActions.innerHTML="",t.modalActions.appendChild(G("Accept Game Over",U,"facility-action danger")),t.modalActions.appendChild(G("Use Emergency Loan",F,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function P(){let F=e.totals.processed,U=F?Math.round(e.totals.correct/F*100):0,S=_i(e);t.modalTitle.textContent=oe.phases.gameover,t.modalBody.innerHTML=`

Your cash went negative.

-
Final Score${S.score}
Survival${e.totals.turnsCompleted} days
Final Cash${x(e.cash)}
Accuracy${U}%
-
Score breakdown -
Formula
Base = Cash + Total revenue + Factory value \xD70.5 + Event bonus \xD70.5 = ${x(S.base)}
Daily earned = ceil(Base \xF7 Days) = ${x(S.dailyEarned)}
Score = max(0, floor(Base + Daily earned + Correct bonus - Total outflow - Day penalty)) = ${S.score}
-
Factory Value${x(S.factoryValue)}
Total Revenue${x(e.totals.revenue)}
Daily Earned${x(S.dailyEarned)} / day
Total Outflow${x(e.totals.penalty)}
Fairies Tribute${x(e.totals.fairiesTribute||0)}
Correct Sorts${e.totals.correct}
Auto Sorted${e.totals.autoSorted}
Poop Control${e.totals.poopTrash} trashed / ${e.totals.poopTruck} shipped / ${e.totals.poopMixer} mixer
Explosion Penalty${x(e.totals.explosionDamage)}
Event Bonus${x(e.totals.eventBonus)}
Day Penalty-${S.dayPenalty}
Events${e.totals.eventSuccess} success / ${e.totals.eventFailed} failed
-
`,t.modalActions.innerHTML="",t.modalActions.appendChild(G(oe.actions.restart||"Restart",o,"primary-button restart-button")),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible","gameover-modal")}function G(F,U,S="primary-button"){let g=document.createElement("button");return g.type="button",g.className=S,g.textContent=F,g.addEventListener("click",U),g}function H(){t.modal.classList.remove("visible","equipment-popover","gameover-modal"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function be(){}return{updatePanels:C,updateUI:X,showTitle:re,showTurnResult:se,showEmergencyLoanDecision:ie,showGameOver:P,hideModal:H,checkGameOver:be}}function br(e){e.totals.processed+=1}function Zt(e){e.stats.correct+=1,e.totals.correct+=1}function vt(e){e.stats.mistakes+=1,e.totals.mistakes+=1}function Ls(e){e.stats.autoSorted+=1,e.totals.autoSorted+=1}function Os(e){e.stats.poopSpawned+=1}function Ns(e){e.stats.mixerCount+=1,br(e)}function _s(e){e.stats.trashCount+=1,br(e)}function Gs(e,t){t==="female"?e.stats.truckFemale+=1:t==="male"&&(e.stats.truckMale+=1),br(e)}function Zn(e,t){let n=t==="truck"?"poopTruck":t==="trash"?"poopTrash":t==="mixer"?"poopMixer":null;n&&(e.stats[n]+=1,e.totals[n]+=1)}function Us({game:e,currentConveyorSpeed:t,onGameOverCheck:n}){function o(d){return Rt(d)*Yn(d)*fs(e)/ki(e)}function r(d){let p=B(d.col,d.row),v=1+ps(e,d),M=l(d,v);if(!M.length)return i(d,p),!0;let k=0,R=0;for(let D of M){let q=B(D.col,D.row),le=c(q);if(le){le.stoppedTimer=.85,R+=1;continue}let Ne=Is(e,{stage:"belt",scannerId:null,route:[q]});Ne.sex==="poop"&&Os(e),e.chicks.push(Ne),Ji(e,d),k+=1}return k>0?(Ui(e,p.x,p.y),k>1&&K(e,p.x,p.y-28,`x${k}`,y.green),!0):R===0}function i(d,p){(d.noRouteNoticeCooldown||0)<=0&&(K(e,p.x,p.y-24,"NO BELT: PAUSED",y.warn),d.noRouteNoticeCooldown=2.5)}function l(d,p){let M=de.map(k=>({col:d.col+k.dc,row:d.row+k.dr})).filter(k=>Ee(k.col,k.row)&&e.conveyorTiles.has(A(k.col,k.row))).map(k=>({p:k,blocked:$(null,B(k.col,k.row))?1:0,roll:Math.random()}));return M.sort((k,R)=>k.blocked-R.blocked||k.roll-R.roll),M.slice(0,Math.max(1,p||1)).map(k=>k.p)}function c(d){return e.chicks.find(p=>p.stage!=="flying"&&Math.hypot(p.x-d.x,p.y-d.y)0;if(e.timeLeft=Math.max(0,e.timeLeft-d),M&&e.timeLeft<=0&&p(),e.timeLeft<=0){e.shutdownTimeLeft>0&&(e.shutdownTimeLeft=Math.max(0,e.shutdownTimeLeft-d));for(let k of e.eggFarms)k.shutterProgress=Math.min(1,(k.shutterProgress||0)+d*2.8)}if(M&&e.timeLeft>0){for(let k of e.eggFarms)if(k.noRouteNoticeCooldown>0&&(k.noRouteNoticeCooldown=Math.max(0,k.noRouteNoticeCooldown-d)),k.nextSpawn-=d,k.nextSpawn<=0){let R=r(k);k.nextSpawn=R?o(k):.15,k.lastInterval=k.nextSpawn}}for(let k=e.chicks.length-1;k>=0;k-=1){let R=e.chicks[k];R.bob+=d*7,R.stoppedTimer>0&&(R.stoppedTimer=Math.max(0,R.stoppedTimer-d)),R.stage!=="queued"&&T(R,k,d)}_(d),_t(),on(),e.timeLeft<=0&&(e.chicks.length===0?v():e.shutdownTimeLeft<=0&&C())}function C(){if(e.cleanupBlown)return;e.cleanupBlown=!0,e.cleanupTimer=1;let d=[...e.chicks];for(let p of d)qo(e,p.sex,p.x,p.y,-Math.PI/2,!0);e.chicks=[];for(let p of e.scanners)p.queue=[];if(_t(),d.length){let p=d.reduce((M,k)=>M+k.x,0)/d.length,v=d.reduce((M,k)=>M+k.y,0)/d.length;Xe(e,p,v,y.warn,58),K(e,p,v-24,"CLEANUP",y.warn)}}function T(d,p,v){if(I(d)){d.stoppedTimer=.35;return}if(pe(d,v),!(d.route&&d.targetIndex=d.route.length)return!1;let p=d.route[d.targetIndex];return $(d,p)}function $(d,p){if(!p)return!1;for(let v of e.chicks)if(!(d&&v.id===d.id)&&v.stage!=="flying"&&Math.hypot(v.x-p.x,v.y-p.y)1)&&d.push({x:p.x,y:p.y})}function ee(d){let p=e.conveyorMeta?.get?.(d)||{},v=[];Array.isArray(p.outDirs)&&v.push(...p.outDirs),p.dir&&v.push(p.dir);let M=[...new Set(v)].filter(le=>de.some(Ne=>Ne.name===le)),k=te(d),R=de.filter(le=>P(k,le.name)).map(le=>le.name),D=M.filter(le=>R.includes(le)),q=R;return D.length?D:q}function X(d){return de.find(p=>p.name===d)||null}function ae(d,p){return e.scanners.find(v=>v.col<=d&&d<=v.col+1&&v.row-1<=p&&p<=v.row+1)||null}function he(d,p){let v=X(p);if(!v)return null;let M=ae(d.col+v.dc,d.row+v.dr);if(!M)return null;let k=Re(M,"inputA");return k&&k.col===d.col&&k.row===d.row?M:null}function re(d){return Object.entries(e.facilities||{}).find(([,p])=>p?.entry&&p.entry.col===d.col&&p.entry.row===d.row)||null}function se(d){return d?.baseId||d?.id||""}function ie(d,p){return d.side==="left"&&p==="left"||d.side==="right"&&p==="right"||d.side==="top"&&p==="up"||d.side==="bottom"&&p==="down"}function P(d,p){let v=X(p);if(!v)return null;let M={col:d.col+v.dc,row:d.row+v.dr};if(Ee(M.col,M.row)&&e.conveyorTiles.has(A(M.col,M.row)))return{type:"conveyor",dirName:p,target:B(M.col,M.row),nextCell:M};let k=he(d,p);if(k)return{type:"scanner",dirName:p,target:ye(k),scanner:k};let R=re(d);return R&&ie(R[1],p)?{type:"facility",dirName:p,facilityId:R[0],facility:R[1],target:B(d.col,d.row)}:null}function G(d,p){let v=X(p);if(!v)return!1;let M=e.conveyorMeta?.get?.(A(d.col+v.dc,d.row+v.dr));return M?[...new Set([...Array.isArray(M.outDirs)?M.outDirs:[],M.dir].filter(Boolean))].includes(v.opposite):!1}function H(d){return de.filter(p=>Ee(d.col+p.dc,d.row+p.dr)&&e.conveyorTiles.has(A(d.col+p.dc,d.row+p.dr))).map(p=>p.name)}function be(d,p,v="random"){let M=H(d);if(M.length<3)return p;let k=new Set(M.filter(q=>G(d,q))),R=M.filter(q=>!k.has(q)),D=k.size&&R.length>=2?R:[...new Set(p.filter(q=>M.includes(q)))];return D.length<2&&(D=M),v&&v!=="random"&&v!=="pass"&&D.includes(v)?[v]:D}function F(d,p){return p&&(p.type==="facility"||!$(d,p.target))}function U(d,p,v,M="random"){let k=v.map(le=>P(p,le)).filter(Boolean);if(!k.length)return null;let D=k.filter(le=>le.type!=="facility").filter(le=>!$(d,le.target)),q=D.length?D:k.filter(le=>le.type==="facility");return q.length?q[Math.floor(Math.random()*q.length)]:null}function S(d,p){let v=[];O(v,{x:d.x,y:d.y}),O(v,p),d.route=v.length?v:[{x:d.x,y:d.y}],d.targetIndex=d.route.length>1?1:d.route.length}function g(d,p){let v=He(d.x,d.y);if(!v)return Mt(p,"OFF GRID");let M=A(v.col,v.row);if(!e.conveyorTiles.has(M))return Mt(p,"OFF BELT");let k=e.conveyorMeta?.get(M)||{},R=be(v,ee(M),k.branchMode||"random");if(!R.length){d.stoppedTimer=.25;return}let D=U(d,v,R,k.branchMode||"random");if(!D){d.stoppedTimer=.25;return}if(D.type==="facility"){let q=se(D.facility);q==="mixer"?io(p,D.facility):q==="truck"?Mn(p,D.facility):q==="trash"?so(p,D.facility):Mt(p,"DONE");return}D.type==="scanner"&&(d.pendingScannerId=D.scanner.id),d.prevConveyorCell=M,S(d,D.target)}function N(d){let p=He(d.x,d.y);if(!p)return null;let v=A(p.col,p.row);return e.conveyorTiles.has(v)?v:null}function j(d){let p=N(d)||N(d.route?.[d.targetIndex]||d);return t(p)}function J(d,p){let v=N(p);!v||d.lastWearKey===v||(d.lastWearKey=v,Qi(e,v))}function pe(d,p){let v=j(d)*p;for(;v>0&&d.targetIndex=D?(d.x=M.x,d.y=M.y,J(d,M),d.targetIndex+=1,v-=D):(d.x+=k/D*v,d.y+=R/D*v,v=0)}}function xe(d,p,v){d.stage="queued",d.route=null,d.queueRoute=v?v.map(M=>({x:M.x,y:M.y})):[ye(p)],d.scannerId=p.id,p.queue.includes(d.id)||p.queue.push(d.id),Pe(p)}function Pe(d){d.queue=d.queue.filter(v=>e.chicks.some(M=>M.id===v&&M.stage==="queued"));let p=f.cell*.86*ys(e);d.queue.forEach((v,M)=>{let k=e.chicks.find(R=>R.id===v);k&&(Ae(k,k.queueRoute||[ye(d)],M*p),k.queueIndex=M)})}function Ae(d,p,v){if(!p||!p.length)return;if(p.length===1||v<=0){let R=p[p.length-1];d.x=R.x,d.y=R.y;return}let M=v;for(let R=p.length-1;R>0;R-=1){let D=p[R-1],q=p[R],le=Math.hypot(q.x-D.x,q.y-D.y);if(M<=le){let Ne=1-M/le;d.x=D.x+(q.x-D.x)*Ne,d.y=D.y+(q.y-D.y)*Ne;return}M-=le}let k=p[0];d.x=k.x,d.y=k.y}function _(d){for(let p of e.scanners){if(p.cooldown>0&&(p.cooldown=Math.max(0,p.cooldown-d)),p.keyPressTime>0&&(p.keyPressTime=Math.max(0,p.keyPressTime-d)),Pe(p),p.kind!=="auto"||p.cooldown>0||!p.queue.length)continue;let v=p.queue[0],M=e.chicks.findIndex(k=>k.id===v);if(M<0){p.queue.shift();continue}nn(M,Io(p,e.chicks[M]),!0)&&(ji(e,p),p.cooldown=nt(p,e),Ls(e))}}function De(d){let p=Ro(e,d);return!p||!p.queue.length?null:e.chicks.find(v=>v.id===p.queue[0])||null}function Ye(d,p){if(e.phase!=="running")return;let v=Ro(e,d);Ve(v,p)}function Ve(d,p){if(e.phase!=="running"||!d||d.kind!=="manual"||(d.keyPressTime=.18,d.keyPressSide=p,!d.queue.length))return;let v=e.chicks.findIndex(M=>M.id===d.queue[0]);v>=0&&nn(v,p,!1)}function Te(d,p,v){return d.kind==="manual"&&Io(d,p)===v}function kt(d){let p=e.manualCombo?.count||0;if(e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=0,e.manualCombo.lastBonus=0,e.stats.manualComboFailure=(e.stats.manualComboFailure||0)+1,e.totals.manualComboFailure=(e.totals.manualComboFailure||0)+1,p>=10){let v=ye(d);Ft(e,10,.25),K(e,v.x,v.y-36,"COMBO RESET",y.danger)}}function oo(d){e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=Math.max(0,e.manualCombo.count||0)+1,e.stats.manualComboSuccess=(e.stats.manualComboSuccess||0)+1,e.totals.manualComboSuccess=(e.totals.manualComboSuccess||0)+1;let p=e.manualCombo.count;if(e.manualCombo.lastBonus=0,p<10)return 0;let v=Math.max(1,Math.floor(p/10)),M=e.scanners.filter(q=>q.kind==="manual").length,k=Math.min(1,(20+M*10)/100),R=0;for(let q=0;q0){Ge(e,D),e.stats.manualComboBonus=(e.stats.manualComboBonus||0)+D,e.totals.manualComboBonus=(e.totals.manualComboBonus||0)+D,e.manualCombo.lastBonus=D;let q=ye(d);K(e,q.x,q.y-42,`COMBO +${x(D)}`,y.green)}return D}function Cn(d,p){let v=Re(d,p);if(!v)return null;let M=A(v.col,v.row);if(e.conveyorTiles.has(M))return{...v};let R=(_e(e).scannerPorts.get(d.id)?.[p]?.keys||[]).filter(Boolean);if(!R.length)return null;let D=R.map(te);return D.find(le=>le.col===v.col&&le.row===v.row)||D[0]||null}function ro(d,p,v,M){let k=[];O(k,{x:d.x,y:d.y});let R=Re(p,v);return R&&O(k,B(R.col,R.row)),O(k,B(M.col,M.row)),k}function nn(d,p,v){let M=e.chicks[d];if(!M||M.stage!=="queued")return!1;let k=At(e,M.scannerId);if(!k)return!1;let R=Cn(k,p);if(!R)return!v&&k.kind==="manual"&&kt(k),K(e,M.x,M.y-16,p==="left"?"NO LEFT BELT":"NO RIGHT BELT",y.danger),!1;!v&&k.kind==="manual"&&(Te(k,M,p)?oo(k):kt(k)),k.queue=k.queue.filter(q=>q!==M.id),M.stage="belt",M.route=ro(M,k,p,R),M.targetIndex=M.route.length>1?1:M.route.length,M.scannerId=null,M.nextScannerId=null,M.pendingScannerId=null,M.queueRoute=null,M.queueIndex=-1;let D=v?y.green:p==="left"?y.mixerBlue:y.truckPink;return Wi(e,ye(k).x,ye(k).y,D),K(e,M.x,M.y-20,v?"AUTO":p.toUpperCase(),D),!0}function Ct(d){let p=e.chicks[d];return p?(e.chicks.splice(d,1),p):null}function io(d,p=e.facilities.mixer){if(p?.processingCooldown>0){let D=e.chicks[d];D&&(D.stoppedTimer=.25);return}let v=Ct(d);if(!v)return;let{x:M,y:k}=v;if(Ns(e),er(e,p),tr(e,p),v.sex==="poop"){let D=Ii(e);Zn(e,"mixer"),vt(e),Hi(e,M,k),K(e,M,k-18,`-${x(D)}`,y.danger);return}let R=Di(e);v.sex==="male"?Zt(e):vt(e),Ki(e,M,k),K(e,M,k-18,`+${x(R)}`,y.green)}function Mn(d,p=e.facilities.truck){let v=Ct(d);if(!v)return;let{x:M,y:k}=v;lo(v.sex,p),Yi(e,M,k,v.sex),Gs(e,v.sex);let R=je(e),D=Mi(e,v.sex);if(v.sex==="poop"){if(Zn(e,"truck"),D)Zt(e),K(e,M,k-18,`+${x(Fe(e))}`,y.green);else{let q=$i(e);vt(e),K(e,M,k-18,`-${x(q)}`,y.danger)}return}if(v.sex==="female"){D?(Zt(e),K(e,M,k-18,`+${x(Fe(e))}`,y.green)):(vt(e),K(e,M,k-18,R==="male"?"REJECT":"NO SALE",y.warn));return}if(D){Zt(e),K(e,M,k-18,`+${x(Fe(e))}`,y.green);return}if(gi(e)){let q=Fi(e);vt(e),K(e,M,k-18,`-${x(q)}`,y.danger)}else vt(e),K(e,M,k-18,"REJECT",y.warn)}function so(d,p=e.facilities.trash){if(p?.processingCooldown>0){let q=e.chicks[d];q&&(q.stoppedTimer=.25);return}let v=Ct(d);if(!v)return;let{x:M,y:k}=v;qi(e,M,k,v.sex),_s(e),er(e,p),tr(e,p);let R={amount:0},D="";if(v.sex==="poop"){R=Ri(e),D=R.amount>0?` +${x(R.amount)}`:"",Zn(e,"trash"),Zt(e);let q=Math.ceil(Math.max(0,Number(e.cardEffects?.composter)||0)*3*On(e));if(q>0){let le=Ge(e,q);e.stats.composterIncome=(e.stats.composterIncome||0)+le,e.totals.composterIncome=(e.totals.composterIncome||0)+le,K(e,M,k-36,`COMPOST +${x(le)}`,y.green)}K(e,M,k-18,`CLEAN${D}`,R.amount>0?y.green:y.green)}else vt(e),K(e,M,k-18,R.amount>0?`WASTE${D}`:"WASTE",R.amount>0?y.green:y.ink)}function Mt(d,p){let v=Ct(d);v&&K(e,v.x,v.y-12,p,y.muted)}function lo(d,p=e.facilities.truck){let v=p||e.facilities.truck;v&&(e.truckCargo.push({sex:d,x:W(22,v.w-22),y:W(66,v.h-24)}),e.truckCargo.length>45&&e.truckCargo.shift())}function gn(d){let p=He(d.x,d.y);if(p){let R=A(p.col,p.row);if(e.conveyorTiles.has(R))return R}let v=ui(e,d.x,d.y);if(!v)return null;let M=te(v),k=B(M.col,M.row);return Math.hypot(d.x-k.x,d.y-k.y)<=f.cell*.55?v:null}function _t(){let{components:d,cellToComponent:p}=ci(e);for(let v of e.chicks){if(v.stage==="flying")continue;let M=gn(v);if(!M)continue;let k=p.get(M),R=d.get(k);R&&(R.count+=1)}for(let v of d.values())v.ratio=v.count/v.capacity;e.congestion=d,e.componentLookup=p}function on(){for(let d of e.congestion.values()){let p=_o(e),v=xi(e);if(d.ratio>v&&d.ratio=p){let M=rn(d.id);if(!M.length||M.some(D=>D.stage!=="queued"&&D.stoppedTimer<=.2))continue;let k=e.lastExplodedComponent.get(d.id)||0,R=performance.now();R-k>900&&(e.lastExplodedComponent.set(d.id,R),ao(d))}}}function rn(d){return e.chicks.filter(p=>{let v=gn(p);return v&&e.componentLookup?.get(v)===d})}function ao(d){let p=rn(d.id);if(!p.length)return;for(let k of p)qo(e,k.sex,k.x,k.y);e.chicks=e.chicks.filter(k=>!p.some(R=>R.id===k.id));for(let k of e.scanners)k.queue=k.queue.filter(R=>e.chicks.some(D=>D.id===R));for(let k of d.cells){let R=te(k),D=B(R.col,R.row);Xe(e,D.x,D.y,y.danger),Ze(e,D.x,D.y,6),Gn(e,D.x,D.y,4)}Ft(e,18,.75);let v=te(d.cells[0]),M=B(v.col,v.row);e.stats.explosions=(e.stats.explosions||0)+1,e.totals.explosions=(e.totals.explosions||0)+1,K(e,M.x,M.y-22,`${Math.round(_o(e)*100)}% JAM EXPLOSION`,y.danger)}return{activeQueuedChick:De,currentSpawnDelay:o,sortSlot:Ye,updateCongestion:_t,sortScanner:Ve,updateRunning:b}}var fe=document.getElementById("gameCanvas"),kc=fe.getContext("2d"),L={shell:document.getElementById("gameShell"),money:document.getElementById("money"),turn:document.getElementById("turn"),timeLeft:document.getElementById("timeLeft"),phase:document.getElementById("phaseLabel"),comboCount:document.getElementById("comboCount"),eventBrief:document.getElementById("eventBrief"),targetBrief:document.getElementById("targetBrief"),speedBrief:document.getElementById("speedBrief"),turnProfit:document.getElementById("turnProfit"),mixerCount:document.getElementById("mixerCount"),truckFemaleCount:document.getElementById("truckFemaleCount"),truckMaleCount:document.getElementById("truckMaleCount"),poopCount:document.getElementById("poopCount"),buildStatus:document.getElementById("buildStatus"),turnSummary:document.getElementById("turnSummary"),eventPanel:document.getElementById("eventPanel"),modal:document.getElementById("modal"),modalTitle:document.getElementById("modalTitle"),modalBody:document.getElementById("modalBody"),modalActions:document.getElementById("modalActions"),hoverTooltip:document.getElementById("hoverTooltip"),manualScannerMonitor:document.getElementById("manualScannerMonitor"),debug:{panel:document.getElementById("debugPanel"),infiniteCash:document.getElementById("debugInfiniteCash"),dayInput:document.getElementById("debugDayInput"),setDay:document.getElementById("debugSetDayButton"),zeroTimer:document.getElementById("debugZeroTimerButton"),cardSelect:document.getElementById("debugCardSelect"),targetSelect:document.getElementById("debugTargetSelect"),grantCard:document.getElementById("debugGrantCardButton"),grantAllCards:document.getElementById("debugGrantAllCardsButton"),readout:document.getElementById("debugReadout")},buttons:{s1Left:document.getElementById("scanner1MixerButton"),s1Right:document.getElementById("scanner1TruckButton"),s2Left:document.getElementById("scanner2MixerButton"),s2Right:document.getElementById("scanner2TruckButton"),nextTurn:document.getElementById("nextTurnButton"),conveyor:document.getElementById("buildConveyorButton"),boostConveyor:document.getElementById("buildBoostConveyorButton"),eggFarm:document.getElementById("buildEggFarmButton"),autoScanner:document.getElementById("buildAutoScannerButton"),manualScanner:document.getElementById("buildManualScannerButton"),mixer:document.getElementById("buildMixerButton"),trash:document.getElementById("buildTrashButton"),truck:document.getElementById("buildTruckButton"),maintenanceRoom:document.getElementById("buildMaintenanceRoomButton"),erase:document.getElementById("eraseButton"),undo:document.getElementById("undoButton"),redo:document.getElementById("redoButton")}};function Cc(){let e={conveyor:"conveyor",boostConveyor:"boostConveyor",eggFarm:"eggFarm",autoScanner:"autoScanner",manualScanner:"manualScanner",mixer:"mixer",trash:"trash",truck:"truck",maintenanceRoom:"maintenanceRoom"};for(let[t,n]of Object.entries(e))L.buttons[t]&&(L.buttons[t].innerHTML=Or(n))}function Mc(e){let t=new Set(e.tags||[]);return["upgradeEgg","crowdedFarming","hatchingFeed","extraEggOutlet"].includes(e.id)||t.has("EGG")?"Production / EGG":["upgradeTrash","poopRateBooster","composter","chemicalWeaponSubsidy"].includes(e.id)||t.has("POOP")?"Poop / Shredder":["upgradeAutoScanner","autoScannerTuning","scannerQueueSpacing"].includes(e.id)||t.has("SCANNER")?"Scanner":["bearing","dynamite"].includes(e.id)||t.has("CONVEYOR")?"Conveyor / Map":["safetyCover","preventiveMaintenance","durabilityCoating","sparePartsBin","laborExploitation"].includes(e.id)||t.has("MAINTENANCE")?"Maintenance / Risk":["dudFilter","dudRefund","freeReroll","extraCards"].includes(e.id)||t.has("CARD")?"Card Engine":t.has("ULTRA RARE")?"Ultra Rare":t.has("ECONOMY")||["upgradeMixer","upgradeTruck","recyclingSubsidy","usedMachine","newMachine","flattery","legalWork","rescueLoan"].includes(e.id)?"Economy / Shipment":"Other"}function gc(){if(!L.debug?.panel||!L.debug.cardSelect)return;let e=["Production / EGG","Poop / Shredder","Scanner","Conveyor / Map","Maintenance / Risk","Card Engine","Economy / Shipment","Ultra Rare","Other"],t=new Map(e.map(n=>[n,[]]));for(let n of Qt){let o=Mc(n);t.has(o)||t.set(o,[]),t.get(o).push(n)}L.debug.cardSelect.innerHTML="";for(let n of e){let o=t.get(n)||[];if(!o.length)continue;let r=document.createElement("optgroup");r.label=n;for(let i of o){let l=document.createElement("option");l.value=i.id;let c=i.rarity==="ultraRare"?"UR":i.rarity==="rare"?"R":"C";l.textContent=`[${c}] ${i.title}`,r.appendChild(l)}L.debug.cardSelect.appendChild(r)}L.debug.cardSelect.addEventListener("change",Ot),Ot()}function Ot(){if(!L.debug?.targetSelect)return;let e=L.debug.cardSelect?.value,t=Jt(e),n=t?hs(u,t):[];if(L.debug.targetSelect.innerHTML="",!n.length){let r=document.createElement("option");r.value="__none__",r.textContent=t?"No target required":"No card selected",L.debug.targetSelect.appendChild(r),L.debug.targetSelect.disabled=!0;return}let o=document.createElement("option");o.value="__auto__",o.textContent=t?.id==="dynamite"?"Auto: first 3 blocked cells":"Auto: first valid target",L.debug.targetSelect.appendChild(o);for(let r of n){let i=document.createElement("option");i.value=r.key,i.textContent=r.label,L.debug.targetSelect.appendChild(i)}L.debug.targetSelect.disabled=!1}function xc(){let e=Math.max(1,Math.floor(Number(L.debug.dayInput?.value)||1));u.turn=e,L.debug.dayInput&&(L.debug.dayInput.value=String(e)),K(u,fe.width/2-u.view.x,86-u.view.y,`DAY ${e}`,y.green),z.updatePanels(),z.updateUI(),Ot(),Nt(`Day set to ${e}.`)}function Tc(){u.timeLeft=0,u.phase==="running"&&Vs(),K(u,fe.width/2-u.view.x,86-u.view.y,"TIMER 0",y.warn),z.updatePanels(),z.updateUI(),Nt("Timer set to 0.")}function Ec(){let e=L.debug.cardSelect?.value,t=L.debug.targetSelect?.disabled?void 0:L.debug.targetSelect?.value,n=ir(u,e,{targetKey:t});L.debug.grantCard&&(L.debug.grantCard.textContent=n.ok?"Granted":"Failed",window.setTimeout(()=>{L.debug.grantCard&&(L.debug.grantCard.textContent="Grant Selected")},900)),ge?.updateCongestion?.(),z.updatePanels(),z.updateUI(),Ot(),Nt(n.reason)}function Rc(){let t=Qt.map(n=>ir(u,n,{targetKey:"__auto__"})).filter(n=>n.ok).length;ge?.updateCongestion?.(),z.updatePanels(),z.updateUI(),Ot(),Nt(`Granted ${t}/${Qt.length} cards.`)}function Pc(){L.debug?.infiniteCash?.checked&&u.cash<999999&&(u.cash=999999,u.totals.maxCash=Math.max(u.totals.maxCash,u.cash))}function Nt(e=""){L.debug?.readout&&(L.debug.readout.textContent=[e,`D${u.turn}`,x(u.cash),`Combo ${u.manualCombo?.count||0}`,`Event ${u.eventActive?.title||u.eventOffer?.title||"none"}`,`Rescue ${u.cardEffects?.rescueLoanCharges||0}`,`Chem ${u.cardEffects?.chemicalWeaponSubsidy||0}`].filter(Boolean).join(" | "))}var u=To(),V,z,ge,tn;function Ac(e=null){let t=Xn(u,e);return e?t*Xo(u,e):t}function Dc(){Object.assign(u,To()),u.phase="running",u.view={x:0,y:0,scale:1},Eo(u),Xs(),Se(u),z.hideModal(),ge.updateCongestion(),z.updatePanels(),z.updateUI(),Nt()}function Ic(){if(u.phase!=="build")return;if(u.cardDraft?.pending||u.cardTargetPick?.pending){V.fail(u.cardTargetPick?.pending?"Choose upgrade target first.":"Choose an upgrade card first."),z.updatePanels();return}let e=fn(u);if(e.length){V.fail(`Cannot start: ${e[0]}`),z.updatePanels();return}Se(u),ai(u),ns(u);let t=Math.max(0,Math.floor(u.lastResult?.profit??u.stats?.profit??0)),n=Oi(u,Math.max(1,u.turn||1),t);u.lastStartFees={fairiesTribute:n.amount||0,tribute:n},n.amount>0&&K(u,fe.width/2-u.view.x,116-u.view.y,`FAIRIES -${x(n.amount)}`,y.danger),vi(u),u.phase="running",u.turn+=1,u.timeLeft=Si(u),u.shutdownTimeLeft=0,u.cleanupTimer=null,u.cleanupBlown=!1,u.chicks=[],u.effects=[],u.floatingTexts=[],u.shake={time:0,strength:0},u.truckCargo=[],Xs(),u.stats=xo(),u.stats.fairiesTribute=u.lastStartFees?.fairiesTribute||0,u.stats.fairiesTribute>0&&(u.stats.penalty+=u.stats.fairiesTribute,u.stats.profit-=u.stats.fairiesTribute);for(let o of u.scanners)o.queue=[],o.cooldown=0;for(let o of u.eggFarms)o.nextSpawn=ge.currentSpawnDelay(o),o.lastInterval=o.nextSpawn,o.shutterProgress=0,o.shutterSparked=!1;u.buildTool=null,u.selected=null,u.groupDrag=null,u.selectionBox=null,u.pan=null,ge.updateCongestion(),z.updatePanels(),z.updateUI()}function $c(){if(u.phase!=="running")return;let e=Li(u),t=u.eventActive?{...u.eventActive}:null,n=Ei(u),o=Ni(u);if(e.adjusted>0){let i=u.facilities.truck,l=i?i.x+i.w/2:fe.width/2-u.view.x,c=i?i.y+26:96-u.view.y;K(u,l,c,`${e.target==="poop"?"POOP SHIP":"SHIP"} +${x(e.adjusted)}`,y.green)}n?.bonus>0&&K(u,fe.width/2-u.view.x,96-u.view.y,`EVENT +${x(n.bonus)}`,y.green),o.amount>0&&K(u,fe.width/2-u.view.x,116-u.view.y,`CHEM SUBSIDY +${x(o.amount)}`,y.green),wi(u),u.totals.turnsCompleted+=1;let r=Ti(t);if(r!==1&&(u.pendingFairiesTributeMultiplier=r),u.lastResult={...u.stats,ship:e,event:n,chemical:o,rescue:{amount:0,used:0,remaining:u.cardEffects?.rescueLoanCharges||0},fairiesTribute:{amount:u.stats.fairiesTribute||0},tributeMultiplier:r,turn:u.turn,cash:u.cash},u.cash<0){if((u.cardEffects?.rescueLoanCharges||0)>0){u.phase="loanDecision",z.showEmergencyLoanDecision(Ys,eo);return}u.phase="gameover",z.showGameOver();return}qs()}function qs(){u.phase="build",u.truckCargo=[],u.chicks=[],u.shutdownTimeLeft=0,u.cleanupTimer=null,u.cleanupBlown=!1,u.buildSession+=1,u.undoStack=[],u.redoStack=[],u.timeLeft=0;for(let e of u.scanners)e.queue=[];for(let e of u.eggFarms)e.shutterProgress=0,e.shutterSparked=!1;os(u),u.eventOffer=bi(u),tn&&tn.prepareDraft(),u.cardTargetPick=null,u.buildTool=null,u.groupDrag=null,u.selectionBox=null,u.pan=null,z.updatePanels(),z.showTurnResult(u.lastResult)}function Ys(){if((u.cardEffects?.rescueLoanCharges||0)<=0)return eo();u.cardEffects.rescueLoanCharges-=1,u.stats.rescueLoan=(u.stats.rescueLoan||0)+500,u.totals.rescueLoan=(u.totals.rescueLoan||0)+500;let e=Ge(u,500);u.lastResult={...u.lastResult||{},...u.stats,rescue:{amount:(u.lastResult?.rescue?.amount||0)+e,used:(u.lastResult?.rescue?.used||0)+1,remaining:u.cardEffects.rescueLoanCharges},cash:u.cash},K(u,fe.width/2-u.view.x,176-u.view.y,`RESCUE +${x(e)}`,y.green),u.cash>=0?qs():(u.cardEffects?.rescueLoanCharges||0)>0?(u.phase="loanDecision",z.showEmergencyLoanDecision(Ys,eo)):eo()}function eo(){u.phase="gameover",z.showGameOver()}function Vs(){u.shutdownTimeLeft<=0&&(u.shutdownTimeLeft=u.shutdownGraceSeconds||10);for(let e of u.eggFarms){if(e.shutterSparked)continue;e.shutterProgress=.02,e.shutterSparked=!0;let t=B(e.col,e.row);Xe(u,t.x,t.y,y.ink),Ze(u,t.x,t.y+10,10),K(u,t.x,t.y-34,"SHUT +10s",y.ink)}}function zs(e){u.lastTimestamp||(u.lastTimestamp=e);let t=Math.min((e-u.lastTimestamp)/1e3,.05);u.lastTimestamp=e,u.phase==="running"&&ge.updateRunning(t,{closeFarmShutters:Vs,completeTurn:$c}),zi(u,t,fe,V.equipmentHitBoxes),ge.updateCongestion(),Cs(kc,fe,u,{activeQueuedChick:ge.activeQueuedChick,selectedObject:V.selectedObject,selectedTitle:V.selectedTitle}),Pc(),z.updateUI(),Js(),Nt(),requestAnimationFrame(zs)}function to(){return u.view?.scale||1}function kn(){u.view||(u.view={x:0,y:0,scale:1}),u.view.scale==null&&(u.view.scale=1)}function no(e){let t=fe.getBoundingClientRect();return{x:(e.clientX-t.left)*fe.width/t.width,y:(e.clientY-t.top)*fe.height/t.height}}function wt(e){let t=no(e),n=to();return{x:(t.x-(u.view?.x||0))/n,y:(t.y-(u.view?.y||0))/n}}function Fc(e){let t=to();return{x:e.x*t+(u.view?.x||0),y:e.y*t+(u.view?.y||0)}}function Bc(){let e={left:f.x-90,top:f.y-130,right:f.x+f.cols*f.cell+260,bottom:f.y+f.rows*f.cell+220};if(u.phase==="build")for(let t of Tt(u)){let n=Et(t);e.left=Math.min(e.left,n.x-60),e.top=Math.min(e.top,n.y-80),e.right=Math.max(e.right,n.x+n.w+80),e.bottom=Math.max(e.bottom,n.y+n.h+80)}return e}function Ws(e,t){if(e<=t)return[e,t];let n=(e+t)/2;return[n,n]}function St(){kn();let e=to(),t=Bc(),[n,o]=Ws(fe.width-160-t.right*e,110-t.left*e),[r,i]=Ws(fe.height-150-t.bottom*e,150-t.top*e);u.view.x=un(u.view.x,n,o),u.view.y=un(u.view.y,r,i)}function Xs(){kn(),u.view.scale=1;let e=u.eggFarms?.[0],t=e?B(e.col,e.row):{x:f.x,y:f.y};u.view.x=280-t.x,u.view.y=190-t.y,St()}function Lc(e){let t=no(e);kn(),u.pan={start:t,viewX:u.view.x,viewY:u.view.y,moved:!1}}function Oc(e){if(!u.pan)return;let t=no(e);Math.hypot(t.x-u.pan.start.x,t.y-u.pan.start.y)>5&&(u.pan.moved=!0),kn(),u.view.x=u.pan.viewX+t.x-u.pan.start.x,u.view.y=u.pan.viewY+t.y-u.pan.start.y,St()}function Nc(e){e.preventDefault(),kn();let t=no(e),n=wt(e),o=Math.exp(-e.deltaY*.0012),r=un(to()*o,.55,1.8);u.view.scale=r,u.view.x=t.x-n.x*r,u.view.y=t.y-n.y*r,St(),st()}function _c(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:{type:e.type,id:e.ref.id}:null}function Gc(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:e.ref||null:null}function st(){L.hoverTooltip&&(L.hoverTooltip.classList.remove("visible"),L.hoverTooltip.setAttribute("aria-hidden","true"),u.hover=null)}function Uc(e,t){if(!L.hoverTooltip||u.phase!=="build"||u.cardTargetPick?.pending||u.groupDrag||u.selectionBox||u.pan)return st();let n=Gc(t);if(!n)return st();let o=V.selectedTitle(n),r=V.flavorText?V.flavorText(n):"",i=V.disconnectedWarningFor?V.disconnectedWarningFor(n):"",l=V.selectedInfoLines(n).slice(0,7);L.hoverTooltip.innerHTML=`${o}${i?`${i}`:r?`${r}`:""}${l.map(C=>`${C}`).join("")}`;let c=Math.min(window.innerWidth-330,e.clientX+18),b=Math.min(window.innerHeight-220,e.clientY+18);L.hoverTooltip.style.left=`${Math.max(8,c)}px`,L.hoverTooltip.style.top=`${Math.max(8,b)}px`,L.hoverTooltip.classList.add("visible"),L.hoverTooltip.setAttribute("aria-hidden","false"),u.hover={type:t.type,id:t.oldKey||t.ref?.id||null}}function Wc(e){if(u.phase!=="build")return st();Uc(e,V.equipmentAtPoint(wt(e)))}function Qs(e){st();let t=wt(e),n=V.equipmentAtPoint(t),o=_c(n);if(!o){u.selected=null,u.multiSelected=[],z.updatePanels();return}u.selected=o,u.multiSelected=[o],z.updatePanels();let r=V.selectedObject();r?.type==="scanner"&&r.kind==="manual"&&V.showManualScannerMenu(r),r?.type==="scanner"&&r.kind==="auto"&&V.showAutoScannerMenu(r)}function en(){u.buildTool=null,u.selected=null,u.multiSelected=[],u.selectionBox=null,u.cardTargetPick?.mode==="autoScannerMenu"&&(u.cardTargetPick=null),z.hideModal(),st(),z.updatePanels(),z.updateUI()}function Ks(e){return String(e).replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function Kc(e){let t=e?.queue?.[0];return t==null?null:u.chicks.find(n=>n.id===t)||null}function Hc(e){if(!e)return'WAIT';let t=e.sex==="poop"?"\u{1F4A9} POOP":e.sex==="male"?"\u2642 MALE":"\u2640 FEMALE";return`${t}`}function qc(e,t){let n=new Set(u.eggFarms.map(T=>A(T.col,T.row))),o=new Map(u.scanners.map(T=>[A(T.col,T.row),T])),r=Re(e,"inputA"),i=r?A(r.col,r.row):null,l=new Set(Object.values(u.facilities||{}).map(T=>T.entry?A(T.entry.col,T.entry.row):null).filter(Boolean)),c=t?.sex||"",b=c==="poop"?"\u{1F4A9}":c==="male"?"\u2642":c==="female"?"\u2640":"",C=[];for(let T=e.row-2;T<=e.row+2;T+=1)for(let I=e.col-2;I<=e.col+2;I+=1){let $=A(I,T),O=["mini-cell"],ee="";I===e.col&&T===e.row?(O.push("scanner"),c&&O.push(c),ee=b||"S"):$===i?(O.push("input"),ee="IN"):n.has($)?(O.push("egg"),ee="E"):o.has($)?(O.push("scanner-other"),ee="S"):l.has($)?(O.push("port"),ee="P"):u.conveyorTiles.has($)?(O.push("belt"),ee="\u2022"):u.blockedCells?.has?.($)&&(O.push("blocked"),ee="\xD7"),C.push(`${ee}`)}return`
${C.join("")}
`}function Yc(e){let t=Fc(B(e.col,e.row)),n=76;return t.x<-n||t.y<-n||t.x>fe.width+n||t.y>fe.height+n}function Js(){if(!L.manualScannerMonitor)return;if(u.phase!=="running"){L.manualScannerMonitor.classList.remove("visible"),L.manualScannerMonitor.innerHTML="";return}let e=u.scanners.filter(t=>t.kind==="manual"&&Yc(t));if(!e.length){L.manualScannerMonitor.classList.remove("visible"),L.manualScannerMonitor.innerHTML="";return}L.manualScannerMonitor.innerHTML=e.map(t=>{let n=Kc(t),o=t.keys?.left?.label||(t.slot===0?"A":"Left"),r=t.keys?.right?.label||(t.slot===0?"D":"Right"),i=t.role===0?"MIXER":"WASTE",l=t.role===0?"S2":"TRUCK",c=n?"":" disabled";return` -
-
S${(t.slot??0)+1}OFFSCREEN / Q:${t.queue.length}
-
- IN${Hc(n)}SCANNER -
- ${qc(t,n)} -
- - -
-
`}).join(""),L.manualScannerMonitor.classList.add("visible")}L.manualScannerMonitor?.addEventListener("click",e=>{let t=e.target.closest("button[data-scanner-id]");if(!t||t.disabled)return;let n=u.scanners.find(o=>o.id===Number(t.dataset.scannerId));n&&(ge.sortScanner(n,t.dataset.side),Js())});fe.addEventListener("contextmenu",e=>e.preventDefault());fe.addEventListener("wheel",Nc,{passive:!1});fe.addEventListener("pointerdown",e=>{if(u.phase!=="build")return;fe.setPointerCapture(e.pointerId);let t=wt(e);if(e.button===2){Lc(e);return}if(e.button!==0)return;if(u.cardTargetPick?.mode==="autoScannerMenu"){en();return}if(u.cardTargetPick?.pending){tn.chooseTargetAtPoint(t);return}let n=V.expansionOfferAtPoint?.(t);if(n){V.buyGridExpansion(n),St(),z.updatePanels(),z.updateUI();return}if(V.cycleBranchModeAtPoint?.(t)){z.updatePanels(),z.updateUI();return}let o=He(t.x,t.y),r=V.equipmentAtPoint(t);if(!u.buildTool&&r?.type==="conveyor"&&o&&V.cycleSingleConveyorDirection?.(o)){z.updatePanels(),z.updateUI();return}if(u.buildTool==="erase"){if(!V.equipmentAtPoint(t)){en();return}V.eraseAtPoint(t);return}if(u.buildTool){let i=He(t.x,t.y);if(!i&&!["mixer","trash","truck"].includes(u.buildTool)){en();return}if(u.buildTool==="conveyor"||u.buildTool==="boostConveyor"){V.beginConveyorDrag(i);return}if(V.equipmentAtPoint(t)){u.buildTool=null,Qs(e);return}V.buildAtPoint(t);return}V.startGroupDrag(e)||V.startSelectionBox(e)});fe.addEventListener("pointermove",e=>{if(u.phase!=="build"){st();return}Wc(e),u.pan&&e.buttons&2&&Oc(e),u.groupDrag&&e.buttons&1&&V.updateGroupDrag(e),u.selectionBox&&e.buttons&1&&V.updateSelectionBox(e),(u.buildTool==="conveyor"||u.buildTool==="boostConveyor")&&e.buttons&1&&V.continueConveyorDrag(He(wt(e).x,wt(e).y)),u.buildTool==="erase"&&e.buttons&1&&V.eraseAtPoint(wt(e))});fe.addEventListener("pointerup",e=>{u.selectionBox?V.finishSelectionBox():u.groupDrag&&(u.groupDrag.committed||Qs(e),V.finishGroupDrag()),e.button===2&&u.pan&&!u.pan.moved&&u.buildTool&&en(),(u.buildTool==="conveyor"||u.buildTool==="boostConveyor")&&V.endConveyorDrag?.(),u.groupDrag=null,u.pan=null;try{fe.releasePointerCapture(e.pointerId)}catch{}});fe.addEventListener("pointerleave",st);fe.addEventListener("pointercancel",()=>{V?.endConveyorDrag?.(),u.groupDrag=null,u.selectionBox=null,u.pan=null,st()});document.addEventListener("pointerdown",e=>{!L.modal.classList.contains("visible")||!L.modal.classList.contains("equipment-popover")||e.target.closest("#modal .modal-card")||en()},!0);L.buttons.s1Left.addEventListener("click",()=>ge.sortSlot(0,"left"));L.buttons.s1Right.addEventListener("click",()=>ge.sortSlot(0,"right"));L.buttons.s2Left.addEventListener("click",()=>ge.sortSlot(1,"left"));L.buttons.s2Right.addEventListener("click",()=>ge.sortSlot(1,"right"));L.buttons.nextTurn.addEventListener("click",Ic);L.buttons.conveyor.addEventListener("click",()=>V.setBuildTool("conveyor"));L.buttons.boostConveyor.addEventListener("click",()=>V.setBuildTool("boostConveyor"));L.buttons.eggFarm.addEventListener("click",()=>V.setBuildTool("eggFarm"));L.buttons.autoScanner.addEventListener("click",()=>V.setBuildTool("autoScanner"));L.buttons.manualScanner.addEventListener("click",()=>V.setBuildTool("manualScanner"));L.buttons.mixer.addEventListener("click",()=>V.setBuildTool("mixer"));L.buttons.trash.addEventListener("click",()=>V.setBuildTool("trash"));L.buttons.truck.addEventListener("click",()=>V.setBuildTool("truck"));L.buttons.maintenanceRoom.addEventListener("click",()=>V.setBuildTool("maintenanceRoom"));L.buttons.erase.addEventListener("click",()=>V.setBuildTool("erase"));L.debug.setDay?.addEventListener("click",xc);L.debug.zeroTimer?.addEventListener("click",Tc);L.debug.grantCard?.addEventListener("click",Ec);L.debug.grantAllCards?.addEventListener("click",Rc);L.buttons.undo.addEventListener("click",()=>{Ko(u)&&(St(),z.updatePanels(),z.updateUI(),Ot())});L.buttons.redo.addEventListener("click",()=>{Ho(u)&&(St(),z.updatePanels(),z.updateUI(),Ot())});function Hs(e,t,n){let o=e.keys?.[t];return o?o.code&&n.code===o.code||o.key&&n.key.toLowerCase()===o.key:!1}window.addEventListener("keydown",e=>{if(e.repeat)return;let t=e.key.toLowerCase();if(u.phase==="running")for(let n of u.scanners.filter(o=>o.kind==="manual")){if(Hs(n,"left",e)){e.preventDefault(),ge.sortScanner(n,"left");return}if(Hs(n,"right",e)){e.preventDefault(),ge.sortScanner(n,"right");return}}u.phase==="build"&&(e.ctrlKey||e.metaKey)&&t==="z"&&(e.preventDefault(),Ko(u)&&(St(),z.updatePanels(),z.updateUI())),u.phase==="build"&&(e.ctrlKey||e.metaKey)&&(t==="y"||e.shiftKey&&t==="z")&&(e.preventDefault(),Ho(u)&&(St(),z.updatePanels(),z.updateUI())),e.key==="Escape"&&u.cardTargetPick?.pending&&(e.preventDefault(),u.cardTargetPick.mode==="autoScannerMenu"?en():tn.cancelTargetPick())});V=Fs({game:u,ui:L,canvas:fe,canvasPoint:wt,onUpdatePanels:()=>z?.updatePanels()});ge=Us({game:u,currentConveyorSpeed:Ac,onGameOverCheck:()=>z?.checkGameOver()});tn=vs({game:u,ui:L,onUpdatePanels:()=>z?.updatePanels()});z=Bs({game:u,ui:L,build:V,startGame:Dc,beginCardDraft:()=>tn.showDraft(),activeQueuedChick:ge.activeQueuedChick});Cc();gc();Eo(u);Se(u);ge.updateCongestion();z.updatePanels();z.updateUI();z.showTitle();Nt();requestAnimationFrame(zs); diff --git a/dist/game-v27.19.js b/dist/game-v27.19.js deleted file mode 100644 index 29d8c43..0000000 --- a/dist/game-v27.19.js +++ /dev/null @@ -1,51 +0,0 @@ -var q={version:"v27.19 LAND + UI PATCH",time:{daySeconds:60,farmShutdownGraceSeconds:10},cash:{starting:250},grid:{x:170,y:78,cols:20,rows:10,cell:46,expansion:{colsPerPurchase:10,rowsPerPurchase:10,costBase:1e3,costMultiplier:1.3333333333333333,truncateUnit:100}},map:{blockedRatio:.03,blockedExpansionIncrement:.005,blockedRatioMax:.1},economy:{income:{mixer:5,truck:10},poopFine:10,fairiesTribute:{perDay:10,profitExemption:300,legalWorkExemptionBonus:250,profitRate:.12},incomeUpgradeRate:1.1,explosionDamageDivisor:30,maleTruckFinePerHalfDay:30,shredderBonus:{maxCards:30,incomePerUpgrade:1.25},chemicalWeaponSubsidy:{poopPerBlock:70,yenPerBlock:1200}},production:{poopRate:.08,autoScannerCooldown:3.5,autoScannerUpgradeRate:.95,autoScannerCardUpgradeRate:.95,autoScannerMinCooldown:.5,poopRateCardBonus:.04,eggSpawnRanges:[[1.95,4.35],[1.55,3.45],[1.25,2.8],[1.05,2.35]]},conveyor:{baseSpeed:52,maxSpeed:300,bearingSpeedMultiplier:1.075},cards:{definitions:[{id:"upgradeEgg",title:"EGG Improvement",rarity:"common",type:"equipmentUpgrade",target:"eggFarm",description:"Choose one EGG FARM on the map and raise it by 1 level.",tags:["EGG","ACTIVE"]},{id:"upgradeAutoScanner",title:"AUTO SCANNER Improvement",rarity:"common",type:"equipmentUpgrade",target:"autoScanner",description:"Choose one AUTO SCANNER on the map and raise it by 1 level.",tags:["SCANNER","ACTIVE"]},{id:"autoScannerTuning",title:"AUTO SCANNER Tuning",rarity:"common",type:"instant",description:"All AUTO SCANNER cooldowns use default cooldown x0.95 per copy.",tags:["SCANNER","PASSIVE"]},{id:"upgradeMixer",title:"MIXER Improvement",rarity:"common",type:"equipmentUpgrade",target:"mixer",description:"Choose MIXER on the map and raise it by 1 level.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeTruck",title:"TRUCK Improvement",rarity:"common",type:"equipmentUpgrade",target:"truck",description:"Choose TRUCK on the map and raise it by 1 level.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeTrash",title:"SHREDDER Improvement",rarity:"common",type:"equipmentUpgrade",target:"trash",description:"Shred poops for a little money. Max 30 upgrades.",tags:["POOP","ACTIVE"]},{id:"crowdedFarming",title:"Crowded Farming",rarity:"common",type:"instant",description:"EGG production interval -5%. Equipment deterioration +4%. Max 10 cards.",tags:["EGG","RISK","PASSIVE"]},{id:"hatchingFeed",title:"Hatching Feed",rarity:"common",type:"instant",description:"EGG production interval -4%. Poop rate +3%. No card limit.",tags:["EGG","POOP","PASSIVE"]},{id:"poopRateBooster",title:"Poop Culture",rarity:"common",type:"instant",description:"Base poop rate +4 percentage points. No card limit.",tags:["POOP","PASSIVE"]},{id:"safetyCover",title:"Safety Cover",rarity:"common",type:"instant",description:"Explosion damage -5%. No card limit.",tags:["RISK","PASSIVE"]},{id:"preventiveMaintenance",title:"Preventive Maintenance Manual",rarity:"common",type:"instant",description:"All equipment deterioration speed -5%. No card limit.",tags:["MAINTENANCE","PASSIVE"]},{id:"dudFilter",title:"DUD Filter",rarity:"common",type:"instant",description:"DUD chance -5 percentage points. Stacks until DUD chance reaches 0%.",tags:["CARD","PASSIVE"]},{id:"durabilityCoating",title:"Durability Coating",rarity:"common",type:"instant",description:"All equipment maximum durability +3%. No card limit.",tags:["MAINTENANCE","PASSIVE"]},{id:"bearing",title:"High-Quality Bearing",rarity:"common",type:"instant",description:"Conveyor speed +7.5%.",tags:["CONVEYOR","PASSIVE"]},{id:"sparePartsBin",title:"SPARE PARTS BIN",rarity:"common",type:"instant",description:"Restores 2% durability to every machine. A box of almost-compatible parts.",tags:["MAINTENANCE","ACTIVE"]},{id:"dudRefund",title:"DUD REFUND",rarity:"common",type:"instant",description:"DUDs now come with paperwork. Gain JPY 50 per copy when you pick a DUD.",tags:["CARD","ECONOMY","PASSIVE"]},{id:"freeReroll",title:"FREE REROLL",rarity:"common",type:"instant",description:"The first bad ideas are free.",tags:["CARD","PASSIVE"]},{id:"composter",title:"COMPOSTER",rarity:"common",type:"instant",description:"Turns shredder waste into suspicious fertilizer. Gain JPY 3 per copy when SHREDDER processes poop.",tags:["POOP","ECONOMY","PASSIVE"]},{id:"scannerQueueSpacing",title:"Scanner Queue Spacing",rarity:"common",type:"instant",description:"Manual and Auto Scanner queue spacing -15%. No card limit.",tags:["SCANNER","PASSIVE"]},{id:"extraEggOutlet",title:"Extra Egg Outlet",rarity:"rare",type:"equipmentUpgrade",target:"eggOutlet",description:"Choose one EGG FARM and add +1 output port to that EGG. Max +3 per EGG.",tags:["EGG","RARE","ACTIVE"]},{id:"recyclingSubsidy",title:"Recycling Subsidy",rarity:"rare",type:"instant",description:"SELL refund rate +10 points. Max 3 cards; normal SELL can reach 80%.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"dynamite",title:"Dynamite",rarity:"rare",type:"cellAction",target:"blockedCell",description:"Choose and remove up to 3 unbuildable cells.",tags:["RISK","RARE","ONE-SHOT"]},{id:"usedMachine",title:"Used Machines",rarity:"rare",type:"instant",description:"Future equipment costs half. New purchases have no refund and 60% durability. New Machines cancels it.",tags:["ECONOMY","RISK","RARE"]},{id:"newMachine",title:"New Machines",rarity:"common",type:"instant",description:"Cancel Used Machines and restore normal prices, refunds, and durability.",tags:["ECONOMY","ONE-SHOT"]},{id:"flattery",title:"Flattery",rarity:"rare",type:"instant",description:"Next Fairies tribute -50%.",tags:["ECONOMY","RARE","ONE-SHOT"]},{id:"extraCards",title:"Extra Cards",rarity:"rare",type:"instant",description:"Draw 2 cards now and choose both.",tags:["RARE","ACTIVE"]},{id:"legalWork",title:"Legal Work",rarity:"rare",type:"instant",description:"Fairies tribute profit exemption +JPY 250.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"chemicalWeaponSubsidy",title:"Chemical Weapons Subsidy",rarity:"ultraRare",type:"instant",description:"Each day, gain JPY 1200 per 70 poop shipped by truck. No card limit.",tags:["POOP","ULTRA RARE","PASSIVE"]},{id:"laborExploitation",title:"Motivational Exploitation",rarity:"ultraRare",type:"instant",description:"Repair room work time -30%. The repairman smiles with bloodshot eyes. One time only.",tags:["MAINTENANCE","ULTRA RARE","PASSIVE"]},{id:"rescueLoan",title:"Emergency Loan",rarity:"ultraRare",type:"instant",description:"If cash is below JPY 0 at day-end settlement, gain JPY 500. Consumed on use.",tags:["ECONOMY","ULTRA RARE","ONE-SHOT"]}],defaultEffects:{bearing:0,legalWork:0,fairiesFlatteryNext:0,autoScannerTuning:0,poopRateBooster:0,crowdedFarming:0,hatchingFeed:0,safetyCover:0,recyclingSubsidy:0,chemicalWeaponSubsidy:0,preventiveMaintenance:0,dudFilter:0,durabilityCoating:0,sparePartsBin:0,dudRefund:0,freeReroll:0,composter:0,scannerQueueSpacing:0,laborExploitation:0,usedMachineActive:!1,rescueLoanCharges:0},commonWeight:8,rareWeight:2,ultraRareWeight:.45,baseDraftSize:3,maxDudsPerDraft:2,dudChancePerCard:.3,dudChanceReductionPerFilter:.05,extraCardsAddedPicks:2,rerollCost:{dayDivisor:2,multiplier:100}},events:{eventChance:.1,firstTurn:8},maintenance:{fullPerformanceUntilWear:.5,minimumPerformance:.5,durability:{conveyor:1300,eggFarm:475,autoScanner:850,mixer:775,trash:950},processingDelayMaxSeconds:{mixer:1.2,trash:1},repairman:{secondsPerOnePercent:.5,walkSpeed:90}},facilities:{conveyor:{id:"conveyor",type:"conveyor",name:"Conveyor",shortName:"Belt",price:30,buildable:!0,upgradeable:!1},boostConveyor:{id:"boostConveyor",type:"conveyor",name:"Boost Conveyor",shortName:"BOOST BELT",price:75,buildable:!0,upgradeable:!1,speedMultiplier:2},eggFarm:{id:"eggFarm",type:"eggFarm",name:"Egg Farm",shortName:"EGG",price:250,buildable:!0,upgradeable:!0,maxLevel:4},manualScanner:{id:"manualScanner",type:"scanner",kind:"manual",name:"Manual Scanner",shortName:"Manual Scanner",price:260,buildable:!0,upgradeable:!1},autoScanner:{id:"autoScanner",type:"scanner",kind:"auto",name:"Auto Scanner",shortName:"Auto Scanner",price:180,buildable:!0,upgradeable:!1},mixer:{id:"mixer",type:"facility",name:"Mixer",shortName:"MIXER",price:450,buildable:!0,upgradeable:!0,incomeKey:"mixer",body:{w:164,h:126}},trash:{id:"trash",type:"facility",name:"Waste Shredder",shortName:"SHREDDER",price:240,buildable:!0,upgradeable:!0,body:{w:180,h:100}},truck:{id:"truck",type:"facility",name:"Truck",shortName:"TRUCK",price:450,buildable:!0,upgradeable:!0,incomeKey:"truck",body:{w:176,h:138}},maintenanceRoom:{id:"maintenanceRoom",type:"maintenanceRoom",name:"Maintenance Room",shortName:"REPAIR ROOM",price:220,buildable:!0,upgradeable:!1,footprint:{cols:2,rows:2}}}};var Pr=q.version,xt=q.time.daySeconds,an=q.cash.starting,ke=q.economy,Ar=q.time.farmShutdownGraceSeconds,Tn=q.production.autoScannerCooldown,Ir=q.production.autoScannerUpgradeRate,ho=q.production.autoScannerCardUpgradeRate||q.production.autoScannerUpgradeRate,mo=q.production.autoScannerMinCooldown,Dr=q.events.eventChance,cn=q.events.firstTurn,bo=q.production.poopRate,vo=q.production.poopRateCardBonus||0,En=q.conveyor.baseSpeed,Kt=q.conveyor.maxSpeed,Rn=q.conveyor.bearingSpeedMultiplier,De=q.cards,$r=q.cards.definitions,wo=q.cards.defaultEffects,st=q.production.eggSpawnRanges,f=q.grid,ve=q.facilities,So=["conveyor","boostConveyor","eggFarm","autoScanner","manualScanner","mixer","trash","truck","maintenanceRoom"],un=["mixer","trash","truck"],Fr=["mixer","truck"],lt=Object.fromEntries(Object.entries(ve).map(([e,t])=>[e,t.price])),de=[{name:"right",dc:1,dr:0,angle:0,opposite:"left"},{name:"left",dc:-1,dr:0,angle:Math.PI,opposite:"right"},{name:"down",dc:0,dr:1,angle:Math.PI/2,opposite:"up"},{name:"up",dc:0,dr:-1,angle:-Math.PI/2,opposite:"down"}],y={bg:"#111318",ink:"#090a0d",muted:"#8f9bab",green:"#7bd84f",greenSoft:"#273c24",mixerBlue:"#4aa3ff",truckPink:"#ffb33e",wasteGreen:"#88d35a",danger:"#e34a36",warn:"#ffb827",white:"#e6edf2",poop:"#7b4a23",male:"#4aa3ff",female:"#ff6fae"},Ce={ambient:0,important:1,critical:2};function T(e){let t=Number(e)||0;return`${t<0?"-":""}\uFFE5${Math.ceil(Math.abs(t)).toLocaleString("ja-JP")}`}function I(e,t){return`${e},${t}`}function te(e){let[t,n]=String(e).split(",").map(Number);return{col:t,row:n}}function dn(e,t,n){return Math.max(t,Math.min(n,e))}function K(e,t){return e+Math.random()*(t-e)}function Ee(e,t){return e>=0&&e=0&&tMath.round(dn(r,0,255)).toString(16).padStart(2,"0");return`#${o(e)}${o(t)}${o(n)}`}function Ht(e,t,n){let o=Br(e),r=Br(t);return cl(ko(o.r,r.r,n),ko(o.g,r.g,n),ko(o.b,r.b,n))}var re={appTitle:"Chick Sorter",versionTitle:`Chick Sorter ${Pr}`,currency:"\uFFE5",phases:{title:"Title",build:"Build",running:"Sorting",clearing:"Clearing",loanDecision:"Emergency Loan",gameover:"Game Over"},actions:{startGame:"Start Game",nextDay:"Next Day",buildPhase:"Build Phase",restart:"Restart",close:"Close",remove:"Remove",refund:"Refund",autoMenu:"Auto Menu"},status:{build:e=>`BUILD: ${(e==="erase"?"SELL":e||"SELECT").toUpperCase()} | Right-drag pan | Hover equipment for info`,sorting:"Sorting: use scanner keys. Build after clearing the day.",allPortsConnected:"Start condition met: one EGG route reaches an exit.",equipmentPanelEmpty:"Hover equipment in Build phase."},routeLabels:{mixer:"MIXER",truck:"TRUCK",trash:"WASTE",scanner:"NEXT","scanner-role-1":"NEXT",input:"IN"},fail:{outOfGrid:"Out of grid",cellOccupied:"Cell occupied",notEnoughCash:"Not enough cash",facilityExists:"Facility already exists",facilityOverlap:"Facility overlap",nothingToErase:"Nothing to sell",noUpgrade:"No upgrade available"}};function ct(e){return ve[e]?.name||String(e||"").replace(/^[a-z]/,t=>t.toUpperCase())}function ul(e){let t=ve[e];return t?e==="conveyor"||e==="boostConveyor"?`${T(t.price)} / tile`:e==="autoScanner"?`${T(t.price)} / ${Tn.toFixed(1)}s cooldown`:e==="trash"?T(t.price):T(t.price):""}function dl(e){return{conveyor:"A narrow green belt. Routes decide whether chicks live, ship, or become invoices.",boostConveyor:"Moves chicks twice as fast. Wears down like a normal belt.",eggFarm:"A tiny gatehouse producing questionable eggs on schedule.",autoScanner:"Slower than hands without upgrades.",manualScanner:"A manual checkpoint. The operator is the algorithm.",mixer:"Male chicks become revenue here. Do not feed it poop.",trash:"A polite shredder for poop and other regrets.",truck:"Ships the target cargo. Wrong cargo still leaves a paper trail.",maintenanceRoom:"2\xD72 repair bay. Each room dispatches one repairman during the day."}[e]||""}function Or(e){let t=dl(e);return`${ct(e)}${ul(e)}${t?`${t}`:""}`}function Nr(e){return re.routeLabels[e]||String(e).toUpperCase()}function _r(e){let t=2166136261;for(let n=0;n>>0}function Gr(e){let t=e>>>0;return()=>{t+=1831565813;let n=Math.imul(t^t>>>15,1|t);return n^=n+Math.imul(n^n>>>7,61|n),((n^n>>>14)>>>0)/4294967296}}function Ur(e,{base:t=.03,increment:n=.005,max:o=.1}={}){let r=Math.max(0,Math.floor(Number(e)||0));return Number(Math.min(o,t+r*n).toFixed(6))}function An(){return`RUN-${Date.now().toString(36)}-${Math.floor(Math.random()*1e6).toString(36)}`.toUpperCase()}function Wr({seed:e,targetRatio:t=.2,reserved:n=[]}={}){let o=Gr(_r(e||An())),r=new Set(n.map(c=>typeof c=="string"?c:I(c.col,c.row))),i=[];for(let c=0;c0;c-=1){let b=Math.floor(o()*(c+1));[i[c],i[b]]=[i[b],i[c]]}let l=Math.round(f.cols*f.rows*t+1e-9);return new Set(i.slice(0,Math.min(l,i.length)).map(c=>c.k))}function Kr({seed:e,colStart:t=0,colEnd:n=f.cols,rowStart:o=0,rowEnd:r=f.rows,targetRatio:i=.2,reserved:l=[]}={}){let c=Gr(_r(e||An())),b=new Set(l.map(z=>typeof z=="string"?z:I(z.col,z.row))),C=[],x=Math.max(0,Math.floor(t)),A=Math.max(x,Math.floor(n)),$=Math.max(0,Math.floor(o)),B=Math.max($,Math.floor(r));for(let z=$;z0;z-=1){let ce=Math.floor(c()*(z+1));[C[z],C[ce]]=[C[ce],C[z]]}let j=Math.round((A-x)*(B-$)*i+1e-9);return new Set(C.slice(0,Math.min(j,C.length)).map(z=>z.k))}var qt=10,Hr=2,qr=1;function Yt(e,t){return`${e},${t}`}function fl(e){let[t,n]=String(e).split(",").map(Number);return{chunkX:t,chunkY:n}}function In(e){let t=q.grid.expansion||{},n=Math.max(1,(e.gridExpansionPurchases||0)+1),o=(t.costBase||1e3)*n*(t.costMultiplier||4/3),r=Math.max(1,t.truncateUnit||100);return Math.floor(o/r)*r}function Yr(e){e.ownedCells=new Set,e.ownedChunks=new Set,e.gridChunkOriginY=0,e.gridExpansionPurchases=0,e.gridExpansionPurchasesByDirection={right:0,up:0};for(let t=0;t=0&&t=0&&n0)continue;let C=Yt(b.chunkX,b.chunkY);t.has(C)||n.has(C)||n.set(C,Co(e,b.chunkX,b.chunkY,b.direction))}}return[...n.values()].sort((o,r)=>{let i=o.direction===r.direction?0:o.direction==="right"?-1:1;return i||(o.chunkY!==r.chunkY?o.chunkY-r.chunkY:o.chunkX-r.chunkX)})}function Xr(e,t="right"){let n=Tt(e);return n.find(o=>o.direction===t)||n[0]||null}function Et(e){return{x:f.x+e.colStart*f.cell,y:f.y+e.rowStart*f.cell,w:e.cols*f.cell,h:e.rows*f.cell}}function Mo(e){let t=Et(e);return{x:t.x+t.w/2-116,y:t.y+t.h/2-36,w:232,h:72,cx:t.x+t.w/2,cy:t.y+t.h/2}}function Qr(e,t){let n=Mo(e);return t.x>=n.x&&t.x<=n.x+n.w&&t.y>=n.y&&t.y<=n.y+n.h}function Jr(e){let t=[];for(let n=e.rowStart;nEe(t.col,t.row))}function Sl(e){return[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}].filter(t=>Ee(t.col,t.row))}function kl(e){return[{col:e.col,row:e.row+1},{col:e.col-1,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row-1}].filter(t=>Ee(t.col,t.row))}function oi(e){let t=new Set([...e.conveyorTiles]),n=o=>{o&&Ee(o.col,o.row)&&t.add(I(o.col,o.row))};for(let o of e.scanners){for(let r of Sl(o))n(r);for(let r of wl(o))n(r)}for(let o of e.eggFarms){n(o);for(let r of kl(o))n(r)}for(let o of Object.values(e.facilities))n(o.entry);return t}function ti(e){let t=hl.map(([n,o])=>({col:n,row:o}));for(let{col:n,row:o}of t)ni(e,n,o);for(let n=0;n({...n,keys:n.keys?{left:{...n.keys.left},right:{...n.keys.right}}:null,queue:[]})),e.eggFarms=bl.map(n=>{let o=Rt(n);return{...n,nextSpawn:o,lastInterval:o}});let t=oi(e);e.blockedCells=Wr({seed:e.runSeed,targetRatio:q.map.blockedRatio,reserved:[...t]}),Cl(e),ti(e),e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function Pt(e){return e?[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}]:[]}function ye(e){let t=F(e.col,e.row);return{x:t.x+f.cell/2,y:t.y}}function dt(e,t,n){return e.eggFarms.find(o=>o.col===t&&o.row===n)||null}function ft(e,t,n){return e.scanners.find(o=>Pt(o).some(r=>r.col===t&&r.row===n))||null}function At(e,t){return e.scanners.find(n=>n.id===t)||null}function Ro(e,t){return e.scanners.find(n=>n.kind==="manual"&&n.slot===t)||null}function Bn(e){return e?.baseId||e?.id||""}function Po(e,t){return Object.entries(e.facilities||{}).filter(([,n])=>Bn(n)===t)}function Re(e,t){return{inputA:{col:e.col,row:e.row-2},inputB:null,left:{col:e.col-1,row:e.row},right:{col:e.col+2,row:e.row}}[t]}function si(e){return e?de.map(t=>({col:e.col+t.dc,row:e.row+t.dr})).filter(t=>Ee(t.col,t.row)):[]}function li(e,t,n=[],o=[]){if(!t||!Ee(t.col,t.row))return[];let r=[],i=l=>{!l||!Ee(l.col,l.row)||!e.conveyorTiles.has(I(l.col,l.row))||n.some(c=>c&&Pn(l,c))||r.some(c=>Pn(c,l))||r.push({...l,viaTolerance:!Pn(l,t)})};i(t);for(let l of o)i(l);for(let l of si(t))i(l);return r}function ri(e,t,n=[],o=[]){let r=li(e,t,n,o),i=r.filter(l=>!l.viaTolerance);return i.length?i:r}function Ml(e,t){let n=Re(t,"inputA");return!n||!Ee(n.col,n.row)?[]:e.conveyorTiles.has(I(n.col,n.row))?[{...n,viaTolerance:!1}]:[]}function gl(e,t,n){let o=Re(t,n);return li(e,o,Pt(t))}function xl(e,t){let n=e.facilities[t]||Po(e,t)[0]?.[1];if(!n)return null;if(n.entry)return F(n.entry.col,n.entry.row);let o=Bn(n)||t;return o==="mixer"?{x:n.x+n.w,y:n.y+n.h*.52}:o==="truck"?{x:n.x,y:n.y+n.h*.52}:o==="trash"?{x:n.x+n.w/2,y:n.y+8}:{x:n.x+n.w/2,y:n.y+n.h/2}}function ai(e,t,n){return n==="inputA"?Ml(e,t).length>0:gl(e,t,n).length>0}function be(e){e.branchCounters?.clear?.(),e.routeCache=null,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function $e(e,t){return I(e,t)}function Vt(e){return te(e)}function Tl(e,t){let n=e.conveyorMeta?.get?.(t)||{},o=[];return Array.isArray(n.outDirs)&&o.push(...n.outDirs),n.dir&&o.push(n.dir),[...new Set(o)].filter(r=>de.some(i=>i.name===r))}function El(e,t,n){let o=de.find(l=>l.name===n);if(!o)return!1;let r=e.conveyorMeta?.get?.($e(t.col+o.dc,t.row+o.dr));return r?[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))].includes(o.opposite):!1}function Rl(e,t){let n=Vt(t),o=e.conveyorMeta?.get?.(t)||{},r=de.filter(x=>e.conveyorTiles.has($e(n.col+x.dc,n.row+x.dr))).map(x=>x.name),i=Tl(e,t).filter(x=>r.includes(x)),l=i.length?i:r;if(r.length<3)return l;let c=new Set(r.filter(x=>El(e,n,x))),b=r.filter(x=>!c.has(x)),C=c.size&&b.length>=2?b:[...new Set(l)];return C.length<2&&(C=r),o.branchMode&&o.branchMode!=="random"&&C.includes(o.branchMode)?[o.branchMode]:C}function Pl(e){return{version:e.routingVersion||0,cells:new Set,adjacency:new Map,components:new Map,cellToComponent:new Map,scannerInputs:new Map,scannerPorts:new Map,facilityPorts:new Map,farmOutputs:new Map,pathCache:new Map,metrics:{conveyorCells:0,edges:0,components:0,deadEnds:0,crosses:0,scannerPorts:0,connectedScannerPorts:0,facilityPorts:0,connectedFacilityPorts:0,farmOutputs:0},issues:[]}}function Al(e){let t=Pl(e);for(let o of e.conveyorTiles)t.cells.add(o),t.adjacency.set(o,[]);for(let o of t.cells){let r=Vt(o),i=Rl(e,o),l=de.filter(c=>i.includes(c.name));for(let c of l){let b=$e(r.col+c.dc,r.row+c.dr);t.cells.has(b)&&t.adjacency.get(o).push({key:b,dir:c.name})}}let n=0;for(let[o,r]of t.adjacency.entries()){n+=r.length;let i=new Set(r.map(l=>l.dir));r.length===1&&(t.metrics.deadEnds+=1),r.length===4&&i.has("left")&&i.has("right")&&i.has("up")&&i.has("down")&&(t.metrics.crosses+=1)}return t.metrics.conveyorCells=t.cells.size,t.metrics.edges=Math.floor(n/2),Il(t),Dl(e,t),t.issues=Kl(e,t,{includeRoutes:!1}),t}function Il(e){let t=1;for(let n of e.cells){if(e.cellToComponent.has(n))continue;let o=t++,r=[n],i=[];for(e.cellToComponent.set(n,o);r.length;){let l=r.shift();i.push(l);for(let c of e.adjacency.get(l)||[])e.cellToComponent.has(c.key)||(e.cellToComponent.set(c.key,o),r.push(c.key))}e.components.set(o,{id:o,cells:i,capacity:Math.max(1,i.length),count:0,ratio:0})}e.metrics.components=e.components.size}function Dl(e,t){for(let n of e.scanners){let o={};for(let r of["inputA","left","right"]){let i=Re(n,r),l=r==="inputA"?i&&t.cells.has($e(i.col,i.row))?[{...i}]:[]:ri(e,i,Pt(n)).filter(C=>t.cells.has($e(C.col,C.row))),c=l.map(C=>$e(C.col,C.row)),b=c.length>0;if(o[r]={type:r,cell:i,cells:l,keys:c,key:c[0]||null,connected:b},t.metrics.scannerPorts+=1,b&&(t.metrics.connectedScannerPorts+=1),r==="inputA")for(let C of c)t.scannerInputs.set(C,n.id)}t.scannerPorts.set(n.id,o)}for(let[n,o]of Object.entries(e.facilities)){if(!o.entry)continue;let r=ri(e,o.entry).filter(c=>t.cells.has($e(c.col,c.row))),i=r.map(c=>$e(c.col,c.row)),l=i.length>0;t.facilityPorts.set(n,{id:n,cell:{...o.entry},cells:r,keys:i,key:i[0]||null,connected:l}),t.metrics.facilityPorts+=1,l&&(t.metrics.connectedFacilityPorts+=1)}for(let n of e.eggFarms){let o=si({col:n.col,row:n.row}).map(r=>$e(r.col,r.row)).filter(r=>t.cells.has(r));t.farmOutputs.set(n.id,o),t.metrics.farmOutputs+=o.length}}function _e(e){let t=e.routingVersion||0;return(!e.factoryGraph||e.factoryGraph.version!==t)&&(e.factoryGraph=Al(e)),e.factoryGraph}function ci(e){let t=_e(e);return e.factoryGraphCommittedVersion=t.version,e.factoryGraphSnapshot=$l(t),t}function $l(e){return e?{version:e.version,conveyorCells:e.metrics.conveyorCells,edges:e.metrics.edges,components:e.metrics.components,deadEnds:e.metrics.deadEnds,crosses:e.metrics.crosses,scannerPorts:`${e.metrics.connectedScannerPorts}/${e.metrics.scannerPorts}`,facilityPorts:`${e.metrics.connectedFacilityPorts}/${e.metrics.facilityPorts}`,farmOutputs:e.metrics.farmOutputs,issues:[...e.issues||[]]}:null}function Fl(e,t){let n=t.col-e.col,o=t.row-e.row;return de.find(r=>r.dc===n&&r.dr===o)?.name||null}function Ao(e,t,n){let o=_e(e),r=$e(t.col,t.row);if(!o.cells.has(r))return[];let i=`${r}|${n.cacheKey||"dynamic"}`;if(n.cacheKey&&o.pathCache.has(i))return o.pathCache.get(i).map(le=>le.map(se=>({...se})));let l=`${r}|none`,c=[{key:r,col:t.col,row:t.row,incoming:"none",depth:0}],b=new Map([[l,0]]),C=new Map,x=[],A=1/0,$=8,B=24,j=80;for(;c.length;){let le=c.shift();if(le.depth>A)break;let se=`${le.key}|${le.incoming}`;if(n(le)){if(x.push(se),A=le.depth,x.length>=B)break;continue}for(let R of o.adjacency.get(le.key)||[]){let _=Vt(R.key),Y=Fl(le,_),O=le.depth+1;if(O>A)continue;let W=`${R.key}|${Y}`,U=b.get(W);if(U==null)b.set(W,O),C.set(W,[se]),c.push({key:R.key,col:_.col,row:_.row,incoming:Y,depth:O});else if(U===O){let M=C.get(W)||[];M.length<$&&!M.includes(se)&&M.push(se),C.set(W,M)}}}let z=[],ce=(le,se)=>{if(z.length>=j)return;let[R]=le.split("|"),_=[Vt(R),...se];if(le===l||R===r){z.push(_);return}for(let Y of C.get(le)||[])ce(Y,_)};for(let le of x)ce(le,[]);let he=[],ie=new Set;for(let le of z){let se=le.map(R=>$e(R.col,R.row)).join(">");ie.has(se)||(ie.add(se),he.push(le))}return n.cacheKey&&o.pathCache.set(i,he.map(le=>le.map(se=>({...se})))),he}function ui(e){let t=_e(e),n=new Map;for(let[o,r]of t.components.entries())n.set(o,{id:o,cells:[...r.cells],capacity:r.capacity,count:0,ratio:0});return{components:n,cellToComponent:new Map(t.cellToComponent)}}function di(e,t,n){let o=_e(e),r=null,i=1/0;for(let l of o.cells){let c=te(l),b=F(c.col,c.row),C=Math.hypot(b.x-t,b.y-n);CF(o.col,o.row));return t&&n.push(t),n}function ut(e,t){t&&(!e.length||Lr(e[e.length-1],t)>1)&&e.push(t)}function Bl(e,t,n,o=null){let r=[{x:e.x,y:e.y}];ut(r,F(t.col,t.row));for(let i of Ln(n,o))ut(r,i);return r}function Ll(e,t){let n=Ln(e),o=Re(t,"inputA");return o&&ut(n,F(o.col,o.row)),ut(n,ye(t)),n}function Ol(e,t,n,o){let r=[{x:e.x,y:e.y}];ut(r,F(t.col,t.row));for(let l of Ln(n))ut(r,l);let i=Re(o,"inputA");return i&&ut(r,F(i.col,i.row)),ut(r,ye(o)),r}function Nl(e,t,n=0){let o=F(t.col,t.row),r=0;for(let i of e.chicks||[]){if(i.stage==="flying"||i.stage==="queued")continue;Math.hypot(i.x-o.x,i.y-o.y){let A=C.roleBias??0,$=x.roleBias??0;if(A!==$)return A-$;let B=C.cells?.length??C.route?.length??Number.POSITIVE_INFINITY,j=x.cells?.length??x.route?.length??Number.POSITIVE_INFINITY;if(B!==j)return B-j;let z=C.key||JSON.stringify(C.route||C.cells||C),ce=x.key||JSON.stringify(x.route||x.cells||x);return z.localeCompare(ce)});if(!o||r.length===1)return r[0];let i=r[0].roleBias??0,l=r.filter(C=>(C.roleBias??0)===i),c=Math.min(...l.map(C=>ii(e,C)));l=l.filter(C=>ii(e,C)===c);let b=e.branchCounters.get(t)||0;return e.branchCounters.set(t,b+1),l[Math.floor(Math.random()*l.length)]}function fi(e){return e.role===0?{left:{match:"male",destination:"mixer"},right:{match:"default",destination:"scanner-role-1"}}:{left:{match:"poop",destination:"trash"},right:{match:"default",destination:"truck"}}}function Io(e){let t=fi(e);return{left:t.left.destination,right:t.right.destination}}function Do(e,t){return fi(e).left.match===t.sex?"left":"right"}function $o(e){return Nr(e)}function Fo(e){return{mixer:"#2477ff",truck:"#ff6aa8",trash:"#22b94f","scanner-role-1":"#526456",scanner:"#526456",input:"#526456"}[e]||"#102015"}function It(e,t,n=!1){let o=_e(e),r=(o.farmOutputs.get(t.id)||[]).map(Vt),i=[];for(let b of r){let C=A=>o.scannerInputs.has($e(A.col,A.row));C.cacheKey=`farmInput:${b.col},${b.row}:v${o.version}`;let x=Ao(e,b,C);for(let A of x){let $=A[A.length-1],B=o.scannerInputs.get($e($.col,$.row)),j=At(e,B);j&&i.push({key:`${j.id}:${$.col},${$.row}:${A.length}`,scanner:j,cells:A})}}let l=Fn(e,`farm:${t.id}`,i,n);if(l)return{scannerId:l.scanner.id,route:Ll(l.cells,l.scanner)};let c=Fn(e,`farm:${t.id}:output`,r.map(b=>({key:I(b.col,b.row),cells:[b]})),n);return c?{scannerId:null,route:Ln(c.cells)}:null}function pi(e,t,n,o,r=!1){let i=At(e,o);if(!i)return null;let c=_e(e).scannerPorts.get(i.id)?.[t],b=Re(i,t),C=c?.connected?(c.keys||[c.key]).filter(Boolean).map(Vt):[];if(!b||!C.length)return null;let x=Io(i)[t];return x==="scanner-role-1"?_l(e,i,t,n,b,C,r):Gl(e,i,t,n,b,C,x,r)}function _l(e,t,n,o,r,i,l){let c=_e(e),b=e.scanners.filter(A=>A.id!==t.id&&c.scannerPorts.get(A.id)?.inputA?.connected),C=[];for(let A of i)for(let $ of b){let B=c.scannerPorts.get($.id)?.inputA?.key;if(!B)continue;let j=(c.scannerPorts.get($.id)?.inputA?.keys||[B]).filter(Boolean),z=ie=>j.includes($e(ie.col,ie.row));z.cacheKey=`toScanner:${A.col},${A.row}:${$.id}:v${c.version}`;let ce=Ao(e,A,z),he=$.role===1?0:1;for(let ie of ce)C.push({key:`${he}:start${I(A.col,A.row)}:s${$.id}:${ie.length}:${I(ie[ie.length-1].col,ie[ie.length-1].row)}`,target:$,cells:ie,roleBias:he})}let x=Fn(e,`scanner:${t.id}:${n}:toRole1`,C,l);return x?{destination:"scanner",nextScannerId:x.target.id,route:Ol(o,r,x.cells,x.target)}:null}function Gl(e,t,n,o,r,i,l,c){let b=_e(e),C=[...b.facilityPorts.entries()].filter(([$,B])=>B?.connected&&Bn(e.facilities?.[$])===l);if(!C.length)return null;let x=[];for(let $ of i)for(let[B,j]of C){let z=(j.keys||[j.key]).filter(Boolean);if(!z.length)continue;let ce=ie=>z.includes($e(ie.col,ie.row));ce.cacheKey=`toFacility:${$.col},${$.row}:${B}:v${b.version}`;let he=Ao(e,$,ce);for(let ie of he)x.push({key:`start${I($.col,$.row)}:${B}:${ie.length}:${I(ie[ie.length-1].col,ie[ie.length-1].row)}`,cells:ie,facilityId:B})}let A=Fn(e,`scanner:${t.id}:${n}:${l}`,x,c);return A?{destination:l,facilityId:A.facilityId,route:Bl(o,r,A.cells,xl(e,A.facilityId))}:null}function yi(e,t,n=new Set){if(!t||n.has(t.id))return!1;n.add(t.id);for(let o of["left","right"]){let r=pi(e,o,ye(t),t.id,!1);if(r){if(["mixer","trash","truck"].includes(r.destination))return!0;if(r.destination==="scanner"){let i=At(e,r.nextScannerId);if(yi(e,i,n))return!0}}}return!1}function Ul(e,t){return!!It(e,t,!1)?.scannerId}function On(e){if(e.phase!=="build")return[];let t=[];for(let n of e.eggFarms||[])Ul(e,n)||t.push({type:"eggFarm",id:n.id,ref:n,message:"This Egg will not produce chicks"});for(let n of un)for(let[o,r]of Po(e,n))_e(e).facilityPorts.get(o)?.connected||t.push({type:"facility",id:o,ref:r,message:"This facility cannot receive items"});return t}function Wl(e){let t=_e(e);for(let r of e.eggFarms||[]){let i=It(e,r,!1);if(!i?.scannerId)continue;let l=At(e,i.scannerId);if(yi(e,l))return[]}let n=e.eggFarms?.length||0,o=[...t.facilityPorts.entries()].filter(([r,i])=>i?.connected&&["mixer","trash","truck"].includes(Bn(e.facilities?.[r]))).length;return n?t.metrics.farmOutputs?e.scanners?.length?o?["Connect at least one EGG through a scanner to any valid exit."]:["Connect at least one receiver exit: Mixer, Shredder, or Truck."]:["Build at least one scanner and connect it to an EGG route."]:["Connect at least one EGG to a conveyor."]:["Build at least one EGG before starting the next day."]}function $n(e){return e.kind==="manual"?`S${(e.slot??0)+1}`:`Auto Scanner #${e.id}`}function Kl(e,t=_e(e),n={}){let o=n.includeRoutes!==!1,r=[],i={mixer:"Mixer",trash:"Shredder",truck:"Truck"};for(let l of un){let c=Po(e,l);if(!c.length){r.push(`${i[l]||l} is missing`);continue}for(let[b]of c)t.facilityPorts.get(b)?.connected||r.push(`${i[l]||l} receiver has no conveyor`)}for(let l of e.scanners){let c=t.scannerPorts.get(l.id)||{};if(c.inputA?.connected||r.push(`${$n(l)} input has no conveyor`),c.left?.connected||r.push(`${$n(l)} left output has no conveyor`),c.right?.connected||r.push(`${$n(l)} right output has no conveyor`),!!o)for(let b of["left","right"])c[b]?.connected&&!pi(e,b,ye(l),l.id)&&r.push(`${$n(l)} ${b} route is incomplete`)}if(o)for(let l of e.eggFarms)It(e,l)?.scannerId||r.push(`Egg Farm #${l.id} has no scanner route`);else for(let l of e.eggFarms)(t.farmOutputs.get(l.id)||[]).length||r.push(`Egg Farm #${l.id} has no output conveyor`);return[...new Set(r)]}function pn(e){return Wl(e)}function hi(e){return pn(e).length===0}var mi=[{key:"premiumFemaleShipment",target:"female",truckTarget:"female",title:"Premium Female Shipment",route:"Female -> Truck",note:"Today only: ship female chicks to Truck. Meet the export target for a bonus.",objective:"truckTarget"},{key:"contaminantSampleExport",target:"poop",truckTarget:"poop",title:"Contaminant Sample Export",route:"Poop value x2",note:"Today only: poop is valid Truck cargo and all poop income is doubled.",objective:"truckTarget",poopValueMultiplier:2},{key:"healthInspection",title:"Health Inspection",route:"Poop -> Shredder",note:"Today only: poop mistakes are fined double. Shred enough poop for an inspection bonus.",objective:"poopTrash",poopFineMultiplier:2},{key:"conveyorJamWarning",title:"Conveyor Jam Warning",route:"No explosions",note:"Today only: jam explosions trigger at 85% congestion. Finish with zero explosions for a bonus.",objective:"noExplosion",congestionExplosionThreshold:.85,congestionWarningThreshold:.68},{key:"powerSavingOrder",title:"Power Saving Order",route:"Slow factory subsidy",note:"Today only: conveyors -20% speed and Auto Scanners +20% cooldown. A subsidy is paid at settlement.",objective:"flatBonus",conveyorSpeedMultiplier:.8,autoScannerCooldownMultiplier:1.2},{key:"overtimeDay",title:"Overtime Day",route:"80 second day",note:"Today only: the work day is longer. No extra reward or penalty.",objective:"none",daySeconds:80},{key:"shortShift",title:"Short Shift",route:"40 second day",note:"Today only: the work day is shorter. The next Fairies tribute is reduced by 10%.",objective:"none",daySeconds:40,fairiesTributeMultiplier:.9},{key:"chickBoom",title:"Chick Boom",route:"EGG interval x0.65",note:"Today only: eggs hatch faster and poop rate rises by 5 percentage points.",objective:"none",productionMultiplier:1/.65,poopRateAdd:.05},{key:"rottenFeed",title:"Rotten Feed",route:"Poop surge",note:"Today only: poop rate rises by 20 percentage points and Shredder poop income is multiplied by 1.5.",objective:"none",poopRateAdd:.2,shredderIncomeMultiplier:1.5},{key:"maintenanceAudit",title:"Maintenance Audit",route:"Durability check",note:"Today only: machines below 50% remaining durability fail the audit. Passing with none below 50% pays a bonus.",objective:"maintenanceAudit"}];function we(e,t=0){let n=Number(e);return Number.isFinite(n)?n:t}function Hl(e,t=0,n=1){let o=Math.max(1,Number(e?.turn||1)+1),r=Math.floor(Bo(e)*(.08+Math.random()*.08)),i=Math.floor(Math.max(0,e.cash||0)*.25),l=Math.floor(Math.max(0,t)*Math.max(1,o)*.75);return Math.max(120,Math.ceil(Math.max(r,i,l)*n))}function bi(e){return Math.max(0,Math.ceil(500+Math.max(1,e?.turn||1)*25))}function Bo(e){return[...e.eggFarms.map(t=>t.price||0),...e.scanners.map(t=>t.price||0),...Object.values(e.facilities).map(t=>t.price||0),...[...e.conveyorMeta.values()].map(t=>t.price||0)].reduce((t,n)=>t+n,0)}function ql(e,t=1,n=xt){return e.eggFarms.reduce((o,r)=>{let[i,l]=fn(r),c=Math.max(.1,(i+l)/2);return o+Math.max(1,n)/c*Math.max(.01,t||1)},0)}function Yl(e,t){let n=we(t.productionMultiplier,1),o=we(t.daySeconds,xt),r=ql(e,n,o),i=Math.max(0,Number(e?.cardEffects?.hatchingFeed)||0),l=Math.max(0,Number(e?.cardEffects?.poopRateBooster)||0),c=Math.pow(1.03,i),b=bo+vo*l,C=Math.min(.95,Math.max(0,(b+we(t.poopRateAdd,0))*we(t.poopMultiplier,1)*c));return{estimate:r,poopRate:C}}function vi(e){if(e.turn+1Dr)return null;let n=mi[Math.floor(Math.random()*mi.length)],{estimate:o,poopRate:r}=Yl(e,n),i=0;n.objective==="truckTarget"?i=Math.max(1,Math.ceil(o*.3)):n.objective==="poopTrash"&&(i=Math.max(1,Math.ceil(o*r*.8)));let l=0;return["truckTarget","poopTrash","noExplosion"].includes(n.objective)&&(l=Hl(e,o)),n.objective==="flatBonus"&&(l=bi(e)),n.objective==="maintenanceAudit"&&(l=bi(e)),{id:`event-${e.turn}-${Date.now()}-${Math.floor(Math.random()*9999)}`,...n,target:n.target||null,truckTarget:n.truckTarget||null,forced:!0,productionMultiplier:we(n.productionMultiplier,1),poopMultiplier:we(n.poopMultiplier,1),poopRateAdd:we(n.poopRateAdd,0),daySeconds:we(n.daySeconds,xt),targetAmount:i,estimatedOutput:Math.round(o),reward:l,createdTurn:e.turn,oneTurnOnly:!0}}function wi(e){e.eventActive=e.eventOffer?{...e.eventOffer}:null,e.eventOffer=null}function Si(e){e.eventActive=null}function ki(e){return Math.max(1,we(e.eventActive?.daySeconds,xt))}function Ci(e){return we(e.eventActive?.productionMultiplier,1)}function Mi(e){let t=Math.max(0,Number(e?.cardEffects?.hatchingFeed)||0),n=Math.max(0,Number(e?.cardEffects?.poopRateBooster)||0),o=Math.pow(1.03,t),r=bo+vo*n,i=we(e.eventActive?.poopRateAdd,0);return Math.min(.95,Math.max(0,(r+i)*we(e.eventActive?.poopMultiplier,1)*o))}function pt(e){return e.eventActive?.truckTarget||e.eventActive?.target||"female"}function Lo(e,t){return t==="male"?e.truckMale||0:t==="poop"?e.poopTruck||0:e.truckFemale||0}function gi(e,t){return pt(e)===t}function xi(e){return pt(e)!=="male"}function Oo(e){return Math.max(.01,we(e.eventActive?.poopValueMultiplier,1))}function Nn(e){return Math.max(.01,Oo(e)*we(e.eventActive?.shredderIncomeMultiplier,1))}function No(e){return Math.max(.01,we(e.eventActive?.poopFineMultiplier,1))}function _o(e){return Math.max(.1,Math.min(1,we(e.eventActive?.congestionExplosionThreshold,1)))}function Ti(e){return Math.max(.1,Math.min(1,we(e.eventActive?.congestionWarningThreshold,.8)))}function Ei(e){return Math.max(.01,we(e?.fairiesTributeMultiplier,1))}function Vl(e){let t=0,n=(o,r)=>{let i=Math.max(1,we(r,1)),l=Math.max(0,we(o,0));1-Math.min(1,l/i)<.5&&(t+=1)};for(let o of e.conveyorMeta?.values?.()||[])n(o.uses,o.durability);for(let o of e.eggFarms||[])n(o.maintenance?.uses,o.maintenance?.durability);for(let o of e.scanners||[])o.kind==="auto"&&n(o.maintenance?.uses,o.maintenance?.durability);for(let o of Object.values(e.facilities||{})){let r=o?.baseId||o?.id;(r==="mixer"||r==="trash")&&n(o.maintenance?.uses,o.maintenance?.durability)}return t}function Ri(e){let t=e.eventActive;if(!t)return null;let n=0,o=!0,r=0,i="";t.objective==="truckTarget"?(n=Lo(e.stats,t.target),o=n>=t.targetAmount,r=o?t.reward:0):t.objective==="poopTrash"?(n=e.stats.poopTrash||0,o=n>=t.targetAmount,r=o?t.reward:0):t.objective==="noExplosion"?(n=e.stats.explosions||0,o=n===0,r=o?t.reward:0,i=`${n} explosion(s)`):t.objective==="flatBonus"?(o=!0,r=t.reward):t.objective==="maintenanceAudit"?(n=Vl(e),o=n===0,o&&(r=t.reward),i=`${n} machine(s) below 50%`):o=!0,r>0?(Ge(e,r),e.stats.eventBonus=(e.stats.eventBonus||0)+r,e.totals.eventBonus+=r,e.totals.eventSuccess+=1):t.objective&&t.objective!=="none"&&(e.stats.eventBonus=e.stats.eventBonus||0,e.totals.eventFailed+=o?0:1,o&&(e.totals.eventSuccess+=1));let l={title:t.title,key:t.key,target:t.target,route:t.route,objective:t.objective,targetAmount:t.targetAmount||0,count:n,success:o,bonus:r,reward:t.reward||0,productionMultiplier:t.productionMultiplier,poopMultiplier:t.poopMultiplier,daySeconds:t.daySeconds,detail:i};return e.stats.eventResult=l,l}function Go(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function zl(e){return!!e?.cardEffects?.usedMachineActive}function Xl(e,t){return t?1:Math.min(.8,.5+.1*Math.min(3,Go(e,"recyclingSubsidy")))}function Ql(e){return Math.pow(.95,Go(e,"safetyCover"))}function _n(e){let t=e?.ref||e||{},n=e?.type||t.type;return n==="conveyor"?t.price||ve[t.kind]?.price||ve.conveyor.price:n==="eggFarm"?t.price||ve.eggFarm.price:n==="scanner"?t.price||(t.kind==="auto"?ve.autoScanner.price:ve.manualScanner.price):n==="facility"?t.price||ve[t.id]?.price||0:n==="maintenanceRoom"?t.price||ve.maintenanceRoom.price:ve[t.id]?.price||0}function Oe(e,t=null){let n=ve[e]?.price||0;return zl(t)?Math.ceil(n*.5):n}function Jl(e,t){return e?.facilities?Object.values(e.facilities).filter(n=>(n?.baseId||n?.id)===t).reduce((n,o)=>n+Math.max(0,(o.level||1)-1),0):0}function yt(e,t){return Fr.includes(t)?Math.pow(ke.incomeUpgradeRate,Jl(e,t)):1}function ze(e){return Math.ceil(ke.income.mixer*yt(e,"mixer"))}function Fe(e){return Math.ceil(ke.income.truck*yt(e,"truck"))}function yn(e){return Math.ceil(ke.poopFine*yt(e,"mixer")*No(e))}function hn(e){return Math.ceil(ke.poopFine*yt(e,"truck")*No(e))}function Uo(e){let t=ke.maleTruckFinePerHalfDay*(e.turn/2);return Math.ceil(t*yt(e,"truck"))}function Wo(e){return e?.facilities?Object.values(e.facilities).filter(t=>(t?.baseId||t?.id)==="trash").reduce((t,n)=>t+Math.max(0,(n.level||1)-1),0):0}function Dt(e){return Math.min(ke.shredderBonus.maxCards,Wo(e))}function zt(){return ke.shredderBonus.maxCards}function ht(e){let t=typeof e=="number"?e:Dt(e),n=Math.min(ke.shredderBonus.maxCards,Math.max(0,t));return n>0?Math.ceil(n*(ke.shredderBonus.incomePerUpgrade||1)):0}function jl(e){let t=Dt(e),n=ht(t),o=Math.ceil(n*Nn(e));return{cards:t,chance:o>0?1:0,amount:o,expected:o,baseAmount:n}}function Pi(e){let t=jl(e);return t.amount>0&&(e.stats.shredderBonus=(e.stats.shredderBonus||0)+t.amount,e.totals.shredderBonus=(e.totals.shredderBonus||0)+t.amount,Ge(e,t.amount)),t}function Ko(e,t=e.turn,n=null){let o=Math.max(1,Math.floor(Number(t)||1)),r=ke.fairiesTribute||{perDay:10,profitExemption:300,legalWorkExemptionBonus:250,profitRate:.12},i=Math.ceil(o*(r.perDay||10)),l=Math.max(0,Math.floor(Number(n??e?.lastResult?.profit??e?.stats?.profit??0)||0)),c=Math.max(0,e?.cardEffects?.legalWork||0),b=Math.max(0,(r.profitExemption||0)+c*(r.legalWorkExemptionBonus||0)),C=Math.max(0,l-b),x=Math.ceil(C*Math.max(0,Number(r.profitRate)||0)),A=i+x,$=Math.max(0,e?.cardEffects?.fairiesFlatteryNext||e?.cardEffects?.flattery||0),B=$>0?Math.pow(.5,$):1,j=Math.max(.01,Number(e?.pendingFairiesTributeMultiplier)||1),z=B*j,ce=Math.max(0,Math.ceil(A*z)),he=Math.max(0,A-ce);return{day:o,base:i,profit:l,legalWork:c,profitExemption:b,taxableProfit:C,profitTribute:x,gross:A,flatteryCount:$,eventMultiplier:j,perCardReduction:Math.ceil(A*.5),reduction:he,amount:ce}}function mt(e,t){let n=e?.ref||e||{},o=e?.type==="conveyor"?t?.conveyorMeta?.get(e.oldKey||n.id):n,r=o?.price||_n(e||n),i=o?.builtSession===t?.buildSession;if(o?.noRefund||n?.noRefund)return{amount:0,sameBuild:i,price:r,rate:0,noRefund:!0};let l=Xl(t,i);return{amount:Math.max(0,Math.ceil(r*l)),sameBuild:i,price:r,rate:l,noRefund:!1}}function Zl(e,t=null){let n=Math.max(1,Math.ceil((Number(e)||0)/ke.explosionDamageDivisor));return Math.max(1,Math.ceil(n*Ql(t)))}function ea(e,t){return Math.max(0,Math.ceil(t))}function Ai(e,t){e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,t>=0?(e.stats.revenue+=t,e.totals.revenue+=t):(e.stats.penalty+=Math.abs(t),e.totals.penalty+=Math.abs(t)),e.totals.maxCash=Math.max(e.totals.maxCash,e.cash)}function Ge(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&Ai(e,n),n}function bt(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&Ai(e,-n),n}function $t(e,t){bt(e,t)}function Ii(e,t){t<=0||(e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,e.totals.maxCash=Math.max(e.totals.maxCash,e.cash))}function Di(e){let t=ze(e);return e.stats.mixerRevenue+=t,Ge(e,t),t}function $i(e){let t=yn(e);return e.stats.mixerPoopFine+=t,e.totals.mixerPoopFine+=t,bt(e,t),t}function Fi(e){let t=hn(e);return e.stats.truckPoopFine+=t,e.totals.truckPoopFine+=t,bt(e,t),t}function Bi(e){let t=Uo(e);return e.stats.maleTruckFine+=t,e.totals.maleTruckFine+=t,bt(e,t),t}function Li(e,t){let n=Zl(t,e);return e.stats.explosionDamage+=n,e.totals.explosionDamage+=n,bt(e,n),n}function Oi(e){let t=pt(e),n=Lo(e.stats,t),o=t==="poop"?Math.ceil(Fe(e)*Oo(e)):Fe(e),r=n*o,i=ea(e,r);return e.stats.pendingTruckRevenue=i,e.stats.truckRevenue=i,t==="poop"?e.stats.poopShipmentIncome=i:e.stats.chickShipmentIncome=i,i>0&&Ge(e,i),{base:r,adjusted:i,target:t,targetCount:n,unitPrice:o}}function Ni(e,t=e.turn,n=null,o={}){let r=Ko(e,t,n);return e.cardEffects&&(e.cardEffects.fairiesFlatteryNext=0,e.cardEffects.flattery!=null&&delete e.cardEffects.flattery),e.pendingFairiesTributeMultiplier!=null&&(e.pendingFairiesTributeMultiplier=1),r.amount<=0||(o.recordStats?(e.stats.fairiesTribute=(e.stats.fairiesTribute||0)+r.amount,e.totals.fairiesTribute=(e.totals.fairiesTribute||0)+r.amount,bt(e,r.amount)):(e.totals.fairiesTribute=(e.totals.fairiesTribute||0)+r.amount,e.totals.penalty=(e.totals.penalty||0)+r.amount,e.totals.profit=(e.totals.profit||0)-r.amount,e.cash-=r.amount)),r}function _i(e){let t=Go(e,"chemicalWeaponSubsidy"),n=Math.max(0,e?.stats?.poopTruck||0),o=ke.chemicalWeaponSubsidy||{poopPerBlock:70,yenPerBlock:1200},r=Math.floor(n/Math.max(1,o.poopPerBlock||70)),i=t>0&&r>0?r*Math.max(0,o.yenPerBlock||1200)*t:0;return i>0&&(e.stats.chemicalWeaponSubsidy=(e.stats.chemicalWeaponSubsidy||0)+i,e.totals.chemicalWeaponSubsidy=(e.totals.chemicalWeaponSubsidy||0)+i,Ge(e,i)),{cards:t,poopTruck:n,blocks:r,amount:i}}function Gi(e){let t=Bo(e),n=Math.max(1,e.totals.turnsCompleted||e.turn||1),o=Math.max(0,e.cash+e.totals.revenue+t*.5+e.totals.eventBonus*.5),r=Math.ceil(o/n),i=Math.floor(n*35+Math.max(0,n-5)*15),l=e.totals.correct*5,c=e.totals.explosionDamage;return{score:Math.max(0,Math.floor(o+r+l-e.totals.penalty-i)),factoryValue:t,base:o,dailyEarned:r,dayPenalty:i,correctBonus:l,explosionPenalty:c,days:n}}function ta(e){return{...e,keys:e.keys?{left:{...e.keys.left},right:{...e.keys.right}}:null,queue:[],cooldown:e.cooldown||0}}function mn(e){return JSON.stringify({cash:e.cash,stats:e.stats,totals:e.totals,nextId:e.nextId,gridX:f.x,gridY:f.y,gridCols:e.gridCols||f.cols,gridRows:e.gridRows||f.rows,gridExpansionPurchases:e.gridExpansionPurchases||0,gridExpansionPurchasesByDirection:e.gridExpansionPurchasesByDirection||{right:0,up:0},gridChunkOriginY:e.gridChunkOriginY||0,ownedCells:[...e.ownedCells||[]],ownedChunks:[...e.ownedChunks||[]],blockedCells:[...e.blockedCells||[]],selected:e.selected,multiSelected:e.multiSelected||[],buildTool:e.buildTool,view:e.view,facilities:e.facilities,eggFarms:e.eggFarms,scanners:e.scanners.map(ta),conveyorTiles:[...e.conveyorTiles],conveyorMeta:[...e.conveyorMeta.entries()],branchCounters:[...e.branchCounters.entries()],cardEffects:e.cardEffects,cardDraft:e.cardDraft,cardTargetPick:e.cardTargetPick})}function Ui(e,t){let n=JSON.parse(t);e.cash=n.cash,e.stats=n.stats,e.totals=n.totals,e.nextId=n.nextId,f.x=n.gridX??q.grid.x,f.y=n.gridY??q.grid.y,f.cols=n.gridCols||q.grid.cols,f.rows=n.gridRows||q.grid.rows,e.gridCols=f.cols,e.gridRows=f.rows,e.gridExpansionPurchases=n.gridExpansionPurchases||0,e.gridExpansionPurchasesByDirection=n.gridExpansionPurchasesByDirection||{right:0,up:0},e.gridChunkOriginY=n.gridChunkOriginY||0,e.ownedCells=new Set(n.ownedCells||[]),e.ownedChunks=new Set(n.ownedChunks||[]),e.gridOwnedCells=e.ownedCells.size||f.cols*f.rows,e.blockedCells=new Set(n.blockedCells||[]),e.selected=n.selected,e.multiSelected=n.multiSelected||[],e.buildTool=n.buildTool,e.view=n.view||{x:0,y:0,scale:1},e.view.scale==null&&(e.view.scale=1),e.facilities=n.facilities||{},e.eggFarms=n.eggFarms||[],e.scanners=(n.scanners||[]).map(o=>({...o,queue:[],cooldown:o.cooldown||0})),e.conveyorTiles=new Set(n.conveyorTiles||[]),e.conveyorMeta=new Map(n.conveyorMeta||[]),e.branchCounters=new Map(n.branchCounters||[]),e.cardEffects=n.cardEffects||{bearing:0,legalWork:0,fairiesFlatteryNext:0,scannerQueueSpacing:0},e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft=n.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardTargetPick=n.cardTargetPick||null,e.groupDrag=null,e.selectionBox=null,e.pan=null,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function Be(e){e.phase==="build"&&(e.undoStack.push(mn(e)),e.undoStack.length>80&&e.undoStack.shift(),e.redoStack=[])}function Ho(e){return e.phase!=="build"||!e.undoStack.length?!1:(e.redoStack.push(mn(e)),Ui(e,e.undoStack.pop()),!0)}function qo(e){return e.phase!=="build"||!e.redoStack.length?!1:(e.undoStack.push(mn(e)),Ui(e,e.redoStack.pop()),!0)}function H(e,t,n,o,r=y.ink){e.floatingTexts.push({x:t,y:n,text:o,color:r,life:1,maxLife:1})}function Ft(e,t,n){e.shake.strength=Math.max(e.shake.strength,t),e.shake.time=Math.max(e.shake.time,n)}function Wi(e,t,n){e.effects.push({type:"spawn",priority:Ce.ambient,x:t,y:n,life:.42,maxLife:.42,size:12})}function Ki(e,t,n,o=y.green){e.effects.push({type:"scannerPulse",priority:Ce.important,x:t,y:n,color:o,life:.42,maxLife:.42,size:24})}function Hi(e,t,n){for(let o=0;o<12;o+=1)e.effects.push({type:"meat",priority:Ce.important,x:t+K(-18,18),y:n+K(-12,16),vx:K(-60,60),vy:K(-90,-25),life:K(.45,.85),maxLife:.85,size:K(4,8)})}function qi(e,t,n){for(let o=0;o<16;o+=1)e.effects.push({type:"sludge",priority:Ce.important,x:t+K(-18,18),y:n+K(-12,16),vx:K(-46,46),vy:K(-70,-20),life:K(.45,.9),maxLife:.9,size:K(4,8)})}function Yi(e,t,n,o){let r=o==="poop"?y.poop:o==="male"?y.male:y.female;for(let i=0;i<22;i+=1)e.effects.push({type:"shred",priority:Ce.important,x:t+K(-16,16),y:n+K(-8,8),vx:K(-70,70),vy:K(40,160),color:i%3===0?y.white:r,life:K(.45,.95),maxLife:.95,w:K(3,7),h:K(10,24),rot:K(-Math.PI,Math.PI)});Xe(e,t,n,y.green,34,Ce.important)}function Vi(e,t,n,o){let r=o==="poop"?y.poop:o==="male"?y.danger:y.green;for(let i=0;i<8;i+=1)e.effects.push({type:"load",priority:Ce.important,x:t+K(-18,18),y:n+K(-18,18),vx:K(-42,42),vy:K(-90,-25),color:r,life:K(.35,.65),maxLife:.65,size:8})}function Xe(e,t,n,o=y.danger,r=52,i=Ce.critical){e.effects.push({type:"shockwave",priority:i,x:t,y:n,color:o,life:.55,maxLife:.55,size:8,maxSize:r})}function Ze(e,t,n,o=12,r=y.danger,i=Ce.critical){for(let l=0;l0&&(e.shake.time=Math.max(0,e.shake.time-t),e.shake.time<=0&&(e.shake.strength=0));for(let r of e.effects)if(r.life-=t,["meat","sludge","spark","smoke","shred","load","rage"].includes(r.type))r.x+=(r.vx||0)*t,r.y+=(r.vy||0)*t,r.vy=(r.vy||0)+150*t;else if(r.type==="flyingChick"){r.x+=r.vx*t,r.y+=r.vy*t,r.vy+=360*t,r.noDamage||na(e,r,o);let i=r.x+e.view.x,l=r.y+e.view.y;(i<-100||l<-100||i>n.width+100||l>n.height+100)&&(r.life=0)}e.effects=e.effects.filter(r=>r.life>0);for(let r of e.floatingTexts)r.life-=t,r.y-=34*t;e.floatingTexts=e.floatingTexts.filter(r=>r.life>0)}function na(e,t,n){t.hit||(t.hit=new Set);for(let o of n()){if(t.hit.has(o.id)||t.xo.x+o.w||t.yo.y+o.h)continue;t.hit.add(o.id);let r=Li(e,o.price);H(e,t.x,t.y-10,`-${T(r)}`,y.danger),Xe(e,t.x,t.y,y.danger,30),Ze(e,t.x,t.y,5,y.danger),Ft(e,5,.18)}}var Ue=q.maintenance;function Vo(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function Wn(e){let t=Math.min(1.4,1+.04*Math.min(10,Vo(e,"crowdedFarming"))),n=Math.pow(.95,Vo(e,"preventiveMaintenance"));return t*n}function oa(e){return Math.pow(1.03,Vo(e,"durabilityCoating"))}function Kn(e,t,n=1){let o=Ue.durability[t]||1e3;return Math.max(1,Math.ceil(o*Math.max(.1,n||1)*oa(e)))}function Qi(e){return Math.max(.1,Number(e?.durabilityBaseMultiplier)||1)}function ra(e,t=0){if(!e)return{x:f.x+f.cell*(.5+t*.55),y:f.y+f.rows*f.cell+84};let n=f.x+e.col*f.cell+f.cell,o=f.y+e.row*f.cell+f.cell;return{x:n,y:o}}function ia(e,t=0){let n=(e.maintenanceRooms||[])[t];return ra(n,t)}function Se(e){e.repairman||(e.repairman={active:!1,x:f.x+f.cell*.5,y:f.y+f.rows*f.cell+84,target:null,repairedToday:0}),Array.isArray(e.maintenanceRooms)||(e.maintenanceRooms=[]),Array.isArray(e.repairmen)||(e.repairmen=[]);for(let[t,n]of e.conveyorMeta||[]){n.uses==null&&(n.uses=0),n.maintenanceType==null&&(n.maintenanceType="conveyor"),n.kind||(n.kind="conveyor"),n.speedMultiplier||(n.speedMultiplier=n.kind==="boostConveyor"?2:1),n.branchMode||(n.branchMode="random");let o=Kn(e,"conveyor",Qi(n));(n.durability==null||n.durability0&&(n.processingCooldown=Math.max(0,n.processingCooldown-t))}function wn(e){Se(e);let t=[];for(let[n,o]of e.conveyorMeta||[])t.push({type:"conveyor",key:n,meta:o,label:`${o.kind==="boostConveyor"?"Boost Belt":"Belt"} ${n}`,center:F(te(n).col,te(n).row)});for(let n of e.eggFarms||[])t.push({type:"eggFarm",ref:n,label:`EGG #${n.id}`,center:F(n.col,n.row)});for(let n of(e.scanners||[]).filter(o=>o.kind==="auto"))t.push({type:"autoScanner",ref:n,label:`AUTO #${n.id}`,center:F(n.col,n.row)});for(let n of Object.values(e.facilities||{})){let o=Vn(n);["mixer","trash"].includes(o)&&t.push({type:o,ref:n,label:`${n.shortName||n.name||o} #${n.id}`,center:{x:n.x+n.w/2,y:n.y+n.h/2}})}return t}function Bt(e){return e.meta?Xt(e):Xt(e.ref)}function bn(e){return e.meta?zo(e):zo(e.ref)}function Un(e){return e.meta?Xo(e):Xo(e.ref)}function ts(e,t){sa(e.meta?e:e.ref,Math.max(0,bn(e)-t))}function or(e){return e.type==="conveyor"?`conveyor:${e.key}`:`${e.type}:${e.ref?.id||e.ref?.type||e.type}`}function ns(e,t=.02){Se(e);let n=Math.max(0,Number(t)||0),o=0;for(let r of wn(e)){let i=bn(r);ts(r,Un(r)*n),o+=Math.max(0,i-bn(r))/Un(r)*100}return o}function os(e){Se(e);let t=e.maintenanceRooms||[];e.repairmen=t.map((o,r)=>{let i=ia(e,r);return{id:`room-${o.id}`,roomId:o.id,active:!0,x:i.x,y:i.y,target:null,repairedToday:0}});let n=e.repairmen[0];e.repairman.active=!!n,e.repairman.target=n?.target||null,e.repairman.repairedToday=0,n&&(e.repairman.x=n.x,e.repairman.y=n.y)}function rs(e){Se(e);for(let t of e.repairmen||[])t.active=!1,t.target=null;e.repairmen=[],e.repairman.active=!1,e.repairman.target=null}function aa(e,t){return t&&wn(e).find(o=>or(o)===t.key)||null}function ca(e){let t=null;for(let n of wn(e)){let o=Bt(n);o<=.001||(!t||o>Bt(t))&&(t=n)}return t}function is(e,t){Se(e);let n=e.repairmen?.length?e.repairmen:e.repairman?.active?[e.repairman]:[];if(!n.length||e.phase!=="running")return;let o=new Set(n.map(i=>i.target?.key).filter(Boolean));for(let i of n)ua(e,i,t,o);let r=n[0];r&&e.repairman!==r&&(e.repairman.active=!0,e.repairman.x=r.x,e.repairman.y=r.y,e.repairman.target=r.target,e.repairman.repairedToday=r.repairedToday||0)}function ua(e,t,n,o){if(!t.active)return;let r=aa(e,t.target);if((!r||Bt(r)<=.001)&&(t.target?.key&&o.delete(t.target.key),r=da(e,o)),!r){t.target=null;return}let i=or(r);o.add(i),t.target={key:i,label:r.label};let l=Ue.repairman.walkSpeed,c=r.center.x-t.x,b=r.center.y-t.y,C=Math.hypot(c,b);if(C>8){let z=Math.min(C,l*n);t.x+=c/C*z,t.y+=b/C*z;return}let x=e?.cardEffects?.laborExploitation?.7:1,A=n/(Ue.repairman.secondsPerOnePercent*x*100),$=bn(r),B=A*Un(r);ts(r,B);let j=Math.max(0,($-bn(r))/Un(r)*100);t.repairedToday=(t.repairedToday||0)+j,j>0&&Math.random()<.02&&H(e,t.x,t.y-28,"REPAIR",y.green),Bt(r)<=.001&&(o.delete(i),t.target=null)}function da(e,t=new Set){let n=null;for(let o of wn(e)){if(t.has(or(o)))continue;let r=Bt(o);r<=.001||(!n||r>Bt(n))&&(n=o)}return n||ca(e)}function fa(e){let t=0,n="none";for(let o of wn(e)){let r=Bt(o);r>t&&(t=r,n=o.label)}return{ratio:t,percent:Math.round(t*100),label:n}}function rr(e){let t=fa(e),n=Jo(e);return{worst:t,avgBeltPerformance:n,repairman:e.repairman||null,repairmen:e.repairmen||[],rooms:e.maintenanceRooms||[]}}var pa=De.commonWeight,ya=De.rareWeight,ha=De.ultraRareWeight||.45,Lt=De.baseDraftSize,Jt=$r;function Qt(e,t){let n=Le(e);return Math.max(0,Number(n[t])||0)}function Le(e){e.cardEffects||(e.cardEffects={...wo});for(let[t,n]of Object.entries(wo))e.cardEffects[t]==null&&(e.cardEffects[t]=Array.isArray(n)?[]:n);return e.cardEffects.flattery!=null&&(e.cardEffects.fairiesFlatteryNext=Math.max(0,e.cardEffects.fairiesFlatteryNext||0)+Math.max(0,e.cardEffects.flattery||0),delete e.cardEffects.flattery),e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft||(e.cardDraft={pending:!1,choices:[],rerolls:0,picksRemaining:0}),e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardEffects}function ps(e){let t=Math.max(.5,1-.05*Math.min(10,Qt(e,"crowdedFarming"))),n=Math.pow(.96,Qt(e,"hatchingFeed"));return t*n}function ys(e,t=null){return Math.min(3,Math.max(0,Number(t?.extraEggOutlet)||0))}function hs(e){return Math.pow(.85,Qt(e,"scannerQueueSpacing"))}function Xn(e,t=null){let n=Le(e),o=En*Math.pow(Rn,Math.max(0,n.bearing||0)),r=t?Math.max(.1,Number(e?.conveyorMeta?.get?.(t)?.speedMultiplier)||1):1,i=t?1:Jo(e),l=Math.max(.01,Number(e?.eventActive?.conveyorSpeedMultiplier)||1);return Math.min(Kt,o*i)*r*l}function nt(e,t=null){let n=Math.max(0,(e?.level||1)-1),o=t?Qt(t,"autoScannerTuning"):0,r=Tn*Math.pow(Ir,n)*Math.pow(ho,o),i=Math.max(mo,r),l=t?Math.max(.01,Number(t?.eventActive?.autoScannerCooldownMultiplier)||1):1;return t?Math.max(mo,i*qn(e)*l):i}function ss(e){let t=e.cardDraft||{rerolls:0},n=Math.max(1,(t.rerolls||0)+1);return Math.ceil(Math.max(1,e.turn||1)/De.rerollCost.dayDivisor*n*De.rerollCost.multiplier)}function Ot(e){return Jt.find(t=>t.id===e)||null}function ms(e,t){let n=typeof t=="string"?Ot(t):t;return Le(e),!n||!(n.type==="equipmentUpgrade"||n.type==="cellAction")?[]:We(e,n).map(o=>({key:tt(o),label:lr(e,o),type:o.type}))}function sr(e,t,n={}){let o=typeof t=="string"?Ot(t):t;if(Le(e),!o||o.type==="dud")return{ok:!1,reason:"Card not found."};if(o.id==="extraCards")return e.cardDraft=e.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.choices.push(...zn(e,2)),{ok:!0,reason:`${o.title} added 2 draft cards.`};if(o.type==="instant")return vs(e,o),{ok:!0,reason:`${o.title} granted.`};if(o.type==="equipmentUpgrade"){let r=We(e,o);if(!r.length)return{ok:!1,reason:`No valid target for ${o.title}.`};let i=n.targetKey&&n.targetKey!=="__auto__"?String(n.targetKey):"",l=i?r.find(c=>tt(c)===i):r[0];return l?(bs(e,l),{ok:!0,reason:`${o.title} applied to ${lr(e,l)}.`}):{ok:!1,reason:`Selected target is no longer valid for ${o.title}.`}}if(o.type==="cellAction"&&o.target==="blockedCell"){let r=We(e,o);if(!r.length)return{ok:!1,reason:"No blocked cells to remove."};let i=new Set((Array.isArray(n.targetKeys)?n.targetKeys:[n.targetKey]).filter(c=>c&&c!=="__auto__").map(String)),l=i.size?r.filter(c=>i.has(tt(c))):r.slice(0,3);if(!l.length)return{ok:!1,reason:`Selected target is no longer valid for ${o.title}.`};for(let c of l.slice(0,3)){e.blockedCells.delete(I(c.col,c.row));let b=F(c.col,c.row);et(e,b.x,b.y),Xe(e,b.x,b.y,y.danger,42),Ze(e,b.x,b.y,8,y.warn)}return be(e),{ok:!0,reason:`${o.title} removed ${Math.min(3,l.length)} blocked cell(s).`}}return{ok:!1,reason:`${o.title} cannot be debug-granted.`}}function lr(e,t){if(t.type==="blockedCell")return`Blocked cell ${t.col},${t.row}`;if(t.type==="eggFarm")return`EGG #${t.id} L${t.level} -> L${t.level+1}`;if(t.type==="eggOutlet"){let n=Math.max(0,Number(t.farm?.extraEggOutlet)||0);return`EGG #${t.id} OUTLET ${1+n} -> ${2+n}`}if(t.type==="scanner")return`AUTO #${t.id} L${t.level} -> L${t.level+1} | CD ${nt(t,e).toFixed(1)}s -> ${nt({...t,level:t.level+1},e).toFixed(1)}s`;if(t.type==="facility"&&(t.baseId||t.id)==="mixer"){let n=t.level,o=ze(e);t.level=n+1;let r=ze(e);return t.level=n,`MIXER L${t.level} -> L${t.level+1} | ${T(o)} -> ${T(r)}`}if(t.type==="facility"&&(t.baseId||t.id)==="truck"){let n=t.level,o=Fe(e);t.level=n+1;let r=Fe(e);return t.level=n,`TRUCK L${t.level} -> L${t.level+1} | ${T(o)} -> ${T(r)}`}if(t.type==="facility"&&t.id==="trash"){let n=Dt(e),o=Math.min(zt(),n+1),r=ht(n),i=ht(o);return`SHREDDER L${t.level||1} -> L${(t.level||1)+1} | poop income ${T(r)} -> ${T(i)} per item`}return`${t.name||t.id} L${t.level||1} -> L${(t.level||1)+1}`}function ma(e){return[...e.blockedCells||[]].map(t=>{let[n,o]=String(t).split(",").map(Number);return{type:"blockedCell",id:t,col:n,row:o}}).filter(t=>Number.isFinite(t.col)&&Number.isFinite(t.row))}function We(e,t){let n=typeof t=="string"?Ot(t):t;return Le(e),n?n.target==="blockedCell"?ma(e):n.target==="eggFarm"?e.eggFarms.filter(o=>(o.level||1)<4):n.target==="eggOutlet"?e.eggFarms.filter(o=>Math.max(0,Number(o.extraEggOutlet)||0)<3).map(o=>({type:"eggOutlet",id:o.id,col:o.col,row:o.row,farm:o})):n.target==="autoScanner"?e.scanners.filter(o=>o.kind==="auto"):n.target==="mixer"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="mixer"):n.target==="truck"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="truck"):n.target==="trash"?Wo(e)(o.baseId||o.id)==="trash"):[]:[]:[]}function ba(e,t){let n=Le(e);if(t.id==="crowdedFarming")return(n.crowdedFarming||0)>=10;if(t.id==="recyclingSubsidy")return(n.recyclingSubsidy||0)>=3;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,De.dudChancePerCard||0)),r=Math.max(1e-4,Math.min(1,De.dudChanceReductionPerFilter||.05));return(n.dudFilter||0)>=Math.ceil(o/r)}return t.id==="laborExploitation"?!!n.laborExploitation:t.id==="usedMachine"?!!n.usedMachineActive:t.id==="newMachine"?!n.usedMachineActive:!1}function va(e){return!!((e.maintenanceRooms||[]).length||(e.repairmen||[]).length||e.repairman?.active)}function wa(e){return Jt.filter(t=>!(t.id==="laborExploitation"&&!va(e)||ba(e,t)||(t.type==="equipmentUpgrade"||t.type==="cellAction")&&We(e,t).length<=0))}function ls(e,t){return t.rarity==="ultraRare"?ha:t.rarity==="rare"?ya:pa}function Sa(e,t){let n=t.reduce((r,i)=>r+ls(e,i),0);if(n<=0)return t[Math.floor(Math.random()*t.length)];let o=Math.random()*n;for(let r of t)if(o-=ls(e,r),o<=0)return r;return t[t.length-1]}var as=0;function ka(){return as+=1,{id:`dud:${Date.now()}:${as}`,title:"Dud",rarity:"dud",type:"dud",description:"Click to flick this dud away. It does not consume a pick."}}function Ca(e){let t=Le(e),n=Math.max(0,Math.min(1,De.dudChancePerCard||0)),o=Math.max(0,Math.min(1,De.dudChanceReductionPerFilter||0));return Math.max(0,n-o*Math.max(0,t.dudFilter||0))}function Ma(e,t){let n=[...t],o=0,r=Math.max(0,De.maxDudsPerDraft||0),i=Ca(e);for(let l=0;lc.id===i.id);l>=0&&r.splice(l,1)}return Ma(e,o)}function tt(e){return e?e.type==="blockedCell"?`blockedCell:${e.id}`:e.type==="eggFarm"?`eggFarm:${e.id}`:e.type==="eggOutlet"?`eggOutlet:${e.id}`:e.type==="scanner"?`scanner:${e.id}`:e.type==="facility"?`facility:${e.id}`:`${e.type}:${e.id}`:""}function cs(e){if(!e)return null;if(e.type==="blockedCell"){let t=F(e.col,e.row);return{x:t.x-f.cell*.48,y:t.y-f.cell*.48,w:f.cell*.96,h:f.cell*.96,cx:t.x,cy:t.y}}if(e.type==="eggFarm"||e.type==="eggOutlet"){let t=F(e.col,e.row);return{x:t.x-34,y:t.y-34,w:68,h:68,cx:t.x,cy:t.y}}if(e.type==="scanner"){let t=ye(e);return{x:t.x-54,y:t.y-77,w:108,h:154,cx:t.x,cy:t.y}}return e.type==="facility"?{x:e.x,y:e.y,w:e.w,h:e.h,cx:e.x+e.w/2,cy:e.y+e.h/2}:null}function ar(e){if(!e.cardTargetPick?.pending)return[];if(e.cardTargetPick.mode==="autoScannerMenu"){let n=new Set(e.cardTargetPick.targetKeys||[]);return e.scanners.filter(o=>o.kind==="auto"&&n.has(tt(o))).map(o=>({key:tt(o),label:"AUTO ROUTE SETTINGS",target:o,bounds:cs(o)})).filter(o=>o.bounds)}let t=new Set(e.cardTargetPick.targetKeys||[]);return We(e,e.cardTargetPick.cardId).filter(n=>t.has(tt(n))).map(n=>({key:tt(n),label:lr(e,n),target:n,bounds:cs(n)})).filter(n=>n.bounds)}function ga(e,t){let n=ar(e);for(let o of n){let r=o.bounds;if(t.x>=r.x&&t.x<=r.x+r.w&&t.y>=r.y&&t.y<=r.y+r.h)return o.target}return null}function bs(e,t){if(t.type==="eggOutlet"){let n=t.farm||e.eggFarms.find(r=>r.id===t.id);if(!n)return;n.extraEggOutlet=Math.min(3,Math.max(0,Number(n.extraEggOutlet)||0)+1);let o=F(n.col,n.row);H(e,o.x,o.y-30,`OUTLET ${1+n.extraEggOutlet}`,y.green),be(e);return}if(t.level=(t.level||1)+1,t.type==="eggFarm"){t.nextSpawn=Rt(t),t.lastInterval=t.nextSpawn;let n=F(t.col,t.row);H(e,n.x,n.y-30,`LV ${t.level}`,y.green);return}if(t.type==="scanner"){let n=ye(t);H(e,n.x,n.y-34,`LV ${t.level}`,y.green);return}t.type==="facility"&&H(e,t.x+t.w/2,t.y+18,`LV ${t.level}`,y.green)}function vs(e,t){let n=Le(e),o=r=>{n[r]=Math.max(0,n[r]||0)+1};if(t.id==="bearing"&&o("bearing"),t.id==="autoScannerTuning"&&o("autoScannerTuning"),t.id==="legalWork"&&o("legalWork"),t.id==="crowdedFarming"&&(n.crowdedFarming=Math.min(10,(n.crowdedFarming||0)+1)),t.id==="hatchingFeed"&&o("hatchingFeed"),t.id==="poopRateBooster"&&o("poopRateBooster"),t.id==="safetyCover"&&o("safetyCover"),t.id==="recyclingSubsidy"&&(n.recyclingSubsidy=Math.min(3,(n.recyclingSubsidy||0)+1)),t.id==="chemicalWeaponSubsidy"&&o("chemicalWeaponSubsidy"),t.id==="preventiveMaintenance"&&o("preventiveMaintenance"),t.id==="dudFilter"&&o("dudFilter"),t.id==="durabilityCoating"&&(o("durabilityCoating"),Se(e)),t.id==="sparePartsBin"){o("sparePartsBin");let r=ns(e,.02);e.stats.sparePartsRepair=(e.stats.sparePartsRepair||0)+r,e.totals.sparePartsRepair=(e.totals.sparePartsRepair||0)+r,H(e,f.x+f.cols*f.cell/2,f.y-30,"REPAIR +2%",y.green)}t.id==="dudRefund"&&o("dudRefund"),t.id==="freeReroll"&&o("freeReroll"),t.id==="composter"&&o("composter"),t.id==="scannerQueueSpacing"&&o("scannerQueueSpacing"),t.id==="flattery"&&o("fairiesFlatteryNext"),t.id==="usedMachine"&&(n.usedMachineActive=!0),t.id==="newMachine"&&(n.usedMachineActive=!1),t.id==="laborExploitation"&&(n.laborExploitation=1),t.id==="rescueLoan"&&(o("rescueLoanCharges"),H(e,f.x+f.cols*f.cell/2,f.y-30,"RESCUE HELD",y.green))}function qe(e){return`${Math.round(Number(e||0)*100)}%`}function us(e){let t=st[Math.max(0,Math.min(st.length-1,e-1))]||st[0]||[0,0];return`${t[0].toFixed(2)}-${t[1].toFixed(2)}s`}function ds(e,t){return Math.ceil(e*Math.pow(ke.incomeUpgradeRate,Math.max(0,t-1)))}function fs(e,t,n){let r=We(e,t==="mixer"?"upgradeMixer":"upgradeTruck")[0];if(!r)return{before:ds(n,1),after:ds(n,2)};let i=t==="mixer"?ze(e):Fe(e),l=r.level||1;r.level=l+1;let c=t==="mixer"?ze(e):Fe(e);return r.level=l,{before:i,after:c}}function xa(e,t){let n=Le(e);if(t.id==="upgradeEgg"){let o=We(e,t),r=Math.min(3,Math.max(1,o[0]?.level||1));return`Choose one EGG. Level +1. Production interval ${us(r)} -> ${us(r+1)}.`}if(t.id==="upgradeAutoScanner"){let o=We(e,t)[0]||{level:1},r=nt(o,e),i=nt({...o,level:(o.level||1)+1},e);return`Choose one AUTO SCANNER. Level +1. Cooldown ${r.toFixed(2)}s -> ${i.toFixed(2)}s.`}if(t.id==="upgradeMixer"){let o=fs(e,"mixer",ke.income.mixer);return`Choose one MIXER. Earning +10%. Male-chick income ${T(o.before)} -> ${T(o.after)}.`}if(t.id==="upgradeTruck"){let o=fs(e,"truck",ke.income.truck);return`Choose one TRUCK. Earning +10%. Correct shipment income ${T(o.before)} -> ${T(o.after)}.`}if(t.id==="upgradeTrash"){let o=Dt(e),r=Math.min(zt(),o+1),i=ht(o),l=ht(r);return`SHREDDER level +1. Poop income ${T(i)} -> ${T(l)} per item.`}if(t.id==="bearing"){let o=Math.min(Kt,En*Math.pow(Rn,Math.max(0,n.bearing||0))),r=Math.min(Kt,En*Math.pow(Rn,Math.max(0,(n.bearing||0)+1)));return`Conveyor speed +7.5%. After pick: ${o.toFixed(1)} -> ${r.toFixed(1)} px/s.`}if(t.id==="legalWork"){let o=Math.max(0,n.legalWork||0);return`Fairies tribute profit exemption +${T(250)}. After pick: exemption bonus ${T(250*(o+1))}.`}if(t.id==="crowdedFarming"){let o=Math.min(10,(n.crowdedFarming||0)+1);return`Held ${n.crowdedFarming||0}/10. After pick: EGG interval ${qe(Math.max(.5,1-.05*o))}, deterioration ${qe(Math.min(1.4,1+.04*o))}.`}if(t.id==="extraEggOutlet"){let o=We(e,t),r=Math.max(0,Number(o[0]?.farm?.extraEggOutlet)||0);return`Choose one EGG. Output ports ${1+r} -> ${2+r}. Max 4 ports per EGG.`}if(t.id==="hatchingFeed")return`Held ${n.hatchingFeed||0}. After pick: EGG interval ${qe(Math.pow(.96,(n.hatchingFeed||0)+1))}, poop rate multiplier ${qe(Math.pow(1.03,(n.hatchingFeed||0)+1))}.`;if(t.id==="poopRateBooster")return`Held ${n.poopRateBooster||0}. After pick: base poop rate +${Math.round((n.poopRateBooster||0)+1)*4} percentage points.`;if(t.id==="autoScannerTuning")return`Held ${n.autoScannerTuning||0}. After pick: all AUTO SCANNER default cooldown ${qe(Math.pow(ho,(n.autoScannerTuning||0)+1))}.`;if(t.id==="safetyCover")return`Held ${n.safetyCover||0}. After pick: explosion damage ${qe(Math.pow(.95,(n.safetyCover||0)+1))}.`;if(t.id==="recyclingSubsidy")return`Held ${n.recyclingSubsidy||0}/3. After pick: normal SELL refund ${Math.round(Math.min(.8,.5+.1*((n.recyclingSubsidy||0)+1))*100)}%.`;if(t.id==="chemicalWeaponSubsidy")return`Held ${n.chemicalWeaponSubsidy||0}. After pick: ${T(1200*((n.chemicalWeaponSubsidy||0)+1))} per 70 truck-shipped poop each day.`;if(t.id==="preventiveMaintenance")return`Held ${n.preventiveMaintenance||0}. After pick: deterioration speed ${qe(Math.pow(.95,(n.preventiveMaintenance||0)+1))}.`;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,De.dudChancePerCard||0)),r=Math.max(0,Math.min(1,De.dudChanceReductionPerFilter||.05)),i=Math.max(0,n.dudFilter||0),l=Math.max(0,o-r*i),c=Math.max(0,o-r*(i+1));return`Held ${i}. DUD chance per card ${qe(l)} -> ${qe(c)}.`}return t.id==="durabilityCoating"?`Held ${n.durabilityCoating||0}. After pick: maximum durability ${qe(Math.pow(1.03,(n.durabilityCoating||0)+1))}.`:t.id==="sparePartsBin"?`Held ${n.sparePartsBin||0}. Immediately restores 2% durability to every maintained machine. Common card weight.`:t.id==="dudRefund"?`Held ${n.dudRefund||0}. After pick: DUD clicks award ${T(50*((n.dudRefund||0)+1))}.`:t.id==="freeReroll"?`Held ${n.freeReroll||0}. After pick: each card screen starts with ${(n.freeReroll||0)+1} free reroll${(n.freeReroll||0)+1===1?"":"s"}.`:t.id==="composter"?`Held ${n.composter||0}. After pick: SHREDDER poop grants ${T(3*((n.composter||0)+1))}.`:t.id==="scannerQueueSpacing"?`Held ${n.scannerQueueSpacing||0}. After pick: Manual/Auto Scanner queue spacing ${qe(Math.pow(.85,(n.scannerQueueSpacing||0)+1))}.`:t.id==="flattery"?`Next Fairies tribute -50%. Held for next tribute: ${n.fairiesFlatteryNext||0}.`:t.id==="usedMachine"?"Enable Used Machines: future equipment costs 50%, has no SELL refund, and starts with 60% durability.":t.id==="newMachine"?"Cancel Used Machines. Future equipment returns to normal price, refund, and durability.":t.id==="laborExploitation"?"Repairman dispatch paperwork is streamlined. Repair rooms keep operating; one time only.":t.id==="rescueLoan"?`At day-end bankruptcy check, gain ${T(500)} if cash is below ${T(0)}. Held: ${n.rescueLoanCharges||0}.`:t.id==="dynamite"?"Choose any blocked tiles on the map and destroy up to 3. Empty-space clicks are ignored; press Esc to finish after at least one blast.":t.description}function ir(e,t){let n=e.cardDraft?.choices||[],o=n.findIndex(r=>r.id===t.id);o>=0&&n.splice(o,1)}function ws({game:e,ui:t,onUpdatePanels:n}){function o(){n&&n()}function r(){Le(e),e.cardTargetPick=null,e.cardDraft={pending:!0,choices:zn(e,Lt),rerolls:0,freeRerolls:Qt(e,"freeReroll"),picksRemaining:1}}function i(){Le(e),e.cardDraft.pending=!1,e.cardDraft.choices=[],e.cardDraft.picksRemaining=0,e.cardTargetPick=null,t.modal.classList.remove("visible","equipment-popover"),o()}function l(R=Lt){Le(e),e.cardDraft.choices=zn(e,R)}function c(){Le(e),!e.cardDraft.choices.length&&e.cardDraft.picksRemaining>0&&l(Lt)}function b(R){ir(e,R),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1),e.cardTargetPick=null,c(),e.cardDraft.picksRemaining<=0?i():se()}function C(R){ir(e,R),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1)+De.extraCardsAddedPicks,e.cardDraft.choices.push(...zn(e,2)),se()}function x(R,_){let Y=Qt(e,"dudRefund")*50;if(Y>0){let O=Ge(e,Y);e.stats.dudRefundIncome=(e.stats.dudRefundIncome||0)+O,e.totals.dudRefundIncome=(e.totals.dudRefundIncome||0)+O,H(e,f.x+f.cols*f.cell/2,f.y-30,`DUD REFUND +${T(O)}`,y.green)}Ft(e,34,.62),document.body?.animate&&document.body.animate([{transform:"translate(0, 0)"},{transform:"translate(-10px, 7px)"},{transform:"translate(12px, -8px)"},{transform:"translate(-8px, -5px)"},{transform:"translate(9px, 6px)"},{transform:"translate(0, 0)"}],{duration:260,easing:"steps(5, end)"}),_&&(_.style.setProperty("--fling-x",`${260+Math.random()*260}px`),_.style.setProperty("--fling-y",`${-260-Math.random()*170}px`),_.style.setProperty("--fling-r",`${(Math.random()<.5?-1:1)*(52+Math.random()*38)}deg`),_.classList.add("flung")),window.setTimeout(()=>{ir(e,R),c(),se()},340)}function A(R,_=null){if(R.type==="dud")return x(R,_);if(R.id==="extraCards")return C(R);if(R.type==="equipmentUpgrade"||R.type==="cellAction")return $(R);vs(e,R),b(R)}function $(R){let _=We(e,R);_.length&&(e.cardTargetPick={pending:!0,cardId:R.id,mode:R.target==="blockedCell"?"blockedCell":"equipment",targetKeys:_.map(tt),remaining:R.id==="dynamite"?Math.min(3,_.length):1,used:0},t.modal.classList.remove("visible","equipment-popover"),o())}function B(R){if(!R||R.type!=="blockedCell")return!1;let _=I(R.col,R.row);if(!e.blockedCells?.has(_))return!1;e.blockedCells.delete(_);let Y=F(R.col,R.row);return et(e,Y.x,Y.y),Xe(e,Y.x,Y.y,y.danger,62),Ze(e,Y.x,Y.y,18,y.warn),Gn(e,Y.x,Y.y,8),Ft(e,16,.35),H(e,Y.x,Y.y-18,"BOOM",y.danger),be(e),e.cardTargetPick.remaining=Math.max(0,(e.cardTargetPick.remaining||1)-1),e.cardTargetPick.used=Math.max(0,e.cardTargetPick.used||0)+1,e.cardTargetPick.targetKeys=We(e,"dynamite").map(tt),o(),!0}function j(R){if(!e.cardTargetPick?.pending)return!1;let _=Ot(e.cardTargetPick.cardId),Y=ga(e,R);return _?_.id==="dynamite"?(!Y||!B(Y)||((e.cardTargetPick.remaining||0)<=0||!We(e,"dynamite").length)&&b(_),!0):Y?(bs(e,Y),b(_),!0):(z(),!0):(z(),!0)}function z(){if(!e.cardTargetPick?.pending)return;let R=e.cardTargetPick,_=Ot(R.cardId);if(_?.id==="dynamite"&&(R.used||0)>0){b(_);return}e.cardTargetPick=null,se()}function ce(){let R=Math.max(0,e.cardDraft?.freeRerolls||0);if(R>0){e.cardDraft.freeRerolls=R-1,e.cardDraft.rerolls+=1,l(Lt),se();return}let _=ss(e);e.cash<_||(bt(e,_),e.stats.cardRerollCost=(e.stats.cardRerollCost||0)+_,e.totals.cardRerollCost=(e.totals.cardRerollCost||0)+_,e.cardDraft.rerolls+=1,l(Lt),se())}function he(R){let _=new Set(R.tags||[]),Y={eggFarm:{type:"image",src:"./assets/dark_factory/facilities/machines/egg_farm_16.png",alt:"EGG"},eggOutlet:{type:"image",src:"./assets/dark_factory/facilities/machines/egg_farm_16.png",alt:"EGG"},autoScanner:{type:"image",src:"./assets/dark_factory/facilities/machines/auto_scanner_32x48.png",alt:"SCAN"},mixer:{type:"image",src:"./assets/dark_factory/facilities/machines/mixer_compact_16.png",alt:"MIX"},truck:{type:"image",src:"./assets/dark_factory/facilities/vehicles/truck_compact_16.png",alt:"TRUCK"},trash:{type:"image",src:"./assets/dark_factory/facilities/machines/shredder_compact_16.png",alt:"SHR"},blockedCell:{type:"image",src:"./assets/dark_factory/facilities/utility/obstacle_crate_16.png",alt:"BLOCK"}};return Y[R.target]?Y[R.target]:R.id==="bearing"||_.has("CONVEYOR")?{type:"image",src:"./assets/dark_factory/facilities/conveyor/conveyor_straight_h_16.png",alt:"BELT"}:_.has("SCANNER")?{type:"image",src:"./assets/dark_factory/facilities/machines/auto_scanner_32x48.png",alt:"SCAN"}:_.has("EGG")?{type:"image",src:"./assets/dark_factory/facilities/machines/egg_farm_16.png",alt:"EGG"}:_.has("POOP")?{type:"glyph",text:"\u{1F4A9}"}:_.has("MAINTENANCE")?{type:"image",src:"./assets/dark_factory/facilities/utility/repairman_16.png",alt:"FIX"}:_.has("CARD")?{type:"glyph",text:"\u25A3"}:_.has("ECONOMY")?{type:"glyph",text:"\uFFE5"}:_.has("RISK")?{type:"glyph",text:"!"}:{type:"glyph",text:"\u25C6"}}function ie(R){let _=he(R);return _.type==="image"?`
${_.alt||
`:``}function le(R,_){let Y=document.createElement("button");Y.type="button";let O=R.type==="dud"?"dud":R.rarity==="ultraRare"?"ultra-rare":R.rarity==="rare"?"rare":"common";Y.className=`card-choice ${O}`;let W=R.type==="dud"?"MISS":R.rarity==="ultraRare"?"ULTRA RARE":R.rarity==="rare"?"RARE":"COMMON",U=[W,...(R.tags||[]).filter(M=>M!==W)].slice(0,5);return Y.innerHTML=`${ie(R)}
${R.title}
${U.map(M=>`${M}`).join("")}
${xa(e,R)}
`,Y.addEventListener("click",()=>A(R,Y)),Y.dataset.index=String(_),Y}function se(){Le(e),e.cardTargetPick=null,e.cardDraft?.pending||r(),e.cardDraft.choices?.length||l(Lt);let R=e.cardDraft.choices||[],_=ss(e),Y=Math.max(0,e.cardDraft?.freeRerolls||0),O=Math.max(1,e.cardDraft.picksRemaining||1);t.modalTitle.textContent="Choose Upgrade Card",t.modalBody.innerHTML=`

Choose ${O} card${O===1?"":"s"} before Build phase. Dud cards can be flicked away without consuming a pick. Equipment cards target machines; Dynamite targets blocked cells.

`;let W=t.modalBody.querySelector("#cardChoices");R.forEach((g,G)=>W.appendChild(le(g,G))),t.modalActions.innerHTML="";let U=document.createElement("button");U.type="button",U.className="facility-action warn reroll-button",U.textContent=Y>0?`Reroll (FREE x${Y})`:`Reroll ${T(_)}`,U.disabled=Y<=0&&e.cash<_,U.title=Y>0?`${Y} free reroll${Y===1?"":"s"} remaining.`:U.disabled?"Not enough cash":"",U.addEventListener("click",ce),t.modalActions.appendChild(U);let M=document.createElement("button");M.type="button",M.className="facility-action",M.textContent="No Card",M.title="Skip this upgrade pick and enter Build phase.",M.addEventListener("click",i),t.modalActions.appendChild(M),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible")}return{prepareDraft:r,showDraft:se,finishDraft:i,chooseTargetAtPoint:j,cancelTargetPick:z}}var Ta=!0,Ea={chickMale:"./assets/images/chick_male.png",chickFemale:"./assets/images/chick_female.png",poop:"./assets/images/poop.png",conveyorStraightH:"./assets/dark_factory/facilities/conveyor/conveyor_straight_h_16.png",conveyorStraightV:"./assets/dark_factory/facilities/conveyor/conveyor_straight_v_16.png",conveyorTurnNe:"./assets/dark_factory/facilities/conveyor/conveyor_turn_ne_16.png",conveyorTurnNw:"./assets/dark_factory/facilities/conveyor/conveyor_turn_nw_16.png",conveyorTurnSe:"./assets/dark_factory/facilities/conveyor/conveyor_turn_se_16.png",conveyorTurnSw:"./assets/dark_factory/facilities/conveyor/conveyor_turn_sw_16.png",boostConveyorStraightH:"./assets/dark_factory/facilities/conveyor/boost_conveyor_straight_h_16.png",boostConveyorStraightV:"./assets/dark_factory/facilities/conveyor/boost_conveyor_straight_v_16.png",boostConveyorTurnNe:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_ne_16.png",boostConveyorTurnNw:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_nw_16.png",boostConveyorTurnSe:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_se_16.png",boostConveyorTurnSw:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_sw_16.png",scannerManual:"./assets/dark_factory/facilities/machines/manual_scanner_32x48.png",scannerAuto:"./assets/dark_factory/facilities/machines/auto_scanner_32x48.png",eggFarm:"./assets/dark_factory/facilities/machines/egg_farm_16.png",mixer:"./assets/dark_factory/facilities/machines/mixer_32.png",shredder:"./assets/dark_factory/facilities/machines/shredder_32.png",truck:"./assets/dark_factory/facilities/vehicles/truck_32.png",mixerCompact:"./assets/dark_factory/facilities/machines/mixer_compact_16.png",shredderCompact:"./assets/dark_factory/facilities/machines/shredder_compact_16.png",truckCompact:"./assets/dark_factory/facilities/vehicles/truck_compact_16.png",maintenanceRoom:"./assets/dark_factory/facilities/utility/maintenance_room_32.png",repairman:"./assets/dark_factory/facilities/utility/repairman_16.png",obstacleCrate:"./assets/dark_factory/facilities/utility/obstacle_crate_16.png"},ue={};for(let[e,t]of Object.entries(Ea)){let n=new Image;n.loaded=!1,n.onerror=()=>{n.loaded=!1},Ta&&t&&(n.onload=()=>{n.loaded=!0},n.src=t),ue[e]=n}function Cs(e,t,n,o){e.imageSmoothingEnabled=!1,e.clearRect(0,0,t.width,t.height),$a(e,t),e.save();let r=n.shake.time>0?K(-n.shake.strength,n.shake.strength):0,i=n.shake.time>0?K(-n.shake.strength,n.shake.strength):0,l=n.view?.scale||1;e.translate((n.view?.x||0)+r,(n.view?.y||0)+i),e.scale(l,l),Ba(e,n),La(e,n),Na(e,n),Xa(e,n),oc(e,n),rc(e,n),Qa(e,n),ja(e,n),Pa(e,n),ac(e,n,o.activeQueuedChick),bc(e,n),pc(e,t,n),fc(e,n,o.selectedObject,o.selectedTitle),yc(e,n),hc(e,n),mc(e,n),e.restore(),wc(e,n,t)}function Ra(e){if(e.type==="eggFarm"){let n=F(e.ref.col,e.ref.row);return{x:n.x-34,y:n.y-34,w:68,h:68,cx:n.x,cy:n.y}}let t=e.ref;return{x:t.x,y:t.y,w:t.w,h:t.h,cx:t.x+t.w/2,cy:t.y+t.h/2}}function Pa(e,t){if(t.phase!=="build")return;let n=On(t);for(let o of n){let r=Ra(o);e.save(),e.fillStyle="rgba(196,36,36,.22)",e.strokeStyle=y.danger,e.lineWidth=5,e.setLineDash([10,6]),ee(e,r.x,r.y,r.w,r.h,!0,!0),e.setLineDash([]),e.fillStyle=y.danger,e.strokeStyle=y.white,e.lineWidth=4,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.strokeText("!",r.cx,r.y+24),e.fillText("!",r.cx,r.y+24),e.font="900 11px ui-monospace, monospace",e.strokeText("NO ROUTE",r.cx,r.y+r.h-8),e.fillText("NO ROUTE",r.cx,r.y+r.h-8),e.restore()}}function ee(e,t,n,o,r,i=!0,l=!0){e.beginPath(),e.rect(t,n,o,r),i&&e.fill(),l&&e.stroke()}function ur(e,t,n,o,r=y.ink){e.save(),e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.lineWidth=4,e.strokeStyle=y.white,e.fillStyle=r,e.strokeText(o,t,n),e.fillText(o,t,n),e.restore()}function vt(e,t,n,o,r,i){if(!t?.loaded)return!1;let l=e.imageSmoothingEnabled;return e.imageSmoothingEnabled=!1,e.drawImage(t,Math.round(n),Math.round(o),Math.round(r),Math.round(i)),e.imageSmoothingEnabled=l,!0}function Aa(e,t,n,o,r,i,l=null,c=1){e.fillStyle=i,e.fillRect(Math.round(t),Math.round(n),Math.round(o),Math.round(r)),l&&(e.strokeStyle=l,e.lineWidth=c,e.strokeRect(Math.round(t)+.5,Math.round(n)+.5,Math.round(o)-1,Math.round(r)-1))}function Ia(e,t){let n=(Math.imul(e+37,73856093)^Math.imul(t+71,19349663))>>>0;return n^=n>>>13,n>>>0}function Da(e,t,n,o,r){let i=Ia(o,r);if(i%31!==0)return;let l=10+(i>>>4)%Math.max(1,f.cell-22),c=10+(i>>>9)%Math.max(1,f.cell-22),b=(i>>>14)%16*Math.PI/16;e.save(),e.globalAlpha=.46,e.fillStyle="#4d9638",e.strokeStyle="rgba(30,66,27,.48)",e.lineWidth=1,e.beginPath();for(let x=0;x<8;x+=1){let A=b+x*Math.PI/4,$=3.5+(i>>>x+2&3),B=t+l+Math.cos(A)*$*1.35,j=n+c+Math.sin(A)*$*.75;x===0?e.moveTo(B,j):e.lineTo(B,j)}e.closePath(),e.fill(),e.stroke();let C=3+(i>>>24)%4;for(let x=0;x>>x+8&3)*.18,$=8+(i>>>x+11&7),B=1.1+(i>>>x+17&3)*.45;e.beginPath(),e.arc(t+l+Math.cos(A)*$,n+c+Math.sin(A)*$*.72,B,0,Math.PI*2),e.fill()}e.fillStyle="rgba(151,218,101,.40)",e.beginPath(),e.arc(t+l-2,n+c-2,1.7,0,Math.PI*2),e.fill(),e.restore()}function $a(e,t){e.fillStyle=y.bg,e.fillRect(0,0,t.width,t.height),e.save(),e.globalAlpha=.85;for(let n=0;n=n;for(let r of Tt(t)){let i=Et(r);e.save(),e.fillStyle=o?"rgba(183,245,198,.34)":"rgba(255,255,255,.22)",e.strokeStyle=o?y.green:y.muted,e.lineWidth=5,e.setLineDash([16,10]),ee(e,i.x,i.y,i.w,i.h,!0,!0),e.setLineDash([]);let l=Mo(r),c=l.cx,b=l.cy;e.fillStyle="rgba(255,255,255,.94)",e.strokeStyle=y.ink,e.lineWidth=4,ee(e,l.x,l.y,l.w,l.h,!0,!0),e.fillStyle=o?y.green:y.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText(r.direction==="right"?"BUY RIGHT LOT":"BUY UPPER LOT",c,b-12),e.fillStyle=y.ink,e.font="900 16px ui-monospace, monospace",e.fillText(`${T(n)} / 10\xD710`,c,b+15),e.fillStyle=y.muted,e.font="900 11px ui-monospace, monospace",e.fillText("blocked tiles included",c,b+30),e.restore()}}function ot(e,t,n,o,r,i,l=0){let c=Xt(i);c<.5||(e.save(),e.globalAlpha=Math.min(.62,.12+c*.54),e.fillStyle="#6b4a23",l>0?(e.beginPath(),e.roundRect?.(t,n,o,r,l),e.roundRect?e.fill():ee(e,t,n,o,r,!0,!1)):ee(e,t,n,o,r,!0,!1),e.globalAlpha=Math.min(.9,.25+c*.6),e.strokeStyle="#3a2a16",e.lineWidth=Math.max(2,Math.floor(2+c*5)),e.setLineDash([5,6]),ee(e,t+3,n+3,o-6,r-6,!1,!0),e.restore())}function cr(e,t){let n=e.componentLookup?.get(t);return(n?e.congestion.get(n):null)?.ratio||0}function Oa(e,t,n={}){let o=kn(e,t).sort(),i=n.kind==="boostConveyor"?"boostConveyor":"conveyor",l=c=>o.includes(c);if(o.length===2){if(l("left")&&l("right"))return ue[`${i}StraightH`];if(l("up")&&l("down"))return ue[`${i}StraightV`];if(l("up")&&l("right"))return ue[`${i}TurnNe`];if(l("up")&&l("left"))return ue[`${i}TurnNw`];if(l("down")&&l("right"))return ue[`${i}TurnSe`];if(l("down")&&l("left"))return ue[`${i}TurnSw`]}return o.length===1?l("up")||l("down")?ue[`${i}StraightV`]:ue[`${i}StraightH`]:l("up")||l("down")?ue[`${i}StraightV`]:ue[`${i}StraightH`]}function Na(e,t){let n=[],o=new Set;for(let i of t.conveyorTiles){let{col:l,row:c}=te(i);for(let b of de){let C={col:l+b.dc,row:c+b.dr},x=I(C.col,C.row);if(!t.conveyorTiles.has(x))continue;let A=[i,x].sort().join("|");if(o.has(A))continue;o.add(A);let $=Math.max(cr(t,i),cr(t,x));n.push({a:F(l,c),b:F(C.col,C.row),ratio:$})}}e.save(),e.lineCap="round",e.lineJoin="round";for(let i of[{width:31,color:"#0b0c0f",alpha:1},{width:23,color:"#444b56",alpha:1},{width:15,color:"#171a1f",alpha:1}]){e.globalAlpha=i.alpha,e.strokeStyle=i.color,e.lineWidth=i.width;for(let l of n)e.beginPath(),e.moveTo(l.a.x,l.a.y),e.lineTo(l.b.x,l.b.y),e.stroke()}for(let i of n){let l=Math.max(0,(i.ratio-.5)/.5);e.strokeStyle=Ht(y.green,y.danger,l),e.globalAlpha=i.ratio>.5?.35+l*.55:.8,e.lineWidth=6,e.beginPath(),e.moveTo(i.a.x,i.a.y),e.lineTo(i.b.x,i.b.y),e.stroke()}let r=Ya(t);for(let i of t.conveyorTiles){let l=F(...Object.values(te(i))),c=t.conveyorMeta.get(i)||{},b=cr(t,i),C=Oa(t,i,c),x=b>.5;if(e.fillStyle=x?"rgba(196,36,36,.28)":"rgba(0,0,0,.35)",e.strokeStyle=x?y.danger:"rgba(255,184,39,.34)",e.lineWidth=x?3:1,ee(e,l.x-20,l.y-20,40,40,!0,!0),!vt(e,C,l.x-19,l.y-19,38,38)){let $=c.kind==="boostConveyor"?"#315e92":"#454b55";e.fillStyle=b>.5?Ht($,"#a12c2c",Math.max(0,(b-.5)/.5)):$,e.strokeStyle=y.ink,e.lineWidth=2,ee(e,l.x-18,l.y-18,36,36,!0,!0)}_a(e,l,i,c,b),ot(e,l.x-18,l.y-18,36,36,{meta:c}),rt(e,t,"conveyor",i,l.x,l.y,38,38),Va(e,l,r.get(i)||[]);let A=kn(t,i);Ha(e,l,c,Wa(t,i,A),A),b>.5&&ur(e,l.x,l.y-15,`${Math.floor(b*100)}%`,y.danger)}e.restore()}function _a(e,t,n,o={},r=0){let l=[...new Set([...Array.isArray(o.outDirs)?o.outDirs:[],o.dir].filter(Boolean))][0]||"right",c=l==="up"||l==="down",b=l==="left"||l==="up",C=o.kind==="boostConveyor",x=typeof performance<"u"?performance.now()/(C?70:105):0,A=((b?-x:x)%10+10)%10;e.save(),e.beginPath(),e.rect(t.x-18,t.y-18,36,36),e.clip();let $=C?"rgba(20,126,124,.62)":"rgba(42,47,54,.72)";if(e.fillStyle=$,e.fillRect(t.x-18,t.y-18,36,36),e.strokeStyle=r>.5?"rgba(238,83,61,.90)":"rgba(184,190,198,.92)",e.lineWidth=4,c)for(let B=t.y-28+A;Be.conveyorTiles.has(I(n.col+o.dc,n.row+o.dr))).map(o=>o.name)}function Ga(e,t,n){let o=de.find(l=>l.name===n);if(!o)return!1;let r=e.conveyorMeta?.get?.(I(t.col+o.dc,t.row+o.dr));return r?[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))].includes(o.opposite):!1}function Ms(e,t,n,o=kn(e,t)){if(o.length<3)return n;let r=te(t),i=new Set(o.filter(b=>Ga(e,r,b))),l=o.filter(b=>!i.has(b));if(i.size&&l.length>=2)return l;let c=n.filter(b=>o.includes(b));return c.length>=2?[...new Set(c)]:o}function Ua(e,t,n,o=kn(e,t),r="random"){let i=Ms(e,t,n,o);return o.length>=3&&r&&r!=="random"&&i.includes(r)?[r]:i}function Wa(e,t,n=kn(e,t)){let o=e.conveyorMeta?.get?.(t)||{},r=[...new Set([...Array.isArray(o.outDirs)?o.outDirs:[],o.dir].filter(Boolean))];return n.length<3?[]:Ms(e,t,r,n)}function Ka(e,t,n){let o=te(t),r=de.filter(c=>e.conveyorTiles.has(I(o.col+c.dc,o.row+c.dr))).map(c=>c.name),i=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(c=>r.includes(c)),l=r;return i.length?i:l}function Ha(e,t,n,o,r=o){if(r.length<3||o.length<2)return;e.save();let i=o.includes(n.branchMode)?n.branchMode:"random",l=i!=="random";if(e.lineJoin="round",e.lineCap="round",e.lineWidth=2,e.fillStyle="rgba(18,21,26,.94)",e.strokeStyle=l?y.warn:y.green,e.lineWidth=4,ee(e,t.x-18,t.y-18,36,36,!0,!0),e.strokeStyle="#ffd36a",e.lineWidth=3,e.fillStyle="#020304",i!=="random"){let c=de.find(b=>b.name===i);Sn(e,t.x,t.y,c?.angle||0,9,6)}else e.beginPath(),e.moveTo(t.x-10,t.y),e.lineTo(t.x-2,t.y),e.lineTo(t.x+8,t.y-8),e.moveTo(t.x-2,t.y),e.lineTo(t.x+8,t.y+8),e.stroke(),Sn(e,t.x+9,t.y-9,-Math.PI/4,4,3),Sn(e,t.x+9,t.y+9,Math.PI/4,4,3);e.restore()}function qa(e,t,n){if(!n)return[];let o=te(t),r=de.filter(c=>e.conveyorTiles.has(I(o.col+c.dc,o.row+c.dr))).map(c=>c.name),i=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(c=>r.includes(c));return Ua(e,t,i.length?i:Ka(e,t,n),r,n.branchMode||"random").map(c=>de.find(b=>b.name===c)).filter(Boolean)}function Ya(e){let t=new Map;for(let[n,o]of e.conveyorMeta||[]){let r=qa(e,n,o);r.length&&t.set(n,r)}return t}function Va(e,t,n){let o=n.slice(0,4);o.length&&(e.save(),e.globalAlpha=1,o.forEach(r=>{let i=t.x+r.dc*11,l=t.y+r.dr*11;e.fillStyle="rgba(255,205,83,.96)",Sn(e,i,l,r.angle,9,7),e.fillStyle="#020304",Sn(e,i,l,r.angle,6.5,4.6)}),e.restore())}function Sn(e,t,n,o,r=11,i=8){e.save(),e.translate(t,n),e.rotate(o),e.beginPath(),e.moveTo(r,0),e.lineTo(-r*.72,-i),e.lineTo(-r*.72,i),e.closePath(),e.fill(),e.restore()}function za(e,t,n,o,r){let i=ye(t),l=null;if(n==="inputA"&&(l={x:i.x,y:i.y-67}),n==="left"&&(l={x:i.x-49,y:i.y+14}),n==="right"&&(l={x:i.x+49,y:i.y+14}),!l)return;let c=n==="inputA"?{x:o.x,y:l.y}:{x:l.x,y:o.y};e.save(),e.lineCap="square",e.lineJoin="bevel",e.strokeStyle="#050609",e.lineWidth=15,e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(c.x,c.y),e.lineTo(l.x,l.y),e.stroke(),e.strokeStyle="#596473",e.lineWidth=9,e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(c.x,c.y),e.lineTo(l.x,l.y),e.stroke(),e.strokeStyle=r||"#7b8795",e.lineWidth=3,e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(c.x,c.y),e.lineTo(l.x,l.y),e.stroke(),e.fillStyle=r||"#7b8795",e.strokeStyle="#050609",e.lineWidth=3,ee(e,l.x-9,l.y-7,18,14,!0,!0),e.restore()}function Xa(e,t){e.save(),e.lineWidth=2,e.font="900 12px ui-monospace, monospace",e.textAlign="center";for(let n of t.scanners){let o=Io(n),r=[{type:"inputA",p:Re(n,"inputA"),label:"IN",color:y.green},{type:"left",p:Re(n,"left"),label:$o(o.left),color:Fo(o.left)},{type:"right",p:Re(n,"right"),label:$o(o.right),color:Fo(o.right)}];for(let i of r){if(!i.p)continue;let l=F(i.p.col,i.p.row);za(e,n,i.type,l,i.color);let c=ai(t,n,i.type||(i.label==="IN"?"inputA":null))||t.conveyorTiles.has(I(i.p.col,i.p.row));e.fillStyle=c?Ht("#1a1d23",i.color,.24):"#3a1e22",e.strokeStyle=c?i.color:y.danger,ee(e,l.x-18,l.y-12,36,24,!0,!0),e.fillStyle=y.white,e.fillText(i.label,l.x,l.y+4)}}e.restore()}function Qa(e,t){for(let n of t.eggFarms)Ja(e,n,t)}function Ja(e,t,n){let o=F(t.col,t.row);if(e.save(),vt(e,ue.eggFarm,o.x-29,o.y-29,58,58)){ot(e,o.x-29,o.y-29,58,58,t);let l=1+Math.max(0,Number(t.extraEggOutlet)||0);e.fillStyle="rgba(255,255,255,.92)",e.strokeStyle=y.ink,e.lineWidth=2,ee(e,o.x+9,o.y+12,30,18,!0,!0),e.fillStyle=y.ink,e.font="900 10px ui-monospace, monospace",e.textAlign="center",e.fillText(`O${l}`,o.x+24,o.y+24),rt(e,n,"eggFarm",t.id,o.x,o.y,68,68),e.restore();return}e.fillStyle=y.white,e.strokeStyle=y.ink,e.lineWidth=4,ee(e,o.x-28,o.y-28,56,56,!0,!0),e.fillStyle=y.green,e.font="900 19px ui-monospace, monospace",e.textAlign="center",e.fillText("EGG",o.x,o.y-4);let r=1+Math.max(0,Number(t.extraEggOutlet)||0);e.font="900 11px ui-monospace, monospace",e.fillStyle=y.ink,e.fillText(`L${t.level} O${r}`,o.x,o.y+13),e.fillText(`${t.nextSpawn.toFixed(1)}s`,o.x,o.y+26);let i=Math.max(0,Math.min(1,t.shutterProgress||0));if(i>0){let l=56*i;e.fillStyle=y.ink,ee(e,o.x-28,o.y-28,56,l,!0,!1),e.strokeStyle=y.white,e.lineWidth=2;for(let c=o.y-24;c=1&&(e.fillStyle=y.white,e.font="900 12px ui-monospace, monospace",e.fillText("SHUT",o.x,o.y+4))}ot(e,o.x-28,o.y-28,56,56,t),rt(e,n,"eggFarm",t.id,o.x,o.y,68,68),e.restore()}function ja(e,t){for(let n of t.scanners)Za(e,n,t)}function Za(e,t,n){let o=ye(t);if(e.save(),t.kind==="manual"&&(n.manualCombo?.count||0)>=10){let b=n.manualCombo.count;e.save(),e.globalAlpha=Math.min(.55,.16+b/120),e.strokeStyle=b>=30?y.warn:y.green,e.lineWidth=Math.min(14,5+Math.floor(b/10)),e.shadowColor=e.strokeStyle,e.shadowBlur=Math.min(28,8+b),ee(e,o.x-54,o.y-76,108,152,!1,!0),e.restore()}let r=t.kind==="auto"?ue.scannerAuto:ue.scannerManual;if(vt(e,r,o.x-50,o.y-73,100,146)){t.kind==="auto"?ot(e,o.x-50,o.y-73,100,146,t):Ss(e,t,o),rt(e,n,"scanner",t.id,o.x,o.y,108,154),e.restore();return}e.fillStyle=t.kind==="auto"?"#d8ffe2":y.white,e.strokeStyle=y.ink,e.lineWidth=4,ee(e,o.x-50,o.y-73,100,146,!0,!0),e.fillStyle=t.kind==="auto"?y.green:y.ink,e.font="900 19px ui-monospace, monospace",e.textAlign="center",e.fillText(`${t.kind==="auto"?"AUTO":`S${(t.slot??0)+1}`}`,o.x,o.y-48),e.font="900 11px ui-monospace, monospace";let i=t.keys?.left?.label||(t.slot===0?"A":"Left"),l=t.keys?.right?.label||(t.slot===0?"D":"Right");e.fillText(t.role===0?`${i}:M ${l}:NEXT`:`${i}:WASTE ${l}:TRUCK`,o.x,o.y-28);let c=t.queue.length;t.kind==="manual"?(Ss(e,t,o),e.fillStyle=c>0?y.green:y.muted,e.font="900 10px ui-monospace, monospace",e.fillText(`Q:${c}`,o.x,o.y+54)):(e.fillStyle=c>0?y.green:y.muted,e.font="900 12px ui-monospace, monospace",e.fillText(`Q:${c} CD:${t.cooldown.toFixed(1)}`,o.x,o.y+54),ot(e,o.x-50,o.y-73,100,146,t)),rt(e,n,"scanner",t.id,o.x,o.y,108,154),e.restore()}function Ss(e,t,n){if(t.kind!=="manual")return;let r=(t.slot??0)===0?[{side:"left",text:"A"},{side:"right",text:"D"}]:[{side:"left",text:"\u2190"},{side:"right",text:"\u2192"}];r[0].text=t.keys?.left?.label||r[0].text,r[1].text=t.keys?.right?.label||r[1].text;let i=t.keyPressTime>0?t.keyPressSide:null,l=n.x-30,c=n.y+18;e.save(),e.lineWidth=3,e.fillStyle="#f7fff5",e.strokeStyle=y.ink,ee(e,l-4,c-4,68,25,!0,!0),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let b=0;b.8,i=t.y+Math.sin(t.bob)*(r?5:1.5);if(e.save(),n&&(e.strokeStyle=y.green,e.lineWidth=5,e.beginPath(),e.arc(t.x,i,t.radius+8,0,Math.PI*2),e.stroke()),r&&(e.strokeStyle=y.danger,e.lineWidth=3,e.beginPath(),e.arc(t.x,i,t.radius+12+Math.sin(t.bob*2)*4,0,Math.PI*2),e.stroke()),t.sex==="poop")mr(e,t.x,i,t.radius);else{let l=t.sex==="male"?ue.chickMale:ue.chickFemale;if(!vt(e,l,t.x-t.radius,i-t.radius,t.radius*2,t.radius*2)){let C=t.sex==="male"?y.male:y.female,x=t.sex==="male"?"#164f8f":"#8b2252";e.fillStyle=C,e.strokeStyle=y.ink,e.lineWidth=5,e.beginPath(),e.arc(t.x,i,t.radius,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle="rgba(255,255,255,.24)",e.beginPath(),e.arc(t.x-5,i-7,t.radius*.36,0,Math.PI*2),e.fill(),e.fillStyle=y.ink,e.beginPath(),e.arc(t.x-6,i-5,2.5,0,Math.PI*2),e.arc(t.x+6,i-5,2.5,0,Math.PI*2),e.fill(),e.fillStyle="#ffaa2e",e.beginPath(),e.moveTo(t.x,i+2),e.lineTo(t.x+9,i+6),e.lineTo(t.x,i+10),e.closePath(),e.fill(),e.strokeStyle=x,e.lineWidth=3,t.sex==="male"?(e.beginPath(),e.moveTo(t.x-8,i-t.radius-2),e.lineTo(t.x+8,i-t.radius-2),e.stroke()):(e.beginPath(),e.moveTo(t.x-9,i-t.radius+2),e.lineTo(t.x,i-t.radius-6),e.lineTo(t.x+9,i-t.radius+2),e.stroke())}e.fillStyle=t.sex==="male"?"#dff1ff":"#fff0f7",e.strokeStyle="#050609",e.lineWidth=3,e.font=`900 ${Math.max(10,Math.round(t.radius*.72))}px ui-monospace, monospace`,e.textAlign="center";let b=t.sex==="male"?"\u2642":"\u2640";e.strokeText(b,t.x+t.radius*.54,i+t.radius*.7),e.fillText(b,t.x+t.radius*.54,i+t.radius*.7)}e.restore()}function uc(e,t){let n=null,o=1/0;for(let[r,i]of e.componentLookup.entries()){let l=te(r),c=F(l.col,l.row),b=Math.hypot(t.x-c.x,t.y-c.y);bks(o.type,o.id)===ks(t,n))}function rt(e,t,n,o,r,i,l,c){dc(t,n,o)&&(e.save(),e.fillStyle="rgba(34,185,79,.18)",e.strokeStyle=y.green,e.lineWidth=(t.multiSelected||[]).length>1?6:4,e.setLineDash((t.multiSelected||[]).length>1?[]:[8,5]),ee(e,r-l/2,i-c/2,l,c,!0,!0),e.restore())}function fc(e,t,n,o){if(t.phase==="build"&&(t.multiSelected||[]).length>1){e.save(),e.fillStyle="rgba(255,255,255,.96)",e.strokeStyle=y.ink,e.lineWidth=3,ee(e,54-t.view.x,66-t.view.y,214,42,!0,!0),e.fillStyle=y.ink,e.font="900 11px ui-monospace, monospace",e.fillText(`${t.multiSelected.length} ITEMS SELECTED`,65-t.view.x,83-t.view.y),e.fillStyle=y.muted,e.font="900 11px ui-monospace, monospace",e.fillText("drag any selected item to move group",65-t.view.x,99-t.view.y),e.restore();return}}function pc(e,t,n){if(!n.cardTargetPick?.pending)return;let o=ar(n);e.save(),e.fillStyle="rgba(0,0,0,.66)",e.beginPath();let r=n.view?.scale||1;e.rect(-(n.view?.x||0)/r,-(n.view?.y||0)/r,t.width/r,t.height/r);for(let C of o){let x=C.bounds,A=8;e.rect(x.x-A,x.y-A,x.w+A*2,x.h+A*2)}e.fill("evenodd");let i=n.cardTargetPick?.mode==="blockedCell";if(!o.length){e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=y.ink,e.lineWidth=3,ee(e,(260-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,420/r,42/r,!0,!0),e.fillStyle=y.danger,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(i?"NO BLOCKED CELL. PRESS ESC.":"NO VALID UPGRADE TARGET. PRESS ESC.",(470-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore();return}e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=y.ink,e.lineWidth=3;let l=Math.max(1,n.cardTargetPick?.remaining||1),c=Math.max(0,n.cardTargetPick?.used||0),b=n.cardTargetPick?.mode==="autoScannerMenu"?"AUTO SCANNER ROUTE SETTINGS. CLICK EMPTY AREA TO CLOSE.":i?`DYNAMITE: CLICK ANY BLOCKED TILE (${l} LEFT). ESC ${c>0?"FINISHES":"CANCELS"}.`:"CLICK AN UPGRADEABLE MACHINE. PRESS ESC TO CANCEL.";ee(e,(216-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,560/r,42/r,!0,!0),e.fillStyle=y.ink,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(b,(496-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore()}function yc(e,t){if(t.phase!=="build"||!t.selectionBox)return;let n=t.selectionBox,o=Math.min(n.x1,n.x2),r=Math.min(n.y1,n.y2),i=Math.abs(n.x2-n.x1),l=Math.abs(n.y2-n.y1);e.save(),e.fillStyle="rgba(34,185,79,.12)",e.strokeStyle=y.green,e.lineWidth=2,e.setLineDash([7,4]),ee(e,o,r,i,l,!0,!0),e.restore()}function hc(e,t){let n=[...t.effects].sort((o,r)=>(o.priority??Ce.ambient)-(r.priority??Ce.ambient));for(let o of n){let r=Math.max(0,o.life/o.maxLife);e.save(),e.globalAlpha=r,o.type==="meat"?(e.fillStyle=y.green,ee(e,o.x-o.size/2,o.y-o.size/2,o.size*1.5,o.size,!0,!1)):o.type==="sludge"?(e.fillStyle=y.poop,ee(e,o.x-o.size/2,o.y-o.size/2,o.size*1.4,o.size,!0,!1)):o.type==="spawn"?(e.strokeStyle=y.green,e.lineWidth=3,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*20,0,Math.PI*2),e.stroke()):o.type==="spark"?(e.fillStyle=o.color||y.danger,ee(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!0,!1)):o.type==="smoke"?(e.fillStyle="rgba(16,32,21,.24)",e.beginPath(),e.arc(o.x,o.y,o.size*(1.2-r*.2),0,Math.PI*2),e.fill()):o.type==="shockwave"?(e.strokeStyle=o.color||y.danger,e.lineWidth=4,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*(o.maxSize||44),0,Math.PI*2),e.stroke()):o.type==="scannerPulse"?(e.strokeStyle=o.color||y.green,e.lineWidth=5,e.setLineDash([8,6]),e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*38,0,Math.PI*2),e.stroke()):o.type==="shred"?(e.fillStyle=o.color||y.ink,e.save(),e.translate(o.x,o.y),e.rotate(o.rot||0),ee(e,-o.w/2,-o.h/2,o.w,o.h,!0,!1),e.restore()):o.type==="load"?(e.strokeStyle=o.color||y.green,e.lineWidth=3,e.beginPath(),e.moveTo(o.x-14,o.y),e.lineTo(o.x+14,o.y),e.moveTo(o.x,o.y-14),e.lineTo(o.x,o.y+14),e.stroke()):o.type==="erase"?(e.strokeStyle=y.ink,e.lineWidth=3,e.setLineDash([4,4]),ee(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!1,!0)):o.type==="rage"?(e.fillStyle=o.color||y.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText("!",o.x,o.y)):o.type==="flyingChick"&&(o.sex==="poop"?mr(e,o.x,o.y,o.radius||11):br(e,o.x,o.y,o.sex,o.sex==="male")),e.restore()}}function mc(e,t){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let n of t.floatingTexts){let o=Math.max(0,n.life/n.maxLife);e.globalAlpha=o,e.lineWidth=5,e.strokeStyle=y.white,e.fillStyle=n.color,e.strokeText(n.text,n.x,n.y),e.fillText(n.text,n.x,n.y)}e.restore()}function bc(e,t){let n=t.repairmen&&t.repairmen.length?t.repairmen:t.repairman?[t.repairman]:[];for(let o of n)vc(e,t,o)}function vc(e,t,n){if(!!!n?.active)return;if(e.save(),vt(e,ue.repairman,n.x-18,n.y-18,36,36)){n.target?.label&&ur(e,n.x,n.y-24,n.target.label,y.green),e.restore();return}e.lineWidth=3,e.fillStyle="#fff0d1",e.strokeStyle=y.ink,e.beginPath(),e.arc(n.x,n.y,17,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle="#ffd6e7",e.beginPath(),e.arc(n.x-6,n.y-2,3.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+6,n.y-2,3.2,0,Math.PI*2),e.fill();let r=!!t.cardEffects?.laborExploitation;e.fillStyle=r?y.danger:y.ink,e.beginPath(),e.arc(n.x-5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.strokeStyle=y.ink,e.lineWidth=r?3:2,e.beginPath(),e.arc(n.x,n.y+(r?0:1),r?8:7,.1*Math.PI,.9*Math.PI),e.stroke(),e.fillStyle=y.green,ee(e,n.x-9,n.y+14,18,8,!0,!0),e.strokeStyle=y.ink,e.lineWidth=3,e.beginPath(),e.moveTo(n.x-11,n.y+18),e.lineTo(n.x-20,n.y+24),e.stroke(),e.beginPath(),e.moveTo(n.x+11,n.y+18),e.lineTo(n.x+20,n.y+24),e.stroke(),e.fillStyle=y.ink,e.font="900 11px ui-monospace, monospace",e.textAlign="center",e.fillText("FIX",n.x,n.y+33),n.target?.label&&ur(e,n.x,n.y-24,n.target.label,y.green),e.restore()}function wc(e,t,n){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="left",e.fillStyle=y.ink,e.font="900 19px ui-monospace, monospace",e.fillStyle=y.ink;let o=[];t.phase==="running"&&o.push(t.timeLeft<=0?"TIME UP: FARMS SHUT. CLEAR LINE.":"A/D: S1 \u2190/\u2192: S2"),t.phase==="build"&&o.push(`BUILD: ${t.buildTool||"SELECT"} | connect 1 EGG route to any exit`);let r=76;for(let i of o)e.strokeStyle=y.white,e.lineWidth=4,e.strokeText(i,24,r),e.fillText(i,24,r),r+=20;e.restore()}var Es=[[{key:"a",code:"KeyA",label:"A"},{key:"d",code:"KeyD",label:"D"}],[{key:"arrowleft",code:"ArrowLeft",label:"Left"},{key:"arrowright",code:"ArrowRight",label:"Right"}],[{key:"j",code:"KeyJ",label:"J"},{key:"l",code:"KeyL",label:"L"}],[{key:"f",code:"KeyF",label:"F"},{key:"h",code:"KeyH",label:"H"}],[{key:"q",code:"KeyQ",label:"Q"},{key:"e",code:"KeyE",label:"E"}],[{key:"z",code:"KeyZ",label:"Z"},{key:"x",code:"KeyX",label:"X"}],[{key:"u",code:"KeyU",label:"U"},{key:"o",code:"KeyO",label:"O"}],[{key:"n",code:"KeyN",label:"N"},{key:"m",code:"KeyM",label:"M"}]];function Sc(e){let t=Es[e]||Es[0];return{left:{...t[0]},right:{...t[1]}}}function Rs(e,t,n){let o={type:"eggFarm",id:e.nextId++,col:t,row:n,level:1,nextSpawn:2,lastInterval:2,extraEggOutlet:0,price:lt.eggFarm,builtSession:e.buildSession};return o.nextSpawn=Rt(o),o.lastInterval=o.nextSpawn,o}function Ps(e,t,n,o){let r=o==="auto"?ve.autoScanner.price:ve.manualScanner.price,i=new Set(e.scanners.filter(c=>c.kind==="manual").map(c=>c.slot)),l=0;for(;i.has(l);)l+=1;return{type:"scanner",id:e.nextId++,kind:o,slot:o==="manual"?l:null,role:o==="manual"?l%2:0,col:t,row:n,level:1,queue:[],cooldown:0,price:r,builtSession:e.buildSession,autoMode:"standard",keys:o==="manual"?Sc(l):null}}function Jn(e){let t=(e.x-f.x)/f.cell,n=(e.y-f.y)/f.cell,o=Math.max(0,Math.min(f.cols-1,Math.round(t-.5))),r=Math.max(0,Math.min(f.rows-1,Math.round(n-.5))),i=Math.abs(e.x-f.x),l=Math.abs(e.x-(f.x+f.cols*f.cell)),c=Math.abs(e.y-f.y),b=Math.abs(e.y-(f.y+f.rows*f.cell)),C=[["left",i],["right",l],["top",c],["bottom",b]].sort((x,A)=>x[1]-A[1])[0][0];return C==="left"?{side:C,entry:{col:0,row:r}}:C==="right"?{side:C,entry:{col:f.cols-1,row:r}}:C==="top"?{side:C,entry:{col:o,row:0}}:{side:C,entry:{col:o,row:f.rows-1}}}function jn(e,t,n){let o={x:f.x+t.col*f.cell+f.cell/2,y:f.y+t.row*f.cell+f.cell/2},r={left:f.x,right:f.x+f.cols*f.cell,top:f.y,bottom:f.y+f.rows*f.cell};return e.entry={...t},e.side=n,n==="left"?(e.x=r.left-e.w-18,e.y=o.y-e.h/2):n==="right"?(e.x=r.right+18,e.y=o.y-e.h/2):n==="top"?(e.x=o.x-e.w/2,e.y=r.top-e.h-18):(e.x=o.x-e.w/2,e.y=r.bottom+18),e}function As(e,t,n,o){let{entry:r,side:i}=Jn(n),l=ve[t],c=l?{name:l.name,w:l.body?.w||168,h:l.body?.h||110,price:l.price}:{name:t[0].toUpperCase()+t.slice(1),w:168,h:110,price:o},b={type:"facility",id:t,name:c.name,x:0,y:0,w:c.w,h:c.h,level:1,price:o||c.price,builtSession:e.buildSession};return jn(b,r,i)}function jt(e){return e?[{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}]:[]}function Is(e,t,n){return{type:"maintenanceRoom",id:e.nextId++,col:t,row:n,price:lt.maintenanceRoom,builtSession:e.buildSession,wCells:2,hCells:2}}function kc(e){return Math.random()({x:i.x,y:i.y})),r=o[0];return{id:e.nextId++,sex:n,x:r.x,y:r.y,route:o,targetIndex:o.length>1?1:o.length,stage:t.stage||"belt",scannerId:t.scannerId??null,nextScannerId:null,pendingScannerId:null,radius:n==="poop"?15:17,bob:Math.random()*Math.PI*2,queueIndex:-1,queueRoute:null}}function $s({game:e,canvasPoint:t,updatePanels:n,equipmentAtPoint:o,fail:r,pointInGrid:i,rectOfFacility:l,rectsOverlap:c}){function b(M){return M?M.type==="conveyor"?`conveyor:${M.id||M.oldKey}`:M.type==="facility"?`facility:${M.id||M.ref?.id}`:M.type==="maintenanceRoom"?`maintenanceRoom:${M.id||M.ref?.id}`:`${M.type}:${M.id||M.ref?.id}`:""}function C(M){return M?M.type==="conveyor"?{type:"conveyor",id:M.oldKey}:{type:M.type,id:M.ref.id}:null}function x(M){let g=b(C(M));return(e.multiSelected||[]).some(G=>b(G)===g)}function A(M){return M?M.type==="eggFarm"?e.eggFarms.find(g=>g.id===M.id)||null:M.type==="scanner"?e.scanners.find(g=>g.id===M.id)||null:M.type==="facility"?e.facilities[M.id]||null:M.type==="maintenanceRoom"?(e.maintenanceRooms||[]).find(g=>g.id===M.id)||null:M.type==="conveyor"&&e.conveyorTiles.has(M.id)?{type:"conveyor",id:M.id}:null:null}function $(){let M=[];for(let g of e.conveyorTiles){let G=te(g),oe=F(G.col,G.row);M.push({type:"conveyor",id:g,center:oe,cell:G})}for(let g of e.eggFarms)M.push({type:"eggFarm",id:g.id,ref:g,center:F(g.col,g.row),cell:{col:g.col,row:g.row}});for(let g of e.scanners)M.push({type:"scanner",id:g.id,ref:g,center:ye(g),cell:{col:g.col,row:g.row}});for(let g of e.maintenanceRooms||[]){let G=F(g.col,g.row);M.push({type:"maintenanceRoom",id:g.id,ref:g,center:{x:G.x+f.cell/2,y:G.y+f.cell/2},cell:{col:g.col,row:g.row}})}for(let g of Object.values(e.facilities)){let G={x:g.x+g.w/2,y:g.y+g.h/2},oe=g.entry?F(g.entry.col,g.entry.row):G;M.push({type:"facility",id:g.id,ref:g,center:G,portCenter:oe})}return M}function B(M,g){let G=Math.min(g.x1,g.x2),oe=Math.max(g.x1,g.x2),Z=Math.min(g.y1,g.y2),me=Math.max(g.y1,g.y2);return M.x>=G&&M.x<=oe&&M.y>=Z&&M.y<=me}function j(M){let g=[];for(let G of $())(B(G.center,M)||G.portCenter&&B(G.portCenter,M))&&g.push({type:G.type,id:G.id});return e.multiSelected=g,e.selected=g[0]||null,n(),g.length}function z(){e.multiSelected=[],e.selected=null,n()}function ce(M){let g=t(M);return e.selectionBox={x1:g.x,y1:g.y,x2:g.x,y2:g.y},e.multiSelected=[],e.selected=null,n(),!0}function he(M){if(!e.selectionBox)return;let g=t(M);e.selectionBox.x2=g.x,e.selectionBox.y2=g.y}function ie(){if(!e.selectionBox)return 0;let M=e.selectionBox,g=Math.abs(M.x2-M.x1),G=Math.abs(M.y2-M.y1);return e.selectionBox=null,g<6&&G<6?(z(),0):j(M)}function le(M){let g=C(M);return g?(e.multiSelected||[]).length&&x(M)?[...e.multiSelected]:[g]:[]}function se(M){let g=A(M);if(!g)return null;if(M.type==="conveyor"){let G=te(M.id);return{...M,obj:g,oldKey:M.id,currentKey:M.id,meta:e.conveyorMeta.get(M.id)||{price:Oe("conveyor"),builtSession:null},col:G.col,row:G.row}}return M.type==="eggFarm"||M.type==="scanner"||M.type==="maintenanceRoom"?{...M,obj:g,col:g.col,row:g.row}:M.type==="facility"?{...M,obj:g,x:g.x,y:g.y,w:g.w,h:g.h,entry:g.entry?{...g.entry}:null,side:g.side,center:{x:g.x+g.w/2,y:g.y+g.h/2}}:null}function R(M){let g=t(M),G=o(g);if(!G)return!1;let oe=le(G),Z=oe.map(se).filter(Boolean);return Z.length?(e.groupDrag={start:g,selections:oe,origins:Z,historySnapshot:mn(e),committed:!1,lastDCol:0,lastDRow:0},e.multiSelected=oe,e.selected=oe[0]||null,n(),!0):!1}function _(){!e.groupDrag||e.groupDrag.committed||(e.undoStack.push(e.groupDrag.historySnapshot),e.redoStack=[],e.groupDrag.committed=!0)}function Y(M,g,G){let oe=I(M,g),Z=dt(e,M,g);if(Z&&!G.has(`eggFarm:${Z.id}`))return!0;let me=ft(e,M,g);if(me&&!G.has(`scanner:${me.id}`))return!0;let ge=(e.maintenanceRooms||[]).find(Pe=>jt(Pe).some(Ae=>Ae.col===M&&Ae.row===g));return!!(ge&&!G.has(`maintenanceRoom:${ge.id}`)||e.conveyorTiles.has(oe)&&!G.has(`conveyor:${oe}`))}function O(M,g,G){let oe=[];for(let Z of e.groupDrag.origins){if(Z.type!=="facility")continue;let me={x:Z.center.x+M,y:Z.center.y+g},{entry:ge,side:Pe}=Jn(me);if(!i(ge.col,ge.row)||e.blockedCells?.has?.(I(ge.col,ge.row)))return!0;let Ae={...Z.obj,entry:{...ge},side:Pe};jn(Ae,ge,Pe),oe.push({id:Z.id,rect:l(Ae)})}for(let Z of oe)for(let me of Object.values(e.facilities))if(!G.has(`facility:${me.id}`)&&c(Z.rect,l(me),12))return!0;for(let Z=0;ZN.type==="conveyor");for(let N of Ae){let Ie=N.currentKey||N.oldKey;e.conveyorTiles.delete(Ie),e.conveyorMeta.delete(Ie)}for(let N of Ae){let Ie=I(N.col+Z,N.row+me);e.conveyorTiles.add(Ie),e.conveyorMeta.set(Ie,N.meta||{price:Oe("conveyor"),builtSession:null,uses:0}),N.currentKey=Ie}for(let N of e.groupDrag.origins)if(N.type==="eggFarm")N.obj.col=N.col+Z,N.obj.row=N.row+me;else if(N.type==="scanner")N.obj.col=N.col+Z,N.obj.row=N.row+me;else if(N.type==="maintenanceRoom")N.obj.col=N.col+Z,N.obj.row=N.row+me;else if(N.type==="facility"){let Ie={x:N.center.x+G,y:N.center.y+oe},{entry:Ye,side:Ve}=Jn(Ie);jn(N.obj,Ye,Ve)}e.groupDrag.selections=e.groupDrag.origins.map(N=>N.type==="conveyor"?{type:"conveyor",id:N.currentKey||N.oldKey}:{type:N.type,id:N.id}),e.multiSelected=[...e.groupDrag.selections],e.selected=e.multiSelected[0]||null,be(e),n()}function U(){e.groupDrag&&(be(e),e.groupDrag=null,n())}return{selectionFromHit:C,startSelectionBox:ce,updateSelectionBox:he,finishSelectionBox:ie,startGroupDrag:R,updateGroupDrag:W,finishGroupDrag:U}}function Fs({game:e,ui:t,canvas:n,canvasPoint:o,onUpdatePanels:r}){function i(){r&&r()}let l=null,c=!1,b=null,C=!1,x=["random","up","right","down","left"],A={random:"RND",up:"UP",right:"RT",down:"DN",left:"LF"},$={w:40,h:40,y:0};function B(){return In(e)}function j(){e.gridCols=f.cols,e.gridRows=f.rows,e.gridOwnedCells=zr(e)}function z(s){if(s){f.y-=s*f.cell,f.rows+=s,e.gridChunkOriginY=(e.gridChunkOriginY||0)-Math.floor(s/10),e.ownedCells=Dn(e.ownedCells,s),e.blockedCells=Dn(e.blockedCells,s),e.conveyorTiles=Dn(e.conveyorTiles,s),e.conveyorMeta=jr(e.conveyorMeta,s);for(let a of e.eggFarms||[])a.row+=s;for(let a of e.scanners||[])a.row+=s;for(let a of Object.values(e.facilities||{}))a.entry&&(a.entry.row+=s)}}function ce(s){e.ownedCells=e.ownedCells||new Set;for(let a of Jr(s))e.ownedCells.add(I(a.col,a.row))}function he(s){return e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending?null:Tt(e).find(a=>a&&Qr(a,s))||null}function ie(s="right"){if(s&&typeof s=="object"&&Number.isFinite(s.chunkX)&&Number.isFinite(s.chunkY))return s;let a=["right","up"].includes(s)?s:"right";return Xr(e,a)}function le(s="right"){let a=ie(s);if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return{ok:!1,reason:"Cannot expand now."};if(!a)return{ok:!1,reason:"Invalid expansion lot."};let h=a.direction||"right",m=B();if(e.cashf.cols&&(f.cols=E.colStart+E.cols),E.rowStart+E.rows>f.rows&&(f.rows=E.rowStart+E.rows),ce(E),Zr(e,E.chunkX,E.chunkY),e.gridExpansionPurchases=(e.gridExpansionPurchases||0)+1,e.gridExpansionPurchasesByDirection[h]=(e.gridExpansionPurchasesByDirection[h]||0)+1,j();let ne=Ur(e.gridExpansionPurchases,{base:q.map.blockedRatio??.03,increment:q.map.blockedExpansionIncrement??.005,max:q.map.blockedRatioMax??.1}),J=Kr({seed:`${e.runSeed}:grid-expansion:${E.chunkX},${E.chunkY}:${e.gridExpansionPurchases}`,colStart:E.colStart,colEnd:E.colStart+E.cols,rowStart:E.rowStart,rowEnd:E.rowStart+E.rows,targetRatio:ne});for(let Je of J)e.blockedCells.add(Je);be(e);let pe=E.cols*E.rows,Te=Et(E);return H(e,Te.x+Te.w/2,Te.y+Te.h/2,`${h.toUpperCase()} +${pe} CELLS -${T(m)}`,y.green),i(),{ok:!0,direction:h,cost:m,addedCells:pe,blocked:J.size,blockedRatio:ne,chunkX:E.chunkX,chunkY:E.chunkY}}function se(s,a){return s>=0&&s=0&&a!a.has(m.id)&&Y(h,_(m),12))}function W(s,a,h=null){if(!se(s,a))return!1;if(R(s,a))return!0;let m=I(s,a),w=dt(e,s,a);if(w&&!(h?.type==="eggFarm"&&h.ref?.id===w.id))return!0;let E=ft(e,s,a);if(E&&!(h?.type==="scanner"&&h.ref?.id===E.id))return!0;let ne=U(e,s,a);return!!(ne&&!(h?.type==="maintenanceRoom"&&h.ref?.id===ne.id)||e.conveyorTiles.has(m)&&!(h?.type==="conveyor"&&h.oldKey===m))}function U(s,a,h){return(s.maintenanceRooms||[]).find(m=>jt(m).some(w=>w.col===a&&w.row===h))||null}function M(s,a,h=null){let m={col:s,row:a};for(let w of jt(m)){if(!se(w.col,w.row)||R(w.col,w.row))return!0;let E=I(w.col,w.row);if(dt(e,w.col,w.row)||ft(e,w.col,w.row))return!0;let pe=U(e,w.col,w.row);if(pe&&!(h?.type==="maintenanceRoom"&&h.ref?.id===pe.id)||e.conveyorTiles.has(E))return!0}return!1}function g(s,a,h=null){let m={col:s,row:a};for(let w of Pt(m)){if(!se(w.col,w.row)||R(w.col,w.row))return!0;let E=I(w.col,w.row);if(dt(e,w.col,w.row))return!0;let J=ft(e,w.col,w.row);if(J&&!(h?.type==="scanner"&&h.ref?.id===J.id)||e.conveyorTiles.has(E))return!0}return!1}function G(){return e.selected?e.selected.type==="eggFarm"?e.eggFarms.find(s=>s.id===e.selected.id)||null:e.selected.type==="scanner"?e.scanners.find(s=>s.id===e.selected.id)||null:e.selected.type==="conveyor"?e.conveyorTiles.has(e.selected.id)?{type:"conveyor",id:e.selected.id}:null:e.selected.type==="facility"?e.facilities[e.selected.id]||null:e.selected.type==="maintenanceRoom"&&(e.maintenanceRooms||[]).find(s=>s.id===e.selected.id)||null:null}function oe(s){return s?s.type==="eggFarm"?`${ct("eggFarm")} #${s.id}`:s.type==="scanner"?`${s.kind==="auto"?ct("autoScanner"):ct("manualScanner")} #${s.id}`:s.type==="conveyor"?e.conveyorMeta.get(s.id)?.kind==="boostConveyor"?ct("boostConveyor"):ct("conveyor"):s.type==="facility"?s.name:s.type==="maintenanceRoom"?`${ct("maintenanceRoom")} #${s.id}`:"Equipment":"Equipment"}function Z(s){return s?.type==="conveyor"?e.conveyorMeta?.get(s.oldKey||s.ref?.id)?.price||_n(s):_n(s)}function me(){return!!e.cardEffects?.usedMachineActive}function ge(){return me()?{usedMachine:!0,noRefund:!0,durabilityBaseMultiplier:.6}:{usedMachine:!1,noRefund:!1,durabilityBaseMultiplier:1}}function Pe(s){let a=ge();return Object.assign(s,a),s}function Ae(s){let a=s?.ref||s||{};if(s?.type==="eggFarm"||a.type==="eggFarm")return e.eggFarms.length<=1?"Cannot sell the last EGG FARM.":"";if((s?.type==="facility"||a.type==="facility")&&["mixer","trash","truck"].includes(a.baseId||a.id)){let h=a.baseId||a.id;if(Object.values(e.facilities).filter(w=>(w.baseId||w.id)===h).length<=1)return`Cannot sell the last ${a.shortName||a.name||a.id}.`}return""}function N(s){t.buildStatus.textContent=s,H(e,n.width/2-e.view.x,86-e.view.y,s.toUpperCase(),y.danger)}function Ie(s){if(!s)return null;let a=I(s.col,s.row);return e.conveyorMeta.get(a)||null}function Ye(s){return s?(Array.isArray(s.outDirs)||(s.outDirs=[]),s.outDirs=[...new Set(s.outDirs.filter(a=>["right","left","down","up"].includes(a)))],x.includes(s.branchMode)||(s.branchMode="random"),s.kind||(s.kind="conveyor"),s.speedMultiplier||(s.speedMultiplier=s.kind==="boostConveyor"?2:1),s.outDirs):[]}function Ve(s){return s?de.filter(a=>e.conveyorTiles.has(I(s.col+a.dc,s.row+a.dr))).map(a=>a.name):[]}function xe(s){return Ve(s).length>=3}function Ct(s,a){let h=de.find(J=>J.name===a);if(!s||!h)return!1;let m=I(s.col+h.dc,s.row+h.dr),w=e.conveyorMeta.get(m);if(!w)return!1;let E=h.opposite;return[...new Set([...Array.isArray(w.outDirs)?w.outDirs:[],w.dir].filter(Boolean))].includes(E)}function oo(s){if(!e.conveyorTiles.has(s))return[];let a=te(s),h=e.conveyorMeta.get(s),m=Ye(h),w=Ve(a),E=[...new Set([...m,h?.dir].filter(Boolean))].filter(pe=>w.includes(pe)),ne=w,J=E.length?E:ne;return h&&(h.outDirs=m.filter(pe=>w.includes(pe)),h.dir&&!w.includes(h.dir)&&(h.dir=h.outDirs[0]||null),h.branchMode!=="random"&&!w.includes(h.branchMode)&&(h.branchMode="random")),J}function Mn(s){if(!e.conveyorTiles.has(s))return[];let a=te(s),h=Ve(a);return xe(a)||h.length?h:oo(s)}function ro(s){let a=te(s),h=Mn(s);if(h.length<3)return[];let m=e.conveyorMeta.get(s)||{},w=new Set(h.filter(J=>Ct(a,J))),E=h.filter(J=>!w.has(J));if(w.size&&E.length>=2)return E;let ne=[...new Set([...Array.isArray(m.outDirs)?m.outDirs:[],m.dir].filter(Boolean))].filter(J=>h.includes(J));return ne.length>=2?ne:h}function nn(s,a){let h=at(s,a);if(!h)return!1;let m=I(s.col,s.row),w=I(a.col,a.row),E=e.conveyorMeta.get(m),ne=e.conveyorMeta.get(w);if(!E||!ne)return!1;let J=Ye(E),pe=!J.includes(h)||E.dir!==h||!ne.dir;return J.includes(h)||J.push(h),E.dir=h,ne.dir||(ne.dir=h),pe}function Mt(s){let a=so(s);return a.length<2?io(s):(Be(e),lo(a),be(e),i(),!0)}function io(s){if(!s)return!1;let a=I(s.col,s.row),h=e.conveyorMeta.get(a);if(!h||xe(s))return!1;let m=de.map(ne=>ne.name),w=h.dir&&m.includes(h.dir)?h.dir:null,E=m[(Math.max(-1,m.indexOf(w))+1)%m.length];return Be(e),h.dir=E,h.outDirs=[E],h.branchMode="random",be(e),i(),!0}function gn(s){return s?de.map(a=>({col:s.col+a.dc,row:s.row+a.dr})).filter(a=>e.conveyorTiles.has(I(a.col,a.row))):[]}function so(s){if(!s||!e.conveyorTiles.has(I(s.col,s.row))||xe(s))return[];let a=gn(s);if(!a.length||a.length>2)return[];let h=E=>{let ne=[],J=new Set([I(s.col,s.row)]),pe=s,Te=E,Je=0;for(;Te&&Je<200;){Je+=1;let Tr=I(Te.col,Te.row);if(J.has(Tr)||(J.add(Tr),ne.push(Te),xe(Te)))break;let Er=gn(Te).filter(Rr=>!(Rr.col===pe.col&&Rr.row===pe.row));if(Er.length!==1)break;pe=Te,Te=Er[0]}return ne},m=a[0]?h(a[0]).reverse():[],w=a[1]?h(a[1]):[];return[...m,s,...w]}function gt(s,a){return!!s&&[...new Set([...Array.isArray(s.outDirs)?s.outDirs:[],s.dir].filter(Boolean))].includes(a)}function lo(s){let a=0,h=0;for(let w=0;wh?[...s].reverse():s;for(let w=0;w=Math.abs(m)?{col:s.col+Math.sign(h),row:s.row}:{col:s.col,row:s.row+Math.sign(m)}}function ao(s){c=!1,b=s?{col:s.col,row:s.row}:null,C=!1,l=null,on(s)}function d(s){if(!s)return;if(!l)return on(s);let a=l,h=0;for(;(a.col!==s.col||a.row!==s.row)&&h<64;){let m=rn(a,s);if(on(m),a=l||m,h+=1,!l)break}}function p(){!C&&b&&e.conveyorTiles.has(I(b.col,b.row))&&Mt(b),b=null,C=!1,l=null,c=!1}function v(s){if(!s)return N(re.fail.outOfGrid);let{col:a,row:h}=s;if(e.buildTool==="conveyor"||e.buildTool==="boostConveyor"){let m=Gt(s,null);if(!m.ok)return N(m.reason||re.fail.cellOccupied);be(e);return}if(R(a,h))return N("Cannot build on blocked ground.");if(e.buildTool==="maintenanceRoom")return M(a,h)?N(re.fail.cellOccupied):D(a,h);if(e.buildTool==="manualScanner"||e.buildTool==="autoScanner"?g(a,h):W(a,h))return N(re.fail.cellOccupied);e.buildTool==="eggFarm"?S(a,h):e.buildTool==="manualScanner"?P(a,h,"manual"):e.buildTool==="autoScanner"&&P(a,h,"auto")}function k(s){let a=He(s.x,s.y);if(["conveyor","boostConveyor","eggFarm","manualScanner","autoScanner","maintenanceRoom"].includes(e.buildTool))return v(a);if(un.includes(e.buildTool))return ae(s,e.buildTool)}function S(s,a){let h=Oe("eggFarm",e);if(e.cashE.kind==="manual").length>=8)return N("Manual Scanner limit reached (8 max).");let m=h==="auto"?Oe("autoScanner",e):Oe("manualScanner",e);if(e.cashw.id!==a.ref.id),et(e,m.x,m.y),be(e)}if(a.type==="scanner"){let m=ye(a.ref);Ne(a,m.x,m.y),e.scanners=e.scanners.filter(w=>w.id!==a.ref.id),et(e,m.x,m.y),be(e)}if(a.type==="facility"){let m=a.ref;Ne(a,m.x+m.w/2,m.y+m.h/2),delete e.facilities[m.id],et(e,m.x+m.w/2,m.y+m.h/2),be(e)}if(a.type==="maintenanceRoom"){let m=a.ref,w=V(m);Ne(a,w.x,w.y),e.maintenanceRooms=(e.maintenanceRooms||[]).filter(E=>E.id!==m.id),et(e,w.x,w.y)}e.selected=null,e.multiSelected=[],i()}function co(s){let a=Object.values(e.facilities).find(J=>{if(s.x>=J.x&&s.x<=J.x+J.w&&s.y>=J.y&&s.y<=J.y+J.h)return!0;if(!J.entry)return!1;let Te=F(J.entry.col,J.entry.row);return Math.abs(s.x-Te.x)<=f.cell*.46&&Math.abs(s.y-Te.y)<=f.cell*.46});if(a)return{type:"facility",ref:a};let h=He(s.x,s.y);if(!h)return null;let m=dt(e,h.col,h.row);if(m)return{type:"eggFarm",ref:m};let w=ft(e,h.col,h.row);if(w)return{type:"scanner",ref:w};let E=U(e,h.col,h.row);if(E)return{type:"maintenanceRoom",ref:E};let ne=I(h.col,h.row);return e.conveyorTiles.has(ne)?{type:"conveyor",oldKey:ne,ref:{type:"conveyor",id:ne}}:null}let Wt=$s({game:e,canvasPoint:o,updatePanels:i,equipmentAtPoint:co,fail:N,pointInGrid:se,rectOfFacility:_,rectsOverlap:Y});function js(s){return null}function wr(){let s=G();s&&(s.type==="conveyor"?Ut(F(...Object.values(te(s.id)))):s.type==="eggFarm"?Ut(F(s.col,s.row)):s.type==="scanner"?Ut(ye(s)):s.type==="facility"?Ut({x:s.x+s.w/2,y:s.y+s.h/2}):s.type==="maintenanceRoom"&&Ut(V(s)))}function Ke(s,a,h="primary-button"){let m=document.createElement("button");return m.type="button",m.className=h,m.textContent=s,m.addEventListener("click",a),m}function sn(){e.cardTargetPick?.mode==="autoScannerMenu"&&(e.cardTargetPick=null),t.modal.classList.remove("visible","equipment-popover"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function uo(s){t.modalTitle.textContent="Auto Scanner",e.cardTargetPick={pending:!0,mode:"autoScannerMenu",cardId:null,targetKeys:[`scanner:${s.id}`],remaining:1},t.modalBody.innerHTML=` -
-

Left / right output routing for this AUTO scanner.

-

Current: ${s.role===0?"Male left / others right":"Poop left / others right"}

-

Cooldown: ${nt(s).toFixed(1)}s.

-
`,t.modalActions.innerHTML="";let a=Ke("Male Left / Others Right",()=>{Be(e),s.role=0,sn(),i()},s.role===0?"facility-action warn":"facility-action"),h=Ke("Poop Left / Others Right",()=>{Be(e),s.role=1,sn(),i()},s.role===1?"facility-action warn":"facility-action");t.modalActions.append(a,h,Ke("Close",sn,"facility-action")),fo(s),t.modal.classList.add("visible","equipment-popover"),i()}function Sr(s){return s?.label||s?.key||"?"}function Zs(s){let a=s.key===" "?"Space":s.key.length===1?s.key.toUpperCase():s.key.replace(/^Arrow/,"");return{key:s.key.toLowerCase(),code:s.code,label:a}}function el(s,a,h){for(let m of e.scanners.filter(w=>w.kind==="manual"))for(let w of["left","right"]){if(m.id===s.id&&w===a)continue;let E=m.keys?.[w];if(E&&(E.code===h.code||E.key===h.key))return!0}return!1}function ln(s,a=""){if(!s||s.kind!=="manual")return;t.modalTitle.textContent=`Manual Scanner #${s.id}`;let h=Sr(s.keys?.left),m=Sr(s.keys?.right),w=tl(s);t.modalBody.innerHTML=` -
-

Left route key: ${h}

-

Right route key: ${m}

- ${a?`

${a}

`:""} - ${w?`

${w}

`:""} -
`,t.modalActions.innerHTML="",t.modalActions.appendChild(Ke("Set Left Key",()=>kr(s,"left"),"facility-action warn")),t.modalActions.appendChild(Ke("Set Right Key",()=>kr(s,"right"),"facility-action warn")),t.modalActions.appendChild(Ke("Close",sn,"facility-action")),fo(s),t.modal.classList.add("visible","equipment-popover")}function tl(s){let a=[{side:"left",binding:s.keys?.left},{side:"right",binding:s.keys?.right}];if(a[0].binding&&a[1].binding&&(a[0].binding.code===a[1].binding.code||a[0].binding.key===a[1].binding.key))return"Left and right keys conflict.";for(let h of a)if(h.binding)for(let m of e.scanners.filter(w=>w.kind==="manual"&&w.id!==s.id)){if(m.keys?.left&&(m.keys.left.code===h.binding.code||m.keys.left.key===h.binding.key))return`Key conflicts with Manual Scanner #${m.id} left.`;if(m.keys?.right&&(m.keys.right.code===h.binding.code||m.keys.right.key===h.binding.key))return`Key conflicts with Manual Scanner #${m.id} right.`}return""}function kr(s,a){t.modalBody.innerHTML=`

Press a key for ${a.toUpperCase()} route.

Esc cancels.

`,t.modalActions.innerHTML="";let h=m=>{if(m.preventDefault(),m.stopPropagation(),window.removeEventListener("keydown",h,!0),m.key==="Escape")return ln(s);let w=Zs(m),E=el(s,a,w);Be(e),s.keys=s.keys||{left:null,right:null},s.keys[a]=w,i(),ln(s,E?`${w.label} assigned, but another scanner already uses it.`:`${a.toUpperCase()} set to ${w.label}.`)};window.addEventListener("keydown",h,!0)}function nl(){let s=G();if(!(!s||s.type!=="scanner"))return s.kind==="auto"?uo(s):ln(s)}function ol(s){if(!s)return{x:80,y:80};if(s.type==="conveyor"){let a=te(s.id);return F(a.col,a.row)}return s.type==="eggFarm"?F(s.col,s.row):s.type==="scanner"?ye(s):s.type==="facility"?{x:s.x+s.w/2,y:s.y+10}:{x:80,y:80}}function fo(s){let a=n.getBoundingClientRect(),h=ol(s),m=e.view?.scale||1,w=a.left+(h.x*m+(e.view?.x||0))/n.width*a.width+18,E=a.top+(h.y*m+(e.view?.y||0))/n.height*a.height-12,ne=Math.max(12,window.innerWidth-274),J=Math.max(12,window.innerHeight-220);t.modal.style.setProperty("--popover-x",`${Math.max(12,Math.min(ne,w))}px`),t.modal.style.setProperty("--popover-y",`${Math.max(12,Math.min(J,E))}px`)}function Cr(){let s=G();if(!s)return;let a=xr(s);if(t.modalTitle.textContent=oe(s),t.modalBody.innerHTML=` -
${a.map(w=>`

${w}

`).join("")}
- ${["mixer","truck"].includes(s.baseId||s.id)?'

Income/Fine = ceil(base x 1.10^upgrades)

':""}`,t.modalActions.innerHTML="",s.type==="scanner"&&s.kind==="auto"&&t.modalActions.appendChild(Ke("Auto Menu",()=>uo(s),"facility-action warn")),s.type==="scanner"&&s.kind==="manual"&&t.modalActions.appendChild(Ke("Set Keys",()=>ln(s),"facility-action warn")),s.type==="conveyor"&&po(s.id)){let w=e.conveyorMeta.get(s.id)?.branchMode||"random";t.modalActions.appendChild(Ke(`Branch: ${Mr(w)}`,()=>{yo(s.id),e.selected={type:"conveyor",id:s.id},Cr()},"facility-action warn branch-action"))}let h=s.type==="conveyor"?{type:"conveyor",oldKey:s.id,ref:s}:{type:s.type,ref:s},m=Ae(h);if(m){let w=Ke(m,()=>{},"facility-action danger disabled");w.disabled=!0,t.modalActions.appendChild(w)}else{let w=mt(h,e),E=w.sameBuild?`Remove / Refund ${T(w.amount)}`:`Sell ${T(w.amount)}`;t.modalActions.appendChild(Ke(E,()=>{wr(),sn()},"facility-action danger"))}fo(s),t.modal.classList.add("visible","equipment-popover")}function rl(s){e.phase==="build"&&(p(),e.buildTool=e.buildTool===s?null:s,e.selected=null,e.multiSelected=[],e.selectionBox=null,i())}function il(){let s=[];for(let[a,h]of Object.entries(e.facilities))if(s.push({id:`facility:${a}`,price:Z({type:"facility",ref:h}),x:h.x,y:h.y,w:h.w,h:h.h}),h.entry){let m=F(h.entry.col,h.entry.row);s.push({id:`facilityPort:${a}`,price:Z({type:"facility",ref:h}),x:m.x-18,y:m.y-18,w:36,h:36})}for(let a of e.maintenanceRooms||[]){let h=V(a);s.push({id:`maintenanceRoom:${a.id}`,price:Z({type:"maintenanceRoom",ref:a}),x:h.x-f.cell,y:h.y-f.cell,w:f.cell*2,h:f.cell*2})}for(let a of e.eggFarms){let h=F(a.col,a.row);s.push({id:`eggFarm:${a.id}`,price:Z({type:"eggFarm",ref:a}),x:h.x-24,y:h.y-24,w:48,h:48})}for(let a of e.scanners){let h=ye(a);s.push({id:`scanner:${a.id}`,price:Z({type:"scanner",ref:a}),x:h.x-50,y:h.y-73,w:100,h:146})}for(let a of e.conveyorTiles){let h=te(a),m=F(h.col,h.row),w=e.conveyorMeta.get(a)||{};s.push({id:`conveyor:${a}`,price:w.price||Oe(w.kind==="boostConveyor"?"boostConveyor":"conveyor",e),x:m.x-22,y:m.y-22,w:44,h:44})}return s}function Mr(s){return A[s]||A.random}function zc(s){return Mn(s)}function po(s){return e.conveyorTiles.has(s)?xe(te(s)):!1}function gr(s){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return null;for(let a of e.conveyorTiles){if(!po(a))continue;let h=te(a),m=F(h.col,h.row),w=m.x-$.w/2,E=m.y+$.y-$.h/2;if(s.x>=w&&s.x<=w+$.w&&s.y>=E&&s.y<=E+$.h)return a}return null}function sl(s){let a=gr(s);return a?yo(a):!1}function yo(s){let a=e.conveyorMeta.get(s);if(!a)return!1;let h=ro(s);if(h.length<2)return!1;Be(e);let m=x.includes(a.branchMode)?a.branchMode:"random",w=["random",...de.map(E=>E.name).filter(E=>h.includes(E))];return a.branchMode=w[(Math.max(0,w.indexOf(m))+1)%w.length],be(e),e.selected=null,e.multiSelected=[],i(),!0}function xr(s){Se(e);let a=[],h=s?.type==="facility"?s.baseId||s.id:"";if(s.type==="eggFarm"){let[m,w]=fn(s);a.push(`Price: ${T(Z(s))}`);{let E=Ae({type:s.type,ref:s});a.push(E?`Sale: blocked (${E})`:`Sale value: ${T(mt({type:s.type,ref:s},e).amount)}`)}a.push(`Level: ${s.level}/4`),a.push(`Random interval: ${m.toFixed(2)}-${w.toFixed(2)}s`),a.push(`Durability: ${vn(s)}% | Spawn delay x${Yn(s).toFixed(2)}`)}else if(s.type==="scanner")a.push(`Price: ${T(Z(s))}`),a.push(`Sale value: ${T(mt({type:s.type,ref:s},e).amount)}`),a.push(`Type: ${s.kind.toUpperCase()} / Standard`),s.kind==="auto"&&a.push(`Role: ${s.role===0?"Male left / Others right":"Poop left / Others right"}`),a.push(`Queue: ${s.queue.length}`),s.kind==="auto"&&a.push(`Cooldown: ${s.cooldown.toFixed(1)}s / ${nt(s,e).toFixed(1)}s`),s.kind==="auto"&&a.push(`Durability: ${vn(s)}% | Delay x${qn(s).toFixed(2)}`),s.kind==="manual"&&a.push("Durability: none | Always normal");else if(s.type==="conveyor"){let m=e.conveyorMeta.get(s.id),w=e.componentLookup?.get(s.id),E=w?e.congestion.get(w):null;a.push(`Price: ${T(Z({type:"conveyor",oldKey:s.id,ref:s}))}`),a.push(`Cell: ${s.id}`),a.push(`Type: ${m?.kind==="boostConveyor"?"BOOST BELT":"Normal Belt"} | Speed x${Number(m?.speedMultiplier||1).toFixed(1)}`),a.push(`Congestion: ${E?Math.floor(E.ratio*100):0}%`),a.push(`Durability: ${vn({meta:m})}% | Speed x${Hn({meta:m}).toFixed(2)}`),po(s.id)?(a.push(`Branch mode: ${Mr(m?.branchMode||"random")}`),a.push("Click the Branch button or the large on-belt badge to cycle RANDOM / fixed exit.")):a.push("Branch mode: needs 3+ conveyor connections."),a.push(`Sale value: ${T(mt({type:"conveyor",oldKey:s.id,ref:s},e).amount)}`)}else if(s.type==="maintenanceRoom")a.push(`Price: ${T(Z({type:"maintenanceRoom",ref:s}))}`),a.push(`Sale value: ${T(mt({type:"maintenanceRoom",ref:s},e).amount)}`),a.push("Size: 2\xD72 grid cells"),a.push("Dispatch: 1 repairman during each production day");else if(s.type==="facility"){a.push(`Price: ${T(Z(s))}`);{let m=Ae({type:s.type,ref:s});a.push(m?`Sale: blocked (${m})`:`Sale value: ${T(mt({type:s.type,ref:s},e).amount)}`)}if(a.push(["mixer","truck","trash"].includes(s.id)?`Level: ${s.level} / no cap`:`Level: ${s.level}`),h==="truck"&&a.push("Durability: none | Always normal"),["mixer","trash"].includes(h)&&a.push(`Durability: ${vn(s)}% | Extra delay ${er(e,s).toFixed(2)}s`),h==="mixer"&&(a.push(`Income: ${T(ze(e))} per chick | upgrade x${yt(e,"mixer").toFixed(3)}`),a.push(`Poop fine: -${T(yn(e))}`)),h==="truck"&&(a.push(`Income: ${T(Fe(e))} per target cargo | upgrade x${yt(e,"truck").toFixed(3)}`),a.push(`Poop shipment fine: -${T(hn(e))}`)),h==="trash"){let m=Dt(e),w=ht(m);a.push(`Bonus cards: ${m}/${zt()}`),a.push(`Poop income bonus: ${T(w)} per processed poop.`),a.push("With enough upgrades, poop can out-earn male/female routes.")}s.entry&&a.push(`Receiver: edge cell ${s.entry.col},${s.entry.row} (${s.side})`)}return a}function ll(s){if(!s||e.phase!=="build")return"";let a=On(e).find(h=>h.type===s.type&&h.id===s.id);return a?a.message||"Not connected to conveyor route":""}function al(s){return s?s.type==="conveyor"&&e.conveyorMeta.get(s.id)?.kind==="boostConveyor"?"Moves chicks twice as fast. Wears down like a normal belt.":s.type==="conveyor"?"A stubborn belt tile. It only cares about the next cell.":s.type==="eggFarm"?"A tiny gatehouse producing questionable eggs on schedule.":s.type==="scanner"&&s.kind==="auto"?"Slower than hands without upgrades.":s.type==="scanner"?"A manual checkpoint. The operator is the algorithm.":s.type==="facility"&&(s.baseId||s.id)==="mixer"?"Male chicks become revenue here. Do not feed it poop.":s.type==="facility"&&(s.baseId||s.id)==="trash"?"Poop goes in. Sometimes coins come out, for reasons best left unaudited.":s.type==="facility"&&(s.baseId||s.id)==="truck"?"The shipping endpoint. Correct cargo pays; wrong cargo complains.":s.type==="maintenanceRoom"?"A cramped 2\xD72 storage and break room with lockers, spare parts, a bench and one dispatched repairman.":"Factory equipment.":""}return{buildAtCell:v,buildAtPoint:k,eraseAtPoint:Ut,equipmentAtPoint:co,startSelectionBox:Wt.startSelectionBox,updateSelectionBox:Wt.updateSelectionBox,finishSelectionBox:Wt.finishSelectionBox,startGroupDrag:Wt.startGroupDrag,updateGroupDrag:Wt.updateGroupDrag,finishGroupDrag:Wt.finishGroupDrag,selectedObject:G,selectedTitle:oe,equipmentPrice:Z,selectedUpgradeCost:js,selectedInfoLines:xr,flavorText:al,disconnectedWarningFor:ll,gridExpansionCost:B,buyGridExpansion:le,expansionOfferAtPoint:he,beginConveyorDrag:ao,continueConveyorDrag:d,endConveyorDrag:p,cycleSingleConveyorDirection:Mt,branchSwitcherAtPoint:gr,cycleBranchModeAtPoint:sl,cycleBranchModeForKey:yo,removeSelected:wr,switchScannerRole:nl,showManualScannerMenu:ln,showAutoScannerMenu:uo,showSelectedMenu:Cr,setBuildTool:rl,fail:N,isEquipmentCell:W,equipmentHitBoxes:il,routeFromFarmToScanner:It}}function Bs({game:e,ui:t,build:n,startGame:o,beginCardDraft:r,activeQueuedChick:i}){function l(O){return String(O).replace(/[&<>"']/g,W=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[W])}function c(){return Math.round(Xn(e))}function b(){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return!1;let O=!1;for(let W of So)if(O=!0,e.cash>=Oe(W,e))return!1;return O}function C(){x(),A(),B(),$()}function x(){for(let[W,U]of Object.entries(t.buttons))U?.classList?.contains("tool-button")&&U.classList.toggle("active",e.buildTool===W);for(let W of So){let U=t.buttons[W];if(!U)continue;let M=Oe(W,e),g=U.querySelector("span");g&&(g.textContent=W==="conveyor"||W==="boostConveyor"?`${T(M)} / tile`:T(M));let G=W==="manualScanner"&&e.scanners.filter(Z=>Z.kind==="manual").length>=8,oe=e.cashIt(e,U)?.scannerId).length,W=pn(e);t.turnSummary.innerHTML=[`Seed: ${l(e.runSeed||"none")} | Grid box: ${e.gridRows||10}x${e.gridCols||20} | Owned: ${e.gridOwnedCells||e.ownedCells?.size||(e.gridRows||10)*(e.gridCols||20)} cells | Blocked: ${e.blockedCells?.size||0} cells`,`Penalties: wrong shipment -${T(Uo(e))} | Mixer poop -${T(yn(e))} | Shipment poop -${T(hn(e))}`,`Maintenance: worst ${rr(e).worst.percent}% dirty (${rr(e).worst.label}) | Rooms: ${(e.maintenanceRooms||[]).length} | Repairmen: ${(e.repairmen||[]).length}`,`Card draft: ${e.cardDraft?.pending?Math.max(1,e.cardDraft.picksRemaining||1)+" pick(s) left":"ready after each day"} | Farms with scanner route: ${O}/${e.eggFarms.length}`,e.cardEffects?.usedMachineActive?'Procurement: USED MACHINE MODE / no refunds / 60% durability':"",W.length?`Blocked: ${W[0]}`:`${re.status.allPortsConnected}`].filter(Boolean).join("
")}function j(){x(),t.shell.classList.toggle("phase-running",e.phase==="running"),t.shell.classList.toggle("phase-build",e.phase==="build"),t.shell.classList.toggle("phase-gameover",e.phase==="gameover"),t.shell.classList.toggle("phase-title",e.phase==="title"),t.shell.classList.toggle("phase-loanDecision",e.phase==="loanDecision"),t.money.textContent=T(e.cash),t.money.classList.toggle("cash-negative",e.cash<0),t.money.classList.toggle("cash-positive",e.cash>an),t.turn.textContent=e.turn,t.timeLeft.textContent=e.phase==="running"&&e.timeLeft<=0&&e.shutdownTimeLeft>0?`+${e.shutdownTimeLeft.toFixed(1)}s`:`${Math.max(0,e.timeLeft).toFixed(1)}s`,t.timeLeft.closest?.(".hud-card")?.classList.toggle("time-critical",e.phase==="running"&&(e.timeLeft<=10||e.timeLeft<=0&&e.shutdownTimeLeft>0)),t.phase.textContent=ce(),t.comboCount&&(t.comboCount.textContent=e.manualCombo?.count||0),z(),t.turnProfit.textContent=T(e.stats.profit),t.turnProfit.classList.toggle("cash-negative",e.stats.profit<0),t.turnProfit.classList.toggle("cash-positive",e.stats.profit>0),t.mixerCount.textContent=e.stats.mixerCount,t.truckFemaleCount.textContent=e.stats.truckFemale,t.truckMaleCount.textContent=e.stats.truckMale,t.poopCount.textContent=e.stats.poopSpawned,t.buttons.s1Left.disabled=e.phase!=="running"||!i(0),t.buttons.s1Right.disabled=e.phase!=="running"||!i(0),t.buttons.s2Left.disabled=e.phase!=="running"||!i(1),t.buttons.s2Right.disabled=e.phase!=="running"||!i(1);let O=e.scanners.find(g=>g.kind==="manual"&&g.slot===0),W=e.scanners.find(g=>g.kind==="manual"&&g.slot===1);O&&(t.buttons.s1Left.textContent=`S1 ${O.keys?.left?.label||"A"} -> Mixer`,t.buttons.s1Right.textContent=`S1 ${O.keys?.right?.label||"D"} -> S2`),W&&(t.buttons.s2Left.textContent=`S2 ${W.keys?.left?.label||"Left"} -> Waste`,t.buttons.s2Right.textContent=`S2 ${W.keys?.right?.label||"Right"} -> Truck`);let U=Math.max(0,Math.floor(e.lastResult?.profit??e.stats?.profit??0)),M=Ko(e,Math.max(1,Number(e.turn)||1),U).amount;t.buttons.nextTurn.innerHTML=e.phase==="build"&&M>0?`NEXT DAYFAIRIES -${T(M)}`:`${re.actions.nextDay}`,t.buttons.nextTurn.disabled=e.phase!=="build"||!!e.cardDraft?.pending||!!e.cardTargetPick?.pending||!hi(e)}function z(){if(!t.eventBrief||!t.targetBrief||!t.speedBrief)return;let O=pt(e).toUpperCase();t.targetBrief.textContent=`TRUCK TARGET: ${O}`,t.speedBrief.textContent=`BELT SPEED: ${c()} px/s`,t.speedBrief.title=`Conveyor speed does not increase by day. Degraded belts reduce speed. Cap: ${Kt}px/s.`;let W=e.eventActive,U=e.eventOffer;W?(t.eventBrief.textContent=`ACTIVE EVENT: ${W.title} | ${W.route}`,t.eventBrief.className="event-brief active"):e.phase==="build"&&U?(t.eventBrief.textContent=`NEXT DAY EVENT: ${U.title} | ${U.route}${U.targetAmount?` | Target ${U.targetAmount}`:""}${U.reward?` | Reward ${T(U.reward)}`:""}`,t.eventBrief.className="event-brief next"):e.phase==="build"&&e.turn+1
\u2642Male->MixerS1: A
\u2640Female->TruckS1: D, then S2: right
\u{1F4A9}Poop->ShredderS1: D, then S2: left

Build phase: connect at least one EGG through a scanner to Mixer, Shredder, or Truck before Next Day. One day is one run.

',t.modalActions.innerHTML="",t.modalActions.appendChild(R(re.actions.startGame,o,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function ie(O){let W=G=>`${G>0?"+":""}${T(G)}`,U=G=>`${G>0?"-":""}${T(G)}`,M=O.profit>=0?"cash-positive":"cash-negative",g=(O.mixerPoopFine||0)+(O.truckPoopFine||0)+(O.maleTruckFine||0)+(O.explosionDamage||0)+(O.cardRerollCost||0);t.modalTitle.textContent=`Day ${O.turn} Settlement`,t.modalBody.innerHTML=` -
Net result${T(O.profit)}
-
-
Chick shipment income${W(O.chickShipmentIncome||0)}
-
Poop shipment income${W(O.poopShipmentIncome||0)}
-
Mixer income${W(O.mixerRevenue||0)}
-
Composter income${W(O.composterIncome||0)}
-
DUD refund income${W(O.dudRefundIncome||0)}
-
Manual combo bonus${W(O.manualComboBonus||0)}
-
Chemical subsidy${W(O.chemicalWeaponSubsidy||0)}
-
Event bonus${W(O.eventBonus||0)}
-
Penalties${U(g)}
-
Fairies fee${U(O.fairiesTribute?.amount||O.fairiesTribute||0)}
-
-

Income ${T(O.revenue)} - losses ${T(O.penalty)} = ${T(O.profit)}

`,t.modalActions.innerHTML="",t.modalActions.appendChild(R("Choose Upgrade Card",r||_,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function le(O,W){let U=Math.max(0,e.cardEffects?.rescueLoanCharges||0);t.modalTitle.textContent="Emergency Loan Available",t.modalBody.innerHTML=` -

End-of-day cash is below ${T(0)}.

-
-
Current money${T(e.cash)}
-
Emergency Loan+${T(500)}
-
Cards remaining${U}
-
-

Use one Emergency Loan to gain ${T(500)} immediately. If cash is still negative, another decision will be shown if another card remains.

`,t.modalActions.innerHTML="",t.modalActions.appendChild(R("Accept Game Over",W,"facility-action danger")),t.modalActions.appendChild(R("Use Emergency Loan",O,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function se(){let O=e.totals.processed,W=O?Math.round(e.totals.correct/O*100):0,U=Gi(e);t.modalTitle.textContent=re.phases.gameover,t.modalBody.innerHTML=`

Your cash went negative.

-
Final Score${U.score}
Survival${e.totals.turnsCompleted} days
Final Cash${T(e.cash)}
Accuracy${W}%
-
Score breakdown -
Formula
Base = Cash + Total revenue + Factory value \xD70.5 + Event bonus \xD70.5 = ${T(U.base)}
Daily earned = ceil(Base \xF7 Days) = ${T(U.dailyEarned)}
Score = max(0, floor(Base + Daily earned + Correct bonus - Total outflow - Day penalty)) = ${U.score}
-
Factory Value${T(U.factoryValue)}
Total Revenue${T(e.totals.revenue)}
Daily Earned${T(U.dailyEarned)} / day
Total Outflow${T(e.totals.penalty)}
Fairies Tribute${T(e.totals.fairiesTribute||0)}
Correct Sorts${e.totals.correct}
Auto Sorted${e.totals.autoSorted}
Poop Control${e.totals.poopTrash} trashed / ${e.totals.poopTruck} shipped / ${e.totals.poopMixer} mixer
Explosion Penalty${T(e.totals.explosionDamage)}
Event Bonus${T(e.totals.eventBonus)}
Day Penalty-${U.dayPenalty}
Events${e.totals.eventSuccess} success / ${e.totals.eventFailed} failed
-
`,t.modalActions.innerHTML="",t.modalActions.appendChild(R(re.actions.restart||"Restart",o,"primary-button restart-button")),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible","gameover-modal")}function R(O,W,U="primary-button"){let M=document.createElement("button");return M.type="button",M.className=U,M.textContent=O,M.addEventListener("click",W),M}function _(){t.modal.classList.remove("visible","equipment-popover","gameover-modal"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function Y(){}return{updatePanels:C,updateUI:j,showTitle:he,showTurnResult:ie,showEmergencyLoanDecision:le,showGameOver:se,hideModal:_,checkGameOver:Y}}function vr(e){e.totals.processed+=1}function Zt(e){e.stats.correct+=1,e.totals.correct+=1}function wt(e){e.stats.mistakes+=1,e.totals.mistakes+=1}function Ls(e){e.stats.autoSorted+=1,e.totals.autoSorted+=1}function Os(e){e.stats.poopSpawned+=1}function Ns(e){e.stats.mixerCount+=1,vr(e)}function _s(e){e.stats.trashCount+=1,vr(e)}function Gs(e,t){t==="female"?e.stats.truckFemale+=1:t==="male"&&(e.stats.truckMale+=1),vr(e)}function Zn(e,t){let n=t==="truck"?"poopTruck":t==="trash"?"poopTrash":t==="mixer"?"poopMixer":null;n&&(e.stats[n]+=1,e.totals[n]+=1)}function Us({game:e,currentConveyorSpeed:t,onGameOverCheck:n}){function o(d){return Rt(d)*Yn(d)*ps(e)/Ci(e)}function r(d){let p=F(d.col,d.row),v=1+ys(e,d),k=l(d,v);if(!k.length)return i(d,p),!0;let S=0,P=0;for(let D of k){let V=F(D.col,D.row),ae=c(V);if(ae){ae.stoppedTimer=.85,P+=1;continue}let Ne=Ds(e,{stage:"belt",scannerId:null,route:[V]});Ne.sex==="poop"&&Os(e),e.chicks.push(Ne),ji(e,d),S+=1}return S>0?(Wi(e,p.x,p.y),S>1&&H(e,p.x,p.y-28,`x${S}`,y.green),!0):P===0}function i(d,p){(d.noRouteNoticeCooldown||0)<=0&&(H(e,p.x,p.y-24,"NO BELT: PAUSED",y.warn),d.noRouteNoticeCooldown=2.5)}function l(d,p){let k=de.map(S=>({col:d.col+S.dc,row:d.row+S.dr})).filter(S=>Ee(S.col,S.row)&&e.conveyorTiles.has(I(S.col,S.row))).map(S=>({p:S,blocked:$(null,F(S.col,S.row))?1:0,roll:Math.random()}));return k.sort((S,P)=>S.blocked-P.blocked||S.roll-P.roll),k.slice(0,Math.max(1,p||1)).map(S=>S.p)}function c(d){return e.chicks.find(p=>p.stage!=="flying"&&Math.hypot(p.x-d.x,p.y-d.y)0;if(e.timeLeft=Math.max(0,e.timeLeft-d),k&&e.timeLeft<=0&&p(),e.timeLeft<=0){e.shutdownTimeLeft>0&&(e.shutdownTimeLeft=Math.max(0,e.shutdownTimeLeft-d));for(let S of e.eggFarms)S.shutterProgress=Math.min(1,(S.shutterProgress||0)+d*2.8)}if(k&&e.timeLeft>0){for(let S of e.eggFarms)if(S.noRouteNoticeCooldown>0&&(S.noRouteNoticeCooldown=Math.max(0,S.noRouteNoticeCooldown-d)),S.nextSpawn-=d,S.nextSpawn<=0){let P=r(S);S.nextSpawn=P?o(S):.15,S.lastInterval=S.nextSpawn}}for(let S=e.chicks.length-1;S>=0;S-=1){let P=e.chicks[S];P.bob+=d*7,P.stoppedTimer>0&&(P.stoppedTimer=Math.max(0,P.stoppedTimer-d)),P.stage!=="queued"&&x(P,S,d)}N(d),Gt(),on(),e.timeLeft<=0&&(e.chicks.length===0?v():e.shutdownTimeLeft<=0&&C())}function C(){if(e.cleanupBlown)return;e.cleanupBlown=!0,e.cleanupTimer=1;let d=[...e.chicks];for(let p of d)Yo(e,p.sex,p.x,p.y,-Math.PI/2,!0);e.chicks=[];for(let p of e.scanners)p.queue=[];if(Gt(),d.length){let p=d.reduce((k,S)=>k+S.x,0)/d.length,v=d.reduce((k,S)=>k+S.y,0)/d.length;Xe(e,p,v,y.warn,58),H(e,p,v-24,"CLEANUP",y.warn)}}function x(d,p,v){if(A(d)){d.stoppedTimer=.35;return}if(me(d,v),!(d.route&&d.targetIndex=d.route.length)return!1;let p=d.route[d.targetIndex];return $(d,p)}function $(d,p){if(!p)return!1;for(let v of e.chicks)if(!(d&&v.id===d.id)&&v.stage!=="flying"&&Math.hypot(v.x-p.x,v.y-p.y)1)&&d.push({x:p.x,y:p.y})}function j(d){let p=e.conveyorMeta?.get?.(d)||{},v=[];Array.isArray(p.outDirs)&&v.push(...p.outDirs),p.dir&&v.push(p.dir);let k=[...new Set(v)].filter(ae=>de.some(Ne=>Ne.name===ae)),S=te(d),P=de.filter(ae=>R(S,ae.name)).map(ae=>ae.name),D=k.filter(ae=>P.includes(ae)),V=P;return D.length?D:V}function z(d){return de.find(p=>p.name===d)||null}function ce(d,p){return e.scanners.find(v=>v.col<=d&&d<=v.col+1&&v.row-1<=p&&p<=v.row+1)||null}function he(d,p){let v=z(p);if(!v)return null;let k=ce(d.col+v.dc,d.row+v.dr);if(!k)return null;let S=Re(k,"inputA");return S&&S.col===d.col&&S.row===d.row?k:null}function ie(d){return Object.entries(e.facilities||{}).find(([,p])=>p?.entry&&p.entry.col===d.col&&p.entry.row===d.row)||null}function le(d){return d?.baseId||d?.id||""}function se(d,p){return d.side==="left"&&p==="left"||d.side==="right"&&p==="right"||d.side==="top"&&p==="up"||d.side==="bottom"&&p==="down"}function R(d,p){let v=z(p);if(!v)return null;let k={col:d.col+v.dc,row:d.row+v.dr};if(Ee(k.col,k.row)&&e.conveyorTiles.has(I(k.col,k.row)))return{type:"conveyor",dirName:p,target:F(k.col,k.row),nextCell:k};let S=he(d,p);if(S)return{type:"scanner",dirName:p,target:ye(S),scanner:S};let P=ie(d);return P&&se(P[1],p)?{type:"facility",dirName:p,facilityId:P[0],facility:P[1],target:F(d.col,d.row)}:null}function _(d,p){let v=z(p);if(!v)return!1;let k=e.conveyorMeta?.get?.(I(d.col+v.dc,d.row+v.dr));return k?[...new Set([...Array.isArray(k.outDirs)?k.outDirs:[],k.dir].filter(Boolean))].includes(v.opposite):!1}function Y(d){return de.filter(p=>Ee(d.col+p.dc,d.row+p.dr)&&e.conveyorTiles.has(I(d.col+p.dc,d.row+p.dr))).map(p=>p.name)}function O(d,p,v="random"){let k=Y(d);if(k.length<3)return p;let S=new Set(k.filter(V=>_(d,V))),P=k.filter(V=>!S.has(V)),D=S.size&&P.length>=2?P:[...new Set(p.filter(V=>k.includes(V)))];return D.length<2&&(D=k),v&&v!=="random"&&v!=="pass"&&D.includes(v)?[v]:D}function W(d,p){return p&&(p.type==="facility"||!$(d,p.target))}function U(d,p,v,k="random"){let S=v.map(ae=>R(p,ae)).filter(Boolean);if(!S.length)return null;let D=S.filter(ae=>ae.type!=="facility").filter(ae=>!$(d,ae.target)),V=D.length?D:S.filter(ae=>ae.type==="facility");return V.length?V[Math.floor(Math.random()*V.length)]:null}function M(d,p){let v=[];B(v,{x:d.x,y:d.y}),B(v,p),d.route=v.length?v:[{x:d.x,y:d.y}],d.targetIndex=d.route.length>1?1:d.route.length}function g(d,p){let v=He(d.x,d.y);if(!v)return gt(p,"OFF GRID");let k=I(v.col,v.row);if(!e.conveyorTiles.has(k))return gt(p,"OFF BELT");let S=e.conveyorMeta?.get(k)||{},P=O(v,j(k),S.branchMode||"random");if(!P.length){d.stoppedTimer=.25;return}let D=U(d,v,P,S.branchMode||"random");if(!D){d.stoppedTimer=.25;return}if(D.type==="facility"){let V=le(D.facility);V==="mixer"?io(p,D.facility):V==="truck"?gn(p,D.facility):V==="trash"?so(p,D.facility):gt(p,"DONE");return}D.type==="scanner"&&(d.pendingScannerId=D.scanner.id),d.prevConveyorCell=k,M(d,D.target)}function G(d){let p=He(d.x,d.y);if(!p)return null;let v=I(p.col,p.row);return e.conveyorTiles.has(v)?v:null}function oe(d){let p=G(d)||G(d.route?.[d.targetIndex]||d);return t(p)}function Z(d,p){let v=G(p);!v||d.lastWearKey===v||(d.lastWearKey=v,Ji(e,v))}function me(d,p){let v=oe(d)*p;for(;v>0&&d.targetIndex=D?(d.x=k.x,d.y=k.y,Z(d,k),d.targetIndex+=1,v-=D):(d.x+=S/D*v,d.y+=P/D*v,v=0)}}function ge(d,p,v){d.stage="queued",d.route=null,d.queueRoute=v?v.map(k=>({x:k.x,y:k.y})):[ye(p)],d.scannerId=p.id,p.queue.includes(d.id)||p.queue.push(d.id),Pe(p)}function Pe(d){d.queue=d.queue.filter(v=>e.chicks.some(k=>k.id===v&&k.stage==="queued"));let p=f.cell*.86*hs(e);d.queue.forEach((v,k)=>{let S=e.chicks.find(P=>P.id===v);S&&(Ae(S,S.queueRoute||[ye(d)],k*p),S.queueIndex=k)})}function Ae(d,p,v){if(!p||!p.length)return;if(p.length===1||v<=0){let P=p[p.length-1];d.x=P.x,d.y=P.y;return}let k=v;for(let P=p.length-1;P>0;P-=1){let D=p[P-1],V=p[P],ae=Math.hypot(V.x-D.x,V.y-D.y);if(k<=ae){let Ne=1-k/ae;d.x=D.x+(V.x-D.x)*Ne,d.y=D.y+(V.y-D.y)*Ne;return}k-=ae}let S=p[0];d.x=S.x,d.y=S.y}function N(d){for(let p of e.scanners){if(p.cooldown>0&&(p.cooldown=Math.max(0,p.cooldown-d)),p.keyPressTime>0&&(p.keyPressTime=Math.max(0,p.keyPressTime-d)),Pe(p),p.kind!=="auto"||p.cooldown>0||!p.queue.length)continue;let v=p.queue[0],k=e.chicks.findIndex(S=>S.id===v);if(k<0){p.queue.shift();continue}nn(k,Do(p,e.chicks[k]),!0)&&(Zi(e,p),p.cooldown=nt(p,e),Ls(e))}}function Ie(d){let p=Ro(e,d);return!p||!p.queue.length?null:e.chicks.find(v=>v.id===p.queue[0])||null}function Ye(d,p){if(e.phase!=="running")return;let v=Ro(e,d);Ve(v,p)}function Ve(d,p){if(e.phase!=="running"||!d||d.kind!=="manual"||(d.keyPressTime=.18,d.keyPressSide=p,!d.queue.length))return;let v=e.chicks.findIndex(k=>k.id===d.queue[0]);v>=0&&nn(v,p,!1)}function xe(d,p,v){return d.kind==="manual"&&Do(d,p)===v}function Ct(d){let p=e.manualCombo?.count||0;if(e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=0,e.manualCombo.lastBonus=0,e.stats.manualComboFailure=(e.stats.manualComboFailure||0)+1,e.totals.manualComboFailure=(e.totals.manualComboFailure||0)+1,p>=10){let v=ye(d);Ft(e,10,.25),H(e,v.x,v.y-36,"COMBO RESET",y.danger)}}function oo(d){e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=Math.max(0,e.manualCombo.count||0)+1,e.stats.manualComboSuccess=(e.stats.manualComboSuccess||0)+1,e.totals.manualComboSuccess=(e.totals.manualComboSuccess||0)+1;let p=e.manualCombo.count;if(e.manualCombo.lastBonus=0,p<10)return 0;let v=Math.max(1,Math.floor(p/10)),k=e.scanners.filter(V=>V.kind==="manual").length,S=Math.min(1,(20+k*10)/100),P=0;for(let V=0;V0){Ge(e,D),e.stats.manualComboBonus=(e.stats.manualComboBonus||0)+D,e.totals.manualComboBonus=(e.totals.manualComboBonus||0)+D,e.manualCombo.lastBonus=D;let V=ye(d);H(e,V.x,V.y-42,`COMBO +${T(D)}`,y.green)}return D}function Mn(d,p){let v=Re(d,p);if(!v)return null;let k=I(v.col,v.row);if(e.conveyorTiles.has(k))return{...v};let P=(_e(e).scannerPorts.get(d.id)?.[p]?.keys||[]).filter(Boolean);if(!P.length)return null;let D=P.map(te);return D.find(ae=>ae.col===v.col&&ae.row===v.row)||D[0]||null}function ro(d,p,v,k){let S=[];B(S,{x:d.x,y:d.y});let P=Re(p,v);return P&&B(S,F(P.col,P.row)),B(S,F(k.col,k.row)),S}function nn(d,p,v){let k=e.chicks[d];if(!k||k.stage!=="queued")return!1;let S=At(e,k.scannerId);if(!S)return!1;let P=Mn(S,p);if(!P)return!v&&S.kind==="manual"&&Ct(S),H(e,k.x,k.y-16,p==="left"?"NO LEFT BELT":"NO RIGHT BELT",y.danger),!1;!v&&S.kind==="manual"&&(xe(S,k,p)?oo(S):Ct(S)),S.queue=S.queue.filter(V=>V!==k.id),k.stage="belt",k.route=ro(k,S,p,P),k.targetIndex=k.route.length>1?1:k.route.length,k.scannerId=null,k.nextScannerId=null,k.pendingScannerId=null,k.queueRoute=null,k.queueIndex=-1;let D=v?y.green:p==="left"?y.mixerBlue:y.truckPink;return Ki(e,ye(S).x,ye(S).y,D),H(e,k.x,k.y-20,v?"AUTO":p.toUpperCase(),D),!0}function Mt(d){let p=e.chicks[d];return p?(e.chicks.splice(d,1),p):null}function io(d,p=e.facilities.mixer){if(p?.processingCooldown>0){let D=e.chicks[d];D&&(D.stoppedTimer=.25);return}let v=Mt(d);if(!v)return;let{x:k,y:S}=v;if(Ns(e),tr(e,p),nr(e,p),v.sex==="poop"){let D=$i(e);Zn(e,"mixer"),wt(e),qi(e,k,S),H(e,k,S-18,`-${T(D)}`,y.danger);return}let P=Di(e);v.sex==="male"?Zt(e):wt(e),Hi(e,k,S),H(e,k,S-18,`+${T(P)}`,y.green)}function gn(d,p=e.facilities.truck){let v=Mt(d);if(!v)return;let{x:k,y:S}=v;lo(v.sex,p),Vi(e,k,S,v.sex),Gs(e,v.sex);let P=pt(e),D=gi(e,v.sex);if(v.sex==="poop"){if(Zn(e,"truck"),D)Zt(e),H(e,k,S-18,`+${T(Fe(e))}`,y.green);else{let V=Fi(e);wt(e),H(e,k,S-18,`-${T(V)}`,y.danger)}return}if(v.sex==="female"){D?(Zt(e),H(e,k,S-18,`+${T(Fe(e))}`,y.green)):(wt(e),H(e,k,S-18,P==="male"?"REJECT":"NO SALE",y.warn));return}if(D){Zt(e),H(e,k,S-18,`+${T(Fe(e))}`,y.green);return}if(xi(e)){let V=Bi(e);wt(e),H(e,k,S-18,`-${T(V)}`,y.danger)}else wt(e),H(e,k,S-18,"REJECT",y.warn)}function so(d,p=e.facilities.trash){if(p?.processingCooldown>0){let V=e.chicks[d];V&&(V.stoppedTimer=.25);return}let v=Mt(d);if(!v)return;let{x:k,y:S}=v;Yi(e,k,S,v.sex),_s(e),tr(e,p),nr(e,p);let P={amount:0},D="";if(v.sex==="poop"){P=Pi(e),D=P.amount>0?` +${T(P.amount)}`:"",Zn(e,"trash"),Zt(e);let V=Math.ceil(Math.max(0,Number(e.cardEffects?.composter)||0)*3*Nn(e));if(V>0){let ae=Ge(e,V);e.stats.composterIncome=(e.stats.composterIncome||0)+ae,e.totals.composterIncome=(e.totals.composterIncome||0)+ae,H(e,k,S-36,`COMPOST +${T(ae)}`,y.green)}H(e,k,S-18,`CLEAN${D}`,P.amount>0?y.green:y.green)}else wt(e),H(e,k,S-18,P.amount>0?`WASTE${D}`:"WASTE",P.amount>0?y.green:y.ink)}function gt(d,p){let v=Mt(d);v&&H(e,v.x,v.y-12,p,y.muted)}function lo(d,p=e.facilities.truck){let v=p||e.facilities.truck;v&&(e.truckCargo.push({sex:d,x:K(22,v.w-22),y:K(66,v.h-24)}),e.truckCargo.length>45&&e.truckCargo.shift())}function xn(d){let p=He(d.x,d.y);if(p){let P=I(p.col,p.row);if(e.conveyorTiles.has(P))return P}let v=di(e,d.x,d.y);if(!v)return null;let k=te(v),S=F(k.col,k.row);return Math.hypot(d.x-S.x,d.y-S.y)<=f.cell*.55?v:null}function Gt(){let{components:d,cellToComponent:p}=ui(e);for(let v of e.chicks){if(v.stage==="flying")continue;let k=xn(v);if(!k)continue;let S=p.get(k),P=d.get(S);P&&(P.count+=1)}for(let v of d.values())v.ratio=v.count/v.capacity;e.congestion=d,e.componentLookup=p}function on(){for(let d of e.congestion.values()){let p=_o(e),v=Ti(e);if(d.ratio>v&&d.ratio=p){let k=rn(d.id);if(!k.length||k.some(D=>D.stage!=="queued"&&D.stoppedTimer<=.2))continue;let S=e.lastExplodedComponent.get(d.id)||0,P=performance.now();P-S>900&&(e.lastExplodedComponent.set(d.id,P),ao(d))}}}function rn(d){return e.chicks.filter(p=>{let v=xn(p);return v&&e.componentLookup?.get(v)===d})}function ao(d){let p=rn(d.id);if(!p.length)return;for(let S of p)Yo(e,S.sex,S.x,S.y);e.chicks=e.chicks.filter(S=>!p.some(P=>P.id===S.id));for(let S of e.scanners)S.queue=S.queue.filter(P=>e.chicks.some(D=>D.id===P));for(let S of d.cells){let P=te(S),D=F(P.col,P.row);Xe(e,D.x,D.y,y.danger),Ze(e,D.x,D.y,6),Gn(e,D.x,D.y,4)}Ft(e,18,.75);let v=te(d.cells[0]),k=F(v.col,v.row);e.stats.explosions=(e.stats.explosions||0)+1,e.totals.explosions=(e.totals.explosions||0)+1,H(e,k.x,k.y-22,`${Math.round(_o(e)*100)}% JAM EXPLOSION`,y.danger)}return{activeQueuedChick:Ie,currentSpawnDelay:o,sortSlot:Ye,updateCongestion:Gt,sortScanner:Ve,updateRunning:b}}var fe=document.getElementById("gameCanvas"),Cc=fe.getContext("2d"),L={shell:document.getElementById("gameShell"),money:document.getElementById("money"),turn:document.getElementById("turn"),timeLeft:document.getElementById("timeLeft"),phase:document.getElementById("phaseLabel"),comboCount:document.getElementById("comboCount"),eventBrief:document.getElementById("eventBrief"),targetBrief:document.getElementById("targetBrief"),speedBrief:document.getElementById("speedBrief"),turnProfit:document.getElementById("turnProfit"),mixerCount:document.getElementById("mixerCount"),truckFemaleCount:document.getElementById("truckFemaleCount"),truckMaleCount:document.getElementById("truckMaleCount"),poopCount:document.getElementById("poopCount"),buildStatus:document.getElementById("buildStatus"),turnSummary:document.getElementById("turnSummary"),modal:document.getElementById("modal"),modalTitle:document.getElementById("modalTitle"),modalBody:document.getElementById("modalBody"),modalActions:document.getElementById("modalActions"),hoverTooltip:document.getElementById("hoverTooltip"),manualScannerMonitor:document.getElementById("manualScannerMonitor"),debug:{panel:document.getElementById("debugPanel"),infiniteCash:document.getElementById("debugInfiniteCash"),dayInput:document.getElementById("debugDayInput"),setDay:document.getElementById("debugSetDayButton"),zeroTimer:document.getElementById("debugZeroTimerButton"),cardSelect:document.getElementById("debugCardSelect"),targetSelect:document.getElementById("debugTargetSelect"),grantCard:document.getElementById("debugGrantCardButton"),grantAllCards:document.getElementById("debugGrantAllCardsButton"),readout:document.getElementById("debugReadout")},buttons:{s1Left:document.getElementById("scanner1MixerButton"),s1Right:document.getElementById("scanner1TruckButton"),s2Left:document.getElementById("scanner2MixerButton"),s2Right:document.getElementById("scanner2TruckButton"),nextTurn:document.getElementById("nextTurnButton"),conveyor:document.getElementById("buildConveyorButton"),boostConveyor:document.getElementById("buildBoostConveyorButton"),eggFarm:document.getElementById("buildEggFarmButton"),autoScanner:document.getElementById("buildAutoScannerButton"),manualScanner:document.getElementById("buildManualScannerButton"),mixer:document.getElementById("buildMixerButton"),trash:document.getElementById("buildTrashButton"),truck:document.getElementById("buildTruckButton"),maintenanceRoom:document.getElementById("buildMaintenanceRoomButton"),erase:document.getElementById("eraseButton"),undo:document.getElementById("undoButton"),redo:document.getElementById("redoButton")}};function Mc(){let e={conveyor:"conveyor",boostConveyor:"boostConveyor",eggFarm:"eggFarm",autoScanner:"autoScanner",manualScanner:"manualScanner",mixer:"mixer",trash:"trash",truck:"truck",maintenanceRoom:"maintenanceRoom"};for(let[t,n]of Object.entries(e))L.buttons[t]&&(L.buttons[t].innerHTML=Or(n))}function gc(e){let t=new Set(e.tags||[]);return["upgradeEgg","crowdedFarming","hatchingFeed","extraEggOutlet"].includes(e.id)||t.has("EGG")?"Production / EGG":["upgradeTrash","poopRateBooster","composter","chemicalWeaponSubsidy"].includes(e.id)||t.has("POOP")?"Poop / Shredder":["upgradeAutoScanner","autoScannerTuning","scannerQueueSpacing"].includes(e.id)||t.has("SCANNER")?"Scanner":["bearing","dynamite"].includes(e.id)||t.has("CONVEYOR")?"Conveyor / Map":["safetyCover","preventiveMaintenance","durabilityCoating","sparePartsBin","laborExploitation"].includes(e.id)||t.has("MAINTENANCE")?"Maintenance / Risk":["dudFilter","dudRefund","freeReroll","extraCards"].includes(e.id)||t.has("CARD")?"Card Engine":t.has("ULTRA RARE")?"Ultra Rare":t.has("ECONOMY")||["upgradeMixer","upgradeTruck","recyclingSubsidy","usedMachine","newMachine","flattery","legalWork","rescueLoan"].includes(e.id)?"Economy / Shipment":"Other"}function xc(){if(!L.debug?.panel||!L.debug.cardSelect)return;let e=["Production / EGG","Poop / Shredder","Scanner","Conveyor / Map","Maintenance / Risk","Card Engine","Economy / Shipment","Ultra Rare","Other"],t=new Map(e.map(n=>[n,[]]));for(let n of Jt){let o=gc(n);t.has(o)||t.set(o,[]),t.get(o).push(n)}L.debug.cardSelect.innerHTML="";for(let n of e){let o=t.get(n)||[];if(!o.length)continue;let r=document.createElement("optgroup");r.label=n;for(let i of o){let l=document.createElement("option");l.value=i.id;let c=i.rarity==="ultraRare"?"UR":i.rarity==="rare"?"R":"C";l.textContent=`[${c}] ${i.title}`,r.appendChild(l)}L.debug.cardSelect.appendChild(r)}L.debug.cardSelect.addEventListener("change",Nt),Nt()}function Nt(){if(!L.debug?.targetSelect)return;let e=L.debug.cardSelect?.value,t=Ot(e),n=t?ms(u,t):[];if(L.debug.targetSelect.innerHTML="",!n.length){let r=document.createElement("option");r.value="__none__",r.textContent=t?"No target required":"No card selected",L.debug.targetSelect.appendChild(r),L.debug.targetSelect.disabled=!0;return}let o=document.createElement("option");o.value="__auto__",o.textContent=t?.id==="dynamite"?"Auto: first 3 blocked cells":"Auto: first valid target",L.debug.targetSelect.appendChild(o);for(let r of n){let i=document.createElement("option");i.value=r.key,i.textContent=r.label,L.debug.targetSelect.appendChild(i)}L.debug.targetSelect.disabled=!1}function Tc(){let e=Math.max(1,Math.floor(Number(L.debug.dayInput?.value)||1));u.turn=e,L.debug.dayInput&&(L.debug.dayInput.value=String(e)),H(u,fe.width/2-u.view.x,86-u.view.y,`DAY ${e}`,y.green),Q.updatePanels(),Q.updateUI(),Nt(),_t(`Day set to ${e}.`)}function Ec(){u.timeLeft=0,u.phase==="running"&&Vs(),H(u,fe.width/2-u.view.x,86-u.view.y,"TIMER 0",y.warn),Q.updatePanels(),Q.updateUI(),_t("Timer set to 0.")}function Rc(){let e=L.debug.cardSelect?.value,t=L.debug.targetSelect?.disabled?void 0:L.debug.targetSelect?.value,n=sr(u,e,{targetKey:t});L.debug.grantCard&&(L.debug.grantCard.textContent=n.ok?"Granted":"Failed",window.setTimeout(()=>{L.debug.grantCard&&(L.debug.grantCard.textContent="Grant Selected")},900)),Me?.updateCongestion?.(),Q.updatePanels(),Q.updateUI(),Nt(),_t(n.reason)}function Pc(){let t=Jt.map(n=>sr(u,n,{targetKey:"__auto__"})).filter(n=>n.ok).length;Me?.updateCongestion?.(),Q.updatePanels(),Q.updateUI(),Nt(),_t(`Granted ${t}/${Jt.length} cards.`)}function Ac(){L.debug?.infiniteCash?.checked&&u.cash<999999&&(u.cash=999999,u.totals.maxCash=Math.max(u.totals.maxCash,u.cash))}function _t(e=""){L.debug?.readout&&(L.debug.readout.textContent=[e,`D${u.turn}`,T(u.cash),`Combo ${u.manualCombo?.count||0}`,`Event ${u.eventActive?.title||u.eventOffer?.title||"none"}`,`Rescue ${u.cardEffects?.rescueLoanCharges||0}`,`Chem ${u.cardEffects?.chemicalWeaponSubsidy||0}`].filter(Boolean).join(" | "))}var u=To(),X,Q,Me,tn;function Ic(e=null){let t=Xn(u,e);return e?t*Qo(u,e):t}function Dc(){Object.assign(u,To()),u.phase="running",u.view={x:0,y:0,scale:1},Eo(u),Xs(),Se(u),Q.hideModal(),Me.updateCongestion(),Q.updatePanels(),Q.updateUI(),_t()}function $c(){if(u.phase!=="build")return;if(u.cardDraft?.pending||u.cardTargetPick?.pending){X.fail(u.cardTargetPick?.pending?"Choose upgrade target first.":"Choose an upgrade card first."),Q.updatePanels();return}let e=pn(u);if(e.length){X.fail(`Cannot start: ${e[0]}`),Q.updatePanels();return}Se(u),ci(u),os(u);let t=Math.max(0,Math.floor(u.lastResult?.profit??u.stats?.profit??0)),n=Ni(u,Math.max(1,u.turn||1),t);u.lastStartFees={fairiesTribute:n.amount||0,tribute:n},n.amount>0&&H(u,fe.width/2-u.view.x,116-u.view.y,`FAIRIES -${T(n.amount)}`,y.danger),wi(u),u.phase="running",u.turn+=1,u.timeLeft=ki(u),u.shutdownTimeLeft=0,u.cleanupTimer=null,u.cleanupBlown=!1,u.chicks=[],u.effects=[],u.floatingTexts=[],u.shake={time:0,strength:0},u.truckCargo=[],Xs(),u.stats=xo(),u.stats.fairiesTribute=u.lastStartFees?.fairiesTribute||0,u.stats.fairiesTribute>0&&(u.stats.penalty+=u.stats.fairiesTribute,u.stats.profit-=u.stats.fairiesTribute);for(let o of u.scanners)o.queue=[],o.cooldown=0;for(let o of u.eggFarms)o.nextSpawn=Me.currentSpawnDelay(o),o.lastInterval=o.nextSpawn,o.shutterProgress=0,o.shutterSparked=!1;u.buildTool=null,u.selected=null,u.groupDrag=null,u.selectionBox=null,u.pan=null,Me.updateCongestion(),Q.updatePanels(),Q.updateUI()}function Fc(){if(u.phase!=="running")return;let e=Oi(u),t=u.eventActive?{...u.eventActive}:null,n=Ri(u),o=_i(u);if(e.adjusted>0){let i=u.facilities.truck,l=i?i.x+i.w/2:fe.width/2-u.view.x,c=i?i.y+26:96-u.view.y;H(u,l,c,`${e.target==="poop"?"POOP SHIP":"SHIP"} +${T(e.adjusted)}`,y.green)}n?.bonus>0&&H(u,fe.width/2-u.view.x,96-u.view.y,`EVENT +${T(n.bonus)}`,y.green),o.amount>0&&H(u,fe.width/2-u.view.x,116-u.view.y,`CHEM SUBSIDY +${T(o.amount)}`,y.green),Si(u),u.totals.turnsCompleted+=1;let r=Ei(t);if(r!==1&&(u.pendingFairiesTributeMultiplier=r),u.lastResult={...u.stats,ship:e,event:n,chemical:o,rescue:{amount:0,used:0,remaining:u.cardEffects?.rescueLoanCharges||0},fairiesTribute:{amount:u.stats.fairiesTribute||0},tributeMultiplier:r,turn:u.turn,cash:u.cash},u.cash<0){if((u.cardEffects?.rescueLoanCharges||0)>0){u.phase="loanDecision",Q.showEmergencyLoanDecision(Ys,eo);return}u.phase="gameover",Q.showGameOver();return}qs()}function qs(){u.phase="build",u.truckCargo=[],u.chicks=[],u.shutdownTimeLeft=0,u.cleanupTimer=null,u.cleanupBlown=!1,u.buildSession+=1,u.undoStack=[],u.redoStack=[],u.timeLeft=0;for(let e of u.scanners)e.queue=[];for(let e of u.eggFarms)e.shutterProgress=0,e.shutterSparked=!1;rs(u),u.eventOffer=vi(u),tn&&tn.prepareDraft(),u.cardTargetPick=null,u.buildTool=null,u.groupDrag=null,u.selectionBox=null,u.pan=null,Q.updatePanels(),Q.showTurnResult(u.lastResult)}function Ys(){if((u.cardEffects?.rescueLoanCharges||0)<=0)return eo();u.cardEffects.rescueLoanCharges-=1,u.stats.rescueLoan=(u.stats.rescueLoan||0)+500,u.totals.rescueLoan=(u.totals.rescueLoan||0)+500;let e=Ge(u,500);u.lastResult={...u.lastResult||{},...u.stats,rescue:{amount:(u.lastResult?.rescue?.amount||0)+e,used:(u.lastResult?.rescue?.used||0)+1,remaining:u.cardEffects.rescueLoanCharges},cash:u.cash},H(u,fe.width/2-u.view.x,176-u.view.y,`RESCUE +${T(e)}`,y.green),u.cash>=0?qs():(u.cardEffects?.rescueLoanCharges||0)>0?(u.phase="loanDecision",Q.showEmergencyLoanDecision(Ys,eo)):eo()}function eo(){u.phase="gameover",Q.showGameOver()}function Vs(){u.shutdownTimeLeft<=0&&(u.shutdownTimeLeft=u.shutdownGraceSeconds||10);for(let e of u.eggFarms){if(e.shutterSparked)continue;e.shutterProgress=.02,e.shutterSparked=!0;let t=F(e.col,e.row);Xe(u,t.x,t.y,y.ink),Ze(u,t.x,t.y+10,10),H(u,t.x,t.y-34,"SHUT +10s",y.ink)}}function zs(e){u.lastTimestamp||(u.lastTimestamp=e);let t=Math.min((e-u.lastTimestamp)/1e3,.05);u.lastTimestamp=e,u.phase==="running"&&Me.updateRunning(t,{closeFarmShutters:Vs,completeTurn:Fc}),Xi(u,t,fe,X.equipmentHitBoxes),Me.updateCongestion(),Cs(Cc,fe,u,{activeQueuedChick:Me.activeQueuedChick,selectedObject:X.selectedObject,selectedTitle:X.selectedTitle}),Ac(),Q.updateUI(),Js(),_t(),requestAnimationFrame(zs)}function to(){return u.view?.scale||1}function Cn(){u.view||(u.view={x:0,y:0,scale:1}),u.view.scale==null&&(u.view.scale=1)}function no(e){let t=fe.getBoundingClientRect();return{x:(e.clientX-t.left)*fe.width/t.width,y:(e.clientY-t.top)*fe.height/t.height}}function St(e){let t=no(e),n=to();return{x:(t.x-(u.view?.x||0))/n,y:(t.y-(u.view?.y||0))/n}}function Bc(e){let t=to();return{x:e.x*t+(u.view?.x||0),y:e.y*t+(u.view?.y||0)}}function Lc(){let e={left:f.x-90,top:f.y-130,right:f.x+f.cols*f.cell+260,bottom:f.y+f.rows*f.cell+220};if(u.phase==="build")for(let t of Tt(u)){let n=Et(t);e.left=Math.min(e.left,n.x-60),e.top=Math.min(e.top,n.y-80),e.right=Math.max(e.right,n.x+n.w+80),e.bottom=Math.max(e.bottom,n.y+n.h+80)}return e}function Ws(e,t){if(e<=t)return[e,t];let n=(e+t)/2;return[n,n]}function kt(){Cn();let e=to(),t=Lc(),[n,o]=Ws(fe.width-160-t.right*e,110-t.left*e),[r,i]=Ws(fe.height-150-t.bottom*e,150-t.top*e);u.view.x=dn(u.view.x,n,o),u.view.y=dn(u.view.y,r,i)}function Xs(){Cn(),u.view.scale=1;let e=u.eggFarms?.[0],t=e?F(e.col,e.row):{x:f.x,y:f.y};u.view.x=280-t.x,u.view.y=190-t.y,kt()}function Oc(e){let t=no(e);Cn(),u.pan={start:t,viewX:u.view.x,viewY:u.view.y,moved:!1}}function Nc(e){if(!u.pan)return;let t=no(e);Math.hypot(t.x-u.pan.start.x,t.y-u.pan.start.y)>5&&(u.pan.moved=!0),Cn(),u.view.x=u.pan.viewX+t.x-u.pan.start.x,u.view.y=u.pan.viewY+t.y-u.pan.start.y,kt()}function _c(e){e.preventDefault(),Cn();let t=no(e),n=St(e),o=Math.exp(-e.deltaY*.0012),r=dn(to()*o,.55,1.8);u.view.scale=r,u.view.x=t.x-n.x*r,u.view.y=t.y-n.y*r,kt(),it()}function Gc(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:{type:e.type,id:e.ref.id}:null}function Uc(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:e.ref||null:null}function it(){L.hoverTooltip&&(L.hoverTooltip.classList.remove("visible"),L.hoverTooltip.setAttribute("aria-hidden","true"),u.hover=null)}function Wc(e,t){if(!L.hoverTooltip||u.phase!=="build"||u.cardTargetPick?.pending||u.groupDrag||u.selectionBox||u.pan)return it();let n=Uc(t);if(!n)return it();let o=X.selectedTitle(n),r=X.flavorText?X.flavorText(n):"",i=X.disconnectedWarningFor?X.disconnectedWarningFor(n):"",l=X.selectedInfoLines(n).slice(0,7);L.hoverTooltip.innerHTML=`${o}${i?`${i}`:r?`${r}`:""}${l.map(C=>`${C}`).join("")}`;let c=Math.min(window.innerWidth-330,e.clientX+18),b=Math.min(window.innerHeight-220,e.clientY+18);L.hoverTooltip.style.left=`${Math.max(8,c)}px`,L.hoverTooltip.style.top=`${Math.max(8,b)}px`,L.hoverTooltip.classList.add("visible"),L.hoverTooltip.setAttribute("aria-hidden","false"),u.hover={type:t.type,id:t.oldKey||t.ref?.id||null}}function Kc(e){if(u.phase!=="build")return it();Wc(e,X.equipmentAtPoint(St(e)))}function Qs(e){it();let t=St(e),n=X.equipmentAtPoint(t),o=Gc(n);if(!o){u.selected=null,u.multiSelected=[],Q.updatePanels();return}u.selected=o,u.multiSelected=[o],Q.updatePanels();let r=X.selectedObject();r?.type==="scanner"&&r.kind==="manual"&&X.showManualScannerMenu(r),r?.type==="scanner"&&r.kind==="auto"&&X.showAutoScannerMenu(r)}function en(){u.buildTool=null,u.selected=null,u.multiSelected=[],u.selectionBox=null,u.cardTargetPick?.mode==="autoScannerMenu"&&(u.cardTargetPick=null),Q.hideModal(),it(),Q.updatePanels(),Q.updateUI()}function Ks(e){return String(e).replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function Hc(e){let t=e?.queue?.[0];return t==null?null:u.chicks.find(n=>n.id===t)||null}function qc(e){if(!e)return'WAIT';let t=e.sex==="poop"?"\u{1F4A9} POOP":e.sex==="male"?"\u2642 MALE":"\u2640 FEMALE";return`${t}`}function Yc(e,t){let n=new Set(u.eggFarms.map(x=>I(x.col,x.row))),o=new Map(u.scanners.map(x=>[I(x.col,x.row),x])),r=Re(e,"inputA"),i=r?I(r.col,r.row):null,l=new Set(Object.values(u.facilities||{}).map(x=>x.entry?I(x.entry.col,x.entry.row):null).filter(Boolean)),c=t?.sex||"",b=c==="poop"?"\u{1F4A9}":c==="male"?"\u2642":c==="female"?"\u2640":"",C=[];for(let x=e.row-2;x<=e.row+2;x+=1)for(let A=e.col-2;A<=e.col+2;A+=1){let $=I(A,x),B=["mini-cell"],j="";A===e.col&&x===e.row?(B.push("scanner"),c&&B.push(c),j=b||"S"):$===i?(B.push("input"),j="IN"):n.has($)?(B.push("egg"),j="E"):o.has($)?(B.push("scanner-other"),j="S"):l.has($)?(B.push("port"),j="P"):u.conveyorTiles.has($)?(B.push("belt"),j="\u2022"):u.blockedCells?.has?.($)&&(B.push("blocked"),j="\xD7"),C.push(`${j}`)}return`
${C.join("")}
`}function Vc(e){let t=Bc(F(e.col,e.row)),n=76;return t.x<-n||t.y<-n||t.x>fe.width+n||t.y>fe.height+n}function Js(){if(!L.manualScannerMonitor)return;if(u.phase!=="running"){L.manualScannerMonitor.classList.remove("visible"),L.manualScannerMonitor.innerHTML="";return}let e=u.scanners.filter(t=>t.kind==="manual"&&Vc(t));if(!e.length){L.manualScannerMonitor.classList.remove("visible"),L.manualScannerMonitor.innerHTML="";return}L.manualScannerMonitor.innerHTML=e.map(t=>{let n=Hc(t),o=t.keys?.left?.label||(t.slot===0?"A":"Left"),r=t.keys?.right?.label||(t.slot===0?"D":"Right"),i=t.role===0?"MIXER":"WASTE",l=t.role===0?"S2":"TRUCK",c=n?"":" disabled";return` -
-
S${(t.slot??0)+1}OFFSCREEN / Q:${t.queue.length}
-
- IN${qc(n)}SCANNER -
- ${Yc(t,n)} -
- - -
-
`}).join(""),L.manualScannerMonitor.classList.add("visible")}L.manualScannerMonitor?.addEventListener("click",e=>{let t=e.target.closest("button[data-scanner-id]");if(!t||t.disabled)return;let n=u.scanners.find(o=>o.id===Number(t.dataset.scannerId));n&&(Me.sortScanner(n,t.dataset.side),Js())});fe.addEventListener("contextmenu",e=>e.preventDefault());fe.addEventListener("wheel",_c,{passive:!1});fe.addEventListener("pointerdown",e=>{if(u.phase!=="build")return;fe.setPointerCapture(e.pointerId);let t=St(e);if(e.button===2){Oc(e);return}if(e.button!==0)return;if(u.cardTargetPick?.mode==="autoScannerMenu"){en();return}if(u.cardTargetPick?.pending){tn.chooseTargetAtPoint(t);return}let n=X.expansionOfferAtPoint?.(t);if(n){X.buyGridExpansion(n),kt(),Q.updatePanels(),Q.updateUI();return}if(X.cycleBranchModeAtPoint?.(t)){Q.updatePanels(),Q.updateUI();return}let o=He(t.x,t.y),r=X.equipmentAtPoint(t);if(!u.buildTool&&r?.type==="conveyor"&&o&&X.cycleSingleConveyorDirection?.(o)){Q.updatePanels(),Q.updateUI();return}if(u.buildTool==="erase"){if(!X.equipmentAtPoint(t)){en();return}X.eraseAtPoint(t);return}if(u.buildTool){let i=He(t.x,t.y);if(!i&&!["mixer","trash","truck"].includes(u.buildTool)){en();return}if(u.buildTool==="conveyor"||u.buildTool==="boostConveyor"){X.beginConveyorDrag(i);return}if(X.equipmentAtPoint(t)){u.buildTool=null,Qs(e);return}X.buildAtPoint(t);return}X.startGroupDrag(e)||X.startSelectionBox(e)});fe.addEventListener("pointermove",e=>{if(u.phase!=="build"){it();return}Kc(e),u.pan&&e.buttons&2&&Nc(e),u.groupDrag&&e.buttons&1&&X.updateGroupDrag(e),u.selectionBox&&e.buttons&1&&X.updateSelectionBox(e),(u.buildTool==="conveyor"||u.buildTool==="boostConveyor")&&e.buttons&1&&X.continueConveyorDrag(He(St(e).x,St(e).y)),u.buildTool==="erase"&&e.buttons&1&&X.eraseAtPoint(St(e))});fe.addEventListener("pointerup",e=>{u.selectionBox?X.finishSelectionBox():u.groupDrag&&(u.groupDrag.committed||Qs(e),X.finishGroupDrag()),e.button===2&&u.pan&&!u.pan.moved&&u.buildTool&&en(),(u.buildTool==="conveyor"||u.buildTool==="boostConveyor")&&X.endConveyorDrag?.(),u.groupDrag=null,u.pan=null;try{fe.releasePointerCapture(e.pointerId)}catch{}});fe.addEventListener("pointerleave",it);fe.addEventListener("pointercancel",()=>{X?.endConveyorDrag?.(),u.groupDrag=null,u.selectionBox=null,u.pan=null,it()});document.addEventListener("pointerdown",e=>{!L.modal.classList.contains("visible")||!L.modal.classList.contains("equipment-popover")||e.target.closest("#modal .modal-card")||en()},!0);L.buttons.s1Left.addEventListener("click",()=>Me.sortSlot(0,"left"));L.buttons.s1Right.addEventListener("click",()=>Me.sortSlot(0,"right"));L.buttons.s2Left.addEventListener("click",()=>Me.sortSlot(1,"left"));L.buttons.s2Right.addEventListener("click",()=>Me.sortSlot(1,"right"));L.buttons.nextTurn.addEventListener("click",$c);L.buttons.conveyor.addEventListener("click",()=>X.setBuildTool("conveyor"));L.buttons.boostConveyor.addEventListener("click",()=>X.setBuildTool("boostConveyor"));L.buttons.eggFarm.addEventListener("click",()=>X.setBuildTool("eggFarm"));L.buttons.autoScanner.addEventListener("click",()=>X.setBuildTool("autoScanner"));L.buttons.manualScanner.addEventListener("click",()=>X.setBuildTool("manualScanner"));L.buttons.mixer.addEventListener("click",()=>X.setBuildTool("mixer"));L.buttons.trash.addEventListener("click",()=>X.setBuildTool("trash"));L.buttons.truck.addEventListener("click",()=>X.setBuildTool("truck"));L.buttons.maintenanceRoom.addEventListener("click",()=>X.setBuildTool("maintenanceRoom"));L.buttons.erase.addEventListener("click",()=>X.setBuildTool("erase"));L.debug.setDay?.addEventListener("click",Tc);L.debug.zeroTimer?.addEventListener("click",Ec);L.debug.grantCard?.addEventListener("click",Rc);L.debug.grantAllCards?.addEventListener("click",Pc);L.buttons.undo.addEventListener("click",()=>{Ho(u)&&(kt(),Q.updatePanels(),Q.updateUI(),Nt())});L.buttons.redo.addEventListener("click",()=>{qo(u)&&(kt(),Q.updatePanels(),Q.updateUI(),Nt())});function Hs(e,t,n){let o=e.keys?.[t];return o?o.code&&n.code===o.code||o.key&&n.key.toLowerCase()===o.key:!1}window.addEventListener("keydown",e=>{if(e.repeat)return;let t=e.key.toLowerCase();if(u.phase==="running")for(let n of u.scanners.filter(o=>o.kind==="manual")){if(Hs(n,"left",e)){e.preventDefault(),Me.sortScanner(n,"left");return}if(Hs(n,"right",e)){e.preventDefault(),Me.sortScanner(n,"right");return}}u.phase==="build"&&(e.ctrlKey||e.metaKey)&&t==="z"&&(e.preventDefault(),Ho(u)&&(kt(),Q.updatePanels(),Q.updateUI())),u.phase==="build"&&(e.ctrlKey||e.metaKey)&&(t==="y"||e.shiftKey&&t==="z")&&(e.preventDefault(),qo(u)&&(kt(),Q.updatePanels(),Q.updateUI())),e.key==="Escape"&&u.cardTargetPick?.pending&&(e.preventDefault(),u.cardTargetPick.mode==="autoScannerMenu"?en():tn.cancelTargetPick())});X=Fs({game:u,ui:L,canvas:fe,canvasPoint:St,onUpdatePanels:()=>Q?.updatePanels()});Me=Us({game:u,currentConveyorSpeed:Ic,onGameOverCheck:()=>Q?.checkGameOver()});tn=ws({game:u,ui:L,onUpdatePanels:()=>Q?.updatePanels()});Q=Bs({game:u,ui:L,build:X,startGame:Dc,beginCardDraft:()=>tn.showDraft(),activeQueuedChick:Me.activeQueuedChick});Mc();xc();Eo(u);Se(u);Me.updateCongestion();Q.updatePanels();Q.updateUI();Q.showTitle();_t();requestAnimationFrame(zs); diff --git a/dist/game.js b/dist/game.js index 0bd90d6..06d7c9c 100644 --- a/dist/game.js +++ b/dist/game.js @@ -1,60 +1 @@ -var q={version:"v27.15 dark factory visual patch",time:{daySeconds:60,farmShutdownGraceSeconds:10},cash:{starting:250},grid:{x:170,y:78,cols:20,rows:10,cell:46,expansion:{colsPerPurchase:10,rowsPerPurchase:10,costBase:1e3,costMultiplier:1.3333333333333333,truncateUnit:100}},map:{blockedRatio:.075},economy:{income:{mixer:5,truck:10},poopFine:10,fairiesTribute:{perDay:10,profitExemption:300,legalWorkExemptionBonus:250,profitRate:.12},incomeUpgradeRate:1.1,explosionDamageDivisor:30,maleTruckFinePerHalfDay:30,shredderBonus:{maxCards:30,incomePerUpgrade:1.25},chemicalWeaponSubsidy:{poopPerBlock:70,yenPerBlock:1200}},production:{poopRate:.08,autoScannerCooldown:3.5,autoScannerUpgradeRate:.95,autoScannerCardUpgradeRate:.95,autoScannerMinCooldown:.5,poopRateCardBonus:.04,eggSpawnRanges:[[1.95,4.35],[1.55,3.45],[1.25,2.8],[1.05,2.35]]},conveyor:{baseSpeed:52,maxSpeed:300,bearingSpeedMultiplier:1.075},cards:{definitions:[{id:"upgradeEgg",title:"EGG Improvement",rarity:"common",type:"equipmentUpgrade",target:"eggFarm",description:"Choose one EGG FARM on the map and raise it by 1 level.",tags:["EGG","ACTIVE"]},{id:"upgradeAutoScanner",title:"AUTO SCANNER Improvement",rarity:"common",type:"equipmentUpgrade",target:"autoScanner",description:"Choose one AUTO SCANNER on the map and raise it by 1 level.",tags:["SCANNER","ACTIVE"]},{id:"autoScannerTuning",title:"AUTO SCANNER Tuning",rarity:"common",type:"instant",description:"All AUTO SCANNER cooldowns use default cooldown x0.95 per copy.",tags:["SCANNER","PASSIVE"]},{id:"upgradeMixer",title:"MIXER Improvement",rarity:"common",type:"equipmentUpgrade",target:"mixer",description:"Choose MIXER on the map and raise it by 1 level.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeTruck",title:"TRUCK Improvement",rarity:"common",type:"equipmentUpgrade",target:"truck",description:"Choose TRUCK on the map and raise it by 1 level.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeTrash",title:"SHREDDER Improvement",rarity:"common",type:"equipmentUpgrade",target:"trash",description:"Shred poops for a little money. Max 30 upgrades.",tags:["POOP","ACTIVE"]},{id:"crowdedFarming",title:"Crowded Farming",rarity:"common",type:"instant",description:"EGG production interval -5%. Equipment deterioration +4%. Max 10 cards.",tags:["EGG","RISK","PASSIVE"]},{id:"hatchingFeed",title:"Hatching Feed",rarity:"common",type:"instant",description:"EGG production interval -4%. Poop rate +3%. No card limit.",tags:["EGG","POOP","PASSIVE"]},{id:"poopRateBooster",title:"Poop Culture",rarity:"common",type:"instant",description:"Base poop rate +4 percentage points. No card limit.",tags:["POOP","PASSIVE"]},{id:"safetyCover",title:"Safety Cover",rarity:"common",type:"instant",description:"Explosion damage -5%. No card limit.",tags:["RISK","PASSIVE"]},{id:"preventiveMaintenance",title:"Preventive Maintenance Manual",rarity:"common",type:"instant",description:"All equipment deterioration speed -5%. No card limit.",tags:["MAINTENANCE","PASSIVE"]},{id:"dudFilter",title:"DUD Filter",rarity:"common",type:"instant",description:"DUD chance -5 percentage points. Stacks until DUD chance reaches 0%.",tags:["CARD","PASSIVE"]},{id:"durabilityCoating",title:"Durability Coating",rarity:"common",type:"instant",description:"All equipment maximum durability +3%. No card limit.",tags:["MAINTENANCE","PASSIVE"]},{id:"bearing",title:"High-Quality Bearing",rarity:"common",type:"instant",description:"Conveyor speed +7.5%.",tags:["CONVEYOR","PASSIVE"]},{id:"sparePartsBin",title:"SPARE PARTS BIN",rarity:"common",type:"instant",description:"Restores 2% durability to every machine. A box of almost-compatible parts.",tags:["MAINTENANCE","ACTIVE"]},{id:"dudRefund",title:"DUD REFUND",rarity:"common",type:"instant",description:"DUDs now come with paperwork. Gain JPY 50 per copy when you pick a DUD.",tags:["CARD","ECONOMY","PASSIVE"]},{id:"freeReroll",title:"FREE REROLL",rarity:"common",type:"instant",description:"The first bad ideas are free.",tags:["CARD","PASSIVE"]},{id:"composter",title:"COMPOSTER",rarity:"common",type:"instant",description:"Turns shredder waste into suspicious fertilizer. Gain JPY 3 per copy when SHREDDER processes poop.",tags:["POOP","ECONOMY","PASSIVE"]},{id:"scannerQueueSpacing",title:"Scanner Queue Spacing",rarity:"common",type:"instant",description:"Manual and Auto Scanner queue spacing -15%. No card limit.",tags:["SCANNER","PASSIVE"]},{id:"extraEggOutlet",title:"Extra Egg Outlet",rarity:"rare",type:"equipmentUpgrade",target:"eggOutlet",description:"Choose one EGG FARM and add +1 output port to that EGG. Max +3 per EGG.",tags:["EGG","RARE","ACTIVE"]},{id:"recyclingSubsidy",title:"Recycling Subsidy",rarity:"rare",type:"instant",description:"SELL refund rate +10 points. Max 3 cards; normal SELL can reach 80%.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"dynamite",title:"Dynamite",rarity:"rare",type:"cellAction",target:"blockedCell",description:"Remove any 3 unbuildable cells",tags:["RISK","RARE","ONE-SHOT"]},{id:"usedMachine",title:"Used Machines",rarity:"rare",type:"instant",description:"Future equipment costs half. New purchases have no refund and 60% durability. New Machines cancels it.",tags:["ECONOMY","RISK","RARE"]},{id:"newMachine",title:"New Machines",rarity:"common",type:"instant",description:"Cancel Used Machines and restore normal prices, refunds, and durability.",tags:["ECONOMY","ONE-SHOT"]},{id:"flattery",title:"Flattery",rarity:"rare",type:"instant",description:"Next Fairies tribute -50%.",tags:["ECONOMY","RARE","ONE-SHOT"]},{id:"extraCards",title:"Extra Cards",rarity:"rare",type:"instant",description:"Draw 2 cards now and choose both.",tags:["RARE","ACTIVE"]},{id:"legalWork",title:"Legal Work",rarity:"rare",type:"instant",description:"Fairies tribute profit exemption +JPY 250.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"chemicalWeaponSubsidy",title:"Chemical Weapons Subsidy",rarity:"ultraRare",type:"instant",description:"Each day, gain JPY 1200 per 70 poop shipped by truck. No card limit.",tags:["POOP","ULTRA RARE","PASSIVE"]},{id:"laborExploitation",title:"Motivational Exploitation",rarity:"ultraRare",type:"instant",description:"Repairman labor cost -30%. The repairman smiles with bloodshot eyes. One time only.",tags:["MAINTENANCE","ULTRA RARE","PASSIVE"]},{id:"rescueLoan",title:"Emergency Loan",rarity:"ultraRare",type:"instant",description:"If cash is below JPY 0 at day-end settlement, gain JPY 500. Consumed on use.",tags:["ECONOMY","ULTRA RARE","ONE-SHOT"]}],defaultEffects:{bearing:0,legalWork:0,fairiesFlatteryNext:0,autoScannerTuning:0,poopRateBooster:0,crowdedFarming:0,hatchingFeed:0,safetyCover:0,recyclingSubsidy:0,chemicalWeaponSubsidy:0,preventiveMaintenance:0,dudFilter:0,durabilityCoating:0,sparePartsBin:0,dudRefund:0,freeReroll:0,composter:0,scannerQueueSpacing:0,laborExploitation:0,usedMachineActive:!1,rescueLoanCharges:0},commonWeight:8,rareWeight:2,ultraRareWeight:.45,baseDraftSize:3,maxDudsPerDraft:2,dudChancePerCard:.3,dudChanceReductionPerFilter:.05,extraCardsAddedPicks:2,rerollCost:{dayDivisor:2,multiplier:100}},events:{eventChance:.1,firstTurn:8},maintenance:{fullPerformanceUntilWear:.5,minimumPerformance:.5,durability:{conveyor:1300,eggFarm:475,autoScanner:850,mixer:775,trash:950},processingDelayMaxSeconds:{mixer:1.2,trash:1},repairman:{dailyCost:100,secondsPerOnePercent:.5,walkSpeed:90}},facilities:{conveyor:{id:"conveyor",type:"conveyor",name:"Conveyor",shortName:"Belt",price:30,buildable:!0,upgradeable:!1},boostConveyor:{id:"boostConveyor",type:"conveyor",name:"Boost Conveyor",shortName:"BOOST BELT",price:75,buildable:!0,upgradeable:!1,speedMultiplier:2},eggFarm:{id:"eggFarm",type:"eggFarm",name:"Egg Farm",shortName:"EGG",price:250,buildable:!0,upgradeable:!0,maxLevel:4},manualScanner:{id:"manualScanner",type:"scanner",kind:"manual",name:"Manual Scanner",shortName:"Manual Scanner",price:260,buildable:!0,upgradeable:!1},autoScanner:{id:"autoScanner",type:"scanner",kind:"auto",name:"Auto Scanner",shortName:"Auto Scanner",price:180,buildable:!0,upgradeable:!1},mixer:{id:"mixer",type:"facility",name:"Mixer",shortName:"MIXER",price:450,buildable:!0,upgradeable:!0,incomeKey:"mixer",body:{w:164,h:126}},trash:{id:"trash",type:"facility",name:"Waste Shredder",shortName:"SHREDDER",price:240,buildable:!0,upgradeable:!0,body:{w:180,h:100}},truck:{id:"truck",type:"facility",name:"Truck",shortName:"TRUCK",price:450,buildable:!0,upgradeable:!0,incomeKey:"truck",body:{w:176,h:138}}}};var Sn=q.version,wt=q.time.daySeconds,tn=q.cash.starting,xe=q.economy,kr=q.time.farmShutdownGraceSeconds,kn=q.production.autoScannerCooldown,xr=q.production.autoScannerUpgradeRate,co=q.production.autoScannerCardUpgradeRate||q.production.autoScannerUpgradeRate,uo=q.production.autoScannerMinCooldown,Cr=q.events.eventChance,St=q.events.firstTurn,fo=q.production.poopRate,po=q.production.poopRateCardBonus||0,xn=q.conveyor.baseSpeed,_t=q.conveyor.maxSpeed,Cn=q.conveyor.bearingSpeedMultiplier,Ae=q.cards,Mr=q.cards.definitions,yo=q.cards.defaultEffects,lt=q.production.eggSpawnRanges,y=q.grid,ke=q.facilities,ho=["conveyor","boostConveyor","eggFarm","autoScanner","manualScanner","mixer","trash","truck"],nn=["mixer","trash","truck"],gr=["mixer","truck"],kt=Object.fromEntries(Object.entries(ke).map(([e,t])=>[e,t.price])),ue=[{name:"right",dc:1,dr:0,angle:0,opposite:"left"},{name:"left",dc:-1,dr:0,angle:Math.PI,opposite:"right"},{name:"down",dc:0,dr:1,angle:Math.PI/2,opposite:"up"},{name:"up",dc:0,dr:-1,angle:-Math.PI/2,opposite:"down"}],p={bg:"#111318",ink:"#090a0d",muted:"#8f9bab",green:"#7bd84f",greenSoft:"#273c24",mixerBlue:"#4aa3ff",truckPink:"#ffb33e",wasteGreen:"#88d35a",danger:"#e34a36",warn:"#ffb827",white:"#e6edf2",poop:"#7b4a23",male:"#ffd23d",female:"#ffdf69"},Ce={ambient:0,important:1,critical:2};function M(e){let t=Number(e)||0;return`${t<0?"-":""}\uFFE5${Math.ceil(Math.abs(t)).toLocaleString("ja-JP")}`}function I(e,t){return`${e},${t}`}function Q(e){let[t,n]=String(e).split(",").map(Number);return{col:t,row:n}}function on(e,t,n){return Math.max(t,Math.min(n,e))}function G(e,t){return e+Math.random()*(t-e)}function Ee(e,t){return e>=0&&e=0&&tMath.round(on(r,0,255)).toString(16).padStart(2,"0");return`#${o(e)}${o(t)}${o(n)}`}function gn(e,t,n){let o=Tr(e),r=Tr(t);return nl(mo(o.r,r.r,n),mo(o.g,r.g,n),mo(o.b,r.b,n))}var re={appTitle:"Chick Sorter",versionTitle:`Chick Sorter ${Sn}`,currency:"\uFFE5",phases:{title:"Title",build:"Build",running:"Sorting",clearing:"Clearing",loanDecision:"Emergency Loan",gameover:"Game Over"},actions:{startGame:"Start Game",nextDay:"Next Day",buildPhase:"Build Phase",restart:"Restart",close:"Close",remove:"Remove",refund:"Refund",autoMenu:"Auto Menu"},status:{build:e=>`BUILD: ${(e==="erase"?"SELL":e||"SELECT").toUpperCase()} | Right-drag pan | Hover equipment for info`,sorting:"Sorting: use scanner keys. Build after clearing the day.",allPortsConnected:"Start condition met: one EGG route reaches an exit.",equipmentPanelEmpty:"Hover equipment in Build phase.",eventPanelRunning:"Forced events appear in Build phase."},routeLabels:{mixer:"MIXER",truck:"TRUCK",trash:"WASTE",scanner:"NEXT","scanner-role-1":"NEXT",input:"IN"},fail:{outOfGrid:"Out of grid",cellOccupied:"Cell occupied",notEnoughCash:"Not enough cash",facilityExists:"Facility already exists",facilityOverlap:"Facility overlap",nothingToErase:"Nothing to sell",noUpgrade:"No upgrade available"}};function xt(e){return ke[e]?.name||String(e||"").replace(/^[a-z]/,t=>t.toUpperCase())}function ol(e){let t=ke[e];return t?e==="conveyor"||e==="boostConveyor"?`${M(t.price)} / tile`:e==="autoScanner"?`${M(t.price)} / ${kn.toFixed(1)}s cooldown`:e==="trash"?M(t.price):M(t.price):""}function rl(e){return{conveyor:"A narrow green belt. Routes decide whether chicks live, ship, or become invoices.",boostConveyor:"Moves chicks twice as fast. Wears down like a normal belt.",eggFarm:"A tiny gatehouse producing questionable eggs on schedule.",autoScanner:"Slower than hands without upgrades.",manualScanner:"A manual checkpoint. The operator is the algorithm.",mixer:"Male chicks become revenue here. Do not feed it poop.",trash:"A polite shredder for poop and other regrets.",truck:"Ships the target cargo. Wrong cargo still leaves a paper trail."}[e]||""}function Pr(e){let t=rl(e);return`${xt(e)}${ol(e)}${t?`${t}`:""}`}function Rr(e){return re.routeLabels[e]||String(e).toUpperCase()}function Ar(e){let t=2166136261;for(let n=0;n>>0}function Dr(e){let t=e>>>0;return()=>{t+=1831565813;let n=Math.imul(t^t>>>15,1|t);return n^=n+Math.imul(n^n>>>7,61|n),((n^n>>>14)>>>0)/4294967296}}function Tn(){return`RUN-${Date.now().toString(36)}-${Math.floor(Math.random()*1e6).toString(36)}`.toUpperCase()}function $r({seed:e,targetRatio:t=.2,reserved:n=[]}={}){let o=Dr(Ar(e||Tn())),r=new Set(n.map(d=>typeof d=="string"?d:I(d.col,d.row))),s=[];for(let d=0;d0;d-=1){let v=Math.floor(o()*(d+1));[s[d],s[v]]=[s[v],s[d]]}let l=Math.round(y.cols*y.rows*t);return new Set(s.slice(0,Math.min(l,s.length)).map(d=>d.k))}function Ir({seed:e,colStart:t=0,colEnd:n=y.cols,rowStart:o=0,rowEnd:r=y.rows,targetRatio:s=.2,reserved:l=[]}={}){let d=Dr(Ar(e||Tn())),v=new Set(l.map(z=>typeof z=="string"?z:I(z.col,z.row))),C=[],P=Math.max(0,Math.floor(t)),R=Math.max(P,Math.floor(n)),L=Math.max(0,Math.floor(o)),V=Math.max(L,Math.floor(r));for(let z=L;z0;z-=1){let se=Math.floor(d()*(z+1));[C[z],C[se]]=[C[se],C[z]]}let te=Math.round((R-P)*(V-L)*s);return new Set(C.slice(0,Math.min(te,C.length)).map(z=>z.k))}var Gt=10,Fr=2,Br=1;function Ut(e,t){return`${e},${t}`}function il(e){let[t,n]=String(e).split(",").map(Number);return{chunkX:t,chunkY:n}}function En(e){let t=q.grid.expansion||{},n=Math.max(1,(e.gridExpansionPurchases||0)+1),o=(t.costBase||1e3)*n*(t.costMultiplier||4/3),r=Math.max(1,t.truncateUnit||100);return Math.floor(o/r)*r}function Lr(e){e.ownedCells=new Set,e.ownedChunks=new Set,e.gridChunkOriginY=0,e.gridExpansionPurchases=0,e.gridExpansionPurchasesByDirection={right:0,up:0};for(let t=0;t=0&&t=0&&n0)continue;let C=Ut(v.chunkX,v.chunkY);t.has(C)||n.has(C)||n.set(C,bo(e,v.chunkX,v.chunkY,v.direction))}}return[...n.values()].sort((o,r)=>{let s=o.direction===r.direction?0:o.direction==="right"?-1:1;return s||(o.chunkY!==r.chunkY?o.chunkY-r.chunkY:o.chunkX-r.chunkX)})}function _r(e,t="right"){let n=Ct(e);return n.find(o=>o.direction===t)||n[0]||null}function Mt(e){return{x:y.x+e.colStart*y.cell,y:y.y+e.rowStart*y.cell,w:e.cols*y.cell,h:e.rows*y.cell}}function vo(e){let t=Mt(e);return{x:t.x+t.w/2-116,y:t.y+t.h/2-36,w:232,h:72,cx:t.x+t.w/2,cy:t.y+t.h/2}}function Gr(e,t){let n=vo(e);return t.x>=n.x&&t.x<=n.x+n.w&&t.y>=n.y&&t.y<=n.y+n.h}function Ur(e){let t=[];for(let n=e.rowStart;nEe(t.col,t.row))}function pl(e){return[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}].filter(t=>Ee(t.col,t.row))}function yl(e){return[{col:e.col,row:e.row+1},{col:e.col-1,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row-1}].filter(t=>Ee(t.col,t.row))}function Vr(e){let t=new Set([...e.conveyorTiles]),n=o=>{o&&Ee(o.col,o.row)&&t.add(I(o.col,o.row))};for(let o of e.scanners){for(let r of pl(o))n(r);for(let r of fl(o))n(r)}for(let o of e.eggFarms){n(o);for(let r of yl(o))n(r)}for(let o of Object.values(e.facilities))n(o.entry);return t}function qr(e){let t=al.map(([n,o])=>({col:n,row:o}));for(let{col:n,row:o}of t)Yr(e,n,o);for(let n=0;n({...n,keys:n.keys?{left:{...n.keys.left},right:{...n.keys.right}}:null,queue:[]})),e.eggFarms=ul.map(n=>{let o=gt(n);return{...n,nextSpawn:o,lastInterval:o}});let t=Vr(e);e.blockedCells=$r({seed:e.runSeed,targetRatio:q.map.blockedRatio,reserved:[...t]}),hl(e),qr(e),e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function Tt(e){return e?[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}]:[]}function pe(e){let t=F(e.col,e.row);return{x:t.x+y.cell/2,y:t.y}}function Et(e,t,n){return e.eggFarms.find(o=>o.col===t&&o.row===n)||null}function Pt(e,t,n){return e.scanners.find(o=>Tt(o).some(r=>r.col===t&&r.row===n))||null}function Rt(e,t){return e.scanners.find(n=>n.id===t)||null}function Co(e,t){return e.scanners.find(n=>n.kind==="manual"&&n.slot===t)||null}function Dn(e){return e?.baseId||e?.id||""}function Mo(e,t){return Object.entries(e.facilities||{}).filter(([,n])=>Dn(n)===t)}function Pe(e,t){return{inputA:{col:e.col,row:e.row-2},inputB:null,left:{col:e.col-1,row:e.row},right:{col:e.col+2,row:e.row}}[t]}function Qr(e){return e?ue.map(t=>({col:e.col+t.dc,row:e.row+t.dr})).filter(t=>Ee(t.col,t.row)):[]}function Jr(e,t,n=[],o=[]){if(!t||!Ee(t.col,t.row))return[];let r=[],s=l=>{!l||!Ee(l.col,l.row)||!e.conveyorTiles.has(I(l.col,l.row))||n.some(d=>d&&Mn(l,d))||r.some(d=>Mn(d,l))||r.push({...l,viaTolerance:!Mn(l,t)})};s(t);for(let l of o)s(l);for(let l of Qr(t))s(l);return r}function zr(e,t,n=[],o=[]){let r=Jr(e,t,n,o),s=r.filter(l=>!l.viaTolerance);return s.length?s:r}function ml(e,t){let n=Pe(t,"inputA");return!n||!Ee(n.col,n.row)?[]:e.conveyorTiles.has(I(n.col,n.row))?[{...n,viaTolerance:!1}]:[]}function bl(e,t,n){let o=Pe(t,n);return Jr(e,o,Tt(t))}function vl(e,t){let n=e.facilities[t]||Mo(e,t)[0]?.[1];if(!n)return null;if(n.entry)return F(n.entry.col,n.entry.row);let o=Dn(n)||t;return o==="mixer"?{x:n.x+n.w,y:n.y+n.h*.52}:o==="truck"?{x:n.x,y:n.y+n.h*.52}:o==="trash"?{x:n.x+n.w/2,y:n.y+8}:{x:n.x+n.w/2,y:n.y+n.h/2}}function jr(e,t,n){return n==="inputA"?ml(e,t).length>0:bl(e,t,n).length>0}function ve(e){e.branchCounters?.clear?.(),e.routeCache=null,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function De(e,t){return I(e,t)}function Wt(e){return Q(e)}function wl(e,t){let n=e.conveyorMeta?.get?.(t)||{},o=[];return Array.isArray(n.outDirs)&&o.push(...n.outDirs),n.dir&&o.push(n.dir),[...new Set(o)].filter(r=>ue.some(s=>s.name===r))}function Sl(e,t,n){let o=ue.find(l=>l.name===n);if(!o)return!1;let r=e.conveyorMeta?.get?.(De(t.col+o.dc,t.row+o.dr));return r?[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))].includes(o.opposite):!1}function kl(e,t){let n=Wt(t),o=e.conveyorMeta?.get?.(t)||{},r=ue.filter(R=>e.conveyorTiles.has(De(n.col+R.dc,n.row+R.dr))).map(R=>R.name),s=wl(e,t).filter(R=>r.includes(R)),l=r,d=s.length?s:l;if(r.length<3)return d;let v=new Set(r.filter(R=>Sl(e,n,R)));if(o.branchMode&&o.branchMode!=="random"&&r.includes(o.branchMode)){let R=new Set(v);R.add(o.branchMode),r.filter(L=>!R.has(L)).length>=2&&v.add(o.branchMode)}let C=r.filter(R=>!v.has(R));if(C.length)return C;let P=d.filter(R=>!v.has(R));return P.length?P:d}function xl(e){return{version:e.routingVersion||0,cells:new Set,adjacency:new Map,components:new Map,cellToComponent:new Map,scannerInputs:new Map,scannerPorts:new Map,facilityPorts:new Map,farmOutputs:new Map,pathCache:new Map,metrics:{conveyorCells:0,edges:0,components:0,deadEnds:0,crosses:0,scannerPorts:0,connectedScannerPorts:0,facilityPorts:0,connectedFacilityPorts:0,farmOutputs:0},issues:[]}}function Cl(e){let t=xl(e);for(let o of e.conveyorTiles)t.cells.add(o),t.adjacency.set(o,[]);for(let o of t.cells){let r=Wt(o),s=kl(e,o),l=ue.filter(d=>s.includes(d.name));for(let d of l){let v=De(r.col+d.dc,r.row+d.dr);t.cells.has(v)&&t.adjacency.get(o).push({key:v,dir:d.name})}}let n=0;for(let[o,r]of t.adjacency.entries()){n+=r.length;let s=new Set(r.map(l=>l.dir));r.length===1&&(t.metrics.deadEnds+=1),r.length===4&&s.has("left")&&s.has("right")&&s.has("up")&&s.has("down")&&(t.metrics.crosses+=1)}return t.metrics.conveyorCells=t.cells.size,t.metrics.edges=Math.floor(n/2),Ml(t),gl(e,t),t.issues=Ll(e,t,{includeRoutes:!1}),t}function Ml(e){let t=1;for(let n of e.cells){if(e.cellToComponent.has(n))continue;let o=t++,r=[n],s=[];for(e.cellToComponent.set(n,o);r.length;){let l=r.shift();s.push(l);for(let d of e.adjacency.get(l)||[])e.cellToComponent.has(d.key)||(e.cellToComponent.set(d.key,o),r.push(d.key))}e.components.set(o,{id:o,cells:s,capacity:Math.max(1,s.length),count:0,ratio:0})}e.metrics.components=e.components.size}function gl(e,t){for(let n of e.scanners){let o={};for(let r of["inputA","left","right"]){let s=Pe(n,r),l=r==="inputA"?s&&t.cells.has(De(s.col,s.row))?[{...s}]:[]:zr(e,s,Tt(n)).filter(C=>t.cells.has(De(C.col,C.row))),d=l.map(C=>De(C.col,C.row)),v=d.length>0;if(o[r]={type:r,cell:s,cells:l,keys:d,key:d[0]||null,connected:v},t.metrics.scannerPorts+=1,v&&(t.metrics.connectedScannerPorts+=1),r==="inputA")for(let C of d)t.scannerInputs.set(C,n.id)}t.scannerPorts.set(n.id,o)}for(let[n,o]of Object.entries(e.facilities)){if(!o.entry)continue;let r=zr(e,o.entry).filter(d=>t.cells.has(De(d.col,d.row))),s=r.map(d=>De(d.col,d.row)),l=s.length>0;t.facilityPorts.set(n,{id:n,cell:{...o.entry},cells:r,keys:s,key:s[0]||null,connected:l}),t.metrics.facilityPorts+=1,l&&(t.metrics.connectedFacilityPorts+=1)}for(let n of e.eggFarms){let o=Qr({col:n.col,row:n.row}).map(r=>De(r.col,r.row)).filter(r=>t.cells.has(r));t.farmOutputs.set(n.id,o),t.metrics.farmOutputs+=o.length}}function Oe(e){let t=e.routingVersion||0;return(!e.factoryGraph||e.factoryGraph.version!==t)&&(e.factoryGraph=Cl(e)),e.factoryGraph}function Zr(e){let t=Oe(e);return e.factoryGraphCommittedVersion=t.version,e.factoryGraphSnapshot=Tl(t),t}function Tl(e){return e?{version:e.version,conveyorCells:e.metrics.conveyorCells,edges:e.metrics.edges,components:e.metrics.components,deadEnds:e.metrics.deadEnds,crosses:e.metrics.crosses,scannerPorts:`${e.metrics.connectedScannerPorts}/${e.metrics.scannerPorts}`,facilityPorts:`${e.metrics.connectedFacilityPorts}/${e.metrics.facilityPorts}`,farmOutputs:e.metrics.farmOutputs,issues:[...e.issues||[]]}:null}function El(e,t){let n=t.col-e.col,o=t.row-e.row;return ue.find(r=>r.dc===n&&r.dr===o)?.name||null}function go(e,t,n){let o=Oe(e),r=De(t.col,t.row);if(!o.cells.has(r))return[];let s=`${r}|${n.cacheKey||"dynamic"}`;if(n.cacheKey&&o.pathCache.has(s))return o.pathCache.get(s).map($=>$.map(U=>({...U})));let l=`${r}|none`,d=[{key:r,col:t.col,row:t.row,incoming:"none",depth:0}],v=new Map([[l,0]]),C=new Map,P=[],R=1/0,L=8,V=24,te=80;for(;d.length;){let $=d.shift();if($.depth>R)break;let U=`${$.key}|${$.incoming}`;if(n($)){if(P.push(U),R=$.depth,P.length>=V)break;continue}for(let N of o.adjacency.get($.key)||[]){let le=Wt(N.key),Se=El($,le),he=$.depth+1;if(he>R)continue;let A=`${N.key}|${Se}`,_=v.get(A);if(_==null)v.set(A,he),C.set(A,[U]),d.push({key:N.key,col:le.col,row:le.row,incoming:Se,depth:he});else if(_===he){let k=C.get(A)||[];k.length{if(z.length>=te)return;let[N]=$.split("|"),le=[Wt(N),...U];if($===l||N===r){z.push(le);return}for(let Se of C.get($)||[])se(Se,le)};for(let $ of P)se($,[]);let ye=[],Z=new Set;for(let $ of z){let U=$.map(N=>De(N.col,N.row)).join(">");Z.has(U)||(Z.add(U),ye.push($))}return n.cacheKey&&o.pathCache.set(s,ye.map($=>$.map(U=>({...U})))),ye}function ei(e){let t=Oe(e),n=new Map;for(let[o,r]of t.components.entries())n.set(o,{id:o,cells:[...r.cells],capacity:r.capacity,count:0,ratio:0});return{components:n,cellToComponent:new Map(t.cellToComponent)}}function ti(e,t,n){let o=Oe(e),r=null,s=1/0;for(let l of o.cells){let d=Q(l),v=F(d.col,d.row),C=Math.hypot(v.x-t,v.y-n);CF(o.col,o.row));return t&&n.push(t),n}function ct(e,t){t&&(!e.length||Er(e[e.length-1],t)>1)&&e.push(t)}function Pl(e,t,n,o=null){let r=[{x:e.x,y:e.y}];ct(r,F(t.col,t.row));for(let s of $n(n,o))ct(r,s);return r}function Rl(e,t){let n=$n(e),o=Pe(t,"inputA");return o&&ct(n,F(o.col,o.row)),ct(n,pe(t)),n}function Al(e,t,n,o){let r=[{x:e.x,y:e.y}];ct(r,F(t.col,t.row));for(let l of $n(n))ct(r,l);let s=Pe(o,"inputA");return s&&ct(r,F(s.col,s.row)),ct(r,pe(o)),r}function Dl(e,t,n=0){let o=F(t.col,t.row),r=0;for(let s of e.chicks||[]){if(s.stage==="flying"||s.stage==="queued")continue;Math.hypot(s.x-o.x,s.y-o.y){let R=C.roleBias??0,L=P.roleBias??0;if(R!==L)return R-L;let V=C.cells?.length??C.route?.length??Number.POSITIVE_INFINITY,te=P.cells?.length??P.route?.length??Number.POSITIVE_INFINITY;if(V!==te)return V-te;let z=C.key||JSON.stringify(C.route||C.cells||C),se=P.key||JSON.stringify(P.route||P.cells||P);return z.localeCompare(se)});if(!o||r.length===1)return r[0];let s=r[0].roleBias??0,l=r.filter(C=>(C.roleBias??0)===s),d=Math.min(...l.map(C=>Xr(e,C)));l=l.filter(C=>Xr(e,C)===d);let v=e.branchCounters.get(t)||0;return e.branchCounters.set(t,v+1),l[Math.floor(Math.random()*l.length)]}function ni(e){return e.role===0?{left:{match:"male",destination:"mixer"},right:{match:"default",destination:"scanner-role-1"}}:{left:{match:"poop",destination:"trash"},right:{match:"default",destination:"truck"}}}function To(e){let t=ni(e);return{left:t.left.destination,right:t.right.destination}}function Eo(e,t){return ni(e).left.match===t.sex?"left":"right"}function Po(e){return Rr(e)}function Ro(e){return{mixer:"#2477ff",truck:"#ff6aa8",trash:"#22b94f","scanner-role-1":"#526456",scanner:"#526456",input:"#526456"}[e]||"#102015"}function At(e,t,n=!1){let o=Oe(e),r=(o.farmOutputs.get(t.id)||[]).map(Wt),s=[];for(let v of r){let C=R=>o.scannerInputs.has(De(R.col,R.row));C.cacheKey=`farmInput:${v.col},${v.row}:v${o.version}`;let P=go(e,v,C);for(let R of P){let L=R[R.length-1],V=o.scannerInputs.get(De(L.col,L.row)),te=Rt(e,V);te&&s.push({key:`${te.id}:${L.col},${L.row}:${R.length}`,scanner:te,cells:R})}}let l=An(e,`farm:${t.id}`,s,n);if(l)return{scannerId:l.scanner.id,route:Rl(l.cells,l.scanner)};let d=An(e,`farm:${t.id}:output`,r.map(v=>({key:I(v.col,v.row),cells:[v]})),n);return d?{scannerId:null,route:$n(d.cells)}:null}function oi(e,t,n,o,r=!1){let s=Rt(e,o);if(!s)return null;let d=Oe(e).scannerPorts.get(s.id)?.[t],v=Pe(s,t),C=d?.connected?(d.keys||[d.key]).filter(Boolean).map(Wt):[];if(!v||!C.length)return null;let P=To(s)[t];return P==="scanner-role-1"?$l(e,s,t,n,v,C,r):Il(e,s,t,n,v,C,P,r)}function $l(e,t,n,o,r,s,l){let d=Oe(e),v=e.scanners.filter(R=>R.id!==t.id&&d.scannerPorts.get(R.id)?.inputA?.connected),C=[];for(let R of s)for(let L of v){let V=d.scannerPorts.get(L.id)?.inputA?.key;if(!V)continue;let te=(d.scannerPorts.get(L.id)?.inputA?.keys||[V]).filter(Boolean),z=Z=>te.includes(De(Z.col,Z.row));z.cacheKey=`toScanner:${R.col},${R.row}:${L.id}:v${d.version}`;let se=go(e,R,z),ye=L.role===1?0:1;for(let Z of se)C.push({key:`${ye}:start${I(R.col,R.row)}:s${L.id}:${Z.length}:${I(Z[Z.length-1].col,Z[Z.length-1].row)}`,target:L,cells:Z,roleBias:ye})}let P=An(e,`scanner:${t.id}:${n}:toRole1`,C,l);return P?{destination:"scanner",nextScannerId:P.target.id,route:Al(o,r,P.cells,P.target)}:null}function Il(e,t,n,o,r,s,l,d){let v=Oe(e),C=[...v.facilityPorts.entries()].filter(([L,V])=>V?.connected&&Dn(e.facilities?.[L])===l);if(!C.length)return null;let P=[];for(let L of s)for(let[V,te]of C){let z=(te.keys||[te.key]).filter(Boolean);if(!z.length)continue;let se=Z=>z.includes(De(Z.col,Z.row));se.cacheKey=`toFacility:${L.col},${L.row}:${V}:v${v.version}`;let ye=go(e,L,se);for(let Z of ye)P.push({key:`start${I(L.col,L.row)}:${V}:${Z.length}:${I(Z[Z.length-1].col,Z[Z.length-1].row)}`,cells:Z,facilityId:V})}let R=An(e,`scanner:${t.id}:${n}:${l}`,P,d);return R?{destination:l,facilityId:R.facilityId,route:Pl(o,r,R.cells,vl(e,R.facilityId))}:null}function ri(e,t,n=new Set){if(!t||n.has(t.id))return!1;n.add(t.id);for(let o of["left","right"]){let r=oi(e,o,pe(t),t.id,!1);if(r){if(["mixer","trash","truck"].includes(r.destination))return!0;if(r.destination==="scanner"){let s=Rt(e,r.nextScannerId);if(ri(e,s,n))return!0}}}return!1}function Fl(e,t){return!!At(e,t,!1)?.scannerId}function In(e){if(e.phase!=="build")return[];let t=[];for(let n of e.eggFarms||[])Fl(e,n)||t.push({type:"eggFarm",id:n.id,ref:n,message:"This Egg will not produce chicks"});for(let n of nn)for(let[o,r]of Mo(e,n))Oe(e).facilityPorts.get(o)?.connected||t.push({type:"facility",id:o,ref:r,message:"This facility cannot receive items"});return t}function Bl(e){let t=Oe(e);for(let r of e.eggFarms||[]){let s=At(e,r,!1);if(!s?.scannerId)continue;let l=Rt(e,s.scannerId);if(ri(e,l))return[]}let n=e.eggFarms?.length||0,o=[...t.facilityPorts.entries()].filter(([r,s])=>s?.connected&&["mixer","trash","truck"].includes(Dn(e.facilities?.[r]))).length;return n?t.metrics.farmOutputs?e.scanners?.length?o?["Connect at least one EGG through a scanner to any valid exit."]:["Connect at least one receiver exit: Mixer, Shredder, or Truck."]:["Build at least one scanner and connect it to an EGG route."]:["Connect at least one EGG to a conveyor."]:["Build at least one EGG before starting the next day."]}function Rn(e){return e.kind==="manual"?`S${(e.slot??0)+1}`:`Auto Scanner #${e.id}`}function Ll(e,t=Oe(e),n={}){let o=n.includeRoutes!==!1,r=[],s={mixer:"Mixer",trash:"Shredder",truck:"Truck"};for(let l of nn){let d=Mo(e,l);if(!d.length){r.push(`${s[l]||l} is missing`);continue}for(let[v]of d)t.facilityPorts.get(v)?.connected||r.push(`${s[l]||l} receiver has no conveyor`)}for(let l of e.scanners){let d=t.scannerPorts.get(l.id)||{};if(d.inputA?.connected||r.push(`${Rn(l)} input has no conveyor`),d.left?.connected||r.push(`${Rn(l)} left output has no conveyor`),d.right?.connected||r.push(`${Rn(l)} right output has no conveyor`),!!o)for(let v of["left","right"])d[v]?.connected&&!oi(e,v,pe(l),l.id)&&r.push(`${Rn(l)} ${v} route is incomplete`)}if(o)for(let l of e.eggFarms)At(e,l)?.scannerId||r.push(`Egg Farm #${l.id} has no scanner route`);else for(let l of e.eggFarms)(t.farmOutputs.get(l.id)||[]).length||r.push(`Egg Farm #${l.id} has no output conveyor`);return[...new Set(r)]}function sn(e){return Bl(e)}function ii(e){return sn(e).length===0}var si=[{key:"premiumFemaleShipment",target:"female",truckTarget:"female",title:"Premium Female Shipment",route:"Female -> Truck",note:"Today only: ship female chicks to Truck. Meet the export target for a bonus.",objective:"truckTarget"},{key:"contaminantSampleExport",target:"poop",truckTarget:"poop",title:"Contaminant Sample Export",route:"Poop value x2",note:"Today only: poop is valid Truck cargo and all poop income is doubled.",objective:"truckTarget",poopValueMultiplier:2},{key:"healthInspection",title:"Health Inspection",route:"Poop -> Shredder",note:"Today only: poop mistakes are fined double. Shred enough poop for an inspection bonus.",objective:"poopTrash",poopFineMultiplier:2},{key:"conveyorJamWarning",title:"Conveyor Jam Warning",route:"No explosions",note:"Today only: jam explosions trigger at 85% congestion. Finish with zero explosions for a bonus.",objective:"noExplosion",congestionExplosionThreshold:.85,congestionWarningThreshold:.68},{key:"powerSavingOrder",title:"Power Saving Order",route:"Slow factory subsidy",note:"Today only: conveyors -20% speed and Auto Scanners +20% cooldown. A subsidy is paid at settlement.",objective:"flatBonus",conveyorSpeedMultiplier:.8,autoScannerCooldownMultiplier:1.2},{key:"overtimeDay",title:"Overtime Day",route:"80 second day",note:"Today only: the work day is longer. No extra reward or penalty.",objective:"none",daySeconds:80},{key:"shortShift",title:"Short Shift",route:"40 second day",note:"Today only: the work day is shorter. The next Fairies tribute is reduced by 10%.",objective:"none",daySeconds:40,fairiesTributeMultiplier:.9},{key:"chickBoom",title:"Chick Boom",route:"EGG interval x0.65",note:"Today only: eggs hatch faster and poop rate rises by 5 percentage points.",objective:"none",productionMultiplier:1/.65,poopRateAdd:.05},{key:"rottenFeed",title:"Rotten Feed",route:"Poop surge",note:"Today only: poop rate rises by 20 percentage points and Shredder poop income is multiplied by 1.5.",objective:"none",poopRateAdd:.2,shredderIncomeMultiplier:1.5},{key:"maintenanceAudit",title:"Maintenance Audit",route:"Durability check",note:"Today only: machines below 50% remaining durability fail the audit. Passing with none below 50% pays a bonus.",objective:"maintenanceAudit"}];function we(e,t=0){let n=Number(e);return Number.isFinite(n)?n:t}function Ol(e,t=0,n=1){let o=Math.max(1,Number(e?.turn||1)+1),r=Math.floor(Ao(e)*(.08+Math.random()*.08)),s=Math.floor(Math.max(0,e.cash||0)*.25),l=Math.floor(Math.max(0,t)*Math.max(1,o)*.75);return Math.max(120,Math.ceil(Math.max(r,s,l)*n))}function li(e){return Math.max(0,Math.ceil(500+Math.max(1,e?.turn||1)*25))}function Ao(e){return[...e.eggFarms.map(t=>t.price||0),...e.scanners.map(t=>t.price||0),...Object.values(e.facilities).map(t=>t.price||0),...[...e.conveyorMeta.values()].map(t=>t.price||0)].reduce((t,n)=>t+n,0)}function Nl(e,t=1,n=wt){return e.eggFarms.reduce((o,r)=>{let[s,l]=rn(r),d=Math.max(.1,(s+l)/2);return o+Math.max(1,n)/d*Math.max(.01,t||1)},0)}function _l(e,t){let n=we(t.productionMultiplier,1),o=we(t.daySeconds,wt),r=Nl(e,n,o),s=Math.max(0,Number(e?.cardEffects?.hatchingFeed)||0),l=Math.max(0,Number(e?.cardEffects?.poopRateBooster)||0),d=Math.pow(1.03,s),v=fo+po*l,C=Math.min(.95,Math.max(0,(v+we(t.poopRateAdd,0))*we(t.poopMultiplier,1)*d));return{estimate:r,poopRate:C}}function ai(e){if(e.turn+1Cr)return null;let n=si[Math.floor(Math.random()*si.length)],{estimate:o,poopRate:r}=_l(e,n),s=0;n.objective==="truckTarget"?s=Math.max(1,Math.ceil(o*.3)):n.objective==="poopTrash"&&(s=Math.max(1,Math.ceil(o*r*.8)));let l=0;return["truckTarget","poopTrash","noExplosion"].includes(n.objective)&&(l=Ol(e,o)),n.objective==="flatBonus"&&(l=li(e)),n.objective==="maintenanceAudit"&&(l=li(e)),{id:`event-${e.turn}-${Date.now()}-${Math.floor(Math.random()*9999)}`,...n,target:n.target||null,truckTarget:n.truckTarget||null,forced:!0,productionMultiplier:we(n.productionMultiplier,1),poopMultiplier:we(n.poopMultiplier,1),poopRateAdd:we(n.poopRateAdd,0),daySeconds:we(n.daySeconds,wt),targetAmount:s,estimatedOutput:Math.round(o),reward:l,createdTurn:e.turn,oneTurnOnly:!0}}function ci(e){e.eventActive=e.eventOffer?{...e.eventOffer}:null,e.eventOffer=null}function ui(e){e.eventActive=null}function di(e){return Math.max(1,we(e.eventActive?.daySeconds,wt))}function fi(e){return we(e.eventActive?.productionMultiplier,1)}function pi(e){let t=Math.max(0,Number(e?.cardEffects?.hatchingFeed)||0),n=Math.max(0,Number(e?.cardEffects?.poopRateBooster)||0),o=Math.pow(1.03,t),r=fo+po*n,s=we(e.eventActive?.poopRateAdd,0);return Math.min(.95,Math.max(0,(r+s)*we(e.eventActive?.poopMultiplier,1)*o))}function je(e){return e.eventActive?.truckTarget||e.eventActive?.target||"female"}function Do(e,t){return t==="male"?e.truckMale||0:t==="poop"?e.poopTruck||0:e.truckFemale||0}function yi(e,t){return je(e)===t}function hi(e){return je(e)!=="male"}function $o(e){return Math.max(.01,we(e.eventActive?.poopValueMultiplier,1))}function Fn(e){return Math.max(.01,$o(e)*we(e.eventActive?.shredderIncomeMultiplier,1))}function Io(e){return Math.max(.01,we(e.eventActive?.poopFineMultiplier,1))}function Fo(e){return Math.max(.1,Math.min(1,we(e.eventActive?.congestionExplosionThreshold,1)))}function mi(e){return Math.max(.1,Math.min(1,we(e.eventActive?.congestionWarningThreshold,.8)))}function bi(e){return Math.max(.01,we(e?.fairiesTributeMultiplier,1))}function Gl(e){let t=0,n=(o,r)=>{let s=Math.max(1,we(r,1)),l=Math.max(0,we(o,0));1-Math.min(1,l/s)<.5&&(t+=1)};for(let o of e.conveyorMeta?.values?.()||[])n(o.uses,o.durability);for(let o of e.eggFarms||[])n(o.maintenance?.uses,o.maintenance?.durability);for(let o of e.scanners||[])o.kind==="auto"&&n(o.maintenance?.uses,o.maintenance?.durability);for(let o of Object.values(e.facilities||{})){let r=o?.baseId||o?.id;(r==="mixer"||r==="trash")&&n(o.maintenance?.uses,o.maintenance?.durability)}return t}function vi(e){let t=e.eventActive;if(!t)return null;let n=0,o=!0,r=0,s="";t.objective==="truckTarget"?(n=Do(e.stats,t.target),o=n>=t.targetAmount,r=o?t.reward:0):t.objective==="poopTrash"?(n=e.stats.poopTrash||0,o=n>=t.targetAmount,r=o?t.reward:0):t.objective==="noExplosion"?(n=e.stats.explosions||0,o=n===0,r=o?t.reward:0,s=`${n} explosion(s)`):t.objective==="flatBonus"?(o=!0,r=t.reward):t.objective==="maintenanceAudit"?(n=Gl(e),o=n===0,o&&(r=t.reward),s=`${n} machine(s) below 50%`):o=!0,r>0?(Ne(e,r),e.stats.eventBonus=(e.stats.eventBonus||0)+r,e.totals.eventBonus+=r,e.totals.eventSuccess+=1):t.objective&&t.objective!=="none"&&(e.stats.eventBonus=e.stats.eventBonus||0,e.totals.eventFailed+=o?0:1,o&&(e.totals.eventSuccess+=1));let l={title:t.title,key:t.key,target:t.target,route:t.route,objective:t.objective,targetAmount:t.targetAmount||0,count:n,success:o,bonus:r,reward:t.reward||0,productionMultiplier:t.productionMultiplier,poopMultiplier:t.poopMultiplier,daySeconds:t.daySeconds,detail:s};return e.stats.eventResult=l,l}function Bo(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function Ul(e){return!!e?.cardEffects?.usedMachineActive}function Wl(e,t){return t?1:Math.min(.8,.5+.1*Math.min(3,Bo(e,"recyclingSubsidy")))}function Kl(e){return Math.pow(.95,Bo(e,"safetyCover"))}function Bn(e){let t=e?.ref||e||{},n=e?.type||t.type;return n==="conveyor"?t.price||ke[t.kind]?.price||ke.conveyor.price:n==="eggFarm"?t.price||ke.eggFarm.price:n==="scanner"?t.price||(t.kind==="auto"?ke.autoScanner.price:ke.manualScanner.price):n==="facility"?t.price||ke[t.id]?.price||0:ke[t.id]?.price||0}function _e(e,t=null){let n=ke[e]?.price||0;return Ul(t)?Math.ceil(n*.5):n}function Hl(e,t){return e?.facilities?Object.values(e.facilities).filter(n=>(n?.baseId||n?.id)===t).reduce((n,o)=>n+Math.max(0,(o.level||1)-1),0):0}function ut(e,t){return gr.includes(t)?Math.pow(xe.incomeUpgradeRate,Hl(e,t)):1}function Ye(e){return Math.ceil(xe.income.mixer*ut(e,"mixer"))}function $e(e){return Math.ceil(xe.income.truck*ut(e,"truck"))}function ln(e){return Math.ceil(xe.poopFine*ut(e,"mixer")*Io(e))}function an(e){return Math.ceil(xe.poopFine*ut(e,"truck")*Io(e))}function Lo(e){let t=xe.maleTruckFinePerHalfDay*(e.turn/2);return Math.ceil(t*ut(e,"truck"))}function Oo(e){return e?.facilities?Object.values(e.facilities).filter(t=>(t?.baseId||t?.id)==="trash").reduce((t,n)=>t+Math.max(0,(n.level||1)-1),0):0}function Dt(e){return Math.min(xe.shredderBonus.maxCards,Oo(e))}function Kt(){return xe.shredderBonus.maxCards}function dt(e){let t=typeof e=="number"?e:Dt(e),n=Math.min(xe.shredderBonus.maxCards,Math.max(0,t));return n>0?Math.ceil(n*(xe.shredderBonus.incomePerUpgrade||1)):0}function ql(e){let t=Dt(e),n=dt(t),o=Math.ceil(n*Fn(e));return{cards:t,chance:o>0?1:0,amount:o,expected:o,baseAmount:n}}function wi(e){let t=ql(e);return t.amount>0&&(e.stats.shredderBonus=(e.stats.shredderBonus||0)+t.amount,e.totals.shredderBonus=(e.totals.shredderBonus||0)+t.amount,Ne(e,t.amount)),t}function Ln(e,t=e.turn,n=null){let o=Math.max(1,Math.floor(Number(t)||1)),r=xe.fairiesTribute||{perDay:10,profitExemption:300,legalWorkExemptionBonus:250,profitRate:.12},s=Math.ceil(o*(r.perDay||10)),l=Math.max(0,Math.floor(Number(n??e?.lastResult?.profit??e?.stats?.profit??0)||0)),d=Math.max(0,e?.cardEffects?.legalWork||0),v=Math.max(0,(r.profitExemption||0)+d*(r.legalWorkExemptionBonus||0)),C=Math.max(0,l-v),P=Math.ceil(C*Math.max(0,Number(r.profitRate)||0)),R=s+P,L=Math.max(0,e?.cardEffects?.fairiesFlatteryNext||e?.cardEffects?.flattery||0),V=L>0?Math.pow(.5,L):1,te=Math.max(.01,Number(e?.pendingFairiesTributeMultiplier)||1),z=V*te,se=Math.max(0,Math.ceil(R*z)),ye=Math.max(0,R-se);return{day:o,base:s,profit:l,legalWork:d,profitExemption:v,taxableProfit:C,profitTribute:P,gross:R,flatteryCount:L,eventMultiplier:te,perCardReduction:Math.ceil(R*.5),reduction:ye,amount:se}}function $t(e,t){let n=e?.ref||e||{},o=e?.type==="conveyor"?t?.conveyorMeta?.get(e.oldKey||n.id):n,r=o?.price||Bn(e||n),s=o?.builtSession===t?.buildSession;if(o?.noRefund||n?.noRefund)return{amount:0,sameBuild:s,price:r,rate:0,noRefund:!0};let l=Wl(t,s);return{amount:Math.max(0,Math.ceil(r*l)),sameBuild:s,price:r,rate:l,noRefund:!1}}function Yl(e,t=null){let n=Math.max(1,Math.ceil((Number(e)||0)/xe.explosionDamageDivisor));return Math.max(1,Math.ceil(n*Kl(t)))}function Vl(e,t){return Math.max(0,Math.ceil(t))}function Si(e,t){e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,t>=0?(e.stats.revenue+=t,e.totals.revenue+=t):(e.stats.penalty+=Math.abs(t),e.totals.penalty+=Math.abs(t)),e.totals.maxCash=Math.max(e.totals.maxCash,e.cash)}function Ne(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&Si(e,n),n}function ft(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&Si(e,-n),n}function pt(e,t){ft(e,t)}function ki(e,t){t<=0||(e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,e.totals.maxCash=Math.max(e.totals.maxCash,e.cash))}function xi(e){let t=Ye(e);return e.stats.mixerRevenue+=t,Ne(e,t),t}function Ci(e){let t=ln(e);return e.stats.mixerPoopFine+=t,e.totals.mixerPoopFine+=t,ft(e,t),t}function Mi(e){let t=an(e);return e.stats.truckPoopFine+=t,e.totals.truckPoopFine+=t,ft(e,t),t}function gi(e){let t=Lo(e);return e.stats.maleTruckFine+=t,e.totals.maleTruckFine+=t,ft(e,t),t}function Ti(e,t){let n=Yl(t,e);return e.stats.explosionDamage+=n,e.totals.explosionDamage+=n,ft(e,n),n}function Ei(e){let t=je(e),n=Do(e.stats,t),o=t==="poop"?Math.ceil($e(e)*$o(e)):$e(e),r=n*o,s=Vl(e,r);return e.stats.pendingTruckRevenue=s,e.stats.truckRevenue=s,t==="poop"?e.stats.poopShipmentIncome=s:e.stats.chickShipmentIncome=s,s>0&&Ne(e,s),{base:r,adjusted:s,target:t,targetCount:n,unitPrice:o}}function Pi(e,t=e.turn,n=null,o={}){let r=Ln(e,t,n);return e.cardEffects&&(e.cardEffects.fairiesFlatteryNext=0,e.cardEffects.flattery!=null&&delete e.cardEffects.flattery),e.pendingFairiesTributeMultiplier!=null&&(e.pendingFairiesTributeMultiplier=1),r.amount<=0||(o.recordStats?(e.stats.fairiesTribute=(e.stats.fairiesTribute||0)+r.amount,e.totals.fairiesTribute=(e.totals.fairiesTribute||0)+r.amount,ft(e,r.amount)):(e.totals.fairiesTribute=(e.totals.fairiesTribute||0)+r.amount,e.totals.penalty=(e.totals.penalty||0)+r.amount,e.totals.profit=(e.totals.profit||0)-r.amount,e.cash-=r.amount)),r}function Ri(e){let t=Bo(e,"chemicalWeaponSubsidy"),n=Math.max(0,e?.stats?.poopTruck||0),o=xe.chemicalWeaponSubsidy||{poopPerBlock:70,yenPerBlock:1200},r=Math.floor(n/Math.max(1,o.poopPerBlock||70)),s=t>0&&r>0?r*Math.max(0,o.yenPerBlock||1200)*t:0;return s>0&&(e.stats.chemicalWeaponSubsidy=(e.stats.chemicalWeaponSubsidy||0)+s,e.totals.chemicalWeaponSubsidy=(e.totals.chemicalWeaponSubsidy||0)+s,Ne(e,s)),{cards:t,poopTruck:n,blocks:r,amount:s}}function Ai(e){let t=Ao(e),n=Math.max(1,e.totals.turnsCompleted||e.turn||1),o=Math.max(0,e.cash+e.totals.revenue+t*.5+e.totals.eventBonus*.5),r=Math.ceil(o/n),s=Math.floor(n*35+Math.max(0,n-5)*15),l=e.totals.correct*5,d=e.totals.explosionDamage;return{score:Math.max(0,Math.floor(o+r+l-e.totals.penalty-s)),factoryValue:t,base:o,dailyEarned:r,dayPenalty:s,correctBonus:l,explosionPenalty:d,days:n}}function zl(e){return{...e,keys:e.keys?{left:{...e.keys.left},right:{...e.keys.right}}:null,queue:[],cooldown:e.cooldown||0}}function cn(e){return JSON.stringify({cash:e.cash,stats:e.stats,totals:e.totals,nextId:e.nextId,gridX:y.x,gridY:y.y,gridCols:e.gridCols||y.cols,gridRows:e.gridRows||y.rows,gridExpansionPurchases:e.gridExpansionPurchases||0,gridExpansionPurchasesByDirection:e.gridExpansionPurchasesByDirection||{right:0,up:0},gridChunkOriginY:e.gridChunkOriginY||0,ownedCells:[...e.ownedCells||[]],ownedChunks:[...e.ownedChunks||[]],blockedCells:[...e.blockedCells||[]],selected:e.selected,multiSelected:e.multiSelected||[],buildTool:e.buildTool,view:e.view,facilities:e.facilities,eggFarms:e.eggFarms,scanners:e.scanners.map(zl),conveyorTiles:[...e.conveyorTiles],conveyorMeta:[...e.conveyorMeta.entries()],branchCounters:[...e.branchCounters.entries()],cardEffects:e.cardEffects,cardDraft:e.cardDraft,cardTargetPick:e.cardTargetPick})}function Di(e,t){let n=JSON.parse(t);e.cash=n.cash,e.stats=n.stats,e.totals=n.totals,e.nextId=n.nextId,y.x=n.gridX??q.grid.x,y.y=n.gridY??q.grid.y,y.cols=n.gridCols||q.grid.cols,y.rows=n.gridRows||q.grid.rows,e.gridCols=y.cols,e.gridRows=y.rows,e.gridExpansionPurchases=n.gridExpansionPurchases||0,e.gridExpansionPurchasesByDirection=n.gridExpansionPurchasesByDirection||{right:0,up:0},e.gridChunkOriginY=n.gridChunkOriginY||0,e.ownedCells=new Set(n.ownedCells||[]),e.ownedChunks=new Set(n.ownedChunks||[]),e.gridOwnedCells=e.ownedCells.size||y.cols*y.rows,e.blockedCells=new Set(n.blockedCells||[]),e.selected=n.selected,e.multiSelected=n.multiSelected||[],e.buildTool=n.buildTool,e.view=n.view||{x:0,y:0,scale:1},e.view.scale==null&&(e.view.scale=1),e.facilities=n.facilities||{},e.eggFarms=n.eggFarms||[],e.scanners=(n.scanners||[]).map(o=>({...o,queue:[],cooldown:o.cooldown||0})),e.conveyorTiles=new Set(n.conveyorTiles||[]),e.conveyorMeta=new Map(n.conveyorMeta||[]),e.branchCounters=new Map(n.branchCounters||[]),e.cardEffects=n.cardEffects||{bearing:0,legalWork:0,fairiesFlatteryNext:0,scannerQueueSpacing:0},e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft=n.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardTargetPick=n.cardTargetPick||null,e.groupDrag=null,e.selectionBox=null,e.pan=null,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function Fe(e){e.phase==="build"&&(e.undoStack.push(cn(e)),e.undoStack.length>80&&e.undoStack.shift(),e.redoStack=[])}function No(e){return e.phase!=="build"||!e.undoStack.length?!1:(e.redoStack.push(cn(e)),Di(e,e.undoStack.pop()),!0)}function _o(e){return e.phase!=="build"||!e.redoStack.length?!1:(e.undoStack.push(cn(e)),Di(e,e.redoStack.pop()),!0)}function W(e,t,n,o,r=p.ink){e.floatingTexts.push({x:t,y:n,text:o,color:r,life:1,maxLife:1})}function It(e,t,n){e.shake.strength=Math.max(e.shake.strength,t),e.shake.time=Math.max(e.shake.time,n)}function $i(e,t,n){e.effects.push({type:"spawn",priority:Ce.ambient,x:t,y:n,life:.42,maxLife:.42,size:12})}function Ii(e,t,n,o=p.green){e.effects.push({type:"scannerPulse",priority:Ce.important,x:t,y:n,color:o,life:.42,maxLife:.42,size:24})}function Fi(e,t,n){for(let o=0;o<12;o+=1)e.effects.push({type:"meat",priority:Ce.important,x:t+G(-18,18),y:n+G(-12,16),vx:G(-60,60),vy:G(-90,-25),life:G(.45,.85),maxLife:.85,size:G(4,8)})}function Bi(e,t,n){for(let o=0;o<16;o+=1)e.effects.push({type:"sludge",priority:Ce.important,x:t+G(-18,18),y:n+G(-12,16),vx:G(-46,46),vy:G(-70,-20),life:G(.45,.9),maxLife:.9,size:G(4,8)})}function Li(e,t,n,o){let r=o==="poop"?p.poop:o==="male"?p.male:p.female;for(let s=0;s<22;s+=1)e.effects.push({type:"shred",priority:Ce.important,x:t+G(-16,16),y:n+G(-8,8),vx:G(-70,70),vy:G(40,160),color:s%3===0?p.white:r,life:G(.45,.95),maxLife:.95,w:G(3,7),h:G(10,24),rot:G(-Math.PI,Math.PI)});Ve(e,t,n,p.green,34,Ce.important)}function Oi(e,t,n,o){let r=o==="poop"?p.poop:o==="male"?p.danger:p.green;for(let s=0;s<8;s+=1)e.effects.push({type:"load",priority:Ce.important,x:t+G(-18,18),y:n+G(-18,18),vx:G(-42,42),vy:G(-90,-25),color:r,life:G(.35,.65),maxLife:.65,size:8})}function Ve(e,t,n,o=p.danger,r=52,s=Ce.critical){e.effects.push({type:"shockwave",priority:s,x:t,y:n,color:o,life:.55,maxLife:.55,size:8,maxSize:r})}function Ze(e,t,n,o=12,r=p.danger,s=Ce.critical){for(let l=0;l0&&(e.shake.time=Math.max(0,e.shake.time-t),e.shake.time<=0&&(e.shake.strength=0));for(let r of e.effects)if(r.life-=t,["meat","sludge","spark","smoke","shred","load","rage"].includes(r.type))r.x+=(r.vx||0)*t,r.y+=(r.vy||0)*t,r.vy=(r.vy||0)+150*t;else if(r.type==="flyingChick"){r.x+=r.vx*t,r.y+=r.vy*t,r.vy+=360*t,r.noDamage||Xl(e,r,o);let s=r.x+e.view.x,l=r.y+e.view.y;(s<-100||l<-100||s>n.width+100||l>n.height+100)&&(r.life=0)}e.effects=e.effects.filter(r=>r.life>0);for(let r of e.floatingTexts)r.life-=t,r.y-=34*t;e.floatingTexts=e.floatingTexts.filter(r=>r.life>0)}function Xl(e,t,n){t.hit||(t.hit=new Set);for(let o of n()){if(t.hit.has(o.id)||t.xo.x+o.w||t.yo.y+o.h)continue;t.hit.add(o.id);let r=Ti(e,o.price);W(e,t.x,t.y-10,`-${M(r)}`,p.danger),Ve(e,t.x,t.y,p.danger,30),Ze(e,t.x,t.y,5,p.danger),It(e,5,.18)}}var Be=q.maintenance;function Uo(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function Gn(e){let t=Math.min(1.4,1+.04*Math.min(10,Uo(e,"crowdedFarming"))),n=Math.pow(.95,Uo(e,"preventiveMaintenance"));return t*n}function Ql(e){return Math.pow(1.03,Uo(e,"durabilityCoating"))}function Un(e,t,n=1){let o=Be.durability[t]||1e3;return Math.max(1,Math.ceil(o*Math.max(.1,n||1)*Ql(e)))}function Ho(e){let t=Be.repairman.dailyCost;return e?.cardEffects?.laborExploitation?Math.ceil(t*.7):t}function Gi(e){return Math.max(.1,Number(e?.durabilityBaseMultiplier)||1)}function me(e){e.repairman||(e.repairman={hiredForNextDay:!1,active:!1,x:y.x+y.cell*.5,y:y.y+y.rows*y.cell+84,target:null,repairedToday:0});for(let[t,n]of e.conveyorMeta||[]){n.uses==null&&(n.uses=0),n.maintenanceType==null&&(n.maintenanceType="conveyor"),n.kind||(n.kind="conveyor"),n.speedMultiplier||(n.speedMultiplier=n.kind==="boostConveyor"?2:1),n.branchMode||(n.branchMode="random");let o=Un(e,"conveyor",Gi(n));(n.durability==null||n.durability0&&(n.processingCooldown=Math.max(0,n.processingCooldown-t))}function Yn(e){me(e);let t=[];for(let[n,o]of e.conveyorMeta||[])t.push({type:"conveyor",key:n,meta:o,label:`${o.kind==="boostConveyor"?"Boost Belt":"Belt"} ${n}`,center:F(Q(n).col,Q(n).row)});for(let n of e.eggFarms||[])t.push({type:"eggFarm",ref:n,label:`EGG #${n.id}`,center:F(n.col,n.row)});for(let n of(e.scanners||[]).filter(o=>o.kind==="auto"))t.push({type:"autoScanner",ref:n,label:`AUTO #${n.id}`,center:F(n.col,n.row)});for(let n of Object.values(e.facilities||{})){let o=qn(n);["mixer","trash"].includes(o)&&t.push({type:o,ref:n,label:`${n.shortName||n.name||o} #${n.id}`,center:{x:n.x+n.w/2,y:n.y+n.h/2}})}return t}function Nn(e){return e.meta?Ht(e):Ht(e.ref)}function un(e){return e.meta?Wo(e):Wo(e.ref)}function _n(e){return e.meta?Ko(e):Ko(e.ref)}function qi(e,t){Jl(e.meta?e:e.ref,Math.max(0,un(e)-t))}function Yi(e){return e.type==="conveyor"?`conveyor:${e.key}`:`${e.type}:${e.ref?.id||e.ref?.type||e.type}`}function Vi(e,t=.02){me(e);let n=Math.max(0,Number(t)||0),o=0;for(let r of Yn(e)){let s=un(r);qi(r,_n(r)*n),o+=Math.max(0,s-un(r))/_n(r)*100}return o}function zi(e){if(me(e),e.repairman.hiredForNextDay)return{ok:!1,reason:"Repairman already hired."};let t=Ho(e);return e.cashYi(o)===t.key)||null}function ea(e){let t=null;for(let n of Yn(e)){let o=Nn(n);o<=.001||(!t||o>Nn(t))&&(t=n)}return t}function Ji(e,t){me(e);let n=e.repairman;if(!n.active||e.phase!=="running")return;let o=Zl(e,n.target)||ea(e);if(!o){n.target=null;return}n.target={key:Yi(o),label:o.label};let r=Be.repairman.walkSpeed,s=o.center.x-n.x,l=o.center.y-n.y,d=Math.hypot(s,l);if(d>8){let L=Math.min(d,r*t);n.x+=s/d*L,n.y+=l/d*L;return}let v=t/(Be.repairman.secondsPerOnePercent*100),C=un(o),P=v*_n(o);qi(o,P);let R=Math.max(0,(C-un(o))/_n(o)*100);n.repairedToday=(n.repairedToday||0)+R,R>0&&Math.random()<.02&&W(e,n.x,n.y-28,"REPAIR",p.green),Nn(o)<=.001&&(n.target=null)}function ta(e){let t=0,n="none";for(let o of Yn(e)){let r=Nn(o);r>t&&(t=r,n=o.label)}return{ratio:t,percent:Math.round(t*100),label:n}}function jo(e){let t=ta(e),n=Yo(e);return{worst:t,avgBeltPerformance:n,repairman:e.repairman||null}}var na=Ae.commonWeight,oa=Ae.rareWeight,ra=Ae.ultraRareWeight||.45,Ft=Ae.baseDraftSize,Yt=Mr;function qt(e,t){let n=Ie(e);return Math.max(0,Number(n[t])||0)}function Ie(e){e.cardEffects||(e.cardEffects={...yo});for(let[t,n]of Object.entries(yo))e.cardEffects[t]==null&&(e.cardEffects[t]=Array.isArray(n)?[]:n);return e.cardEffects.flattery!=null&&(e.cardEffects.fairiesFlatteryNext=Math.max(0,e.cardEffects.fairiesFlatteryNext||0)+Math.max(0,e.cardEffects.flattery||0),delete e.cardEffects.flattery),e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft||(e.cardDraft={pending:!1,choices:[],rerolls:0,picksRemaining:0}),e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardEffects}function is(e){let t=Math.max(.5,1-.05*Math.min(10,qt(e,"crowdedFarming"))),n=Math.pow(.96,qt(e,"hatchingFeed"));return t*n}function ss(e,t=null){return Math.min(3,Math.max(0,Number(t?.extraEggOutlet)||0))}function ls(e){return Math.pow(.85,qt(e,"scannerQueueSpacing"))}function zn(e,t=null){let n=Ie(e),o=xn*Math.pow(Cn,Math.max(0,n.bearing||0)),r=t?Math.max(.1,Number(e?.conveyorMeta?.get?.(t)?.speedMultiplier)||1):1,s=t?1:Yo(e),l=Math.max(.01,Number(e?.eventActive?.conveyorSpeedMultiplier)||1);return Math.min(_t,o*s)*r*l}function tt(e,t=null){let n=Math.max(0,(e?.level||1)-1),o=t?qt(t,"autoScannerTuning"):0,r=kn*Math.pow(xr,n)*Math.pow(co,o),s=Math.max(uo,r),l=t?Math.max(.01,Number(t?.eventActive?.autoScannerCooldownMultiplier)||1):1;return t?Math.max(uo,s*Kn(e)*l):s}function ji(e){let t=e.cardDraft||{rerolls:0},n=Math.max(1,(t.rerolls||0)+1);return Math.ceil(Math.max(1,e.turn||1)/Ae.rerollCost.dayDivisor*n*Ae.rerollCost.multiplier)}function Vt(e){return Yt.find(t=>t.id===e)||null}function as(e,t){let n=typeof t=="string"?Vt(t):t;return Ie(e),!n||!(n.type==="equipmentUpgrade"||n.type==="cellAction")?[]:Ue(e,n).map(o=>({key:et(o),label:tr(e,o),type:o.type}))}function er(e,t,n={}){let o=typeof t=="string"?Vt(t):t;if(Ie(e),!o||o.type==="dud")return{ok:!1,reason:"Card not found."};if(o.id==="extraCards")return e.cardDraft=e.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.choices.push(...Vn(e,2)),{ok:!0,reason:`${o.title} added 2 draft cards.`};if(o.type==="instant")return us(e,o),{ok:!0,reason:`${o.title} granted.`};if(o.type==="equipmentUpgrade"){let r=Ue(e,o);if(!r.length)return{ok:!1,reason:`No valid target for ${o.title}.`};let s=n.targetKey&&n.targetKey!=="__auto__"?String(n.targetKey):"",l=s?r.find(d=>et(d)===s):r[0];return l?(cs(e,l),{ok:!0,reason:`${o.title} applied to ${tr(e,l)}.`}):{ok:!1,reason:`Selected target is no longer valid for ${o.title}.`}}if(o.type==="cellAction"&&o.target==="blockedCell"){let r=Ue(e,o);if(!r.length)return{ok:!1,reason:"No blocked cells to remove."};let s=new Set((Array.isArray(n.targetKeys)?n.targetKeys:[n.targetKey]).filter(d=>d&&d!=="__auto__").map(String)),l=s.size?r.filter(d=>s.has(et(d))):r.slice(0,3);if(!l.length)return{ok:!1,reason:`Selected target is no longer valid for ${o.title}.`};for(let d of l.slice(0,3)){e.blockedCells.delete(I(d.col,d.row));let v=F(d.col,d.row);yt(e,v.x,v.y),Ve(e,v.x,v.y,p.danger,42),Ze(e,v.x,v.y,8,p.warn)}return ve(e),{ok:!0,reason:`${o.title} removed ${Math.min(3,l.length)} blocked cell(s).`}}return{ok:!1,reason:`${o.title} cannot be debug-granted.`}}function tr(e,t){if(t.type==="blockedCell")return`Blocked cell ${t.col},${t.row}`;if(t.type==="eggFarm")return`EGG #${t.id} L${t.level} -> L${t.level+1}`;if(t.type==="eggOutlet"){let n=Math.max(0,Number(t.farm?.extraEggOutlet)||0);return`EGG #${t.id} OUTLET ${1+n} -> ${2+n}`}if(t.type==="scanner")return`AUTO #${t.id} L${t.level} -> L${t.level+1} | CD ${tt(t,e).toFixed(1)}s -> ${tt({...t,level:t.level+1},e).toFixed(1)}s`;if(t.type==="facility"&&(t.baseId||t.id)==="mixer"){let n=t.level,o=Ye(e);t.level=n+1;let r=Ye(e);return t.level=n,`MIXER L${t.level} -> L${t.level+1} | ${M(o)} -> ${M(r)}`}if(t.type==="facility"&&(t.baseId||t.id)==="truck"){let n=t.level,o=$e(e);t.level=n+1;let r=$e(e);return t.level=n,`TRUCK L${t.level} -> L${t.level+1} | ${M(o)} -> ${M(r)}`}if(t.type==="facility"&&t.id==="trash"){let n=Dt(e),o=Math.min(Kt(),n+1),r=dt(n),s=dt(o);return`SHREDDER L${t.level||1} -> L${(t.level||1)+1} | poop income ${M(r)} -> ${M(s)} per item`}return`${t.name||t.id} L${t.level||1} -> L${(t.level||1)+1}`}function ia(e){return[...e.blockedCells||[]].map(t=>{let[n,o]=String(t).split(",").map(Number);return{type:"blockedCell",id:t,col:n,row:o}}).filter(t=>Number.isFinite(t.col)&&Number.isFinite(t.row))}function Ue(e,t){let n=typeof t=="string"?Vt(t):t;return Ie(e),n?n.target==="blockedCell"?ia(e):n.target==="eggFarm"?e.eggFarms.filter(o=>(o.level||1)<4):n.target==="eggOutlet"?e.eggFarms.filter(o=>Math.max(0,Number(o.extraEggOutlet)||0)<3).map(o=>({type:"eggOutlet",id:o.id,col:o.col,row:o.row,farm:o})):n.target==="autoScanner"?e.scanners.filter(o=>o.kind==="auto"):n.target==="mixer"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="mixer"):n.target==="truck"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="truck"):n.target==="trash"?Oo(e)(o.baseId||o.id)==="trash"):[]:[]:[]}function sa(e,t){let n=Ie(e);if(t.id==="crowdedFarming")return(n.crowdedFarming||0)>=10;if(t.id==="recyclingSubsidy")return(n.recyclingSubsidy||0)>=3;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,Ae.dudChancePerCard||0)),r=Math.max(1e-4,Math.min(1,Ae.dudChanceReductionPerFilter||.05));return(n.dudFilter||0)>=Math.ceil(o/r)}return t.id==="laborExploitation"?!!n.laborExploitation:t.id==="usedMachine"?!!n.usedMachineActive:t.id==="newMachine"?!n.usedMachineActive:!1}function la(e){let t=e.repairman||{};return!!(t.active||t.hiredForNextDay||e.pendingRepairWorkerWages>0)}function aa(e){return Yt.filter(t=>!(t.id==="laborExploitation"&&!la(e)||sa(e,t)||(t.type==="equipmentUpgrade"||t.type==="cellAction")&&Ue(e,t).length<=0))}function Zi(e,t){return t.rarity==="ultraRare"?ra:t.rarity==="rare"?oa:na}function ca(e,t){let n=t.reduce((r,s)=>r+Zi(e,s),0);if(n<=0)return t[Math.floor(Math.random()*t.length)];let o=Math.random()*n;for(let r of t)if(o-=Zi(e,r),o<=0)return r;return t[t.length-1]}var es=0;function ua(){return es+=1,{id:`dud:${Date.now()}:${es}`,title:"Dud",rarity:"dud",type:"dud",description:"Click to flick this dud away. It does not consume a pick."}}function da(e){let t=Ie(e),n=Math.max(0,Math.min(1,Ae.dudChancePerCard||0)),o=Math.max(0,Math.min(1,Ae.dudChanceReductionPerFilter||0));return Math.max(0,n-o*Math.max(0,t.dudFilter||0))}function fa(e,t){let n=[...t],o=0,r=Math.max(0,Ae.maxDudsPerDraft||0),s=da(e);for(let l=0;ld.id===s.id);l>=0&&r.splice(l,1)}return fa(e,o)}function et(e){return e?e.type==="blockedCell"?`blockedCell:${e.id}`:e.type==="eggFarm"?`eggFarm:${e.id}`:e.type==="eggOutlet"?`eggOutlet:${e.id}`:e.type==="scanner"?`scanner:${e.id}`:e.type==="facility"?`facility:${e.id}`:`${e.type}:${e.id}`:""}function ts(e){if(!e)return null;if(e.type==="blockedCell"){let t=F(e.col,e.row);return{x:t.x-y.cell*.48,y:t.y-y.cell*.48,w:y.cell*.96,h:y.cell*.96,cx:t.x,cy:t.y}}if(e.type==="eggFarm"||e.type==="eggOutlet"){let t=F(e.col,e.row);return{x:t.x-34,y:t.y-34,w:68,h:68,cx:t.x,cy:t.y}}if(e.type==="scanner"){let t=pe(e);return{x:t.x-54,y:t.y-77,w:108,h:154,cx:t.x,cy:t.y}}return e.type==="facility"?{x:e.x,y:e.y,w:e.w,h:e.h,cx:e.x+e.w/2,cy:e.y+e.h/2}:null}function nr(e){if(!e.cardTargetPick?.pending)return[];if(e.cardTargetPick.mode==="autoScannerMenu"){let n=new Set(e.cardTargetPick.targetKeys||[]);return e.scanners.filter(o=>o.kind==="auto"&&n.has(et(o))).map(o=>({key:et(o),label:"AUTO ROUTE SETTINGS",target:o,bounds:ts(o)})).filter(o=>o.bounds)}let t=new Set(e.cardTargetPick.targetKeys||[]);return Ue(e,e.cardTargetPick.cardId).filter(n=>t.has(et(n))).map(n=>({key:et(n),label:tr(e,n),target:n,bounds:ts(n)})).filter(n=>n.bounds)}function pa(e,t){let n=nr(e);for(let o of n){let r=o.bounds;if(t.x>=r.x&&t.x<=r.x+r.w&&t.y>=r.y&&t.y<=r.y+r.h)return o.target}return null}function cs(e,t){if(t.type==="eggOutlet"){let n=t.farm||e.eggFarms.find(r=>r.id===t.id);if(!n)return;n.extraEggOutlet=Math.min(3,Math.max(0,Number(n.extraEggOutlet)||0)+1);let o=F(n.col,n.row);W(e,o.x,o.y-30,`OUTLET ${1+n.extraEggOutlet}`,p.green),ve(e);return}if(t.level=(t.level||1)+1,t.type==="eggFarm"){t.nextSpawn=gt(t),t.lastInterval=t.nextSpawn;let n=F(t.col,t.row);W(e,n.x,n.y-30,`LV ${t.level}`,p.green);return}if(t.type==="scanner"){let n=pe(t);W(e,n.x,n.y-34,`LV ${t.level}`,p.green);return}t.type==="facility"&&W(e,t.x+t.w/2,t.y+18,`LV ${t.level}`,p.green)}function us(e,t){let n=Ie(e),o=r=>{n[r]=Math.max(0,n[r]||0)+1};if(t.id==="bearing"&&o("bearing"),t.id==="autoScannerTuning"&&o("autoScannerTuning"),t.id==="legalWork"&&o("legalWork"),t.id==="crowdedFarming"&&(n.crowdedFarming=Math.min(10,(n.crowdedFarming||0)+1)),t.id==="hatchingFeed"&&o("hatchingFeed"),t.id==="poopRateBooster"&&o("poopRateBooster"),t.id==="safetyCover"&&o("safetyCover"),t.id==="recyclingSubsidy"&&(n.recyclingSubsidy=Math.min(3,(n.recyclingSubsidy||0)+1)),t.id==="chemicalWeaponSubsidy"&&o("chemicalWeaponSubsidy"),t.id==="preventiveMaintenance"&&o("preventiveMaintenance"),t.id==="dudFilter"&&o("dudFilter"),t.id==="durabilityCoating"&&(o("durabilityCoating"),me(e)),t.id==="sparePartsBin"){o("sparePartsBin");let r=Vi(e,.02);e.stats.sparePartsRepair=(e.stats.sparePartsRepair||0)+r,e.totals.sparePartsRepair=(e.totals.sparePartsRepair||0)+r,W(e,y.x+y.cols*y.cell/2,y.y-30,"REPAIR +2%",p.green)}t.id==="dudRefund"&&o("dudRefund"),t.id==="freeReroll"&&o("freeReroll"),t.id==="composter"&&o("composter"),t.id==="scannerQueueSpacing"&&o("scannerQueueSpacing"),t.id==="flattery"&&o("fairiesFlatteryNext"),t.id==="usedMachine"&&(n.usedMachineActive=!0),t.id==="newMachine"&&(n.usedMachineActive=!1),t.id==="laborExploitation"&&(n.laborExploitation=1),t.id==="rescueLoan"&&(o("rescueLoanCharges"),W(e,y.x+y.cols*y.cell/2,y.y-30,"RESCUE HELD",p.green))}function Ke(e){return`${Math.round(Number(e||0)*100)}%`}function ns(e){let t=lt[Math.max(0,Math.min(lt.length-1,e-1))]||lt[0]||[0,0];return`${t[0].toFixed(2)}-${t[1].toFixed(2)}s`}function os(e,t){return Math.ceil(e*Math.pow(xe.incomeUpgradeRate,Math.max(0,t-1)))}function rs(e,t,n){let r=Ue(e,t==="mixer"?"upgradeMixer":"upgradeTruck")[0];if(!r)return{before:os(n,1),after:os(n,2)};let s=t==="mixer"?Ye(e):$e(e),l=r.level||1;r.level=l+1;let d=t==="mixer"?Ye(e):$e(e);return r.level=l,{before:s,after:d}}function ya(e,t){let n=Ie(e);if(t.id==="upgradeEgg"){let o=Ue(e,t),r=Math.min(3,Math.max(1,o[0]?.level||1));return`Choose one EGG. Level +1. Production interval ${ns(r)} -> ${ns(r+1)}.`}if(t.id==="upgradeAutoScanner"){let o=Ue(e,t)[0]||{level:1},r=tt(o,e),s=tt({...o,level:(o.level||1)+1},e);return`Choose one AUTO SCANNER. Level +1. Cooldown ${r.toFixed(2)}s -> ${s.toFixed(2)}s.`}if(t.id==="upgradeMixer"){let o=rs(e,"mixer",xe.income.mixer);return`Choose one MIXER. Earning +10%. Male-chick income ${M(o.before)} -> ${M(o.after)}.`}if(t.id==="upgradeTruck"){let o=rs(e,"truck",xe.income.truck);return`Choose one TRUCK. Earning +10%. Correct shipment income ${M(o.before)} -> ${M(o.after)}.`}if(t.id==="upgradeTrash"){let o=Dt(e),r=Math.min(Kt(),o+1),s=dt(o),l=dt(r);return`SHREDDER level +1. Poop income ${M(s)} -> ${M(l)} per item.`}if(t.id==="bearing"){let o=Math.min(_t,xn*Math.pow(Cn,Math.max(0,n.bearing||0))),r=Math.min(_t,xn*Math.pow(Cn,Math.max(0,(n.bearing||0)+1)));return`Conveyor speed +7.5%. After pick: ${o.toFixed(1)} -> ${r.toFixed(1)} px/s.`}if(t.id==="legalWork"){let o=Math.max(0,n.legalWork||0);return`Fairies tribute profit exemption +${M(250)}. After pick: exemption bonus ${M(250*(o+1))}.`}if(t.id==="crowdedFarming"){let o=Math.min(10,(n.crowdedFarming||0)+1);return`Held ${n.crowdedFarming||0}/10. After pick: EGG interval ${Ke(Math.max(.5,1-.05*o))}, deterioration ${Ke(Math.min(1.4,1+.04*o))}.`}if(t.id==="extraEggOutlet"){let o=Ue(e,t),r=Math.max(0,Number(o[0]?.farm?.extraEggOutlet)||0);return`Choose one EGG. Output ports ${1+r} -> ${2+r}. Max 4 ports per EGG.`}if(t.id==="hatchingFeed")return`Held ${n.hatchingFeed||0}. After pick: EGG interval ${Ke(Math.pow(.96,(n.hatchingFeed||0)+1))}, poop rate multiplier ${Ke(Math.pow(1.03,(n.hatchingFeed||0)+1))}.`;if(t.id==="poopRateBooster")return`Held ${n.poopRateBooster||0}. After pick: base poop rate +${Math.round((n.poopRateBooster||0)+1)*4} percentage points.`;if(t.id==="autoScannerTuning")return`Held ${n.autoScannerTuning||0}. After pick: all AUTO SCANNER default cooldown ${Ke(Math.pow(co,(n.autoScannerTuning||0)+1))}.`;if(t.id==="safetyCover")return`Held ${n.safetyCover||0}. After pick: explosion damage ${Ke(Math.pow(.95,(n.safetyCover||0)+1))}.`;if(t.id==="recyclingSubsidy")return`Held ${n.recyclingSubsidy||0}/3. After pick: normal SELL refund ${Math.round(Math.min(.8,.5+.1*((n.recyclingSubsidy||0)+1))*100)}%.`;if(t.id==="chemicalWeaponSubsidy")return`Held ${n.chemicalWeaponSubsidy||0}. After pick: ${M(1200*((n.chemicalWeaponSubsidy||0)+1))} per 70 truck-shipped poop each day.`;if(t.id==="preventiveMaintenance")return`Held ${n.preventiveMaintenance||0}. After pick: deterioration speed ${Ke(Math.pow(.95,(n.preventiveMaintenance||0)+1))}.`;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,Ae.dudChancePerCard||0)),r=Math.max(0,Math.min(1,Ae.dudChanceReductionPerFilter||.05)),s=Math.max(0,n.dudFilter||0),l=Math.max(0,o-r*s),d=Math.max(0,o-r*(s+1));return`Held ${s}. DUD chance per card ${Ke(l)} -> ${Ke(d)}.`}return t.id==="durabilityCoating"?`Held ${n.durabilityCoating||0}. After pick: maximum durability ${Ke(Math.pow(1.03,(n.durabilityCoating||0)+1))}.`:t.id==="sparePartsBin"?`Held ${n.sparePartsBin||0}. Immediately restores 2% durability to every maintained machine. Common card weight.`:t.id==="dudRefund"?`Held ${n.dudRefund||0}. After pick: DUD clicks award ${M(50*((n.dudRefund||0)+1))}.`:t.id==="freeReroll"?`Held ${n.freeReroll||0}. After pick: each card screen starts with ${(n.freeReroll||0)+1} free reroll${(n.freeReroll||0)+1===1?"":"s"}.`:t.id==="composter"?`Held ${n.composter||0}. After pick: SHREDDER poop grants ${M(3*((n.composter||0)+1))}.`:t.id==="scannerQueueSpacing"?`Held ${n.scannerQueueSpacing||0}. After pick: Manual/Auto Scanner queue spacing ${Ke(Math.pow(.85,(n.scannerQueueSpacing||0)+1))}.`:t.id==="flattery"?`Next Fairies tribute -50%. Held for next tribute: ${n.fairiesFlatteryNext||0}.`:t.id==="usedMachine"?"Enable Used Machines: future equipment costs 50%, has no SELL refund, and starts with 60% durability.":t.id==="newMachine"?"Cancel Used Machines. Future equipment returns to normal price, refund, and durability.":t.id==="laborExploitation"?"Repairman labor cost -30% permanently. One time only.":t.id==="rescueLoan"?`At day-end bankruptcy check, gain ${M(500)} if cash is below ${M(0)}. Held: ${n.rescueLoanCharges||0}.`:t.description}function Zo(e,t){let n=e.cardDraft?.choices||[],o=n.findIndex(r=>r.id===t.id);o>=0&&n.splice(o,1)}function ds({game:e,ui:t,onUpdatePanels:n}){function o(){n&&n()}function r(){Ie(e),e.cardTargetPick=null,e.cardDraft={pending:!0,choices:Vn(e,Ft),rerolls:0,freeRerolls:qt(e,"freeReroll"),picksRemaining:1}}function s(){Ie(e),e.cardDraft.pending=!1,e.cardDraft.choices=[],e.cardDraft.picksRemaining=0,e.cardTargetPick=null,t.modal.classList.remove("visible","equipment-popover"),o()}function l($=Ft){Ie(e),e.cardDraft.choices=Vn(e,$)}function d(){Ie(e),!e.cardDraft.choices.length&&e.cardDraft.picksRemaining>0&&l(Ft)}function v($){Zo(e,$),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1),e.cardTargetPick=null,d(),e.cardDraft.picksRemaining<=0?s():Z()}function C($){Zo(e,$),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1)+Ae.extraCardsAddedPicks,e.cardDraft.choices.push(...Vn(e,2)),Z()}function P($,U){let N=qt(e,"dudRefund")*50;if(N>0){let le=Ne(e,N);e.stats.dudRefundIncome=(e.stats.dudRefundIncome||0)+le,e.totals.dudRefundIncome=(e.totals.dudRefundIncome||0)+le,W(e,y.x+y.cols*y.cell/2,y.y-30,`DUD REFUND +${M(le)}`,p.green)}It(e,34,.62),document.body?.animate&&document.body.animate([{transform:"translate(0, 0)"},{transform:"translate(-10px, 7px)"},{transform:"translate(12px, -8px)"},{transform:"translate(-8px, -5px)"},{transform:"translate(9px, 6px)"},{transform:"translate(0, 0)"}],{duration:260,easing:"steps(5, end)"}),U&&(U.style.setProperty("--fling-x",`${260+Math.random()*260}px`),U.style.setProperty("--fling-y",`${-260-Math.random()*170}px`),U.style.setProperty("--fling-r",`${(Math.random()<.5?-1:1)*(52+Math.random()*38)}deg`),U.classList.add("flung")),window.setTimeout(()=>{Zo(e,$),d(),Z()},340)}function R($,U=null){if($.type==="dud")return P($,U);if($.id==="extraCards")return C($);if($.type==="equipmentUpgrade"||$.type==="cellAction")return L($);us(e,$),v($)}function L($){let U=Ue(e,$);U.length&&(e.cardTargetPick={pending:!0,cardId:$.id,mode:$.target==="blockedCell"?"blockedCell":"equipment",targetKeys:U.map(et),remaining:$.id==="dynamite"?Math.min(3,U.length):1},t.modal.classList.remove("visible","equipment-popover"),o())}function V($){if(!$||$.type!=="blockedCell")return!1;let U=I($.col,$.row);if(!e.blockedCells?.has(U))return!1;e.blockedCells.delete(U);let N=F($.col,$.row);return yt(e,N.x,N.y),Ve(e,N.x,N.y,p.danger,62),Ze(e,N.x,N.y,18,p.warn),On(e,N.x,N.y,8),It(e,16,.35),W(e,N.x,N.y-18,"BOOM",p.danger),ve(e),e.cardTargetPick.remaining=Math.max(0,(e.cardTargetPick.remaining||1)-1),e.cardTargetPick.targetKeys=Ue(e,"dynamite").map(et),o(),!0}function te($){if(!e.cardTargetPick?.pending)return!1;let U=Vt(e.cardTargetPick.cardId),N=pa(e,$);return!U||!N?(z(),!0):U.id==="dynamite"?(V(N)&&((e.cardTargetPick.remaining||0)<=0||!Ue(e,"dynamite").length)&&v(U),!0):(cs(e,N),v(U),!0)}function z(){e.cardTargetPick?.pending&&(e.cardTargetPick=null,Z())}function se(){let $=Math.max(0,e.cardDraft?.freeRerolls||0);if($>0){e.cardDraft.freeRerolls=$-1,e.cardDraft.rerolls+=1,l(Ft),Z();return}let U=ji(e);e.cashA!==Se)].slice(0,5);return N.innerHTML=`${$.title}
${he.map(A=>`${A}`).join("")}
${ya(e,$)}`,N.addEventListener("click",()=>R($,N)),N.dataset.index=String(U),N}function Z(){Ie(e),e.cardTargetPick=null,e.cardDraft?.pending||r(),e.cardDraft.choices?.length||l(Ft);let $=e.cardDraft.choices||[],U=ji(e),N=Math.max(0,e.cardDraft?.freeRerolls||0),le=Math.max(1,e.cardDraft.picksRemaining||1);t.modalTitle.textContent="Choose Upgrade Card",t.modalBody.innerHTML=`

Choose ${le} card${le===1?"":"s"} before Build phase. Dud cards can be flicked away without consuming a pick. Equipment cards target machines; Dynamite targets blocked cells.

`;let Se=t.modalBody.querySelector("#cardChoices");$.forEach((_,k)=>Se.appendChild(ye(_,k))),t.modalActions.innerHTML="";let he=document.createElement("button");he.type="button",he.className="facility-action warn reroll-button",he.textContent=N>0?`Reroll (FREE x${N})`:`Reroll ${M(U)}`,he.disabled=N<=0&&e.cash0?`${N} free reroll${N===1?"":"s"} remaining.`:he.disabled?"Not enough cash":"",he.addEventListener("click",se),t.modalActions.appendChild(he);let A=document.createElement("button");A.type="button",A.className="facility-action",A.textContent="No Card",A.title="Skip this upgrade pick and enter Build phase.",A.addEventListener("click",s),t.modalActions.appendChild(A),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible")}return{prepareDraft:r,showDraft:Z,finishDraft:s,chooseTargetAtPoint:te,cancelTargetPick:z}}var ha=!0,ma={chickMale:"./assets/images/chick_male.png",chickFemale:"./assets/images/chick_female.png",poop:"./assets/images/poop.png",conveyorStraightH:"./assets/dark_factory/facilities/conveyor/conveyor_straight_h_16.png",conveyorStraightV:"./assets/dark_factory/facilities/conveyor/conveyor_straight_v_16.png",conveyorTurnNe:"./assets/dark_factory/facilities/conveyor/conveyor_turn_ne_16.png",conveyorTurnNw:"./assets/dark_factory/facilities/conveyor/conveyor_turn_nw_16.png",conveyorTurnSe:"./assets/dark_factory/facilities/conveyor/conveyor_turn_se_16.png",conveyorTurnSw:"./assets/dark_factory/facilities/conveyor/conveyor_turn_sw_16.png",boostConveyorStraightH:"./assets/dark_factory/facilities/conveyor/boost_conveyor_straight_h_16.png",boostConveyorStraightV:"./assets/dark_factory/facilities/conveyor/boost_conveyor_straight_v_16.png",boostConveyorTurnNe:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_ne_16.png",boostConveyorTurnNw:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_nw_16.png",boostConveyorTurnSe:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_se_16.png",boostConveyorTurnSw:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_sw_16.png",scannerManual:"./assets/dark_factory/facilities/machines/manual_scanner_32x48.png",scannerAuto:"./assets/dark_factory/facilities/machines/auto_scanner_32x48.png",eggFarm:"./assets/dark_factory/facilities/machines/egg_farm_16.png",mixer:"./assets/dark_factory/facilities/machines/mixer_32.png",shredder:"./assets/dark_factory/facilities/machines/shredder_32.png",truck:"./assets/dark_factory/facilities/vehicles/truck_32.png",repairman:"./assets/dark_factory/facilities/utility/repairman_16.png",obstacleCrate:"./assets/dark_factory/facilities/utility/obstacle_crate_16.png"},be={};for(let[e,t]of Object.entries(ma)){let n=new Image;n.loaded=!1,n.onerror=()=>{n.loaded=!1},(ha&&e!=="chickMale"&&e!=="chickFemale"||e==="poop")&&t&&(n.onload=()=>{n.loaded=!0},n.src=t),be[e]=n}function hs(e,t,n,o){e.imageSmoothingEnabled=!1,e.clearRect(0,0,t.width,t.height),wa(e,t),e.save();let r=n.shake.time>0?G(-n.shake.strength,n.shake.strength):0,s=n.shake.time>0?G(-n.shake.strength,n.shake.strength):0,l=n.view?.scale||1;e.translate((n.view?.x||0)+r,(n.view?.y||0)+s),e.scale(l,l),ka(e,n),xa(e,n),Ma(e,n),$a(e,n),_a(e,n),Ia(e,n),Ba(e,n),va(e,n),Ka(e,n,o.activeQueuedChick),ja(e,n),za(e,t,n),Va(e,n,o.selectedObject,o.selectedTitle),Xa(e,n),Qa(e,n),Ja(e,n),e.restore(),Za(e,n,t)}function ba(e){if(e.type==="eggFarm"){let n=F(e.ref.col,e.ref.row);return{x:n.x-34,y:n.y-34,w:68,h:68,cx:n.x,cy:n.y}}let t=e.ref;return{x:t.x,y:t.y,w:t.w,h:t.h,cx:t.x+t.w/2,cy:t.y+t.h/2}}function va(e,t){if(t.phase!=="build")return;let n=In(t);for(let o of n){let r=ba(o);e.save(),e.fillStyle="rgba(196,36,36,.22)",e.strokeStyle=p.danger,e.lineWidth=5,e.setLineDash([10,6]),ne(e,r.x,r.y,r.w,r.h,!0,!0),e.setLineDash([]),e.fillStyle=p.danger,e.strokeStyle=p.white,e.lineWidth=4,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.strokeText("!",r.cx,r.y+24),e.fillText("!",r.cx,r.y+24),e.font="900 11px ui-monospace, monospace",e.strokeText("NO ROUTE",r.cx,r.y+r.h-8),e.fillText("NO ROUTE",r.cx,r.y+r.h-8),e.restore()}}function ne(e,t,n,o,r,s=!0,l=!0){e.beginPath(),e.rect(t,n,o,r),s&&e.fill(),l&&e.stroke()}function fn(e,t,n,o,r=p.ink){e.save(),e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.lineWidth=4,e.strokeStyle=p.white,e.fillStyle=r,e.strokeText(o,t,n),e.fillText(o,t,n),e.restore()}function Xe(e,t,n,o,r,s){if(!t?.loaded)return!1;let l=e.imageSmoothingEnabled;return e.imageSmoothingEnabled=!1,e.drawImage(t,Math.round(n),Math.round(o),Math.round(r),Math.round(s)),e.imageSmoothingEnabled=l,!0}function fs(e,t,n,o,r,s,l=null,d=1){e.fillStyle=s,e.fillRect(Math.round(t),Math.round(n),Math.round(o),Math.round(r)),l&&(e.strokeStyle=l,e.lineWidth=d,e.strokeRect(Math.round(t)+.5,Math.round(n)+.5,Math.round(o)-1,Math.round(r)-1))}function wa(e,t){e.fillStyle=p.bg,e.fillRect(0,0,t.width,t.height),e.save(),e.globalAlpha=.85;for(let n=0;n=n;for(let r of Ct(t)){let s=Mt(r);e.save(),e.fillStyle=o?"rgba(183,245,198,.34)":"rgba(255,255,255,.22)",e.strokeStyle=o?p.green:p.muted,e.lineWidth=5,e.setLineDash([16,10]),ne(e,s.x,s.y,s.w,s.h,!0,!0),e.setLineDash([]);let l=vo(r),d=l.cx,v=l.cy;e.fillStyle="rgba(255,255,255,.94)",e.strokeStyle=p.ink,e.lineWidth=4,ne(e,l.x,l.y,l.w,l.h,!0,!0),e.fillStyle=o?p.green:p.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText(r.direction==="right"?"BUY RIGHT LOT":"BUY UPPER LOT",d,v-12),e.fillStyle=p.ink,e.font="900 16px ui-monospace, monospace",e.fillText(`${M(n)} / 10\xD710`,d,v+15),e.fillStyle=p.muted,e.font="900 11px ui-monospace, monospace",e.fillText("blocked tiles included",d,v+30),e.restore()}}function nt(e,t,n,o,r,s,l=0){let d=Ht(s);d<.5||(e.save(),e.globalAlpha=Math.min(.62,.12+d*.54),e.fillStyle="#6b4a23",l>0?(e.beginPath(),e.roundRect?.(t,n,o,r,l),e.roundRect?e.fill():ne(e,t,n,o,r,!0,!1)):ne(e,t,n,o,r,!0,!1),e.globalAlpha=Math.min(.9,.25+d*.6),e.strokeStyle="#3a2a16",e.lineWidth=Math.max(2,Math.floor(2+d*5)),e.setLineDash([5,6]),ne(e,t+3,n+3,o-6,r-6,!1,!0),e.restore())}function or(e,t){let n=e.componentLookup?.get(t);return(n?e.congestion.get(n):null)?.ratio||0}function Ca(e,t,n={}){let o=Qn(e,t).sort(),s=n.kind==="boostConveyor"?"boostConveyor":"conveyor",l=d=>o.includes(d);if(o.length===2){if(l("left")&&l("right"))return be[`${s}StraightH`];if(l("up")&&l("down"))return be[`${s}StraightV`];if(l("up")&&l("right"))return be[`${s}TurnNe`];if(l("up")&&l("left"))return be[`${s}TurnNw`];if(l("down")&&l("right"))return be[`${s}TurnSe`];if(l("down")&&l("left"))return be[`${s}TurnSw`]}return o.length===1?l("up")||l("down")?be[`${s}StraightV`]:be[`${s}StraightH`]:l("up")||l("down")?be[`${s}StraightV`]:be[`${s}StraightH`]}function Ma(e,t){let n=[],o=new Set;for(let s of t.conveyorTiles){let{col:l,row:d}=Q(s);for(let v of ue){let C={col:l+v.dc,row:d+v.dr},P=I(C.col,C.row);if(!t.conveyorTiles.has(P))continue;let R=[s,P].sort().join("|");if(o.has(R))continue;o.add(R);let L=Math.max(or(t,s),or(t,P));n.push({a:F(l,d),b:F(C.col,C.row),ratio:L})}}e.save(),e.lineCap="round",e.lineJoin="round";for(let s of[{width:31,color:"#0b0c0f",alpha:1},{width:23,color:"#444b56",alpha:1},{width:15,color:"#171a1f",alpha:1}]){e.globalAlpha=s.alpha,e.strokeStyle=s.color,e.lineWidth=s.width;for(let l of n)e.beginPath(),e.moveTo(l.a.x,l.a.y),e.lineTo(l.b.x,l.b.y),e.stroke()}for(let s of n){let l=Math.max(0,(s.ratio-.5)/.5);e.strokeStyle=gn(p.green,p.danger,l),e.globalAlpha=s.ratio>.5?.35+l*.55:.8,e.lineWidth=6,e.beginPath(),e.moveTo(s.a.x,s.a.y),e.lineTo(s.b.x,s.b.y),e.stroke()}let r=Aa(t);for(let s of t.conveyorTiles){let l=F(...Object.values(Q(s))),d=t.conveyorMeta.get(s)||{},v=or(t,s),C=Ca(t,s,d),P=v>.5;if(e.fillStyle=P?"rgba(196,36,36,.28)":"rgba(0,0,0,.35)",e.strokeStyle=P?p.danger:"rgba(255,184,39,.34)",e.lineWidth=P?3:1,ne(e,l.x-20,l.y-20,40,40,!0,!0),!Xe(e,C,l.x-19,l.y-19,38,38)){let L=d.kind==="boostConveyor"?"#315e92":"#454b55";e.fillStyle=v>.5?gn(L,"#a12c2c",Math.max(0,(v-.5)/.5)):L,e.strokeStyle=p.ink,e.lineWidth=2,ne(e,l.x-18,l.y-18,36,36,!0,!0)}nt(e,l.x-18,l.y-18,36,36,{meta:d}),He(e,t,"conveyor",s,l.x,l.y,38,38),Da(e,l,r.get(s)||[]);let R=Qn(t,s);Pa(e,l,d,Ta(t,s,R),R),v>.5&&fn(e,l.x,l.y-15,`${Math.floor(v*100)}%`,p.danger)}e.restore()}function Qn(e,t){let n=Q(t);return ue.filter(o=>e.conveyorTiles.has(I(n.col+o.dc,n.row+o.dr))).map(o=>o.name)}function ms(e,t,n){let o=ue.find(l=>l.name===n);if(!o)return!1;let r=e.conveyorMeta?.get?.(I(t.col+o.dc,t.row+o.dr));return r?[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))].includes(o.opposite):!1}function ga(e,t,n,o=Qn(e,t),r="random"){if(o.length<3)return n;let s=Q(t),l=new Set(o.filter(C=>ms(e,s,C)));if(r&&r!=="random"&&o.includes(r)){let C=new Set(l);C.add(r),o.filter(P=>!C.has(P)).length>=2&&l.add(r)}let d=o.filter(C=>!l.has(C));if(d.length)return d;let v=n.filter(C=>!l.has(C));return v.length?v:n}function Ta(e,t,n=Qn(e,t)){if(n.length<3)return[];let o=Q(t),r=new Set(n.filter(s=>ms(e,o,s)));return n.filter(s=>{let l=new Set(r);return l.add(s),n.filter(d=>!l.has(d)).length>=2})}function Ea(e,t,n){let o=Q(t),r=ue.filter(d=>e.conveyorTiles.has(I(o.col+d.dc,o.row+d.dr))).map(d=>d.name),s=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(d=>r.includes(d)),l=r;return s.length?s:l}function Pa(e,t,n,o,r=o){if(r.length<3||o.length<2)return;e.save();let s=o.includes(n.branchMode)?n.branchMode:"random",l=s!=="random";if(e.lineJoin="round",e.lineCap="round",e.lineWidth=2,e.fillStyle="rgba(255,255,255,.9)",e.strokeStyle=l?p.warn:p.green,ne(e,t.x-17,t.y-17,34,34,!0,!0),e.strokeStyle=p.ink,e.lineWidth=2,e.fillStyle=p.ink,s!=="random"){let d=ue.find(v=>v.name===s);Xn(e,t.x,t.y,d?.angle||0,9,6)}else e.beginPath(),e.moveTo(t.x-10,t.y),e.lineTo(t.x-2,t.y),e.lineTo(t.x+8,t.y-8),e.moveTo(t.x-2,t.y),e.lineTo(t.x+8,t.y+8),e.stroke(),Xn(e,t.x+9,t.y-9,-Math.PI/4,4,3),Xn(e,t.x+9,t.y+9,Math.PI/4,4,3);e.restore()}function Ra(e,t,n){if(!n)return[];let o=Q(t),r=ue.filter(d=>e.conveyorTiles.has(I(o.col+d.dc,o.row+d.dr))).map(d=>d.name),s=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(d=>r.includes(d));return ga(e,t,s.length?s:Ea(e,t,n),r,n.branchMode||"random").map(d=>ue.find(v=>v.name===d)).filter(Boolean)}function Aa(e){let t=new Map;for(let[n,o]of e.conveyorMeta||[]){let r=Ra(e,n,o);r.length&&t.set(n,r)}return t}function Da(e,t,n){let o=n.slice(0,4);o.length&&(e.save(),e.fillStyle=p.ink,e.globalAlpha=.86,o.forEach(r=>{Xn(e,t.x+r.dc*12,t.y+r.dr*12,r.angle,6,5)}),e.restore())}function Xn(e,t,n,o,r=11,s=8){e.save(),e.translate(t,n),e.rotate(o),e.beginPath(),e.moveTo(r,0),e.lineTo(-r*.72,-s),e.lineTo(-r*.72,s),e.closePath(),e.fill(),e.restore()}function $a(e,t){e.save(),e.lineWidth=2,e.font="900 12px ui-monospace, monospace",e.textAlign="center";for(let n of t.scanners){let o=To(n),r=[{type:"inputA",p:Pe(n,"inputA"),label:"IN",color:p.green},{type:"left",p:Pe(n,"left"),label:Po(o.left),color:Ro(o.left)},{type:"right",p:Pe(n,"right"),label:Po(o.right),color:Ro(o.right)}];for(let s of r){if(!s.p)continue;let l=F(s.p.col,s.p.row),d=jr(t,n,s.type||(s.label==="IN"?"inputA":null))||t.conveyorTiles.has(I(s.p.col,s.p.row));e.fillStyle=d?gn("#1a1d23",s.color,.24):"#3a1e22",e.strokeStyle=d?s.color:p.danger,ne(e,l.x-18,l.y-12,36,24,!0,!0),e.fillStyle=p.white,e.fillText(s.label,l.x,l.y+4)}}e.restore()}function Ia(e,t){for(let n of t.eggFarms)Fa(e,n,t)}function Fa(e,t,n){let o=F(t.col,t.row);if(e.save(),Xe(e,be.eggFarm,o.x-29,o.y-29,58,58)){nt(e,o.x-29,o.y-29,58,58,t);let l=1+Math.max(0,Number(t.extraEggOutlet)||0);e.fillStyle="rgba(255,255,255,.92)",e.strokeStyle=p.ink,e.lineWidth=2,ne(e,o.x+9,o.y+12,30,18,!0,!0),e.fillStyle=p.ink,e.font="900 10px ui-monospace, monospace",e.textAlign="center",e.fillText(`O${l}`,o.x+24,o.y+24),He(e,n,"eggFarm",t.id,o.x,o.y,68,68),e.restore();return}e.fillStyle=p.white,e.strokeStyle=p.ink,e.lineWidth=4,ne(e,o.x-28,o.y-28,56,56,!0,!0),e.fillStyle=p.green,e.font="900 19px ui-monospace, monospace",e.textAlign="center",e.fillText("EGG",o.x,o.y-4);let r=1+Math.max(0,Number(t.extraEggOutlet)||0);e.font="900 11px ui-monospace, monospace",e.fillStyle=p.ink,e.fillText(`L${t.level} O${r}`,o.x,o.y+13),e.fillText(`${t.nextSpawn.toFixed(1)}s`,o.x,o.y+26);let s=Math.max(0,Math.min(1,t.shutterProgress||0));if(s>0){let l=56*s;e.fillStyle=p.ink,ne(e,o.x-28,o.y-28,56,l,!0,!1),e.strokeStyle=p.white,e.lineWidth=2;for(let d=o.y-24;d=1&&(e.fillStyle=p.white,e.font="900 12px ui-monospace, monospace",e.fillText("SHUT",o.x,o.y+4))}nt(e,o.x-28,o.y-28,56,56,t),He(e,n,"eggFarm",t.id,o.x,o.y,68,68),e.restore()}function Ba(e,t){for(let n of t.scanners)La(e,n,t)}function La(e,t,n){let o=pe(t);if(e.save(),t.kind==="manual"&&(n.manualCombo?.count||0)>=10){let v=n.manualCombo.count;e.save(),e.globalAlpha=Math.min(.55,.16+v/120),e.strokeStyle=v>=30?p.warn:p.green,e.lineWidth=Math.min(14,5+Math.floor(v/10)),e.shadowColor=e.strokeStyle,e.shadowBlur=Math.min(28,8+v),ne(e,o.x-54,o.y-76,108,152,!1,!0),e.restore()}let r=t.kind==="auto"?be.scannerAuto:be.scannerManual;if(Xe(e,r,o.x-50,o.y-73,100,146)){t.kind==="auto"?nt(e,o.x-50,o.y-73,100,146,t):ps(e,t,o),He(e,n,"scanner",t.id,o.x,o.y,108,154),e.restore();return}e.fillStyle=t.kind==="auto"?"#d8ffe2":p.white,e.strokeStyle=p.ink,e.lineWidth=4,ne(e,o.x-50,o.y-73,100,146,!0,!0),e.fillStyle=t.kind==="auto"?p.green:p.ink,e.font="900 19px ui-monospace, monospace",e.textAlign="center",e.fillText(`${t.kind==="auto"?"AUTO":`S${(t.slot??0)+1}`}`,o.x,o.y-48),e.font="900 11px ui-monospace, monospace";let s=t.keys?.left?.label||(t.slot===0?"A":"Left"),l=t.keys?.right?.label||(t.slot===0?"D":"Right");e.fillText(t.role===0?`${s}:M ${l}:NEXT`:`${s}:WASTE ${l}:TRUCK`,o.x,o.y-28);let d=t.queue.length;t.kind==="manual"?(ps(e,t,o),e.fillStyle=d>0?p.green:p.muted,e.font="900 10px ui-monospace, monospace",e.fillText(`Q:${d}`,o.x,o.y+54)):(e.fillStyle=d>0?p.green:p.muted,e.font="900 12px ui-monospace, monospace",e.fillText(`Q:${d} CD:${t.cooldown.toFixed(1)}`,o.x,o.y+54),nt(e,o.x-50,o.y-73,100,146,t)),He(e,n,"scanner",t.id,o.x,o.y,108,154),e.restore()}function ps(e,t,n){if(t.kind!=="manual")return;let r=(t.slot??0)===0?[{side:"left",text:"A"},{side:"right",text:"D"}]:[{side:"left",text:"\u2190"},{side:"right",text:"\u2192"}];r[0].text=t.keys?.left?.label||r[0].text,r[1].text=t.keys?.right?.label||r[1].text;let s=t.keyPressTime>0?t.keyPressSide:null,l=n.x-30,d=n.y+18;e.save(),e.lineWidth=3,e.fillStyle="#f7fff5",e.strokeStyle=p.ink,ne(e,l-4,d-4,68,25,!0,!0),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let v=0;v.8,s=t.y+Math.sin(t.bob)*(r?5:1.5);if(e.save(),n&&(e.strokeStyle=p.green,e.lineWidth=5,e.beginPath(),e.arc(t.x,s,t.radius+8,0,Math.PI*2),e.stroke()),r&&(e.strokeStyle=p.danger,e.lineWidth=3,e.beginPath(),e.arc(t.x,s,t.radius+12+Math.sin(t.bob*2)*4,0,Math.PI*2),e.stroke()),t.sex==="poop")lr(e,t.x,s,t.radius);else{let l=t.sex==="male"?be.chickMale:be.chickFemale;Xe(e,l,t.x-t.radius,s-t.radius,t.radius*2,t.radius*2)||(e.fillStyle=t.sex==="male"?p.male:p.female,e.strokeStyle=p.ink,e.lineWidth=5,e.beginPath(),e.arc(t.x,s,t.radius,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle=p.ink,e.beginPath(),e.arc(t.x-6,s-5,2.5,0,Math.PI*2),e.arc(t.x+6,s-5,2.5,0,Math.PI*2),e.fill(),e.fillStyle="#ffaa2e",e.beginPath(),e.moveTo(t.x,s+2),e.lineTo(t.x+9,s+6),e.lineTo(t.x,s+10),e.closePath(),e.fill())}e.restore()}function qa(e,t){let n=null,o=1/0;for(let[r,s]of e.componentLookup.entries()){let l=Q(r),d=F(l.col,l.row),v=Math.hypot(t.x-d.x,t.y-d.y);vys(o.type,o.id)===ys(t,n))}function He(e,t,n,o,r,s,l,d){Ya(t,n,o)&&(e.save(),e.fillStyle="rgba(34,185,79,.18)",e.strokeStyle=p.green,e.lineWidth=(t.multiSelected||[]).length>1?6:4,e.setLineDash((t.multiSelected||[]).length>1?[]:[8,5]),ne(e,r-l/2,s-d/2,l,d,!0,!0),e.restore())}function Va(e,t,n,o){if(t.phase==="build"&&(t.multiSelected||[]).length>1){e.save(),e.fillStyle="rgba(255,255,255,.96)",e.strokeStyle=p.ink,e.lineWidth=3,ne(e,54-t.view.x,66-t.view.y,214,42,!0,!0),e.fillStyle=p.ink,e.font="900 11px ui-monospace, monospace",e.fillText(`${t.multiSelected.length} ITEMS SELECTED`,65-t.view.x,83-t.view.y),e.fillStyle=p.muted,e.font="900 11px ui-monospace, monospace",e.fillText("drag any selected item to move group",65-t.view.x,99-t.view.y),e.restore();return}}function za(e,t,n){if(!n.cardTargetPick?.pending)return;let o=nr(n);e.save(),e.fillStyle="rgba(0,0,0,.66)",e.beginPath();let r=n.view?.scale||1;e.rect(-(n.view?.x||0)/r,-(n.view?.y||0)/r,t.width/r,t.height/r);for(let v of o){let C=v.bounds,P=8;e.rect(C.x-P,C.y-P,C.w+P*2,C.h+P*2)}e.fill("evenodd");let s=n.cardTargetPick?.mode==="blockedCell";if(!o.length){e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=p.ink,e.lineWidth=3,ne(e,(260-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,420/r,42/r,!0,!0),e.fillStyle=p.danger,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(s?"NO BLOCKED CELL. PRESS ESC.":"NO VALID UPGRADE TARGET. PRESS ESC.",(470-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore();return}e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=p.ink,e.lineWidth=3;let l=Math.max(1,n.cardTargetPick?.remaining||1),d=n.cardTargetPick?.mode==="autoScannerMenu"?"AUTO SCANNER ROUTE SETTINGS. CLICK EMPTY AREA TO CLOSE.":s?`CLICK BLOCKED CELL: ${l} LEFT. PRESS ESC TO CANCEL.`:"CLICK AN UPGRADEABLE MACHINE. PRESS ESC TO CANCEL.";ne(e,(216-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,560/r,42/r,!0,!0),e.fillStyle=p.ink,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(d,(496-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore()}function Xa(e,t){if(t.phase!=="build"||!t.selectionBox)return;let n=t.selectionBox,o=Math.min(n.x1,n.x2),r=Math.min(n.y1,n.y2),s=Math.abs(n.x2-n.x1),l=Math.abs(n.y2-n.y1);e.save(),e.fillStyle="rgba(34,185,79,.12)",e.strokeStyle=p.green,e.lineWidth=2,e.setLineDash([7,4]),ne(e,o,r,s,l,!0,!0),e.restore()}function Qa(e,t){let n=[...t.effects].sort((o,r)=>(o.priority??Ce.ambient)-(r.priority??Ce.ambient));for(let o of n){let r=Math.max(0,o.life/o.maxLife);e.save(),e.globalAlpha=r,o.type==="meat"?(e.fillStyle=p.green,ne(e,o.x-o.size/2,o.y-o.size/2,o.size*1.5,o.size,!0,!1)):o.type==="sludge"?(e.fillStyle=p.poop,ne(e,o.x-o.size/2,o.y-o.size/2,o.size*1.4,o.size,!0,!1)):o.type==="spawn"?(e.strokeStyle=p.green,e.lineWidth=3,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*20,0,Math.PI*2),e.stroke()):o.type==="spark"?(e.fillStyle=o.color||p.danger,ne(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!0,!1)):o.type==="smoke"?(e.fillStyle="rgba(16,32,21,.24)",e.beginPath(),e.arc(o.x,o.y,o.size*(1.2-r*.2),0,Math.PI*2),e.fill()):o.type==="shockwave"?(e.strokeStyle=o.color||p.danger,e.lineWidth=4,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*(o.maxSize||44),0,Math.PI*2),e.stroke()):o.type==="scannerPulse"?(e.strokeStyle=o.color||p.green,e.lineWidth=5,e.setLineDash([8,6]),e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*38,0,Math.PI*2),e.stroke()):o.type==="shred"?(e.fillStyle=o.color||p.ink,e.save(),e.translate(o.x,o.y),e.rotate(o.rot||0),ne(e,-o.w/2,-o.h/2,o.w,o.h,!0,!1),e.restore()):o.type==="load"?(e.strokeStyle=o.color||p.green,e.lineWidth=3,e.beginPath(),e.moveTo(o.x-14,o.y),e.lineTo(o.x+14,o.y),e.moveTo(o.x,o.y-14),e.lineTo(o.x,o.y+14),e.stroke()):o.type==="erase"?(e.strokeStyle=p.ink,e.lineWidth=3,e.setLineDash([4,4]),ne(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!1,!0)):o.type==="rage"?(e.fillStyle=o.color||p.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText("!",o.x,o.y)):o.type==="flyingChick"&&(o.sex==="poop"?lr(e,o.x,o.y,o.radius||11):ar(e,o.x,o.y,o.sex,o.sex==="male")),e.restore()}}function Ja(e,t){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let n of t.floatingTexts){let o=Math.max(0,n.life/n.maxLife);e.globalAlpha=o,e.lineWidth=5,e.strokeStyle=p.white,e.fillStyle=n.color,e.strokeText(n.text,n.x,n.y),e.fillText(n.text,n.x,n.y)}e.restore()}function ja(e,t){let n=t.repairman;if(!(!!n?.active||t.phase==="build"&&!!n?.hiredForNextDay))return;if(e.save(),Xe(e,be.repairman,n.x-18,n.y-18,36,36)){n.target?.label?fn(e,n.x,n.y-24,n.target.label,p.green):!n.active&&n.hiredForNextDay&&fn(e,n.x,n.y-24,"NEXT DAY",p.green),e.restore();return}e.lineWidth=3,e.fillStyle="#fff0d1",e.strokeStyle=p.ink,e.beginPath(),e.arc(n.x,n.y,17,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle="#ffd6e7",e.beginPath(),e.arc(n.x-6,n.y-2,3.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+6,n.y-2,3.2,0,Math.PI*2),e.fill();let r=!!t.cardEffects?.laborExploitation;e.fillStyle=r?p.danger:p.ink,e.beginPath(),e.arc(n.x-5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.strokeStyle=p.ink,e.lineWidth=r?3:2,e.beginPath(),e.arc(n.x,n.y+(r?0:1),r?8:7,.1*Math.PI,.9*Math.PI),e.stroke(),e.fillStyle=p.green,ne(e,n.x-9,n.y+14,18,8,!0,!0),e.strokeStyle=p.ink,e.lineWidth=3,e.beginPath(),e.moveTo(n.x-11,n.y+18),e.lineTo(n.x-20,n.y+24),e.stroke(),e.beginPath(),e.moveTo(n.x+11,n.y+18),e.lineTo(n.x+20,n.y+24),e.stroke(),e.fillStyle=p.ink,e.font="900 11px ui-monospace, monospace",e.textAlign="center",e.fillText(n.active?"FIX":"HIRED",n.x,n.y+33),n.target?.label?fn(e,n.x,n.y-24,n.target.label,p.green):!n.active&&n.hiredForNextDay&&fn(e,n.x,n.y-24,"NEXT DAY",p.green),e.restore()}function Za(e,t,n){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="left",e.fillStyle=p.ink,e.fillStyle="rgba(255,255,255,.92)",e.strokeStyle=p.ink,e.lineWidth=3,ne(e,n.width-284,18,260,34,!0,!0),e.fillStyle=p.green,e.font="900 12px ui-monospace, monospace",e.fillText(Sn,n.width-270,40),e.font="900 19px ui-monospace, monospace",e.fillStyle=p.ink;let o=[];t.phase==="running"&&o.push(t.timeLeft<=0?"TIME UP: FARMS SHUT. CLEAR LINE.":"A/D: S1 \u2190/\u2192: S2"),t.phase==="build"&&o.push(`BUILD: ${t.buildTool||"SELECT"} | connect 1 EGG route to any exit`);let r=76;for(let s of o)e.strokeStyle=p.white,e.lineWidth=4,e.strokeText(s,24,r),e.fillText(s,24,r),r+=20;e.restore()}var Ss=[[{key:"a",code:"KeyA",label:"A"},{key:"d",code:"KeyD",label:"D"}],[{key:"arrowleft",code:"ArrowLeft",label:"Left"},{key:"arrowright",code:"ArrowRight",label:"Right"}],[{key:"j",code:"KeyJ",label:"J"},{key:"l",code:"KeyL",label:"L"}],[{key:"f",code:"KeyF",label:"F"},{key:"h",code:"KeyH",label:"H"}],[{key:"q",code:"KeyQ",label:"Q"},{key:"e",code:"KeyE",label:"E"}],[{key:"z",code:"KeyZ",label:"Z"},{key:"x",code:"KeyX",label:"X"}],[{key:"u",code:"KeyU",label:"U"},{key:"o",code:"KeyO",label:"O"}],[{key:"n",code:"KeyN",label:"N"},{key:"m",code:"KeyM",label:"M"}]];function ec(e){let t=Ss[e]||Ss[0];return{left:{...t[0]},right:{...t[1]}}}function ks(e,t,n){let o={type:"eggFarm",id:e.nextId++,col:t,row:n,level:1,nextSpawn:2,lastInterval:2,extraEggOutlet:0,price:kt.eggFarm,builtSession:e.buildSession};return o.nextSpawn=gt(o),o.lastInterval=o.nextSpawn,o}function xs(e,t,n,o){let r=o==="auto"?ke.autoScanner.price:ke.manualScanner.price,s=new Set(e.scanners.filter(d=>d.kind==="manual").map(d=>d.slot)),l=0;for(;s.has(l);)l+=1;return{type:"scanner",id:e.nextId++,kind:o,slot:o==="manual"?l:null,role:o==="manual"?l%2:0,col:t,row:n,level:1,queue:[],cooldown:0,price:r,builtSession:e.buildSession,autoMode:"standard",keys:o==="manual"?ec(l):null}}function Jn(e){let t=(e.x-y.x)/y.cell,n=(e.y-y.y)/y.cell,o=Math.max(0,Math.min(y.cols-1,Math.round(t-.5))),r=Math.max(0,Math.min(y.rows-1,Math.round(n-.5))),s=Math.abs(e.x-y.x),l=Math.abs(e.x-(y.x+y.cols*y.cell)),d=Math.abs(e.y-y.y),v=Math.abs(e.y-(y.y+y.rows*y.cell)),C=[["left",s],["right",l],["top",d],["bottom",v]].sort((P,R)=>P[1]-R[1])[0][0];return C==="left"?{side:C,entry:{col:0,row:r}}:C==="right"?{side:C,entry:{col:y.cols-1,row:r}}:C==="top"?{side:C,entry:{col:o,row:0}}:{side:C,entry:{col:o,row:y.rows-1}}}function jn(e,t,n){let o={x:y.x+t.col*y.cell+y.cell/2,y:y.y+t.row*y.cell+y.cell/2},r={left:y.x,right:y.x+y.cols*y.cell,top:y.y,bottom:y.y+y.rows*y.cell};return e.entry={...t},e.side=n,n==="left"?(e.x=r.left-e.w-18,e.y=o.y-e.h/2):n==="right"?(e.x=r.right+18,e.y=o.y-e.h/2):n==="top"?(e.x=o.x-e.w/2,e.y=r.top-e.h-18):(e.x=o.x-e.w/2,e.y=r.bottom+18),e}function Cs(e,t,n,o){let{entry:r,side:s}=Jn(n),l=ke[t],d=l?{name:l.name,w:l.body?.w||168,h:l.body?.h||110,price:l.price}:{name:t[0].toUpperCase()+t.slice(1),w:168,h:110,price:o},v={type:"facility",id:t,name:d.name,x:0,y:0,w:d.w,h:d.h,level:1,price:o||d.price,builtSession:e.buildSession};return jn(v,r,s)}function tc(e){return Math.random()({x:s.x,y:s.y})),r=o[0];return{id:e.nextId++,sex:n,x:r.x,y:r.y,route:o,targetIndex:o.length>1?1:o.length,stage:t.stage||"belt",scannerId:t.scannerId??null,nextScannerId:null,pendingScannerId:null,radius:n==="poop"?15:17,bob:Math.random()*Math.PI*2,queueIndex:-1,queueRoute:null}}function gs({game:e,canvasPoint:t,updatePanels:n,equipmentAtPoint:o,fail:r,pointInGrid:s,rectOfFacility:l,rectsOverlap:d}){function v(k){return k?k.type==="conveyor"?`conveyor:${k.id||k.oldKey}`:k.type==="facility"?`facility:${k.id||k.ref?.id}`:`${k.type}:${k.id||k.ref?.id}`:""}function C(k){return k?k.type==="conveyor"?{type:"conveyor",id:k.oldKey}:{type:k.type,id:k.ref.id}:null}function P(k){let g=v(C(k));return(e.multiSelected||[]).some(O=>v(O)===g)}function R(k){return k?k.type==="eggFarm"?e.eggFarms.find(g=>g.id===k.id)||null:k.type==="scanner"?e.scanners.find(g=>g.id===k.id)||null:k.type==="facility"?e.facilities[k.id]||null:k.type==="conveyor"&&e.conveyorTiles.has(k.id)?{type:"conveyor",id:k.id}:null:null}function L(){let k=[];for(let g of e.conveyorTiles){let O=Q(g),X=F(O.col,O.row);k.push({type:"conveyor",id:g,center:X,cell:O})}for(let g of e.eggFarms)k.push({type:"eggFarm",id:g.id,ref:g,center:F(g.col,g.row),cell:{col:g.col,row:g.row}});for(let g of e.scanners)k.push({type:"scanner",id:g.id,ref:g,center:pe(g),cell:{col:g.col,row:g.row}});for(let g of Object.values(e.facilities)){let O={x:g.x+g.w/2,y:g.y+g.h/2},X=g.entry?F(g.entry.col,g.entry.row):O;k.push({type:"facility",id:g.id,ref:g,center:O,portCenter:X})}return k}function V(k,g){let O=Math.min(g.x1,g.x2),X=Math.max(g.x1,g.x2),oe=Math.min(g.y1,g.y2),de=Math.max(g.y1,g.y2);return k.x>=O&&k.x<=X&&k.y>=oe&&k.y<=de}function te(k){let g=[];for(let O of L())(V(O.center,k)||O.portCenter&&V(O.portCenter,k))&&g.push({type:O.type,id:O.id});return e.multiSelected=g,e.selected=g[0]||null,n(),g.length}function z(){e.multiSelected=[],e.selected=null,n()}function se(k){let g=t(k);return e.selectionBox={x1:g.x,y1:g.y,x2:g.x,y2:g.y},e.multiSelected=[],e.selected=null,n(),!0}function ye(k){if(!e.selectionBox)return;let g=t(k);e.selectionBox.x2=g.x,e.selectionBox.y2=g.y}function Z(){if(!e.selectionBox)return 0;let k=e.selectionBox,g=Math.abs(k.x2-k.x1),O=Math.abs(k.y2-k.y1);return e.selectionBox=null,g<6&&O<6?(z(),0):te(k)}function $(k){let g=C(k);return g?(e.multiSelected||[]).length&&P(k)?[...e.multiSelected]:[g]:[]}function U(k){let g=R(k);if(!g)return null;if(k.type==="conveyor"){let O=Q(k.id);return{...k,obj:g,oldKey:k.id,currentKey:k.id,meta:e.conveyorMeta.get(k.id)||{price:_e("conveyor"),builtSession:null},col:O.col,row:O.row}}return k.type==="eggFarm"||k.type==="scanner"?{...k,obj:g,col:g.col,row:g.row}:k.type==="facility"?{...k,obj:g,x:g.x,y:g.y,w:g.w,h:g.h,entry:g.entry?{...g.entry}:null,side:g.side,center:{x:g.x+g.w/2,y:g.y+g.h/2}}:null}function N(k){let g=t(k),O=o(g);if(!O)return!1;let X=$(O),oe=X.map(U).filter(Boolean);return oe.length?(e.groupDrag={start:g,selections:X,origins:oe,historySnapshot:cn(e),committed:!1,lastDCol:0,lastDRow:0},e.multiSelected=X,e.selected=X[0]||null,n(),!0):!1}function le(){!e.groupDrag||e.groupDrag.committed||(e.undoStack.push(e.groupDrag.historySnapshot),e.redoStack=[],e.groupDrag.committed=!0)}function Se(k,g,O){let X=I(k,g),oe=Et(e,k,g);if(oe&&!O.has(`eggFarm:${oe.id}`))return!0;let de=Pt(e,k,g);return!!(de&&!O.has(`scanner:${de.id}`)||e.conveyorTiles.has(X)&&!O.has(`conveyor:${X}`))}function he(k,g,O){let X=[];for(let oe of e.groupDrag.origins){if(oe.type!=="facility")continue;let de={x:oe.center.x+k,y:oe.center.y+g},{entry:Te,side:ce}=Jn(de);if(!s(Te.col,Te.row)||e.blockedCells?.has?.(I(Te.col,Te.row)))return!0;let rt={...oe.obj,entry:{...Te},side:ce};jn(rt,Te,ce),X.push({id:oe.id,rect:l(rt)})}for(let oe of X)for(let de of Object.values(e.facilities))if(!O.has(`facility:${de.id}`)&&d(oe.rect,l(de),12))return!0;for(let oe=0;oeJ.type==="conveyor");for(let J of rt){let ge=J.currentKey||J.oldKey;e.conveyorTiles.delete(ge),e.conveyorMeta.delete(ge)}for(let J of rt){let ge=I(J.col+oe,J.row+de);e.conveyorTiles.add(ge),e.conveyorMeta.set(ge,J.meta||{price:_e("conveyor"),builtSession:null,uses:0}),J.currentKey=ge}for(let J of e.groupDrag.origins)if(J.type==="eggFarm")J.obj.col=J.col+oe,J.obj.row=J.row+de;else if(J.type==="scanner")J.obj.col=J.col+oe,J.obj.row=J.row+de;else if(J.type==="facility"){let ge={x:J.center.x+O,y:J.center.y+X},{entry:Le,side:it}=Jn(ge);jn(J.obj,Le,it)}e.groupDrag.selections=e.groupDrag.origins.map(J=>J.type==="conveyor"?{type:"conveyor",id:J.currentKey||J.oldKey}:{type:J.type,id:J.id}),e.multiSelected=[...e.groupDrag.selections],e.selected=e.multiSelected[0]||null,ve(e),n()}function _(){e.groupDrag&&(ve(e),e.groupDrag=null,n())}return{selectionFromHit:C,startSelectionBox:se,updateSelectionBox:ye,finishSelectionBox:Z,startGroupDrag:N,updateGroupDrag:A,finishGroupDrag:_}}function Ts({game:e,ui:t,canvas:n,canvasPoint:o,onUpdatePanels:r}){function s(){r&&r()}let l=null,d=!1,v=null,C=!1,P=["random","up","right","down","left"],R={random:"RND",up:"UP",right:"RT",down:"DN",left:"LF"},L={w:40,h:40,y:0};function V(){return En(e)}function te(){e.gridCols=y.cols,e.gridRows=y.rows,e.gridOwnedCells=Nr(e)}function z(i){if(i){y.y-=i*y.cell,y.rows+=i,e.gridChunkOriginY=(e.gridChunkOriginY||0)-Math.floor(i/10),e.ownedCells=Pn(e.ownedCells,i),e.blockedCells=Pn(e.blockedCells,i),e.conveyorTiles=Pn(e.conveyorTiles,i),e.conveyorMeta=Wr(e.conveyorMeta,i);for(let c of e.eggFarms||[])c.row+=i;for(let c of e.scanners||[])c.row+=i;for(let c of Object.values(e.facilities||{}))c.entry&&(c.entry.row+=i)}}function se(i){e.ownedCells=e.ownedCells||new Set;for(let c of Ur(i))e.ownedCells.add(I(c.col,c.row))}function ye(i){return e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending?null:Ct(e).find(c=>c&&Gr(c,i))||null}function Z(i="right"){if(i&&typeof i=="object"&&Number.isFinite(i.chunkX)&&Number.isFinite(i.chunkY))return i;let c=["right","up"].includes(i)?i:"right";return _r(e,c)}function $(i="right"){let c=Z(i);if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return{ok:!1,reason:"Cannot expand now."};if(!c)return{ok:!1,reason:"Invalid expansion lot."};let h=c.direction||"right",m=V();if(e.cashy.cols&&(y.cols=T.colStart+T.cols),T.rowStart+T.rows>y.rows&&(y.rows=T.rowStart+T.rows),se(T),Kr(e,T.chunkX,T.chunkY),e.gridExpansionPurchases=(e.gridExpansionPurchases||0)+1,e.gridExpansionPurchasesByDirection[h]=(e.gridExpansionPurchasesByDirection[h]||0)+1,te();let j=Ir({seed:`${e.runSeed}:grid-expansion:${T.chunkX},${T.chunkY}:${e.gridExpansionPurchases}`,colStart:T.colStart,colEnd:T.colStart+T.cols,rowStart:T.rowStart,rowEnd:T.rowStart+T.rows,targetRatio:q.map.blockedRatio});for(let Re of j)e.blockedCells.add(Re);ve(e);let ie=T.cols*T.rows,fe=Mt(T);return W(e,fe.x+fe.w/2,fe.y+fe.h/2,`${h.toUpperCase()} +${ie} CELLS -${M(m)}`,p.green),s(),{ok:!0,direction:h,cost:m,addedCells:ie,blocked:j.size,chunkX:T.chunkX,chunkY:T.chunkY}}function U(i,c){return i>=0&&i=0&&c!c.has(m.id)&&Se(h,le(m),12))}function A(i,c,h=null){if(!U(i,c))return!1;if(N(i,c))return!0;let m=I(i,c),x=Et(e,i,c);if(x&&!(h?.type==="eggFarm"&&h.ref?.id===x.id))return!0;let T=Pt(e,i,c);return!!(T&&!(h?.type==="scanner"&&h.ref?.id===T.id)||e.conveyorTiles.has(m)&&!(h?.type==="conveyor"&&h.oldKey===m))}function _(i,c,h=null){let m={col:i,row:c};for(let x of Tt(m)){if(!U(x.col,x.row)||N(x.col,x.row))return!0;let T=I(x.col,x.row);if(Et(e,x.col,x.row))return!0;let ie=Pt(e,x.col,x.row);if(ie&&!(h?.type==="scanner"&&h.ref?.id===ie.id)||e.conveyorTiles.has(T))return!0}return!1}function k(){return e.selected?e.selected.type==="eggFarm"?e.eggFarms.find(i=>i.id===e.selected.id)||null:e.selected.type==="scanner"?e.scanners.find(i=>i.id===e.selected.id)||null:e.selected.type==="conveyor"?e.conveyorTiles.has(e.selected.id)?{type:"conveyor",id:e.selected.id}:null:e.selected.type==="facility"&&e.facilities[e.selected.id]||null:null}function g(i){return i?i.type==="eggFarm"?`${xt("eggFarm")} #${i.id}`:i.type==="scanner"?`${i.kind==="auto"?xt("autoScanner"):xt("manualScanner")} #${i.id}`:i.type==="conveyor"?e.conveyorMeta.get(i.id)?.kind==="boostConveyor"?xt("boostConveyor"):xt("conveyor"):i.type==="facility"?i.name:"Equipment":"Equipment"}function O(i){return i?.type==="conveyor"?e.conveyorMeta?.get(i.oldKey||i.ref?.id)?.price||Bn(i):Bn(i)}function X(){return!!e.cardEffects?.usedMachineActive}function oe(){return X()?{usedMachine:!0,noRefund:!0,durabilityBaseMultiplier:.6}:{usedMachine:!1,noRefund:!1,durabilityBaseMultiplier:1}}function de(i){let c=oe();return Object.assign(i,c),i}function Te(i){let c=i?.ref||i||{};if(i?.type==="eggFarm"||c.type==="eggFarm")return e.eggFarms.length<=1?"Cannot sell the last EGG FARM.":"";if((i?.type==="facility"||c.type==="facility")&&["mixer","trash","truck"].includes(c.baseId||c.id)){let h=c.baseId||c.id;if(Object.values(e.facilities).filter(x=>(x.baseId||x.id)===h).length<=1)return`Cannot sell the last ${c.shortName||c.name||c.id}.`}return""}function ce(i){t.buildStatus.textContent=i,W(e,n.width/2-e.view.x,86-e.view.y,i.toUpperCase(),p.danger)}function rt(i){if(!i)return null;let c=I(i.col,i.row);return e.conveyorMeta.get(c)||null}function J(i){return i?(Array.isArray(i.outDirs)||(i.outDirs=[]),i.outDirs=[...new Set(i.outDirs.filter(c=>["right","left","down","up"].includes(c)))],P.includes(i.branchMode)||(i.branchMode="random"),i.kind||(i.kind="conveyor"),i.speedMultiplier||(i.speedMultiplier=i.kind==="boostConveyor"?2:1),i.outDirs):[]}function ge(i){return i?ue.filter(c=>e.conveyorTiles.has(I(i.col+c.dc,i.row+c.dr))).map(c=>c.name):[]}function Le(i){return ge(i).length>=3}function it(i,c){let h=ue.find(ie=>ie.name===c);if(!i||!h)return!1;let m=I(i.col+h.dc,i.row+h.dr),x=e.conveyorMeta.get(m);if(!x)return!1;let T=h.opposite;return[...new Set([...Array.isArray(x.outDirs)?x.outDirs:[],x.dir].filter(Boolean))].includes(T)}function Ge(i){if(!e.conveyorTiles.has(i))return[];let c=Q(i),h=e.conveyorMeta.get(i),m=J(h),x=ge(c),T=[...new Set([...m,h?.dir].filter(Boolean))].filter(fe=>x.includes(fe)),j=x,ie=T.length?T:j;return h&&(h.outDirs=m.filter(fe=>x.includes(fe)),h.dir&&!x.includes(h.dir)&&(h.dir=h.outDirs[0]||null),h.branchMode!=="random"&&!x.includes(h.branchMode)&&(h.branchMode="random")),ie}function st(i){if(!e.conveyorTiles.has(i))return[];let c=Q(i),h=ge(c);return Le(c)||h.length?h:Ge(i)}function oo(i){let c=Q(i),h=st(i);if(h.length<3)return[];let m=new Set(h.filter(x=>it(c,x)));return h.filter(x=>{let T=new Set(m);return T.add(x),h.filter(j=>!T.has(j)).length>=2})}function yn(i,c){let h=at(i,c);if(!h)return!1;let m=I(i.col,i.row),x=I(c.col,c.row),T=e.conveyorMeta.get(m),j=e.conveyorMeta.get(x);if(!T||!j)return!1;let ie=J(T),fe=!ie.includes(h)||T.dir!==h||!j.dir;return ie.includes(h)||ie.push(h),T.dir=h,j.dir||(j.dir=h),fe}function hn(i){let c=ro(i);return c.length<2?mn(i):(Fe(e),io(c),ve(e),s(),!0)}function mn(i){if(!i)return!1;let c=I(i.col,i.row),h=e.conveyorMeta.get(c);if(!h||Le(i))return!1;let m=ue.map(j=>j.name),x=h.dir&&m.includes(h.dir)?h.dir:null,T=m[(Math.max(-1,m.indexOf(x))+1)%m.length];return Fe(e),h.dir=T,h.outDirs=[T],h.branchMode="random",ve(e),s(),!0}function vt(i){return i?ue.map(c=>({col:i.col+c.dc,row:i.row+c.dr})).filter(c=>e.conveyorTiles.has(I(c.col,c.row))):[]}function ro(i){if(!i||!e.conveyorTiles.has(I(i.col,i.row))||Le(i))return[];let c=vt(i);if(!c.length||c.length>2)return[];let h=T=>{let j=[],ie=new Set([I(i.col,i.row)]),fe=i,Re=T,br=0;for(;Re&&br<200;){br+=1;let vr=I(Re.col,Re.row);if(ie.has(vr)||(ie.add(vr),j.push(Re),Le(Re)))break;let wr=vt(Re).filter(Sr=>!(Sr.col===fe.col&&Sr.row===fe.row));if(wr.length!==1)break;fe=Re,Re=wr[0]}return j},m=c[0]?h(c[0]).reverse():[],x=c[1]?h(c[1]):[];return[...m,i,...x]}function bn(i,c){return!!i&&[...new Set([...Array.isArray(i.outDirs)?i.outDirs:[],i.dir].filter(Boolean))].includes(c)}function io(i){let c=0,h=0;for(let x=0;xh?[...i].reverse():i;for(let x=0;x=Math.abs(m)?{col:i.col+Math.sign(h),row:i.row}:{col:i.col,row:i.row+Math.sign(m)}}function so(i){d=!1,v=i?{col:i.col,row:i.row}:null,C=!1,l=null,Nt(i)}function jt(i){if(!i)return;if(!l)return Nt(i);let c=l,h=0;for(;(c.col!==i.col||c.row!==i.row)&&h<64;){let m=Jt(c,i);if(Nt(m),c=l||m,h+=1,!l)break}}function wn(){!C&&v&&e.conveyorTiles.has(I(v.col,v.row))&&hn(v),v=null,C=!1,l=null,d=!1}function u(i){if(!i)return ce(re.fail.outOfGrid);let{col:c,row:h}=i;if(e.buildTool==="conveyor"||e.buildTool==="boostConveyor"){let m=vn(i,null);if(!m.ok)return ce(m.reason||re.fail.cellOccupied);ve(e);return}if(N(c,h))return ce("Cannot build on blocked ground.");if(e.buildTool==="manualScanner"||e.buildTool==="autoScanner"?_(c,h):A(c,h))return ce(re.fail.cellOccupied);e.buildTool==="eggFarm"?b(c,h):e.buildTool==="manualScanner"?S(c,h,"manual"):e.buildTool==="autoScanner"&&S(c,h,"auto")}function f(i){let c=We(i.x,i.y);if(["conveyor","boostConveyor","eggFarm","manualScanner","autoScanner"].includes(e.buildTool))return u(c);if(nn.includes(e.buildTool))return w(i,e.buildTool)}function b(i,c){let h=_e("eggFarm",e);if(e.cashT.kind==="manual").length>=8)return ce("Manual Scanner limit reached (8 max).");let m=h==="auto"?_e("autoScanner",e):_e("manualScanner",e);if(e.cashx.id!==c.ref.id),yt(e,m.x,m.y),ve(e)}if(c.type==="scanner"){let m=pe(c.ref);E(c,m.x,m.y),e.scanners=e.scanners.filter(x=>x.id!==c.ref.id),yt(e,m.x,m.y),ve(e)}if(c.type==="facility"){let m=c.ref;E(c,m.x+m.w/2,m.y+m.h/2),delete e.facilities[m.id],yt(e,m.x+m.w/2,m.y+m.h/2),ve(e)}e.selected=null,e.multiSelected=[],s()}function K(i){let c=Object.values(e.facilities).find(j=>{if(i.x>=j.x&&i.x<=j.x+j.w&&i.y>=j.y&&i.y<=j.y+j.h)return!0;if(!j.entry)return!1;let fe=F(j.entry.col,j.entry.row);return Math.abs(i.x-fe.x)<=y.cell*.46&&Math.abs(i.y-fe.y)<=y.cell*.46});if(c)return{type:"facility",ref:c};let h=We(i.x,i.y);if(!h)return null;let m=Et(e,h.col,h.row);if(m)return{type:"eggFarm",ref:m};let x=Pt(e,h.col,h.row);if(x)return{type:"scanner",ref:x};let T=I(h.col,h.row);return e.conveyorTiles.has(T)?{type:"conveyor",oldKey:T,ref:{type:"conveyor",id:T}}:null}let ee=gs({game:e,canvasPoint:o,updatePanels:s,equipmentAtPoint:K,fail:ce,pointInGrid:U,rectOfFacility:le,rectsOverlap:Se});function Qe(i){return null}function ur(){let i=k();i&&(i.type==="conveyor"?D(F(...Object.values(Q(i.id)))):i.type==="eggFarm"?D(F(i.col,i.row)):i.type==="scanner"?D(pe(i)):i.type==="facility"&&D({x:i.x+i.w/2,y:i.y+i.h/2}))}function qe(i,c,h="primary-button"){let m=document.createElement("button");return m.type="button",m.className=h,m.textContent=i,m.addEventListener("click",c),m}function Zt(){e.cardTargetPick?.mode==="autoScannerMenu"&&(e.cardTargetPick=null),t.modal.classList.remove("visible","equipment-popover"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function lo(i){t.modalTitle.textContent="Auto Scanner",e.cardTargetPick={pending:!0,mode:"autoScannerMenu",cardId:null,targetKeys:[`scanner:${i.id}`],remaining:1},t.modalBody.innerHTML=` -
-

Left / right output routing for this AUTO scanner.

-

Current: ${i.role===0?"Male left / others right":"Poop left / others right"}

-

Cooldown: ${tt(i).toFixed(1)}s.

-
`,t.modalActions.innerHTML="";let c=qe("Male Left / Others Right",()=>{Fe(e),i.role=0,Zt(),s()},i.role===0?"facility-action warn":"facility-action"),h=qe("Poop Left / Others Right",()=>{Fe(e),i.role=1,Zt(),s()},i.role===1?"facility-action warn":"facility-action");t.modalActions.append(c,h,qe("Close",Zt,"facility-action")),ao(i),t.modal.classList.add("visible","equipment-popover"),s()}function dr(i){return i?.label||i?.key||"?"}function Hs(i){let c=i.key===" "?"Space":i.key.length===1?i.key.toUpperCase():i.key.replace(/^Arrow/,"");return{key:i.key.toLowerCase(),code:i.code,label:c}}function qs(i,c,h){for(let m of e.scanners.filter(x=>x.kind==="manual"))for(let x of["left","right"]){if(m.id===i.id&&x===c)continue;let T=m.keys?.[x];if(T&&(T.code===h.code||T.key===h.key))return!0}return!1}function en(i,c=""){if(!i||i.kind!=="manual")return;t.modalTitle.textContent=`Manual Scanner #${i.id}`;let h=dr(i.keys?.left),m=dr(i.keys?.right),x=Ys(i);t.modalBody.innerHTML=` -
-

Left route key: ${h}

-

Right route key: ${m}

- ${c?`

${c}

`:""} - ${x?`

${x}

`:""} -
`,t.modalActions.innerHTML="",t.modalActions.appendChild(qe("Set Left Key",()=>fr(i,"left"),"facility-action warn")),t.modalActions.appendChild(qe("Set Right Key",()=>fr(i,"right"),"facility-action warn")),t.modalActions.appendChild(qe("Close",Zt,"facility-action")),ao(i),t.modal.classList.add("visible","equipment-popover")}function Ys(i){let c=[{side:"left",binding:i.keys?.left},{side:"right",binding:i.keys?.right}];if(c[0].binding&&c[1].binding&&(c[0].binding.code===c[1].binding.code||c[0].binding.key===c[1].binding.key))return"Left and right keys conflict.";for(let h of c)if(h.binding)for(let m of e.scanners.filter(x=>x.kind==="manual"&&x.id!==i.id)){if(m.keys?.left&&(m.keys.left.code===h.binding.code||m.keys.left.key===h.binding.key))return`Key conflicts with Manual Scanner #${m.id} left.`;if(m.keys?.right&&(m.keys.right.code===h.binding.code||m.keys.right.key===h.binding.key))return`Key conflicts with Manual Scanner #${m.id} right.`}return""}function fr(i,c){t.modalBody.innerHTML=`

Press a key for ${c.toUpperCase()} route.

Esc cancels.

`,t.modalActions.innerHTML="";let h=m=>{if(m.preventDefault(),m.stopPropagation(),window.removeEventListener("keydown",h,!0),m.key==="Escape")return en(i);let x=Hs(m),T=qs(i,c,x);Fe(e),i.keys=i.keys||{left:null,right:null},i.keys[c]=x,s(),en(i,T?`${x.label} assigned, but another scanner already uses it.`:`${c.toUpperCase()} set to ${x.label}.`)};window.addEventListener("keydown",h,!0)}function Vs(){let i=k();if(!(!i||i.type!=="scanner"))return i.kind==="auto"?lo(i):en(i)}function zs(i){if(!i)return{x:80,y:80};if(i.type==="conveyor"){let c=Q(i.id);return F(c.col,c.row)}return i.type==="eggFarm"?F(i.col,i.row):i.type==="scanner"?pe(i):i.type==="facility"?{x:i.x+i.w/2,y:i.y+10}:{x:80,y:80}}function ao(i){let c=n.getBoundingClientRect(),h=zs(i),m=e.view?.scale||1,x=c.left+(h.x*m+(e.view?.x||0))/n.width*c.width+18,T=c.top+(h.y*m+(e.view?.y||0))/n.height*c.height-12,j=Math.max(12,window.innerWidth-274),ie=Math.max(12,window.innerHeight-220);t.modal.style.setProperty("--popover-x",`${Math.max(12,Math.min(j,x))}px`),t.modal.style.setProperty("--popover-y",`${Math.max(12,Math.min(ie,T))}px`)}function Xs(){let i=k();if(!i)return;let c=mr(i);t.modalTitle.textContent=g(i),t.modalBody.innerHTML=` -
${c.map(x=>`

${x}

`).join("")}
- ${["mixer","truck"].includes(i.baseId||i.id)?'

Income/Fine = ceil(base x 1.10^upgrades)

':""}`,t.modalActions.innerHTML="",i.type==="scanner"&&i.kind==="auto"&&t.modalActions.appendChild(qe("Auto Menu",()=>lo(i),"facility-action warn")),i.type==="scanner"&&i.kind==="manual"&&t.modalActions.appendChild(qe("Set Keys",()=>en(i),"facility-action warn"));let h=i.type==="conveyor"?{type:"conveyor",oldKey:i.id,ref:i}:{type:i.type,ref:i},m=Te(h);if(m){let x=qe(m,()=>{},"facility-action danger disabled");x.disabled=!0,t.modalActions.appendChild(x)}else{let x=$t(h,e),T=x.sameBuild?`Remove / Refund ${M(x.amount)}`:`Sell ${M(x.amount)}`;t.modalActions.appendChild(qe(T,()=>{ur(),Zt()},"facility-action danger"))}ao(i),t.modal.classList.add("visible","equipment-popover")}function Qs(i){e.phase==="build"&&(wn(),e.buildTool=e.buildTool===i?null:i,e.selected=null,e.multiSelected=[],e.selectionBox=null,s())}function Js(){let i=[];for(let[c,h]of Object.entries(e.facilities))if(i.push({id:`facility:${c}`,price:O({type:"facility",ref:h}),x:h.x,y:h.y,w:h.w,h:h.h}),h.entry){let m=F(h.entry.col,h.entry.row);i.push({id:`facilityPort:${c}`,price:O({type:"facility",ref:h}),x:m.x-18,y:m.y-18,w:36,h:36})}for(let c of e.eggFarms){let h=F(c.col,c.row);i.push({id:`eggFarm:${c.id}`,price:O({type:"eggFarm",ref:c}),x:h.x-24,y:h.y-24,w:48,h:48})}for(let c of e.scanners){let h=pe(c);i.push({id:`scanner:${c.id}`,price:O({type:"scanner",ref:c}),x:h.x-50,y:h.y-73,w:100,h:146})}for(let c of e.conveyorTiles){let h=Q(c),m=F(h.col,h.row),x=e.conveyorMeta.get(c)||{};i.push({id:`conveyor:${c}`,price:x.price||_e(x.kind==="boostConveyor"?"boostConveyor":"conveyor",e),x:m.x-22,y:m.y-22,w:44,h:44})}return i}function js(i){return R[i]||R.random}function Rc(i){return st(i)}function pr(i){return e.conveyorTiles.has(i)?Le(Q(i)):!1}function yr(i){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return null;for(let c of e.conveyorTiles){if(!pr(c))continue;let h=Q(c),m=F(h.col,h.row),x=m.x-L.w/2,T=m.y+L.y-L.h/2;if(i.x>=x&&i.x<=x+L.w&&i.y>=T&&i.y<=T+L.h)return c}return null}function Zs(i){let c=yr(i);return c?(hr(c),!0):!1}function hr(i){let c=e.conveyorMeta.get(i);if(!c)return!1;let h=oo(i);if(h.length<2)return!1;Fe(e);let m=P.includes(c.branchMode)?c.branchMode:"random",x=["random",...ue.map(T=>T.name).filter(T=>h.includes(T))];return c.branchMode=x[(Math.max(0,x.indexOf(m))+1)%x.length],e.selected=null,e.multiSelected=[],s(),!0}function mr(i){me(e);let c=[],h=i?.type==="facility"?i.baseId||i.id:"";if(i.type==="eggFarm"){let[m,x]=rn(i);c.push(`Price: ${M(O(i))}`);{let T=Te({type:i.type,ref:i});c.push(T?`Sale: blocked (${T})`:`Sale value: ${M($t({type:i.type,ref:i},e).amount)}`)}c.push(`Level: ${i.level}/4`),c.push(`Random interval: ${m.toFixed(2)}-${x.toFixed(2)}s`),c.push(`Durability: ${dn(i)}% | Spawn delay x${Hn(i).toFixed(2)}`)}else if(i.type==="scanner")c.push(`Price: ${M(O(i))}`),c.push(`Sale value: ${M($t({type:i.type,ref:i},e).amount)}`),c.push(`Type: ${i.kind.toUpperCase()} / Standard`),i.kind==="auto"&&c.push(`Role: ${i.role===0?"Male left / Others right":"Poop left / Others right"}`),c.push(`Queue: ${i.queue.length}`),i.kind==="auto"&&c.push(`Cooldown: ${i.cooldown.toFixed(1)}s / ${tt(i,e).toFixed(1)}s`),i.kind==="auto"&&c.push(`Durability: ${dn(i)}% | Delay x${Kn(i).toFixed(2)}`),i.kind==="manual"&&c.push("Durability: none | Always normal");else if(i.type==="conveyor"){let m=e.conveyorMeta.get(i.id),x=e.componentLookup?.get(i.id),T=x?e.congestion.get(x):null;c.push(`Price: ${M(O({type:"conveyor",oldKey:i.id,ref:i}))}`),c.push(`Cell: ${i.id}`),c.push(`Type: ${m?.kind==="boostConveyor"?"BOOST BELT":"Normal Belt"} | Speed x${Number(m?.speedMultiplier||1).toFixed(1)}`),c.push(`Congestion: ${T?Math.floor(T.ratio*100):0}%`),c.push(`Durability: ${dn({meta:m})}% | Speed x${Wn({meta:m}).toFixed(2)}`),pr(i.id)?(c.push(`Branch mode: ${js(m?.branchMode||"random")}`),c.push("Use the Branch button below or the on-belt branch badge.")):c.push("Branch mode: needs 3+ conveyor connections."),c.push(`Sale value: ${M($t({type:"conveyor",oldKey:i.id,ref:i},e).amount)}`)}else if(i.type==="facility"){c.push(`Price: ${M(O(i))}`);{let m=Te({type:i.type,ref:i});c.push(m?`Sale: blocked (${m})`:`Sale value: ${M($t({type:i.type,ref:i},e).amount)}`)}if(c.push(["mixer","truck","trash"].includes(i.id)?`Level: ${i.level} / no cap`:`Level: ${i.level}`),h==="truck"&&c.push("Durability: none | Always normal"),["mixer","trash"].includes(h)&&c.push(`Durability: ${dn(i)}% | Extra delay ${Xo(e,i).toFixed(2)}s`),h==="mixer"&&(c.push(`Income: ${M(Ye(e))} per chick | upgrade x${ut(e,"mixer").toFixed(3)}`),c.push(`Poop fine: -${M(ln(e))}`)),h==="truck"&&(c.push(`Income: ${M($e(e))} per target cargo | upgrade x${ut(e,"truck").toFixed(3)}`),c.push(`Poop shipment fine: -${M(an(e))}`)),h==="trash"){let m=Dt(e),x=dt(m);c.push(`Bonus cards: ${m}/${Kt()}`),c.push(`Poop income bonus: ${M(x)} per processed poop.`),c.push("With enough upgrades, poop can out-earn male/female routes.")}i.entry&&c.push(`Receiver: edge cell ${i.entry.col},${i.entry.row} (${i.side})`)}return c}function el(i){if(!i||e.phase!=="build")return"";let c=In(e).find(h=>h.type===i.type&&h.id===i.id);return c?c.message||"Not connected to conveyor route":""}function tl(i){return i?i.type==="conveyor"&&e.conveyorMeta.get(i.id)?.kind==="boostConveyor"?"Moves chicks twice as fast. Wears down like a normal belt.":i.type==="conveyor"?"A stubborn belt tile. It only cares about the next cell.":i.type==="eggFarm"?"A tiny gatehouse producing questionable eggs on schedule.":i.type==="scanner"&&i.kind==="auto"?"Slower than hands without upgrades.":i.type==="scanner"?"A manual checkpoint. The operator is the algorithm.":i.type==="facility"&&(i.baseId||i.id)==="mixer"?"Male chicks become revenue here. Do not feed it poop.":i.type==="facility"&&(i.baseId||i.id)==="trash"?"Poop goes in. Sometimes coins come out, for reasons best left unaudited.":i.type==="facility"&&(i.baseId||i.id)==="truck"?"The shipping endpoint. Correct cargo pays; wrong cargo complains.":"Factory equipment.":""}return{buildAtCell:u,buildAtPoint:f,eraseAtPoint:D,equipmentAtPoint:K,startSelectionBox:ee.startSelectionBox,updateSelectionBox:ee.updateSelectionBox,finishSelectionBox:ee.finishSelectionBox,startGroupDrag:ee.startGroupDrag,updateGroupDrag:ee.updateGroupDrag,finishGroupDrag:ee.finishGroupDrag,selectedObject:k,selectedTitle:g,equipmentPrice:O,selectedUpgradeCost:Qe,selectedInfoLines:mr,flavorText:tl,disconnectedWarningFor:el,gridExpansionCost:V,buyGridExpansion:$,expansionOfferAtPoint:ye,beginConveyorDrag:so,continueConveyorDrag:jt,endConveyorDrag:wn,cycleSingleConveyorDirection:hn,branchSwitcherAtPoint:yr,cycleBranchModeAtPoint:Zs,cycleBranchModeForKey:hr,removeSelected:ur,switchScannerRole:Vs,showManualScannerMenu:en,showAutoScannerMenu:lo,showSelectedMenu:Xs,setBuildTool:Qs,fail:ce,isEquipmentCell:A,equipmentHitBoxes:Js,routeFromFarmToScanner:At}}function Es({game:e,ui:t,build:n,startGame:o,beginCardDraft:r,activeQueuedChick:s}){function l(A){return String(A).replace(/[&<>"']/g,_=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[_])}function d(){return Math.round(zn(e))}function v(){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return!1;let A=!1;for(let _ of ho)if(A=!0,e.cash>=_e(_,e))return!1;return A}function C(){P(),R(),te(),V(),L()}function P(){for(let[_,k]of Object.entries(t.buttons))k?.classList?.contains("tool-button")&&k.classList.toggle("active",e.buildTool===_);for(let _ of ho){let k=t.buttons[_];if(!k)continue;let g=_e(_,e),O=k.querySelector("span");O&&(O.textContent=_==="conveyor"||_==="boostConveyor"?`${M(g)} / tile`:M(g));let X=_==="manualScanner"&&e.scanners.filter(de=>de.kind==="manual").length>=8,oe=e.cashAt(e,X)?.scannerId).length,_=sn(e),k=Math.max(0,Math.floor(e.lastResult?.profit??e.stats?.profit??0)),g=Math.max(1,Number(e.turn)||1),O=Ln(e,g,k);t.turnSummary.innerHTML=[`Seed: ${l(e.runSeed||"none")} | Grid box: ${e.gridRows||10}x${e.gridCols||20} | Owned: ${e.gridOwnedCells||e.ownedCells?.size||(e.gridRows||10)*(e.gridCols||20)} cells | Blocked: ${e.blockedCells?.size||0} cells`,`Truck target: ${je(e).toUpperCase()} | Male fine: -${M(Lo(e))}`,`Poop fine: Mixer -${M(ln(e))} / Shipment -${M(an(e))}`,`Fairies tribute on Next Day: -${M(O.amount)} | base ${M(O.base)} + profit share ${M(O.profitTribute)} | basis net ${M(k)} | exemption ${M(O.profitExemption)}${O.reduction?` | reduction -${M(O.reduction)}`:""}`,`Maintenance: worst ${jo(e).worst.percent}% dirty (${jo(e).worst.label}) | Repairman: ${e.repairman?.hiredForNextDay?"hired next day":e.repairman?.active?"working":"none"}`,`Manual combo: ${e.manualCombo?.count||0} | Card draft: ${e.cardDraft?.pending?Math.max(1,e.cardDraft.picksRemaining||1)+" pick(s) left":"ready after each day"} | Belt: ${d()}px/s | Farms with scanner route: ${A}/${e.eggFarms.length}`,e.cardEffects?.usedMachineActive?'Procurement: USED MACHINE MODE / no refunds / 60% durability':"",_.length?`Blocked: ${_[0]}`:`${re.status.allPortsConnected}`].join("
")}function te(){if(!t.eventPanel)return;let A=e.eventOffer;if(e.phase!=="build"){t.eventPanel.innerHTML=re.status.eventPanelRunning;return}if(!A){t.eventPanel.className="event-card empty",e.turn+1Event lock active.No irregular events during Days 1-7. First possible forced event: Day ${St}.`:t.eventPanel.innerHTML="No event.Random forced events can appear later.";return}t.eventPanel.className="event-card accepted",t.eventPanel.innerHTML=` -
FORCED NEXT DAY
-

${A.title}

-
- Effect: ${A.route} - ${A.targetAmount?`Target: ${A.targetAmount}`:"Target: none"} - ${A.reward?`Reward: ${M(A.reward)}`:"Reward: none"} - Time ${A.daySeconds||60}s / Output x${Number(A.productionMultiplier||1).toFixed(2)} / Poop +${Math.round((A.poopRateAdd||0)*100)}pt -
`}function z(){P(),t.shell.classList.toggle("phase-running",e.phase==="running"),t.shell.classList.toggle("phase-build",e.phase==="build"),t.shell.classList.toggle("phase-gameover",e.phase==="gameover"),t.shell.classList.toggle("phase-title",e.phase==="title"),t.shell.classList.toggle("phase-loanDecision",e.phase==="loanDecision"),t.money.textContent=M(e.cash),t.money.classList.toggle("cash-negative",e.cash<0),t.money.classList.toggle("cash-positive",e.cash>tn),t.turn.textContent=e.turn,t.timeLeft.textContent=e.phase==="running"&&e.timeLeft<=0&&e.shutdownTimeLeft>0?`+${e.shutdownTimeLeft.toFixed(1)}s`:`${Math.max(0,e.timeLeft).toFixed(1)}s`,t.timeLeft.closest?.(".hud-card")?.classList.toggle("time-critical",e.phase==="running"&&(e.timeLeft<=10||e.timeLeft<=0&&e.shutdownTimeLeft>0)),t.phase.textContent=ye(),t.comboCount&&(t.comboCount.textContent=e.manualCombo?.count||0),se(),t.turnProfit.textContent=M(e.stats.profit),t.turnProfit.classList.toggle("cash-negative",e.stats.profit<0),t.turnProfit.classList.toggle("cash-positive",e.stats.profit>0),t.mixerCount.textContent=e.stats.mixerCount,t.truckFemaleCount.textContent=e.stats.truckFemale,t.truckMaleCount.textContent=e.stats.truckMale,t.poopCount.textContent=e.stats.poopSpawned,t.buttons.s1Left.disabled=e.phase!=="running"||!s(0),t.buttons.s1Right.disabled=e.phase!=="running"||!s(0),t.buttons.s2Left.disabled=e.phase!=="running"||!s(1),t.buttons.s2Right.disabled=e.phase!=="running"||!s(1);let A=e.scanners.find(O=>O.kind==="manual"&&O.slot===0),_=e.scanners.find(O=>O.kind==="manual"&&O.slot===1);A&&(t.buttons.s1Left.textContent=`S1 ${A.keys?.left?.label||"A"} -> Mixer`,t.buttons.s1Right.textContent=`S1 ${A.keys?.right?.label||"D"} -> S2`),_&&(t.buttons.s2Left.textContent=`S2 ${_.keys?.left?.label||"Left"} -> Waste`,t.buttons.s2Right.textContent=`S2 ${_.keys?.right?.label||"Right"} -> Truck`);let k=Math.max(0,Math.floor(e.lastResult?.profit??e.stats?.profit??0)),g=Ln(e,Math.max(1,Number(e.turn)||1),k).amount;t.buttons.nextTurn.textContent=e.phase==="build"&&g>0?`Next Day - Fairies ${M(g)}`:re.actions.nextDay,t.buttons.nextTurn.disabled=e.phase!=="build"||!!e.cardDraft?.pending||!!e.cardTargetPick?.pending||!ii(e)}function se(){if(!t.eventBrief||!t.targetBrief||!t.speedBrief)return;let A=je(e).toUpperCase();t.targetBrief.textContent=`TRUCK TARGET: ${A}`,t.speedBrief.textContent=`BELT: ${d()} px/s | COMBO: ${e.manualCombo?.count||0}`,t.speedBrief.title=`Conveyor speed does not increase by day. Degraded belts reduce speed. Cap: ${_t}px/s.`;let _=e.eventActive,k=e.eventOffer;_?(t.eventBrief.textContent=`ACTIVE EVENT: ${_.title} | ${_.route}`,t.eventBrief.className="event-brief active"):e.phase==="build"&&k?(t.eventBrief.textContent=`NEXT DAY EVENT: ${k.title} | ${k.route}${k.targetAmount?` | Target ${k.targetAmount}`:""}${k.reward?` | Reward ${M(k.reward)}`:""}`,t.eventBrief.className="event-brief next"):e.phase==="build"&&e.turn+1
\u2642Male->MixerS1: A
\u2640Female->TruckS1: D, then S2: right
\u{1F4A9}Poop->ShredderS1: D, then S2: left

Build phase: connect at least one EGG through a scanner to Mixer, Shredder, or Truck before Next Day. One day is one run.

',t.modalActions.innerHTML="",t.modalActions.appendChild(le(re.actions.startGame,o,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function $(A){let _=X=>`${X>0?"+":""}${M(X)}`,k=X=>`${X>0?"-":""}${M(X)}`,g=A.profit>=0?"cash-positive":"cash-negative",O=(A.mixerPoopFine||0)+(A.truckPoopFine||0)+(A.maleTruckFine||0)+(A.explosionDamage||0)+(A.cardRerollCost||0);t.modalTitle.textContent=`Day ${A.turn} Settlement`,t.modalBody.innerHTML=` -
Net result${M(A.profit)}
-
-
Chick shipment income${_(A.chickShipmentIncome||0)}
-
Poop shipment income${_(A.poopShipmentIncome||0)}
-
Mixer income${_(A.mixerRevenue||0)}
-
Composter income${_(A.composterIncome||0)}
-
DUD refund income${_(A.dudRefundIncome||0)}
-
Manual combo bonus${_(A.manualComboBonus||0)}
-
Chemical subsidy${_(A.chemicalWeaponSubsidy||0)}
-
Event bonus${_(A.eventBonus||0)}
-
Penalties${k(O)}
-
Fairies fee${k(A.fairiesTribute?.amount||A.fairiesTribute||0)}
-
Repair worker wages${k(A.repairWorkerWages||0)}
-
-

Income ${M(A.revenue)} - losses ${M(A.penalty)} = ${M(A.profit)}

`,t.modalActions.innerHTML="",t.modalActions.appendChild(le("Choose Upgrade Card",r||Se,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function U(A,_){let k=Math.max(0,e.cardEffects?.rescueLoanCharges||0);t.modalTitle.textContent="Emergency Loan Available",t.modalBody.innerHTML=` -

End-of-day cash is below ${M(0)}.

-
-
Current money${M(e.cash)}
-
Emergency Loan+${M(500)}
-
Cards remaining${k}
-
-

Use one Emergency Loan to gain ${M(500)} immediately. If cash is still negative, another decision will be shown if another card remains.

`,t.modalActions.innerHTML="",t.modalActions.appendChild(le("Accept Game Over",_,"facility-action danger")),t.modalActions.appendChild(le("Use Emergency Loan",A,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function N(){let A=e.totals.processed,_=A?Math.round(e.totals.correct/A*100):0,k=Ai(e);t.modalTitle.textContent=re.phases.gameover,t.modalBody.innerHTML=`

Your cash went negative.

-
Final Score${k.score}
Survival${e.totals.turnsCompleted} days
Final Cash${M(e.cash)}
Accuracy${_}%
-
Score breakdown -
Formula
Base = Cash + Total revenue + Factory value \xD70.5 + Event bonus \xD70.5 = ${M(k.base)}
Daily earned = ceil(Base \xF7 Days) = ${M(k.dailyEarned)}
Score = max(0, floor(Base + Daily earned + Correct bonus - Total outflow - Day penalty)) = ${k.score}
-
Factory Value${M(k.factoryValue)}
Total Revenue${M(e.totals.revenue)}
Daily Earned${M(k.dailyEarned)} / day
Total Outflow${M(e.totals.penalty)}
Fairies Tribute${M(e.totals.fairiesTribute||0)}
Correct Sorts${e.totals.correct}
Auto Sorted${e.totals.autoSorted}
Poop Control${e.totals.poopTrash} trashed / ${e.totals.poopTruck} shipped / ${e.totals.poopMixer} mixer
Explosion Penalty${M(e.totals.explosionDamage)}
Event Bonus${M(e.totals.eventBonus)}
Day Penalty-${k.dayPenalty}
Events${e.totals.eventSuccess} success / ${e.totals.eventFailed} failed
-
`,t.modalActions.innerHTML="",t.modalActions.appendChild(le(re.actions.restart||"Restart",o,"primary-button restart-button")),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible","gameover-modal")}function le(A,_,k="primary-button"){let g=document.createElement("button");return g.type="button",g.className=k,g.textContent=A,g.addEventListener("click",_),g}function Se(){t.modal.classList.remove("visible","equipment-popover","gameover-modal"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function he(){}return{updatePanels:C,updateUI:z,showTitle:Z,showTurnResult:$,showEmergencyLoanDecision:U,showGameOver:N,hideModal:Se,checkGameOver:he}}function cr(e){e.totals.processed+=1}function zt(e){e.stats.correct+=1,e.totals.correct+=1}function ht(e){e.stats.mistakes+=1,e.totals.mistakes+=1}function Ps(e){e.stats.autoSorted+=1,e.totals.autoSorted+=1}function Rs(e){e.stats.poopSpawned+=1}function As(e){e.stats.mixerCount+=1,cr(e)}function Ds(e){e.stats.trashCount+=1,cr(e)}function $s(e,t){t==="female"?e.stats.truckFemale+=1:t==="male"&&(e.stats.truckMale+=1),cr(e)}function Zn(e,t){let n=t==="truck"?"poopTruck":t==="trash"?"poopTrash":t==="mixer"?"poopMixer":null;n&&(e.stats[n]+=1,e.totals[n]+=1)}function Is({game:e,currentConveyorSpeed:t,onGameOverCheck:n}){function o(u){return gt(u)*Hn(u)*is(e)/fi(e)}function r(u){let f=F(u.col,u.row),b=1+ss(e,u),S=l(u,b);if(!S.length)return s(u,f),!0;let w=0,E=0;for(let D of S){let K=F(D.col,D.row),ee=d(K);if(ee){ee.stoppedTimer=.85,E+=1;continue}let Qe=Ms(e,{stage:"belt",scannerId:null,route:[K]});Qe.sex==="poop"&&Rs(e),e.chicks.push(Qe),Wi(e,u),w+=1}return w>0?($i(e,f.x,f.y),w>1&&W(e,f.x,f.y-28,`x${w}`,p.green),!0):E===0}function s(u,f){(u.noRouteNoticeCooldown||0)<=0&&(W(e,f.x,f.y-24,"NO BELT: PAUSED",p.warn),u.noRouteNoticeCooldown=2.5)}function l(u,f){let S=ue.map(w=>({col:u.col+w.dc,row:u.row+w.dr})).filter(w=>Ee(w.col,w.row)&&e.conveyorTiles.has(I(w.col,w.row))).map(w=>({p:w,blocked:L(null,F(w.col,w.row))?1:0,roll:Math.random()}));return S.sort((w,E)=>w.blocked-E.blocked||w.roll-E.roll),S.slice(0,Math.max(1,f||1)).map(w=>w.p)}function d(u){return e.chicks.find(f=>f.stage!=="flying"&&Math.hypot(f.x-u.x,f.y-u.y)0;if(e.timeLeft=Math.max(0,e.timeLeft-u),S&&e.timeLeft<=0&&f(),e.timeLeft<=0){e.shutdownTimeLeft>0&&(e.shutdownTimeLeft=Math.max(0,e.shutdownTimeLeft-u));for(let w of e.eggFarms)w.shutterProgress=Math.min(1,(w.shutterProgress||0)+u*2.8)}if(S&&e.timeLeft>0){for(let w of e.eggFarms)if(w.noRouteNoticeCooldown>0&&(w.noRouteNoticeCooldown=Math.max(0,w.noRouteNoticeCooldown-u)),w.nextSpawn-=u,w.nextSpawn<=0){let E=r(w);w.nextSpawn=E?o(w):.15,w.lastInterval=w.nextSpawn}}for(let w=e.chicks.length-1;w>=0;w-=1){let E=e.chicks[w];E.bob+=u*7,E.stoppedTimer>0&&(E.stoppedTimer=Math.max(0,E.stoppedTimer-u)),E.stage!=="queued"&&P(E,w,u)}J(u),Jt(),so(),e.timeLeft<=0&&(e.chicks.length===0?b():e.shutdownTimeLeft<=0&&C())}function C(){if(e.cleanupBlown)return;e.cleanupBlown=!0,e.cleanupTimer=1;let u=[...e.chicks];for(let f of u)Go(e,f.sex,f.x,f.y,-Math.PI/2,!0);e.chicks=[];for(let f of e.scanners)f.queue=[];if(Jt(),u.length){let f=u.reduce((S,w)=>S+w.x,0)/u.length,b=u.reduce((S,w)=>S+w.y,0)/u.length;Ve(e,f,b,p.warn,58),W(e,f,b-24,"CLEANUP",p.warn)}}function P(u,f,b){if(R(u)){u.stoppedTimer=.35;return}if(de(u,b),!(u.route&&u.targetIndex=u.route.length)return!1;let f=u.route[u.targetIndex];return L(u,f)}function L(u,f){if(!f)return!1;for(let b of e.chicks)if(!(u&&b.id===u.id)&&b.stage!=="flying"&&Math.hypot(b.x-f.x,b.y-f.y)1)&&u.push({x:f.x,y:f.y})}function te(u){let f=e.conveyorMeta?.get?.(u)||{},b=[];Array.isArray(f.outDirs)&&b.push(...f.outDirs),f.dir&&b.push(f.dir);let S=[...new Set(b)].filter(ee=>ue.some(Qe=>Qe.name===ee)),w=Q(u),E=ue.filter(ee=>N(w,ee.name)).map(ee=>ee.name),D=S.filter(ee=>E.includes(ee)),K=E;return D.length?D:K}function z(u){return ue.find(f=>f.name===u)||null}function se(u,f){return e.scanners.find(b=>b.col<=u&&u<=b.col+1&&b.row-1<=f&&f<=b.row+1)||null}function ye(u,f){let b=z(f);if(!b)return null;let S=se(u.col+b.dc,u.row+b.dr);if(!S)return null;let w=Pe(S,"inputA");return w&&w.col===u.col&&w.row===u.row?S:null}function Z(u){return Object.entries(e.facilities||{}).find(([,f])=>f?.entry&&f.entry.col===u.col&&f.entry.row===u.row)||null}function $(u){return u?.baseId||u?.id||""}function U(u,f){return u.side==="left"&&f==="left"||u.side==="right"&&f==="right"||u.side==="top"&&f==="up"||u.side==="bottom"&&f==="down"}function N(u,f){let b=z(f);if(!b)return null;let S={col:u.col+b.dc,row:u.row+b.dr};if(Ee(S.col,S.row)&&e.conveyorTiles.has(I(S.col,S.row)))return{type:"conveyor",dirName:f,target:F(S.col,S.row),nextCell:S};let w=ye(u,f);if(w)return{type:"scanner",dirName:f,target:pe(w),scanner:w};let E=Z(u);return E&&U(E[1],f)?{type:"facility",dirName:f,facilityId:E[0],facility:E[1],target:F(u.col,u.row)}:null}function le(u,f){let b=z(f);if(!b)return!1;let S=e.conveyorMeta?.get?.(I(u.col+b.dc,u.row+b.dr));return S?[...new Set([...Array.isArray(S.outDirs)?S.outDirs:[],S.dir].filter(Boolean))].includes(b.opposite):!1}function Se(u){return ue.filter(f=>Ee(u.col+f.dc,u.row+f.dr)&&e.conveyorTiles.has(I(u.col+f.dc,u.row+f.dr))).map(f=>f.name)}function he(u,f,b="random"){let S=Se(u);if(S.length<3)return f;let w=new Set(S.filter(K=>le(u,K)));if(b&&b!=="random"&&b!=="pass"&&S.includes(b)){let K=new Set(w);K.add(b),S.filter(ee=>!K.has(ee)).length>=2&&w.add(b)}let E=S.filter(K=>!w.has(K));if(E.length)return E;let D=f.filter(K=>!w.has(K));return D.length?D:f}function A(u,f){return f&&(f.type==="facility"||!L(u,f.target))}function _(u,f,b,S="random"){let w=b.map(ee=>N(f,ee)).filter(Boolean);if(!w.length)return null;let D=w.filter(ee=>ee.type!=="facility").filter(ee=>!L(u,ee.target)),K=D.length?D:w.filter(ee=>ee.type==="facility");return K.length?K[Math.floor(Math.random()*K.length)]:null}function k(u,f){let b=[];V(b,{x:u.x,y:u.y}),V(b,f),u.route=b.length?b:[{x:u.x,y:u.y}],u.targetIndex=u.route.length>1?1:u.route.length}function g(u,f){let b=We(u.x,u.y);if(!b)return Ot(f,"OFF GRID");let S=I(b.col,b.row);if(!e.conveyorTiles.has(S))return Ot(f,"OFF BELT");let w=e.conveyorMeta?.get(S)||{},E=he(b,te(S),w.branchMode||"random");if(!E.length){u.stoppedTimer=.25;return}let D=_(u,b,E,w.branchMode||"random");if(!D){u.stoppedTimer=.25;return}if(D.type==="facility"){let K=$(D.facility);K==="mixer"?ro(f,D.facility):K==="truck"?bn(f,D.facility):K==="trash"?io(f,D.facility):Ot(f,"DONE");return}D.type==="scanner"&&(u.pendingScannerId=D.scanner.id),u.prevConveyorCell=S,k(u,D.target)}function O(u){let f=We(u.x,u.y);if(!f)return null;let b=I(f.col,f.row);return e.conveyorTiles.has(b)?b:null}function X(u){let f=O(u)||O(u.route?.[u.targetIndex]||u);return t(f)}function oe(u,f){let b=O(f);!b||u.lastWearKey===b||(u.lastWearKey=b,Ui(e,b))}function de(u,f){let b=X(u)*f;for(;b>0&&u.targetIndex=D?(u.x=S.x,u.y=S.y,oe(u,S),u.targetIndex+=1,b-=D):(u.x+=w/D*b,u.y+=E/D*b,b=0)}}function Te(u,f,b){u.stage="queued",u.route=null,u.queueRoute=b?b.map(S=>({x:S.x,y:S.y})):[pe(f)],u.scannerId=f.id,f.queue.includes(u.id)||f.queue.push(u.id),ce(f)}function ce(u){u.queue=u.queue.filter(b=>e.chicks.some(S=>S.id===b&&S.stage==="queued"));let f=y.cell*.86*ls(e);u.queue.forEach((b,S)=>{let w=e.chicks.find(E=>E.id===b);w&&(rt(w,w.queueRoute||[pe(u)],S*f),w.queueIndex=S)})}function rt(u,f,b){if(!f||!f.length)return;if(f.length===1||b<=0){let E=f[f.length-1];u.x=E.x,u.y=E.y;return}let S=b;for(let E=f.length-1;E>0;E-=1){let D=f[E-1],K=f[E],ee=Math.hypot(K.x-D.x,K.y-D.y);if(S<=ee){let Qe=1-S/ee;u.x=D.x+(K.x-D.x)*Qe,u.y=D.y+(K.y-D.y)*Qe;return}S-=ee}let w=f[0];u.x=w.x,u.y=w.y}function J(u){for(let f of e.scanners){if(f.cooldown>0&&(f.cooldown=Math.max(0,f.cooldown-u)),f.keyPressTime>0&&(f.keyPressTime=Math.max(0,f.keyPressTime-u)),ce(f),f.kind!=="auto"||f.cooldown>0||!f.queue.length)continue;let b=f.queue[0],S=e.chicks.findIndex(w=>w.id===b);if(S<0){f.queue.shift();continue}mn(S,Eo(f,e.chicks[S]),!0)&&(Ki(e,f),f.cooldown=tt(f,e),Ps(e))}}function ge(u){let f=Co(e,u);return!f||!f.queue.length?null:e.chicks.find(b=>b.id===f.queue[0])||null}function Le(u,f){if(e.phase!=="running")return;let b=Co(e,u);it(b,f)}function it(u,f){if(e.phase!=="running"||!u||u.kind!=="manual"||(u.keyPressTime=.18,u.keyPressSide=f,!u.queue.length))return;let b=e.chicks.findIndex(S=>S.id===u.queue[0]);b>=0&&mn(b,f,!1)}function Ge(u,f,b){return u.kind==="manual"&&Eo(u,f)===b}function st(u){let f=e.manualCombo?.count||0;if(e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=0,e.manualCombo.lastBonus=0,e.stats.manualComboFailure=(e.stats.manualComboFailure||0)+1,e.totals.manualComboFailure=(e.totals.manualComboFailure||0)+1,f>=10){let b=pe(u);It(e,10,.25),W(e,b.x,b.y-36,"COMBO RESET",p.danger)}}function oo(u){e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=Math.max(0,e.manualCombo.count||0)+1,e.stats.manualComboSuccess=(e.stats.manualComboSuccess||0)+1,e.totals.manualComboSuccess=(e.totals.manualComboSuccess||0)+1;let f=e.manualCombo.count;if(e.manualCombo.lastBonus=0,f<10)return 0;let b=Math.max(1,Math.floor(f/10)),S=e.scanners.filter(K=>K.kind==="manual").length,w=Math.min(1,(20+S*10)/100),E=0;for(let K=0;K0){Ne(e,D),e.stats.manualComboBonus=(e.stats.manualComboBonus||0)+D,e.totals.manualComboBonus=(e.totals.manualComboBonus||0)+D,e.manualCombo.lastBonus=D;let K=pe(u);W(e,K.x,K.y-42,`COMBO +${M(D)}`,p.green)}return D}function yn(u,f){let b=Pe(u,f);if(!b)return null;let S=I(b.col,b.row);if(e.conveyorTiles.has(S))return{...b};let E=(Oe(e).scannerPorts.get(u.id)?.[f]?.keys||[]).filter(Boolean);if(!E.length)return null;let D=E.map(Q);return D.find(ee=>ee.col===b.col&&ee.row===b.row)||D[0]||null}function hn(u,f,b,S){let w=[];V(w,{x:u.x,y:u.y});let E=Pe(f,b);return E&&V(w,F(E.col,E.row)),V(w,F(S.col,S.row)),w}function mn(u,f,b){let S=e.chicks[u];if(!S||S.stage!=="queued")return!1;let w=Rt(e,S.scannerId);if(!w)return!1;let E=yn(w,f);if(!E)return!b&&w.kind==="manual"&&st(w),W(e,S.x,S.y-16,f==="left"?"NO LEFT BELT":"NO RIGHT BELT",p.danger),!1;!b&&w.kind==="manual"&&(Ge(w,S,f)?oo(w):st(w)),w.queue=w.queue.filter(K=>K!==S.id),S.stage="belt",S.route=hn(S,w,f,E),S.targetIndex=S.route.length>1?1:S.route.length,S.scannerId=null,S.nextScannerId=null,S.pendingScannerId=null,S.queueRoute=null,S.queueIndex=-1;let D=b?p.green:f==="left"?p.mixerBlue:p.truckPink;return Ii(e,pe(w).x,pe(w).y,D),W(e,S.x,S.y-20,b?"AUTO":f.toUpperCase(),D),!0}function vt(u){let f=e.chicks[u];return f?(e.chicks.splice(u,1),f):null}function ro(u,f=e.facilities.mixer){if(f?.processingCooldown>0){let D=e.chicks[u];D&&(D.stoppedTimer=.25);return}let b=vt(u);if(!b)return;let{x:S,y:w}=b;if(As(e),Qo(e,f),Jo(e,f),b.sex==="poop"){let D=Ci(e);Zn(e,"mixer"),ht(e),Bi(e,S,w),W(e,S,w-18,`-${M(D)}`,p.danger);return}let E=xi(e);b.sex==="male"?zt(e):ht(e),Fi(e,S,w),W(e,S,w-18,`+${M(E)}`,p.green)}function bn(u,f=e.facilities.truck){let b=vt(u);if(!b)return;let{x:S,y:w}=b;vn(b.sex,f),Oi(e,S,w,b.sex),$s(e,b.sex);let E=je(e),D=yi(e,b.sex);if(b.sex==="poop"){if(Zn(e,"truck"),D)zt(e),W(e,S,w-18,`+${M($e(e))}`,p.green);else{let K=Mi(e);ht(e),W(e,S,w-18,`-${M(K)}`,p.danger)}return}if(b.sex==="female"){D?(zt(e),W(e,S,w-18,`+${M($e(e))}`,p.green)):(ht(e),W(e,S,w-18,E==="male"?"REJECT":"NO SALE",p.warn));return}if(D){zt(e),W(e,S,w-18,`+${M($e(e))}`,p.green);return}if(hi(e)){let K=gi(e);ht(e),W(e,S,w-18,`-${M(K)}`,p.danger)}else ht(e),W(e,S,w-18,"REJECT",p.warn)}function io(u,f=e.facilities.trash){if(f?.processingCooldown>0){let K=e.chicks[u];K&&(K.stoppedTimer=.25);return}let b=vt(u);if(!b)return;let{x:S,y:w}=b;Li(e,S,w,b.sex),Ds(e),Qo(e,f),Jo(e,f);let E={amount:0},D="";if(b.sex==="poop"){E=wi(e),D=E.amount>0?` +${M(E.amount)}`:"",Zn(e,"trash"),zt(e);let K=Math.ceil(Math.max(0,Number(e.cardEffects?.composter)||0)*3*Fn(e));if(K>0){let ee=Ne(e,K);e.stats.composterIncome=(e.stats.composterIncome||0)+ee,e.totals.composterIncome=(e.totals.composterIncome||0)+ee,W(e,S,w-36,`COMPOST +${M(ee)}`,p.green)}W(e,S,w-18,`CLEAN${D}`,E.amount>0?p.green:p.green)}else ht(e),W(e,S,w-18,E.amount>0?`WASTE${D}`:"WASTE",E.amount>0?p.green:p.ink)}function Ot(u,f){let b=vt(u);b&&W(e,b.x,b.y-12,f,p.muted)}function vn(u,f=e.facilities.truck){let b=f||e.facilities.truck;b&&(e.truckCargo.push({sex:u,x:G(22,b.w-22),y:G(66,b.h-24)}),e.truckCargo.length>45&&e.truckCargo.shift())}function Nt(u){let f=We(u.x,u.y);if(f){let E=I(f.col,f.row);if(e.conveyorTiles.has(E))return E}let b=ti(e,u.x,u.y);if(!b)return null;let S=Q(b),w=F(S.col,S.row);return Math.hypot(u.x-w.x,u.y-w.y)<=y.cell*.55?b:null}function Jt(){let{components:u,cellToComponent:f}=ei(e);for(let b of e.chicks){if(b.stage==="flying")continue;let S=Nt(b);if(!S)continue;let w=f.get(S),E=u.get(w);E&&(E.count+=1)}for(let b of u.values())b.ratio=b.count/b.capacity;e.congestion=u,e.componentLookup=f}function so(){for(let u of e.congestion.values()){let f=Fo(e),b=mi(e);if(u.ratio>b&&u.ratio=f){let S=jt(u.id);if(!S.length||S.some(D=>D.stage!=="queued"&&D.stoppedTimer<=.2))continue;let w=e.lastExplodedComponent.get(u.id)||0,E=performance.now();E-w>900&&(e.lastExplodedComponent.set(u.id,E),wn(u))}}}function jt(u){return e.chicks.filter(f=>{let b=Nt(f);return b&&e.componentLookup?.get(b)===u})}function wn(u){let f=jt(u.id);if(!f.length)return;for(let w of f)Go(e,w.sex,w.x,w.y);e.chicks=e.chicks.filter(w=>!f.some(E=>E.id===w.id));for(let w of e.scanners)w.queue=w.queue.filter(E=>e.chicks.some(D=>D.id===E));for(let w of u.cells){let E=Q(w),D=F(E.col,E.row);Ve(e,D.x,D.y,p.danger),Ze(e,D.x,D.y,6),On(e,D.x,D.y,4)}It(e,18,.75);let b=Q(u.cells[0]),S=F(b.col,b.row);e.stats.explosions=(e.stats.explosions||0)+1,e.totals.explosions=(e.totals.explosions||0)+1,W(e,S.x,S.y-22,`${Math.round(Fo(e)*100)}% JAM EXPLOSION`,p.danger)}return{activeQueuedChick:ge,currentSpawnDelay:o,sortSlot:Le,updateCongestion:Jt,sortScanner:it,updateRunning:v}}var ae=document.getElementById("gameCanvas"),nc=ae.getContext("2d"),B={shell:document.getElementById("gameShell"),money:document.getElementById("money"),turn:document.getElementById("turn"),timeLeft:document.getElementById("timeLeft"),phase:document.getElementById("phaseLabel"),comboCount:document.getElementById("comboCount"),eventBrief:document.getElementById("eventBrief"),targetBrief:document.getElementById("targetBrief"),speedBrief:document.getElementById("speedBrief"),turnProfit:document.getElementById("turnProfit"),mixerCount:document.getElementById("mixerCount"),truckFemaleCount:document.getElementById("truckFemaleCount"),truckMaleCount:document.getElementById("truckMaleCount"),poopCount:document.getElementById("poopCount"),buildStatus:document.getElementById("buildStatus"),turnSummary:document.getElementById("turnSummary"),eventPanel:document.getElementById("eventPanel"),modal:document.getElementById("modal"),modalTitle:document.getElementById("modalTitle"),modalBody:document.getElementById("modalBody"),modalActions:document.getElementById("modalActions"),hoverTooltip:document.getElementById("hoverTooltip"),manualScannerMonitor:document.getElementById("manualScannerMonitor"),hireRepairmanButton:document.getElementById("hireRepairmanButton"),debug:{panel:document.getElementById("debugPanel"),infiniteCash:document.getElementById("debugInfiniteCash"),dayInput:document.getElementById("debugDayInput"),setDay:document.getElementById("debugSetDayButton"),zeroTimer:document.getElementById("debugZeroTimerButton"),cardSelect:document.getElementById("debugCardSelect"),targetSelect:document.getElementById("debugTargetSelect"),grantCard:document.getElementById("debugGrantCardButton"),grantAllCards:document.getElementById("debugGrantAllCardsButton"),readout:document.getElementById("debugReadout")},buttons:{s1Left:document.getElementById("scanner1MixerButton"),s1Right:document.getElementById("scanner1TruckButton"),s2Left:document.getElementById("scanner2MixerButton"),s2Right:document.getElementById("scanner2TruckButton"),nextTurn:document.getElementById("nextTurnButton"),conveyor:document.getElementById("buildConveyorButton"),boostConveyor:document.getElementById("buildBoostConveyorButton"),eggFarm:document.getElementById("buildEggFarmButton"),autoScanner:document.getElementById("buildAutoScannerButton"),manualScanner:document.getElementById("buildManualScannerButton"),mixer:document.getElementById("buildMixerButton"),trash:document.getElementById("buildTrashButton"),truck:document.getElementById("buildTruckButton"),erase:document.getElementById("eraseButton"),undo:document.getElementById("undoButton"),redo:document.getElementById("redoButton")}};function oc(){let e={conveyor:"conveyor",boostConveyor:"boostConveyor",eggFarm:"eggFarm",autoScanner:"autoScanner",manualScanner:"manualScanner",mixer:"mixer",trash:"trash",truck:"truck"};for(let[t,n]of Object.entries(e))B.buttons[t]&&(B.buttons[t].innerHTML=Pr(n))}function rc(e){let t=new Set(e.tags||[]);return["upgradeEgg","crowdedFarming","hatchingFeed","extraEggOutlet"].includes(e.id)||t.has("EGG")?"Production / EGG":["upgradeTrash","poopRateBooster","composter","chemicalWeaponSubsidy"].includes(e.id)||t.has("POOP")?"Poop / Shredder":["upgradeAutoScanner","autoScannerTuning","scannerQueueSpacing"].includes(e.id)||t.has("SCANNER")?"Scanner":["bearing","dynamite"].includes(e.id)||t.has("CONVEYOR")?"Conveyor / Map":["safetyCover","preventiveMaintenance","durabilityCoating","sparePartsBin","laborExploitation"].includes(e.id)||t.has("MAINTENANCE")?"Maintenance / Risk":["dudFilter","dudRefund","freeReroll","extraCards"].includes(e.id)||t.has("CARD")?"Card Engine":t.has("ULTRA RARE")?"Ultra Rare":t.has("ECONOMY")||["upgradeMixer","upgradeTruck","recyclingSubsidy","usedMachine","newMachine","flattery","legalWork","rescueLoan"].includes(e.id)?"Economy / Shipment":"Other"}function ic(){if(!B.debug?.panel||!B.debug.cardSelect)return;let e=["Production / EGG","Poop / Shredder","Scanner","Conveyor / Map","Maintenance / Risk","Card Engine","Economy / Shipment","Ultra Rare","Other"],t=new Map(e.map(n=>[n,[]]));for(let n of Yt){let o=rc(n);t.has(o)||t.set(o,[]),t.get(o).push(n)}B.debug.cardSelect.innerHTML="";for(let n of e){let o=t.get(n)||[];if(!o.length)continue;let r=document.createElement("optgroup");r.label=n;for(let s of o){let l=document.createElement("option");l.value=s.id;let d=s.rarity==="ultraRare"?"UR":s.rarity==="rare"?"R":"C";l.textContent=`[${d}] ${s.title}`,r.appendChild(l)}B.debug.cardSelect.appendChild(r)}B.debug.cardSelect.addEventListener("change",Bt),Bt()}function Bt(){if(!B.debug?.targetSelect)return;let e=B.debug.cardSelect?.value,t=Vt(e),n=t?as(a,t):[];if(B.debug.targetSelect.innerHTML="",!n.length){let r=document.createElement("option");r.value="__none__",r.textContent=t?"No target required":"No card selected",B.debug.targetSelect.appendChild(r),B.debug.targetSelect.disabled=!0;return}let o=document.createElement("option");o.value="__auto__",o.textContent=t?.id==="dynamite"?"Auto: first 3 blocked cells":"Auto: first valid target",B.debug.targetSelect.appendChild(o);for(let r of n){let s=document.createElement("option");s.value=r.key,s.textContent=r.label,B.debug.targetSelect.appendChild(s)}B.debug.targetSelect.disabled=!1}function sc(){let e=Math.max(1,Math.floor(Number(B.debug.dayInput?.value)||1));a.turn=e,B.debug.dayInput&&(B.debug.dayInput.value=String(e)),W(a,ae.width/2-a.view.x,86-a.view.y,`DAY ${e}`,p.green),H.updatePanels(),H.updateUI(),Bt(),Lt(`Day set to ${e}.`)}function lc(){a.timeLeft=0,a.phase==="running"&&_s(),W(a,ae.width/2-a.view.x,86-a.view.y,"TIMER 0",p.warn),H.updatePanels(),H.updateUI(),Lt("Timer set to 0.")}function ac(){let e=B.debug.cardSelect?.value,t=B.debug.targetSelect?.disabled?void 0:B.debug.targetSelect?.value,n=er(a,e,{targetKey:t});B.debug.grantCard&&(B.debug.grantCard.textContent=n.ok?"Granted":"Failed",window.setTimeout(()=>{B.debug.grantCard&&(B.debug.grantCard.textContent="Grant Selected")},900)),Me?.updateCongestion?.(),H.updatePanels(),H.updateUI(),Bt(),Lt(n.reason)}function cc(){let t=Yt.map(n=>er(a,n,{targetKey:"__auto__"})).filter(n=>n.ok).length;Me?.updateCongestion?.(),H.updatePanels(),H.updateUI(),Bt(),Lt(`Granted ${t}/${Yt.length} cards.`)}function uc(){B.debug?.infiniteCash?.checked&&a.cash<999999&&(a.cash=999999,a.totals.maxCash=Math.max(a.totals.maxCash,a.cash))}function Lt(e=""){B.debug?.readout&&(B.debug.readout.textContent=[e,`D${a.turn}`,M(a.cash),`Combo ${a.manualCombo?.count||0}`,`Event ${a.eventActive?.title||a.eventOffer?.title||"none"}`,`Rescue ${a.cardEffects?.rescueLoanCharges||0}`,`Chem ${a.cardEffects?.chemicalWeaponSubsidy||0}`].filter(Boolean).join(" | "))}var a=ko(),Y,H,Me,Qt;function dc(e=null){let t=zn(a,e);return e?t*qo(a,e):t}function fc(){Object.assign(a,ko()),a.phase="running",a.view={x:0,y:0,scale:1},xo(a),Us(),me(a),H.hideModal(),Me.updateCongestion(),H.updatePanels(),H.updateUI(),Lt()}function pc(){if(a.phase!=="build")return;if(a.cardDraft?.pending||a.cardTargetPick?.pending){Y.fail(a.cardTargetPick?.pending?"Choose upgrade target first.":"Choose an upgrade card first."),H.updatePanels();return}let e=sn(a);if(e.length){Y.fail(`Cannot start: ${e[0]}`),H.updatePanels();return}me(a),Zr(a),Xi(a);let t=Math.max(0,Math.floor(a.lastResult?.profit??a.stats?.profit??0)),n=Pi(a,Math.max(1,a.turn||1),t);a.lastStartFees={fairiesTribute:n.amount||0,tribute:n},n.amount>0&&W(a,ae.width/2-a.view.x,116-a.view.y,`FAIRIES -${M(n.amount)}`,p.danger),ci(a),a.phase="running",a.turn+=1,a.timeLeft=di(a),a.shutdownTimeLeft=0,a.cleanupTimer=null,a.cleanupBlown=!1,a.chicks=[],a.effects=[],a.floatingTexts=[],a.shake={time:0,strength:0},a.truckCargo=[],Us(),a.stats=So(),a.stats.fairiesTribute=a.lastStartFees?.fairiesTribute||0,a.stats.repairWorkerWages=a.pendingRepairWorkerWages||0;let o=a.stats.fairiesTribute+a.stats.repairWorkerWages;o>0&&(a.stats.penalty+=o,a.stats.profit-=o),a.pendingRepairWorkerWages=0;for(let r of a.scanners)r.queue=[],r.cooldown=0;for(let r of a.eggFarms)r.nextSpawn=Me.currentSpawnDelay(r),r.lastInterval=r.nextSpawn,r.shutterProgress=0,r.shutterSparked=!1;a.buildTool=null,a.selected=null,a.groupDrag=null,a.selectionBox=null,a.pan=null,Me.updateCongestion(),H.updatePanels(),H.updateUI()}function yc(){me(a);let e=zi(a);e.ok?W(a,ae.width/2-a.view.x,96-a.view.y,`Repairman hired -${M(e.cost)}`,p.green):(W(a,ae.width/2-a.view.x,96-a.view.y,e.reason||"Cannot hire repairman.",p.danger),Y?.fail?.(e.reason||"Cannot hire repairman.")),H.updatePanels(),H.updateUI()}function hc(){if(a.phase!=="running")return;let e=Ei(a),t=a.eventActive?{...a.eventActive}:null,n=vi(a),o=Ri(a);if(e.adjusted>0){let s=a.facilities.truck,l=s?s.x+s.w/2:ae.width/2-a.view.x,d=s?s.y+26:96-a.view.y;W(a,l,d,`${e.target==="poop"?"POOP SHIP":"SHIP"} +${M(e.adjusted)}`,p.green)}n?.bonus>0&&W(a,ae.width/2-a.view.x,96-a.view.y,`EVENT +${M(n.bonus)}`,p.green),o.amount>0&&W(a,ae.width/2-a.view.x,116-a.view.y,`CHEM SUBSIDY +${M(o.amount)}`,p.green),ui(a),a.totals.turnsCompleted+=1;let r=bi(t);if(r!==1&&(a.pendingFairiesTributeMultiplier=r),a.lastResult={...a.stats,ship:e,event:n,chemical:o,rescue:{amount:0,used:0,remaining:a.cardEffects?.rescueLoanCharges||0},fairiesTribute:{amount:a.stats.fairiesTribute||0},tributeMultiplier:r,turn:a.turn,cash:a.cash},a.cash<0){if((a.cardEffects?.rescueLoanCharges||0)>0){a.phase="loanDecision",H.showEmergencyLoanDecision(Ns,eo);return}a.phase="gameover",H.showGameOver();return}Os()}function Os(){a.phase="build",a.truckCargo=[],a.chicks=[],a.shutdownTimeLeft=0,a.cleanupTimer=null,a.cleanupBlown=!1,a.buildSession+=1,a.undoStack=[],a.redoStack=[],a.timeLeft=0;for(let e of a.scanners)e.queue=[];for(let e of a.eggFarms)e.shutterProgress=0,e.shutterSparked=!1;Qi(a),a.eventOffer=ai(a),Qt&&Qt.prepareDraft(),a.cardTargetPick=null,a.buildTool=null,a.groupDrag=null,a.selectionBox=null,a.pan=null,H.updatePanels(),H.showTurnResult(a.lastResult)}function Ns(){if((a.cardEffects?.rescueLoanCharges||0)<=0)return eo();a.cardEffects.rescueLoanCharges-=1,a.stats.rescueLoan=(a.stats.rescueLoan||0)+500,a.totals.rescueLoan=(a.totals.rescueLoan||0)+500;let e=Ne(a,500);a.lastResult={...a.lastResult||{},...a.stats,rescue:{amount:(a.lastResult?.rescue?.amount||0)+e,used:(a.lastResult?.rescue?.used||0)+1,remaining:a.cardEffects.rescueLoanCharges},cash:a.cash},W(a,ae.width/2-a.view.x,176-a.view.y,`RESCUE +${M(e)}`,p.green),a.cash>=0?Os():(a.cardEffects?.rescueLoanCharges||0)>0?(a.phase="loanDecision",H.showEmergencyLoanDecision(Ns,eo)):eo()}function eo(){a.phase="gameover",H.showGameOver()}function _s(){a.shutdownTimeLeft<=0&&(a.shutdownTimeLeft=a.shutdownGraceSeconds||10);for(let e of a.eggFarms){if(e.shutterSparked)continue;e.shutterProgress=.02,e.shutterSparked=!0;let t=F(e.col,e.row);Ve(a,t.x,t.y,p.ink),Ze(a,t.x,t.y+10,10),W(a,t.x,t.y-34,"SHUT +10s",p.ink)}}function Gs(e){a.lastTimestamp||(a.lastTimestamp=e);let t=Math.min((e-a.lastTimestamp)/1e3,.05);a.lastTimestamp=e,a.phase==="running"&&Me.updateRunning(t,{closeFarmShutters:_s,completeTurn:hc}),_i(a,t,ae,Y.equipmentHitBoxes),Me.updateCongestion(),hs(nc,ae,a,{activeQueuedChick:Me.activeQueuedChick,selectedObject:Y.selectedObject,selectedTitle:Y.selectedTitle}),uc(),H.updateUI(),Ks(),Lt(),requestAnimationFrame(Gs)}function to(){return a.view?.scale||1}function pn(){a.view||(a.view={x:0,y:0,scale:1}),a.view.scale==null&&(a.view.scale=1)}function no(e){let t=ae.getBoundingClientRect();return{x:(e.clientX-t.left)*ae.width/t.width,y:(e.clientY-t.top)*ae.height/t.height}}function mt(e){let t=no(e),n=to();return{x:(t.x-(a.view?.x||0))/n,y:(t.y-(a.view?.y||0))/n}}function mc(e){let t=to();return{x:e.x*t+(a.view?.x||0),y:e.y*t+(a.view?.y||0)}}function bc(){let e={left:y.x-90,top:y.y-130,right:y.x+y.cols*y.cell+260,bottom:y.y+y.rows*y.cell+220};if(a.phase==="build")for(let t of Ct(a)){let n=Mt(t);e.left=Math.min(e.left,n.x-60),e.top=Math.min(e.top,n.y-80),e.right=Math.max(e.right,n.x+n.w+80),e.bottom=Math.max(e.bottom,n.y+n.h+80)}return e}function Fs(e,t){if(e<=t)return[e,t];let n=(e+t)/2;return[n,n]}function bt(){pn();let e=to(),t=bc(),[n,o]=Fs(ae.width-160-t.right*e,110-t.left*e),[r,s]=Fs(ae.height-150-t.bottom*e,150-t.top*e);a.view.x=on(a.view.x,n,o),a.view.y=on(a.view.y,r,s)}function Us(){pn(),a.view.scale=1;let e=a.eggFarms?.[0],t=e?F(e.col,e.row):{x:y.x,y:y.y};a.view.x=280-t.x,a.view.y=190-t.y,bt()}function vc(e){let t=no(e);pn(),a.pan={start:t,viewX:a.view.x,viewY:a.view.y,moved:!1}}function wc(e){if(!a.pan)return;let t=no(e);Math.hypot(t.x-a.pan.start.x,t.y-a.pan.start.y)>5&&(a.pan.moved=!0),pn(),a.view.x=a.pan.viewX+t.x-a.pan.start.x,a.view.y=a.pan.viewY+t.y-a.pan.start.y,bt()}function Sc(e){e.preventDefault(),pn();let t=no(e),n=mt(e),o=Math.exp(-e.deltaY*.0012),r=on(to()*o,.55,1.8);a.view.scale=r,a.view.x=t.x-n.x*r,a.view.y=t.y-n.y*r,bt(),ot()}function kc(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:{type:e.type,id:e.ref.id}:null}function xc(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:e.ref||null:null}function ot(){B.hoverTooltip&&(B.hoverTooltip.classList.remove("visible"),B.hoverTooltip.setAttribute("aria-hidden","true"),a.hover=null)}function Cc(e,t){if(!B.hoverTooltip||a.phase!=="build"||a.cardTargetPick?.pending||a.groupDrag||a.selectionBox||a.pan)return ot();let n=xc(t);if(!n)return ot();let o=Y.selectedTitle(n),r=Y.flavorText?Y.flavorText(n):"",s=Y.disconnectedWarningFor?Y.disconnectedWarningFor(n):"",l=Y.selectedInfoLines(n).slice(0,7);B.hoverTooltip.innerHTML=`${o}${s?`${s}`:r?`${r}`:""}${l.map(C=>`${C}`).join("")}`;let d=Math.min(window.innerWidth-330,e.clientX+18),v=Math.min(window.innerHeight-220,e.clientY+18);B.hoverTooltip.style.left=`${Math.max(8,d)}px`,B.hoverTooltip.style.top=`${Math.max(8,v)}px`,B.hoverTooltip.classList.add("visible"),B.hoverTooltip.setAttribute("aria-hidden","false"),a.hover={type:t.type,id:t.oldKey||t.ref?.id||null}}function Mc(e){if(a.phase!=="build")return ot();Cc(e,Y.equipmentAtPoint(mt(e)))}function Ws(e){ot();let t=mt(e),n=Y.equipmentAtPoint(t),o=kc(n);if(!o){a.selected=null,a.multiSelected=[],H.updatePanels();return}a.selected=o,a.multiSelected=[o],H.updatePanels();let r=Y.selectedObject();r?.type==="scanner"&&r.kind==="manual"&&Y.showManualScannerMenu(r),r?.type==="scanner"&&r.kind==="auto"&&Y.showAutoScannerMenu(r)}function Xt(){a.buildTool=null,a.selected=null,a.multiSelected=[],a.selectionBox=null,a.cardTargetPick?.mode==="autoScannerMenu"&&(a.cardTargetPick=null),H.hideModal(),ot(),H.updatePanels(),H.updateUI()}function Bs(e){return String(e).replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function gc(e){let t=e?.queue?.[0];return t==null?null:a.chicks.find(n=>n.id===t)||null}function Tc(e){if(!e)return'WAIT';let t=e.sex==="poop"?"\u{1F4A9} POOP":e.sex==="male"?"\u2642 MALE":"\u2640 FEMALE";return`${t}`}function Ec(e,t){let n=new Set(a.eggFarms.map(P=>I(P.col,P.row))),o=new Map(a.scanners.map(P=>[I(P.col,P.row),P])),r=Pe(e,"inputA"),s=r?I(r.col,r.row):null,l=new Set(Object.values(a.facilities||{}).map(P=>P.entry?I(P.entry.col,P.entry.row):null).filter(Boolean)),d=t?.sex||"",v=d==="poop"?"\u{1F4A9}":d==="male"?"\u2642":d==="female"?"\u2640":"",C=[];for(let P=e.row-2;P<=e.row+2;P+=1)for(let R=e.col-2;R<=e.col+2;R+=1){let L=I(R,P),V=["mini-cell"],te="";R===e.col&&P===e.row?(V.push("scanner"),d&&V.push(d),te=v||"S"):L===s?(V.push("input"),te="IN"):n.has(L)?(V.push("egg"),te="E"):o.has(L)?(V.push("scanner-other"),te="S"):l.has(L)?(V.push("port"),te="P"):a.conveyorTiles.has(L)?(V.push("belt"),te="\u2022"):a.blockedCells?.has?.(L)&&(V.push("blocked"),te="\xD7"),C.push(`${te}`)}return`
${C.join("")}
`}function Pc(e){let t=mc(F(e.col,e.row)),n=76;return t.x<-n||t.y<-n||t.x>ae.width+n||t.y>ae.height+n}function Ks(){if(!B.manualScannerMonitor)return;if(a.phase!=="running"){B.manualScannerMonitor.classList.remove("visible"),B.manualScannerMonitor.innerHTML="";return}let e=a.scanners.filter(t=>t.kind==="manual"&&Pc(t));if(!e.length){B.manualScannerMonitor.classList.remove("visible"),B.manualScannerMonitor.innerHTML="";return}B.manualScannerMonitor.innerHTML=e.map(t=>{let n=gc(t),o=t.keys?.left?.label||(t.slot===0?"A":"Left"),r=t.keys?.right?.label||(t.slot===0?"D":"Right"),s=t.role===0?"MIXER":"WASTE",l=t.role===0?"S2":"TRUCK",d=n?"":" disabled";return` -
-
S${(t.slot??0)+1}OFFSCREEN / Q:${t.queue.length}
-
- IN${Tc(n)}SCANNER -
- ${Ec(t,n)} -
- - -
-
`}).join(""),B.manualScannerMonitor.classList.add("visible")}B.manualScannerMonitor?.addEventListener("click",e=>{let t=e.target.closest("button[data-scanner-id]");if(!t||t.disabled)return;let n=a.scanners.find(o=>o.id===Number(t.dataset.scannerId));n&&(Me.sortScanner(n,t.dataset.side),Ks())});ae.addEventListener("contextmenu",e=>e.preventDefault());ae.addEventListener("wheel",Sc,{passive:!1});ae.addEventListener("pointerdown",e=>{if(a.phase!=="build")return;ae.setPointerCapture(e.pointerId);let t=mt(e);if(e.button===2){vc(e);return}if(e.button!==0)return;if(a.cardTargetPick?.mode==="autoScannerMenu"){Xt();return}if(a.cardTargetPick?.pending){Qt.chooseTargetAtPoint(t);return}let n=Y.expansionOfferAtPoint?.(t);if(n){Y.buyGridExpansion(n),bt(),H.updatePanels(),H.updateUI();return}if(Y.cycleBranchModeAtPoint?.(t)){H.updatePanels(),H.updateUI();return}let o=We(t.x,t.y),r=Y.equipmentAtPoint(t);if(!a.buildTool&&r?.type==="conveyor"&&o&&Y.cycleSingleConveyorDirection?.(o)){H.updatePanels(),H.updateUI();return}if(a.buildTool==="erase"){if(!Y.equipmentAtPoint(t)){Xt();return}Y.eraseAtPoint(t);return}if(a.buildTool){let s=We(t.x,t.y);if(!s&&!["mixer","trash","truck"].includes(a.buildTool)){Xt();return}if(a.buildTool==="conveyor"||a.buildTool==="boostConveyor"){Y.beginConveyorDrag(s);return}if(Y.equipmentAtPoint(t)){a.buildTool=null,Ws(e);return}Y.buildAtPoint(t);return}Y.startGroupDrag(e)||Y.startSelectionBox(e)});ae.addEventListener("pointermove",e=>{if(a.phase!=="build"){ot();return}Mc(e),a.pan&&e.buttons&2&&wc(e),a.groupDrag&&e.buttons&1&&Y.updateGroupDrag(e),a.selectionBox&&e.buttons&1&&Y.updateSelectionBox(e),(a.buildTool==="conveyor"||a.buildTool==="boostConveyor")&&e.buttons&1&&Y.continueConveyorDrag(We(mt(e).x,mt(e).y)),a.buildTool==="erase"&&e.buttons&1&&Y.eraseAtPoint(mt(e))});ae.addEventListener("pointerup",e=>{a.selectionBox?Y.finishSelectionBox():a.groupDrag&&(a.groupDrag.committed||Ws(e),Y.finishGroupDrag()),e.button===2&&a.pan&&!a.pan.moved&&a.buildTool&&Xt(),(a.buildTool==="conveyor"||a.buildTool==="boostConveyor")&&Y.endConveyorDrag?.(),a.groupDrag=null,a.pan=null;try{ae.releasePointerCapture(e.pointerId)}catch{}});ae.addEventListener("pointerleave",ot);ae.addEventListener("pointercancel",()=>{Y?.endConveyorDrag?.(),a.groupDrag=null,a.selectionBox=null,a.pan=null,ot()});document.addEventListener("pointerdown",e=>{!B.modal.classList.contains("visible")||!B.modal.classList.contains("equipment-popover")||e.target.closest("#modal .modal-card")||Xt()},!0);B.buttons.s1Left.addEventListener("click",()=>Me.sortSlot(0,"left"));B.buttons.s1Right.addEventListener("click",()=>Me.sortSlot(0,"right"));B.buttons.s2Left.addEventListener("click",()=>Me.sortSlot(1,"left"));B.buttons.s2Right.addEventListener("click",()=>Me.sortSlot(1,"right"));B.buttons.nextTurn.addEventListener("click",pc);B.buttons.conveyor.addEventListener("click",()=>Y.setBuildTool("conveyor"));B.buttons.boostConveyor.addEventListener("click",()=>Y.setBuildTool("boostConveyor"));B.buttons.eggFarm.addEventListener("click",()=>Y.setBuildTool("eggFarm"));B.buttons.autoScanner.addEventListener("click",()=>Y.setBuildTool("autoScanner"));B.buttons.manualScanner.addEventListener("click",()=>Y.setBuildTool("manualScanner"));B.buttons.mixer.addEventListener("click",()=>Y.setBuildTool("mixer"));B.buttons.trash.addEventListener("click",()=>Y.setBuildTool("trash"));B.buttons.truck.addEventListener("click",()=>Y.setBuildTool("truck"));B.buttons.erase.addEventListener("click",()=>Y.setBuildTool("erase"));B.hireRepairmanButton?.addEventListener("click",yc);B.debug.setDay?.addEventListener("click",sc);B.debug.zeroTimer?.addEventListener("click",lc);B.debug.grantCard?.addEventListener("click",ac);B.debug.grantAllCards?.addEventListener("click",cc);B.buttons.undo.addEventListener("click",()=>{No(a)&&(bt(),H.updatePanels(),H.updateUI(),Bt())});B.buttons.redo.addEventListener("click",()=>{_o(a)&&(bt(),H.updatePanels(),H.updateUI(),Bt())});function Ls(e,t,n){let o=e.keys?.[t];return o?o.code&&n.code===o.code||o.key&&n.key.toLowerCase()===o.key:!1}window.addEventListener("keydown",e=>{if(e.repeat)return;let t=e.key.toLowerCase();if(a.phase==="running")for(let n of a.scanners.filter(o=>o.kind==="manual")){if(Ls(n,"left",e)){e.preventDefault(),Me.sortScanner(n,"left");return}if(Ls(n,"right",e)){e.preventDefault(),Me.sortScanner(n,"right");return}}a.phase==="build"&&(e.ctrlKey||e.metaKey)&&t==="z"&&(e.preventDefault(),No(a)&&(bt(),H.updatePanels(),H.updateUI())),a.phase==="build"&&(e.ctrlKey||e.metaKey)&&(t==="y"||e.shiftKey&&t==="z")&&(e.preventDefault(),_o(a)&&(bt(),H.updatePanels(),H.updateUI())),e.key==="Escape"&&a.cardTargetPick?.pending&&(e.preventDefault(),a.cardTargetPick.mode==="autoScannerMenu"?Xt():Qt.cancelTargetPick())});Y=Ts({game:a,ui:B,canvas:ae,canvasPoint:mt,onUpdatePanels:()=>H?.updatePanels()});Me=Is({game:a,currentConveyorSpeed:dc,onGameOverCheck:()=>H?.checkGameOver()});Qt=ds({game:a,ui:B,onUpdatePanels:()=>H?.updatePanels()});H=Es({game:a,ui:B,build:Y,startGame:fc,beginCardDraft:()=>Qt.showDraft(),activeQueuedChick:Me.activeQueuedChick});oc();ic();xo(a);me(a);Me.updateCongestion();H.updatePanels();H.updateUI();H.showTitle();Lt();requestAnimationFrame(Gs); +import '../src/game.js'; diff --git a/index.html b/index.html index ee5d73e..905b0d5 100644 --- a/index.html +++ b/index.html @@ -6,13 +6,13 @@ - Chick Sorter v27.19 — Land and UI Patch - + Chick Sorter v27.20 — Card and Expansion Patch +
-
-
v27.19 VERIFIED
+
+
v27.20 VERIFIED
@@ -40,7 +40,7 @@
-

CHICK SORTER v27.19

+

CHICK SORTER v27.20

Build, expand, connect at least one valid EGG route, then start the next day.

@@ -110,6 +110,6 @@
- + diff --git a/package-lock.json b/package-lock.json index 8035d10..f368279 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "zunda-shiwake", - "version": "27.19.0", + "version": "27.20.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "zunda-shiwake", - "version": "27.19.0", + "version": "27.20.0", "devDependencies": { "esbuild": "^0.25.0" } diff --git a/package.json b/package.json index 8ff31e7..d948287 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { "name": "zunda-shiwake", - "version": "27.19.0", + "version": "27.20.0", "private": true, "type": "module", "scripts": { "clean": "node -e \"require('fs').rmSync('dist', { recursive: true, force: true })\"", - "build": "npm run clean && node -e \"require('fs').copyFileSync('styles.css', 'styles-v27.19.css')\" && esbuild src/game.js --bundle --format=esm --target=es2020 --minify --outfile=dist/game-v27.19.js" + "build": "npm run clean && esbuild src/game.js --bundle --format=esm --target=es2020 --minify --outfile=dist/game.js" }, "devDependencies": { "esbuild": "^0.25.0" diff --git a/src/core/balance.js b/src/core/balance.js index 58adddb..5713af2 100644 --- a/src/core/balance.js +++ b/src/core/balance.js @@ -1,7 +1,7 @@ // Central balance sheet for tuning gameplay. // Edit this file first when adjusting prices, income, penalties, timing, card rates, or caps. export const BALANCE = { - version: 'v27.19 LAND + UI PATCH', + version: 'v27.20 CARD + EXPANSION PATCH', time: { daySeconds: 60, farmShutdownGraceSeconds: 10 @@ -24,9 +24,9 @@ export const BALANCE = { } }, map: { - blockedRatio: 0.03, - blockedExpansionIncrement: 0.005, - blockedRatioMax: 0.10 + blockedRatio: 0.00, + blockedExpansionIncrement: 0.0075, + blockedRatioMax: 0.12 }, economy: { income: { @@ -253,7 +253,7 @@ export const BALANCE = { rarity: 'rare', type: 'cellAction', target: 'blockedCell', - description: 'Choose and remove up to 3 unbuildable cells.', + description: 'Choose and remove up to 10 unbuildable cells.', tags: ['RISK', 'RARE', 'ONE-SHOT'] }, { diff --git a/src/core/gridExpansion.js b/src/core/gridExpansion.js index 83e040d..b52f328 100644 --- a/src/core/gridExpansion.js +++ b/src/core/gridExpansion.js @@ -25,7 +25,7 @@ export function resetOwnedCells(game) { game.ownedChunks = new Set(); game.gridChunkOriginY = 0; game.gridExpansionPurchases = 0; - game.gridExpansionPurchasesByDirection = { right: 0, up: 0 }; + game.gridExpansionPurchasesByDirection = { right: 0, up: 0, down: 0 }; for (let chunkY = 0; chunkY < INITIAL_CHUNKS_Y; chunkY += 1) { for (let chunkX = 0; chunkX < INITIAL_CHUNKS_X; chunkX += 1) game.ownedChunks.add(chunkKey(chunkX, chunkY)); } @@ -83,15 +83,17 @@ export function expansionLots(game) { const { chunkX, chunkY } = parseChunkKey(k); const right = { chunkX: chunkX + 1, chunkY, direction: 'right' }; const up = { chunkX, chunkY: chunkY - 1, direction: 'up' }; - for (const candidate of [right, up]) { - if (candidate.chunkX < 0 || candidate.chunkY > 0) continue; + const down = { chunkX, chunkY: chunkY + 1, direction: 'down' }; + for (const candidate of [right, up, down]) { + if (candidate.chunkX < 0) continue; const ck = chunkKey(candidate.chunkX, candidate.chunkY); if (owned.has(ck) || candidates.has(ck)) continue; candidates.set(ck, lotFromChunk(game, candidate.chunkX, candidate.chunkY, candidate.direction)); } } + const directionOrder = { right: 0, up: 1, down: 2 }; return [...candidates.values()].sort((a, b) => { - const dir = (a.direction === b.direction) ? 0 : (a.direction === 'right' ? -1 : 1); + const dir = (directionOrder[a.direction] ?? 9) - (directionOrder[b.direction] ?? 9); if (dir) return dir; if (a.chunkY !== b.chunkY) return a.chunkY - b.chunkY; return a.chunkX - b.chunkX; diff --git a/src/core/mapGen.js b/src/core/mapGen.js index dde8d4f..758f913 100644 --- a/src/core/mapGen.js +++ b/src/core/mapGen.js @@ -21,7 +21,7 @@ function mulberry32(seed) { } -export function blockedRatioForExpansionPurchase(purchaseCount, { base = 0.03, increment = 0.005, max = 0.10 } = {}) { +export function blockedRatioForExpansionPurchase(purchaseCount, { base = 0.00, increment = 0.0075, max = 0.12 } = {}) { const count = Math.max(0, Math.floor(Number(purchaseCount) || 0)); return Number(Math.min(max, base + count * increment).toFixed(6)); } diff --git a/src/game.js b/src/game.js index 254230d..6915b84 100644 --- a/src/game.js +++ b/src/game.js @@ -122,7 +122,7 @@ function refreshDebugTargetSelect() { } const auto = document.createElement('option'); auto.value = '__auto__'; - auto.textContent = card?.id === 'dynamite' ? 'Auto: first 3 blocked cells' : 'Auto: first valid target'; + auto.textContent = card?.id === 'dynamite' ? 'Auto: first 10 blocked cells' : 'Auto: first valid target'; ui.debug.targetSelect.appendChild(auto); for (const target of targets) { const option = document.createElement('option'); diff --git a/src/render/draw.js b/src/render/draw.js index dd7c62b..343ccd4 100644 --- a/src/render/draw.js +++ b/src/render/draw.js @@ -150,15 +150,15 @@ function floorCellHash(col, row) { } function drawFloorSlime(ctx, x, y, col, row) { const h = floorCellHash(col, row); - // Sparse, deterministic splashes: about 3% of owned floor cells. - if (h % 31 !== 0) return; + // Sparse, deterministic splashes: roughly 1.5% of owned floor cells. + if (h % 67 !== 0) return; const ox = 10 + ((h >>> 4) % Math.max(1, GRID.cell - 22)); const oy = 10 + ((h >>> 9) % Math.max(1, GRID.cell - 22)); const angle = ((h >>> 14) % 16) * Math.PI / 16; ctx.save(); - ctx.globalAlpha = 0.46; - ctx.fillStyle = '#4d9638'; - ctx.strokeStyle = 'rgba(30,66,27,.48)'; + ctx.globalAlpha = 0.38; + ctx.fillStyle = '#4a8d37'; + ctx.strokeStyle = 'rgba(30,66,27,.34)'; ctx.lineWidth = 1; // Small irregular core rather than a large puddle. @@ -175,16 +175,16 @@ function drawFloorSlime(ctx, x, y, col, row) { ctx.stroke(); // Several separated droplets produce a splattered silhouette. - const droplets = 3 + ((h >>> 24) % 4); + const droplets = 4 + ((h >>> 24) % 5); for (let i = 0; i < droplets; i += 1) { const a = angle + i * 2.17 + ((h >>> (i + 8)) & 3) * .18; - const dist = 8 + ((h >>> (i + 11)) & 7); - const radius = 1.1 + ((h >>> (i + 17)) & 3) * .45; + const dist = 10 + ((h >>> (i + 11)) & 10); + const radius = 0.9 + ((h >>> (i + 17)) & 3) * .35; ctx.beginPath(); ctx.arc(x + ox + Math.cos(a) * dist, y + oy + Math.sin(a) * dist * .72, radius, 0, Math.PI * 2); ctx.fill(); } - ctx.fillStyle = 'rgba(151,218,101,.40)'; + ctx.fillStyle = 'rgba(151,218,101,.26)'; ctx.beginPath(); ctx.arc(x + ox - 2, y + oy - 2, 1.7, 0, Math.PI * 2); ctx.fill(); @@ -248,36 +248,32 @@ function drawGrid(ctx, game) { const c = cellCenter(p.col, p.row); const x = c.x - GRID.cell / 2; const y = c.y - GRID.cell / 2; - // Muted floor-level hazard striping. It remains readable without dominating machines. + // Muted floor-level warning striping that sits close to the floor tone range. ctx.save(); ctx.beginPath(); ctx.rect(Math.round(x + 1), Math.round(y + 1), GRID.cell - 2, GRID.cell - 2); ctx.clip(); - ctx.fillStyle = 'rgba(42,45,48,.42)'; + ctx.fillStyle = 'rgba(70,72,76,.16)'; ctx.fillRect(Math.round(x), Math.round(y), GRID.cell, GRID.cell); - ctx.lineWidth = 8; - ctx.strokeStyle = 'rgba(196,163,79,.38)'; - for (let stripe = -GRID.cell; stripe < GRID.cell * 2; stripe += 16) { + ctx.lineWidth = 6; + ctx.strokeStyle = 'rgba(165,145,73,.24)'; + for (let stripe = -GRID.cell; stripe < GRID.cell * 2; stripe += 14) { ctx.beginPath(); ctx.moveTo(x + stripe, y + GRID.cell); ctx.lineTo(x + stripe + GRID.cell, y); ctx.stroke(); } - ctx.lineWidth = 8; - ctx.strokeStyle = 'rgba(20,23,26,.32)'; - for (let stripe = -GRID.cell + 8; stripe < GRID.cell * 2; stripe += 16) { + ctx.strokeStyle = 'rgba(27,29,33,.22)'; + for (let stripe = -GRID.cell + 7; stripe < GRID.cell * 2; stripe += 14) { ctx.beginPath(); ctx.moveTo(x + stripe, y + GRID.cell); ctx.lineTo(x + stripe + GRID.cell, y); ctx.stroke(); } ctx.restore(); - ctx.strokeStyle = 'rgba(17,19,22,.72)'; - ctx.lineWidth = 2; - ctx.strokeRect(Math.round(x) + 1, Math.round(y) + 1, GRID.cell - 2, GRID.cell - 2); - ctx.strokeStyle = 'rgba(224,194,112,.24)'; + ctx.strokeStyle = 'rgba(20,23,26,.42)'; ctx.lineWidth = 1; - ctx.strokeRect(Math.round(x) + 4, Math.round(y) + 4, GRID.cell - 8, GRID.cell - 8); + ctx.strokeRect(Math.round(x) + 1.5, Math.round(y) + 1.5, GRID.cell - 3, GRID.cell - 3); } ctx.restore(); } @@ -304,7 +300,8 @@ function drawExpansionOffers(ctx, game) { ctx.fillStyle = affordable ? THEME.green : THEME.danger; ctx.font = '900 16px ui-monospace, monospace'; ctx.textAlign = 'center'; - ctx.fillText(lot.direction === 'right' ? 'BUY RIGHT LOT' : 'BUY UPPER LOT', cx, cy - 12); + const lotLabel = lot.direction === 'right' ? 'BUY RIGHT LOT' : (lot.direction === 'down' ? 'BUY LOWER LOT' : 'BUY UPPER LOT'); + ctx.fillText(lotLabel, cx, cy - 12); ctx.fillStyle = THEME.ink; ctx.font = '900 16px ui-monospace, monospace'; ctx.fillText(`${yen(cost)} / 10×10`, cx, cy + 15); @@ -663,27 +660,47 @@ function drawEggFarms(ctx, game) { for (const farm of game.eggFarms) drawEggFarm function drawEggFarm(ctx, farm, game) { const c = cellCenter(farm.col, farm.row); ctx.save(); - if (drawImageIfLoaded(ctx, assets.eggFarm, c.x - 29, c.y - 29, 58, 58)) { - drawDirtOverlay(ctx, c.x - 29, c.y - 29, 58, 58, farm); - const outlets = 1 + Math.max(0, Number(farm.extraEggOutlet) || 0); - ctx.fillStyle = 'rgba(255,255,255,.92)'; ctx.strokeStyle = THEME.ink; ctx.lineWidth = 2; - rect(ctx, c.x + 9, c.y + 12, 30, 18, true, true); - ctx.fillStyle = THEME.ink; ctx.font = '900 10px ui-monospace, monospace'; ctx.textAlign = 'center'; ctx.fillText(`O${outlets}`, c.x + 24, c.y + 24); - drawSelection(ctx, game, 'eggFarm', farm.id, c.x, c.y, 68, 68); - ctx.restore(); return; + ctx.fillStyle = '#5a6470'; + ctx.strokeStyle = THEME.ink; + ctx.lineWidth = 3; + rect(ctx, c.x - 27, c.y - 27, 54, 54, true, true); + ctx.fillStyle = '#6f5130'; + ctx.strokeStyle = '#2f2112'; + ctx.lineWidth = 3; + ctx.beginPath(); + ctx.ellipse(c.x, c.y + 3, 19, 12, 0, 0, Math.PI * 2); + ctx.fill(); + ctx.stroke(); + ctx.strokeStyle = '#a77b4b'; + ctx.lineWidth = 2; + for (let i = -16; i <= 16; i += 6) { + ctx.beginPath(); + ctx.moveTo(c.x - 18, c.y + i * 0.1); + ctx.quadraticCurveTo(c.x + i, c.y - 10 + Math.abs(i) * 0.2, c.x + 18, c.y + i * 0.08); + ctx.stroke(); + } + const eggs = [{ x: -8, y: 1 }, { x: 0, y: -3 }, { x: 8, y: 2 }]; + for (const egg of eggs) { + ctx.fillStyle = '#e8e2cf'; + ctx.strokeStyle = '#8d8475'; + ctx.lineWidth = 1.5; + ctx.beginPath(); + ctx.ellipse(c.x + egg.x, c.y + egg.y, 4.8, 6.2, 0.2, 0, Math.PI * 2); + ctx.fill(); + ctx.stroke(); } - ctx.fillStyle = THEME.white; ctx.strokeStyle = THEME.ink; ctx.lineWidth = 4; - rect(ctx, c.x - 28, c.y - 28, 56, 56, true, true); - ctx.fillStyle = THEME.green; ctx.font = '900 19px ui-monospace, monospace'; ctx.textAlign = 'center'; ctx.fillText('EGG', c.x, c.y - 4); const outlets = 1 + Math.max(0, Number(farm.extraEggOutlet) || 0); - ctx.font = '900 11px ui-monospace, monospace'; ctx.fillStyle = THEME.ink; ctx.fillText(`L${farm.level} O${outlets}`, c.x, c.y + 13); ctx.fillText(`${farm.nextSpawn.toFixed(1)}s`, c.x, c.y + 26); + ctx.fillStyle = 'rgba(255,255,255,.92)'; ctx.strokeStyle = THEME.ink; ctx.lineWidth = 2; + rect(ctx, c.x + 8, c.y + 11, 30, 18, true, true); + ctx.fillStyle = THEME.ink; ctx.font = '900 10px ui-monospace, monospace'; ctx.textAlign = 'center'; ctx.fillText(`O${outlets}`, c.x + 23, c.y + 23); + ctx.fillStyle = '#d5e35a'; ctx.font = '900 9px ui-monospace, monospace'; ctx.fillText(`L${farm.level}`, c.x - 13, c.y - 15); const shutter = Math.max(0, Math.min(1, farm.shutterProgress || 0)); if (shutter > 0) { - const h = 56 * shutter; - ctx.fillStyle = THEME.ink; - rect(ctx, c.x - 28, c.y - 28, 56, h, true, false); - ctx.strokeStyle = THEME.white; ctx.lineWidth = 2; - for (let yy = c.y - 24; yy < c.y - 28 + h; yy += 8) { ctx.beginPath(); ctx.moveTo(c.x - 24, yy); ctx.lineTo(c.x + 24, yy); ctx.stroke(); } + const h = 54 * shutter; + ctx.fillStyle = 'rgba(10,12,15,.86)'; + rect(ctx, c.x - 27, c.y - 27, 54, h, true, false); + ctx.strokeStyle = 'rgba(230,237,242,.64)'; ctx.lineWidth = 2; + for (let yy = c.y - 23; yy < c.y - 27 + h; yy += 8) { ctx.beginPath(); ctx.moveTo(c.x - 23, yy); ctx.lineTo(c.x + 23, yy); ctx.stroke(); } if (shutter >= 1) { ctx.fillStyle = THEME.white; ctx.font = '900 12px ui-monospace, monospace'; ctx.fillText('SHUT', c.x, c.y + 4); } } drawDirtOverlay(ctx, c.x - 28, c.y - 28, 56, 56, farm); @@ -952,11 +969,16 @@ function drawMixer(ctx, game, m = game.facilities.mixer) { ctx.fillText(`MIXER L${m.level}`, m.x + 14, m.y + 18); ctx.fillStyle = THEME.muted; ctx.font = '900 10px ui-monospace, monospace'; ctx.fillText(`PAY ${yen(upgradedMixerPrice(game))}`, m.x + 14, m.y + 34); - const drew = drawFacilityTexture(ctx, assets.mixerCompact.loaded ? assets.mixerCompact : assets.mixer, m, 2.05); - if (!drew) { - ctx.strokeStyle = THEME.green; ctx.lineWidth = 5; - for (let i = 0; i < 3; i += 1) { ctx.beginPath(); ctx.arc(m.x + m.w / 2, m.y + m.h / 2 + 6, 11 + i * 8, 0, Math.PI * 1.5); ctx.stroke(); } - } + ctx.fillStyle = '#1a2028'; ctx.strokeStyle = '#87bfff'; ctx.lineWidth = 4; + rect(ctx, m.x + 44, m.y + 34, 76, 50, true, true); + ctx.strokeStyle = '#4aa3ff'; ctx.lineWidth = 3; + ctx.beginPath(); ctx.arc(m.x + 82, m.y + 58, 15, 0, Math.PI * 2); ctx.stroke(); + ctx.beginPath(); ctx.moveTo(m.x + 82, m.y + 43); ctx.lineTo(m.x + 82, m.y + 73); ctx.stroke(); + ctx.beginPath(); ctx.moveTo(m.x + 69, m.y + 56); ctx.lineTo(m.x + 95, m.y + 60); ctx.stroke(); + ctx.fillStyle = '#59687a'; ctx.strokeStyle = '#0d1014'; + rect(ctx, m.x + 56, m.y + 24, 12, 10, true, true); + rect(ctx, m.x + 96, m.y + 24, 12, 10, true, true); + ctx.fillStyle = '#7ea9dc'; ctx.fillRect(m.x + 48, m.y + 42, 68, 5); drawTargetBadge(ctx, m.x + 14, m.y + m.h - 40, m.w - 28, 'SEND MALE', 'male', 'safe meat route'); drawDirtOverlay(ctx, m.x, m.y, m.w, m.h, m); drawSelection(ctx, game, 'facility', m.id, m.x + m.w / 2, m.y + m.h / 2, m.w + 12, m.h + 12); @@ -969,11 +991,23 @@ function drawTrash(ctx, game, t = game.facilities.trash) { drawFacilityDetails(ctx, t, THEME.wasteGreen); ctx.fillStyle = THEME.white; ctx.font = '900 14px ui-monospace, monospace'; ctx.textAlign = 'left'; ctx.fillText(`SHREDDER L${t.level}`, t.x + 14, t.y + 18); - const drew = drawFacilityTexture(ctx, assets.shredderCompact.loaded ? assets.shredderCompact : assets.shredder, t, 1.85); - if (!drew) { - ctx.fillStyle = '#0a0b0e'; - for (let i = 0; i < 7; i += 1) ctx.fillRect(t.x + 40 + i * 12, t.y + 42, 6, Math.max(20, t.h - 72)); + ctx.fillStyle = '#181d20'; ctx.strokeStyle = '#9fd473'; ctx.lineWidth = 4; + rect(ctx, t.x + 38, t.y + 36, 92, 22, true, true); + ctx.fillStyle = '#262d30'; ctx.strokeStyle = '#0d1014'; + rect(ctx, t.x + 46, t.y + 58, 76, 18, true, true); + ctx.fillStyle = '#111418'; + for (let i = 0; i < 7; i += 1) { + const tx = t.x + 51 + i * 10; + ctx.beginPath(); + ctx.moveTo(tx, t.y + 58); + ctx.lineTo(tx + 5, t.y + 68); + ctx.lineTo(tx + 10, t.y + 58); + ctx.closePath(); + ctx.fill(); } + ctx.fillStyle = '#6f7e8d'; + rect(ctx, t.x + 54, t.y + 27, 16, 9, true, true); + rect(ctx, t.x + 98, t.y + 27, 16, 9, true, true); drawTargetBadge(ctx, t.x + 14, t.y + t.h - 42, t.w - 28, 'SEND POOP', 'poop', 'shredder'); drawDirtOverlay(ctx, t.x, t.y, t.w, t.h, t); drawSelection(ctx, game, 'facility', t.id, t.x + t.w / 2, t.y + t.h / 2, t.w + 12, t.h + 12); diff --git a/src/systems/buildSystem.js b/src/systems/buildSystem.js index 6a94566..403f2a3 100644 --- a/src/systems/buildSystem.js +++ b/src/systems/buildSystem.js @@ -61,7 +61,7 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel function resolveExpansionRequest(request = 'right') { if (request && typeof request === 'object' && Number.isFinite(request.chunkX) && Number.isFinite(request.chunkY)) return request; - const direction = ['right', 'up'].includes(request) ? request : 'right'; + const direction = ['right', 'up', 'down'].includes(request) ? request : 'right'; return expansionLot(game, direction); } @@ -78,7 +78,7 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel } record(game); spendCash(game, cost); - if (!game.gridExpansionPurchasesByDirection) game.gridExpansionPurchasesByDirection = { right: 0, up: 0 }; + if (!game.gridExpansionPurchasesByDirection) game.gridExpansionPurchasesByDirection = { right: 0, up: 0, down: 0 }; const originY = game.gridChunkOriginY || 0; if (offer.chunkY < originY) { const chunksToAdd = originY - offer.chunkY; @@ -93,9 +93,9 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel game.gridExpansionPurchasesByDirection[direction] = (game.gridExpansionPurchasesByDirection[direction] || 0) + 1; syncGridSizeToGame(); const blockedRatio = blockedRatioForExpansionPurchase(game.gridExpansionPurchases, { - base: BALANCE.map.blockedRatio ?? 0.03, - increment: BALANCE.map.blockedExpansionIncrement ?? 0.005, - max: BALANCE.map.blockedRatioMax ?? 0.10 + base: BALANCE.map.blockedRatio ?? 0.00, + increment: BALANCE.map.blockedExpansionIncrement ?? 0.0075, + max: BALANCE.map.blockedRatioMax ?? 0.12 }); const blocked = generateBlockedCellsInRect({ seed: `${game.runSeed}:grid-expansion:${lot.chunkX},${lot.chunkY}:${game.gridExpansionPurchases}`, diff --git a/src/systems/cards.js b/src/systems/cards.js index 098cfb0..fc36b60 100644 --- a/src/systems/cards.js +++ b/src/systems/cards.js @@ -119,7 +119,7 @@ export function debugGrantCard(game, cardOrId, options = {}) { .map(String)); const selected = requestedKeys.size ? targets.filter(t => requestedKeys.has(targetKey(t))) - : targets.slice(0, 3); + : targets.slice(0, 10); if (!selected.length) return { ok: false, reason: `Selected target is no longer valid for ${card.title}.` }; for (const target of selected.slice(0, 3)) { game.blockedCells.delete(key(target.col, target.row)); @@ -129,7 +129,7 @@ export function debugGrantCard(game, cardOrId, options = {}) { sparkBurst(game, c.x, c.y, 8, THEME.warn); } refreshRoutingAfterEdit(game); - return { ok: true, reason: `${card.title} removed ${Math.min(3, selected.length)} blocked cell(s).` }; + return { ok: true, reason: `${card.title} removed ${Math.min(10, selected.length)} blocked cell(s).` }; } return { ok: false, reason: `${card.title} cannot be debug-granted.` }; } @@ -507,7 +507,7 @@ function cardDescription(game, card) { if (card.id === 'newMachine') return 'Cancel Used Machines. Future equipment returns to normal price, refund, and durability.'; if (card.id === 'laborExploitation') return 'Repairman dispatch paperwork is streamlined. Repair rooms keep operating; one time only.'; if (card.id === 'rescueLoan') return `At day-end bankruptcy check, gain ${yen(500)} if cash is below ${yen(0)}. Held: ${e.rescueLoanCharges || 0}.`; - if (card.id === 'dynamite') return 'Choose any blocked tiles on the map and destroy up to 3. Empty-space clicks are ignored; press Esc to finish after at least one blast.'; + if (card.id === 'dynamite') return 'Choose any blocked tiles on the map and destroy up to 10. Empty-space clicks are ignored; press Esc to finish after at least one blast.'; return card.description; } @@ -610,7 +610,7 @@ export function createCardSystem({ game, ui, onUpdatePanels }) { cardId: card.id, mode: card.target === 'blockedCell' ? 'blockedCell' : 'equipment', targetKeys: targets.map(targetKey), - remaining: card.id === 'dynamite' ? Math.min(3, targets.length) : 1, + remaining: card.id === 'dynamite' ? Math.min(10, targets.length) : 1, used: 0 }; ui.modal.classList.remove('visible', 'equipment-popover'); @@ -721,8 +721,10 @@ export function createCardSystem({ game, ui, onUpdatePanels }) { function cardIconHtml(card) { const icon = cardIconFor(card); - if (icon.type === 'image') return `
${icon.alt || ''}
`; - return ``; + if (icon.type === 'image') { + return `
${icon.alt || ''}
`; + } + return ``; } function cardButton(card, index) { diff --git a/src/systems/contracts.js b/src/systems/contracts.js deleted file mode 100644 index 2920238..0000000 --- a/src/systems/contracts.js +++ /dev/null @@ -1,143 +0,0 @@ -import { TURN_SECONDS, POOP_RATE, CONTRACT_EVENT_CHANCE, CONTRACT_EVENT_FIRST_TURN } from '../core/config.js'; -import { getSpawnRange } from '../core/state.js'; -import { applyRevenue } from './economy.js'; - -const CONTRACT_TARGETS = [ - { - target: 'female', - title: 'Premium Female Shipment', - route: 'Female -> Truck', - note: 'Only female chicks are valid truck cargo this turn.' - }, - { - target: 'male', - title: 'Male Export Trial', - route: 'Male -> Truck', - note: 'Male chicks are temporarily valid truck cargo. Male truck fines are suspended for valid male cargo.' - }, - { - target: 'poop', - title: 'Contaminant Sample Export', - route: 'Poop -> Truck', - note: 'Poop is temporarily valid truck cargo. Shipped poop does not soil this contract shipment.' - } -]; - -export function factoryValue(game) { - return [ - ...game.eggFarms.map(f => f.price || 0), - ...game.scanners.map(s => s.price || 0), - ...Object.values(game.facilities).map(f => f.price || 0), - ...[...game.conveyorMeta.values()].map(m => m.price || 0) - ].reduce((a, b) => a + b, 0); -} - -export function estimatedChicksPerTurn(game, productionMultiplier = 1) { - return game.eggFarms.reduce((sum, farm) => { - const [min, max] = getSpawnRange(farm); - const avg = Math.max(0.1, (min + max) / 2); - return sum + (TURN_SECONDS / avg) * productionMultiplier; - }, 0); -} - -export function rollContractOffer(game) { - // No irregular events during the first seven running turns. - // Offers created after Turn 7 apply to Turn 8 or later. - const nextTurn = game.turn + 1; - if (nextTurn < CONTRACT_EVENT_FIRST_TURN) return null; - if (Math.random() > CONTRACT_EVENT_CHANCE) return null; - const template = CONTRACT_TARGETS[Math.floor(Math.random() * CONTRACT_TARGETS.length)]; - const productionMultiplier = 2; - const poopMultiplier = 3; - const estimate = estimatedChicksPerTurn(game, productionMultiplier); - const targetAmount = Math.max(1, Math.ceil(estimate * 0.9)); - const rate = Math.round((0.08 + Math.random() * 0.08) * 100) / 100; - const rewardByFactory = Math.floor(factoryValue(game) * rate); - const rewardByCash = Math.floor(Math.max(0, game.cash) * 0.25); - const reward = Math.max(rewardByFactory, rewardByCash); - return { - id: `contract-${game.turn}-${Date.now()}-${Math.floor(Math.random() * 9999)}`, - ...template, - forced: true, - productionMultiplier, - poopMultiplier, - targetAmount, - estimatedOutput: Math.round(estimate), - rewardRate: rate, - reward, - rewardByFactory, - rewardByCash, - createdTurn: game.turn, - oneTurnOnly: true - }; -} - -export function activateAcceptedContract(game) { - // v10.1: limited events are forced. If an event is shown during Build phase, - // it automatically applies to the next turn; there is no accept/skip step. - game.contractActive = game.contractOffer ? { ...game.contractOffer } : null; - game.contractOffer = null; -} - -export function clearActiveContract(game) { - game.contractActive = null; -} - -export function productionMultiplier(game) { - return game.contractActive?.productionMultiplier || 1; -} - -export function currentPoopRate(game) { - const feedCards = Math.max(0, Number(game?.cardEffects?.hatchingFeed) || 0); - const feedMultiplier = Math.pow(1.03, feedCards); - return Math.min(0.95, POOP_RATE * (game.contractActive?.poopMultiplier || 1) * feedMultiplier); -} - -export function truckTarget(game) { - return game.contractActive?.target || 'female'; -} - -export function targetTruckCount(stats, target) { - if (target === 'male') return stats.truckMale || 0; - if (target === 'poop') return stats.poopTruck || 0; - return stats.truckFemale || 0; -} - -export function isTargetTruckCargo(game, sex) { - return truckTarget(game) === sex; -} - -export function shouldFineMaleTruck(game) { - return truckTarget(game) !== 'male'; -} - -export function resolveContract(game) { - const contract = game.contractActive; - if (!contract) return null; - const count = targetTruckCount(game.stats, contract.target); - const success = count >= contract.targetAmount; - const bonus = success ? contract.reward : 0; - if (bonus > 0) { - applyRevenue(game, bonus); - game.stats.contractBonus = bonus; - game.totals.contractBonus += bonus; - game.totals.contractSuccess += 1; - } else { - game.stats.contractBonus = 0; - game.totals.contractFailed += 1; - } - const result = { - title: contract.title, - target: contract.target, - route: contract.route, - targetAmount: contract.targetAmount, - count, - success, - bonus, - reward: contract.reward, - productionMultiplier: contract.productionMultiplier, - poopMultiplier: contract.poopMultiplier - }; - game.stats.contractResult = result; - return result; -} diff --git a/styles-v27.17.css b/styles-v27.17.css deleted file mode 100644 index 1219389..0000000 --- a/styles-v27.17.css +++ /dev/null @@ -1,1130 +0,0 @@ -:root { - --bg: #f2fff0; - --screen: #eefbea; - --panel: rgba(245, 255, 242, 0.96); - --ink: #102015; - --muted: #526456; - --line: #102015; - --green: #22b94f; - --green-soft: #b7f5c6; - --white: #ffffff; - --danger: #c42424; - --shadow: 8px 8px 0 rgba(16, 32, 21, 0.22); -} -* { box-sizing: border-box; } -html, body { min-height: 100%; } -body { margin: 0; background: var(--bg); color: var(--ink); font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; overflow-x: hidden; } -button { font: inherit; } -h1, h2, p { margin: 0; } -#app { width: min(100vw, 1680px); margin: 0 auto; padding: 0 8px 12px; } -.game-shell { position: relative; width: 100%; min-height: min(100vh, 920px); border: 4px solid var(--line); border-top: 0; background: var(--screen); overflow: hidden; box-shadow: var(--shadow); } -#gameCanvas { display: block; width: 100%; height: min(calc(100vh - 10px), 900px); min-height: 720px; background: var(--screen); touch-action: none; } -.hud { position: absolute; z-index: 4; display: grid; gap: 6px; pointer-events: none; } -.hud-top-left { top: 10px; left: 10px; grid-template-columns: repeat(6, minmax(82px, auto)); } -.hud-top-right { top: 10px; right: 10px; grid-template-columns: repeat(4, minmax(78px, auto)); } -.hud-card { min-width: 82px; padding: 7px 9px; border: 3px solid var(--line); background: rgba(255,255,255,.88); box-shadow: 4px 4px 0 rgba(16,32,21,.16); } -.hud-card.primary { min-width: 116px; padding: 10px 12px; background: rgba(255,255,255,.96); } -.hud-card.primary span { font-size: 9px; } -.hud-card.primary strong { font-size: clamp(22px, 2vw, 32px); } -.hud-card.time-critical { background: #fff0d1; box-shadow: inset 0 0 0 4px var(--danger), 4px 4px 0 rgba(16,32,21,.16); } -.hud-card span { display: block; font-size: 9px; letter-spacing: .1em; color: var(--muted); margin-bottom: 4px; } -.hud-card strong { font-size: clamp(15px, 1.3vw, 22px); line-height: 1; color: var(--ink); } -.hud-card.cash strong, .hud-card.profit strong, .hud-card.combo strong, .cash-positive { color: var(--green) !important; } -.cash-negative { color: var(--danger) !important; } - -.priority-strip { position: absolute; z-index: 5; top: 76px; left: 10px; display: grid; grid-template-columns: minmax(280px, 1.2fr) minmax(170px, .75fr) minmax(130px, .55fr); gap: 8px; max-width: calc(100% - 420px); pointer-events: none; } -.priority-strip > div { border: 3px solid var(--line); background: rgba(255,255,255,.94); padding: 8px 10px; font-weight: 900; text-transform: uppercase; box-shadow: 4px 4px 0 rgba(16,32,21,.14); font-size: 12px; letter-spacing: .03em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } -.event-brief.active { background: #fff0d1; box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(16,32,21,.14); } -.event-brief.next { background: var(--green-soft); box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(16,32,21,.14); } -.event-brief.locked { background: #edf3ec; color: var(--muted); } -.target-brief { color: var(--green); } -.speed-brief { color: var(--ink); } - -.build-panel { position: absolute; z-index: 6; top: 118px; right: 12px; bottom: 12px; width: clamp(278px, 23vw, 360px); min-height: 0; padding: 10px; border: 4px solid var(--line); background: var(--panel); box-shadow: var(--shadow); overflow: auto; } -.panel-head { display: grid; gap: 8px; margin-bottom: 10px; } -.panel-head h1 { font-size: 15px; letter-spacing: .06em; } -.panel-head h1 span { font-size: 9px; color: var(--white); background: var(--green); border: 2px solid var(--line); padding: 1px 6px; } -.panel-head p { color: var(--muted); margin-top: 4px; font-size: 9px; line-height: 1.25; } -.panel-grid { display: grid; grid-template-columns: 1fr; gap: 10px; } -.build-panel h2 { font-size: 11px; text-transform: uppercase; letter-spacing: .1em; margin-bottom: 7px; } -.large-tools { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; } -.history-tools { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; grid-column: 1 / -1; } -.tool-button.small { min-height: 40px; padding: 6px; } -.tool-button, .primary-button, .sort-button, .facility-action { border: 3px solid var(--line); background: var(--white); color: var(--ink); font-weight: 900; text-transform: uppercase; cursor: pointer; box-shadow: 4px 4px 0 rgba(16,32,21,.18); } -.tool-button { min-height: 50px; text-align: left; padding: 8px; } -.tool-button strong { display: block; font-size: 12px; } -.tool-button span { display: block; margin-top: 4px; font-size: 9px; color: var(--muted); } -.tool-button.active { background: var(--green-soft); box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(16,32,21,.18); } -.tool-button.danger.active { background: #ffdada; box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(16,32,21,.18); } -.primary-button { padding: 10px 12px; background: var(--green); color: var(--white); white-space: nowrap; } -.primary-button:disabled, .tool-button:disabled, .sort-button:disabled, .facility-action:disabled { opacity: .42; cursor: not-allowed; } -.mini-box { border: 3px solid var(--line); background: var(--white); padding: 12px; line-height: 1.45; color: var(--muted); font-size: 11px; } -.facility-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; } -.facility-action { padding: 7px 9px; font-size: 9px; } -.facility-action.good { background: var(--green-soft); } -.facility-action.warn { background: #fff0d1; } -.facility-action.danger { background: #ffdada; } -.control-dock { position: absolute; z-index: 7; left: 50%; bottom: 12px; transform: translateX(-50%); display: grid; grid-template-columns: repeat(4, 150px); gap: 8px; padding: 7px; border: 3px solid var(--line); background: rgba(255,255,255,.90); } -.sort-button { min-height: 46px; font-size: 12px; } -/* Debug UI is intentionally kept for active balancing builds. Do not remove during cleanup/audit passes unless explicitly requested. */ -.debug-panel { - position: absolute; - z-index: 9; - left: 10px; - bottom: 10px; - width: min(410px, calc(100% - 20px)); - border: 3px solid var(--line); - background: rgba(255,255,255,.96); - box-shadow: 4px 4px 0 rgba(16,32,21,.16); - font-weight: 900; -} -.debug-panel summary { - cursor: pointer; - padding: 5px 8px; - color: var(--danger); - font-size: 14px; - line-height: 1.1; -} -.debug-body { - display: grid; - grid-template-columns: 1fr 92px; - gap: 6px; - padding: 7px; - border-top: 3px solid var(--line); - font-size: 12px; - line-height: 1.15; -} -.debug-body label, -.debug-body button, -.debug-body select, -.debug-body input { - min-width: 0; - font: inherit; -} -.debug-check, -.debug-card, -.debug-target, -.debug-readout { - grid-column: 1 / -1; -} -.debug-row { - display: grid; - grid-template-columns: 1fr 92px; - gap: 6px; - grid-column: 1 / -1; -} -.debug-day { - display: grid; - grid-template-columns: 38px 1fr; - align-items: center; - gap: 4px; -} -.debug-body button { - border: 2px solid var(--line); - background: var(--white); - cursor: pointer; - font-weight: 900; - padding: 5px 6px; - line-height: 1.05; -} -.debug-body input[type="number"], -.debug-body select { - width: 100%; - border: 2px solid var(--line); - background: var(--white); - padding: 4px 5px; - min-height: 29px; -} -.debug-target select:disabled { - opacity: .55; -} -.debug-readout { - border: 2px solid var(--line); - background: #f7fff5; - color: var(--muted); - padding: 5px; - line-height: 1.25; - max-height: 64px; - overflow: auto; -} -.modal { position: fixed; inset: 0; z-index: 20; display: none; align-items: center; justify-content: center; padding: 22px; background: rgba(16,32,21,.45); } -.modal.visible { display: flex; } -.modal-card { width: min(860px, 96vw); border: 4px solid var(--line); padding: 24px; background: var(--white); box-shadow: var(--shadow); } -.modal-card h2 { font-size: 26px; text-transform: uppercase; margin-bottom: 12px; } -.modal-card p { line-height: 1.55; } -.modal-card ul { margin: 12px 0 0; padding-left: 22px; line-height: 1.55; color: var(--muted); } -.modal-actions { margin-top: 18px; display: flex; justify-content: flex-end; gap: 10px; flex-wrap: wrap; } -.route-cards { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; margin: 14px 0; } -.route-card { border: 3px solid var(--line); background: #f7fff5; padding: 14px; display: grid; grid-template-columns: 44px 1fr 28px 1fr; align-items: center; gap: 4px 8px; } -.route-card .route-icon { grid-row: 1 / span 2; font-size: 30px; text-align: center; } -.route-card strong, .route-card em { font-style: normal; font-weight: 900; text-transform: uppercase; } -.route-card b { font-size: 24px; color: var(--green); text-align: center; } -.route-card small { grid-column: 2 / span 3; color: var(--muted); font-weight: 900; } -.result-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin-top: 12px; } -.result-grid div { border: 3px solid var(--line); padding: 10px; background: #f7fff5; } -.result-grid strong { display: block; font-size: 11px; color: var(--muted); text-transform: uppercase; margin-bottom: 6px; } -.result-grid span { font-size: 16px; font-weight: 900; color: var(--ink); } -.game-shell:not(.phase-build) .build-panel { display: none; } -.game-shell.phase-running .hud-top-right { display: none; } -.game-shell:not(.phase-running) .control-dock { display: none; } -@media (max-width: 1180px) { - #app { padding: 0; } - .game-shell { min-height: 100vh; } - #gameCanvas { height: 100vh; } - .hud-top-left, .hud-top-right { grid-template-columns: repeat(2, minmax(76px, auto)); } - .priority-strip { top: 150px; left: 8px; right: 8px; max-width: none; grid-template-columns: 1fr; } - .build-panel { top: auto; left: 8px; right: 8px; bottom: 8px; width: auto; max-height: 42vh; } - .large-tools { grid-template-columns: 1fr 1fr; } - .control-dock { grid-template-columns: repeat(2, 150px); } - .route-cards, .result-grid { grid-template-columns: 1fr; } -} - -.event-card { border: 3px solid var(--line); background: #f7fff5; padding: 12px; line-height: 1.35; color: var(--ink); font-size: 11px; box-shadow: 4px 4px 0 rgba(16,32,21,.14); } -.event-card.empty { color: var(--muted); background: rgba(255,255,255,.72); } -.event-card.empty strong { display: block; color: var(--ink); margin-bottom: 4px; } -.event-card h3 { margin: 2px 0 7px; font-size: 14px; text-transform: uppercase; letter-spacing: .04em; } -.event-card p { margin: 5px 0; } -.event-card.accepted { background: var(--green-soft); box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(16,32,21,.14); } -.event-card.declined { background: #f1f1f1; color: var(--muted); } -.event-status { display: inline-block; padding: 2px 7px; border: 2px solid var(--line); background: var(--white); font-size: 9px; font-weight: 900; letter-spacing: .1em; margin-bottom: 4px; } -.event-metrics { display: grid; grid-template-columns: 1fr; gap: 4px; margin: 8px 0; } -.event-metrics span { display: block; border: 2px solid rgba(16,32,21,.55); background: rgba(255,255,255,.82); padding: 5px; font-weight: 900; color: var(--ink); } -.event-actions { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; } -.result-section-title { margin: 16px 0 8px; font-size: 12px; font-weight: 900; text-transform: uppercase; letter-spacing: .12em; color: var(--green); } -.result-section-title:first-child { margin-top: 0; } -.muted-title { color: var(--muted); border: 3px solid var(--line); padding: 10px; background: #f7fff5; } - -.compact-rules .mini-box { padding: 8px; font-size: 9px; } -.primary-button:disabled { filter: grayscale(1); background: #c9d2ca; color: #526456; } -.formula-box { - border: 3px solid var(--line); - background: #f7fff5; - padding: 10px; - margin: 10px 0; - line-height: 1.5; - color: var(--ink); - font-size: 12px; - font-weight: 700; -} -.equipment-menu-lines { - border: 3px solid var(--line); - background: #ffffff; - padding: 10px; - margin: 8px 0; - color: var(--muted); - line-height: 1.45; -} -.equipment-menu-lines p { margin: 4px 0; } - -/* v11 compact clicked-equipment bubble */ -.modal.equipment-popover { - background: transparent; - align-items: flex-start; - justify-content: flex-start; - padding: 0; - pointer-events: none; -} -.modal.equipment-popover .modal-card { - position: absolute; - left: var(--popover-x, 16px); - top: var(--popover-y, 16px); - width: min(250px, calc(100vw - 24px)); - max-height: min(280px, calc(100vh - 24px)); - overflow: auto; - padding: 8px; - border-width: 3px; - pointer-events: auto; - box-shadow: 6px 6px 0 rgba(16,32,21,.18); -} -.modal.equipment-popover .modal-card h2 { - font-size: 14px; - margin-bottom: 6px; -} -.modal.equipment-popover .modal-actions { - margin-top: 8px; - gap: 6px; - justify-content: flex-start; -} -.modal.equipment-popover .modal-actions button { - padding: 5px 7px; - font-size: 9px; -} -.equipment-menu-lines.compact { - padding: 7px; - margin: 6px 0; - font-size: 9px; -} -.formula-box.compact { - padding: 7px; - margin: 6px 0; - font-size: 9px; -} - -/* v15 pre-build card draft */ -.card-choices { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(190px, 220px)); - justify-content: center; - align-items: stretch; - gap: 10px; - margin-top: 14px; -} -.card-choice { - min-height: 132px; - border: 3px solid var(--line); - background: #f7fff5; - color: var(--ink); - box-shadow: 5px 5px 0 rgba(16,32,21,.16); - padding: 12px; - text-align: left; - cursor: pointer; - font-weight: 900; -} -.card-choice:hover { transform: translate(-1px, -1px); box-shadow: 6px 6px 0 rgba(16,32,21,.18); } -.card-choice strong { display: block; font-size: 14px; text-transform: uppercase; line-height: 1.2; } -.card-choice span { display: inline-block; margin: 8px 0; padding: 2px 7px; border: 2px solid var(--line); background: var(--white); font-size: 9px; letter-spacing: .1em; } -.card-tags { display: flex; flex-wrap: wrap; gap: 4px; margin: 7px 0; } -.card-tags span { margin: 0; padding: 2px 5px; font-size: 8px; line-height: 1.1; letter-spacing: .04em; } -.card-choice small { display: block; color: var(--muted); font-size: 11px; line-height: 1.35; } -.card-choice.rare { background: #fff0d1; box-shadow: inset 0 0 0 3px #f0a020, 5px 5px 0 rgba(16,32,21,.16); } -.card-choice.ultra-rare { background: #ffe6f0; box-shadow: inset 0 0 0 3px #c42424, 5px 5px 0 rgba(16,32,21,.18); } -.card-choice.ultra-rare span { background: #c42424; color: #fff; } -.muted-card-note { color: var(--muted); font-weight: 700; } -.card-targets { display: grid; gap: 8px; margin-top: 14px; } -.card-target-button { border: 3px solid var(--line); background: #f7fff5; padding: 10px 12px; text-align: left; cursor: pointer; font-weight: 900; box-shadow: 4px 4px 0 rgba(16,32,21,.14); } -.card-target-button:hover { background: var(--green-soft); } - -/* v19 readability pass */ -body { font-size: 16px; } -.hud-card span { font-size: 11px; } -.hud-card strong { font-size: clamp(18px, 1.5vw, 25px); } -.priority-strip > div { font-size: 14px; } -.panel-head h1 { font-size: 18px; } -.panel-head p { font-size: 11px; } -.build-panel h2 { font-size: 13px; } -.tool-button strong { font-size: 14px; } -.tool-button span { font-size: 11px; } -.mini-box, .event-card { font-size: 12px; } -.sort-button { font-size: 14px; } -.modal-card h2 { font-size: 29px; } -.card-choice strong { font-size: 16px; } -.card-choice small { font-size: 13px; } - -.tool-button.unaffordable, .tool-button.already-built { opacity: .42; filter: grayscale(.7); } - -.hover-tooltip { - position: fixed; - z-index: 30; - width: min(320px, calc(100vw - 20px)); - display: none; - border: 3px solid var(--line); - background: rgba(255,255,255,.96); - color: var(--ink); - box-shadow: 6px 6px 0 rgba(16,32,21,.18); - padding: 10px; - pointer-events: none; - line-height: 1.35; -} -.hover-tooltip.visible { display: block; } -.hover-tooltip strong { display: block; font-size: 15px; text-transform: uppercase; margin-bottom: 5px; } -.hover-tooltip em { display: block; font-style: normal; color: var(--green); font-weight: 900; margin-bottom: 7px; } -.hover-tooltip em.warning { color: var(--danger); } -.hover-tooltip span { display: block; color: var(--muted); font-size: 12px; } - - -.card-choice.dud { - background: #eeeeee; - color: #777; - filter: grayscale(1); - border-style: dashed; - box-shadow: 5px 5px 0 rgba(16,32,21,.10); -} -.card-choice.dud span { background: #f8f8f8; } -.card-choice.flung { - pointer-events: none; - transform: translate(var(--fling-x, 480px), var(--fling-y, -320px)) rotate(var(--fling-r, 68deg)) scale(.68); - opacity: 0; - transition: transform .34s cubic-bezier(.18,.84,.26,.99), opacity .28s ease-in; -} - - - -.route-card .route-icon.male, -.route-card .route-icon.female, -.route-card .route-icon.poop { - display: inline-grid; - place-items: center; - width: 38px; - height: 38px; - border-radius: 999px; - border: 3px solid var(--line, #102015); - background: var(--white, #fff); - line-height: 1; -} -.route-card .route-icon.male { color: #2477ff; background: #d9ecff; } -.route-card .route-icon.female { color: #d62a85; background: #ffe0f0; } -.route-card .route-icon.poop { color: #7b4a23; background: #fff0d1; font-size: 24px; } -.restart-button { min-width: 160px; } -.restart-fallback-note { margin-top: 12px; color: var(--muted, #526456); font-weight: 700; } - -/* v24.4 hover-only build-button flavor / cashout guidance / compact game-over */ -.tool-button .tool-flavor { - display: block; - max-height: 0; - opacity: 0; - overflow: hidden; - margin-top: 0; - color: var(--muted); - font-size: 8px; - line-height: 1.22; - text-transform: none; - letter-spacing: 0; - transition: max-height .12s ease, opacity .12s ease, margin-top .12s ease; -} -.tool-button:hover .tool-flavor { - max-height: 42px; - opacity: 1; - margin-top: 5px; -} -.large-tools .tool-button { min-height: 58px; } -.large-tools .tool-button:hover { min-height: 78px; } -.history-tools .tool-button.small { min-height: 40px; } -.primary-button.cashout-emphasis, -.tool-button.cashout-emphasis { - opacity: 1 !important; - filter: none !important; - animation: cashoutPulse 0.9s ease-in-out infinite alternate; -} -.primary-button.cashout-emphasis { - box-shadow: inset 0 0 0 4px #fff0d1, 6px 6px 0 rgba(16,32,21,.22); -} -.tool-button.cashout-emphasis { - background: #fff0d1; - box-shadow: inset 0 0 0 3px var(--danger), 6px 6px 0 rgba(16,32,21,.20); -} -@keyframes cashoutPulse { - from { transform: translate(0, 0); } - to { transform: translate(-1px, -1px); } -} -.modal.gameover-modal { padding: 12px; } -.modal.gameover-modal .modal-card { - width: min(640px, 92vw); - max-height: min(82vh, 720px); - overflow: auto; - padding: 16px; -} -.modal.gameover-modal .modal-card h2 { - font-size: 22px; - margin-bottom: 8px; -} -.gameover-reason { font-weight: 900; color: var(--danger); margin-bottom: 8px; } -.settlement-net { - border: 3px solid var(--line); - background: #f7fff5; - padding: 10px 12px; - margin-bottom: 10px; - display: flex; - justify-content: space-between; - align-items: center; - gap: 12px; - font-weight: 900; - text-transform: uppercase; -} -.settlement-net strong { font-size: 24px; } -.settlement-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; } -.settlement-grid div { padding: 8px; } -.settlement-grid span { display: block; font-size: 14px; } -.gameover-summary { - grid-template-columns: repeat(4, minmax(0, 1fr)); - gap: 6px; - margin-top: 8px; -} -.gameover-breakdown { - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 6px; - margin-top: 8px; -} -.modal.gameover-modal .result-grid div { padding: 7px; } -.modal.gameover-modal .result-grid strong { font-size: 9px; margin-bottom: 3px; } -.modal.gameover-modal .result-grid span { font-size: 12px; } -.gameover-details { - margin-top: 10px; - border: 3px solid var(--line); - background: #f7fff5; - padding: 8px; -} -.gameover-details summary { - cursor: pointer; - font-weight: 900; - text-transform: uppercase; -} -.modal.gameover-modal .formula-box.compact { font-size: 9px; line-height: 1.35; } -@media (max-width: 720px) { - .gameover-summary, .gameover-breakdown { grid-template-columns: 1fr 1fr; } -} - -/* v27.0 cleanup and stable build-menu tooltip pass */ -body { font-size: 18px; } -.build-panel { width: clamp(330px, 26vw, 420px); } -.panel-head h1 { font-size: 20px; } -.panel-head h1 span { font-size: 12px; } -.panel-head p { font-size: 13px; line-height: 1.35; } -.build-panel h2 { font-size: 14px; } -.priority-strip > div { font-size: 15px; } -.hud-card span { font-size: 12px; } -.hud-card strong { font-size: clamp(20px, 1.7vw, 28px); } -.mini-box, .event-card { font-size: 14px; line-height: 1.45; } -.compact-rules .mini-box { font-size: 13px; } -.tool-button { - position: relative; - overflow: visible; - min-height: 62px; - padding: 10px; -} -.large-tools .tool-button { min-height: 62px; } -.large-tools .tool-button:hover { min-height: 62px; } -.tool-button strong { font-size: 15px; line-height: 1.15; } -.tool-button span { font-size: 12px; } -.tool-button .tool-flavor { - display: none; - position: absolute; - z-index: 60; - left: 0; - top: calc(100% + 7px); - width: min(300px, calc(100vw - 40px)); - max-height: none; - opacity: 1; - overflow: visible; - margin: 0; - padding: 10px 12px; - border: 3px solid var(--line); - background: rgba(255,255,255,.98); - color: var(--ink); - box-shadow: 5px 5px 0 rgba(16,32,21,.18); - font-size: 13px; - line-height: 1.35; - text-transform: none; - letter-spacing: 0; - pointer-events: none; - transition: none; -} -.tool-button .tool-flavor::before { - content: ''; - position: absolute; - left: 16px; - top: -10px; - width: 16px; - height: 16px; - border-left: 3px solid var(--line); - border-top: 3px solid var(--line); - background: rgba(255,255,255,.98); - transform: rotate(45deg); -} -.tool-button:hover .tool-flavor { - display: block; - max-height: none; - opacity: 1; - margin: 0; -} -.primary-button { font-size: 16px; padding: 13px 16px; } -#nextTurnButton { min-height: 56px; font-size: 18px; } -@keyframes cashoutPulse { - from { box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(16,32,21,.18); filter: brightness(1); } - to { box-shadow: inset 0 0 0 5px #fff0d1, 4px 4px 0 rgba(16,32,21,.20); filter: brightness(1.08); } -} -.card-choices { grid-template-columns: repeat(auto-fill, minmax(230px, 270px)); gap: 14px; } -.card-choice { min-height: 164px; padding: 15px; } -.card-choice strong { font-size: 18px; } -.card-choice span { font-size: 11px; } -.card-choice small { font-size: 15px; line-height: 1.4; } -.muted-card-note { font-size: 15px; line-height: 1.45; } -.modal-card { width: min(980px, 96vw); } -.modal-card p, .modal-card li { font-size: 16px; } -.modal-actions .reroll-button { - order: 99; - flex: 1 1 100%; - min-height: 64px; - margin-top: 8px; - font-size: 20px; - text-align: center; - justify-content: center; - background: #fff0d1; - box-shadow: inset 0 0 0 4px var(--green), 6px 6px 0 rgba(16,32,21,.20); -} -.modal-actions .reroll-button:disabled { box-shadow: 4px 4px 0 rgba(16,32,21,.12); } -.hover-tooltip strong { font-size: 17px; } -.hover-tooltip span { font-size: 14px; } -.sort-button { font-size: 16px; min-height: 56px; } -.control-dock { grid-template-columns: repeat(4, 172px); } -@media (max-width: 1180px) { - .build-panel { width: auto; } - .control-dock { grid-template-columns: repeat(2, 172px); } -} - -/* v27.1 expansion/readability pass */ -body { font-size: 20px; } -.panel-head h1 { font-size: 22px; } -.panel-head h1 span { font-size: 13px; } -.panel-head p { font-size: 14px; line-height: 1.35; } -.build-panel h2 { font-size: 15px; } -.priority-strip > div { font-size: 16px; } -.hud-card span { font-size: 13px; } -.hud-card strong { font-size: clamp(22px, 1.8vw, 30px); } -.mini-box, .event-card { font-size: 15px; line-height: 1.5; } -.compact-rules .mini-box { font-size: 14px; } -.tool-button strong { font-size: 16px; line-height: 1.15; } -.tool-button span { font-size: 13px; line-height: 1.2; } -.tool-button .tool-flavor { - left: auto; - right: 0; - width: min(320px, calc(100vw - 40px)); - font-size: 14px; - line-height: 1.4; - overflow-wrap: anywhere; -} -.tool-button .tool-flavor::before { left: auto; right: 18px; } -.tool-button.unaffordable .tool-flavor, -.tool-button.unaffordable:hover .tool-flavor, -.tool-button:disabled .tool-flavor, -.tool-button:disabled:hover .tool-flavor { display: none; } -.facility-action { font-size: 12px; } -.primary-button { font-size: 17px; } -#nextTurnButton { font-size: 19px; } -.card-choice strong { font-size: 19px; } -.card-choice span { font-size: 12px; } -.card-choice small { font-size: 16px; line-height: 1.45; } -.muted-card-note { font-size: 16px; } -.modal-card p, .modal-card li { font-size: 17px; } -.modal.equipment-popover .modal-card h2 { font-size: 16px; } -.modal.equipment-popover .modal-actions button { font-size: 11px; } -.equipment-menu-lines.compact, .formula-box.compact { font-size: 11px; } -.hover-tooltip strong { font-size: 18px; } - -/* Keep construction flavor text readable as a hover bubble, not button content. */ -.large-tools .tool-button { - min-height: 62px; - position: relative; - overflow: visible; -} -.large-tools .tool-button:hover { - min-height: 62px; -} -.large-tools .tool-button .tool-flavor { - display: none; - position: absolute; - z-index: 90; - right: 0; - top: calc(100% + 8px); - width: min(320px, calc(100vw - 40px)); - max-height: none; - opacity: 1; - overflow: visible; - margin: 0; - padding: 10px 12px; - border: 3px solid var(--line); - background: rgba(255,255,255,.98); - color: var(--ink); - box-shadow: 5px 5px 0 rgba(16,32,21,.18); - font-size: 14px; - line-height: 1.35; - pointer-events: none; - overflow-wrap: anywhere; -} -.large-tools .tool-button:hover .tool-flavor { - display: block; -} -.large-tools .tool-button .tool-flavor::before { - content: ''; - position: absolute; - right: 18px; - top: -10px; - width: 16px; - height: 16px; - border-left: 3px solid var(--line); - border-top: 3px solid var(--line); - background: rgba(255,255,255,.98); - transform: rotate(45deg); -} -.hover-tooltip span { font-size: 15px; } -.sort-button { font-size: 17px; } - -/* v27.3 offscreen scanner monitor / expansion UI pass */ -.scanner-monitor { - position: absolute; - z-index: 8; - left: 12px; - bottom: 92px; - display: none; - grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); - gap: 8px; - width: min(560px, calc(100% - 24px)); - pointer-events: auto; -} -.scanner-monitor.visible { display: grid; } -.scanner-monitor-card { - border: 3px solid var(--line); - background: rgba(255,255,255,.95); - box-shadow: 5px 5px 0 rgba(16,32,21,.18); - padding: 9px; - font-weight: 900; -} -.scanner-monitor-card header { - display: flex; - align-items: center; - justify-content: space-between; - gap: 8px; - margin-bottom: 7px; - text-transform: uppercase; -} -.scanner-monitor-card header strong { font-size: 20px; color: var(--green); } -.scanner-monitor-card header span { font-size: 12px; color: var(--muted); } -.scanner-mini-map { - display: grid; - grid-template-columns: 42px 1fr 82px; - align-items: center; - gap: 6px; - margin-bottom: 8px; -} -.scanner-mini-map > span, -.scanner-mini-map > b { - border: 2px solid var(--line); - background: #f7fff5; - padding: 7px 6px; - text-align: center; - font-size: 13px; - min-height: 36px; -} -.scanner-current { display: block; color: var(--ink); } -.scanner-current.male { color: #2477ff; } -.scanner-current.female { color: #d62a85; } -.scanner-current.poop { color: #7b4a23; } -.scanner-current.empty { color: var(--muted); } - -.scanner-mini-grid { - display: grid; - grid-template-columns: repeat(5, 27px); - gap: 3px; - justify-content: center; - align-items: center; - padding: 6px; - margin: 0 0 8px; - border: 2px solid var(--line); - background: #f6f1df; -} -.scanner-mini-grid .mini-cell { - width: 27px; - height: 27px; - display: grid; - place-items: center; - border: 1px solid rgba(22,38,25,.28); - background: #fffdfa; - color: var(--muted); - font-size: 11px; - font-weight: 900; - line-height: 1; -} -.scanner-mini-grid .mini-cell.belt { background: #e7f7e4; color: var(--green-dark); } -.scanner-mini-grid .mini-cell.input { background: #fff3bf; color: var(--ink); font-size: 9px; } -.scanner-mini-grid .mini-cell.scanner { background: var(--green); color: #fff; border-color: var(--line); font-size: 16px; } -.scanner-mini-grid .mini-cell.scanner.male { background: #2477ff; } -.scanner-mini-grid .mini-cell.scanner.female { background: #d62a85; } -.scanner-mini-grid .mini-cell.scanner.poop { background: #7b4a23; } -.scanner-mini-grid .mini-cell.scanner-other { background: #b7f5c6; color: var(--ink); } -.scanner-mini-grid .mini-cell.egg { background: #fff7c4; color: #7a5a00; } -.scanner-mini-grid .mini-cell.port { background: #dbe7ff; color: #27427d; } -.scanner-mini-grid .mini-cell.blocked { background: #d7cfc1; color: #6d4d35; } - -.scanner-monitor-actions { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 7px; -} -.scanner-monitor-actions button { - border: 3px solid var(--line); - background: var(--green-soft); - color: var(--ink); - cursor: pointer; - font: inherit; - font-size: 14px; - font-weight: 900; - min-height: 44px; - box-shadow: 3px 3px 0 rgba(16,32,21,.18); -} -.scanner-monitor-actions button:disabled { - background: #edf3ec; - color: var(--muted); - opacity: .62; - cursor: not-allowed; -} -@media (max-width: 1180px) { - .scanner-monitor { bottom: 132px; width: min(520px, calc(100% - 16px)); left: 8px; } -} - -/* ------------------------------------------------------------------ - DARK FACTORY VISUAL PASS - - Facility sprites are now loaded from assets/dark_factory/. - - Debug UI is intentionally retained for balancing builds. Do not remove. - ------------------------------------------------------------------ */ -:root { - --bg: #0b0c0f; - --screen: #111318; - --panel: rgba(24, 27, 34, 0.96); - --panel-2: #20242b; - --panel-3: #2a303a; - --ink: #e6edf2; - --muted: #8f9bab; - --line: #050609; - --green: #7bd84f; - --green-soft: #273c24; - --white: #e6edf2; - --danger: #e34a36; - --warn: #ffb827; - --cyan: #4aa3ff; - --orange: #c86a2b; - --shadow: 6px 6px 0 rgba(0, 0, 0, 0.62); -} -html, body { background: #050609; color: var(--ink); } -body { - background: - linear-gradient(90deg, rgba(255,184,39,.035) 1px, transparent 1px) 0 0 / 32px 32px, - linear-gradient(rgba(255,184,39,.028) 1px, transparent 1px) 0 0 / 32px 32px, - #050609; -} -#app { width: min(100vw, 1720px); padding: 0; } -.game-shell { - min-height: 100vh; - border: 0; - background: var(--screen); - box-shadow: inset 0 0 0 4px #050609, inset 0 0 0 8px #303744; -} -#gameCanvas { - height: 100vh; - min-height: 720px; - background: var(--screen); - image-rendering: pixelated; - image-rendering: crisp-edges; -} -.hud { gap: 4px; } -.hud-top-left { - top: 8px; - left: 8px; - right: 420px; - grid-template-columns: 1.25fr repeat(5, minmax(92px, .65fr)); -} -.hud-top-right { - top: 8px; - right: 8px; - grid-template-columns: repeat(4, minmax(74px, auto)); -} -.hud-card { - min-width: 74px; - padding: 7px 9px; - border: 3px solid var(--line); - background: linear-gradient(#242a33, #171a20); - box-shadow: 4px 4px 0 rgba(0,0,0,.7), inset 0 0 0 2px rgba(255,184,39,.10); - color: var(--ink); -} -.hud-card span { color: var(--warn); font-size: 9px; letter-spacing: .12em; } -.hud-card strong { color: var(--ink); text-shadow: 2px 2px 0 #050609; } -.hud-card.cash strong, .hud-card.profit strong, .hud-card.combo strong, .cash-positive { color: var(--green) !important; } -.hud-card.time-critical { background: #3a1f1f; box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(0,0,0,.7); } -.priority-strip { - top: 74px; - left: 10px; - width: clamp(250px, 21vw, 330px); - max-width: none; - grid-template-columns: 1fr; - gap: 6px; -} -.priority-strip > div { - border: 3px solid var(--line); - background: linear-gradient(#222832, #15181e); - color: var(--ink); - box-shadow: 4px 4px 0 rgba(0,0,0,.66), inset 0 0 0 2px rgba(255,184,39,.12); -} -.event-brief.active { background: #38251a; box-shadow: inset 0 0 0 3px var(--orange), 4px 4px 0 rgba(0,0,0,.66); } -.event-brief.next { background: #1c2c20; box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(0,0,0,.66); } -.event-brief.locked { background: #181b20; color: var(--muted); } -.target-brief { color: var(--warn); } -.speed-brief { color: var(--cyan); } -.build-panel { - top: 82px; - right: 8px; - bottom: 8px; - width: clamp(320px, 24vw, 410px); - padding: 9px; - border: 4px solid var(--line); - background: linear-gradient(#222832, #14171d); - box-shadow: 6px 6px 0 rgba(0,0,0,.72), inset 0 0 0 3px rgba(255,184,39,.10); - scrollbar-color: var(--warn) #111318; -} -.panel-head { - display: grid; - grid-template-columns: 1fr 126px; - align-items: stretch; - gap: 8px; - margin-bottom: 8px; -} -.panel-head h1 { color: var(--warn); text-shadow: 2px 2px 0 #050609; font-size: 17px; } -.panel-head h1 span { color: #050609; background: var(--warn); border-color: var(--line); } -.panel-head p { color: var(--muted); } -.panel-grid { - display: grid; - grid-template-columns: 1fr; - gap: 8px; -} -.build-panel h2, .result-section-title { color: var(--warn); } -.large-tools { - grid-template-columns: 1fr 1fr; - gap: 6px; -} -.tool-button, .primary-button, .sort-button, .facility-action { - border: 3px solid var(--line); - background: linear-gradient(#2a303a, #171a20); - color: var(--ink); - box-shadow: 4px 4px 0 rgba(0,0,0,.70), inset 0 0 0 2px rgba(255,184,39,.08); - text-shadow: 1px 1px 0 #050609; -} -.tool-button { min-height: 48px; padding: 8px; } -.tool-button strong { color: var(--ink); } -.tool-button span { color: var(--muted); } -.tool-button.active { - background: linear-gradient(#33311d, #1e2117); - box-shadow: inset 0 0 0 3px var(--warn), 4px 4px 0 rgba(0,0,0,.70); -} -.tool-button.danger.active { background: linear-gradient(#4b1f1c, #241014); box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(0,0,0,.70); } -.primary-button { background: linear-gradient(#8b2d23, #4b1714); color: #fff3d2; } -.primary-button:not(:disabled) { box-shadow: inset 0 0 0 3px #ffb827, 5px 5px 0 rgba(0,0,0,.72); } -.primary-button:disabled, .tool-button:disabled, .sort-button:disabled, .facility-action:disabled { opacity: .42; filter: grayscale(1); } -.mini-box, .event-card, .formula-box, .equipment-menu-lines, .route-card, .result-grid div, .muted-title { - border: 3px solid var(--line); - background: #15181e; - color: var(--muted); - box-shadow: inset 0 0 0 2px rgba(255,184,39,.08); -} -.event-card h3, .event-card strong, .event-metrics span { color: var(--ink); } -.event-card.accepted { background: #1c2c20; box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(0,0,0,.66); } -.event-card.empty { background: #15181e; color: var(--muted); } -.event-metrics span { border-color: #3d4654; background: #20242b; } -.event-status { background: #2a303a; color: var(--warn); border-color: var(--line); } -.control-dock { - left: 50%; - right: auto; - bottom: 8px; - transform: translateX(-50%); - grid-template-columns: repeat(4, minmax(135px, 160px)); - gap: 6px; - padding: 6px; - border: 4px solid var(--line); - background: rgba(13,15,19,.96); - box-shadow: 5px 5px 0 rgba(0,0,0,.72), inset 0 0 0 2px rgba(255,184,39,.10); -} -.sort-button { min-height: 44px; font-size: 12px; } -.scanner-monitor { - position: absolute; - z-index: 5; - left: 10px; - top: 198px; - width: clamp(250px, 21vw, 330px); -} -.scanner-monitor-card { - border: 3px solid var(--line) !important; - background: linear-gradient(#222832, #15181e) !important; - color: var(--ink) !important; - box-shadow: 4px 4px 0 rgba(0,0,0,.66), inset 0 0 0 2px rgba(255,184,39,.10) !important; -} -.scanner-monitor-card strong { color: var(--warn); } -.debug-panel { - left: auto; - right: 12px; - bottom: 10px; - width: min(420px, calc(100% - 24px)); - border-color: var(--line); - background: rgba(16,18,23,.97); - box-shadow: 5px 5px 0 rgba(0,0,0,.72), inset 0 0 0 2px rgba(227,74,54,.18); - color: var(--ink); -} -.debug-panel summary { color: var(--danger); } -.debug-body { border-top-color: var(--line); } -.debug-body button, .debug-body input[type="number"], .debug-body select, .debug-readout { - border-color: var(--line); - background: #20242b; - color: var(--ink); -} -.debug-readout { color: var(--muted); } -.modal { background: rgba(3,4,6,.72); } -.modal-card { - border-color: var(--line); - background: linear-gradient(#242a33, #15181e); - color: var(--ink); - box-shadow: 8px 8px 0 rgba(0,0,0,.72), inset 0 0 0 3px rgba(255,184,39,.12); -} -.modal-card h2 { color: var(--warn); text-shadow: 2px 2px 0 #050609; } -.modal-card ul, .modal-card p { color: var(--muted); } -.hover-tooltip { - border-color: var(--line) !important; - background: rgba(20,23,29,.98) !important; - color: var(--ink) !important; - box-shadow: 5px 5px 0 rgba(0,0,0,.72) !important; -} -::-webkit-scrollbar { width: 14px; height: 14px; } -::-webkit-scrollbar-track { background: #111318; } -::-webkit-scrollbar-thumb { background: #333b48; border: 3px solid #111318; } -::-webkit-scrollbar-thumb:hover { background: #ffb827; } -@media (max-width: 1180px) { - .hud-top-left { right: 8px; grid-template-columns: repeat(3, minmax(80px, 1fr)); } - .hud-top-right { top: 132px; left: 8px; right: auto; grid-template-columns: repeat(2, minmax(82px, auto)); } - .priority-strip { top: 226px; } - .scanner-monitor { top: 348px; } - .build-panel { left: 8px; right: 8px; bottom: 8px; width: auto; max-height: 46vh; } - .control-dock { grid-template-columns: repeat(2, 150px); } -} - -/* v27.16: compact collapsed debug panel + icon card layout */ -.debug-panel:not([open]) { - width: 104px !important; - min-width: 0; - overflow: hidden; -} -.debug-panel:not([open]) summary { - display: block; - width: 100%; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} -.debug-panel[open] { - width: min(420px, calc(100% - 24px)); -} - -.card-choice { - position: relative; - display: grid; - grid-template-columns: 54px minmax(0, 1fr); - gap: 10px; - align-items: start; - min-height: 150px; - overflow: hidden; - background: - linear-gradient(135deg, rgba(255,255,255,.08), rgba(0,0,0,.20)), - #20242b; - border-color: var(--line); -} -.card-choice::before { - content: ""; - position: absolute; - inset: 5px; - border: 1px solid rgba(255,184,39,.18); - pointer-events: none; -} -.card-icon { - position: relative; - z-index: 1; - width: 46px; - height: 46px; - display: grid; - place-items: center; - border: 3px solid var(--line); - background: #15181e; - box-shadow: inset 0 0 0 2px rgba(255,184,39,.10), 3px 3px 0 rgba(0,0,0,.35); - image-rendering: pixelated; -} -.card-icon img { - width: 36px; - height: 36px; - object-fit: contain; - image-rendering: pixelated; -} -.card-icon.glyph { - color: var(--warn, #ffb827); - font-size: 24px; - font-weight: 900; - text-align: center; - line-height: 1; -} -.card-copy { - position: relative; - z-index: 1; - min-width: 0; -} -.card-choice strong { - color: var(--warn, #ffb827); - text-shadow: 1px 1px 0 #050609; -} -.card-choice small { color: var(--muted); } -.card-tags span { - background: #15181e; - color: var(--white); - border-color: var(--line); -} -.card-choice.common { background: linear-gradient(145deg, #262c35, #171a20); } -.card-choice.rare { - background: linear-gradient(145deg, #3b3020, #191b20); - box-shadow: inset 0 0 0 3px #f0a020, 5px 5px 0 rgba(0,0,0,.50); -} -.card-choice.ultra-rare { - background: linear-gradient(145deg, #401d2a, #171a20); - box-shadow: inset 0 0 0 3px #c42424, 5px 5px 0 rgba(0,0,0,.55); -} -.card-choice.dud { - background: linear-gradient(145deg, #2b2b2b, #191919); - color: #878787; -} -.card-choice.dud .card-tags span { background: #222; color: #aaa; } - -@media (max-width: 1180px) { - .debug-panel:not([open]) { - width: 92px !important; - right: 8px; - bottom: 8px; - } -} - - -/* v27.17 verified visual patch: cache-proof identity and final UI overrides */ -.build-stamp { - position: absolute; - z-index: 12; - right: 14px; - top: 76px; - padding: 5px 9px; - border: 2px solid #ffb827; - background: rgba(14, 17, 22, .94); - color: #80e067; - box-shadow: 3px 3px 0 rgba(0,0,0,.7); - font: 900 11px/1 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; - letter-spacing: .04em; - pointer-events: none; -} -.debug-panel:not([open]) { - width: 58px !important; - max-width: 58px !important; - height: 30px; - min-height: 0; -} -.debug-panel:not([open]) summary { - box-sizing: border-box; - width: 58px; - height: 27px; - padding: 5px 7px; - text-align: center; - overflow: hidden; - text-overflow: clip; -} -.debug-panel[open] { - width: min(390px, calc(100% - 24px)) !important; - height: auto; -} -.card-choice { - border-width: 3px; - box-shadow: 4px 4px 0 rgba(0,0,0,.55), inset 0 0 0 1px rgba(255,184,39,.14); -} -.card-choice:hover { - transform: translateY(-2px); - box-shadow: 4px 6px 0 rgba(0,0,0,.65), inset 0 0 0 2px rgba(128,224,103,.24); -} -.card-icon img { - image-rendering: pixelated; - filter: drop-shadow(2px 2px 0 rgba(0,0,0,.7)); -} -#gameCanvas { image-rendering: pixelated; } diff --git a/styles-v27.18.css b/styles-v27.18.css deleted file mode 100644 index 8bb1b90..0000000 --- a/styles-v27.18.css +++ /dev/null @@ -1,1253 +0,0 @@ -:root { - --bg: #f2fff0; - --screen: #eefbea; - --panel: rgba(245, 255, 242, 0.96); - --ink: #102015; - --muted: #526456; - --line: #102015; - --green: #22b94f; - --green-soft: #b7f5c6; - --white: #ffffff; - --danger: #c42424; - --shadow: 8px 8px 0 rgba(16, 32, 21, 0.22); -} -* { box-sizing: border-box; } -html, body { min-height: 100%; } -body { margin: 0; background: var(--bg); color: var(--ink); font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; overflow-x: hidden; } -button { font: inherit; } -h1, h2, p { margin: 0; } -#app { width: min(100vw, 1680px); margin: 0 auto; padding: 0 8px 12px; } -.game-shell { position: relative; width: 100%; min-height: min(100vh, 920px); border: 4px solid var(--line); border-top: 0; background: var(--screen); overflow: hidden; box-shadow: var(--shadow); } -#gameCanvas { display: block; width: 100%; height: min(calc(100vh - 10px), 900px); min-height: 720px; background: var(--screen); touch-action: none; } -.hud { position: absolute; z-index: 4; display: grid; gap: 6px; pointer-events: none; } -.hud-top-left { top: 10px; left: 10px; grid-template-columns: repeat(6, minmax(82px, auto)); } -.hud-top-right { top: 10px; right: 10px; grid-template-columns: repeat(4, minmax(78px, auto)); } -.hud-card { min-width: 82px; padding: 7px 9px; border: 3px solid var(--line); background: rgba(255,255,255,.88); box-shadow: 4px 4px 0 rgba(16,32,21,.16); } -.hud-card.primary { min-width: 116px; padding: 10px 12px; background: rgba(255,255,255,.96); } -.hud-card.primary span { font-size: 9px; } -.hud-card.primary strong { font-size: clamp(22px, 2vw, 32px); } -.hud-card.time-critical { background: #fff0d1; box-shadow: inset 0 0 0 4px var(--danger), 4px 4px 0 rgba(16,32,21,.16); } -.hud-card span { display: block; font-size: 9px; letter-spacing: .1em; color: var(--muted); margin-bottom: 4px; } -.hud-card strong { font-size: clamp(15px, 1.3vw, 22px); line-height: 1; color: var(--ink); } -.hud-card.cash strong, .hud-card.profit strong, .hud-card.combo strong, .cash-positive { color: var(--green) !important; } -.cash-negative { color: var(--danger) !important; } - -.priority-strip { position: absolute; z-index: 5; top: 76px; left: 10px; display: grid; grid-template-columns: minmax(280px, 1.2fr) minmax(170px, .75fr) minmax(130px, .55fr); gap: 8px; max-width: calc(100% - 420px); pointer-events: none; } -.priority-strip > div { border: 3px solid var(--line); background: rgba(255,255,255,.94); padding: 8px 10px; font-weight: 900; text-transform: uppercase; box-shadow: 4px 4px 0 rgba(16,32,21,.14); font-size: 12px; letter-spacing: .03em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } -.event-brief.active { background: #fff0d1; box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(16,32,21,.14); } -.event-brief.next { background: var(--green-soft); box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(16,32,21,.14); } -.event-brief.locked { background: #edf3ec; color: var(--muted); } -.target-brief { color: var(--green); } -.speed-brief { color: var(--ink); } - -.build-panel { position: absolute; z-index: 6; top: 118px; right: 12px; bottom: 12px; width: clamp(278px, 23vw, 360px); min-height: 0; padding: 10px; border: 4px solid var(--line); background: var(--panel); box-shadow: var(--shadow); overflow: auto; } -.panel-head { display: grid; gap: 8px; margin-bottom: 10px; } -.panel-head h1 { font-size: 15px; letter-spacing: .06em; } -.panel-head h1 span { font-size: 9px; color: var(--white); background: var(--green); border: 2px solid var(--line); padding: 1px 6px; } -.panel-head p { color: var(--muted); margin-top: 4px; font-size: 9px; line-height: 1.25; } -.panel-grid { display: grid; grid-template-columns: 1fr; gap: 10px; } -.build-panel h2 { font-size: 11px; text-transform: uppercase; letter-spacing: .1em; margin-bottom: 7px; } -.large-tools { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; } -.history-tools { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; grid-column: 1 / -1; } -.tool-button.small { min-height: 40px; padding: 6px; } -.tool-button, .primary-button, .sort-button, .facility-action { border: 3px solid var(--line); background: var(--white); color: var(--ink); font-weight: 900; text-transform: uppercase; cursor: pointer; box-shadow: 4px 4px 0 rgba(16,32,21,.18); } -.tool-button { min-height: 50px; text-align: left; padding: 8px; } -.tool-button strong { display: block; font-size: 12px; } -.tool-button span { display: block; margin-top: 4px; font-size: 9px; color: var(--muted); } -.tool-button.active { background: var(--green-soft); box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(16,32,21,.18); } -.tool-button.danger.active { background: #ffdada; box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(16,32,21,.18); } -.primary-button { padding: 10px 12px; background: var(--green); color: var(--white); white-space: nowrap; } -.primary-button:disabled, .tool-button:disabled, .sort-button:disabled, .facility-action:disabled { opacity: .42; cursor: not-allowed; } -.mini-box { border: 3px solid var(--line); background: var(--white); padding: 12px; line-height: 1.45; color: var(--muted); font-size: 11px; } -.facility-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; } -.facility-action { padding: 7px 9px; font-size: 9px; } -.facility-action.good { background: var(--green-soft); } -.facility-action.warn { background: #fff0d1; } -.facility-action.danger { background: #ffdada; } -.control-dock { position: absolute; z-index: 7; left: 50%; bottom: 12px; transform: translateX(-50%); display: grid; grid-template-columns: repeat(4, 150px); gap: 8px; padding: 7px; border: 3px solid var(--line); background: rgba(255,255,255,.90); } -.sort-button { min-height: 46px; font-size: 12px; } -/* Debug UI is intentionally kept for active balancing builds. Do not remove during cleanup/audit passes unless explicitly requested. */ -.debug-panel { - position: absolute; - z-index: 9; - left: 10px; - bottom: 10px; - width: min(410px, calc(100% - 20px)); - border: 3px solid var(--line); - background: rgba(255,255,255,.96); - box-shadow: 4px 4px 0 rgba(16,32,21,.16); - font-weight: 900; -} -.debug-panel summary { - cursor: pointer; - padding: 5px 8px; - color: var(--danger); - font-size: 14px; - line-height: 1.1; -} -.debug-body { - display: grid; - grid-template-columns: 1fr 92px; - gap: 6px; - padding: 7px; - border-top: 3px solid var(--line); - font-size: 12px; - line-height: 1.15; -} -.debug-body label, -.debug-body button, -.debug-body select, -.debug-body input { - min-width: 0; - font: inherit; -} -.debug-check, -.debug-card, -.debug-target, -.debug-readout { - grid-column: 1 / -1; -} -.debug-row { - display: grid; - grid-template-columns: 1fr 92px; - gap: 6px; - grid-column: 1 / -1; -} -.debug-day { - display: grid; - grid-template-columns: 38px 1fr; - align-items: center; - gap: 4px; -} -.debug-body button { - border: 2px solid var(--line); - background: var(--white); - cursor: pointer; - font-weight: 900; - padding: 5px 6px; - line-height: 1.05; -} -.debug-body input[type="number"], -.debug-body select { - width: 100%; - border: 2px solid var(--line); - background: var(--white); - padding: 4px 5px; - min-height: 29px; -} -.debug-target select:disabled { - opacity: .55; -} -.debug-readout { - border: 2px solid var(--line); - background: #f7fff5; - color: var(--muted); - padding: 5px; - line-height: 1.25; - max-height: 64px; - overflow: auto; -} -.modal { position: fixed; inset: 0; z-index: 20; display: none; align-items: center; justify-content: center; padding: 22px; background: rgba(16,32,21,.45); } -.modal.visible { display: flex; } -.modal-card { width: min(860px, 96vw); border: 4px solid var(--line); padding: 24px; background: var(--white); box-shadow: var(--shadow); } -.modal-card h2 { font-size: 26px; text-transform: uppercase; margin-bottom: 12px; } -.modal-card p { line-height: 1.55; } -.modal-card ul { margin: 12px 0 0; padding-left: 22px; line-height: 1.55; color: var(--muted); } -.modal-actions { margin-top: 18px; display: flex; justify-content: flex-end; gap: 10px; flex-wrap: wrap; } -.route-cards { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; margin: 14px 0; } -.route-card { border: 3px solid var(--line); background: #f7fff5; padding: 14px; display: grid; grid-template-columns: 44px 1fr 28px 1fr; align-items: center; gap: 4px 8px; } -.route-card .route-icon { grid-row: 1 / span 2; font-size: 30px; text-align: center; } -.route-card strong, .route-card em { font-style: normal; font-weight: 900; text-transform: uppercase; } -.route-card b { font-size: 24px; color: var(--green); text-align: center; } -.route-card small { grid-column: 2 / span 3; color: var(--muted); font-weight: 900; } -.result-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin-top: 12px; } -.result-grid div { border: 3px solid var(--line); padding: 10px; background: #f7fff5; } -.result-grid strong { display: block; font-size: 11px; color: var(--muted); text-transform: uppercase; margin-bottom: 6px; } -.result-grid span { font-size: 16px; font-weight: 900; color: var(--ink); } -.game-shell:not(.phase-build) .build-panel { display: none; } -.game-shell.phase-running .hud-top-right { display: none; } -.game-shell:not(.phase-running) .control-dock { display: none; } -@media (max-width: 1180px) { - #app { padding: 0; } - .game-shell { min-height: 100vh; } - #gameCanvas { height: 100vh; } - .hud-top-left, .hud-top-right { grid-template-columns: repeat(2, minmax(76px, auto)); } - .priority-strip { top: 150px; left: 8px; right: 8px; max-width: none; grid-template-columns: 1fr; } - .build-panel { top: auto; left: 8px; right: 8px; bottom: 8px; width: auto; max-height: 42vh; } - .large-tools { grid-template-columns: 1fr 1fr; } - .control-dock { grid-template-columns: repeat(2, 150px); } - .route-cards, .result-grid { grid-template-columns: 1fr; } -} - -.event-card { border: 3px solid var(--line); background: #f7fff5; padding: 12px; line-height: 1.35; color: var(--ink); font-size: 11px; box-shadow: 4px 4px 0 rgba(16,32,21,.14); } -.event-card.empty { color: var(--muted); background: rgba(255,255,255,.72); } -.event-card.empty strong { display: block; color: var(--ink); margin-bottom: 4px; } -.event-card h3 { margin: 2px 0 7px; font-size: 14px; text-transform: uppercase; letter-spacing: .04em; } -.event-card p { margin: 5px 0; } -.event-card.accepted { background: var(--green-soft); box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(16,32,21,.14); } -.event-card.declined { background: #f1f1f1; color: var(--muted); } -.event-status { display: inline-block; padding: 2px 7px; border: 2px solid var(--line); background: var(--white); font-size: 9px; font-weight: 900; letter-spacing: .1em; margin-bottom: 4px; } -.event-metrics { display: grid; grid-template-columns: 1fr; gap: 4px; margin: 8px 0; } -.event-metrics span { display: block; border: 2px solid rgba(16,32,21,.55); background: rgba(255,255,255,.82); padding: 5px; font-weight: 900; color: var(--ink); } -.event-actions { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; } -.result-section-title { margin: 16px 0 8px; font-size: 12px; font-weight: 900; text-transform: uppercase; letter-spacing: .12em; color: var(--green); } -.result-section-title:first-child { margin-top: 0; } -.muted-title { color: var(--muted); border: 3px solid var(--line); padding: 10px; background: #f7fff5; } - -.compact-rules .mini-box { padding: 8px; font-size: 9px; } -.primary-button:disabled { filter: grayscale(1); background: #c9d2ca; color: #526456; } -.formula-box { - border: 3px solid var(--line); - background: #f7fff5; - padding: 10px; - margin: 10px 0; - line-height: 1.5; - color: var(--ink); - font-size: 12px; - font-weight: 700; -} -.equipment-menu-lines { - border: 3px solid var(--line); - background: #ffffff; - padding: 10px; - margin: 8px 0; - color: var(--muted); - line-height: 1.45; -} -.equipment-menu-lines p { margin: 4px 0; } - -/* v11 compact clicked-equipment bubble */ -.modal.equipment-popover { - background: transparent; - align-items: flex-start; - justify-content: flex-start; - padding: 0; - pointer-events: none; -} -.modal.equipment-popover .modal-card { - position: absolute; - left: var(--popover-x, 16px); - top: var(--popover-y, 16px); - width: min(250px, calc(100vw - 24px)); - max-height: min(280px, calc(100vh - 24px)); - overflow: auto; - padding: 8px; - border-width: 3px; - pointer-events: auto; - box-shadow: 6px 6px 0 rgba(16,32,21,.18); -} -.modal.equipment-popover .modal-card h2 { - font-size: 14px; - margin-bottom: 6px; -} -.modal.equipment-popover .modal-actions { - margin-top: 8px; - gap: 6px; - justify-content: flex-start; -} -.modal.equipment-popover .modal-actions button { - padding: 5px 7px; - font-size: 9px; -} -.equipment-menu-lines.compact { - padding: 7px; - margin: 6px 0; - font-size: 9px; -} -.formula-box.compact { - padding: 7px; - margin: 6px 0; - font-size: 9px; -} - -/* v15 pre-build card draft */ -.card-choices { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(190px, 220px)); - justify-content: center; - align-items: stretch; - gap: 10px; - margin-top: 14px; -} -.card-choice { - min-height: 132px; - border: 3px solid var(--line); - background: #f7fff5; - color: var(--ink); - box-shadow: 5px 5px 0 rgba(16,32,21,.16); - padding: 12px; - text-align: left; - cursor: pointer; - font-weight: 900; -} -.card-choice:hover { transform: translate(-1px, -1px); box-shadow: 6px 6px 0 rgba(16,32,21,.18); } -.card-choice strong { display: block; font-size: 14px; text-transform: uppercase; line-height: 1.2; } -.card-choice span { display: inline-block; margin: 8px 0; padding: 2px 7px; border: 2px solid var(--line); background: var(--white); font-size: 9px; letter-spacing: .1em; } -.card-tags { display: flex; flex-wrap: wrap; gap: 4px; margin: 7px 0; } -.card-tags span { margin: 0; padding: 2px 5px; font-size: 8px; line-height: 1.1; letter-spacing: .04em; } -.card-choice small { display: block; color: var(--muted); font-size: 11px; line-height: 1.35; } -.card-choice.rare { background: #fff0d1; box-shadow: inset 0 0 0 3px #f0a020, 5px 5px 0 rgba(16,32,21,.16); } -.card-choice.ultra-rare { background: #ffe6f0; box-shadow: inset 0 0 0 3px #c42424, 5px 5px 0 rgba(16,32,21,.18); } -.card-choice.ultra-rare span { background: #c42424; color: #fff; } -.muted-card-note { color: var(--muted); font-weight: 700; } -.card-targets { display: grid; gap: 8px; margin-top: 14px; } -.card-target-button { border: 3px solid var(--line); background: #f7fff5; padding: 10px 12px; text-align: left; cursor: pointer; font-weight: 900; box-shadow: 4px 4px 0 rgba(16,32,21,.14); } -.card-target-button:hover { background: var(--green-soft); } - -/* v19 readability pass */ -body { font-size: 16px; } -.hud-card span { font-size: 11px; } -.hud-card strong { font-size: clamp(18px, 1.5vw, 25px); } -.priority-strip > div { font-size: 14px; } -.panel-head h1 { font-size: 18px; } -.panel-head p { font-size: 11px; } -.build-panel h2 { font-size: 13px; } -.tool-button strong { font-size: 14px; } -.tool-button span { font-size: 11px; } -.mini-box, .event-card { font-size: 12px; } -.sort-button { font-size: 14px; } -.modal-card h2 { font-size: 29px; } -.card-choice strong { font-size: 16px; } -.card-choice small { font-size: 13px; } - -.tool-button.unaffordable, .tool-button.already-built { opacity: .42; filter: grayscale(.7); } - -.hover-tooltip { - position: fixed; - z-index: 30; - width: min(320px, calc(100vw - 20px)); - display: none; - border: 3px solid var(--line); - background: rgba(255,255,255,.96); - color: var(--ink); - box-shadow: 6px 6px 0 rgba(16,32,21,.18); - padding: 10px; - pointer-events: none; - line-height: 1.35; -} -.hover-tooltip.visible { display: block; } -.hover-tooltip strong { display: block; font-size: 15px; text-transform: uppercase; margin-bottom: 5px; } -.hover-tooltip em { display: block; font-style: normal; color: var(--green); font-weight: 900; margin-bottom: 7px; } -.hover-tooltip em.warning { color: var(--danger); } -.hover-tooltip span { display: block; color: var(--muted); font-size: 12px; } - - -.card-choice.dud { - background: #eeeeee; - color: #777; - filter: grayscale(1); - border-style: dashed; - box-shadow: 5px 5px 0 rgba(16,32,21,.10); -} -.card-choice.dud span { background: #f8f8f8; } -.card-choice.flung { - pointer-events: none; - transform: translate(var(--fling-x, 480px), var(--fling-y, -320px)) rotate(var(--fling-r, 68deg)) scale(.68); - opacity: 0; - transition: transform .34s cubic-bezier(.18,.84,.26,.99), opacity .28s ease-in; -} - - - -.route-card .route-icon.male, -.route-card .route-icon.female, -.route-card .route-icon.poop { - display: inline-grid; - place-items: center; - width: 38px; - height: 38px; - border-radius: 999px; - border: 3px solid var(--line, #102015); - background: var(--white, #fff); - line-height: 1; -} -.route-card .route-icon.male { color: #2477ff; background: #d9ecff; } -.route-card .route-icon.female { color: #d62a85; background: #ffe0f0; } -.route-card .route-icon.poop { color: #7b4a23; background: #fff0d1; font-size: 24px; } -.restart-button { min-width: 160px; } -.restart-fallback-note { margin-top: 12px; color: var(--muted, #526456); font-weight: 700; } - -/* v24.4 hover-only build-button flavor / cashout guidance / compact game-over */ -.tool-button .tool-flavor { - display: block; - max-height: 0; - opacity: 0; - overflow: hidden; - margin-top: 0; - color: var(--muted); - font-size: 8px; - line-height: 1.22; - text-transform: none; - letter-spacing: 0; - transition: max-height .12s ease, opacity .12s ease, margin-top .12s ease; -} -.tool-button:hover .tool-flavor { - max-height: 42px; - opacity: 1; - margin-top: 5px; -} -.large-tools .tool-button { min-height: 58px; } -.large-tools .tool-button:hover { min-height: 78px; } -.history-tools .tool-button.small { min-height: 40px; } -.primary-button.cashout-emphasis, -.tool-button.cashout-emphasis { - opacity: 1 !important; - filter: none !important; - animation: cashoutPulse 0.9s ease-in-out infinite alternate; -} -.primary-button.cashout-emphasis { - box-shadow: inset 0 0 0 4px #fff0d1, 6px 6px 0 rgba(16,32,21,.22); -} -.tool-button.cashout-emphasis { - background: #fff0d1; - box-shadow: inset 0 0 0 3px var(--danger), 6px 6px 0 rgba(16,32,21,.20); -} -@keyframes cashoutPulse { - from { transform: translate(0, 0); } - to { transform: translate(-1px, -1px); } -} -.modal.gameover-modal { padding: 12px; } -.modal.gameover-modal .modal-card { - width: min(640px, 92vw); - max-height: min(82vh, 720px); - overflow: auto; - padding: 16px; -} -.modal.gameover-modal .modal-card h2 { - font-size: 22px; - margin-bottom: 8px; -} -.gameover-reason { font-weight: 900; color: var(--danger); margin-bottom: 8px; } -.settlement-net { - border: 3px solid var(--line); - background: #f7fff5; - padding: 10px 12px; - margin-bottom: 10px; - display: flex; - justify-content: space-between; - align-items: center; - gap: 12px; - font-weight: 900; - text-transform: uppercase; -} -.settlement-net strong { font-size: 24px; } -.settlement-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; } -.settlement-grid div { padding: 8px; } -.settlement-grid span { display: block; font-size: 14px; } -.gameover-summary { - grid-template-columns: repeat(4, minmax(0, 1fr)); - gap: 6px; - margin-top: 8px; -} -.gameover-breakdown { - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 6px; - margin-top: 8px; -} -.modal.gameover-modal .result-grid div { padding: 7px; } -.modal.gameover-modal .result-grid strong { font-size: 9px; margin-bottom: 3px; } -.modal.gameover-modal .result-grid span { font-size: 12px; } -.gameover-details { - margin-top: 10px; - border: 3px solid var(--line); - background: #f7fff5; - padding: 8px; -} -.gameover-details summary { - cursor: pointer; - font-weight: 900; - text-transform: uppercase; -} -.modal.gameover-modal .formula-box.compact { font-size: 9px; line-height: 1.35; } -@media (max-width: 720px) { - .gameover-summary, .gameover-breakdown { grid-template-columns: 1fr 1fr; } -} - -/* v27.0 cleanup and stable build-menu tooltip pass */ -body { font-size: 18px; } -.build-panel { width: clamp(330px, 26vw, 420px); } -.panel-head h1 { font-size: 20px; } -.panel-head h1 span { font-size: 12px; } -.panel-head p { font-size: 13px; line-height: 1.35; } -.build-panel h2 { font-size: 14px; } -.priority-strip > div { font-size: 15px; } -.hud-card span { font-size: 12px; } -.hud-card strong { font-size: clamp(20px, 1.7vw, 28px); } -.mini-box, .event-card { font-size: 14px; line-height: 1.45; } -.compact-rules .mini-box { font-size: 13px; } -.tool-button { - position: relative; - overflow: visible; - min-height: 62px; - padding: 10px; -} -.large-tools .tool-button { min-height: 62px; } -.large-tools .tool-button:hover { min-height: 62px; } -.tool-button strong { font-size: 15px; line-height: 1.15; } -.tool-button span { font-size: 12px; } -.tool-button .tool-flavor { - display: none; - position: absolute; - z-index: 60; - left: 0; - top: calc(100% + 7px); - width: min(300px, calc(100vw - 40px)); - max-height: none; - opacity: 1; - overflow: visible; - margin: 0; - padding: 10px 12px; - border: 3px solid var(--line); - background: rgba(255,255,255,.98); - color: var(--ink); - box-shadow: 5px 5px 0 rgba(16,32,21,.18); - font-size: 13px; - line-height: 1.35; - text-transform: none; - letter-spacing: 0; - pointer-events: none; - transition: none; -} -.tool-button .tool-flavor::before { - content: ''; - position: absolute; - left: 16px; - top: -10px; - width: 16px; - height: 16px; - border-left: 3px solid var(--line); - border-top: 3px solid var(--line); - background: rgba(255,255,255,.98); - transform: rotate(45deg); -} -.tool-button:hover .tool-flavor { - display: block; - max-height: none; - opacity: 1; - margin: 0; -} -.primary-button { font-size: 16px; padding: 13px 16px; } -#nextTurnButton { min-height: 56px; font-size: 18px; } -@keyframes cashoutPulse { - from { box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(16,32,21,.18); filter: brightness(1); } - to { box-shadow: inset 0 0 0 5px #fff0d1, 4px 4px 0 rgba(16,32,21,.20); filter: brightness(1.08); } -} -.card-choices { grid-template-columns: repeat(auto-fill, minmax(230px, 270px)); gap: 14px; } -.card-choice { min-height: 164px; padding: 15px; } -.card-choice strong { font-size: 18px; } -.card-choice span { font-size: 11px; } -.card-choice small { font-size: 15px; line-height: 1.4; } -.muted-card-note { font-size: 15px; line-height: 1.45; } -.modal-card { width: min(980px, 96vw); } -.modal-card p, .modal-card li { font-size: 16px; } -.modal-actions .reroll-button { - order: 99; - flex: 1 1 100%; - min-height: 64px; - margin-top: 8px; - font-size: 20px; - text-align: center; - justify-content: center; - background: #fff0d1; - box-shadow: inset 0 0 0 4px var(--green), 6px 6px 0 rgba(16,32,21,.20); -} -.modal-actions .reroll-button:disabled { box-shadow: 4px 4px 0 rgba(16,32,21,.12); } -.hover-tooltip strong { font-size: 17px; } -.hover-tooltip span { font-size: 14px; } -.sort-button { font-size: 16px; min-height: 56px; } -.control-dock { grid-template-columns: repeat(4, 172px); } -@media (max-width: 1180px) { - .build-panel { width: auto; } - .control-dock { grid-template-columns: repeat(2, 172px); } -} - -/* v27.1 expansion/readability pass */ -body { font-size: 20px; } -.panel-head h1 { font-size: 22px; } -.panel-head h1 span { font-size: 13px; } -.panel-head p { font-size: 14px; line-height: 1.35; } -.build-panel h2 { font-size: 15px; } -.priority-strip > div { font-size: 16px; } -.hud-card span { font-size: 13px; } -.hud-card strong { font-size: clamp(22px, 1.8vw, 30px); } -.mini-box, .event-card { font-size: 15px; line-height: 1.5; } -.compact-rules .mini-box { font-size: 14px; } -.tool-button strong { font-size: 16px; line-height: 1.15; } -.tool-button span { font-size: 13px; line-height: 1.2; } -.tool-button .tool-flavor { - left: auto; - right: 0; - width: min(320px, calc(100vw - 40px)); - font-size: 14px; - line-height: 1.4; - overflow-wrap: anywhere; -} -.tool-button .tool-flavor::before { left: auto; right: 18px; } -.tool-button.unaffordable .tool-flavor, -.tool-button.unaffordable:hover .tool-flavor, -.tool-button:disabled .tool-flavor, -.tool-button:disabled:hover .tool-flavor { display: none; } -.facility-action { font-size: 12px; } -.primary-button { font-size: 17px; } -#nextTurnButton { font-size: 19px; } -.card-choice strong { font-size: 19px; } -.card-choice span { font-size: 12px; } -.card-choice small { font-size: 16px; line-height: 1.45; } -.muted-card-note { font-size: 16px; } -.modal-card p, .modal-card li { font-size: 17px; } -.modal.equipment-popover .modal-card h2 { font-size: 16px; } -.modal.equipment-popover .modal-actions button { font-size: 11px; } -.equipment-menu-lines.compact, .formula-box.compact { font-size: 11px; } -.hover-tooltip strong { font-size: 18px; } - -/* Keep construction flavor text readable as a hover bubble, not button content. */ -.large-tools .tool-button { - min-height: 62px; - position: relative; - overflow: visible; -} -.large-tools .tool-button:hover { - min-height: 62px; -} -.large-tools .tool-button .tool-flavor { - display: none; - position: absolute; - z-index: 90; - right: 0; - top: calc(100% + 8px); - width: min(320px, calc(100vw - 40px)); - max-height: none; - opacity: 1; - overflow: visible; - margin: 0; - padding: 10px 12px; - border: 3px solid var(--line); - background: rgba(255,255,255,.98); - color: var(--ink); - box-shadow: 5px 5px 0 rgba(16,32,21,.18); - font-size: 14px; - line-height: 1.35; - pointer-events: none; - overflow-wrap: anywhere; -} -.large-tools .tool-button:hover .tool-flavor { - display: block; -} -.large-tools .tool-button .tool-flavor::before { - content: ''; - position: absolute; - right: 18px; - top: -10px; - width: 16px; - height: 16px; - border-left: 3px solid var(--line); - border-top: 3px solid var(--line); - background: rgba(255,255,255,.98); - transform: rotate(45deg); -} -.hover-tooltip span { font-size: 15px; } -.sort-button { font-size: 17px; } - -/* v27.3 offscreen scanner monitor / expansion UI pass */ -.scanner-monitor { - position: absolute; - z-index: 8; - left: 12px; - bottom: 92px; - display: none; - grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); - gap: 8px; - width: min(560px, calc(100% - 24px)); - pointer-events: auto; -} -.scanner-monitor.visible { display: grid; } -.scanner-monitor-card { - border: 3px solid var(--line); - background: rgba(255,255,255,.95); - box-shadow: 5px 5px 0 rgba(16,32,21,.18); - padding: 9px; - font-weight: 900; -} -.scanner-monitor-card header { - display: flex; - align-items: center; - justify-content: space-between; - gap: 8px; - margin-bottom: 7px; - text-transform: uppercase; -} -.scanner-monitor-card header strong { font-size: 20px; color: var(--green); } -.scanner-monitor-card header span { font-size: 12px; color: var(--muted); } -.scanner-mini-map { - display: grid; - grid-template-columns: 42px 1fr 82px; - align-items: center; - gap: 6px; - margin-bottom: 8px; -} -.scanner-mini-map > span, -.scanner-mini-map > b { - border: 2px solid var(--line); - background: #f7fff5; - padding: 7px 6px; - text-align: center; - font-size: 13px; - min-height: 36px; -} -.scanner-current { display: block; color: var(--ink); } -.scanner-current.male { color: #2477ff; } -.scanner-current.female { color: #d62a85; } -.scanner-current.poop { color: #7b4a23; } -.scanner-current.empty { color: var(--muted); } - -.scanner-mini-grid { - display: grid; - grid-template-columns: repeat(5, 27px); - gap: 3px; - justify-content: center; - align-items: center; - padding: 6px; - margin: 0 0 8px; - border: 2px solid var(--line); - background: #f6f1df; -} -.scanner-mini-grid .mini-cell { - width: 27px; - height: 27px; - display: grid; - place-items: center; - border: 1px solid rgba(22,38,25,.28); - background: #fffdfa; - color: var(--muted); - font-size: 11px; - font-weight: 900; - line-height: 1; -} -.scanner-mini-grid .mini-cell.belt { background: #e7f7e4; color: var(--green-dark); } -.scanner-mini-grid .mini-cell.input { background: #fff3bf; color: var(--ink); font-size: 9px; } -.scanner-mini-grid .mini-cell.scanner { background: var(--green); color: #fff; border-color: var(--line); font-size: 16px; } -.scanner-mini-grid .mini-cell.scanner.male { background: #2477ff; } -.scanner-mini-grid .mini-cell.scanner.female { background: #d62a85; } -.scanner-mini-grid .mini-cell.scanner.poop { background: #7b4a23; } -.scanner-mini-grid .mini-cell.scanner-other { background: #b7f5c6; color: var(--ink); } -.scanner-mini-grid .mini-cell.egg { background: #fff7c4; color: #7a5a00; } -.scanner-mini-grid .mini-cell.port { background: #dbe7ff; color: #27427d; } -.scanner-mini-grid .mini-cell.blocked { background: #d7cfc1; color: #6d4d35; } - -.scanner-monitor-actions { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 7px; -} -.scanner-monitor-actions button { - border: 3px solid var(--line); - background: var(--green-soft); - color: var(--ink); - cursor: pointer; - font: inherit; - font-size: 14px; - font-weight: 900; - min-height: 44px; - box-shadow: 3px 3px 0 rgba(16,32,21,.18); -} -.scanner-monitor-actions button:disabled { - background: #edf3ec; - color: var(--muted); - opacity: .62; - cursor: not-allowed; -} -@media (max-width: 1180px) { - .scanner-monitor { bottom: 132px; width: min(520px, calc(100% - 16px)); left: 8px; } -} - -/* ------------------------------------------------------------------ - DARK FACTORY VISUAL PASS - - Facility sprites are now loaded from assets/dark_factory/. - - Debug UI is intentionally retained for balancing builds. Do not remove. - ------------------------------------------------------------------ */ -:root { - --bg: #0b0c0f; - --screen: #111318; - --panel: rgba(24, 27, 34, 0.96); - --panel-2: #20242b; - --panel-3: #2a303a; - --ink: #e6edf2; - --muted: #8f9bab; - --line: #050609; - --green: #7bd84f; - --green-soft: #273c24; - --white: #e6edf2; - --danger: #e34a36; - --warn: #ffb827; - --cyan: #4aa3ff; - --orange: #c86a2b; - --shadow: 6px 6px 0 rgba(0, 0, 0, 0.62); -} -html, body { background: #050609; color: var(--ink); } -body { - background: - linear-gradient(90deg, rgba(255,184,39,.035) 1px, transparent 1px) 0 0 / 32px 32px, - linear-gradient(rgba(255,184,39,.028) 1px, transparent 1px) 0 0 / 32px 32px, - #050609; -} -#app { width: min(100vw, 1720px); padding: 0; } -.game-shell { - min-height: 100vh; - border: 0; - background: var(--screen); - box-shadow: inset 0 0 0 4px #050609, inset 0 0 0 8px #303744; -} -#gameCanvas { - height: 100vh; - min-height: 720px; - background: var(--screen); - image-rendering: pixelated; - image-rendering: crisp-edges; -} -.hud { gap: 4px; } -.hud-top-left { - top: 8px; - left: 8px; - right: 420px; - grid-template-columns: 1.25fr repeat(5, minmax(92px, .65fr)); -} -.hud-top-right { - top: 8px; - right: 8px; - grid-template-columns: repeat(4, minmax(74px, auto)); -} -.hud-card { - min-width: 74px; - padding: 7px 9px; - border: 3px solid var(--line); - background: linear-gradient(#242a33, #171a20); - box-shadow: 4px 4px 0 rgba(0,0,0,.7), inset 0 0 0 2px rgba(255,184,39,.10); - color: var(--ink); -} -.hud-card span { color: var(--warn); font-size: 9px; letter-spacing: .12em; } -.hud-card strong { color: var(--ink); text-shadow: 2px 2px 0 #050609; } -.hud-card.cash strong, .hud-card.profit strong, .hud-card.combo strong, .cash-positive { color: var(--green) !important; } -.hud-card.time-critical { background: #3a1f1f; box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(0,0,0,.7); } -.priority-strip { - top: 74px; - left: 10px; - width: clamp(250px, 21vw, 330px); - max-width: none; - grid-template-columns: 1fr; - gap: 6px; -} -.priority-strip > div { - border: 3px solid var(--line); - background: linear-gradient(#222832, #15181e); - color: var(--ink); - box-shadow: 4px 4px 0 rgba(0,0,0,.66), inset 0 0 0 2px rgba(255,184,39,.12); -} -.event-brief.active { background: #38251a; box-shadow: inset 0 0 0 3px var(--orange), 4px 4px 0 rgba(0,0,0,.66); } -.event-brief.next { background: #1c2c20; box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(0,0,0,.66); } -.event-brief.locked { background: #181b20; color: var(--muted); } -.target-brief { color: var(--warn); } -.speed-brief { color: var(--cyan); } -.build-panel { - top: 82px; - right: 8px; - bottom: 8px; - width: clamp(320px, 24vw, 410px); - padding: 9px; - border: 4px solid var(--line); - background: linear-gradient(#222832, #14171d); - box-shadow: 6px 6px 0 rgba(0,0,0,.72), inset 0 0 0 3px rgba(255,184,39,.10); - scrollbar-color: var(--warn) #111318; -} -.panel-head { - display: grid; - grid-template-columns: 1fr 126px; - align-items: stretch; - gap: 8px; - margin-bottom: 8px; -} -.panel-head h1 { color: var(--warn); text-shadow: 2px 2px 0 #050609; font-size: 17px; } -.panel-head h1 span { color: #050609; background: var(--warn); border-color: var(--line); } -.panel-head p { color: var(--muted); } -.panel-grid { - display: grid; - grid-template-columns: 1fr; - gap: 8px; -} -.build-panel h2, .result-section-title { color: var(--warn); } -.large-tools { - grid-template-columns: 1fr 1fr; - gap: 6px; -} -.tool-button, .primary-button, .sort-button, .facility-action { - border: 3px solid var(--line); - background: linear-gradient(#2a303a, #171a20); - color: var(--ink); - box-shadow: 4px 4px 0 rgba(0,0,0,.70), inset 0 0 0 2px rgba(255,184,39,.08); - text-shadow: 1px 1px 0 #050609; -} -.tool-button { min-height: 48px; padding: 8px; } -.tool-button strong { color: var(--ink); } -.tool-button span { color: var(--muted); } -.tool-button.active { - background: linear-gradient(#33311d, #1e2117); - box-shadow: inset 0 0 0 3px var(--warn), 4px 4px 0 rgba(0,0,0,.70); -} -.tool-button.danger.active { background: linear-gradient(#4b1f1c, #241014); box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(0,0,0,.70); } -.primary-button { background: linear-gradient(#8b2d23, #4b1714); color: #fff3d2; } -.primary-button:not(:disabled) { box-shadow: inset 0 0 0 3px #ffb827, 5px 5px 0 rgba(0,0,0,.72); } -.primary-button:disabled, .tool-button:disabled, .sort-button:disabled, .facility-action:disabled { opacity: .42; filter: grayscale(1); } -.mini-box, .event-card, .formula-box, .equipment-menu-lines, .route-card, .result-grid div, .muted-title { - border: 3px solid var(--line); - background: #15181e; - color: var(--muted); - box-shadow: inset 0 0 0 2px rgba(255,184,39,.08); -} -.event-card h3, .event-card strong, .event-metrics span { color: var(--ink); } -.event-card.accepted { background: #1c2c20; box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(0,0,0,.66); } -.event-card.empty { background: #15181e; color: var(--muted); } -.event-metrics span { border-color: #3d4654; background: #20242b; } -.event-status { background: #2a303a; color: var(--warn); border-color: var(--line); } -.control-dock { - left: 50%; - right: auto; - bottom: 8px; - transform: translateX(-50%); - grid-template-columns: repeat(4, minmax(135px, 160px)); - gap: 6px; - padding: 6px; - border: 4px solid var(--line); - background: rgba(13,15,19,.96); - box-shadow: 5px 5px 0 rgba(0,0,0,.72), inset 0 0 0 2px rgba(255,184,39,.10); -} -.sort-button { min-height: 44px; font-size: 12px; } -.scanner-monitor { - position: absolute; - z-index: 5; - left: 10px; - top: 198px; - width: clamp(250px, 21vw, 330px); -} -.scanner-monitor-card { - border: 3px solid var(--line) !important; - background: linear-gradient(#222832, #15181e) !important; - color: var(--ink) !important; - box-shadow: 4px 4px 0 rgba(0,0,0,.66), inset 0 0 0 2px rgba(255,184,39,.10) !important; -} -.scanner-monitor-card strong { color: var(--warn); } -.debug-panel { - left: auto; - right: 12px; - bottom: 10px; - width: min(420px, calc(100% - 24px)); - border-color: var(--line); - background: rgba(16,18,23,.97); - box-shadow: 5px 5px 0 rgba(0,0,0,.72), inset 0 0 0 2px rgba(227,74,54,.18); - color: var(--ink); -} -.debug-panel summary { color: var(--danger); } -.debug-body { border-top-color: var(--line); } -.debug-body button, .debug-body input[type="number"], .debug-body select, .debug-readout { - border-color: var(--line); - background: #20242b; - color: var(--ink); -} -.debug-readout { color: var(--muted); } -.modal { background: rgba(3,4,6,.72); } -.modal-card { - border-color: var(--line); - background: linear-gradient(#242a33, #15181e); - color: var(--ink); - box-shadow: 8px 8px 0 rgba(0,0,0,.72), inset 0 0 0 3px rgba(255,184,39,.12); -} -.modal-card h2 { color: var(--warn); text-shadow: 2px 2px 0 #050609; } -.modal-card ul, .modal-card p { color: var(--muted); } -.hover-tooltip { - border-color: var(--line) !important; - background: rgba(20,23,29,.98) !important; - color: var(--ink) !important; - box-shadow: 5px 5px 0 rgba(0,0,0,.72) !important; -} -::-webkit-scrollbar { width: 14px; height: 14px; } -::-webkit-scrollbar-track { background: #111318; } -::-webkit-scrollbar-thumb { background: #333b48; border: 3px solid #111318; } -::-webkit-scrollbar-thumb:hover { background: #ffb827; } -@media (max-width: 1180px) { - .hud-top-left { right: 8px; grid-template-columns: repeat(3, minmax(80px, 1fr)); } - .hud-top-right { top: 132px; left: 8px; right: auto; grid-template-columns: repeat(2, minmax(82px, auto)); } - .priority-strip { top: 226px; } - .scanner-monitor { top: 348px; } - .build-panel { left: 8px; right: 8px; bottom: 8px; width: auto; max-height: 46vh; } - .control-dock { grid-template-columns: repeat(2, 150px); } -} - -/* v27.16: compact collapsed debug panel + icon card layout */ -.debug-panel:not([open]) { - width: 104px !important; - min-width: 0; - overflow: hidden; -} -.debug-panel:not([open]) summary { - display: block; - width: 100%; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} -.debug-panel[open] { - width: min(420px, calc(100% - 24px)); -} - -.card-choice { - position: relative; - display: grid; - grid-template-columns: 54px minmax(0, 1fr); - gap: 10px; - align-items: start; - min-height: 150px; - overflow: hidden; - background: - linear-gradient(135deg, rgba(255,255,255,.08), rgba(0,0,0,.20)), - #20242b; - border-color: var(--line); -} -.card-choice::before { - content: ""; - position: absolute; - inset: 5px; - border: 1px solid rgba(255,184,39,.18); - pointer-events: none; -} -.card-icon { - position: relative; - z-index: 1; - width: 46px; - height: 46px; - display: grid; - place-items: center; - border: 3px solid var(--line); - background: #15181e; - box-shadow: inset 0 0 0 2px rgba(255,184,39,.10), 3px 3px 0 rgba(0,0,0,.35); - image-rendering: pixelated; -} -.card-icon img { - width: 36px; - height: 36px; - object-fit: contain; - image-rendering: pixelated; -} -.card-icon.glyph { - color: var(--warn, #ffb827); - font-size: 24px; - font-weight: 900; - text-align: center; - line-height: 1; -} -.card-copy { - position: relative; - z-index: 1; - min-width: 0; -} -.card-choice strong { - color: var(--warn, #ffb827); - text-shadow: 1px 1px 0 #050609; -} -.card-choice small { color: var(--muted); } -.card-tags span { - background: #15181e; - color: var(--white); - border-color: var(--line); -} -.card-choice.common { background: linear-gradient(145deg, #262c35, #171a20); } -.card-choice.rare { - background: linear-gradient(145deg, #3b3020, #191b20); - box-shadow: inset 0 0 0 3px #f0a020, 5px 5px 0 rgba(0,0,0,.50); -} -.card-choice.ultra-rare { - background: linear-gradient(145deg, #401d2a, #171a20); - box-shadow: inset 0 0 0 3px #c42424, 5px 5px 0 rgba(0,0,0,.55); -} -.card-choice.dud { - background: linear-gradient(145deg, #2b2b2b, #191919); - color: #878787; -} -.card-choice.dud .card-tags span { background: #222; color: #aaa; } - -@media (max-width: 1180px) { - .debug-panel:not([open]) { - width: 92px !important; - right: 8px; - bottom: 8px; - } -} - - -/* v27.18 inherited cache-proof identity and final UI overrides */ -.build-stamp { - position: absolute; - z-index: 12; - right: 14px; - top: 76px; - padding: 5px 9px; - border: 2px solid #ffb827; - background: rgba(14, 17, 22, .94); - color: #80e067; - box-shadow: 3px 3px 0 rgba(0,0,0,.7); - font: 900 11px/1 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; - letter-spacing: .04em; - pointer-events: none; -} -.debug-panel:not([open]) { - width: 58px !important; - max-width: 58px !important; - height: 30px; - min-height: 0; -} -.debug-panel:not([open]) summary { - box-sizing: border-box; - width: 58px; - height: 27px; - padding: 5px 7px; - text-align: center; - overflow: hidden; - text-overflow: clip; -} -.debug-panel[open] { - width: min(390px, calc(100% - 24px)) !important; - height: auto; -} -.card-choice { - border-width: 3px; - box-shadow: 4px 4px 0 rgba(0,0,0,.55), inset 0 0 0 1px rgba(255,184,39,.14); -} -.card-choice:hover { - transform: translateY(-2px); - box-shadow: 4px 6px 0 rgba(0,0,0,.65), inset 0 0 0 2px rgba(128,224,103,.24); -} -.card-icon img { - image-rendering: pixelated; - filter: drop-shadow(2px 2px 0 rgba(0,0,0,.7)); -} -#gameCanvas { image-rendering: pixelated; } - -/* v27.18: status relocation, consistent industrial controls, card watermarks */ -.hud-top-left { grid-template-columns: repeat(5, minmax(82px, auto)); } - -.left-bottom-status { - position: absolute; - z-index: 6; - left: 10px; - bottom: 10px; - width: min(310px, calc(100% - 20px)); - display: grid; - grid-template-columns: 1fr 1fr; - gap: 6px; - pointer-events: none; -} -.left-bottom-status > div { - min-width: 0; - border: 3px solid var(--line); - background: rgba(22, 26, 32, .95); - color: var(--ink); - padding: 8px 10px; - box-shadow: 4px 4px 0 rgba(0,0,0,.68), inset 0 0 0 1px rgba(255,184,39,.10); - font-size: 12px; - line-height: 1.2; - font-weight: 900; - text-transform: uppercase; - letter-spacing: .025em; - overflow: hidden; - text-overflow: ellipsis; -} -.left-bottom-status .event-brief { grid-column: 1 / -1; white-space: normal; min-height: 39px; } -.left-bottom-status .event-brief.active { background: #35221c; box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(0,0,0,.68); } -.left-bottom-status .event-brief.next { background: #22301f; box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(0,0,0,.68); } -.left-bottom-status .event-brief.locked { background: #1c2027; color: var(--muted); } -.left-bottom-status .speed-brief { color: #d9e2e8; } -.left-bottom-status .target-brief { color: #ffcf68; } -.left-bottom-status .combo-brief { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; } -.left-bottom-status .combo-brief span { color: var(--muted); font-size: 10px; } -.left-bottom-status .combo-brief strong { color: var(--green); font-size: 22px; line-height: 1; } - -/* Remove the remaining bright green/white control styling from modal actions. */ -.modal-actions button, -.facility-action, -.card-target-button { - border: 3px solid #07080a; - background: linear-gradient(#353d48, #1b1f25); - color: #e6edf2; - box-shadow: inset 0 0 0 1px rgba(255,184,39,.14), 4px 4px 0 rgba(0,0,0,.68); -} -.modal-actions button:hover:not(:disabled), -.facility-action:hover:not(:disabled), -.card-target-button:hover:not(:disabled) { - background: linear-gradient(#424b58, #242930); - color: #fff0c9; - box-shadow: inset 0 0 0 2px rgba(255,184,39,.42), 4px 4px 0 rgba(0,0,0,.72); -} -.facility-action.warn, -.modal-actions .reroll-button { - background: linear-gradient(#554221, #2b2419); - color: #ffd36a; - box-shadow: inset 0 0 0 3px #b97810, 5px 5px 0 rgba(0,0,0,.72); -} -.modal-actions .reroll-button:hover:not(:disabled) { - background: linear-gradient(#6b5227, #342919); - color: #fff0bd; - box-shadow: inset 0 0 0 3px #ffb827, 5px 5px 0 rgba(0,0,0,.76); -} -.facility-action.good { background: linear-gradient(#29422a, #19271a); color: #a9ed91; } -.facility-action.danger { background: linear-gradient(#57251f, #2d1715); color: #ffb1a3; } -.modal-actions button:disabled, -.facility-action:disabled, -.card-target-button:disabled { opacity: .42; filter: grayscale(.85); box-shadow: 3px 3px 0 rgba(0,0,0,.45); } - -/* Icons are now translucent background art rather than separate foreground badges. */ -.card-choice { - display: block; - min-height: 170px; - padding: 16px; - isolation: isolate; -} -.card-choice::before { z-index: 1; } -.card-copy { position: relative; z-index: 3; padding-right: 6px; } -.card-icon { - position: absolute; - z-index: 0; - right: -9px; - bottom: -12px; - width: 124px; - height: 124px; - border: 0; - background: transparent; - box-shadow: none; - opacity: .14; - transform: rotate(-7deg); - pointer-events: none; - overflow: visible; -} -.card-icon img { - width: 100%; - height: 100%; - object-fit: contain; - filter: grayscale(.12) contrast(1.2) drop-shadow(3px 3px 0 rgba(0,0,0,.55)); -} -.card-icon.glyph { - display: grid; - place-items: center; - color: #f0b437; - font-size: 88px; - line-height: 1; - text-shadow: 4px 4px 0 rgba(0,0,0,.55); -} -.card-choice.rare .card-icon { opacity: .16; } -.card-choice.ultra-rare .card-icon { opacity: .17; } -.card-choice.dud .card-icon { opacity: .08; filter: grayscale(1); } - -@media (max-width: 1180px) { - .hud-top-left { grid-template-columns: repeat(3, minmax(80px, 1fr)); } - .left-bottom-status { width: 290px; left: 8px; bottom: 8px; } -} -@media (max-width: 760px) { - .left-bottom-status { width: min(270px, calc(100% - 16px)); grid-template-columns: 1fr; } - .left-bottom-status .event-brief { grid-column: auto; } -} diff --git a/styles-v27.19.css b/styles-v27.19.css deleted file mode 100644 index 3ddf905..0000000 --- a/styles-v27.19.css +++ /dev/null @@ -1,1279 +0,0 @@ -:root { - --bg: #f2fff0; - --screen: #eefbea; - --panel: rgba(245, 255, 242, 0.96); - --ink: #102015; - --muted: #526456; - --line: #102015; - --green: #22b94f; - --green-soft: #b7f5c6; - --white: #ffffff; - --danger: #c42424; - --shadow: 8px 8px 0 rgba(16, 32, 21, 0.22); -} -* { box-sizing: border-box; } -html, body { min-height: 100%; } -body { margin: 0; background: var(--bg); color: var(--ink); font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; overflow-x: hidden; } -button { font: inherit; } -h1, h2, p { margin: 0; } -#app { width: min(100vw, 1680px); margin: 0 auto; padding: 0 8px 12px; } -.game-shell { position: relative; width: 100%; min-height: min(100vh, 920px); border: 4px solid var(--line); border-top: 0; background: var(--screen); overflow: hidden; box-shadow: var(--shadow); } -#gameCanvas { display: block; width: 100%; height: min(calc(100vh - 10px), 900px); min-height: 720px; background: var(--screen); touch-action: none; } -.hud { position: absolute; z-index: 4; display: grid; gap: 6px; pointer-events: none; } -.hud-top-left { top: 10px; left: 10px; grid-template-columns: repeat(6, minmax(82px, auto)); } -.hud-top-right { top: 10px; right: 10px; grid-template-columns: repeat(4, minmax(78px, auto)); } -.hud-card { min-width: 82px; padding: 7px 9px; border: 3px solid var(--line); background: rgba(255,255,255,.88); box-shadow: 4px 4px 0 rgba(16,32,21,.16); } -.hud-card.primary { min-width: 116px; padding: 10px 12px; background: rgba(255,255,255,.96); } -.hud-card.primary span { font-size: 9px; } -.hud-card.primary strong { font-size: clamp(22px, 2vw, 32px); } -.hud-card.time-critical { background: #fff0d1; box-shadow: inset 0 0 0 4px var(--danger), 4px 4px 0 rgba(16,32,21,.16); } -.hud-card span { display: block; font-size: 9px; letter-spacing: .1em; color: var(--muted); margin-bottom: 4px; } -.hud-card strong { font-size: clamp(15px, 1.3vw, 22px); line-height: 1; color: var(--ink); } -.hud-card.cash strong, .hud-card.profit strong, .hud-card.combo strong, .cash-positive { color: var(--green) !important; } -.cash-negative { color: var(--danger) !important; } - -.priority-strip { position: absolute; z-index: 5; top: 76px; left: 10px; display: grid; grid-template-columns: minmax(280px, 1.2fr) minmax(170px, .75fr) minmax(130px, .55fr); gap: 8px; max-width: calc(100% - 420px); pointer-events: none; } -.priority-strip > div { border: 3px solid var(--line); background: rgba(255,255,255,.94); padding: 8px 10px; font-weight: 900; text-transform: uppercase; box-shadow: 4px 4px 0 rgba(16,32,21,.14); font-size: 12px; letter-spacing: .03em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } -.event-brief.active { background: #fff0d1; box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(16,32,21,.14); } -.event-brief.next { background: var(--green-soft); box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(16,32,21,.14); } -.event-brief.locked { background: #edf3ec; color: var(--muted); } -.target-brief { color: var(--green); } -.speed-brief { color: var(--ink); } - -.build-panel { position: absolute; z-index: 6; top: 118px; right: 12px; bottom: 12px; width: clamp(278px, 23vw, 360px); min-height: 0; padding: 10px; border: 4px solid var(--line); background: var(--panel); box-shadow: var(--shadow); overflow: auto; } -.panel-head { display: grid; gap: 8px; margin-bottom: 10px; } -.panel-head h1 { font-size: 15px; letter-spacing: .06em; } -.panel-head h1 span { font-size: 9px; color: var(--white); background: var(--green); border: 2px solid var(--line); padding: 1px 6px; } -.panel-head p { color: var(--muted); margin-top: 4px; font-size: 9px; line-height: 1.25; } -.panel-grid { display: grid; grid-template-columns: 1fr; gap: 10px; } -.build-panel h2 { font-size: 11px; text-transform: uppercase; letter-spacing: .1em; margin-bottom: 7px; } -.large-tools { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; } -.history-tools { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; grid-column: 1 / -1; } -.tool-button.small { min-height: 40px; padding: 6px; } -.tool-button, .primary-button, .sort-button, .facility-action { border: 3px solid var(--line); background: var(--white); color: var(--ink); font-weight: 900; text-transform: uppercase; cursor: pointer; box-shadow: 4px 4px 0 rgba(16,32,21,.18); } -.tool-button { min-height: 50px; text-align: left; padding: 8px; } -.tool-button strong { display: block; font-size: 12px; } -.tool-button span { display: block; margin-top: 4px; font-size: 9px; color: var(--muted); } -.tool-button.active { background: var(--green-soft); box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(16,32,21,.18); } -.tool-button.danger.active { background: #ffdada; box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(16,32,21,.18); } -.primary-button { padding: 10px 12px; background: var(--green); color: var(--white); white-space: nowrap; } -.primary-button:disabled, .tool-button:disabled, .sort-button:disabled, .facility-action:disabled { opacity: .42; cursor: not-allowed; } -.mini-box { border: 3px solid var(--line); background: var(--white); padding: 12px; line-height: 1.45; color: var(--muted); font-size: 11px; } -.facility-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; } -.facility-action { padding: 7px 9px; font-size: 9px; } -.facility-action.good { background: var(--green-soft); } -.facility-action.warn { background: #fff0d1; } -.facility-action.danger { background: #ffdada; } -.control-dock { position: absolute; z-index: 7; left: 50%; bottom: 12px; transform: translateX(-50%); display: grid; grid-template-columns: repeat(4, 150px); gap: 8px; padding: 7px; border: 3px solid var(--line); background: rgba(255,255,255,.90); } -.sort-button { min-height: 46px; font-size: 12px; } -/* Debug UI is intentionally kept for active balancing builds. Do not remove during cleanup/audit passes unless explicitly requested. */ -.debug-panel { - position: absolute; - z-index: 9; - left: 10px; - bottom: 10px; - width: min(410px, calc(100% - 20px)); - border: 3px solid var(--line); - background: rgba(255,255,255,.96); - box-shadow: 4px 4px 0 rgba(16,32,21,.16); - font-weight: 900; -} -.debug-panel summary { - cursor: pointer; - padding: 5px 8px; - color: var(--danger); - font-size: 14px; - line-height: 1.1; -} -.debug-body { - display: grid; - grid-template-columns: 1fr 92px; - gap: 6px; - padding: 7px; - border-top: 3px solid var(--line); - font-size: 12px; - line-height: 1.15; -} -.debug-body label, -.debug-body button, -.debug-body select, -.debug-body input { - min-width: 0; - font: inherit; -} -.debug-check, -.debug-card, -.debug-target, -.debug-readout { - grid-column: 1 / -1; -} -.debug-row { - display: grid; - grid-template-columns: 1fr 92px; - gap: 6px; - grid-column: 1 / -1; -} -.debug-day { - display: grid; - grid-template-columns: 38px 1fr; - align-items: center; - gap: 4px; -} -.debug-body button { - border: 2px solid var(--line); - background: var(--white); - cursor: pointer; - font-weight: 900; - padding: 5px 6px; - line-height: 1.05; -} -.debug-body input[type="number"], -.debug-body select { - width: 100%; - border: 2px solid var(--line); - background: var(--white); - padding: 4px 5px; - min-height: 29px; -} -.debug-target select:disabled { - opacity: .55; -} -.debug-readout { - border: 2px solid var(--line); - background: #f7fff5; - color: var(--muted); - padding: 5px; - line-height: 1.25; - max-height: 64px; - overflow: auto; -} -.modal { position: fixed; inset: 0; z-index: 20; display: none; align-items: center; justify-content: center; padding: 22px; background: rgba(16,32,21,.45); } -.modal.visible { display: flex; } -.modal-card { width: min(860px, 96vw); border: 4px solid var(--line); padding: 24px; background: var(--white); box-shadow: var(--shadow); } -.modal-card h2 { font-size: 26px; text-transform: uppercase; margin-bottom: 12px; } -.modal-card p { line-height: 1.55; } -.modal-card ul { margin: 12px 0 0; padding-left: 22px; line-height: 1.55; color: var(--muted); } -.modal-actions { margin-top: 18px; display: flex; justify-content: flex-end; gap: 10px; flex-wrap: wrap; } -.route-cards { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; margin: 14px 0; } -.route-card { border: 3px solid var(--line); background: #f7fff5; padding: 14px; display: grid; grid-template-columns: 44px 1fr 28px 1fr; align-items: center; gap: 4px 8px; } -.route-card .route-icon { grid-row: 1 / span 2; font-size: 30px; text-align: center; } -.route-card strong, .route-card em { font-style: normal; font-weight: 900; text-transform: uppercase; } -.route-card b { font-size: 24px; color: var(--green); text-align: center; } -.route-card small { grid-column: 2 / span 3; color: var(--muted); font-weight: 900; } -.result-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin-top: 12px; } -.result-grid div { border: 3px solid var(--line); padding: 10px; background: #f7fff5; } -.result-grid strong { display: block; font-size: 11px; color: var(--muted); text-transform: uppercase; margin-bottom: 6px; } -.result-grid span { font-size: 16px; font-weight: 900; color: var(--ink); } -.game-shell:not(.phase-build) .build-panel { display: none; } -.game-shell.phase-running .hud-top-right { display: none; } -.game-shell:not(.phase-running) .control-dock { display: none; } -@media (max-width: 1180px) { - #app { padding: 0; } - .game-shell { min-height: 100vh; } - #gameCanvas { height: 100vh; } - .hud-top-left, .hud-top-right { grid-template-columns: repeat(2, minmax(76px, auto)); } - .priority-strip { top: 150px; left: 8px; right: 8px; max-width: none; grid-template-columns: 1fr; } - .build-panel { top: auto; left: 8px; right: 8px; bottom: 8px; width: auto; max-height: 42vh; } - .large-tools { grid-template-columns: 1fr 1fr; } - .control-dock { grid-template-columns: repeat(2, 150px); } - .route-cards, .result-grid { grid-template-columns: 1fr; } -} - -.event-card { border: 3px solid var(--line); background: #f7fff5; padding: 12px; line-height: 1.35; color: var(--ink); font-size: 11px; box-shadow: 4px 4px 0 rgba(16,32,21,.14); } -.event-card.empty { color: var(--muted); background: rgba(255,255,255,.72); } -.event-card.empty strong { display: block; color: var(--ink); margin-bottom: 4px; } -.event-card h3 { margin: 2px 0 7px; font-size: 14px; text-transform: uppercase; letter-spacing: .04em; } -.event-card p { margin: 5px 0; } -.event-card.accepted { background: var(--green-soft); box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(16,32,21,.14); } -.event-card.declined { background: #f1f1f1; color: var(--muted); } -.event-status { display: inline-block; padding: 2px 7px; border: 2px solid var(--line); background: var(--white); font-size: 9px; font-weight: 900; letter-spacing: .1em; margin-bottom: 4px; } -.event-metrics { display: grid; grid-template-columns: 1fr; gap: 4px; margin: 8px 0; } -.event-metrics span { display: block; border: 2px solid rgba(16,32,21,.55); background: rgba(255,255,255,.82); padding: 5px; font-weight: 900; color: var(--ink); } -.event-actions { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; } -.result-section-title { margin: 16px 0 8px; font-size: 12px; font-weight: 900; text-transform: uppercase; letter-spacing: .12em; color: var(--green); } -.result-section-title:first-child { margin-top: 0; } -.muted-title { color: var(--muted); border: 3px solid var(--line); padding: 10px; background: #f7fff5; } - -.compact-rules .mini-box { padding: 8px; font-size: 9px; } -.primary-button:disabled { filter: grayscale(1); background: #c9d2ca; color: #526456; } -.formula-box { - border: 3px solid var(--line); - background: #f7fff5; - padding: 10px; - margin: 10px 0; - line-height: 1.5; - color: var(--ink); - font-size: 12px; - font-weight: 700; -} -.equipment-menu-lines { - border: 3px solid var(--line); - background: #ffffff; - padding: 10px; - margin: 8px 0; - color: var(--muted); - line-height: 1.45; -} -.equipment-menu-lines p { margin: 4px 0; } - -/* v11 compact clicked-equipment bubble */ -.modal.equipment-popover { - background: transparent; - align-items: flex-start; - justify-content: flex-start; - padding: 0; - pointer-events: none; -} -.modal.equipment-popover .modal-card { - position: absolute; - left: var(--popover-x, 16px); - top: var(--popover-y, 16px); - width: min(250px, calc(100vw - 24px)); - max-height: min(280px, calc(100vh - 24px)); - overflow: auto; - padding: 8px; - border-width: 3px; - pointer-events: auto; - box-shadow: 6px 6px 0 rgba(16,32,21,.18); -} -.modal.equipment-popover .modal-card h2 { - font-size: 14px; - margin-bottom: 6px; -} -.modal.equipment-popover .modal-actions { - margin-top: 8px; - gap: 6px; - justify-content: flex-start; -} -.modal.equipment-popover .modal-actions button { - padding: 5px 7px; - font-size: 9px; -} -.equipment-menu-lines.compact { - padding: 7px; - margin: 6px 0; - font-size: 9px; -} -.formula-box.compact { - padding: 7px; - margin: 6px 0; - font-size: 9px; -} - -/* v15 pre-build card draft */ -.card-choices { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(190px, 220px)); - justify-content: center; - align-items: stretch; - gap: 10px; - margin-top: 14px; -} -.card-choice { - min-height: 132px; - border: 3px solid var(--line); - background: #f7fff5; - color: var(--ink); - box-shadow: 5px 5px 0 rgba(16,32,21,.16); - padding: 12px; - text-align: left; - cursor: pointer; - font-weight: 900; -} -.card-choice:hover { transform: translate(-1px, -1px); box-shadow: 6px 6px 0 rgba(16,32,21,.18); } -.card-choice strong { display: block; font-size: 14px; text-transform: uppercase; line-height: 1.2; } -.card-choice span { display: inline-block; margin: 8px 0; padding: 2px 7px; border: 2px solid var(--line); background: var(--white); font-size: 9px; letter-spacing: .1em; } -.card-tags { display: flex; flex-wrap: wrap; gap: 4px; margin: 7px 0; } -.card-tags span { margin: 0; padding: 2px 5px; font-size: 8px; line-height: 1.1; letter-spacing: .04em; } -.card-choice small { display: block; color: var(--muted); font-size: 11px; line-height: 1.35; } -.card-choice.rare { background: #fff0d1; box-shadow: inset 0 0 0 3px #f0a020, 5px 5px 0 rgba(16,32,21,.16); } -.card-choice.ultra-rare { background: #ffe6f0; box-shadow: inset 0 0 0 3px #c42424, 5px 5px 0 rgba(16,32,21,.18); } -.card-choice.ultra-rare span { background: #c42424; color: #fff; } -.muted-card-note { color: var(--muted); font-weight: 700; } -.card-targets { display: grid; gap: 8px; margin-top: 14px; } -.card-target-button { border: 3px solid var(--line); background: #f7fff5; padding: 10px 12px; text-align: left; cursor: pointer; font-weight: 900; box-shadow: 4px 4px 0 rgba(16,32,21,.14); } -.card-target-button:hover { background: var(--green-soft); } - -/* v19 readability pass */ -body { font-size: 16px; } -.hud-card span { font-size: 11px; } -.hud-card strong { font-size: clamp(18px, 1.5vw, 25px); } -.priority-strip > div { font-size: 14px; } -.panel-head h1 { font-size: 18px; } -.panel-head p { font-size: 11px; } -.build-panel h2 { font-size: 13px; } -.tool-button strong { font-size: 14px; } -.tool-button span { font-size: 11px; } -.mini-box, .event-card { font-size: 12px; } -.sort-button { font-size: 14px; } -.modal-card h2 { font-size: 29px; } -.card-choice strong { font-size: 16px; } -.card-choice small { font-size: 13px; } - -.tool-button.unaffordable, .tool-button.already-built { opacity: .42; filter: grayscale(.7); } - -.hover-tooltip { - position: fixed; - z-index: 30; - width: min(320px, calc(100vw - 20px)); - display: none; - border: 3px solid var(--line); - background: rgba(255,255,255,.96); - color: var(--ink); - box-shadow: 6px 6px 0 rgba(16,32,21,.18); - padding: 10px; - pointer-events: none; - line-height: 1.35; -} -.hover-tooltip.visible { display: block; } -.hover-tooltip strong { display: block; font-size: 15px; text-transform: uppercase; margin-bottom: 5px; } -.hover-tooltip em { display: block; font-style: normal; color: var(--green); font-weight: 900; margin-bottom: 7px; } -.hover-tooltip em.warning { color: var(--danger); } -.hover-tooltip span { display: block; color: var(--muted); font-size: 12px; } - - -.card-choice.dud { - background: #eeeeee; - color: #777; - filter: grayscale(1); - border-style: dashed; - box-shadow: 5px 5px 0 rgba(16,32,21,.10); -} -.card-choice.dud span { background: #f8f8f8; } -.card-choice.flung { - pointer-events: none; - transform: translate(var(--fling-x, 480px), var(--fling-y, -320px)) rotate(var(--fling-r, 68deg)) scale(.68); - opacity: 0; - transition: transform .34s cubic-bezier(.18,.84,.26,.99), opacity .28s ease-in; -} - - - -.route-card .route-icon.male, -.route-card .route-icon.female, -.route-card .route-icon.poop { - display: inline-grid; - place-items: center; - width: 38px; - height: 38px; - border-radius: 999px; - border: 3px solid var(--line, #102015); - background: var(--white, #fff); - line-height: 1; -} -.route-card .route-icon.male { color: #2477ff; background: #d9ecff; } -.route-card .route-icon.female { color: #d62a85; background: #ffe0f0; } -.route-card .route-icon.poop { color: #7b4a23; background: #fff0d1; font-size: 24px; } -.restart-button { min-width: 160px; } -.restart-fallback-note { margin-top: 12px; color: var(--muted, #526456); font-weight: 700; } - -/* v24.4 hover-only build-button flavor / cashout guidance / compact game-over */ -.tool-button .tool-flavor { - display: block; - max-height: 0; - opacity: 0; - overflow: hidden; - margin-top: 0; - color: var(--muted); - font-size: 8px; - line-height: 1.22; - text-transform: none; - letter-spacing: 0; - transition: max-height .12s ease, opacity .12s ease, margin-top .12s ease; -} -.tool-button:hover .tool-flavor { - max-height: 42px; - opacity: 1; - margin-top: 5px; -} -.large-tools .tool-button { min-height: 58px; } -.large-tools .tool-button:hover { min-height: 78px; } -.history-tools .tool-button.small { min-height: 40px; } -.primary-button.cashout-emphasis, -.tool-button.cashout-emphasis { - opacity: 1 !important; - filter: none !important; - animation: cashoutPulse 0.9s ease-in-out infinite alternate; -} -.primary-button.cashout-emphasis { - box-shadow: inset 0 0 0 4px #fff0d1, 6px 6px 0 rgba(16,32,21,.22); -} -.tool-button.cashout-emphasis { - background: #fff0d1; - box-shadow: inset 0 0 0 3px var(--danger), 6px 6px 0 rgba(16,32,21,.20); -} -@keyframes cashoutPulse { - from { transform: translate(0, 0); } - to { transform: translate(-1px, -1px); } -} -.modal.gameover-modal { padding: 12px; } -.modal.gameover-modal .modal-card { - width: min(640px, 92vw); - max-height: min(82vh, 720px); - overflow: auto; - padding: 16px; -} -.modal.gameover-modal .modal-card h2 { - font-size: 22px; - margin-bottom: 8px; -} -.gameover-reason { font-weight: 900; color: var(--danger); margin-bottom: 8px; } -.settlement-net { - border: 3px solid var(--line); - background: #f7fff5; - padding: 10px 12px; - margin-bottom: 10px; - display: flex; - justify-content: space-between; - align-items: center; - gap: 12px; - font-weight: 900; - text-transform: uppercase; -} -.settlement-net strong { font-size: 24px; } -.settlement-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; } -.settlement-grid div { padding: 8px; } -.settlement-grid span { display: block; font-size: 14px; } -.gameover-summary { - grid-template-columns: repeat(4, minmax(0, 1fr)); - gap: 6px; - margin-top: 8px; -} -.gameover-breakdown { - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 6px; - margin-top: 8px; -} -.modal.gameover-modal .result-grid div { padding: 7px; } -.modal.gameover-modal .result-grid strong { font-size: 9px; margin-bottom: 3px; } -.modal.gameover-modal .result-grid span { font-size: 12px; } -.gameover-details { - margin-top: 10px; - border: 3px solid var(--line); - background: #f7fff5; - padding: 8px; -} -.gameover-details summary { - cursor: pointer; - font-weight: 900; - text-transform: uppercase; -} -.modal.gameover-modal .formula-box.compact { font-size: 9px; line-height: 1.35; } -@media (max-width: 720px) { - .gameover-summary, .gameover-breakdown { grid-template-columns: 1fr 1fr; } -} - -/* v27.0 cleanup and stable build-menu tooltip pass */ -body { font-size: 18px; } -.build-panel { width: clamp(330px, 26vw, 420px); } -.panel-head h1 { font-size: 20px; } -.panel-head h1 span { font-size: 12px; } -.panel-head p { font-size: 13px; line-height: 1.35; } -.build-panel h2 { font-size: 14px; } -.priority-strip > div { font-size: 15px; } -.hud-card span { font-size: 12px; } -.hud-card strong { font-size: clamp(20px, 1.7vw, 28px); } -.mini-box, .event-card { font-size: 14px; line-height: 1.45; } -.compact-rules .mini-box { font-size: 13px; } -.tool-button { - position: relative; - overflow: visible; - min-height: 62px; - padding: 10px; -} -.large-tools .tool-button { min-height: 62px; } -.large-tools .tool-button:hover { min-height: 62px; } -.tool-button strong { font-size: 15px; line-height: 1.15; } -.tool-button span { font-size: 12px; } -.tool-button .tool-flavor { - display: none; - position: absolute; - z-index: 60; - left: 0; - top: calc(100% + 7px); - width: min(300px, calc(100vw - 40px)); - max-height: none; - opacity: 1; - overflow: visible; - margin: 0; - padding: 10px 12px; - border: 3px solid var(--line); - background: rgba(255,255,255,.98); - color: var(--ink); - box-shadow: 5px 5px 0 rgba(16,32,21,.18); - font-size: 13px; - line-height: 1.35; - text-transform: none; - letter-spacing: 0; - pointer-events: none; - transition: none; -} -.tool-button .tool-flavor::before { - content: ''; - position: absolute; - left: 16px; - top: -10px; - width: 16px; - height: 16px; - border-left: 3px solid var(--line); - border-top: 3px solid var(--line); - background: rgba(255,255,255,.98); - transform: rotate(45deg); -} -.tool-button:hover .tool-flavor { - display: block; - max-height: none; - opacity: 1; - margin: 0; -} -.primary-button { font-size: 16px; padding: 13px 16px; } -#nextTurnButton { min-height: 56px; font-size: 18px; } -@keyframes cashoutPulse { - from { box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(16,32,21,.18); filter: brightness(1); } - to { box-shadow: inset 0 0 0 5px #fff0d1, 4px 4px 0 rgba(16,32,21,.20); filter: brightness(1.08); } -} -.card-choices { grid-template-columns: repeat(auto-fill, minmax(230px, 270px)); gap: 14px; } -.card-choice { min-height: 164px; padding: 15px; } -.card-choice strong { font-size: 18px; } -.card-choice span { font-size: 11px; } -.card-choice small { font-size: 15px; line-height: 1.4; } -.muted-card-note { font-size: 15px; line-height: 1.45; } -.modal-card { width: min(980px, 96vw); } -.modal-card p, .modal-card li { font-size: 16px; } -.modal-actions .reroll-button { - order: 99; - flex: 1 1 100%; - min-height: 64px; - margin-top: 8px; - font-size: 20px; - text-align: center; - justify-content: center; - background: #fff0d1; - box-shadow: inset 0 0 0 4px var(--green), 6px 6px 0 rgba(16,32,21,.20); -} -.modal-actions .reroll-button:disabled { box-shadow: 4px 4px 0 rgba(16,32,21,.12); } -.hover-tooltip strong { font-size: 17px; } -.hover-tooltip span { font-size: 14px; } -.sort-button { font-size: 16px; min-height: 56px; } -.control-dock { grid-template-columns: repeat(4, 172px); } -@media (max-width: 1180px) { - .build-panel { width: auto; } - .control-dock { grid-template-columns: repeat(2, 172px); } -} - -/* v27.1 expansion/readability pass */ -body { font-size: 20px; } -.panel-head h1 { font-size: 22px; } -.panel-head h1 span { font-size: 13px; } -.panel-head p { font-size: 14px; line-height: 1.35; } -.build-panel h2 { font-size: 15px; } -.priority-strip > div { font-size: 16px; } -.hud-card span { font-size: 13px; } -.hud-card strong { font-size: clamp(22px, 1.8vw, 30px); } -.mini-box, .event-card { font-size: 15px; line-height: 1.5; } -.compact-rules .mini-box { font-size: 14px; } -.tool-button strong { font-size: 16px; line-height: 1.15; } -.tool-button span { font-size: 13px; line-height: 1.2; } -.tool-button .tool-flavor { - left: auto; - right: 0; - width: min(320px, calc(100vw - 40px)); - font-size: 14px; - line-height: 1.4; - overflow-wrap: anywhere; -} -.tool-button .tool-flavor::before { left: auto; right: 18px; } -.tool-button.unaffordable .tool-flavor, -.tool-button.unaffordable:hover .tool-flavor, -.tool-button:disabled .tool-flavor, -.tool-button:disabled:hover .tool-flavor { display: none; } -.facility-action { font-size: 12px; } -.primary-button { font-size: 17px; } -#nextTurnButton { font-size: 19px; } -.card-choice strong { font-size: 19px; } -.card-choice span { font-size: 12px; } -.card-choice small { font-size: 16px; line-height: 1.45; } -.muted-card-note { font-size: 16px; } -.modal-card p, .modal-card li { font-size: 17px; } -.modal.equipment-popover .modal-card h2 { font-size: 16px; } -.modal.equipment-popover .modal-actions button { font-size: 11px; } -.equipment-menu-lines.compact, .formula-box.compact { font-size: 11px; } -.hover-tooltip strong { font-size: 18px; } - -/* Keep construction flavor text readable as a hover bubble, not button content. */ -.large-tools .tool-button { - min-height: 62px; - position: relative; - overflow: visible; -} -.large-tools .tool-button:hover { - min-height: 62px; -} -.large-tools .tool-button .tool-flavor { - display: none; - position: absolute; - z-index: 90; - right: 0; - top: calc(100% + 8px); - width: min(320px, calc(100vw - 40px)); - max-height: none; - opacity: 1; - overflow: visible; - margin: 0; - padding: 10px 12px; - border: 3px solid var(--line); - background: rgba(255,255,255,.98); - color: var(--ink); - box-shadow: 5px 5px 0 rgba(16,32,21,.18); - font-size: 14px; - line-height: 1.35; - pointer-events: none; - overflow-wrap: anywhere; -} -.large-tools .tool-button:hover .tool-flavor { - display: block; -} -.large-tools .tool-button .tool-flavor::before { - content: ''; - position: absolute; - right: 18px; - top: -10px; - width: 16px; - height: 16px; - border-left: 3px solid var(--line); - border-top: 3px solid var(--line); - background: rgba(255,255,255,.98); - transform: rotate(45deg); -} -.hover-tooltip span { font-size: 15px; } -.sort-button { font-size: 17px; } - -/* v27.3 offscreen scanner monitor / expansion UI pass */ -.scanner-monitor { - position: absolute; - z-index: 8; - left: 12px; - bottom: 92px; - display: none; - grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); - gap: 8px; - width: min(560px, calc(100% - 24px)); - pointer-events: auto; -} -.scanner-monitor.visible { display: grid; } -.scanner-monitor-card { - border: 3px solid var(--line); - background: rgba(255,255,255,.95); - box-shadow: 5px 5px 0 rgba(16,32,21,.18); - padding: 9px; - font-weight: 900; -} -.scanner-monitor-card header { - display: flex; - align-items: center; - justify-content: space-between; - gap: 8px; - margin-bottom: 7px; - text-transform: uppercase; -} -.scanner-monitor-card header strong { font-size: 20px; color: var(--green); } -.scanner-monitor-card header span { font-size: 12px; color: var(--muted); } -.scanner-mini-map { - display: grid; - grid-template-columns: 42px 1fr 82px; - align-items: center; - gap: 6px; - margin-bottom: 8px; -} -.scanner-mini-map > span, -.scanner-mini-map > b { - border: 2px solid var(--line); - background: #f7fff5; - padding: 7px 6px; - text-align: center; - font-size: 13px; - min-height: 36px; -} -.scanner-current { display: block; color: var(--ink); } -.scanner-current.male { color: #2477ff; } -.scanner-current.female { color: #d62a85; } -.scanner-current.poop { color: #7b4a23; } -.scanner-current.empty { color: var(--muted); } - -.scanner-mini-grid { - display: grid; - grid-template-columns: repeat(5, 27px); - gap: 3px; - justify-content: center; - align-items: center; - padding: 6px; - margin: 0 0 8px; - border: 2px solid var(--line); - background: #f6f1df; -} -.scanner-mini-grid .mini-cell { - width: 27px; - height: 27px; - display: grid; - place-items: center; - border: 1px solid rgba(22,38,25,.28); - background: #fffdfa; - color: var(--muted); - font-size: 11px; - font-weight: 900; - line-height: 1; -} -.scanner-mini-grid .mini-cell.belt { background: #e7f7e4; color: var(--green-dark); } -.scanner-mini-grid .mini-cell.input { background: #fff3bf; color: var(--ink); font-size: 9px; } -.scanner-mini-grid .mini-cell.scanner { background: var(--green); color: #fff; border-color: var(--line); font-size: 16px; } -.scanner-mini-grid .mini-cell.scanner.male { background: #2477ff; } -.scanner-mini-grid .mini-cell.scanner.female { background: #d62a85; } -.scanner-mini-grid .mini-cell.scanner.poop { background: #7b4a23; } -.scanner-mini-grid .mini-cell.scanner-other { background: #b7f5c6; color: var(--ink); } -.scanner-mini-grid .mini-cell.egg { background: #fff7c4; color: #7a5a00; } -.scanner-mini-grid .mini-cell.port { background: #dbe7ff; color: #27427d; } -.scanner-mini-grid .mini-cell.blocked { background: #d7cfc1; color: #6d4d35; } - -.scanner-monitor-actions { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 7px; -} -.scanner-monitor-actions button { - border: 3px solid var(--line); - background: var(--green-soft); - color: var(--ink); - cursor: pointer; - font: inherit; - font-size: 14px; - font-weight: 900; - min-height: 44px; - box-shadow: 3px 3px 0 rgba(16,32,21,.18); -} -.scanner-monitor-actions button:disabled { - background: #edf3ec; - color: var(--muted); - opacity: .62; - cursor: not-allowed; -} -@media (max-width: 1180px) { - .scanner-monitor { bottom: 132px; width: min(520px, calc(100% - 16px)); left: 8px; } -} - -/* ------------------------------------------------------------------ - DARK FACTORY VISUAL PASS - - Facility sprites are now loaded from assets/dark_factory/. - - Debug UI is intentionally retained for balancing builds. Do not remove. - ------------------------------------------------------------------ */ -:root { - --bg: #0b0c0f; - --screen: #111318; - --panel: rgba(24, 27, 34, 0.96); - --panel-2: #20242b; - --panel-3: #2a303a; - --ink: #e6edf2; - --muted: #8f9bab; - --line: #050609; - --green: #7bd84f; - --green-soft: #273c24; - --white: #e6edf2; - --danger: #e34a36; - --warn: #ffb827; - --cyan: #4aa3ff; - --orange: #c86a2b; - --shadow: 6px 6px 0 rgba(0, 0, 0, 0.62); -} -html, body { background: #050609; color: var(--ink); } -body { - background: - linear-gradient(90deg, rgba(255,184,39,.035) 1px, transparent 1px) 0 0 / 32px 32px, - linear-gradient(rgba(255,184,39,.028) 1px, transparent 1px) 0 0 / 32px 32px, - #050609; -} -#app { width: min(100vw, 1720px); padding: 0; } -.game-shell { - min-height: 100vh; - border: 0; - background: var(--screen); - box-shadow: inset 0 0 0 4px #050609, inset 0 0 0 8px #303744; -} -#gameCanvas { - height: 100vh; - min-height: 720px; - background: var(--screen); - image-rendering: pixelated; - image-rendering: crisp-edges; -} -.hud { gap: 4px; } -.hud-top-left { - top: 8px; - left: 8px; - right: 420px; - grid-template-columns: 1.25fr repeat(5, minmax(92px, .65fr)); -} -.hud-top-right { - top: 8px; - right: 8px; - grid-template-columns: repeat(4, minmax(74px, auto)); -} -.hud-card { - min-width: 74px; - padding: 7px 9px; - border: 3px solid var(--line); - background: linear-gradient(#242a33, #171a20); - box-shadow: 4px 4px 0 rgba(0,0,0,.7), inset 0 0 0 2px rgba(255,184,39,.10); - color: var(--ink); -} -.hud-card span { color: var(--warn); font-size: 9px; letter-spacing: .12em; } -.hud-card strong { color: var(--ink); text-shadow: 2px 2px 0 #050609; } -.hud-card.cash strong, .hud-card.profit strong, .hud-card.combo strong, .cash-positive { color: var(--green) !important; } -.hud-card.time-critical { background: #3a1f1f; box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(0,0,0,.7); } -.priority-strip { - top: 74px; - left: 10px; - width: clamp(250px, 21vw, 330px); - max-width: none; - grid-template-columns: 1fr; - gap: 6px; -} -.priority-strip > div { - border: 3px solid var(--line); - background: linear-gradient(#222832, #15181e); - color: var(--ink); - box-shadow: 4px 4px 0 rgba(0,0,0,.66), inset 0 0 0 2px rgba(255,184,39,.12); -} -.event-brief.active { background: #38251a; box-shadow: inset 0 0 0 3px var(--orange), 4px 4px 0 rgba(0,0,0,.66); } -.event-brief.next { background: #1c2c20; box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(0,0,0,.66); } -.event-brief.locked { background: #181b20; color: var(--muted); } -.target-brief { color: var(--warn); } -.speed-brief { color: var(--cyan); } -.build-panel { - top: 82px; - right: 8px; - bottom: 8px; - width: clamp(320px, 24vw, 410px); - padding: 9px; - border: 4px solid var(--line); - background: linear-gradient(#222832, #14171d); - box-shadow: 6px 6px 0 rgba(0,0,0,.72), inset 0 0 0 3px rgba(255,184,39,.10); - scrollbar-color: var(--warn) #111318; -} -.panel-head { - display: grid; - grid-template-columns: 1fr 126px; - align-items: stretch; - gap: 8px; - margin-bottom: 8px; -} -.panel-head h1 { color: var(--warn); text-shadow: 2px 2px 0 #050609; font-size: 17px; } -.panel-head h1 span { color: #050609; background: var(--warn); border-color: var(--line); } -.panel-head p { color: var(--muted); } -.panel-grid { - display: grid; - grid-template-columns: 1fr; - gap: 8px; -} -.build-panel h2, .result-section-title { color: var(--warn); } -.large-tools { - grid-template-columns: 1fr 1fr; - gap: 6px; -} -.tool-button, .primary-button, .sort-button, .facility-action { - border: 3px solid var(--line); - background: linear-gradient(#2a303a, #171a20); - color: var(--ink); - box-shadow: 4px 4px 0 rgba(0,0,0,.70), inset 0 0 0 2px rgba(255,184,39,.08); - text-shadow: 1px 1px 0 #050609; -} -.tool-button { min-height: 48px; padding: 8px; } -.tool-button strong { color: var(--ink); } -.tool-button span { color: var(--muted); } -.tool-button.active { - background: linear-gradient(#33311d, #1e2117); - box-shadow: inset 0 0 0 3px var(--warn), 4px 4px 0 rgba(0,0,0,.70); -} -.tool-button.danger.active { background: linear-gradient(#4b1f1c, #241014); box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(0,0,0,.70); } -.primary-button { background: linear-gradient(#8b2d23, #4b1714); color: #fff3d2; } -.primary-button:not(:disabled) { box-shadow: inset 0 0 0 3px #ffb827, 5px 5px 0 rgba(0,0,0,.72); } -.primary-button:disabled, .tool-button:disabled, .sort-button:disabled, .facility-action:disabled { opacity: .42; filter: grayscale(1); } -.mini-box, .event-card, .formula-box, .equipment-menu-lines, .route-card, .result-grid div, .muted-title { - border: 3px solid var(--line); - background: #15181e; - color: var(--muted); - box-shadow: inset 0 0 0 2px rgba(255,184,39,.08); -} -.event-card h3, .event-card strong, .event-metrics span { color: var(--ink); } -.event-card.accepted { background: #1c2c20; box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(0,0,0,.66); } -.event-card.empty { background: #15181e; color: var(--muted); } -.event-metrics span { border-color: #3d4654; background: #20242b; } -.event-status { background: #2a303a; color: var(--warn); border-color: var(--line); } -.control-dock { - left: 50%; - right: auto; - bottom: 8px; - transform: translateX(-50%); - grid-template-columns: repeat(4, minmax(135px, 160px)); - gap: 6px; - padding: 6px; - border: 4px solid var(--line); - background: rgba(13,15,19,.96); - box-shadow: 5px 5px 0 rgba(0,0,0,.72), inset 0 0 0 2px rgba(255,184,39,.10); -} -.sort-button { min-height: 44px; font-size: 12px; } -.scanner-monitor { - position: absolute; - z-index: 5; - left: 10px; - top: 198px; - width: clamp(250px, 21vw, 330px); -} -.scanner-monitor-card { - border: 3px solid var(--line) !important; - background: linear-gradient(#222832, #15181e) !important; - color: var(--ink) !important; - box-shadow: 4px 4px 0 rgba(0,0,0,.66), inset 0 0 0 2px rgba(255,184,39,.10) !important; -} -.scanner-monitor-card strong { color: var(--warn); } -.debug-panel { - left: auto; - right: 12px; - bottom: 10px; - width: min(420px, calc(100% - 24px)); - border-color: var(--line); - background: rgba(16,18,23,.97); - box-shadow: 5px 5px 0 rgba(0,0,0,.72), inset 0 0 0 2px rgba(227,74,54,.18); - color: var(--ink); -} -.debug-panel summary { color: var(--danger); } -.debug-body { border-top-color: var(--line); } -.debug-body button, .debug-body input[type="number"], .debug-body select, .debug-readout { - border-color: var(--line); - background: #20242b; - color: var(--ink); -} -.debug-readout { color: var(--muted); } -.modal { background: rgba(3,4,6,.72); } -.modal-card { - border-color: var(--line); - background: linear-gradient(#242a33, #15181e); - color: var(--ink); - box-shadow: 8px 8px 0 rgba(0,0,0,.72), inset 0 0 0 3px rgba(255,184,39,.12); -} -.modal-card h2 { color: var(--warn); text-shadow: 2px 2px 0 #050609; } -.modal-card ul, .modal-card p { color: var(--muted); } -.hover-tooltip { - border-color: var(--line) !important; - background: rgba(20,23,29,.98) !important; - color: var(--ink) !important; - box-shadow: 5px 5px 0 rgba(0,0,0,.72) !important; -} -::-webkit-scrollbar { width: 14px; height: 14px; } -::-webkit-scrollbar-track { background: #111318; } -::-webkit-scrollbar-thumb { background: #333b48; border: 3px solid #111318; } -::-webkit-scrollbar-thumb:hover { background: #ffb827; } -@media (max-width: 1180px) { - .hud-top-left { right: 8px; grid-template-columns: repeat(3, minmax(80px, 1fr)); } - .hud-top-right { top: 132px; left: 8px; right: auto; grid-template-columns: repeat(2, minmax(82px, auto)); } - .priority-strip { top: 226px; } - .scanner-monitor { top: 348px; } - .build-panel { left: 8px; right: 8px; bottom: 8px; width: auto; max-height: 46vh; } - .control-dock { grid-template-columns: repeat(2, 150px); } -} - -/* v27.16: compact collapsed debug panel + icon card layout */ -.debug-panel:not([open]) { - width: 104px !important; - min-width: 0; - overflow: hidden; -} -.debug-panel:not([open]) summary { - display: block; - width: 100%; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} -.debug-panel[open] { - width: min(420px, calc(100% - 24px)); -} - -.card-choice { - position: relative; - display: grid; - grid-template-columns: 54px minmax(0, 1fr); - gap: 10px; - align-items: start; - min-height: 150px; - overflow: hidden; - background: - linear-gradient(135deg, rgba(255,255,255,.08), rgba(0,0,0,.20)), - #20242b; - border-color: var(--line); -} -.card-choice::before { - content: ""; - position: absolute; - inset: 5px; - border: 1px solid rgba(255,184,39,.18); - pointer-events: none; -} -.card-icon { - position: relative; - z-index: 1; - width: 46px; - height: 46px; - display: grid; - place-items: center; - border: 3px solid var(--line); - background: #15181e; - box-shadow: inset 0 0 0 2px rgba(255,184,39,.10), 3px 3px 0 rgba(0,0,0,.35); - image-rendering: pixelated; -} -.card-icon img { - width: 36px; - height: 36px; - object-fit: contain; - image-rendering: pixelated; -} -.card-icon.glyph { - color: var(--warn, #ffb827); - font-size: 24px; - font-weight: 900; - text-align: center; - line-height: 1; -} -.card-copy { - position: relative; - z-index: 1; - min-width: 0; -} -.card-choice strong { - color: var(--warn, #ffb827); - text-shadow: 1px 1px 0 #050609; -} -.card-choice small { color: var(--muted); } -.card-tags span { - background: #15181e; - color: var(--white); - border-color: var(--line); -} -.card-choice.common { background: linear-gradient(145deg, #262c35, #171a20); } -.card-choice.rare { - background: linear-gradient(145deg, #3b3020, #191b20); - box-shadow: inset 0 0 0 3px #f0a020, 5px 5px 0 rgba(0,0,0,.50); -} -.card-choice.ultra-rare { - background: linear-gradient(145deg, #401d2a, #171a20); - box-shadow: inset 0 0 0 3px #c42424, 5px 5px 0 rgba(0,0,0,.55); -} -.card-choice.dud { - background: linear-gradient(145deg, #2b2b2b, #191919); - color: #878787; -} -.card-choice.dud .card-tags span { background: #222; color: #aaa; } - -@media (max-width: 1180px) { - .debug-panel:not([open]) { - width: 92px !important; - right: 8px; - bottom: 8px; - } -} - - -/* v27.18 inherited cache-proof identity and final UI overrides */ -.build-stamp { - position: absolute; - z-index: 12; - right: 14px; - top: 76px; - padding: 5px 9px; - border: 2px solid #ffb827; - background: rgba(14, 17, 22, .94); - color: #80e067; - box-shadow: 3px 3px 0 rgba(0,0,0,.7); - font: 900 11px/1 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; - letter-spacing: .04em; - pointer-events: none; -} -.debug-panel:not([open]) { - width: 58px !important; - max-width: 58px !important; - height: 30px; - min-height: 0; -} -.debug-panel:not([open]) summary { - box-sizing: border-box; - width: 58px; - height: 27px; - padding: 5px 7px; - text-align: center; - overflow: hidden; - text-overflow: clip; -} -.debug-panel[open] { - width: min(390px, calc(100% - 24px)) !important; - height: auto; -} -.card-choice { - border-width: 3px; - box-shadow: 4px 4px 0 rgba(0,0,0,.55), inset 0 0 0 1px rgba(255,184,39,.14); -} -.card-choice:hover { - transform: translateY(-2px); - box-shadow: 4px 6px 0 rgba(0,0,0,.65), inset 0 0 0 2px rgba(128,224,103,.24); -} -.card-icon img { - image-rendering: pixelated; - filter: drop-shadow(2px 2px 0 rgba(0,0,0,.7)); -} -#gameCanvas { image-rendering: pixelated; } - -/* v27.18: status relocation, consistent industrial controls, card watermarks */ -.hud-top-left { grid-template-columns: repeat(5, minmax(82px, auto)); } - -.left-bottom-status { - position: absolute; - z-index: 6; - left: 10px; - bottom: 10px; - width: min(310px, calc(100% - 20px)); - display: grid; - grid-template-columns: 1fr 1fr; - gap: 6px; - pointer-events: none; -} -.left-bottom-status > div { - min-width: 0; - border: 3px solid var(--line); - background: rgba(22, 26, 32, .95); - color: var(--ink); - padding: 8px 10px; - box-shadow: 4px 4px 0 rgba(0,0,0,.68), inset 0 0 0 1px rgba(255,184,39,.10); - font-size: 12px; - line-height: 1.2; - font-weight: 900; - text-transform: uppercase; - letter-spacing: .025em; - overflow: hidden; - text-overflow: ellipsis; -} -.left-bottom-status .event-brief { grid-column: 1 / -1; white-space: normal; min-height: 39px; } -.left-bottom-status .event-brief.active { background: #35221c; box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(0,0,0,.68); } -.left-bottom-status .event-brief.next { background: #22301f; box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(0,0,0,.68); } -.left-bottom-status .event-brief.locked { background: #1c2027; color: var(--muted); } -.left-bottom-status .speed-brief { color: #d9e2e8; } -.left-bottom-status .target-brief { color: #ffcf68; } -.left-bottom-status .combo-brief { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; } -.left-bottom-status .combo-brief span { color: var(--muted); font-size: 10px; } -.left-bottom-status .combo-brief strong { color: var(--green); font-size: 22px; line-height: 1; } - -/* Remove the remaining bright green/white control styling from modal actions. */ -.modal-actions button, -.facility-action, -.card-target-button { - border: 3px solid #07080a; - background: linear-gradient(#353d48, #1b1f25); - color: #e6edf2; - box-shadow: inset 0 0 0 1px rgba(255,184,39,.14), 4px 4px 0 rgba(0,0,0,.68); -} -.modal-actions button:hover:not(:disabled), -.facility-action:hover:not(:disabled), -.card-target-button:hover:not(:disabled) { - background: linear-gradient(#424b58, #242930); - color: #fff0c9; - box-shadow: inset 0 0 0 2px rgba(255,184,39,.42), 4px 4px 0 rgba(0,0,0,.72); -} -.facility-action.warn, -.modal-actions .reroll-button { - background: linear-gradient(#554221, #2b2419); - color: #ffd36a; - box-shadow: inset 0 0 0 3px #b97810, 5px 5px 0 rgba(0,0,0,.72); -} -.modal-actions .reroll-button:hover:not(:disabled) { - background: linear-gradient(#6b5227, #342919); - color: #fff0bd; - box-shadow: inset 0 0 0 3px #ffb827, 5px 5px 0 rgba(0,0,0,.76); -} -.facility-action.good { background: linear-gradient(#29422a, #19271a); color: #a9ed91; } -.facility-action.danger { background: linear-gradient(#57251f, #2d1715); color: #ffb1a3; } -.modal-actions button:disabled, -.facility-action:disabled, -.card-target-button:disabled { opacity: .42; filter: grayscale(.85); box-shadow: 3px 3px 0 rgba(0,0,0,.45); } - -/* Icons are now translucent background art rather than separate foreground badges. */ -.card-choice { - display: block; - min-height: 170px; - padding: 16px; - isolation: isolate; -} -.card-choice::before { z-index: 1; } -.card-copy { position: relative; z-index: 3; padding-right: 6px; } -.card-icon { - position: absolute; - z-index: 0; - right: -9px; - bottom: -12px; - width: 124px; - height: 124px; - border: 0; - background: transparent; - box-shadow: none; - opacity: .14; - transform: rotate(-7deg); - pointer-events: none; - overflow: visible; -} -.card-icon img { - width: 100%; - height: 100%; - object-fit: contain; - filter: grayscale(.12) contrast(1.2) drop-shadow(3px 3px 0 rgba(0,0,0,.55)); -} -.card-icon.glyph { - display: grid; - place-items: center; - color: #f0b437; - font-size: 88px; - line-height: 1; - text-shadow: 4px 4px 0 rgba(0,0,0,.55); -} -.card-choice.rare .card-icon { opacity: .16; } -.card-choice.ultra-rare .card-icon { opacity: .17; } -.card-choice.dud .card-icon { opacity: .08; filter: grayscale(1); } - -@media (max-width: 1180px) { - .hud-top-left { grid-template-columns: repeat(3, minmax(80px, 1fr)); } - .left-bottom-status { width: 290px; left: 8px; bottom: 8px; } -} -@media (max-width: 760px) { - .left-bottom-status { width: min(270px, calc(100% - 16px)); grid-template-columns: 1fr; } - .left-bottom-status .event-brief { grid-column: auto; } -} - - -/* v27.19: compact Next Day fee label and deduplicated side panel */ -.panel-head { grid-template-columns: minmax(0, 1fr) minmax(112px, 126px); } -.primary-button#nextTurnButton { - min-width: 0; - max-width: 126px; - padding: 8px 7px; - white-space: normal; - overflow: hidden; - line-height: 1.08; - display: grid; - place-content: center; - gap: 4px; - text-align: center; -} -#nextTurnButton .next-day-main { display: block; font-size: 15px; letter-spacing: .035em; } -#nextTurnButton .next-day-fee { - display: block; - max-width: 100%; - color: #ffd36a; - font-size: 9px; - line-height: 1.15; - letter-spacing: 0; - overflow-wrap: anywhere; -} diff --git a/styles.css b/styles.css index 3ddf905..ec641aa 100644 --- a/styles.css +++ b/styles.css @@ -263,7 +263,7 @@ h1, h2, p { margin: 0; } /* v15 pre-build card draft */ .card-choices { display: grid; - grid-template-columns: repeat(auto-fill, minmax(190px, 220px)); + grid-template-columns: repeat(auto-fit, minmax(190px, 220px)); justify-content: center; align-items: stretch; gap: 10px; @@ -532,7 +532,7 @@ body { font-size: 18px; } from { box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(16,32,21,.18); filter: brightness(1); } to { box-shadow: inset 0 0 0 5px #fff0d1, 4px 4px 0 rgba(16,32,21,.20); filter: brightness(1.08); } } -.card-choices { grid-template-columns: repeat(auto-fill, minmax(230px, 270px)); gap: 14px; } +.card-choices { grid-template-columns: repeat(auto-fit, minmax(230px, 270px)); gap: 14px; } .card-choice { min-height: 164px; padding: 15px; } .card-choice strong { font-size: 18px; } .card-choice span { font-size: 11px; } @@ -613,9 +613,10 @@ body { font-size: 20px; } display: none; position: absolute; z-index: 90; - right: 0; - top: calc(100% + 8px); - width: min(320px, calc(100vw - 40px)); + right: calc(100% + 10px); + top: 50%; + transform: translateY(-50%); + width: min(320px, 34vw); max-height: none; opacity: 1; overflow: visible; @@ -636,11 +637,11 @@ body { font-size: 20px; } .large-tools .tool-button .tool-flavor::before { content: ''; position: absolute; - right: 18px; - top: -10px; + right: -10px; + top: calc(50% - 8px); width: 16px; height: 16px; - border-left: 3px solid var(--line); + border-right: 3px solid var(--line); border-top: 3px solid var(--line); background: rgba(255,255,255,.98); transform: rotate(45deg); @@ -1201,6 +1202,35 @@ body { .facility-action:disabled, .card-target-button:disabled { opacity: .42; filter: grayscale(.85); box-shadow: 3px 3px 0 rgba(0,0,0,.45); } +/* Keep the translucent watermark, but also show a readable foreground icon badge. */ +.card-badge-icon { + position: absolute; + z-index: 4; + left: 14px; + top: 14px; + width: 42px; + height: 42px; + display: grid; + place-items: center; + border: 3px solid rgba(7,8,10,.95); + background: rgba(16,19,25,.88); + box-shadow: inset 0 0 0 1px rgba(255,184,39,.18), 3px 3px 0 rgba(0,0,0,.48); + image-rendering: pixelated; +} +.card-badge-icon img { + width: 30px; + height: 30px; + object-fit: contain; + image-rendering: pixelated; + filter: drop-shadow(1px 1px 0 rgba(0,0,0,.7)); +} +.card-badge-icon.glyph { + color: #ffcf68; + font-size: 22px; + line-height: 1; + text-shadow: 2px 2px 0 rgba(0,0,0,.55); +} + /* Icons are now translucent background art rather than separate foreground badges. */ .card-choice { display: block; @@ -1209,7 +1239,7 @@ body { isolation: isolate; } .card-choice::before { z-index: 1; } -.card-copy { position: relative; z-index: 3; padding-right: 6px; } +.card-copy { position: relative; z-index: 3; padding-right: 6px; padding-left: 54px; } .card-icon { position: absolute; z-index: 0; From 22e6366dc298d5b25b2a7b76b4586af98ef8c44c Mon Sep 17 00:00:00 2001 From: 33333-33333 Date: Thu, 11 Jun 2026 22:49:46 +0900 Subject: [PATCH 4/5] twe --- README.md | 93 +- assets/README_ASSETS_DARK_FACTORY.md | 16 - assets/dark_factory/facilities/README.md | 1 - .../facilities/machines/mixer_compact_16.png | Bin 475 -> 0 bytes .../machines/shredder_compact_16.png | Bin 326 -> 0 bytes .../facilities/vehicles/truck_compact_16.png | Bin 401 -> 0 bytes assets/dark_factory/manifest.json | 17 +- assets/dark_factory/previews/README.md | 1 - .../facilities_overview_dark_factory.png | Bin 2448 -> 0 bytes assets/images/README.md | 3 - codex_all_new_ideas_prompt_en.md | 903 ++++++++++++++++++ dist/game.js | 53 +- index.html | 16 +- package-lock.json | 4 +- package.json | 5 +- src/core/balance.js | 66 +- src/core/config.js | 11 +- src/core/entities.js | 138 ++- src/core/gridExpansion.js | 39 +- src/core/state.js | 36 +- src/core/text.js | 27 +- src/game.js | 162 +++- src/render/draw.js | 457 +++++++-- src/systems/buildSystem.js | 226 ++++- src/systems/cards.js | 82 +- src/systems/chickSystem.js | 263 ++++- src/systems/economy.js | 65 +- src/systems/effects.js | 4 +- src/systems/events.js | 22 +- src/systems/history.js | 8 +- src/systems/maintenance.js | 8 +- src/systems/routing.js | 110 ++- src/systems/selectionSystem.js | 91 +- src/systems/uiSystem.js | 23 +- styles.css | 24 +- 35 files changed, 2595 insertions(+), 379 deletions(-) delete mode 100644 assets/README_ASSETS_DARK_FACTORY.md delete mode 100644 assets/dark_factory/facilities/README.md delete mode 100644 assets/dark_factory/facilities/machines/mixer_compact_16.png delete mode 100644 assets/dark_factory/facilities/machines/shredder_compact_16.png delete mode 100644 assets/dark_factory/facilities/vehicles/truck_compact_16.png delete mode 100644 assets/dark_factory/previews/README.md delete mode 100644 assets/dark_factory/previews/facilities_overview_dark_factory.png delete mode 100644 assets/images/README.md create mode 100644 codex_all_new_ideas_prompt_en.md diff --git a/README.md b/README.md index a761a09..19d991e 100644 --- a/README.md +++ b/README.md @@ -2,22 +2,93 @@ Serve this folder with a static HTTP server and open `index.html`. -The launch page uses the unversioned app assets: +The launch page uses: - `styles.css` - `dist/game.js` ## Build -Run `npm install` once, then `npm run build` after editing JavaScript or `styles.css`. Without a local Node/npm toolchain, `dist/game.js` remains a source-module wrapper for local static serving. +Run `npm install` once, then `npm run build` after editing JavaScript. -## Current changes +## Current gameplay specification (v28.21) -- Initial no-build tiles are 3% of the starting 20x10 land. -- Each purchased 10x10 lot increases its own no-build ratio by 0.5 percentage points, capped at 10%. -- Floor slime is sparse, deterministic splatter instead of frequent puddles. -- No-build tiles use subdued black/yellow hazard striping. -- The duplicate right-side event panel was removed. -- The Status panel no longer repeats event, belt speed, combo, or truck target data. -- NEXT DAY displays the Fairies fee on a contained second line. -- Dynamite lets the player select any highlighted no-build tiles, up to three. Empty clicks do not cancel selection. +### Boost conveyor rendering hotfix (v28.21) + +- Fixed a runtime `ReferenceError` caused by an undeclared `boost` variable in the animated conveyor renderer. +- Added a runtime smoke test for both normal and boost conveyor drawing. + + +### Input and motion fixes (v28.20) + +- Clicking either end of a conveyor run now reverses the complete run, including the clicked terminal tile. +- Conveyor stripe animation uses the same effective pixels per second as chicks on each tile. Boost Conveyor is therefore exactly 2× the normal animation speed before other modifiers. +- NEXT DAY no longer rebuilds its child markup every frame, preventing lost clicks during pointer press/release. +- Explosion debris horizontal velocity is reduced to 82% while vertical launch energy is unchanged. + +### Land expansion + +- Each purchase adds a 10×10 lot. +- First expansion costs JPY 850. +- Later prices use linear growth: `850 × (1 + 0.75 × previous purchases)`, rounded down to JPY 50. +- Expected prices: JPY 850, 1,450, 2,100, 2,750, 3,400... + +### Map obstacles + +- Initial no-build ratio: 0%. +- Each purchased lot adds 0.75 percentage points to that lot's obstacle ratio. +- Obstacle ratio is capped at 12%. + +### Scanners + +- Scanner footprint: 2×2 grid cells. +- Lv1 Auto Scanner cooldown: 1.5 seconds, about 40 items/day. +- This equals about 2.1 average Lv1 Egg Farms. +- Auto Scanner local and global tuning each multiply cooldown by 0.95 per upgrade. + +### Mixer / Sausage production chain + +- Mixer remains an external edge facility. +- When mounted along a horizontal map edge, its chick inlet is on the top of the body and its meat outlet is on the bottom. +- When mounted along a vertical map edge, its chick inlet is on the left of the body and its meat outlet is on the right. +- The inlet and outlet use separate receiver cells, leaving the cell between them open. +- A non-poop chick processed by Mixer creates 1 meat when the outlet conveyor is present and clear. +- If meat cannot leave the outlet because no conveyor is connected or the outlet cell is occupied, Mixer falls back to a fixed direct sale of JPY 5. Mixer upgrades affect sausage value, not this fallback. +- Sausage Machine costs JPY 380 and occupies exactly 3×3 owned grid cells. +- Its single meat inlet is one cell left of the middle row; its single sausage outlet is one cell right of the middle row. +- Placement is rejected if the 3×3 body or either port would be outside owned, usable grid space. +- It consumes 2 meat and outputs 1 sausage. +- Sausages are accepted by Truck regardless of the live-cargo event target. +- Base sausage sale value is JPY 26. +- MIXER Improvement and SAUSAGE MACHINE Improvement each multiply sausage value by 1.10 per installed level. + +### Conveyor branches + +- Fixed branch direction is shown by a triangle rather than an `RT`/direction abbreviation. +- A branch never offers a direction that points back toward an incoming conveyor. +- Branch selection is unavailable unless at least two outgoing conveyors remain after incoming directions are removed. + +### Camera controls + +- Build phase: right- or middle-drag pans the camera. +- Factory-running phase: left-, right-, or middle-drag pans the camera. +- Mouse wheel zoom remains available during both phases. + +### Shredder upgrades + +- SHREDDER Improvement uses a nonlinear scrap lottery. +- Upgrade count increases payout approximately with `1.6 × cards^1.25`. +- It also increases hit chance from 28%, by 1.8 percentage points per upgrade, capped at 82%. +- Winning payouts roll 1×, 2×, 4×, or 10×. +- Big-win and jackpot odds increase as more SHREDDER Improvement cards are installed. + +### Card eligibility + +- Equipment-targeted cards are excluded when no valid target exists. +- Equipment-specific passive cards can declare facility requirements and are excluded while those facilities are absent. + +### Other verified rules + +- Floor slime is deterministic decoration. +- Dynamite removes up to 3 selected blocked cells. +- Bankruptcy is checked only after day-end settlement. diff --git a/assets/README_ASSETS_DARK_FACTORY.md b/assets/README_ASSETS_DARK_FACTORY.md deleted file mode 100644 index 5057cf3..0000000 --- a/assets/README_ASSETS_DARK_FACTORY.md +++ /dev/null @@ -1,16 +0,0 @@ -# Assets organization (prepared, not yet wired into the game) - -This patch adds a **dark factory** art set without changing runtime references yet. - -## Folder guide -- `assets/dark_factory/facilities/` : new factory equipment sprites -- `assets/dark_factory/previews/` : visual overview sheet -- `assets/images/` : user-supplied chick and poop sprites used by the renderer -- `assets/images/` : left untouched for compatibility with the current build - -## Notes -- Grid base unit: **16x16** -- Non-grid UI object base unit: **32x32** -- Color count intentionally limited for a coarse pixel-art look -- Sprites are supplied as individual PNG files with transparency -- This patch **does not yet hook the new art into the live game** diff --git a/assets/dark_factory/facilities/README.md b/assets/dark_factory/facilities/README.md deleted file mode 100644 index 81deae0..0000000 --- a/assets/dark_factory/facilities/README.md +++ /dev/null @@ -1 +0,0 @@ -Dark factory facility sprites. See ../manifest.json for file roles and dimensions.\n \ No newline at end of file diff --git a/assets/dark_factory/facilities/machines/mixer_compact_16.png b/assets/dark_factory/facilities/machines/mixer_compact_16.png deleted file mode 100644 index 980ab2e9eed9c330e277f6d5bdac90d686b1fdfa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 475 zcmV<10VMv3P)LW%{!T0*cC8w({NV6=#e zxIT~-0u~lxVIztn7kn&H!EIe)sxv9pd)DP*@bSZe;h*{cGc%lHn3gR(2c~6eaLZZP0JR;v}_p}`=$+J^E3awu(P{Y$HPMd7^Y=QL+CACJs(+|o6Z<5EqKHg zFN<~D*wn)A&K9`A zJU>eeQ2*rsfUmP}@Ly&$IRGLG5yi@CjE)asElN(dlALU1qd!k`%||I*%^d?lB<)!A zX#;?(iFaANYvOj|^0y->&%*9r7YK%Q{&tDpx1>Z!96JEKs;cqiTx9J4V0*9x z0AF;IvPwT?m3|V(4!-Cn02kve#Mjq!ydH$N3Qo zqxF8f00|Ns?X;xGM30hGABc<6H Y0J&0;{a?*IS*07*qoM6N<$f_A5p+W-In diff --git a/assets/dark_factory/facilities/vehicles/truck_compact_16.png b/assets/dark_factory/facilities/vehicles/truck_compact_16.png deleted file mode 100644 index 72275bd9e406d1774c324da2e3020b3a0b8d318a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 401 zcmV;C0dD?@P)!#{aq~Eabue#pN~QF~0Duz3?bTW6 z=8@5HQ`c)gN)!MQ08tW}0M(Nr0G<;r8Ur*Hh$!C5#Xq-ORs<*Y0>Cn3XiR{h$u>MO z(*=Im{x82ogS8rf_e!ZvprpUIbe*KV$<8qIt>5Tn vb9n*0s2!829TULoOx@G7<}>v)+-Lj%$Qrti8HC?l00000NkvXXu0mjfUn;bi diff --git a/assets/dark_factory/manifest.json b/assets/dark_factory/manifest.json index 98ccc56..555fac0 100644 --- a/assets/dark_factory/manifest.json +++ b/assets/dark_factory/manifest.json @@ -59,28 +59,25 @@ { "id": "mixer", "files": [ - "mixer_32.png", - "mixer_compact_16.png" + "mixer_32.png" ], - "size": "32x32 + 16x16 compact", + "size": "32x32", "folder": "facilities/machines" }, { "id": "shredder", "files": [ - "shredder_32.png", - "shredder_compact_16.png" + "shredder_32.png" ], - "size": "32x32 + 16x16 compact", + "size": "32x32", "folder": "facilities/machines" }, { "id": "truck", "files": [ - "truck_32.png", - "truck_compact_16.png" + "truck_32.png" ], - "size": "32x32 + 16x16 compact", + "size": "32x32", "folder": "facilities/vehicles" }, { @@ -100,4 +97,4 @@ "folder": "facilities/utility" } ] -} \ No newline at end of file +} diff --git a/assets/dark_factory/previews/README.md b/assets/dark_factory/previews/README.md deleted file mode 100644 index b1790a8..0000000 --- a/assets/dark_factory/previews/README.md +++ /dev/null @@ -1 +0,0 @@ -Preview sheet(s) for quick inspection. These are reference only, not runtime assets.\n \ No newline at end of file diff --git a/assets/dark_factory/previews/facilities_overview_dark_factory.png b/assets/dark_factory/previews/facilities_overview_dark_factory.png deleted file mode 100644 index b387a8d20efd2f4034e8530c98ba612523318b60..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2448 zcmc(heLT}^AIB$_A?#MEROZ$>IY>?qEXAgsn&Yw1OjvZXkQSAxC6A|4x+8g5(x^l? zi-~5Ar#02VNK!0ptelCh%{*;pPxsuXbHD1`-GAJFoqw*^_4-}k@Ar3I*XR5Dynk2r z`?wkEo9P1p07Lg5_xJ$-TCSQo7qnC}o|4nW0DvCaeb4R#XKxER`!3&(Sg$LNz#FZ! z_ka7;W^dgMguU-&&vxtMdATl|K)$#1wdTMet?ZvpMeYs+oBci85&`<{4&q7Ko0RJG z=l3q%_E>GOkqErnefaKaPy3(jYs}-IwY8HiligkNh+$bG416|Xj3gyAkd&gC$;6{~ zhcIk!fEM1*BWmIz?~48RZzmoQ>2+JDf?y$A5Vp z!7_4AnvJzhoE?A43O{vK{>XXMDXO6trie-CRMhaSu% zfOmh3;g;GfW7ZuLcUa8SA0zPKm3I}MQXg{=qhW&II(48Is2UhB*3Tl(7T3ZzJ6E+% z)JDtg*v;UFLxZxba&=9SZc+I+faC>n$h(tyFtwO?u?-(-sY4TuaMVOUk2Av@XR)*R zAMV#P9R8N3RJBp_b#bVU)m&~4BfBk>P@Z9u6`B-O)uQmlX8||c7oQD~2n5u8LtIUd zaI+|%YC?~^^oYNvy{z+PknYXW41CJL(FA1{O>+pl;Qx zQf=k1K9PpBEq%{%&R9{YZF^4BQWy~8DZEQDQc5Ue{<%Uqf{akuzz;Iy!4hzhG z&R#Y&q*rdY%Yr976Euhze+6D|)VB56W1GzT)BAb5#7r!*)m){F#4 zVMLTED#_}{*R&e%=tDtp^`X$U0)_qY6Q~2r2e}mb{QK0lk@*g~S%o|Gc>41$8!|Nj zPd;Ui1r8sI2`dUpqXN10g_d1GohR8-j|ovuj<`vpkO6_d=92}>*FO*zvw|m_(0$eI zJo4I$ELgYG=yxsvC{d+GCq!8*V}GMIG1?E8)b_&XIZ$a9tx9?17T+7&yRf`%du2(T zm(2m5S! zT%3eyn_d+>CqigC*h{l6QCbyH=y+AQCfJigK?kHWeh!X`nq#U?dQ9|;Zp|}Kv2A9k zraI6qAxwwlnP&JT^)HcKhR${nyS=XqKRIl3d zD(d1@?^TcBJ-kT#s`>9~9m%_@9J~2riEi%wJ1LGTXg4{Xrt(WD*n1>_I81Ia@+6~; zfSgo|kGR~RBKPZn%*G25vrPv<&)%7Sj5Roadvs`Je~h`1dQ2MhxFn10SO2V(wng3< zcFAE5cLH1RpirGo6tC;cgLgZjI)fF?9cg14IoAi?@{?RoIT1t1oKcsp>%xXiMtj0ZBPqmTN_t1Js{NDVHS_uW)@$2;zm`j2<=oR8<73NdP-~6`oqyt3#+-s zCtxnq)EG=6>~z|O=#c91ohWM?X!O75 z;~bhhRMuo{Z_ad+G0`p4R;32Z{(#nJz81YmzZZp_#LX7I+6uX@=cwg!yB zAaahM3c+Cb(90?Sx%QJtV@%lRJp8QmV#a?TW|4vtZJk#BqRHfI%yzJARf%>uSo8Q3 z9KW9P#xFRafOpOlz@FOxr^`^%fEgGi5&m$?p1OLp}E zmwpcGzh*xf$KfKL$SN?r`n5(qjn+se>;K=^Tqur3Ie85u4%hr?0o?cc?5RS8rTq)A CxMX<% diff --git a/assets/images/README.md b/assets/images/README.md deleted file mode 100644 index 0e29b23..0000000 --- a/assets/images/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Image assets - -`poop.png` is bundled and loaded by default. Other equipment/chick art is optional and currently falls back to canvas drawing unless external art loading is enabled in `src/render/draw.js`. diff --git a/codex_all_new_ideas_prompt_en.md b/codex_all_new_ideas_prompt_en.md new file mode 100644 index 0000000..999dc8f --- /dev/null +++ b/codex_all_new_ideas_prompt_en.md @@ -0,0 +1,903 @@ +# Codex Implementation Prompt — Chick Sorter v29.00 + +Implement the next major version of the attached **Chick Sorter v28.21 source project**. + +The objective is to add a deterministic power-network system, fuel-based generation, inbound logistics, egg-farm quality overflow, and realistic repair-worker navigation while preserving every feature and regression fix already present in v28.21. + +Treat this prompt as the authoritative implementation brief. Do not expand the mandatory scope with optional backlog items unless they are explicitly marked as required. + +--- + +## 1. Non-negotiable engineering rules + +1. Do not edit the minified production bundle directly. +2. Modify source files under `src/` and the appropriate source HTML/CSS/README files, then rebuild the production bundle. +3. Preserve all v28.21 behavior and regression fixes. +4. Keep all tunable values in the existing centralized balance/configuration module. +5. Prefer isolated modules for new systems, including: + - `src/systems/power.js` + - `src/systems/imports.js` + - `src/systems/farmQuality.js` if farm-quality logic cannot remain cleanly isolated in the existing farm module. +6. Do not add texture assets. Draw new equipment with Canvas geometry, symbols, labels, and simple temporary colors. +7. Update the version to `29.0.0`, the visible version to `v29.00`, and the bundle cache key to `game.js?v=29.00` or the equivalent used by the project. +8. Implement the work in stages. After every stage, run relevant syntax checks and tests. +9. Do not silently discard transport items because of congestion, power loss, or invalid machine state. +10. Update README so every documented value matches the actual implementation constants. + +After each implementation stage, report: + +- files changed; +- behavior implemented; +- tests run and results; +- unresolved assumptions or defects. + +--- + +## 2. Preserve all existing v28.21 features + +Do not regress any of the following: + +- land expansion starts at 850 yen and uses the current reduced linear increase model; +- the level-1 automatic scanner occupies 2x2 cells and processes approximately 2.1 level-1 farms; +- shredder upgrades scale nonlinearly and retain high random variance; +- the mixer emits meat through its configured output and pays a fixed fallback revenue of exactly +5 yen when meat cannot be emitted; +- the 3x3 sausage machine consumes two meat items and emits one sausage; +- sausage revenue is collected by the shipping truck; +- equipment-specific cards are excluded from the card pool when the relevant equipment does not exist; +- README matches implemented obstacle and balance behavior; +- mixer input/output ports, sausage-machine placement, conveyor branching rules, triangle direction indicators, and running-phase camera panning remain intact; +- clicking an edge conveyor reverses the connected conveyor line correctly; +- Boost Conveyor animation is twice the regular conveyor animation speed; +- conveyor animation speed stays synchronized with actual transported-item movement, including modifiers and wear; +- NEXT DAY works on a single click; +- explosion horizontal impulse remains reduced to the v28.20 value; +- normal and Boost Conveyor drawing never throws `boost is not defined` or another undefined-variable error. + +Keep the existing internal truck ID for compatibility. Rename only the player-facing label of the current truck to **Shipping Truck**. + +--- + +# Mandatory v29.00 systems + +## 3. Power model + +### 3.1 Equipment exempt from electricity + +The following operate without voltage: + +- manual scanner; +- egg farm; +- regular conveyor; +- Boost Conveyor; +- regular power wire; +- insulated power wire; +- footbridge; +- starter generator; +- biomass generator; +- coal generator. + +Every other active machine requires sufficient received voltage. + +When a machine is under-voltage: + +- stop accepting or processing new items; +- do not remove an item from an upstream conveyor until acceptance is confirmed; +- pause processing timers rather than resetting them; +- retain internal queues and pending outputs; +- resume normally after voltage is restored. + +### 3.2 Voltage terminology + +This is an intentionally simplified game system, not a physical electrical simulation. + +Each powered machine has: + +- `minVoltage`: minimum received voltage required to operate; +- `drawV`: its contribution to generator load sag; +- `relayDropV`: optional extra route loss only if the implementation allows a power route to pass through a declared machine relay node. + +Use the player-facing term **Voltage Load** for `drawV`. + +### 3.3 Generator load sag + +A pure path-loss system would allow one 25V generator to power unlimited parallel machines. Prevent that with source load sag. + +For each source: + +```text +busVoltage = currentGeneratorOutputV - sum(drawV of admitted machines) +receivedVoltage(machine) = busVoltage - routeLossV(machine) +``` + +Admit a machine only when adding its load keeps every already admitted machine at or above its own `minVoltage`. + +Different generators do not add their voltages together in v29.00. + +A machine is assigned to at most one generator. + +Choose and admit sources deterministically: + +1. calculate the best route from every available generator; +2. prefer the source with the highest open-circuit received voltage; +3. admit higher `powerPriority` first; +4. then lower route loss; +5. then earlier build order; +6. then stable equipment ID. + +Use default `powerPriority = 50`. + +Use priority 100 for the initial mixer, shredder, and shipping truck. + +Repeat assignment until stable, with a hard maximum of eight passes. + +### 3.4 Power routing + +Power wires form a four-directional graph. + +- Regular Power Wire loses **0.5V per traversed tile**. +- Insulated Power Wire loses **0.15V per traversed tile**. +- Wire types connect directly to each other. +- Branches do not divide voltage. +- Loops must never increase voltage. +- Separate generators are not summed. +- Active fuel pulses in the same fuel generator are summed. +- Stop exploring a path at 0V or below. +- Use a maximum-priority Dijkstra-style propagation or an equivalent monotonic minimum-loss algorithm. + +Do not run a complete graph search every render frame. Recalculate after structural changes and at no more than 10Hz while timed generator pulses change. + +Recommended public functions: + +```js +ensurePowerState(game) +markPowerDirty(game) +updatePowerSystem(game, dt) +recalculatePowerNetwork(game) +receivedVoltageFor(game, equipment) +isEquipmentPowered(game, equipment) +powerSummary(game) +``` + +### 3.5 Power layer + +Power wires use an overlay layer separate from equipment and conveyor occupancy. + +Wires may overlap: + +- regular conveyors; +- Boost Conveyors; +- footbridges. + +Wires may not occupy: + +- unowned cells; +- obstacle cells; +- equipment body cells, unless a future explicit relay contact supports it. + +Equipment receives power through an adjacent wire touching a declared power contact. + +When Power Overlay is off, wires should not interfere with normal conveyor clicking. + +### 3.6 Power-wire equipment + +#### Regular Power Wire + +- ID: `powerWire` +- Price: 10 yen per tile +- Loss: 0.5V per tile +- Temporary art: thin dark line, brighter in Power Overlay mode + +#### Insulated Power Wire + +- ID: `insulatedPowerWire` +- Price: 22 yen per tile +- Loss: 0.15V per tile +- Temporary art: thicker line with a light outer casing +- Replacing one wire type with the other should be a direct operation that charges or refunds the price difference. + +### 3.7 Powered-machine values + +Place these values in the centralized balance table. + +| Equipment | Minimum voltage | Voltage load | Relay drop | +|---|---:|---:|---:| +| Mixer | 10V | 4V | 4V | +| Shredder | 8V | 3V | 3V | +| Shipping Truck | 6V | 2V | 2V | +| Automatic Scanner | 8V | 2V | 2V | +| Sausage Machine | 12V | 5V | 5V | +| Maintenance Room | 6V | 1V | 1V | +| Inbound Truck | 5V | 1V | 1V | + +### 3.8 Starter generator and initial wiring + +Add one starter generator to every new game. + +- ID: `starterGenerator` +- Size: 2x2 +- Continuous output: 25V +- Exists from game start +- Cannot be sold +- Cannot be built again +- May be moved during build phase +- Requires no electricity +- Temporary art: dark body, lightning symbol, and `25V` label + +A new game must also contain free regular power wires connecting the starter generator to: + +- the initial mixer; +- the initial shredder; +- the initial shipping truck. + +All three machines must be powered on day one without player intervention. + +Implementation requirements: + +1. reserve the generator footprint and required route cells before obstacle generation; +2. create default equipment first; +3. run a deterministic helper such as `createStarterPowerLayout(game)`; +4. route through owned, non-obstacle cells; +5. allow wires to cross conveyor cells because wires are on a separate layer; +6. never route through equipment bodies; +7. charge zero money for the starter generator and initial wires; +8. validate the completed layout; +9. fail loudly in development if valid initial routing cannot be created. + +The initial mixer, shredder, and shipping truck create 9V total load, leaving a 16V bus before path loss. + +### 3.9 Biomass generator + +- ID: `biomassGenerator` +- Size: 3x3 +- Price: 520 yen +- Inputs: three ports at left-center, top-center, and bottom-center +- Accepts male chicks, female chicks, and poop +- Rejects meat, sausage, coal, and zunda mochi +- Each accepted item adds +5V for 2 seconds +- Multiple active pulses in the same generator stack additively +- Three overlapping inputs therefore provide +15V during the overlap +- Clear pulses at day end +- Requires no electricity +- Temporary art: leaf/flame symbol and current output label + +### 3.10 Coal generator + +- ID: `coalGenerator` +- Size: 2x3 +- Price: 680 yen +- One coal input at left-center +- Each coal adds +15V for 3 seconds +- Multiple active pulses in the same generator stack additively +- Reject all non-coal items +- Clear pulses at day end +- Requires no electricity + +### 3.11 Power UI + +Add a build-phase **POWER OVERLAY** toggle. + +Display: + +- wire type; +- generator output; +- assigned source; +- source bus voltage after admitted load; +- route loss; +- received voltage; +- minimum required voltage; +- Voltage Load; +- under-voltage state. + +Example equipment tooltip: + +```text +Power: 9.5V / 10V +Source: Starter Generator +Source bus: 15.5V +Route loss: 6.0V +Voltage Load: 4V +Status: UNDER VOLTAGE +``` + +Show a red crossed-lightning symbol on an under-voltage machine during operation. + +Warn before NEXT DAY when machines are unpowered, but do not block starting the day. + +--- + +## 4. Inbound logistics + +### 4.1 Inbound Truck + +Add a new edge machine. + +- ID: `inboundTruck` +- Price: 350 yen +- Multiple inbound trucks may be built +- One output port faces the grid +- Requires 5V and contributes 1V Voltage Load +- Imports coal and zunda mochi +- Clicking it opens a per-truck configuration panel + +Store: + +```js +inboundOrder: { + coalPerDay: 0, + zundaMochiPerDay: 0 +} +``` + +Daily limits per truck: + +- coal: 0–60; +- zunda mochi: 0–30; +- combined total: 80 items. + +Purchase prices: + +- coal: **2 yen each**; +- zunda mochi: **4 yen each**. + +Charge the complete order cost at the beginning of the day. + +### 4.2 Delivery timing + +Distribute imports across the 60-second operating day. + +For `n` items: + +```js +baseTime = ((i + 0.5) / n) * TURN_SECONDS +``` + +Apply deterministic or seeded jitter within ±15% of the base interval. + +Merge coal and zunda schedules and dispatch in timestamp order. + +If the output is blocked: + +- retain the item in the truck queue; +- do not delete it; +- resume release when space becomes available. + +If the truck is under-voltage, pause release timing and resume after power restoration. + +Items still unreleased at day end are undelivered, do not carry over, and are not refunded. + +### 4.3 New transport types + +Add transport-item types compatible with the current entity structure: + +```js +sex: 'coal' +sex: 'zundaMochi' +``` + +Temporary art: + +- coal: small black rounded square; +- zunda mochi: small green circle or diamond. + +Manual and automatic scanners must reject both items without deleting them. + +--- + +## 5. Egg-farm output cap and product quality + +### 5.1 Design goal + +Farm upgrades currently reach a point where farms produce faster than even a Boost Conveyor can remove items. + +From v29.00 onward: + +- production speed up to the theoretical capacity of one Boost Conveyor increases item count; +- theoretical production beyond that capacity no longer increases item count; +- the excess becomes a diminishing product-quality multiplier. + +Never derive quality from real congestion, a blocked output, queue size, or deliberate obstruction. + +### 5.2 Derive Boost Conveyor capacity + +Do not introduce a duplicate hard-coded throughput constant. + +Derive capacity from the live movement model, for example: + +```js +boostOutputCapacityPerSecond = + BALANCE.conveyor.boostSpeedPxPerSecond / + BALANCE.transport.minimumItemSpacingPx; +``` + +Use the actual variable names from the project. + +Changing Boost Conveyor speed or minimum spacing must automatically change the farm cap. + +### 5.3 Farm formula + +For each farm: + +```text +R = theoretical production rate after permanent upgrades, cards, events, and zunda boost +C = theoretical maximum output rate of one Boost Conveyor +actualSpawnRate = min(R, C) +overflowRatio = max(0, R / C - 1) +qualityMultiplier = clamp(1 + 0.45 * overflowRatio^0.85, 1.0, 2.5) +``` + +Store the formula constants in centralized balance data. + +Expected behavior: + +| Theoretical rate | Actual item rate | Approximate quality | +|---:|---:|---:| +| 0.8C | 0.8C | 1.00x | +| 1.0C | 1.0C | 1.00x | +| 1.5C | 1.0C | about 1.25x | +| 2.0C | 1.0C | 1.45x | +| 3.0C | 1.0C | about 1.81x | +| 5.0C | 1.0C | about 2.46x | + +Snapshot quality when an item is spawned: + +```js +sourceQuality: 1.0 +``` + +### 5.4 Quality inheritance + +- A female chick shipped directly multiplies shipping revenue by its `sourceQuality`. +- A male chick processed into meat transfers its quality to that meat item. +- A sausage made from two meat items uses the arithmetic mean of the two meat-quality values. +- Shipping sausage multiplies its base value by sausage quality. +- Poop has no quality multiplier. +- Biomass power output ignores quality. +- Coal and zunda have no quality. +- The mixer blocked-output fallback remains exactly +5 yen and ignores quality. + +### 5.5 Farm UI + +Show: + +- theoretical production rate; +- actual capped output rate; +- Boost Conveyor cap; +- current quality multiplier; +- quality grade. + +Display-only grades: + +- 1.00–1.14x: Standard +- 1.15–1.34x: Select +- 1.35–1.74x: Premium +- 1.75x and above: Luxury + +Revenue must use the continuous multiplier, not grade buckets. + +If the connected belt is slower than the farm's actual capped output, show: + +```text +OUTPUT BELT BELOW FARM CAPACITY +``` + +--- + +## 6. Zunda mochi farm boost + +A zunda mochi item reaching a conveyor cell orthogonally adjacent to an egg farm is consumed by that farm. + +- Accept from any of the four adjacent directions. +- Each item adds 8 seconds to the boost timer. +- Maximum stored boost time: 30 seconds. +- While active, production interval multiplier: 0.55. +- Multiple items extend duration but do not multiply the speed factor. +- Clear remaining boost time at day end. +- Keep the existing safe minimum production interval of 0.25 seconds. +- Zunda changes theoretical rate `R`. +- If zunda raises `R` above the Boost Conveyor cap, the excess becomes quality rather than extra item count. + +Record realized zunda value in daily statistics. + +Do not add all of the following balancing restrictions at once. They are tuning controls only if playtests show zunda is dominant: + +- reduce duration from 8 seconds to 6 seconds; +- add a per-farm consumption cooldown; +- reduce only the zunda-derived quality-conversion efficiency; +- add a per-farm daily appetite limit. + +--- + +## 7. Repair-worker navigation and footbridges + +### 7.1 Collision rules + +Replace direct straight-line repair-worker movement with four-directional A* or BFS grid pathfinding. + +A worker may enter a cell only when it is: + +- owned; +- not an obstacle; +- not occupied by equipment, a farm, scanner, or maintenance room; +- not occupied by a conveyor unless a footbridge covers that conveyor cell. + +Power wires do not block walking. + +### 7.2 Footbridge + +- ID: `footbridge` +- Price: 90 yen +- Size: 1x3 or 3x1 +- Rotatable +- May overlap conveyor and power-wire layers +- May not overlap obstacles, unowned cells, or equipment bodies +- Affects repair-worker movement only +- Must not alter conveyor transport, direction editing, or branch selection +- Temporary art: translucent deck with side rails + +### 7.3 Path caching + +Each worker should store: + +```js +path +pathIndex +pathVersion +``` + +Maintain `game.walkabilityVersion` and increment it whenever construction changes passability. + +Recalculate only when: + +- target changes; +- walkability version changes; +- current path becomes invalid. + +Do not run pathfinding every frame. + +### 7.4 Repair position + +Workers repair from a reachable cell orthogonally adjacent to the target footprint. + +They must not stand inside the target machine. + +- Generate adjacent candidate work cells. +- Choose the nearest reachable candidate. +- Repair conveyors from an adjacent walkable cell or a valid footbridge cell. +- Repair edge equipment from the nearest reachable grid-side work cell. +- Skip unreachable targets. +- Show `NO REPAIR ACCESS` in details for unreachable equipment. +- Workers must exit the maintenance room from a valid perimeter cell rather than its center. + +--- + +## 8. Layer selection and editing + +Because conveyors, power wires, and footbridges may overlap: + +- equipment selection has highest priority; +- with Power Overlay enabled, wires participate in hit testing; +- with Power Overlay disabled, conveyors take priority and wires are not directly clickable; +- footbridges must remain selectable without breaking conveyor editing; +- erase one layer at a time in this order: + 1. footbridge; + 2. power wire; + 3. conveyor; +- optionally support Shift+Erase to remove all overlay layers on one cell. + +Do not regress edge-conveyor reversal or conveyor branch selection rules. + +--- + +## 9. Power gates for existing machines + +Add power checks at these points: + +- automatic scanner before queue processing; +- mixer before acceptance and processing; +- shredder before acceptance and processing; +- shipping truck before acceptance; +- sausage machine before acceptance, processing, and output; +- inbound truck before item release; +- maintenance room before worker dispatch and while repair work is progressing. + +Do not remove an item from the upstream conveyor before the destination confirms that it is powered and has capacity. + +--- + +## 10. Card behavior and durability + +Preserve equipment-dependent card filtering. + +Do not add generator, wire, inbound-truck, or footbridge cards in v29.00. + +Repairable new equipment: + +- starter generator; +- biomass generator; +- coal generator; +- inbound truck. + +No wear in v29.00: + +- regular wire; +- insulated wire; +- footbridge. + +Generator wear must not reduce output voltage in this version. Use the existing normal delay/maintenance model only if required. + +--- + +## 11. Statistics and UI + +Add daily statistics for: + +- coal ordered, released, consumed, and undelivered; +- zunda ordered, released, consumed, and undelivered; +- import purchase cost; +- fuel consumed by generator type; +- maximum output per generator; +- under-voltage seconds per machine; +- generator-source assignment changes; +- zunda boost seconds per farm; +- farm theoretical rate; +- farm actual output rate; +- average and maximum quality multiplier; +- revenue added by quality; +- unreachable repair-target count. + +Build controls: + +- POWER WIRE +- INSULATED WIRE +- BIOMASS GEN +- COAL GEN +- INBOUND TRUCK +- FOOTBRIDGE +- POWER OVERLAY + +Do not add a build button for the starter generator. + +Inbound Truck panel: + +- coal per day; +- zunda mochi per day; +- combined total; +- daily purchase cost; +- average release interval; +- current output queue. + +Editable only in build phase. + +Top-level power summary example: + +```text +POWER: Starter 25V / 3 powered / 1 under-voltage +``` + +Do not display a summed `TOTAL V`, because independent generators are not combined. + +--- + +## 12. README requirements + +Document the implemented values and behavior for: + +- machines that do and do not require electricity; +- generator load sag; +- regular-wire loss of 0.5V per tile; +- insulated-wire loss of 0.15V per tile; +- non-splitting branches; +- non-additive separate generators; +- machine minimum voltage and Voltage Load; +- starter, biomass, and coal generators; +- free initial generator and wiring; +- inbound orders and item prices; +- zunda farm boost; +- Boost Conveyor production cap; +- quality overflow and inheritance; +- repair-worker collision rules; +- footbridges; +- temporary geometric art for new machines. + +Every README number must come from or match the centralized balance values. + +--- + +## 13. Required tests + +Retain all v28.21 tests and add a dedicated v29.00 test suite. + +### Power + +1. One regular wire tile loses 0.5V. +2. Ten regular wire tiles lose 5V. +3. One insulated wire tile loses 0.15V. +4. Ten insulated wire tiles lose 1.5V. +5. Mixed paths calculate exact combined loss. +6. Branches do not divide voltage. +7. Loops never increase voltage. +8. Separate generators are not summed. +9. Three overlapping biomass pulses produce +15V. +10. One coal pulse produces +15V for 3 seconds. +11. Starter mixer, shredder, and shipping truck create 9V total load. +12. A machine that would invalidate the admitted source set remains unpowered. +13. Under-voltage machines do not consume items. +14. Paused processing resumes after power restoration. +15. New games include the starter generator and initial wires. +16. Initial mixer, shredder, and shipping truck are powered on day one. +17. Starter power equipment costs zero. +18. Initial power cells do not overlap obstacles or equipment bodies. + +### Imports + +19. Coal costs 2 yen each. +20. Zunda mochi costs 4 yen each. +21. Sixty coal items schedule at approximately one-second intervals. +22. Six items schedule at approximately ten-second intervals. +23. A blocked inbound output retains its item. +24. Coal and zunda cannot enter scanners. +25. Order cost is charged correctly at day start. +26. Under-voltage pauses release without losing queued imports. + +### Farm quality + +27. Spawn count is unchanged below the Boost Conveyor capacity. +28. Spawn rate is capped at the derived Boost Conveyor capacity. +29. Quality is exactly 1.0x at or below the cap. +30. Quality increases monotonically above the cap. +31. Quality never exceeds 2.5x. +32. Blocking farm output does not raise quality. +33. Female shipping revenue uses source quality. +34. Meat inherits chick quality. +35. Sausage quality equals the arithmetic mean of its two meat inputs. +36. Mixer fallback remains exactly +5 yen regardless of quality. +37. Poop and generator output ignore farm quality. +38. Changing Boost Conveyor movement speed changes the derived cap without editing another constant. + +### Zunda + +39. A farm consumes adjacent zunda mochi. +40. One item adds 8 seconds up to 30 seconds. +41. Zunda changes theoretical farm rate. +42. Zunda cannot increase count beyond the Boost Conveyor cap. +43. Zunda overflow increases quality through the same formula. +44. Multiple zunda items extend duration but do not multiply the speed factor. + +### Repair workers + +45. Workers cannot pass through equipment. +46. Workers cannot walk on uncovered conveyor cells. +47. Workers can cross conveyor cells covered by a footbridge. +48. Workers repair from an adjacent cell. +49. Unreachable machines are skipped and flagged. +50. Construction edits invalidate and recalculate cached paths. + +### Regression and build + +51. Every v28.21 test passes. +52. `npm run build` succeeds. +53. Generated output contains no `boost is not defined` regression. +54. NEXT DAY enters the running phase with one click. +55. Regular and Boost Conveyor drawing does not throw. +56. Edge-conveyor reversal still works. +57. Conveyor item movement remains synchronized with conveyor animation. +58. A new factory runs without manual power edits. +59. The final ZIP contains source, updated README, and rebuilt production files. + +--- + +## 14. Implementation order + +Implement in this order, with a working checkpoint after each stage: + +1. balance constants, IDs, equipment definitions, temporary drawing; +2. starter-generator placement reservation and free initial wiring; +3. wire overlay and route-loss calculation; +4. generator load admission and machine power gates; +5. biomass and coal generators; +6. inbound truck and imported transport items; +7. egg-farm throughput cap and quality inheritance; +8. zunda integration; +9. footbridge and repair-worker pathfinding; +10. UI, statistics, and README; +11. full regression tests, production build, and release ZIP. + +Do not implement all systems as one large patch. + +--- + +## 15. Completion criteria + +The implementation is complete only when: + +- a new game visibly includes a starter generator and connected wires; +- the initial mixer, shredder, and shipping truck work on day one; +- long wire runs reduce received voltage; +- insulated wire loses exactly 0.15V per tile; +- adding powered machines creates source load and can cause under-voltage; +- under-voltage never deletes or silently consumes items; +- fuel inputs create timed additive output pulses inside each generator; +- coal and zunda imports are distributed across the day; +- farm output count cannot exceed one Boost Conveyor's theoretical transport capacity; +- production above that cap increases product quality rather than count; +- deliberate congestion never creates quality; +- quality survives the female shipping and meat-to-sausage chains; +- repair workers avoid machines and uncovered conveyors; +- footbridges permit repair-worker conveyor crossings; +- README values match implementation values; +- all old and new tests pass; +- the production bundle builds successfully. + +--- + +# Optional future-design backlog — do not implement in v29.00 + +Record these ideas in a short `FUTURE_IDEAS.md` or an equivalent non-executable design note. Do not implement them unless explicitly requested. + +## A. Capacitor / battery + +Store short biomass and coal voltage pulses and release them gradually to reduce intermittent under-voltage. + +Potential parameters: + +- storage capacity; +- maximum charge rate; +- maximum discharge rate; +- round-trip efficiency; +- player-selectable reserve threshold. + +## B. Transformer or power-combiner station + +Allow multiple generators to feed one managed bus only through a dedicated late-game machine. This would intentionally replace the v29.00 rule that independent generator voltages are never summed. + +## C. Editable power priorities + +Allow Low, Normal, and High priority per machine so nonessential production shuts down before critical logistics during shortages. + +## D. Advanced power statistics + +Possible additions: + +- average received voltage; +- brownout count; +- energy/fuel cost per shipped item; +- source utilization percentage; +- unused generator output; +- voltage-loss heat map. + +## E. Additional wire tiers + +Possible late-game wire types with lower loss, higher purchase price, or limited placement requirements. Do not reduce Insulated Power Wire below its required 0.15V-per-tile value in v29.00. + +## F. Zunda balancing controls + +Only if telemetry shows zunda is dominant: + +- shorter duration; +- farm consumption cooldown; +- reduced zunda-only contribution to quality overflow; +- daily appetite limit. + +Change one control at a time and measure the result. + +## G. Repair-access visualization + +A build-mode overlay showing: + +- reachable worker cells; +- planned repair paths; +- machines with no adjacent work cell; +- recommended footbridge locations. + +## H. Power-aware card ideas + +Possible future cards after the base system is stable: + +- reduced machine Voltage Load; +- lower regular-wire loss; +- longer fuel pulses; +- improved biomass voltage per item; +- temporary emergency generator output; +- capacitor efficiency. + +Do not add these cards in v29.00 because the base power economy must be measured first. diff --git a/dist/game.js b/dist/game.js index 06d7c9c..a4d13f9 100644 --- a/dist/game.js +++ b/dist/game.js @@ -1 +1,52 @@ -import '../src/game.js'; +var V={version:"v28.21 BOOST DRAW HOTFIX",time:{daySeconds:60,farmShutdownGraceSeconds:10},cash:{starting:250},grid:{x:170,y:78,cols:20,rows:10,cell:46,expansion:{colsPerPurchase:10,rowsPerPurchase:10,costBase:850,costGrowthRate:.75,truncateUnit:50}},map:{blockedRatio:0,blockedExpansionIncrement:.0075,blockedRatioMax:.12},economy:{income:{mixer:5,truck:10,sausage:26},poopFine:10,fairiesTribute:{perDay:10,profitExemption:300,legalWorkExemptionBonus:250,profitRate:.12},incomeUpgradeRate:1.1,explosionDamageDivisor:30,maleTruckFinePerHalfDay:30,shredderBonus:{maxCards:30,payoutCoefficient:1.6,payoutExponent:1.25,baseHitChance:.28,hitChancePerUpgrade:.018,maxHitChance:.82,jackpotBaseChance:.01,jackpotChancePerUpgrade:.0025,jackpotMaxChance:.08,bigWinBaseChance:.07,bigWinChancePerUpgrade:.0015,bigWinMaxChance:.12,doubleChance:.2,jackpotMultiplier:10,bigWinMultiplier:4,doubleMultiplier:2},chemicalWeaponSubsidy:{poopPerBlock:70,yenPerBlock:1200}},production:{poopRate:.08,autoScannerCooldown:1.5,autoScannerUpgradeRate:.95,autoScannerCardUpgradeRate:.95,autoScannerMinCooldown:.5,poopRateCardBonus:.04,eggSpawnRanges:[[1.95,4.35],[1.55,3.45],[1.25,2.8],[1.05,2.35]]},conveyor:{baseSpeed:52,maxSpeed:300,bearingSpeedMultiplier:1.075},effects:{explosionHorizontalVelocityMultiplier:.82},cards:{definitions:[{id:"upgradeEgg",title:"EGG Improvement",rarity:"common",type:"equipmentUpgrade",target:"eggFarm",description:"Choose one EGG FARM on the map and raise it by 1 level.",tags:["EGG","ACTIVE"]},{id:"upgradeAutoScanner",title:"AUTO SCANNER Improvement",rarity:"common",type:"equipmentUpgrade",target:"autoScanner",description:"Choose one AUTO SCANNER on the map and raise it by 1 level.",tags:["SCANNER","ACTIVE"]},{id:"autoScannerTuning",title:"AUTO SCANNER Tuning",rarity:"common",type:"instant",description:"All AUTO SCANNER cooldowns use default cooldown x0.95 per copy.",requiresFacility:"autoScanner",tags:["SCANNER","PASSIVE"]},{id:"upgradeMixer",title:"MIXER Improvement",rarity:"common",type:"equipmentUpgrade",target:"mixer",description:"Choose one MIXER. Each level improves meat quality and raises sausage sale value by 10%.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeTruck",title:"TRUCK Improvement",rarity:"common",type:"equipmentUpgrade",target:"truck",description:"Choose TRUCK on the map and raise it by 1 level.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeSausageMaker",title:"SAUSAGE MACHINE Improvement",rarity:"common",type:"equipmentUpgrade",target:"sausageMaker",description:"Choose one SAUSAGE MACHINE. Each level raises sausage sale value by 10%.",tags:["ECONOMY","SAUSAGE","ACTIVE"]},{id:"upgradeTrash",title:"SHREDDER Improvement",rarity:"common",type:"equipmentUpgrade",target:"trash",description:"Adds a nonlinear scrap-lottery upgrade. More copies raise both payout and win chance; max 30.",tags:["POOP","ACTIVE"]},{id:"crowdedFarming",title:"Crowded Farming",rarity:"common",type:"instant",description:"EGG production interval -5%. Equipment deterioration +4%. Max 10 cards.",requiresFacility:"eggFarm",tags:["EGG","RISK","PASSIVE"]},{id:"hatchingFeed",title:"Hatching Feed",rarity:"common",type:"instant",description:"EGG production interval -4%. Poop rate +3%. No card limit.",requiresFacility:"eggFarm",tags:["EGG","POOP","PASSIVE"]},{id:"poopRateBooster",title:"Poop Culture",rarity:"common",type:"instant",description:"Base poop rate +4 percentage points. No card limit.",tags:["POOP","PASSIVE"]},{id:"safetyCover",title:"Safety Cover",rarity:"common",type:"instant",description:"Explosion damage -5%. No card limit.",tags:["RISK","PASSIVE"]},{id:"preventiveMaintenance",title:"Preventive Maintenance Manual",rarity:"common",type:"instant",description:"All equipment deterioration speed -5%. No card limit.",requiresAnyFacility:["conveyor","eggFarm","autoScanner","manualScanner","mixer","trash","sausageMaker"],tags:["MAINTENANCE","PASSIVE"]},{id:"dudFilter",title:"DUD Filter",rarity:"common",type:"instant",description:"DUD chance -5 percentage points. Stacks until DUD chance reaches 0%.",tags:["CARD","PASSIVE"]},{id:"durabilityCoating",title:"Durability Coating",rarity:"common",type:"instant",description:"All equipment maximum durability +3%. No card limit.",requiresAnyFacility:["conveyor","eggFarm","autoScanner","manualScanner","mixer","trash","sausageMaker"],tags:["MAINTENANCE","PASSIVE"]},{id:"bearing",title:"High-Quality Bearing",rarity:"common",type:"instant",description:"Conveyor speed +7.5%.",requiresFacility:"conveyor",tags:["CONVEYOR","PASSIVE"]},{id:"sparePartsBin",title:"SPARE PARTS BIN",rarity:"common",type:"instant",description:"Restores 2% durability to every machine. A box of almost-compatible parts.",requiresAnyFacility:["conveyor","eggFarm","autoScanner","manualScanner","mixer","trash","sausageMaker"],tags:["MAINTENANCE","ACTIVE"]},{id:"dudRefund",title:"DUD REFUND",rarity:"common",type:"instant",description:"DUDs now come with paperwork. Gain JPY 50 per copy when you pick a DUD.",tags:["CARD","ECONOMY","PASSIVE"]},{id:"freeReroll",title:"FREE REROLL",rarity:"common",type:"instant",description:"The first bad ideas are free.",tags:["CARD","PASSIVE"]},{id:"composter",title:"COMPOSTER",rarity:"common",type:"instant",description:"Turns shredder waste into suspicious fertilizer. Gain JPY 3 per copy when SHREDDER processes poop.",requiresFacility:"trash",tags:["POOP","ECONOMY","PASSIVE"]},{id:"scannerQueueSpacing",title:"Scanner Queue Spacing",rarity:"common",type:"instant",description:"Manual and Auto Scanner queue spacing -15%. No card limit.",requiresAnyFacility:["manualScanner","autoScanner"],tags:["SCANNER","PASSIVE"]},{id:"extraEggOutlet",title:"Extra Egg Outlet",rarity:"rare",type:"equipmentUpgrade",target:"eggOutlet",description:"Choose one EGG FARM and add +1 output port to that EGG. Max +3 per EGG.",tags:["EGG","RARE","ACTIVE"]},{id:"recyclingSubsidy",title:"Recycling Subsidy",rarity:"rare",type:"instant",description:"SELL refund rate +10 points. Max 3 cards; normal SELL can reach 80%.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"dynamite",title:"Dynamite",rarity:"rare",type:"cellAction",target:"blockedCell",description:"Choose and remove up to 3 unbuildable cells.",tags:["RISK","RARE","ONE-SHOT"]},{id:"usedMachine",title:"Used Machines",rarity:"rare",type:"instant",description:"Future equipment costs half. New purchases have no refund and 60% durability. New Machines cancels it.",tags:["ECONOMY","RISK","RARE"]},{id:"newMachine",title:"New Machines",rarity:"common",type:"instant",description:"Cancel Used Machines and restore normal prices, refunds, and durability.",tags:["ECONOMY","ONE-SHOT"]},{id:"flattery",title:"Flattery",rarity:"rare",type:"instant",description:"Next Fairies tribute -50%.",tags:["ECONOMY","RARE","ONE-SHOT"]},{id:"extraCards",title:"Extra Cards",rarity:"rare",type:"instant",description:"Draw 2 cards now and choose both.",tags:["RARE","ACTIVE"]},{id:"legalWork",title:"Legal Work",rarity:"rare",type:"instant",description:"Fairies tribute profit exemption +JPY 250.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"chemicalWeaponSubsidy",title:"Chemical Weapons Subsidy",rarity:"ultraRare",type:"instant",description:"Each day, gain JPY 1200 per 70 poop shipped by truck. No card limit.",tags:["POOP","ULTRA RARE","PASSIVE"]},{id:"laborExploitation",title:"Motivational Exploitation",rarity:"ultraRare",type:"instant",description:"Repair room work time -30%. The repairman smiles with bloodshot eyes. One time only.",tags:["MAINTENANCE","ULTRA RARE","PASSIVE"]},{id:"rescueLoan",title:"Emergency Loan",rarity:"ultraRare",type:"instant",description:"If cash is below JPY 0 at day-end settlement, gain JPY 500. Consumed on use.",tags:["ECONOMY","ULTRA RARE","ONE-SHOT"]}],defaultEffects:{bearing:0,legalWork:0,fairiesFlatteryNext:0,autoScannerTuning:0,poopRateBooster:0,crowdedFarming:0,hatchingFeed:0,safetyCover:0,recyclingSubsidy:0,chemicalWeaponSubsidy:0,preventiveMaintenance:0,dudFilter:0,durabilityCoating:0,sparePartsBin:0,dudRefund:0,freeReroll:0,composter:0,scannerQueueSpacing:0,laborExploitation:0,usedMachineActive:!1,rescueLoanCharges:0},commonWeight:8,rareWeight:2,ultraRareWeight:.45,baseDraftSize:3,maxDudsPerDraft:2,dudChancePerCard:.3,dudChanceReductionPerFilter:.05,extraCardsAddedPicks:2,rerollCost:{dayDivisor:2,multiplier:100}},events:{eventChance:.1,firstTurn:8},maintenance:{fullPerformanceUntilWear:.5,minimumPerformance:.5,durability:{conveyor:1300,eggFarm:475,autoScanner:850,mixer:775,trash:950,sausageMaker:825},processingDelayMaxSeconds:{mixer:1.2,trash:1,sausageMaker:.9},repairman:{secondsPerOnePercent:.5,walkSpeed:90}},facilities:{conveyor:{id:"conveyor",type:"conveyor",name:"Conveyor",shortName:"Belt",price:30,buildable:!0,upgradeable:!1},boostConveyor:{id:"boostConveyor",type:"conveyor",name:"Boost Conveyor",shortName:"BOOST BELT",price:75,buildable:!0,upgradeable:!1,speedMultiplier:2},eggFarm:{id:"eggFarm",type:"eggFarm",name:"Egg Farm",shortName:"EGG",price:250,buildable:!0,upgradeable:!0,maxLevel:4},manualScanner:{id:"manualScanner",type:"scanner",kind:"manual",name:"Manual Scanner",shortName:"Manual Scanner",price:260,buildable:!0,upgradeable:!1},autoScanner:{id:"autoScanner",type:"scanner",kind:"auto",name:"Auto Scanner",shortName:"Auto Scanner",price:180,buildable:!0,upgradeable:!1},mixer:{id:"mixer",type:"facility",name:"Mixer",shortName:"MIXER",price:450,buildable:!0,upgradeable:!0,incomeKey:"mixer",body:{w:164,h:126}},trash:{id:"trash",type:"facility",name:"Waste Shredder",shortName:"SHREDDER",price:240,buildable:!0,upgradeable:!0,body:{w:180,h:100}},truck:{id:"truck",type:"facility",name:"Truck",shortName:"TRUCK",price:450,buildable:!0,upgradeable:!0,incomeKey:"truck",body:{w:176,h:138}},sausageMaker:{id:"sausageMaker",type:"facility",name:"Sausage Machine",shortName:"SAUSAGE",price:380,buildable:!0,upgradeable:!0,incomeKey:"sausage",footprint:{cols:3,rows:3},body:{w:138,h:138},outputProduct:"sausage"},maintenanceRoom:{id:"maintenanceRoom",type:"maintenanceRoom",name:"Maintenance Room",shortName:"REPAIR ROOM",price:220,buildable:!0,upgradeable:!1,footprint:{cols:2,rows:2}}}};var si=V.version,Gt=V.time.daySeconds,Rn=V.cash.starting,xe=V.economy,ai=V.time.farmShutdownGraceSeconds,Qn=V.production.autoScannerCooldown,li=V.production.autoScannerUpgradeRate,Yo=V.production.autoScannerCardUpgradeRate||V.production.autoScannerUpgradeRate,Vo=V.production.autoScannerMinCooldown,ci=V.events.eventChance,Pn=V.events.firstTurn,zo=V.production.poopRate,Xo=V.production.poopRateCardBonus||0,Jn=V.conveyor.baseSpeed,tn=V.conveyor.maxSpeed,Zn=V.conveyor.bearingSpeedMultiplier,Ue=V.cards,ui=V.cards.definitions,jo=V.cards.defaultEffects,Et=V.production.eggSpawnRanges,f=V.grid,Te=V.facilities,Qo=["conveyor","boostConveyor","eggFarm","autoScanner","manualScanner","mixer","trash","truck","sausageMaker","maintenanceRoom"],eo=["mixer","trash","truck"],to=["sausageMaker"],Jo=[...eo,...to],di=["mixer","trash","truck"],fi=["mixer","truck","sausageMaker"],Rt=Object.fromEntries(Object.entries(Te).map(([e,t])=>[e,t.price])),fe=[{name:"right",dc:1,dr:0,angle:0,opposite:"left"},{name:"left",dc:-1,dr:0,angle:Math.PI,opposite:"right"},{name:"down",dc:0,dr:1,angle:Math.PI/2,opposite:"up"},{name:"up",dc:0,dr:-1,angle:-Math.PI/2,opposite:"down"}],b={bg:"#111318",ink:"#090a0d",muted:"#8f9bab",green:"#7bd84f",greenSoft:"#273c24",mixerBlue:"#4aa3ff",truckPink:"#ffb33e",wasteGreen:"#88d35a",meatRed:"#d96b72",sausageOrange:"#d78b3f",danger:"#e34a36",warn:"#ffb827",white:"#e6edf2",poop:"#7b4a23",male:"#4aa3ff",female:"#ff6fae"},Ie={ambient:0,important:1,critical:2};function x(e){let t=Number(e)||0;return`${t<0?"-":""}\uFFE5${Math.ceil(Math.abs(t)).toLocaleString("ja-JP")}`}function I(e,t){return`${e},${t}`}function re(e){let[t,n]=String(e).split(",").map(Number);return{col:t,row:n}}function An(e,t,n){return Math.max(t,Math.min(n,e))}function z(e,t){return e+Math.random()*(t-e)}function $e(e,t){return e>=0&&e=0&&tMath.round(An(r,0,255)).toString(16).padStart(2,"0");return`#${o(e)}${o(t)}${o(n)}`}function In(e,t,n){let o=pi(e),r=pi(t);return Wa(Zo(o.r,r.r,n),Zo(o.g,r.g,n),Zo(o.b,r.b,n))}var ce={appTitle:"Chick Sorter",versionTitle:`Chick Sorter ${si}`,currency:"\uFFE5",phases:{title:"Title",build:"Build",running:"Sorting",clearing:"Clearing",loanDecision:"Emergency Loan",gameover:"Game Over"},actions:{startGame:"Start Game",nextDay:"Next Day",buildPhase:"Build Phase",restart:"Restart",close:"Close",remove:"Remove",refund:"Refund",autoMenu:"Auto Menu"},status:{build:e=>`BUILD: ${(e==="erase"?"SELL":e||"SELECT").toUpperCase()} | Right-drag pan | Hover equipment for info`,sorting:"Sorting: use scanner keys. Build after clearing the day.",allPortsConnected:"Start condition met: one EGG route reaches an exit.",equipmentPanelEmpty:"Hover equipment in Build phase."},routeLabels:{mixer:"MIXER",truck:"TRUCK",trash:"WASTE",sausageMaker:"SAUSAGE",scanner:"NEXT","scanner-role-1":"NEXT",input:"IN"},fail:{outOfGrid:"Out of grid",cellOccupied:"Cell occupied",notEnoughCash:"Not enough cash",facilityExists:"Facility already exists",facilityOverlap:"Facility overlap",nothingToErase:"Nothing to sell",noUpgrade:"No upgrade available"}};function Pt(e){return Te[e]?.name||String(e||"").replace(/^[a-z]/,t=>t.toUpperCase())}function Ha(e){let t=Te[e];return t?e==="conveyor"||e==="boostConveyor"?`${x(t.price)} / tile`:e==="autoScanner"?`${x(t.price)} / ${Qn.toFixed(1)}s cooldown`:e==="trash"?x(t.price):x(t.price):""}function Ka(e){return{conveyor:"A narrow green belt. Routes decide whether chicks live, ship, or become invoices.",boostConveyor:"Moves chicks twice as fast. Wears down like a normal belt.",eggFarm:"A tiny gatehouse producing questionable eggs on schedule.",autoScanner:"Processes about 40 items per day at Lv1, roughly 2.1 Lv1 farms.",manualScanner:"A manual checkpoint. The operator is the algorithm.",mixer:"Makes meat when OUT is clear; otherwise falls back to direct sale.",trash:"A polite shredder for poop and other regrets.",truck:"Ships target chicks and all sausages. Wrong live cargo still leaves a paper trail.",sausageMaker:"A 3\xD73 grid machine. Left inlet takes 2 meat; right outlet emits 1 sausage.",maintenanceRoom:"2\xD72 repair bay. Each room dispatches one repairman during the day."}[e]||""}function qa(e){return{conveyor:"./assets/dark_factory/facilities/conveyor/conveyor_straight_h_16.png",boostConveyor:"./assets/dark_factory/facilities/conveyor/boost_conveyor_straight_h_16.png",eggFarm:"./assets/dark_factory/facilities/machines/egg_farm_16.png?v=dark_factory",autoScanner:"./assets/dark_factory/facilities/machines/auto_scanner_32x48.png",manualScanner:"./assets/dark_factory/facilities/machines/manual_scanner_32x48.png",mixer:"./assets/dark_factory/facilities/machines/mixer_32.png",trash:"./assets/dark_factory/facilities/machines/shredder_32.png",truck:"./assets/dark_factory/facilities/vehicles/truck_32.png",sausageMaker:"./assets/dark_factory/facilities/machines/mixer_32.png",maintenanceRoom:"./assets/dark_factory/facilities/utility/maintenance_room_32.png"}[e]||""}function hi(e){let t=Ka(e),n=qa(e);return`${n?``:""}${Pt(e)}${Ha(e)}${t?`${t}`:""}`}function mi(e){return ce.routeLabels[e]||String(e).toUpperCase()}function bi(e){let t=2166136261;for(let n=0;n>>0}function vi(e){let t=e>>>0;return()=>{t+=1831565813;let n=Math.imul(t^t>>>15,1|t);return n^=n+Math.imul(n^n>>>7,61|n),((n^n>>>14)>>>0)/4294967296}}function wi(e,{base:t=0,increment:n=.0075,max:o=.12}={}){let r=Math.max(0,Math.floor(Number(e)||0));return Number(Math.min(o,t+r*n).toFixed(6))}function oo(){return`RUN-${Date.now().toString(36)}-${Math.floor(Math.random()*1e6).toString(36)}`.toUpperCase()}function Si({seed:e,targetRatio:t=.2,reserved:n=[]}={}){let o=vi(bi(e||oo())),r=new Set(n.map(c=>typeof c=="string"?c:I(c.col,c.row))),i=[];for(let c=0;c0;c-=1){let h=Math.floor(o()*(c+1));[i[c],i[h]]=[i[h],i[c]]}let a=Math.round(f.cols*f.rows*t+1e-9);return new Set(i.slice(0,Math.min(a,i.length)).map(c=>c.k))}function ki({seed:e,colStart:t=0,colEnd:n=f.cols,rowStart:o=0,rowEnd:r=f.rows,targetRatio:i=.2,reserved:a=[]}={}){let c=vi(bi(e||oo())),h=new Set(a.map(Z=>typeof Z=="string"?Z:I(Z.col,Z.row))),g=[],C=Math.max(0,Math.floor(t)),P=Math.max(C,Math.floor(n)),L=Math.max(0,Math.floor(o)),K=Math.max(L,Math.floor(r));for(let Z=L;Z0;Z-=1){let Q=Math.floor(c()*(Z+1));[g[Z],g[Q]]=[g[Q],g[Z]]}let j=Math.round((P-C)*(K-L)*i+1e-9);return new Set(g.slice(0,Math.min(j,g.length)).map(Z=>Z.k))}var nn=10,gi=2,Ci=1;function on(e,t){return`${e},${t}`}function Ya(e){let[t,n]=String(e).split(",").map(Number);return{chunkX:t,chunkY:n}}function ro(e){let t=V.grid.expansion||{},n=Math.max(1,(e.gridExpansionPurchases||0)+1),o=Math.max(0,Number(t.costBase)||850),r=Math.max(0,Number(t.costGrowthRate)||.75),i=o*(1+r*(n-1)),a=Math.max(1,t.truncateUnit||50);return Math.floor(i/a)*a}function Mi(e){e.ownedCells=new Set,e.ownedChunks=new Set,e.gridChunkOriginX=0,e.gridChunkOriginY=0,e.gridExpansionPurchases=0,e.gridExpansionPurchasesByDirection={left:0,right:0,up:0,down:0};for(let t=0;t=0&&t=0&&n{let a=(o[r.direction]??9)-(o[i.direction]??9);return a||(r.chunkY!==i.chunkY?r.chunkY-i.chunkY:r.chunkX-i.chunkX)})}function Ei(e,t="right"){let n=Ut(e);return n.find(o=>o.direction===t)||n[0]||null}function dt(e){return{x:f.x+e.colStart*f.cell,y:f.y+e.rowStart*f.cell,w:e.cols*f.cell,h:e.rows*f.cell}}function tr(e){let t=dt(e);return{x:t.x+t.w/2-116,y:t.y+t.h/2-36,w:232,h:72,cx:t.x+t.w/2,cy:t.y+t.h/2}}function Ri(e,t){let n=tr(e);return t.x>=n.x&&t.x<=n.x+n.w&&t.y>=n.y&&t.y<=n.y+n.h}function Pi(e){let t=[];for(let n=e.rowStart;n$e(t.col,t.row))}function el(e){return[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row}].filter(t=>$e(t.col,t.row))}function tl(e){return[{col:e.col,row:e.row+1},{col:e.col-1,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row-1}].filter(t=>$e(t.col,t.row))}function Oi(e){let t=new Set([...e.conveyorTiles]),n=o=>{o&&$e(o.col,o.row)&&t.add(I(o.col,o.row))};for(let o of e.scanners){for(let r of el(o))n(r);for(let r of Za(o))n(r)}for(let o of e.eggFarms){n(o);for(let r of tl(o))n(r)}for(let o of Object.values(e.facilities))n(o.entry);return t}function Di(e){let t=Xa.map(([n,o])=>({col:n,row:o}));for(let{col:n,row:o}of t)Bi(e,n,o);for(let n=0;n({...n,keys:n.keys?{left:{...n.keys.left},right:{...n.keys.right}}:null,queue:[]})),e.eggFarms=Qa.map(n=>{let o=Wt(n);return{...n,nextSpawn:o,lastInterval:o}});let t=Oi(e);e.blockedCells=Si({seed:e.runSeed,targetRatio:V.map.blockedRatio,reserved:[...t]}),nl(e),Di(e),e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function ft(e){return e?[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row}]:[]}function ge(e){let t=$(e.col,e.row);return{x:t.x+f.cell/2,y:t.y-f.cell/2}}function it(e,t,n){return e.eggFarms.find(o=>o.col===t&&o.row===n)||null}function st(e,t,n){return e.scanners.find(o=>ft(o).some(r=>r.col===t&&r.row===n))||null}function Ht(e,t){return e.scanners.find(n=>n.id===t)||null}function ar(e,t){return e.scanners.find(n=>n.kind==="manual"&&n.slot===t)||null}function sn(e){return e?.baseId||e?.id||""}function lr(e,t){return Object.entries(e.facilities||{}).filter(([,n])=>sn(n)===t)}function lo(e,t){return!!(t&&$e(t.col,t.row)&&(!e?.ownedCells?.size||e.ownedCells.has(I(t.col,t.row))))}function pt(e,t,n){return Object.values(e?.facilities||{}).find(o=>o?.gridPlaced?t>=o.col&&t=o.row&&n({col:e.col+t.dc,row:e.row+t.dr})).filter(t=>$e(t.col,t.row)):[]}function _i(e,t,n=[],o=[]){if(!t||!$e(t.col,t.row))return[];let r=[],i=a=>{!a||!$e(a.col,a.row)||!e.conveyorTiles.has(I(a.col,a.row))||n.some(c=>c&&no(a,c))||r.some(c=>no(c,a))||r.push({...a,viaTolerance:!no(a,t)})};i(t);for(let a of o)i(a);for(let a of Ni(t))i(a);return r}function sr(e,t,n=[],o=[]){let r=_i(e,t,n,o),i=r.filter(a=>!a.viaTolerance);return i.length?i:r}function ol(e,t){let n=Fe(t,"inputA");return!n||!$e(n.col,n.row)?[]:sr(e,n,ft(t))}function rl(e,t,n){let o=Fe(t,n);return _i(e,o,ft(t))}function il(e,t){let n=e.facilities[t]||lr(e,t)[0]?.[1];if(!n)return null;let o=nt(e,n);if(o)return $(o.col,o.row);let r=sn(n)||t;return r==="mixer"?{x:n.x+n.w,y:n.y+n.h*.52}:r==="truck"?{x:n.x,y:n.y+n.h*.52}:r==="trash"?{x:n.x+n.w/2,y:n.y+8}:{x:n.x+n.w/2,y:n.y+n.h/2}}function Gi(e,t,n){return n==="inputA"?ol(e,t).length>0:rl(e,t,n).length>0}function Me(e){e.branchCounters?.clear?.(),e.routeCache=null,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1,e.frameCache&&(e.frameCache.routingVersion=-1,e.frameCache.congestionFrame=-1,e.frameCache.draw={})}function We(e,t){return I(e,t)}function rn(e){return re(e)}function sl(e,t){let n=e.conveyorMeta?.get?.(t)||{},o=[];return Array.isArray(n.outDirs)&&o.push(...n.outDirs),n.dir&&o.push(n.dir),[...new Set(o)].filter(r=>fe.some(i=>i.name===r))}function Li(e,t,n){let o=fe.find(a=>a.name===n);if(!o)return!1;let r=e.conveyorMeta?.get?.(We(t.col+o.dc,t.row+o.dr));return r?[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))].includes(o.opposite):!1}function al(e,t){let n=rn(t),o=e.conveyorMeta?.get?.(t)||{},r=fe.filter(C=>e.conveyorTiles.has(We(n.col+C.dc,n.row+C.dr))).map(C=>C.name),i=sl(e,t).filter(C=>r.includes(C)),a=i.length?i:r;if(r.length===1&&(!i.length||i.includes(r[0]))&&Li(e,n,r[0]))return[];if(r.length<3)return a;let c=new Set(r.filter(C=>Li(e,n,C))),h=r.filter(C=>!c.has(C)),g=c.size?h:[...new Set(a)];return!g.length&&!c.size&&(g=r),o.branchMode&&o.branchMode!=="random"&&g.length>=2&&g.includes(o.branchMode)?[o.branchMode]:g}function ll(e){return{version:e.routingVersion||0,cells:new Set,adjacency:new Map,components:new Map,cellToComponent:new Map,scannerInputs:new Map,scannerPorts:new Map,facilityPorts:new Map,farmOutputs:new Map,pathCache:new Map,metrics:{conveyorCells:0,edges:0,components:0,deadEnds:0,crosses:0,scannerPorts:0,connectedScannerPorts:0,facilityPorts:0,connectedFacilityPorts:0,farmOutputs:0},issues:[]}}function cl(e){let t=ll(e);for(let o of e.conveyorTiles)t.cells.add(o),t.adjacency.set(o,[]);for(let o of t.cells){let r=rn(o),i=al(e,o),a=fe.filter(c=>i.includes(c.name));for(let c of a){let h=We(r.col+c.dc,r.row+c.dr);t.cells.has(h)&&t.adjacency.get(o).push({key:h,dir:c.name})}}let n=0;for(let[o,r]of t.adjacency.entries()){n+=r.length;let i=new Set(r.map(a=>a.dir));r.length===1&&(t.metrics.deadEnds+=1),r.length===4&&i.has("left")&&i.has("right")&&i.has("up")&&i.has("down")&&(t.metrics.crosses+=1)}return t.metrics.conveyorCells=t.cells.size,t.metrics.edges=Math.floor(n/2),ul(t),dl(e,t),t.issues=Cl(e,t,{includeRoutes:!1}),t}function ul(e){let t=1;for(let n of e.cells){if(e.cellToComponent.has(n))continue;let o=t++,r=[n],i=[];for(e.cellToComponent.set(n,o);r.length;){let a=r.shift();i.push(a);for(let c of e.adjacency.get(a)||[])e.cellToComponent.has(c.key)||(e.cellToComponent.set(c.key,o),r.push(c.key))}e.components.set(o,{id:o,cells:i,capacity:Math.max(1,i.length),count:0,ratio:0})}e.metrics.components=e.components.size}function dl(e,t){for(let n of e.scanners){let o={};for(let r of["inputA","left","right"]){let i=Fe(n,r),a=sr(e,i,ft(n)).filter(g=>t.cells.has(We(g.col,g.row))),c=a.map(g=>We(g.col,g.row)),h=c.length>0;if(o[r]={type:r,cell:i,cells:a,keys:c,key:c[0]||null,connected:h},t.metrics.scannerPorts+=1,h&&(t.metrics.connectedScannerPorts+=1),r==="inputA")for(let g of c)t.scannerInputs.set(g,n.id)}t.scannerPorts.set(n.id,o)}for(let[n,o]of Object.entries(e.facilities)){let r=nt(e,o);if(!r)continue;let i=sr(e,r).filter(h=>t.cells.has(We(h.col,h.row))),a=i.map(h=>We(h.col,h.row)),c=a.length>0;t.facilityPorts.set(n,{id:n,cell:{...r},cells:i,keys:a,key:a[0]||null,connected:c}),t.metrics.facilityPorts+=1,c&&(t.metrics.connectedFacilityPorts+=1)}for(let n of e.eggFarms){let o=Ni({col:n.col,row:n.row}).map(r=>We(r.col,r.row)).filter(r=>t.cells.has(r));t.farmOutputs.set(n.id,o),t.metrics.farmOutputs+=o.length}}function Je(e){let t=e.routingVersion||0;return(!e.factoryGraph||e.factoryGraph.version!==t)&&(e.factoryGraph=cl(e)),e.factoryGraph}function Ui(e){let t=Je(e);return e.factoryGraphCommittedVersion=t.version,e.factoryGraphSnapshot=fl(t),t}function fl(e){return e?{version:e.version,conveyorCells:e.metrics.conveyorCells,edges:e.metrics.edges,components:e.metrics.components,deadEnds:e.metrics.deadEnds,crosses:e.metrics.crosses,scannerPorts:`${e.metrics.connectedScannerPorts}/${e.metrics.scannerPorts}`,facilityPorts:`${e.metrics.connectedFacilityPorts}/${e.metrics.facilityPorts}`,farmOutputs:e.metrics.farmOutputs,issues:[...e.issues||[]]}:null}function pl(e,t){let n=t.col-e.col,o=t.row-e.row;return fe.find(r=>r.dc===n&&r.dr===o)?.name||null}function cr(e,t,n){let o=Je(e),r=We(t.col,t.row);if(!o.cells.has(r))return[];let i=`${r}|${n.cacheKey||"dynamic"}`;if(n.cacheKey&&o.pathCache.has(i))return o.pathCache.get(i).map(le=>le.map(ue=>({...ue})));let a=`${r}|none`,c=[{key:r,col:t.col,row:t.row,incoming:"none",depth:0}],h=new Map([[a,0]]),g=new Map,C=[],P=1/0,L=8,K=24,j=80;for(;c.length;){let le=c.shift();if(le.depth>P)break;let ue=`${le.key}|${le.incoming}`;if(n(le)){if(C.push(ue),P=le.depth,C.length>=K)break;continue}for(let D of o.adjacency.get(le.key)||[]){let U=rn(D.key),ee=pl(le,U),O=le.depth+1;if(O>P)continue;let G=`${D.key}|${ee}`,Y=h.get(G);if(Y==null)h.set(G,O),g.set(G,[ue]),c.push({key:D.key,col:U.col,row:U.row,incoming:ee,depth:O});else if(Y===O){let ie=g.get(G)||[];ie.length{if(Z.length>=j)return;let[D]=le.split("|"),U=[rn(D),...ue];if(le===a||D===r){Z.push(U);return}for(let ee of g.get(le)||[])Q(ee,U)};for(let le of C)Q(le,[]);let ke=[],pe=new Set;for(let le of Z){let ue=le.map(D=>We(D.col,D.row)).join(">");pe.has(ue)||(pe.add(ue),ke.push(le))}return n.cacheKey&&o.pathCache.set(i,ke.map(le=>le.map(ue=>({...ue})))),ke}function Wi(e){let t=Je(e),n=new Map;for(let[o,r]of t.components.entries())n.set(o,{id:o,cells:[...r.cells],capacity:r.capacity,count:0,ratio:0});return{components:n,cellToComponent:new Map(t.cellToComponent)}}function uo(e,t=null){let n=e.map(o=>$(o.col,o.row));return t&&n.push(t),n}function At(e,t){t&&(!e.length||yi(e[e.length-1],t)>1)&&e.push(t)}function yl(e,t,n,o=null){let r=[{x:e.x,y:e.y}];At(r,$(t.col,t.row));for(let i of uo(n,o))At(r,i);return r}function hl(e,t){let n=uo(e),o=Fe(t,"inputA");return o&&At(n,$(o.col,o.row)),At(n,ge(t)),n}function ml(e,t,n,o){let r=[{x:e.x,y:e.y}];At(r,$(t.col,t.row));for(let a of uo(n))At(r,a);let i=Fe(o,"inputA");return i&&At(r,$(i.col,i.row)),At(r,ge(o)),r}function bl(e,t,n=0){let o=$(t.col,t.row),r=0;for(let i of e.chicks||[]){if(i.stage==="flying"||i.stage==="queued")continue;Math.hypot(i.x-o.x,i.y-o.y){let L=C.roleBias??0,K=P.roleBias??0;if(L!==K)return L-K;let j=C.cells?.length??C.route?.length??Number.POSITIVE_INFINITY,Z=P.cells?.length??P.route?.length??Number.POSITIVE_INFINITY;if(j!==Z)return j-Z;let Q=C.key||JSON.stringify(C.route||C.cells||C),ke=P.key||JSON.stringify(P.route||P.cells||P);return Q.localeCompare(ke)});if(!o||r.length===1)return r[0];let i=r[0].roleBias??0,a=r.filter(C=>(C.roleBias??0)===i),c=a.map(C=>({item:C,score:vl(e,C)})),h=Math.min(...c.map(C=>C.score));a=c.filter(C=>C.score===h).map(C=>C.item);let g=e.branchCounters.get(t)||0;return e.branchCounters.set(t,g+1),a[Math.floor(Math.random()*a.length)]}function Hi(e){return e.role===0?{left:{match:"male",destination:"mixer"},right:{match:"default",destination:"scanner-role-1"}}:{left:{match:"poop",destination:"trash"},right:{match:"default",destination:"truck"}}}function ur(e){let t=Hi(e);return{left:t.left.destination,right:t.right.destination}}function dr(e,t){return Hi(e).left.match===t.sex?"left":"right"}function fr(e){return mi(e)}function pr(e){return{mixer:"#2477ff",truck:"#ff6aa8",trash:"#22b94f",sausageMaker:"#d78b3f","scanner-role-1":"#526456",scanner:"#526456",input:"#526456"}[e]||"#102015"}function Kt(e,t,n=!1){let o=Je(e),r=(o.farmOutputs.get(t.id)||[]).map(rn),i=[];for(let h of r){let g=P=>o.scannerInputs.has(We(P.col,P.row));g.cacheKey=`farmInput:${h.col},${h.row}:v${o.version}`;let C=cr(e,h,g);for(let P of C){let L=P[P.length-1],K=o.scannerInputs.get(We(L.col,L.row)),j=Ht(e,K);j&&i.push({key:`${j.id}:${L.col},${L.row}:${P.length}`,scanner:j,cells:P})}}let a=co(e,`farm:${t.id}`,i,n);if(a)return{scannerId:a.scanner.id,route:hl(a.cells,a.scanner)};let c=co(e,`farm:${t.id}:output`,r.map(h=>({key:I(h.col,h.row),cells:[h]})),n);return c?{scannerId:null,route:uo(c.cells)}:null}function Ki(e,t,n,o,r=!1){let i=Ht(e,o);if(!i)return null;let c=Je(e).scannerPorts.get(i.id)?.[t],h=Fe(i,t),g=c?.connected?(c.keys||[c.key]).filter(Boolean).map(rn):[];if(!h||!g.length)return null;let C=ur(i)[t];return C==="scanner-role-1"?wl(e,i,t,n,h,g,r):Sl(e,i,t,n,h,g,C,r)}function wl(e,t,n,o,r,i,a){let c=Je(e),h=e.scanners.filter(P=>P.id!==t.id&&c.scannerPorts.get(P.id)?.inputA?.connected),g=[];for(let P of i)for(let L of h){let K=c.scannerPorts.get(L.id)?.inputA?.key;if(!K)continue;let j=(c.scannerPorts.get(L.id)?.inputA?.keys||[K]).filter(Boolean),Z=pe=>j.includes(We(pe.col,pe.row));Z.cacheKey=`toScanner:${P.col},${P.row}:${L.id}:v${c.version}`;let Q=cr(e,P,Z),ke=L.role===1?0:1;for(let pe of Q)g.push({key:`${ke}:start${I(P.col,P.row)}:s${L.id}:${pe.length}:${I(pe[pe.length-1].col,pe[pe.length-1].row)}`,target:L,cells:pe,roleBias:ke})}let C=co(e,`scanner:${t.id}:${n}:toRole1`,g,a);return C?{destination:"scanner",nextScannerId:C.target.id,route:ml(o,r,C.cells,C.target)}:null}function Sl(e,t,n,o,r,i,a,c){let h=Je(e),g=[...h.facilityPorts.entries()].filter(([L,K])=>K?.connected&&sn(e.facilities?.[L])===a);if(!g.length)return null;let C=[];for(let L of i)for(let[K,j]of g){let Z=(j.keys||[j.key]).filter(Boolean);if(!Z.length)continue;let Q=pe=>Z.includes(We(pe.col,pe.row));Q.cacheKey=`toFacility:${L.col},${L.row}:${K}:v${h.version}`;let ke=cr(e,L,Q);for(let pe of ke)C.push({key:`start${I(L.col,L.row)}:${K}:${pe.length}:${I(pe[pe.length-1].col,pe[pe.length-1].row)}`,cells:pe,facilityId:K})}let P=co(e,`scanner:${t.id}:${n}:${a}`,C,c);return P?{destination:a,facilityId:P.facilityId,route:yl(o,r,P.cells,il(e,P.facilityId))}:null}function qi(e,t,n=new Set){if(!t||n.has(t.id))return!1;n.add(t.id);for(let o of["left","right"]){let r=Ki(e,o,ge(t),t.id,!1);if(r){if(["mixer","trash","truck","sausageMaker"].includes(r.destination))return!0;if(r.destination==="scanner"){let i=Ht(e,r.nextScannerId);if(qi(e,i,n))return!0}}}return!1}function kl(e,t){return!!Kt(e,t,!1)?.scannerId}function an(e){if(e.phase!=="build")return[];let t=[];for(let n of e.eggFarms||[])kl(e,n)||t.push({type:"eggFarm",id:n.id,ref:n,message:"This Egg will not produce chicks"});for(let n of Jo)for(let[o,r]of lr(e,n))Je(e).facilityPorts.get(o)?.connected||t.push({type:"facility",id:o,ref:r,message:"This facility cannot receive items"});return t}function gl(e){let t=Je(e);for(let r of e.eggFarms||[]){let i=Kt(e,r,!1);if(!i?.scannerId)continue;let a=Ht(e,i.scannerId);if(qi(e,a))return[]}let n=e.eggFarms?.length||0,o=[...t.facilityPorts.entries()].filter(([r,i])=>i?.connected&&["mixer","trash","truck"].includes(sn(e.facilities?.[r]))).length;return n?t.metrics.farmOutputs?e.scanners?.length?o?["No route from an EGG scanner to a receiver."]:["Connect at least one receiver exit: Mixer, Shredder, or Truck."]:["Build at least one scanner and connect it to an EGG route."]:["Connect at least one EGG to a conveyor."]:["Build at least one EGG before starting the next day."]}function ao(e){return e.kind==="manual"?`S${(e.slot??0)+1}`:`Auto Scanner #${e.id}`}function Cl(e,t=Je(e),n={}){let o=n.includeRoutes!==!1,r=[],i={mixer:"Mixer",trash:"Shredder",truck:"Truck",sausageMaker:"Sausage Machine"};for(let a of Jo){let c=lr(e,a);if(!c.length){di.includes(a)&&r.push(`${i[a]||a} is missing`);continue}for(let[h]of c)t.facilityPorts.get(h)?.connected||r.push(`${i[a]||a} receiver has no conveyor`)}for(let a of e.scanners){let c=t.scannerPorts.get(a.id)||{};if(c.inputA?.connected||r.push(`${ao(a)} input has no conveyor`),c.left?.connected||r.push(`${ao(a)} left output has no conveyor`),c.right?.connected||r.push(`${ao(a)} right output has no conveyor`),!!o)for(let h of["left","right"])c[h]?.connected&&!Ki(e,h,ge(a),a.id)&&r.push(`${ao(a)} ${h} route is incomplete`)}if(o)for(let a of e.eggFarms)Kt(e,a)?.scannerId||r.push(`Egg Farm #${a.id} has no scanner route`);else for(let a of e.eggFarms)(t.farmOutputs.get(a.id)||[]).length||r.push(`Egg Farm #${a.id} has no output conveyor`);return[...new Set(r)]}function fo(e){return gl(e)}var Fn=[{key:"premiumFemaleShipment",target:"female",truckTarget:"female",title:"Premium Female Shipment",route:"Female -> Truck",note:"Today only: ship female chicks to Truck. Meet the export target for a bonus.",objective:"truckTarget"},{key:"contaminantSampleExport",target:"poop",truckTarget:"poop",title:"Contaminant Sample Export",route:"Poop value x2",note:"Today only: poop is valid Truck cargo and all poop income is doubled.",objective:"truckTarget",poopValueMultiplier:2},{key:"healthInspection",title:"Health Inspection",route:"Poop -> Shredder",note:"Today only: poop mistakes are fined double. Shred enough poop for an inspection bonus.",objective:"poopTrash",poopFineMultiplier:2},{key:"conveyorJamWarning",title:"Conveyor Jam Warning",route:"No explosions",note:"Today only: jam explosions trigger at 85% congestion. Finish with zero explosions for a bonus.",objective:"noExplosion",congestionExplosionThreshold:.85,congestionWarningThreshold:.68},{key:"powerSavingOrder",title:"Power Saving Order",route:"Slow factory subsidy",note:"Today only: conveyors -20% speed and Auto Scanners +20% cooldown. A subsidy is paid at settlement.",objective:"flatBonus",conveyorSpeedMultiplier:.8,autoScannerCooldownMultiplier:1.2},{key:"overtimeDay",title:"Overtime Day",route:"80 second day",note:"Today only: the work day is longer. No extra reward or penalty.",objective:"none",daySeconds:80},{key:"shortShift",title:"Short Shift",route:"40 second day",note:"Today only: the work day is shorter. The next Fairies tribute is reduced by 10%.",objective:"none",daySeconds:40,fairiesTributeMultiplier:.9},{key:"chickBoom",title:"Chick Boom",route:"EGG interval x0.65",note:"Today only: eggs hatch faster and poop rate rises by 5 percentage points.",objective:"none",productionMultiplier:1/.65,poopRateAdd:.05},{key:"rottenFeed",title:"Rotten Feed",route:"Poop surge",note:"Today only: poop rate rises by 20 percentage points and Shredder poop income is multiplied by 1.5.",objective:"none",poopRateAdd:.2,shredderIncomeMultiplier:1.5},{key:"maintenanceAudit",title:"Maintenance Audit",route:"Durability check",note:"Today only: machines below 50% remaining durability fail the audit. Passing with none below 50% pays a bonus.",objective:"maintenanceAudit"}];function Ee(e,t=0){let n=Number(e);return Number.isFinite(n)?n:t}function Ml(e,t=0,n=1){let o=Math.max(1,Number(e?.turn||1)+1),r=Math.floor(yr(e)*(.08+Math.random()*.08)),i=Math.floor(Math.max(0,e.cash||0)*.25),a=Math.floor(Math.max(0,t)*Math.max(1,o)*.75);return Math.max(120,Math.ceil(Math.max(r,i,a)*n))}function Yi(e){return Math.max(0,Math.ceil(500+Math.max(1,e?.turn||1)*25))}function yr(e){return[...e.eggFarms.map(t=>t.price||0),...e.scanners.map(t=>t.price||0),...Object.values(e.facilities).map(t=>t.price||0),...[...e.conveyorMeta.values()].map(t=>t.price||0)].reduce((t,n)=>t+n,0)}function xl(e,t=1,n=Gt){return e.eggFarms.reduce((o,r)=>{let[i,a]=$n(r),c=Math.max(.1,(i+a)/2);return o+Math.max(1,n)/c*Math.max(.01,t||1)},0)}function Tl(e,t){let n=Ee(t.productionMultiplier,1),o=Ee(t.daySeconds,Gt),r=xl(e,n,o),i=Math.max(0,Number(e?.cardEffects?.hatchingFeed)||0),a=Math.max(0,Number(e?.cardEffects?.poopRateBooster)||0),c=Math.pow(1.03,i),h=zo+Xo*a,g=Math.min(.95,Math.max(0,(h+Ee(t.poopRateAdd,0))*Ee(t.poopMultiplier,1)*c));return{estimate:r,poopRate:g}}function hr(e,t){let n=typeof t=="string"?Fn.find(c=>c.key===t):t;if(!n)return null;let{estimate:o,poopRate:r}=Tl(e,n),i=0;n.objective==="truckTarget"?i=Math.max(1,Math.ceil(o*.3)):n.objective==="poopTrash"&&(i=Math.max(1,Math.ceil(o*r*.8)));let a=0;return["truckTarget","poopTrash","noExplosion"].includes(n.objective)&&(a=Ml(e,o)),n.objective==="flatBonus"&&(a=Yi(e)),n.objective==="maintenanceAudit"&&(a=Yi(e)),{id:`event-${e.turn}-${Date.now()}-${Math.floor(Math.random()*9999)}`,...n,target:n.target||null,truckTarget:n.truckTarget||null,forced:!0,productionMultiplier:Ee(n.productionMultiplier,1),poopMultiplier:Ee(n.poopMultiplier,1),poopRateAdd:Ee(n.poopRateAdd,0),daySeconds:Ee(n.daySeconds,Gt),targetAmount:i,estimatedOutput:Math.round(o),reward:a,createdTurn:e.turn,oneTurnOnly:!0}}function Vi(e){if(e.turn+1ci)return null;let n=Fn[Math.floor(Math.random()*Fn.length)];return hr(e,n)}function zi(e){e.eventActive=e.eventOffer?{...e.eventOffer}:null,e.eventOffer=null}function Xi(e){e.eventActive=null}function ji(e){return Math.max(1,Ee(e.eventActive?.daySeconds,Gt))}function Qi(e){return Ee(e.eventActive?.productionMultiplier,1)}function Ji(e){let t=Math.max(0,Number(e?.cardEffects?.hatchingFeed)||0),n=Math.max(0,Number(e?.cardEffects?.poopRateBooster)||0),o=Math.pow(1.03,t),r=zo+Xo*n,i=Ee(e.eventActive?.poopRateAdd,0);return Math.min(.95,Math.max(0,(r+i)*Ee(e.eventActive?.poopMultiplier,1)*o))}function ln(e){return e.eventActive?.truckTarget||e.eventActive?.target||"female"}function mr(e,t){return t==="male"?e.truckMale||0:t==="poop"?e.poopTruck||0:e.truckFemale||0}function Zi(e,t){return ln(e)===t}function es(e){return ln(e)!=="male"}function br(e){return Math.max(.01,Ee(e.eventActive?.poopValueMultiplier,1))}function po(e){return Math.max(.01,br(e)*Ee(e.eventActive?.shredderIncomeMultiplier,1))}function vr(e){return Math.max(.01,Ee(e.eventActive?.poopFineMultiplier,1))}function wr(e){return Math.max(.1,Math.min(1,Ee(e.eventActive?.congestionExplosionThreshold,1)))}function ts(e){return Math.max(.1,Math.min(1,Ee(e.eventActive?.congestionWarningThreshold,.8)))}function ns(e){return Math.max(.01,Ee(e?.fairiesTributeMultiplier,1))}function El(e){let t=0,n=(o,r)=>{let i=Math.max(1,Ee(r,1)),a=Math.max(0,Ee(o,0));1-Math.min(1,a/i)<.5&&(t+=1)};for(let o of e.conveyorMeta?.values?.()||[])n(o.uses,o.durability);for(let o of e.eggFarms||[])n(o.maintenance?.uses,o.maintenance?.durability);for(let o of e.scanners||[])o.kind==="auto"&&n(o.maintenance?.uses,o.maintenance?.durability);for(let o of Object.values(e.facilities||{})){let r=o?.baseId||o?.id;(r==="mixer"||r==="trash"||r==="sausageMaker")&&n(o.maintenance?.uses,o.maintenance?.durability)}return t}function os(e){let t=e.eventActive;if(!t)return null;let n=0,o=!0,r=0,i="";t.objective==="truckTarget"?(n=mr(e.stats,t.target),o=n>=t.targetAmount,r=o?t.reward:0):t.objective==="poopTrash"?(n=e.stats.poopTrash||0,o=n>=t.targetAmount,r=o?t.reward:0):t.objective==="noExplosion"?(n=e.stats.explosions||0,o=n===0,r=o?t.reward:0,i=`${n} explosion(s)`):t.objective==="flatBonus"?(o=!0,r=t.reward):t.objective==="maintenanceAudit"?(n=El(e),o=n===0,o&&(r=t.reward),i=`${n} machine(s) below 50%`):o=!0,r>0?(je(e,r),e.stats.eventBonus=(e.stats.eventBonus||0)+r,e.totals.eventBonus+=r,e.totals.eventSuccess+=1):t.objective&&t.objective!=="none"&&(e.stats.eventBonus=e.stats.eventBonus||0,e.totals.eventFailed+=o?0:1,o&&(e.totals.eventSuccess+=1));let a={title:t.title,key:t.key,target:t.target,route:t.route,objective:t.objective,targetAmount:t.targetAmount||0,count:n,success:o,bonus:r,reward:t.reward||0,productionMultiplier:t.productionMultiplier,poopMultiplier:t.poopMultiplier,daySeconds:t.daySeconds,detail:i};return e.stats.eventResult=a,a}function Sr(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function Rl(e){return!!e?.cardEffects?.usedMachineActive}function Pl(e,t){return t?1:Math.min(.8,.5+.1*Math.min(3,Sr(e,"recyclingSubsidy")))}function Al(e){return Math.pow(.95,Sr(e,"safetyCover"))}function yo(e){let t=e?.ref||e||{},n=e?.type||t.type;return n==="conveyor"?t.price||Te[t.kind]?.price||Te.conveyor.price:n==="eggFarm"?t.price||Te.eggFarm.price:n==="scanner"?t.price||(t.kind==="auto"?Te.autoScanner.price:Te.manualScanner.price):n==="facility"?t.price||Te[t.id]?.price||0:n==="maintenanceRoom"?t.price||Te.maintenanceRoom.price:Te[t.id]?.price||0}function He(e,t=null){let n=Te[e]?.price||0;return Rl(t)?Math.ceil(n*.5):n}function Il(e,t){return e?.facilities?Object.values(e.facilities).filter(n=>(n?.baseId||n?.id)===t).reduce((n,o)=>n+Math.max(0,(o.level||1)-1),0):0}function yt(e,t){return fi.includes(t)?Math.pow(xe.incomeUpgradeRate,Il(e,t)):1}function Ve(e){return Math.ceil(xe.income.truck*yt(e,"truck"))}function Ze(e){return Math.ceil((xe.income.sausage||26)*yt(e,"mixer")*yt(e,"sausageMaker"))}function Dn(e){return Math.ceil(xe.poopFine*yt(e,"mixer")*vr(e))}function Bn(e){return Math.ceil(xe.poopFine*yt(e,"truck")*vr(e))}function kr(e){let t=xe.maleTruckFinePerHalfDay*(e.turn/2);return Math.ceil(t*yt(e,"truck"))}function gr(e){return e?.facilities?Object.values(e.facilities).filter(t=>(t?.baseId||t?.id)==="trash").reduce((t,n)=>t+Math.max(0,(n.level||1)-1),0):0}function mt(e){return Math.min(xe.shredderBonus.maxCards,gr(e))}function cn(){return xe.shredderBonus.maxCards}function ho(){return xe.shredderBonus||{}}function rs(e){let t=typeof e=="number"?e:mt(e),n=ho(),o=Math.min(n.maxCards||30,Math.max(0,t));return o>0?Math.ceil((n.payoutCoefficient||1.6)*Math.pow(o,n.payoutExponent||1.25)):0}function qt(e){let t=typeof e=="number"?e:mt(e);if(t<=0)return 0;let n=ho();return Math.min(n.maxHitChance||.82,(n.baseHitChance||.28)+t*(n.hitChancePerUpgrade||.018))}function $l(e){let t=ho(),n=Math.min(t.jackpotMaxChance||.08,(t.jackpotBaseChance||.01)+e*(t.jackpotChancePerUpgrade||.0025)),o=Math.min(t.bigWinMaxChance||.12,(t.bigWinBaseChance||.07)+e*(t.bigWinChancePerUpgrade||.0015)),r=Math.min(1-n-o,t.doubleChance||.2),i=Math.max(0,1-n-o-r);return n*(t.jackpotMultiplier||10)+o*(t.bigWinMultiplier||4)+r*(t.doubleMultiplier||2)+i}function ht(e){let t=typeof e=="number"?e:mt(e);return Math.round(rs(t)*qt(t)*$l(t))}function Fl(e){let t=mt(e),n=qt(t),o=rs(t);if(t<=0||Math.random()>=n)return{cards:t,chance:n,amount:0,expected:ht(t),baseAmount:o,multiplier:0,tier:"miss"};let r=ho(),i=Math.min(r.jackpotMaxChance||.08,(r.jackpotBaseChance||.01)+t*(r.jackpotChancePerUpgrade||.0025)),a=Math.min(r.bigWinMaxChance||.12,(r.bigWinBaseChance||.07)+t*(r.bigWinChancePerUpgrade||.0015)),c=Math.min(1-i-a,r.doubleChance||.2),h=Math.random(),g=1,C="normal";h0&&(e.stats.shredderBonus=(e.stats.shredderBonus||0)+t.amount,e.totals.shredderBonus=(e.totals.shredderBonus||0)+t.amount,je(e,t.amount)),t}function Cr(e,t=e.turn,n=null){let o=Math.max(1,Math.floor(Number(t)||1)),r=xe.fairiesTribute||{perDay:10,profitExemption:300,legalWorkExemptionBonus:250,profitRate:.12},i=Math.ceil(o*(r.perDay||10)),a=Math.max(0,Math.floor(Number(n??e?.lastResult?.profit??e?.stats?.profit??0)||0)),c=Math.max(0,e?.cardEffects?.legalWork||0),h=Math.max(0,(r.profitExemption||0)+c*(r.legalWorkExemptionBonus||0)),g=Math.max(0,a-h),C=Math.ceil(g*Math.max(0,Number(r.profitRate)||0)),P=i+C,L=Math.max(0,e?.cardEffects?.fairiesFlatteryNext||e?.cardEffects?.flattery||0),K=L>0?Math.pow(.5,L):1,j=Math.max(.01,Number(e?.pendingFairiesTributeMultiplier)||1),Z=K*j,Q=Math.max(0,Math.ceil(P*Z)),ke=Math.max(0,P-Q);return{day:o,base:i,profit:a,legalWork:c,profitExemption:h,taxableProfit:g,profitTribute:C,gross:P,flatteryCount:L,eventMultiplier:j,perCardReduction:Math.ceil(P*.5),reduction:ke,amount:Q}}function $t(e,t){let n=e?.ref||e||{},o=e?.type==="conveyor"?t?.conveyorMeta?.get(e.oldKey||n.id):n,r=o?.price||yo(e||n),i=o?.builtSession===t?.buildSession;if(o?.noRefund||n?.noRefund)return{amount:0,sameBuild:i,price:r,rate:0,noRefund:!0};let a=Pl(t,i);return{amount:Math.max(0,Math.ceil(r*a)),sameBuild:i,price:r,rate:a,noRefund:!1}}function Dl(e,t=null){let n=Math.max(1,Math.ceil((Number(e)||0)/xe.explosionDamageDivisor));return Math.max(1,Math.ceil(n*Al(t)))}function Bl(e,t){return Math.max(0,Math.ceil(t))}function ss(e,t){e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,t>=0?(e.stats.revenue+=t,e.totals.revenue+=t):(e.stats.penalty+=Math.abs(t),e.totals.penalty+=Math.abs(t)),e.totals.maxCash=Math.max(e.totals.maxCash,e.cash)}function je(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&ss(e,n),n}function Ft(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&ss(e,-n),n}function Dt(e,t){Ft(e,t)}function as(e,t){t<=0||(e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,e.totals.maxCash=Math.max(e.totals.maxCash,e.cash))}function ls(e){let t=xe.income.mixer;return e.stats.mixerRevenue+=t,je(e,t),t}function cs(e){let t=Dn(e);return e.stats.mixerPoopFine+=t,e.totals.mixerPoopFine+=t,Ft(e,t),t}function us(e){let t=Bn(e);return e.stats.truckPoopFine+=t,e.totals.truckPoopFine+=t,Ft(e,t),t}function ds(e){let t=kr(e);return e.stats.maleTruckFine+=t,e.totals.maleTruckFine+=t,Ft(e,t),t}function fs(e,t){let n=Dl(t,e);return e.stats.explosionDamage+=n,e.totals.explosionDamage+=n,Ft(e,n),n}function ps(e){let t=ln(e),n=mr(e.stats,t),o=t==="poop"?Math.ceil(Ve(e)*br(e)):Ve(e),r=n*o,i=Math.max(0,e?.stats?.sausageShipped||0),a=Ze(e),c=i*a,h=Bl(e,r+c);return e.stats.pendingTruckRevenue=h,e.stats.truckRevenue=h,e.stats.sausageRevenue=c,t==="poop"?e.stats.poopShipmentIncome=r:e.stats.chickShipmentIncome=r,h>0&&je(e,h),{base:r,adjusted:h,target:t,targetCount:n,unitPrice:o,sausageCount:i,sausageUnitPrice:a,sausageRevenue:c}}function ys(e,t=e.turn,n=null,o={}){let r=Cr(e,t,n);return e.cardEffects&&(e.cardEffects.fairiesFlatteryNext=0,e.cardEffects.flattery!=null&&delete e.cardEffects.flattery),e.pendingFairiesTributeMultiplier!=null&&(e.pendingFairiesTributeMultiplier=1),r.amount<=0||(o.recordStats?(e.stats.fairiesTribute=(e.stats.fairiesTribute||0)+r.amount,e.totals.fairiesTribute=(e.totals.fairiesTribute||0)+r.amount,Ft(e,r.amount)):(e.totals.fairiesTribute=(e.totals.fairiesTribute||0)+r.amount,e.totals.penalty=(e.totals.penalty||0)+r.amount,e.totals.profit=(e.totals.profit||0)-r.amount,e.cash-=r.amount)),r}function hs(e){let t=Sr(e,"chemicalWeaponSubsidy"),n=Math.max(0,e?.stats?.poopTruck||0),o=xe.chemicalWeaponSubsidy||{poopPerBlock:70,yenPerBlock:1200},r=Math.floor(n/Math.max(1,o.poopPerBlock||70)),i=t>0&&r>0?r*Math.max(0,o.yenPerBlock||1200)*t:0;return i>0&&(e.stats.chemicalWeaponSubsidy=(e.stats.chemicalWeaponSubsidy||0)+i,e.totals.chemicalWeaponSubsidy=(e.totals.chemicalWeaponSubsidy||0)+i,je(e,i)),{cards:t,poopTruck:n,blocks:r,amount:i}}function ms(e){let t=yr(e),n=Math.max(1,e.totals.turnsCompleted||e.turn||1),o=Math.max(0,e.cash+e.totals.revenue+t*.5+e.totals.eventBonus*.5),r=Math.ceil(o/n),i=Math.floor(n*35+Math.max(0,n-5)*15),a=e.totals.correct*5,c=e.totals.explosionDamage;return{score:Math.max(0,Math.floor(o+r+a-e.totals.penalty-i)),factoryValue:t,base:o,dailyEarned:r,dayPenalty:i,correctBonus:a,explosionPenalty:c,days:n}}function Ol(e){return{...e,keys:e.keys?{left:{...e.keys.left},right:{...e.keys.right}}:null,queue:[],cooldown:e.cooldown||0}}function On(e){return JSON.stringify({cash:e.cash,stats:e.stats,totals:e.totals,nextId:e.nextId,gridX:f.x,gridY:f.y,gridCols:e.gridCols||f.cols,gridRows:e.gridRows||f.rows,gridExpansionPurchases:e.gridExpansionPurchases||0,gridExpansionPurchasesByDirection:e.gridExpansionPurchasesByDirection||{left:0,right:0,up:0,down:0},gridChunkOriginX:e.gridChunkOriginX||0,gridChunkOriginY:e.gridChunkOriginY||0,ownedCells:[...e.ownedCells||[]],ownedChunks:[...e.ownedChunks||[]],blockedCells:[...e.blockedCells||[]],selected:e.selected,multiSelected:e.multiSelected||[],buildTool:e.buildTool,view:e.view,facilities:e.facilities,eggFarms:e.eggFarms,scanners:e.scanners.map(Ol),conveyorTiles:[...e.conveyorTiles],conveyorMeta:[...e.conveyorMeta.entries()],branchCounters:[...e.branchCounters.entries()],cardEffects:e.cardEffects,cardDraft:e.cardDraft,cardTargetPick:e.cardTargetPick})}function bs(e,t){let n=JSON.parse(t);e.cash=n.cash,e.stats=n.stats,e.totals=n.totals,e.nextId=n.nextId,f.x=n.gridX??V.grid.x,f.y=n.gridY??V.grid.y,f.cols=n.gridCols||V.grid.cols,f.rows=n.gridRows||V.grid.rows,e.gridCols=f.cols,e.gridRows=f.rows,e.gridExpansionPurchases=n.gridExpansionPurchases||0,e.gridExpansionPurchasesByDirection=n.gridExpansionPurchasesByDirection||{left:0,right:0,up:0,down:0},e.gridExpansionPurchasesByDirection.left==null&&(e.gridExpansionPurchasesByDirection.left=0),e.gridExpansionPurchasesByDirection.down==null&&(e.gridExpansionPurchasesByDirection.down=0),e.gridChunkOriginX=n.gridChunkOriginX||0,e.gridChunkOriginY=n.gridChunkOriginY||0,e.ownedCells=new Set(n.ownedCells||[]),e.ownedChunks=new Set(n.ownedChunks||[]),e.gridOwnedCells=e.ownedCells.size||f.cols*f.rows,e.blockedCells=new Set(n.blockedCells||[]),e.selected=n.selected,e.multiSelected=n.multiSelected||[],e.buildTool=n.buildTool,e.view=n.view||{x:0,y:0,scale:1},e.view.scale==null&&(e.view.scale=1),e.facilities=n.facilities||{},e.eggFarms=n.eggFarms||[],e.scanners=(n.scanners||[]).map(o=>({...o,queue:[],cooldown:o.cooldown||0})),e.conveyorTiles=new Set(n.conveyorTiles||[]),e.conveyorMeta=new Map(n.conveyorMeta||[]),e.branchCounters=new Map(n.branchCounters||[]),e.cardEffects=n.cardEffects||{bearing:0,legalWork:0,fairiesFlatteryNext:0,scannerQueueSpacing:0},e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft=n.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardTargetPick=n.cardTargetPick||null,e.groupDrag=null,e.selectionBox=null,e.pan=null,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function _e(e){e.phase==="build"&&(e.undoStack.push(On(e)),e.undoStack.length>80&&e.undoStack.shift(),e.redoStack=[])}function Mr(e){return e.phase!=="build"||!e.undoStack.length?!1:(e.redoStack.push(On(e)),bs(e,e.undoStack.pop()),!0)}function xr(e){return e.phase!=="build"||!e.redoStack.length?!1:(e.undoStack.push(On(e)),bs(e,e.redoStack.pop()),!0)}function H(e,t,n,o,r=b.ink){e.floatingTexts.push({x:t,y:n,text:o,color:r,life:1,maxLife:1})}function Yt(e,t,n){e.shake.strength=Math.max(e.shake.strength,t),e.shake.time=Math.max(e.shake.time,n)}function vs(e,t,n){e.effects.push({type:"spawn",priority:Ie.ambient,x:t,y:n,life:.42,maxLife:.42,size:12})}function ws(e,t,n,o=b.green){e.effects.push({type:"scannerPulse",priority:Ie.important,x:t,y:n,color:o,life:.42,maxLife:.42,size:24})}function Ss(e,t,n){for(let o=0;o<12;o+=1)e.effects.push({type:"meat",priority:Ie.important,x:t+z(-18,18),y:n+z(-12,16),vx:z(-60,60),vy:z(-90,-25),life:z(.45,.85),maxLife:.85,size:z(4,8)})}function ks(e,t,n){for(let o=0;o<16;o+=1)e.effects.push({type:"sludge",priority:Ie.important,x:t+z(-18,18),y:n+z(-12,16),vx:z(-46,46),vy:z(-70,-20),life:z(.45,.9),maxLife:.9,size:z(4,8)})}function gs(e,t,n,o){let r=o==="poop"?b.poop:o==="male"?b.male:b.female;for(let i=0;i<22;i+=1)e.effects.push({type:"shred",priority:Ie.important,x:t+z(-16,16),y:n+z(-8,8),vx:z(-70,70),vy:z(40,160),color:i%3===0?b.white:r,life:z(.45,.95),maxLife:.95,w:z(3,7),h:z(10,24),rot:z(-Math.PI,Math.PI)});at(e,t,n,b.green,34,Ie.important)}function Cs(e,t,n,o){let r=o==="poop"?b.poop:o==="male"?b.danger:b.green;for(let i=0;i<8;i+=1)e.effects.push({type:"load",priority:Ie.important,x:t+z(-18,18),y:n+z(-18,18),vx:z(-42,42),vy:z(-90,-25),color:r,life:z(.35,.65),maxLife:.65,size:8})}function at(e,t,n,o=b.danger,r=52,i=Ie.critical){e.effects.push({type:"shockwave",priority:i,x:t,y:n,color:o,life:.55,maxLife:.55,size:8,maxSize:r})}function bt(e,t,n,o=12,r=b.danger,i=Ie.critical){for(let a=0;a0&&(e.shake.time=Math.max(0,e.shake.time-t),e.shake.time<=0&&(e.shake.strength=0));for(let r of e.effects)if(r.life-=t,["meat","sludge","spark","smoke","shred","load","rage"].includes(r.type))r.x+=(r.vx||0)*t,r.y+=(r.vy||0)*t,r.vy=(r.vy||0)+150*t;else if(r.type==="flyingChick"){r.x+=r.vx*t,r.y+=r.vy*t,r.vy+=360*t,r.noDamage||Ll(e,r,o);let i=r.x+e.view.x,a=r.y+e.view.y;(i<-100||a<-100||i>n.width+100||a>n.height+100)&&(r.life=0)}e.effects=e.effects.filter(r=>r.life>0);for(let r of e.floatingTexts)r.life-=t,r.y-=34*t;e.floatingTexts=e.floatingTexts.filter(r=>r.life>0)}function Ll(e,t,n){t.hit||(t.hit=new Set);for(let o of n()){if(t.hit.has(o.id)||t.xo.x+o.w||t.yo.y+o.h)continue;t.hit.add(o.id);let r=fs(e,o.price);H(e,t.x,t.y-10,`-${x(r)}`,b.danger),at(e,t.x,t.y,b.danger,30),bt(e,t.x,t.y,5,b.danger),Yt(e,5,.18)}}var Qe=V.maintenance;function Er(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function vo(e){let t=Math.min(1.4,1+.04*Math.min(10,Er(e,"crowdedFarming"))),n=Math.pow(.95,Er(e,"preventiveMaintenance"));return t*n}function Nl(e){return Math.pow(1.03,Er(e,"durabilityCoating"))}function wo(e,t,n=1){let o=Qe.durability[t]||1e3;return Math.max(1,Math.ceil(o*Math.max(.1,n||1)*Nl(e)))}function Ts(e){return Math.max(.1,Number(e?.durabilityBaseMultiplier)||1)}function _l(e,t=0){if(!e)return{x:f.x+f.cell*(.5+t*.55),y:f.y+f.rows*f.cell+84};let n=f.x+e.col*f.cell+f.cell,o=f.y+e.row*f.cell+f.cell;return{x:n,y:o}}function Gl(e,t=0){let n=(e.maintenanceRooms||[])[t];return _l(n,t)}function Re(e){e.repairman||(e.repairman={active:!1,x:f.x+f.cell*.5,y:f.y+f.rows*f.cell+84,target:null,repairedToday:0}),Array.isArray(e.maintenanceRooms)||(e.maintenanceRooms=[]),Array.isArray(e.repairmen)||(e.repairmen=[]);for(let[t,n]of e.conveyorMeta||[]){n.uses==null&&(n.uses=0),n.maintenanceType==null&&(n.maintenanceType="conveyor"),n.kind||(n.kind="conveyor"),n.speedMultiplier||(n.speedMultiplier=n.kind==="boostConveyor"?2:1),n.branchMode||(n.branchMode="random");let o=wo(e,"conveyor",Ts(n));(n.durability==null||n.durability0&&(n.processingCooldown=Math.max(0,n.processingCooldown-t))}function Gn(e){Re(e);let t=[];for(let[n,o]of e.conveyorMeta||[])t.push({type:"conveyor",key:n,meta:o,label:`${o.kind==="boostConveyor"?"Boost Belt":"Belt"} ${n}`,center:$(re(n).col,re(n).row)});for(let n of e.eggFarms||[])t.push({type:"eggFarm",ref:n,label:`EGG #${n.id}`,center:$(n.col,n.row)});for(let n of(e.scanners||[]).filter(o=>o.kind==="auto"))t.push({type:"autoScanner",ref:n,label:`AUTO #${n.id}`,center:$(n.col,n.row)});for(let n of Object.values(e.facilities||{})){let o=Co(n);["mixer","trash","sausageMaker"].includes(o)&&t.push({type:o,ref:n,label:`${n.shortName||n.name||o} #${n.id}`,center:{x:n.x+n.w/2,y:n.y+n.h/2}})}return t}function Vt(e){return e.meta?un(e):un(e.ref)}function Ln(e){return e.meta?Rr(e):Rr(e.ref)}function bo(e){return e.meta?Pr(e):Pr(e.ref)}function Is(e,t){Ul(e.meta?e:e.ref,Math.max(0,Ln(e)-t))}function Dr(e){return e.type==="conveyor"?`conveyor:${e.key}`:`${e.type}:${e.ref?.id||e.ref?.type||e.type}`}function $s(e,t=.02){Re(e);let n=Math.max(0,Number(t)||0),o=0;for(let r of Gn(e)){let i=Ln(r);Is(r,bo(r)*n),o+=Math.max(0,i-Ln(r))/bo(r)*100}return o}function Fs(e){Re(e);let t=e.maintenanceRooms||[];e.repairmen=t.map((o,r)=>{let i=Gl(e,r);return{id:`room-${o.id}`,roomId:o.id,active:!0,x:i.x,y:i.y,target:null,repairedToday:0}});let n=e.repairmen[0];e.repairman.active=!!n,e.repairman.target=n?.target||null,e.repairman.repairedToday=0,n&&(e.repairman.x=n.x,e.repairman.y=n.y)}function Ds(e){Re(e);for(let t of e.repairmen||[])t.active=!1,t.target=null;e.repairmen=[],e.repairman.active=!1,e.repairman.target=null}function Hl(e,t){return t&&Gn(e).find(o=>Dr(o)===t.key)||null}function Kl(e){let t=null;for(let n of Gn(e)){let o=Vt(n);o<=.001||(!t||o>Vt(t))&&(t=n)}return t}function Bs(e,t){Re(e);let n=e.repairmen?.length?e.repairmen:e.repairman?.active?[e.repairman]:[];if(!n.length||e.phase!=="running")return;let o=new Set(n.map(i=>i.target?.key).filter(Boolean));for(let i of n)ql(e,i,t,o);let r=n[0];r&&e.repairman!==r&&(e.repairman.active=!0,e.repairman.x=r.x,e.repairman.y=r.y,e.repairman.target=r.target,e.repairman.repairedToday=r.repairedToday||0)}function ql(e,t,n,o){if(!t.active)return;let r=Hl(e,t.target);if((!r||Vt(r)<=.001)&&(t.target?.key&&o.delete(t.target.key),r=Yl(e,o)),!r){t.target=null;return}let i=Dr(r);o.add(i),t.target={key:i,label:r.label};let a=Qe.repairman.walkSpeed,c=r.center.x-t.x,h=r.center.y-t.y,g=Math.hypot(c,h);if(g>8){let Z=Math.min(g,a*n);t.x+=c/g*Z,t.y+=h/g*Z;return}let C=e?.cardEffects?.laborExploitation?.7:1,P=n/(Qe.repairman.secondsPerOnePercent*C*100),L=Ln(r),K=P*bo(r);Is(r,K);let j=Math.max(0,(L-Ln(r))/bo(r)*100);t.repairedToday=(t.repairedToday||0)+j,j>0&&Math.random()<.02&&H(e,t.x,t.y-28,"REPAIR",b.green),Vt(r)<=.001&&(o.delete(i),t.target=null)}function Yl(e,t=new Set){let n=null;for(let o of Gn(e)){if(t.has(Dr(o)))continue;let r=Vt(o);r<=.001||(!n||r>Vt(n))&&(n=o)}return n||Kl(e)}function Vl(e){let t=0,n="none";for(let o of Gn(e)){let r=Vt(o);r>t&&(t=r,n=o.label)}return{ratio:t,percent:Math.round(t*100),label:n}}function Br(e){let t=Vl(e),n=Ar(e);return{worst:t,avgBeltPerformance:n,repairman:e.repairman||null,repairmen:e.repairmen||[],rooms:e.maintenanceRooms||[]}}var zl=Ue.commonWeight,Xl=Ue.rareWeight,jl=Ue.ultraRareWeight||.45,zt=Ue.baseDraftSize,fn=ui;function dn(e,t){let n=Ke(e);return Math.max(0,Number(n[t])||0)}function Ke(e){e.cardEffects||(e.cardEffects={...jo});for(let[t,n]of Object.entries(jo))e.cardEffects[t]==null&&(e.cardEffects[t]=Array.isArray(n)?[]:n);return e.cardEffects.flattery!=null&&(e.cardEffects.fairiesFlatteryNext=Math.max(0,e.cardEffects.fairiesFlatteryNext||0)+Math.max(0,e.cardEffects.flattery||0),delete e.cardEffects.flattery),e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft||(e.cardDraft={pending:!1,choices:[],rerolls:0,picksRemaining:0}),e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardEffects}function Hs(e){let t=Math.max(.5,1-.05*Math.min(10,dn(e,"crowdedFarming"))),n=Math.pow(.96,dn(e,"hatchingFeed"));return t*n}function Ks(e,t=null){return Math.min(3,Math.max(0,Number(t?.extraEggOutlet)||0))}function qs(e){return Math.pow(.85,dn(e,"scannerQueueSpacing"))}function pn(e,t=null){let n=Ke(e),o=Jn*Math.pow(Zn,Math.max(0,n.bearing||0)),r=t?Math.max(.1,Number(e?.conveyorMeta?.get?.(t)?.speedMultiplier)||1):1,i=t?1:Ar(e),a=Math.max(.01,Number(e?.eventActive?.conveyorSpeedMultiplier)||1);return Math.min(tn,o*i)*r*a}function St(e,t=null){let n=Math.max(0,(e?.level||1)-1),o=t?dn(t,"autoScannerTuning"):0,r=Qn*Math.pow(li,n)*Math.pow(Yo,o),i=Math.max(Vo,r),a=t?Math.max(.01,Number(t?.eventActive?.autoScannerCooldownMultiplier)||1):1;return t?Math.max(Vo,i*ko(e)*a):i}function Os(e){let t=e.cardDraft||{rerolls:0},n=Math.max(1,(t.rerolls||0)+1);return Math.ceil(Math.max(1,e.turn||1)/Ue.rerollCost.dayDivisor*n*Ue.rerollCost.multiplier)}function Xt(e){return fn.find(t=>t.id===e)||null}function Ys(e,t){let n=typeof t=="string"?Xt(t):t;return Ke(e),!n||!(n.type==="equipmentUpgrade"||n.type==="cellAction")?[]:et(e,n).map(o=>({key:wt(o),label:_r(e,o),type:o.type}))}function Nr(e,t,n={}){let o=typeof t=="string"?Xt(t):t;if(Ke(e),!o||o.type==="dud")return{ok:!1,reason:"Card not found."};if(o.id==="extraCards")return e.cardDraft=e.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.choices.push(...To(e,2)),{ok:!0,reason:`${o.title} added 2 draft cards.`};if(o.type==="instant")return zs(e,o),{ok:!0,reason:`${o.title} granted.`};if(o.type==="equipmentUpgrade"){let r=et(e,o);if(!r.length)return{ok:!1,reason:`No valid target for ${o.title}.`};let i=n.targetKey&&n.targetKey!=="__auto__"?String(n.targetKey):"",a=i?r.find(c=>wt(c)===i):r[0];return a?(Vs(e,a),{ok:!0,reason:`${o.title} applied to ${_r(e,a)}.`}):{ok:!1,reason:`Selected target is no longer valid for ${o.title}.`}}if(o.type==="cellAction"&&o.target==="blockedCell"){let r=et(e,o);if(!r.length)return{ok:!1,reason:"No blocked cells to remove."};let i=new Set((Array.isArray(n.targetKeys)?n.targetKeys:[n.targetKey]).filter(c=>c&&c!=="__auto__").map(String)),a=i.size?r.filter(c=>i.has(wt(c))):r.slice(0,10);if(!a.length)return{ok:!1,reason:`Selected target is no longer valid for ${o.title}.`};for(let c of a.slice(0,3)){e.blockedCells.delete(I(c.col,c.row));let h=$(c.col,c.row);vt(e,h.x,h.y),at(e,h.x,h.y,b.danger,42),bt(e,h.x,h.y,8,b.warn)}return Me(e),{ok:!0,reason:`${o.title} removed ${Math.min(10,a.length)} blocked cell(s).`}}return{ok:!1,reason:`${o.title} cannot be debug-granted.`}}function _r(e,t){if(t.type==="blockedCell")return`Blocked cell ${t.col},${t.row}`;if(t.type==="eggFarm")return`EGG #${t.id} L${t.level} -> L${t.level+1}`;if(t.type==="eggOutlet"){let n=Math.max(0,Number(t.farm?.extraEggOutlet)||0);return`EGG #${t.id} OUTLET ${1+n} -> ${2+n}`}if(t.type==="scanner")return`AUTO #${t.id} L${t.level} -> L${t.level+1} | CD ${St(t,e).toFixed(1)}s -> ${St({...t,level:t.level+1},e).toFixed(1)}s`;if(t.type==="facility"&&["mixer","sausageMaker"].includes(t.baseId||t.id)){let n=t.baseId||t.id,o=t.level||1,r=Ze(e);t.level=o+1;let i=Ze(e);return t.level=o,`${n==="mixer"?"MIXER":"SAUSAGE MACHINE"} L${t.level} -> L${t.level+1} | sausage ${x(r)} -> ${x(i)}`}if(t.type==="facility"&&(t.baseId||t.id)==="truck"){let n=t.level,o=Ve(e);t.level=n+1;let r=Ve(e);return t.level=n,`TRUCK L${t.level} -> L${t.level+1} | ${x(o)} -> ${x(r)}`}if(t.type==="facility"&&(t.baseId||t.id)==="trash"){let n=mt(e),o=Math.min(cn(),n+1),r=ht(n),i=ht(o);return`SHREDDER L${t.level||1} -> L${(t.level||1)+1} | expected ${x(r)} -> ${x(i)} per poop`}return`${t.name||t.id} L${t.level||1} -> L${(t.level||1)+1}`}function Ql(e){return[...e.blockedCells||[]].map(t=>{let[n,o]=String(t).split(",").map(Number);return{type:"blockedCell",id:t,col:n,row:o}}).filter(t=>Number.isFinite(t.col)&&Number.isFinite(t.row))}function et(e,t){let n=typeof t=="string"?Xt(t):t;return Ke(e),n?n.target==="blockedCell"?Ql(e):n.target==="eggFarm"?e.eggFarms.filter(o=>(o.level||1)<4):n.target==="eggOutlet"?e.eggFarms.filter(o=>Math.max(0,Number(o.extraEggOutlet)||0)<3).map(o=>({type:"eggOutlet",id:o.id,col:o.col,row:o.row,farm:o})):n.target==="autoScanner"?e.scanners.filter(o=>o.kind==="auto"):n.target==="mixer"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="mixer"):n.target==="truck"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="truck"):n.target==="sausageMaker"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="sausageMaker"):n.target==="trash"?gr(e)(o.baseId||o.id)==="trash"):[]:[]:[]}function Jl(e,t){let n=Ke(e);if(t.id==="crowdedFarming")return(n.crowdedFarming||0)>=10;if(t.id==="recyclingSubsidy")return(n.recyclingSubsidy||0)>=3;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,Ue.dudChancePerCard||0)),r=Math.max(1e-4,Math.min(1,Ue.dudChanceReductionPerFilter||.05));return(n.dudFilter||0)>=Math.ceil(o/r)}return t.id==="laborExploitation"?!!n.laborExploitation:t.id==="usedMachine"?!!n.usedMachineActive:t.id==="newMachine"?!n.usedMachineActive:!1}function Zl(e){return!!((e.maintenanceRooms||[]).length||(e.repairmen||[]).length||e.repairman?.active)}function Ls(e,t){return t==="conveyor"?(e.conveyorTiles?.size||0)>0:t==="autoScanner"?(e.scanners||[]).some(n=>n.kind==="auto"):t==="manualScanner"?(e.scanners||[]).some(n=>n.kind==="manual"):t==="eggFarm"?(e.eggFarms||[]).length>0:Object.values(e.facilities||{}).some(n=>(n.baseId||n.id)===t)}function ec(e,t){return!(t.requiresFacility&&!Ls(e,t.requiresFacility)||Array.isArray(t.requiresAnyFacility)&&!t.requiresAnyFacility.some(n=>Ls(e,n)))}function tc(e){return fn.filter(t=>!(t.id==="laborExploitation"&&!Zl(e)||!ec(e,t)||Jl(e,t)||(t.type==="equipmentUpgrade"||t.type==="cellAction")&&et(e,t).length<=0))}function Ns(e,t){return t.rarity==="ultraRare"?jl:t.rarity==="rare"?Xl:zl}function nc(e,t){let n=t.reduce((r,i)=>r+Ns(e,i),0);if(n<=0)return t[Math.floor(Math.random()*t.length)];let o=Math.random()*n;for(let r of t)if(o-=Ns(e,r),o<=0)return r;return t[t.length-1]}var _s=0;function oc(){return _s+=1,{id:`dud:${Date.now()}:${_s}`,title:"Dud",rarity:"dud",type:"dud",description:"Click to flick this dud away. It does not consume a pick."}}function rc(e){let t=Ke(e),n=Math.max(0,Math.min(1,Ue.dudChancePerCard||0)),o=Math.max(0,Math.min(1,Ue.dudChanceReductionPerFilter||0));return Math.max(0,n-o*Math.max(0,t.dudFilter||0))}function ic(e,t){let n=[...t],o=0,r=Math.max(0,Ue.maxDudsPerDraft||0),i=rc(e);for(let a=0;ac.id===i.id);a>=0&&r.splice(a,1)}return ic(e,o)}function wt(e){return e?e.type==="blockedCell"?`blockedCell:${e.id}`:e.type==="eggFarm"?`eggFarm:${e.id}`:e.type==="eggOutlet"?`eggOutlet:${e.id}`:e.type==="scanner"?`scanner:${e.id}`:e.type==="facility"?`facility:${e.id}`:`${e.type}:${e.id}`:""}function Gs(e){if(!e)return null;if(e.type==="blockedCell"){let t=$(e.col,e.row);return{x:t.x-f.cell*.48,y:t.y-f.cell*.48,w:f.cell*.96,h:f.cell*.96,cx:t.x,cy:t.y}}if(e.type==="eggFarm"||e.type==="eggOutlet"){let t=$(e.col,e.row);return{x:t.x-34,y:t.y-34,w:68,h:68,cx:t.x,cy:t.y}}if(e.type==="scanner"){let t=ge(e);return{x:t.x-48,y:t.y-48,w:96,h:96,cx:t.x,cy:t.y}}return e.type==="facility"?{x:e.x,y:e.y,w:e.w,h:e.h,cx:e.x+e.w/2,cy:e.y+e.h/2}:null}function Gr(e){if(!e.cardTargetPick?.pending)return[];if(e.cardTargetPick.mode==="autoScannerMenu"){let n=new Set(e.cardTargetPick.targetKeys||[]);return e.scanners.filter(o=>o.kind==="auto"&&n.has(wt(o))).map(o=>({key:wt(o),label:"AUTO ROUTE SETTINGS",target:o,bounds:Gs(o)})).filter(o=>o.bounds)}let t=new Set(e.cardTargetPick.targetKeys||[]);return et(e,e.cardTargetPick.cardId).filter(n=>t.has(wt(n))).map(n=>({key:wt(n),label:_r(e,n),target:n,bounds:Gs(n)})).filter(n=>n.bounds)}function sc(e,t){let n=Gr(e);for(let o of n){let r=o.bounds;if(t.x>=r.x&&t.x<=r.x+r.w&&t.y>=r.y&&t.y<=r.y+r.h)return o.target}return null}function Vs(e,t){if(t.type==="eggOutlet"){let n=t.farm||e.eggFarms.find(r=>r.id===t.id);if(!n)return;n.extraEggOutlet=Math.min(3,Math.max(0,Number(n.extraEggOutlet)||0)+1);let o=$(n.col,n.row);H(e,o.x,o.y-30,`OUTLET ${1+n.extraEggOutlet}`,b.green),Me(e);return}if(t.level=(t.level||1)+1,t.type==="eggFarm"){t.nextSpawn=Wt(t),t.lastInterval=t.nextSpawn;let n=$(t.col,t.row);H(e,n.x,n.y-30,`LV ${t.level}`,b.green);return}if(t.type==="scanner"){let n=ge(t);H(e,n.x,n.y-34,`LV ${t.level}`,b.green);return}t.type==="facility"&&H(e,t.x+t.w/2,t.y+18,`LV ${t.level}`,b.green)}function zs(e,t){let n=Ke(e),o=r=>{n[r]=Math.max(0,n[r]||0)+1};if(t.id==="bearing"&&o("bearing"),t.id==="autoScannerTuning"&&o("autoScannerTuning"),t.id==="legalWork"&&o("legalWork"),t.id==="crowdedFarming"&&(n.crowdedFarming=Math.min(10,(n.crowdedFarming||0)+1)),t.id==="hatchingFeed"&&o("hatchingFeed"),t.id==="poopRateBooster"&&o("poopRateBooster"),t.id==="safetyCover"&&o("safetyCover"),t.id==="recyclingSubsidy"&&(n.recyclingSubsidy=Math.min(3,(n.recyclingSubsidy||0)+1)),t.id==="chemicalWeaponSubsidy"&&o("chemicalWeaponSubsidy"),t.id==="preventiveMaintenance"&&o("preventiveMaintenance"),t.id==="dudFilter"&&o("dudFilter"),t.id==="durabilityCoating"&&(o("durabilityCoating"),Re(e)),t.id==="sparePartsBin"){o("sparePartsBin");let r=$s(e,.02);e.stats.sparePartsRepair=(e.stats.sparePartsRepair||0)+r,e.totals.sparePartsRepair=(e.totals.sparePartsRepair||0)+r,H(e,f.x+f.cols*f.cell/2,f.y-30,"REPAIR +2%",b.green)}t.id==="dudRefund"&&o("dudRefund"),t.id==="freeReroll"&&o("freeReroll"),t.id==="composter"&&o("composter"),t.id==="scannerQueueSpacing"&&o("scannerQueueSpacing"),t.id==="flattery"&&o("fairiesFlatteryNext"),t.id==="usedMachine"&&(n.usedMachineActive=!0),t.id==="newMachine"&&(n.usedMachineActive=!1),t.id==="laborExploitation"&&(n.laborExploitation=1),t.id==="rescueLoan"&&(o("rescueLoanCharges"),H(e,f.x+f.cols*f.cell/2,f.y-30,"RESCUE HELD",b.green))}function ot(e){return`${Math.round(Number(e||0)*100)}%`}function Us(e){let t=Et[Math.max(0,Math.min(Et.length-1,e-1))]||Et[0]||[0,0];return`${t[0].toFixed(2)}-${t[1].toFixed(2)}s`}function Ws(e,t){return Math.ceil(e*Math.pow(xe.incomeUpgradeRate,Math.max(0,t-1)))}function Or(e,t,n){let r=et(e,t==="mixer"?"upgradeMixer":t==="sausageMaker"?"upgradeSausageMaker":"upgradeTruck")[0];if(!r)return{before:Ws(n,1),after:Ws(n,2)};let i=()=>t==="truck"?Ve(e):Ze(e),a=i(),c=r.level||1;r.level=c+1;let h=i();return r.level=c,{before:a,after:h}}function ac(e,t){let n=Ke(e);if(t.id==="upgradeEgg"){let o=et(e,t),r=Math.min(3,Math.max(1,o[0]?.level||1));return`Choose one EGG. Level +1. Production interval ${Us(r)} -> ${Us(r+1)}.`}if(t.id==="upgradeAutoScanner"){let o=et(e,t)[0]||{level:1},r=St(o,e),i=St({...o,level:(o.level||1)+1},e);return`Choose one AUTO SCANNER. Level +1. Cooldown ${r.toFixed(2)}s -> ${i.toFixed(2)}s.`}if(t.id==="upgradeMixer"){let o=Or(e,"mixer",xe.income.sausage);return`Choose one MIXER. Meat quality +10%. Sausage sale value ${x(o.before)} -> ${x(o.after)}.`}if(t.id==="upgradeSausageMaker"){let o=Or(e,"sausageMaker",xe.income.sausage);return`Choose one SAUSAGE MACHINE. Product value +10%. Sausage sale value ${x(o.before)} -> ${x(o.after)}.`}if(t.id==="upgradeTruck"){let o=Or(e,"truck",xe.income.truck);return`Choose one TRUCK. Earning +10%. Correct shipment income ${x(o.before)} -> ${x(o.after)}.`}if(t.id==="upgradeTrash"){let o=mt(e),r=Math.min(cn(),o+1),i=ht(o),a=ht(r),c=Math.round(qt(o)*100),h=Math.round(qt(r)*100);return`SHREDDER level +1. Expected value ${x(i)} -> ${x(a)} per poop; hit chance ${c}% -> ${h}%.`}if(t.id==="bearing"){let o=Math.min(tn,Jn*Math.pow(Zn,Math.max(0,n.bearing||0))),r=Math.min(tn,Jn*Math.pow(Zn,Math.max(0,(n.bearing||0)+1)));return`Conveyor speed +7.5%. After pick: ${o.toFixed(1)} -> ${r.toFixed(1)} px/s.`}if(t.id==="legalWork"){let o=Math.max(0,n.legalWork||0);return`Fairies tribute profit exemption +${x(250)}. After pick: exemption bonus ${x(250*(o+1))}.`}if(t.id==="crowdedFarming"){let o=Math.min(10,(n.crowdedFarming||0)+1);return`Held ${n.crowdedFarming||0}/10. After pick: EGG interval ${ot(Math.max(.5,1-.05*o))}, deterioration ${ot(Math.min(1.4,1+.04*o))}.`}if(t.id==="extraEggOutlet"){let o=et(e,t),r=Math.max(0,Number(o[0]?.farm?.extraEggOutlet)||0);return`Choose one EGG. Output ports ${1+r} -> ${2+r}. Max 4 ports per EGG.`}if(t.id==="hatchingFeed")return`Held ${n.hatchingFeed||0}. After pick: EGG interval ${ot(Math.pow(.96,(n.hatchingFeed||0)+1))}, poop rate multiplier ${ot(Math.pow(1.03,(n.hatchingFeed||0)+1))}.`;if(t.id==="poopRateBooster")return`Held ${n.poopRateBooster||0}. After pick: base poop rate +${Math.round((n.poopRateBooster||0)+1)*4} percentage points.`;if(t.id==="autoScannerTuning")return`Held ${n.autoScannerTuning||0}. After pick: all AUTO SCANNER default cooldown ${ot(Math.pow(Yo,(n.autoScannerTuning||0)+1))}.`;if(t.id==="safetyCover")return`Held ${n.safetyCover||0}. After pick: explosion damage ${ot(Math.pow(.95,(n.safetyCover||0)+1))}.`;if(t.id==="recyclingSubsidy")return`Held ${n.recyclingSubsidy||0}/3. After pick: normal SELL refund ${Math.round(Math.min(.8,.5+.1*((n.recyclingSubsidy||0)+1))*100)}%.`;if(t.id==="chemicalWeaponSubsidy")return`Held ${n.chemicalWeaponSubsidy||0}. After pick: ${x(1200*((n.chemicalWeaponSubsidy||0)+1))} per 70 truck-shipped poop each day.`;if(t.id==="preventiveMaintenance")return`Held ${n.preventiveMaintenance||0}. After pick: deterioration speed ${ot(Math.pow(.95,(n.preventiveMaintenance||0)+1))}.`;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,Ue.dudChancePerCard||0)),r=Math.max(0,Math.min(1,Ue.dudChanceReductionPerFilter||.05)),i=Math.max(0,n.dudFilter||0),a=Math.max(0,o-r*i),c=Math.max(0,o-r*(i+1));return`Held ${i}. DUD chance per card ${ot(a)} -> ${ot(c)}.`}return t.id==="durabilityCoating"?`Held ${n.durabilityCoating||0}. After pick: maximum durability ${ot(Math.pow(1.03,(n.durabilityCoating||0)+1))}.`:t.id==="sparePartsBin"?`Held ${n.sparePartsBin||0}. Immediately restores 2% durability to every maintained machine. Common card weight.`:t.id==="dudRefund"?`Held ${n.dudRefund||0}. After pick: DUD clicks award ${x(50*((n.dudRefund||0)+1))}.`:t.id==="freeReroll"?`Held ${n.freeReroll||0}. After pick: each card screen starts with ${(n.freeReroll||0)+1} free reroll${(n.freeReroll||0)+1===1?"":"s"}.`:t.id==="composter"?`Held ${n.composter||0}. After pick: SHREDDER poop grants ${x(3*((n.composter||0)+1))}.`:t.id==="scannerQueueSpacing"?`Held ${n.scannerQueueSpacing||0}. After pick: Manual/Auto Scanner queue spacing ${ot(Math.pow(.85,(n.scannerQueueSpacing||0)+1))}.`:t.id==="flattery"?`Next Fairies tribute -50%. Held for next tribute: ${n.fairiesFlatteryNext||0}.`:t.id==="usedMachine"?"Enable Used Machines: future equipment costs 50%, has no SELL refund, and starts with 60% durability.":t.id==="newMachine"?"Cancel Used Machines. Future equipment returns to normal price, refund, and durability.":t.id==="laborExploitation"?"Repairman dispatch paperwork is streamlined. Repair rooms keep operating; one time only.":t.id==="rescueLoan"?`At day-end bankruptcy check, gain ${x(500)} if cash is below ${x(0)}. Held: ${n.rescueLoanCharges||0}.`:t.id==="dynamite"?"Choose any blocked tiles on the map and destroy up to 3. Empty-space clicks are ignored; press Esc to finish after at least one blast.":t.description}function Lr(e,t){let n=e.cardDraft?.choices||[],o=n.findIndex(r=>r.id===t.id);o>=0&&n.splice(o,1)}function Xs({game:e,ui:t,onUpdatePanels:n}){function o(){n&&n()}function r(){Ke(e),e.cardTargetPick=null,e.cardDraft={pending:!0,choices:To(e,zt),rerolls:0,freeRerolls:dn(e,"freeReroll"),picksRemaining:1}}function i(){Ke(e),e.cardDraft.pending=!1,e.cardDraft.choices=[],e.cardDraft.picksRemaining=0,e.cardTargetPick=null,t.modal.classList.remove("visible","equipment-popover"),o()}function a(D=zt){Ke(e),e.cardDraft.choices=To(e,D)}function c(){Ke(e),!e.cardDraft.choices.length&&e.cardDraft.picksRemaining>0&&a(zt)}function h(D){Lr(e,D),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1),e.cardTargetPick=null,c(),e.cardDraft.picksRemaining<=0?i():ue()}function g(D){Lr(e,D),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1)+Ue.extraCardsAddedPicks,e.cardDraft.choices.push(...To(e,2)),ue()}function C(D,U){let ee=dn(e,"dudRefund")*50;if(ee>0){let O=je(e,ee);e.stats.dudRefundIncome=(e.stats.dudRefundIncome||0)+O,e.totals.dudRefundIncome=(e.totals.dudRefundIncome||0)+O,H(e,f.x+f.cols*f.cell/2,f.y-30,`DUD REFUND +${x(O)}`,b.green)}Yt(e,34,.62),document.body?.animate&&document.body.animate([{transform:"translate(0, 0)"},{transform:"translate(-10px, 7px)"},{transform:"translate(12px, -8px)"},{transform:"translate(-8px, -5px)"},{transform:"translate(9px, 6px)"},{transform:"translate(0, 0)"}],{duration:260,easing:"steps(5, end)"}),U&&(U.style.setProperty("--fling-x",`${260+Math.random()*260}px`),U.style.setProperty("--fling-y",`${-260-Math.random()*170}px`),U.style.setProperty("--fling-r",`${(Math.random()<.5?-1:1)*(52+Math.random()*38)}deg`),U.classList.add("flung")),window.setTimeout(()=>{Lr(e,D),c(),ue()},340)}function P(D,U=null){if(D.type==="dud")return C(D,U);if(D.id==="extraCards")return g(D);if(D.type==="equipmentUpgrade"||D.type==="cellAction")return L(D);zs(e,D),h(D)}function L(D){let U=et(e,D);U.length&&(e.cardTargetPick={pending:!0,cardId:D.id,mode:D.target==="blockedCell"?"blockedCell":"equipment",targetKeys:U.map(wt),remaining:D.id==="dynamite"?Math.min(10,U.length):1,used:0},t.modal.classList.remove("visible","equipment-popover"),o())}function K(D){if(!D||D.type!=="blockedCell")return!1;let U=I(D.col,D.row);if(!e.blockedCells?.has(U))return!1;e.blockedCells.delete(U);let ee=$(D.col,D.row);return vt(e,ee.x,ee.y),at(e,ee.x,ee.y,b.danger,62),bt(e,ee.x,ee.y,18,b.warn),mo(e,ee.x,ee.y,8),Yt(e,16,.35),H(e,ee.x,ee.y-18,"BOOM",b.danger),Me(e),e.cardTargetPick.remaining=Math.max(0,(e.cardTargetPick.remaining||1)-1),e.cardTargetPick.used=Math.max(0,e.cardTargetPick.used||0)+1,e.cardTargetPick.targetKeys=et(e,"dynamite").map(wt),o(),!0}function j(D){if(!e.cardTargetPick?.pending)return!1;let U=Xt(e.cardTargetPick.cardId),ee=sc(e,D);return U?U.id==="dynamite"?(!ee||!K(ee)||((e.cardTargetPick.remaining||0)<=0||!et(e,"dynamite").length)&&h(U),!0):ee?(Vs(e,ee),h(U),!0):(Z(),!0):(Z(),!0)}function Z(){if(!e.cardTargetPick?.pending)return;let D=e.cardTargetPick,U=Xt(D.cardId);if(U?.id==="dynamite"&&(D.used||0)>0){h(U);return}e.cardTargetPick=null,ue()}function Q(){let D=Math.max(0,e.cardDraft?.freeRerolls||0);if(D>0){e.cardDraft.freeRerolls=D-1,e.cardDraft.rerolls+=1,a(zt),ue();return}let U=Os(e);e.cash${U.alt||
`:``}function le(D,U){let ee=document.createElement("button");ee.type="button";let O=D.type==="dud"?"dud":D.rarity==="ultraRare"?"ultra-rare":D.rarity==="rare"?"rare":"common";ee.className=`card-choice ${O}`;let G=D.type==="dud"?"MISS":D.rarity==="ultraRare"?"ULTRA RARE":D.rarity==="rare"?"RARE":"COMMON",Y=[G,...(D.tags||[]).filter(ie=>ie!==G)].slice(0,5);return ee.innerHTML=`${pe(D)}
${D.title}
${Y.map(ie=>`${ie}`).join("")}
${ac(e,D)}
`,ee.addEventListener("click",()=>P(D,ee)),ee.dataset.index=String(U),ee}function ue(){Ke(e),e.cardTargetPick=null,e.cardDraft?.pending||r(),e.cardDraft.choices?.length||a(zt);let D=e.cardDraft.choices||[],U=Os(e),ee=Math.max(0,e.cardDraft?.freeRerolls||0),O=Math.max(1,e.cardDraft.picksRemaining||1);t.modalTitle.textContent="Choose Upgrade Card",t.modalBody.innerHTML=`

Choose ${O} card${O===1?"":"s"} before Build phase. Dud cards can be flicked away without consuming a pick. Equipment cards target machines; Dynamite targets blocked cells.

`;let G=t.modalBody.querySelector("#cardChoices");D.forEach((De,me)=>G.appendChild(le(De,me))),t.modalActions.innerHTML="";let Y=document.createElement("button");Y.type="button",Y.className="facility-action warn reroll-button",Y.textContent=ee>0?`Reroll (FREE x${ee})`:`Reroll ${x(U)}`,Y.disabled=ee<=0&&e.cash0?`${ee} free reroll${ee===1?"":"s"} remaining.`:Y.disabled?"Not enough cash":"",Y.addEventListener("click",Q),t.modalActions.appendChild(Y);let ie=document.createElement("button");ie.type="button",ie.className="facility-action",ie.textContent="No Card",ie.title="Skip this upgrade pick and enter Build phase.",ie.addEventListener("click",i),t.modalActions.appendChild(ie),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible")}return{prepareDraft:r,showDraft:ue,finishDraft:i,chooseTargetAtPoint:j,cancelTargetPick:Z}}var js=[[{key:"a",code:"KeyA",label:"A"},{key:"d",code:"KeyD",label:"D"}],[{key:"arrowleft",code:"ArrowLeft",label:"Left"},{key:"arrowright",code:"ArrowRight",label:"Right"}],[{key:"j",code:"KeyJ",label:"J"},{key:"l",code:"KeyL",label:"L"}],[{key:"f",code:"KeyF",label:"F"},{key:"h",code:"KeyH",label:"H"}],[{key:"q",code:"KeyQ",label:"Q"},{key:"e",code:"KeyE",label:"E"}],[{key:"z",code:"KeyZ",label:"Z"},{key:"x",code:"KeyX",label:"X"}],[{key:"u",code:"KeyU",label:"U"},{key:"o",code:"KeyO",label:"O"}],[{key:"n",code:"KeyN",label:"N"},{key:"m",code:"KeyM",label:"M"}]];function lc(e){let t=js[e]||js[0];return{left:{...t[0]},right:{...t[1]}}}function Qs(e,t,n){let o={type:"eggFarm",id:e.nextId++,col:t,row:n,level:1,nextSpawn:2,lastInterval:2,extraEggOutlet:0,price:Rt.eggFarm,builtSession:e.buildSession};return o.nextSpawn=Wt(o),o.lastInterval=o.nextSpawn,o}function Js(e,t,n,o){let r=o==="auto"?Te.autoScanner.price:Te.manualScanner.price,i=new Set(e.scanners.filter(c=>c.kind==="manual").map(c=>c.slot)),a=0;for(;i.has(a);)a+=1;return{type:"scanner",id:e.nextId++,kind:o,slot:o==="manual"?a:null,role:o==="manual"?a%2:0,col:t,row:n,level:1,queue:[],cooldown:0,price:r,builtSession:e.buildSession,autoMode:"standard",keys:o==="manual"?lc(a):null}}function cc(e,t,n){let o=n.x-t.x,r=n.y-t.y,i=o*o+r*r,a=i>0?Math.max(0,Math.min(1,((e.x-t.x)*o+(e.y-t.y)*r)/i)):0,c=t.x+o*a,h=t.y+r*a;return Math.hypot(e.x-c,e.y-h)}function uc(e){let t=[],n=e?.ownedCells?.size?[...e.ownedCells].map(o=>{let[r,i]=String(o).split(",").map(Number);return{col:r,row:i}}):Array.from({length:f.cols*f.rows},(o,r)=>({col:r%f.cols,row:Math.floor(r/f.cols)}));for(let o of n){let r=f.x+o.col*f.cell,i=f.y+o.row*f.cell,a=r+f.cell,c=i+f.cell;Ye(e,o.col-1,o.row)||t.push({side:"left",entry:o,a:{x:r,y:i},b:{x:r,y:c}}),Ye(e,o.col+1,o.row)||t.push({side:"right",entry:o,a:{x:a,y:i},b:{x:a,y:c}}),Ye(e,o.col,o.row-1)||t.push({side:"top",entry:o,a:{x:r,y:i},b:{x:a,y:i}}),Ye(e,o.col,o.row+1)||t.push({side:"bottom",entry:o,a:{x:r,y:c},b:{x:a,y:c}})}return t}function Eo(e,t=null){let n=uc(t);if(n.length){let L=n.map(K=>({...K,distance:cc(e,K.a,K.b)})).sort((K,j)=>K.distance-j.distance)[0];return{side:L.side,entry:{...L.entry}}}let o=(e.x-f.x)/f.cell,r=(e.y-f.y)/f.cell,i=Math.max(0,Math.min(f.cols-1,Math.round(o-.5))),a=Math.max(0,Math.min(f.rows-1,Math.round(r-.5))),c=Math.abs(e.x-f.x),h=Math.abs(e.x-(f.x+f.cols*f.cell)),g=Math.abs(e.y-f.y),C=Math.abs(e.y-(f.y+f.rows*f.cell)),P=[["left",c],["right",h],["top",g],["bottom",C]].sort((L,K)=>L[1]-K[1])[0][0];return P==="left"?{side:P,entry:{col:0,row:a}}:P==="right"?{side:P,entry:{col:f.cols-1,row:a}}:P==="top"?{side:P,entry:{col:i,row:0}}:{side:P,entry:{col:i,row:f.rows-1}}}function Ur(e){return e?.baseId||e?.id||""}function yn(e){return e?.gridPlaced&&(e.wCells=Math.max(1,e.wCells||3),e.hCells=Math.max(1,e.hCells||3),e.x=f.x+e.col*f.cell,e.y=f.y+e.row*f.cell,e.w=e.wCells*f.cell,e.h=e.hCells*f.cell,Ur(e)==="sausageMaker"&&(e.entry={col:e.col-1,row:e.row+Math.floor(e.hCells/2)},e.side="grid")),e}function Ro(e){if(!e?.gridPlaced)return[];let t=[];for(let n=0;n<(e.hCells||3);n+=1)for(let o=0;o<(e.wCells||3);o+=1)t.push({col:e.col+o,row:e.row+n});return t}function dc(e,t){if(Ur(e)!=="mixer")return;let n=e.baseW||e.w||168,o=e.baseH||e.h||110;e.baseW=n,e.baseH=o;let r=t==="top"||t==="bottom";e.w=r?Math.max(n,o):Math.min(n,o),e.h=r?Math.min(n,o):Math.max(n,o)}function Po(e,t="input"){if(!e)return null;let n=Ur(e);return n==="mixer"?e.side==="top"||e.side==="bottom"?t==="input"?{x:e.x+e.w/2,y:e.y}:{x:e.x+e.w/2,y:e.y+e.h}:t==="input"?{x:e.x,y:e.y+e.h/2}:{x:e.x+e.w,y:e.y+e.h/2}:n==="sausageMaker"&&e.gridPlaced?t==="input"?{x:e.x,y:e.y+e.h/2}:{x:e.x+e.w,y:e.y+e.h/2}:{x:e.x+e.w/2,y:e.y+e.h/2}}function Ao(e,t,n){dc(e,n);let o={x0:f.x+t.col*f.cell,y0:f.y+t.row*f.cell,x1:f.x+(t.col+1)*f.cell,y1:f.y+(t.row+1)*f.cell},r={x:(o.x0+o.x1)/2,y:(o.y0+o.y1)/2};return e.entry={...t},e.side=n,n==="left"?(e.x=o.x0-e.w-18,e.y=r.y-e.h/2):n==="right"?(e.x=o.x1+18,e.y=r.y-e.h/2):n==="top"?(e.x=r.x-e.w/2,e.y=o.y0-e.h-18):(e.x=r.x-e.w/2,e.y=o.y1+18),e}function Zs(e,t,n,o){let{entry:r,side:i}=Eo(n,e),a=Te[t],c=a?{name:a.name,w:a.body?.w||168,h:a.body?.h||110,price:a.price}:{name:t[0].toUpperCase()+t.slice(1),w:168,h:110,price:o},h={type:"facility",id:t,name:c.name,x:0,y:0,w:c.w,h:c.h,baseW:c.w,baseH:c.h,level:1,price:o||c.price,builtSession:e.buildSession};return Ao(h,r,i)}function ea(e,t,n,o,r){let i=Te[t],a={type:"facility",id:t,name:i?.name||t,baseId:t,col:n,row:o,wCells:t==="sausageMaker"?3:1,hCells:t==="sausageMaker"?3:1,gridPlaced:!0,level:1,price:r||i?.price||0,builtSession:e.buildSession};return yn(a)}function jt(e){return e?[{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}]:[]}function ta(e,t,n){return{type:"maintenanceRoom",id:e.nextId++,col:t,row:n,price:Rt.maintenanceRoom,builtSession:e.buildSession,wCells:2,hCells:2}}function fc(e){return Math.random()({x:i.x,y:i.y})),r=o[0];return{id:e.nextId++,sex:n,x:r.x,y:r.y,route:o,targetIndex:o.length>1?1:o.length,stage:t.stage||"belt",scannerId:t.scannerId??null,nextScannerId:null,pendingScannerId:null,radius:n==="poop"?15:17,bob:Math.random()*Math.PI*2,queueIndex:-1,queueRoute:null}}var pc=!0,yc={chickMale:"./assets/images/chick_male.png",chickFemale:"./assets/images/chick_female.png",poop:"./assets/images/poop.png",conveyorStraightH:"./assets/dark_factory/facilities/conveyor/conveyor_straight_h_16.png",conveyorStraightV:"./assets/dark_factory/facilities/conveyor/conveyor_straight_v_16.png",conveyorTurnNe:"./assets/dark_factory/facilities/conveyor/conveyor_turn_ne_16.png",conveyorTurnNw:"./assets/dark_factory/facilities/conveyor/conveyor_turn_nw_16.png",conveyorTurnSe:"./assets/dark_factory/facilities/conveyor/conveyor_turn_se_16.png",conveyorTurnSw:"./assets/dark_factory/facilities/conveyor/conveyor_turn_sw_16.png",boostConveyorStraightH:"./assets/dark_factory/facilities/conveyor/boost_conveyor_straight_h_16.png",boostConveyorStraightV:"./assets/dark_factory/facilities/conveyor/boost_conveyor_straight_v_16.png",boostConveyorTurnNe:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_ne_16.png",boostConveyorTurnNw:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_nw_16.png",boostConveyorTurnSe:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_se_16.png",boostConveyorTurnSw:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_sw_16.png",scannerManual:"./assets/dark_factory/facilities/machines/manual_scanner_32x48.png",scannerAuto:"./assets/dark_factory/facilities/machines/auto_scanner_32x48.png",eggFarm:"./assets/dark_factory/facilities/machines/egg_farm_16.png",mixer:"./assets/dark_factory/facilities/machines/mixer_32.png",shredder:"./assets/dark_factory/facilities/machines/shredder_32.png",truck:"./assets/dark_factory/facilities/vehicles/truck_32.png",maintenanceRoom:"./assets/dark_factory/facilities/utility/maintenance_room_32.png",repairman:"./assets/dark_factory/facilities/utility/repairman_16.png",obstacleCrate:"./assets/dark_factory/facilities/utility/obstacle_crate_16.png"},Pe={};for(let[e,t]of Object.entries(yc)){let n=new Image;n.loaded=!1,n.onerror=()=>{n.loaded=!1},pc&&t&&(n.onload=()=>{n.loaded=!0},n.src=t),Pe[e]=n}function qr(e){return e.frameCache||(e.frameCache={}),e.frameCache.draw||(e.frameCache.draw={}),e.frameCache.draw}function Yr(e,t){let n=document.createElement("canvas");return n.width=Math.max(1,Math.ceil(e)),n.height=Math.max(1,Math.ceil(t)),n}function sa(e,t,n,o){e.imageSmoothingEnabled=!1,e.clearRect(0,0,t.width,t.height),Sc(e,t,n),e.save();let r=n.shake.time>0?z(-n.shake.strength,n.shake.strength):0,i=n.shake.time>0?z(-n.shake.strength,n.shake.strength):0,a=n.view?.scale||1;e.translate((n.view?.x||0)+r,(n.view?.y||0)+i),e.scale(a,a),Mc(e,n),xc(e,n),Ic(e,n),Uc(e,n),jc(e,n),Qc(e,n),Wc(e,n),Kc(e,n),mc(e,n),ou(e,n,o.activeQueuedChick),fu(e,n),lu(e,t,n),au(e,n,o.selectedObject,o.selectedTitle),cu(e,n),uu(e,n),du(e,n),e.restore(),yu(e,n,t)}function hc(e){if(e.type==="eggFarm"){let n=$(e.ref.col,e.ref.row);return{x:n.x-34,y:n.y-34,w:68,h:68,cx:n.x,cy:n.y}}let t=e.ref;return{x:t.x,y:t.y,w:t.w,h:t.h,cx:t.x+t.w/2,cy:t.y+t.h/2}}function mc(e,t){if(t.phase!=="build")return;let n=an(t);for(let o of n){let r=hc(o);e.save(),e.fillStyle="rgba(196,36,36,.22)",e.strokeStyle=b.danger,e.lineWidth=5,e.setLineDash([10,6]),X(e,r.x,r.y,r.w,r.h,!0,!0),e.setLineDash([]),e.fillStyle=b.danger,e.strokeStyle=b.white,e.lineWidth=4,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.strokeText("!",r.cx,r.y+24),e.fillText("!",r.cx,r.y+24),e.font="900 11px ui-monospace, monospace",e.strokeText("NO ROUTE",r.cx,r.y+r.h-8),e.fillText("NO ROUTE",r.cx,r.y+r.h-8),e.restore()}}function X(e,t,n,o,r,i=!0,a=!0){e.beginPath(),e.rect(t,n,o,r),i&&e.fill(),a&&e.stroke()}function Hr(e,t,n,o,r=b.ink){e.save(),e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.lineWidth=4,e.strokeStyle=b.white,e.fillStyle=r,e.strokeText(o,t,n),e.fillText(o,t,n),e.restore()}function Qt(e,t,n,o,r,i){if(!t?.loaded)return!1;let a=e.imageSmoothingEnabled;return e.imageSmoothingEnabled=!1,e.drawImage(t,Math.round(n),Math.round(o),Math.round(r),Math.round(i)),e.imageSmoothingEnabled=a,!0}function bc(e,t,n,o,r,i,a=null,c=1){e.fillStyle=i,e.fillRect(Math.round(t),Math.round(n),Math.round(o),Math.round(r)),a&&(e.strokeStyle=a,e.lineWidth=c,e.strokeRect(Math.round(t)+.5,Math.round(n)+.5,Math.round(o)-1,Math.round(r)-1))}function vc(e,t){let n=(Math.imul(e+37,73856093)^Math.imul(t+71,19349663))>>>0;return n^=n>>>13,n>>>0}function wc(e,t,n,o,r){let i=vc(o,r);if(i%67!==0)return;let a=10+(i>>>4)%Math.max(1,f.cell-22),c=10+(i>>>9)%Math.max(1,f.cell-22),h=(i>>>14)%16*Math.PI/16;e.save(),e.globalAlpha=.38,e.fillStyle="#4a8d37",e.strokeStyle="rgba(30,66,27,.34)",e.lineWidth=1,e.beginPath();for(let C=0;C<8;C+=1){let P=h+C*Math.PI/4,L=3.5+(i>>>C+2&3),K=t+a+Math.cos(P)*L*1.35,j=n+c+Math.sin(P)*L*.75;C===0?e.moveTo(K,j):e.lineTo(K,j)}e.closePath(),e.fill(),e.stroke();let g=4+(i>>>24)%5;for(let C=0;C>>C+8&3)*.18,L=10+(i>>>C+11&10),K=.9+(i>>>C+17&3)*.35;e.beginPath(),e.arc(t+a+Math.cos(P)*L,n+c+Math.sin(P)*L*.72,K,0,Math.PI*2),e.fill()}e.fillStyle="rgba(151,218,101,.26)",e.beginPath(),e.arc(t+a-2,n+c-2,1.7,0,Math.PI*2),e.fill(),e.restore()}function oa(e,t){e.fillStyle=b.bg,e.fillRect(0,0,t.width,t.height),e.save(),e.globalAlpha=.85;for(let n=0;na.col)),o=Math.max(...t.map(a=>a.col)),r=Math.min(...t.map(a=>a.row)),i=Math.max(...t.map(a=>a.row));return{x:f.x+n*f.cell-6,y:f.y+r*f.cell-6,w:(o-n+1)*f.cell+12,h:(i-r+1)*f.cell+12}}function Mc(e,t){let n=qr(t),o=gc(t);if(!n.grid||n.grid.signature!==o){let a=Cc(t),c=Yr(a.w,a.h),h=c.getContext("2d");h.translate(-a.x,-a.y),kc(h,t),n.grid={signature:o,bounds:a,layer:c}}let{bounds:r,layer:i}=n.grid;e.drawImage(i,r.x,r.y)}function xc(e,t){if(t.phase!=="build"||t.cardDraft?.pending||t.cardTargetPick?.pending)return;let n=ro(t),o=t.cash>=n,r=i=>{let a=dt(i);return Object.values(t.facilities||{}).some(c=>{let h=c?.baseId||c?.id;return["mixer","trash","truck"].includes(h)?!(a.x+a.w<=c.x||c.x+c.w<=a.x||a.y+a.h<=c.y||c.y+c.h<=a.y):!1})};for(let i of Ut(t)){let a=r(i),c=dt(i);e.save(),e.fillStyle=a?"rgba(112,130,118,.34)":o?"rgba(118,226,142,.36)":"rgba(255,255,255,.18)",e.strokeStyle=a?"#708278":o?"#6bd579":b.muted,e.lineWidth=5,e.setLineDash([16,10]),X(e,c.x,c.y,c.w,c.h,!0,!0),e.setLineDash([]);let h=tr(i),g=h.cx,C=h.cy;e.fillStyle="rgba(255,255,255,.94)",e.strokeStyle=b.ink,e.lineWidth=4,X(e,h.x,h.y,h.w,h.h,!0,!0),e.fillStyle=a?"#7c9285":o?b.green:b.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center";let P=i.direction==="left"?"BUY LEFT LOT":i.direction==="right"?"BUY RIGHT LOT":i.direction==="down"?"BUY LOWER LOT":"BUY UPPER LOT";e.fillText(P,g,C-12),e.fillStyle=b.ink,e.font="900 16px ui-monospace, monospace",e.fillText(`${x(n)} / 10\xD710`,g,C+15),e.restore()}}function kt(e,t,n,o,r,i,a=0){let c=un(i);c<.5||(e.save(),e.globalAlpha=Math.min(.62,.12+c*.54),e.fillStyle="#6b4a23",a>0?(e.beginPath(),e.roundRect?.(t,n,o,r,a),e.roundRect?e.fill():X(e,t,n,o,r,!0,!1)):X(e,t,n,o,r,!0,!1),e.globalAlpha=Math.min(.9,.25+c*.6),e.strokeStyle="#3a2a16",e.lineWidth=Math.max(2,Math.floor(2+c*5)),e.setLineDash([5,6]),X(e,t+3,n+3,o-6,r-6,!1,!0),e.restore())}function Wr(e,t){let n=e.componentLookup?.get(t);return(n?e.congestion.get(n):null)?.ratio||0}function Tc(e,t,n={}){let o=Wn(e,t).sort(),i=n.kind==="boostConveyor"?"boostConveyor":"conveyor",a=c=>o.includes(c);if(o.length===2){if(a("left")&&a("right"))return Pe[`${i}StraightH`];if(a("up")&&a("down"))return Pe[`${i}StraightV`];if(a("up")&&a("right"))return Pe[`${i}TurnNe`];if(a("up")&&a("left"))return Pe[`${i}TurnNw`];if(a("down")&&a("right"))return Pe[`${i}TurnSe`];if(a("down")&&a("left"))return Pe[`${i}TurnSw`]}return o.length===1?a("up")||a("down")?Pe[`${i}StraightV`]:Pe[`${i}StraightH`]:a("up")||a("down")?Pe[`${i}StraightV`]:Pe[`${i}StraightH`]}function Ec(e){let t=Object.entries(Pe).filter(([o])=>o.includes("conveyor")||o.includes("Conveyor")).map(([o,r])=>`${o}:${r.loaded?1:0}`).join("|"),n=[...e.conveyorTiles].sort().map(o=>{let r=e.conveyorMeta.get(o)||{};return`${o}:${r.kind||""}:${r.dir||""}:${(r.outDirs||[]).join(",")}:${r.branchMode||""}`}).join("|");return`${e.routingVersion||0};${t};${n}`}function Rc(e){if(!e.conveyorTiles?.size)return{x:0,y:0,w:1,h:1};let t=[...e.conveyorTiles].map(re),n=Math.min(...t.map(a=>a.col)),o=Math.max(...t.map(a=>a.col)),r=Math.min(...t.map(a=>a.row)),i=Math.max(...t.map(a=>a.row));return{x:f.x+n*f.cell-36,y:f.y+r*f.cell-36,w:(o-n+1)*f.cell+72,h:(i-r+1)*f.cell+72}}function Pc(e){let t=[],n=new Set;for(let i of e.conveyorTiles){let{col:a,row:c}=re(i);for(let h of fe){let g={col:a+h.dc,row:c+h.dr},C=I(g.col,g.row);if(!e.conveyorTiles.has(C))continue;let P=[i,C].sort().join("|");n.has(P)||(n.add(P),t.push({fromKey:i,toKey:C,a:$(a,c),b:$(g.col,g.row)}))}}let o=Nc(e),r=[...e.conveyorTiles].map(i=>{let a=re(i),c=$(a.col,a.row),h=e.conveyorMeta.get(i)||{},g=Wn(e,i);return{k:i,c,meta:h,connectedDirs:g,branchDirs:Dc(e,i,g),markers:o.get(i)||[],sprite:Tc(e,i,h)}});return{edges:t,tiles:r}}function Ac(e,t){e.save(),e.lineCap="round",e.lineJoin="round";for(let n of[{width:31,color:"#0b0c0f",alpha:1},{width:23,color:"#444b56",alpha:1},{width:15,color:"#171a1f",alpha:1}]){e.globalAlpha=n.alpha,e.strokeStyle=n.color,e.lineWidth=n.width;for(let o of t.edges)e.beginPath(),e.moveTo(o.a.x,o.a.y),e.lineTo(o.b.x,o.b.y),e.stroke()}e.globalAlpha=1;for(let n of t.tiles){let{c:o,meta:r,sprite:i}=n;e.fillStyle="rgba(0,0,0,.35)",e.strokeStyle="rgba(255,184,39,.34)",e.lineWidth=1,X(e,o.x-20,o.y-20,40,40,!0,!0),Qt(e,i,o.x-19,o.y-19,38,38)||(e.fillStyle=r.kind==="boostConveyor"?"#315e92":"#454b55",e.strokeStyle=b.ink,e.lineWidth=2,X(e,o.x-18,o.y-18,36,36,!0,!0))}e.restore()}function Ic(e,t){let n=qr(t),o=Ec(t);if(!n.conveyors||n.conveyors.signature!==o){let c=Pc(t),h=Rc(t),g=Yr(h.w,h.h),C=g.getContext("2d");C.translate(-h.x,-h.y),Ac(C,c),n.conveyors={signature:o,bounds:h,layer:g,data:c}}let{bounds:r,layer:i,data:a}=n.conveyors;e.drawImage(i,r.x,r.y),e.save(),e.lineCap="round",e.lineJoin="round";for(let c of a.edges){let h=Math.max(Wr(t,c.fromKey),Wr(t,c.toKey)),g=Math.max(0,(h-.5)/.5);e.strokeStyle=In(b.green,b.danger,g),e.globalAlpha=h>.5?.35+g*.55:.8,e.lineWidth=6,e.beginPath(),e.moveTo(c.a.x,c.a.y),e.lineTo(c.b.x,c.b.y),e.stroke()}e.globalAlpha=1;for(let c of a.tiles){let{k:h,c:g,meta:C}=c,P=Wr(t,h);P>.5&&(e.fillStyle="rgba(196,36,36,.28)",e.strokeStyle=b.danger,e.lineWidth=3,X(e,g.x-20,g.y-20,40,40,!0,!0)),$c(e,t,g,h,C,P),kt(e,g.x-18,g.y-18,36,36,{meta:C}),gt(e,t,"conveyor",h,g.x,g.y,38,38),_c(e,g,c.markers),Oc(e,g,C,c.branchDirs,c.connectedDirs),P>.5&&Hr(e,g.x,g.y-15,`${Math.floor(P*100)}%`,b.danger)}e.restore()}function $c(e,t,n,o,r={},i=0){let a=r.kind==="boostConveyor",h=[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))][0]||"right",g=h==="up"||h==="down",C=h==="left"||h==="up",P=pn(t,o)*_n(t,o),K=(typeof performance<"u"?performance.now()/1e3:0)*P,j=((C?-K:K)%10+10)%10;e.save(),e.beginPath(),e.rect(n.x-18,n.y-18,36,36),e.clip();let Z=a?"rgba(20,126,124,.62)":"rgba(42,47,54,.72)";if(e.fillStyle=Z,e.fillRect(n.x-18,n.y-18,36,36),e.strokeStyle=i>.5?"rgba(238,83,61,.90)":"rgba(184,190,198,.92)",e.lineWidth=4,g)for(let Q=n.y-28+j;Qe.conveyorTiles.has(I(n.col+o.dc,n.row+o.dr))).map(o=>o.name)}function la(e,t,n){let o=fe.find(a=>a.name===n);if(!o)return!1;let r=e.conveyorMeta?.get?.(I(t.col+o.dc,t.row+o.dr));return r?[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))].includes(o.opposite):!1}function ca(e,t,n,o=Wn(e,t)){if(o.length<3)return n;let r=re(t),i=new Set(o.filter(h=>la(e,r,h))),a=o.filter(h=>!i.has(h));if(i.size)return a;let c=n.filter(h=>o.includes(h));return c.length>=2?[...new Set(c)]:o}function Fc(e,t,n,o=Wn(e,t),r="random"){let i=ca(e,t,n,o);return o.length>=3&&r&&r!=="random"&&i.includes(r)?[r]:i}function Dc(e,t,n=Wn(e,t)){let o=e.conveyorMeta?.get?.(t)||{},r=[...new Set([...Array.isArray(o.outDirs)?o.outDirs:[],o.dir].filter(Boolean))];return n.length<3?[]:ca(e,t,r,n)}function Bc(e,t,n){let o=re(t),r=fe.filter(c=>e.conveyorTiles.has(I(o.col+c.dc,o.row+c.dr))).map(c=>c.name),i=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(c=>r.includes(c));if(r.length===1&&(!i.length||i.includes(r[0]))&&la(e,o,r[0]))return[];let a=r;return i.length?i:a}function Oc(e,t,n,o,r=o){if(r.length<3||o.length<2)return;e.save();let i=o.includes(n.branchMode)?n.branchMode:"random",a=i!=="random";if(e.lineJoin="round",e.lineCap="round",e.lineWidth=2,e.fillStyle="rgba(18,21,26,.94)",e.strokeStyle=a?b.warn:b.green,e.lineWidth=4,X(e,t.x-18,t.y-18,36,36,!0,!0),e.strokeStyle="#ffd36a",e.lineWidth=3,e.fillStyle="#020304",i!=="random"){let c=fe.find(h=>h.name===i);Un(e,t.x,t.y-4,c?.angle||0,8,5)}else e.beginPath(),e.moveTo(t.x-10,t.y),e.lineTo(t.x-2,t.y),e.lineTo(t.x+8,t.y-8),e.moveTo(t.x-2,t.y),e.lineTo(t.x+8,t.y+8),e.stroke(),Un(e,t.x+9,t.y-9,-Math.PI/4,4,3),Un(e,t.x+9,t.y+9,Math.PI/4,4,3);i==="random"&&(e.font="900 9px ui-monospace, monospace",e.textAlign="center",e.textBaseline="middle",e.lineWidth=3,e.strokeStyle="#020304",e.fillStyle=b.warn,e.strokeText("RND",t.x,t.y+11),e.fillText("RND",t.x,t.y+11)),e.restore()}function Lc(e,t,n){if(!n)return[];let o=re(t),r=fe.filter(c=>e.conveyorTiles.has(I(o.col+c.dc,o.row+c.dr))).map(c=>c.name),i=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(c=>r.includes(c));return Fc(e,t,i.length?i:Bc(e,t,n),r,n.branchMode||"random").map(c=>fe.find(h=>h.name===c)).filter(Boolean)}function Nc(e){let t=new Map;for(let[n,o]of e.conveyorMeta||[]){let r=Lc(e,n,o);r.length&&t.set(n,r)}return t}function _c(e,t,n){let o=n.slice(0,4);o.length&&(e.save(),e.globalAlpha=1,o.forEach(r=>{let i=t.x+r.dc*11,a=t.y+r.dr*11;e.fillStyle="rgba(255,205,83,.96)",Un(e,i,a,r.angle,9,7),e.fillStyle="#020304",Un(e,i,a,r.angle,6.5,4.6)}),e.restore())}function Un(e,t,n,o,r=11,i=8){e.save(),e.translate(t,n),e.rotate(o),e.beginPath(),e.moveTo(r,0),e.lineTo(-r*.72,-i),e.lineTo(-r*.72,i),e.closePath(),e.fill(),e.restore()}function Gc(e,t,n,o,r){let i=ge(t),a=null;if(n==="inputA"&&(a={x:i.x,y:i.y-40}),n==="left"&&(a={x:i.x-42,y:i.y+10}),n==="right"&&(a={x:i.x+42,y:i.y+10}),!a)return;let c=n==="inputA"?{x:o.x,y:a.y}:{x:a.x,y:o.y};e.save(),e.lineCap="square",e.lineJoin="bevel",e.strokeStyle="#050609",e.lineWidth=15,e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(c.x,c.y),e.lineTo(a.x,a.y),e.stroke(),e.strokeStyle="#596473",e.lineWidth=9,e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(c.x,c.y),e.lineTo(a.x,a.y),e.stroke(),e.strokeStyle=r||"#7b8795",e.lineWidth=3,e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(c.x,c.y),e.lineTo(a.x,a.y),e.stroke(),e.fillStyle=r||"#7b8795",e.strokeStyle="#050609",e.lineWidth=3,X(e,a.x-9,a.y-7,18,14,!0,!0),e.restore()}function Uc(e,t){e.save(),e.lineWidth=2,e.font="900 12px ui-monospace, monospace",e.textAlign="center";for(let n of t.scanners){let o=ur(n),r=[{type:"inputA",p:Fe(n,"inputA"),label:"IN",color:b.green},{type:"left",p:Fe(n,"left"),label:fr(o.left),color:pr(o.left)},{type:"right",p:Fe(n,"right"),label:fr(o.right),color:pr(o.right)}];for(let i of r){if(!i.p)continue;let a=$(i.p.col,i.p.row);Gc(e,n,i.type,a,i.color);let c=Gi(t,n,i.type||(i.label==="IN"?"inputA":null))||t.conveyorTiles.has(I(i.p.col,i.p.row));e.fillStyle=c?In("#1a1d23",i.color,.24):"#3a1e22",e.strokeStyle=c?i.color:b.danger,X(e,a.x-18,a.y-12,36,24,!0,!0),e.fillStyle=b.white,e.fillText(i.label,a.x,a.y+4)}}e.restore()}function Wc(e,t){for(let n of t.eggFarms)Hc(e,n,t)}function Hc(e,t,n){let o=$(t.col,t.row);e.save(),e.fillStyle="#5a6470",e.strokeStyle=b.ink,e.lineWidth=3,X(e,o.x-27,o.y-27,54,54,!0,!0),e.fillStyle="#6f5130",e.strokeStyle="#2f2112",e.lineWidth=3,e.beginPath(),e.ellipse(o.x,o.y+3,19,12,0,0,Math.PI*2),e.fill(),e.stroke(),e.strokeStyle="#a77b4b",e.lineWidth=2;for(let c=-16;c<=16;c+=6)e.beginPath(),e.moveTo(o.x-18,o.y+c*.1),e.quadraticCurveTo(o.x+c,o.y-10+Math.abs(c)*.2,o.x+18,o.y+c*.08),e.stroke();let r=[{x:-8,y:1},{x:0,y:-3},{x:8,y:2}];for(let c of r)e.fillStyle="#e8e2cf",e.strokeStyle="#8d8475",e.lineWidth=1.5,e.beginPath(),e.ellipse(o.x+c.x,o.y+c.y,4.8,6.2,.2,0,Math.PI*2),e.fill(),e.stroke();let i=1+Math.max(0,Number(t.extraEggOutlet)||0);e.fillStyle="rgba(255,255,255,.92)",e.strokeStyle=b.ink,e.lineWidth=2,X(e,o.x+8,o.y+11,30,18,!0,!0),e.fillStyle=b.ink,e.font="900 10px ui-monospace, monospace",e.textAlign="center",e.fillText(`O${i}`,o.x+23,o.y+23),e.fillStyle="#d5e35a",e.font="900 9px ui-monospace, monospace",e.fillText(`L${t.level}`,o.x-13,o.y-15);let a=Math.max(0,Math.min(1,t.shutterProgress||0));if(a>0){let c=54*a;e.fillStyle="rgba(10,12,15,.86)",X(e,o.x-27,o.y-27,54,c,!0,!1),e.strokeStyle="rgba(230,237,242,.64)",e.lineWidth=2;for(let h=o.y-23;h=1&&(e.fillStyle=b.white,e.font="900 12px ui-monospace, monospace",e.fillText("SHUT",o.x,o.y+4))}kt(e,o.x-28,o.y-28,56,56,t),gt(e,n,"eggFarm",t.id,o.x,o.y,68,68),e.restore()}function Kc(e,t){for(let n of t.scanners)qc(e,n,t)}function qc(e,t,n){let o=ge(t);if(e.save(),t.kind==="manual"&&(n.manualCombo?.count||0)>=10){let h=n.manualCombo.count;e.save(),e.globalAlpha=Math.min(.55,.16+h/120),e.strokeStyle=h>=30?b.warn:b.green,e.lineWidth=Math.min(12,4+Math.floor(h/10)),e.shadowColor=e.strokeStyle,e.shadowBlur=Math.min(24,8+h),X(e,o.x-48,o.y-48,96,96,!1,!0),e.restore()}let r=t.kind==="auto"?Pe.scannerAuto:Pe.scannerManual;if(Qt(e,r,o.x-44,o.y-44,88,88)){t.kind==="auto"?kt(e,o.x-44,o.y-44,88,88,t):ra(e,t,o),gt(e,n,"scanner",t.id,o.x,o.y,96,96),e.restore();return}e.fillStyle=t.kind==="auto"?"#d8ffe2":b.white,e.strokeStyle=b.ink,e.lineWidth=4,X(e,o.x-44,o.y-44,88,88,!0,!0),e.fillStyle=t.kind==="auto"?b.green:b.ink,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText(t.kind==="auto"?"AUTO":`S${(t.slot??0)+1}`,o.x,o.y-24),e.font="900 9px ui-monospace, monospace";let i=t.keys?.left?.label||(t.slot===0?"A":"Left"),a=t.keys?.right?.label||(t.slot===0?"D":"Right");e.fillText(t.kind==="auto"?"2.1 FARMS":`${i}/${a}`,o.x,o.y-8);let c=t.queue.length;t.kind==="manual"?ra(e,t,o):(e.fillStyle=c>0?b.green:b.muted,e.font="900 10px ui-monospace, monospace",e.fillText(`Q:${c} CD:${t.cooldown.toFixed(1)}`,o.x,o.y+35),kt(e,o.x-44,o.y-44,88,88,t)),gt(e,n,"scanner",t.id,o.x,o.y,96,96),e.restore()}function ra(e,t,n){if(t.kind!=="manual")return;let r=(t.slot??0)===0?[{side:"left",text:"A"},{side:"right",text:"D"}]:[{side:"left",text:"\u2190"},{side:"right",text:"\u2192"}];r[0].text=t.keys?.left?.label||r[0].text,r[1].text=t.keys?.right?.label||r[1].text;let i=t.keyPressTime>0?t.keyPressSide:null,a=n.x-30,c=n.y+8;e.save(),e.lineWidth=3,e.fillStyle="#f7fff5",e.strokeStyle=b.ink,X(e,a-4,c-4,68,25,!0,!0),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let h=0;h MEAT","meat","connect OUT to sausage machine"),kt(e,n.x,n.y,n.w,n.h,n),gt(e,t,"facility",n.id,n.x+n.w/2,n.y+n.h/2,n.w+12,n.h+12),e.restore()}function eu(e,t,n=t.facilities.trash){e.save(),zr(e,n),Hn(e,n.x,n.y,n.w,n.h,"#29342d",b.ink,b.wasteGreen),Fo(e,n,b.wasteGreen),e.fillStyle=b.white,e.font="900 14px ui-monospace, monospace",e.textAlign="left",e.fillText(`SHREDDER L${n.level}`,n.x+14,n.y+18),e.fillStyle="#181d20",e.strokeStyle="#9fd473",e.lineWidth=4,X(e,n.x+38,n.y+36,92,22,!0,!0),e.fillStyle="#262d30",e.strokeStyle="#0d1014",X(e,n.x+46,n.y+58,76,18,!0,!0),e.fillStyle="#111418";for(let o=0;o<7;o+=1){let r=n.x+51+o*10;e.beginPath(),e.moveTo(r,n.y+58),e.lineTo(r+5,n.y+68),e.lineTo(r+10,n.y+58),e.closePath(),e.fill()}e.fillStyle="#6f7e8d",X(e,n.x+54,n.y+27,16,9,!0,!0),X(e,n.x+98,n.y+27,16,9,!0,!0),Io(e,n.x+14,n.y+n.h-42,n.w-28,"SEND POOP","poop","shredder"),kt(e,n.x,n.y,n.w,n.h,n),gt(e,t,"facility",n.id,n.x+n.w/2,n.y+n.h/2,n.w+12,n.h+12),e.restore()}function tu(e,t,n){e.save(),Hn(e,n.x,n.y,n.w,n.h,"#3b3029",b.ink,b.sausageOrange),Fo(e,n,b.sausageOrange),e.fillStyle=b.white,e.font="900 14px ui-monospace, monospace",e.textAlign="left",e.fillText(`SAUSAGE L${n.level}`,n.x+14,n.y+18),e.fillStyle=b.muted,e.font="900 10px ui-monospace, monospace",e.fillText(`2 MEAT -> 1 | ${x(Ze(t))}`,n.x+14,n.y+34),e.fillStyle="#211915",e.strokeStyle=b.sausageOrange,e.lineWidth=4,X(e,n.x+20,n.y+43,n.w-40,38,!0,!0);for(let o=0;o<3;o+=1)Do(e,n.x+n.w/2-28+o*28,n.y+62,9);e.fillStyle=b.meatRed,e.fillRect(n.x,n.y+n.h/2-8,8,16),e.fillStyle=b.sausageOrange,e.fillRect(n.x+n.w-8,n.y+n.h/2-8,8,16),Io(e,n.x+10,n.y+n.h-42,n.w-20,"2 MEAT -> SAUSAGE","sausage",`buffer ${n.meatBuffer||0}/2`),kt(e,n.x,n.y,n.w,n.h,n),gt(e,t,"facility",n.id,n.x+n.w/2,n.y+n.h/2,n.w+12,n.h+12),e.restore()}function nu(e,t,n=t.facilities.truck){e.save(),zr(e,n),Hn(e,n.x,n.y,n.w,n.h,"#343128",b.ink,b.truckPink),Fo(e,n,b.truckPink),e.fillStyle=b.white,e.font="900 14px ui-monospace, monospace",e.textAlign="left",e.fillText(`TRUCK L${n.level}`,n.x+14,n.y+18),e.fillStyle=b.muted,e.font="900 10px ui-monospace, monospace",e.fillText(`UNIT ${x(Ve(t))}`,n.x+14,n.y+34),zc(e,Pe.truck,n,2);let o=Kr(t);Io(e,n.x+15,n.y+50,n.w-30,`SEND ${o.toUpperCase()}`,o,t.eventOffer&&!t.eventActive?"next event":"truck cargo"),e.fillStyle="rgba(39,60,36,.9)",X(e,n.x+13,n.y+88,n.w-26,Math.max(18,n.h-103),!0,!1);for(let r of t.truckCargo)r.sex==="poop"?ua(e,n.x+r.x,n.y+r.y):r.sex==="sausage"?Do(e,n.x+r.x,n.y+r.y,7):jr(e,n.x+r.x,n.y+r.y,r.sex,r.sex==="male");kt(e,n.x,n.y,n.w,n.h,n),gt(e,t,"facility",n.id,n.x+n.w/2,n.y+n.h/2,n.w+12,n.h+12),e.restore()}function ou(e,t,n){let o=n(0),r=n(1);for(let i of t.chicks){let a=o&&o.id===i.id||r&&r.id===i.id||i.queueIndex===0;ru(e,i,a,t)}}function ru(e,t,n,o){let r=o.componentLookup&&iu(o,t)>.8,i=t.y+Math.sin(t.bob)*(r?5:1.5);if(e.save(),n&&(e.strokeStyle=b.green,e.lineWidth=5,e.beginPath(),e.arc(t.x,i,t.radius+8,0,Math.PI*2),e.stroke()),r&&(e.strokeStyle=b.danger,e.lineWidth=3,e.beginPath(),e.arc(t.x,i,t.radius+12+Math.sin(t.bob*2)*4,0,Math.PI*2),e.stroke()),t.sex==="poop")Xr(e,t.x,i,t.radius);else if(t.sex==="meat")da(e,t.x,i,t.radius);else if(t.sex==="sausage")Do(e,t.x,i,t.radius);else{let a=t.sex==="male"?Pe.chickMale:Pe.chickFemale;if(!Qt(e,a,t.x-t.radius,i-t.radius,t.radius*2,t.radius*2)){let g=t.sex==="male"?b.male:b.female,C=t.sex==="male"?"#164f8f":"#8b2252";e.fillStyle=g,e.strokeStyle=b.ink,e.lineWidth=5,e.beginPath(),e.arc(t.x,i,t.radius,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle="rgba(255,255,255,.24)",e.beginPath(),e.arc(t.x-5,i-7,t.radius*.36,0,Math.PI*2),e.fill(),e.fillStyle=b.ink,e.beginPath(),e.arc(t.x-6,i-5,2.5,0,Math.PI*2),e.arc(t.x+6,i-5,2.5,0,Math.PI*2),e.fill(),e.fillStyle="#ffaa2e",e.beginPath(),e.moveTo(t.x,i+2),e.lineTo(t.x+9,i+6),e.lineTo(t.x,i+10),e.closePath(),e.fill(),e.strokeStyle=C,e.lineWidth=3,t.sex==="male"?(e.beginPath(),e.moveTo(t.x-8,i-t.radius-2),e.lineTo(t.x+8,i-t.radius-2),e.stroke()):(e.beginPath(),e.moveTo(t.x-9,i-t.radius+2),e.lineTo(t.x,i-t.radius-6),e.lineTo(t.x+9,i-t.radius+2),e.stroke())}e.fillStyle=t.sex==="male"?"#dff1ff":"#fff0f7",e.strokeStyle="#050609",e.lineWidth=3,e.font=`900 ${Math.max(10,Math.round(t.radius*.72))}px ui-monospace, monospace`,e.textAlign="center";let h=t.sex==="male"?"\u2642":"\u2640";e.strokeText(h,t.x+t.radius*.54,i+t.radius*.7),e.fillText(h,t.x+t.radius*.54,i+t.radius*.7)}e.restore()}function iu(e,t){let n=null,o=1/0;for(let[r,i]of e.componentLookup.entries()){let a=re(r),c=$(a.col,a.row),h=Math.hypot(t.x-c.x,t.y-c.y);hia(o.type,o.id)===ia(t,n))}function gt(e,t,n,o,r,i,a,c){su(t,n,o)&&(e.save(),e.fillStyle="rgba(34,185,79,.18)",e.strokeStyle=b.green,e.lineWidth=(t.multiSelected||[]).length>1?6:4,e.setLineDash((t.multiSelected||[]).length>1?[]:[8,5]),X(e,r-a/2,i-c/2,a,c,!0,!0),e.restore())}function au(e,t,n,o){if(t.phase==="build"&&(t.multiSelected||[]).length>1){e.save(),e.fillStyle="rgba(255,255,255,.96)",e.strokeStyle=b.ink,e.lineWidth=3,X(e,54-t.view.x,66-t.view.y,214,42,!0,!0),e.fillStyle=b.ink,e.font="900 11px ui-monospace, monospace",e.fillText(`${t.multiSelected.length} ITEMS SELECTED`,65-t.view.x,83-t.view.y),e.fillStyle=b.muted,e.font="900 11px ui-monospace, monospace",e.fillText("drag any selected item to move group",65-t.view.x,99-t.view.y),e.restore();return}}function lu(e,t,n){if(!n.cardTargetPick?.pending)return;let o=Gr(n);e.save(),e.fillStyle="rgba(0,0,0,.66)",e.beginPath();let r=n.view?.scale||1;e.rect(-(n.view?.x||0)/r,-(n.view?.y||0)/r,t.width/r,t.height/r);for(let g of o){let C=g.bounds,P=8;e.rect(C.x-P,C.y-P,C.w+P*2,C.h+P*2)}e.fill("evenodd");let i=n.cardTargetPick?.mode==="blockedCell";if(!o.length){e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=b.ink,e.lineWidth=3,X(e,(260-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,420/r,42/r,!0,!0),e.fillStyle=b.danger,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(i?"NO BLOCKED CELL. PRESS ESC.":"NO VALID UPGRADE TARGET. PRESS ESC.",(470-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore();return}e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=b.ink,e.lineWidth=3;let a=Math.max(1,n.cardTargetPick?.remaining||1),c=Math.max(0,n.cardTargetPick?.used||0),h=n.cardTargetPick?.mode==="autoScannerMenu"?"AUTO SCANNER ROUTE SETTINGS. CLICK EMPTY AREA TO CLOSE.":i?`DYNAMITE: CLICK ANY BLOCKED TILE (${a} LEFT). ESC ${c>0?"FINISHES":"CANCELS"}.`:"CLICK AN UPGRADEABLE MACHINE. PRESS ESC TO CANCEL.";X(e,(216-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,560/r,42/r,!0,!0),e.fillStyle=b.ink,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(h,(496-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore()}function cu(e,t){if(t.phase!=="build"||!t.selectionBox)return;let n=t.selectionBox,o=Math.min(n.x1,n.x2),r=Math.min(n.y1,n.y2),i=Math.abs(n.x2-n.x1),a=Math.abs(n.y2-n.y1);e.save(),e.fillStyle="rgba(34,185,79,.12)",e.strokeStyle=b.green,e.lineWidth=2,e.setLineDash([7,4]),X(e,o,r,i,a,!0,!0),e.restore()}function uu(e,t){let n=[...t.effects].sort((o,r)=>(o.priority??Ie.ambient)-(r.priority??Ie.ambient));for(let o of n){let r=Math.max(0,o.life/o.maxLife);e.save(),e.globalAlpha=r,o.type==="meat"?(e.fillStyle=b.green,X(e,o.x-o.size/2,o.y-o.size/2,o.size*1.5,o.size,!0,!1)):o.type==="sludge"?(e.fillStyle=b.poop,X(e,o.x-o.size/2,o.y-o.size/2,o.size*1.4,o.size,!0,!1)):o.type==="spawn"?(e.strokeStyle=b.green,e.lineWidth=3,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*20,0,Math.PI*2),e.stroke()):o.type==="spark"?(e.fillStyle=o.color||b.danger,X(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!0,!1)):o.type==="smoke"?(e.fillStyle="rgba(16,32,21,.24)",e.beginPath(),e.arc(o.x,o.y,o.size*(1.2-r*.2),0,Math.PI*2),e.fill()):o.type==="shockwave"?(e.strokeStyle=o.color||b.danger,e.lineWidth=4,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*(o.maxSize||44),0,Math.PI*2),e.stroke()):o.type==="scannerPulse"?(e.strokeStyle=o.color||b.green,e.lineWidth=5,e.setLineDash([8,6]),e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*38,0,Math.PI*2),e.stroke()):o.type==="shred"?(e.fillStyle=o.color||b.ink,e.save(),e.translate(o.x,o.y),e.rotate(o.rot||0),X(e,-o.w/2,-o.h/2,o.w,o.h,!0,!1),e.restore()):o.type==="load"?(e.strokeStyle=o.color||b.green,e.lineWidth=3,e.beginPath(),e.moveTo(o.x-14,o.y),e.lineTo(o.x+14,o.y),e.moveTo(o.x,o.y-14),e.lineTo(o.x,o.y+14),e.stroke()):o.type==="erase"?(e.strokeStyle=b.ink,e.lineWidth=3,e.setLineDash([4,4]),X(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!1,!0)):o.type==="rage"?(e.fillStyle=o.color||b.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText("!",o.x,o.y)):o.type==="flyingChick"&&(o.sex==="poop"?Xr(e,o.x,o.y,o.radius||11):jr(e,o.x,o.y,o.sex,o.sex==="male")),e.restore()}}function du(e,t){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let n of t.floatingTexts){let o=Math.max(0,n.life/n.maxLife);e.globalAlpha=o,e.lineWidth=5,e.strokeStyle=b.white,e.fillStyle=n.color,e.strokeText(n.text,n.x,n.y),e.fillText(n.text,n.x,n.y)}e.restore()}function fu(e,t){let n=t.repairmen&&t.repairmen.length?t.repairmen:t.repairman?[t.repairman]:[];for(let o of n)pu(e,t,o)}function pu(e,t,n){if(!!!n?.active)return;if(e.save(),Qt(e,Pe.repairman,n.x-18,n.y-18,36,36)){n.target?.label&&Hr(e,n.x,n.y-24,n.target.label,b.green),e.restore();return}e.lineWidth=3,e.fillStyle="#fff0d1",e.strokeStyle=b.ink,e.beginPath(),e.arc(n.x,n.y,17,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle="#ffd6e7",e.beginPath(),e.arc(n.x-6,n.y-2,3.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+6,n.y-2,3.2,0,Math.PI*2),e.fill();let r=!!t.cardEffects?.laborExploitation;e.fillStyle=r?b.danger:b.ink,e.beginPath(),e.arc(n.x-5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.strokeStyle=b.ink,e.lineWidth=r?3:2,e.beginPath(),e.arc(n.x,n.y+(r?0:1),r?8:7,.1*Math.PI,.9*Math.PI),e.stroke(),e.fillStyle=b.green,X(e,n.x-9,n.y+14,18,8,!0,!0),e.strokeStyle=b.ink,e.lineWidth=3,e.beginPath(),e.moveTo(n.x-11,n.y+18),e.lineTo(n.x-20,n.y+24),e.stroke(),e.beginPath(),e.moveTo(n.x+11,n.y+18),e.lineTo(n.x+20,n.y+24),e.stroke(),e.fillStyle=b.ink,e.font="900 11px ui-monospace, monospace",e.textAlign="center",e.fillText("FIX",n.x,n.y+33),n.target?.label&&Hr(e,n.x,n.y-24,n.target.label,b.green),e.restore()}function yu(e,t,n){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="left",e.fillStyle=b.ink,e.font="900 19px ui-monospace, monospace",e.fillStyle=b.ink;let o=[];t.phase==="running"&&o.push(t.timeLeft<=0?"TIME UP: FARMS SHUT. CLEAR LINE.":"A/D: S1 \u2190/\u2192: S2"),t.phase==="build"&&o.push(`BUILD: ${t.buildTool||"SELECT"} | connect 1 EGG route to any exit`);let r=76;for(let i of o)e.strokeStyle=b.white,e.lineWidth=4,e.strokeText(i,24,r),e.fillText(i,24,r),r+=20;e.restore()}function fa({game:e,canvasPoint:t,updatePanels:n,equipmentAtPoint:o,fail:r,pointInGrid:i,rectOfFacility:a,rectsOverlap:c}){function h(T){return T?T.type==="conveyor"?`conveyor:${T.id||T.oldKey}`:T.type==="facility"?`facility:${T.id||T.ref?.id}`:T.type==="maintenanceRoom"?`maintenanceRoom:${T.id||T.ref?.id}`:`${T.type}:${T.id||T.ref?.id}`:""}function g(T){return T?T.type==="conveyor"?{type:"conveyor",id:T.oldKey}:{type:T.type,id:T.ref.id}:null}function C(T){let M=h(g(T));return(e.multiSelected||[]).some(q=>h(q)===M)}function P(T){return T?T.type==="eggFarm"?e.eggFarms.find(M=>M.id===T.id)||null:T.type==="scanner"?e.scanners.find(M=>M.id===T.id)||null:T.type==="facility"?e.facilities[T.id]||null:T.type==="maintenanceRoom"?(e.maintenanceRooms||[]).find(M=>M.id===T.id)||null:T.type==="conveyor"&&e.conveyorTiles.has(T.id)?{type:"conveyor",id:T.id}:null:null}function L(){let T=[];for(let M of e.conveyorTiles){let q=re(M),ne=$(q.col,q.row);T.push({type:"conveyor",id:M,center:ne,cell:q})}for(let M of e.eggFarms)T.push({type:"eggFarm",id:M.id,ref:M,center:$(M.col,M.row),cell:{col:M.col,row:M.row}});for(let M of e.scanners)T.push({type:"scanner",id:M.id,ref:M,center:ge(M),cell:{col:M.col,row:M.row}});for(let M of e.maintenanceRooms||[]){let q=$(M.col,M.row);T.push({type:"maintenanceRoom",id:M.id,ref:M,center:{x:q.x+f.cell/2,y:q.y+f.cell/2},cell:{col:M.col,row:M.row}})}for(let M of Object.values(e.facilities)){let q={x:M.x+M.w/2,y:M.y+M.h/2},ne=M.entry?$(M.entry.col,M.entry.row):q;T.push({type:"facility",id:M.id,ref:M,center:q,portCenter:ne})}return T}function K(T,M){let q=Math.min(M.x1,M.x2),ne=Math.max(M.x1,M.x2),oe=Math.min(M.y1,M.y2),se=Math.max(M.y1,M.y2);return T.x>=q&&T.x<=ne&&T.y>=oe&&T.y<=se}function j(T){let M=[];for(let q of L())(K(q.center,T)||q.portCenter&&K(q.portCenter,T))&&M.push({type:q.type,id:q.id});return e.multiSelected=M,e.selected=M[0]||null,n(),M.length}function Z(){e.multiSelected=[],e.selected=null,n()}function Q(T){let M=t(T);return e.selectionBox={x1:M.x,y1:M.y,x2:M.x,y2:M.y},e.multiSelected=[],e.selected=null,n(),!0}function ke(T){if(!e.selectionBox)return;let M=t(T);e.selectionBox.x2=M.x,e.selectionBox.y2=M.y}function pe(){if(!e.selectionBox)return 0;let T=e.selectionBox,M=Math.abs(T.x2-T.x1),q=Math.abs(T.y2-T.y1);return e.selectionBox=null,M<6&&q<6?(Z(),0):j(T)}function le(T){let M=g(T);return M?(e.multiSelected||[]).length&&C(T)?[...e.multiSelected]:[M]:[]}function ue(T){let M=P(T);if(!M)return null;if(T.type==="conveyor"){let q=re(T.id);return{...T,obj:M,oldKey:T.id,currentKey:T.id,meta:e.conveyorMeta.get(T.id)||{price:He("conveyor"),builtSession:null},col:q.col,row:q.row}}return T.type==="eggFarm"||T.type==="scanner"||T.type==="maintenanceRoom"?{...T,obj:M,col:M.col,row:M.row}:T.type==="facility"?M.gridPlaced?{...T,obj:M,gridPlaced:!0,col:M.col,row:M.row,x:M.x,y:M.y,w:M.w,h:M.h,entry:M.entry?{...M.entry}:null,side:M.side,center:{x:M.x+M.w/2,y:M.y+M.h/2}}:{...T,obj:M,gridPlaced:!1,x:M.x,y:M.y,w:M.w,h:M.h,entry:M.entry?{...M.entry}:null,side:M.side,center:{x:M.x+M.w/2,y:M.y+M.h/2}}:null}function D(T){let M=t(T),q=o(M);if(!q)return!1;let ne=le(q),oe=ne.map(ue).filter(Boolean);return oe.length?(e.groupDrag={start:M,selections:ne,origins:oe,historySnapshot:On(e),committed:!1,lastDCol:0,lastDRow:0},e.multiSelected=ne,e.selected=ne[0]||null,n(),!0):!1}function U(){!e.groupDrag||e.groupDrag.committed||(e.undoStack.push(e.groupDrag.historySnapshot),e.redoStack=[],e.groupDrag.committed=!0)}function ee(T,M,q){let ne=I(T,M),oe=it(e,T,M);if(oe&&!q.has(`eggFarm:${oe.id}`))return!0;let se=st(e,T,M);if(se&&!q.has(`scanner:${se.id}`))return!0;let Se=(e.maintenanceRooms||[]).find(Ce=>jt(Ce).some(B=>B.col===T&&B.row===M));if(Se&&!q.has(`maintenanceRoom:${Se.id}`))return!0;let be=pt(e,T,M);return!!(be&&!q.has(`facility:${be.id}`)||e.conveyorTiles.has(ne)&&!q.has(`conveyor:${ne}`))}function O(T,M,q){for(let ne of Object.values(e.facilities||{})){if(q.has(`facility:${ne.id}`))continue;let oe=nt(e,ne),se=Xe(e,ne);if(oe&&oe.col===T&&oe.row===M||se&&se.col===T&&se.row===M)return!0}return!1}function G(T,M,q,ne){let oe=it(e,M,q);if(oe&&!ne.has(`eggFarm:${oe.id}`))return!0;let se=st(e,M,q);if(se&&!ne.has(`scanner:${se.id}`))return!0;let Se=(e.maintenanceRooms||[]).find(Ce=>jt(Ce).some(B=>B.col===M&&B.row===q));if(Se&&!ne.has(`maintenanceRoom:${Se.id}`))return!0;let be=pt(e,M,q);if(be&&be.id!==T.id&&!ne.has(`facility:${be.id}`))return!0;for(let Ce of Object.values(e.facilities||{})){if(Ce.id===T.id||ne.has(`facility:${Ce.id}`))continue;let B=nt(e,Ce),ye=Xe(e,Ce);if(B&&B.col===M&&B.row===q||ye&&ye.col===M&&ye.row===q)return!0}return!1}function Y(T,M,q){let ne=[];for(let oe of e.groupDrag.origins){if(oe.type!=="facility"||oe.gridPlaced)continue;let se={x:oe.center.x+T,y:oe.center.y+M},{entry:Se,side:be}=Eo(se,e);if(!i(Se.col,Se.row)||e.blockedCells?.has?.(I(Se.col,Se.row)))return!0;let Ce={...oe.obj,entry:{...Se},side:be};Ao(Ce,Se,be),ne.push({id:oe.id,rect:a(Ce)})}for(let oe of ne)for(let se of Object.values(e.facilities))if(!q.has(`facility:${se.id}`)&&c(oe.rect,a(se),12))return!0;for(let oe=0;oeI(q.col,q.row)));for(let q of["left","right"]){let ne=Fe(T,q),oe=I(ne.col,ne.row);if(!e.conveyorTiles.has(oe))continue;let se=e.conveyorMeta.get(oe);if(!se)continue;let Se=fe.find(B=>B.name===q),be=fe.filter(B=>{let ye=I(ne.col+B.dc,ne.row+B.dr);return e.conveyorTiles.has(ye)&&!M.has(ye)}),Ce=be.find(B=>B.name===Se?.name)||be[0]||Se;Ce&&(se.dir=Ce.name,se.outDirs=[Ce.name],se.branchMode="random")}}function De(T){if(!e.groupDrag)return;let M=t(T),q=M.x-e.groupDrag.start.x,ne=M.y-e.groupDrag.start.y;if(Math.hypot(q,ne)<3)return;let oe=Math.round(q/f.cell),se=Math.round(ne/f.cell),Se=new Set(e.groupDrag.selections.map(h)),be=new Set;for(let B of e.groupDrag.origins){if(B.type==="facility"&&!B.gridPlaced)continue;let ye=B.col+oe,Be=B.row+se,de=B.type==="scanner"?ft({col:ye,row:Be}):B.type==="maintenanceRoom"?jt({col:ye,row:Be}):B.type==="facility"?Ro({...B.obj,col:ye,row:Be}):[{col:ye,row:Be}];for(let Oe of de){if(!i(Oe.col,Oe.row))return r("Selection outside grid");if(e.blockedCells?.has?.(I(Oe.col,Oe.row)))return r("Selection hits blocked ground");let ct=I(Oe.col,Oe.row);if(be.has(ct))return r("Selection overlap");if(ee(Oe.col,Oe.row,Se))return r("Cell occupied");if(B.type!=="conveyor"&&O(Oe.col,Oe.row,Se))return r("Machine port must remain open");be.add(ct)}if(B.type==="facility"&&B.gridPlaced){let Oe={...B.obj,col:ye,row:Be},ct={col:ye-1,row:Be+Math.floor((Oe.hCells||3)/2)},xt={col:ye+(Oe.wCells||3),row:Be+Math.floor((Oe.hCells||3)/2)};for(let Le of[ct,xt]){if(!i(Le.col,Le.row)||e.blockedCells?.has?.(I(Le.col,Le.row)))return r("Machine port outside usable grid");if(G(B.obj,Le.col,Le.row,Se))return r("Machine port is occupied")}}}if(Y(q,ne,Se))return r("Facility overlap");U();let Ce=e.groupDrag.origins.filter(B=>B.type==="conveyor");for(let B of Ce){let ye=B.currentKey||B.oldKey;e.conveyorTiles.delete(ye),e.conveyorMeta.delete(ye)}for(let B of Ce){let ye=I(B.col+oe,B.row+se);e.conveyorTiles.add(ye),e.conveyorMeta.set(ye,B.meta||{price:He("conveyor"),builtSession:null,uses:0}),B.currentKey=ye}for(let B of e.groupDrag.origins)if(B.type==="eggFarm")B.obj.col=B.col+oe,B.obj.row=B.row+se;else if(B.type==="scanner")B.obj.col=B.col+oe,B.obj.row=B.row+se,ie(B.obj);else if(B.type==="maintenanceRoom")B.obj.col=B.col+oe,B.obj.row=B.row+se;else if(B.type==="facility"&&B.gridPlaced)B.obj.col=B.col+oe,B.obj.row=B.row+se,yn(B.obj);else if(B.type==="facility"){let ye={x:B.center.x+q,y:B.center.y+ne},{entry:Be,side:de}=Eo(ye,e);Ao(B.obj,Be,de)}e.groupDrag.selections=e.groupDrag.origins.map(B=>B.type==="conveyor"?{type:"conveyor",id:B.currentKey||B.oldKey}:{type:B.type,id:B.id}),e.multiSelected=[...e.groupDrag.selections],e.selected=e.multiSelected[0]||null,Me(e),n()}function me(){e.groupDrag&&(Me(e),e.groupDrag=null,n())}return{selectionFromHit:g,startSelectionBox:Q,updateSelectionBox:ke,finishSelectionBox:pe,startGroupDrag:D,updateGroupDrag:De,finishGroupDrag:me}}function pa({game:e,ui:t,canvas:n,canvasPoint:o,onUpdatePanels:r}){function i(){r&&r()}let a=null,c=!1,h=null,g=!1,C=["random","up","right","down","left"],P={random:"RND",up:"\u25B2",right:"\u25B6",down:"\u25BC",left:"\u25C0"},L={w:40,h:40,y:0};function K(){return ro(e)}function j(){e.gridCols=f.cols,e.gridRows=f.rows,e.gridOwnedCells=Ti(e)}function Z(s){if(s){f.y-=s*f.cell,f.rows+=s,e.gridChunkOriginY=(e.gridChunkOriginY||0)-Math.floor(s/10),e.ownedCells=io(e.ownedCells,s),e.blockedCells=io(e.blockedCells,s),e.conveyorTiles=io(e.conveyorTiles,s),e.conveyorMeta=Ai(e.conveyorMeta,s);for(let l of e.eggFarms||[])l.row+=s;for(let l of e.scanners||[])l.row+=s;for(let l of Object.values(e.facilities||{}))l.gridPlaced?(l.row+=s,yn(l)):l.entry&&(l.entry.row+=s)}}function Q(s){if(s){f.x-=s*f.cell,f.cols+=s,e.gridChunkOriginX=(e.gridChunkOriginX||0)-Math.floor(s/10),e.ownedCells=so(e.ownedCells,s),e.blockedCells=so(e.blockedCells,s),e.conveyorTiles=so(e.conveyorTiles,s),e.conveyorMeta=Ii(e.conveyorMeta,s);for(let l of e.eggFarms||[])l.col+=s;for(let l of e.scanners||[])l.col+=s;for(let l of e.maintenanceRooms||[])l.col+=s;for(let l of Object.values(e.facilities||{}))l.gridPlaced?(l.col+=s,yn(l)):l.entry&&(l.entry.col+=s)}}function ke(s){e.ownedCells=e.ownedCells||new Set;for(let l of Pi(s))e.ownedCells.add(I(l.col,l.row))}function pe(s){return e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending?null:Ut(e).map(l=>D(l)).find(l=>l&&Ri(l,s))||null}function le(s){let l=dt(s);return{x:l.x,y:l.y,w:l.w,h:l.h}}function ue(s){let l=le(s);return Object.values(e.facilities||{}).some(y=>{let m=y?.baseId||y?.id;return!eo.includes(m)||y.gridPlaced?!1:ie(l,Y(y),0)})}function D(s){if(!s)return null;let l=ue(s);return{...s,disabled:l,disabledReason:l?"Move edge facilities before buying this lot.":""}}function U(s="right"){if(s&&typeof s=="object"&&Number.isFinite(s.chunkX)&&Number.isFinite(s.chunkY))return s;let l=["left","right","up","down"].includes(s)?s:"right";return Ei(e,l)}function ee(s="right"){let l=U(s);if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return{ok:!1,reason:"Cannot expand now."};if(!l)return{ok:!1,reason:"Invalid expansion lot."};if(ue(l)){let qe="Move edge facilities before buying this lot.";return de(qe),{ok:!1,reason:qe}}let y=l.direction||"right",m=K();if(e.cashf.cols&&(f.cols=N.colStart+N.cols),N.rowStart+N.rows>f.rows&&(f.rows=N.rowStart+N.rows),ke(N),$i(e,N.chunkX,N.chunkY),e.gridExpansionPurchases=(e.gridExpansionPurchases||0)+1,e.gridExpansionPurchasesByDirection[y]=(e.gridExpansionPurchasesByDirection[y]||0)+1,j();let _=wi(e.gridExpansionPurchases,{base:V.map.blockedRatio??0,increment:V.map.blockedExpansionIncrement??.0075,max:V.map.blockedRatioMax??.12}),we=ki({seed:`${e.runSeed}:grid-expansion:${N.chunkX},${N.chunkY}:${e.gridExpansionPurchases}`,colStart:N.colStart,colEnd:N.colStart+N.cols,rowStart:N.rowStart,rowEnd:N.rowStart+N.rows,targetRatio:_});for(let qe of we)e.blockedCells.add(qe);Me(e);let Ne=N.cols*N.rows,Ge=dt(N);return H(e,Ge.x+Ge.w/2,Ge.y+Ge.h/2,`${y.toUpperCase()} +${Ne} CELLS -${x(m)}`,b.green),i(),{ok:!0,direction:y,cost:m,addedCells:Ne,blocked:we.size,blockedRatio:_,chunkX:N.chunkX,chunkY:N.chunkY}}function O(s,l){return s>=0&&s=0&&l!l.has(m.id)&&ie(y,Y(m),12))}function me(s,l,y=null){if(!O(s,l))return!1;if(G(s,l))return!0;let m=I(s,l),v=it(e,s,l);if(v&&!(y?.type==="eggFarm"&&y.ref?.id===v.id))return!0;let R=st(e,s,l);if(R&&!(y?.type==="scanner"&&y.ref?.id===R.id))return!0;let N=M(e,s,l);if(N&&!(y?.type==="maintenanceRoom"&&y.ref?.id===N.id))return!0;let _=pt(e,s,l);return!!(_&&!(y?.type==="facility"&&y.ref?.id===_.id)||e.conveyorTiles.has(m)&&!(y?.type==="conveyor"&&y.oldKey===m))}function T(s,l,y=null){return Object.values(e.facilities||{}).find(m=>{if(y?.type==="facility"&&y.ref?.id===m.id)return!1;let v=nt(e,m),R=Xe(e,m);return v&&v.col===s&&v.row===l||R&&R.col===s&&R.row===l})||null}function M(s,l,y){return(s.maintenanceRooms||[]).find(m=>jt(m).some(v=>v.col===l&&v.row===y))||null}function q(s,l,y=null){let m={col:s,row:l};for(let v of jt(m)){if(!O(v.col,v.row)||G(v.col,v.row))return!0;let R=I(v.col,v.row);if(it(e,v.col,v.row)||st(e,v.col,v.row))return!0;let we=M(e,v.col,v.row);if(we&&!(y?.type==="maintenanceRoom"&&y.ref?.id===we.id)||pt(e,v.col,v.row)||T(v.col,v.row,y)||e.conveyorTiles.has(R))return!0}return!1}function ne(s,l,y=null){let m={col:s,row:l};for(let v of ft(m)){if(!O(v.col,v.row)||G(v.col,v.row))return!0;let R=I(v.col,v.row);if(it(e,v.col,v.row))return!0;let _=st(e,v.col,v.row);if(_&&!(y?.type==="scanner"&&y.ref?.id===_.id)||pt(e,v.col,v.row)||T(v.col,v.row,y)||e.conveyorTiles.has(R))return!0}return!1}function oe(s,l,y,m=null){let v={baseId:s,id:s,gridPlaced:!0,col:l,row:y,wCells:s==="sausageMaker"?3:1,hCells:s==="sausageMaker"?3:1};for(let R of Ro(v))if(!O(R.col,R.row)||G(R.col,R.row)||me(R.col,R.row,m)||T(R.col,R.row,m))return!0;if(s==="sausageMaker"){let R={col:l-1,row:y+1},N={col:l+3,row:y+1};if(!O(R.col,R.row)||!O(N.col,N.row)||G(R.col,R.row)||G(N.col,N.row))return!0;for(let _ of[R,N]){let we=pt(e,_.col,_.row);if(we&&we.id!==m?.ref?.id||it(e,_.col,_.row)||st(e,_.col,_.row)||M(e,_.col,_.row)||T(_.col,_.row,m))return!0}}return!1}function se(){return e.selected?e.selected.type==="eggFarm"?e.eggFarms.find(s=>s.id===e.selected.id)||null:e.selected.type==="scanner"?e.scanners.find(s=>s.id===e.selected.id)||null:e.selected.type==="conveyor"?e.conveyorTiles.has(e.selected.id)?{type:"conveyor",id:e.selected.id}:null:e.selected.type==="facility"?e.facilities[e.selected.id]||null:e.selected.type==="maintenanceRoom"&&(e.maintenanceRooms||[]).find(s=>s.id===e.selected.id)||null:null}function Se(s){return s?s.type==="eggFarm"?`${Pt("eggFarm")} #${s.id}`:s.type==="scanner"?`${s.kind==="auto"?Pt("autoScanner"):Pt("manualScanner")} #${s.id}`:s.type==="conveyor"?e.conveyorMeta.get(s.id)?.kind==="boostConveyor"?Pt("boostConveyor"):Pt("conveyor"):s.type==="facility"?s.name:s.type==="maintenanceRoom"?`${Pt("maintenanceRoom")} #${s.id}`:"Equipment":"Equipment"}function be(s){return s?.type==="conveyor"?e.conveyorMeta?.get(s.oldKey||s.ref?.id)?.price||yo(s):yo(s)}function Ce(){return!!e.cardEffects?.usedMachineActive}function B(){return Ce()?{usedMachine:!0,noRefund:!0,durabilityBaseMultiplier:.6}:{usedMachine:!1,noRefund:!1,durabilityBaseMultiplier:1}}function ye(s){let l=B();return Object.assign(s,l),s}function Be(s){let l=s?.ref||s||{};if(s?.type==="eggFarm"||l.type==="eggFarm")return e.eggFarms.length<=1?"Cannot sell the last EGG FARM.":"";if((s?.type==="facility"||l.type==="facility")&&["mixer","trash","truck"].includes(l.baseId||l.id)){let y=l.baseId||l.id;if(Object.values(e.facilities).filter(v=>(v.baseId||v.id)===y).length<=1)return`Cannot sell the last ${l.shortName||l.name||l.id}.`}return""}function de(s){t.buildStatus.textContent=s,H(e,n.width/2-e.view.x,86-e.view.y,s.toUpperCase(),b.danger)}function Oe(s){if(!s)return null;let l=I(s.col,s.row);return e.conveyorMeta.get(l)||null}function ct(s){return s?(Array.isArray(s.outDirs)||(s.outDirs=[]),s.outDirs=[...new Set(s.outDirs.filter(l=>["right","left","down","up"].includes(l)))],C.includes(s.branchMode)||(s.branchMode="random"),s.kind||(s.kind="conveyor"),s.speedMultiplier||(s.speedMultiplier=s.kind==="boostConveyor"?2:1),s.outDirs):[]}function xt(s){return s?fe.filter(l=>e.conveyorTiles.has(I(s.col+l.dc,s.row+l.dr))).map(l=>l.name):[]}function Le(s){return xt(s).length>=3}function qn(s,l){let y=fe.find(_=>_.name===l);if(!s||!y)return!1;let m=I(s.col+y.dc,s.row+y.dr),v=e.conveyorMeta.get(m);if(!v)return!1;let R=y.opposite;return[...new Set([...Array.isArray(v.outDirs)?v.outDirs:[],v.dir].filter(Boolean))].includes(R)}function wn(s,l){let y=xt(s);if(y.length!==1)return null;let m=y[0];return l.includes(m)&&qn(s,m)?m:null}function No(s){if(!e.conveyorTiles.has(s))return[];let l=re(s),y=e.conveyorMeta.get(s),m=ct(y),v=xt(l),R=[...new Set([...m,y?.dir].filter(Boolean))].filter(Ge=>v.includes(Ge)),N=v,_=R.length?R:N,we=wn(l,_),Ne=R.length?R.filter(Ge=>Ge!==we):N.filter(Ge=>Ge!==we);return y&&(y.outDirs=m.filter(Ge=>v.includes(Ge)),y.dir&&!v.includes(y.dir)&&(y.dir=y.outDirs[0]||null),y.branchMode!=="random"&&!v.includes(y.branchMode)&&(y.branchMode="random")),Ne}function Yn(s){if(!e.conveyorTiles.has(s))return[];let l=re(s),y=xt(l);return Le(l)?y:No(s)}function Lt(s){let l=re(s),y=Yn(s);if(y.length<3)return[];let m=e.conveyorMeta.get(s)||{},v=new Set(y.filter(_=>qn(l,_))),R=y.filter(_=>!v.has(_));if(v.size)return R.length>=2?R:[];let N=[...new Set([...Array.isArray(m.outDirs)?m.outDirs:[],m.dir].filter(Boolean))].filter(_=>y.includes(_));return N.length>=2?N:y}function Sn(s,l){let y=ut(s,l);if(!y)return!1;let m=I(s.col,s.row),v=I(l.col,l.row),R=e.conveyorMeta.get(m),N=e.conveyorMeta.get(v);if(!R||!N)return!1;let _=ct(R),we=!_.includes(y)||R.dir!==y||!N.dir;return _.includes(y)||_.push(y),R.dir=y,N.dir||(N.dir=y),we}function Tt(s){if(kn(s).length===0)return Vn(s);let l=_o(s);return l.length<2?Vn(s):(_e(e),zn(l),Me(e),i(),!0)}function Vn(s){if(!s)return!1;let l=I(s.col,s.row),y=e.conveyorMeta.get(l);if(!y||Le(s))return!1;let m=wn(s,fe.map(_=>_.name)),v=fe.map(_=>_.name).filter(_=>_!==m),R=y.dir&&v.includes(y.dir)?y.dir:null,N=v[(Math.max(-1,v.indexOf(R))+1)%v.length];return _e(e),y.dir=N,y.outDirs=[N],y.branchMode="random",Me(e),i(),!0}function kn(s){return s?fe.map(l=>({col:s.col+l.dc,row:s.row+l.dr})).filter(l=>e.conveyorTiles.has(I(l.col,l.row))):[]}function _o(s){if(!s||!e.conveyorTiles.has(I(s.col,s.row))||Le(s))return[];let l=kn(s);if(!l.length||l.length>2)return[];let y=R=>{let N=[],_=new Set([I(s.col,s.row)]),we=s,Ne=R,Ge=0;for(;Ne&&Ge<200;){Ge+=1;let qe=I(Ne.col,Ne.row);if(_.has(qe)||(_.add(qe),N.push(Ne),Le(Ne)))break;let ri=kn(Ne).filter(ii=>!(ii.col===we.col&&ii.row===we.row));if(ri.length!==1)break;we=Ne,Ne=ri[0]}return N},m=l[0]?y(l[0]).reverse():[],v=l[1]?y(l[1]):[];return[...m,s,...v]}function gn(s,l){return!!s&&[...new Set([...Array.isArray(s.outDirs)?s.outDirs:[],s.dir].filter(Boolean))].includes(l)}function zn(s){let l=0,y=0;for(let v=0;vy?[...s].reverse():s;for(let v=0;v=2){let v=m[m.length-2],R=m[m.length-1];if(!Le(R)){let N=e.conveyorMeta.get(I(R.col,R.row)),_=ut(v,R);N&&_&&(N.dir=_,N.outDirs=[_],N.branchMode="random")}}}function Cn(){return V.facilities[e.buildTool==="boostConveyor"?"boostConveyor":"conveyor"]}function Xn(s,l=null){if(!s)return{ok:!1,reason:ce.fail.outOfGrid};let{col:y,row:m}=s,v=I(y,m);if(e.conveyorTiles.has(v))return{ok:!1,exists:!0};if(G(y,m))return{ok:!1,reason:"Cannot build on blocked ground."};if(me(y,m))return{ok:!1,reason:ce.fail.cellOccupied};let R=Cn(),N=R.id||"conveyor",_=He(N,e);if(e.cash<_)return{ok:!1,reason:ce.fail.notEnoughCash};_e(e),Dt(e,_),e.conveyorTiles.add(v);let we=B();return e.conveyorMeta.set(v,{price:_,builtSession:e.buildSession,uses:0,durability:wo(e,"conveyor",we.durabilityBaseMultiplier),maintenanceType:"conveyor",kind:N,speedMultiplier:R.speedMultiplier||1,dir:l||null,outDirs:[],branchMode:"random",...we}),e.selected={type:"conveyor",id:v},H(e,$(y,m).x,$(y,m).y,`-${x(_)}`,b.ink),{ok:!0,cell:s,key:v}}function Mn(s){if(!s)return de(ce.fail.outOfGrid);let l=I(s.col,s.row),y=e.conveyorTiles.has(l),m=a;if(m&&m.col===s.col&&m.row===s.row)return;if(m&&(g=!0),y){m&&Sn(m,s)&&(c||(_e(e),c=!0),Me(e)),e.selected={type:"conveyor",id:l},a={col:s.col,row:s.row};return}let v=m?ut(m,s):null,R=Xn(s,v);if(!R.ok)return de(R.reason||ce.fail.cellOccupied);m&&Sn(m,s),a={col:s.col,row:s.row},Me(e)}function Zt(s,l){if(!s||!l)return l;let y=l.col-s.col,m=l.row-s.row;return y===0&&m===0?s:Math.abs(y)>=Math.abs(m)?{col:s.col+Math.sign(y),row:s.row}:{col:s.col,row:s.row+Math.sign(m)}}function Go(s){c=!1,h=s?{col:s.col,row:s.row}:null,g=!1,a=null,Mn(s)}function Uo(s){if(!s)return;if(!a)return Mn(s);let l=a,y=0;for(;(l.col!==s.col||l.row!==s.row)&&y<64;){let m=Zt(l,s);if(Mn(m),l=a||m,y+=1,!a)break}}function Nt(){!g&&h&&e.conveyorTiles.has(I(h.col,h.row))&&Tt(h),h=null,g=!1,a=null,c=!1}function jn(s){if(!s)return de(ce.fail.outOfGrid);let{col:l,row:y}=s;if(e.buildTool==="conveyor"||e.buildTool==="boostConveyor"){let m=Xn(s,null);if(!m.ok)return de(m.reason||ce.fail.cellOccupied);Me(e);return}if(G(l,y))return de("Cannot build on blocked ground.");if(T(l,y)&&!["conveyor","boostConveyor"].includes(e.buildTool))return de("Machine port must remain open for a conveyor.");if(e.buildTool==="maintenanceRoom")return q(l,y)?de(ce.fail.cellOccupied):p(l,y);if(to.includes(e.buildTool))return oe(e.buildTool,l,y)?de("3x3 machine or its ports do not fit here."):k(l,y,e.buildTool);if(e.buildTool==="manualScanner"||e.buildTool==="autoScanner"?ne(l,y):me(l,y))return de(ce.fail.cellOccupied);e.buildTool==="eggFarm"?Wo(l,y):e.buildTool==="manualScanner"?d(l,y,"manual"):e.buildTool==="autoScanner"&&d(l,y,"auto")}function xn(s){let l=tt(s.x,s.y);if(["conveyor","boostConveyor","eggFarm","manualScanner","autoScanner","maintenanceRoom",...to].includes(e.buildTool))return jn(l);if(eo.includes(e.buildTool))return S(s,e.buildTool)}function Wo(s,l){let y=He("eggFarm",e);if(e.cashR.kind==="manual").length>=8)return de("Manual Scanner limit reached (8 max).");let m=y==="auto"?He("autoScanner",e):He("manualScanner",e);if(e.cashv.id!==l.ref.id),vt(e,m.x,m.y),Me(e)}if(l.type==="scanner"){let m=ge(l.ref);A(l,m.x,m.y),e.scanners=e.scanners.filter(v=>v.id!==l.ref.id),vt(e,m.x,m.y),Me(e)}if(l.type==="facility"){let m=l.ref;A(l,m.x+m.w/2,m.y+m.h/2),delete e.facilities[m.id],vt(e,m.x+m.w/2,m.y+m.h/2),Me(e)}if(l.type==="maintenanceRoom"){let m=l.ref,v=w(m);A(l,v.x,v.y),e.maintenanceRooms=(e.maintenanceRooms||[]).filter(R=>R.id!==m.id),vt(e,v.x,v.y)}e.selected=null,e.multiSelected=[],i()}function W(s){let l=Object.values(e.facilities).find(_=>{if(s.x>=_.x&&s.x<=_.x+_.w&&s.y>=_.y&&s.y<=_.y+_.h)return!0;if(!_.entry)return!1;let Ne=$(_.entry.col,_.entry.row);return Math.abs(s.x-Ne.x)<=f.cell*.46&&Math.abs(s.y-Ne.y)<=f.cell*.46});if(l)return{type:"facility",ref:l};let y=tt(s.x,s.y);if(!y)return null;let m=it(e,y.col,y.row);if(m)return{type:"eggFarm",ref:m};let v=st(e,y.col,y.row);if(v)return{type:"scanner",ref:v};let R=M(e,y.col,y.row);if(R)return{type:"maintenanceRoom",ref:R};let N=I(y.col,y.row);return e.conveyorTiles.has(N)?{type:"conveyor",oldKey:N,ref:{type:"conveyor",id:N}}:null}let ae=fa({game:e,canvasPoint:o,updatePanels:i,equipmentAtPoint:W,fail:de,pointInGrid:O,rectOfFacility:Y,rectsOverlap:ie});function ve(s){return null}function en(){let s=se();s&&(s.type==="conveyor"?E($(...Object.values(re(s.id)))):s.type==="eggFarm"?E($(s.col,s.row)):s.type==="scanner"?E(ge(s)):s.type==="facility"?E({x:s.x+s.w/2,y:s.y+s.h/2}):s.type==="maintenanceRoom"&&E(w(s)))}function ze(s,l,y="primary-button"){let m=document.createElement("button");return m.type="button",m.className=y,m.textContent=s,m.addEventListener("click",l),m}function _t(){e.cardTargetPick?.mode==="autoScannerMenu"&&(e.cardTargetPick=null),t.modal.classList.remove("visible","equipment-popover"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function Tn(s){t.modalTitle.textContent="Auto Scanner",e.cardTargetPick={pending:!0,mode:"autoScannerMenu",cardId:null,targetKeys:[`scanner:${s.id}`],remaining:1},t.modalBody.innerHTML=` +
+

Left / right output routing for this AUTO scanner.

+

Current: ${s.role===0?"Male left / others right":"Poop left / others right"}

+

Cooldown: ${St(s).toFixed(1)}s.

+
`,t.modalActions.innerHTML="";let l=ze("Male Left / Others Right",()=>{_e(e),s.role=0,_t(),i()},s.role===0?"facility-action warn":"facility-action"),y=ze("Poop Left / Others Right",()=>{_e(e),s.role=1,_t(),i()},s.role===1?"facility-action warn":"facility-action");t.modalActions.append(l,y,ze("Close",_t,"facility-action")),Ho(s),t.modal.classList.add("visible","equipment-popover"),i()}function Jr(s){return s?.label||s?.key||"?"}function $a(s){let l=s.key===" "?"Space":s.key.length===1?s.key.toUpperCase():s.key.replace(/^Arrow/,"");return{key:s.key.toLowerCase(),code:s.code,label:l}}function Fa(s,l,y){for(let m of e.scanners.filter(v=>v.kind==="manual"))for(let v of["left","right"]){if(m.id===s.id&&v===l)continue;let R=m.keys?.[v];if(R&&(R.code===y.code||R.key===y.key))return!0}return!1}function En(s,l=""){if(!s||s.kind!=="manual")return;t.modalTitle.textContent=`Manual Scanner #${s.id}`;let y=Jr(s.keys?.left),m=Jr(s.keys?.right),v=Da(s);t.modalBody.innerHTML=` +
+

Left route key: ${y}

+

Right route key: ${m}

+ ${l?`

${l}

`:""} + ${v?`

${v}

`:""} +
`,t.modalActions.innerHTML="",t.modalActions.appendChild(ze("Set Left Key",()=>Zr(s,"left"),"facility-action warn")),t.modalActions.appendChild(ze("Set Right Key",()=>Zr(s,"right"),"facility-action warn")),t.modalActions.appendChild(ze("Close",_t,"facility-action")),Ho(s),t.modal.classList.add("visible","equipment-popover")}function Da(s){let l=[{side:"left",binding:s.keys?.left},{side:"right",binding:s.keys?.right}];if(l[0].binding&&l[1].binding&&(l[0].binding.code===l[1].binding.code||l[0].binding.key===l[1].binding.key))return"Left and right keys conflict.";for(let y of l)if(y.binding)for(let m of e.scanners.filter(v=>v.kind==="manual"&&v.id!==s.id)){if(m.keys?.left&&(m.keys.left.code===y.binding.code||m.keys.left.key===y.binding.key))return`Key conflicts with Manual Scanner #${m.id} left.`;if(m.keys?.right&&(m.keys.right.code===y.binding.code||m.keys.right.key===y.binding.key))return`Key conflicts with Manual Scanner #${m.id} right.`}return""}function Zr(s,l){t.modalBody.innerHTML=`

Press a key for ${l.toUpperCase()} route.

Esc cancels.

`,t.modalActions.innerHTML="";let y=m=>{if(m.preventDefault(),m.stopPropagation(),window.removeEventListener("keydown",y,!0),m.key==="Escape")return En(s);let v=$a(m),R=Fa(s,l,v);_e(e),s.keys=s.keys||{left:null,right:null},s.keys[l]=v,i(),En(s,R?`${v.label} assigned, but another scanner already uses it.`:`${l.toUpperCase()} set to ${v.label}.`)};window.addEventListener("keydown",y,!0)}function Ba(){let s=se();if(!(!s||s.type!=="scanner"))return s.kind==="auto"?Tn(s):En(s)}function Oa(s){if(!s)return{x:80,y:80};if(s.type==="conveyor"){let l=re(s.id);return $(l.col,l.row)}return s.type==="eggFarm"?$(s.col,s.row):s.type==="scanner"?ge(s):s.type==="facility"?{x:s.x+s.w/2,y:s.y+10}:{x:80,y:80}}function Ho(s){let l=n.getBoundingClientRect(),y=Oa(s),m=e.view?.scale||1,v=l.left+(y.x*m+(e.view?.x||0))/n.width*l.width+18,R=l.top+(y.y*m+(e.view?.y||0))/n.height*l.height-12,N=Math.max(12,window.innerWidth-274),_=Math.max(12,window.innerHeight-220);t.modal.style.setProperty("--popover-x",`${Math.max(12,Math.min(N,v))}px`),t.modal.style.setProperty("--popover-y",`${Math.max(12,Math.min(_,R))}px`)}function ei(){let s=se();if(!s)return;let l=oi(s);if(t.modalTitle.textContent=Se(s),t.modalBody.innerHTML=` +
${l.map(v=>`

${v}

`).join("")}
+ ${["mixer","truck"].includes(s.baseId||s.id)?'

Income/Fine = ceil(base x 1.10^upgrades)

':""}`,t.modalActions.innerHTML="",s.type==="scanner"&&s.kind==="auto"&&t.modalActions.appendChild(ze("Auto Menu",()=>Tn(s),"facility-action warn")),s.type==="scanner"&&s.kind==="manual"&&t.modalActions.appendChild(ze("Set Keys",()=>En(s),"facility-action warn")),s.type==="conveyor"&&Ko(s.id)&&Lt(s.id).length>=2){let v=e.conveyorMeta.get(s.id)?.branchMode||"random";t.modalActions.appendChild(ze(`Branch: ${ti(v)}`,()=>{qo(s.id),e.selected={type:"conveyor",id:s.id},ei()},"facility-action warn branch-action"))}let y=s.type==="conveyor"?{type:"conveyor",oldKey:s.id,ref:s}:{type:s.type,ref:s},m=Be(y);if(m){let v=ze(m,()=>{},"facility-action danger disabled");v.disabled=!0,t.modalActions.appendChild(v)}else{let v=$t(y,e),R=v.sameBuild?`Remove / Refund ${x(v.amount)}`:`Sell ${x(v.amount)}`;t.modalActions.appendChild(ze(R,()=>{en(),_t()},"facility-action danger"))}Ho(s),t.modal.classList.add("visible","equipment-popover")}function La(s){e.phase==="build"&&(Nt(),e.buildTool=e.buildTool===s?null:s,e.selected=null,e.multiSelected=[],e.selectionBox=null,i())}function Na(){let s=[];for(let[l,y]of Object.entries(e.facilities))if(s.push({id:`facility:${l}`,price:be({type:"facility",ref:y}),x:y.x,y:y.y,w:y.w,h:y.h}),y.entry){let m=$(y.entry.col,y.entry.row);s.push({id:`facilityPort:${l}`,price:be({type:"facility",ref:y}),x:m.x-18,y:m.y-18,w:36,h:36})}for(let l of e.maintenanceRooms||[]){let y=w(l);s.push({id:`maintenanceRoom:${l.id}`,price:be({type:"maintenanceRoom",ref:l}),x:y.x-f.cell,y:y.y-f.cell,w:f.cell*2,h:f.cell*2})}for(let l of e.eggFarms){let y=$(l.col,l.row);s.push({id:`eggFarm:${l.id}`,price:be({type:"eggFarm",ref:l}),x:y.x-24,y:y.y-24,w:48,h:48})}for(let l of e.scanners){let y=ge(l);s.push({id:`scanner:${l.id}`,price:be({type:"scanner",ref:l}),x:y.x-50,y:y.y-73,w:100,h:146})}for(let l of e.conveyorTiles){let y=re(l),m=$(y.col,y.row),v=e.conveyorMeta.get(l)||{};s.push({id:`conveyor:${l}`,price:v.price||He(v.kind==="boostConveyor"?"boostConveyor":"conveyor",e),x:m.x-22,y:m.y-22,w:44,h:44})}return s}function ti(s){return P[s]||P.random}function Vu(s){return Yn(s)}function Ko(s){return e.conveyorTiles.has(s)?Le(re(s)):!1}function ni(s){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return null;for(let l of e.conveyorTiles){if(!Ko(l)||Lt(l).length<2)continue;let y=re(l),m=$(y.col,y.row),v=m.x-L.w/2,R=m.y+L.y-L.h/2;if(s.x>=v&&s.x<=v+L.w&&s.y>=R&&s.y<=R+L.h)return l}return null}function _a(s){let l=ni(s);return l?qo(l):!1}function qo(s){let l=e.conveyorMeta.get(s);if(!l)return!1;let y=Lt(s);if(y.length<2)return!1;_e(e);let m=C.includes(l.branchMode)?l.branchMode:"random",v=["random",...fe.map(R=>R.name).filter(R=>y.includes(R))];return l.branchMode=v[(Math.max(0,v.indexOf(m))+1)%v.length],Me(e),e.selected=null,e.multiSelected=[],i(),!0}function oi(s){Re(e);let l=[],y=s?.type==="facility"?s.baseId||s.id:"";if(s.type==="eggFarm"){let[m,v]=$n(s);l.push(`Price: ${x(be(s))}`);{let R=Be({type:s.type,ref:s});l.push(R?`Sale: blocked (${R})`:`Sale value: ${x($t({type:s.type,ref:s},e).amount)}`)}l.push(`Level: ${s.level}/4`),l.push(`Random interval: ${m.toFixed(2)}-${v.toFixed(2)}s`),l.push(`Durability: ${Nn(s)}% | Spawn delay x${go(s).toFixed(2)}`)}else if(s.type==="scanner")l.push(`Price: ${x(be(s))}`),l.push(`Sale value: ${x($t({type:s.type,ref:s},e).amount)}`),l.push(`Type: ${s.kind.toUpperCase()} / Standard`),s.kind==="auto"&&l.push(`Role: ${s.role===0?"Male left / Others right":"Poop left / Others right"}`),l.push(`Queue: ${s.queue.length}`),s.kind==="auto"&&l.push(`Cooldown: ${s.cooldown.toFixed(1)}s / ${St(s,e).toFixed(1)}s`),s.kind==="auto"&&l.push(`Durability: ${Nn(s)}% | Delay x${ko(s).toFixed(2)}`),s.kind==="manual"&&l.push("Durability: none | Always normal");else if(s.type==="conveyor"){let m=e.conveyorMeta.get(s.id),v=e.componentLookup?.get(s.id),R=v?e.congestion.get(v):null;l.push(`Price: ${x(be({type:"conveyor",oldKey:s.id,ref:s}))}`),l.push(`Cell: ${s.id}`),l.push(`Type: ${m?.kind==="boostConveyor"?"BOOST BELT":"Normal Belt"} | Speed x${Number(m?.speedMultiplier||1).toFixed(1)}`),l.push(`Congestion: ${R?Math.floor(R.ratio*100):0}%`),l.push(`Durability: ${Nn({meta:m})}% | Speed x${So({meta:m}).toFixed(2)}`),Ko(s.id)?Lt(s.id).length>=2?(l.push(`Branch mode: ${ti(m?.branchMode||"random")}`),l.push("Click the Branch button or the on-belt triangle to cycle RANDOM / fixed exit.")):l.push("Branch mode: unavailable \u2014 fewer than two outgoing conveyors."):l.push("Branch mode: needs 3+ conveyor connections."),l.push(`Sale value: ${x($t({type:"conveyor",oldKey:s.id,ref:s},e).amount)}`)}else if(s.type==="maintenanceRoom")l.push(`Price: ${x(be({type:"maintenanceRoom",ref:s}))}`),l.push(`Sale value: ${x($t({type:"maintenanceRoom",ref:s},e).amount)}`),l.push("Size: 2\xD72 grid cells"),l.push("Dispatch: 1 repairman during each production day");else if(s.type==="facility"){l.push(`Price: ${x(be(s))}`);{let m=Be({type:s.type,ref:s});l.push(m?`Sale: blocked (${m})`:`Sale value: ${x($t({type:s.type,ref:s},e).amount)}`)}if(l.push(["mixer","truck","trash","sausageMaker"].includes(y)?`Level: ${s.level} / no cap`:`Level: ${s.level}`),y==="truck"&&l.push("Durability: none | Always normal"),["mixer","trash","sausageMaker"].includes(y)&&l.push(`Durability: ${Nn(s)}% | Extra delay ${Fr(e,s).toFixed(2)}s`),y==="mixer"){l.push(`Output: 1 meat per non-poop chick | meat buffer ${s.meatBuffer||0}`),l.push(`Meat quality: x${yt(e,"mixer").toFixed(3)} to sausage value`);let m=Xe(e,s);l.push(`OUT: ${m?`${m.col},${m.row}`:"none"} | conveyor ${It(e,s)?"connected":"missing"}`),l.push(`Fallback sale: ${x(xe.income.mixer)} when OUT is missing or blocked`),l.push(`Poop fine: -${x(Dn(e))}`)}if(y==="truck"&&(l.push(`Income: ${x(Ve(e))} per target cargo | upgrade x${yt(e,"truck").toFixed(3)}`),l.push(`Poop shipment fine: -${x(Bn(e))}`)),y==="trash"){let m=mt(e),v=ht(m),R=qt(m);l.push(`Bonus cards: ${m}/${cn()}`),l.push(`Expected poop bonus: ${x(v)} | hit chance ${Math.round(R*100)}%`),l.push("Winning payouts roll 1x / 2x / 4x / 10x, with jackpot odds rising per card."),l.push("With enough upgrades, poop can out-earn male/female routes.")}if(y==="sausageMaker"){let m=nt(e,s),v=Xe(e,s);l.push("Size: 3\xD73 grid cells | IN left / OUT right"),l.push(`Recipe: 2 meat -> 1 sausage | meat buffer ${s.meatBuffer||0} | sausage buffer ${s.sausageBuffer||0}`),l.push(`Sausage sale value: ${x(Ze(e))}`),l.push(`IN: ${m?`${m.col},${m.row}`:"none"} | OUT: ${v?`${v.col},${v.row}`:"none"} | conveyor ${It(e,s)?"connected":"missing"}`)}s.entry&&l.push(`Receiver: edge cell ${s.entry.col},${s.entry.row} (${s.side})`)}return l}function Ga(s){if(!s||e.phase!=="build")return"";let l=an(e).find(y=>y.type===s.type&&y.id===s.id);return l?l.message||"Not connected to conveyor route":""}function Ua(s){return s?s.type==="conveyor"&&e.conveyorMeta.get(s.id)?.kind==="boostConveyor"?"Moves chicks twice as fast. Wears down like a normal belt.":s.type==="conveyor"?"A stubborn belt tile. It only cares about the next cell.":s.type==="eggFarm"?"A tiny gatehouse producing questionable eggs on schedule.":s.type==="scanner"&&s.kind==="auto"?"A compact 2\xD72 scanner sized for roughly 2.1 level-1 farms.":s.type==="scanner"?"A manual checkpoint. The operator is the algorithm.":s.type==="facility"&&(s.baseId||s.id)==="mixer"?"Chicks become meat when OUT is clear; a blocked OUT falls back to direct sale.":s.type==="facility"&&(s.baseId||s.id)==="trash"?"Poop goes in. Sometimes coins come out, for reasons best left unaudited.":s.type==="facility"&&(s.baseId||s.id)==="truck"?"The shipping endpoint. Correct cargo and sausages pay; wrong cargo complains.":s.type==="facility"&&(s.baseId||s.id)==="sausageMaker"?"A 3\xD73 in-grid machine with one meat inlet on the left and one sausage outlet on the right.":s.type==="maintenanceRoom"?"A cramped 2\xD72 storage and break room with lockers, spare parts, a bench and one dispatched repairman.":"Factory equipment.":""}return{buildAtCell:jn,buildAtPoint:xn,eraseAtPoint:E,equipmentAtPoint:W,startSelectionBox:ae.startSelectionBox,updateSelectionBox:ae.updateSelectionBox,finishSelectionBox:ae.finishSelectionBox,startGroupDrag:ae.startGroupDrag,updateGroupDrag:ae.updateGroupDrag,finishGroupDrag:ae.finishGroupDrag,selectedObject:se,selectedTitle:Se,equipmentPrice:be,selectedUpgradeCost:ve,selectedInfoLines:oi,flavorText:Ua,disconnectedWarningFor:Ga,gridExpansionCost:K,buyGridExpansion:ee,expansionOfferAtPoint:pe,beginConveyorDrag:Go,continueConveyorDrag:Uo,endConveyorDrag:Nt,cycleSingleConveyorDirection:Tt,branchSwitcherAtPoint:ni,cycleBranchModeAtPoint:_a,cycleBranchModeForKey:qo,branchSelectableExitDirsForKey:Lt,removeSelected:en,switchScannerRole:Ba,showManualScannerMenu:En,showAutoScannerMenu:Tn,showSelectedMenu:ei,setBuildTool:La,fail:de,isEquipmentCell:me,equipmentHitBoxes:Na,routeFromFarmToScanner:Kt}}function ya({game:e,ui:t,build:n,startGame:o,beginCardDraft:r,activeQueuedChick:i}){function a(O){return String(O).replace(/[&<>"']/g,G=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[G])}function c(){return Math.round(pn(e))}function h(){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return!1;let O=!1;for(let G of Qo)if(O=!0,e.cash>=He(G,e))return!1;return O}function g(){C(),P(),K(),L()}function C(){for(let[G,Y]of Object.entries(t.buttons))Y?.classList?.contains("tool-button")&&Y.classList.toggle("active",e.buildTool===G);for(let G of Qo){let Y=t.buttons[G];if(!Y)continue;let ie=He(G,e),De=Y.querySelector("span");De&&(De.textContent=G==="conveyor"||G==="boostConveyor"?`${x(ie)} / tile`:x(ie));let me=G==="manualScanner"&&e.scanners.filter(M=>M.kind==="manual").length>=8,T=e.cashKt(e,Y)?.scannerId).length,G=fo(e);t.turnSummary.innerHTML=[`Seed: ${a(e.runSeed||"none")} | Grid box: ${e.gridRows||10}x${e.gridCols||20} | Owned: ${e.gridOwnedCells||e.ownedCells?.size||(e.gridRows||10)*(e.gridCols||20)} cells | Blocked: ${e.blockedCells?.size||0} cells`,`Penalties: wrong shipment -${x(kr(e))} | Mixer poop -${x(Dn(e))} | Shipment poop -${x(Bn(e))}`,`Maintenance: worst ${Br(e).worst.percent}% dirty (${Br(e).worst.label}) | Rooms: ${(e.maintenanceRooms||[]).length} | Repairmen: ${(e.repairmen||[]).length}`,`Card draft: ${e.cardDraft?.pending?Math.max(1,e.cardDraft.picksRemaining||1)+" pick(s) left":"ready after each day"} | Farms with scanner route: ${O}/${e.eggFarms.length}`,e.cardEffects?.usedMachineActive?'Procurement: USED MACHINE MODE / no refunds / 60% durability':"",G.length?`Blocked: ${G[0]}`:`${ce.status.allPortsConnected}`].filter(Boolean).join("
")}function j(){C(),t.shell.classList.toggle("phase-running",e.phase==="running"),t.shell.classList.toggle("phase-build",e.phase==="build"),t.shell.classList.toggle("phase-gameover",e.phase==="gameover"),t.shell.classList.toggle("phase-title",e.phase==="title"),t.shell.classList.toggle("phase-loanDecision",e.phase==="loanDecision"),t.money.textContent=x(e.cash),t.money.classList.toggle("cash-negative",e.cash<0),t.money.classList.toggle("cash-positive",e.cash>Rn),t.turn.textContent=e.turn,t.timeLeft.textContent=e.phase==="running"&&e.timeLeft<=0&&e.shutdownTimeLeft>0?`+${e.shutdownTimeLeft.toFixed(1)}s`:`${Math.max(0,e.timeLeft).toFixed(1)}s`,t.timeLeft.closest?.(".hud-card")?.classList.toggle("time-critical",e.phase==="running"&&(e.timeLeft<=10||e.timeLeft<=0&&e.shutdownTimeLeft>0)),t.phase.textContent=Q(),t.comboCount&&(t.comboCount.textContent=e.manualCombo?.count||0),Z(),t.turnProfit.textContent=x(e.stats.profit),t.turnProfit.classList.toggle("cash-negative",e.stats.profit<0),t.turnProfit.classList.toggle("cash-positive",e.stats.profit>0),t.mixerCount.textContent=e.stats.mixerCount,t.truckFemaleCount.textContent=e.stats.truckFemale,t.truckMaleCount.textContent=e.stats.truckMale,t.poopCount.textContent=e.stats.poopSpawned,t.buttons.s1Left.disabled=e.phase!=="running"||!i(0),t.buttons.s1Right.disabled=e.phase!=="running"||!i(0),t.buttons.s2Left.disabled=e.phase!=="running"||!i(1),t.buttons.s2Right.disabled=e.phase!=="running"||!i(1);let O=e.scanners.find(me=>me.kind==="manual"&&me.slot===0),G=e.scanners.find(me=>me.kind==="manual"&&me.slot===1);O&&(t.buttons.s1Left.textContent=`S1 ${O.keys?.left?.label||"A"} -> Mixer`,t.buttons.s1Right.textContent=`S1 ${O.keys?.right?.label||"D"} -> S2`),G&&(t.buttons.s2Left.textContent=`S2 ${G.keys?.left?.label||"Left"} -> Waste`,t.buttons.s2Right.textContent=`S2 ${G.keys?.right?.label||"Right"} -> Truck`);let Y=Math.max(0,Math.floor(e.lastResult?.profit??e.stats?.profit??0)),ie=Cr(e,Math.max(1,Number(e.turn)||1),Y).amount,De=e.phase==="build"&&ie>0?`NEXT DAYFAIRIES -${x(ie)}`:`${ce.actions.nextDay}`;t.buttons.nextTurn.dataset.renderedHtml!==De&&(t.buttons.nextTurn.innerHTML=De,t.buttons.nextTurn.dataset.renderedHtml=De),t.buttons.nextTurn.disabled=e.phase!=="build"||!!e.cardDraft?.pending||!!e.cardTargetPick?.pending}function Z(){if(!t.eventBrief||!t.speedBrief)return;t.speedBrief.textContent=`BELT SPEED: ${c()} px/s`,t.speedBrief.title=`Conveyor speed does not increase by day. Degraded belts reduce speed. Cap: ${tn}px/s.`;let O=e.eventActive,G=e.eventOffer;O?(t.eventBrief.textContent=`ACTIVE EVENT: ${O.title} | ${O.route}`,t.eventBrief.className="event-brief active"):e.phase==="build"&&G?(t.eventBrief.textContent=`NEXT DAY EVENT: ${G.title} | ${G.route}${G.targetAmount?` | Target ${G.targetAmount}`:""}${G.reward?` | Reward ${x(G.reward)}`:""}`,t.eventBrief.className="event-brief next"):e.phase==="build"&&e.turn+1
\u2642Male->Mixer -> MeatS1: A
\u2640Female->TruckS1: D, then S2: right
\u{1F4A9}Poop->ShredderS1: D, then S2: left

Build phase: connect at least one EGG through a scanner to Mixer, Shredder, or Truck before Next Day. One day is one run.

',t.modalActions.innerHTML="",t.modalActions.appendChild(D(ce.actions.startGame,o,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function pe(O){let G=me=>`${me>0?"+":""}${x(me)}`,Y=me=>`${me>0?"-":""}${x(me)}`,ie=O.profit>=0?"cash-positive":"cash-negative",De=(O.mixerPoopFine||0)+(O.truckPoopFine||0)+(O.maleTruckFine||0)+(O.explosionDamage||0)+(O.cardRerollCost||0);t.modalTitle.textContent=`Day ${O.turn} Settlement`,t.modalBody.innerHTML=` +
Net result${x(O.profit)}
+
+
Chick shipment income${G(O.chickShipmentIncome||0)}
+
Poop shipment income${G(O.poopShipmentIncome||0)}
+
Sausage shipment income${G(O.sausageRevenue||0)}
+
Meat / sausages${O.meatProduced||0} meat -> ${O.sausageProduced||0} made / ${O.sausageShipped||0} shipped
+
Composter income${G(O.composterIncome||0)}
+
DUD refund income${G(O.dudRefundIncome||0)}
+
Manual combo bonus${G(O.manualComboBonus||0)}
+
Chemical subsidy${G(O.chemicalWeaponSubsidy||0)}
+
Event bonus${G(O.eventBonus||0)}
+
Penalties${Y(De)}
+
Fairies fee${Y(O.fairiesTribute?.amount||O.fairiesTribute||0)}
+
+

Income ${x(O.revenue)} - losses ${x(O.penalty)} = ${x(O.profit)}

`,t.modalActions.innerHTML="",t.modalActions.appendChild(D("Choose Upgrade Card",r||U,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function le(O,G){let Y=Math.max(0,e.cardEffects?.rescueLoanCharges||0);t.modalTitle.textContent="Emergency Loan Available",t.modalBody.innerHTML=` +

End-of-day cash is below ${x(0)}.

+
+
Current money${x(e.cash)}
+
Emergency Loan+${x(500)}
+
Cards remaining${Y}
+
+

Use one Emergency Loan to gain ${x(500)} immediately. If cash is still negative, another decision will be shown if another card remains.

`,t.modalActions.innerHTML="",t.modalActions.appendChild(D("Accept Game Over",G,"facility-action danger")),t.modalActions.appendChild(D("Use Emergency Loan",O,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function ue(){let O=e.totals.processed,G=O?Math.round(e.totals.correct/O*100):0,Y=ms(e);t.modalTitle.textContent=ce.phases.gameover,t.modalBody.innerHTML=`

Your cash went negative.

+
Final Score${Y.score}
Survival${e.totals.turnsCompleted} days
Final Cash${x(e.cash)}
Accuracy${G}%
+
Score breakdown +
Formula
Base = Cash + Total revenue + Factory value \xD70.5 + Event bonus \xD70.5 = ${x(Y.base)}
Daily earned = ceil(Base \xF7 Days) = ${x(Y.dailyEarned)}
Score = max(0, floor(Base + Daily earned + Correct bonus - Total outflow - Day penalty)) = ${Y.score}
+
Factory Value${x(Y.factoryValue)}
Total Revenue${x(e.totals.revenue)}
Daily Earned${x(Y.dailyEarned)} / day
Total Outflow${x(e.totals.penalty)}
Fairies Tribute${x(e.totals.fairiesTribute||0)}
Correct Sorts${e.totals.correct}
Auto Sorted${e.totals.autoSorted}
Poop Control${e.totals.poopTrash} trashed / ${e.totals.poopTruck} shipped / ${e.totals.poopMixer} mixer
Explosion Penalty${x(e.totals.explosionDamage)}
Event Bonus${x(e.totals.eventBonus)}
Day Penalty-${Y.dayPenalty}
Events${e.totals.eventSuccess} success / ${e.totals.eventFailed} failed
+
`,t.modalActions.innerHTML="",t.modalActions.appendChild(D(ce.actions.restart||"Restart",o,"primary-button restart-button")),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible","gameover-modal")}function D(O,G,Y="primary-button"){let ie=document.createElement("button");return ie.type="button",ie.className=Y,ie.textContent=O,ie.addEventListener("click",G),ie}function U(){t.modal.classList.remove("visible","equipment-popover","gameover-modal"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function ee(){}return{updatePanels:g,updateUI:j,showTitle:ke,showTurnResult:pe,showEmergencyLoanDecision:le,showGameOver:ue,hideModal:U,checkGameOver:ee}}function Qr(e){e.totals.processed+=1}function hn(e){e.stats.correct+=1,e.totals.correct+=1}function rt(e){e.stats.mistakes+=1,e.totals.mistakes+=1}function ha(e){e.stats.autoSorted+=1,e.totals.autoSorted+=1}function ma(e){e.stats.poopSpawned+=1}function ba(e){e.stats.mixerCount+=1,Qr(e)}function va(e){e.stats.trashCount+=1,Qr(e)}function wa(e,t){t==="female"?e.stats.truckFemale+=1:t==="male"&&(e.stats.truckMale+=1),Qr(e)}function Bo(e,t){let n=t==="truck"?"poopTruck":t==="trash"?"poopTrash":t==="mixer"?"poopMixer":null;n&&(e.stats[n]+=1,e.totals[n]+=1)}function Sa({game:e,currentConveyorSpeed:t,onGameOverCheck:n}){function o(){return e.frameCache||(e.frameCache={frameId:-1,routingVersion:-1,chickRevision:0,spatialRevision:-1,spatial:new Map,congestionFrame:-1,componentChicks:new Map,manualMonitorSignature:"",draw:{}}),e.frameCache}function r(){let d=o();d.chickRevision=(d.chickRevision||0)+1,d.congestionFrame=-1}function i(){o().congestionFrame=-1}function a(d){let p=o();p.frameId!==d&&(p.frameId=d,p.spatialRevision=-1,p.congestionFrame=-1)}function c(d,p){return`${Math.floor(d/f.cell)},${Math.floor(p/f.cell)}`}function h(){let d=o();if(d.spatialRevision===d.chickRevision)return d.spatial;let p=new Map;for(let w of e.chicks){if(w.stage==="flying")continue;let k=c(w.x,w.y);p.has(k)||p.set(k,[]),p.get(k).push(w)}return d.spatial=p,d.spatialRevision=d.chickRevision,p}function g(d){let p=h(),w=Math.floor(d.x/f.cell),k=Math.floor(d.y/f.cell),S=[];for(let A=k-1;A<=k+1;A+=1)for(let E=w-1;E<=w+1;E+=1){let W=p.get(`${E},${A}`);W&&S.push(...W)}return S}function C(d){return Wt(d)*go(d)*Hs(e)/Qi(e)}function P(d){let p=$(d.col,d.row),w=1+Ks(e,d),k=K(d,w);if(!k.length)return L(d,p),!0;let S=0,A=0;for(let E of k){let W=$(E.col,E.row),ae=j(W);if(ae){ae.stoppedTimer=.85,A+=1;continue}let ve=na(e,{stage:"belt",scannerId:null,route:[W]});ve.sex==="poop"&&ma(e),e.chicks.push(ve),r(),Rs(e,d),S+=1}return S>0?(vs(e,p.x,p.y),S>1&&H(e,p.x,p.y-28,`x${S}`,b.green),!0):A===0}function L(d,p){(d.noRouteNoticeCooldown||0)<=0&&(H(e,p.x,p.y-24,"NO BELT: PAUSED",b.warn),d.noRouteNoticeCooldown=2.5)}function K(d,p){let k=fe.map(S=>({col:d.col+S.dc,row:d.row+S.dr})).filter(S=>$e(S.col,S.row)&&e.conveyorTiles.has(I(S.col,S.row))).map(S=>({p:S,blocked:le(null,$(S.col,S.row))?1:0,roll:Math.random()}));return k.sort((S,A)=>S.blocked-A.blocked||S.roll-A.roll),k.slice(0,Math.max(1,p||1)).map(S=>S.p)}function j(d){return g(d).find(p=>Math.hypot(p.x-d.x,p.y-d.y)0;if(e.timeLeft=Math.max(0,e.timeLeft-d),k&&e.timeLeft<=0&&p(),e.timeLeft<=0){e.shutdownTimeLeft>0&&(e.shutdownTimeLeft=Math.max(0,e.shutdownTimeLeft-d));for(let S of e.eggFarms)S.shutterProgress=Math.min(1,(S.shutterProgress||0)+d*2.8)}if(k&&e.timeLeft>0){for(let S of e.eggFarms)if(S.noRouteNoticeCooldown>0&&(S.noRouteNoticeCooldown=Math.max(0,S.noRouteNoticeCooldown-d)),S.nextSpawn-=d,S.nextSpawn<=0){let A=P(S);S.nextSpawn=A?C(S):.15,S.lastInterval=S.nextSpawn}}for(let S=e.chicks.length-1;S>=0;S-=1){let A=e.chicks[S];A.bob+=d*7,A.stoppedTimer>0&&(A.stoppedTimer=Math.max(0,A.stoppedTimer-d)),A.stage!=="queued"&&ke(A,S,d)}Oe(d),Nt(e.frameId),jn(),e.timeLeft<=0&&(e.chicks.length===0?w():e.shutdownTimeLeft<=0&&Q())}function Q(){if(e.cleanupBlown)return;e.cleanupBlown=!0,e.cleanupTimer=1;let d=[...e.chicks];for(let p of d)Tr(e,p.sex,p.x,p.y,-Math.PI/2,!0);e.chicks=[];for(let p of e.scanners)p.queue=[];if(r(),Nt(e.frameId),d.length){let p=d.reduce((k,S)=>k+S.x,0)/d.length,w=d.reduce((k,S)=>k+S.y,0)/d.length;at(e,p,w,b.warn,58),H(e,p,w-24,"CLEANUP",b.warn)}}function ke(d,p,w){if(pe(d)){d.stoppedTimer=.35;return}if(B(d,w),!(d.route&&d.targetIndex=d.route.length)return!1;let p=d.route[d.targetIndex];return le(d,p)}function le(d,p){if(!p)return!1;for(let w of g(p))if(!(d&&w.id===d.id)&&Math.hypot(w.x-p.x,w.y-p.y)1)&&d.push({x:p.x,y:p.y})}function D(d){let p=e.conveyorMeta?.get?.(d)||{},w=[];Array.isArray(p.outDirs)&&w.push(...p.outDirs),p.dir&&w.push(p.dir);let k=[...new Set(w)].filter(ve=>fe.some(en=>en.name===ve)),S=re(d),A=fe.filter(ve=>De(S,ve.name,null)).map(ve=>ve.name),E=k.filter(ve=>A.includes(ve)),W=fe.filter(ve=>e.conveyorTiles.has(I(S.col+ve.dc,S.row+ve.dr))).map(ve=>ve.name);if(W.length===1&&(!E.length||E.includes(W[0]))&&me(S,W[0]))return E.filter(ve=>ve!==W[0]);let ae=A;return E.length?E:ae}function U(d){return fe.find(p=>p.name===d)||null}function ee(d,p){return e.scanners.find(w=>w.col<=d&&d<=w.col+1&&w.row-1<=p&&p<=w.row)||null}function O(d,p){let w=U(p);if(!w)return null;let k=ee(d.col+w.dc,d.row+w.dr);if(!k)return null;let S=Fe(k,"inputA");return S&&S.col===d.col&&S.row===d.row?k:null}function G(d){return Object.entries(e.facilities||{}).find(([,p])=>p?.entry&&p.entry.col===d.col&&p.entry.row===d.row)||null}function Y(d){return d?.baseId||d?.id||""}function ie(d,p){return d?.gridPlaced&&Y(d)==="sausageMaker"?p==="right":d.side==="left"&&p==="left"||d.side==="right"&&p==="right"||d.side==="top"&&p==="up"||d.side==="bottom"&&p==="down"}function De(d,p,w=null){let k=U(p);if(!k)return null;let S={col:d.col+k.dc,row:d.row+k.dr};if($e(S.col,S.row)&&e.conveyorTiles.has(I(S.col,S.row)))return{type:"conveyor",dirName:p,target:$(S.col,S.row),nextCell:S};let A=O(d,p);if(A&&!["meat","sausage"].includes(w?.sex))return{type:"scanner",dirName:p,target:ge(A),scanner:A};let E=G(d);return E&&ie(E[1],p)?{type:"facility",dirName:p,facilityId:E[0],facility:E[1],target:$(d.col,d.row)}:null}function me(d,p){let w=U(p);if(!w)return!1;let k=e.conveyorMeta?.get?.(I(d.col+w.dc,d.row+w.dr));return k?[...new Set([...Array.isArray(k.outDirs)?k.outDirs:[],k.dir].filter(Boolean))].includes(w.opposite):!1}function T(d){return fe.filter(p=>$e(d.col+p.dc,d.row+p.dr)&&e.conveyorTiles.has(I(d.col+p.dc,d.row+p.dr))).map(p=>p.name)}function M(d,p,w="random"){let k=T(d);if(k.length<3)return p;let S=new Set(k.filter(W=>me(d,W))),A=k.filter(W=>!S.has(W)),E=S.size?A:[...new Set(p.filter(W=>k.includes(W)))];return!E.length&&!S.size&&(E=k),w&&w!=="random"&&w!=="pass"&&E.length>=2&&E.includes(w)?[w]:E}function q(d,p){return p&&(p.type==="facility"||!le(d,p.target))}function ne(d,p,w,k="random"){let S=w.map(ae=>De(p,ae,d)).filter(Boolean);if(!S.length)return null;let E=S.filter(ae=>ae.type!=="facility").filter(ae=>!le(d,ae.target)),W=E.length?E:S.filter(ae=>ae.type==="facility");return W.length?W[Math.floor(Math.random()*W.length)]:null}function oe(d,p){let w=[];ue(w,{x:d.x,y:d.y}),ue(w,p),d.route=w.length?w:[{x:d.x,y:d.y}],d.targetIndex=d.route.length>1?1:d.route.length}function se(d,p){let w=tt(d.x,d.y);if(!w)return Zt(p,"OFF GRID");let k=I(w.col,w.row);if(!e.conveyorTiles.has(k))return Zt(p,"OFF BELT");let S=e.conveyorMeta?.get(k)||{},A=M(w,D(k),S.branchMode||"random");if(!A.length){d.stoppedTimer=.25;return}let E=ne(d,w,A,S.branchMode||"random");if(!E){d.stoppedTimer=.25;return}if(E.type==="facility"){let W=Y(E.facility);W==="mixer"?Vn(p,E.facility):W==="truck"?kn(p,E.facility):W==="trash"?Mn(p,E.facility):W==="sausageMaker"?Xn(p,E.facility):Zt(p,"DONE");return}E.type==="scanner"&&(d.pendingScannerId=E.scanner.id),d.prevConveyorCell=k,oe(d,E.target)}function Se(d){let p=tt(d.x,d.y);if(!p)return null;let w=I(p.col,p.row);return e.conveyorTiles.has(w)?w:null}function be(d){let p=Se(d)||Se(d.route?.[d.targetIndex]||d);return t(p)}function Ce(d,p){let w=Se(p);!w||d.lastWearKey===w||(d.lastWearKey=w,Es(e,w))}function B(d,p){let w=be(d)*p;for(;w>0&&d.targetIndex=E?(d.x=k.x,d.y=k.y,Ce(d,k),d.targetIndex+=1,w-=E,i()):(d.x+=S/E*w,d.y+=A/E*w,w=0,i())}}function ye(d,p,w){d.stage="queued",d.route=null,d.queueRoute=w?w.map(k=>({x:k.x,y:k.y})):[ge(p)],d.scannerId=p.id,p.queue.includes(d.id)||p.queue.push(d.id),r(),Be(p)}function Be(d){d.queue=d.queue.filter(w=>e.chicks.some(k=>k.id===w&&k.stage==="queued"));let p=f.cell*.86*qs(e);d.queue.forEach((w,k)=>{let S=e.chicks.find(A=>A.id===w);S&&(de(S,S.queueRoute||[ge(d)],k*p),S.queueIndex=k)})}function de(d,p,w){if(!p||!p.length)return;if(p.length===1||w<=0){let A=p[p.length-1];d.x=A.x,d.y=A.y,i();return}let k=w;for(let A=p.length-1;A>0;A-=1){let E=p[A-1],W=p[A],ae=Math.hypot(W.x-E.x,W.y-E.y);if(k<=ae){let ve=1-k/ae;d.x=E.x+(W.x-E.x)*ve,d.y=E.y+(W.y-E.y)*ve,i();return}k-=ae}let S=p[0];d.x=S.x,d.y=S.y,i()}function Oe(d){for(let p of e.scanners){if(p.cooldown>0&&(p.cooldown=Math.max(0,p.cooldown-d)),p.keyPressTime>0&&(p.keyPressTime=Math.max(0,p.keyPressTime-d)),Be(p),p.kind!=="auto"||p.cooldown>0||!p.queue.length)continue;let w=p.queue[0],k=e.chicks.findIndex(S=>S.id===w);if(k<0){p.queue.shift();continue}Sn(k,dr(p,e.chicks[k]),!0)&&(Ps(e,p),p.cooldown=St(p,e),ha(e))}}function ct(d){let p=ar(e,d);return!p||!p.queue.length?null:e.chicks.find(w=>w.id===p.queue[0])||null}function xt(d,p){if(e.phase!=="running")return;let w=ar(e,d);Le(w,p)}function Le(d,p){if(e.phase!=="running"||!d||d.kind!=="manual"||(d.keyPressTime=.18,d.keyPressSide=p,!d.queue.length))return;let w=e.chicks.findIndex(k=>k.id===d.queue[0]);w>=0&&Sn(w,p,!1)}function qn(d,p,w){return d.kind==="manual"&&dr(d,p)===w}function wn(d){let p=e.manualCombo?.count||0;if(e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=0,e.manualCombo.lastBonus=0,e.stats.manualComboFailure=(e.stats.manualComboFailure||0)+1,e.totals.manualComboFailure=(e.totals.manualComboFailure||0)+1,p>=10){let w=ge(d);Yt(e,10,.25),H(e,w.x,w.y-36,"COMBO RESET",b.danger)}}function No(d){e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=Math.max(0,e.manualCombo.count||0)+1,e.stats.manualComboSuccess=(e.stats.manualComboSuccess||0)+1,e.totals.manualComboSuccess=(e.totals.manualComboSuccess||0)+1;let p=e.manualCombo.count;if(e.manualCombo.lastBonus=0,p<10)return 0;let w=Math.max(1,Math.floor(p/10)),k=e.scanners.filter(W=>W.kind==="manual").length,S=Math.min(1,(20+k*10)/100),A=0;for(let W=0;W0){je(e,E),e.stats.manualComboBonus=(e.stats.manualComboBonus||0)+E,e.totals.manualComboBonus=(e.totals.manualComboBonus||0)+E,e.manualCombo.lastBonus=E;let W=ge(d);H(e,W.x,W.y-42,`COMBO +${x(E)}`,b.green)}return E}function Yn(d,p){let w=Fe(d,p);if(!w)return null;let k=I(w.col,w.row);if(e.conveyorTiles.has(k))return{...w};let A=(Je(e).scannerPorts.get(d.id)?.[p]?.keys||[]).filter(Boolean);if(!A.length)return null;let E=A.map(re).sort((ae,ve)=>{let en=$(ae.col,ae.row),ze=$(ve.col,ve.row),_t=le(null,en)?1:0,Tn=le(null,ze)?1:0;return _t-Tn});return E.find(ae=>ae.col===w.col&&ae.row===w.row)||E[0]||null}function Lt(d,p,w,k){let S=[];ue(S,{x:d.x,y:d.y});let A=Fe(p,w);return A&&ue(S,$(A.col,A.row)),ue(S,$(k.col,k.row)),S}function Sn(d,p,w){let k=e.chicks[d];if(!k||k.stage!=="queued")return!1;let S=Ht(e,k.scannerId);if(!S)return!1;let A=Yn(S,p);if(!A)return!w&&S.kind==="manual"&&wn(S),H(e,k.x,k.y-16,p==="left"?"NO LEFT BELT":"NO RIGHT BELT",b.danger),!1;!w&&S.kind==="manual"&&(qn(S,k,p)?No(S):wn(S)),S.queue=S.queue.filter(W=>W!==k.id),k.stage="belt",k.route=Lt(k,S,p,A),k.targetIndex=k.route.length>1?1:k.route.length,k.scannerId=null,k.nextScannerId=null,k.pendingScannerId=null,k.queueRoute=null,k.queueIndex=-1,r();let E=w?b.green:p==="left"?b.mixerBlue:b.truckPink;return ws(e,ge(S).x,ge(S).y,E),H(e,k.x,k.y-20,w?"AUTO":p.toUpperCase(),E),!0}function Tt(d){let p=e.chicks[d];return p?(e.chicks.splice(d,1),r(),p):null}function Vn(d,p=e.facilities.mixer){if(p?.processingCooldown>0){let E=e.chicks[d];E&&(E.stoppedTimer=.25);return}let w=Tt(d);if(!w)return;let{x:k,y:S}=w;if(ba(e),Mo(e,p),xo(e,p),w.sex==="meat"||w.sex==="sausage"){rt(e),H(e,k,S-18,"CHICKS ONLY",b.warn);return}if(w.sex==="poop"){let E=cs(e);Bo(e,"mixer"),rt(e),ks(e,k,S),H(e,k,S-18,`-${x(E)}`,b.danger);return}w.sex==="male"?hn(e):rt(e);let A=Xe(e,p);if(!A||!It(e,p)||!gn(A)){let E=ls(e);H(e,k,S-18,`DIRECT +${x(E)}`,b.green);return}p.meatBuffer=Math.max(0,p.meatBuffer||0)+1,e.stats.meatProduced=(e.stats.meatProduced||0)+1,e.totals.meatProduced=(e.totals.meatProduced||0)+1,Ss(e,k,S),H(e,k,S-18,"MEAT +1",b.meatRed),Cn()}function kn(d,p=e.facilities.truck){let w=Tt(d);if(!w)return;let{x:k,y:S}=w;Go(w.sex,p),Cs(e,k,S,w.sex),wa(e,w.sex);let A=ln(e),E=Zi(e,w.sex);if(w.sex==="sausage"){e.stats.sausageShipped=(e.stats.sausageShipped||0)+1,e.totals.sausageShipped=(e.totals.sausageShipped||0)+1,H(e,k,S-18,`SAUSAGE +${x(Ze(e))}`,b.sausageOrange);return}if(w.sex==="meat"){rt(e),H(e,k,S-18,"RAW MEAT REJECT",b.warn);return}if(w.sex==="poop"){if(Bo(e,"truck"),E)hn(e),H(e,k,S-18,`+${x(Ve(e))}`,b.green);else{let W=us(e);rt(e),H(e,k,S-18,`-${x(W)}`,b.danger)}return}if(w.sex==="female"){E?(hn(e),H(e,k,S-18,`+${x(Ve(e))}`,b.green)):(rt(e),H(e,k,S-18,A==="male"?"REJECT":"NO SALE",b.warn));return}if(E){hn(e),H(e,k,S-18,`+${x(Ve(e))}`,b.green);return}if(es(e)){let W=ds(e);rt(e),H(e,k,S-18,`-${x(W)}`,b.danger)}else rt(e),H(e,k,S-18,"REJECT",b.warn)}function _o(d,p){let w=$(p.col,p.row);return{id:e.nextId++,sex:d,x:w.x,y:w.y,route:[{x:w.x,y:w.y}],targetIndex:1,stage:"belt",scannerId:null,nextScannerId:null,pendingScannerId:null,radius:d==="sausage"?11:10,bob:Math.random()*Math.PI*2,queueIndex:-1,queueRoute:null,stoppedTimer:0}}function gn(d){if(!d||!e.conveyorTiles.has(I(d.col,d.row)))return!1;let p=$(d.col,d.row);return!le(null,p)}function zn(d,p,w){let k=Xe(e,d);if(!k||!It(e,d)||!gn(k)||Math.max(0,d[w]||0)<=0)return!1;d[w]-=1,e.chicks.push(_o(p,k)),r();let S=$(k.col,k.row);return H(e,S.x,S.y-16,p==="meat"?"MEAT OUT":"SAUSAGE OUT",p==="meat"?b.meatRed:b.sausageOrange),!0}function Cn(){for(let d of Object.values(e.facilities||{})){let p=Y(d);p==="mixer"&&zn(d,"meat","meatBuffer"),p==="sausageMaker"&&zn(d,"sausage","sausageBuffer")}}function Xn(d,p){if(p?.processingCooldown>0){let A=e.chicks[d];A&&(A.stoppedTimer=.25);return}let w=Tt(d);if(!w)return;let{x:k,y:S}=w;if(w.sex!=="meat"){rt(e),H(e,k,S-18,"MEAT ONLY",b.warn);return}Mo(e,p),xo(e,p),p.meatBuffer=Math.max(0,p.meatBuffer||0)+1,p.meatBuffer>=2?(p.meatBuffer-=2,p.sausageBuffer=Math.max(0,p.sausageBuffer||0)+1,e.stats.sausageProduced=(e.stats.sausageProduced||0)+1,e.totals.sausageProduced=(e.totals.sausageProduced||0)+1,H(e,k,S-18,"SAUSAGE +1",b.sausageOrange)):H(e,k,S-18,"MEAT 1/2",b.meatRed),Cn()}function Mn(d,p=e.facilities.trash){if(p?.processingCooldown>0){let W=e.chicks[d];W&&(W.stoppedTimer=.25);return}let w=Tt(d);if(!w)return;let{x:k,y:S}=w;gs(e,k,S,w.sex),va(e),Mo(e,p),xo(e,p);let A={amount:0},E="";if(w.sex==="poop"){A=is(e),E=A.amount>0?` ${A.tier==="jackpot"?"JACKPOT ":"+"}${x(A.amount)}`:" MISS",Bo(e,"trash"),hn(e);let W=Math.ceil(Math.max(0,Number(e.cardEffects?.composter)||0)*3*po(e));if(W>0){let ae=je(e,W);e.stats.composterIncome=(e.stats.composterIncome||0)+ae,e.totals.composterIncome=(e.totals.composterIncome||0)+ae,H(e,k,S-36,`COMPOST +${x(ae)}`,b.green)}H(e,k,S-18,`CLEAN${E}`,A.amount>0?b.green:b.green)}else rt(e),H(e,k,S-18,A.amount>0?`WASTE${E}`:"WASTE",A.amount>0?b.green:b.ink)}function Zt(d,p){let w=Tt(d);w&&H(e,w.x,w.y-12,p,b.muted)}function Go(d,p=e.facilities.truck){let w=p||e.facilities.truck;w&&(e.truckCargo.push({sex:d,x:z(22,w.w-22),y:z(66,w.h-24)}),e.truckCargo.length>45&&e.truckCargo.shift())}function Uo(d){let p=tt(d.x,d.y);if(p){let S=I(p.col,p.row);if(e.conveyorTiles.has(S))return S}if(!p)return null;let w=null,k=1/0;for(let S of[p,...fe.map(A=>({col:p.col+A.dc,row:p.row+A.dr}))]){if(!$e(S.col,S.row))continue;let A=I(S.col,S.row);if(!e.conveyorTiles.has(A))continue;let E=$(S.col,S.row),W=Math.hypot(d.x-E.x,d.y-E.y);Ww&&d.ratio=p){let k=xn(d.id);if(!k.length||k.some(E=>E.stage!=="queued"&&E.stoppedTimer<=.2))continue;let S=e.lastExplodedComponent.get(d.id)||0,A=performance.now();A-S>900&&(e.lastExplodedComponent.set(d.id,A),Wo(d))}}}function xn(d){return Nt(e.frameId||0),e.frameCache?.componentChicks?.get(d)||[]}function Wo(d){let p=xn(d.id);if(!p.length)return;for(let S of p)Tr(e,S.sex,S.x,S.y);e.chicks=e.chicks.filter(S=>!p.some(A=>A.id===S.id));for(let S of e.scanners)S.queue=S.queue.filter(A=>e.chicks.some(E=>E.id===A));r();for(let S of d.cells){let A=re(S),E=$(A.col,A.row);at(e,E.x,E.y,b.danger),bt(e,E.x,E.y,6),mo(e,E.x,E.y,4)}Yt(e,18,.75);let w=re(d.cells[0]),k=$(w.col,w.row);e.stats.explosions=(e.stats.explosions||0)+1,e.totals.explosions=(e.totals.explosions||0)+1,H(e,k.x,k.y-22,`${Math.round(wr(e)*100)}% JAM EXPLOSION`,b.danger)}return{activeQueuedChick:ct,beginFrame:a,currentSpawnDelay:C,sortSlot:xt,updateCongestion:Nt,sortScanner:Le,updateRunning:Z}}var he=document.getElementById("gameCanvas"),hu=he.getContext("2d"),F={shell:document.getElementById("gameShell"),money:document.getElementById("money"),turn:document.getElementById("turn"),timeLeft:document.getElementById("timeLeft"),phase:document.getElementById("phaseLabel"),comboCount:document.getElementById("comboCount"),eventBrief:document.getElementById("eventBrief"),speedBrief:document.getElementById("speedBrief"),turnProfit:document.getElementById("turnProfit"),mixerCount:document.getElementById("mixerCount"),truckFemaleCount:document.getElementById("truckFemaleCount"),truckMaleCount:document.getElementById("truckMaleCount"),poopCount:document.getElementById("poopCount"),buildStatus:document.getElementById("buildStatus"),turnSummary:document.getElementById("turnSummary"),modal:document.getElementById("modal"),modalTitle:document.getElementById("modalTitle"),modalBody:document.getElementById("modalBody"),modalActions:document.getElementById("modalActions"),hoverTooltip:document.getElementById("hoverTooltip"),manualScannerMonitor:document.getElementById("manualScannerMonitor"),debug:{panel:document.getElementById("debugPanel"),infiniteCash:document.getElementById("debugInfiniteCash"),dayInput:document.getElementById("debugDayInput"),setDay:document.getElementById("debugSetDayButton"),zeroTimer:document.getElementById("debugZeroTimerButton"),cardSelect:document.getElementById("debugCardSelect"),targetSelect:document.getElementById("debugTargetSelect"),eventSelect:document.getElementById("debugEventSelect"),grantCard:document.getElementById("debugGrantCardButton"),grantAllCards:document.getElementById("debugGrantAllCardsButton"),readout:document.getElementById("debugReadout")},buttons:{s1Left:document.getElementById("scanner1MixerButton"),s1Right:document.getElementById("scanner1TruckButton"),s2Left:document.getElementById("scanner2MixerButton"),s2Right:document.getElementById("scanner2TruckButton"),nextTurn:document.getElementById("nextTurnButton"),conveyor:document.getElementById("buildConveyorButton"),boostConveyor:document.getElementById("buildBoostConveyorButton"),eggFarm:document.getElementById("buildEggFarmButton"),autoScanner:document.getElementById("buildAutoScannerButton"),manualScanner:document.getElementById("buildManualScannerButton"),mixer:document.getElementById("buildMixerButton"),trash:document.getElementById("buildTrashButton"),truck:document.getElementById("buildTruckButton"),sausageMaker:document.getElementById("buildSausageMakerButton"),maintenanceRoom:document.getElementById("buildMaintenanceRoomButton"),erase:document.getElementById("eraseButton"),undo:document.getElementById("undoButton"),redo:document.getElementById("redoButton")}};function mu(){let e={conveyor:"conveyor",boostConveyor:"boostConveyor",eggFarm:"eggFarm",autoScanner:"autoScanner",manualScanner:"manualScanner",mixer:"mixer",trash:"trash",truck:"truck",sausageMaker:"sausageMaker",maintenanceRoom:"maintenanceRoom"};for(let[t,n]of Object.entries(e))F.buttons[t]&&(F.buttons[t].innerHTML=hi(n))}function bu(e){let t=new Set(e.tags||[]);return["upgradeEgg","crowdedFarming","hatchingFeed","extraEggOutlet"].includes(e.id)||t.has("EGG")?"Production / EGG":["upgradeTrash","poopRateBooster","composter","chemicalWeaponSubsidy"].includes(e.id)||t.has("POOP")?"Poop / Shredder":["upgradeAutoScanner","autoScannerTuning","scannerQueueSpacing"].includes(e.id)||t.has("SCANNER")?"Scanner":["bearing","dynamite"].includes(e.id)||t.has("CONVEYOR")?"Conveyor / Map":["safetyCover","preventiveMaintenance","durabilityCoating","sparePartsBin","laborExploitation"].includes(e.id)||t.has("MAINTENANCE")?"Maintenance / Risk":["dudFilter","dudRefund","freeReroll","extraCards"].includes(e.id)||t.has("CARD")?"Card Engine":t.has("ULTRA RARE")?"Ultra Rare":t.has("ECONOMY")||["upgradeMixer","upgradeTruck","upgradeSausageMaker","recyclingSubsidy","usedMachine","newMachine","flattery","legalWork","rescueLoan"].includes(e.id)?"Economy / Shipment":"Other"}function vu(){if(!F.debug?.panel||!F.debug.cardSelect)return;let e=["Production / EGG","Poop / Shredder","Scanner","Conveyor / Map","Maintenance / Risk","Card Engine","Economy / Shipment","Ultra Rare","Other"],t=new Map(e.map(n=>[n,[]]));for(let n of fn){let o=bu(n);t.has(o)||t.set(o,[]),t.get(o).push(n)}F.debug.cardSelect.innerHTML="";for(let n of e){let o=t.get(n)||[];if(!o.length)continue;let r=document.createElement("optgroup");r.label=n;for(let i of o){let a=document.createElement("option");a.value=i.id;let c=i.rarity==="ultraRare"?"UR":i.rarity==="rare"?"R":"C";a.textContent=`[${c}] ${i.title}`,r.appendChild(a)}F.debug.cardSelect.appendChild(r)}F.debug.cardSelect.addEventListener("change",Jt),wu(),Jt()}function wu(){if(!F.debug?.eventSelect)return;F.debug.eventSelect.innerHTML="";let e=document.createElement("option");e.value="__roll__",e.textContent="Roll normally",F.debug.eventSelect.appendChild(e);let t=document.createElement("option");t.value="__none__",t.textContent="No event",F.debug.eventSelect.appendChild(t);for(let n of Fn){let o=document.createElement("option");o.value=n.key,o.textContent=n.title,F.debug.eventSelect.appendChild(o)}F.debug.eventSelect.value=u.debugNextEventKey||"__roll__",F.debug.eventSelect.addEventListener("change",ku)}function Ma(){let e=u.debugNextEventKey||"__roll__";return e==="__none__"?null:e==="__roll__"?Vi(u):hr(u,e)}function Jt(){if(!F.debug?.targetSelect)return;let e=F.debug.cardSelect?.value,t=Xt(e),n=t?Ys(u,t):[];if(F.debug.targetSelect.innerHTML="",!n.length){let r=document.createElement("option");r.value="__none__",r.textContent=t?"No target required":"No card selected",F.debug.targetSelect.appendChild(r),F.debug.targetSelect.disabled=!0;return}let o=document.createElement("option");o.value="__auto__",o.textContent=t?.id==="dynamite"?"Auto: first 10 blocked cells":"Auto: first valid target",F.debug.targetSelect.appendChild(o);for(let r of n){let i=document.createElement("option");i.value=r.key,i.textContent=r.label,F.debug.targetSelect.appendChild(i)}F.debug.targetSelect.disabled=!1}function Su(){let e=Math.max(1,Math.floor(Number(F.debug.dayInput?.value)||1));u.turn=e,F.debug.dayInput&&(F.debug.dayInput.value=String(e)),H(u,he.width/2-u.view.x,86-u.view.y,`DAY ${e}`,b.green),J.updatePanels(),J.updateUI(),Jt(),Ot(`Day set to ${e}.`)}function ku(){u.debugNextEventKey=F.debug.eventSelect?.value||"__roll__",u.phase==="build"&&(u.eventOffer=Ma(),J.updatePanels(),J.updateUI());let e=F.debug.eventSelect?.selectedOptions?.[0]?.textContent||"Roll normally";Ot(`Next event: ${e}.`)}function gu(){let e=u.phase==="running"&&(u.timeLeft<=0||u.shutdownTimeLeft>0||u.cleanupTimer!==null);u.timeLeft=0,u.cleanupTimer!==null&&(u.cleanupTimer=0),e?u.shutdownTimeLeft=0:u.phase==="running"&&Ea(),H(u,he.width/2-u.view.x,86-u.view.y,"TIMER 0",b.warn),J.updatePanels(),J.updateUI(),Ot("Timer set to 0.")}function Cu(){let e=F.debug.cardSelect?.value,t=F.debug.targetSelect?.disabled?void 0:F.debug.targetSelect?.value,n=Nr(u,e,{targetKey:t});F.debug.grantCard&&(F.debug.grantCard.textContent=n.ok?"Granted":"Failed",window.setTimeout(()=>{F.debug.grantCard&&(F.debug.grantCard.textContent="Grant Selected")},900)),Ae?.updateCongestion?.(u.frameId||0),J.updatePanels(),J.updateUI(),Jt(),Ot(n.reason)}function Mu(){let t=fn.map(n=>Nr(u,n,{targetKey:"__auto__"})).filter(n=>n.ok).length;Ae?.updateCongestion?.(u.frameId||0),J.updatePanels(),J.updateUI(),Jt(),Ot(`Granted ${t}/${fn.length} cards.`)}function xu(){F.debug?.infiniteCash?.checked&&u.cash<999999&&(u.cash=999999,u.totals.maxCash=Math.max(u.totals.maxCash,u.cash))}function Ot(e=""){F.debug?.readout&&(F.debug.readout.textContent=[e,`D${u.turn}`,x(u.cash),`Combo ${u.manualCombo?.count||0}`,`Event ${u.eventActive?.title||u.eventOffer?.title||"none"}`,`Next ${F.debug?.eventSelect?.selectedOptions?.[0]?.textContent||"Roll normally"}`,`Rescue ${u.cardEffects?.rescueLoanCharges||0}`,`Chem ${u.cardEffects?.chemicalWeaponSubsidy||0}`].filter(Boolean).join(" | "))}var u=rr(),te,J,Ae,bn;function Tu(e=null){let t=pn(u,e);return e?t*_n(u,e):t}function Eu(){Object.assign(u,rr()),u.phase="running",u.view={x:0,y:0,scale:1},ir(u),Pa(),Re(u),J.hideModal(),Ae.updateCongestion(u.frameId||0),J.updatePanels(),J.updateUI(),Ot()}function Ru(){if(u.phase!=="build")return;if(u.cardDraft?.pending||u.cardTargetPick?.pending){te.fail(u.cardTargetPick?.pending?"Choose upgrade target first.":"Choose an upgrade card first."),J.updatePanels();return}let e=fo(u);if(e.length){Du(),te.fail(`Cannot start: ${e[0]}`),J.updatePanels();return}Re(u),Ui(u),Fs(u);let t=Math.max(0,Math.floor(u.lastResult?.profit??u.stats?.profit??0)),n=ys(u,Math.max(1,u.turn||1),t);u.lastStartFees={fairiesTribute:n.amount||0,tribute:n},n.amount>0&&H(u,he.width/2-u.view.x,116-u.view.y,`FAIRIES -${x(n.amount)}`,b.danger),zi(u),u.phase="running",u.turn+=1,u.timeLeft=ji(u),u.shutdownTimeLeft=0,u.cleanupTimer=null,u.cleanupBlown=!1,u.chicks=[],u.effects=[],u.floatingTexts=[],u.shake={time:0,strength:0},u.truckCargo=[],Pa(),u.stats=or(),u.stats.fairiesTribute=u.lastStartFees?.fairiesTribute||0,u.stats.fairiesTribute>0&&(u.stats.penalty+=u.stats.fairiesTribute,u.stats.profit-=u.stats.fairiesTribute);for(let o of u.scanners)o.queue=[],o.cooldown=0;for(let o of u.eggFarms)o.nextSpawn=Ae.currentSpawnDelay(o),o.lastInterval=o.nextSpawn,o.shutterProgress=0,o.shutterSparked=!1;u.buildTool=null,u.selected=null,u.groupDrag=null,u.selectionBox=null,u.pan=null,Ae.updateCongestion(u.frameId||0),J.updatePanels(),J.updateUI()}function Pu(){if(u.phase!=="running")return;let e=ps(u),t=u.eventActive?{...u.eventActive}:null,n=os(u),o=hs(u);if(e.adjusted>0){let i=u.facilities.truck,a=i?i.x+i.w/2:he.width/2-u.view.x,c=i?i.y+26:96-u.view.y;H(u,a,c,`${e.target==="poop"?"POOP SHIP":"SHIP"} +${x(e.adjusted)}`,b.green)}n?.bonus>0&&H(u,he.width/2-u.view.x,96-u.view.y,`EVENT +${x(n.bonus)}`,b.green),o.amount>0&&H(u,he.width/2-u.view.x,116-u.view.y,`CHEM SUBSIDY +${x(o.amount)}`,b.green),Xi(u),u.totals.turnsCompleted+=1;let r=ns(t);if(r!==1&&(u.pendingFairiesTributeMultiplier=r),u.lastResult={...u.stats,ship:e,event:n,chemical:o,rescue:{amount:0,used:0,remaining:u.cardEffects?.rescueLoanCharges||0},fairiesTribute:{amount:u.stats.fairiesTribute||0},tributeMultiplier:r,turn:u.turn,cash:u.cash},u.cash<0){if((u.cardEffects?.rescueLoanCharges||0)>0){u.phase="loanDecision",J.showEmergencyLoanDecision(Ta,Oo);return}u.phase="gameover",J.showGameOver();return}xa()}function xa(){u.phase="build",u.truckCargo=[],u.chicks=[],u.shutdownTimeLeft=0,u.cleanupTimer=null,u.cleanupBlown=!1,u.buildSession+=1,u.undoStack=[],u.redoStack=[],u.timeLeft=0;for(let e of u.scanners)e.queue=[];for(let e of u.eggFarms)e.shutterProgress=0,e.shutterSparked=!1;Ds(u),u.eventOffer=Ma(),bn&&bn.prepareDraft(),u.cardTargetPick=null,u.buildTool=null,u.groupDrag=null,u.selectionBox=null,u.pan=null,J.updatePanels(),J.showTurnResult(u.lastResult)}function Ta(){if((u.cardEffects?.rescueLoanCharges||0)<=0)return Oo();u.cardEffects.rescueLoanCharges-=1,u.stats.rescueLoan=(u.stats.rescueLoan||0)+500,u.totals.rescueLoan=(u.totals.rescueLoan||0)+500;let e=je(u,500);u.lastResult={...u.lastResult||{},...u.stats,rescue:{amount:(u.lastResult?.rescue?.amount||0)+e,used:(u.lastResult?.rescue?.used||0)+1,remaining:u.cardEffects.rescueLoanCharges},cash:u.cash},H(u,he.width/2-u.view.x,176-u.view.y,`RESCUE +${x(e)}`,b.green),u.cash>=0?xa():(u.cardEffects?.rescueLoanCharges||0)>0?(u.phase="loanDecision",J.showEmergencyLoanDecision(Ta,Oo)):Oo()}function Oo(){u.phase="gameover",J.showGameOver()}function Ea(){u.shutdownTimeLeft<=0&&(u.shutdownTimeLeft=u.shutdownGraceSeconds||10);for(let e of u.eggFarms){if(e.shutterSparked)continue;e.shutterProgress=.02,e.shutterSparked=!0;let t=$(e.col,e.row);at(u,t.x,t.y,b.ink),bt(u,t.x,t.y+10,10),H(u,t.x,t.y-34,"SHUT +10s",b.ink)}}function Ra(e){u.lastTimestamp||(u.lastTimestamp=e);let t=Math.min((e-u.lastTimestamp)/1e3,.05);u.lastTimestamp=e,u.frameId=(u.frameId||0)+1,Ae.beginFrame?.(u.frameId),u.phase==="running"&&Ae.updateRunning(t,{closeFarmShutters:Ea,completeTurn:Pu}),xs(u,t,he,te.equipmentHitBoxes),Ae.updateCongestion(u.frameId),sa(hu,he,u,{activeQueuedChick:Ae.activeQueuedChick,selectedObject:te.selectedObject,selectedTitle:te.selectedTitle}),xu(),J.updateUI(),Ia(),Ot(),requestAnimationFrame(Ra)}function Kn(){return u.view?.scale||1}function vn(){u.view||(u.view={x:0,y:0,scale:1}),u.view.scale==null&&(u.view.scale=1)}function Lo(e){let t=he.getBoundingClientRect();return{x:(e.clientX-t.left)*he.width/t.width,y:(e.clientY-t.top)*he.height/t.height}}function Bt(e){let t=Lo(e),n=Kn();return{x:(t.x-(u.view?.x||0))/n,y:(t.y-(u.view?.y||0))/n}}function Au(e){let t=Kn();return{x:e.x*t+(u.view?.x||0),y:e.y*t+(u.view?.y||0)}}function Iu(){let e={left:f.x-90,top:f.y-130,right:f.x+f.cols*f.cell+260,bottom:f.y+f.rows*f.cell+220};if(u.phase==="build")for(let t of Ut(u)){let n=dt(t);e.left=Math.min(e.left,n.x-60),e.top=Math.min(e.top,n.y-80),e.right=Math.max(e.right,n.x+n.w+80),e.bottom=Math.max(e.bottom,n.y+n.h+80)}return e}function ka(e,t){if(e<=t)return[e,t];let n=(e+t)/2;return[n,n]}function Ct(){vn();let e=Kn(),t=Iu(),[n,o]=ka(he.width-160-t.right*e,110-t.left*e),[r,i]=ka(he.height-150-t.bottom*e,150-t.top*e);u.view.x=An(u.view.x,n,o),u.view.y=An(u.view.y,r,i)}function Pa(){vn(),u.view.scale=1;let e=u.eggFarms?.[0],t=e?$(e.col,e.row):{x:f.x,y:f.y};u.view.x=280-t.x,u.view.y=190-t.y,Ct()}function $u(e){if(!e)return!1;vn();let t=Kn();return u.view.x=he.width/2-e.x*t,u.view.y=he.height/2-e.y*t,Ct(),!0}function Fu(e){let t=e?.ref;return t?e.type==="facility"?{x:t.x+t.w/2,y:t.y+t.h/2}:e.type==="eggFarm"?$(t.col,t.row):e.type==="scanner"?{x:$(t.col,t.row).x+f.cell/2,y:$(t.col,t.row).y}:e.type==="maintenanceRoom"?{x:$(t.col,t.row).x+f.cell/2,y:$(t.col,t.row).y+f.cell/2}:null:null}function Du(){let e=an(u),t=e.find(o=>o.type==="facility")||e[0]||Bu(),n=Fu(t);$u(n)&&t&&(u.selected={type:t.type,id:t.id})}function Bu(){let e=Object.values(u.facilities||{}).find(o=>o?.entry&&u.conveyorTiles.has(I(o.entry.col,o.entry.row)))||Object.values(u.facilities||{})[0];if(e)return{type:"facility",id:e.id,ref:e};let t=u.scanners?.find(o=>o);if(t)return{type:"scanner",id:t.id,ref:t};let n=u.eggFarms?.[0];return n?{type:"eggFarm",id:n.id,ref:n}:null}function Ou(e){let t=Lo(e);vn(),u.pan={start:t,viewX:u.view.x,viewY:u.view.y,moved:!1}}function Lu(e){if(!u.pan)return;let t=Lo(e);Math.hypot(t.x-u.pan.start.x,t.y-u.pan.start.y)>5&&(u.pan.moved=!0),vn(),u.view.x=u.pan.viewX+t.x-u.pan.start.x,u.view.y=u.pan.viewY+t.y-u.pan.start.y,Ct()}function Nu(e){e.preventDefault(),vn();let t=Lo(e),n=Bt(e),o=Math.exp(-e.deltaY*.0012),r=An(Kn()*o,.55,1.8);u.view.scale=r,u.view.x=t.x-n.x*r,u.view.y=t.y-n.y*r,Ct(),Mt()}function _u(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:{type:e.type,id:e.ref.id}:null}function Gu(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:e.ref||null:null}function Mt(){F.hoverTooltip&&(F.hoverTooltip.classList.remove("visible"),F.hoverTooltip.setAttribute("aria-hidden","true"),u.hover=null)}function Uu(e,t){if(!F.hoverTooltip||u.phase!=="build"||u.cardTargetPick?.pending||u.groupDrag||u.selectionBox||u.pan)return Mt();let n=Gu(t);if(!n)return Mt();let o=te.selectedTitle(n),r=te.flavorText?te.flavorText(n):"",i=te.disconnectedWarningFor?te.disconnectedWarningFor(n):"",a=te.selectedInfoLines(n).slice(0,7);F.hoverTooltip.innerHTML=`${o}${i?`${i}`:r?`${r}`:""}${a.map(g=>`${g}`).join("")}`;let c=Math.min(window.innerWidth-330,e.clientX+18),h=Math.min(window.innerHeight-220,e.clientY+18);F.hoverTooltip.style.left=`${Math.max(8,c)}px`,F.hoverTooltip.style.top=`${Math.max(8,h)}px`,F.hoverTooltip.classList.add("visible"),F.hoverTooltip.setAttribute("aria-hidden","false"),u.hover={type:t.type,id:t.oldKey||t.ref?.id||null}}function Wu(e){if(u.phase!=="build")return Mt();Uu(e,te.equipmentAtPoint(Bt(e)))}function Aa(e){Mt();let t=Bt(e),n=te.equipmentAtPoint(t),o=_u(n);if(!o){u.selected=null,u.multiSelected=[],J.updatePanels();return}u.selected=o,u.multiSelected=[o],J.updatePanels();let r=te.selectedObject();r?.type==="scanner"&&r.kind==="manual"&&te.showManualScannerMenu(r),r?.type==="scanner"&&r.kind==="auto"&&te.showAutoScannerMenu(r)}function mn(){u.buildTool=null,u.selected=null,u.multiSelected=[],u.selectionBox=null,u.cardTargetPick?.mode==="autoScannerMenu"&&(u.cardTargetPick=null),J.hideModal(),Mt(),J.updatePanels(),J.updateUI()}function ga(e){return String(e).replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function Hu(e){let t=e?.queue?.[0];return t==null?null:u.chicks.find(n=>n.id===t)||null}function Ku(e){if(!e)return'WAIT';let t=e.sex==="poop"?"POOP":e.sex==="male"?"M MALE":"F FEMALE";return`${t}`}function qu(e,t){let n=new Set(u.eggFarms.map(C=>I(C.col,C.row))),o=new Map(u.scanners.map(C=>[I(C.col,C.row),C])),r=Fe(e,"inputA"),i=r?I(r.col,r.row):null,a=new Set(Object.values(u.facilities||{}).map(C=>C.entry?I(C.entry.col,C.entry.row):null).filter(Boolean)),c=t?.sex||"",h=c==="poop"?"P":c==="male"?"M":c==="female"?"F":"",g=[];for(let C=e.row-2;C<=e.row+2;C+=1)for(let P=e.col-2;P<=e.col+2;P+=1){let L=I(P,C),K=["mini-cell"],j="";P===e.col&&C===e.row?(K.push("scanner"),c&&K.push(c),j=h||"S"):L===i?(K.push("input"),j="IN"):n.has(L)?(K.push("egg"),j="E"):o.has(L)?(K.push("scanner-other"),j="S"):a.has(L)?(K.push("port"),j="P"):u.conveyorTiles.has(L)?(K.push("belt"),j="."):u.blockedCells?.has?.(L)&&(K.push("blocked"),j="X"),g.push(`${j}`)}return`
${g.join("")}
`}function Yu(e){let t=Au($(e.col,e.row)),n=76;return t.x<-n||t.y<-n||t.x>he.width+n||t.y>he.height+n}function Ia(){if(!F.manualScannerMonitor)return;let e=u.frameCache||(u.frameCache={}),t=u.view||{},n=[u.phase,Math.round((t.x||0)*10),Math.round((t.y||0)*10),Math.round((t.scale||1)*100),u.chicks.length,u.scanners.map(r=>[r.id,r.kind,r.col,r.row,r.queue?.join(",")||"",r.keyPressSide||"",Math.ceil((r.keyPressTime||0)*10)].join(":")).join("|")].join(";");if(e.manualMonitorSignature===n)return;if(e.manualMonitorSignature=n,u.phase!=="running"){F.manualScannerMonitor.classList.remove("visible"),F.manualScannerMonitor.innerHTML="";return}let o=u.scanners.filter(r=>r.kind==="manual"&&Yu(r));if(!o.length){F.manualScannerMonitor.classList.remove("visible"),F.manualScannerMonitor.innerHTML="";return}F.manualScannerMonitor.innerHTML=o.map(r=>{let i=Hu(r),a=r.keys?.left?.label||(r.slot===0?"A":"Left"),c=r.keys?.right?.label||(r.slot===0?"D":"Right"),h=r.role===0?"MIXER":"WASTE",g=r.role===0?"S2":"TRUCK",C=i?"":" disabled";return` +
+
S${(r.slot??0)+1}OFFSCREEN / Q:${r.queue.length}
+
+ IN${Ku(i)}SCANNER +
+ ${qu(r,i)} +
+ + +
+
`}).join(""),F.manualScannerMonitor.classList.add("visible")}F.manualScannerMonitor?.addEventListener("click",e=>{let t=e.target.closest("button[data-scanner-id]");if(!t||t.disabled)return;let n=u.scanners.find(o=>o.id===Number(t.dataset.scannerId));n&&(Ae.sortScanner(n,t.dataset.side),Ia())});he.addEventListener("contextmenu",e=>e.preventDefault());he.addEventListener("wheel",Nu,{passive:!1});he.addEventListener("pointerdown",e=>{if(!["build","running"].includes(u.phase))return;if(e.button===2||e.button===1||u.phase==="running"&&e.button===0){he.setPointerCapture(e.pointerId),Ou(e);return}if(u.phase!=="build"||e.button!==0)return;he.setPointerCapture(e.pointerId);let t=Bt(e);if(u.cardTargetPick?.mode==="autoScannerMenu"){mn();return}if(u.cardTargetPick?.pending){bn.chooseTargetAtPoint(t);return}let n=te.expansionOfferAtPoint?.(t);if(n){te.buyGridExpansion(n),Ct(),J.updatePanels(),J.updateUI();return}if(te.cycleBranchModeAtPoint?.(t)){J.updatePanels(),J.updateUI();return}let o=tt(t.x,t.y),r=te.equipmentAtPoint(t);if(!u.buildTool&&r?.type==="conveyor"&&o&&te.cycleSingleConveyorDirection?.(o)){J.updatePanels(),J.updateUI();return}if(u.buildTool==="erase"){if(!te.equipmentAtPoint(t)){mn();return}te.eraseAtPoint(t);return}if(u.buildTool){let i=tt(t.x,t.y);if(!i&&!["mixer","trash","truck"].includes(u.buildTool)){mn();return}if(u.buildTool==="conveyor"||u.buildTool==="boostConveyor"){te.beginConveyorDrag(i);return}if(te.equipmentAtPoint(t)){u.buildTool=null,Aa(e);return}te.buildAtPoint(t);return}te.startGroupDrag(e)||te.startSelectionBox(e)});he.addEventListener("pointermove",e=>{if(u.pan&&e.buttons&7&&Lu(e),u.phase!=="build"){Mt();return}Wu(e),u.groupDrag&&e.buttons&1&&te.updateGroupDrag(e),u.selectionBox&&e.buttons&1&&te.updateSelectionBox(e),(u.buildTool==="conveyor"||u.buildTool==="boostConveyor")&&e.buttons&1&&te.continueConveyorDrag(tt(Bt(e).x,Bt(e).y)),u.buildTool==="erase"&&e.buttons&1&&te.eraseAtPoint(Bt(e))});he.addEventListener("pointerup",e=>{u.selectionBox?te.finishSelectionBox():u.groupDrag&&(u.groupDrag.committed||Aa(e),te.finishGroupDrag()),(e.button===2||e.button===1)&&u.pan&&!u.pan.moved&&u.buildTool&&u.phase==="build"&&mn(),(u.buildTool==="conveyor"||u.buildTool==="boostConveyor")&&te.endConveyorDrag?.(),u.groupDrag=null,u.pan=null;try{he.releasePointerCapture(e.pointerId)}catch{}});he.addEventListener("pointerleave",Mt);he.addEventListener("pointercancel",()=>{te?.endConveyorDrag?.(),u.groupDrag=null,u.selectionBox=null,u.pan=null,Mt()});document.addEventListener("pointerdown",e=>{!F.modal.classList.contains("visible")||!F.modal.classList.contains("equipment-popover")||e.target.closest("#modal .modal-card")||mn()},!0);F.buttons.s1Left.addEventListener("click",()=>Ae.sortSlot(0,"left"));F.buttons.s1Right.addEventListener("click",()=>Ae.sortSlot(0,"right"));F.buttons.s2Left.addEventListener("click",()=>Ae.sortSlot(1,"left"));F.buttons.s2Right.addEventListener("click",()=>Ae.sortSlot(1,"right"));F.buttons.nextTurn.addEventListener("click",Ru);F.buttons.conveyor.addEventListener("click",()=>te.setBuildTool("conveyor"));F.buttons.boostConveyor.addEventListener("click",()=>te.setBuildTool("boostConveyor"));F.buttons.eggFarm.addEventListener("click",()=>te.setBuildTool("eggFarm"));F.buttons.autoScanner.addEventListener("click",()=>te.setBuildTool("autoScanner"));F.buttons.manualScanner.addEventListener("click",()=>te.setBuildTool("manualScanner"));F.buttons.mixer.addEventListener("click",()=>te.setBuildTool("mixer"));F.buttons.trash.addEventListener("click",()=>te.setBuildTool("trash"));F.buttons.truck.addEventListener("click",()=>te.setBuildTool("truck"));F.buttons.sausageMaker.addEventListener("click",()=>te.setBuildTool("sausageMaker"));F.buttons.maintenanceRoom.addEventListener("click",()=>te.setBuildTool("maintenanceRoom"));F.buttons.erase.addEventListener("click",()=>te.setBuildTool("erase"));F.debug.setDay?.addEventListener("click",Su);F.debug.zeroTimer?.addEventListener("click",gu);F.debug.grantCard?.addEventListener("click",Cu);F.debug.grantAllCards?.addEventListener("click",Mu);F.buttons.undo.addEventListener("click",()=>{Mr(u)&&(Ct(),J.updatePanels(),J.updateUI(),Jt())});F.buttons.redo.addEventListener("click",()=>{xr(u)&&(Ct(),J.updatePanels(),J.updateUI(),Jt())});function Ca(e,t,n){let o=e.keys?.[t];return o?o.code&&n.code===o.code||o.key&&n.key.toLowerCase()===o.key:!1}window.addEventListener("keydown",e=>{if(e.repeat)return;let t=e.key.toLowerCase();if(u.phase==="running")for(let n of u.scanners.filter(o=>o.kind==="manual")){if(Ca(n,"left",e)){e.preventDefault(),Ae.sortScanner(n,"left");return}if(Ca(n,"right",e)){e.preventDefault(),Ae.sortScanner(n,"right");return}}u.phase==="build"&&(e.ctrlKey||e.metaKey)&&t==="z"&&(e.preventDefault(),Mr(u)&&(Ct(),J.updatePanels(),J.updateUI())),u.phase==="build"&&(e.ctrlKey||e.metaKey)&&(t==="y"||e.shiftKey&&t==="z")&&(e.preventDefault(),xr(u)&&(Ct(),J.updatePanels(),J.updateUI())),e.key==="Escape"&&u.cardTargetPick?.pending&&(e.preventDefault(),u.cardTargetPick.mode==="autoScannerMenu"?mn():bn.cancelTargetPick())});te=pa({game:u,ui:F,canvas:he,canvasPoint:Bt,onUpdatePanels:()=>J?.updatePanels()});Ae=Sa({game:u,currentConveyorSpeed:Tu,onGameOverCheck:()=>J?.checkGameOver()});bn=Xs({game:u,ui:F,onUpdatePanels:()=>J?.updatePanels()});J=ya({game:u,ui:F,build:te,startGame:Eu,beginCardDraft:()=>bn.showDraft(),activeQueuedChick:Ae.activeQueuedChick});mu();vu();ir(u);Re(u);Ae.updateCongestion(u.frameId||0);J.updatePanels();J.updateUI();J.showTitle();Ot();requestAnimationFrame(Ra); diff --git a/index.html b/index.html index 905b0d5..3197a04 100644 --- a/index.html +++ b/index.html @@ -6,13 +6,13 @@ - Chick Sorter v27.20 — Card and Expansion Patch + Chick Sorter v28.21 — Boost Draw Hotfix
-
-
v27.20 VERIFIED
+
+
v28.21 VERIFIED
@@ -34,14 +34,12 @@
NO ACTIVE EVENT
BELT: 52 px/s
COMBO0
-
TRUCK TARGET: FEMALE
-

CHICK SORTER v27.20

-

Build, expand, connect at least one valid EGG route, then start the next day.

+

CHICK SORTER v28.21

@@ -53,11 +51,12 @@ - + +
@@ -94,6 +93,7 @@ +
@@ -110,6 +110,6 @@ - + diff --git a/package-lock.json b/package-lock.json index f368279..2c9dd91 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "zunda-shiwake", - "version": "27.20.0", + "version": "28.2.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "zunda-shiwake", - "version": "27.20.0", + "version": "28.2.1", "devDependencies": { "esbuild": "^0.25.0" } diff --git a/package.json b/package.json index d948287..8d03f46 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,12 @@ { "name": "zunda-shiwake", - "version": "27.20.0", + "version": "28.2.1", "private": true, "type": "module", "scripts": { "clean": "node -e \"require('fs').rmSync('dist', { recursive: true, force: true })\"", - "build": "npm run clean && esbuild src/game.js --bundle --format=esm --target=es2020 --minify --outfile=dist/game.js" + "build": "npm run clean && esbuild src/game.js --bundle --format=esm --target=es2020 --minify --outfile=dist/game.js", + "test": "node test_v28_21.mjs" }, "devDependencies": { "esbuild": "^0.25.0" diff --git a/src/core/balance.js b/src/core/balance.js index 5713af2..2de476e 100644 --- a/src/core/balance.js +++ b/src/core/balance.js @@ -1,7 +1,7 @@ // Central balance sheet for tuning gameplay. // Edit this file first when adjusting prices, income, penalties, timing, card rates, or caps. export const BALANCE = { - version: 'v27.20 CARD + EXPANSION PATCH', + version: 'v28.21 BOOST DRAW HOTFIX', time: { daySeconds: 60, farmShutdownGraceSeconds: 10 @@ -18,9 +18,9 @@ export const BALANCE = { expansion: { colsPerPurchase: 10, rowsPerPurchase: 10, - costBase: 1000, - costMultiplier: 4 / 3, - truncateUnit: 100 + costBase: 850, + costGrowthRate: 0.75, + truncateUnit: 50 } }, map: { @@ -31,7 +31,8 @@ export const BALANCE = { economy: { income: { mixer: 5, - truck: 10 + truck: 10, + sausage: 26 }, poopFine: 10, fairiesTribute: { @@ -45,7 +46,21 @@ export const BALANCE = { maleTruckFinePerHalfDay: 30, shredderBonus: { maxCards: 30, - incomePerUpgrade: 1.25 + payoutCoefficient: 1.6, + payoutExponent: 1.25, + baseHitChance: 0.28, + hitChancePerUpgrade: 0.018, + maxHitChance: 0.82, + jackpotBaseChance: 0.01, + jackpotChancePerUpgrade: 0.0025, + jackpotMaxChance: 0.08, + bigWinBaseChance: 0.07, + bigWinChancePerUpgrade: 0.0015, + bigWinMaxChance: 0.12, + doubleChance: 0.20, + jackpotMultiplier: 10, + bigWinMultiplier: 4, + doubleMultiplier: 2 }, chemicalWeaponSubsidy: { poopPerBlock: 70, @@ -54,7 +69,7 @@ export const BALANCE = { }, production: { poopRate: 0.08, - autoScannerCooldown: 3.5, + autoScannerCooldown: 1.5, autoScannerUpgradeRate: 0.95, autoScannerCardUpgradeRate: 0.95, autoScannerMinCooldown: 0.5, @@ -71,6 +86,9 @@ export const BALANCE = { maxSpeed: 300, bearingSpeedMultiplier: 1.075 }, + effects: { + explosionHorizontalVelocityMultiplier: 0.82 + }, cards: { definitions: [ { @@ -97,6 +115,7 @@ export const BALANCE = { rarity: 'common', type: 'instant', description: 'All AUTO SCANNER cooldowns use default cooldown x0.95 per copy.', + requiresFacility: 'autoScanner', tags: ['SCANNER', 'PASSIVE'] }, { @@ -105,7 +124,7 @@ export const BALANCE = { rarity: 'common', type: 'equipmentUpgrade', target: 'mixer', - description: 'Choose MIXER on the map and raise it by 1 level.', + description: 'Choose one MIXER. Each level improves meat quality and raises sausage sale value by 10%.', tags: ['ECONOMY', 'ACTIVE'] }, { @@ -117,13 +136,22 @@ export const BALANCE = { description: 'Choose TRUCK on the map and raise it by 1 level.', tags: ['ECONOMY', 'ACTIVE'] }, + { + id: 'upgradeSausageMaker', + title: 'SAUSAGE MACHINE Improvement', + rarity: 'common', + type: 'equipmentUpgrade', + target: 'sausageMaker', + description: 'Choose one SAUSAGE MACHINE. Each level raises sausage sale value by 10%.', + tags: ['ECONOMY', 'SAUSAGE', 'ACTIVE'] + }, { id: 'upgradeTrash', title: 'SHREDDER Improvement', rarity: 'common', type: 'equipmentUpgrade', target: 'trash', - description: 'Shred poops for a little money. Max 30 upgrades.', + description: 'Adds a nonlinear scrap-lottery upgrade. More copies raise both payout and win chance; max 30.', tags: ['POOP', 'ACTIVE'] }, { @@ -132,6 +160,7 @@ export const BALANCE = { rarity: 'common', type: 'instant', description: 'EGG production interval -5%. Equipment deterioration +4%. Max 10 cards.', + requiresFacility: 'eggFarm', tags: ['EGG', 'RISK', 'PASSIVE'] }, { @@ -140,6 +169,7 @@ export const BALANCE = { rarity: 'common', type: 'instant', description: 'EGG production interval -4%. Poop rate +3%. No card limit.', + requiresFacility: 'eggFarm', tags: ['EGG', 'POOP', 'PASSIVE'] }, { @@ -164,6 +194,7 @@ export const BALANCE = { rarity: 'common', type: 'instant', description: 'All equipment deterioration speed -5%. No card limit.', + requiresAnyFacility: ['conveyor', 'eggFarm', 'autoScanner', 'manualScanner', 'mixer', 'trash', 'sausageMaker'], tags: ['MAINTENANCE', 'PASSIVE'] }, { @@ -180,6 +211,7 @@ export const BALANCE = { rarity: 'common', type: 'instant', description: 'All equipment maximum durability +3%. No card limit.', + requiresAnyFacility: ['conveyor', 'eggFarm', 'autoScanner', 'manualScanner', 'mixer', 'trash', 'sausageMaker'], tags: ['MAINTENANCE', 'PASSIVE'] }, { @@ -188,6 +220,7 @@ export const BALANCE = { rarity: 'common', type: 'instant', description: 'Conveyor speed +7.5%.', + requiresFacility: 'conveyor', tags: ['CONVEYOR', 'PASSIVE'] }, { @@ -196,6 +229,7 @@ export const BALANCE = { rarity: 'common', type: 'instant', description: 'Restores 2% durability to every machine. A box of almost-compatible parts.', + requiresAnyFacility: ['conveyor', 'eggFarm', 'autoScanner', 'manualScanner', 'mixer', 'trash', 'sausageMaker'], tags: ['MAINTENANCE', 'ACTIVE'] }, { @@ -220,6 +254,7 @@ export const BALANCE = { rarity: 'common', type: 'instant', description: 'Turns shredder waste into suspicious fertilizer. Gain JPY 3 per copy when SHREDDER processes poop.', + requiresFacility: 'trash', tags: ['POOP', 'ECONOMY', 'PASSIVE'] }, { @@ -228,6 +263,7 @@ export const BALANCE = { rarity: 'common', type: 'instant', description: 'Manual and Auto Scanner queue spacing -15%. No card limit.', + requiresAnyFacility: ['manualScanner', 'autoScanner'], tags: ['SCANNER', 'PASSIVE'] }, { @@ -253,7 +289,7 @@ export const BALANCE = { rarity: 'rare', type: 'cellAction', target: 'blockedCell', - description: 'Choose and remove up to 10 unbuildable cells.', + description: 'Choose and remove up to 3 unbuildable cells.', tags: ['RISK', 'RARE', 'ONE-SHOT'] }, { @@ -369,11 +405,13 @@ export const BALANCE = { eggFarm: 475, autoScanner: 850, mixer: 775, - trash: 950 + trash: 950, + sausageMaker: 825 }, processingDelayMaxSeconds: { mixer: 1.20, - trash: 1.00 + trash: 1.00, + sausageMaker: 0.90 }, repairman: { secondsPerOnePercent: 0.5, @@ -413,6 +451,10 @@ export const BALANCE = { id: 'truck', type: 'facility', name: 'Truck', shortName: 'TRUCK', price: 450, buildable: true, upgradeable: true, incomeKey: 'truck', body: { w: 176, h: 138 } }, + sausageMaker: { + id: 'sausageMaker', type: 'facility', name: 'Sausage Machine', shortName: 'SAUSAGE', price: 380, + buildable: true, upgradeable: true, incomeKey: 'sausage', footprint: { cols: 3, rows: 3 }, body: { w: 138, h: 138 }, outputProduct: 'sausage' + }, maintenanceRoom: { id: 'maintenanceRoom', type: 'maintenanceRoom', name: 'Maintenance Room', shortName: 'REPAIR ROOM', price: 220, buildable: true, upgradeable: false, footprint: { cols: 2, rows: 2 } diff --git a/src/core/config.js b/src/core/config.js index dfa135f..60aa59a 100644 --- a/src/core/config.js +++ b/src/core/config.js @@ -26,9 +26,12 @@ export const EGG_SPAWN_RANGES = BALANCE.production.eggSpawnRanges; export const GRID = BALANCE.grid; export const FACILITY_DEFS = BALANCE.facilities; -export const BUILD_TOOL_IDS = ['conveyor', 'boostConveyor', 'eggFarm', 'autoScanner', 'manualScanner', 'mixer', 'trash', 'truck', 'maintenanceRoom']; -export const MACHINE_FACILITY_IDS = ['mixer', 'trash', 'truck']; -export const INCOME_FACILITY_IDS = ['mixer', 'truck']; +export const BUILD_TOOL_IDS = ['conveyor', 'boostConveyor', 'eggFarm', 'autoScanner', 'manualScanner', 'mixer', 'trash', 'truck', 'sausageMaker', 'maintenanceRoom']; +export const EDGE_FACILITY_IDS = ['mixer', 'trash', 'truck']; +export const GRID_FACILITY_IDS = ['sausageMaker']; +export const MACHINE_FACILITY_IDS = [...EDGE_FACILITY_IDS, ...GRID_FACILITY_IDS]; +export const REQUIRED_RECEIVER_FACILITY_IDS = ['mixer', 'trash', 'truck']; +export const INCOME_FACILITY_IDS = ['mixer', 'truck', 'sausageMaker']; export const BUILD_COSTS = Object.fromEntries(Object.entries(FACILITY_DEFS).map(([id, def]) => [id, def.price])); @@ -48,6 +51,8 @@ export const THEME = { mixerBlue: '#4aa3ff', truckPink: '#ffb33e', wasteGreen: '#88d35a', + meatRed: '#d96b72', + sausageOrange: '#d78b3f', danger: '#e34a36', warn: '#ffb827', white: '#e6edf2', diff --git a/src/core/entities.js b/src/core/entities.js index 75d699e..9faf1dc 100644 --- a/src/core/entities.js +++ b/src/core/entities.js @@ -1,4 +1,5 @@ import { BUILD_COSTS, FACILITY_DEFS, GRID } from './config.js'; +import { isOwnedCell } from './gridExpansion.js'; import { nextSpawnDelay } from './state.js'; import { currentPoopRate } from '../systems/events.js'; @@ -49,7 +50,45 @@ export function createScanner(game, col, row, kind) { }; } -export function nearestGridEdge(point) { +function distanceToSegment(point, a, b) { + const dx = b.x - a.x; + const dy = b.y - a.y; + const len2 = dx * dx + dy * dy; + const t = len2 > 0 ? Math.max(0, Math.min(1, ((point.x - a.x) * dx + (point.y - a.y) * dy) / len2)) : 0; + const x = a.x + dx * t; + const y = a.y + dy * t; + return Math.hypot(point.x - x, point.y - y); +} + +function ownedBoundaryEdges(game) { + const edges = []; + const cells = game?.ownedCells?.size + ? [...game.ownedCells].map(k => { + const [col, row] = String(k).split(',').map(Number); + return { col, row }; + }) + : Array.from({ length: GRID.cols * GRID.rows }, (_, i) => ({ col: i % GRID.cols, row: Math.floor(i / GRID.cols) })); + for (const cell of cells) { + const x0 = GRID.x + cell.col * GRID.cell; + const y0 = GRID.y + cell.row * GRID.cell; + const x1 = x0 + GRID.cell; + const y1 = y0 + GRID.cell; + if (!isOwnedCell(game, cell.col - 1, cell.row)) edges.push({ side: 'left', entry: cell, a: { x: x0, y: y0 }, b: { x: x0, y: y1 } }); + if (!isOwnedCell(game, cell.col + 1, cell.row)) edges.push({ side: 'right', entry: cell, a: { x: x1, y: y0 }, b: { x: x1, y: y1 } }); + if (!isOwnedCell(game, cell.col, cell.row - 1)) edges.push({ side: 'top', entry: cell, a: { x: x0, y: y0 }, b: { x: x1, y: y0 } }); + if (!isOwnedCell(game, cell.col, cell.row + 1)) edges.push({ side: 'bottom', entry: cell, a: { x: x0, y: y1 }, b: { x: x1, y: y1 } }); + } + return edges; +} + +export function nearestGridEdge(point, game = null) { + const boundary = ownedBoundaryEdges(game); + if (boundary.length) { + const best = boundary + .map(edge => ({ ...edge, distance: distanceToSegment(point, edge.a, edge.b) })) + .sort((a, b) => a.distance - b.distance)[0]; + return { side: best.side, entry: { ...best.entry } }; + } const colFloat = (point.x - GRID.x) / GRID.cell; const rowFloat = (point.y - GRID.y) / GRID.cell; const col = Math.max(0, Math.min(GRID.cols - 1, Math.round(colFloat - 0.5))); @@ -65,20 +104,83 @@ export function nearestGridEdge(point) { return { side, entry: { col, row: GRID.rows - 1 } }; } +function facilityKind(facility) { return facility?.baseId || facility?.id || ''; } + +export function syncGridFacilityGeometry(facility) { + if (!facility?.gridPlaced) return facility; + facility.wCells = Math.max(1, facility.wCells || 3); + facility.hCells = Math.max(1, facility.hCells || 3); + facility.x = GRID.x + facility.col * GRID.cell; + facility.y = GRID.y + facility.row * GRID.cell; + facility.w = facility.wCells * GRID.cell; + facility.h = facility.hCells * GRID.cell; + if (facilityKind(facility) === 'sausageMaker') { + facility.entry = { col: facility.col - 1, row: facility.row + Math.floor(facility.hCells / 2) }; + facility.side = 'grid'; + } + return facility; +} + +export function gridFacilityFootprintCells(facility) { + if (!facility?.gridPlaced) return []; + const cells = []; + for (let dr = 0; dr < (facility.hCells || 3); dr += 1) { + for (let dc = 0; dc < (facility.wCells || 3); dc += 1) cells.push({ col: facility.col + dc, row: facility.row + dr }); + } + return cells; +} + +function orientEdgeFacility(facility, side) { + if (facilityKind(facility) !== 'mixer') return; + const baseW = facility.baseW || facility.w || 168; + const baseH = facility.baseH || facility.h || 110; + facility.baseW = baseW; + facility.baseH = baseH; + const horizontal = side === 'top' || side === 'bottom'; + facility.w = horizontal ? Math.max(baseW, baseH) : Math.min(baseW, baseH); + facility.h = horizontal ? Math.min(baseW, baseH) : Math.max(baseW, baseH); +} + +export function facilityBodyPortPoint(facility, type = 'input') { + if (!facility) return null; + const kind = facilityKind(facility); + if (kind === 'mixer') { + const horizontal = facility.side === 'top' || facility.side === 'bottom'; + if (horizontal) return type === 'input' + ? { x: facility.x + facility.w / 2, y: facility.y } + : { x: facility.x + facility.w / 2, y: facility.y + facility.h }; + return type === 'input' + ? { x: facility.x, y: facility.y + facility.h / 2 } + : { x: facility.x + facility.w, y: facility.y + facility.h / 2 }; + } + if (kind === 'sausageMaker' && facility.gridPlaced) { + return type === 'input' + ? { x: facility.x, y: facility.y + facility.h / 2 } + : { x: facility.x + facility.w, y: facility.y + facility.h / 2 }; + } + return { x: facility.x + facility.w / 2, y: facility.y + facility.h / 2 }; +} + export function layoutFacilityOnEdge(facility, entry, side) { - const center = { x: GRID.x + entry.col * GRID.cell + GRID.cell / 2, y: GRID.y + entry.row * GRID.cell + GRID.cell / 2 }; - const edge = { left: GRID.x, right: GRID.x + GRID.cols * GRID.cell, top: GRID.y, bottom: GRID.y + GRID.rows * GRID.cell }; + orientEdgeFacility(facility, side); + const cell = { + x0: GRID.x + entry.col * GRID.cell, + y0: GRID.y + entry.row * GRID.cell, + x1: GRID.x + (entry.col + 1) * GRID.cell, + y1: GRID.y + (entry.row + 1) * GRID.cell + }; + const center = { x: (cell.x0 + cell.x1) / 2, y: (cell.y0 + cell.y1) / 2 }; facility.entry = { ...entry }; facility.side = side; - if (side === 'left') { facility.x = edge.left - facility.w - 18; facility.y = center.y - facility.h / 2; } - else if (side === 'right') { facility.x = edge.right + 18; facility.y = center.y - facility.h / 2; } - else if (side === 'top') { facility.x = center.x - facility.w / 2; facility.y = edge.top - facility.h - 18; } - else { facility.x = center.x - facility.w / 2; facility.y = edge.bottom + 18; } + if (side === 'left') { facility.x = cell.x0 - facility.w - 18; facility.y = center.y - facility.h / 2; } + else if (side === 'right') { facility.x = cell.x1 + 18; facility.y = center.y - facility.h / 2; } + else if (side === 'top') { facility.x = center.x - facility.w / 2; facility.y = cell.y0 - facility.h - 18; } + else { facility.x = center.x - facility.w / 2; facility.y = cell.y1 + 18; } return facility; } export function createFacility(game, id, p, price) { - const { entry, side } = nearestGridEdge(p); + const { entry, side } = nearestGridEdge(p, game); const def = FACILITY_DEFS[id]; const spec = def ? { name: def.name, w: def.body?.w || 168, h: def.body?.h || 110, price: def.price } @@ -86,7 +188,7 @@ export function createFacility(game, id, p, price) { const f = { type: 'facility', id, name: spec.name, - x: 0, y: 0, w: spec.w, h: spec.h, + x: 0, y: 0, w: spec.w, h: spec.h, baseW: spec.w, baseH: spec.h, level: 1, price: price || spec.price, builtSession: game.buildSession @@ -95,6 +197,24 @@ export function createFacility(game, id, p, price) { } +export function createGridFacility(game, id, col, row, price) { + const def = FACILITY_DEFS[id]; + const f = { + type: 'facility', id, + name: def?.name || id, + baseId: id, + col, row, + wCells: id === 'sausageMaker' ? 3 : 1, + hCells: id === 'sausageMaker' ? 3 : 1, + gridPlaced: true, + level: 1, + price: price || def?.price || 0, + builtSession: game.buildSession + }; + return syncGridFacilityGeometry(f); +} + + export function maintenanceRoomFootprint(room) { if (!room) return []; return [ diff --git a/src/core/gridExpansion.js b/src/core/gridExpansion.js index b52f328..febbe9f 100644 --- a/src/core/gridExpansion.js +++ b/src/core/gridExpansion.js @@ -15,17 +15,20 @@ function parseChunkKey(value) { export function expansionCost(game) { const cfg = BALANCE.grid.expansion || {}; const purchaseCount = Math.max(1, (game.gridExpansionPurchases || 0) + 1); - const raw = (cfg.costBase || 1000) * purchaseCount * (cfg.costMultiplier || (4 / 3)); - const unit = Math.max(1, cfg.truncateUnit || 100); + const base = Math.max(0, Number(cfg.costBase) || 850); + const growth = Math.max(0, Number(cfg.costGrowthRate) || 0.75); + const raw = base * (1 + growth * (purchaseCount - 1)); + const unit = Math.max(1, cfg.truncateUnit || 50); return Math.floor(raw / unit) * unit; } export function resetOwnedCells(game) { game.ownedCells = new Set(); game.ownedChunks = new Set(); + game.gridChunkOriginX = 0; game.gridChunkOriginY = 0; game.gridExpansionPurchases = 0; - game.gridExpansionPurchasesByDirection = { right: 0, up: 0, down: 0 }; + game.gridExpansionPurchasesByDirection = { left: 0, right: 0, up: 0, down: 0 }; for (let chunkY = 0; chunkY < INITIAL_CHUNKS_Y; chunkY += 1) { for (let chunkX = 0; chunkX < INITIAL_CHUNKS_X; chunkX += 1) game.ownedChunks.add(chunkKey(chunkX, chunkY)); } @@ -41,7 +44,8 @@ export function ensureOwnedChunks(game) { const originY = game.gridChunkOriginY || 0; for (const k of game.ownedCells) { const p = parseKey(k); - const chunkX = Math.floor(p.col / GRID_CHUNK_SIZE); + const originX = game.gridChunkOriginX || 0; + const chunkX = Math.floor(p.col / GRID_CHUNK_SIZE) + originX; const chunkY = Math.floor(p.row / GRID_CHUNK_SIZE) + originY; game.ownedChunks.add(chunkKey(chunkX, chunkY)); } @@ -63,13 +67,14 @@ export function countOwnedCells(game) { } export function lotFromChunk(game, chunkX, chunkY, direction = 'up') { + const originX = game.gridChunkOriginX || 0; const originY = game.gridChunkOriginY || 0; return { direction, key: chunkKey(chunkX, chunkY), chunkX, chunkY, - colStart: chunkX * GRID_CHUNK_SIZE, + colStart: (chunkX - originX) * GRID_CHUNK_SIZE, rowStart: (chunkY - originY) * GRID_CHUNK_SIZE, cols: GRID_CHUNK_SIZE, rows: GRID_CHUNK_SIZE @@ -81,17 +86,17 @@ export function expansionLots(game) { const candidates = new Map(); for (const k of owned) { const { chunkX, chunkY } = parseChunkKey(k); + const left = { chunkX: chunkX - 1, chunkY, direction: 'left' }; const right = { chunkX: chunkX + 1, chunkY, direction: 'right' }; const up = { chunkX, chunkY: chunkY - 1, direction: 'up' }; const down = { chunkX, chunkY: chunkY + 1, direction: 'down' }; - for (const candidate of [right, up, down]) { - if (candidate.chunkX < 0) continue; + for (const candidate of [left, right, up, down]) { const ck = chunkKey(candidate.chunkX, candidate.chunkY); if (owned.has(ck) || candidates.has(ck)) continue; candidates.set(ck, lotFromChunk(game, candidate.chunkX, candidate.chunkY, candidate.direction)); } } - const directionOrder = { right: 0, up: 1, down: 2 }; + const directionOrder = { left: 0, right: 1, up: 2, down: 3 }; return [...candidates.values()].sort((a, b) => { const dir = (directionOrder[a.direction] ?? 9) - (directionOrder[b.direction] ?? 9); if (dir) return dir; @@ -157,6 +162,24 @@ export function shiftRowIndexedMap(map, rowDelta) { return next; } +export function shiftColIndexedSet(set, colDelta) { + const next = new Set(); + for (const k of set || []) { + const p = parseKey(k); + next.add(key(p.col + colDelta, p.row)); + } + return next; +} + +export function shiftColIndexedMap(map, colDelta) { + const next = new Map(); + for (const [k, v] of map || []) { + const p = parseKey(k); + next.set(key(p.col + colDelta, p.row), v); + } + return next; +} + export function ownChunk(game, chunkX, chunkY) { ensureOwnedChunks(game).add(chunkKey(chunkX, chunkY)); } diff --git a/src/core/state.js b/src/core/state.js index 783cd54..0e87cde 100644 --- a/src/core/state.js +++ b/src/core/state.js @@ -21,6 +21,10 @@ export function newTurnStats() { pendingTruckRevenue: 0, mixerRevenue: 0, truckRevenue: 0, + sausageRevenue: 0, + meatProduced: 0, + sausageProduced: 0, + sausageShipped: 0, chickShipmentIncome: 0, poopShipmentIncome: 0, manualComboBonus: 0, @@ -62,6 +66,9 @@ export function newTotalStats() { poopTruck: 0, poopTrash: 0, poopMixer: 0, + meatProduced: 0, + sausageProduced: 0, + sausageShipped: 0, explosionDamage: 0, shredderBonus: 0, eventBonus: 0, @@ -102,7 +109,8 @@ export function createGame() { gridCols: BALANCE.grid.cols, gridRows: BALANCE.grid.rows, gridExpansionPurchases: 0, - gridExpansionPurchasesByDirection: { right: 0, up: 0 }, + gridExpansionPurchasesByDirection: { left: 0, right: 0, up: 0, down: 0 }, + gridChunkOriginX: 0, gridChunkOriginY: 0, ownedCells: new Set(), blockedCells: new Set(), @@ -136,6 +144,19 @@ export function createGame() { factoryGraphSnapshot: null, mixerHalfTimer: 0, congestion: new Map(), + componentLookup: new Map(), + frameId: 0, + frameCache: { + frameId: -1, + routingVersion: -1, + chickRevision: 0, + spatialRevision: -1, + spatial: new Map(), + congestionFrame: -1, + componentChicks: new Map(), + manualMonitorSignature: '', + draw: {} + }, lastExplodedComponent: new Map(), eventOffer: null, eventActive: null, @@ -171,7 +192,14 @@ function facilityBodyForEntry(id, entry, side) { else if (side === 'right') { x = g.right + 18; y = c.y - spec.h / 2; } else if (side === 'bottom') { x = c.x - spec.w / 2; y = g.bottom + 18; } else if (side === 'top') { x = c.x - spec.w / 2; y = g.top - spec.h - 18; } - return { type: 'facility', id, name: spec.name, x, y, w: spec.w, h: spec.h, level: 1, price: spec.price, entry: { ...entry }, side }; + const facility = { type: 'facility', id, name: spec.name, x, y, w: spec.w, h: spec.h, baseW: spec.w, baseH: spec.h, level: 1, price: spec.price, entry: { ...entry }, side }; + if (id === 'mixer' && (side === 'left' || side === 'right')) { + facility.w = Math.min(spec.w, spec.h); + facility.h = Math.max(spec.w, spec.h); + if (side === 'left') { facility.x = g.left - facility.w - 18; facility.y = c.y - facility.h / 2; } + else { facility.x = g.right + 18; facility.y = c.y - facility.h / 2; } + } + return facility; } export function defaultFacilities() { @@ -263,9 +291,7 @@ function scannerBodyCells(scanner) { { col: scanner.col, row: scanner.row - 1 }, { col: scanner.col + 1, row: scanner.row - 1 }, { col: scanner.col, row: scanner.row }, - { col: scanner.col + 1, row: scanner.row }, - { col: scanner.col, row: scanner.row + 1 }, - { col: scanner.col + 1, row: scanner.row + 1 } + { col: scanner.col + 1, row: scanner.row } ].filter(p => inGrid(p.col, p.row)); } diff --git a/src/core/text.js b/src/core/text.js index fb14317..1835764 100644 --- a/src/core/text.js +++ b/src/core/text.js @@ -33,6 +33,7 @@ export const TEXT = { mixer: 'MIXER', truck: 'TRUCK', trash: 'WASTE', + sausageMaker: 'SAUSAGE', scanner: 'NEXT', 'scanner-role-1': 'NEXT', input: 'IN' @@ -66,19 +67,37 @@ export function buildToolFlavorText(id) { conveyor: 'A narrow green belt. Routes decide whether chicks live, ship, or become invoices.', boostConveyor: 'Moves chicks twice as fast. Wears down like a normal belt.', eggFarm: 'A tiny gatehouse producing questionable eggs on schedule.', - autoScanner: 'Slower than hands without upgrades.', + autoScanner: 'Processes about 40 items per day at Lv1, roughly 2.1 Lv1 farms.', manualScanner: 'A manual checkpoint. The operator is the algorithm.', - mixer: 'Male chicks become revenue here. Do not feed it poop.', + mixer: 'Makes meat when OUT is clear; otherwise falls back to direct sale.', trash: 'A polite shredder for poop and other regrets.', - truck: 'Ships the target cargo. Wrong cargo still leaves a paper trail.', + truck: 'Ships target chicks and all sausages. Wrong live cargo still leaves a paper trail.', + sausageMaker: 'A 3×3 grid machine. Left inlet takes 2 meat; right outlet emits 1 sausage.', maintenanceRoom: '2×2 repair bay. Each room dispatches one repairman during the day.' }; return flavors[id] || ''; } +function buildToolIconSrc(id) { + const icons = { + conveyor: './assets/dark_factory/facilities/conveyor/conveyor_straight_h_16.png', + boostConveyor: './assets/dark_factory/facilities/conveyor/boost_conveyor_straight_h_16.png', + eggFarm: './assets/dark_factory/facilities/machines/egg_farm_16.png?v=dark_factory', + autoScanner: './assets/dark_factory/facilities/machines/auto_scanner_32x48.png', + manualScanner: './assets/dark_factory/facilities/machines/manual_scanner_32x48.png', + mixer: './assets/dark_factory/facilities/machines/mixer_32.png', + trash: './assets/dark_factory/facilities/machines/shredder_32.png', + truck: './assets/dark_factory/facilities/vehicles/truck_32.png', + sausageMaker: './assets/dark_factory/facilities/machines/mixer_32.png', + maintenanceRoom: './assets/dark_factory/facilities/utility/maintenance_room_32.png' + }; + return icons[id] || ''; +} + export function buildToolButtonHtml(id) { const flavor = buildToolFlavorText(id); - return `${equipmentName(id)}${buildToolPriceText(id)}${flavor ? `${flavor}` : ''}`; + const icon = buildToolIconSrc(id); + return `${icon ? `` : ''}${equipmentName(id)}${buildToolPriceText(id)}${flavor ? `${flavor}` : ''}`; } export function routeLabel(dest) { diff --git a/src/game.js b/src/game.js index 6915b84..2b73711 100644 --- a/src/game.js +++ b/src/game.js @@ -1,9 +1,9 @@ -import { GRID, TURN_SECONDS, THEME } from './core/config.js'; +import { GRID, THEME } from './core/config.js'; import { buildToolButtonHtml } from './core/text.js'; import { createGame, resetLayout, newTurnStats } from './core/state.js'; import { clamp, pointToCell, cellCenter, key, yen } from './core/utils.js'; import { expansionLots, lotBounds } from './core/gridExpansion.js'; -import { commitFactoryGraphForDay, facilityConnectionIssues, scannerConnector } from './systems/routing.js'; +import { commitFactoryGraphForDay, disconnectedBuildWarnings, facilityConnectionIssues, scannerConnector } from './systems/routing.js'; import { applyRevenue, collectChemicalWeaponSubsidy, collectFairiesTribute, settleTruckRevenue } from './systems/economy.js'; import { undo, redo } from './systems/history.js'; import { drawAll } from './render/draw.js'; @@ -12,7 +12,7 @@ import { createUISystem } from './systems/uiSystem.js'; import { createChickSystem } from './systems/chickSystem.js'; import { CARD_DEFS, cardById, conveyorSpeedForGame, createCardSystem, debugCardTargets, debugGrantCard } from './systems/cards.js'; import { floating, shockwave, sparkBurst, updateEffects } from './systems/effects.js'; -import { rollEventOffer, activateEventOffer, clearActiveEvent, resolveEvent, eventDaySeconds, fairiesTributeMultiplierFromEvent } from './systems/events.js'; +import { EVENT_TARGETS, createEventOffer, rollEventOffer, activateEventOffer, clearActiveEvent, resolveEvent, eventDaySeconds, fairiesTributeMultiplierFromEvent } from './systems/events.js'; import { ensureMaintenanceState, activateRepairmanForDay, deactivateRepairman, conveyorSpeedFactorForKey } from './systems/maintenance.js'; const canvas = document.getElementById('gameCanvas'); @@ -21,7 +21,7 @@ const ctx = canvas.getContext('2d'); const ui = { shell: document.getElementById('gameShell'), money: document.getElementById('money'), turn: document.getElementById('turn'), timeLeft: document.getElementById('timeLeft'), phase: document.getElementById('phaseLabel'), comboCount: document.getElementById('comboCount'), - eventBrief: document.getElementById('eventBrief'), targetBrief: document.getElementById('targetBrief'), speedBrief: document.getElementById('speedBrief'), + eventBrief: document.getElementById('eventBrief'), speedBrief: document.getElementById('speedBrief'), turnProfit: document.getElementById('turnProfit'), mixerCount: document.getElementById('mixerCount'), truckFemaleCount: document.getElementById('truckFemaleCount'), truckMaleCount: document.getElementById('truckMaleCount'), poopCount: document.getElementById('poopCount'), buildStatus: document.getElementById('buildStatus'), turnSummary: document.getElementById('turnSummary'), modal: document.getElementById('modal'), modalTitle: document.getElementById('modalTitle'), modalBody: document.getElementById('modalBody'), modalActions: document.getElementById('modalActions'), @@ -35,13 +35,14 @@ const ui = { zeroTimer: document.getElementById('debugZeroTimerButton'), cardSelect: document.getElementById('debugCardSelect'), targetSelect: document.getElementById('debugTargetSelect'), + eventSelect: document.getElementById('debugEventSelect'), grantCard: document.getElementById('debugGrantCardButton'), grantAllCards: document.getElementById('debugGrantAllCardsButton'), readout: document.getElementById('debugReadout') }, buttons: { s1Left: document.getElementById('scanner1MixerButton'), s1Right: document.getElementById('scanner1TruckButton'), s2Left: document.getElementById('scanner2MixerButton'), s2Right: document.getElementById('scanner2TruckButton'), - nextTurn: document.getElementById('nextTurnButton'), conveyor: document.getElementById('buildConveyorButton'), boostConveyor: document.getElementById('buildBoostConveyorButton'), eggFarm: document.getElementById('buildEggFarmButton'), autoScanner: document.getElementById('buildAutoScannerButton'), manualScanner: document.getElementById('buildManualScannerButton'), mixer: document.getElementById('buildMixerButton'), trash: document.getElementById('buildTrashButton'), truck: document.getElementById('buildTruckButton'), maintenanceRoom: document.getElementById('buildMaintenanceRoomButton'), erase: document.getElementById('eraseButton'), undo: document.getElementById('undoButton'), redo: document.getElementById('redoButton') + nextTurn: document.getElementById('nextTurnButton'), conveyor: document.getElementById('buildConveyorButton'), boostConveyor: document.getElementById('buildBoostConveyorButton'), eggFarm: document.getElementById('buildEggFarmButton'), autoScanner: document.getElementById('buildAutoScannerButton'), manualScanner: document.getElementById('buildManualScannerButton'), mixer: document.getElementById('buildMixerButton'), trash: document.getElementById('buildTrashButton'), truck: document.getElementById('buildTruckButton'), sausageMaker: document.getElementById('buildSausageMakerButton'), maintenanceRoom: document.getElementById('buildMaintenanceRoomButton'), erase: document.getElementById('eraseButton'), undo: document.getElementById('undoButton'), redo: document.getElementById('redoButton') } }; @@ -56,6 +57,7 @@ function initializeStaticText() { mixer: 'mixer', trash: 'trash', truck: 'truck', + sausageMaker: 'sausageMaker', maintenanceRoom: 'maintenanceRoom' }; for (const [buttonKey, toolId] of Object.entries(buttonToolMap)) { @@ -74,7 +76,7 @@ function debugCategoryForCard(card) { if (['safetyCover', 'preventiveMaintenance', 'durabilityCoating', 'sparePartsBin', 'laborExploitation'].includes(card.id) || tags.has('MAINTENANCE')) return 'Maintenance / Risk'; if (['dudFilter', 'dudRefund', 'freeReroll', 'extraCards'].includes(card.id) || tags.has('CARD')) return 'Card Engine'; if (tags.has('ULTRA RARE')) return 'Ultra Rare'; - if (tags.has('ECONOMY') || ['upgradeMixer', 'upgradeTruck', 'recyclingSubsidy', 'usedMachine', 'newMachine', 'flattery', 'legalWork', 'rescueLoan'].includes(card.id)) return 'Economy / Shipment'; + if (tags.has('ECONOMY') || ['upgradeMixer', 'upgradeTruck', 'upgradeSausageMaker', 'recyclingSubsidy', 'usedMachine', 'newMachine', 'flattery', 'legalWork', 'rescueLoan'].includes(card.id)) return 'Economy / Shipment'; return 'Other'; } @@ -103,9 +105,38 @@ function initializeDebugPanel() { ui.debug.cardSelect.appendChild(optGroup); } ui.debug.cardSelect.addEventListener('change', refreshDebugTargetSelect); + initializeDebugEventSelect(); refreshDebugTargetSelect(); } +function initializeDebugEventSelect() { + if (!ui.debug?.eventSelect) return; + ui.debug.eventSelect.innerHTML = ''; + const roll = document.createElement('option'); + roll.value = '__roll__'; + roll.textContent = 'Roll normally'; + ui.debug.eventSelect.appendChild(roll); + const none = document.createElement('option'); + none.value = '__none__'; + none.textContent = 'No event'; + ui.debug.eventSelect.appendChild(none); + for (const event of EVENT_TARGETS) { + const option = document.createElement('option'); + option.value = event.key; + option.textContent = event.title; + ui.debug.eventSelect.appendChild(option); + } + ui.debug.eventSelect.value = game.debugNextEventKey || '__roll__'; + ui.debug.eventSelect.addEventListener('change', debugSetNextEvent); +} + +function debugNextEventOffer() { + const key = game.debugNextEventKey || '__roll__'; + if (key === '__none__') return null; + if (key === '__roll__') return rollEventOffer(game); + return createEventOffer(game, key); +} + function refreshDebugTargetSelect() { if (!ui.debug?.targetSelect) return; const id = ui.debug.cardSelect?.value; @@ -144,9 +175,23 @@ function debugSetDay() { updateDebugReadout(`Day set to ${day}.`); } +function debugSetNextEvent() { + game.debugNextEventKey = ui.debug.eventSelect?.value || '__roll__'; + if (game.phase === 'build') { + game.eventOffer = debugNextEventOffer(); + uiSystem.updatePanels(); + uiSystem.updateUI(); + } + const label = ui.debug.eventSelect?.selectedOptions?.[0]?.textContent || 'Roll normally'; + updateDebugReadout(`Next event: ${label}.`); +} + function debugZeroTimer() { + const wasClearing = game.phase === 'running' && (game.timeLeft <= 0 || game.shutdownTimeLeft > 0 || game.cleanupTimer !== null); game.timeLeft = 0; - if (game.phase === 'running') closeFarmShutters(); + if (game.cleanupTimer !== null) game.cleanupTimer = 0; + if (wasClearing) game.shutdownTimeLeft = 0; + else if (game.phase === 'running') closeFarmShutters(); floating(game, canvas.width / 2 - game.view.x, 86 - game.view.y, 'TIMER 0', THEME.warn); uiSystem.updatePanels(); uiSystem.updateUI(); @@ -161,7 +206,7 @@ function debugGrantSelectedCard() { ui.debug.grantCard.textContent = result.ok ? 'Granted' : 'Failed'; window.setTimeout(() => { if (ui.debug.grantCard) ui.debug.grantCard.textContent = 'Grant Selected'; }, 900); } - chicks?.updateCongestion?.(); + chicks?.updateCongestion?.(game.frameId || 0); uiSystem.updatePanels(); uiSystem.updateUI(); refreshDebugTargetSelect(); @@ -171,7 +216,7 @@ function debugGrantSelectedCard() { function debugGrantAllCards() { const results = CARD_DEFS.map(card => debugGrantCard(game, card, { targetKey: '__auto__' })); const ok = results.filter(result => result.ok).length; - chicks?.updateCongestion?.(); + chicks?.updateCongestion?.(game.frameId || 0); uiSystem.updatePanels(); uiSystem.updateUI(); refreshDebugTargetSelect(); @@ -193,6 +238,7 @@ function updateDebugReadout(message = '') { yen(game.cash), `Combo ${game.manualCombo?.count || 0}`, `Event ${game.eventActive?.title || game.eventOffer?.title || 'none'}`, + `Next ${ui.debug?.eventSelect?.selectedOptions?.[0]?.textContent || 'Roll normally'}`, `Rescue ${game.cardEffects?.rescueLoanCharges || 0}`, `Chem ${game.cardEffects?.chemicalWeaponSubsidy || 0}` ].filter(Boolean).join(' | '); @@ -217,7 +263,7 @@ function startGame() { resetCameraToFactoryStart(); ensureMaintenanceState(game); uiSystem.hideModal(); - chicks.updateCongestion(); + chicks.updateCongestion(game.frameId || 0); uiSystem.updatePanels(); uiSystem.updateUI(); updateDebugReadout(); @@ -232,6 +278,7 @@ function startNextTurn() { } const issues = facilityConnectionIssues(game); if (issues.length) { + focusFirstStartIssue(); build.fail(`Cannot start: ${issues[0]}`); uiSystem.updatePanels(); return; @@ -270,7 +317,7 @@ function startNextTurn() { game.groupDrag = null; game.selectionBox = null; game.pan = null; - chicks.updateCongestion(); + chicks.updateCongestion(game.frameId || 0); uiSystem.updatePanels(); uiSystem.updateUI(); } @@ -320,7 +367,7 @@ function enterBuildPhase() { for (const scanner of game.scanners) scanner.queue = []; for (const farm of game.eggFarms) { farm.shutterProgress = 0; farm.shutterSparked = false; } deactivateRepairman(game); - game.eventOffer = rollEventOffer(game); + game.eventOffer = debugNextEventOffer(); if (cardSystem) cardSystem.prepareDraft(); game.cardTargetPick = null; game.buildTool = null; @@ -366,9 +413,11 @@ function update(timestamp) { if (!game.lastTimestamp) game.lastTimestamp = timestamp; const dt = Math.min((timestamp - game.lastTimestamp) / 1000, 0.05); game.lastTimestamp = timestamp; + game.frameId = (game.frameId || 0) + 1; + chicks.beginFrame?.(game.frameId); if (game.phase === 'running') chicks.updateRunning(dt, { closeFarmShutters, completeTurn }); updateEffects(game, dt, canvas, build.equipmentHitBoxes); - chicks.updateCongestion(); + chicks.updateCongestion(game.frameId); drawAll(ctx, canvas, game, { activeQueuedChick: chicks.activeQueuedChick, selectedObject: build.selectedObject, selectedTitle: build.selectedTitle }); applyDebugState(); uiSystem.updateUI(); @@ -434,6 +483,43 @@ function resetCameraToFactoryStart() { game.view.y = 190 - anchor.y; clampCamera(); } + +function focusCameraOnWorldPoint(point) { + if (!point) return false; + ensureView(); + const s = viewScale(); + game.view.x = canvas.width / 2 - point.x * s; + game.view.y = canvas.height / 2 - point.y * s; + clampCamera(); + return true; +} + +function warningFocusPoint(warning) { + const ref = warning?.ref; + if (!ref) return null; + if (warning.type === 'facility') return { x: ref.x + ref.w / 2, y: ref.y + ref.h / 2 }; + if (warning.type === 'eggFarm') return cellCenter(ref.col, ref.row); + if (warning.type === 'scanner') return { x: cellCenter(ref.col, ref.row).x + GRID.cell / 2, y: cellCenter(ref.col, ref.row).y }; + if (warning.type === 'maintenanceRoom') return { x: cellCenter(ref.col, ref.row).x + GRID.cell / 2, y: cellCenter(ref.col, ref.row).y + GRID.cell / 2 }; + return null; +} + +function focusFirstStartIssue() { + const warnings = disconnectedBuildWarnings(game); + const warning = warnings.find(item => item.type === 'facility') || warnings[0] || fallbackStartIssue(); + const point = warningFocusPoint(warning); + if (focusCameraOnWorldPoint(point) && warning) game.selected = { type: warning.type, id: warning.id }; +} + +function fallbackStartIssue() { + const facility = Object.values(game.facilities || {}).find(f => f?.entry && game.conveyorTiles.has(key(f.entry.col, f.entry.row))) + || Object.values(game.facilities || {})[0]; + if (facility) return { type: 'facility', id: facility.id, ref: facility }; + const scanner = game.scanners?.find(s => s); + if (scanner) return { type: 'scanner', id: scanner.id, ref: scanner }; + const farm = game.eggFarms?.[0]; + return farm ? { type: 'eggFarm', id: farm.id, ref: farm } : null; +} function startPan(event) { const p = rawCanvasPoint(event); ensureView(); game.pan = { start: p, viewX: game.view.x, viewY: game.view.y, moved: false }; } function updatePan(event) { if (!game.pan) return; @@ -530,7 +616,7 @@ function activeQueuedForScanner(scanner) { function chickDisplay(chick) { if (!chick) return 'WAIT'; - const label = chick.sex === 'poop' ? '💩 POOP' : chick.sex === 'male' ? '♂ MALE' : '♀ FEMALE'; + const label = chick.sex === 'poop' ? 'POOP' : chick.sex === 'male' ? 'M MALE' : 'F FEMALE'; return `${label}`; } @@ -541,7 +627,7 @@ function miniScannerGrid(scanner, chick) { const inputKey = inputCell ? key(inputCell.col, inputCell.row) : null; const facilityEntryCells = new Set(Object.values(game.facilities || {}).map(f => f.entry ? key(f.entry.col, f.entry.row) : null).filter(Boolean)); const activeSex = chick?.sex || ''; - const activeLabel = activeSex === 'poop' ? '💩' : activeSex === 'male' ? '♂' : activeSex === 'female' ? '♀' : ''; + const activeLabel = activeSex === 'poop' ? 'P' : activeSex === 'male' ? 'M' : activeSex === 'female' ? 'F' : ''; const cells = []; for (let row = scanner.row - 2; row <= scanner.row + 2; row += 1) { for (let col = scanner.col - 2; col <= scanner.col + 2; col += 1) { @@ -566,10 +652,10 @@ function miniScannerGrid(scanner, chick) { label = 'P'; } else if (game.conveyorTiles.has(k)) { classes.push('belt'); - label = '•'; + label = '.'; } else if (game.blockedCells?.has?.(k)) { classes.push('blocked'); - label = '×'; + label = 'X'; } cells.push(`${label}`); } @@ -585,6 +671,26 @@ function scannerIsOffscreen(scanner) { function updateManualScannerMonitor() { if (!ui.manualScannerMonitor) return; + const cache = game.frameCache || (game.frameCache = {}); + const view = game.view || {}; + const signature = [ + game.phase, + Math.round((view.x || 0) * 10), + Math.round((view.y || 0) * 10), + Math.round((view.scale || 1) * 100), + game.chicks.length, + game.scanners.map(scanner => [ + scanner.id, + scanner.kind, + scanner.col, + scanner.row, + scanner.queue?.join(',') || '', + scanner.keyPressSide || '', + Math.ceil((scanner.keyPressTime || 0) * 10) + ].join(':')).join('|') + ].join(';'); + if (cache.manualMonitorSignature === signature) return; + cache.manualMonitorSignature = signature; if (game.phase !== 'running') { ui.manualScannerMonitor.classList.remove('visible'); ui.manualScannerMonitor.innerHTML = ''; @@ -611,8 +717,8 @@ function updateManualScannerMonitor() { ${miniScannerGrid(scanner, chick)}
- - + +
`; }).join(''); @@ -631,11 +737,15 @@ ui.manualScannerMonitor?.addEventListener('click', event => { canvas.addEventListener('contextmenu', event => event.preventDefault()); canvas.addEventListener('wheel', zoomAt, { passive: false }); canvas.addEventListener('pointerdown', event => { - if (game.phase !== 'build') return; + if (!['build', 'running'].includes(game.phase)) return; + if (event.button === 2 || event.button === 1 || (game.phase === 'running' && event.button === 0)) { + canvas.setPointerCapture(event.pointerId); + startPan(event); + return; + } + if (game.phase !== 'build' || event.button !== 0) return; canvas.setPointerCapture(event.pointerId); const world = canvasPoint(event); - if (event.button === 2) { startPan(event); return; } - if (event.button !== 0) return; if (game.cardTargetPick?.mode === 'autoScannerMenu') { cancelBuildAction(); return; } if (game.cardTargetPick?.pending) { cardSystem.chooseTargetAtPoint(world); return; } const expansionOffer = build.expansionOfferAtPoint?.(world); @@ -669,9 +779,9 @@ canvas.addEventListener('pointerdown', event => { build.startSelectionBox(event); }); canvas.addEventListener('pointermove', event => { + if (game.pan && (event.buttons & 7)) updatePan(event); if (game.phase !== 'build') { hideHoverTooltip(); return; } updateHover(event); - if (game.pan && (event.buttons & 2)) updatePan(event); if (game.groupDrag && (event.buttons & 1)) build.updateGroupDrag(event); if (game.selectionBox && (event.buttons & 1)) build.updateSelectionBox(event); if ((game.buildTool === 'conveyor' || game.buildTool === 'boostConveyor') && (event.buttons & 1)) build.continueConveyorDrag(pointToCell(canvasPoint(event).x, canvasPoint(event).y)); @@ -683,7 +793,7 @@ canvas.addEventListener('pointerup', event => { if (!game.groupDrag.committed) clickSelect(event); build.finishGroupDrag(); } - if (event.button === 2 && game.pan && !game.pan.moved && game.buildTool) cancelBuildAction(); + if ((event.button === 2 || event.button === 1) && game.pan && !game.pan.moved && game.buildTool && game.phase === 'build') cancelBuildAction(); if (game.buildTool === 'conveyor' || game.buildTool === 'boostConveyor') build.endConveyorDrag?.(); game.groupDrag = null; game.pan = null; try { canvas.releasePointerCapture(event.pointerId); } catch (_) { /* noop */ } @@ -697,7 +807,7 @@ document.addEventListener('pointerdown', event => { }, true); ui.buttons.s1Left.addEventListener('click', () => chicks.sortSlot(0, 'left')); ui.buttons.s1Right.addEventListener('click', () => chicks.sortSlot(0, 'right')); ui.buttons.s2Left.addEventListener('click', () => chicks.sortSlot(1, 'left')); ui.buttons.s2Right.addEventListener('click', () => chicks.sortSlot(1, 'right')); -ui.buttons.nextTurn.addEventListener('click', startNextTurn); ui.buttons.conveyor.addEventListener('click', () => build.setBuildTool('conveyor')); ui.buttons.boostConveyor.addEventListener('click', () => build.setBuildTool('boostConveyor')); ui.buttons.eggFarm.addEventListener('click', () => build.setBuildTool('eggFarm')); ui.buttons.autoScanner.addEventListener('click', () => build.setBuildTool('autoScanner')); ui.buttons.manualScanner.addEventListener('click', () => build.setBuildTool('manualScanner')); ui.buttons.mixer.addEventListener('click', () => build.setBuildTool('mixer')); ui.buttons.trash.addEventListener('click', () => build.setBuildTool('trash')); ui.buttons.truck.addEventListener('click', () => build.setBuildTool('truck')); ui.buttons.maintenanceRoom.addEventListener('click', () => build.setBuildTool('maintenanceRoom')); ui.buttons.erase.addEventListener('click', () => build.setBuildTool('erase')); +ui.buttons.nextTurn.addEventListener('click', startNextTurn); ui.buttons.conveyor.addEventListener('click', () => build.setBuildTool('conveyor')); ui.buttons.boostConveyor.addEventListener('click', () => build.setBuildTool('boostConveyor')); ui.buttons.eggFarm.addEventListener('click', () => build.setBuildTool('eggFarm')); ui.buttons.autoScanner.addEventListener('click', () => build.setBuildTool('autoScanner')); ui.buttons.manualScanner.addEventListener('click', () => build.setBuildTool('manualScanner')); ui.buttons.mixer.addEventListener('click', () => build.setBuildTool('mixer')); ui.buttons.trash.addEventListener('click', () => build.setBuildTool('trash')); ui.buttons.truck.addEventListener('click', () => build.setBuildTool('truck')); ui.buttons.sausageMaker.addEventListener('click', () => build.setBuildTool('sausageMaker')); ui.buttons.maintenanceRoom.addEventListener('click', () => build.setBuildTool('maintenanceRoom')); ui.buttons.erase.addEventListener('click', () => build.setBuildTool('erase')); ui.debug.setDay?.addEventListener('click', debugSetDay); ui.debug.zeroTimer?.addEventListener('click', debugZeroTimer); ui.debug.grantCard?.addEventListener('click', debugGrantSelectedCard); @@ -733,4 +843,4 @@ build = createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanels: () => chicks = createChickSystem({ game, currentConveyorSpeed, onGameOverCheck: () => uiSystem?.checkGameOver() }); cardSystem = createCardSystem({ game, ui, onUpdatePanels: () => uiSystem?.updatePanels() }); uiSystem = createUISystem({ game, ui, build, startGame, beginCardDraft: () => cardSystem.showDraft(), activeQueuedChick: chicks.activeQueuedChick }); -initializeStaticText(); initializeDebugPanel(); resetLayout(game); ensureMaintenanceState(game); chicks.updateCongestion(); uiSystem.updatePanels(); uiSystem.updateUI(); uiSystem.showTitle(); updateDebugReadout(); requestAnimationFrame(update); +initializeStaticText(); initializeDebugPanel(); resetLayout(game); ensureMaintenanceState(game); chicks.updateCongestion(game.frameId || 0); uiSystem.updatePanels(); uiSystem.updateUI(); uiSystem.showTitle(); updateDebugReadout(); requestAnimationFrame(update); diff --git a/src/render/draw.js b/src/render/draw.js index 343ccd4..e5111b2 100644 --- a/src/render/draw.js +++ b/src/render/draw.js @@ -1,10 +1,11 @@ import { DIRS, GRID, THEME, EFFECT_PRIORITY, VERSION } from '../core/config.js'; import { expansionCost, expansionLots, lotBounds, expansionButtonBounds, isOwnedCell } from '../core/gridExpansion.js'; import { key, parseKey, cellCenter, mixHex, randomBetween, yen } from '../core/utils.js'; -import { scannerCenter, scannerConnector, scannerOutputs, destinationLabel, destinationColor, scannerPortHasConveyor, disconnectedBuildWarnings } from '../systems/routing.js'; -import { upgradedMixerPrice, upgradedTruckPrice } from '../systems/economy.js'; -import { cardTargetBounds } from '../systems/cards.js'; -import { wearRatio } from '../systems/maintenance.js'; +import { scannerCenter, scannerConnector, scannerOutputs, destinationLabel, destinationColor, scannerPortHasConveyor, facilityInputCell, facilityOutputCell, facilityOutputHasConveyor, disconnectedBuildWarnings } from '../systems/routing.js'; +import { upgradedTruckPrice, upgradedSausagePrice } from '../systems/economy.js'; +import { cardTargetBounds, conveyorSpeedForGame } from '../systems/cards.js'; +import { wearRatio, conveyorSpeedFactorForKey } from '../systems/maintenance.js'; +import { facilityBodyPortPoint } from '../core/entities.js'; // Optional art overlay hook. // Keep external art probing disabled by default so a clean checkout does not emit 404s for missing PNGs. @@ -33,9 +34,6 @@ const ASSET_PATHS = { mixer: './assets/dark_factory/facilities/machines/mixer_32.png', shredder: './assets/dark_factory/facilities/machines/shredder_32.png', truck: './assets/dark_factory/facilities/vehicles/truck_32.png', - mixerCompact: './assets/dark_factory/facilities/machines/mixer_compact_16.png', - shredderCompact: './assets/dark_factory/facilities/machines/shredder_compact_16.png', - truckCompact: './assets/dark_factory/facilities/vehicles/truck_compact_16.png', maintenanceRoom: './assets/dark_factory/facilities/utility/maintenance_room_32.png', repairman: './assets/dark_factory/facilities/utility/repairman_16.png', obstacleCrate: './assets/dark_factory/facilities/utility/obstacle_crate_16.png' @@ -55,10 +53,23 @@ for (const [name, src] of Object.entries(ASSET_PATHS)) { // Each draw* function first checks whether an image loaded; if not, it falls back to simple canvas shapes. +function drawCache(game) { + if (!game.frameCache) game.frameCache = {}; + if (!game.frameCache.draw) game.frameCache.draw = {}; + return game.frameCache.draw; +} + +function makeCanvas(width, height) { + const c = document.createElement('canvas'); + c.width = Math.max(1, Math.ceil(width)); + c.height = Math.max(1, Math.ceil(height)); + return c; +} + export function drawAll(ctx, canvas, game, helpers) { ctx.imageSmoothingEnabled = false; ctx.clearRect(0, 0, canvas.width, canvas.height); - drawBackground(ctx, canvas); + drawBackground(ctx, canvas, game); ctx.save(); const sx = game.shake.time > 0 ? randomBetween(-game.shake.strength, game.shake.strength) : 0; const sy = game.shake.time > 0 ? randomBetween(-game.shake.strength, game.shake.strength) : 0; @@ -190,7 +201,7 @@ function drawFloorSlime(ctx, x, y, col, row) { ctx.fill(); ctx.restore(); } -function drawBackground(ctx, canvas) { +function renderBackground(ctx, canvas) { ctx.fillStyle = THEME.bg; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.save(); @@ -208,6 +219,18 @@ function drawBackground(ctx, canvas) { for (let y = 0; y < canvas.height; y += 64) { ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(canvas.width, y); ctx.stroke(); } ctx.restore(); } + +function drawBackground(ctx, canvas, game = null) { + const cache = game ? drawCache(game) : null; + const signature = `${canvas.width}x${canvas.height}`; + if (!cache) return renderBackground(ctx, canvas); + if (!cache.background || cache.background.signature !== signature) { + const layer = makeCanvas(canvas.width, canvas.height); + renderBackground(layer.getContext('2d'), layer); + cache.background = { signature, layer }; + } + ctx.drawImage(cache.background.layer, 0, 0); +} function ownedCellKeys(game) { if (game.ownedCells?.size) return [...game.ownedCells]; const cells = []; @@ -215,7 +238,7 @@ function ownedCellKeys(game) { return cells; } -function drawGrid(ctx, game) { +function renderGrid(ctx, game) { ctx.save(); const cells = ownedCellKeys(game); for (const k of cells) { @@ -253,17 +276,17 @@ function drawGrid(ctx, game) { ctx.beginPath(); ctx.rect(Math.round(x + 1), Math.round(y + 1), GRID.cell - 2, GRID.cell - 2); ctx.clip(); - ctx.fillStyle = 'rgba(70,72,76,.16)'; + ctx.fillStyle = 'rgba(124,82,36,.36)'; ctx.fillRect(Math.round(x), Math.round(y), GRID.cell, GRID.cell); ctx.lineWidth = 6; - ctx.strokeStyle = 'rgba(165,145,73,.24)'; + ctx.strokeStyle = 'rgba(255,199,73,.72)'; for (let stripe = -GRID.cell; stripe < GRID.cell * 2; stripe += 14) { ctx.beginPath(); ctx.moveTo(x + stripe, y + GRID.cell); ctx.lineTo(x + stripe + GRID.cell, y); ctx.stroke(); } - ctx.strokeStyle = 'rgba(27,29,33,.22)'; + ctx.strokeStyle = 'rgba(18,20,24,.58)'; for (let stripe = -GRID.cell + 7; stripe < GRID.cell * 2; stripe += 14) { ctx.beginPath(); ctx.moveTo(x + stripe, y + GRID.cell); @@ -271,21 +294,70 @@ function drawGrid(ctx, game) { ctx.stroke(); } ctx.restore(); - ctx.strokeStyle = 'rgba(20,23,26,.42)'; - ctx.lineWidth = 1; + ctx.strokeStyle = 'rgba(255,213,91,.86)'; + ctx.lineWidth = 2; ctx.strokeRect(Math.round(x) + 1.5, Math.round(y) + 1.5, GRID.cell - 3, GRID.cell - 3); + ctx.strokeStyle = 'rgba(20,23,26,.82)'; + ctx.lineWidth = 1; + ctx.strokeRect(Math.round(x) + 5.5, Math.round(y) + 5.5, GRID.cell - 11, GRID.cell - 11); } ctx.restore(); } + +function gridCacheSignature(game) { + const owned = game.ownedCells?.size ? [...game.ownedCells].sort().join('|') : `default:${GRID.cols}x${GRID.rows}`; + const blocked = [...(game.blockedCells || [])].sort().join('|'); + return `${GRID.x},${GRID.y},${GRID.cols},${GRID.rows};${owned};${blocked}`; +} + +function gridLayerBounds(game) { + const cells = ownedCellKeys(game).map(parseKey); + for (const k of game.blockedCells || []) cells.push(parseKey(k)); + if (!cells.length) return { x: 0, y: 0, w: 1, h: 1 }; + const minCol = Math.min(...cells.map(p => p.col)); + const maxCol = Math.max(...cells.map(p => p.col)); + const minRow = Math.min(...cells.map(p => p.row)); + const maxRow = Math.max(...cells.map(p => p.row)); + return { + x: GRID.x + minCol * GRID.cell - 6, + y: GRID.y + minRow * GRID.cell - 6, + w: (maxCol - minCol + 1) * GRID.cell + 12, + h: (maxRow - minRow + 1) * GRID.cell + 12 + }; +} + +function drawGrid(ctx, game) { + const cache = drawCache(game); + const signature = gridCacheSignature(game); + if (!cache.grid || cache.grid.signature !== signature) { + const bounds = gridLayerBounds(game); + const layer = makeCanvas(bounds.w, bounds.h); + const layerCtx = layer.getContext('2d'); + layerCtx.translate(-bounds.x, -bounds.y); + renderGrid(layerCtx, game); + cache.grid = { signature, bounds, layer }; + } + const { bounds, layer } = cache.grid; + ctx.drawImage(layer, bounds.x, bounds.y); +} function drawExpansionOffers(ctx, game) { if (game.phase !== 'build' || game.cardDraft?.pending || game.cardTargetPick?.pending) return; const cost = expansionCost(game); const affordable = game.cash >= cost; + const lotBlockedByFacility = lot => { + const b = lotBounds(lot); + return Object.values(game.facilities || {}).some(f => { + const kind = f?.baseId || f?.id; + if (!['mixer', 'trash', 'truck'].includes(kind)) return false; + return !(b.x + b.w <= f.x || f.x + f.w <= b.x || b.y + b.h <= f.y || f.y + f.h <= b.y); + }); + }; for (const lot of expansionLots(game)) { + const disabled = lotBlockedByFacility(lot); const b = lotBounds(lot); ctx.save(); - ctx.fillStyle = affordable ? 'rgba(183,245,198,.34)' : 'rgba(255,255,255,.22)'; - ctx.strokeStyle = affordable ? THEME.green : THEME.muted; + ctx.fillStyle = disabled ? 'rgba(112,130,118,.34)' : (affordable ? 'rgba(118,226,142,.36)' : 'rgba(255,255,255,.18)'); + ctx.strokeStyle = disabled ? '#708278' : (affordable ? '#6bd579' : THEME.muted); ctx.lineWidth = 5; ctx.setLineDash([16, 10]); rect(ctx, b.x, b.y, b.w, b.h, true, true); @@ -297,17 +369,16 @@ function drawExpansionOffers(ctx, game) { ctx.strokeStyle = THEME.ink; ctx.lineWidth = 4; rect(ctx, button.x, button.y, button.w, button.h, true, true); - ctx.fillStyle = affordable ? THEME.green : THEME.danger; + ctx.fillStyle = disabled ? '#7c9285' : (affordable ? THEME.green : THEME.danger); ctx.font = '900 16px ui-monospace, monospace'; ctx.textAlign = 'center'; - const lotLabel = lot.direction === 'right' ? 'BUY RIGHT LOT' : (lot.direction === 'down' ? 'BUY LOWER LOT' : 'BUY UPPER LOT'); + const lotLabel = lot.direction === 'left' + ? 'BUY LEFT LOT' + : (lot.direction === 'right' ? 'BUY RIGHT LOT' : (lot.direction === 'down' ? 'BUY LOWER LOT' : 'BUY UPPER LOT')); ctx.fillText(lotLabel, cx, cy - 12); ctx.fillStyle = THEME.ink; ctx.font = '900 16px ui-monospace, monospace'; ctx.fillText(`${yen(cost)} / 10×10`, cx, cy + 15); - ctx.fillStyle = THEME.muted; - ctx.font = '900 11px ui-monospace, monospace'; - ctx.fillText('blocked tiles included', cx, cy + 30); ctx.restore(); } } @@ -352,7 +423,35 @@ function conveyorAssetForTile(game, k, meta = {}) { if (dirs.length === 1) return has('up') || has('down') ? assets[`${prefix}StraightV`] : assets[`${prefix}StraightH`]; return has('up') || has('down') ? assets[`${prefix}StraightV`] : assets[`${prefix}StraightH`]; } -function drawConveyors(ctx, game) { + +function conveyorCacheSignature(game) { + const assetsReady = Object.entries(assets) + .filter(([name]) => name.includes('conveyor') || name.includes('Conveyor')) + .map(([name, img]) => `${name}:${img.loaded ? 1 : 0}`) + .join('|'); + const tiles = [...game.conveyorTiles].sort().map(k => { + const meta = game.conveyorMeta.get(k) || {}; + return `${k}:${meta.kind || ''}:${meta.dir || ''}:${(meta.outDirs || []).join(',')}:${meta.branchMode || ''}`; + }).join('|'); + return `${game.routingVersion || 0};${assetsReady};${tiles}`; +} + +function conveyorLayerBounds(game) { + if (!game.conveyorTiles?.size) return { x: 0, y: 0, w: 1, h: 1 }; + const cells = [...game.conveyorTiles].map(parseKey); + const minCol = Math.min(...cells.map(p => p.col)); + const maxCol = Math.max(...cells.map(p => p.col)); + const minRow = Math.min(...cells.map(p => p.row)); + const maxRow = Math.max(...cells.map(p => p.row)); + return { + x: GRID.x + minCol * GRID.cell - 36, + y: GRID.y + minRow * GRID.cell - 36, + w: (maxCol - minCol + 1) * GRID.cell + 72, + h: (maxRow - minRow + 1) * GRID.cell + 72 + }; +} + +function conveyorRenderData(game) { const edges = []; const seen = new Set(); for (const k of game.conveyorTiles) { @@ -364,64 +463,122 @@ function drawConveyors(ctx, game) { const e = [k, nk].sort().join('|'); if (seen.has(e)) continue; seen.add(e); - const ratio = Math.max(componentRatio(game, k), componentRatio(game, nk)); - edges.push({ a: cellCenter(col, row), b: cellCenter(n.col, n.row), ratio }); + edges.push({ fromKey: k, toKey: nk, a: cellCenter(col, row), b: cellCenter(n.col, n.row) }); } } + const directionMarkers = collectConveyorDirectionMarkers(game); + const tiles = [...game.conveyorTiles].map(k => { + const p = parseKey(k); + const c = cellCenter(p.col, p.row); + const meta = game.conveyorMeta.get(k) || {}; + const connectedDirs = connectedConveyorDirs(game, k); + return { + k, + c, + meta, + connectedDirs, + branchDirs: branchSelectableExitDirs(game, k, connectedDirs), + markers: directionMarkers.get(k) || [], + sprite: conveyorAssetForTile(game, k, meta) + }; + }); + return { edges, tiles }; +} + +function renderConveyorBase(ctx, data) { ctx.save(); - ctx.lineCap = 'round'; ctx.lineJoin = 'round'; + ctx.lineCap = 'round'; + ctx.lineJoin = 'round'; for (const layer of [ { width: 31, color: '#0b0c0f', alpha: 1 }, { width: 23, color: '#444b56', alpha: 1 }, { width: 15, color: '#171a1f', alpha: 1 } ]) { - ctx.globalAlpha = layer.alpha; ctx.strokeStyle = layer.color; ctx.lineWidth = layer.width; - for (const e of edges) { ctx.beginPath(); ctx.moveTo(e.a.x, e.a.y); ctx.lineTo(e.b.x, e.b.y); ctx.stroke(); } + ctx.globalAlpha = layer.alpha; + ctx.strokeStyle = layer.color; + ctx.lineWidth = layer.width; + for (const e of data.edges) { + ctx.beginPath(); + ctx.moveTo(e.a.x, e.a.y); + ctx.lineTo(e.b.x, e.b.y); + ctx.stroke(); + } } - for (const e of edges) { - const t = Math.max(0, (e.ratio - 0.5) / 0.5); + ctx.globalAlpha = 1; + for (const tile of data.tiles) { + const { c, meta, sprite } = tile; + ctx.fillStyle = 'rgba(0,0,0,.35)'; + ctx.strokeStyle = 'rgba(255,184,39,.34)'; + ctx.lineWidth = 1; + rect(ctx, c.x - 20, c.y - 20, 40, 40, true, true); + if (!drawImageIfLoaded(ctx, sprite, c.x - 19, c.y - 19, 38, 38)) { + ctx.fillStyle = meta.kind === 'boostConveyor' ? '#315e92' : '#454b55'; + ctx.strokeStyle = THEME.ink; + ctx.lineWidth = 2; + rect(ctx, c.x - 18, c.y - 18, 36, 36, true, true); + } + } + ctx.restore(); +} + +function drawConveyors(ctx, game) { + const cache = drawCache(game); + const signature = conveyorCacheSignature(game); + if (!cache.conveyors || cache.conveyors.signature !== signature) { + const data = conveyorRenderData(game); + const bounds = conveyorLayerBounds(game); + const layer = makeCanvas(bounds.w, bounds.h); + const layerCtx = layer.getContext('2d'); + layerCtx.translate(-bounds.x, -bounds.y); + renderConveyorBase(layerCtx, data); + cache.conveyors = { signature, bounds, layer, data }; + } + const { bounds, layer, data } = cache.conveyors; + ctx.drawImage(layer, bounds.x, bounds.y); + ctx.save(); + ctx.lineCap = 'round'; ctx.lineJoin = 'round'; + for (const e of data.edges) { + const ratio = Math.max(componentRatio(game, e.fromKey), componentRatio(game, e.toKey)); + const t = Math.max(0, (ratio - 0.5) / 0.5); ctx.strokeStyle = mixHex(THEME.green, THEME.danger, t); - ctx.globalAlpha = e.ratio > 0.5 ? 0.35 + t * 0.55 : 0.8; + ctx.globalAlpha = ratio > 0.5 ? 0.35 + t * 0.55 : 0.8; ctx.lineWidth = 6; ctx.beginPath(); ctx.moveTo(e.a.x, e.a.y); ctx.lineTo(e.b.x, e.b.y); ctx.stroke(); } - const directionMarkers = collectConveyorDirectionMarkers(game); - for (const k of game.conveyorTiles) { - const c = cellCenter(...Object.values(parseKey(k))); - const meta = game.conveyorMeta.get(k) || {}; + ctx.globalAlpha = 1; + for (const tile of data.tiles) { + const { k, c, meta } = tile; const ratio = componentRatio(game, k); - const sprite = conveyorAssetForTile(game, k, meta); - const congested = ratio > 0.5; - ctx.fillStyle = congested ? 'rgba(196,36,36,.28)' : 'rgba(0,0,0,.35)'; - ctx.strokeStyle = congested ? THEME.danger : 'rgba(255,184,39,.34)'; - ctx.lineWidth = congested ? 3 : 1; - rect(ctx, c.x - 20, c.y - 20, 40, 40, true, true); - if (!drawImageIfLoaded(ctx, sprite, c.x - 19, c.y - 19, 38, 38)) { - const baseFill = meta.kind === 'boostConveyor' ? '#315e92' : '#454b55'; - ctx.fillStyle = ratio > 0.5 ? mixHex(baseFill, '#a12c2c', Math.max(0, (ratio - .5) / .5)) : baseFill; - ctx.strokeStyle = THEME.ink; ctx.lineWidth = 2; - rect(ctx, c.x - 18, c.y - 18, 36, 36, true, true); + if (ratio > 0.5) { + ctx.fillStyle = 'rgba(196,36,36,.28)'; + ctx.strokeStyle = THEME.danger; + ctx.lineWidth = 3; + rect(ctx, c.x - 20, c.y - 20, 40, 40, true, true); } - drawAnimatedConveyorStripes(ctx, c, k, meta, ratio); + drawAnimatedConveyorStripes(ctx, game, c, k, meta, ratio); drawDirtOverlay(ctx, c.x - 18, c.y - 18, 36, 36, { meta }); drawSelection(ctx, game, 'conveyor', k, c.x, c.y, 38, 38); - drawConveyorDirectionMarkers(ctx, c, directionMarkers.get(k) || []); - const connectedDirs = connectedConveyorDirs(game, k); - drawBranchModeIcon(ctx, c, meta, branchSelectableExitDirs(game, k, connectedDirs), connectedDirs); + drawConveyorDirectionMarkers(ctx, c, tile.markers); + drawBranchModeIcon(ctx, c, meta, tile.branchDirs, tile.connectedDirs); if (ratio > 0.5) label(ctx, c.x, c.y - 15, `${Math.floor(ratio * 100)}%`, THEME.danger); } ctx.restore(); } -function drawAnimatedConveyorStripes(ctx, center, tileKey, meta = {}, ratio = 0) { +export function drawAnimatedConveyorStripes(ctx, game, center, tileKey, meta = {}, ratio = 0) { + const boost = meta.kind === 'boostConveyor'; const names = [...new Set([...(Array.isArray(meta.outDirs) ? meta.outDirs : []), meta.dir].filter(Boolean))]; const primary = names[0] || 'right'; const verticalTravel = primary === 'up' || primary === 'down'; const reverse = primary === 'left' || primary === 'up'; - const boost = meta.kind === 'boostConveyor'; - const t = typeof performance !== 'undefined' ? performance.now() / (boost ? 70 : 105) : 0; - const phase = ((reverse ? -t : t) % 10 + 10) % 10; + // Stripe travel uses the same effective px/s as chicks on this exact tile, + // including Boost x2, card upgrades, events, and wear. This keeps the visual + // belt movement synchronized with item movement instead of using a fixed timer. + const effectiveSpeed = conveyorSpeedForGame(game, tileKey) * conveyorSpeedFactorForKey(game, tileKey); + const elapsedSeconds = typeof performance !== 'undefined' ? performance.now() / 1000 : 0; + const travel = elapsedSeconds * effectiveSpeed; + const phase = ((reverse ? -travel : travel) % 10 + 10) % 10; ctx.save(); ctx.beginPath(); ctx.rect(center.x - 18, center.y - 18, 36, 36); @@ -471,6 +628,7 @@ function reachableConveyorDirs(game, k, meta) { .map(d => d.name); const explicit = [...new Set([...(Array.isArray(meta.outDirs) ? meta.outDirs : []), meta.dir].filter(Boolean))] .filter(name => neighborNames.includes(name)); + if (neighborNames.length === 1 && (explicit.length ? explicit.includes(neighborNames[0]) : true) && neighborPointsIntoCell(game, p, neighborNames[0])) return []; const inferred = neighborNames; return explicit.length ? explicit : inferred; } @@ -496,7 +654,7 @@ function branchExitCandidates(game, k, dirs, connectedDirs = connectedConveyorDi const p = parseKey(k); const physicalEntrances = new Set(connectedDirs.filter(dir => neighborPointsIntoCell(game, p, dir))); const physicalExits = connectedDirs.filter(dir => !physicalEntrances.has(dir)); - if (physicalEntrances.size && physicalExits.length >= 2) return physicalExits; + if (physicalEntrances.size) return physicalExits; const explicit = dirs.filter(dir => connectedDirs.includes(dir)); if (explicit.length >= 2) return [...new Set(explicit)]; return connectedDirs; @@ -521,6 +679,7 @@ function effectiveConveyorDirs(game, k, meta) { .map(d => d.name); const explicit = [...new Set([...(Array.isArray(meta.outDirs) ? meta.outDirs : []), meta.dir].filter(Boolean))] .filter(name => neighborNames.includes(name)); + if (neighborNames.length === 1 && (explicit.length ? explicit.includes(neighborNames[0]) : true) && neighborPointsIntoCell(game, p, neighborNames[0])) return []; const inferred = neighborNames; return explicit.length ? explicit : inferred; } @@ -542,7 +701,7 @@ function drawBranchModeIcon(ctx, center, meta, dirs, connectedDirs = dirs) { ctx.fillStyle = '#020304'; if (mode !== 'random') { const d = DIRS.find(item => item.name === mode); - drawDirectionTriangle(ctx, center.x, center.y, d?.angle || 0, 9, 6); + drawDirectionTriangle(ctx, center.x, center.y - 4, d?.angle || 0, 8, 5); } else { ctx.beginPath(); ctx.moveTo(center.x - 10, center.y); @@ -554,6 +713,16 @@ function drawBranchModeIcon(ctx, center, meta, dirs, connectedDirs = dirs) { drawDirectionTriangle(ctx, center.x + 9, center.y - 9, -Math.PI / 4, 4, 3); drawDirectionTriangle(ctx, center.x + 9, center.y + 9, Math.PI / 4, 4, 3); } + if (mode === 'random') { + ctx.font = '900 9px ui-monospace, monospace'; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.lineWidth = 3; + ctx.strokeStyle = '#020304'; + ctx.fillStyle = THEME.warn; + ctx.strokeText('RND', center.x, center.y + 11); + ctx.fillText('RND', center.x, center.y + 11); + } ctx.restore(); } @@ -604,9 +773,9 @@ function drawDirectionTriangle(ctx, x, y, angle, length = 11, halfWidth = 8) { function drawScannerPortDuct(ctx, scanner, type, p, color) { const c = scannerCenter(scanner); let target = null; - if (type === 'inputA') target = { x: c.x, y: c.y - 67 }; - if (type === 'left') target = { x: c.x - 49, y: c.y + 14 }; - if (type === 'right') target = { x: c.x + 49, y: c.y + 14 }; + if (type === 'inputA') target = { x: c.x, y: c.y - 40 }; + if (type === 'left') target = { x: c.x - 42, y: c.y + 10 }; + if (type === 'right') target = { x: c.x + 42, y: c.y + 10 }; if (!target) return; const elbow = type === 'inputA' ? { x: p.x, y: target.y } @@ -716,42 +885,39 @@ function drawScanner(ctx, scanner, game) { ctx.save(); ctx.globalAlpha = Math.min(0.55, 0.16 + combo / 120); ctx.strokeStyle = combo >= 30 ? THEME.warn : THEME.green; - ctx.lineWidth = Math.min(14, 5 + Math.floor(combo / 10)); + ctx.lineWidth = Math.min(12, 4 + Math.floor(combo / 10)); ctx.shadowColor = ctx.strokeStyle; - ctx.shadowBlur = Math.min(28, 8 + combo); - rect(ctx, c.x - 54, c.y - 76, 108, 152, false, true); + ctx.shadowBlur = Math.min(24, 8 + combo); + rect(ctx, c.x - 48, c.y - 48, 96, 96, false, true); ctx.restore(); } const img = scanner.kind === 'auto' ? assets.scannerAuto : assets.scannerManual; - if (drawImageIfLoaded(ctx, img, c.x - 50, c.y - 73, 100, 146)) { - if (scanner.kind === 'auto') drawDirtOverlay(ctx, c.x - 50, c.y - 73, 100, 146, scanner); + if (drawImageIfLoaded(ctx, img, c.x - 44, c.y - 44, 88, 88)) { + if (scanner.kind === 'auto') drawDirtOverlay(ctx, c.x - 44, c.y - 44, 88, 88, scanner); else drawManualKeyboardIcon(ctx, scanner, c); - drawSelection(ctx, game, 'scanner', scanner.id, c.x, c.y, 108, 154); + drawSelection(ctx, game, 'scanner', scanner.id, c.x, c.y, 96, 96); ctx.restore(); return; } ctx.fillStyle = scanner.kind === 'auto' ? '#d8ffe2' : THEME.white; ctx.strokeStyle = THEME.ink; ctx.lineWidth = 4; - rect(ctx, c.x - 50, c.y - 73, 100, 146, true, true); + rect(ctx, c.x - 44, c.y - 44, 88, 88, true, true); ctx.fillStyle = scanner.kind === 'auto' ? THEME.green : THEME.ink; - ctx.font = '900 19px ui-monospace, monospace'; ctx.textAlign = 'center'; - ctx.fillText(`${scanner.kind === 'auto' ? 'AUTO' : `S${(scanner.slot ?? 0) + 1}`}`, c.x, c.y - 48); - ctx.font = '900 11px ui-monospace, monospace'; + ctx.font = '900 16px ui-monospace, monospace'; ctx.textAlign = 'center'; + ctx.fillText(scanner.kind === 'auto' ? 'AUTO' : `S${(scanner.slot ?? 0) + 1}`, c.x, c.y - 24); + ctx.font = '900 9px ui-monospace, monospace'; const leftKey = scanner.keys?.left?.label || (scanner.slot === 0 ? 'A' : 'Left'); const rightKey = scanner.keys?.right?.label || (scanner.slot === 0 ? 'D' : 'Right'); - ctx.fillText(scanner.role === 0 ? `${leftKey}:M ${rightKey}:NEXT` : `${leftKey}:WASTE ${rightKey}:TRUCK`, c.x, c.y - 28); + ctx.fillText(scanner.kind === 'auto' ? '2.1 FARMS' : `${leftKey}/${rightKey}`, c.x, c.y - 8); const q = scanner.queue.length; if (scanner.kind === 'manual') { drawManualKeyboardIcon(ctx, scanner, c); - ctx.fillStyle = q > 0 ? THEME.green : THEME.muted; - ctx.font = '900 10px ui-monospace, monospace'; - ctx.fillText(`Q:${q}`, c.x, c.y + 54); } else { ctx.fillStyle = q > 0 ? THEME.green : THEME.muted; - ctx.font = '900 12px ui-monospace, monospace'; - ctx.fillText(`Q:${q} CD:${scanner.cooldown.toFixed(1)}`, c.x, c.y + 54); - drawDirtOverlay(ctx, c.x - 50, c.y - 73, 100, 146, scanner); + ctx.font = '900 10px ui-monospace, monospace'; + ctx.fillText(`Q:${q} CD:${scanner.cooldown.toFixed(1)}`, c.x, c.y + 35); + drawDirtOverlay(ctx, c.x - 44, c.y - 44, 88, 88, scanner); } - drawSelection(ctx, game, 'scanner', scanner.id, c.x, c.y, 108, 154); + drawSelection(ctx, game, 'scanner', scanner.id, c.x, c.y, 96, 96); ctx.restore(); } @@ -765,7 +931,7 @@ function drawManualKeyboardIcon(ctx, scanner, c) { labels[1].text = scanner.keys?.right?.label || labels[1].text; const pressedSide = scanner.keyPressTime > 0 ? scanner.keyPressSide : null; const baseX = c.x - 30; - const baseY = c.y + 18; + const baseY = c.y + 8; ctx.save(); ctx.lineWidth = 3; ctx.fillStyle = '#f7fff5'; @@ -800,6 +966,8 @@ function targetForTruck(game) { } function drawItemIcon(ctx, x, y, type) { if (type === 'poop') drawTinyPoop(ctx, x, y); + else if (type === 'meat') drawMeatItem(ctx, x, y, 9); + else if (type === 'sausage') drawSausageItem(ctx, x, y, 10); else drawTinyChick(ctx, x, y, type, false); } function drawTargetBadge(ctx, x, y, w, title, type, subtitle = '') { @@ -823,6 +991,7 @@ function drawTargetBadge(ctx, x, y, w, title, type, subtitle = '') { function receiverTitle(id, game) { if (id === 'mixer') return { title: 'IN: MALE', type: 'male', color: THEME.mixerBlue }; if (id === 'trash') return { title: 'IN: POOP', type: 'poop', color: THEME.wasteGreen }; + if (id === 'sausageMaker') return { title: 'IN: MEAT', type: 'meat', color: THEME.sausageOrange }; if (id === 'truck') return { title: `IN: ${targetForTruck(game).toUpperCase()}`, type: targetForTruck(game), color: THEME.truckPink }; return { title: 'IN', type: 'female', color: THEME.green }; } @@ -831,10 +1000,22 @@ function facilityKind(fOrId) { } function drawFacilityReceiver(ctx, game, facility) { const f = typeof facility === 'string' ? game.facilities[facility] : facility; - if (!f?.entry) return; + const input = facilityInputCell(game, f); + if (!f || !input) return; const id = facilityKind(f); - const c = cellCenter(f.entry.col, f.entry.row); + const c = cellCenter(input.col, input.row); const info = receiverTitle(id, game); + if (f.gridPlaced) { + const bodyPort = facilityBodyPortPoint(f, 'input'); + if (bodyPort) { + ctx.save(); + ctx.strokeStyle = '#07080a'; ctx.lineWidth = 11; ctx.lineCap = 'round'; + ctx.beginPath(); ctx.moveTo(c.x, c.y); ctx.lineTo(bodyPort.x, bodyPort.y); ctx.stroke(); + ctx.strokeStyle = '#6f4a43'; ctx.lineWidth = 5; + ctx.beginPath(); ctx.moveTo(c.x, c.y); ctx.lineTo(bodyPort.x, bodyPort.y); ctx.stroke(); + ctx.restore(); + } + } ctx.save(); ctx.fillStyle = '#191c22'; ctx.strokeStyle = info.color; @@ -940,17 +1121,56 @@ function drawFacilities(ctx, game) { if (kind === 'mixer') drawMixer(ctx, game, f); else if (kind === 'trash') drawTrash(ctx, game, f); else if (kind === 'truck') drawTruck(ctx, game, f); + else if (kind === 'sausageMaker') drawSausageMaker(ctx, game, f); + } + for (const f of Object.values(game.facilities || {})) { + drawFacilityReceiver(ctx, game, f); + drawFacilityOutput(ctx, game, f); } - for (const f of Object.values(game.facilities || {})) drawFacilityReceiver(ctx, game, f); } +function drawFacilityOutput(ctx, game, f) { + const p = facilityOutputCell(game, f); + if (!p) return; + const c = cellCenter(p.col, p.row); + const bodyPort = facilityBodyPortPoint(f, 'output'); + if (bodyPort) { + ctx.save(); + ctx.strokeStyle = '#07080a'; + ctx.lineWidth = 11; + ctx.lineCap = 'round'; + ctx.beginPath(); ctx.moveTo(bodyPort.x, bodyPort.y); ctx.lineTo(c.x, c.y); ctx.stroke(); + ctx.strokeStyle = '#77524a'; ctx.lineWidth = 5; + ctx.beginPath(); ctx.moveTo(bodyPort.x, bodyPort.y); ctx.lineTo(c.x, c.y); ctx.stroke(); + ctx.restore(); + } + const kind = facilityKind(f); + const product = kind === 'mixer' ? 'meat' : 'sausage'; + const color = kind === 'mixer' ? THEME.meatRed : THEME.sausageOrange; + const connected = facilityOutputHasConveyor(game, f); + ctx.save(); + ctx.fillStyle = connected ? '#1d2423' : '#3a1e22'; + ctx.strokeStyle = connected ? color : THEME.danger; + ctx.lineWidth = 5; + rect(ctx, c.x - 22, c.y - 22, 44, 44, true, true); + drawItemIcon(ctx, c.x, c.y - 3, product); + ctx.fillStyle = THEME.white; + ctx.font = '900 10px ui-monospace, monospace'; + ctx.textAlign = 'center'; + ctx.fillText('OUT', c.x, c.y + 20); + ctx.restore(); +} + function drawExternalDuct(ctx, f) { - if (!f?.entry) return; + if (!f?.entry || f.gridPlaced) return; const c = cellCenter(f.entry.col, f.entry.row); - let bx = f.x + f.w / 2, by = f.y + f.h / 2; - if (f.side === 'left') { bx = f.x + f.w; by = c.y; } - else if (f.side === 'right') { bx = f.x; by = c.y; } - else if (f.side === 'top') { bx = c.x; by = f.y + f.h; } - else if (f.side === 'bottom') { bx = c.x; by = f.y; } + const bodyPort = facilityBodyPortPoint(f, 'input'); + let bx = bodyPort?.x ?? (f.x + f.w / 2), by = bodyPort?.y ?? (f.y + f.h / 2); + if (facilityKind(f) !== 'mixer') { + if (f.side === 'left') { bx = f.x + f.w; by = c.y; } + else if (f.side === 'right') { bx = f.x; by = c.y; } + else if (f.side === 'top') { bx = c.x; by = f.y + f.h; } + else if (f.side === 'bottom') { bx = c.x; by = f.y; } + } ctx.save(); ctx.strokeStyle = '#07080a'; ctx.lineWidth = 11; @@ -968,7 +1188,7 @@ function drawMixer(ctx, game, m = game.facilities.mixer) { ctx.fillStyle = THEME.white; ctx.font = '900 14px ui-monospace, monospace'; ctx.textAlign = 'left'; ctx.fillText(`MIXER L${m.level}`, m.x + 14, m.y + 18); ctx.fillStyle = THEME.muted; ctx.font = '900 10px ui-monospace, monospace'; - ctx.fillText(`PAY ${yen(upgradedMixerPrice(game))}`, m.x + 14, m.y + 34); + ctx.fillText(`MEAT ${m.meatBuffer || 0} | SAUSAGE ${yen(upgradedSausagePrice(game))}`, m.x + 14, m.y + 34); ctx.fillStyle = '#1a2028'; ctx.strokeStyle = '#87bfff'; ctx.lineWidth = 4; rect(ctx, m.x + 44, m.y + 34, 76, 50, true, true); ctx.strokeStyle = '#4aa3ff'; ctx.lineWidth = 3; @@ -979,7 +1199,7 @@ function drawMixer(ctx, game, m = game.facilities.mixer) { rect(ctx, m.x + 56, m.y + 24, 12, 10, true, true); rect(ctx, m.x + 96, m.y + 24, 12, 10, true, true); ctx.fillStyle = '#7ea9dc'; ctx.fillRect(m.x + 48, m.y + 42, 68, 5); - drawTargetBadge(ctx, m.x + 14, m.y + m.h - 40, m.w - 28, 'SEND MALE', 'male', 'safe meat route'); + drawTargetBadge(ctx, m.x + 14, m.y + m.h - 40, m.w - 28, 'CHICK -> MEAT', 'meat', 'connect OUT to sausage machine'); drawDirtOverlay(ctx, m.x, m.y, m.w, m.h, m); drawSelection(ctx, game, 'facility', m.id, m.x + m.w / 2, m.y + m.h / 2, m.w + 12, m.h + 12); ctx.restore(); @@ -1013,6 +1233,30 @@ function drawTrash(ctx, game, t = game.facilities.trash) { drawSelection(ctx, game, 'facility', t.id, t.x + t.w / 2, t.y + t.h / 2, t.w + 12, t.h + 12); ctx.restore(); } +function drawSausageMaker(ctx, game, s) { + ctx.save(); + drawMetalPanel(ctx, s.x, s.y, s.w, s.h, '#3b3029', THEME.ink, THEME.sausageOrange); + drawFacilityDetails(ctx, s, THEME.sausageOrange); + ctx.fillStyle = THEME.white; + ctx.font = '900 14px ui-monospace, monospace'; + ctx.textAlign = 'left'; + ctx.fillText(`SAUSAGE L${s.level}`, s.x + 14, s.y + 18); + ctx.fillStyle = THEME.muted; + ctx.font = '900 10px ui-monospace, monospace'; + ctx.fillText(`2 MEAT -> 1 | ${yen(upgradedSausagePrice(game))}`, s.x + 14, s.y + 34); + ctx.fillStyle = '#211915'; + ctx.strokeStyle = THEME.sausageOrange; + ctx.lineWidth = 4; + rect(ctx, s.x + 20, s.y + 43, s.w - 40, 38, true, true); + for (let i = 0; i < 3; i += 1) drawSausageItem(ctx, s.x + s.w / 2 - 28 + i * 28, s.y + 62, 9); + ctx.fillStyle = THEME.meatRed; ctx.fillRect(s.x, s.y + s.h / 2 - 8, 8, 16); + ctx.fillStyle = THEME.sausageOrange; ctx.fillRect(s.x + s.w - 8, s.y + s.h / 2 - 8, 8, 16); + drawTargetBadge(ctx, s.x + 10, s.y + s.h - 42, s.w - 20, '2 MEAT -> SAUSAGE', 'sausage', `buffer ${s.meatBuffer || 0}/2`); + drawDirtOverlay(ctx, s.x, s.y, s.w, s.h, s); + drawSelection(ctx, game, 'facility', s.id, s.x + s.w / 2, s.y + s.h / 2, s.w + 12, s.h + 12); + ctx.restore(); +} + function drawTruck(ctx, game, t = game.facilities.truck) { ctx.save(); drawExternalDuct(ctx, t); @@ -1022,11 +1266,15 @@ function drawTruck(ctx, game, t = game.facilities.truck) { ctx.fillText(`TRUCK L${t.level}`, t.x + 14, t.y + 18); ctx.fillStyle = THEME.muted; ctx.font = '900 10px ui-monospace, monospace'; ctx.fillText(`UNIT ${yen(upgradedTruckPrice(game))}`, t.x + 14, t.y + 34); - drawFacilityTexture(ctx, assets.truckCompact.loaded ? assets.truckCompact : assets.truck, t, 2.0); + drawFacilityTexture(ctx, assets.truck, t, 2.0); const truckTargetType = targetForTruck(game); drawTargetBadge(ctx, t.x + 15, t.y + 50, t.w - 30, `SEND ${truckTargetType.toUpperCase()}`, truckTargetType, game.eventOffer && !game.eventActive ? 'next event' : 'truck cargo'); ctx.fillStyle = 'rgba(39,60,36,.9)'; rect(ctx, t.x + 13, t.y + 88, t.w - 26, Math.max(18, t.h - 103), true, false); - for (const cargo of game.truckCargo) cargo.sex === 'poop' ? drawTinyPoop(ctx, t.x + cargo.x, t.y + cargo.y) : drawTinyChick(ctx, t.x + cargo.x, t.y + cargo.y, cargo.sex, cargo.sex === 'male'); + for (const cargo of game.truckCargo) { + if (cargo.sex === 'poop') drawTinyPoop(ctx, t.x + cargo.x, t.y + cargo.y); + else if (cargo.sex === 'sausage') drawSausageItem(ctx, t.x + cargo.x, t.y + cargo.y, 7); + else drawTinyChick(ctx, t.x + cargo.x, t.y + cargo.y, cargo.sex, cargo.sex === 'male'); + } drawDirtOverlay(ctx, t.x, t.y, t.w, t.h, t); drawSelection(ctx, game, 'facility', t.id, t.x + t.w / 2, t.y + t.h / 2, t.w + 12, t.h + 12); ctx.restore(); @@ -1046,6 +1294,8 @@ function drawChick(ctx, chick, active, game) { if (active) { ctx.strokeStyle = THEME.green; ctx.lineWidth = 5; ctx.beginPath(); ctx.arc(chick.x, y, chick.radius + 8, 0, Math.PI * 2); ctx.stroke(); } if (rage) { ctx.strokeStyle = THEME.danger; ctx.lineWidth = 3; ctx.beginPath(); ctx.arc(chick.x, y, chick.radius + 12 + Math.sin(chick.bob * 2) * 4, 0, Math.PI * 2); ctx.stroke(); } if (chick.sex === 'poop') drawPoop(ctx, chick.x, y, chick.radius); + else if (chick.sex === 'meat') drawMeatItem(ctx, chick.x, y, chick.radius); + else if (chick.sex === 'sausage') drawSausageItem(ctx, chick.x, y, chick.radius); else { const img = chick.sex === 'male' ? assets.chickMale : assets.chickFemale; const spriteDrawn = drawImageIfLoaded(ctx, img, chick.x - chick.radius, y - chick.radius, chick.radius * 2, chick.radius * 2); @@ -1092,6 +1342,31 @@ function drawPoop(ctx, x, y, radius) { ctx.fillStyle = THEME.white; ctx.beginPath(); ctx.arc(x - 5, y + 1, 2, 0, Math.PI * 2); ctx.arc(x + 5, y + 1, 2, 0, Math.PI * 2); ctx.fill(); ctx.restore(); } function drawTinyPoop(ctx, x, y) { drawPoop(ctx, x, y, 7); } +function drawMeatItem(ctx, x, y, radius = 10) { + ctx.save(); + ctx.fillStyle = THEME.meatRed; + ctx.strokeStyle = THEME.ink; + ctx.lineWidth = 3; + ctx.beginPath(); + ctx.ellipse(x, y, radius * 1.15, radius * 0.78, -0.25, 0, Math.PI * 2); + ctx.fill(); ctx.stroke(); + ctx.fillStyle = '#f1b8b8'; + ctx.beginPath(); ctx.arc(x - radius * 0.25, y - radius * 0.12, radius * 0.22, 0, Math.PI * 2); ctx.fill(); + ctx.restore(); +} +function drawSausageItem(ctx, x, y, radius = 10) { + ctx.save(); + ctx.translate(x, y); ctx.rotate(-0.2); + ctx.fillStyle = THEME.sausageOrange; + ctx.strokeStyle = THEME.ink; + ctx.lineWidth = 3; + rect(ctx, -radius, -radius * 0.45, radius * 2, radius * 0.9, true, true); + ctx.strokeStyle = '#8a4823'; ctx.lineWidth = 2; + for (const dx of [-radius * 0.45, radius * 0.45]) { + ctx.beginPath(); ctx.moveTo(dx, -radius * 0.36); ctx.lineTo(dx, radius * 0.36); ctx.stroke(); + } + ctx.restore(); +} function drawTinyChick(ctx, x, y, sex, warning = false) { ctx.save(); const bodyColor = sex === 'male' ? THEME.male : THEME.female; diff --git a/src/systems/buildSystem.js b/src/systems/buildSystem.js index 403f2a3..425d4bc 100644 --- a/src/systems/buildSystem.js +++ b/src/systems/buildSystem.js @@ -1,13 +1,13 @@ import { BALANCE } from '../core/balance.js'; -import { DIRS, MACHINE_FACILITY_IDS, GRID, THEME } from '../core/config.js'; +import { DIRS, EDGE_FACILITY_IDS, GRID_FACILITY_IDS, MACHINE_FACILITY_IDS, GRID, THEME, ECONOMY } from '../core/config.js'; import { getSpawnRange } from '../core/state.js'; -import { createEggFarm, createScanner, createFacility, createMaintenanceRoom, maintenanceRoomFootprint } from '../core/entities.js'; +import { createEggFarm, createScanner, createFacility, createGridFacility, createMaintenanceRoom, maintenanceRoomFootprint, gridFacilityFootprintCells, syncGridFacilityGeometry } from '../core/entities.js'; import { generateBlockedCellsInRect, blockedRatioForExpansionPurchase } from '../core/mapGen.js'; -import { expansionCost, expansionLot, expansionLots, lotFromChunk, lotBounds, lotContainsPoint, cellsInLot, isOwnedCell, countOwnedCells, shiftRowIndexedSet, shiftRowIndexedMap, ownChunk } from '../core/gridExpansion.js'; +import { expansionCost, expansionLot, expansionLots, lotFromChunk, lotBounds, lotContainsPoint, cellsInLot, isOwnedCell, countOwnedCells, shiftColIndexedSet, shiftColIndexedMap, shiftRowIndexedSet, shiftRowIndexedMap, ownChunk } from '../core/gridExpansion.js'; import { key, parseKey, pointToCell, cellCenter, yen, directionNameBetweenCells } from '../core/utils.js'; import { TEXT, equipmentName } from '../core/text.js'; -import { farmAt, scannerAt, scannerCenter, scannerFootprintCells, routeFromFarmToScanner, refreshRoutingAfterEdit, disconnectedBuildWarnings } from './routing.js'; -import { buildPrice, equipmentBasePrice, incomeMultiplier, mixerPoopPenalty, refundCash, spendCash, truckPoopPenalty, upgradedMixerPrice, upgradedTruckPrice, resaleValueFor, shredderUpgradeCount, shredderBonusIncome, shredderBonusMaxCards } from './economy.js'; +import { farmAt, scannerAt, scannerCenter, scannerFootprintCells, gridFacilityAt, facilityInputCell, facilityOutputCell, facilityOutputHasConveyor, routeFromFarmToScanner, refreshRoutingAfterEdit, disconnectedBuildWarnings } from './routing.js'; +import { buildPrice, equipmentBasePrice, incomeMultiplier, mixerPoopPenalty, refundCash, spendCash, truckPoopPenalty, upgradedMixerPrice, upgradedTruckPrice, resaleValueFor, shredderUpgradeCount, shredderBonusIncome, shredderBonusChance, shredderBonusMaxCards, upgradedSausagePrice } from './economy.js'; import { autoScannerCooldownSeconds } from './cards.js'; import { record } from './history.js'; import { floating, eraseEffect } from './effects.js'; @@ -22,7 +22,7 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel let conveyorDragStartCell = null; let conveyorDragMoved = false; const BRANCH_MODES = ['random', 'up', 'right', 'down', 'left']; - const BRANCH_LABELS = { random: 'RND', up: 'UP', right: 'RT', down: 'DN', left: 'LF' }; + const BRANCH_LABELS = { random: 'RND', up: '▲', right: '▶', down: '▼', left: '◀' }; const BRANCH_MARKER = { w: 40, h: 40, y: 0 }; function gridExpansionCost() { return expansionCost(game); } @@ -45,7 +45,26 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel for (const farm of game.eggFarms || []) farm.row += rowDelta; for (const scanner of game.scanners || []) scanner.row += rowDelta; for (const facility of Object.values(game.facilities || {})) { - if (facility.entry) facility.entry.row += rowDelta; + if (facility.gridPlaced) { facility.row += rowDelta; syncGridFacilityGeometry(facility); } + else if (facility.entry) facility.entry.row += rowDelta; + } + } + + function shiftWorldColsRight(colDelta) { + if (!colDelta) return; + GRID.x -= colDelta * GRID.cell; + GRID.cols += colDelta; + game.gridChunkOriginX = (game.gridChunkOriginX || 0) - Math.floor(colDelta / 10); + game.ownedCells = shiftColIndexedSet(game.ownedCells, colDelta); + game.blockedCells = shiftColIndexedSet(game.blockedCells, colDelta); + game.conveyorTiles = shiftColIndexedSet(game.conveyorTiles, colDelta); + game.conveyorMeta = shiftColIndexedMap(game.conveyorMeta, colDelta); + for (const farm of game.eggFarms || []) farm.col += colDelta; + for (const scanner of game.scanners || []) scanner.col += colDelta; + for (const room of game.maintenanceRooms || []) room.col += colDelta; + for (const facility of Object.values(game.facilities || {})) { + if (facility.gridPlaced) { facility.col += colDelta; syncGridFacilityGeometry(facility); } + else if (facility.entry) facility.entry.col += colDelta; } } @@ -56,12 +75,36 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel function expansionOfferAtPoint(p) { if (game.phase !== 'build' || game.cardDraft?.pending || game.cardTargetPick?.pending) return null; - return expansionLots(game).find(lot => lot && lotContainsPoint(lot, p)) || null; + return expansionLots(game).map(lot => expansionLotStatus(lot)).find(lot => lot && lotContainsPoint(lot, p)) || null; + } + + function lotRect(lot) { + const b = lotBounds(lot); + return { x: b.x, y: b.y, w: b.w, h: b.h }; + } + + function facilityBlocksExpansionLot(lot) { + const rect = lotRect(lot); + return Object.values(game.facilities || {}).some(f => { + const kind = f?.baseId || f?.id; + if (!EDGE_FACILITY_IDS.includes(kind) || f.gridPlaced) return false; + return rectsOverlap(rect, rectOfFacility(f), 0); + }); + } + + function expansionLotStatus(lot) { + if (!lot) return null; + const blockedByFacility = facilityBlocksExpansionLot(lot); + return { + ...lot, + disabled: blockedByFacility, + disabledReason: blockedByFacility ? 'Move edge facilities before buying this lot.' : '' + }; } function resolveExpansionRequest(request = 'right') { if (request && typeof request === 'object' && Number.isFinite(request.chunkX) && Number.isFinite(request.chunkY)) return request; - const direction = ['right', 'up', 'down'].includes(request) ? request : 'right'; + const direction = ['left', 'right', 'up', 'down'].includes(request) ? request : 'right'; return expansionLot(game, direction); } @@ -69,6 +112,11 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel const offer = resolveExpansionRequest(request); if (game.phase !== 'build' || game.cardDraft?.pending || game.cardTargetPick?.pending) return { ok: false, reason: 'Cannot expand now.' }; if (!offer) return { ok: false, reason: 'Invalid expansion lot.' }; + if (facilityBlocksExpansionLot(offer)) { + const reason = 'Move edge facilities before buying this lot.'; + fail(reason); + return { ok: false, reason }; + } const direction = offer.direction || 'right'; const cost = gridExpansionCost(); if (game.cash < cost) { @@ -78,8 +126,13 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel } record(game); spendCash(game, cost); - if (!game.gridExpansionPurchasesByDirection) game.gridExpansionPurchasesByDirection = { right: 0, up: 0, down: 0 }; + if (!game.gridExpansionPurchasesByDirection) game.gridExpansionPurchasesByDirection = { left: 0, right: 0, up: 0, down: 0 }; const originY = game.gridChunkOriginY || 0; + const originX = game.gridChunkOriginX || 0; + if (offer.chunkX < originX) { + const chunksToAdd = originX - offer.chunkX; + shiftWorldColsRight(chunksToAdd * (BALANCE.grid.expansion?.colsPerPurchase || 10)); + } if (offer.chunkY < originY) { const chunksToAdd = originY - offer.chunkY; shiftWorldRowsDown(chunksToAdd * (BALANCE.grid.expansion?.rowsPerPurchase || 10)); @@ -136,10 +189,21 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel if (existingScanner && !(moving?.type === 'scanner' && moving.ref?.id === existingScanner.id)) return true; const existingRoom = maintenanceRoomAt(game, col, row); if (existingRoom && !(moving?.type === 'maintenanceRoom' && moving.ref?.id === existingRoom.id)) return true; + const existingGridFacility = gridFacilityAt(game, col, row); + if (existingGridFacility && !(moving?.type === 'facility' && moving.ref?.id === existingGridFacility.id)) return true; if (game.conveyorTiles.has(k) && !(moving?.type === 'conveyor' && moving.oldKey === k)) return true; return false; } + function facilityPortAt(col, row, moving = null) { + return Object.values(game.facilities || {}).find(facility => { + if (moving?.type === 'facility' && moving.ref?.id === facility.id) return false; + const input = facilityInputCell(game, facility); + const output = facilityOutputCell(game, facility); + return (input && input.col === col && input.row === row) || (output && output.col === col && output.row === row); + }) || null; + } + function maintenanceRoomAt(gameRef, col, row) { return (gameRef.maintenanceRooms || []).find(room => maintenanceRoomFootprint(room).some(cell => cell.col === col && cell.row === row)) || null; } @@ -155,6 +219,9 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel if (existingScanner) return true; const existingRoom = maintenanceRoomAt(game, cell.col, cell.row); if (existingRoom && !(moving?.type === 'maintenanceRoom' && moving.ref?.id === existingRoom.id)) return true; + const existingGridFacility = gridFacilityAt(game, cell.col, cell.row); + if (existingGridFacility) return true; + if (facilityPortAt(cell.col, cell.row, moving)) return true; if (game.conveyorTiles.has(k)) return true; } return false; @@ -169,11 +236,34 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel if (existingFarm) return true; const existingScanner = scannerAt(game, cell.col, cell.row); if (existingScanner && !(moving?.type === 'scanner' && moving.ref?.id === existingScanner.id)) return true; + const existingGridFacility = gridFacilityAt(game, cell.col, cell.row); + if (existingGridFacility) return true; + if (facilityPortAt(cell.col, cell.row, moving)) return true; if (game.conveyorTiles.has(k)) return true; } return false; } + function gridFacilityPlacementBlocked(id, col, row, moving = null) { + const draft = { baseId: id, id, gridPlaced: true, col, row, wCells: id === 'sausageMaker' ? 3 : 1, hCells: id === 'sausageMaker' ? 3 : 1 }; + for (const cell of gridFacilityFootprintCells(draft)) { + if (!pointInGrid(cell.col, cell.row) || isBlockedCell(cell.col, cell.row) || isEquipmentCell(cell.col, cell.row, moving) || facilityPortAt(cell.col, cell.row, moving)) return true; + } + if (id === 'sausageMaker') { + const input = { col: col - 1, row: row + 1 }; + const output = { col: col + 3, row: row + 1 }; + if (!pointInGrid(input.col, input.row) || !pointInGrid(output.col, output.row)) return true; + if (isBlockedCell(input.col, input.row) || isBlockedCell(output.col, output.row)) return true; + for (const port of [input, output]) { + const portGridFacility = gridFacilityAt(game, port.col, port.row); + if (portGridFacility && portGridFacility.id !== moving?.ref?.id) return true; + if (farmAt(game, port.col, port.row) || scannerAt(game, port.col, port.row) || maintenanceRoomAt(game, port.col, port.row)) return true; + if (facilityPortAt(port.col, port.row, moving)) return true; + } + } + return false; + } + function selectedObject() { if (!game.selected) return null; if (game.selected.type === 'eggFarm') return game.eggFarms.find(f => f.id === game.selected.id) || null; @@ -269,6 +359,13 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel return dirs.includes(incoming); } + function deadEndReverseDir(cell, dirs) { + const neighbors = conveyorNeighborOutDirs(cell); + if (neighbors.length !== 1) return null; + const only = neighbors[0]; + return dirs.includes(only) && neighborPointsIntoCell(cell, only) ? only : null; + } + function reachableOutDirsForKey(k) { if (!game.conveyorTiles.has(k)) return []; const cell = parseKey(k); @@ -278,7 +375,11 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel const explicitReachable = [...new Set([...explicit, meta?.dir].filter(Boolean))] .filter(dir => neighbors.includes(dir)); const inferredExits = neighbors; - const reachable = explicitReachable.length ? explicitReachable : inferredExits; + const candidateReachable = explicitReachable.length ? explicitReachable : inferredExits; + const reverseDeadEnd = deadEndReverseDir(cell, candidateReachable); + const reachable = explicitReachable.length + ? explicitReachable.filter(dir => dir !== reverseDeadEnd) + : inferredExits.filter(dir => dir !== reverseDeadEnd); if (meta) { meta.outDirs = explicit.filter(dir => neighbors.includes(dir)); if (meta.dir && !neighbors.includes(meta.dir)) meta.dir = meta.outDirs[0] || null; @@ -291,7 +392,7 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel if (!game.conveyorTiles.has(k)) return []; const cell = parseKey(k); const connected = conveyorNeighborOutDirs(cell); - if (!isBranchCell(cell)) return connected.length ? connected : reachableOutDirsForKey(k); + if (!isBranchCell(cell)) return reachableOutDirsForKey(k); return connected; } @@ -302,11 +403,10 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel const meta = game.conveyorMeta.get(k) || {}; const physicalEntrances = new Set(connected.filter(dir => neighborPointsIntoCell(cell, dir))); const physicalExits = connected.filter(dir => !physicalEntrances.has(dir)); - if (physicalEntrances.size && physicalExits.length >= 2) return physicalExits; + if (physicalEntrances.size) return physicalExits.length >= 2 ? physicalExits : []; const explicit = [...new Set([...(Array.isArray(meta.outDirs) ? meta.outDirs : []), meta.dir].filter(Boolean))] .filter(dir => connected.includes(dir)); - if (explicit.length >= 2) return explicit; - return connected; + return explicit.length >= 2 ? explicit : connected; } function markConveyorDirection(from, to) { @@ -326,6 +426,9 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel } function cycleSingleConveyorDirection(cell) { + // A true isolated tile has no neighboring belt. An end tile has one neighbor + // and must reverse the whole connected run rather than rotating by itself. + if (conveyorNeighborCells(cell).length === 0) return cycleIsolatedConveyorDirection(cell); const path = conveyorRunPathFrom(cell); if (path.length < 2) return cycleIsolatedConveyorDirection(cell); record(game); @@ -340,7 +443,8 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel const k = key(cell.col, cell.row); const meta = game.conveyorMeta.get(k); if (!meta || isBranchCell(cell)) return false; - const choices = DIRS.map(d => d.name); + const blockedReverseDir = deadEndReverseDir(cell, DIRS.map(d => d.name)); + const choices = DIRS.map(d => d.name).filter(dir => dir !== blockedReverseDir); const current = meta.dir && choices.includes(meta.dir) ? meta.dir : null; const next = choices[(Math.max(-1, choices.indexOf(current)) + 1) % choices.length]; record(game); @@ -413,6 +517,22 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel meta.outDirs = [dir]; meta.branchMode = 'random'; } + // The last belt has no following belt in the run, but it still needs an + // explicit outward direction. Without this, clicking the end tile only + // reversed the interior tiles and left the clicked end visually unchanged. + if (target.length >= 2) { + const previous = target[target.length - 2]; + const terminal = target[target.length - 1]; + if (!isBranchCell(terminal)) { + const terminalMeta = game.conveyorMeta.get(key(terminal.col, terminal.row)); + const terminalDir = directionNameBetweenCells(previous, terminal); + if (terminalMeta && terminalDir) { + terminalMeta.dir = terminalDir; + terminalMeta.outDirs = [terminalDir]; + terminalMeta.branchMode = 'random'; + } + } + } } function conveyorToolDef() { @@ -425,7 +545,7 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel const k = key(col, row); if (game.conveyorTiles.has(k)) return { ok: false, exists: true }; if (isBlockedCell(col, row)) return { ok: false, reason: 'Cannot build on blocked ground.' }; - if (farmAt(game, col, row) || scannerAt(game, col, row)) return { ok: false, reason: TEXT.fail.cellOccupied }; + if (isEquipmentCell(col, row)) return { ok: false, reason: TEXT.fail.cellOccupied }; const toolDef = conveyorToolDef(); const kind = toolDef.id || 'conveyor'; const cost = buildPrice(kind, game); @@ -533,10 +653,15 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel return; } if (isBlockedCell(col, row)) return fail('Cannot build on blocked ground.'); + if (facilityPortAt(col, row) && !['conveyor', 'boostConveyor'].includes(game.buildTool)) return fail('Machine port must remain open for a conveyor.'); if (game.buildTool === 'maintenanceRoom') { if (maintenanceRoomPlacementBlocked(col, row)) return fail(TEXT.fail.cellOccupied); return buildMaintenanceRoom(col, row); } + if (GRID_FACILITY_IDS.includes(game.buildTool)) { + if (gridFacilityPlacementBlocked(game.buildTool, col, row)) return fail('3x3 machine or its ports do not fit here.'); + return buildGridFacility(col, row, game.buildTool); + } if ((game.buildTool === 'manualScanner' || game.buildTool === 'autoScanner') ? scannerPlacementBlocked(col, row) : isEquipmentCell(col, row)) return fail(TEXT.fail.cellOccupied); if (game.buildTool === 'eggFarm') buildFarm(col, row); else if (game.buildTool === 'manualScanner') buildScanner(col, row, 'manual'); @@ -545,8 +670,8 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel function buildAtPoint(p) { const cell = pointToCell(p.x, p.y); - if (['conveyor', 'boostConveyor', 'eggFarm', 'manualScanner', 'autoScanner', 'maintenanceRoom'].includes(game.buildTool)) return buildAtCell(cell); - if (MACHINE_FACILITY_IDS.includes(game.buildTool)) return buildFacility(p, game.buildTool); + if (['conveyor', 'boostConveyor', 'eggFarm', 'manualScanner', 'autoScanner', 'maintenanceRoom', ...GRID_FACILITY_IDS].includes(game.buildTool)) return buildAtCell(cell); + if (EDGE_FACILITY_IDS.includes(game.buildTool)) return buildFacility(p, game.buildTool); } function buildFarm(col, row) { @@ -597,6 +722,22 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel return { x: first.x + GRID.cell / 2, y: first.y + GRID.cell / 2 }; } + function buildGridFacility(col, row, id) { + const cost = buildPrice(id, game); + if (game.cash < cost) return fail(TEXT.fail.notEnoughCash); + if (gridFacilityPlacementBlocked(id, col, row)) return fail('3x3 machine or its ports do not fit here.'); + const f = applyBuildQuality(createGridFacility(game, id, col, row, cost)); + const storageId = game.facilities[id] ? `${id}:${game.nextId++}` : id; + f.baseId = id; + f.id = storageId; + record(game); + spendCash(game, cost); + game.facilities[storageId] = f; + refreshRoutingAfterEdit(game); + game.selected = { type: 'facility', id: storageId }; + floating(game, f.x + f.w / 2, f.y + f.h / 2, `-${yen(cost)}`, THEME.ink); + } + function buildFacility(p, id) { const cost = buildPrice(id, game); if (game.cash < cost) return fail(TEXT.fail.notEnoughCash); @@ -605,6 +746,9 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel f.baseId = id; f.id = storageId; if (f.entry && isBlockedCell(f.entry.col, f.entry.row)) return fail('Receiver cell is blocked.'); + if (f.entry && (farmAt(game, f.entry.col, f.entry.row) || scannerAt(game, f.entry.col, f.entry.row) || maintenanceRoomAt(game, f.entry.col, f.entry.row) || gridFacilityAt(game, f.entry.col, f.entry.row))) { + return fail('Receiver cell must remain free of equipment. A conveyor may occupy it.'); + } if (facilityOverlaps(f)) return fail(TEXT.fail.facilityOverlap); record(game); spendCash(game, cost); @@ -863,7 +1007,7 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel ui.modalActions.innerHTML = ''; if (obj.type === 'scanner' && obj.kind === 'auto') ui.modalActions.appendChild(modalButton('Auto Menu', () => showAutoScannerMenu(obj), 'facility-action warn')); if (obj.type === 'scanner' && obj.kind === 'manual') ui.modalActions.appendChild(modalButton('Set Keys', () => showManualScannerMenu(obj), 'facility-action warn')); - if (obj.type === 'conveyor' && isBranchKey(obj.id)) { + if (obj.type === 'conveyor' && isBranchKey(obj.id) && branchSelectableExitDirsForKey(obj.id).length >= 2) { const mode = game.conveyorMeta.get(obj.id)?.branchMode || 'random'; ui.modalActions.appendChild(modalButton(`Branch: ${branchModeLabel(mode)}`, () => { cycleBranchModeForKey(obj.id); @@ -930,7 +1074,7 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel function branchSwitcherAtPoint(p) { if (game.phase !== 'build' || game.cardDraft?.pending || game.cardTargetPick?.pending) return null; for (const k of game.conveyorTiles) { - if (!isBranchKey(k)) continue; + if (!isBranchKey(k) || branchSelectableExitDirsForKey(k).length < 2) continue; const cell = parseKey(k); const c = cellCenter(cell.col, cell.row); const left = c.x - BRANCH_MARKER.w / 2; @@ -993,8 +1137,13 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel lines.push(`Congestion: ${c ? Math.floor(c.ratio * 100) : 0}%`); lines.push(`Durability: ${remainingPercent({ meta })}% | Speed x${performanceFactor({ meta }).toFixed(2)}`); if (isBranchKey(obj.id)) { - lines.push(`Branch mode: ${branchModeLabel(meta?.branchMode || 'random')}`); - lines.push('Click the Branch button or the large on-belt badge to cycle RANDOM / fixed exit.'); + const selectableExits = branchSelectableExitDirsForKey(obj.id); + if (selectableExits.length >= 2) { + lines.push(`Branch mode: ${branchModeLabel(meta?.branchMode || 'random')}`); + lines.push('Click the Branch button or the on-belt triangle to cycle RANDOM / fixed exit.'); + } else { + lines.push('Branch mode: unavailable — fewer than two outgoing conveyors.'); + } } else { lines.push('Branch mode: needs 3+ conveyor connections.'); } @@ -1007,11 +1156,15 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel } else if (obj.type === 'facility') { lines.push(`Price: ${yen(equipmentPrice(obj))}`); { const reason = lastProtectedSaleReason({ type: obj.type, ref: obj }); lines.push(reason ? `Sale: blocked (${reason})` : `Sale value: ${yen(resaleValueFor({ type: obj.type, ref: obj }, game).amount)}`); } - lines.push(['mixer', 'truck', 'trash'].includes(obj.id) ? `Level: ${obj.level} / no cap` : `Level: ${obj.level}`); + lines.push(['mixer', 'truck', 'trash', 'sausageMaker'].includes(facilityKind) ? `Level: ${obj.level} / no cap` : `Level: ${obj.level}`); if (facilityKind === 'truck') lines.push('Durability: none | Always normal'); - if (['mixer', 'trash'].includes(facilityKind)) lines.push(`Durability: ${remainingPercent(obj)}% | Extra delay ${facilityProcessingDelay(game, obj).toFixed(2)}s`); + if (['mixer', 'trash', 'sausageMaker'].includes(facilityKind)) lines.push(`Durability: ${remainingPercent(obj)}% | Extra delay ${facilityProcessingDelay(game, obj).toFixed(2)}s`); if (facilityKind === 'mixer') { - lines.push(`Income: ${yen(upgradedMixerPrice(game))} per chick | upgrade x${incomeMultiplier(game, 'mixer').toFixed(3)}`); + lines.push(`Output: 1 meat per non-poop chick | meat buffer ${obj.meatBuffer || 0}`); + lines.push(`Meat quality: x${incomeMultiplier(game, 'mixer').toFixed(3)} to sausage value`); + const out = facilityOutputCell(game, obj); + lines.push(`OUT: ${out ? `${out.col},${out.row}` : 'none'} | conveyor ${facilityOutputHasConveyor(game, obj) ? 'connected' : 'missing'}`); + lines.push(`Fallback sale: ${yen(ECONOMY.income.mixer)} when OUT is missing or blocked`); lines.push(`Poop fine: -${yen(mixerPoopPenalty(game))}`); } if (facilityKind === 'truck') { @@ -1021,10 +1174,20 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel if (facilityKind === 'trash') { const cards = shredderUpgradeCount(game); const income = shredderBonusIncome(cards); + const chance = shredderBonusChance(cards); lines.push(`Bonus cards: ${cards}/${shredderBonusMaxCards()}`); - lines.push(`Poop income bonus: ${yen(income)} per processed poop.`); + lines.push(`Expected poop bonus: ${yen(income)} | hit chance ${Math.round(chance * 100)}%`); + lines.push('Winning payouts roll 1x / 2x / 4x / 10x, with jackpot odds rising per card.'); lines.push(`With enough upgrades, poop can out-earn male/female routes.`); } + if (facilityKind === 'sausageMaker') { + const input = facilityInputCell(game, obj); + const out = facilityOutputCell(game, obj); + lines.push('Size: 3×3 grid cells | IN left / OUT right'); + lines.push(`Recipe: 2 meat -> 1 sausage | meat buffer ${obj.meatBuffer || 0} | sausage buffer ${obj.sausageBuffer || 0}`); + lines.push(`Sausage sale value: ${yen(upgradedSausagePrice(game))}`); + lines.push(`IN: ${input ? `${input.col},${input.row}` : 'none'} | OUT: ${out ? `${out.col},${out.row}` : 'none'} | conveyor ${facilityOutputHasConveyor(game, obj) ? 'connected' : 'missing'}`); + } if (obj.entry) lines.push(`Receiver: edge cell ${obj.entry.col},${obj.entry.row} (${obj.side})`); } return lines; @@ -1043,11 +1206,12 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel if (obj.type === 'conveyor' && game.conveyorMeta.get(obj.id)?.kind === 'boostConveyor') return 'Moves chicks twice as fast. Wears down like a normal belt.'; if (obj.type === 'conveyor') return 'A stubborn belt tile. It only cares about the next cell.'; if (obj.type === 'eggFarm') return 'A tiny gatehouse producing questionable eggs on schedule.'; - if (obj.type === 'scanner' && obj.kind === 'auto') return 'Slower than hands without upgrades.'; + if (obj.type === 'scanner' && obj.kind === 'auto') return 'A compact 2×2 scanner sized for roughly 2.1 level-1 farms.'; if (obj.type === 'scanner') return 'A manual checkpoint. The operator is the algorithm.'; - if (obj.type === 'facility' && (obj.baseId || obj.id) === 'mixer') return 'Male chicks become revenue here. Do not feed it poop.'; + if (obj.type === 'facility' && (obj.baseId || obj.id) === 'mixer') return 'Chicks become meat when OUT is clear; a blocked OUT falls back to direct sale.'; if (obj.type === 'facility' && (obj.baseId || obj.id) === 'trash') return 'Poop goes in. Sometimes coins come out, for reasons best left unaudited.'; - if (obj.type === 'facility' && (obj.baseId || obj.id) === 'truck') return 'The shipping endpoint. Correct cargo pays; wrong cargo complains.'; + if (obj.type === 'facility' && (obj.baseId || obj.id) === 'truck') return 'The shipping endpoint. Correct cargo and sausages pay; wrong cargo complains.'; + if (obj.type === 'facility' && (obj.baseId || obj.id) === 'sausageMaker') return 'A 3×3 in-grid machine with one meat inlet on the left and one sausage outlet on the right.'; if (obj.type === 'maintenanceRoom') return 'A cramped 2×2 storage and break room with lockers, spare parts, a bench and one dispatched repairman.'; return 'Factory equipment.'; } @@ -1065,7 +1229,7 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel gridExpansionCost, buyGridExpansion, expansionOfferAtPoint, beginConveyorDrag, continueConveyorDrag, endConveyorDrag, cycleSingleConveyorDirection, - branchSwitcherAtPoint, cycleBranchModeAtPoint, cycleBranchModeForKey, + branchSwitcherAtPoint, cycleBranchModeAtPoint, cycleBranchModeForKey, branchSelectableExitDirsForKey, removeSelected, switchScannerRole, showManualScannerMenu, showAutoScannerMenu, showSelectedMenu, setBuildTool, fail, isEquipmentCell, equipmentHitBoxes, diff --git a/src/systems/cards.js b/src/systems/cards.js index fc36b60..0b982cb 100644 --- a/src/systems/cards.js +++ b/src/systems/cards.js @@ -1,7 +1,7 @@ import { AUTO_SCANNER_COOLDOWN, AUTO_SCANNER_UPGRADE_RATE, AUTO_SCANNER_CARD_UPGRADE_RATE, AUTO_SCANNER_MIN_COOLDOWN, BEARING_SPEED_MULTIPLIER, CARD_BALANCE, CARD_DEFAULT_EFFECTS, CARD_DEFS as CARD_DEFINITIONS, CONVEYOR_SPEED, CONVEYOR_SPEED_MAX, ECONOMY, EGG_SPAWN_RANGES, GRID, THEME } from '../core/config.js'; import { nextSpawnDelay } from '../core/state.js'; import { cellCenter, key, yen } from '../core/utils.js'; -import { applyPenalty, applyRevenue, upgradedMixerPrice, upgradedTruckPrice, shredderUpgradeCount, rawShredderUpgradeCount, shredderBonusIncome, shredderBonusMaxCards } from './economy.js'; +import { applyPenalty, applyRevenue, upgradedTruckPrice, upgradedSausagePrice, shredderUpgradeCount, rawShredderUpgradeCount, shredderBonusIncome, shredderBonusChance, shredderBonusMaxCards } from './economy.js'; import { floating, shake, eraseEffect, shockwave, sparkBurst, smokeBurst } from './effects.js'; import { averageConveyorPerformance, autoScannerDelayMultiplier, ensureMaintenanceState, repairAllEquipment } from './maintenance.js'; import { scannerCenter, refreshRoutingAfterEdit } from './routing.js'; @@ -146,13 +146,15 @@ function targetLabel(game, target) { if (target.type === 'scanner') { return `AUTO #${target.id} L${target.level} -> L${target.level + 1} | CD ${autoScannerCooldownSeconds(target, game).toFixed(1)}s -> ${autoScannerCooldownSeconds({ ...target, level: target.level + 1 }, game).toFixed(1)}s`; } - if (target.type === 'facility' && (target.baseId || target.id) === 'mixer') { - const beforeLevel = target.level; - const before = upgradedMixerPrice(game); + if (target.type === 'facility' && ['mixer', 'sausageMaker'].includes(target.baseId || target.id)) { + const kind = target.baseId || target.id; + const beforeLevel = target.level || 1; + const before = upgradedSausagePrice(game); target.level = beforeLevel + 1; - const after = upgradedMixerPrice(game); + const after = upgradedSausagePrice(game); target.level = beforeLevel; - return `MIXER L${target.level} -> L${target.level + 1} | ${yen(before)} -> ${yen(after)}`; + const label = kind === 'mixer' ? 'MIXER' : 'SAUSAGE MACHINE'; + return `${label} L${target.level} -> L${target.level + 1} | sausage ${yen(before)} -> ${yen(after)}`; } if (target.type === 'facility' && (target.baseId || target.id) === 'truck') { const beforeLevel = target.level; @@ -162,12 +164,12 @@ function targetLabel(game, target) { target.level = beforeLevel; return `TRUCK L${target.level} -> L${target.level + 1} | ${yen(before)} -> ${yen(after)}`; } - if (target.type === 'facility' && target.id === 'trash') { + if (target.type === 'facility' && (target.baseId || target.id) === 'trash') { const before = shredderUpgradeCount(game); const after = Math.min(shredderBonusMaxCards(), before + 1); const beforeIncome = shredderBonusIncome(before); const afterIncome = shredderBonusIncome(after); - return `SHREDDER L${target.level || 1} -> L${(target.level || 1) + 1} | poop income ${yen(beforeIncome)} -> ${yen(afterIncome)} per item`; + return `SHREDDER L${target.level || 1} -> L${(target.level || 1) + 1} | expected ${yen(beforeIncome)} -> ${yen(afterIncome)} per poop`; } return `${target.name || target.id} L${target.level || 1} -> L${(target.level || 1) + 1}`; } @@ -191,6 +193,7 @@ export function targetsForCard(game, cardOrId) { if (card.target === 'autoScanner') return game.scanners.filter(s => s.kind === 'auto'); if (card.target === 'mixer') return Object.values(game.facilities || {}).filter(f => (f.baseId || f.id) === 'mixer'); if (card.target === 'truck') return Object.values(game.facilities || {}).filter(f => (f.baseId || f.id) === 'truck'); + if (card.target === 'sausageMaker') return Object.values(game.facilities || {}).filter(f => (f.baseId || f.id) === 'sausageMaker'); if (card.target === 'trash') return rawShredderUpgradeCount(game) < shredderBonusMaxCards() ? Object.values(game.facilities || {}).filter(f => (f.baseId || f.id) === 'trash') : []; @@ -216,9 +219,24 @@ function repairmanCardVisible(game) { return !!((game.maintenanceRooms || []).length || (game.repairmen || []).length || game.repairman?.active); } +function facilityRequirementMet(game, id) { + if (id === 'conveyor') return (game.conveyorTiles?.size || 0) > 0; + if (id === 'autoScanner') return (game.scanners || []).some(s => s.kind === 'auto'); + if (id === 'manualScanner') return (game.scanners || []).some(s => s.kind === 'manual'); + if (id === 'eggFarm') return (game.eggFarms || []).length > 0; + return Object.values(game.facilities || {}).some(f => (f.baseId || f.id) === id); +} + +function cardRequirementsMet(game, card) { + if (card.requiresFacility && !facilityRequirementMet(game, card.requiresFacility)) return false; + if (Array.isArray(card.requiresAnyFacility) && !card.requiresAnyFacility.some(id => facilityRequirementMet(game, id))) return false; + return true; +} + function availableCards(game) { return CARD_DEFS.filter(card => { if (card.id === 'laborExploitation' && !repairmanCardVisible(game)) return false; + if (!cardRequirementsMet(game, card)) return false; if (cardAtCap(game, card)) return false; if ((card.type === 'equipmentUpgrade' || card.type === 'cellAction') && targetsForCard(game, card).length <= 0) return false; return true; @@ -313,7 +331,7 @@ function boundsForTarget(target) { } if (target.type === 'scanner') { const c = scannerCenter(target); - return { x: c.x - 54, y: c.y - 77, w: 108, h: 154, cx: c.x, cy: c.y }; + return { x: c.x - 48, y: c.y - 48, w: 96, h: 96, cx: c.x, cy: c.y }; } if (target.type === 'facility') { return { x: target.x, y: target.y, w: target.w, h: target.h, cx: target.x + target.w / 2, cy: target.y + target.h / 2 }; @@ -424,13 +442,14 @@ function incomeAtLevel(base, level) { } function incomeUpgradePreview(game, id, base) { - const targets = targetsForCard(game, id === 'mixer' ? 'upgradeMixer' : 'upgradeTruck'); - const target = targets[0]; + const cardId = id === 'mixer' ? 'upgradeMixer' : id === 'sausageMaker' ? 'upgradeSausageMaker' : 'upgradeTruck'; + const target = targetsForCard(game, cardId)[0]; if (!target) return { before: incomeAtLevel(base, 1), after: incomeAtLevel(base, 2) }; - const before = id === 'mixer' ? upgradedMixerPrice(game) : upgradedTruckPrice(game); + const price = () => id === 'truck' ? upgradedTruckPrice(game) : upgradedSausagePrice(game); + const before = price(); const beforeLevel = target.level || 1; target.level = beforeLevel + 1; - const after = id === 'mixer' ? upgradedMixerPrice(game) : upgradedTruckPrice(game); + const after = price(); target.level = beforeLevel; return { before, after }; } @@ -449,8 +468,12 @@ function cardDescription(game, card) { return `Choose one AUTO SCANNER. Level +1. Cooldown ${before.toFixed(2)}s -> ${after.toFixed(2)}s.`; } if (card.id === 'upgradeMixer') { - const preview = incomeUpgradePreview(game, 'mixer', ECONOMY.income.mixer); - return `Choose one MIXER. Earning +10%. Male-chick income ${yen(preview.before)} -> ${yen(preview.after)}.`; + const preview = incomeUpgradePreview(game, 'mixer', ECONOMY.income.sausage); + return `Choose one MIXER. Meat quality +10%. Sausage sale value ${yen(preview.before)} -> ${yen(preview.after)}.`; + } + if (card.id === 'upgradeSausageMaker') { + const preview = incomeUpgradePreview(game, 'sausageMaker', ECONOMY.income.sausage); + return `Choose one SAUSAGE MACHINE. Product value +10%. Sausage sale value ${yen(preview.before)} -> ${yen(preview.after)}.`; } if (card.id === 'upgradeTruck') { const preview = incomeUpgradePreview(game, 'truck', ECONOMY.income.truck); @@ -461,7 +484,9 @@ function cardDescription(game, card) { const after = Math.min(shredderBonusMaxCards(), before + 1); const beforeIncome = shredderBonusIncome(before); const afterIncome = shredderBonusIncome(after); - return `SHREDDER level +1. Poop income ${yen(beforeIncome)} -> ${yen(afterIncome)} per item.`; + const beforeChance = Math.round(shredderBonusChance(before) * 100); + const afterChance = Math.round(shredderBonusChance(after) * 100); + return `SHREDDER level +1. Expected value ${yen(beforeIncome)} -> ${yen(afterIncome)} per poop; hit chance ${beforeChance}% -> ${afterChance}%.`; } if (card.id === 'bearing') { const before = Math.min(CONVEYOR_SPEED_MAX, CONVEYOR_SPEED * Math.pow(BEARING_SPEED_MULTIPLIER, Math.max(0, e.bearing || 0))); @@ -507,7 +532,7 @@ function cardDescription(game, card) { if (card.id === 'newMachine') return 'Cancel Used Machines. Future equipment returns to normal price, refund, and durability.'; if (card.id === 'laborExploitation') return 'Repairman dispatch paperwork is streamlined. Repair rooms keep operating; one time only.'; if (card.id === 'rescueLoan') return `At day-end bankruptcy check, gain ${yen(500)} if cash is below ${yen(0)}. Held: ${e.rescueLoanCharges || 0}.`; - if (card.id === 'dynamite') return 'Choose any blocked tiles on the map and destroy up to 10. Empty-space clicks are ignored; press Esc to finish after at least one blast.'; + if (card.id === 'dynamite') return 'Choose any blocked tiles on the map and destroy up to 3. Empty-space clicks are ignored; press Esc to finish after at least one blast.'; return card.description; } @@ -699,24 +724,25 @@ export function createCardSystem({ game, ui, onUpdatePanels }) { function cardIconFor(card) { const tags = new Set(card.tags || []); const byTarget = { - eggFarm: { type: 'image', src: './assets/dark_factory/facilities/machines/egg_farm_16.png', alt: 'EGG' }, - eggOutlet: { type: 'image', src: './assets/dark_factory/facilities/machines/egg_farm_16.png', alt: 'EGG' }, + eggFarm: { type: 'image', src: './assets/dark_factory/facilities/machines/egg_farm_16.png?v=dark_factory', alt: 'EGG' }, + eggOutlet: { type: 'image', src: './assets/dark_factory/facilities/machines/egg_farm_16.png?v=dark_factory', alt: 'EGG' }, autoScanner: { type: 'image', src: './assets/dark_factory/facilities/machines/auto_scanner_32x48.png', alt: 'SCAN' }, - mixer: { type: 'image', src: './assets/dark_factory/facilities/machines/mixer_compact_16.png', alt: 'MIX' }, - truck: { type: 'image', src: './assets/dark_factory/facilities/vehicles/truck_compact_16.png', alt: 'TRUCK' }, - trash: { type: 'image', src: './assets/dark_factory/facilities/machines/shredder_compact_16.png', alt: 'SHR' }, + mixer: { type: 'image', src: './assets/dark_factory/facilities/machines/mixer_32.png', alt: 'MIX' }, + truck: { type: 'image', src: './assets/dark_factory/facilities/vehicles/truck_32.png', alt: 'TRUCK' }, + trash: { type: 'image', src: './assets/dark_factory/facilities/machines/shredder_32.png', alt: 'SHR' }, + sausageMaker: { type: 'glyph', text: 'S' }, blockedCell: { type: 'image', src: './assets/dark_factory/facilities/utility/obstacle_crate_16.png', alt: 'BLOCK' } }; if (byTarget[card.target]) return byTarget[card.target]; if (card.id === 'bearing' || tags.has('CONVEYOR')) return { type: 'image', src: './assets/dark_factory/facilities/conveyor/conveyor_straight_h_16.png', alt: 'BELT' }; if (tags.has('SCANNER')) return { type: 'image', src: './assets/dark_factory/facilities/machines/auto_scanner_32x48.png', alt: 'SCAN' }; - if (tags.has('EGG')) return { type: 'image', src: './assets/dark_factory/facilities/machines/egg_farm_16.png', alt: 'EGG' }; - if (tags.has('POOP')) return { type: 'glyph', text: '💩' }; + if (tags.has('EGG')) return { type: 'image', src: './assets/dark_factory/facilities/machines/egg_farm_16.png?v=dark_factory', alt: 'EGG' }; + if (tags.has('POOP')) return { type: 'image', src: './assets/images/poop.png', alt: 'POOP' }; if (tags.has('MAINTENANCE')) return { type: 'image', src: './assets/dark_factory/facilities/utility/repairman_16.png', alt: 'FIX' }; - if (tags.has('CARD')) return { type: 'glyph', text: '▣' }; - if (tags.has('ECONOMY')) return { type: 'glyph', text: '¥' }; + if (tags.has('CARD')) return { type: 'image', src: './assets/dark_factory/facilities/utility/maintenance_room_32.png', alt: 'CARD' }; + if (tags.has('ECONOMY')) return { type: 'image', src: './assets/dark_factory/facilities/vehicles/truck_32.png', alt: 'YEN' }; if (tags.has('RISK')) return { type: 'glyph', text: '!' }; - return { type: 'glyph', text: '◆' }; + return { type: 'glyph', text: '*' }; } function cardIconHtml(card) { @@ -724,7 +750,7 @@ export function createCardSystem({ game, ui, onUpdatePanels }) { if (icon.type === 'image') { return `
${icon.alt || ''}
`; } - return ``; + return ``; } function cardButton(card, index) { diff --git a/src/systems/chickSystem.js b/src/systems/chickSystem.js index 1662557..c39320b 100644 --- a/src/systems/chickSystem.js +++ b/src/systems/chickSystem.js @@ -2,8 +2,8 @@ import { DIRS, GRID, THEME } from '../core/config.js'; import { createChick } from '../core/entities.js'; import { nextSpawnDelay } from '../core/state.js'; import { key, parseKey, pointToCell, cellCenter, randomBetween, yen, inGrid } from '../core/utils.js'; -import { scannerById, scannerBySlot, scannerCenter, scannerConnector, nearestConveyorKey, buildConveyorComponents, autoSideFor, ensureFactoryGraph } from './routing.js'; -import { applyMixerIncome, applyMixerPoopFine, applyTruckPoopFine, applyWrongTruckFine, upgradedTruckPrice, applyShredderBonus, applyRevenue } from './economy.js'; +import { scannerById, scannerBySlot, scannerCenter, scannerConnector, facilityOutputCell, facilityOutputHasConveyor, buildConveyorComponents, autoSideFor, ensureFactoryGraph } from './routing.js'; +import { applyMixerIncome, applyMixerPoopFine, applyTruckPoopFine, applyWrongTruckFine, upgradedTruckPrice, upgradedSausagePrice, applyShredderBonus, applyRevenue } from './economy.js'; import { autoScannerCooldownSeconds, eggProductionDelayMultiplier, extraEggOutletCount, scannerQueueSpacingMultiplier } from './cards.js'; import { productionMultiplier, truckTarget, isTargetTruckCargo, shouldFineMaleTruck, shredderPayoutMultiplier, congestionExplosionThreshold, congestionWarningThreshold } from './events.js'; import { floating, shake, spawnPulse, scannerPulse, meatEffect, sludgeEffect, shredEffect, truckLoadEffect, shockwave, sparkBurst, smokeBurst, flyingDebris, rageEffect } from './effects.js'; @@ -11,6 +11,74 @@ import { countAutoSorted, countCorrect, countMistake, countMixer, countPoopDesti import { eggSpawnDelayMultiplier, recordFarmProduction, recordConveyorPass, recordAutoScan, recordFacilityProcess, updateProcessingCooldowns, setFacilityCooldownAfterProcess, updateRepairman } from './maintenance.js'; export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck }) { + function frameCache() { + if (!game.frameCache) { + game.frameCache = { + frameId: -1, + routingVersion: -1, + chickRevision: 0, + spatialRevision: -1, + spatial: new Map(), + congestionFrame: -1, + componentChicks: new Map(), + manualMonitorSignature: '', + draw: {} + }; + } + return game.frameCache; + } + + function markChicksChanged() { + const cache = frameCache(); + cache.chickRevision = (cache.chickRevision || 0) + 1; + cache.congestionFrame = -1; + } + + function markPositionsChanged() { + frameCache().congestionFrame = -1; + } + + function beginFrame(frameId) { + const cache = frameCache(); + if (cache.frameId === frameId) return; + cache.frameId = frameId; + cache.spatialRevision = -1; + cache.congestionFrame = -1; + } + + function spatialKeyForPoint(x, y) { + return `${Math.floor(x / GRID.cell)},${Math.floor(y / GRID.cell)}`; + } + + function buildSpatialIndex() { + const cache = frameCache(); + if (cache.spatialRevision === cache.chickRevision) return cache.spatial; + const spatial = new Map(); + for (const chick of game.chicks) { + if (chick.stage === 'flying') continue; + const k = spatialKeyForPoint(chick.x, chick.y); + if (!spatial.has(k)) spatial.set(k, []); + spatial.get(k).push(chick); + } + cache.spatial = spatial; + cache.spatialRevision = cache.chickRevision; + return spatial; + } + + function nearbyChicks(target) { + const spatial = buildSpatialIndex(); + const sx = Math.floor(target.x / GRID.cell); + const sy = Math.floor(target.y / GRID.cell); + const result = []; + for (let y = sy - 1; y <= sy + 1; y += 1) { + for (let x = sx - 1; x <= sx + 1; x += 1) { + const list = spatial.get(`${x},${y}`); + if (list) result.push(...list); + } + } + return result; + } + function currentSpawnDelay(farm) { return nextSpawnDelay(farm) * eggSpawnDelayMultiplier(farm) * eggProductionDelayMultiplier(game) / productionMultiplier(game); } @@ -36,6 +104,7 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck const chick = createChick(game, { stage: 'belt', scannerId: null, route: [start] }); if (chick.sex === 'poop') countPoopSpawned(game); game.chicks.push(chick); + markChicksChanged(); recordFarmProduction(game, farm); spawned += 1; } @@ -65,12 +134,13 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck function spawnTileBlocker(start) { - return game.chicks.find(ch => ch.stage !== 'flying' && Math.hypot(ch.x - start.x, ch.y - start.y) < GRID.cell * 0.68) || null; + return nearbyChicks(start).find(ch => Math.hypot(ch.x - start.x, ch.y - start.y) < GRID.cell * 0.68) || null; } function updateRunning(dt, { closeFarmShutters, completeTurn }) { updateRepairman(game, dt); updateProcessingCooldowns(game, dt); + flushFacilityOutputs(); if (game.cleanupTimer !== null) { game.cleanupTimer = Math.max(0, game.cleanupTimer - dt); if (game.cleanupTimer <= 0) completeTurn(); @@ -103,7 +173,7 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck updateRoutedChick(chick, i, dt); } updateScannerQueues(dt); - updateCongestion(); + updateCongestion(game.frameId); checkCongestionExplosions(); if (game.timeLeft <= 0) { if (game.chicks.length === 0) completeTurn(); @@ -119,7 +189,8 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck for (const chick of victims) flyingDebris(game, chick.sex, chick.x, chick.y, -Math.PI / 2, true); game.chicks = []; for (const scanner of game.scanners) scanner.queue = []; - updateCongestion(); + markChicksChanged(); + updateCongestion(game.frameId); if (victims.length) { const cx = victims.reduce((sum, chick) => sum + chick.x, 0) / victims.length; const cy = victims.reduce((sum, chick) => sum + chick.y, 0) / victims.length; @@ -153,9 +224,8 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck function targetBlockedByChick(chick, target) { if (!target) return false; - for (const other of game.chicks) { + for (const other of nearbyChicks(target)) { if (chick && other.id === chick.id) continue; - if (other.stage === 'flying') continue; if (Math.hypot(other.x - target.x, other.y - target.y) < GRID.cell * 0.55) return true; } return false; @@ -175,9 +245,15 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck const explicit = [...new Set(dirs)].filter(dir => DIRS.some(d => d.name === dir)); const cell = parseKey(cellKey); const inferred = DIRS - .filter(d => movementOptionFromDir(cell, d.name)) + .filter(d => movementOptionFromDir(cell, d.name, null)) .map(d => d.name); const cleanExplicit = explicit.filter(dir => inferred.includes(dir)); + const connected = DIRS + .filter(d => game.conveyorTiles.has(key(cell.col + d.dc, cell.row + d.dr))) + .map(d => d.name); + if (connected.length === 1 && (cleanExplicit.length ? cleanExplicit.includes(connected[0]) : true) && neighborPointsIntoCell(cell, connected[0])) { + return cleanExplicit.filter(dir => dir !== connected[0]); + } const inferredExits = inferred; return cleanExplicit.length ? cleanExplicit : inferredExits; } @@ -187,7 +263,7 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck } function scannerAtBodyCell(col, row) { - return game.scanners.find(scanner => scanner.col <= col && col <= scanner.col + 1 && scanner.row - 1 <= row && row <= scanner.row + 1) || null; + return game.scanners.find(scanner => scanner.col <= col && col <= scanner.col + 1 && scanner.row - 1 <= row && row <= scanner.row) || null; } function scannerReceivingFrom(cell, dirName) { @@ -208,13 +284,14 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck } function dirExitsToFacility(facility, dirName) { + if (facility?.gridPlaced && facilityKind(facility) === 'sausageMaker') return dirName === 'right'; return (facility.side === 'left' && dirName === 'left') || (facility.side === 'right' && dirName === 'right') || (facility.side === 'top' && dirName === 'up') || (facility.side === 'bottom' && dirName === 'down'); } - function movementOptionFromDir(cell, dirName) { + function movementOptionFromDir(cell, dirName, item = null) { const d = dirByName(dirName); if (!d) return null; const next = { col: cell.col + d.dc, row: cell.row + d.dr }; @@ -222,7 +299,7 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck return { type: 'conveyor', dirName, target: cellCenter(next.col, next.row), nextCell: next }; } const scanner = scannerReceivingFrom(cell, dirName); - if (scanner) return { type: 'scanner', dirName, target: scannerCenter(scanner), scanner }; + if (scanner && !['meat', 'sausage'].includes(item?.sex)) return { type: 'scanner', dirName, target: scannerCenter(scanner), scanner }; const facilityPair = facilityAtEntryCell(cell); if (facilityPair && dirExitsToFacility(facilityPair[1], dirName)) { return { type: 'facility', dirName, facilityId: facilityPair[0], facility: facilityPair[1], target: cellCenter(cell.col, cell.row) }; @@ -250,11 +327,11 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck if (connected.length < 3) return dirs; const entrances = new Set(connected.filter(dir => neighborPointsIntoCell(cell, dir))); const physicalExits = connected.filter(dir => !entrances.has(dir)); - let candidates = entrances.size && physicalExits.length >= 2 + let candidates = entrances.size ? physicalExits : [...new Set(dirs.filter(dir => connected.includes(dir)))]; - if (candidates.length < 2) candidates = connected; - if (branchMode && branchMode !== 'random' && branchMode !== 'pass' && candidates.includes(branchMode)) return [branchMode]; + if (!candidates.length && !entrances.size) candidates = connected; + if (branchMode && branchMode !== 'random' && branchMode !== 'pass' && candidates.length >= 2 && candidates.includes(branchMode)) return [branchMode]; return candidates; } @@ -263,7 +340,7 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck } function pickMovementOption(chick, cell, dirs, branchMode = 'random') { - const candidates = dirs.map(dir => movementOptionFromDir(cell, dir)).filter(Boolean); + const candidates = dirs.map(dir => movementOptionFromDir(cell, dir, chick)).filter(Boolean); if (!candidates.length) return null; const moving = candidates.filter(opt => opt.type !== 'facility'); const empty = moving.filter(opt => !targetBlockedByChick(chick, opt.target)); @@ -301,6 +378,7 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck if (kind === 'mixer') resolveMixer(index, option.facility); else if (kind === 'truck') resolveTruck(index, option.facility); else if (kind === 'trash') resolveTrash(index, option.facility); + else if (kind === 'sausageMaker') resolveSausageMaker(index, option.facility); else removeChick(index, 'DONE'); return; } @@ -345,10 +423,12 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck recordPassAtPoint(chick, target); chick.targetIndex += 1; remaining -= dist; + markPositionsChanged(); } else { chick.x += dx / dist * remaining; chick.y += dy / dist * remaining; remaining = 0; + markPositionsChanged(); } } } @@ -359,6 +439,7 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck chick.queueRoute = routeOverride ? routeOverride.map(p => ({ x: p.x, y: p.y })) : [scannerCenter(scanner)]; chick.scannerId = scanner.id; if (!scanner.queue.includes(chick.id)) scanner.queue.push(chick.id); + markChicksChanged(); positionScannerQueue(scanner); } @@ -379,6 +460,7 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck const end = route[route.length - 1]; chick.x = end.x; chick.y = end.y; + markPositionsChanged(); return; } let remain = distanceBack; @@ -389,6 +471,7 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck const t = 1 - remain / len; chick.x = a.x + (b.x - a.x) * t; chick.y = a.y + (b.y - a.y) * t; + markPositionsChanged(); return; } remain -= len; @@ -396,6 +479,7 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck const start = route[0]; chick.x = start.x; chick.y = start.y; + markPositionsChanged(); } function updateScannerQueues(dt) { @@ -492,7 +576,13 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck const graph = ensureFactoryGraph(game); const keys = (graph.scannerPorts.get(scanner.id)?.[side]?.keys || []).filter(Boolean); if (!keys.length) return null; - const parsed = keys.map(parseKey); + const parsed = keys.map(parseKey).sort((a, b) => { + const ac = cellCenter(a.col, a.row); + const bc = cellCenter(b.col, b.row); + const ab = targetBlockedByChick(null, ac) ? 1 : 0; + const bb = targetBlockedByChick(null, bc) ? 1 : 0; + return ab - bb; + }); const exact = parsed.find(p => p.col === connector.col && p.row === connector.row); return exact || parsed[0] || null; } @@ -530,6 +620,7 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck chick.pendingScannerId = null; chick.queueRoute = null; chick.queueIndex = -1; + markChicksChanged(); const pulseColor = auto ? THEME.green : (side === 'left' ? THEME.mixerBlue : THEME.truckPink); scannerPulse(game, scannerCenter(scanner).x, scannerCenter(scanner).y, pulseColor); floating(game, chick.x, chick.y - 20, auto ? 'AUTO' : side.toUpperCase(), pulseColor); @@ -540,6 +631,7 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck const chick = game.chicks[index]; if (!chick) return null; game.chicks.splice(index, 1); + markChicksChanged(); return chick; } @@ -555,6 +647,11 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck countMixer(game); recordFacilityProcess(game, mixer); setFacilityCooldownAfterProcess(game, mixer); + if (chick.sex === 'meat' || chick.sex === 'sausage') { + countMistake(game); + floating(game, x, y - 18, 'CHICKS ONLY', THEME.warn); + return; + } if (chick.sex === 'poop') { const penalty = applyMixerPoopFine(game); countPoopDestination(game, 'mixer'); @@ -563,11 +660,20 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck floating(game, x, y - 18, `-${yen(penalty)}`, THEME.danger); return; } - const amount = applyMixerIncome(game); if (chick.sex === 'male') countCorrect(game); else countMistake(game); + const out = facilityOutputCell(game, mixer); + if (!out || !facilityOutputHasConveyor(game, mixer) || !outputCellFree(out)) { + const amount = applyMixerIncome(game); + floating(game, x, y - 18, `DIRECT +${yen(amount)}`, THEME.green); + return; + } + mixer.meatBuffer = Math.max(0, mixer.meatBuffer || 0) + 1; + game.stats.meatProduced = (game.stats.meatProduced || 0) + 1; + game.totals.meatProduced = (game.totals.meatProduced || 0) + 1; meatEffect(game, x, y); - floating(game, x, y - 18, `+${yen(amount)}`, THEME.green); + floating(game, x, y - 18, 'MEAT +1', THEME.meatRed); + flushFacilityOutputs(); } function resolveTruck(index, truck = game.facilities.truck) { @@ -579,6 +685,17 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck countTruckCargo(game, chick.sex); const target = truckTarget(game); const isTarget = isTargetTruckCargo(game, chick.sex); + if (chick.sex === 'sausage') { + game.stats.sausageShipped = (game.stats.sausageShipped || 0) + 1; + game.totals.sausageShipped = (game.totals.sausageShipped || 0) + 1; + floating(game, x, y - 18, `SAUSAGE +${yen(upgradedSausagePrice(game))}`, THEME.sausageOrange); + return; + } + if (chick.sex === 'meat') { + countMistake(game); + floating(game, x, y - 18, 'RAW MEAT REJECT', THEME.warn); + return; + } if (chick.sex === 'poop') { countPoopDestination(game, 'truck'); if (isTarget) { @@ -616,6 +733,72 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck } } + function createProduct(product, cell) { + const c = cellCenter(cell.col, cell.row); + return { + id: game.nextId++, sex: product, x: c.x, y: c.y, + route: [{ x: c.x, y: c.y }], targetIndex: 1, stage: 'belt', + scannerId: null, nextScannerId: null, pendingScannerId: null, + radius: product === 'sausage' ? 11 : 10, bob: Math.random() * Math.PI * 2, + queueIndex: -1, queueRoute: null, stoppedTimer: 0 + }; + } + + function outputCellFree(cell) { + if (!cell || !game.conveyorTiles.has(key(cell.col, cell.row))) return false; + const c = cellCenter(cell.col, cell.row); + return !targetBlockedByChick(null, c); + } + + function emitFromFacility(facility, product, bufferKey) { + const out = facilityOutputCell(game, facility); + if (!out || !facilityOutputHasConveyor(game, facility) || !outputCellFree(out)) return false; + if (Math.max(0, facility[bufferKey] || 0) <= 0) return false; + facility[bufferKey] -= 1; + game.chicks.push(createProduct(product, out)); + markChicksChanged(); + const c = cellCenter(out.col, out.row); + floating(game, c.x, c.y - 16, product === 'meat' ? 'MEAT OUT' : 'SAUSAGE OUT', product === 'meat' ? THEME.meatRed : THEME.sausageOrange); + return true; + } + + function flushFacilityOutputs() { + for (const facility of Object.values(game.facilities || {})) { + const kind = facilityKind(facility); + if (kind === 'mixer') emitFromFacility(facility, 'meat', 'meatBuffer'); + if (kind === 'sausageMaker') emitFromFacility(facility, 'sausage', 'sausageBuffer'); + } + } + + function resolveSausageMaker(index, machine) { + if (machine?.processingCooldown > 0) { + const item = game.chicks[index]; + if (item) item.stoppedTimer = 0.25; + return; + } + const item = takeChick(index); + if (!item) return; + const { x, y } = item; + if (item.sex !== 'meat') { + countMistake(game); + floating(game, x, y - 18, 'MEAT ONLY', THEME.warn); + return; + } + recordFacilityProcess(game, machine); + setFacilityCooldownAfterProcess(game, machine); + machine.meatBuffer = Math.max(0, machine.meatBuffer || 0) + 1; + if (machine.meatBuffer >= 2) { + machine.meatBuffer -= 2; + machine.sausageBuffer = Math.max(0, machine.sausageBuffer || 0) + 1; + game.stats.sausageProduced = (game.stats.sausageProduced || 0) + 1; + game.totals.sausageProduced = (game.totals.sausageProduced || 0) + 1; + floating(game, x, y - 18, 'SAUSAGE +1', THEME.sausageOrange); + } else { + floating(game, x, y - 18, 'MEAT 1/2', THEME.meatRed); + } + flushFacilityOutputs(); + } + function resolveTrash(index, trash = game.facilities.trash) { if (trash?.processingCooldown > 0) { const chick = game.chicks[index]; @@ -633,7 +816,7 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck let bonusText = ''; if (chick.sex === 'poop') { bonus = applyShredderBonus(game); - bonusText = bonus.amount > 0 ? ` +${yen(bonus.amount)}` : ''; + bonusText = bonus.amount > 0 ? ` ${bonus.tier === 'jackpot' ? 'JACKPOT ' : '+'}${yen(bonus.amount)}` : ' MISS'; countPoopDestination(game, 'trash'); countCorrect(game); const compost = Math.ceil(Math.max(0, Number(game.cardEffects?.composter) || 0) * 3 * shredderPayoutMultiplier(game)); @@ -669,15 +852,29 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck const k = key(cell.col, cell.row); if (game.conveyorTiles.has(k)) return k; } - const nearest = nearestConveyorKey(game, chick.x, chick.y); - if (!nearest) return null; - const p = parseKey(nearest); - const c = cellCenter(p.col, p.row); - return Math.hypot(chick.x - c.x, chick.y - c.y) <= GRID.cell * 0.55 ? nearest : null; + if (!cell) return null; + let nearest = null; + let nearestDistance = Infinity; + for (const p of [cell, ...DIRS.map(d => ({ col: cell.col + d.dc, row: cell.row + d.dr }))]) { + if (!inGrid(p.col, p.row)) continue; + const k = key(p.col, p.row); + if (!game.conveyorTiles.has(k)) continue; + const c = cellCenter(p.col, p.row); + const distance = Math.hypot(chick.x - c.x, chick.y - c.y); + if (distance < nearestDistance) { + nearest = k; + nearestDistance = distance; + } + } + return nearestDistance <= GRID.cell * 0.55 ? nearest : null; } - function updateCongestion() { + function updateCongestion(frameId = game.frameId || 0) { + const cache = frameCache(); + const routingVersion = game.routingVersion || 0; + if (cache.congestionFrame === frameId && cache.routingVersion === routingVersion) return game.congestion; const { components, cellToComponent } = buildConveyorComponents(game); + const componentChicks = new Map(); for (const chick of game.chicks) { if (chick.stage === 'flying') continue; const k = conveyorKeyAtChick(chick); @@ -685,10 +882,18 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck const id = cellToComponent.get(k); const comp = components.get(id); if (comp) comp.count += 1; + if (id != null) { + if (!componentChicks.has(id)) componentChicks.set(id, []); + componentChicks.get(id).push(chick); + } } for (const comp of components.values()) comp.ratio = comp.count / comp.capacity; game.congestion = components; game.componentLookup = cellToComponent; + cache.routingVersion = routingVersion; + cache.congestionFrame = frameId; + cache.componentChicks = componentChicks; + return game.congestion; } function checkCongestionExplosions() { @@ -714,10 +919,8 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck } function chicksInComponent(id) { - return game.chicks.filter(ch => { - const k = conveyorKeyAtChick(ch); - return k && game.componentLookup?.get(k) === id; - }); + updateCongestion(game.frameId || 0); + return game.frameCache?.componentChicks?.get(id) || []; } function explodeComponent(comp) { @@ -726,6 +929,7 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck for (const v of victims) flyingDebris(game, v.sex, v.x, v.y); game.chicks = game.chicks.filter(ch => !victims.some(v => v.id === ch.id)); for (const scanner of game.scanners) scanner.queue = scanner.queue.filter(id => game.chicks.some(c => c.id === id)); + markChicksChanged(); for (const k of comp.cells) { const p = parseKey(k); const c = cellCenter(p.col, p.row); @@ -743,6 +947,7 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck return { activeQueuedChick, + beginFrame, currentSpawnDelay, sortSlot, updateCongestion, diff --git a/src/systems/economy.js b/src/systems/economy.js index 89a094a..0733147 100644 --- a/src/systems/economy.js +++ b/src/systems/economy.js @@ -53,6 +53,10 @@ export function upgradedTruckPrice(game) { return Math.ceil(ECONOMY.income.truck * incomeMultiplier(game, 'truck')); } +export function upgradedSausagePrice(game) { + return Math.ceil((ECONOMY.income.sausage || 26) * incomeMultiplier(game, 'mixer') * incomeMultiplier(game, 'sausageMaker')); +} + export function mixerPoopPenalty(game) { return Math.ceil(ECONOMY.poopFine * incomeMultiplier(game, 'mixer') * poopFineMultiplier(game)); } @@ -81,21 +85,54 @@ export function shredderBonusMaxCards() { return ECONOMY.shredderBonus.maxCards; } -export function shredderBonusIncome(gameOrCount) { +function shredderRules() { + return ECONOMY.shredderBonus || {}; +} + +export function shredderBasePayout(gameOrCount) { const count = typeof gameOrCount === 'number' ? gameOrCount : shredderUpgradeCount(gameOrCount); - const capped = Math.min(ECONOMY.shredderBonus.maxCards, Math.max(0, count)); - return capped > 0 ? Math.ceil(capped * (ECONOMY.shredderBonus.incomePerUpgrade || 1)) : 0; + const rules = shredderRules(); + const capped = Math.min(rules.maxCards || 30, Math.max(0, count)); + return capped > 0 ? Math.ceil((rules.payoutCoefficient || 1.6) * Math.pow(capped, rules.payoutExponent || 1.25)) : 0; } export function shredderBonusChance(gameOrCount) { - return shredderBonusIncome(gameOrCount) > 0 ? 1 : 0; + const count = typeof gameOrCount === 'number' ? gameOrCount : shredderUpgradeCount(gameOrCount); + if (count <= 0) return 0; + const rules = shredderRules(); + return Math.min(rules.maxHitChance || 0.82, (rules.baseHitChance || 0.28) + count * (rules.hitChancePerUpgrade || 0.018)); +} + +function shredderExpectedMultiplier(count) { + const rules = shredderRules(); + const jackpot = Math.min(rules.jackpotMaxChance || 0.08, (rules.jackpotBaseChance || 0.01) + count * (rules.jackpotChancePerUpgrade || 0.0025)); + const big = Math.min(rules.bigWinMaxChance || 0.12, (rules.bigWinBaseChance || 0.07) + count * (rules.bigWinChancePerUpgrade || 0.0015)); + const double = Math.min(1 - jackpot - big, rules.doubleChance || 0.20); + const normal = Math.max(0, 1 - jackpot - big - double); + return jackpot * (rules.jackpotMultiplier || 10) + big * (rules.bigWinMultiplier || 4) + double * (rules.doubleMultiplier || 2) + normal; +} + +export function shredderBonusIncome(gameOrCount) { + const count = typeof gameOrCount === 'number' ? gameOrCount : shredderUpgradeCount(gameOrCount); + return Math.round(shredderBasePayout(count) * shredderBonusChance(count) * shredderExpectedMultiplier(count)); } export function rollShredderBonus(game) { const cards = shredderUpgradeCount(game); - const baseAmount = shredderBonusIncome(cards); - const amount = Math.ceil(baseAmount * shredderPayoutMultiplier(game)); - return { cards, chance: amount > 0 ? 1 : 0, amount, expected: amount, baseAmount }; + const chance = shredderBonusChance(cards); + const baseAmount = shredderBasePayout(cards); + if (cards <= 0 || Math.random() >= chance) return { cards, chance, amount: 0, expected: shredderBonusIncome(cards), baseAmount, multiplier: 0, tier: 'miss' }; + const rules = shredderRules(); + const jackpot = Math.min(rules.jackpotMaxChance || 0.08, (rules.jackpotBaseChance || 0.01) + cards * (rules.jackpotChancePerUpgrade || 0.0025)); + const big = Math.min(rules.bigWinMaxChance || 0.12, (rules.bigWinBaseChance || 0.07) + cards * (rules.bigWinChancePerUpgrade || 0.0015)); + const double = Math.min(1 - jackpot - big, rules.doubleChance || 0.20); + const roll = Math.random(); + let multiplier = 1, tier = 'normal'; + if (roll < jackpot) { multiplier = rules.jackpotMultiplier || 10; tier = 'jackpot'; } + else if (roll < jackpot + big) { multiplier = rules.bigWinMultiplier || 4; tier = 'big'; } + else if (roll < jackpot + big + double) { multiplier = rules.doubleMultiplier || 2; tier = 'double'; } + const amount = Math.ceil(baseAmount * multiplier * shredderPayoutMultiplier(game)); + return { cards, chance, amount, expected: shredderBonusIncome(cards), baseAmount, multiplier, tier }; } export function applyShredderBonus(game) { @@ -180,7 +217,7 @@ export function refundCash(game, amount) { } export function applyMixerIncome(game) { - const amount = upgradedMixerPrice(game); + const amount = ECONOMY.income.mixer; game.stats.mixerRevenue += amount; applyRevenue(game, amount); return amount; @@ -223,13 +260,17 @@ export function settleTruckRevenue(game) { const targetCount = targetTruckCount(game.stats, target); const unitPrice = target === 'poop' ? Math.ceil(upgradedTruckPrice(game) * poopValueMultiplier(game)) : upgradedTruckPrice(game); const base = targetCount * unitPrice; - const adjusted = positivePayout(game, base); + const sausageCount = Math.max(0, game?.stats?.sausageShipped || 0); + const sausageUnitPrice = upgradedSausagePrice(game); + const sausageRevenue = sausageCount * sausageUnitPrice; + const adjusted = positivePayout(game, base + sausageRevenue); game.stats.pendingTruckRevenue = adjusted; game.stats.truckRevenue = adjusted; - if (target === 'poop') game.stats.poopShipmentIncome = adjusted; - else game.stats.chickShipmentIncome = adjusted; + game.stats.sausageRevenue = sausageRevenue; + if (target === 'poop') game.stats.poopShipmentIncome = base; + else game.stats.chickShipmentIncome = base; if (adjusted > 0) applyRevenue(game, adjusted); - return { base, adjusted, target, targetCount, unitPrice }; + return { base, adjusted, target, targetCount, unitPrice, sausageCount, sausageUnitPrice, sausageRevenue }; } export function collectFairiesTribute(game, turn = game.turn, basisProfit = null, options = {}) { diff --git a/src/systems/effects.js b/src/systems/effects.js index ebd444f..963f0af 100644 --- a/src/systems/effects.js +++ b/src/systems/effects.js @@ -1,4 +1,5 @@ import { EFFECT_PRIORITY, THEME } from '../core/config.js'; +import { BALANCE } from '../core/balance.js'; import { randomBetween, yen } from '../core/utils.js'; import { applyExplosionDamage } from './economy.js'; @@ -46,7 +47,8 @@ export function smokeBurst(game, x, y, count = 10) { export function flyingDebris(game, sex, x, y, baseAngle = null, noDamage = false) { const angle = baseAngle === null ? randomBetween(-Math.PI, Math.PI) : baseAngle + randomBetween(-0.9, 0.9); const speed = randomBetween(260, 620); - game.effects.push({ type: 'flyingChick', priority: EFFECT_PRIORITY.critical, sex, x: x + randomBetween(-8, 8), y: y + randomBetween(-8, 8), vx: Math.cos(angle) * speed, vy: Math.sin(angle) * speed - randomBetween(80, 220), radius: sex === 'poop' ? 11 : 13, hit: new Set(), life: 4.2, maxLife: 4.2, spin: randomBetween(-8, 8), noDamage }); + const horizontalMultiplier = Math.max(0, Number(BALANCE.effects?.explosionHorizontalVelocityMultiplier) || 1); + game.effects.push({ type: 'flyingChick', priority: EFFECT_PRIORITY.critical, sex, x: x + randomBetween(-8, 8), y: y + randomBetween(-8, 8), vx: Math.cos(angle) * speed * horizontalMultiplier, vy: Math.sin(angle) * speed - randomBetween(80, 220), radius: sex === 'poop' ? 11 : 13, hit: new Set(), life: 4.2, maxLife: 4.2, spin: randomBetween(-8, 8), noDamage }); } export function eraseEffect(game, x, y) { game.effects.push({ type: 'erase', priority: EFFECT_PRIORITY.important, x, y, life: .45, maxLife: .45, size: 54 }); diff --git a/src/systems/events.js b/src/systems/events.js index 47ec63e..523ff62 100644 --- a/src/systems/events.js +++ b/src/systems/events.js @@ -2,7 +2,7 @@ import { TURN_SECONDS, POOP_RATE, POOP_RATE_CARD_BONUS, DAILY_EVENT_CHANCE, DAIL import { getSpawnRange } from '../core/state.js'; import { applyRevenue } from './economy.js'; -const EVENT_TARGETS = [ +export const EVENT_TARGETS = [ { key: 'premiumFemaleShipment', target: 'female', @@ -138,11 +138,11 @@ function estimateForTemplate(game, template) { return { estimate, poopRate }; } -export function rollEventOffer(game) { - const nextTurn = game.turn + 1; - if (nextTurn < DAILY_EVENT_FIRST_TURN) return null; - if (Math.random() > DAILY_EVENT_CHANCE) return null; - const template = EVENT_TARGETS[Math.floor(Math.random() * EVENT_TARGETS.length)]; +export function createEventOffer(game, templateOrKey) { + const template = typeof templateOrKey === 'string' + ? EVENT_TARGETS.find(item => item.key === templateOrKey) + : templateOrKey; + if (!template) return null; const { estimate, poopRate } = estimateForTemplate(game, template); let targetAmount = 0; if (template.objective === 'truckTarget') targetAmount = Math.max(1, Math.ceil(estimate * 0.3)); @@ -169,6 +169,14 @@ export function rollEventOffer(game) { }; } +export function rollEventOffer(game) { + const nextTurn = game.turn + 1; + if (nextTurn < DAILY_EVENT_FIRST_TURN) return null; + if (Math.random() > DAILY_EVENT_CHANCE) return null; + const template = EVENT_TARGETS[Math.floor(Math.random() * EVENT_TARGETS.length)]; + return createEventOffer(game, template); +} + export function activateEventOffer(game) { game.eventActive = game.eventOffer ? { ...game.eventOffer } : null; game.eventOffer = null; @@ -249,7 +257,7 @@ function countLowDurabilityMachines(game) { for (const scanner of game.scanners || []) if (scanner.kind === 'auto') add(scanner.maintenance?.uses, scanner.maintenance?.durability); for (const f of Object.values(game.facilities || {})) { const kind = f?.baseId || f?.id; - if (kind === 'mixer' || kind === 'trash') add(f.maintenance?.uses, f.maintenance?.durability); + if (kind === 'mixer' || kind === 'trash' || kind === 'sausageMaker') add(f.maintenance?.uses, f.maintenance?.durability); } return count; } diff --git a/src/systems/history.js b/src/systems/history.js index 83d421a..c86e9c0 100644 --- a/src/systems/history.js +++ b/src/systems/history.js @@ -14,7 +14,8 @@ export function snapshot(game) { gridCols: game.gridCols || GRID.cols, gridRows: game.gridRows || GRID.rows, gridExpansionPurchases: game.gridExpansionPurchases || 0, - gridExpansionPurchasesByDirection: game.gridExpansionPurchasesByDirection || { right: 0, up: 0 }, + gridExpansionPurchasesByDirection: game.gridExpansionPurchasesByDirection || { left: 0, right: 0, up: 0, down: 0 }, + gridChunkOriginX: game.gridChunkOriginX || 0, gridChunkOriginY: game.gridChunkOriginY || 0, ownedCells: [...(game.ownedCells || [])], ownedChunks: [...(game.ownedChunks || [])], @@ -47,7 +48,10 @@ export function restore(game, text) { game.gridCols = GRID.cols; game.gridRows = GRID.rows; game.gridExpansionPurchases = data.gridExpansionPurchases || 0; - game.gridExpansionPurchasesByDirection = data.gridExpansionPurchasesByDirection || { right: 0, up: 0 }; + game.gridExpansionPurchasesByDirection = data.gridExpansionPurchasesByDirection || { left: 0, right: 0, up: 0, down: 0 }; + if (game.gridExpansionPurchasesByDirection.left == null) game.gridExpansionPurchasesByDirection.left = 0; + if (game.gridExpansionPurchasesByDirection.down == null) game.gridExpansionPurchasesByDirection.down = 0; + game.gridChunkOriginX = data.gridChunkOriginX || 0; game.gridChunkOriginY = data.gridChunkOriginY || 0; game.ownedCells = new Set(data.ownedCells || []); game.ownedChunks = new Set(data.ownedChunks || []); diff --git a/src/systems/maintenance.js b/src/systems/maintenance.js index 6321b38..f343832 100644 --- a/src/systems/maintenance.js +++ b/src/systems/maintenance.js @@ -163,7 +163,7 @@ export function facilityProcessingDelay(game, target) { ensureMaintenanceState(game); const f = facilityFromTarget(game, target); const id = facilityKind(f || target); - if (!f || !['mixer', 'trash'].includes(id)) return 0; + if (!f || !['mixer', 'trash', 'sausageMaker'].includes(id)) return 0; attachMaintenance(f, id); const t = Math.max(0, delayMultiplier(f) - 1); return t * (RULES.processingDelayMaxSeconds?.[id] || 1); @@ -195,7 +195,7 @@ export function recordFacilityProcess(game, target) { ensureMaintenanceState(game); const f = facilityFromTarget(game, target); const id = facilityKind(f || target); - if (!f || !['mixer', 'trash'].includes(id)) return; + if (!f || !['mixer', 'trash', 'sausageMaker'].includes(id)) return; attachMaintenance(f, id); f.maintenance.uses = Math.min(f.maintenance.durability, (f.maintenance.uses || 0) + degradationUseMultiplier(game)); } @@ -210,7 +210,7 @@ export function setFacilityCooldownAfterProcess(game, target) { export function updateProcessingCooldowns(game, dt) { for (const f of Object.values(game.facilities || {})) { - if (!['mixer', 'trash'].includes(f.baseId || f.id)) continue; + if (!['mixer', 'trash', 'sausageMaker'].includes(f.baseId || f.id)) continue; if (f?.processingCooldown > 0) f.processingCooldown = Math.max(0, f.processingCooldown - dt); } } @@ -223,7 +223,7 @@ export function equipmentMaintenanceTargets(game) { for (const scanner of (game.scanners || []).filter(s => s.kind === 'auto')) targets.push({ type: 'autoScanner', ref: scanner, label: `AUTO #${scanner.id}`, center: cellCenter(scanner.col, scanner.row) }); for (const f of Object.values(game.facilities || {})) { const kind = facilityKind(f); - if (!['mixer', 'trash'].includes(kind)) continue; + if (!['mixer', 'trash', 'sausageMaker'].includes(kind)) continue; targets.push({ type: kind, ref: f, label: `${f.shortName || f.name || kind} #${f.id}`, center: { x: f.x + f.w / 2, y: f.y + f.h / 2 } }); } return targets; diff --git a/src/systems/routing.js b/src/systems/routing.js index 99a74c2..c9074e5 100644 --- a/src/systems/routing.js +++ b/src/systems/routing.js @@ -1,4 +1,4 @@ -import { DIRS, GRID, MACHINE_FACILITY_IDS } from '../core/config.js'; +import { DIRS, GRID, MACHINE_FACILITY_IDS, REQUIRED_RECEIVER_FACILITY_IDS } from '../core/config.js'; import { routeLabel } from '../core/text.js'; import { key, parseKey, inGrid, cellCenter, distance, sameCell } from '../core/utils.js'; @@ -11,14 +11,12 @@ export function scannerFootprintCells(scanner) { { col: scanner.col, row: scanner.row - 1 }, { col: scanner.col + 1, row: scanner.row - 1 }, { col: scanner.col, row: scanner.row }, - { col: scanner.col + 1, row: scanner.row }, - { col: scanner.col, row: scanner.row + 1 }, - { col: scanner.col + 1, row: scanner.row + 1 } + { col: scanner.col + 1, row: scanner.row } ]; } export function scannerCenter(scanner) { const c = cellCenter(scanner.col, scanner.row); - return { x: c.x + GRID.cell / 2, y: c.y }; + return { x: c.x + GRID.cell / 2, y: c.y - GRID.cell / 2 }; } export function farmAt(game, col, row) { return game.eggFarms.find(f => f.col === col && f.row === row) || null; } export function scannerAt(game, col, row) { return game.scanners.find(s => scannerFootprintCells(s).some(p => p.col === col && p.row === row)) || null; } @@ -29,6 +27,52 @@ function facilityEntriesForKind(game, kind) { return Object.entries(game.facilities || {}).filter(([, f]) => facilityKind(f) === kind); } +function usableOwnedCell(game, p) { + return !!(p && inGrid(p.col, p.row) && (!game?.ownedCells?.size || game.ownedCells.has(key(p.col, p.row)))); +} + +export function gridFacilityAt(game, col, row) { + return Object.values(game?.facilities || {}).find(f => { + if (!f?.gridPlaced) return false; + return col >= f.col && col < f.col + (f.wCells || 3) && row >= f.row && row < f.row + (f.hCells || 3); + }) || null; +} + +export function facilityInputCell(game, facility) { + const f = typeof facility === 'string' ? game?.facilities?.[facility] : facility; + if (!f) return null; + if (facilityKind(f) === 'sausageMaker' && f.gridPlaced) { + const p = { col: f.col - 1, row: f.row + Math.floor((f.hCells || 3) / 2) }; + return usableOwnedCell(game, p) ? p : null; + } + return usableOwnedCell(game, f.entry) ? { ...f.entry } : null; +} + +export function facilityOutputCell(game, facility) { + const f = typeof facility === 'string' ? game?.facilities?.[facility] : facility; + const kind = facilityKind(f); + if (!f || !['mixer', 'sausageMaker'].includes(kind)) return null; + if (kind === 'sausageMaker' && f.gridPlaced) { + const p = { col: f.col + (f.wCells || 3), row: f.row + Math.floor((f.hCells || 3) / 2) }; + return usableOwnedCell(game, p) ? p : null; + } + const input = facilityInputCell(game, f); + if (!input) return null; + const offsets = [2, -2, 3, -3, 1, -1]; + for (const offset of offsets) { + const p = (f.side === 'left' || f.side === 'right') + ? { col: input.col, row: input.row + offset } + : { col: input.col + offset, row: input.row }; + if (usableOwnedCell(game, p)) return p; + } + return null; +} + +export function facilityOutputHasConveyor(game, facility) { + const p = facilityOutputCell(game, facility); + return !!(p && game?.conveyorTiles?.has?.(key(p.col, p.row))); +} + // ----------------------------------------------------------------------------- // Port definitions. Ports prefer the exact connector cell, but also accept // visually touching adjacent conveyor cells so drawn connections and routing match. @@ -73,7 +117,7 @@ function graphPortConveyorCells(game, point, blocked = [], preferred = []) { export function scannerInputCells(game, scanner) { const connector = scannerConnector(scanner, 'inputA'); if (!connector || !inGrid(connector.col, connector.row)) return []; - return game.conveyorTiles.has(key(connector.col, connector.row)) ? [{ ...connector, viaTolerance: false }] : []; + return graphPortConveyorCells(game, connector, scannerFootprintCells(scanner)); } function outputStartCells(game, scanner, side) { @@ -84,7 +128,8 @@ function outputStartCells(game, scanner, side) { export function facilityEntryPoint(game, dest) { const f = game.facilities[dest] || facilityEntriesForKind(game, dest)[0]?.[1]; if (!f) return null; - if (f.entry) return cellCenter(f.entry.col, f.entry.row); + const input = facilityInputCell(game, f); + if (input) return cellCenter(input.col, input.row); const kind = facilityKind(f) || dest; if (kind === 'mixer') return { x: f.x + f.w, y: f.y + f.h * 0.52 }; if (kind === 'truck') return { x: f.x, y: f.y + f.h * 0.52 }; @@ -103,6 +148,11 @@ export function refreshRoutingAfterEdit(game) { game.routingVersion = (game.routingVersion || 0) + 1; game.factoryGraph = null; game.factoryGraphCommittedVersion = -1; + if (game.frameCache) { + game.frameCache.routingVersion = -1; + game.frameCache.congestionFrame = -1; + game.frameCache.draw = {}; + } } // ----------------------------------------------------------------------------- @@ -139,12 +189,13 @@ function inferredConveyorOutDirNames(game, cellKey) { .map(d => d.name); const explicit = conveyorOutDirNames(game, cellKey).filter(dir => neighbors.includes(dir)); const dirs = explicit.length ? explicit : neighbors; + if (neighbors.length === 1 && (explicit.length ? explicit.includes(neighbors[0]) : true) && neighborPointsIntoCell(game, p, neighbors[0])) return []; if (neighbors.length < 3) return dirs; const entrances = new Set(neighbors.filter(dir => neighborPointsIntoCell(game, p, dir))); const physicalExits = neighbors.filter(dir => !entrances.has(dir)); - let candidates = entrances.size && physicalExits.length >= 2 ? physicalExits : [...new Set(dirs)]; - if (candidates.length < 2) candidates = neighbors; - if (meta.branchMode && meta.branchMode !== 'random' && candidates.includes(meta.branchMode)) return [meta.branchMode]; + let candidates = entrances.size ? physicalExits : [...new Set(dirs)]; + if (!candidates.length && !entrances.size) candidates = neighbors; + if (meta.branchMode && meta.branchMode !== 'random' && candidates.length >= 2 && candidates.includes(meta.branchMode)) return [meta.branchMode]; return candidates; } @@ -237,10 +288,8 @@ function indexGraphPorts(game, graph) { const ports = {}; for (const type of ['inputA', 'left', 'right']) { const cell = scannerConnector(scanner, type); - const cells = type === 'inputA' - ? (cell && graph.cells.has(graphNodeKey(cell.col, cell.row)) ? [{ ...cell }] : []) - : graphPortConveyorCells(game, cell, scannerFootprintCells(scanner)) - .filter(p => graph.cells.has(graphNodeKey(p.col, p.row))); + const cells = graphPortConveyorCells(game, cell, scannerFootprintCells(scanner)) + .filter(p => graph.cells.has(graphNodeKey(p.col, p.row))); const cellKeys = cells.map(p => graphNodeKey(p.col, p.row)); const connected = cellKeys.length > 0; ports[type] = { type, cell, cells, keys: cellKeys, key: cellKeys[0] || null, connected }; @@ -252,11 +301,12 @@ function indexGraphPorts(game, graph) { } for (const [id, f] of Object.entries(game.facilities)) { - if (!f.entry) continue; - const cells = graphPortConveyorCells(game, f.entry).filter(p => graph.cells.has(graphNodeKey(p.col, p.row))); + const input = facilityInputCell(game, f); + if (!input) continue; + const cells = graphPortConveyorCells(game, input).filter(p => graph.cells.has(graphNodeKey(p.col, p.row))); const cellKeys = cells.map(p => graphNodeKey(p.col, p.row)); const connected = cellKeys.length > 0; - graph.facilityPorts.set(id, { id, cell: { ...f.entry }, cells, keys: cellKeys, key: cellKeys[0] || null, connected }); + graph.facilityPorts.set(id, { id, cell: { ...input }, cells, keys: cellKeys, key: cellKeys[0] || null, connected }); graph.metrics.facilityPorts += 1; if (connected) graph.metrics.connectedFacilityPorts += 1; } @@ -458,7 +508,12 @@ function candidateCongestionScore(game, candidate) { const cells = candidate.cells || []; let score = 0; const limit = Math.min(cells.length, 8); - for (let i = 0; i < limit; i += 1) score += chickCellOccupancyScore(game, cells[i], i); + for (let i = 0; i < limit; i += 1) { + const cell = cells[i]; + const compId = game.componentLookup?.get?.(graphNodeKey(cell.col, cell.row)); + const ratio = compId ? (game.congestion?.get?.(compId)?.ratio || 0) : 0; + score += chickCellOccupancyScore(game, cell, i) + ratio * 25; + } return score; } @@ -478,8 +533,9 @@ export function chooseRoundRobin(game, id, candidates, advance = false) { if (!advance || sorted.length === 1) return sorted[0]; const bestBias = sorted[0].roleBias ?? 0; let pool = sorted.filter(item => (item.roleBias ?? 0) === bestBias); - const bestScore = Math.min(...pool.map(item => candidateCongestionScore(game, item))); - pool = pool.filter(item => candidateCongestionScore(game, item) === bestScore); + const scored = pool.map(item => ({ item, score: candidateCongestionScore(game, item) })); + const bestScore = Math.min(...scored.map(entry => entry.score)); + pool = scored.filter(entry => entry.score === bestScore).map(entry => entry.item); const n = game.branchCounters.get(id) || 0; game.branchCounters.set(id, n + 1); return pool[Math.floor(Math.random() * pool.length)]; @@ -503,7 +559,7 @@ export function autoSideFor(scanner, chick) { export function destinationLabel(dest) { return routeLabel(dest); } export function destinationColor(dest) { - return { mixer: '#2477ff', truck: '#ff6aa8', trash: '#22b94f', 'scanner-role-1': '#526456', scanner: '#526456', input: '#526456' }[dest] || '#102015'; + return { mixer: '#2477ff', truck: '#ff6aa8', trash: '#22b94f', sausageMaker: '#d78b3f', 'scanner-role-1': '#526456', scanner: '#526456', input: '#526456' }[dest] || '#102015'; } export function routeFromFarmToScanner(game, farm, advance = false) { @@ -592,7 +648,7 @@ function outputRouteReachesFacility(game, scanner, visited = new Set()) { for (const side of ['left', 'right']) { const plan = outputRoute(game, side, scannerCenter(scanner), scanner.id, false); if (!plan) continue; - if (['mixer', 'trash', 'truck'].includes(plan.destination)) return true; + if (['mixer', 'trash', 'truck', 'sausageMaker'].includes(plan.destination)) return true; if (plan.destination === 'scanner') { const next = scannerById(game, plan.nextScannerId); if (outputRouteReachesFacility(game, next, visited)) return true; @@ -654,7 +710,7 @@ export function minimumStartConnectionIssues(game) { if (!graph.metrics.farmOutputs) return ['Connect at least one EGG to a conveyor.']; if (!game.scanners?.length) return ['Build at least one scanner and connect it to an EGG route.']; if (!exitCount) return ['Connect at least one receiver exit: Mixer, Shredder, or Truck.']; - return ['Connect at least one EGG through a scanner to any valid exit.']; + return ['No route from an EGG scanner to a receiver.']; } function scannerName(scanner) { @@ -665,12 +721,12 @@ function scannerName(scanner) { export function validateFactoryGraph(game, graph = ensureFactoryGraph(game), options = {}) { const includeRoutes = options.includeRoutes !== false; const issues = []; - const labels = { mixer: 'Mixer', trash: 'Shredder', truck: 'Truck' }; + const labels = { mixer: 'Mixer', trash: 'Shredder', truck: 'Truck', sausageMaker: 'Sausage Machine' }; for (const id of MACHINE_FACILITY_IDS) { const facilities = facilityEntriesForKind(game, id); if (!facilities.length) { - issues.push(`${labels[id] || id} is missing`); + if (REQUIRED_RECEIVER_FACILITY_IDS.includes(id)) issues.push(`${labels[id] || id} is missing`); continue; } for (const [facilityId] of facilities) { @@ -706,7 +762,3 @@ export function validateFactoryGraph(game, graph = ensureFactoryGraph(game), opt export function facilityConnectionIssues(game) { return minimumStartConnectionIssues(game); } - -export function factoryReady(game) { - return facilityConnectionIssues(game).length === 0; -} diff --git a/src/systems/selectionSystem.js b/src/systems/selectionSystem.js index 0aaab89..5f501b6 100644 --- a/src/systems/selectionSystem.js +++ b/src/systems/selectionSystem.js @@ -1,7 +1,7 @@ -import { GRID } from '../core/config.js'; +import { DIRS, GRID } from '../core/config.js'; import { key, parseKey, cellCenter } from '../core/utils.js'; -import { nearestGridEdge, layoutFacilityOnEdge, maintenanceRoomFootprint } from '../core/entities.js'; -import { farmAt, scannerAt, scannerCenter, scannerFootprintCells, refreshRoutingAfterEdit } from './routing.js'; +import { nearestGridEdge, layoutFacilityOnEdge, maintenanceRoomFootprint, gridFacilityFootprintCells, syncGridFacilityGeometry } from '../core/entities.js'; +import { farmAt, scannerAt, scannerCenter, scannerConnector, scannerFootprintCells, gridFacilityAt, facilityInputCell, facilityOutputCell, refreshRoutingAfterEdit } from './routing.js'; import { snapshot } from './history.js'; import { buildPrice } from './economy.js'; @@ -124,7 +124,9 @@ export function createSelectionSystem({ game, canvasPoint, updatePanels, equipme return { ...sel, obj, oldKey: sel.id, currentKey: sel.id, meta: game.conveyorMeta.get(sel.id) || { price: buildPrice('conveyor'), builtSession: null }, col: cell.col, row: cell.row }; } if (sel.type === 'eggFarm' || sel.type === 'scanner' || sel.type === 'maintenanceRoom') return { ...sel, obj, col: obj.col, row: obj.row }; - if (sel.type === 'facility') return { ...sel, obj, x: obj.x, y: obj.y, w: obj.w, h: obj.h, entry: obj.entry ? { ...obj.entry } : null, side: obj.side, center: { x: obj.x + obj.w / 2, y: obj.y + obj.h / 2 } }; + if (sel.type === 'facility') return obj.gridPlaced + ? { ...sel, obj, gridPlaced: true, col: obj.col, row: obj.row, x: obj.x, y: obj.y, w: obj.w, h: obj.h, entry: obj.entry ? { ...obj.entry } : null, side: obj.side, center: { x: obj.x + obj.w / 2, y: obj.y + obj.h / 2 } } + : { ...sel, obj, gridPlaced: false, x: obj.x, y: obj.y, w: obj.w, h: obj.h, entry: obj.entry ? { ...obj.entry } : null, side: obj.side, center: { x: obj.x + obj.w / 2, y: obj.y + obj.h / 2 } }; return null; } @@ -157,16 +159,47 @@ export function createSelectionSystem({ game, canvasPoint, updatePanels, equipme if (scanner && !selectedTokens.has(`scanner:${scanner.id}`)) return true; const room = (game.maintenanceRooms || []).find(item => maintenanceRoomFootprint(item).some(cell => cell.col === col && cell.row === row)); if (room && !selectedTokens.has(`maintenanceRoom:${room.id}`)) return true; + const gridFacility = gridFacilityAt(game, col, row); + if (gridFacility && !selectedTokens.has(`facility:${gridFacility.id}`)) return true; if (game.conveyorTiles.has(k) && !selectedTokens.has(`conveyor:${k}`)) return true; return false; } + + function facilityPortOccupiedByNonSelected(col, row, selectedTokens) { + for (const facility of Object.values(game.facilities || {})) { + if (selectedTokens.has(`facility:${facility.id}`)) continue; + const input = facilityInputCell(game, facility); + const output = facilityOutputCell(game, facility); + if ((input && input.col === col && input.row === row) || (output && output.col === col && output.row === row)) return true; + } + return false; + } + + function gridFacilityPortOccupiedByNonSelected(facility, col, row, selectedTokens) { + const farm = farmAt(game, col, row); + if (farm && !selectedTokens.has(`eggFarm:${farm.id}`)) return true; + const scanner = scannerAt(game, col, row); + if (scanner && !selectedTokens.has(`scanner:${scanner.id}`)) return true; + const room = (game.maintenanceRooms || []).find(item => maintenanceRoomFootprint(item).some(cell => cell.col === col && cell.row === row)); + if (room && !selectedTokens.has(`maintenanceRoom:${room.id}`)) return true; + const gridFacility = gridFacilityAt(game, col, row); + if (gridFacility && gridFacility.id !== facility.id && !selectedTokens.has(`facility:${gridFacility.id}`)) return true; + for (const other of Object.values(game.facilities || {})) { + if (other.id === facility.id || selectedTokens.has(`facility:${other.id}`)) continue; + const input = facilityInputCell(game, other); + const output = facilityOutputCell(game, other); + if ((input && input.col === col && input.row === row) || (output && output.col === col && output.row === row)) return true; + } + return false; + } + function facilityDragWouldOverlap(dx, dy, selectedTokens) { const candidateRects = []; for (const origin of game.groupDrag.origins) { - if (origin.type !== 'facility') continue; + if (origin.type !== 'facility' || origin.gridPlaced) continue; const nextCenter = { x: origin.center.x + dx, y: origin.center.y + dy }; - const { entry, side } = nearestGridEdge(nextCenter); + const { entry, side } = nearestGridEdge(nextCenter, game); if (!pointInGrid(entry.col, entry.row)) return true; if (game.blockedCells?.has?.(key(entry.col, entry.row))) return true; const draft = { ...origin.obj, entry: { ...entry }, side }; @@ -187,6 +220,27 @@ export function createSelectionSystem({ game, canvasPoint, updatePanels, equipme return false; } + function repairScannerOutputDirections(scanner) { + const body = new Set(scannerFootprintCells(scanner).map(cell => key(cell.col, cell.row))); + for (const side of ['left', 'right']) { + const port = scannerConnector(scanner, side); + const portKey = key(port.col, port.row); + if (!game.conveyorTiles.has(portKey)) continue; + const meta = game.conveyorMeta.get(portKey); + if (!meta) continue; + const preferred = DIRS.find(d => d.name === side); + const candidates = DIRS.filter(d => { + const nk = key(port.col + d.dc, port.row + d.dr); + return game.conveyorTiles.has(nk) && !body.has(nk); + }); + const chosen = candidates.find(d => d.name === preferred?.name) || candidates[0] || preferred; + if (!chosen) continue; + meta.dir = chosen.name; + meta.outDirs = [chosen.name]; + meta.branchMode = 'random'; + } + } + function updateGroupDrag(event) { if (!game.groupDrag) return; const p = canvasPoint(event); @@ -198,17 +252,31 @@ export function createSelectionSystem({ game, canvasPoint, updatePanels, equipme const selectedTokens = new Set(game.groupDrag.selections.map(selectionToken)); const targetCells = new Set(); for (const origin of game.groupDrag.origins) { - if (origin.type === 'facility') continue; + if (origin.type === 'facility' && !origin.gridPlaced) continue; const col = origin.col + dcol, row = origin.row + drow; - const cells = origin.type === 'scanner' ? scannerFootprintCells({ col, row }) : (origin.type === 'maintenanceRoom' ? maintenanceRoomFootprint({ col, row }) : [{ col, row }]); + const cells = origin.type === 'scanner' + ? scannerFootprintCells({ col, row }) + : (origin.type === 'maintenanceRoom' + ? maintenanceRoomFootprint({ col, row }) + : (origin.type === 'facility' ? gridFacilityFootprintCells({ ...origin.obj, col, row }) : [{ col, row }])); for (const cell of cells) { if (!pointInGrid(cell.col, cell.row)) return fail('Selection outside grid'); if (game.blockedCells?.has?.(key(cell.col, cell.row))) return fail('Selection hits blocked ground'); const tk = key(cell.col, cell.row); if (targetCells.has(tk)) return fail('Selection overlap'); if (cellOccupiedByNonSelected(cell.col, cell.row, selectedTokens)) return fail('Cell occupied'); + if (origin.type !== 'conveyor' && facilityPortOccupiedByNonSelected(cell.col, cell.row, selectedTokens)) return fail('Machine port must remain open'); targetCells.add(tk); } + if (origin.type === 'facility' && origin.gridPlaced) { + const draft = { ...origin.obj, col, row }; + const input = { col: col - 1, row: row + Math.floor((draft.hCells || 3) / 2) }; + const output = { col: col + (draft.wCells || 3), row: row + Math.floor((draft.hCells || 3) / 2) }; + for (const port of [input, output]) { + if (!pointInGrid(port.col, port.row) || game.blockedCells?.has?.(key(port.col, port.row))) return fail('Machine port outside usable grid'); + if (gridFacilityPortOccupiedByNonSelected(origin.obj, port.col, port.row, selectedTokens)) return fail('Machine port is occupied'); + } + } } if (facilityDragWouldOverlap(dx, dy, selectedTokens)) return fail('Facility overlap'); commitGroupDragHistory(); @@ -232,12 +300,17 @@ export function createSelectionSystem({ game, canvasPoint, updatePanels, equipme } else if (origin.type === 'scanner') { origin.obj.col = origin.col + dcol; origin.obj.row = origin.row + drow; + repairScannerOutputDirections(origin.obj); } else if (origin.type === 'maintenanceRoom') { origin.obj.col = origin.col + dcol; origin.obj.row = origin.row + drow; + } else if (origin.type === 'facility' && origin.gridPlaced) { + origin.obj.col = origin.col + dcol; + origin.obj.row = origin.row + drow; + syncGridFacilityGeometry(origin.obj); } else if (origin.type === 'facility') { const nextCenter = { x: origin.center.x + dx, y: origin.center.y + dy }; - const { entry, side } = nearestGridEdge(nextCenter); + const { entry, side } = nearestGridEdge(nextCenter, game); layoutFacilityOnEdge(origin.obj, entry, side); } } diff --git a/src/systems/uiSystem.js b/src/systems/uiSystem.js index ebe08c6..180ef58 100644 --- a/src/systems/uiSystem.js +++ b/src/systems/uiSystem.js @@ -1,9 +1,8 @@ import { BUILD_TOOL_IDS, CONVEYOR_SPEED_MAX, DAILY_EVENT_FIRST_TURN, FACILITY_DEFS, MACHINE_FACILITY_IDS, STARTING_CASH } from '../core/config.js'; import { yen } from '../core/utils.js'; import { TEXT } from '../core/text.js'; -import { routeFromFarmToScanner, factoryReady, facilityConnectionIssues } from './routing.js'; +import { routeFromFarmToScanner, facilityConnectionIssues } from './routing.js'; import { buildPrice, fairiesTributeInfo, finalScore, maleTruckPenalty, mixerPoopPenalty, truckPoopPenalty } from './economy.js'; -import { truckTarget } from './events.js'; import { conveyorSpeedForGame } from './cards.js'; import { maintenanceSummary } from './maintenance.js'; @@ -129,16 +128,21 @@ export function createUISystem({ game, ui, build, startGame, beginCardDraft, act } const nextTributeBasis = Math.max(0, Math.floor(game.lastResult?.profit ?? game.stats?.profit ?? 0)); const nextTribute = fairiesTributeInfo(game, Math.max(1, Number(game.turn) || 1), nextTributeBasis).amount; - ui.buttons.nextTurn.innerHTML = game.phase === 'build' && nextTribute > 0 + const nextTurnHtml = game.phase === 'build' && nextTribute > 0 ? `NEXT DAYFAIRIES -${yen(nextTribute)}` : `${TEXT.actions.nextDay}`; - ui.buttons.nextTurn.disabled = game.phase !== 'build' || !!game.cardDraft?.pending || !!game.cardTargetPick?.pending || !factoryReady(game); + // Replacing a pressed button's child nodes every animation frame can cancel + // the browser's pointerdown -> pointerup -> click sequence. Render only when + // the label actually changes, so one deliberate press always reaches the handler. + if (ui.buttons.nextTurn.dataset.renderedHtml !== nextTurnHtml) { + ui.buttons.nextTurn.innerHTML = nextTurnHtml; + ui.buttons.nextTurn.dataset.renderedHtml = nextTurnHtml; + } + ui.buttons.nextTurn.disabled = game.phase !== 'build' || !!game.cardDraft?.pending || !!game.cardTargetPick?.pending; } function updatePriorityStrip() { - if (!ui.eventBrief || !ui.targetBrief || !ui.speedBrief) return; - const target = truckTarget(game).toUpperCase(); - ui.targetBrief.textContent = `TRUCK TARGET: ${target}`; + if (!ui.eventBrief || !ui.speedBrief) return; ui.speedBrief.textContent = `BELT SPEED: ${displaySpeed()} px/s`; ui.speedBrief.title = `Conveyor speed does not increase by day. Degraded belts reduce speed. Cap: ${CONVEYOR_SPEED_MAX}px/s.`; const active = game.eventActive; @@ -168,7 +172,7 @@ export function createUISystem({ game, ui, build, startGame, beginCardDraft, act function showTitle() { ui.modalTitle.textContent = TEXT.versionTitle; - ui.modalBody.innerHTML = `
♂Male->MixerS1: A
♀Female->TruckS1: D, then S2: right
💩Poop->ShredderS1: D, then S2: left

Build phase: connect at least one EGG through a scanner to Mixer, Shredder, or Truck before Next Day. One day is one run.

`; + ui.modalBody.innerHTML = `
♂Male->Mixer -> MeatS1: A
♀Female->TruckS1: D, then S2: right
💩Poop->ShredderS1: D, then S2: left

Build phase: connect at least one EGG through a scanner to Mixer, Shredder, or Truck before Next Day. One day is one run.

`; ui.modalActions.innerHTML = ''; ui.modalActions.appendChild(button(TEXT.actions.startGame, startGame, 'primary-button')); ui.modal.classList.remove('equipment-popover', 'gameover-modal'); @@ -186,7 +190,8 @@ export function createUISystem({ game, ui, build, startGame, beginCardDraft, act
Chick shipment income${positive(r.chickShipmentIncome || 0)}
Poop shipment income${positive(r.poopShipmentIncome || 0)}
-
Mixer income${positive(r.mixerRevenue || 0)}
+
Sausage shipment income${positive(r.sausageRevenue || 0)}
+
Meat / sausages${r.meatProduced || 0} meat -> ${r.sausageProduced || 0} made / ${r.sausageShipped || 0} shipped
Composter income${positive(r.composterIncome || 0)}
DUD refund income${positive(r.dudRefundIncome || 0)}
Manual combo bonus${positive(r.manualComboBonus || 0)}
diff --git a/styles.css b/styles.css index ec641aa..0ea5e5c 100644 --- a/styles.css +++ b/styles.css @@ -37,7 +37,6 @@ h1, h2, p { margin: 0; } .event-brief.active { background: #fff0d1; box-shadow: inset 0 0 0 3px var(--danger), 4px 4px 0 rgba(16,32,21,.14); } .event-brief.next { background: var(--green-soft); box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(16,32,21,.14); } .event-brief.locked { background: #edf3ec; color: var(--muted); } -.target-brief { color: var(--green); } .speed-brief { color: var(--ink); } .build-panel { position: absolute; z-index: 6; top: 118px; right: 12px; bottom: 12px; width: clamp(278px, 23vw, 360px); min-height: 0; padding: 10px; border: 4px solid var(--line); background: var(--panel); box-shadow: var(--shadow); overflow: auto; } @@ -52,6 +51,7 @@ h1, h2, p { margin: 0; } .tool-button.small { min-height: 40px; padding: 6px; } .tool-button, .primary-button, .sort-button, .facility-action { border: 3px solid var(--line); background: var(--white); color: var(--ink); font-weight: 900; text-transform: uppercase; cursor: pointer; box-shadow: 4px 4px 0 rgba(16,32,21,.18); } .tool-button { min-height: 50px; text-align: left; padding: 8px; } +.tool-button .tool-icon { width: 24px; height: 24px; image-rendering: pixelated; float: left; margin: 0 8px 4px 0; object-fit: contain; } .tool-button strong { display: block; font-size: 12px; } .tool-button span { display: block; margin-top: 4px; font-size: 9px; color: var(--muted); } .tool-button.active { background: var(--green-soft); box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(16,32,21,.18); } @@ -104,6 +104,7 @@ h1, h2, p { margin: 0; } .debug-check, .debug-card, .debug-target, +.debug-event, .debug-readout { grid-column: 1 / -1; } @@ -600,7 +601,7 @@ body { font-size: 20px; } .equipment-menu-lines.compact, .formula-box.compact { font-size: 11px; } .hover-tooltip strong { font-size: 18px; } -/* Keep construction flavor text readable as a hover bubble, not button content. */ +/* Keep construction flavor text readable as a hover bubble. */ .large-tools .tool-button { min-height: 62px; position: relative; @@ -626,7 +627,7 @@ body { font-size: 20px; } background: rgba(255,255,255,.98); color: var(--ink); box-shadow: 5px 5px 0 rgba(16,32,21,.18); - font-size: 14px; + font-size: 13px; line-height: 1.35; pointer-events: none; overflow-wrap: anywhere; @@ -846,7 +847,6 @@ body { .event-brief.active { background: #38251a; box-shadow: inset 0 0 0 3px var(--orange), 4px 4px 0 rgba(0,0,0,.66); } .event-brief.next { background: #1c2c20; box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(0,0,0,.66); } .event-brief.locked { background: #181b20; color: var(--muted); } -.target-brief { color: var(--warn); } .speed-brief { color: var(--cyan); } .build-panel { top: 82px; @@ -1164,7 +1164,6 @@ body { .left-bottom-status .event-brief.next { background: #22301f; box-shadow: inset 0 0 0 3px var(--green), 4px 4px 0 rgba(0,0,0,.68); } .left-bottom-status .event-brief.locked { background: #1c2027; color: var(--muted); } .left-bottom-status .speed-brief { color: #d9e2e8; } -.left-bottom-status .target-brief { color: #ffcf68; } .left-bottom-status .combo-brief { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; } .left-bottom-status .combo-brief span { color: var(--muted); font-size: 10px; } .left-bottom-status .combo-brief strong { color: var(--green); font-size: 22px; line-height: 1; } @@ -1273,6 +1272,21 @@ body { .card-choice.ultra-rare .card-icon { opacity: .17; } .card-choice.dud .card-icon { opacity: .08; filter: grayscale(1); } +/* Construction tool asset icons. */ +.large-tools .tool-button .tool-icon { + width: 28px; + height: 28px; + image-rendering: pixelated; + object-fit: contain; + float: left; + margin: 0 8px 4px 0; + filter: drop-shadow(1px 1px 0 rgba(0,0,0,.55)); +} +.large-tools .tool-button strong, +.large-tools .tool-button .tool-price { + overflow: hidden; +} + @media (max-width: 1180px) { .hud-top-left { grid-template-columns: repeat(3, minmax(80px, 1fr)); } .left-bottom-status { width: 290px; left: 8px; bottom: 8px; } From 6097bac9d52b56dd3b1db4eff5ab961f404ae766 Mon Sep 17 00:00:00 2001 From: 33333-33333 Date: Fri, 12 Jun 2026 13:48:35 +0900 Subject: [PATCH 5/5] aa --- FUTURE_IDEAS.md | 12 ++ README.md | 26 ++- deploy/chick-sorter-v29.00.zip | Bin 0 -> 250390 bytes dist/game.js | 84 +++++---- index.html | 19 ++- package-lock.json | 4 +- package.json | 6 +- scripts/build.mjs | 15 ++ src/core/balance.js | 79 ++++++++- src/core/config.js | 6 +- src/core/entities.js | 15 +- src/core/state.js | 123 +++++++++++++- src/core/text.js | 11 +- src/game.js | 35 +++- src/render/draw.js | 133 ++++++++++++++- src/systems/buildSystem.js | 235 +++++++++++++++++++++++-- src/systems/chickSystem.js | 146 +++++++++++++++- src/systems/economy.js | 19 ++- src/systems/farmQuality.js | 42 +++++ src/systems/history.js | 14 ++ src/systems/imports.js | 149 ++++++++++++++++ src/systems/maintenance.js | 180 +++++++++++++++++++- src/systems/power.js | 302 +++++++++++++++++++++++++++++++++ src/systems/routing.js | 4 +- src/systems/selectionSystem.js | 88 +++++++++- src/systems/uiSystem.js | 16 ++ test_v29_00.mjs | 177 +++++++++++++++++++ 27 files changed, 1831 insertions(+), 109 deletions(-) create mode 100644 FUTURE_IDEAS.md create mode 100644 deploy/chick-sorter-v29.00.zip create mode 100644 scripts/build.mjs create mode 100644 src/systems/farmQuality.js create mode 100644 src/systems/imports.js create mode 100644 src/systems/power.js create mode 100644 test_v29_00.mjs diff --git a/FUTURE_IDEAS.md b/FUTURE_IDEAS.md new file mode 100644 index 0000000..c4df103 --- /dev/null +++ b/FUTURE_IDEAS.md @@ -0,0 +1,12 @@ +# Future Ideas + +These items are intentionally not implemented in v29.00. + +- Capacitor or battery storage for smoothing biomass and coal voltage pulses. +- Transformer or power-combiner station for a late-game managed bus where generators can be combined. +- Editable machine power priorities. +- Advanced power statistics such as average voltage, brownout count, utilization, and loss heat maps. +- Additional wire tiers beyond regular wire at 0.5V per tile and insulated wire at 0.15V per tile. +- Zunda balancing controls such as shorter duration, consumption cooldown, reduced zunda-only quality conversion, or farm appetite limits. +- Repair-access visualization for reachable cells and suggested footbridge locations. +- Power-aware card ideas after the base power economy is measured. diff --git a/README.md b/README.md index 19d991e..eed6ea5 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,24 @@ -# Chick Sorter +# Chick Sorter v29.00 + +## v29.00 systems + +Power is a simplified deterministic voltage network. Manual Scanners, Egg Farms, regular Conveyors, Boost Conveyors, Power Wires, Insulated Power Wires, Footbridges, the Starter Generator, Biomass Generators, and Coal Generators do not require electricity. Mixers need 10V and 4V Voltage Load, Shredders need 8V and 3V Voltage Load, Shipping Trucks need 6V and 2V Voltage Load, Auto Scanners need 8V and 2V Voltage Load, Sausage Machines need 12V and 5V Voltage Load, Maintenance Rooms need 6V and 1V Voltage Load, and Inbound Trucks need 5V and 1V Voltage Load. + +Regular Power Wire costs 10 yen per tile and loses 0.5V per traversed tile. Insulated Power Wire costs 22 yen per tile and loses 0.15V per traversed tile. Wire branches do not divide voltage, loops do not increase voltage, and separate generators are not summed. Each generator admits machine loads deterministically; its bus voltage is generator output minus admitted Voltage Load. + +Every new game includes a free 2x2 Starter Generator with 25V output and free initial regular wiring to the initial Mixer, Shredder, and Shipping Truck. The starter generator cannot be sold and has no build button. + +Biomass Generators are 3x3, cost 520 yen, and accept male chicks, female chicks, and poop. Each accepted fuel item adds +5V for 2 seconds. Coal Generators are 2x3, cost 680 yen, and accept coal only. Each coal adds +15V for 3 seconds. Fuel pulses in one generator stack additively and are cleared by day end. + +Inbound Trucks cost 350 yen and can import coal and zunda mochi. Coal costs 2 yen each, zunda mochi costs 4 yen each, and each truck can order up to 80 combined items per day. Imports are charged at day start, distributed over the 60-second day with deterministic jitter, retained while the output is blocked, and not refunded if undelivered by day end. + +Egg Farm production is capped by the theoretical capacity of one Boost Conveyor, derived from live conveyor speed divided by minimum item spacing. Production above the cap becomes quality overflow using `1 + 0.45 * overflowRatio^0.85`, clamped from 1.0x to 2.5x. Female shipments and sausage shipments use continuous quality multipliers; meat inherits chick quality and sausages use the arithmetic mean of two meat inputs. Mixer blocked-output fallback remains exactly +5 yen and ignores quality. + +Zunda mochi on a conveyor cell orthogonally adjacent to an Egg Farm is consumed by that farm. Each item adds 8 seconds of boost up to 30 seconds. While boosted, the farm production interval is multiplied by 0.55, with the existing 0.25 second safe minimum. + +Repair workers use four-directional grid pathing. They can walk on owned, unobstructed ground; they cannot walk through machines or uncovered conveyor cells, and power wires do not block them. Workers exit maintenance rooms from a reachable perimeter cell and repair from a reachable orthogonally adjacent work cell. + +Footbridges cost 90 yen and live on an overlay layer with wires. They cover 1x3 or 3x1 cells; press R while the Footbridge tool is active to rotate placement. They allow repair-worker pathing over conveyor cells without changing conveyor transport, direction editing, or branch behavior. Serve this folder with a static HTTP server and open `index.html`. @@ -11,9 +31,9 @@ The launch page uses: Run `npm install` once, then `npm run build` after editing JavaScript. -## Current gameplay specification (v28.21) +## Current gameplay specification (v29.00) -### Boost conveyor rendering hotfix (v28.21) +### Preserved boost conveyor rendering behavior - Fixed a runtime `ReferenceError` caused by an undeclared `boost` variable in the animated conveyor renderer. - Added a runtime smoke test for both normal and boost conveyor drawing. diff --git a/deploy/chick-sorter-v29.00.zip b/deploy/chick-sorter-v29.00.zip new file mode 100644 index 0000000000000000000000000000000000000000..93af06244997a62814214dc6a8a41efd0b67fd69 GIT binary patch literal 250390 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

Gsy-f1sb1fwFK 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 z za^5kW8tMvNw=NU=`ONCQs%3u4CANH&vVd-o6-g&g2hGIlb&iQ|e9d0Y)*)J3jSZ{! zS1?a1QTYYs;PN`$7-ulb@d^=%k!1LzwM}?0^lv?!+h!(P!zv)Ry1*Wj%v#K$0A3S7 z9nKKt23*701y(K8J7d&rT=nmCvN^Y~F(XUgQJMJM(-ZP_y0JC8sT(g?5lOki5IkEJ z;NsPK$cW2L&LaXSW*pfetfU>QTH^=wBF3EAVfQN+%VYN7vh%CMhZ2^+KCuKT8Z7zW zx52mt`6r$awLSu4PwE;=W^^)!&J52W?=6j@djiT?);pRw6{D#oY^A$vs>uu0c`iB9 zW8&#}%umcv5Hq|$g}oaTE}kcJhLnzoSm_@M0!l{RJI7h=i+S@XCSBye$k*YP-22%P z0}=4_b;6mMpF0DJG10d`t(7hl5t5$(7Y+*1>%-*O5&M+;375b6{w0oO)FIXXtzyBw zCSlJCU!W)D$Ck8W+!{xw1>4w#7~x}aSwnak+|hScBvJtgLV5vk7g2GIU6o*Ut z$Ae6Z0Jh6({FrNe!VH8+vdl3^e2T9UciN(m&_R=}=2dtV+r>`4>9a#$N(9wSOXfNg zJjuT36VqrLITbFnctb}Tdz)VolW|qLIl#G1wt0AKr5q6Im_iZIWH)>qNS{PTRdH*L zmXrZ>_(!!SIAK>-4KhwNdY5P7hno@KrsQ`0v%A-+=V7C4MBv!oDXdrhZ6ZRNyc*UE zA(YzF`ppSdxjoX3-JU@z942F9FIm);vJ{<}<$zQ;ZCXbKS74T4gUPG9$M!s{Pz*{n zY!YNjaweM(nWfzobdzN2xvl0BoHB-xmWde6R~tExcz6oHlvy&Zf2>S6(wpz#;$J4f ztZK^OzT4dC-g(0AoR5|A{(SVC)Q+^iz%E*{9yElgV+w0 z75giXSZLddbcQc3ceJo%En6zFt+DZn(#&JkYwi_%+&Wc9o5^}8a9jL&=TL1F204>eAr!aEU3))sKvNR|Sp;C6t#E!vYv7Gs!B9OxOAY2~Vi zW*?9_0gpMKul;T8FRC2zs=+L4qpLo~NrL>S17b~KTm3B?V zew6AfV$X54N3F08sqE`pjzksE$Ze?Dcd19;ZXnE|)wO|%T$^QkD%~;JwyHq2j=wQ46;**+ArWK)|>&=?DPa;zl zt%z-3sg?xfSv+fh0=1h>FU~x3%m879rnbIb|F|(QSf9j&9!$V}vmua(wf6S0hmR#z zW(VUz=RM4T!;E<*-;#Bak*eHET3U25WCm+Vj_AB%DBI7TMAq5Lz^SC0+a4gRSKDid zf#B|TY1(n<);B)y5Am)Vny7ZoYsV_=7;<+DX4>BP^YcD;ZoWjzCK+9daoIh*O5iVbx_M~^ju^Zwb@T)>%g=5s_5{p2TvaS`xuYaZ?_GhyylR*7(s%|9)?>Lu=HXQ5Q zoq%=(Opjpiw;tiO7#ng|G+&56h*ny-lX5lPzB4W`MpEbRXnEs0D*Vl+#!;;BGZbHBprbMk21g#d4pF;UamRTuTW4xTx(nzQ(se z#4Ubx-~^0vN}=2{sw_b4n!~eNq|60}nyM4hed8Rcep=yi#`N691SWbMR`V~G`Yjf7 z534=T{60cN6A8k?1zK8PK`cUjjOCMh`_KCU?!rUo2!V#S2?K-bI)jT=`Bl@JlX!+3 znw!}pEErAPH*_fLIN9!ODy0eUGXd+i-^|Ox21X7mx1yrY^iD`H(a1GD zF{s+t-BWDBNycjk-@8=>sl=B37qbq0qODYE6G zNdf>8Kl&}X7hFlos4q^v->OOp+c?i7H#QPmU{%Q#08Q>L@$IEEblRSq+rGzZTy07L zN98)a8*v?I<6)hBkq>vp-+~3L()rDA;#?*eWp7PI)ONd{XDX~YlrwdIwvSu}+(4VA zj#bYA-KkF2O`{zA3bFzo0y-BZoS<)!iV{IJ?^C@{qKuxAcrF*BbI8{-QgBFj9$JQ9;>rQ;nx^Ej|(JFongQwD)jz!q7jtok2K7; zFRlKBddsQwx69=-bbUS_sWAo>$Ca`kg^!#Gn340zPqldNRXv)AvO`k;W=JNT^A-zm z)60XR!V5^DNKPHi{{sJ)0Q`@1@lK^ou?8>zfC%*eLjanZnix6%N51%ox{ci?E5c8% z-T)w$AzLG5--^Qps!UcP=tix15a1Afb+q(mwuwYi`I_a$Z!eePQWnLS1^AT|_J#Xc z*D3B!!qFvtI7kPPTAiL=PxsH|VOd+Bucy~{mq_idc26H67h_x?3rEZKm@NXs+u_{% z;13sX5Bt96>%&MF8lLWrTyFvHvyN&Oj)EU*HC@IU{fQQ_$xp5!VLRIDk~zBP`7-NM zU^@5@)jzCDm7LdfPorKoWdU+ivc}_}3&=F715JM5Tf|CWb(&C1eT6X4CPZYbADWO+ z<$hyJuVrEzl7M}F#d4LNsdb20xAo>Fh34R%BP+gEWX1VY_FK;NIx1;9m*_sRR{cbT zn(%~f_)qjb3l$9&*}5i7Z%>(_MbLGsfc9DdC>7XW%OJ+cMw1xbQ0GHG>F)Ft04k30 z6Q_R^MmTeDyj;mjg~(tyI3n74u`Fd)tsVPgh^&9$4DOR;|AfMHA7N+@DT2<$Cv_#4 z`rI)gP~i5h%fy<%DGHLszAwppjKUKbtU@&girPX6Py8u@$dpl_J;Z2-e_okC*iWvE zM4JyecC)85I#MHv*)r_DG+EL{f8nvgvXPDoYbXCDCCqOQ-5klJF}3EYy`|dkHjtJg9WCdJ!%pSU;Zt=+D?6G(zZI2X3nORF4fKvtB--sK7cBuhV}gg z_RQ6xoslA6kG7+WbDUiV${9DhdrB7V6_>|2+7_YB*mC1YA#{U?h&(b%k?h1*r%b5~ zRTWkPjga$Df_vSrdz;p{1^N>=mKy1x3HE(jn5yi#pH?sSh#an?uMMZs-|-^jk}=Ak z7nbY`*dxIbzH9%yN~a_U<^hfo`wTdtLn*rEKxMyRtRS3q#}IBfToWF8UcUZ_r+A+~ zV8E?YB+h)ewDOg>DLu!P3Y@_yG09$3B-FoFjmg`g;D;uLX7ESCy*)JYJ2Yxaf66cf zHZSRe3*19ATQZ8iFBV|pasjTI{2vSc=^Pn4L&q9RIi&HbcpQq|@8(buzP$_~9{e%WH*LenaPuw~nj&(Z#9V1Q7p z8NUM3=AKFcJuB{ZM&7{OMFis+{G>%wej(I>dgFnQQ%+5TMqUG%_fhn~2$hkSULz%( zMIB&{>!m|o41!^j9zn68x}uw(N|C1QXv?v=R?l&u>?=pLyV!`A|Bmby6qMipw4e`N zt)$$-<_(q%(Es4kVLtI@NReD!V-cSqHgBf3d5d3T{mbzR^2GGlv-Dpx8=A^VM7Bo? zn#?!^qRGtw`H0_V5HQ;nm~~@$T|&LbbP+&`LoUzVuzt81lA> z<-iVz7L41RBGoQ%WQqQW?m|20qYW=GLAek!WEZ*2Aj~01hm!ppHCFD#Zp=rvX_F$4 zcPi|1waIp?X7;S9r^BXCAl#05B z?QO4m3RL!b`R-{mVwG#xIhSU^&NEbu!4TBQ;VXiihrQwQ*s>qs|3Boiyk5|BVE_P< zX#fCF{^u*FtBLJ@&bVt#D?6gL`z}9FVB&kqvdyHN@}9MOj99#hmV4mT#6o%)yqc2Y zm{)@Mu2vMW-ySCKtHdttiB;6IG_Y{F1DMkh4~KGgouh7iI^(a)=aKERr?-a#<0Ue+ zv@|uhRk1^*%fs#a`R9r4xHPmrpuvgxF})uTw~x*9k+++-)1s(DCAaIV!)J5vFyV`fVzNqW(nzj182E*ojxpkHq)9Mxx{CRY z#DD!U;((tKhQg$e?hp9l2~{!#9A?${BiV>Gt$#A5on*;7=9(0PGaY?@xw4S&i4xnA z*TD8Fcj=+g>+&tK=d01@ofGPnBzi2;MRMu7O&b6=$j4YD3eEq7l`~ACSd+vt2O#AeVq}bBL^bOc6!NR5 zrZsg4rt-!IK*HSG`tg4;lo{Hd`+*&?Rl>(U{L9<^#gh3I@IW{i0Gu#lAd_QI|A8O1dB_4Hnv#R9 z4P6PQ8b_C=Iq~>&ognb$yY`P>;Z*nYxNX`Y^fUAp#smCJTrJZ(Mg&0uC1VY2*dm|E z8&8&v%%+PVzZJoz>4G(%m5gue3aW!}2W5v5ol<~&H)bx-7zKC(3rNBSnak@>7Yn5a zn-3JM4;TTZ;un^-I_}R@CPS5fA{P>2El(KD-XrJ)OeCpgTy; z`D-%dn1(568Q-w}2`CQ#N8so$%jjV8NAe^1u;2_5w=V9V^MA2B!A)e7L_jyq`WPVZ z3%9Zv6ma}z#P5+j559X!;MpN)^3vXIMgYe7@Ek=9aT(E- zUidNM@v@VU?&IHyS1`RFFxS0U8BP(cQYG^9=l(#Yu?{nm^Mj%UmeaiC}LlW_a|?;zS)f@+Q90ls3T z<;i+?*wP^dx9l_?VF7&AOcyM79FfMn=rBHDdmak)S1^Ue1_4%(_^87a_=Uk6Ed|c) zk~eT0nvy~3f=kqS74y;@!t7hdNNT$}*GPg%zvPfz3^yzilK1`vR_XOcjFDLd4!S`R zuxuwB6dXNqN$u)_m%}SA8Wf5$Lqx5ee9m(y zu(BCuG8>s_=1CI`syY-18pq=ZG46#@@LiKKB39DWlnu_5*~mMfm|8dm(8Y_0WX%gd z9y^0!{T% zz3m}x956l@@d+@Tf1J`9Iqyib_ z|1#kNuRxxD-wUr_R}h^f+-Ms?H9DqGfTPx{84$4CCQ0tyR(BGcqw|P4A)H|tx>tdG zJL0Ufx6EdLd?DoM)eBlV8^aa<_K8aClf4ee10hfe@DkK|*8~1+t#)W-;7`*ZC`xQj zgMdfQSpa0vwP*l*?)TaFui2xO8tU9)dhY@PuZ08pdwEuh#pAE&v0M=9hx%*I74g5- z9P1jE%dRn{+m^%=s+@egHx1=d`QtbO4CqsO%ypET&iQj^C_n-@q4gDh#KE8ZGVC@| zGs^qZ1m>>%%R$o$5tobRhfr#5^S~VYJDWb$!3`%l&@R=J3R3AkzFrF?_81~JtsKdJ zAt!AgzH4sC(3HA%nzZt6q-PdqdAKmEJP2b7?Pg`~X&23(E$&oyw(0g@{285e154fe zqiJ8a))t?Qfc~u`jsp)BQIc?QaC-*;I$T?oCdRm(M0NIbC2 zUL3NUF`cI?hztddhf(>Hbj&qx9D^n~hw3CgwJit}VH6Tor+F23 zIs3RtX3*|a7J{XxZ-w6Bo_ZvD4$~x6PDOXQevn(V_}vO~&-Qm1OYU+)Tb!zKw_{!Z}$<6b^lORMZ2y zI7UfEEpkM1%_r!!%%Gn{p`-ZgslhoR-kdb)x2m0npG4JWm&kYZ;@3yubH8P}HB#Lr z^Q=*Eg#Ds>?r+QS`TIHH@=Y95Sh@O&9h^m?<@OmfLl$4hCC&G()|{EE)CMKLS+^05 z`8*jUKQLWXnpY#7bZaw~ehKVd77{OiDG9NTOzzl;2w9}! z2rVVx%cA%jp~H5AsBZPryG8&SXZBXtRNhM@%|pW*?A11+t0>=!a*IayGvI-bF-od3 z>$-ESzXd3r3WzkCrLnq*u4IE)_3`??k4iboQ*Ya<^CaZwG><8_tTI!IHY-lL5GPdU z>0+_*3NYh5?W-d9C-3sS*95*hLgwnSR0lp#k$&9rd8>~_JqnYJpTw$1AWFrK9IHjq zM&26?3?)gwUTB9CTq)6wIIwFQUjN2G4*L6qzom-mE2wTGz%Z#XFwt95vuRd{=ZYH! zSi{H8)~npwA4`xV^vnEw3qJ;UD6%<2V51m;pt;s3EYsGjCo3WsOwD`RdF@UB`n=_i zV3tsY`VP=T3(~+Jm!mtM<)aY6s%(~gX{vJ7iCaiQq%@4+1rU!&IFQak8P9>n9ZI*q z4Y5R*>S$zF2dNp^8LZ_P@NY{?PpNLz)?_DcKHB@Otn`sY*Wn70thNiLUkYiZMgrW$ zC{G!Rbvyp#L@?wP!9A^+>akTu3~GSdC}g#@9Tsik#79Cr2jWQ6ax3|+Voy|IDHpnn zc#C=DU>GpC)V32!Wx}d8$5OiIN<$g4#&Qv9-Q7#}1WHdTb9H>>%c&oJ1y777QPp!+ zmaRd;-kwu1(Leq1@gVX?W0~(3Quub!O1b{uMhNUcG}X$Vb;s_|PP3b1O$#ND4Rfjt zV3hV%iqci(j})$cpOcIYR*f_kd>QiA$W8D^Fq!OK;|o#E19KYdxbhPpb^ULEXVy>A zgnDvh4*?`_q>Ek7;sn(K%B1bEm*>^uj(^25Pthu7t0iJ>m^gts0}1sI$CW%j05?5{ z92+y5HYyPqjjYYW_z8(>zx;w_KwpKT<_~HpmMFZPM)F*C?0iLkYeV!j`3%j|Yk6R| z9*>AD@_liTeKxN@T%Ohs2YA>BmXN<5RYI4)5Eid){OOROpi+d{mTO8H^1OR{l@xSAqObr}u6kH6fEu8-Yy+~2kk=x`) z@Sdw%W82iHb)ZtNKva$g5+qD!}YZA{j8SMyHG!;*fL4B>YU_I1DJCFObBuFL|;KK+mD_86aUT z8H&For;-9|r?xcA3KcC!K9MvziDH4aBJ~~+GEikJHxo}z@Dk(3<%R`d#;jVDEr4nP zw>8Ne5l(_2qBjElF0M4x&}D6jK#UU34?Q(=KOI0Q-P&TBNVDBr&1uq%lt_TGI4%+3 zn1U^JW1A{`_=^RIyzMY`Q?+sD2l8#B}Bh6XIHO6vShPstuc4Lw1)xiIx!3}-Wz}fd77z>epg@XK${?5$`-EF1 z$bLv!!IJtD}}P=VSMmzt}^^CZSA|88488)iv; zBN|q7J(Dy&v#gc>?6m!c5Dv%oxybzM%(cb#!^@vphElNr)Y99=V@Dk`F`2@iSNqAd ztSlwS>(|{4s0~d^OMs#rlbZ)e`3AHSk34FoEn|{s+>PnUz_Du{s=So%hlDi|6v31( z+SHoI%!<2S1E$Hl;yL-#eJL>;^|BIO{Pw7Ib5Yf6i03Kk+P{$el!}oG04m+m z3-g|M4xAZqK*+!_xsc-Pfz*p^mX z%}S(+khw|yNqnPfX&O}QHDt}&B#A-tv76@*64s=AuP6;D>dibVK30wTKx(12XqgI0 zC2!hKFg<^xA%)KR;~Amju!|ysIeam*Y`R@ zgx)vqy(6^_rfe9O3wX(VIyuX-%Z+?h6T*@>W!$mX*!}Bj6@H(d2UR@D7_KkYQSdFk zxA_p`ur)3kY{N)wc_7ykkj;t{Pkq4e%YjIolp%Y%5 z&{XVIheP5uElqos(qNSj>#OTr78~& zi>>CBi=@V1ePXrk~qcG$=0WRc%ljO!gBBB=3`dXee?bz0tzx3qs)?d&jJ*Tb) z?b7w~CNw$uDUzRrw0MR>pryGt3BF?spoU7`6&%MxL+mdVpAx@4m_}bi93PK=nYiqA z^#YT=s#&6fM-Q$U+xD3n`Vm(ni&=%o=Pe3~0!J7QQdDT$KZ$$Wqq;1}d2xHq6Jmd=wd(G|m7WF!> zF7fdsR-7_h+#ADhB|Ny0 z!B~AV?_a?{H@AB*>8lag`0Wj+lUHTPOA=^)?$;U<@`KiZMl!r6%xXfo!MtSI6=7iM z+x_NCx=9?R&#F-=JJiCW5`8$W1FNY8Naf^3>{{vW+f6dRx?q2EK|inYtP&TRfkon zyZX0K)HTYKsJsQvm#~D~2Rj0S>fFV;dw{T@hwd(u#b#MtMb2>Sxbl&~@)BTwSv|Hu~%HiF#GSUzdE_QM-=S(ypoRd8e}IaLEkfnJnNdV>c5%3ro*? zJ$(vbR#}uaBS%R2$a=!9(Q!?jSn*HxPP%*4cLkNAw>jU~-1IDW+>!jrgGi#QBYGW5 z?w;6xozCL1FXg!$m|A7p3pjmYh5z|)E~D|k`;J{)Vj=)I007*B=6zM2;DdW5CX$s$6*zbwyWWaRuTksmugnbs#Tfn4|N` zp>ARVsdRN6<-+n|>}k-PrdZK8vAXC1sobz;YMP8>dI(-Cr;euTM)`VfAqI-W?*=tR%y;viAbCO1$axr?Xn6Rs zK5Sg<*fRT0kTxC(L;j7t!8)`vP5V2YsDohBHp0~4Z468+6$s>Sj?EKjqrp=TVY%S3 zuL^_A0yg2{^b(bW5kO2lUca9&`>(3P)w`jJa`#YfI#Dq(G4ow9zJmMSuhSx)N9OGc zH`lYC$#K$7dIAfFRGJ6MC|Y;njfMunK4YSq}L)<#`(V}%E z--!=cx*={#NhS1T5{I6WH$C6{d~`|Nr#l`gw3uG%je&1cjSusybqM~uCY|=BoE0#U82VcaFrFou}v@%f&-bcZgnl3aPc%YltyCZ-wI@WRy?5-C;=db27(e`Wxz7|UyQsIs#TH*hHWTNv-*|w z6N#v2ojlYlj-8*$N`z+_i5+l8m@1IVx?tk7u)++Cm}0*y!ZQ;fGE#fqWtO1~y!+YJ z^}-N#F;7pjA0FkvNAKpY!Tu7}P@Dop5;z4LuR(V5%Tw_}22({#fh(^yyM$<)N?d-_1%KtYWS#gp{IO1SCC&6gg<~;VpaP^4?*K;7eLj z)&lV|5GrwafNSw^>r4^@ETPkMg&xviH zz{o52dcesj{*lo8`7w5@?l35zE%L32qDbm`5)#J%gLfb8AYt5b{>hRQ1Nxv_y5+n6 zg2EVM60`vZxn-dHOIqbZ5puDqbfEi#w(ARBBoxcrGpxQ$0AMh^J1%2W-8WlbFiC zRjdHO5T^$}YRhRQrffxyv1Q51ZdV?}M5xw-Zg^R zK!F@B`!0s_Yqa7g4fB(+FqFv2Nt~-*P8$#E52QF(Y2D%feVJq*Sr?m@#ySC)bsn^XMhJ=)cY2n7Oy4s)oQe-_!Hs16%)xYAm`8cWsoqtVR!SYf!+s^i(j=e6)w8zf~_!h%i4SnmjO94pKOj)GVlBVmZ z`Sc*yxJs^K%Of#+l@5T6w-k#xO%lphpV-+1QV-ODN&@sq%E|(#L@^arg4E^;jMRm4>B{tShlgPcFhWrThjG}mBjAOGsY1IL-Y|dm{oh}H_ z8N%`Eq*00CO2yAu(?*z&9cP$4DhO?QUh0Ptkn77+xj*MIQF3D|>nX9dD!P%~y0Bwx0*A7;2oSE_Suy$s7XX;p>De-fS9282x-b23SP z8eHo$r+!|WB03dL;OlN`N-j9&u!^ICdz`TLfEcj;#%c+3jkayZm-gc9> z5v|u6;pAp7pA?doY2u7Wtwm)pC93+qdG7PJePJPwil~f2$$q6eZH{65>6UN_`e;ev zI$03$;We@mpP7pXuOs9ssofl# zy0KsR%y8zcJ`c{lQ_6GJs1=iR=DhKa#^%=bqQ7EQht(5DNGUA1Yno;IH>H&?#uvN# z8_z**v1&T^PfSo&QUz=Rs@ba5OvAgbE1bBU@Q$swTq6Qvi2m{IFHSpf7+Bako7fuI z8kzi)Ps`k!j+^X_w?9zDtSza3G7_4YTu#Oh%m17iPoGbBoEOph8O_hhAz ze81wHJ@6(h+N~T)3R>dt^Zh+H#NYAp{Po1={r#Q^duf+QAUm&SuqJG}l0Ipn1~)`Z zOZk$h1wTOjm3nkD;j}5xSg}xLsVCMzT(#hJ>Yw`;3M#P;B3;GSN4GeFZOToj+L#RU z+XUKL4hYU~tr8{I_jNcE!p>41e&PUCeA4diFOm9QEE}a=-Z2|#qWfxkuMKp)*xSyB zP?-GOI6V^9-uut+@7d@7>dw}iO57WrC#Eg4LoPWyW6aTg9^w0?2>nh9ni&Y_CaSz< zR^p&Kw1}STQ+^m?tXdRFwbZuc6?rM9R#j5psK{lX@fw?V19qU!jWl5XlI1qQ;aAN1 z5sEpm(FXc^Rlf_K2=gIA(FX*)Shp|@kbMbT^!v>lJ{jO=f5oK?!QuxqAcuZK51ne_ zonvaz14oKH&0s|a%i+bRqOYu z?i=s2MbOXQhH3!KX=>$#;xvCnRrzJHPVu3P?Bw$0MZ$ehkT=Ptzb-G6M_Tv_;q?)k z=;gph$bz&Tz`O{2fuPRz_l1X<0!EJiZ{Ke(AA%KZ59?oiOBCm>1i2CT-G~?@yX+lV zeeh<6+VH(Gjdf|He52_u+EcFp7JLyYTmdVEAo@_mRc8eMQ71P<3BwvB z;GGRtNd{`L$A~D&%w51ICSc*&%gQL~QCK{uct(&Wf z|2jxk-9WDpi(k`=i+-E^m5mXo(XB`Dd=UyeLmb!%1UNT%Ye#9-6z4d;AY6h%M`y*q zy6YsTlt06)K#w{#B#zA*uanAuJrQC^!K}05FWfWHoMw@T98=OL;O4gr+i|0UG}r%| z%O3OZ57YvewoiGZ+H@(#DcDfPKUS*(Ov(begFu=e> zP!%w1Bd}a1o^{&m5~$k!w`_2Z+sbm^NDC*#Wc4=ys6*Z^+y7+H{v&R+FW@}3cXVA* z^4VJun#5WRyX5f+4g!MFLf;d^V`kq4LyawGNaZ$l zU!}YH0OM?7lSbH`pT;;X48@#9e(RRFp0QSf625NH5LYc_m6hUP+DiP<%08?#Z|eBy z<&IMFQKA(DgXrS}XGuS=O=nBDMav0JX|!pF6|8tjq$;R1ofmpiNQ_xcvKVEs$4NuB|8(1G=MRfXof~!R28dBN z=;k8BwqUCM-;?q5w!P!P(Y;3snjrE31Da{m)$(64Bq7p#;8~m%J$%JkUr-3W9h4Ky zAs|fOW~V16fy+%m)I>KHkQdS%x>IXpQ>;Mtm+`AlW-qWQ*#k3Ous~{S%GAO znqrL{< z;!|NG*GJ%5nYhe5guX}A;HijyplAl9F=jI_5hLzh;&b{BmK%BBo*c_2^24EX0q_UT=- z{~E#j>vD`rhhpI2s_(L|#HJ@s%zX92vZN%PQbHr`ulTZbs1Hd+nMrVI(Ips3Lr`1l`vp-2o06wsitoi}2OvGr;~JcVQ8Xl=%g zgYfu#4Gcsh1;Ad(g8q$^_m$|Zlhm)Lfk|vHPXwE|MlR?)AH0JuXh`!i&hy#CWSckx z#bl)_1cLex)|el9BNHc#tu(7o>pgUyVLP0=BZT+WgY(z}AcZ1F!1~I`Lcvf3f}R^$ zCL#4jO0XhN0E|4^3WcUMi&UNNZMjE%t+pm8X=_0C6TrE_pAUmu%A$r_Ru7sH#*pTqGs}l_c<3+=iK52i7ZLQDx8YQg*ESe-zps2z6U>TRfj$`Tsf~3tBeZEGK z&8}2nl%o+x!0Dt@8tG7IrI`RbiPk@SxP}i%C#58a66n%8W$%iO-9BBscJF9`a-#&H zJ^TzCBbNFW2uBd>MvqxEWNY$cvO#|`E&vh#z~5+RoDH<##^7sGS7qs%5mza|3Zv>x zSrhki_wK65aCnE%9HdNN2tg#kof{D0?(W+5`kxAo3?g=Q&NH#GdA9jbr*>9hugRlU z^{z2n!DwBg?x%DViclma$dm3=U(9s59ni(yPKcK+!f{rlK@^wKn^b?yL#OZ+63-xD zTx~%sv`FIVEPblLYX-37m?F~oy?-I98CdI{3c>)?jC4EGf6P@BeR)wQ)ylnP;*Z;@ z)W`=8n(#$bVzDpq8A;|TE7a!M_lF9X54d(Z#LJU#MyMh@^Ob3VLZaj*oq=f$i!$XN zV=-&^epO&HWUUC%SQ`-K#2b3>OE1>1LaZ$CA!d=%ra-{$GiE3X8|QY_cel23L{G^z z5{mYf#GpC9E|80f9P$r4O?Tq^W(}|+>C=YR!vMJeHjNSm5j2A+v+-V6k~>dA|D|6< zdt~(V))UJoV$%bO2*s=~FvTA(MO=a=C{hdj2t)??lC0kAn`X2cZT{9Q4`w>)FWi3& zOOF^S#`w6n{AUOBFqA6VoX85{Z>koNu2~Ftv)I!B0;;UMiIzK|ZS2Q0^9-=8F=Td^ z{bW9Ii~Vq?r^6X>tG<@5IWVOURj_p%0Zo4!-{f`EOs;Nlc#WGTe;AIXZnCm29JXuBcf&!i|N3{9k|d|PF2kFI72?;?}U9|)@zzRiSW1xi+<4y0>A zFIG;6_z-z9T=ZHRw@Gg+amuHeE>K{jX8)eu^XNDc+Ej2g?DGJe!7WFd1B>`9lafHs(vHcy@y_pak4;FiKU5^)dteg%iZaKsT_4uXuleYvmmIh9gRNpC-|GxR!lfQ^zJTQ~_@Bx_JouXik_6dg$o9R1>2=&|W zIW^f(&QwY}K!!cUykj!C)ya5_M5i=4(7h(;f4e2cmkp&NK=v_Gp2 zrDE0JVZGmt?wyDzmdTrZpYO#SKW0cW0*Kl_Lf_gnp&vdaI30o0vNknfZ#8E|>(%^1 z;;)BfU31lHyQu*_w2zb{Nh^-A5B`4haw083i1?X$R0+XwFQr^Hg1#VSz$tOZ+HHj_ zhG)UM>%z4>&b>2du#y&`%LyHF`%kHK7pV#J%0LMVu1a+9APw3(3w3mTsOQKp5^|>! z? zQ{5nJdtf;ty?3S#rAW~zSkxz-H0bLy_sdQcpIRRT$$Z9fe%+AquC4oC& z!-sj~uwb8t?PXv3pQR6^WGmI=8*>EzX3aX|PHv4kAizp&KZO#_?Rnx)+=q;;5^0{fpHz66n`J?l}%bQn=NVvKJ!0WKV9@o%I2w?s8x{=-5 z?AP9us=Hq039j{aK+PAt1Ip?>M~>9(r0*Uu8+($-`-yD=iiONE&Rs?5{BL^K=a$8% zicVD4iaSe9hgJ&ZPTtgm5$&@IFFqrGXlKr8ybe5}3D zCM2ROUs8Qbwh{-A-Lacz^kfl0%6@fttB&o6$yCEROIEb5X|wwG=(ra_X!+ifjrfOU zAvmj!S>tqD+6q%U76i%M{{xdiY`@Qc7>L79Z_Z!7|8%H73XNu^1V_|Nvc**}V*M~% zvDp!3b+`e{=kEVGL6}_zgaSPtFox@3|LGwc4(bYG8=)@HU%jXUf7f`m8mFg|7NNR`IxExZc@|Ghm|{O9#?7-S9DM}vXiQ7WYT@4> zv6g>xMv&?r6}CR5FJT@0M8i)M{K|))Xn2~>)NyEGiC)-rqF1K&=_$^!@e`CZxFM^s zHaMW=8iV&lJ*ueP7gBqakt~ojUd+{b@T{2J`ii1iXWLfL)WazXKuuQ*PGFH0&U~fGt$za(G^)n4U*Ml)Wai~~_xA`$W^A=F6%x${ZTp&Lc9;8uf9VeR1?`;5GYKr~dMf9wi1c zQ^&27vl_YM+;yjI-XW zhC8uflprEOo|w#%9&hK=yj7RO{qY+w9iouokEg(FhGiRPZgf%sZ5jSjPjl%yC8bXZ z<0+ns$ev%uU)516b;A%DjZ8Tw+7x-%ZpXo!0b-2suUvb1eb$6?12`{=2r zUS;CAkMP*xOoH?@4e`-awq%Dw)dryksixMxc93k|8=I?DounF|=emdVI~CK63gw!~ z`WbEZIX#23bovB>h)_P6AGeqa*rp#6zpk19`ymzgUA;39mCajilV4j`PzJ>4KAjP~>b0gNMMI*d;>+V?t*X9%`fY9>Ic3~<4!yoeyMcM0N&RG2h4krBUuiALGkyec{Ycpou9;4}P z`RikKXz9)W%C-G#L_0an7G#aNTQsZgvayj%YMVg;#nol!t+?t&w$!~g-OB^)uK(~) zw^eOPtA-tQ0ar6}wW9w6V~x||0ilzi)=UXq(?`Ij5Nc;UJ+-s%syzLPHRg_^*%A_V zz%&aw4%ek&oBAEROYUZd#7XCxo5WNfbF=5?YBnZUid=Z$UXHr8qa9%0Nk`0f;@bm6 z(=GVD{^_nDd3Fbl{&)d_)ENGa)SZKduyl%wx}yN{%) zLc?KRm2NBq|s6gpK4(UoES z3v11LM(hM!Ea&sMT(@$6mbM@>o$SS5XZWQA`)VEr?fRttgfC35sEvqe%Te>HjW#qE zL^eRo9X@pmtI@W6n_|-c15ir?1QY-O00;nGWXxQv^y!L}3;+OqF8}}(0001Ua${U` zd2@7SZF5|3Z+B&KE^2eN8rg2!Nb=oZ(FO)1aw9YL4hC4rQH)&P4JL7nXxH;#7zjnS z?2ai?!^6io{P(TuyPK`U7|eqWvAepey6!5HEmu|Dk|*-^&8IhK?>>;8Eb3}WMoIEA zt7`gko)&4D(d2tGI^JUn`u)eRvjJ#Ul?!(5LEh5GFgCkwbipD!}U92fAFf2`jUr%V`rK(s;m`d~}a4)9i+ow7JAHS4c~M2SjmAfycD1 z0^$gw*6_{c@K&2iWnEo^ivO)JeCgU%*Iq;#r64P0-2giv>j8TPSV?UkLA6{Cjk?ez z00nL*m7sWYN*$T&x4|NuM(Bwa2zEwQHR>Wp$X@} z&1kMgad~A?S?{2ZNNwsMk2cK&&^AXAv~YcmcZh?UolE{eAaZ0?F%hl+zs97l?&Tx= zA_wG%^y4rr$n5Aj@ILHw@b(;(-?0zh(+hGVEtz%EPl(fznyo`2Ehp{_{q5KSTC)5r za5^N0XYyvxXRM50b~7~-g3Qd))6m09gXgSi(SRFamj#93O2Ou)F`tc>v4+*ls&Ek|oWG6OO;%ZAt3@-KdD3sr=Pl}e?q&bs9s@-Aym zQP7k_#!zc;3=@-WO>t9KtMoc;=_wRfI@wBv26L^x3UE}?d*Esn#U>;E(a{cXEMmOM zlFbd~$lEa~z+iatd(wBsCGv_KqOJ1Zuctd?e`U2sW=6(0DHK34`T1vG?lE~al`Pn& z4OD|rl1s72?~~vSA}Dpm7U_lD*Vu755&yl0jRHWWiNXtAvpL~%0F#cn0^rx!E6?r` z?9w}?9D&!RS0@QxSd=}MdE?*x4J#;#gn$ZKUbi>u9%8M5f-Z{EF`09XryLbTym?~D zSBg&P8*VL+-mpa*#UbS)dlEbWh3-$awFtDl5@BUW9sH=8sqRuN1jm1Sv_UCjaq4R) z5ODSp*1v%cB`sY6o{$RhzpJm46LOgRst{=X+mZrq5v8Y98A!Cey>NjnzhMYT68jTByyXHg88WjgGFIDeV0Okdq_rjq+az1$~qG1 zaSHNT734$o62Qf-7Cq!O6lNN;SFo+8fTvvae8tMMe9INLjvl_i<&j;4nJie*QmYq| z9C`ISsC!;OQ#@?xW-U~p*P>v6M)|~au2|6a6ZrrR(U0YC@P+=HM_}HuBL7n7G|)Bj zLkQ5$Xwx9{ROCKLT?a>GG6V?rj5W>DBI^oBXXhyUGuqx)^{pj0(FpNJN%{#)y>1_| z?S_^LtEsM~&BUa(F-d{qb-4t;ao0thch|ZSE_fjtII%GUH;+ZGQ1*iq-agLw@o*NE zsO_HCG6Arikro#liV|tf0w8I$Bg{G@zxn0>gMfa1zG$yilp6rmqL9+RhwJpsj z;4_dWx<*TGhxVU~w6}x??wYe4E*lI&XhP_=!w}~7PjZ$poch@LM2PBCXhlUOFY6iEkzc~X;u}q0!oz+3Ws)}MA#DV9@#~dA zE>~Vmu}v2K>9HjC$ zMDlId41@^guDJ1!D4xDjtlrK=J_xW(?`ZuPao&(sMd?7Yt9n(7d1%h1Qe&T}zKfw} z5DJ;<=GVQpL27XFIwpJ%u>O6Y*f8b~Y}5{T6N?2C04E+}A~#HI=KFYn-?4LfV*}(F zHm^B!uyL7y)Mso`q5qicbmWvO1Hdy#sR7Uu=PVfi{Eg-YBKX<5-4F%1*TqEL(B9_q z!OVVP%gTYE8D)1gH|HIjutAM6`0B9i#6G~CW&q1qHI%Kkc}>$>_1F*RSymLkOp?S` zAUXr|9#MS7i`3{6>qe6yuDH`<|Bz$jU^Wt^Pj6X^CTXiv_CWLKml#@$fM`h69Cgoukd!3reY~LeklcHiB4(Yf7nww z6O@z0?z8xNMAd1T;||Ewh1jt#5MkCbZ=9&Poiae#gg{ie4>7!vo6GHc*@i5y)^N6wMQN8`fS5pm6R%qEk)Z^8}45Us&BNfB6c}h6z z@#e|Q?rgxFZu$B5h;}^_u_su5Q=co?Xlty90))DiuAXL(4S2Ea$@A8{)Z*{pg+9d# zS9tV1(adOYUKp6<*uFS)2gf0xW$~sVDs-&f=l0_cky&ofl;npm&bwlNDzt?O2sT%C zhqfIUonpMp8y>q4a=&1(zOgvbuO8eI*U|!4l%oObd@Mh@XxWl}qKlRsOhL=`tY=OE z7j?vDj!WtSKKKpDnsah0D|myN$m8O*e%-=NV?AXaoCS-qZ<4~iO)$2%az(mouu?cAzLUu<9WLEf6&i)CrE!)ZlDib&)EtqQ8@hfGPX6;Jf4zOExgL19 z8;cZaXt5L}C-L}fAF3(mme^$q!Ikdq!U6MmOICCzky+L8S7H*YQ}aM}W`9!sHIhKf z4+MjUeRM_veeS2x5QNf^VB{a#FSen6`}kRWQ|3mfjgU^PvdgpFD$X1f_KadjDl%AY zxwi}M8mfs%#3>gx33vm@Ith!nap6}Sq8}1?PW3RK{?V}&76ZF zf%;F=l4cfQhczG62{~#Av%_PGGg7xGDP~o;+MRc&9Jes8|BmxLZBr)Z=|M)QxTXtzIcc(A~`N^7J*etN zDyN$~Kjv-ee;-$lSVN!ox#gN;zH7h5R=NFLC((Xo%z)HJ5ldzwVG4fZjO{!b>LIKdJJ} z-c+Hyw~a_O7XJrOO9KQH0000809v}sT)jc-@Z=r<049I{02TlM0CRF%$w@XoDvHXMWv?!4$7lJnwWU(UAOVU9 zL4XT@ws;Ev`}Jeq7?6}5XYa$gDiJx4o}QkbeofCXTP(|}5qIL*#hc5ac=6`q*-*TE za`v~2SLeSxe{y#5_lvjx{N>^q)V(?Xum8SybN=j?H|J;P7eAlBaq7iJOsjGsdQtS% zq^wf-Uop*YqF?LY@fVpIr7BlV`uBL8=B@TkdfRxd=jnPVmT^_5KjNpXcu{4^P)yQ1 zKTC@yt%f4W>LxBG=}^@1B0Yne7T{Hr6;gzJr!E!oZ@{owyx|NpuUi;P!~HyZA~x8j3ZRuVJ=Mx!8m-o5t1RNz=apE*%O* zg#m5}9tA6+^ycO{w5y|ORwVtYIQc*6u<%k@Y`>qSmpV#=p@F@ zQDr+hYK^0IFxeog%SGB>Vw0th*wR64AIzSvFA|Acmh6L7lqEC(w%!N)WnQYu*YI(# zA?EOz2I(#0Vio5-oLe1Xe=24`*67v}PqI8~)<4qXS%Xbaqj6lP7YTNQFByI4^@6?6 zi>Aub`gvIq9L64zVm6i_S?EM5H>OsRgaF?W{M}{%^U9IS`&UCTy&e!dc{t*X2srYr zL1tCQ<2?Q8Ly;!9^b(7ugTlc9Fapqq#d3ein~1nzfaU!I>~$KI3QBz%)!F}~h#cW- zDxz6j_d(jbK;R!?kVJ*HN&1eyPb6S+-c*7)ap`SpS5PoobsLmcaCA`5O3>VO~Q_wVIb>M*l9;7}XG zZ6Ru?6}>2ytHxR^Rc=c^n51ad%e0*8YG(Bs*r>SaiBsVd=`^}hO|QjBcRN;UW~yn! z7;j6cnmvJ+Trl56!zg?oC5FVfu zww9@rp-*9~k;Z-V#f~0R+Hz~`cPFAKlHbAT80}u7pH|Huy+#a^WtzYF%^D)z4z7BO z>=ssL=&cld&x&!mDw4O=YBKL#M_Dn+R|)JWk{m$>FjDkWR=u@>{wN+`d@|fp7TsD~ z%#e_pwkW}1%IUOD8&EIe3XFz_@ZZ<)2mS+=et1M?*|e-g-);?mRKGTjV6JtRq)gvD zoi;sEELLHa-OQTafcgpIRiY|kY1v@>ooOk@-N-(pRv+D_)mf4m3DHGkO`4^*&Gy_h ze~at0vUs1aVX3?K&eB?}?#*`G)?vJ(CUS(gS&o|ul+tMwQcHyI=Wr!nBL$Ka6jFvX zs3R(=#j;ALX(gIjD$?5+oDIOV0L=zmgI4EIjDb%-UiK5TU-}Xg>LBq*qGTdb;bPwIP+Wm&p>0I6=|iTRXBjeEAzP~b z$T-W5jw1j&=H+CbqRP3t9!l=5K~$cY2l9tGpqArZ7%$h^1%A zEu9e@D-|oq6m@ofmo+N!Fv3nwlbxb54m&1iK}I6_OQ1xk-vMLK{cg$aP+e|GSPta; zqUEZd^~ulxSnsp=ZJDPP#ydvhz#c|&$c7C@{2$Ol@{y-smZ)0vk_@NfzSE1>{2QabjPXy{^p}w7!?}>Yt;e>&N^=sS~5-wQmjqhoA zfrBe-b4}Ldwr~VNx;nfD$Aj(H4p;ELX0&TXTX8zeaMfm~wXwtg4Ne0wZTlqb=;(nc z!Z)P|AGjM7*PBLb`Zg1P5r@&Yk65U>P#SWFT2SuMKdxt8Sm+2NLwd{r_GyZP>M&&2 z21nj&+tdMj3sJ^zjI!Fy3XxsnLdne^#G!@$u1!XxJ6!`40r?J^XZD6|)F)G5lk+5F zUT4&ax5p^ZXJ_EPLIbepCwUrIVAd1&PzySfIEyD>T%Typ)inV7XXuC{g5wn`1}-}s zV4zy}13rY^yMBQJ%7))jpGodu|b81P)A=C!z%1D`H$qk-}QmLv(oxJ~bkb`lZU=?f+B8=S0uK7Kta=4(rxhQ-fF8DvTBJ>^)RgM@63R}ao3w##th-Pw z*Jy+!t7`2X;C6aaRq;B?YWmwpuu(|})L>pRA3K#x0lP%*JR z=#e6j00R=tUF*9|0$rGZ33gs2PP?kCYp16>M++bsb!l=LuJ>l&?)SW-fkT)>DpYan zx?Uk_SJxco3%EsONOy1=i-H^JmUQss@fU6=aE>NwTcc=ygbZ(vs9|VuJ~+0@HAhA@ zu<3k=%9*{2&>#j>`^?KWGLNk~rT0(vP||Kssb-|HWVEM*XqyG3{$ythYqH)+w%Oc> zDtfLk-b39U%dX_~S=2=NTg*Z3_@ul+QVvvX80>P`By$q^BV|u+B-D+fHOgr(i zwkQsE)Ya=7Qq^S5A=&s)bl?@rLs74EwQLn7<%gm-@DY)MLF0k6^;+1XNO6E%P1I?} ztsW$#prv(?ZK#V!*t8pIPpgQ56k^OOY*!aadiz2}Llv`|dLEKx2gcE*58c}Ovd<8F zILZ4MTtRt5cDiILJNoJ>xh-fC=O7Oj=`C7~N5}i^e|Jwu|<(0v=wpZV|%m&)FDYoc=&`WB9Ia-Vr`!+^|2<5|9CEhHiJ}E zn=j1&B}mNz1P$|cfvsfrE=FGBC8)m!WEb)NBEIb($x1~|49~34A~_t23S%trNgZ(o z_MRHgY&;7E+I_A|*S%?ouGU&e13)W6l{e^VDLSfGaWe-11yG^)l?tE^W!}b6rD|Na zmjC4|BMoE78dQA+H%_J74XrUZ3ckyAwrOZ7DBh2{ zcT1CmEXP*&K-Ar0DTyy~l|o$&<5=vp`(z7~;;eVIy=CpmP&dUBQ+!d=j2zVyg zZvK8A?CmoU`a4>-suXyaSNOyTN$w^ksBA&#VP*Z$SIW0hf^4rfQf(!Z%tK5v9}L{} z(XJY;4vmb9BN6VPsqTa{kxeZ#dJ}T&(xP5fZKKWh?B44`pswhF4#Bj~sZ>_BT^K2d z7)p_!2f;J04!6@b82w&B_jN)?Vm6@XW%VpxcYCoNWZCz??Z%#Gu+wD`FY6g*|8wKZ z)nXA>Ys&!dHi-irO!|}j?wy%;goA7}RZPbTd~9(=hT3gwwWGpzjHt`D;+7_A5_Z)j zJQYX@x>2F<(Yr72_E40Yul!~BBAjE#5` z%K03ptV$Qk{es7u7+b@`ArK9pKc5IZ7KOqq6~YbP*w}wpE058Ou$Z$+vx)lQ(21nH ziAivZoe43qb0b44<}}SevExt%ozGDCV8kWRZ$eH>Qjy1kX_l^7fJRT#=0lnm{TOou z?ejalp*EJOr!niNq@prTVvX^yHOCfu2mufICK%PAG*9|k4Ne*JZI?;L)A~uCv)iw- zGB8a845<1=8Rs9jRs`Zlf5E6!-n^raYVnM4v=lGH2q%NmK|LD7C%DhK<>t39?-=Ju zSL3CtWDP{fCcVu&opj{2!gO#NTnC{E0ab5M@LQ30u3E9hfvE#{SB_m=X@bavPGk#? z?^sm2Y%sgQnMVPl_nn!nj$+8rA2%Dy6l6nFPCizIMGF|jIPCe6=pn=&W^pZ>8F8pZ zODcT2R(PoB`_+{}ZzvA0ukEv?xRQRij@6sWDPA1W(G?5EIAU)XuO^J&m93Ix+-v$mI~sL0ot) z)y5B9Y>PvYl=Nd!>X7q^brG-@rDANn#- z?IkPJf-!1pskG85$`6IY!rm!F5d+ML>D!$+8O#pcIZ$c`%Fs;Oiowa<)@pmDdF47B zu~SC{9M>apf&DFML0>&#!GzGl!ccf)f`1~#@NjFcCl>zJjG2^qRwIL`*?9D0rZUq& z*x17yq6cII9wJjCeR5;A&wvK(+Em?C#a@9Z=f;TbrIa?dLISlKlhi}Cg#xo)O{dxI zz`dD3J>6YOqRYK7AcHLAy<gxQQGhQ)^j2YggFg`2zkjTV9$WsVN9-#2&!4W zo}AbU2*^);O!<#y2^nvW0_y=ak!;*s(uB!OHxR6aCls_GVdC|;;Lb#_CXZ0qbH2rpg*&8+yoV`uoGNNi~xWLl>H)=B2};|ccGunk+F*Y1k@)#TIn0$U;`YM~u%2ZZG&ph+&UMKc;0;p{yxi4@yd&6#* zsAJLDdRYR$Mz`Sn!2I~djkUFT5>N+(EoPr8w3A~ssrj)K*?LL1&G#qPyB&WKN70cu zP^(S6;vt^^lKrpT1`oy2HG%vAQwwAr z%T3QICo=sb10kso+wdWw*L<;TVlL(EK|>mboix0up}?riA^Q7T`d%S2STvt(y&dIi zD#|JEUUR&|7o@tqPE;76&)f3Sd16Px4qOk@G-#n>Np*DwbdURE@+4>n#ex@x23@2M zKO3|cL6Bi2N#4d4S~FXjrlB^MTgdf)hh?@h%8vDO=J{_~MVHdM)^ak-CUdlvf0|5I zU_DOOm-u*?b7r1M$M0~2f#nfMx*K^Y zJk8hi90;1~ejRyzNiTd}>MK_2jLLO_yvASG^wn3gwz@owz6Cn)oE}JL7*#4N(WApd z;pTN5JpzD<_GB$xOc1=aP)W3B`pS~C7^*sSNmy61Rbu?e)(R*$bU|tCj4asYb_U8& zJT^N80c6w}{(R3J@#6!^S##n^oVr1ft}-{*2rRpc#AN+TJMZuGc3kjMMS!6kGl`5& z%EKqfr}E<1M3YWmC!hv{(};WUt+kOlZq^IA&qm1bx*LP}i+J>H=Zdxt_hw~TV^Ud> zyeY>(Z1wh+wWzR<A z7#Lj7)2CTni_=p@8(BY=LHJfZJp~Zc8R>YeF@lnZ@ZAQH^AN-sr}{R+DUAxU*DiXs z!s}?!>z^(!-d_BC{>#Oy=NGRo-u}}8#~8K1jqeMNqANUs+)Nm_XZF|L05-iIy*R52>fVyo(AKZTY1eSttpN-&d zp=T=qA{pEo${k(X8gi4-F0qJh2Yl3IPv=s~JT2fb21H}hVElR&j7A^0hC!$qa$7mW zP;)&q8fp*%OSl=lbcTX^IhSHV@@YRJbf}H;)(edNx>~)=udF;;`pCCG`U8+tL|-X2 zuD4x{ezVHcz=N9R9haP^d}!U=R?o-KOF1KaIxy!G7Fec&u7{4)t#eG%(eK8n_DMR8 zS9#OwA_sklgFZa!;aQ>+TJXn(NiJJJ_@4Q_#^tN+JX|-W5~SGfg(9xHg%{C`AG~CHE4|emz}cMEykuHu z5It)G^b~GiKFpvWRMC&*a!u%oOAE$XnZrEI;|`j##BZ>ee|q%Ici&B?u*kHmSTddd zHI5(m(5yBuyJ5xSadIe|0@G0EN8|ta221RR+^{0~?(z6*tQcqIBChKfDG)9O;~y)( z8z+yc*QAVdrzSZ}zD*|d%ACvGSo!Uvzkc)WUwhh?cgn~Guu8q$5CDZ zS^&G!437PS12zYgm)g2;lgG7w*yqYN;VJ&(9^xr#Bs%-cr4KHYLmvdrB%)7&++>v? zu7!#9vaKG@ITSR{Gq(;Vjg4y`+hIb0PRHHA5-6;21r%ObZqI)6&U#gYN$B1T(hN5P z!yMIehlx&$55Oe@Biw++uB9e}v-G1T!blDknaK=!O-CI8CT^~74LF_U1CJ_;G|$KJ zWWN6-Mx1&1PBLHZoOlq?TaSR5^MU0x+FI_^&8>FE7)4f%5r17>iXlA%B1!#FX`lqYg%FR+XU)%8UH|much(9aQj(5?@k#Q30ZQ@(KU9K z%{lQ-J^ZPXSiib{p{76?LS@yK$(W0zB;~$Vha-&@06n9yO!nMA)#;PPq++hEa?+6F za|p_h5qrBuos0En5Os13n^8WGko)ou*?*T~c0VDf{U&c{ky zBMksj~@A}%T+a@%)_QyHJ{^&^pM;4CdI8;cgg$r z8NOha*tv}DpM^rvBO7wwq4B%gud}I!l!NHrAhzWt{`vr2a__j>F7-qnBbRr%vEft< z`{wdcy0Yf%>HuN-5)mt`pS0j0_)vwm{U5ooe$)bi*+FJQ5PTHO0QcKDURtjsA-?Tu z6Bx&aa0LI(b;quH(L=a;$!~I1Z3Dt_MCB;Y%*1>KW3ll6Y_^>fI3WLTzXp(-~L-%|BQmvraZ>oykC&oBQVdaaH@l}$<{}&L*x4IUhiYmTF-fIH)i=Q z&)?sQ4V@chwTAc<6RiIcSC~O+r&a5hgO{+~~ockalgzVqowfuHs(!s73 zALvn(ZH6yffD0u%;>k`TFYS}Nluk!-?H6f{A{yG#v%BXvH{wH<=b|WKgI8s;0_DpI zQ$6cp7;6q0J<%2VJxYVzuBGzO`v}LD!x?>JGsD z*wXSaRQ~BcGRBhhGJ(c~!GoD}+al-$!2)1_?`z5VcU_IEfJjq9gbG|LGMrjz(N>aM zdYd(>{T>o+f6u(zzOwA8Jp|uiV7-39za^liXo%1wnJ3~#fOm|y2a8mkzjz_W=@he2 z$f;A$XOqrM;&s$Bar(}C`qmJVS=)m&rHGN5bl<{(Y6p%_{dhwVX~j15#<(0XYiNjq z24mi_2GI++3st#yD_ZiAc!{es6qmCqO%nVB+lY?(C2$SwRVlX%{dBHGL*YqtSCFY^ zz<9)W7Q2&XT0g3(C-Uy{%RAkSeq@u=r5=bQ4jHI+Pga13+`QsXjuZSYD1>&sbGJq0 z0HK!rGg$bXmo2QEhw;$9a97yT2NCp&eYB{faI){A&pzx@ZKjldv<%JgC#_YP0E zky0ouP`1IE3w(wj8o`c#XUEdF-DS2Eysg$VJD=dARPs(_^}YnF46GL|N!~fi)pK+t zukZKj-0t&K^NzR^A#ER3`O^vQ@QqCU@0gDhft@z@hmO6Z^R~wrJ?tX7>%Gj=CT(#e-_&sC-m;pvzTS0j zTg)|$+h&+EMf3*{5UK-})S=cVk2Dbg07Os#03HAU0CRFxp%d>ay z$L#gHvzKhk=1sk1M``+aRyQ2}tLDXZ`l&rSc~GeFH+(Z@tE_4HulO|MW%+_v9dCl^ z>#itUZ+6AAhPU18rpSNJulbmj*`{81ud-QD7TxB&60OUu0FYHy&G@^zUcRd9Zq-23 zm|eq6HCi{n03zBkYd6*GwblQc*Gt|tn}9N)x9AG)6F1MA9+=_;`hlV(|pR@LDO)I%xi{sA+jw2Fui^$o9*0tgW!7%S#1 zc_=i&)X^%Sg&U{bTv^9L>${)v$hYSGJgfS@=MVri=uOcPVW*= zwJuA;7W51X{hnd(#OfNeBA+mvCxp(n4jXEM0&Io@1IW)dq#t_E+BfU6D})O3+~xo< zw;k(Ho!HdZuPEyyhoS^`LAtcTqfjp{M`;U|3PG^xvk2f3355`kLZZQ9)a7Th>BJ06 z==2^HI`mjV=hxS-zyunZ6TPyvP3J|GCv&8b#D`OGevyxmiy^?$NP2)}s|4K6i1*on zpu_D%uw^sY_zMB(au=Z9eI!@S?QYe=5$z3<-W*7IsN#f3HGe2dIG`3;n<#jvy?a26 z024hK#7Ktwx1!-5O5NU`_8~M=55hQyWAO@1_qC7GboAr2CJ!L>^xEAT`cyds!__A4 zMn+@S!bZNh6p-e1!xGVT!|HitIn;awVFk05E0o;G&8|8@pDphwSpg_K&(fy8)gy_7 zbhU05N#EMuppS(RCTu3$tqH@!PJq~I!JCy72ja#MYcY0lbE#P~%TB7wZ`qq{m5j{1 z9c;$Q_cg_)zegG&TZ*x*zc4oamJanWFi3uk_(0{pi28tPbSyR5%ASs*6et@k(Bs5Z zcs_IS7Nv)V5lQr9Q*{qQC?y~o0i6>)4EB;D+9FpPW=*j&)NzWHahH2kycwcpgQ44T zsT29;)2qN3l2uDD)eV?sO>&R9_B6xWq6k4@td~1Cs()e#0nk*xspt@OGlfv;-3B9?InW>J#_|>F2Cm^EUBL$Y8@<)%ixo zbW=g|oM@h>x0>2HQ9Dl;f=<`;VN9R_%u{%RAner9SkWkzR=%LX!L}RpgIiS{{BoyQ z+r$XmfEwFGxx$hs2q6iN5E+29Mb6)W43m`zJKUq>?id(-lXZ)9SyT!3r+3F6?f9+2II15PYhn-JDU4c#EDO$f^#;2eu9Sh#0Xr0@Ih>E*{M(n2pA?AaWv7wFkM z?Q`kRDq=q5yj6~D^c+Q*qW<~ku+ca?x_l8+lrfXbCQ!om70uQvBHgi>W{8~a9BGPR zSDkdgBeY3{Jn{1=;>J%k+!HgT4SO%1c#fzY1t;#>X-Z38U3ZIcX=WwQ8sqjWE~DhB z#qkLnqQp~#E^9iC?RkBd@XsJ+R~_)IwW54EBtR_y2 zd}#@H&6GFO^10HUb#$>)(j}O-L~WAw|1zDBh1)_QWRlik2i8 zY!A6rrYE~TbyBGLi9ZsIQtF7s>vJJP8 zG+sbPOs%EPyyxAkx_Q}T*I~#%7a_eJ^xILsA^o8ospYHG6FUdOf3d@f=XeIf08G;~ zgmdYr^@XJ3av(u--W1n`lPVCb)>of^&1g!&ViQK~l~J%_T+j1D565!LW%%bU={*B( zp=*p}!GDzIQE?!g^6RF74dt{gd6!Mx(CrO0rPsXEF(wH8o~iAC+0+QHhj zEpRWwO>)N22}9Z~CyZXn3G+j;{^PZ0H4&=Rv5f+mG9TGXp9g7sDV&qwl+fzK7Cgj^0LD|+WZ|1d)jrutoPw7_Z_8}Pb1C{$ zAD0<1Atz-B`xpZ>e7>W=44=S>lKs%T5KoISqbN(fsgR8Dng*3x8#8pN#ZY|mLRi8E z;U8hpAt7Owtuids$~76{aGsSd|LAAS)mM&c49DM0A9q?&Ix zx}s6*DzD#n+3ZHFmp9WBsU3VYTu$`E#|T~+(!(B{NawTJdR6fJ`Q{&WrQLO9pvQXu zk=nMdEkNXOw(HT(uB3eNRMsOT^6uOni1MRh;FLUc5z!9#D33xoYh@C7`_V)ZiYL9@ zWyW`EY9IR1s=1U6l(?PlbI(TUr0KKX@(^*!FD_Gs$N5Zq5_BNrUm#n% z6WE5#S=N4Fs#GhRYg6^$T8qzOjXIdXYR_TB}zLz3>Qxsk^-i&&&SoID! zak#z}gw5h4C?s8P>!$m%UE|!QNTKXXY|F65O*Zb3;@p#6l?~7G z4X^>btYzII6ZzJo0kW(-u%;_0_!=P0$rK`GG}0BJA@-FXy^C0<)^{6qP%--ZtzMV8 ztSV0OyD`f*!`1^fXkK7=jMq#(6=fz-;)R+r3E&+ZmPj8uiA3D9ve%^0`c8<7-*s*w zhgLgmq~upF^KDKC=D+fdU)FIiQg0%w#-FRW{`}~RR8~ho*AG*6?1=!U;)N!3vf~qY?4AC}n;zrEnR!uMO5VKoPpW+% z28UgnhOe@sc`rNw;i|nX8kwWhwR4U!!jdN|WgGoIMbD&Etvb!g0n+y_>Kq@9!mKZC z3DByGqms|NqcJ-IU0!rYL4h5895M|)n@Mz0pu1P}9IWOS9vQyLYRg(&a=A98Cz&CE z^!m>BRby~ZtR_2%a7G`rRm11JX((NY-%|;XDo3H_X$3gMePGC|)|}SNq%=9rHL57h z`Hd$Ow9;ulGqMp4#(mfN)gz`#p2Da!szGb1PwS#?DMfFHj`OLdaY}9E#F{xWv#bX> zLKZkeG1GNnUf?k%h7e?@x2CN@r>`~S(iwBrfOolgQ-k)xnF=p?y*x7JHC6`HbDBgS zib`Mtdu$3(U2@5@cLr~I2fN3JWt4p4d#;W?h+7;RWJf{X3whzc&%M;4?v{IRYk8h~ z_*+7f%9RrPQ-vI+L+(@fb23DO<=h*eZ%46(U0~1}jJ>Y88-<9YP=msIX?p-IjtWu| zS&=Nbq>u#-kt|ET)ooa8JF-Ad*u}jL!`SxHSSoAv2nnnmu@Nhv05`v_>AG+z_E+^1 zV_hH-`0;k#g*fjKuyw0fl&b9{prS*2{PDYcOUn4Y99if9^+y0RWhOBoW{R)P3#3VYdwkRv|nrC=vr^) zAr3!|!R*}Afp3MA!1cE<1Ufp>QnlT0iuLD0e7@W0CXFIKRqrydJ94g&bbGCL20>BB ztq)5q6=fl_w7UniOW0THF@hMlP7SaJo7h9qe{{ z=RDM7J&ZqUWMyX5pC9o7zBA4Gsi=b#xQzW|z6LW~v+RI}XhCh#;h}$aP~yj`GR+VV zABz6c>Cocb-=o<~Vxb#C2udvxePZ0Aa*71v6&au0nnSekA%{4r5hM;gwR?7y;}^PbGs@MNqpuTb!k^wY!EI$!94H+{$t{5I)G3)LD&*mW7g z7GL3_7T)tKK8(|cpjD6yq}|t*(sRpB^iUq%k`TWDgNvM8K&h&sIY@tbA7yF$E7F`E zpFv9w)_dX3sqxIqh?LjdPJt1rl_=r%Q>VO-rrJE>g#Ar~%uv_;6ehr|)*dyJ35%7~ zsr?6y#Iqf)v7Ql5P(0wv&)vV?-ol2TH!>pyOFzh-R)Bvt24(_j=rgRbLRL;8At-p< z>%4Dm|La5eAABl*0!}+w;+yLbLL`Wc3I&FSBw94%Coq+U)((1l1XHy;RYQ5x4G} zgV)P_0lmRyXvVVLyLEz|^pITJwe)jmRL4zL>g4vAET&<6uZx6^Ho^olyUisp+FNuz zYtz2%ER|xvOSkSF1{M`yv*GgU8)-#gsg(FLO5l&x8=(fw&a6ds!RgZti|ski(kG6U z{)t@IJ_lq#^}UZUyzG4%JUCJ?3xw;&P3Oz77(who_J0q0YF2A|oAfkx=Q}*Yu;sin zYE}z0sU$~rbTTOr%8OScj_pU-hIDp(A9ApR^8Ht5(_h#6Q;rx9@Gn4sR|Wt8?f>d) zIsei_{>Q)m+t8Z&pGlaK4!=s*@ACkx5EFAWmq(K*kSHX?Ryc7HUTKdUHSp_^??Vjs zqW2=Ig{qW$3F;`ik2`kbVrTN|Mp!Hc02)s>a4 z4K1WAd|5%$c5t9)=i$Qf{&aBi0xCNJ54@41i|I)k2-vlAvg6_Ga(gkhqyNmI9wjzp z+IQPF>1BlakszI`ej##o(Gkul<&eSj6Tuzo1Y_g;ekcP>TL|q0ORXm?B?EBYH*G|~ z0`p0jt&$@3fge)f#iM`4IYf|><)9<4HM1eKNLs|eMpMAnF;?J@7f%vNifu6aQ<+7I z1ZJqPKO$sQDrMp$EvA96sjYxMc|woKGkY0P--JCjqM!y@EA@7B=HAu7N!qs12;dXf_?!3!5zox4kPo>jZ%+>s z)YWK?AeK&CB||^-WXLd`mxZ_vC@{35x_wJ}e2I!Y z5zP}*RHd<^m5w%}UEr=Jgb^^U{S3lXOb#SJ8z7v~7qT%ONrM*-ZOcXbMXpp;)I{;z zc@H|KOwm|ad#OuNn*1sEkvv=)OPnF!p16zE>*CHhGz;4#ydOsVrxcD!@`eci+=c(l z!3Qk5E0=O;ch`1tSf?jvz~L8+q@b7$jIZjZGi_sQc+PoW!Fi9~S-&jV0KOiI?K0U| z)_Naw)%q#Q)QbC2dD`to;k@pr#%#|eMedS9bJQ0ti~=Drma>D=Z1Q2vK&p8?!PKnV z?`P(p8*wD3@akUbVm1XF-%6naGVeq67eBN-)^bnZhsKN*Zyx6NHy+jMv&K7ZqV@fNgB*)WL!C;RAhpuGInl@@2 z@5(rGkWQvr6-D3IrI>tD>Q1u~Sy276_ohUBGO)3AUa|hh1la|1fS6+6?a7(#&2Pf| z`;uFq+#n31-yLpcBHLyHmKw-C33@D(s?0pV!wGOZ0exK9V~N1uU<&`TonmjNrAk$n zkmE#a5~)~{Sd`xmM{#eH59nKHgh9Udg{#E4a*Z&tS&H!{Z z`Zc9F*88bAm!y}`2kV27q=P@d9?@G;08nv`A$d{9VU%?>d;)QRP~9KR;`wbu zRfEdn%3`2Zv?z4dKp&a{C$NrZeD080&RSwUafUVVGa5ftPx3@txD{~hFnXY9O~ zv6PWwY*64DYa!0t9<&S;q%D%un={WeV6eIdbaG*fU65-&0lqy@$xU`A+ zI3&BL1=i&;frC=u-|1gv={SMt?rL_U4*|Ecwtt;UA+>YQO`1s2Gq3|VAD<}HKY|}6 zd5^S9sM%=H3H{7zrGa)qp7AG^f;B|lT$74DlDAH#0lq1zEG9{GgBSw!|A_K`J63XT z_L#R{ssy6ETF?aVbgV+;f1jF1ELCMQ+yC=KN&2^|Rj(jfI@7!xg#4eQ&Jx&Rh&mYO z^Lf37d|X%#06<|1Xz%#GYaFEMTUM)_!Qgk=aAeH-G>aiqO$@_Lkb)+^|2H7uGLLhk5X6gK>*z1Y>j@Q~- zhrA(8qzS(?N(}LBsqifRlf4_LbP&84f(55<)zmryuCH1_+`kh~BdK-zn*D-{Qr%qr z^QF`>35GCMu1~c|Sgil~jAbol$Pd2t)(D`PHJSw}8`KYet|Wm+SdsQPd;sSD;4RPe=UM)<1$_wPq+ z;B05C&)r=l1;M7{MGNII64WY4J?LCQuE*=3m3~vhR=p9#Xcz`hjaQ#W`<(pfRZDR(Xj7gL)s-v25 zr?+ZOb!OS>iv3&A%{^zO8#KG+SGKy+JwfI&^XjsCOy=T zNJ#Z+;TeoTmS@39dG$nOB7LyQn|iPuk3@d}FfV+5iKeoSv2mtuW>7`caQ_-oCwVrJ zwO5!NraVAPX(DG_3*`Pb;CLamu&Jh|=iZhAKg*056w-Q_6_`2IcL* z!|_rUc%TKZ#9-4SL*Bnm3|zQaILMb3i9VwLK@RgKGEi@>fZFp$aGLNqisz#va&7yX zl9~K5;OiZnATt-`FyavIva$zSlf@RyK~$6_7p{%-BAJ^+v;QO>5PJl`=tX8)2B}wN zonGY$)k_sBh>|c1K>$2YdDkd()9w0w=C9`~rf01+WWd2W6v+EazVAR!3G8Sj@G zj(FJ(z!80-E`2+SfbwKmg)_o&E~gHnY~XIRTiWW?cw*|0?Z#Fj6YtYf^|t`sXss8- zAQ6(h6Vfr9D0wAOncBOO_%GUgpPtkEURu~N(V-Hd6an?9+)`LsB(?O3K0M0tAUm}qyt%$4YvCftRlnGRvF!~`Esoyg@{;L?WtQIu8A?VbaaTONE*j!5?M=iDANMSxdiJ|P z@2mL5c;<_BgiVc3BpnR}sZ0`S@DpccK+0Hv49(b$73|Ff7aHL^K={|%3&#%>9e8_5 zZ}-fG`FN3Y>-NwAbx_y#MUblGq0~*f@-{95r}ccfHQv6grA0_FN``^05 zOeXuRBL+o3zCTYlKiY;Ux(e$UII?|>f<=uHYLng;RpUP;-ggc(bYGfZ!s4IU@?MV> z@bI`jp5RG-R~r-{E$;&Ori>RCh*SJ%xsJiBkCu0!-4D3>)OO+i#e8IO=lBw>58Kx! z>pk_!ulypbCAb$cp`1~<2J|ewW$Vd+S(YMaqJ^b*rHLj8-QUVMrmW6|I!SXFn-(h+ zJ0+eJQYsSdO%Oc(N7SYJq4^hHz!S{N#mA^b0ANBTt~MroYv+t8qXJIJ1~s;&l(o1= z!n$c2f9<8(|4Qpo=dHxJY@Oy9cUaJ5&W&YNwer}$HOT%mdfR@VI04oIOPLv8-`sA9 zUboD2Qv9Nfs5VSj<2A_<4)>B8Vq;7r&!xIRI!ZM64&W_f5Q_9VocYwWgtGl+nNr7w zLr*K-r@YFrpImrW2z!a;<3hTnBaU3uxNmem>cA!mJec3vK#7I$W8l5wD@!; z&M|dlc?OlRz=q5rjZ?_*^X|4$ORcuj)jfd#Rn7Uz>-m0)V{l3}5!AhUMKxB6LRc)GS^z+h{Qyo|I)LN(z_#nt_8{I?*CA-xjlk*xdi&mIQoL9{0 zi~F`XrQpyvNn*OhsJ`Mt{%%NMckwBD^HV{Ff(DsDG_&e2mDA`<36v%T{8M7ZorXiO zfSC`Z$kqo2+#5<0+w)47OOf|2@EK3Y2hk3EXHfN0wWpR6vAqBLjMkzt$~dVbb0FL; zAkZ(naaHvt-du~D9@p`%g*EaVtBl1oDrPEj`7(S7D8~@YY+qO#qdTIT&ZzKAqR1(Y_&}o7U{`OXzb8voq`BK4w^#PXs{x6C=)f{==k@(p);}Lg;d^L(V zEf-^mE0yGiqv-69m;rr2Gwd?-HAU$pRS z4LJeW0&#|b8S2~bU5Cq&ofJCuKpr!ZAd&hCIZ?X1Cs@33ht%DQEvyQNpC*xk zZ8S8`9_|R_hv-JKAK?e8_rt|lk_Cdw{BQ#72t8BDs&Vv?X?Ir9p&3A?HN3Vl3JoT> zBo-!eQwFtH zzS|RG1AgroL~%Kj$gB7MfoX@M3heiVuap90aSvZ3d=QNMl6UEv^T0&hU}B;-@0 z@Mf)_XgyWR$HmVs72r*p837O;w0bzrOP5&EO6rvY&=*TRc@HVD^AfQbPcyW5KG~_Q zXDj*~LbleTd`Ae=-}1d9jzwoJ$a7$*3YBubv2c)gz2sg^WvP4Lt&CbM%nD_`O2!*w zkmAlFr&I=08~}BiRslJCHwuzZ;!tDeu6@x8Y5|dVxdg2QbZVkn7Nb=~!L3yncMiNMxt7ogGkt_Pn}T`kdMC5 zcdWm^K^%#gx=qdT?}8fYk2X}8aTb0lQL-sCbWVuM^rUnA5Iqr}U_e*=;;?6#Ibl#4 ztYJ)&UKo??liHs!vC|4vaCn-RVM%0a{?j9`f*i?T?h#5XR>P!D3v4<(aDHj2FAu zxjakB-E*!?$+5Z8@9F3~o@>63uhD3&4-!P>qC=(o#`|yISjOUa+9@Nl=E-lrIOMlS z|NATwz|qjb+|J2S%fQ*(%81t5!cjX;KyHBkPw>qbN_TN`1>+U^U^G!EB*T>-dr_q( zcZQpT)-3Z?Phv|FLyXV&wx|6lo(A%?JlrCioxkd8U?2O`F>fKLnRvj1dVt>HHc3NbZ^A~N&@%i5Bt)d!B|`?4Cz>jLsVhjCK*k7g=bf7i)z?8WLqK~xcsxZ zfN{Tr%?7tpmrpcXQGskHcIb;G4;J$rpytxbaB!TNy4%{C{IZqq%Y^Ayu>Y!p13RHr zQ34ze|EmV@1wQrOuAA==hw}m%-EZZ~Gb&lV#ox~9vasdxViPwqIEgN7h(cl`rBmgwJpWpB zmuzB`T>J=jvh z18b%GWmLuTyt?w>?XbW^@bS10n*&`&F|}s>o!XlUwQk$DI`s6m5Q%(JKW@;T?i*Oa zb@0N2ZiDL;k{uo1nHJcv{-cM%8fu@#v?8t*!5kD3AZopEMMqKf)H@A{YOjEG@ba%v zwNK#KI4kH@JmSe21q*csVqS5{@Q9#;gGIr2I_cI~c*TB5RkSL6WKv)vq^qA@%1n5f8z${tDsZ&-QOtgfVZ>LC-k_-d1N)!f0E{mUH^+VjJ z&g>L>+AcfE9!Or19*Z=sU~w?9EduwD$*g7)iezYl6@4M(auL#l&c1UO3rYM zRpo+B_H62xB?Mx6vkjP>H0un7`ZasJR9CJb21^?z3jBiHbvG*$3DWl?AIWWGRGgUy z2P#&FtX;PC7jCf+!w4v`9Jxf1<9P1S;oF_LE|v&1XLQ9yCVkfkOZeyOfNua=z0DJe zMS2&!)()*Pvm9J)Amw?mR6U-~1TD}^UpB=z;eNywTL?4P(qouqyB|RXbb;LeL2m7Z zyNJ+>>Eq1U_2N69MrSF zUL6XLA0y$~rskUax!Ix%#){b*yJsZpav==*t1WSf#@kp2e-f#wpTSt!Rw2HYxTL#8ey(_hslX zDK*t5O-)+!kRw*D6az;{Myi&c0!?{ActlZPvT~XVeV!e{m4p^l4U&uTtzFf4)8V6W zG=U9}fm23_SpXTNin%6C*a_Sg(PcUC6ic8v8D_$je4fja{%8xK7QvP%gC;I&MNSQ6 z^K0)38_2`>2PM6#^5{vM)b*ANd`FU?`4Ogu^RmnpUAmY6qq)C?Su4%&S=V4SlCLEZC3437G5-nD{@o9T)_lZxLNqb%;eGmN^k*t;~Wh*Ov9M zf@To;WA6}BSI%(Nk9$pYiDw>P2oqI&F!I8p3ymshT^d@be<%0uC&v&@CdmsGHx8Eg zu>SFKwaMERB2gpAb<%ZUO+rt`9G@(9V8HIYw5&w84dC<*mf;|}t@sY0B96y>gLLZ` zLuLpCrxWWab#etjYC(N4r4MA2l-hCBzyF|RPQD^uvyC89Hg~*cy__(O1piWD0`X$+ zk`=MG^jf#=<*GRTfnR*i_~yP$S1KFvA0YW3_&q6pcTkMYZS7 zdsL84jH^|4f{l!NfUK83^! z^X=D#BehD!$QduxmY%Ag5aDMeZ)BI!#&Q<7fjHeqvQP*)IANaGAb&2FbmJ$avFb#S&iRh z3E=|)i@F8hH26ob(jLuoUv9RUU&{<)9Ah#jLGZ7d0SGoT-fsWmBS#(4^DdHj?IDLL zb4f-z>fsG2Ut?t{vMynmbaiCD6 zy?(5aqkI-3JI!3!ednyFAX7Kvj??I1)6~ROlaNdne;|YkaNJc!EEwv$9ubz3#N8sS z2Cg7HW#Fij?M4zmD^o%QEL}tK*a3X^aG!=>?|7T{s-7zR2Xh$rUejpbI# zLqg2-oa?(X>MI-JP=LwD!0KR2?QA((2h5X%K@A;7rd~QZA9kn6b2HlPzqgh?OJ(V8 zefaa22aL1L@yUD#Tkqq?J&T17pswIA&#iwKaLz_71iR^>So zq9xPe_4KA2DY!Bd=}=Gn4+T;)FR1Drs*FaRHTi|29dtYM^h(kW_|*CK<7<1oF)=%m zJoxf0RX@s2pWV)hRWBQv-E~g-9VEH$;_q&Z4!Q!9nd+Fg?{nTxAomZ6Pv8G$kQ~4H zIC}Y3H`i|lDF*}q@CzXTu+ulR)HnSfh^ehja)N@?06lW>&I=W-x4P=81r3DF0Nb6$ z?VNe}7)^AG`J_yR<7H2#(Gmwp-$>TxL-s=EH7P)N1*f!XoEJMu1t`mXwMU;3ZVebS zu_ua6q;ZPro4~RtY%&a~CAR38jdPGwm)+GVsZCMK;ZZi9hyOoyk+gHrejxosbT8-m z-KeF(`AH{N%^_21@dhhcF8a~zTKZjdP-oj$H$U%o34;VNK904Buw@+dQhbv>CnyHX zDhJe&hU@fhFVwLd*8MI*Xcp~kWz7MBllQWR;Q>i&j~HYzBbdevMz5Ervs)5>UDzRG zjjT}hloH%Mvbdd5)PqTguzhReOpeW;2A&|}IFtrmz{CmxBAN$i^`Fod>W5F;jGa>5 z3Eu9U-aSkfO8*F{&$|fmoe7`G#{K>uls@J)Io|(8j=eLV)Y^+UP{Du(07zi}Pto)L zi%er>YiRj@l-|nJh%FRv54rhJYdT*pjTq89i1%QoX4UH*MyEeEGZ{2__BLJo@y@ED zE@kSFgLP+aQFK<2B-|&`S$Vld6ae|WNY(ZIN zEG7S9cDD#d+v&C4eK{v@?oY(yIB$0MD5uNne1p2%Ej{S`TY9wWYbMpbos_8 zb;02vx&3$22rzKdZIaF+WaE1_CD--{(MQ*F^rq)uBC$Su9mBp?iL5x+0&`fYF$252UE7ehjStpqw5*(MIa=jCSjSEGQ#RBkbpS zBeEiS$+YXoTjKP^i97Yj2YN5$shIMfhKzzv9#qxmjB%>M@jdF)+Usw(D(A^TET`=L z`l+H~{L21eWXuj1;uYLIdNy6a^!vUznwVHETt;rnuK(H}o3? z0i3`m4_@qmml)YjM5pK%g4m25_wm`=tYRE&ex%>wAlQu)))}D6c7R11%7_o+R&V9` zrM`iyy7{=##vbCv{^+D2Rp#GIshDLz@@5AExK{R&PqEclhesiM*O$<(F2OBt5N6D@ zV~}U=h_l&AE=l@1!zM3v*s&;W@-`3wEzbb`Tqd@)dUC^XKYAfxR3F3q6#c&uu@n4M z(lJ%M8w-(JE+%?=A9)?QP>t5e)w!E1i~lf9Xa5b|6|pT4WC-I3y_2OzQwty{z-Q3B ztR#OnV*)S>1@VVy9WV{7PR{=kldYD($zQyq`9_ql#ymRXe(q z*2X4o=V(uxT!{vjm7ZTI?JPpaVld=K z1&MZIV;nxw7WTZ~S^UvfY;V_|E%mj0Fb8vU;vnocs`X%?I%lzd-)!uol^wQKiXMp< z$Z?<8-f?2MsInXN>cNd`N37^1_nSsbT2dEPck={@rQpHFpO7f(m6nzxYMA>(y+j%Z z382s9E?ZhsT4Yo*feP(wL7v`j&rw-u=LsUXEVXdv*dQqK6q=QHf zk9Bfs{+eUZNuqjg_D8mA@Iu$vN^ZR=_$agp_)vzKz&=3LRxJ#mfc`Ku4`(CKUh)_- zY1E7s=}Ob1f$6`b-Mm!9k(x;4yz;NfLe1ZwqyylF8M8<$!oshmK!(y@@)WxHW;l_v+n>m;cRvHeSaci;6uA!of*g27k)YV5;}tV z6dQ8e_n|`pB8L46(1AqOwSYWilKi6|K0<=EC;wL8jZP)df7 zibee#WDC&|Aump67#TB6a~by+wu!)!O;IK#L#CL{h>6B{Xufl{39n>aE~*G{<&tZB zuy3CR-P4re8R&!BR^US$8(NL#C@aXFs?-3yoiS^kQP4#d7)F0+AwXvyeVhm&7|UhR zMIFP!KYLvit%e|FedP=m!2l@gwNSlUUD82SUIz^6wX@8J_~5ulTMAv*L3bHBi1Jj- zjN2sd5Z>IZ<-V|*JabKh|2u+DhHMh78ltS^`YuoZLc|&|yxqFcE`;*ZVXbvgHQ|dq zOz}Am9$1&KjV)|%{hrE2?-#|^Q+jyP?=>=%P}z%e7m6x*u7zgQ4FCpdXGN@cR;Xi>!^*@1z>47z4Y!3f< z!BC0|wV@gVj!`^0DWlqi3H?a2FZ|rUDQ2lD{Nl@wo#dmLOM!}r7}e-c`<6)ueuxnI zG1_*Q{00wrjVT8jK>kPcaMFdH2!dJCQ{Df@iX{J^s=6$U7n ztu-l;ICanH;S&$05mu9VLQFp3%X~k9N;;R)He4yybk=kdgcdP^1sNRKkGA0waJLOe zi-l!HBwA*y9p4m!4^leUVclhkzuOB3YW_^u7k6%x3n|-)%DNMivKW-~3MVEO3SZc? zyJ6X~uAhrA90b!eqgp<^**OPY9LHv0`d+63$ znYNeZeuIs-H<7)lm(sgmYH%9exk1S81LTm%*tb`ss#W;KRe3{J>Hgo?MDo#8jiaQ^ zH^@rODu#bTmUa#Bj<-!4ICZ41>?2le8Q$y9`yfQ)Gy6wUqPPKXIb0faP->%i8)F9j z+~J0VBr*+G$T1sXK|62Y5u}Yc)hQ<*kDMxJM0Dd2ML4SJgNss5Ok8diw!M%E1zfNw zap&s2@L)4?STkai-(PDl11=4?p|3G)=f8i$ZK%znXcK8)#v+ru%B6c8ae1!;QRwVo z5Oqo`84`6ahZ`%J-_^Lx1C(n85`&o@nO|OBQU#@n1$=n3p5z4goWxXI;z&2Vi&zw0 zuJI?^+86)J)5x5gRtW{-h@rxniTYH_k=4-zH$`nbsaSY1LsTEKPbM+?UqcRd(H_q z-Nvkq8ja8Rn;-B3J}u;*mr`cmca=#z^)4u{C-0%v*}E^7ACAW<&3;1zvB&pknqh@L zqW3QESPQM)Ro>i@euQ{BI`Aln?zO+T2t4Nn?j4ORgs&srqhYfM@Y_}MG2u9K7aL0j zzq>xXKRVy9A^*v--+*=JP{l&vI7V;5ZmjgK91PLP{rLPG?fkb`S^XWRK&=UcdjDIc zh~fYMK>ijhiXsBSG9tf??qrP(2P`&3?-jMY@uT(2kRl052jq`2G!6wyNv#A#vX3}I zcHo3M6EGybkkrpGzEQrG6J~lLMTd$8xRz0jypFllh0;E<^Qm!@m-FSfVYlWSA1=&T zIoTX;2|Sh6;Nhgb!^5r(J%1Ry*_vl>6Ghgp#>b+Q3S_)&yG_gU2v! znKmx%P&{!w1F@7jNW_(n7N|=65op|N{QQ6*i>bfGNX7lQpT&$}~IiGA?^3wR= zqRHXW`Yf^5xbDSoib>fzW4&JeHKo!_pI$fD^7*!VYi?07q|`PR-C|e6#bR`C&4R0~ zXtTU~nZ13WtHI08+AM;>4wy=qQ2U|x zCzbskmSMfDm=;D(zNt+glCG1%qCK0J7PYy4N>XO8r6`~@>4?6jzAUxIj%}GKI6kYY z{kl47tQ)={HRi#)=(>)8c#zJj(8e{@Ro6IkCxSXG&%O6% z3Ks>Kivs#r;MgnW8rN~<$q?{jDzKcK5y?Z*R$aigImiSVw`Vj~GZjvD%50Y8tV_l^ zU%OV)E*>s7DT>b^sGz?J``m~^%`8gbu;W@BVg!f#r}#@yg$j2DQcmVA^FHAu?eV}8 z*MH<|0dJ$4da?eQBoo!<#D>m!HYhf{wMuy#RlBj~iAHWuMU?e*Q5-3lKlB^FkoxOf zLPBRHs?s9!A>Y0dp}AhkENvfIFRQC5sFz%D(iS6rI?hfpo?uNq7iB;Trfl?uvSM#qsfxc4^D74MHWRbp~ycKm!k_3 z8lTI2lv>9fF!$20T*FXo6x8FR`(30~FlWqm1mM*Poj2>c;j=&;%rT?ZNVcbXQgNah z6(t6qhAfVEz{4rcqVaEWT#OBPXo4EIa9YYM>*l_Y7^I>Iu4G1p{k-76o$Y&jF)HOv zdp9~rsUgfMl;JstBrYh_Rmq{6gb8_4bzsjm4W~llKfgN8?E%TLq$-E2IB{+h4TF!F zxKDf*%b~(4A!_f`#{0}}dTKfqe&xU!%-I#LH5kRg9Lzm(m-|hil}NFg-#53Mg5i4| zl0^;lH~XX&4n%OCY6Rq#|7D|+kjVRy_0ubi^z@jrrp#DZwZVlzsyZnqQ|~Im=%`^D zeK!ean^0Nd+k@7VNN!V)5xc&L&koWTYF}k>4CgT(7{g0AVyEsH%t3U|7f#s0)ByDM zfL#H~vyu=FCny2K^S(7ZOC69?8`E*S@#_*5{&s;IRlJd|kff{wnB2{kp!qw!z@ap2 z+rU%IB>OMX?L9TDO(3(AgTJ+l_b@u~4}Xdh!u)7Qh;j+79+?!gMCg-Wu-mYHlq1?C zM8}9M+Jn3@$d$#I$d_kb9VPry_!b3ElKw|U3h+8E21cEE@yfD0`zdO=PI3>~3F~mbn03(OEQdN86r=gsWKiJr5`|53s!{ zOu(9Xl;}H`!_@Mq^iT7iC#K{@tb>wbiuKWeLmI412z*MGy`@I9ts!|76* z9!db;?k0iAd65`5Lj-}-Riqt@wgb7%(2YIVg`4^8zXgs9;o_zw~ zoPjl^#JV7%O4yY=dPv!=gQg*e%mhpxNm=s4Gu@+e8jR|B(9SNy zebv;dMP2vVLXgBPUb=jRoWn*j^@-YU=$IG-pARx=TeUy_?2uF3wfaBYi&>{4A&aP# zTt59yYAvROfLnI)9;&+qyzQSF+UXIk+rk*r2914qP!FgOtfpLzAOZ>M8`=|eeVkLC^a9oc#AXH4+DEbO*RoqDu#MBs5?1U|ZQF|@4k7rcnRijUQ;utt_=&Nl765RqQXy6xET)a*Nw5yLDvg&@ZnH22Z$hN}T+ z_-FCruzee|l9Gq;NFt36@l)W%%7k#O=6TQ3tE#;$U_&CUHd-`6t|CBbVjTY?#f3M(z_)Hb#d5w6ST_%B88O>uO*p)^5 z<}fTIu44UTc>q%C7EPeLd}^;6LTq;5qS(;<$cCzF8c2KQ#6U>|43aK3!- zcoSN}Ri{LmaV6p`=2D+Wpd(uZ5lk#d6-;-xG;p<0aB=qt4DA4V`J_u}mAxzM&m7pZ6NZP}$8u4_!L>5)@2tkj6U zgzQ_deRzkRdV89iRAG%>6g{?h5CS0wPT57$oEoeZH#kCY>9&b8#I+=9zFUjV!PDC0 zIDZGoflB5peQ$^@^U=4^^k=EkB8r9~GWG%8f=KwR++j1Tl8-gJha&W08QCLbc{W(xyr_}KM$(UkW7;#oQTOAAJ} z11KFkkppJT@#j47wd15HC(h7@Wn-Ow#*0s5v0IJLeBz_g(<7I-=s9KO$S_jSjqt`L z=#tS-b)j_<9KFl6?li>`1=;(v0!^>^MuH#91NQ}a1REAfbx<7(@TMcqR=QKfPwOkne-4%pX0Xi|L(tdehNwPf5jYw+_yi zHH&)US>@JI>13W+b1CSmnPQQRj&cL=Qhm`}bM39kmOhCO!0bMC@vgk4mnTHT_sM)J zkH}#OhhF% zpD`;EelyWrps-A51ZT`1IE2-m=C^B{q*GX;j14|MCH+bcA| z2`4Y5WEOo<=>YiFeBf;czt<9!R>18iHF=8ZdUQZYkTW?fK5M+f+Z`(6BKC48?uBoBSwNaI zhH%|INc@D4@00PBV)Y-N&HKBpvyga$Z3mPq*8Qo_?b{x+*0kk)l?TZXt@AHd_x(+n z6E%2`&J6Ia;xfmQG458Vjt&klx8r#^ZqJvp!!>EX60R?w=U=v$;Hd~M&W6b<_JowT zk2jRf)A2m3wJ!~v8_wr#=FMpA)XVFe3vGwE6JkM-|oq<(R}9_wE4 zT#x75V7<3|g>b*ObUCwJ2lx)q9hO!+3C;TSZ{2NnTlsiF$vUg-g~05w{yDtJRrk#a zXy@3g!CgIt%$E()Q*#W;#lxMT@_ttQ|4RGnxT>~p?TvJIN`sViBPm_d-QC?F-CY8b z(h^eAjf8ZAbVzqg3w+CSL*;nB``-61ev|lPJkJ_qjydMsd$XRQ+PM=pzCn=PQ}EUq z#aP7cE-vyFCUXD$s5eZRu`<(5u$3sOlkvAjzPH%YoA8+xjWa2r(VpQ?-a9y@Hj%=xc(G^V%2NO48fcrH!AzoTqcBLb~(F+ zKql?d{PZaL2 z%7~jQOspz3aKE@ZU76fvXnCC>k{A0mgYY;Lw4Y5?CujMeFg(vp$BygY$QJ}^NlaI6a4-Q+GYrj$%`!L%_)gP&&AQ}3FbuliZ+=KM# z`f7n-EX+)XTAIyRwq=@W)$xj!PT3Jknvk%FKqL~fy! z?pxWswajFV6R7r&QYv%Irmrb-VGTcEw=)^l5qEX+Bc)|OPrILS34CTd{rs@Ec_rVU zQXTiXzZANuL?Dwkx-_(*EYq`3QmQ)H2l40Tp3=3KH*?dxxmaY&CbCKiYe_chk>!VI zuqV8vB)jb#ak8aoOP0Smf?VhdY%rQi#?p|hNcB<8v&VA;4VS~C2{A(5j z+vKA}md`bOtmv%I!@srW=Qt4ae0()pf1H|BhEnOQu=$LDB%<)W-n3?5hd3p~K8eJx zK8M)%H-~C#Ou~mJk<^rL+Bg!TWx)zIsSKUV7{0=tt1CnC>D_2#T4&Brsm%H&f;_Jj zT%u%KAj2JP&h5Etdc<|PJ4i6qw;W&S(3ch^kjlPSDF`#Y$W%(d+iF6jZqTrBjpCF_ za1gPZta2i4Lwz|LBnVEZ>f0h_GDRyXe|`V9z5L|<0{{C--OEL2rvY=Sn%*aFh3G(0Os*4jtUIHY<0nwe*|ch=`tCT4`Idlg06R`u+5-vo>cjHuYKvH1yQH*u+N6$2^Jg+PJV}y)L+g z0=3H2`AwpF$@BX~j01B&^_kEwl_>3`#sooMSE?j@?_E|tVNqK>he%+LcU3@Io-jq( z&zeJf^X@n&=_;&xlS@suKN&%WP@2ktyK7I`LG;Lgp3+n}sU@%$7h~Jf!u3My@WkDk z2hAemq@>3*$1r(hchh67l@O5+!B|W*-N)+0t|KI-7!8iNhzR^kVGmR??+0(^u1zx$ z&DeL`wWBo*x|3T@JtadaFY?H=BkHG=vWQG zgWmczMV92p`SD=9;OW9yk?q{Wd|2ZcI;iYf5@waxt!w z58I0$2KJI&<^4zIL177R42yXNXdIFxgnNg*kejQ<>>JSg0rgfn0_??CD?WWMj==+leq*B2UAx&V}mM#jRgsraWOf$2J z;jv(RytX=mhU;e^_&{H_N%^uoZltQ_xNMhhBp8yXOdpi*aSm`>sdNZ+Mh4aP={K%r z+&){G+S0{zef*w((3myyB#jwpYPN$So8l(AWnNm}mJxFMRk+==x5x8E{Q!2P*1U&h z!~!$BC!&3x@)7A3#px>jz%vyngnp6q+%ZCCGh}Y;9+*f7 z7m78@6Ma`pJPS%Lo$p1q=Sd=vdDa6{&NNqB@MXKqZUqeoIia638KVRsiX!7Ezoii~ z3dxitzmuiZ>5be5!Qn8WSh`kAT_?ZbJ)a3AwreR!&sL=SBzQSH^G-@8gIeufje!iU zrT?u051lv`Eo&yqgTS;uS{{s%|FNSu*KJqou{xgQf}dB(fw@vOo}fu8-lTIkuamCv z8~=;DnWam%eXY010|d31=X|z(qrs|~)24GBBXI@nL9BB56%Ph zz;^kv<#%z=@Lcy+$i4fB^mPd5K8+I<=B$x8Yrq5SXWOlK*EO9A6>uhLG)5!AW5M33 zFnGQC8E8WlocFBB6xgBk_j{$SI#+X+HYE{vZxI9`9bZGs_cFOv;7zZrA7r+2QNbtP z!19U66XTE*ucicVTPY#7-`5t*z=)i3X)vpJTbE;;u8>Vbb*oI)?2F?R3t_pWdLtJ@gS@pr(CtYdixYl`mOw3c(W<|l;>S>%M>F?0^V?_ zEW_l}IC0y+vgeiKLFzX~3AG=qKWP<_9n;Un0L>=G#Jx*ww{W55^lgt7JQP51E`lJJ zd4I_-P)t)<5N$!evdlxLNvz-JJ|#I?uf*hx)|KR$vF-H@DW~@-BPbR3wbxC3#&*Qh z;@0nivMMev<3X|lo5(ccx7Z7aRh3$V=s3(;5YFXFfW5H)AJbF{w{6cd3v$!tur7iJSnXK}+2|`yo1)1jea$)*CtF-41$wFQ)?04W^ zlq_45O1j_F<(JCRAAQQ%B)u}3V*iK_Ve>r6#G?2hN#~Zu;-q4jo|`*iBqD$wA&5s6 z?piGdr_#l#7f02?ToY1{Q%q4M^Q8`$oDANFrBU=xS{!@JE=JEE;yE{Z4Ap|Ev}DVP zo7i&1TsNR>&`o>n-oNt3u_=D#io0zc9>(%T&HIx~(MKiArr!zX|UYeX}+Tl zXkq5HuoHySo^VZz2!M%~kWEm+G5{Hd^O3!7R1W5TQ zt57|B904>O$n-CeU5#Fh9NoJrT$^`fCJ$zjXUSV!6J{jBW~|DP`Nfs|C&m@h14yd1 zCWDQT){{N{_x81yYuBO@ob7M3!iU0~c_uzVRZ_h1&s3ZuYD2^1+1z87^)`V7< zUokyZ2@Q*6zhTr(pBt+bQiX^ za2s6OE7ZADx*a-`!$+zfqrAm7#_i^=#=89d4poA?`OEka=zY;RiDbc$p%3USu5da;Cct}j;zDj!^~h$lZuC|H~;;nGA* zPIX0d^1K)$rSI#hsg;$);I6TAUI=slI>Y)|bP!~)!#XVZVKQz%quQcqtT7It@*Q33g&35%_B_qzVvD7S9xl| zuTw=P^%*JOdSl&SH9jBZ>NbCgs)$o!+zp26D4zW!HCHg%R1%-3RCS6TL=T~_6W!6QR~ndl zoIhfg)U;#cS<7EqD&kh_rj5Og^B&in-`%FwDDMwu9Vn2QyuO`p=wUUFj30a2zvk>n z4#%c${H*i?H8h_l%OX}ZlutK^1Yyd%^wqjg3K1WoBt~JxHwKLzCc!Hii6IXb4J6!);z;mfLBZWGeNccT%xg6D$CD(D{NhU89L4H`QkPOc`)W&&w zYqo{VZd~!gDQ7u#baErQiC^2$@Fbkio@YdD6)e@0W=O=-4da_O`f#;FfO#1?LSJ#k zB0@+ykPP1JA78!zaoN8_$eeUIv!+7sM}6g62_f<}uvY3W*spq$QckMDVMttrj6h_N zr6DVlG>-Yz0BdXL*92sAT6QquZtvxGa`u$S{#ksZ;@D)^eJn2H?_sIJ@#*RMbwT7a zXmTuIP-!q?VI0*aNO5c*UnX7*$ss{tU9>xRm>9HG+SP5~xl`=8ycI2LO@&NS?9EK1 zZ%@sp_T%KA!Y3Elo(4>W2IC z_nNewPLu>jDrRB`b2auJb=urvZC^By+CpHl+&tzC$FVrj5;`s~eU3~a?BA(TL0X-1 zOqm;8D;yr`RO3uT0sb$eCD@4RtU?IITlNsA)ysr5|WhcNr zuOa{5ZZFjbj0v=r*Eq9|rRJ+k_a&%$?vl2-t=((H04ou5$CB#HkcBP!WFBPNOmGmZ zzz|CM>ox1xnQxBt!GR|RZb8P$k+|fY(PkEBNl!9;{hNK^Zg>M7Z8*(z#d%u4%^sz9 zhIPXZX=i7SR!6@mL*%~Edfgmu(uE^G*mPmFzbvS9q&D@$B0?dLO2ITVYG@)dW+Hdq zir|36H#+~N%Hh?n4Dc`Lbku8CTd}DU2HW=S1A<^E+s*!JC>K#+(uMn0<$EbxlJXoP;gEaB%&zlq)4$8p#ZZU|pV^KQR9i1Gz(*d>JTbxjgy4G+G(%@L z4<8HH(xnp{Z{gQcK|V$1(mzP<5>*Q+b%niT$RMz~OXvs|IdB}z?-} zwu_c~D4Q9*i_v2EEKCYb+Y77R)%fhjp<_{DNbaam@&v|6ki|eCvT^F(!S~QOiSYA^ zKXVoZbULo{8J8c$ZNf#;Eh}5g=<3YVimc_Fv_^BnXJry|(h(8tq|oiFR^ zct-J+lHVKjPs7KSGr3uNlVR@5azribd*;7Kr*>UiAjgT>B_OShE(xhbmOQM&+!An; zq~!1Y+DV<%fe()YTM?-93ST{M6vVxqRzgzt2HbcS#i0Z!8W}66S#?(T5l|1v>*Kcfac3rq~R`Azy0j ze8*4TiKRiP4x@iyb#$CAI@3LVSvE2pn{6gRD0rAeKrn5a2)(l?rQ4UEF*32c$52C2 zQDc%nJ-s%O;R>~<_$1I^xXFvs1MbFGh|)olo0msDO)UG=MCz@x{J^S$M!N^gRkU0O#5`0DplU*uzxV zV1*kd!Znk=o6`-lS!4}Z}NLZUx_wJJbMOl6cu`I zM3|&Mh()W6IEa))eltL8UT(f78gKhL-F9>D+HUK8en518cl!W$zgEZp{Y3Qv@B6(f z|9639YyV}Kh1hLfBLjP)QNyxVw`l2_Ir=IKeUfk7k?&s9e0{hTr^q_cS+>2tyysaZ zKm^a-NjIZENg-ctuH<+S8fvAyr5Uj!A{4ZL{=TuFB|L|d=1S;{Mz*+2Zsv1+&zmNC zl*DHwlA}64coPN2_}!}}a^72%!!Qpd_rgop>iDj=3ZBmozavaA!n=NtYd&LHR)uui zqU>J_Xzo{Bx-P2AJ^bEfuh4z!Fj{Gu?74_dwH1R@{>&>O!I-uj-kSS{j(14QC?7v_ z%awTja|+VHT6%2lDsu z$^CLIepAqM;GE9_ilnWsQsidp$nfZ^@KK z;me3}S!qa{2X(>F=?Ab*S~-Q-eDV#ovRE~o^wF1dT3AwzBMu!sBaya!O-}QqH;>cJ zkZUtx`YwC`%Y%IEqxJ{N`EKulc^x!GD#15tq8XM**L~wo2<{BFG(zTwnxPVZ}x3(Zy)>EMa zqVxRd`5|Py&afy^h&W{WdTMVrVlL&U@-ooZSWV1pSyBWitF+$m)Aiuyje5;zgxO*b z54tcb$1-3HyVnbIhI9lJRS|qPBnvp$7bo4r`RJa8?G&+^K>tKcZ_)AkE57m?XEf07 zj<16%{8ZwpKE`!qLGuftZ9;^1jgg}}ij|ae1NyJxMyZT;-Yu2&1is^jqvTfDmk%nO zlJZEXiZ=7L(;~@|ObXM@e)S=x-cjF%JFHt&9+~arY}p0IbmROpT`Gy_H%ycmBdzI= zF42{OBq0`0N znRFAjx++{IK4Yv#YQh%s^jJMlI}&Xc`@@@4AAzVa+9_gb9yT3M_>SA0bU z$|PEtyg8PL%I{T`q_%j!E}vSXBtu&$uXV0}C8{WoLE4>8ma={Ro)UN^j^1f!9V&)V zrqa>JZPSk4lF07QPp(XwS$$mJp!$}9{&P-&<{=<%Qw%)|>C@R}CnX*-t zN3v?67*Urt3_2~7nXglVP;&#}--sn-3#D7Y)H-L$FT^qCGJe=y^%|rXb&GVFv}cE3 zys=S086bgFAm5v&qCHSS6UC&t%YGuopc%U;xiUBuaT{>)4Ve=CI(HsBMnvYp_q=J^ zE_oA6kPJ^N=^6Z4`UGadH`r&YX3}B#a=<&6(8C6E(F(3`xISS!8@wUtOIl5}yim>} zorl4yNecUF99_e=YqqoZ;t*_`A=&j+CQ|jlknqS1nks zn}SfZiceaIL)BE9y3#+Pgs9t8;m{t574;dB!Tb3TLDr>O)X*vBOtmAoT}OYP@r=o| z-Kx}tUS8Q;C=0Ni4|b~FpZ22}Afel~NGw`(@spH5U!23+=#~4VSp(j;7sJX%rB!0Z z{A9|urEEr5n;Vuh|ZefWpul1=|CfZ%ck(Hdg za5i||IdX_MS2eg+{1g){P1$q(i;gEb1eBsKK8+KW&$gd77Qiv#>N)4Wr$$xlAl#o` zPZKgjD>+#NUY>F^nWD>al+lpziDNtTk6Dylkhq(M!AgK8&)4ki!GUHsQ-KLn}h{!V|LYHAPup>K+t^ zZ?GIbeT06xeIWgQ043FdK*`O*5n+%8B>0zYZDbg1p#76s;Z1KN|FAFjMIa(Ikxw#r zPKh?CHfyZtE1K7{AgMj@48?9^c8_4H0bTN&;Wt?lMD4dtI@f>@Ty=2G4N-rhRGo!YQv3OtE^@5{;4Fl+o1@3 zg#^RLOii+N$p#)Ai>dDhJK&V;!@fS>Y;qk6^GwNwVY<06Z}0FNrDuQAsCL-Ud1zBj z`SKoyc;)<~Xy2iz27~xG2Uh~?tI)3XZWDvq){YG6tnLOy6iY*eGQ zn>Z>La7pHpWmM7h@7(dv6<*5Yf;T)p2&HiyGAs9Wb`Wd+QY&6s&oNW@O2IjsM5;&l z*)xu3Hj{^VnCol@ytCpr?Ax*jQgYF-sZ^k$zOF^$+e!~CiPRb58Cw`qsKl?rivG?5 z0{5}oOqHXC+_wFT+e~Cqt@NRNEGF1~tH>_<5MJ`qf{GPgbj@ZC3bdkc*gWQv9nAFm zSFjEHD^A#RKKP!PTn-22^o?`kS9OSHzTB95>7w5$|Mhi(pO4flKIaOhtyO!xzCDs{ zNtaPiPSmLUp6U4S?Dffr*~@d&%C`zn_jGc3ss#{JxQgCiA)CIw&zw0L7}GyRT{G@| z5%|H9gR59gKP5*(Hj(yJtU$DQDStpgmcMp3rF%y-RSc~<;T}Q+>-y8{Q8{jC^Ku$W zcwBicJ|2OhY<4bLM7GT4fx(N-^D%M$A{WUMZ1g=?lulF)`;E%|5Z5j}E!+WEEXcro zRh@!ih3oe!TJ^H43mW#2Zeqz*tIeMh1Ke0bbxolaD}kUFpnz9W2Wvw4wA2q~1CJ>#pjHu~c8{y4QH$^IA&;}Zpq zd*q+bnP>ye4dUSAl~18TAUEJSlOM85PR5Q-x-QIIx{QoJB&xosYXV(5vAjphlb^uH zE{#{Ot0AqHC~_`U!%W#Mnv8idA{Yr1N+`a;cQG;3Wc#-KdKlp-2fs+hmrn1~`mt6U zR~>E`>)U?DGPbX6De=^2%($Ilnp~rzVZCm)Ixu2ay-OL|>344T?@A?ij|Dz#6UW0L zz2{j`hgh*~973V~3g!Kk8baC+%CY@zC8N-j>X-e5w{)~2;_zf>i)6|uC*(9}7!J>l zUf#iM>J-oW!rt9q3a(Qdb$k1A>d9wgv_61vsciCYiWuGXy%BL@){fxC%ff{!)+?OY7a`{Hg4bwILUYM~8xwa+_33?I*}Iylgg`Y6_N`sPGZG60 z8jDBc<^z9qvy-;@4mv_oWj#A5xaFO-&Bz~ zb?6R;(=rR1L~b?2BlE=|cq8NRtfSy|U^vjBk#iaw&hRf8#xSViYGgN`Gc>3NdKOEG z*6KPQe)P#u83emkqO0=Zc`=U36939?5xxoqm;P<_a|+XMD&ysR2QBU&EpXw?qoXJ2 z<*u%WiMv2!>1$8sW+4h_~K?nJYY;iN&QI#$mRiU&S}&U#z3?4oA)}e8hR0o z5|G-&Q!ZNPK3!$Xsi;6*?#FN4>s+#!>wlCpaqozvVI(D9X$ZawjAEo66BwmLbQBPX za2I7-(w?rAlaIjyhgZTKKkO7^3?1p$*Mmz`S8TL1@Sp+j$4=m5CV74cPNBV;)e`as zsYBT$jEb!rc61NS9K|SSTVr2>WFJ zob`Oaxreohm~5*IJkD6@XjmdO?qa#L*Pwdz!`ZkcH1kv^ep`~XQZen*+vuoS*m z7LZCA;c>rCz+h6^s4jwDik);Z3g!20$v^NBO#R%-VD1H?naH+vqahT~?{X*YgtQuW z0fVMW;%;rDouw+nw(j%r>pFRhrXyUZy+S%7!ftvokP3&55Vro2ZuQ+c8hn^(sS|SV z)?#3d_lU!QfTV3r`>Os zzRSp{;5=__<+&($?O7jj%|P^o42zY2k%yc5$4d{?aNbIvgYF4wzj{QY8nGI_i`oz3 zHq5&G)t(fK$j}juX|^ZQCi?bjnO_t)ul-FON7;|lqi(6+;cMr}N9SpcRpUz~N$?m9 zn{eh;B}W*|rYff-@~_v@R3fmgXncQftU(sOq-8TpPk%+!2hcSuF1qoc^t zVRvRuZ*+K1&ztT(@yWI-P49&Bdh6^TPJMJCEFEAPorrZ5nGSZ&1(XbjK5tm}y4*UO zGzARS(YcQ}eA2dXV-6@T7108xxDwO84WWlSjnmEu_jLI{JVnCt zEgO@-{gV0KgYZ}GtuleTG=?2M)Byp;ML##;*vM;f>X`6gUN zRjP76PvoS)o?w75fTI8i6a}c}{PoL!egjna9$os5j>dqbrIEgarLKv-p_8qHyB6@% z+zJqNGLp()t?dA}c0LIzBv0?+Axc;xKF8{y^?}Jn(40y#443Xb_)r9)DS)H66Y;I$a)54a|0dZ#&0N*poY0TuK>s%~ zF1&x2>>o2z=u{7d7$EwQoxg{%5C7jL`zOzeU$THy0c~9cVDSAmXQDva{~y9=t#4>% zZUYp2eP<_IT}MNG8yjN>T^43HR?a_FQ1%$_YJMOWUjT#SH?C{af1S(N)D+lr9IXGL zl#rR$n~wmI>j#FwZzNIV|2he<|2XSg{m(94a+N1B159+lVEv7)k@A1RX72V^-2N0a zW+AD>Odw#Xe+wEP&A-mzXy#ySWb}_D+-%bmazF-1{VfZaY5zwOXQvDAt=CU;aT3s4i8S5H4=sW$X#Q*4& z>B*shyaq5V0ps_4`^5AwGdURB>6<$M`S6E)`$1CrPy%-jxN;1P-!tHf`F|vFF*Y*? zyl~WVa&R`Z{6oNgFklUd<5dCZWxyc(Enxg?|IJ`-4QLuVY60sJz%enl*0(Z#9Q+?x zer0F;KZMEsfB_VfUoLteLjSqkf5ZAGq)uFYV;=y;0~kP;%wMiUKm+i1Bs*JMyT^B9 z030#{C>&(QCBQ&%A`pK`GyVk0egOg*nL9dZnd)2rkZSz(Fc#G`pmk0Y<;D9P1X?Tt zfq)ajFIPq&7|7AV@K1))fT6!S8)P%E+o}tLKU9Jl`q!sYWX z_Qp0&f1RZtA^e!b7j>;udcfiD1+dTI{+IDzKi`i1f?(=kZY1Jnr*GqEZfo-g7+JX0 zmv4aeehSF3|LzF=%r7w3`gUT*kL^_r2er%x9J-Ey5Sjpy{GoII^E#RT#r{W2+Q)H} zX&lgs!IP4V2i}2H1Gs+(!~eWcfTi?f2LGA}Cu6rCF9Lp@{~s|hck5dEQLKD{R}{aK zk6!*_{i8HFJ~EdFvOv~)ku6&k1bUzad*r+1?SGg%7z3K)4q8SI`mT@cM*x|gEJ<%w zTLECvKLrB;2Y_F$r-D!Zx_QUH`osRG>i>T?i+$`y*3+$rD&VPB-HgY{(Bc0(j-kGT z(PK}NfLXY?1lJIt0)bY`K#%UEpzsmGkJ9kRJGlX-Bkf*JUIJzeD^uM#uyEJg|E`at9SOsMQg6Nj(7x z0@VV`^!EzqbN)My8BnQ!m%xuOjDUNwjfsy3)aXGBe+x^KaEeoe@nJscHl?%^5Z@K58rme6M)cq0o&~Fl?N63cN{xgS7V1q2pT|= zw7lFqUI(@y3g5>OnI`)k!NC?-dNz;i-#M^!0%eY3Sb-%gEcbXfI}-dI!_n9ZND`oU z{V{2OB;4ax*gx|{SLqQJP=y}n%AcA%|3v6f{vF|$me0TD?4LS*`~-Qh1VA45|M=DX zPpvV2nqyjn|I#SqSGzy8#`tOX3b1?BDC1Y-Kebr+X)I_94*J<};a9sqsVV=oi*W`2 zOPjj9?@Si$qznc9?H{hq4avU%>|E(hMtKFYI hAp2>TR}235<1#rZNTBS2K)gS`fGx4J71)|U{|^RBTS))_ literal 0 HcmV?d00001 diff --git a/dist/game.js b/dist/game.js index a4d13f9..c28eb51 100644 --- a/dist/game.js +++ b/dist/game.js @@ -1,52 +1,68 @@ -var V={version:"v28.21 BOOST DRAW HOTFIX",time:{daySeconds:60,farmShutdownGraceSeconds:10},cash:{starting:250},grid:{x:170,y:78,cols:20,rows:10,cell:46,expansion:{colsPerPurchase:10,rowsPerPurchase:10,costBase:850,costGrowthRate:.75,truncateUnit:50}},map:{blockedRatio:0,blockedExpansionIncrement:.0075,blockedRatioMax:.12},economy:{income:{mixer:5,truck:10,sausage:26},poopFine:10,fairiesTribute:{perDay:10,profitExemption:300,legalWorkExemptionBonus:250,profitRate:.12},incomeUpgradeRate:1.1,explosionDamageDivisor:30,maleTruckFinePerHalfDay:30,shredderBonus:{maxCards:30,payoutCoefficient:1.6,payoutExponent:1.25,baseHitChance:.28,hitChancePerUpgrade:.018,maxHitChance:.82,jackpotBaseChance:.01,jackpotChancePerUpgrade:.0025,jackpotMaxChance:.08,bigWinBaseChance:.07,bigWinChancePerUpgrade:.0015,bigWinMaxChance:.12,doubleChance:.2,jackpotMultiplier:10,bigWinMultiplier:4,doubleMultiplier:2},chemicalWeaponSubsidy:{poopPerBlock:70,yenPerBlock:1200}},production:{poopRate:.08,autoScannerCooldown:1.5,autoScannerUpgradeRate:.95,autoScannerCardUpgradeRate:.95,autoScannerMinCooldown:.5,poopRateCardBonus:.04,eggSpawnRanges:[[1.95,4.35],[1.55,3.45],[1.25,2.8],[1.05,2.35]]},conveyor:{baseSpeed:52,maxSpeed:300,bearingSpeedMultiplier:1.075},effects:{explosionHorizontalVelocityMultiplier:.82},cards:{definitions:[{id:"upgradeEgg",title:"EGG Improvement",rarity:"common",type:"equipmentUpgrade",target:"eggFarm",description:"Choose one EGG FARM on the map and raise it by 1 level.",tags:["EGG","ACTIVE"]},{id:"upgradeAutoScanner",title:"AUTO SCANNER Improvement",rarity:"common",type:"equipmentUpgrade",target:"autoScanner",description:"Choose one AUTO SCANNER on the map and raise it by 1 level.",tags:["SCANNER","ACTIVE"]},{id:"autoScannerTuning",title:"AUTO SCANNER Tuning",rarity:"common",type:"instant",description:"All AUTO SCANNER cooldowns use default cooldown x0.95 per copy.",requiresFacility:"autoScanner",tags:["SCANNER","PASSIVE"]},{id:"upgradeMixer",title:"MIXER Improvement",rarity:"common",type:"equipmentUpgrade",target:"mixer",description:"Choose one MIXER. Each level improves meat quality and raises sausage sale value by 10%.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeTruck",title:"TRUCK Improvement",rarity:"common",type:"equipmentUpgrade",target:"truck",description:"Choose TRUCK on the map and raise it by 1 level.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeSausageMaker",title:"SAUSAGE MACHINE Improvement",rarity:"common",type:"equipmentUpgrade",target:"sausageMaker",description:"Choose one SAUSAGE MACHINE. Each level raises sausage sale value by 10%.",tags:["ECONOMY","SAUSAGE","ACTIVE"]},{id:"upgradeTrash",title:"SHREDDER Improvement",rarity:"common",type:"equipmentUpgrade",target:"trash",description:"Adds a nonlinear scrap-lottery upgrade. More copies raise both payout and win chance; max 30.",tags:["POOP","ACTIVE"]},{id:"crowdedFarming",title:"Crowded Farming",rarity:"common",type:"instant",description:"EGG production interval -5%. Equipment deterioration +4%. Max 10 cards.",requiresFacility:"eggFarm",tags:["EGG","RISK","PASSIVE"]},{id:"hatchingFeed",title:"Hatching Feed",rarity:"common",type:"instant",description:"EGG production interval -4%. Poop rate +3%. No card limit.",requiresFacility:"eggFarm",tags:["EGG","POOP","PASSIVE"]},{id:"poopRateBooster",title:"Poop Culture",rarity:"common",type:"instant",description:"Base poop rate +4 percentage points. No card limit.",tags:["POOP","PASSIVE"]},{id:"safetyCover",title:"Safety Cover",rarity:"common",type:"instant",description:"Explosion damage -5%. No card limit.",tags:["RISK","PASSIVE"]},{id:"preventiveMaintenance",title:"Preventive Maintenance Manual",rarity:"common",type:"instant",description:"All equipment deterioration speed -5%. No card limit.",requiresAnyFacility:["conveyor","eggFarm","autoScanner","manualScanner","mixer","trash","sausageMaker"],tags:["MAINTENANCE","PASSIVE"]},{id:"dudFilter",title:"DUD Filter",rarity:"common",type:"instant",description:"DUD chance -5 percentage points. Stacks until DUD chance reaches 0%.",tags:["CARD","PASSIVE"]},{id:"durabilityCoating",title:"Durability Coating",rarity:"common",type:"instant",description:"All equipment maximum durability +3%. No card limit.",requiresAnyFacility:["conveyor","eggFarm","autoScanner","manualScanner","mixer","trash","sausageMaker"],tags:["MAINTENANCE","PASSIVE"]},{id:"bearing",title:"High-Quality Bearing",rarity:"common",type:"instant",description:"Conveyor speed +7.5%.",requiresFacility:"conveyor",tags:["CONVEYOR","PASSIVE"]},{id:"sparePartsBin",title:"SPARE PARTS BIN",rarity:"common",type:"instant",description:"Restores 2% durability to every machine. A box of almost-compatible parts.",requiresAnyFacility:["conveyor","eggFarm","autoScanner","manualScanner","mixer","trash","sausageMaker"],tags:["MAINTENANCE","ACTIVE"]},{id:"dudRefund",title:"DUD REFUND",rarity:"common",type:"instant",description:"DUDs now come with paperwork. Gain JPY 50 per copy when you pick a DUD.",tags:["CARD","ECONOMY","PASSIVE"]},{id:"freeReroll",title:"FREE REROLL",rarity:"common",type:"instant",description:"The first bad ideas are free.",tags:["CARD","PASSIVE"]},{id:"composter",title:"COMPOSTER",rarity:"common",type:"instant",description:"Turns shredder waste into suspicious fertilizer. Gain JPY 3 per copy when SHREDDER processes poop.",requiresFacility:"trash",tags:["POOP","ECONOMY","PASSIVE"]},{id:"scannerQueueSpacing",title:"Scanner Queue Spacing",rarity:"common",type:"instant",description:"Manual and Auto Scanner queue spacing -15%. No card limit.",requiresAnyFacility:["manualScanner","autoScanner"],tags:["SCANNER","PASSIVE"]},{id:"extraEggOutlet",title:"Extra Egg Outlet",rarity:"rare",type:"equipmentUpgrade",target:"eggOutlet",description:"Choose one EGG FARM and add +1 output port to that EGG. Max +3 per EGG.",tags:["EGG","RARE","ACTIVE"]},{id:"recyclingSubsidy",title:"Recycling Subsidy",rarity:"rare",type:"instant",description:"SELL refund rate +10 points. Max 3 cards; normal SELL can reach 80%.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"dynamite",title:"Dynamite",rarity:"rare",type:"cellAction",target:"blockedCell",description:"Choose and remove up to 3 unbuildable cells.",tags:["RISK","RARE","ONE-SHOT"]},{id:"usedMachine",title:"Used Machines",rarity:"rare",type:"instant",description:"Future equipment costs half. New purchases have no refund and 60% durability. New Machines cancels it.",tags:["ECONOMY","RISK","RARE"]},{id:"newMachine",title:"New Machines",rarity:"common",type:"instant",description:"Cancel Used Machines and restore normal prices, refunds, and durability.",tags:["ECONOMY","ONE-SHOT"]},{id:"flattery",title:"Flattery",rarity:"rare",type:"instant",description:"Next Fairies tribute -50%.",tags:["ECONOMY","RARE","ONE-SHOT"]},{id:"extraCards",title:"Extra Cards",rarity:"rare",type:"instant",description:"Draw 2 cards now and choose both.",tags:["RARE","ACTIVE"]},{id:"legalWork",title:"Legal Work",rarity:"rare",type:"instant",description:"Fairies tribute profit exemption +JPY 250.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"chemicalWeaponSubsidy",title:"Chemical Weapons Subsidy",rarity:"ultraRare",type:"instant",description:"Each day, gain JPY 1200 per 70 poop shipped by truck. No card limit.",tags:["POOP","ULTRA RARE","PASSIVE"]},{id:"laborExploitation",title:"Motivational Exploitation",rarity:"ultraRare",type:"instant",description:"Repair room work time -30%. The repairman smiles with bloodshot eyes. One time only.",tags:["MAINTENANCE","ULTRA RARE","PASSIVE"]},{id:"rescueLoan",title:"Emergency Loan",rarity:"ultraRare",type:"instant",description:"If cash is below JPY 0 at day-end settlement, gain JPY 500. Consumed on use.",tags:["ECONOMY","ULTRA RARE","ONE-SHOT"]}],defaultEffects:{bearing:0,legalWork:0,fairiesFlatteryNext:0,autoScannerTuning:0,poopRateBooster:0,crowdedFarming:0,hatchingFeed:0,safetyCover:0,recyclingSubsidy:0,chemicalWeaponSubsidy:0,preventiveMaintenance:0,dudFilter:0,durabilityCoating:0,sparePartsBin:0,dudRefund:0,freeReroll:0,composter:0,scannerQueueSpacing:0,laborExploitation:0,usedMachineActive:!1,rescueLoanCharges:0},commonWeight:8,rareWeight:2,ultraRareWeight:.45,baseDraftSize:3,maxDudsPerDraft:2,dudChancePerCard:.3,dudChanceReductionPerFilter:.05,extraCardsAddedPicks:2,rerollCost:{dayDivisor:2,multiplier:100}},events:{eventChance:.1,firstTurn:8},maintenance:{fullPerformanceUntilWear:.5,minimumPerformance:.5,durability:{conveyor:1300,eggFarm:475,autoScanner:850,mixer:775,trash:950,sausageMaker:825},processingDelayMaxSeconds:{mixer:1.2,trash:1,sausageMaker:.9},repairman:{secondsPerOnePercent:.5,walkSpeed:90}},facilities:{conveyor:{id:"conveyor",type:"conveyor",name:"Conveyor",shortName:"Belt",price:30,buildable:!0,upgradeable:!1},boostConveyor:{id:"boostConveyor",type:"conveyor",name:"Boost Conveyor",shortName:"BOOST BELT",price:75,buildable:!0,upgradeable:!1,speedMultiplier:2},eggFarm:{id:"eggFarm",type:"eggFarm",name:"Egg Farm",shortName:"EGG",price:250,buildable:!0,upgradeable:!0,maxLevel:4},manualScanner:{id:"manualScanner",type:"scanner",kind:"manual",name:"Manual Scanner",shortName:"Manual Scanner",price:260,buildable:!0,upgradeable:!1},autoScanner:{id:"autoScanner",type:"scanner",kind:"auto",name:"Auto Scanner",shortName:"Auto Scanner",price:180,buildable:!0,upgradeable:!1},mixer:{id:"mixer",type:"facility",name:"Mixer",shortName:"MIXER",price:450,buildable:!0,upgradeable:!0,incomeKey:"mixer",body:{w:164,h:126}},trash:{id:"trash",type:"facility",name:"Waste Shredder",shortName:"SHREDDER",price:240,buildable:!0,upgradeable:!0,body:{w:180,h:100}},truck:{id:"truck",type:"facility",name:"Truck",shortName:"TRUCK",price:450,buildable:!0,upgradeable:!0,incomeKey:"truck",body:{w:176,h:138}},sausageMaker:{id:"sausageMaker",type:"facility",name:"Sausage Machine",shortName:"SAUSAGE",price:380,buildable:!0,upgradeable:!0,incomeKey:"sausage",footprint:{cols:3,rows:3},body:{w:138,h:138},outputProduct:"sausage"},maintenanceRoom:{id:"maintenanceRoom",type:"maintenanceRoom",name:"Maintenance Room",shortName:"REPAIR ROOM",price:220,buildable:!0,upgradeable:!1,footprint:{cols:2,rows:2}}}};var si=V.version,Gt=V.time.daySeconds,Rn=V.cash.starting,xe=V.economy,ai=V.time.farmShutdownGraceSeconds,Qn=V.production.autoScannerCooldown,li=V.production.autoScannerUpgradeRate,Yo=V.production.autoScannerCardUpgradeRate||V.production.autoScannerUpgradeRate,Vo=V.production.autoScannerMinCooldown,ci=V.events.eventChance,Pn=V.events.firstTurn,zo=V.production.poopRate,Xo=V.production.poopRateCardBonus||0,Jn=V.conveyor.baseSpeed,tn=V.conveyor.maxSpeed,Zn=V.conveyor.bearingSpeedMultiplier,Ue=V.cards,ui=V.cards.definitions,jo=V.cards.defaultEffects,Et=V.production.eggSpawnRanges,f=V.grid,Te=V.facilities,Qo=["conveyor","boostConveyor","eggFarm","autoScanner","manualScanner","mixer","trash","truck","sausageMaker","maintenanceRoom"],eo=["mixer","trash","truck"],to=["sausageMaker"],Jo=[...eo,...to],di=["mixer","trash","truck"],fi=["mixer","truck","sausageMaker"],Rt=Object.fromEntries(Object.entries(Te).map(([e,t])=>[e,t.price])),fe=[{name:"right",dc:1,dr:0,angle:0,opposite:"left"},{name:"left",dc:-1,dr:0,angle:Math.PI,opposite:"right"},{name:"down",dc:0,dr:1,angle:Math.PI/2,opposite:"up"},{name:"up",dc:0,dr:-1,angle:-Math.PI/2,opposite:"down"}],b={bg:"#111318",ink:"#090a0d",muted:"#8f9bab",green:"#7bd84f",greenSoft:"#273c24",mixerBlue:"#4aa3ff",truckPink:"#ffb33e",wasteGreen:"#88d35a",meatRed:"#d96b72",sausageOrange:"#d78b3f",danger:"#e34a36",warn:"#ffb827",white:"#e6edf2",poop:"#7b4a23",male:"#4aa3ff",female:"#ff6fae"},Ie={ambient:0,important:1,critical:2};function x(e){let t=Number(e)||0;return`${t<0?"-":""}\uFFE5${Math.ceil(Math.abs(t)).toLocaleString("ja-JP")}`}function I(e,t){return`${e},${t}`}function re(e){let[t,n]=String(e).split(",").map(Number);return{col:t,row:n}}function An(e,t,n){return Math.max(t,Math.min(n,e))}function z(e,t){return e+Math.random()*(t-e)}function $e(e,t){return e>=0&&e=0&&tMath.round(An(r,0,255)).toString(16).padStart(2,"0");return`#${o(e)}${o(t)}${o(n)}`}function In(e,t,n){let o=pi(e),r=pi(t);return Wa(Zo(o.r,r.r,n),Zo(o.g,r.g,n),Zo(o.b,r.b,n))}var ce={appTitle:"Chick Sorter",versionTitle:`Chick Sorter ${si}`,currency:"\uFFE5",phases:{title:"Title",build:"Build",running:"Sorting",clearing:"Clearing",loanDecision:"Emergency Loan",gameover:"Game Over"},actions:{startGame:"Start Game",nextDay:"Next Day",buildPhase:"Build Phase",restart:"Restart",close:"Close",remove:"Remove",refund:"Refund",autoMenu:"Auto Menu"},status:{build:e=>`BUILD: ${(e==="erase"?"SELL":e||"SELECT").toUpperCase()} | Right-drag pan | Hover equipment for info`,sorting:"Sorting: use scanner keys. Build after clearing the day.",allPortsConnected:"Start condition met: one EGG route reaches an exit.",equipmentPanelEmpty:"Hover equipment in Build phase."},routeLabels:{mixer:"MIXER",truck:"TRUCK",trash:"WASTE",sausageMaker:"SAUSAGE",scanner:"NEXT","scanner-role-1":"NEXT",input:"IN"},fail:{outOfGrid:"Out of grid",cellOccupied:"Cell occupied",notEnoughCash:"Not enough cash",facilityExists:"Facility already exists",facilityOverlap:"Facility overlap",nothingToErase:"Nothing to sell",noUpgrade:"No upgrade available"}};function Pt(e){return Te[e]?.name||String(e||"").replace(/^[a-z]/,t=>t.toUpperCase())}function Ha(e){let t=Te[e];return t?e==="conveyor"||e==="boostConveyor"?`${x(t.price)} / tile`:e==="autoScanner"?`${x(t.price)} / ${Qn.toFixed(1)}s cooldown`:e==="trash"?x(t.price):x(t.price):""}function Ka(e){return{conveyor:"A narrow green belt. Routes decide whether chicks live, ship, or become invoices.",boostConveyor:"Moves chicks twice as fast. Wears down like a normal belt.",eggFarm:"A tiny gatehouse producing questionable eggs on schedule.",autoScanner:"Processes about 40 items per day at Lv1, roughly 2.1 Lv1 farms.",manualScanner:"A manual checkpoint. The operator is the algorithm.",mixer:"Makes meat when OUT is clear; otherwise falls back to direct sale.",trash:"A polite shredder for poop and other regrets.",truck:"Ships target chicks and all sausages. Wrong live cargo still leaves a paper trail.",sausageMaker:"A 3\xD73 grid machine. Left inlet takes 2 meat; right outlet emits 1 sausage.",maintenanceRoom:"2\xD72 repair bay. Each room dispatches one repairman during the day."}[e]||""}function qa(e){return{conveyor:"./assets/dark_factory/facilities/conveyor/conveyor_straight_h_16.png",boostConveyor:"./assets/dark_factory/facilities/conveyor/boost_conveyor_straight_h_16.png",eggFarm:"./assets/dark_factory/facilities/machines/egg_farm_16.png?v=dark_factory",autoScanner:"./assets/dark_factory/facilities/machines/auto_scanner_32x48.png",manualScanner:"./assets/dark_factory/facilities/machines/manual_scanner_32x48.png",mixer:"./assets/dark_factory/facilities/machines/mixer_32.png",trash:"./assets/dark_factory/facilities/machines/shredder_32.png",truck:"./assets/dark_factory/facilities/vehicles/truck_32.png",sausageMaker:"./assets/dark_factory/facilities/machines/mixer_32.png",maintenanceRoom:"./assets/dark_factory/facilities/utility/maintenance_room_32.png"}[e]||""}function hi(e){let t=Ka(e),n=qa(e);return`${n?``:""}${Pt(e)}${Ha(e)}${t?`${t}`:""}`}function mi(e){return ce.routeLabels[e]||String(e).toUpperCase()}function bi(e){let t=2166136261;for(let n=0;n>>0}function vi(e){let t=e>>>0;return()=>{t+=1831565813;let n=Math.imul(t^t>>>15,1|t);return n^=n+Math.imul(n^n>>>7,61|n),((n^n>>>14)>>>0)/4294967296}}function wi(e,{base:t=0,increment:n=.0075,max:o=.12}={}){let r=Math.max(0,Math.floor(Number(e)||0));return Number(Math.min(o,t+r*n).toFixed(6))}function oo(){return`RUN-${Date.now().toString(36)}-${Math.floor(Math.random()*1e6).toString(36)}`.toUpperCase()}function Si({seed:e,targetRatio:t=.2,reserved:n=[]}={}){let o=vi(bi(e||oo())),r=new Set(n.map(c=>typeof c=="string"?c:I(c.col,c.row))),i=[];for(let c=0;c0;c-=1){let h=Math.floor(o()*(c+1));[i[c],i[h]]=[i[h],i[c]]}let a=Math.round(f.cols*f.rows*t+1e-9);return new Set(i.slice(0,Math.min(a,i.length)).map(c=>c.k))}function ki({seed:e,colStart:t=0,colEnd:n=f.cols,rowStart:o=0,rowEnd:r=f.rows,targetRatio:i=.2,reserved:a=[]}={}){let c=vi(bi(e||oo())),h=new Set(a.map(Z=>typeof Z=="string"?Z:I(Z.col,Z.row))),g=[],C=Math.max(0,Math.floor(t)),P=Math.max(C,Math.floor(n)),L=Math.max(0,Math.floor(o)),K=Math.max(L,Math.floor(r));for(let Z=L;Z0;Z-=1){let Q=Math.floor(c()*(Z+1));[g[Z],g[Q]]=[g[Q],g[Z]]}let j=Math.round((P-C)*(K-L)*i+1e-9);return new Set(g.slice(0,Math.min(j,g.length)).map(Z=>Z.k))}var nn=10,gi=2,Ci=1;function on(e,t){return`${e},${t}`}function Ya(e){let[t,n]=String(e).split(",").map(Number);return{chunkX:t,chunkY:n}}function ro(e){let t=V.grid.expansion||{},n=Math.max(1,(e.gridExpansionPurchases||0)+1),o=Math.max(0,Number(t.costBase)||850),r=Math.max(0,Number(t.costGrowthRate)||.75),i=o*(1+r*(n-1)),a=Math.max(1,t.truncateUnit||50);return Math.floor(i/a)*a}function Mi(e){e.ownedCells=new Set,e.ownedChunks=new Set,e.gridChunkOriginX=0,e.gridChunkOriginY=0,e.gridExpansionPurchases=0,e.gridExpansionPurchasesByDirection={left:0,right:0,up:0,down:0};for(let t=0;t=0&&t=0&&n{let a=(o[r.direction]??9)-(o[i.direction]??9);return a||(r.chunkY!==i.chunkY?r.chunkY-i.chunkY:r.chunkX-i.chunkX)})}function Ei(e,t="right"){let n=Ut(e);return n.find(o=>o.direction===t)||n[0]||null}function dt(e){return{x:f.x+e.colStart*f.cell,y:f.y+e.rowStart*f.cell,w:e.cols*f.cell,h:e.rows*f.cell}}function tr(e){let t=dt(e);return{x:t.x+t.w/2-116,y:t.y+t.h/2-36,w:232,h:72,cx:t.x+t.w/2,cy:t.y+t.h/2}}function Ri(e,t){let n=tr(e);return t.x>=n.x&&t.x<=n.x+n.w&&t.y>=n.y&&t.y<=n.y+n.h}function Pi(e){let t=[];for(let n=e.rowStart;n$e(t.col,t.row))}function el(e){return[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row}].filter(t=>$e(t.col,t.row))}function tl(e){return[{col:e.col,row:e.row+1},{col:e.col-1,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row-1}].filter(t=>$e(t.col,t.row))}function Oi(e){let t=new Set([...e.conveyorTiles]),n=o=>{o&&$e(o.col,o.row)&&t.add(I(o.col,o.row))};for(let o of e.scanners){for(let r of el(o))n(r);for(let r of Za(o))n(r)}for(let o of e.eggFarms){n(o);for(let r of tl(o))n(r)}for(let o of Object.values(e.facilities))n(o.entry);return t}function Di(e){let t=Xa.map(([n,o])=>({col:n,row:o}));for(let{col:n,row:o}of t)Bi(e,n,o);for(let n=0;n({...n,keys:n.keys?{left:{...n.keys.left},right:{...n.keys.right}}:null,queue:[]})),e.eggFarms=Qa.map(n=>{let o=Wt(n);return{...n,nextSpawn:o,lastInterval:o}});let t=Oi(e);e.blockedCells=Si({seed:e.runSeed,targetRatio:V.map.blockedRatio,reserved:[...t]}),nl(e),Di(e),e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function ft(e){return e?[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row}]:[]}function ge(e){let t=$(e.col,e.row);return{x:t.x+f.cell/2,y:t.y-f.cell/2}}function it(e,t,n){return e.eggFarms.find(o=>o.col===t&&o.row===n)||null}function st(e,t,n){return e.scanners.find(o=>ft(o).some(r=>r.col===t&&r.row===n))||null}function Ht(e,t){return e.scanners.find(n=>n.id===t)||null}function ar(e,t){return e.scanners.find(n=>n.kind==="manual"&&n.slot===t)||null}function sn(e){return e?.baseId||e?.id||""}function lr(e,t){return Object.entries(e.facilities||{}).filter(([,n])=>sn(n)===t)}function lo(e,t){return!!(t&&$e(t.col,t.row)&&(!e?.ownedCells?.size||e.ownedCells.has(I(t.col,t.row))))}function pt(e,t,n){return Object.values(e?.facilities||{}).find(o=>o?.gridPlaced?t>=o.col&&t=o.row&&n({col:e.col+t.dc,row:e.row+t.dr})).filter(t=>$e(t.col,t.row)):[]}function _i(e,t,n=[],o=[]){if(!t||!$e(t.col,t.row))return[];let r=[],i=a=>{!a||!$e(a.col,a.row)||!e.conveyorTiles.has(I(a.col,a.row))||n.some(c=>c&&no(a,c))||r.some(c=>no(c,a))||r.push({...a,viaTolerance:!no(a,t)})};i(t);for(let a of o)i(a);for(let a of Ni(t))i(a);return r}function sr(e,t,n=[],o=[]){let r=_i(e,t,n,o),i=r.filter(a=>!a.viaTolerance);return i.length?i:r}function ol(e,t){let n=Fe(t,"inputA");return!n||!$e(n.col,n.row)?[]:sr(e,n,ft(t))}function rl(e,t,n){let o=Fe(t,n);return _i(e,o,ft(t))}function il(e,t){let n=e.facilities[t]||lr(e,t)[0]?.[1];if(!n)return null;let o=nt(e,n);if(o)return $(o.col,o.row);let r=sn(n)||t;return r==="mixer"?{x:n.x+n.w,y:n.y+n.h*.52}:r==="truck"?{x:n.x,y:n.y+n.h*.52}:r==="trash"?{x:n.x+n.w/2,y:n.y+8}:{x:n.x+n.w/2,y:n.y+n.h/2}}function Gi(e,t,n){return n==="inputA"?ol(e,t).length>0:rl(e,t,n).length>0}function Me(e){e.branchCounters?.clear?.(),e.routeCache=null,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1,e.frameCache&&(e.frameCache.routingVersion=-1,e.frameCache.congestionFrame=-1,e.frameCache.draw={})}function We(e,t){return I(e,t)}function rn(e){return re(e)}function sl(e,t){let n=e.conveyorMeta?.get?.(t)||{},o=[];return Array.isArray(n.outDirs)&&o.push(...n.outDirs),n.dir&&o.push(n.dir),[...new Set(o)].filter(r=>fe.some(i=>i.name===r))}function Li(e,t,n){let o=fe.find(a=>a.name===n);if(!o)return!1;let r=e.conveyorMeta?.get?.(We(t.col+o.dc,t.row+o.dr));return r?[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))].includes(o.opposite):!1}function al(e,t){let n=rn(t),o=e.conveyorMeta?.get?.(t)||{},r=fe.filter(C=>e.conveyorTiles.has(We(n.col+C.dc,n.row+C.dr))).map(C=>C.name),i=sl(e,t).filter(C=>r.includes(C)),a=i.length?i:r;if(r.length===1&&(!i.length||i.includes(r[0]))&&Li(e,n,r[0]))return[];if(r.length<3)return a;let c=new Set(r.filter(C=>Li(e,n,C))),h=r.filter(C=>!c.has(C)),g=c.size?h:[...new Set(a)];return!g.length&&!c.size&&(g=r),o.branchMode&&o.branchMode!=="random"&&g.length>=2&&g.includes(o.branchMode)?[o.branchMode]:g}function ll(e){return{version:e.routingVersion||0,cells:new Set,adjacency:new Map,components:new Map,cellToComponent:new Map,scannerInputs:new Map,scannerPorts:new Map,facilityPorts:new Map,farmOutputs:new Map,pathCache:new Map,metrics:{conveyorCells:0,edges:0,components:0,deadEnds:0,crosses:0,scannerPorts:0,connectedScannerPorts:0,facilityPorts:0,connectedFacilityPorts:0,farmOutputs:0},issues:[]}}function cl(e){let t=ll(e);for(let o of e.conveyorTiles)t.cells.add(o),t.adjacency.set(o,[]);for(let o of t.cells){let r=rn(o),i=al(e,o),a=fe.filter(c=>i.includes(c.name));for(let c of a){let h=We(r.col+c.dc,r.row+c.dr);t.cells.has(h)&&t.adjacency.get(o).push({key:h,dir:c.name})}}let n=0;for(let[o,r]of t.adjacency.entries()){n+=r.length;let i=new Set(r.map(a=>a.dir));r.length===1&&(t.metrics.deadEnds+=1),r.length===4&&i.has("left")&&i.has("right")&&i.has("up")&&i.has("down")&&(t.metrics.crosses+=1)}return t.metrics.conveyorCells=t.cells.size,t.metrics.edges=Math.floor(n/2),ul(t),dl(e,t),t.issues=Cl(e,t,{includeRoutes:!1}),t}function ul(e){let t=1;for(let n of e.cells){if(e.cellToComponent.has(n))continue;let o=t++,r=[n],i=[];for(e.cellToComponent.set(n,o);r.length;){let a=r.shift();i.push(a);for(let c of e.adjacency.get(a)||[])e.cellToComponent.has(c.key)||(e.cellToComponent.set(c.key,o),r.push(c.key))}e.components.set(o,{id:o,cells:i,capacity:Math.max(1,i.length),count:0,ratio:0})}e.metrics.components=e.components.size}function dl(e,t){for(let n of e.scanners){let o={};for(let r of["inputA","left","right"]){let i=Fe(n,r),a=sr(e,i,ft(n)).filter(g=>t.cells.has(We(g.col,g.row))),c=a.map(g=>We(g.col,g.row)),h=c.length>0;if(o[r]={type:r,cell:i,cells:a,keys:c,key:c[0]||null,connected:h},t.metrics.scannerPorts+=1,h&&(t.metrics.connectedScannerPorts+=1),r==="inputA")for(let g of c)t.scannerInputs.set(g,n.id)}t.scannerPorts.set(n.id,o)}for(let[n,o]of Object.entries(e.facilities)){let r=nt(e,o);if(!r)continue;let i=sr(e,r).filter(h=>t.cells.has(We(h.col,h.row))),a=i.map(h=>We(h.col,h.row)),c=a.length>0;t.facilityPorts.set(n,{id:n,cell:{...r},cells:i,keys:a,key:a[0]||null,connected:c}),t.metrics.facilityPorts+=1,c&&(t.metrics.connectedFacilityPorts+=1)}for(let n of e.eggFarms){let o=Ni({col:n.col,row:n.row}).map(r=>We(r.col,r.row)).filter(r=>t.cells.has(r));t.farmOutputs.set(n.id,o),t.metrics.farmOutputs+=o.length}}function Je(e){let t=e.routingVersion||0;return(!e.factoryGraph||e.factoryGraph.version!==t)&&(e.factoryGraph=cl(e)),e.factoryGraph}function Ui(e){let t=Je(e);return e.factoryGraphCommittedVersion=t.version,e.factoryGraphSnapshot=fl(t),t}function fl(e){return e?{version:e.version,conveyorCells:e.metrics.conveyorCells,edges:e.metrics.edges,components:e.metrics.components,deadEnds:e.metrics.deadEnds,crosses:e.metrics.crosses,scannerPorts:`${e.metrics.connectedScannerPorts}/${e.metrics.scannerPorts}`,facilityPorts:`${e.metrics.connectedFacilityPorts}/${e.metrics.facilityPorts}`,farmOutputs:e.metrics.farmOutputs,issues:[...e.issues||[]]}:null}function pl(e,t){let n=t.col-e.col,o=t.row-e.row;return fe.find(r=>r.dc===n&&r.dr===o)?.name||null}function cr(e,t,n){let o=Je(e),r=We(t.col,t.row);if(!o.cells.has(r))return[];let i=`${r}|${n.cacheKey||"dynamic"}`;if(n.cacheKey&&o.pathCache.has(i))return o.pathCache.get(i).map(le=>le.map(ue=>({...ue})));let a=`${r}|none`,c=[{key:r,col:t.col,row:t.row,incoming:"none",depth:0}],h=new Map([[a,0]]),g=new Map,C=[],P=1/0,L=8,K=24,j=80;for(;c.length;){let le=c.shift();if(le.depth>P)break;let ue=`${le.key}|${le.incoming}`;if(n(le)){if(C.push(ue),P=le.depth,C.length>=K)break;continue}for(let D of o.adjacency.get(le.key)||[]){let U=rn(D.key),ee=pl(le,U),O=le.depth+1;if(O>P)continue;let G=`${D.key}|${ee}`,Y=h.get(G);if(Y==null)h.set(G,O),g.set(G,[ue]),c.push({key:D.key,col:U.col,row:U.row,incoming:ee,depth:O});else if(Y===O){let ie=g.get(G)||[];ie.length{if(Z.length>=j)return;let[D]=le.split("|"),U=[rn(D),...ue];if(le===a||D===r){Z.push(U);return}for(let ee of g.get(le)||[])Q(ee,U)};for(let le of C)Q(le,[]);let ke=[],pe=new Set;for(let le of Z){let ue=le.map(D=>We(D.col,D.row)).join(">");pe.has(ue)||(pe.add(ue),ke.push(le))}return n.cacheKey&&o.pathCache.set(i,ke.map(le=>le.map(ue=>({...ue})))),ke}function Wi(e){let t=Je(e),n=new Map;for(let[o,r]of t.components.entries())n.set(o,{id:o,cells:[...r.cells],capacity:r.capacity,count:0,ratio:0});return{components:n,cellToComponent:new Map(t.cellToComponent)}}function uo(e,t=null){let n=e.map(o=>$(o.col,o.row));return t&&n.push(t),n}function At(e,t){t&&(!e.length||yi(e[e.length-1],t)>1)&&e.push(t)}function yl(e,t,n,o=null){let r=[{x:e.x,y:e.y}];At(r,$(t.col,t.row));for(let i of uo(n,o))At(r,i);return r}function hl(e,t){let n=uo(e),o=Fe(t,"inputA");return o&&At(n,$(o.col,o.row)),At(n,ge(t)),n}function ml(e,t,n,o){let r=[{x:e.x,y:e.y}];At(r,$(t.col,t.row));for(let a of uo(n))At(r,a);let i=Fe(o,"inputA");return i&&At(r,$(i.col,i.row)),At(r,ge(o)),r}function bl(e,t,n=0){let o=$(t.col,t.row),r=0;for(let i of e.chicks||[]){if(i.stage==="flying"||i.stage==="queued")continue;Math.hypot(i.x-o.x,i.y-o.y){let L=C.roleBias??0,K=P.roleBias??0;if(L!==K)return L-K;let j=C.cells?.length??C.route?.length??Number.POSITIVE_INFINITY,Z=P.cells?.length??P.route?.length??Number.POSITIVE_INFINITY;if(j!==Z)return j-Z;let Q=C.key||JSON.stringify(C.route||C.cells||C),ke=P.key||JSON.stringify(P.route||P.cells||P);return Q.localeCompare(ke)});if(!o||r.length===1)return r[0];let i=r[0].roleBias??0,a=r.filter(C=>(C.roleBias??0)===i),c=a.map(C=>({item:C,score:vl(e,C)})),h=Math.min(...c.map(C=>C.score));a=c.filter(C=>C.score===h).map(C=>C.item);let g=e.branchCounters.get(t)||0;return e.branchCounters.set(t,g+1),a[Math.floor(Math.random()*a.length)]}function Hi(e){return e.role===0?{left:{match:"male",destination:"mixer"},right:{match:"default",destination:"scanner-role-1"}}:{left:{match:"poop",destination:"trash"},right:{match:"default",destination:"truck"}}}function ur(e){let t=Hi(e);return{left:t.left.destination,right:t.right.destination}}function dr(e,t){return Hi(e).left.match===t.sex?"left":"right"}function fr(e){return mi(e)}function pr(e){return{mixer:"#2477ff",truck:"#ff6aa8",trash:"#22b94f",sausageMaker:"#d78b3f","scanner-role-1":"#526456",scanner:"#526456",input:"#526456"}[e]||"#102015"}function Kt(e,t,n=!1){let o=Je(e),r=(o.farmOutputs.get(t.id)||[]).map(rn),i=[];for(let h of r){let g=P=>o.scannerInputs.has(We(P.col,P.row));g.cacheKey=`farmInput:${h.col},${h.row}:v${o.version}`;let C=cr(e,h,g);for(let P of C){let L=P[P.length-1],K=o.scannerInputs.get(We(L.col,L.row)),j=Ht(e,K);j&&i.push({key:`${j.id}:${L.col},${L.row}:${P.length}`,scanner:j,cells:P})}}let a=co(e,`farm:${t.id}`,i,n);if(a)return{scannerId:a.scanner.id,route:hl(a.cells,a.scanner)};let c=co(e,`farm:${t.id}:output`,r.map(h=>({key:I(h.col,h.row),cells:[h]})),n);return c?{scannerId:null,route:uo(c.cells)}:null}function Ki(e,t,n,o,r=!1){let i=Ht(e,o);if(!i)return null;let c=Je(e).scannerPorts.get(i.id)?.[t],h=Fe(i,t),g=c?.connected?(c.keys||[c.key]).filter(Boolean).map(rn):[];if(!h||!g.length)return null;let C=ur(i)[t];return C==="scanner-role-1"?wl(e,i,t,n,h,g,r):Sl(e,i,t,n,h,g,C,r)}function wl(e,t,n,o,r,i,a){let c=Je(e),h=e.scanners.filter(P=>P.id!==t.id&&c.scannerPorts.get(P.id)?.inputA?.connected),g=[];for(let P of i)for(let L of h){let K=c.scannerPorts.get(L.id)?.inputA?.key;if(!K)continue;let j=(c.scannerPorts.get(L.id)?.inputA?.keys||[K]).filter(Boolean),Z=pe=>j.includes(We(pe.col,pe.row));Z.cacheKey=`toScanner:${P.col},${P.row}:${L.id}:v${c.version}`;let Q=cr(e,P,Z),ke=L.role===1?0:1;for(let pe of Q)g.push({key:`${ke}:start${I(P.col,P.row)}:s${L.id}:${pe.length}:${I(pe[pe.length-1].col,pe[pe.length-1].row)}`,target:L,cells:pe,roleBias:ke})}let C=co(e,`scanner:${t.id}:${n}:toRole1`,g,a);return C?{destination:"scanner",nextScannerId:C.target.id,route:ml(o,r,C.cells,C.target)}:null}function Sl(e,t,n,o,r,i,a,c){let h=Je(e),g=[...h.facilityPorts.entries()].filter(([L,K])=>K?.connected&&sn(e.facilities?.[L])===a);if(!g.length)return null;let C=[];for(let L of i)for(let[K,j]of g){let Z=(j.keys||[j.key]).filter(Boolean);if(!Z.length)continue;let Q=pe=>Z.includes(We(pe.col,pe.row));Q.cacheKey=`toFacility:${L.col},${L.row}:${K}:v${h.version}`;let ke=cr(e,L,Q);for(let pe of ke)C.push({key:`start${I(L.col,L.row)}:${K}:${pe.length}:${I(pe[pe.length-1].col,pe[pe.length-1].row)}`,cells:pe,facilityId:K})}let P=co(e,`scanner:${t.id}:${n}:${a}`,C,c);return P?{destination:a,facilityId:P.facilityId,route:yl(o,r,P.cells,il(e,P.facilityId))}:null}function qi(e,t,n=new Set){if(!t||n.has(t.id))return!1;n.add(t.id);for(let o of["left","right"]){let r=Ki(e,o,ge(t),t.id,!1);if(r){if(["mixer","trash","truck","sausageMaker"].includes(r.destination))return!0;if(r.destination==="scanner"){let i=Ht(e,r.nextScannerId);if(qi(e,i,n))return!0}}}return!1}function kl(e,t){return!!Kt(e,t,!1)?.scannerId}function an(e){if(e.phase!=="build")return[];let t=[];for(let n of e.eggFarms||[])kl(e,n)||t.push({type:"eggFarm",id:n.id,ref:n,message:"This Egg will not produce chicks"});for(let n of Jo)for(let[o,r]of lr(e,n))Je(e).facilityPorts.get(o)?.connected||t.push({type:"facility",id:o,ref:r,message:"This facility cannot receive items"});return t}function gl(e){let t=Je(e);for(let r of e.eggFarms||[]){let i=Kt(e,r,!1);if(!i?.scannerId)continue;let a=Ht(e,i.scannerId);if(qi(e,a))return[]}let n=e.eggFarms?.length||0,o=[...t.facilityPorts.entries()].filter(([r,i])=>i?.connected&&["mixer","trash","truck"].includes(sn(e.facilities?.[r]))).length;return n?t.metrics.farmOutputs?e.scanners?.length?o?["No route from an EGG scanner to a receiver."]:["Connect at least one receiver exit: Mixer, Shredder, or Truck."]:["Build at least one scanner and connect it to an EGG route."]:["Connect at least one EGG to a conveyor."]:["Build at least one EGG before starting the next day."]}function ao(e){return e.kind==="manual"?`S${(e.slot??0)+1}`:`Auto Scanner #${e.id}`}function Cl(e,t=Je(e),n={}){let o=n.includeRoutes!==!1,r=[],i={mixer:"Mixer",trash:"Shredder",truck:"Truck",sausageMaker:"Sausage Machine"};for(let a of Jo){let c=lr(e,a);if(!c.length){di.includes(a)&&r.push(`${i[a]||a} is missing`);continue}for(let[h]of c)t.facilityPorts.get(h)?.connected||r.push(`${i[a]||a} receiver has no conveyor`)}for(let a of e.scanners){let c=t.scannerPorts.get(a.id)||{};if(c.inputA?.connected||r.push(`${ao(a)} input has no conveyor`),c.left?.connected||r.push(`${ao(a)} left output has no conveyor`),c.right?.connected||r.push(`${ao(a)} right output has no conveyor`),!!o)for(let h of["left","right"])c[h]?.connected&&!Ki(e,h,ge(a),a.id)&&r.push(`${ao(a)} ${h} route is incomplete`)}if(o)for(let a of e.eggFarms)Kt(e,a)?.scannerId||r.push(`Egg Farm #${a.id} has no scanner route`);else for(let a of e.eggFarms)(t.farmOutputs.get(a.id)||[]).length||r.push(`Egg Farm #${a.id} has no output conveyor`);return[...new Set(r)]}function fo(e){return gl(e)}var Fn=[{key:"premiumFemaleShipment",target:"female",truckTarget:"female",title:"Premium Female Shipment",route:"Female -> Truck",note:"Today only: ship female chicks to Truck. Meet the export target for a bonus.",objective:"truckTarget"},{key:"contaminantSampleExport",target:"poop",truckTarget:"poop",title:"Contaminant Sample Export",route:"Poop value x2",note:"Today only: poop is valid Truck cargo and all poop income is doubled.",objective:"truckTarget",poopValueMultiplier:2},{key:"healthInspection",title:"Health Inspection",route:"Poop -> Shredder",note:"Today only: poop mistakes are fined double. Shred enough poop for an inspection bonus.",objective:"poopTrash",poopFineMultiplier:2},{key:"conveyorJamWarning",title:"Conveyor Jam Warning",route:"No explosions",note:"Today only: jam explosions trigger at 85% congestion. Finish with zero explosions for a bonus.",objective:"noExplosion",congestionExplosionThreshold:.85,congestionWarningThreshold:.68},{key:"powerSavingOrder",title:"Power Saving Order",route:"Slow factory subsidy",note:"Today only: conveyors -20% speed and Auto Scanners +20% cooldown. A subsidy is paid at settlement.",objective:"flatBonus",conveyorSpeedMultiplier:.8,autoScannerCooldownMultiplier:1.2},{key:"overtimeDay",title:"Overtime Day",route:"80 second day",note:"Today only: the work day is longer. No extra reward or penalty.",objective:"none",daySeconds:80},{key:"shortShift",title:"Short Shift",route:"40 second day",note:"Today only: the work day is shorter. The next Fairies tribute is reduced by 10%.",objective:"none",daySeconds:40,fairiesTributeMultiplier:.9},{key:"chickBoom",title:"Chick Boom",route:"EGG interval x0.65",note:"Today only: eggs hatch faster and poop rate rises by 5 percentage points.",objective:"none",productionMultiplier:1/.65,poopRateAdd:.05},{key:"rottenFeed",title:"Rotten Feed",route:"Poop surge",note:"Today only: poop rate rises by 20 percentage points and Shredder poop income is multiplied by 1.5.",objective:"none",poopRateAdd:.2,shredderIncomeMultiplier:1.5},{key:"maintenanceAudit",title:"Maintenance Audit",route:"Durability check",note:"Today only: machines below 50% remaining durability fail the audit. Passing with none below 50% pays a bonus.",objective:"maintenanceAudit"}];function Ee(e,t=0){let n=Number(e);return Number.isFinite(n)?n:t}function Ml(e,t=0,n=1){let o=Math.max(1,Number(e?.turn||1)+1),r=Math.floor(yr(e)*(.08+Math.random()*.08)),i=Math.floor(Math.max(0,e.cash||0)*.25),a=Math.floor(Math.max(0,t)*Math.max(1,o)*.75);return Math.max(120,Math.ceil(Math.max(r,i,a)*n))}function Yi(e){return Math.max(0,Math.ceil(500+Math.max(1,e?.turn||1)*25))}function yr(e){return[...e.eggFarms.map(t=>t.price||0),...e.scanners.map(t=>t.price||0),...Object.values(e.facilities).map(t=>t.price||0),...[...e.conveyorMeta.values()].map(t=>t.price||0)].reduce((t,n)=>t+n,0)}function xl(e,t=1,n=Gt){return e.eggFarms.reduce((o,r)=>{let[i,a]=$n(r),c=Math.max(.1,(i+a)/2);return o+Math.max(1,n)/c*Math.max(.01,t||1)},0)}function Tl(e,t){let n=Ee(t.productionMultiplier,1),o=Ee(t.daySeconds,Gt),r=xl(e,n,o),i=Math.max(0,Number(e?.cardEffects?.hatchingFeed)||0),a=Math.max(0,Number(e?.cardEffects?.poopRateBooster)||0),c=Math.pow(1.03,i),h=zo+Xo*a,g=Math.min(.95,Math.max(0,(h+Ee(t.poopRateAdd,0))*Ee(t.poopMultiplier,1)*c));return{estimate:r,poopRate:g}}function hr(e,t){let n=typeof t=="string"?Fn.find(c=>c.key===t):t;if(!n)return null;let{estimate:o,poopRate:r}=Tl(e,n),i=0;n.objective==="truckTarget"?i=Math.max(1,Math.ceil(o*.3)):n.objective==="poopTrash"&&(i=Math.max(1,Math.ceil(o*r*.8)));let a=0;return["truckTarget","poopTrash","noExplosion"].includes(n.objective)&&(a=Ml(e,o)),n.objective==="flatBonus"&&(a=Yi(e)),n.objective==="maintenanceAudit"&&(a=Yi(e)),{id:`event-${e.turn}-${Date.now()}-${Math.floor(Math.random()*9999)}`,...n,target:n.target||null,truckTarget:n.truckTarget||null,forced:!0,productionMultiplier:Ee(n.productionMultiplier,1),poopMultiplier:Ee(n.poopMultiplier,1),poopRateAdd:Ee(n.poopRateAdd,0),daySeconds:Ee(n.daySeconds,Gt),targetAmount:i,estimatedOutput:Math.round(o),reward:a,createdTurn:e.turn,oneTurnOnly:!0}}function Vi(e){if(e.turn+1ci)return null;let n=Fn[Math.floor(Math.random()*Fn.length)];return hr(e,n)}function zi(e){e.eventActive=e.eventOffer?{...e.eventOffer}:null,e.eventOffer=null}function Xi(e){e.eventActive=null}function ji(e){return Math.max(1,Ee(e.eventActive?.daySeconds,Gt))}function Qi(e){return Ee(e.eventActive?.productionMultiplier,1)}function Ji(e){let t=Math.max(0,Number(e?.cardEffects?.hatchingFeed)||0),n=Math.max(0,Number(e?.cardEffects?.poopRateBooster)||0),o=Math.pow(1.03,t),r=zo+Xo*n,i=Ee(e.eventActive?.poopRateAdd,0);return Math.min(.95,Math.max(0,(r+i)*Ee(e.eventActive?.poopMultiplier,1)*o))}function ln(e){return e.eventActive?.truckTarget||e.eventActive?.target||"female"}function mr(e,t){return t==="male"?e.truckMale||0:t==="poop"?e.poopTruck||0:e.truckFemale||0}function Zi(e,t){return ln(e)===t}function es(e){return ln(e)!=="male"}function br(e){return Math.max(.01,Ee(e.eventActive?.poopValueMultiplier,1))}function po(e){return Math.max(.01,br(e)*Ee(e.eventActive?.shredderIncomeMultiplier,1))}function vr(e){return Math.max(.01,Ee(e.eventActive?.poopFineMultiplier,1))}function wr(e){return Math.max(.1,Math.min(1,Ee(e.eventActive?.congestionExplosionThreshold,1)))}function ts(e){return Math.max(.1,Math.min(1,Ee(e.eventActive?.congestionWarningThreshold,.8)))}function ns(e){return Math.max(.01,Ee(e?.fairiesTributeMultiplier,1))}function El(e){let t=0,n=(o,r)=>{let i=Math.max(1,Ee(r,1)),a=Math.max(0,Ee(o,0));1-Math.min(1,a/i)<.5&&(t+=1)};for(let o of e.conveyorMeta?.values?.()||[])n(o.uses,o.durability);for(let o of e.eggFarms||[])n(o.maintenance?.uses,o.maintenance?.durability);for(let o of e.scanners||[])o.kind==="auto"&&n(o.maintenance?.uses,o.maintenance?.durability);for(let o of Object.values(e.facilities||{})){let r=o?.baseId||o?.id;(r==="mixer"||r==="trash"||r==="sausageMaker")&&n(o.maintenance?.uses,o.maintenance?.durability)}return t}function os(e){let t=e.eventActive;if(!t)return null;let n=0,o=!0,r=0,i="";t.objective==="truckTarget"?(n=mr(e.stats,t.target),o=n>=t.targetAmount,r=o?t.reward:0):t.objective==="poopTrash"?(n=e.stats.poopTrash||0,o=n>=t.targetAmount,r=o?t.reward:0):t.objective==="noExplosion"?(n=e.stats.explosions||0,o=n===0,r=o?t.reward:0,i=`${n} explosion(s)`):t.objective==="flatBonus"?(o=!0,r=t.reward):t.objective==="maintenanceAudit"?(n=El(e),o=n===0,o&&(r=t.reward),i=`${n} machine(s) below 50%`):o=!0,r>0?(je(e,r),e.stats.eventBonus=(e.stats.eventBonus||0)+r,e.totals.eventBonus+=r,e.totals.eventSuccess+=1):t.objective&&t.objective!=="none"&&(e.stats.eventBonus=e.stats.eventBonus||0,e.totals.eventFailed+=o?0:1,o&&(e.totals.eventSuccess+=1));let a={title:t.title,key:t.key,target:t.target,route:t.route,objective:t.objective,targetAmount:t.targetAmount||0,count:n,success:o,bonus:r,reward:t.reward||0,productionMultiplier:t.productionMultiplier,poopMultiplier:t.poopMultiplier,daySeconds:t.daySeconds,detail:i};return e.stats.eventResult=a,a}function Sr(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function Rl(e){return!!e?.cardEffects?.usedMachineActive}function Pl(e,t){return t?1:Math.min(.8,.5+.1*Math.min(3,Sr(e,"recyclingSubsidy")))}function Al(e){return Math.pow(.95,Sr(e,"safetyCover"))}function yo(e){let t=e?.ref||e||{},n=e?.type||t.type;return n==="conveyor"?t.price||Te[t.kind]?.price||Te.conveyor.price:n==="eggFarm"?t.price||Te.eggFarm.price:n==="scanner"?t.price||(t.kind==="auto"?Te.autoScanner.price:Te.manualScanner.price):n==="facility"?t.price||Te[t.id]?.price||0:n==="maintenanceRoom"?t.price||Te.maintenanceRoom.price:Te[t.id]?.price||0}function He(e,t=null){let n=Te[e]?.price||0;return Rl(t)?Math.ceil(n*.5):n}function Il(e,t){return e?.facilities?Object.values(e.facilities).filter(n=>(n?.baseId||n?.id)===t).reduce((n,o)=>n+Math.max(0,(o.level||1)-1),0):0}function yt(e,t){return fi.includes(t)?Math.pow(xe.incomeUpgradeRate,Il(e,t)):1}function Ve(e){return Math.ceil(xe.income.truck*yt(e,"truck"))}function Ze(e){return Math.ceil((xe.income.sausage||26)*yt(e,"mixer")*yt(e,"sausageMaker"))}function Dn(e){return Math.ceil(xe.poopFine*yt(e,"mixer")*vr(e))}function Bn(e){return Math.ceil(xe.poopFine*yt(e,"truck")*vr(e))}function kr(e){let t=xe.maleTruckFinePerHalfDay*(e.turn/2);return Math.ceil(t*yt(e,"truck"))}function gr(e){return e?.facilities?Object.values(e.facilities).filter(t=>(t?.baseId||t?.id)==="trash").reduce((t,n)=>t+Math.max(0,(n.level||1)-1),0):0}function mt(e){return Math.min(xe.shredderBonus.maxCards,gr(e))}function cn(){return xe.shredderBonus.maxCards}function ho(){return xe.shredderBonus||{}}function rs(e){let t=typeof e=="number"?e:mt(e),n=ho(),o=Math.min(n.maxCards||30,Math.max(0,t));return o>0?Math.ceil((n.payoutCoefficient||1.6)*Math.pow(o,n.payoutExponent||1.25)):0}function qt(e){let t=typeof e=="number"?e:mt(e);if(t<=0)return 0;let n=ho();return Math.min(n.maxHitChance||.82,(n.baseHitChance||.28)+t*(n.hitChancePerUpgrade||.018))}function $l(e){let t=ho(),n=Math.min(t.jackpotMaxChance||.08,(t.jackpotBaseChance||.01)+e*(t.jackpotChancePerUpgrade||.0025)),o=Math.min(t.bigWinMaxChance||.12,(t.bigWinBaseChance||.07)+e*(t.bigWinChancePerUpgrade||.0015)),r=Math.min(1-n-o,t.doubleChance||.2),i=Math.max(0,1-n-o-r);return n*(t.jackpotMultiplier||10)+o*(t.bigWinMultiplier||4)+r*(t.doubleMultiplier||2)+i}function ht(e){let t=typeof e=="number"?e:mt(e);return Math.round(rs(t)*qt(t)*$l(t))}function Fl(e){let t=mt(e),n=qt(t),o=rs(t);if(t<=0||Math.random()>=n)return{cards:t,chance:n,amount:0,expected:ht(t),baseAmount:o,multiplier:0,tier:"miss"};let r=ho(),i=Math.min(r.jackpotMaxChance||.08,(r.jackpotBaseChance||.01)+t*(r.jackpotChancePerUpgrade||.0025)),a=Math.min(r.bigWinMaxChance||.12,(r.bigWinBaseChance||.07)+t*(r.bigWinChancePerUpgrade||.0015)),c=Math.min(1-i-a,r.doubleChance||.2),h=Math.random(),g=1,C="normal";h0&&(e.stats.shredderBonus=(e.stats.shredderBonus||0)+t.amount,e.totals.shredderBonus=(e.totals.shredderBonus||0)+t.amount,je(e,t.amount)),t}function Cr(e,t=e.turn,n=null){let o=Math.max(1,Math.floor(Number(t)||1)),r=xe.fairiesTribute||{perDay:10,profitExemption:300,legalWorkExemptionBonus:250,profitRate:.12},i=Math.ceil(o*(r.perDay||10)),a=Math.max(0,Math.floor(Number(n??e?.lastResult?.profit??e?.stats?.profit??0)||0)),c=Math.max(0,e?.cardEffects?.legalWork||0),h=Math.max(0,(r.profitExemption||0)+c*(r.legalWorkExemptionBonus||0)),g=Math.max(0,a-h),C=Math.ceil(g*Math.max(0,Number(r.profitRate)||0)),P=i+C,L=Math.max(0,e?.cardEffects?.fairiesFlatteryNext||e?.cardEffects?.flattery||0),K=L>0?Math.pow(.5,L):1,j=Math.max(.01,Number(e?.pendingFairiesTributeMultiplier)||1),Z=K*j,Q=Math.max(0,Math.ceil(P*Z)),ke=Math.max(0,P-Q);return{day:o,base:i,profit:a,legalWork:c,profitExemption:h,taxableProfit:g,profitTribute:C,gross:P,flatteryCount:L,eventMultiplier:j,perCardReduction:Math.ceil(P*.5),reduction:ke,amount:Q}}function $t(e,t){let n=e?.ref||e||{},o=e?.type==="conveyor"?t?.conveyorMeta?.get(e.oldKey||n.id):n,r=o?.price||yo(e||n),i=o?.builtSession===t?.buildSession;if(o?.noRefund||n?.noRefund)return{amount:0,sameBuild:i,price:r,rate:0,noRefund:!0};let a=Pl(t,i);return{amount:Math.max(0,Math.ceil(r*a)),sameBuild:i,price:r,rate:a,noRefund:!1}}function Dl(e,t=null){let n=Math.max(1,Math.ceil((Number(e)||0)/xe.explosionDamageDivisor));return Math.max(1,Math.ceil(n*Al(t)))}function Bl(e,t){return Math.max(0,Math.ceil(t))}function ss(e,t){e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,t>=0?(e.stats.revenue+=t,e.totals.revenue+=t):(e.stats.penalty+=Math.abs(t),e.totals.penalty+=Math.abs(t)),e.totals.maxCash=Math.max(e.totals.maxCash,e.cash)}function je(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&ss(e,n),n}function Ft(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&ss(e,-n),n}function Dt(e,t){Ft(e,t)}function as(e,t){t<=0||(e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,e.totals.maxCash=Math.max(e.totals.maxCash,e.cash))}function ls(e){let t=xe.income.mixer;return e.stats.mixerRevenue+=t,je(e,t),t}function cs(e){let t=Dn(e);return e.stats.mixerPoopFine+=t,e.totals.mixerPoopFine+=t,Ft(e,t),t}function us(e){let t=Bn(e);return e.stats.truckPoopFine+=t,e.totals.truckPoopFine+=t,Ft(e,t),t}function ds(e){let t=kr(e);return e.stats.maleTruckFine+=t,e.totals.maleTruckFine+=t,Ft(e,t),t}function fs(e,t){let n=Dl(t,e);return e.stats.explosionDamage+=n,e.totals.explosionDamage+=n,Ft(e,n),n}function ps(e){let t=ln(e),n=mr(e.stats,t),o=t==="poop"?Math.ceil(Ve(e)*br(e)):Ve(e),r=n*o,i=Math.max(0,e?.stats?.sausageShipped||0),a=Ze(e),c=i*a,h=Bl(e,r+c);return e.stats.pendingTruckRevenue=h,e.stats.truckRevenue=h,e.stats.sausageRevenue=c,t==="poop"?e.stats.poopShipmentIncome=r:e.stats.chickShipmentIncome=r,h>0&&je(e,h),{base:r,adjusted:h,target:t,targetCount:n,unitPrice:o,sausageCount:i,sausageUnitPrice:a,sausageRevenue:c}}function ys(e,t=e.turn,n=null,o={}){let r=Cr(e,t,n);return e.cardEffects&&(e.cardEffects.fairiesFlatteryNext=0,e.cardEffects.flattery!=null&&delete e.cardEffects.flattery),e.pendingFairiesTributeMultiplier!=null&&(e.pendingFairiesTributeMultiplier=1),r.amount<=0||(o.recordStats?(e.stats.fairiesTribute=(e.stats.fairiesTribute||0)+r.amount,e.totals.fairiesTribute=(e.totals.fairiesTribute||0)+r.amount,Ft(e,r.amount)):(e.totals.fairiesTribute=(e.totals.fairiesTribute||0)+r.amount,e.totals.penalty=(e.totals.penalty||0)+r.amount,e.totals.profit=(e.totals.profit||0)-r.amount,e.cash-=r.amount)),r}function hs(e){let t=Sr(e,"chemicalWeaponSubsidy"),n=Math.max(0,e?.stats?.poopTruck||0),o=xe.chemicalWeaponSubsidy||{poopPerBlock:70,yenPerBlock:1200},r=Math.floor(n/Math.max(1,o.poopPerBlock||70)),i=t>0&&r>0?r*Math.max(0,o.yenPerBlock||1200)*t:0;return i>0&&(e.stats.chemicalWeaponSubsidy=(e.stats.chemicalWeaponSubsidy||0)+i,e.totals.chemicalWeaponSubsidy=(e.totals.chemicalWeaponSubsidy||0)+i,je(e,i)),{cards:t,poopTruck:n,blocks:r,amount:i}}function ms(e){let t=yr(e),n=Math.max(1,e.totals.turnsCompleted||e.turn||1),o=Math.max(0,e.cash+e.totals.revenue+t*.5+e.totals.eventBonus*.5),r=Math.ceil(o/n),i=Math.floor(n*35+Math.max(0,n-5)*15),a=e.totals.correct*5,c=e.totals.explosionDamage;return{score:Math.max(0,Math.floor(o+r+a-e.totals.penalty-i)),factoryValue:t,base:o,dailyEarned:r,dayPenalty:i,correctBonus:a,explosionPenalty:c,days:n}}function Ol(e){return{...e,keys:e.keys?{left:{...e.keys.left},right:{...e.keys.right}}:null,queue:[],cooldown:e.cooldown||0}}function On(e){return JSON.stringify({cash:e.cash,stats:e.stats,totals:e.totals,nextId:e.nextId,gridX:f.x,gridY:f.y,gridCols:e.gridCols||f.cols,gridRows:e.gridRows||f.rows,gridExpansionPurchases:e.gridExpansionPurchases||0,gridExpansionPurchasesByDirection:e.gridExpansionPurchasesByDirection||{left:0,right:0,up:0,down:0},gridChunkOriginX:e.gridChunkOriginX||0,gridChunkOriginY:e.gridChunkOriginY||0,ownedCells:[...e.ownedCells||[]],ownedChunks:[...e.ownedChunks||[]],blockedCells:[...e.blockedCells||[]],selected:e.selected,multiSelected:e.multiSelected||[],buildTool:e.buildTool,view:e.view,facilities:e.facilities,eggFarms:e.eggFarms,scanners:e.scanners.map(Ol),conveyorTiles:[...e.conveyorTiles],conveyorMeta:[...e.conveyorMeta.entries()],branchCounters:[...e.branchCounters.entries()],cardEffects:e.cardEffects,cardDraft:e.cardDraft,cardTargetPick:e.cardTargetPick})}function bs(e,t){let n=JSON.parse(t);e.cash=n.cash,e.stats=n.stats,e.totals=n.totals,e.nextId=n.nextId,f.x=n.gridX??V.grid.x,f.y=n.gridY??V.grid.y,f.cols=n.gridCols||V.grid.cols,f.rows=n.gridRows||V.grid.rows,e.gridCols=f.cols,e.gridRows=f.rows,e.gridExpansionPurchases=n.gridExpansionPurchases||0,e.gridExpansionPurchasesByDirection=n.gridExpansionPurchasesByDirection||{left:0,right:0,up:0,down:0},e.gridExpansionPurchasesByDirection.left==null&&(e.gridExpansionPurchasesByDirection.left=0),e.gridExpansionPurchasesByDirection.down==null&&(e.gridExpansionPurchasesByDirection.down=0),e.gridChunkOriginX=n.gridChunkOriginX||0,e.gridChunkOriginY=n.gridChunkOriginY||0,e.ownedCells=new Set(n.ownedCells||[]),e.ownedChunks=new Set(n.ownedChunks||[]),e.gridOwnedCells=e.ownedCells.size||f.cols*f.rows,e.blockedCells=new Set(n.blockedCells||[]),e.selected=n.selected,e.multiSelected=n.multiSelected||[],e.buildTool=n.buildTool,e.view=n.view||{x:0,y:0,scale:1},e.view.scale==null&&(e.view.scale=1),e.facilities=n.facilities||{},e.eggFarms=n.eggFarms||[],e.scanners=(n.scanners||[]).map(o=>({...o,queue:[],cooldown:o.cooldown||0})),e.conveyorTiles=new Set(n.conveyorTiles||[]),e.conveyorMeta=new Map(n.conveyorMeta||[]),e.branchCounters=new Map(n.branchCounters||[]),e.cardEffects=n.cardEffects||{bearing:0,legalWork:0,fairiesFlatteryNext:0,scannerQueueSpacing:0},e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft=n.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardTargetPick=n.cardTargetPick||null,e.groupDrag=null,e.selectionBox=null,e.pan=null,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function _e(e){e.phase==="build"&&(e.undoStack.push(On(e)),e.undoStack.length>80&&e.undoStack.shift(),e.redoStack=[])}function Mr(e){return e.phase!=="build"||!e.undoStack.length?!1:(e.redoStack.push(On(e)),bs(e,e.undoStack.pop()),!0)}function xr(e){return e.phase!=="build"||!e.redoStack.length?!1:(e.undoStack.push(On(e)),bs(e,e.redoStack.pop()),!0)}function H(e,t,n,o,r=b.ink){e.floatingTexts.push({x:t,y:n,text:o,color:r,life:1,maxLife:1})}function Yt(e,t,n){e.shake.strength=Math.max(e.shake.strength,t),e.shake.time=Math.max(e.shake.time,n)}function vs(e,t,n){e.effects.push({type:"spawn",priority:Ie.ambient,x:t,y:n,life:.42,maxLife:.42,size:12})}function ws(e,t,n,o=b.green){e.effects.push({type:"scannerPulse",priority:Ie.important,x:t,y:n,color:o,life:.42,maxLife:.42,size:24})}function Ss(e,t,n){for(let o=0;o<12;o+=1)e.effects.push({type:"meat",priority:Ie.important,x:t+z(-18,18),y:n+z(-12,16),vx:z(-60,60),vy:z(-90,-25),life:z(.45,.85),maxLife:.85,size:z(4,8)})}function ks(e,t,n){for(let o=0;o<16;o+=1)e.effects.push({type:"sludge",priority:Ie.important,x:t+z(-18,18),y:n+z(-12,16),vx:z(-46,46),vy:z(-70,-20),life:z(.45,.9),maxLife:.9,size:z(4,8)})}function gs(e,t,n,o){let r=o==="poop"?b.poop:o==="male"?b.male:b.female;for(let i=0;i<22;i+=1)e.effects.push({type:"shred",priority:Ie.important,x:t+z(-16,16),y:n+z(-8,8),vx:z(-70,70),vy:z(40,160),color:i%3===0?b.white:r,life:z(.45,.95),maxLife:.95,w:z(3,7),h:z(10,24),rot:z(-Math.PI,Math.PI)});at(e,t,n,b.green,34,Ie.important)}function Cs(e,t,n,o){let r=o==="poop"?b.poop:o==="male"?b.danger:b.green;for(let i=0;i<8;i+=1)e.effects.push({type:"load",priority:Ie.important,x:t+z(-18,18),y:n+z(-18,18),vx:z(-42,42),vy:z(-90,-25),color:r,life:z(.35,.65),maxLife:.65,size:8})}function at(e,t,n,o=b.danger,r=52,i=Ie.critical){e.effects.push({type:"shockwave",priority:i,x:t,y:n,color:o,life:.55,maxLife:.55,size:8,maxSize:r})}function bt(e,t,n,o=12,r=b.danger,i=Ie.critical){for(let a=0;a0&&(e.shake.time=Math.max(0,e.shake.time-t),e.shake.time<=0&&(e.shake.strength=0));for(let r of e.effects)if(r.life-=t,["meat","sludge","spark","smoke","shred","load","rage"].includes(r.type))r.x+=(r.vx||0)*t,r.y+=(r.vy||0)*t,r.vy=(r.vy||0)+150*t;else if(r.type==="flyingChick"){r.x+=r.vx*t,r.y+=r.vy*t,r.vy+=360*t,r.noDamage||Ll(e,r,o);let i=r.x+e.view.x,a=r.y+e.view.y;(i<-100||a<-100||i>n.width+100||a>n.height+100)&&(r.life=0)}e.effects=e.effects.filter(r=>r.life>0);for(let r of e.floatingTexts)r.life-=t,r.y-=34*t;e.floatingTexts=e.floatingTexts.filter(r=>r.life>0)}function Ll(e,t,n){t.hit||(t.hit=new Set);for(let o of n()){if(t.hit.has(o.id)||t.xo.x+o.w||t.yo.y+o.h)continue;t.hit.add(o.id);let r=fs(e,o.price);H(e,t.x,t.y-10,`-${x(r)}`,b.danger),at(e,t.x,t.y,b.danger,30),bt(e,t.x,t.y,5,b.danger),Yt(e,5,.18)}}var Qe=V.maintenance;function Er(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function vo(e){let t=Math.min(1.4,1+.04*Math.min(10,Er(e,"crowdedFarming"))),n=Math.pow(.95,Er(e,"preventiveMaintenance"));return t*n}function Nl(e){return Math.pow(1.03,Er(e,"durabilityCoating"))}function wo(e,t,n=1){let o=Qe.durability[t]||1e3;return Math.max(1,Math.ceil(o*Math.max(.1,n||1)*Nl(e)))}function Ts(e){return Math.max(.1,Number(e?.durabilityBaseMultiplier)||1)}function _l(e,t=0){if(!e)return{x:f.x+f.cell*(.5+t*.55),y:f.y+f.rows*f.cell+84};let n=f.x+e.col*f.cell+f.cell,o=f.y+e.row*f.cell+f.cell;return{x:n,y:o}}function Gl(e,t=0){let n=(e.maintenanceRooms||[])[t];return _l(n,t)}function Re(e){e.repairman||(e.repairman={active:!1,x:f.x+f.cell*.5,y:f.y+f.rows*f.cell+84,target:null,repairedToday:0}),Array.isArray(e.maintenanceRooms)||(e.maintenanceRooms=[]),Array.isArray(e.repairmen)||(e.repairmen=[]);for(let[t,n]of e.conveyorMeta||[]){n.uses==null&&(n.uses=0),n.maintenanceType==null&&(n.maintenanceType="conveyor"),n.kind||(n.kind="conveyor"),n.speedMultiplier||(n.speedMultiplier=n.kind==="boostConveyor"?2:1),n.branchMode||(n.branchMode="random");let o=wo(e,"conveyor",Ts(n));(n.durability==null||n.durability0&&(n.processingCooldown=Math.max(0,n.processingCooldown-t))}function Gn(e){Re(e);let t=[];for(let[n,o]of e.conveyorMeta||[])t.push({type:"conveyor",key:n,meta:o,label:`${o.kind==="boostConveyor"?"Boost Belt":"Belt"} ${n}`,center:$(re(n).col,re(n).row)});for(let n of e.eggFarms||[])t.push({type:"eggFarm",ref:n,label:`EGG #${n.id}`,center:$(n.col,n.row)});for(let n of(e.scanners||[]).filter(o=>o.kind==="auto"))t.push({type:"autoScanner",ref:n,label:`AUTO #${n.id}`,center:$(n.col,n.row)});for(let n of Object.values(e.facilities||{})){let o=Co(n);["mixer","trash","sausageMaker"].includes(o)&&t.push({type:o,ref:n,label:`${n.shortName||n.name||o} #${n.id}`,center:{x:n.x+n.w/2,y:n.y+n.h/2}})}return t}function Vt(e){return e.meta?un(e):un(e.ref)}function Ln(e){return e.meta?Rr(e):Rr(e.ref)}function bo(e){return e.meta?Pr(e):Pr(e.ref)}function Is(e,t){Ul(e.meta?e:e.ref,Math.max(0,Ln(e)-t))}function Dr(e){return e.type==="conveyor"?`conveyor:${e.key}`:`${e.type}:${e.ref?.id||e.ref?.type||e.type}`}function $s(e,t=.02){Re(e);let n=Math.max(0,Number(t)||0),o=0;for(let r of Gn(e)){let i=Ln(r);Is(r,bo(r)*n),o+=Math.max(0,i-Ln(r))/bo(r)*100}return o}function Fs(e){Re(e);let t=e.maintenanceRooms||[];e.repairmen=t.map((o,r)=>{let i=Gl(e,r);return{id:`room-${o.id}`,roomId:o.id,active:!0,x:i.x,y:i.y,target:null,repairedToday:0}});let n=e.repairmen[0];e.repairman.active=!!n,e.repairman.target=n?.target||null,e.repairman.repairedToday=0,n&&(e.repairman.x=n.x,e.repairman.y=n.y)}function Ds(e){Re(e);for(let t of e.repairmen||[])t.active=!1,t.target=null;e.repairmen=[],e.repairman.active=!1,e.repairman.target=null}function Hl(e,t){return t&&Gn(e).find(o=>Dr(o)===t.key)||null}function Kl(e){let t=null;for(let n of Gn(e)){let o=Vt(n);o<=.001||(!t||o>Vt(t))&&(t=n)}return t}function Bs(e,t){Re(e);let n=e.repairmen?.length?e.repairmen:e.repairman?.active?[e.repairman]:[];if(!n.length||e.phase!=="running")return;let o=new Set(n.map(i=>i.target?.key).filter(Boolean));for(let i of n)ql(e,i,t,o);let r=n[0];r&&e.repairman!==r&&(e.repairman.active=!0,e.repairman.x=r.x,e.repairman.y=r.y,e.repairman.target=r.target,e.repairman.repairedToday=r.repairedToday||0)}function ql(e,t,n,o){if(!t.active)return;let r=Hl(e,t.target);if((!r||Vt(r)<=.001)&&(t.target?.key&&o.delete(t.target.key),r=Yl(e,o)),!r){t.target=null;return}let i=Dr(r);o.add(i),t.target={key:i,label:r.label};let a=Qe.repairman.walkSpeed,c=r.center.x-t.x,h=r.center.y-t.y,g=Math.hypot(c,h);if(g>8){let Z=Math.min(g,a*n);t.x+=c/g*Z,t.y+=h/g*Z;return}let C=e?.cardEffects?.laborExploitation?.7:1,P=n/(Qe.repairman.secondsPerOnePercent*C*100),L=Ln(r),K=P*bo(r);Is(r,K);let j=Math.max(0,(L-Ln(r))/bo(r)*100);t.repairedToday=(t.repairedToday||0)+j,j>0&&Math.random()<.02&&H(e,t.x,t.y-28,"REPAIR",b.green),Vt(r)<=.001&&(o.delete(i),t.target=null)}function Yl(e,t=new Set){let n=null;for(let o of Gn(e)){if(t.has(Dr(o)))continue;let r=Vt(o);r<=.001||(!n||r>Vt(n))&&(n=o)}return n||Kl(e)}function Vl(e){let t=0,n="none";for(let o of Gn(e)){let r=Vt(o);r>t&&(t=r,n=o.label)}return{ratio:t,percent:Math.round(t*100),label:n}}function Br(e){let t=Vl(e),n=Ar(e);return{worst:t,avgBeltPerformance:n,repairman:e.repairman||null,repairmen:e.repairmen||[],rooms:e.maintenanceRooms||[]}}var zl=Ue.commonWeight,Xl=Ue.rareWeight,jl=Ue.ultraRareWeight||.45,zt=Ue.baseDraftSize,fn=ui;function dn(e,t){let n=Ke(e);return Math.max(0,Number(n[t])||0)}function Ke(e){e.cardEffects||(e.cardEffects={...jo});for(let[t,n]of Object.entries(jo))e.cardEffects[t]==null&&(e.cardEffects[t]=Array.isArray(n)?[]:n);return e.cardEffects.flattery!=null&&(e.cardEffects.fairiesFlatteryNext=Math.max(0,e.cardEffects.fairiesFlatteryNext||0)+Math.max(0,e.cardEffects.flattery||0),delete e.cardEffects.flattery),e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft||(e.cardDraft={pending:!1,choices:[],rerolls:0,picksRemaining:0}),e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardEffects}function Hs(e){let t=Math.max(.5,1-.05*Math.min(10,dn(e,"crowdedFarming"))),n=Math.pow(.96,dn(e,"hatchingFeed"));return t*n}function Ks(e,t=null){return Math.min(3,Math.max(0,Number(t?.extraEggOutlet)||0))}function qs(e){return Math.pow(.85,dn(e,"scannerQueueSpacing"))}function pn(e,t=null){let n=Ke(e),o=Jn*Math.pow(Zn,Math.max(0,n.bearing||0)),r=t?Math.max(.1,Number(e?.conveyorMeta?.get?.(t)?.speedMultiplier)||1):1,i=t?1:Ar(e),a=Math.max(.01,Number(e?.eventActive?.conveyorSpeedMultiplier)||1);return Math.min(tn,o*i)*r*a}function St(e,t=null){let n=Math.max(0,(e?.level||1)-1),o=t?dn(t,"autoScannerTuning"):0,r=Qn*Math.pow(li,n)*Math.pow(Yo,o),i=Math.max(Vo,r),a=t?Math.max(.01,Number(t?.eventActive?.autoScannerCooldownMultiplier)||1):1;return t?Math.max(Vo,i*ko(e)*a):i}function Os(e){let t=e.cardDraft||{rerolls:0},n=Math.max(1,(t.rerolls||0)+1);return Math.ceil(Math.max(1,e.turn||1)/Ue.rerollCost.dayDivisor*n*Ue.rerollCost.multiplier)}function Xt(e){return fn.find(t=>t.id===e)||null}function Ys(e,t){let n=typeof t=="string"?Xt(t):t;return Ke(e),!n||!(n.type==="equipmentUpgrade"||n.type==="cellAction")?[]:et(e,n).map(o=>({key:wt(o),label:_r(e,o),type:o.type}))}function Nr(e,t,n={}){let o=typeof t=="string"?Xt(t):t;if(Ke(e),!o||o.type==="dud")return{ok:!1,reason:"Card not found."};if(o.id==="extraCards")return e.cardDraft=e.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.choices.push(...To(e,2)),{ok:!0,reason:`${o.title} added 2 draft cards.`};if(o.type==="instant")return zs(e,o),{ok:!0,reason:`${o.title} granted.`};if(o.type==="equipmentUpgrade"){let r=et(e,o);if(!r.length)return{ok:!1,reason:`No valid target for ${o.title}.`};let i=n.targetKey&&n.targetKey!=="__auto__"?String(n.targetKey):"",a=i?r.find(c=>wt(c)===i):r[0];return a?(Vs(e,a),{ok:!0,reason:`${o.title} applied to ${_r(e,a)}.`}):{ok:!1,reason:`Selected target is no longer valid for ${o.title}.`}}if(o.type==="cellAction"&&o.target==="blockedCell"){let r=et(e,o);if(!r.length)return{ok:!1,reason:"No blocked cells to remove."};let i=new Set((Array.isArray(n.targetKeys)?n.targetKeys:[n.targetKey]).filter(c=>c&&c!=="__auto__").map(String)),a=i.size?r.filter(c=>i.has(wt(c))):r.slice(0,10);if(!a.length)return{ok:!1,reason:`Selected target is no longer valid for ${o.title}.`};for(let c of a.slice(0,3)){e.blockedCells.delete(I(c.col,c.row));let h=$(c.col,c.row);vt(e,h.x,h.y),at(e,h.x,h.y,b.danger,42),bt(e,h.x,h.y,8,b.warn)}return Me(e),{ok:!0,reason:`${o.title} removed ${Math.min(10,a.length)} blocked cell(s).`}}return{ok:!1,reason:`${o.title} cannot be debug-granted.`}}function _r(e,t){if(t.type==="blockedCell")return`Blocked cell ${t.col},${t.row}`;if(t.type==="eggFarm")return`EGG #${t.id} L${t.level} -> L${t.level+1}`;if(t.type==="eggOutlet"){let n=Math.max(0,Number(t.farm?.extraEggOutlet)||0);return`EGG #${t.id} OUTLET ${1+n} -> ${2+n}`}if(t.type==="scanner")return`AUTO #${t.id} L${t.level} -> L${t.level+1} | CD ${St(t,e).toFixed(1)}s -> ${St({...t,level:t.level+1},e).toFixed(1)}s`;if(t.type==="facility"&&["mixer","sausageMaker"].includes(t.baseId||t.id)){let n=t.baseId||t.id,o=t.level||1,r=Ze(e);t.level=o+1;let i=Ze(e);return t.level=o,`${n==="mixer"?"MIXER":"SAUSAGE MACHINE"} L${t.level} -> L${t.level+1} | sausage ${x(r)} -> ${x(i)}`}if(t.type==="facility"&&(t.baseId||t.id)==="truck"){let n=t.level,o=Ve(e);t.level=n+1;let r=Ve(e);return t.level=n,`TRUCK L${t.level} -> L${t.level+1} | ${x(o)} -> ${x(r)}`}if(t.type==="facility"&&(t.baseId||t.id)==="trash"){let n=mt(e),o=Math.min(cn(),n+1),r=ht(n),i=ht(o);return`SHREDDER L${t.level||1} -> L${(t.level||1)+1} | expected ${x(r)} -> ${x(i)} per poop`}return`${t.name||t.id} L${t.level||1} -> L${(t.level||1)+1}`}function Ql(e){return[...e.blockedCells||[]].map(t=>{let[n,o]=String(t).split(",").map(Number);return{type:"blockedCell",id:t,col:n,row:o}}).filter(t=>Number.isFinite(t.col)&&Number.isFinite(t.row))}function et(e,t){let n=typeof t=="string"?Xt(t):t;return Ke(e),n?n.target==="blockedCell"?Ql(e):n.target==="eggFarm"?e.eggFarms.filter(o=>(o.level||1)<4):n.target==="eggOutlet"?e.eggFarms.filter(o=>Math.max(0,Number(o.extraEggOutlet)||0)<3).map(o=>({type:"eggOutlet",id:o.id,col:o.col,row:o.row,farm:o})):n.target==="autoScanner"?e.scanners.filter(o=>o.kind==="auto"):n.target==="mixer"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="mixer"):n.target==="truck"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="truck"):n.target==="sausageMaker"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="sausageMaker"):n.target==="trash"?gr(e)(o.baseId||o.id)==="trash"):[]:[]:[]}function Jl(e,t){let n=Ke(e);if(t.id==="crowdedFarming")return(n.crowdedFarming||0)>=10;if(t.id==="recyclingSubsidy")return(n.recyclingSubsidy||0)>=3;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,Ue.dudChancePerCard||0)),r=Math.max(1e-4,Math.min(1,Ue.dudChanceReductionPerFilter||.05));return(n.dudFilter||0)>=Math.ceil(o/r)}return t.id==="laborExploitation"?!!n.laborExploitation:t.id==="usedMachine"?!!n.usedMachineActive:t.id==="newMachine"?!n.usedMachineActive:!1}function Zl(e){return!!((e.maintenanceRooms||[]).length||(e.repairmen||[]).length||e.repairman?.active)}function Ls(e,t){return t==="conveyor"?(e.conveyorTiles?.size||0)>0:t==="autoScanner"?(e.scanners||[]).some(n=>n.kind==="auto"):t==="manualScanner"?(e.scanners||[]).some(n=>n.kind==="manual"):t==="eggFarm"?(e.eggFarms||[]).length>0:Object.values(e.facilities||{}).some(n=>(n.baseId||n.id)===t)}function ec(e,t){return!(t.requiresFacility&&!Ls(e,t.requiresFacility)||Array.isArray(t.requiresAnyFacility)&&!t.requiresAnyFacility.some(n=>Ls(e,n)))}function tc(e){return fn.filter(t=>!(t.id==="laborExploitation"&&!Zl(e)||!ec(e,t)||Jl(e,t)||(t.type==="equipmentUpgrade"||t.type==="cellAction")&&et(e,t).length<=0))}function Ns(e,t){return t.rarity==="ultraRare"?jl:t.rarity==="rare"?Xl:zl}function nc(e,t){let n=t.reduce((r,i)=>r+Ns(e,i),0);if(n<=0)return t[Math.floor(Math.random()*t.length)];let o=Math.random()*n;for(let r of t)if(o-=Ns(e,r),o<=0)return r;return t[t.length-1]}var _s=0;function oc(){return _s+=1,{id:`dud:${Date.now()}:${_s}`,title:"Dud",rarity:"dud",type:"dud",description:"Click to flick this dud away. It does not consume a pick."}}function rc(e){let t=Ke(e),n=Math.max(0,Math.min(1,Ue.dudChancePerCard||0)),o=Math.max(0,Math.min(1,Ue.dudChanceReductionPerFilter||0));return Math.max(0,n-o*Math.max(0,t.dudFilter||0))}function ic(e,t){let n=[...t],o=0,r=Math.max(0,Ue.maxDudsPerDraft||0),i=rc(e);for(let a=0;ac.id===i.id);a>=0&&r.splice(a,1)}return ic(e,o)}function wt(e){return e?e.type==="blockedCell"?`blockedCell:${e.id}`:e.type==="eggFarm"?`eggFarm:${e.id}`:e.type==="eggOutlet"?`eggOutlet:${e.id}`:e.type==="scanner"?`scanner:${e.id}`:e.type==="facility"?`facility:${e.id}`:`${e.type}:${e.id}`:""}function Gs(e){if(!e)return null;if(e.type==="blockedCell"){let t=$(e.col,e.row);return{x:t.x-f.cell*.48,y:t.y-f.cell*.48,w:f.cell*.96,h:f.cell*.96,cx:t.x,cy:t.y}}if(e.type==="eggFarm"||e.type==="eggOutlet"){let t=$(e.col,e.row);return{x:t.x-34,y:t.y-34,w:68,h:68,cx:t.x,cy:t.y}}if(e.type==="scanner"){let t=ge(e);return{x:t.x-48,y:t.y-48,w:96,h:96,cx:t.x,cy:t.y}}return e.type==="facility"?{x:e.x,y:e.y,w:e.w,h:e.h,cx:e.x+e.w/2,cy:e.y+e.h/2}:null}function Gr(e){if(!e.cardTargetPick?.pending)return[];if(e.cardTargetPick.mode==="autoScannerMenu"){let n=new Set(e.cardTargetPick.targetKeys||[]);return e.scanners.filter(o=>o.kind==="auto"&&n.has(wt(o))).map(o=>({key:wt(o),label:"AUTO ROUTE SETTINGS",target:o,bounds:Gs(o)})).filter(o=>o.bounds)}let t=new Set(e.cardTargetPick.targetKeys||[]);return et(e,e.cardTargetPick.cardId).filter(n=>t.has(wt(n))).map(n=>({key:wt(n),label:_r(e,n),target:n,bounds:Gs(n)})).filter(n=>n.bounds)}function sc(e,t){let n=Gr(e);for(let o of n){let r=o.bounds;if(t.x>=r.x&&t.x<=r.x+r.w&&t.y>=r.y&&t.y<=r.y+r.h)return o.target}return null}function Vs(e,t){if(t.type==="eggOutlet"){let n=t.farm||e.eggFarms.find(r=>r.id===t.id);if(!n)return;n.extraEggOutlet=Math.min(3,Math.max(0,Number(n.extraEggOutlet)||0)+1);let o=$(n.col,n.row);H(e,o.x,o.y-30,`OUTLET ${1+n.extraEggOutlet}`,b.green),Me(e);return}if(t.level=(t.level||1)+1,t.type==="eggFarm"){t.nextSpawn=Wt(t),t.lastInterval=t.nextSpawn;let n=$(t.col,t.row);H(e,n.x,n.y-30,`LV ${t.level}`,b.green);return}if(t.type==="scanner"){let n=ge(t);H(e,n.x,n.y-34,`LV ${t.level}`,b.green);return}t.type==="facility"&&H(e,t.x+t.w/2,t.y+18,`LV ${t.level}`,b.green)}function zs(e,t){let n=Ke(e),o=r=>{n[r]=Math.max(0,n[r]||0)+1};if(t.id==="bearing"&&o("bearing"),t.id==="autoScannerTuning"&&o("autoScannerTuning"),t.id==="legalWork"&&o("legalWork"),t.id==="crowdedFarming"&&(n.crowdedFarming=Math.min(10,(n.crowdedFarming||0)+1)),t.id==="hatchingFeed"&&o("hatchingFeed"),t.id==="poopRateBooster"&&o("poopRateBooster"),t.id==="safetyCover"&&o("safetyCover"),t.id==="recyclingSubsidy"&&(n.recyclingSubsidy=Math.min(3,(n.recyclingSubsidy||0)+1)),t.id==="chemicalWeaponSubsidy"&&o("chemicalWeaponSubsidy"),t.id==="preventiveMaintenance"&&o("preventiveMaintenance"),t.id==="dudFilter"&&o("dudFilter"),t.id==="durabilityCoating"&&(o("durabilityCoating"),Re(e)),t.id==="sparePartsBin"){o("sparePartsBin");let r=$s(e,.02);e.stats.sparePartsRepair=(e.stats.sparePartsRepair||0)+r,e.totals.sparePartsRepair=(e.totals.sparePartsRepair||0)+r,H(e,f.x+f.cols*f.cell/2,f.y-30,"REPAIR +2%",b.green)}t.id==="dudRefund"&&o("dudRefund"),t.id==="freeReroll"&&o("freeReroll"),t.id==="composter"&&o("composter"),t.id==="scannerQueueSpacing"&&o("scannerQueueSpacing"),t.id==="flattery"&&o("fairiesFlatteryNext"),t.id==="usedMachine"&&(n.usedMachineActive=!0),t.id==="newMachine"&&(n.usedMachineActive=!1),t.id==="laborExploitation"&&(n.laborExploitation=1),t.id==="rescueLoan"&&(o("rescueLoanCharges"),H(e,f.x+f.cols*f.cell/2,f.y-30,"RESCUE HELD",b.green))}function ot(e){return`${Math.round(Number(e||0)*100)}%`}function Us(e){let t=Et[Math.max(0,Math.min(Et.length-1,e-1))]||Et[0]||[0,0];return`${t[0].toFixed(2)}-${t[1].toFixed(2)}s`}function Ws(e,t){return Math.ceil(e*Math.pow(xe.incomeUpgradeRate,Math.max(0,t-1)))}function Or(e,t,n){let r=et(e,t==="mixer"?"upgradeMixer":t==="sausageMaker"?"upgradeSausageMaker":"upgradeTruck")[0];if(!r)return{before:Ws(n,1),after:Ws(n,2)};let i=()=>t==="truck"?Ve(e):Ze(e),a=i(),c=r.level||1;r.level=c+1;let h=i();return r.level=c,{before:a,after:h}}function ac(e,t){let n=Ke(e);if(t.id==="upgradeEgg"){let o=et(e,t),r=Math.min(3,Math.max(1,o[0]?.level||1));return`Choose one EGG. Level +1. Production interval ${Us(r)} -> ${Us(r+1)}.`}if(t.id==="upgradeAutoScanner"){let o=et(e,t)[0]||{level:1},r=St(o,e),i=St({...o,level:(o.level||1)+1},e);return`Choose one AUTO SCANNER. Level +1. Cooldown ${r.toFixed(2)}s -> ${i.toFixed(2)}s.`}if(t.id==="upgradeMixer"){let o=Or(e,"mixer",xe.income.sausage);return`Choose one MIXER. Meat quality +10%. Sausage sale value ${x(o.before)} -> ${x(o.after)}.`}if(t.id==="upgradeSausageMaker"){let o=Or(e,"sausageMaker",xe.income.sausage);return`Choose one SAUSAGE MACHINE. Product value +10%. Sausage sale value ${x(o.before)} -> ${x(o.after)}.`}if(t.id==="upgradeTruck"){let o=Or(e,"truck",xe.income.truck);return`Choose one TRUCK. Earning +10%. Correct shipment income ${x(o.before)} -> ${x(o.after)}.`}if(t.id==="upgradeTrash"){let o=mt(e),r=Math.min(cn(),o+1),i=ht(o),a=ht(r),c=Math.round(qt(o)*100),h=Math.round(qt(r)*100);return`SHREDDER level +1. Expected value ${x(i)} -> ${x(a)} per poop; hit chance ${c}% -> ${h}%.`}if(t.id==="bearing"){let o=Math.min(tn,Jn*Math.pow(Zn,Math.max(0,n.bearing||0))),r=Math.min(tn,Jn*Math.pow(Zn,Math.max(0,(n.bearing||0)+1)));return`Conveyor speed +7.5%. After pick: ${o.toFixed(1)} -> ${r.toFixed(1)} px/s.`}if(t.id==="legalWork"){let o=Math.max(0,n.legalWork||0);return`Fairies tribute profit exemption +${x(250)}. After pick: exemption bonus ${x(250*(o+1))}.`}if(t.id==="crowdedFarming"){let o=Math.min(10,(n.crowdedFarming||0)+1);return`Held ${n.crowdedFarming||0}/10. After pick: EGG interval ${ot(Math.max(.5,1-.05*o))}, deterioration ${ot(Math.min(1.4,1+.04*o))}.`}if(t.id==="extraEggOutlet"){let o=et(e,t),r=Math.max(0,Number(o[0]?.farm?.extraEggOutlet)||0);return`Choose one EGG. Output ports ${1+r} -> ${2+r}. Max 4 ports per EGG.`}if(t.id==="hatchingFeed")return`Held ${n.hatchingFeed||0}. After pick: EGG interval ${ot(Math.pow(.96,(n.hatchingFeed||0)+1))}, poop rate multiplier ${ot(Math.pow(1.03,(n.hatchingFeed||0)+1))}.`;if(t.id==="poopRateBooster")return`Held ${n.poopRateBooster||0}. After pick: base poop rate +${Math.round((n.poopRateBooster||0)+1)*4} percentage points.`;if(t.id==="autoScannerTuning")return`Held ${n.autoScannerTuning||0}. After pick: all AUTO SCANNER default cooldown ${ot(Math.pow(Yo,(n.autoScannerTuning||0)+1))}.`;if(t.id==="safetyCover")return`Held ${n.safetyCover||0}. After pick: explosion damage ${ot(Math.pow(.95,(n.safetyCover||0)+1))}.`;if(t.id==="recyclingSubsidy")return`Held ${n.recyclingSubsidy||0}/3. After pick: normal SELL refund ${Math.round(Math.min(.8,.5+.1*((n.recyclingSubsidy||0)+1))*100)}%.`;if(t.id==="chemicalWeaponSubsidy")return`Held ${n.chemicalWeaponSubsidy||0}. After pick: ${x(1200*((n.chemicalWeaponSubsidy||0)+1))} per 70 truck-shipped poop each day.`;if(t.id==="preventiveMaintenance")return`Held ${n.preventiveMaintenance||0}. After pick: deterioration speed ${ot(Math.pow(.95,(n.preventiveMaintenance||0)+1))}.`;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,Ue.dudChancePerCard||0)),r=Math.max(0,Math.min(1,Ue.dudChanceReductionPerFilter||.05)),i=Math.max(0,n.dudFilter||0),a=Math.max(0,o-r*i),c=Math.max(0,o-r*(i+1));return`Held ${i}. DUD chance per card ${ot(a)} -> ${ot(c)}.`}return t.id==="durabilityCoating"?`Held ${n.durabilityCoating||0}. After pick: maximum durability ${ot(Math.pow(1.03,(n.durabilityCoating||0)+1))}.`:t.id==="sparePartsBin"?`Held ${n.sparePartsBin||0}. Immediately restores 2% durability to every maintained machine. Common card weight.`:t.id==="dudRefund"?`Held ${n.dudRefund||0}. After pick: DUD clicks award ${x(50*((n.dudRefund||0)+1))}.`:t.id==="freeReroll"?`Held ${n.freeReroll||0}. After pick: each card screen starts with ${(n.freeReroll||0)+1} free reroll${(n.freeReroll||0)+1===1?"":"s"}.`:t.id==="composter"?`Held ${n.composter||0}. After pick: SHREDDER poop grants ${x(3*((n.composter||0)+1))}.`:t.id==="scannerQueueSpacing"?`Held ${n.scannerQueueSpacing||0}. After pick: Manual/Auto Scanner queue spacing ${ot(Math.pow(.85,(n.scannerQueueSpacing||0)+1))}.`:t.id==="flattery"?`Next Fairies tribute -50%. Held for next tribute: ${n.fairiesFlatteryNext||0}.`:t.id==="usedMachine"?"Enable Used Machines: future equipment costs 50%, has no SELL refund, and starts with 60% durability.":t.id==="newMachine"?"Cancel Used Machines. Future equipment returns to normal price, refund, and durability.":t.id==="laborExploitation"?"Repairman dispatch paperwork is streamlined. Repair rooms keep operating; one time only.":t.id==="rescueLoan"?`At day-end bankruptcy check, gain ${x(500)} if cash is below ${x(0)}. Held: ${n.rescueLoanCharges||0}.`:t.id==="dynamite"?"Choose any blocked tiles on the map and destroy up to 3. Empty-space clicks are ignored; press Esc to finish after at least one blast.":t.description}function Lr(e,t){let n=e.cardDraft?.choices||[],o=n.findIndex(r=>r.id===t.id);o>=0&&n.splice(o,1)}function Xs({game:e,ui:t,onUpdatePanels:n}){function o(){n&&n()}function r(){Ke(e),e.cardTargetPick=null,e.cardDraft={pending:!0,choices:To(e,zt),rerolls:0,freeRerolls:dn(e,"freeReroll"),picksRemaining:1}}function i(){Ke(e),e.cardDraft.pending=!1,e.cardDraft.choices=[],e.cardDraft.picksRemaining=0,e.cardTargetPick=null,t.modal.classList.remove("visible","equipment-popover"),o()}function a(D=zt){Ke(e),e.cardDraft.choices=To(e,D)}function c(){Ke(e),!e.cardDraft.choices.length&&e.cardDraft.picksRemaining>0&&a(zt)}function h(D){Lr(e,D),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1),e.cardTargetPick=null,c(),e.cardDraft.picksRemaining<=0?i():ue()}function g(D){Lr(e,D),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1)+Ue.extraCardsAddedPicks,e.cardDraft.choices.push(...To(e,2)),ue()}function C(D,U){let ee=dn(e,"dudRefund")*50;if(ee>0){let O=je(e,ee);e.stats.dudRefundIncome=(e.stats.dudRefundIncome||0)+O,e.totals.dudRefundIncome=(e.totals.dudRefundIncome||0)+O,H(e,f.x+f.cols*f.cell/2,f.y-30,`DUD REFUND +${x(O)}`,b.green)}Yt(e,34,.62),document.body?.animate&&document.body.animate([{transform:"translate(0, 0)"},{transform:"translate(-10px, 7px)"},{transform:"translate(12px, -8px)"},{transform:"translate(-8px, -5px)"},{transform:"translate(9px, 6px)"},{transform:"translate(0, 0)"}],{duration:260,easing:"steps(5, end)"}),U&&(U.style.setProperty("--fling-x",`${260+Math.random()*260}px`),U.style.setProperty("--fling-y",`${-260-Math.random()*170}px`),U.style.setProperty("--fling-r",`${(Math.random()<.5?-1:1)*(52+Math.random()*38)}deg`),U.classList.add("flung")),window.setTimeout(()=>{Lr(e,D),c(),ue()},340)}function P(D,U=null){if(D.type==="dud")return C(D,U);if(D.id==="extraCards")return g(D);if(D.type==="equipmentUpgrade"||D.type==="cellAction")return L(D);zs(e,D),h(D)}function L(D){let U=et(e,D);U.length&&(e.cardTargetPick={pending:!0,cardId:D.id,mode:D.target==="blockedCell"?"blockedCell":"equipment",targetKeys:U.map(wt),remaining:D.id==="dynamite"?Math.min(10,U.length):1,used:0},t.modal.classList.remove("visible","equipment-popover"),o())}function K(D){if(!D||D.type!=="blockedCell")return!1;let U=I(D.col,D.row);if(!e.blockedCells?.has(U))return!1;e.blockedCells.delete(U);let ee=$(D.col,D.row);return vt(e,ee.x,ee.y),at(e,ee.x,ee.y,b.danger,62),bt(e,ee.x,ee.y,18,b.warn),mo(e,ee.x,ee.y,8),Yt(e,16,.35),H(e,ee.x,ee.y-18,"BOOM",b.danger),Me(e),e.cardTargetPick.remaining=Math.max(0,(e.cardTargetPick.remaining||1)-1),e.cardTargetPick.used=Math.max(0,e.cardTargetPick.used||0)+1,e.cardTargetPick.targetKeys=et(e,"dynamite").map(wt),o(),!0}function j(D){if(!e.cardTargetPick?.pending)return!1;let U=Xt(e.cardTargetPick.cardId),ee=sc(e,D);return U?U.id==="dynamite"?(!ee||!K(ee)||((e.cardTargetPick.remaining||0)<=0||!et(e,"dynamite").length)&&h(U),!0):ee?(Vs(e,ee),h(U),!0):(Z(),!0):(Z(),!0)}function Z(){if(!e.cardTargetPick?.pending)return;let D=e.cardTargetPick,U=Xt(D.cardId);if(U?.id==="dynamite"&&(D.used||0)>0){h(U);return}e.cardTargetPick=null,ue()}function Q(){let D=Math.max(0,e.cardDraft?.freeRerolls||0);if(D>0){e.cardDraft.freeRerolls=D-1,e.cardDraft.rerolls+=1,a(zt),ue();return}let U=Os(e);e.cash${U.alt||

`:``}function le(D,U){let ee=document.createElement("button");ee.type="button";let O=D.type==="dud"?"dud":D.rarity==="ultraRare"?"ultra-rare":D.rarity==="rare"?"rare":"common";ee.className=`card-choice ${O}`;let G=D.type==="dud"?"MISS":D.rarity==="ultraRare"?"ULTRA RARE":D.rarity==="rare"?"RARE":"COMMON",Y=[G,...(D.tags||[]).filter(ie=>ie!==G)].slice(0,5);return ee.innerHTML=`${pe(D)}
${D.title}
${Y.map(ie=>`${ie}`).join("")}
${ac(e,D)}
`,ee.addEventListener("click",()=>P(D,ee)),ee.dataset.index=String(U),ee}function ue(){Ke(e),e.cardTargetPick=null,e.cardDraft?.pending||r(),e.cardDraft.choices?.length||a(zt);let D=e.cardDraft.choices||[],U=Os(e),ee=Math.max(0,e.cardDraft?.freeRerolls||0),O=Math.max(1,e.cardDraft.picksRemaining||1);t.modalTitle.textContent="Choose Upgrade Card",t.modalBody.innerHTML=`

Choose ${O} card${O===1?"":"s"} before Build phase. Dud cards can be flicked away without consuming a pick. Equipment cards target machines; Dynamite targets blocked cells.

`;let G=t.modalBody.querySelector("#cardChoices");D.forEach((De,me)=>G.appendChild(le(De,me))),t.modalActions.innerHTML="";let Y=document.createElement("button");Y.type="button",Y.className="facility-action warn reroll-button",Y.textContent=ee>0?`Reroll (FREE x${ee})`:`Reroll ${x(U)}`,Y.disabled=ee<=0&&e.cash0?`${ee} free reroll${ee===1?"":"s"} remaining.`:Y.disabled?"Not enough cash":"",Y.addEventListener("click",Q),t.modalActions.appendChild(Y);let ie=document.createElement("button");ie.type="button",ie.className="facility-action",ie.textContent="No Card",ie.title="Skip this upgrade pick and enter Build phase.",ie.addEventListener("click",i),t.modalActions.appendChild(ie),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible")}return{prepareDraft:r,showDraft:ue,finishDraft:i,chooseTargetAtPoint:j,cancelTargetPick:Z}}var js=[[{key:"a",code:"KeyA",label:"A"},{key:"d",code:"KeyD",label:"D"}],[{key:"arrowleft",code:"ArrowLeft",label:"Left"},{key:"arrowright",code:"ArrowRight",label:"Right"}],[{key:"j",code:"KeyJ",label:"J"},{key:"l",code:"KeyL",label:"L"}],[{key:"f",code:"KeyF",label:"F"},{key:"h",code:"KeyH",label:"H"}],[{key:"q",code:"KeyQ",label:"Q"},{key:"e",code:"KeyE",label:"E"}],[{key:"z",code:"KeyZ",label:"Z"},{key:"x",code:"KeyX",label:"X"}],[{key:"u",code:"KeyU",label:"U"},{key:"o",code:"KeyO",label:"O"}],[{key:"n",code:"KeyN",label:"N"},{key:"m",code:"KeyM",label:"M"}]];function lc(e){let t=js[e]||js[0];return{left:{...t[0]},right:{...t[1]}}}function Qs(e,t,n){let o={type:"eggFarm",id:e.nextId++,col:t,row:n,level:1,nextSpawn:2,lastInterval:2,extraEggOutlet:0,price:Rt.eggFarm,builtSession:e.buildSession};return o.nextSpawn=Wt(o),o.lastInterval=o.nextSpawn,o}function Js(e,t,n,o){let r=o==="auto"?Te.autoScanner.price:Te.manualScanner.price,i=new Set(e.scanners.filter(c=>c.kind==="manual").map(c=>c.slot)),a=0;for(;i.has(a);)a+=1;return{type:"scanner",id:e.nextId++,kind:o,slot:o==="manual"?a:null,role:o==="manual"?a%2:0,col:t,row:n,level:1,queue:[],cooldown:0,price:r,builtSession:e.buildSession,autoMode:"standard",keys:o==="manual"?lc(a):null}}function cc(e,t,n){let o=n.x-t.x,r=n.y-t.y,i=o*o+r*r,a=i>0?Math.max(0,Math.min(1,((e.x-t.x)*o+(e.y-t.y)*r)/i)):0,c=t.x+o*a,h=t.y+r*a;return Math.hypot(e.x-c,e.y-h)}function uc(e){let t=[],n=e?.ownedCells?.size?[...e.ownedCells].map(o=>{let[r,i]=String(o).split(",").map(Number);return{col:r,row:i}}):Array.from({length:f.cols*f.rows},(o,r)=>({col:r%f.cols,row:Math.floor(r/f.cols)}));for(let o of n){let r=f.x+o.col*f.cell,i=f.y+o.row*f.cell,a=r+f.cell,c=i+f.cell;Ye(e,o.col-1,o.row)||t.push({side:"left",entry:o,a:{x:r,y:i},b:{x:r,y:c}}),Ye(e,o.col+1,o.row)||t.push({side:"right",entry:o,a:{x:a,y:i},b:{x:a,y:c}}),Ye(e,o.col,o.row-1)||t.push({side:"top",entry:o,a:{x:r,y:i},b:{x:a,y:i}}),Ye(e,o.col,o.row+1)||t.push({side:"bottom",entry:o,a:{x:r,y:c},b:{x:a,y:c}})}return t}function Eo(e,t=null){let n=uc(t);if(n.length){let L=n.map(K=>({...K,distance:cc(e,K.a,K.b)})).sort((K,j)=>K.distance-j.distance)[0];return{side:L.side,entry:{...L.entry}}}let o=(e.x-f.x)/f.cell,r=(e.y-f.y)/f.cell,i=Math.max(0,Math.min(f.cols-1,Math.round(o-.5))),a=Math.max(0,Math.min(f.rows-1,Math.round(r-.5))),c=Math.abs(e.x-f.x),h=Math.abs(e.x-(f.x+f.cols*f.cell)),g=Math.abs(e.y-f.y),C=Math.abs(e.y-(f.y+f.rows*f.cell)),P=[["left",c],["right",h],["top",g],["bottom",C]].sort((L,K)=>L[1]-K[1])[0][0];return P==="left"?{side:P,entry:{col:0,row:a}}:P==="right"?{side:P,entry:{col:f.cols-1,row:a}}:P==="top"?{side:P,entry:{col:i,row:0}}:{side:P,entry:{col:i,row:f.rows-1}}}function Ur(e){return e?.baseId||e?.id||""}function yn(e){return e?.gridPlaced&&(e.wCells=Math.max(1,e.wCells||3),e.hCells=Math.max(1,e.hCells||3),e.x=f.x+e.col*f.cell,e.y=f.y+e.row*f.cell,e.w=e.wCells*f.cell,e.h=e.hCells*f.cell,Ur(e)==="sausageMaker"&&(e.entry={col:e.col-1,row:e.row+Math.floor(e.hCells/2)},e.side="grid")),e}function Ro(e){if(!e?.gridPlaced)return[];let t=[];for(let n=0;n<(e.hCells||3);n+=1)for(let o=0;o<(e.wCells||3);o+=1)t.push({col:e.col+o,row:e.row+n});return t}function dc(e,t){if(Ur(e)!=="mixer")return;let n=e.baseW||e.w||168,o=e.baseH||e.h||110;e.baseW=n,e.baseH=o;let r=t==="top"||t==="bottom";e.w=r?Math.max(n,o):Math.min(n,o),e.h=r?Math.min(n,o):Math.max(n,o)}function Po(e,t="input"){if(!e)return null;let n=Ur(e);return n==="mixer"?e.side==="top"||e.side==="bottom"?t==="input"?{x:e.x+e.w/2,y:e.y}:{x:e.x+e.w/2,y:e.y+e.h}:t==="input"?{x:e.x,y:e.y+e.h/2}:{x:e.x+e.w,y:e.y+e.h/2}:n==="sausageMaker"&&e.gridPlaced?t==="input"?{x:e.x,y:e.y+e.h/2}:{x:e.x+e.w,y:e.y+e.h/2}:{x:e.x+e.w/2,y:e.y+e.h/2}}function Ao(e,t,n){dc(e,n);let o={x0:f.x+t.col*f.cell,y0:f.y+t.row*f.cell,x1:f.x+(t.col+1)*f.cell,y1:f.y+(t.row+1)*f.cell},r={x:(o.x0+o.x1)/2,y:(o.y0+o.y1)/2};return e.entry={...t},e.side=n,n==="left"?(e.x=o.x0-e.w-18,e.y=r.y-e.h/2):n==="right"?(e.x=o.x1+18,e.y=r.y-e.h/2):n==="top"?(e.x=r.x-e.w/2,e.y=o.y0-e.h-18):(e.x=r.x-e.w/2,e.y=o.y1+18),e}function Zs(e,t,n,o){let{entry:r,side:i}=Eo(n,e),a=Te[t],c=a?{name:a.name,w:a.body?.w||168,h:a.body?.h||110,price:a.price}:{name:t[0].toUpperCase()+t.slice(1),w:168,h:110,price:o},h={type:"facility",id:t,name:c.name,x:0,y:0,w:c.w,h:c.h,baseW:c.w,baseH:c.h,level:1,price:o||c.price,builtSession:e.buildSession};return Ao(h,r,i)}function ea(e,t,n,o,r){let i=Te[t],a={type:"facility",id:t,name:i?.name||t,baseId:t,col:n,row:o,wCells:t==="sausageMaker"?3:1,hCells:t==="sausageMaker"?3:1,gridPlaced:!0,level:1,price:r||i?.price||0,builtSession:e.buildSession};return yn(a)}function jt(e){return e?[{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}]:[]}function ta(e,t,n){return{type:"maintenanceRoom",id:e.nextId++,col:t,row:n,price:Rt.maintenanceRoom,builtSession:e.buildSession,wCells:2,hCells:2}}function fc(e){return Math.random()({x:i.x,y:i.y})),r=o[0];return{id:e.nextId++,sex:n,x:r.x,y:r.y,route:o,targetIndex:o.length>1?1:o.length,stage:t.stage||"belt",scannerId:t.scannerId??null,nextScannerId:null,pendingScannerId:null,radius:n==="poop"?15:17,bob:Math.random()*Math.PI*2,queueIndex:-1,queueRoute:null}}var pc=!0,yc={chickMale:"./assets/images/chick_male.png",chickFemale:"./assets/images/chick_female.png",poop:"./assets/images/poop.png",conveyorStraightH:"./assets/dark_factory/facilities/conveyor/conveyor_straight_h_16.png",conveyorStraightV:"./assets/dark_factory/facilities/conveyor/conveyor_straight_v_16.png",conveyorTurnNe:"./assets/dark_factory/facilities/conveyor/conveyor_turn_ne_16.png",conveyorTurnNw:"./assets/dark_factory/facilities/conveyor/conveyor_turn_nw_16.png",conveyorTurnSe:"./assets/dark_factory/facilities/conveyor/conveyor_turn_se_16.png",conveyorTurnSw:"./assets/dark_factory/facilities/conveyor/conveyor_turn_sw_16.png",boostConveyorStraightH:"./assets/dark_factory/facilities/conveyor/boost_conveyor_straight_h_16.png",boostConveyorStraightV:"./assets/dark_factory/facilities/conveyor/boost_conveyor_straight_v_16.png",boostConveyorTurnNe:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_ne_16.png",boostConveyorTurnNw:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_nw_16.png",boostConveyorTurnSe:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_se_16.png",boostConveyorTurnSw:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_sw_16.png",scannerManual:"./assets/dark_factory/facilities/machines/manual_scanner_32x48.png",scannerAuto:"./assets/dark_factory/facilities/machines/auto_scanner_32x48.png",eggFarm:"./assets/dark_factory/facilities/machines/egg_farm_16.png",mixer:"./assets/dark_factory/facilities/machines/mixer_32.png",shredder:"./assets/dark_factory/facilities/machines/shredder_32.png",truck:"./assets/dark_factory/facilities/vehicles/truck_32.png",maintenanceRoom:"./assets/dark_factory/facilities/utility/maintenance_room_32.png",repairman:"./assets/dark_factory/facilities/utility/repairman_16.png",obstacleCrate:"./assets/dark_factory/facilities/utility/obstacle_crate_16.png"},Pe={};for(let[e,t]of Object.entries(yc)){let n=new Image;n.loaded=!1,n.onerror=()=>{n.loaded=!1},pc&&t&&(n.onload=()=>{n.loaded=!0},n.src=t),Pe[e]=n}function qr(e){return e.frameCache||(e.frameCache={}),e.frameCache.draw||(e.frameCache.draw={}),e.frameCache.draw}function Yr(e,t){let n=document.createElement("canvas");return n.width=Math.max(1,Math.ceil(e)),n.height=Math.max(1,Math.ceil(t)),n}function sa(e,t,n,o){e.imageSmoothingEnabled=!1,e.clearRect(0,0,t.width,t.height),Sc(e,t,n),e.save();let r=n.shake.time>0?z(-n.shake.strength,n.shake.strength):0,i=n.shake.time>0?z(-n.shake.strength,n.shake.strength):0,a=n.view?.scale||1;e.translate((n.view?.x||0)+r,(n.view?.y||0)+i),e.scale(a,a),Mc(e,n),xc(e,n),Ic(e,n),Uc(e,n),jc(e,n),Qc(e,n),Wc(e,n),Kc(e,n),mc(e,n),ou(e,n,o.activeQueuedChick),fu(e,n),lu(e,t,n),au(e,n,o.selectedObject,o.selectedTitle),cu(e,n),uu(e,n),du(e,n),e.restore(),yu(e,n,t)}function hc(e){if(e.type==="eggFarm"){let n=$(e.ref.col,e.ref.row);return{x:n.x-34,y:n.y-34,w:68,h:68,cx:n.x,cy:n.y}}let t=e.ref;return{x:t.x,y:t.y,w:t.w,h:t.h,cx:t.x+t.w/2,cy:t.y+t.h/2}}function mc(e,t){if(t.phase!=="build")return;let n=an(t);for(let o of n){let r=hc(o);e.save(),e.fillStyle="rgba(196,36,36,.22)",e.strokeStyle=b.danger,e.lineWidth=5,e.setLineDash([10,6]),X(e,r.x,r.y,r.w,r.h,!0,!0),e.setLineDash([]),e.fillStyle=b.danger,e.strokeStyle=b.white,e.lineWidth=4,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.strokeText("!",r.cx,r.y+24),e.fillText("!",r.cx,r.y+24),e.font="900 11px ui-monospace, monospace",e.strokeText("NO ROUTE",r.cx,r.y+r.h-8),e.fillText("NO ROUTE",r.cx,r.y+r.h-8),e.restore()}}function X(e,t,n,o,r,i=!0,a=!0){e.beginPath(),e.rect(t,n,o,r),i&&e.fill(),a&&e.stroke()}function Hr(e,t,n,o,r=b.ink){e.save(),e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.lineWidth=4,e.strokeStyle=b.white,e.fillStyle=r,e.strokeText(o,t,n),e.fillText(o,t,n),e.restore()}function Qt(e,t,n,o,r,i){if(!t?.loaded)return!1;let a=e.imageSmoothingEnabled;return e.imageSmoothingEnabled=!1,e.drawImage(t,Math.round(n),Math.round(o),Math.round(r),Math.round(i)),e.imageSmoothingEnabled=a,!0}function bc(e,t,n,o,r,i,a=null,c=1){e.fillStyle=i,e.fillRect(Math.round(t),Math.round(n),Math.round(o),Math.round(r)),a&&(e.strokeStyle=a,e.lineWidth=c,e.strokeRect(Math.round(t)+.5,Math.round(n)+.5,Math.round(o)-1,Math.round(r)-1))}function vc(e,t){let n=(Math.imul(e+37,73856093)^Math.imul(t+71,19349663))>>>0;return n^=n>>>13,n>>>0}function wc(e,t,n,o,r){let i=vc(o,r);if(i%67!==0)return;let a=10+(i>>>4)%Math.max(1,f.cell-22),c=10+(i>>>9)%Math.max(1,f.cell-22),h=(i>>>14)%16*Math.PI/16;e.save(),e.globalAlpha=.38,e.fillStyle="#4a8d37",e.strokeStyle="rgba(30,66,27,.34)",e.lineWidth=1,e.beginPath();for(let C=0;C<8;C+=1){let P=h+C*Math.PI/4,L=3.5+(i>>>C+2&3),K=t+a+Math.cos(P)*L*1.35,j=n+c+Math.sin(P)*L*.75;C===0?e.moveTo(K,j):e.lineTo(K,j)}e.closePath(),e.fill(),e.stroke();let g=4+(i>>>24)%5;for(let C=0;C>>C+8&3)*.18,L=10+(i>>>C+11&10),K=.9+(i>>>C+17&3)*.35;e.beginPath(),e.arc(t+a+Math.cos(P)*L,n+c+Math.sin(P)*L*.72,K,0,Math.PI*2),e.fill()}e.fillStyle="rgba(151,218,101,.26)",e.beginPath(),e.arc(t+a-2,n+c-2,1.7,0,Math.PI*2),e.fill(),e.restore()}function oa(e,t){e.fillStyle=b.bg,e.fillRect(0,0,t.width,t.height),e.save(),e.globalAlpha=.85;for(let n=0;na.col)),o=Math.max(...t.map(a=>a.col)),r=Math.min(...t.map(a=>a.row)),i=Math.max(...t.map(a=>a.row));return{x:f.x+n*f.cell-6,y:f.y+r*f.cell-6,w:(o-n+1)*f.cell+12,h:(i-r+1)*f.cell+12}}function Mc(e,t){let n=qr(t),o=gc(t);if(!n.grid||n.grid.signature!==o){let a=Cc(t),c=Yr(a.w,a.h),h=c.getContext("2d");h.translate(-a.x,-a.y),kc(h,t),n.grid={signature:o,bounds:a,layer:c}}let{bounds:r,layer:i}=n.grid;e.drawImage(i,r.x,r.y)}function xc(e,t){if(t.phase!=="build"||t.cardDraft?.pending||t.cardTargetPick?.pending)return;let n=ro(t),o=t.cash>=n,r=i=>{let a=dt(i);return Object.values(t.facilities||{}).some(c=>{let h=c?.baseId||c?.id;return["mixer","trash","truck"].includes(h)?!(a.x+a.w<=c.x||c.x+c.w<=a.x||a.y+a.h<=c.y||c.y+c.h<=a.y):!1})};for(let i of Ut(t)){let a=r(i),c=dt(i);e.save(),e.fillStyle=a?"rgba(112,130,118,.34)":o?"rgba(118,226,142,.36)":"rgba(255,255,255,.18)",e.strokeStyle=a?"#708278":o?"#6bd579":b.muted,e.lineWidth=5,e.setLineDash([16,10]),X(e,c.x,c.y,c.w,c.h,!0,!0),e.setLineDash([]);let h=tr(i),g=h.cx,C=h.cy;e.fillStyle="rgba(255,255,255,.94)",e.strokeStyle=b.ink,e.lineWidth=4,X(e,h.x,h.y,h.w,h.h,!0,!0),e.fillStyle=a?"#7c9285":o?b.green:b.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center";let P=i.direction==="left"?"BUY LEFT LOT":i.direction==="right"?"BUY RIGHT LOT":i.direction==="down"?"BUY LOWER LOT":"BUY UPPER LOT";e.fillText(P,g,C-12),e.fillStyle=b.ink,e.font="900 16px ui-monospace, monospace",e.fillText(`${x(n)} / 10\xD710`,g,C+15),e.restore()}}function kt(e,t,n,o,r,i,a=0){let c=un(i);c<.5||(e.save(),e.globalAlpha=Math.min(.62,.12+c*.54),e.fillStyle="#6b4a23",a>0?(e.beginPath(),e.roundRect?.(t,n,o,r,a),e.roundRect?e.fill():X(e,t,n,o,r,!0,!1)):X(e,t,n,o,r,!0,!1),e.globalAlpha=Math.min(.9,.25+c*.6),e.strokeStyle="#3a2a16",e.lineWidth=Math.max(2,Math.floor(2+c*5)),e.setLineDash([5,6]),X(e,t+3,n+3,o-6,r-6,!1,!0),e.restore())}function Wr(e,t){let n=e.componentLookup?.get(t);return(n?e.congestion.get(n):null)?.ratio||0}function Tc(e,t,n={}){let o=Wn(e,t).sort(),i=n.kind==="boostConveyor"?"boostConveyor":"conveyor",a=c=>o.includes(c);if(o.length===2){if(a("left")&&a("right"))return Pe[`${i}StraightH`];if(a("up")&&a("down"))return Pe[`${i}StraightV`];if(a("up")&&a("right"))return Pe[`${i}TurnNe`];if(a("up")&&a("left"))return Pe[`${i}TurnNw`];if(a("down")&&a("right"))return Pe[`${i}TurnSe`];if(a("down")&&a("left"))return Pe[`${i}TurnSw`]}return o.length===1?a("up")||a("down")?Pe[`${i}StraightV`]:Pe[`${i}StraightH`]:a("up")||a("down")?Pe[`${i}StraightV`]:Pe[`${i}StraightH`]}function Ec(e){let t=Object.entries(Pe).filter(([o])=>o.includes("conveyor")||o.includes("Conveyor")).map(([o,r])=>`${o}:${r.loaded?1:0}`).join("|"),n=[...e.conveyorTiles].sort().map(o=>{let r=e.conveyorMeta.get(o)||{};return`${o}:${r.kind||""}:${r.dir||""}:${(r.outDirs||[]).join(",")}:${r.branchMode||""}`}).join("|");return`${e.routingVersion||0};${t};${n}`}function Rc(e){if(!e.conveyorTiles?.size)return{x:0,y:0,w:1,h:1};let t=[...e.conveyorTiles].map(re),n=Math.min(...t.map(a=>a.col)),o=Math.max(...t.map(a=>a.col)),r=Math.min(...t.map(a=>a.row)),i=Math.max(...t.map(a=>a.row));return{x:f.x+n*f.cell-36,y:f.y+r*f.cell-36,w:(o-n+1)*f.cell+72,h:(i-r+1)*f.cell+72}}function Pc(e){let t=[],n=new Set;for(let i of e.conveyorTiles){let{col:a,row:c}=re(i);for(let h of fe){let g={col:a+h.dc,row:c+h.dr},C=I(g.col,g.row);if(!e.conveyorTiles.has(C))continue;let P=[i,C].sort().join("|");n.has(P)||(n.add(P),t.push({fromKey:i,toKey:C,a:$(a,c),b:$(g.col,g.row)}))}}let o=Nc(e),r=[...e.conveyorTiles].map(i=>{let a=re(i),c=$(a.col,a.row),h=e.conveyorMeta.get(i)||{},g=Wn(e,i);return{k:i,c,meta:h,connectedDirs:g,branchDirs:Dc(e,i,g),markers:o.get(i)||[],sprite:Tc(e,i,h)}});return{edges:t,tiles:r}}function Ac(e,t){e.save(),e.lineCap="round",e.lineJoin="round";for(let n of[{width:31,color:"#0b0c0f",alpha:1},{width:23,color:"#444b56",alpha:1},{width:15,color:"#171a1f",alpha:1}]){e.globalAlpha=n.alpha,e.strokeStyle=n.color,e.lineWidth=n.width;for(let o of t.edges)e.beginPath(),e.moveTo(o.a.x,o.a.y),e.lineTo(o.b.x,o.b.y),e.stroke()}e.globalAlpha=1;for(let n of t.tiles){let{c:o,meta:r,sprite:i}=n;e.fillStyle="rgba(0,0,0,.35)",e.strokeStyle="rgba(255,184,39,.34)",e.lineWidth=1,X(e,o.x-20,o.y-20,40,40,!0,!0),Qt(e,i,o.x-19,o.y-19,38,38)||(e.fillStyle=r.kind==="boostConveyor"?"#315e92":"#454b55",e.strokeStyle=b.ink,e.lineWidth=2,X(e,o.x-18,o.y-18,36,36,!0,!0))}e.restore()}function Ic(e,t){let n=qr(t),o=Ec(t);if(!n.conveyors||n.conveyors.signature!==o){let c=Pc(t),h=Rc(t),g=Yr(h.w,h.h),C=g.getContext("2d");C.translate(-h.x,-h.y),Ac(C,c),n.conveyors={signature:o,bounds:h,layer:g,data:c}}let{bounds:r,layer:i,data:a}=n.conveyors;e.drawImage(i,r.x,r.y),e.save(),e.lineCap="round",e.lineJoin="round";for(let c of a.edges){let h=Math.max(Wr(t,c.fromKey),Wr(t,c.toKey)),g=Math.max(0,(h-.5)/.5);e.strokeStyle=In(b.green,b.danger,g),e.globalAlpha=h>.5?.35+g*.55:.8,e.lineWidth=6,e.beginPath(),e.moveTo(c.a.x,c.a.y),e.lineTo(c.b.x,c.b.y),e.stroke()}e.globalAlpha=1;for(let c of a.tiles){let{k:h,c:g,meta:C}=c,P=Wr(t,h);P>.5&&(e.fillStyle="rgba(196,36,36,.28)",e.strokeStyle=b.danger,e.lineWidth=3,X(e,g.x-20,g.y-20,40,40,!0,!0)),$c(e,t,g,h,C,P),kt(e,g.x-18,g.y-18,36,36,{meta:C}),gt(e,t,"conveyor",h,g.x,g.y,38,38),_c(e,g,c.markers),Oc(e,g,C,c.branchDirs,c.connectedDirs),P>.5&&Hr(e,g.x,g.y-15,`${Math.floor(P*100)}%`,b.danger)}e.restore()}function $c(e,t,n,o,r={},i=0){let a=r.kind==="boostConveyor",h=[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))][0]||"right",g=h==="up"||h==="down",C=h==="left"||h==="up",P=pn(t,o)*_n(t,o),K=(typeof performance<"u"?performance.now()/1e3:0)*P,j=((C?-K:K)%10+10)%10;e.save(),e.beginPath(),e.rect(n.x-18,n.y-18,36,36),e.clip();let Z=a?"rgba(20,126,124,.62)":"rgba(42,47,54,.72)";if(e.fillStyle=Z,e.fillRect(n.x-18,n.y-18,36,36),e.strokeStyle=i>.5?"rgba(238,83,61,.90)":"rgba(184,190,198,.92)",e.lineWidth=4,g)for(let Q=n.y-28+j;Qe.conveyorTiles.has(I(n.col+o.dc,n.row+o.dr))).map(o=>o.name)}function la(e,t,n){let o=fe.find(a=>a.name===n);if(!o)return!1;let r=e.conveyorMeta?.get?.(I(t.col+o.dc,t.row+o.dr));return r?[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))].includes(o.opposite):!1}function ca(e,t,n,o=Wn(e,t)){if(o.length<3)return n;let r=re(t),i=new Set(o.filter(h=>la(e,r,h))),a=o.filter(h=>!i.has(h));if(i.size)return a;let c=n.filter(h=>o.includes(h));return c.length>=2?[...new Set(c)]:o}function Fc(e,t,n,o=Wn(e,t),r="random"){let i=ca(e,t,n,o);return o.length>=3&&r&&r!=="random"&&i.includes(r)?[r]:i}function Dc(e,t,n=Wn(e,t)){let o=e.conveyorMeta?.get?.(t)||{},r=[...new Set([...Array.isArray(o.outDirs)?o.outDirs:[],o.dir].filter(Boolean))];return n.length<3?[]:ca(e,t,r,n)}function Bc(e,t,n){let o=re(t),r=fe.filter(c=>e.conveyorTiles.has(I(o.col+c.dc,o.row+c.dr))).map(c=>c.name),i=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(c=>r.includes(c));if(r.length===1&&(!i.length||i.includes(r[0]))&&la(e,o,r[0]))return[];let a=r;return i.length?i:a}function Oc(e,t,n,o,r=o){if(r.length<3||o.length<2)return;e.save();let i=o.includes(n.branchMode)?n.branchMode:"random",a=i!=="random";if(e.lineJoin="round",e.lineCap="round",e.lineWidth=2,e.fillStyle="rgba(18,21,26,.94)",e.strokeStyle=a?b.warn:b.green,e.lineWidth=4,X(e,t.x-18,t.y-18,36,36,!0,!0),e.strokeStyle="#ffd36a",e.lineWidth=3,e.fillStyle="#020304",i!=="random"){let c=fe.find(h=>h.name===i);Un(e,t.x,t.y-4,c?.angle||0,8,5)}else e.beginPath(),e.moveTo(t.x-10,t.y),e.lineTo(t.x-2,t.y),e.lineTo(t.x+8,t.y-8),e.moveTo(t.x-2,t.y),e.lineTo(t.x+8,t.y+8),e.stroke(),Un(e,t.x+9,t.y-9,-Math.PI/4,4,3),Un(e,t.x+9,t.y+9,Math.PI/4,4,3);i==="random"&&(e.font="900 9px ui-monospace, monospace",e.textAlign="center",e.textBaseline="middle",e.lineWidth=3,e.strokeStyle="#020304",e.fillStyle=b.warn,e.strokeText("RND",t.x,t.y+11),e.fillText("RND",t.x,t.y+11)),e.restore()}function Lc(e,t,n){if(!n)return[];let o=re(t),r=fe.filter(c=>e.conveyorTiles.has(I(o.col+c.dc,o.row+c.dr))).map(c=>c.name),i=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(c=>r.includes(c));return Fc(e,t,i.length?i:Bc(e,t,n),r,n.branchMode||"random").map(c=>fe.find(h=>h.name===c)).filter(Boolean)}function Nc(e){let t=new Map;for(let[n,o]of e.conveyorMeta||[]){let r=Lc(e,n,o);r.length&&t.set(n,r)}return t}function _c(e,t,n){let o=n.slice(0,4);o.length&&(e.save(),e.globalAlpha=1,o.forEach(r=>{let i=t.x+r.dc*11,a=t.y+r.dr*11;e.fillStyle="rgba(255,205,83,.96)",Un(e,i,a,r.angle,9,7),e.fillStyle="#020304",Un(e,i,a,r.angle,6.5,4.6)}),e.restore())}function Un(e,t,n,o,r=11,i=8){e.save(),e.translate(t,n),e.rotate(o),e.beginPath(),e.moveTo(r,0),e.lineTo(-r*.72,-i),e.lineTo(-r*.72,i),e.closePath(),e.fill(),e.restore()}function Gc(e,t,n,o,r){let i=ge(t),a=null;if(n==="inputA"&&(a={x:i.x,y:i.y-40}),n==="left"&&(a={x:i.x-42,y:i.y+10}),n==="right"&&(a={x:i.x+42,y:i.y+10}),!a)return;let c=n==="inputA"?{x:o.x,y:a.y}:{x:a.x,y:o.y};e.save(),e.lineCap="square",e.lineJoin="bevel",e.strokeStyle="#050609",e.lineWidth=15,e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(c.x,c.y),e.lineTo(a.x,a.y),e.stroke(),e.strokeStyle="#596473",e.lineWidth=9,e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(c.x,c.y),e.lineTo(a.x,a.y),e.stroke(),e.strokeStyle=r||"#7b8795",e.lineWidth=3,e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(c.x,c.y),e.lineTo(a.x,a.y),e.stroke(),e.fillStyle=r||"#7b8795",e.strokeStyle="#050609",e.lineWidth=3,X(e,a.x-9,a.y-7,18,14,!0,!0),e.restore()}function Uc(e,t){e.save(),e.lineWidth=2,e.font="900 12px ui-monospace, monospace",e.textAlign="center";for(let n of t.scanners){let o=ur(n),r=[{type:"inputA",p:Fe(n,"inputA"),label:"IN",color:b.green},{type:"left",p:Fe(n,"left"),label:fr(o.left),color:pr(o.left)},{type:"right",p:Fe(n,"right"),label:fr(o.right),color:pr(o.right)}];for(let i of r){if(!i.p)continue;let a=$(i.p.col,i.p.row);Gc(e,n,i.type,a,i.color);let c=Gi(t,n,i.type||(i.label==="IN"?"inputA":null))||t.conveyorTiles.has(I(i.p.col,i.p.row));e.fillStyle=c?In("#1a1d23",i.color,.24):"#3a1e22",e.strokeStyle=c?i.color:b.danger,X(e,a.x-18,a.y-12,36,24,!0,!0),e.fillStyle=b.white,e.fillText(i.label,a.x,a.y+4)}}e.restore()}function Wc(e,t){for(let n of t.eggFarms)Hc(e,n,t)}function Hc(e,t,n){let o=$(t.col,t.row);e.save(),e.fillStyle="#5a6470",e.strokeStyle=b.ink,e.lineWidth=3,X(e,o.x-27,o.y-27,54,54,!0,!0),e.fillStyle="#6f5130",e.strokeStyle="#2f2112",e.lineWidth=3,e.beginPath(),e.ellipse(o.x,o.y+3,19,12,0,0,Math.PI*2),e.fill(),e.stroke(),e.strokeStyle="#a77b4b",e.lineWidth=2;for(let c=-16;c<=16;c+=6)e.beginPath(),e.moveTo(o.x-18,o.y+c*.1),e.quadraticCurveTo(o.x+c,o.y-10+Math.abs(c)*.2,o.x+18,o.y+c*.08),e.stroke();let r=[{x:-8,y:1},{x:0,y:-3},{x:8,y:2}];for(let c of r)e.fillStyle="#e8e2cf",e.strokeStyle="#8d8475",e.lineWidth=1.5,e.beginPath(),e.ellipse(o.x+c.x,o.y+c.y,4.8,6.2,.2,0,Math.PI*2),e.fill(),e.stroke();let i=1+Math.max(0,Number(t.extraEggOutlet)||0);e.fillStyle="rgba(255,255,255,.92)",e.strokeStyle=b.ink,e.lineWidth=2,X(e,o.x+8,o.y+11,30,18,!0,!0),e.fillStyle=b.ink,e.font="900 10px ui-monospace, monospace",e.textAlign="center",e.fillText(`O${i}`,o.x+23,o.y+23),e.fillStyle="#d5e35a",e.font="900 9px ui-monospace, monospace",e.fillText(`L${t.level}`,o.x-13,o.y-15);let a=Math.max(0,Math.min(1,t.shutterProgress||0));if(a>0){let c=54*a;e.fillStyle="rgba(10,12,15,.86)",X(e,o.x-27,o.y-27,54,c,!0,!1),e.strokeStyle="rgba(230,237,242,.64)",e.lineWidth=2;for(let h=o.y-23;h=1&&(e.fillStyle=b.white,e.font="900 12px ui-monospace, monospace",e.fillText("SHUT",o.x,o.y+4))}kt(e,o.x-28,o.y-28,56,56,t),gt(e,n,"eggFarm",t.id,o.x,o.y,68,68),e.restore()}function Kc(e,t){for(let n of t.scanners)qc(e,n,t)}function qc(e,t,n){let o=ge(t);if(e.save(),t.kind==="manual"&&(n.manualCombo?.count||0)>=10){let h=n.manualCombo.count;e.save(),e.globalAlpha=Math.min(.55,.16+h/120),e.strokeStyle=h>=30?b.warn:b.green,e.lineWidth=Math.min(12,4+Math.floor(h/10)),e.shadowColor=e.strokeStyle,e.shadowBlur=Math.min(24,8+h),X(e,o.x-48,o.y-48,96,96,!1,!0),e.restore()}let r=t.kind==="auto"?Pe.scannerAuto:Pe.scannerManual;if(Qt(e,r,o.x-44,o.y-44,88,88)){t.kind==="auto"?kt(e,o.x-44,o.y-44,88,88,t):ra(e,t,o),gt(e,n,"scanner",t.id,o.x,o.y,96,96),e.restore();return}e.fillStyle=t.kind==="auto"?"#d8ffe2":b.white,e.strokeStyle=b.ink,e.lineWidth=4,X(e,o.x-44,o.y-44,88,88,!0,!0),e.fillStyle=t.kind==="auto"?b.green:b.ink,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText(t.kind==="auto"?"AUTO":`S${(t.slot??0)+1}`,o.x,o.y-24),e.font="900 9px ui-monospace, monospace";let i=t.keys?.left?.label||(t.slot===0?"A":"Left"),a=t.keys?.right?.label||(t.slot===0?"D":"Right");e.fillText(t.kind==="auto"?"2.1 FARMS":`${i}/${a}`,o.x,o.y-8);let c=t.queue.length;t.kind==="manual"?ra(e,t,o):(e.fillStyle=c>0?b.green:b.muted,e.font="900 10px ui-monospace, monospace",e.fillText(`Q:${c} CD:${t.cooldown.toFixed(1)}`,o.x,o.y+35),kt(e,o.x-44,o.y-44,88,88,t)),gt(e,n,"scanner",t.id,o.x,o.y,96,96),e.restore()}function ra(e,t,n){if(t.kind!=="manual")return;let r=(t.slot??0)===0?[{side:"left",text:"A"},{side:"right",text:"D"}]:[{side:"left",text:"\u2190"},{side:"right",text:"\u2192"}];r[0].text=t.keys?.left?.label||r[0].text,r[1].text=t.keys?.right?.label||r[1].text;let i=t.keyPressTime>0?t.keyPressSide:null,a=n.x-30,c=n.y+8;e.save(),e.lineWidth=3,e.fillStyle="#f7fff5",e.strokeStyle=b.ink,X(e,a-4,c-4,68,25,!0,!0),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let h=0;h MEAT","meat","connect OUT to sausage machine"),kt(e,n.x,n.y,n.w,n.h,n),gt(e,t,"facility",n.id,n.x+n.w/2,n.y+n.h/2,n.w+12,n.h+12),e.restore()}function eu(e,t,n=t.facilities.trash){e.save(),zr(e,n),Hn(e,n.x,n.y,n.w,n.h,"#29342d",b.ink,b.wasteGreen),Fo(e,n,b.wasteGreen),e.fillStyle=b.white,e.font="900 14px ui-monospace, monospace",e.textAlign="left",e.fillText(`SHREDDER L${n.level}`,n.x+14,n.y+18),e.fillStyle="#181d20",e.strokeStyle="#9fd473",e.lineWidth=4,X(e,n.x+38,n.y+36,92,22,!0,!0),e.fillStyle="#262d30",e.strokeStyle="#0d1014",X(e,n.x+46,n.y+58,76,18,!0,!0),e.fillStyle="#111418";for(let o=0;o<7;o+=1){let r=n.x+51+o*10;e.beginPath(),e.moveTo(r,n.y+58),e.lineTo(r+5,n.y+68),e.lineTo(r+10,n.y+58),e.closePath(),e.fill()}e.fillStyle="#6f7e8d",X(e,n.x+54,n.y+27,16,9,!0,!0),X(e,n.x+98,n.y+27,16,9,!0,!0),Io(e,n.x+14,n.y+n.h-42,n.w-28,"SEND POOP","poop","shredder"),kt(e,n.x,n.y,n.w,n.h,n),gt(e,t,"facility",n.id,n.x+n.w/2,n.y+n.h/2,n.w+12,n.h+12),e.restore()}function tu(e,t,n){e.save(),Hn(e,n.x,n.y,n.w,n.h,"#3b3029",b.ink,b.sausageOrange),Fo(e,n,b.sausageOrange),e.fillStyle=b.white,e.font="900 14px ui-monospace, monospace",e.textAlign="left",e.fillText(`SAUSAGE L${n.level}`,n.x+14,n.y+18),e.fillStyle=b.muted,e.font="900 10px ui-monospace, monospace",e.fillText(`2 MEAT -> 1 | ${x(Ze(t))}`,n.x+14,n.y+34),e.fillStyle="#211915",e.strokeStyle=b.sausageOrange,e.lineWidth=4,X(e,n.x+20,n.y+43,n.w-40,38,!0,!0);for(let o=0;o<3;o+=1)Do(e,n.x+n.w/2-28+o*28,n.y+62,9);e.fillStyle=b.meatRed,e.fillRect(n.x,n.y+n.h/2-8,8,16),e.fillStyle=b.sausageOrange,e.fillRect(n.x+n.w-8,n.y+n.h/2-8,8,16),Io(e,n.x+10,n.y+n.h-42,n.w-20,"2 MEAT -> SAUSAGE","sausage",`buffer ${n.meatBuffer||0}/2`),kt(e,n.x,n.y,n.w,n.h,n),gt(e,t,"facility",n.id,n.x+n.w/2,n.y+n.h/2,n.w+12,n.h+12),e.restore()}function nu(e,t,n=t.facilities.truck){e.save(),zr(e,n),Hn(e,n.x,n.y,n.w,n.h,"#343128",b.ink,b.truckPink),Fo(e,n,b.truckPink),e.fillStyle=b.white,e.font="900 14px ui-monospace, monospace",e.textAlign="left",e.fillText(`TRUCK L${n.level}`,n.x+14,n.y+18),e.fillStyle=b.muted,e.font="900 10px ui-monospace, monospace",e.fillText(`UNIT ${x(Ve(t))}`,n.x+14,n.y+34),zc(e,Pe.truck,n,2);let o=Kr(t);Io(e,n.x+15,n.y+50,n.w-30,`SEND ${o.toUpperCase()}`,o,t.eventOffer&&!t.eventActive?"next event":"truck cargo"),e.fillStyle="rgba(39,60,36,.9)",X(e,n.x+13,n.y+88,n.w-26,Math.max(18,n.h-103),!0,!1);for(let r of t.truckCargo)r.sex==="poop"?ua(e,n.x+r.x,n.y+r.y):r.sex==="sausage"?Do(e,n.x+r.x,n.y+r.y,7):jr(e,n.x+r.x,n.y+r.y,r.sex,r.sex==="male");kt(e,n.x,n.y,n.w,n.h,n),gt(e,t,"facility",n.id,n.x+n.w/2,n.y+n.h/2,n.w+12,n.h+12),e.restore()}function ou(e,t,n){let o=n(0),r=n(1);for(let i of t.chicks){let a=o&&o.id===i.id||r&&r.id===i.id||i.queueIndex===0;ru(e,i,a,t)}}function ru(e,t,n,o){let r=o.componentLookup&&iu(o,t)>.8,i=t.y+Math.sin(t.bob)*(r?5:1.5);if(e.save(),n&&(e.strokeStyle=b.green,e.lineWidth=5,e.beginPath(),e.arc(t.x,i,t.radius+8,0,Math.PI*2),e.stroke()),r&&(e.strokeStyle=b.danger,e.lineWidth=3,e.beginPath(),e.arc(t.x,i,t.radius+12+Math.sin(t.bob*2)*4,0,Math.PI*2),e.stroke()),t.sex==="poop")Xr(e,t.x,i,t.radius);else if(t.sex==="meat")da(e,t.x,i,t.radius);else if(t.sex==="sausage")Do(e,t.x,i,t.radius);else{let a=t.sex==="male"?Pe.chickMale:Pe.chickFemale;if(!Qt(e,a,t.x-t.radius,i-t.radius,t.radius*2,t.radius*2)){let g=t.sex==="male"?b.male:b.female,C=t.sex==="male"?"#164f8f":"#8b2252";e.fillStyle=g,e.strokeStyle=b.ink,e.lineWidth=5,e.beginPath(),e.arc(t.x,i,t.radius,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle="rgba(255,255,255,.24)",e.beginPath(),e.arc(t.x-5,i-7,t.radius*.36,0,Math.PI*2),e.fill(),e.fillStyle=b.ink,e.beginPath(),e.arc(t.x-6,i-5,2.5,0,Math.PI*2),e.arc(t.x+6,i-5,2.5,0,Math.PI*2),e.fill(),e.fillStyle="#ffaa2e",e.beginPath(),e.moveTo(t.x,i+2),e.lineTo(t.x+9,i+6),e.lineTo(t.x,i+10),e.closePath(),e.fill(),e.strokeStyle=C,e.lineWidth=3,t.sex==="male"?(e.beginPath(),e.moveTo(t.x-8,i-t.radius-2),e.lineTo(t.x+8,i-t.radius-2),e.stroke()):(e.beginPath(),e.moveTo(t.x-9,i-t.radius+2),e.lineTo(t.x,i-t.radius-6),e.lineTo(t.x+9,i-t.radius+2),e.stroke())}e.fillStyle=t.sex==="male"?"#dff1ff":"#fff0f7",e.strokeStyle="#050609",e.lineWidth=3,e.font=`900 ${Math.max(10,Math.round(t.radius*.72))}px ui-monospace, monospace`,e.textAlign="center";let h=t.sex==="male"?"\u2642":"\u2640";e.strokeText(h,t.x+t.radius*.54,i+t.radius*.7),e.fillText(h,t.x+t.radius*.54,i+t.radius*.7)}e.restore()}function iu(e,t){let n=null,o=1/0;for(let[r,i]of e.componentLookup.entries()){let a=re(r),c=$(a.col,a.row),h=Math.hypot(t.x-c.x,t.y-c.y);hia(o.type,o.id)===ia(t,n))}function gt(e,t,n,o,r,i,a,c){su(t,n,o)&&(e.save(),e.fillStyle="rgba(34,185,79,.18)",e.strokeStyle=b.green,e.lineWidth=(t.multiSelected||[]).length>1?6:4,e.setLineDash((t.multiSelected||[]).length>1?[]:[8,5]),X(e,r-a/2,i-c/2,a,c,!0,!0),e.restore())}function au(e,t,n,o){if(t.phase==="build"&&(t.multiSelected||[]).length>1){e.save(),e.fillStyle="rgba(255,255,255,.96)",e.strokeStyle=b.ink,e.lineWidth=3,X(e,54-t.view.x,66-t.view.y,214,42,!0,!0),e.fillStyle=b.ink,e.font="900 11px ui-monospace, monospace",e.fillText(`${t.multiSelected.length} ITEMS SELECTED`,65-t.view.x,83-t.view.y),e.fillStyle=b.muted,e.font="900 11px ui-monospace, monospace",e.fillText("drag any selected item to move group",65-t.view.x,99-t.view.y),e.restore();return}}function lu(e,t,n){if(!n.cardTargetPick?.pending)return;let o=Gr(n);e.save(),e.fillStyle="rgba(0,0,0,.66)",e.beginPath();let r=n.view?.scale||1;e.rect(-(n.view?.x||0)/r,-(n.view?.y||0)/r,t.width/r,t.height/r);for(let g of o){let C=g.bounds,P=8;e.rect(C.x-P,C.y-P,C.w+P*2,C.h+P*2)}e.fill("evenodd");let i=n.cardTargetPick?.mode==="blockedCell";if(!o.length){e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=b.ink,e.lineWidth=3,X(e,(260-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,420/r,42/r,!0,!0),e.fillStyle=b.danger,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(i?"NO BLOCKED CELL. PRESS ESC.":"NO VALID UPGRADE TARGET. PRESS ESC.",(470-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore();return}e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=b.ink,e.lineWidth=3;let a=Math.max(1,n.cardTargetPick?.remaining||1),c=Math.max(0,n.cardTargetPick?.used||0),h=n.cardTargetPick?.mode==="autoScannerMenu"?"AUTO SCANNER ROUTE SETTINGS. CLICK EMPTY AREA TO CLOSE.":i?`DYNAMITE: CLICK ANY BLOCKED TILE (${a} LEFT). ESC ${c>0?"FINISHES":"CANCELS"}.`:"CLICK AN UPGRADEABLE MACHINE. PRESS ESC TO CANCEL.";X(e,(216-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,560/r,42/r,!0,!0),e.fillStyle=b.ink,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(h,(496-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore()}function cu(e,t){if(t.phase!=="build"||!t.selectionBox)return;let n=t.selectionBox,o=Math.min(n.x1,n.x2),r=Math.min(n.y1,n.y2),i=Math.abs(n.x2-n.x1),a=Math.abs(n.y2-n.y1);e.save(),e.fillStyle="rgba(34,185,79,.12)",e.strokeStyle=b.green,e.lineWidth=2,e.setLineDash([7,4]),X(e,o,r,i,a,!0,!0),e.restore()}function uu(e,t){let n=[...t.effects].sort((o,r)=>(o.priority??Ie.ambient)-(r.priority??Ie.ambient));for(let o of n){let r=Math.max(0,o.life/o.maxLife);e.save(),e.globalAlpha=r,o.type==="meat"?(e.fillStyle=b.green,X(e,o.x-o.size/2,o.y-o.size/2,o.size*1.5,o.size,!0,!1)):o.type==="sludge"?(e.fillStyle=b.poop,X(e,o.x-o.size/2,o.y-o.size/2,o.size*1.4,o.size,!0,!1)):o.type==="spawn"?(e.strokeStyle=b.green,e.lineWidth=3,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*20,0,Math.PI*2),e.stroke()):o.type==="spark"?(e.fillStyle=o.color||b.danger,X(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!0,!1)):o.type==="smoke"?(e.fillStyle="rgba(16,32,21,.24)",e.beginPath(),e.arc(o.x,o.y,o.size*(1.2-r*.2),0,Math.PI*2),e.fill()):o.type==="shockwave"?(e.strokeStyle=o.color||b.danger,e.lineWidth=4,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*(o.maxSize||44),0,Math.PI*2),e.stroke()):o.type==="scannerPulse"?(e.strokeStyle=o.color||b.green,e.lineWidth=5,e.setLineDash([8,6]),e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*38,0,Math.PI*2),e.stroke()):o.type==="shred"?(e.fillStyle=o.color||b.ink,e.save(),e.translate(o.x,o.y),e.rotate(o.rot||0),X(e,-o.w/2,-o.h/2,o.w,o.h,!0,!1),e.restore()):o.type==="load"?(e.strokeStyle=o.color||b.green,e.lineWidth=3,e.beginPath(),e.moveTo(o.x-14,o.y),e.lineTo(o.x+14,o.y),e.moveTo(o.x,o.y-14),e.lineTo(o.x,o.y+14),e.stroke()):o.type==="erase"?(e.strokeStyle=b.ink,e.lineWidth=3,e.setLineDash([4,4]),X(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!1,!0)):o.type==="rage"?(e.fillStyle=o.color||b.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText("!",o.x,o.y)):o.type==="flyingChick"&&(o.sex==="poop"?Xr(e,o.x,o.y,o.radius||11):jr(e,o.x,o.y,o.sex,o.sex==="male")),e.restore()}}function du(e,t){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let n of t.floatingTexts){let o=Math.max(0,n.life/n.maxLife);e.globalAlpha=o,e.lineWidth=5,e.strokeStyle=b.white,e.fillStyle=n.color,e.strokeText(n.text,n.x,n.y),e.fillText(n.text,n.x,n.y)}e.restore()}function fu(e,t){let n=t.repairmen&&t.repairmen.length?t.repairmen:t.repairman?[t.repairman]:[];for(let o of n)pu(e,t,o)}function pu(e,t,n){if(!!!n?.active)return;if(e.save(),Qt(e,Pe.repairman,n.x-18,n.y-18,36,36)){n.target?.label&&Hr(e,n.x,n.y-24,n.target.label,b.green),e.restore();return}e.lineWidth=3,e.fillStyle="#fff0d1",e.strokeStyle=b.ink,e.beginPath(),e.arc(n.x,n.y,17,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle="#ffd6e7",e.beginPath(),e.arc(n.x-6,n.y-2,3.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+6,n.y-2,3.2,0,Math.PI*2),e.fill();let r=!!t.cardEffects?.laborExploitation;e.fillStyle=r?b.danger:b.ink,e.beginPath(),e.arc(n.x-5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.strokeStyle=b.ink,e.lineWidth=r?3:2,e.beginPath(),e.arc(n.x,n.y+(r?0:1),r?8:7,.1*Math.PI,.9*Math.PI),e.stroke(),e.fillStyle=b.green,X(e,n.x-9,n.y+14,18,8,!0,!0),e.strokeStyle=b.ink,e.lineWidth=3,e.beginPath(),e.moveTo(n.x-11,n.y+18),e.lineTo(n.x-20,n.y+24),e.stroke(),e.beginPath(),e.moveTo(n.x+11,n.y+18),e.lineTo(n.x+20,n.y+24),e.stroke(),e.fillStyle=b.ink,e.font="900 11px ui-monospace, monospace",e.textAlign="center",e.fillText("FIX",n.x,n.y+33),n.target?.label&&Hr(e,n.x,n.y-24,n.target.label,b.green),e.restore()}function yu(e,t,n){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="left",e.fillStyle=b.ink,e.font="900 19px ui-monospace, monospace",e.fillStyle=b.ink;let o=[];t.phase==="running"&&o.push(t.timeLeft<=0?"TIME UP: FARMS SHUT. CLEAR LINE.":"A/D: S1 \u2190/\u2192: S2"),t.phase==="build"&&o.push(`BUILD: ${t.buildTool||"SELECT"} | connect 1 EGG route to any exit`);let r=76;for(let i of o)e.strokeStyle=b.white,e.lineWidth=4,e.strokeText(i,24,r),e.fillText(i,24,r),r+=20;e.restore()}function fa({game:e,canvasPoint:t,updatePanels:n,equipmentAtPoint:o,fail:r,pointInGrid:i,rectOfFacility:a,rectsOverlap:c}){function h(T){return T?T.type==="conveyor"?`conveyor:${T.id||T.oldKey}`:T.type==="facility"?`facility:${T.id||T.ref?.id}`:T.type==="maintenanceRoom"?`maintenanceRoom:${T.id||T.ref?.id}`:`${T.type}:${T.id||T.ref?.id}`:""}function g(T){return T?T.type==="conveyor"?{type:"conveyor",id:T.oldKey}:{type:T.type,id:T.ref.id}:null}function C(T){let M=h(g(T));return(e.multiSelected||[]).some(q=>h(q)===M)}function P(T){return T?T.type==="eggFarm"?e.eggFarms.find(M=>M.id===T.id)||null:T.type==="scanner"?e.scanners.find(M=>M.id===T.id)||null:T.type==="facility"?e.facilities[T.id]||null:T.type==="maintenanceRoom"?(e.maintenanceRooms||[]).find(M=>M.id===T.id)||null:T.type==="conveyor"&&e.conveyorTiles.has(T.id)?{type:"conveyor",id:T.id}:null:null}function L(){let T=[];for(let M of e.conveyorTiles){let q=re(M),ne=$(q.col,q.row);T.push({type:"conveyor",id:M,center:ne,cell:q})}for(let M of e.eggFarms)T.push({type:"eggFarm",id:M.id,ref:M,center:$(M.col,M.row),cell:{col:M.col,row:M.row}});for(let M of e.scanners)T.push({type:"scanner",id:M.id,ref:M,center:ge(M),cell:{col:M.col,row:M.row}});for(let M of e.maintenanceRooms||[]){let q=$(M.col,M.row);T.push({type:"maintenanceRoom",id:M.id,ref:M,center:{x:q.x+f.cell/2,y:q.y+f.cell/2},cell:{col:M.col,row:M.row}})}for(let M of Object.values(e.facilities)){let q={x:M.x+M.w/2,y:M.y+M.h/2},ne=M.entry?$(M.entry.col,M.entry.row):q;T.push({type:"facility",id:M.id,ref:M,center:q,portCenter:ne})}return T}function K(T,M){let q=Math.min(M.x1,M.x2),ne=Math.max(M.x1,M.x2),oe=Math.min(M.y1,M.y2),se=Math.max(M.y1,M.y2);return T.x>=q&&T.x<=ne&&T.y>=oe&&T.y<=se}function j(T){let M=[];for(let q of L())(K(q.center,T)||q.portCenter&&K(q.portCenter,T))&&M.push({type:q.type,id:q.id});return e.multiSelected=M,e.selected=M[0]||null,n(),M.length}function Z(){e.multiSelected=[],e.selected=null,n()}function Q(T){let M=t(T);return e.selectionBox={x1:M.x,y1:M.y,x2:M.x,y2:M.y},e.multiSelected=[],e.selected=null,n(),!0}function ke(T){if(!e.selectionBox)return;let M=t(T);e.selectionBox.x2=M.x,e.selectionBox.y2=M.y}function pe(){if(!e.selectionBox)return 0;let T=e.selectionBox,M=Math.abs(T.x2-T.x1),q=Math.abs(T.y2-T.y1);return e.selectionBox=null,M<6&&q<6?(Z(),0):j(T)}function le(T){let M=g(T);return M?(e.multiSelected||[]).length&&C(T)?[...e.multiSelected]:[M]:[]}function ue(T){let M=P(T);if(!M)return null;if(T.type==="conveyor"){let q=re(T.id);return{...T,obj:M,oldKey:T.id,currentKey:T.id,meta:e.conveyorMeta.get(T.id)||{price:He("conveyor"),builtSession:null},col:q.col,row:q.row}}return T.type==="eggFarm"||T.type==="scanner"||T.type==="maintenanceRoom"?{...T,obj:M,col:M.col,row:M.row}:T.type==="facility"?M.gridPlaced?{...T,obj:M,gridPlaced:!0,col:M.col,row:M.row,x:M.x,y:M.y,w:M.w,h:M.h,entry:M.entry?{...M.entry}:null,side:M.side,center:{x:M.x+M.w/2,y:M.y+M.h/2}}:{...T,obj:M,gridPlaced:!1,x:M.x,y:M.y,w:M.w,h:M.h,entry:M.entry?{...M.entry}:null,side:M.side,center:{x:M.x+M.w/2,y:M.y+M.h/2}}:null}function D(T){let M=t(T),q=o(M);if(!q)return!1;let ne=le(q),oe=ne.map(ue).filter(Boolean);return oe.length?(e.groupDrag={start:M,selections:ne,origins:oe,historySnapshot:On(e),committed:!1,lastDCol:0,lastDRow:0},e.multiSelected=ne,e.selected=ne[0]||null,n(),!0):!1}function U(){!e.groupDrag||e.groupDrag.committed||(e.undoStack.push(e.groupDrag.historySnapshot),e.redoStack=[],e.groupDrag.committed=!0)}function ee(T,M,q){let ne=I(T,M),oe=it(e,T,M);if(oe&&!q.has(`eggFarm:${oe.id}`))return!0;let se=st(e,T,M);if(se&&!q.has(`scanner:${se.id}`))return!0;let Se=(e.maintenanceRooms||[]).find(Ce=>jt(Ce).some(B=>B.col===T&&B.row===M));if(Se&&!q.has(`maintenanceRoom:${Se.id}`))return!0;let be=pt(e,T,M);return!!(be&&!q.has(`facility:${be.id}`)||e.conveyorTiles.has(ne)&&!q.has(`conveyor:${ne}`))}function O(T,M,q){for(let ne of Object.values(e.facilities||{})){if(q.has(`facility:${ne.id}`))continue;let oe=nt(e,ne),se=Xe(e,ne);if(oe&&oe.col===T&&oe.row===M||se&&se.col===T&&se.row===M)return!0}return!1}function G(T,M,q,ne){let oe=it(e,M,q);if(oe&&!ne.has(`eggFarm:${oe.id}`))return!0;let se=st(e,M,q);if(se&&!ne.has(`scanner:${se.id}`))return!0;let Se=(e.maintenanceRooms||[]).find(Ce=>jt(Ce).some(B=>B.col===M&&B.row===q));if(Se&&!ne.has(`maintenanceRoom:${Se.id}`))return!0;let be=pt(e,M,q);if(be&&be.id!==T.id&&!ne.has(`facility:${be.id}`))return!0;for(let Ce of Object.values(e.facilities||{})){if(Ce.id===T.id||ne.has(`facility:${Ce.id}`))continue;let B=nt(e,Ce),ye=Xe(e,Ce);if(B&&B.col===M&&B.row===q||ye&&ye.col===M&&ye.row===q)return!0}return!1}function Y(T,M,q){let ne=[];for(let oe of e.groupDrag.origins){if(oe.type!=="facility"||oe.gridPlaced)continue;let se={x:oe.center.x+T,y:oe.center.y+M},{entry:Se,side:be}=Eo(se,e);if(!i(Se.col,Se.row)||e.blockedCells?.has?.(I(Se.col,Se.row)))return!0;let Ce={...oe.obj,entry:{...Se},side:be};Ao(Ce,Se,be),ne.push({id:oe.id,rect:a(Ce)})}for(let oe of ne)for(let se of Object.values(e.facilities))if(!q.has(`facility:${se.id}`)&&c(oe.rect,a(se),12))return!0;for(let oe=0;oeI(q.col,q.row)));for(let q of["left","right"]){let ne=Fe(T,q),oe=I(ne.col,ne.row);if(!e.conveyorTiles.has(oe))continue;let se=e.conveyorMeta.get(oe);if(!se)continue;let Se=fe.find(B=>B.name===q),be=fe.filter(B=>{let ye=I(ne.col+B.dc,ne.row+B.dr);return e.conveyorTiles.has(ye)&&!M.has(ye)}),Ce=be.find(B=>B.name===Se?.name)||be[0]||Se;Ce&&(se.dir=Ce.name,se.outDirs=[Ce.name],se.branchMode="random")}}function De(T){if(!e.groupDrag)return;let M=t(T),q=M.x-e.groupDrag.start.x,ne=M.y-e.groupDrag.start.y;if(Math.hypot(q,ne)<3)return;let oe=Math.round(q/f.cell),se=Math.round(ne/f.cell),Se=new Set(e.groupDrag.selections.map(h)),be=new Set;for(let B of e.groupDrag.origins){if(B.type==="facility"&&!B.gridPlaced)continue;let ye=B.col+oe,Be=B.row+se,de=B.type==="scanner"?ft({col:ye,row:Be}):B.type==="maintenanceRoom"?jt({col:ye,row:Be}):B.type==="facility"?Ro({...B.obj,col:ye,row:Be}):[{col:ye,row:Be}];for(let Oe of de){if(!i(Oe.col,Oe.row))return r("Selection outside grid");if(e.blockedCells?.has?.(I(Oe.col,Oe.row)))return r("Selection hits blocked ground");let ct=I(Oe.col,Oe.row);if(be.has(ct))return r("Selection overlap");if(ee(Oe.col,Oe.row,Se))return r("Cell occupied");if(B.type!=="conveyor"&&O(Oe.col,Oe.row,Se))return r("Machine port must remain open");be.add(ct)}if(B.type==="facility"&&B.gridPlaced){let Oe={...B.obj,col:ye,row:Be},ct={col:ye-1,row:Be+Math.floor((Oe.hCells||3)/2)},xt={col:ye+(Oe.wCells||3),row:Be+Math.floor((Oe.hCells||3)/2)};for(let Le of[ct,xt]){if(!i(Le.col,Le.row)||e.blockedCells?.has?.(I(Le.col,Le.row)))return r("Machine port outside usable grid");if(G(B.obj,Le.col,Le.row,Se))return r("Machine port is occupied")}}}if(Y(q,ne,Se))return r("Facility overlap");U();let Ce=e.groupDrag.origins.filter(B=>B.type==="conveyor");for(let B of Ce){let ye=B.currentKey||B.oldKey;e.conveyorTiles.delete(ye),e.conveyorMeta.delete(ye)}for(let B of Ce){let ye=I(B.col+oe,B.row+se);e.conveyorTiles.add(ye),e.conveyorMeta.set(ye,B.meta||{price:He("conveyor"),builtSession:null,uses:0}),B.currentKey=ye}for(let B of e.groupDrag.origins)if(B.type==="eggFarm")B.obj.col=B.col+oe,B.obj.row=B.row+se;else if(B.type==="scanner")B.obj.col=B.col+oe,B.obj.row=B.row+se,ie(B.obj);else if(B.type==="maintenanceRoom")B.obj.col=B.col+oe,B.obj.row=B.row+se;else if(B.type==="facility"&&B.gridPlaced)B.obj.col=B.col+oe,B.obj.row=B.row+se,yn(B.obj);else if(B.type==="facility"){let ye={x:B.center.x+q,y:B.center.y+ne},{entry:Be,side:de}=Eo(ye,e);Ao(B.obj,Be,de)}e.groupDrag.selections=e.groupDrag.origins.map(B=>B.type==="conveyor"?{type:"conveyor",id:B.currentKey||B.oldKey}:{type:B.type,id:B.id}),e.multiSelected=[...e.groupDrag.selections],e.selected=e.multiSelected[0]||null,Me(e),n()}function me(){e.groupDrag&&(Me(e),e.groupDrag=null,n())}return{selectionFromHit:g,startSelectionBox:Q,updateSelectionBox:ke,finishSelectionBox:pe,startGroupDrag:D,updateGroupDrag:De,finishGroupDrag:me}}function pa({game:e,ui:t,canvas:n,canvasPoint:o,onUpdatePanels:r}){function i(){r&&r()}let a=null,c=!1,h=null,g=!1,C=["random","up","right","down","left"],P={random:"RND",up:"\u25B2",right:"\u25B6",down:"\u25BC",left:"\u25C0"},L={w:40,h:40,y:0};function K(){return ro(e)}function j(){e.gridCols=f.cols,e.gridRows=f.rows,e.gridOwnedCells=Ti(e)}function Z(s){if(s){f.y-=s*f.cell,f.rows+=s,e.gridChunkOriginY=(e.gridChunkOriginY||0)-Math.floor(s/10),e.ownedCells=io(e.ownedCells,s),e.blockedCells=io(e.blockedCells,s),e.conveyorTiles=io(e.conveyorTiles,s),e.conveyorMeta=Ai(e.conveyorMeta,s);for(let l of e.eggFarms||[])l.row+=s;for(let l of e.scanners||[])l.row+=s;for(let l of Object.values(e.facilities||{}))l.gridPlaced?(l.row+=s,yn(l)):l.entry&&(l.entry.row+=s)}}function Q(s){if(s){f.x-=s*f.cell,f.cols+=s,e.gridChunkOriginX=(e.gridChunkOriginX||0)-Math.floor(s/10),e.ownedCells=so(e.ownedCells,s),e.blockedCells=so(e.blockedCells,s),e.conveyorTiles=so(e.conveyorTiles,s),e.conveyorMeta=Ii(e.conveyorMeta,s);for(let l of e.eggFarms||[])l.col+=s;for(let l of e.scanners||[])l.col+=s;for(let l of e.maintenanceRooms||[])l.col+=s;for(let l of Object.values(e.facilities||{}))l.gridPlaced?(l.col+=s,yn(l)):l.entry&&(l.entry.col+=s)}}function ke(s){e.ownedCells=e.ownedCells||new Set;for(let l of Pi(s))e.ownedCells.add(I(l.col,l.row))}function pe(s){return e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending?null:Ut(e).map(l=>D(l)).find(l=>l&&Ri(l,s))||null}function le(s){let l=dt(s);return{x:l.x,y:l.y,w:l.w,h:l.h}}function ue(s){let l=le(s);return Object.values(e.facilities||{}).some(y=>{let m=y?.baseId||y?.id;return!eo.includes(m)||y.gridPlaced?!1:ie(l,Y(y),0)})}function D(s){if(!s)return null;let l=ue(s);return{...s,disabled:l,disabledReason:l?"Move edge facilities before buying this lot.":""}}function U(s="right"){if(s&&typeof s=="object"&&Number.isFinite(s.chunkX)&&Number.isFinite(s.chunkY))return s;let l=["left","right","up","down"].includes(s)?s:"right";return Ei(e,l)}function ee(s="right"){let l=U(s);if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return{ok:!1,reason:"Cannot expand now."};if(!l)return{ok:!1,reason:"Invalid expansion lot."};if(ue(l)){let qe="Move edge facilities before buying this lot.";return de(qe),{ok:!1,reason:qe}}let y=l.direction||"right",m=K();if(e.cashf.cols&&(f.cols=N.colStart+N.cols),N.rowStart+N.rows>f.rows&&(f.rows=N.rowStart+N.rows),ke(N),$i(e,N.chunkX,N.chunkY),e.gridExpansionPurchases=(e.gridExpansionPurchases||0)+1,e.gridExpansionPurchasesByDirection[y]=(e.gridExpansionPurchasesByDirection[y]||0)+1,j();let _=wi(e.gridExpansionPurchases,{base:V.map.blockedRatio??0,increment:V.map.blockedExpansionIncrement??.0075,max:V.map.blockedRatioMax??.12}),we=ki({seed:`${e.runSeed}:grid-expansion:${N.chunkX},${N.chunkY}:${e.gridExpansionPurchases}`,colStart:N.colStart,colEnd:N.colStart+N.cols,rowStart:N.rowStart,rowEnd:N.rowStart+N.rows,targetRatio:_});for(let qe of we)e.blockedCells.add(qe);Me(e);let Ne=N.cols*N.rows,Ge=dt(N);return H(e,Ge.x+Ge.w/2,Ge.y+Ge.h/2,`${y.toUpperCase()} +${Ne} CELLS -${x(m)}`,b.green),i(),{ok:!0,direction:y,cost:m,addedCells:Ne,blocked:we.size,blockedRatio:_,chunkX:N.chunkX,chunkY:N.chunkY}}function O(s,l){return s>=0&&s=0&&l!l.has(m.id)&&ie(y,Y(m),12))}function me(s,l,y=null){if(!O(s,l))return!1;if(G(s,l))return!0;let m=I(s,l),v=it(e,s,l);if(v&&!(y?.type==="eggFarm"&&y.ref?.id===v.id))return!0;let R=st(e,s,l);if(R&&!(y?.type==="scanner"&&y.ref?.id===R.id))return!0;let N=M(e,s,l);if(N&&!(y?.type==="maintenanceRoom"&&y.ref?.id===N.id))return!0;let _=pt(e,s,l);return!!(_&&!(y?.type==="facility"&&y.ref?.id===_.id)||e.conveyorTiles.has(m)&&!(y?.type==="conveyor"&&y.oldKey===m))}function T(s,l,y=null){return Object.values(e.facilities||{}).find(m=>{if(y?.type==="facility"&&y.ref?.id===m.id)return!1;let v=nt(e,m),R=Xe(e,m);return v&&v.col===s&&v.row===l||R&&R.col===s&&R.row===l})||null}function M(s,l,y){return(s.maintenanceRooms||[]).find(m=>jt(m).some(v=>v.col===l&&v.row===y))||null}function q(s,l,y=null){let m={col:s,row:l};for(let v of jt(m)){if(!O(v.col,v.row)||G(v.col,v.row))return!0;let R=I(v.col,v.row);if(it(e,v.col,v.row)||st(e,v.col,v.row))return!0;let we=M(e,v.col,v.row);if(we&&!(y?.type==="maintenanceRoom"&&y.ref?.id===we.id)||pt(e,v.col,v.row)||T(v.col,v.row,y)||e.conveyorTiles.has(R))return!0}return!1}function ne(s,l,y=null){let m={col:s,row:l};for(let v of ft(m)){if(!O(v.col,v.row)||G(v.col,v.row))return!0;let R=I(v.col,v.row);if(it(e,v.col,v.row))return!0;let _=st(e,v.col,v.row);if(_&&!(y?.type==="scanner"&&y.ref?.id===_.id)||pt(e,v.col,v.row)||T(v.col,v.row,y)||e.conveyorTiles.has(R))return!0}return!1}function oe(s,l,y,m=null){let v={baseId:s,id:s,gridPlaced:!0,col:l,row:y,wCells:s==="sausageMaker"?3:1,hCells:s==="sausageMaker"?3:1};for(let R of Ro(v))if(!O(R.col,R.row)||G(R.col,R.row)||me(R.col,R.row,m)||T(R.col,R.row,m))return!0;if(s==="sausageMaker"){let R={col:l-1,row:y+1},N={col:l+3,row:y+1};if(!O(R.col,R.row)||!O(N.col,N.row)||G(R.col,R.row)||G(N.col,N.row))return!0;for(let _ of[R,N]){let we=pt(e,_.col,_.row);if(we&&we.id!==m?.ref?.id||it(e,_.col,_.row)||st(e,_.col,_.row)||M(e,_.col,_.row)||T(_.col,_.row,m))return!0}}return!1}function se(){return e.selected?e.selected.type==="eggFarm"?e.eggFarms.find(s=>s.id===e.selected.id)||null:e.selected.type==="scanner"?e.scanners.find(s=>s.id===e.selected.id)||null:e.selected.type==="conveyor"?e.conveyorTiles.has(e.selected.id)?{type:"conveyor",id:e.selected.id}:null:e.selected.type==="facility"?e.facilities[e.selected.id]||null:e.selected.type==="maintenanceRoom"&&(e.maintenanceRooms||[]).find(s=>s.id===e.selected.id)||null:null}function Se(s){return s?s.type==="eggFarm"?`${Pt("eggFarm")} #${s.id}`:s.type==="scanner"?`${s.kind==="auto"?Pt("autoScanner"):Pt("manualScanner")} #${s.id}`:s.type==="conveyor"?e.conveyorMeta.get(s.id)?.kind==="boostConveyor"?Pt("boostConveyor"):Pt("conveyor"):s.type==="facility"?s.name:s.type==="maintenanceRoom"?`${Pt("maintenanceRoom")} #${s.id}`:"Equipment":"Equipment"}function be(s){return s?.type==="conveyor"?e.conveyorMeta?.get(s.oldKey||s.ref?.id)?.price||yo(s):yo(s)}function Ce(){return!!e.cardEffects?.usedMachineActive}function B(){return Ce()?{usedMachine:!0,noRefund:!0,durabilityBaseMultiplier:.6}:{usedMachine:!1,noRefund:!1,durabilityBaseMultiplier:1}}function ye(s){let l=B();return Object.assign(s,l),s}function Be(s){let l=s?.ref||s||{};if(s?.type==="eggFarm"||l.type==="eggFarm")return e.eggFarms.length<=1?"Cannot sell the last EGG FARM.":"";if((s?.type==="facility"||l.type==="facility")&&["mixer","trash","truck"].includes(l.baseId||l.id)){let y=l.baseId||l.id;if(Object.values(e.facilities).filter(v=>(v.baseId||v.id)===y).length<=1)return`Cannot sell the last ${l.shortName||l.name||l.id}.`}return""}function de(s){t.buildStatus.textContent=s,H(e,n.width/2-e.view.x,86-e.view.y,s.toUpperCase(),b.danger)}function Oe(s){if(!s)return null;let l=I(s.col,s.row);return e.conveyorMeta.get(l)||null}function ct(s){return s?(Array.isArray(s.outDirs)||(s.outDirs=[]),s.outDirs=[...new Set(s.outDirs.filter(l=>["right","left","down","up"].includes(l)))],C.includes(s.branchMode)||(s.branchMode="random"),s.kind||(s.kind="conveyor"),s.speedMultiplier||(s.speedMultiplier=s.kind==="boostConveyor"?2:1),s.outDirs):[]}function xt(s){return s?fe.filter(l=>e.conveyorTiles.has(I(s.col+l.dc,s.row+l.dr))).map(l=>l.name):[]}function Le(s){return xt(s).length>=3}function qn(s,l){let y=fe.find(_=>_.name===l);if(!s||!y)return!1;let m=I(s.col+y.dc,s.row+y.dr),v=e.conveyorMeta.get(m);if(!v)return!1;let R=y.opposite;return[...new Set([...Array.isArray(v.outDirs)?v.outDirs:[],v.dir].filter(Boolean))].includes(R)}function wn(s,l){let y=xt(s);if(y.length!==1)return null;let m=y[0];return l.includes(m)&&qn(s,m)?m:null}function No(s){if(!e.conveyorTiles.has(s))return[];let l=re(s),y=e.conveyorMeta.get(s),m=ct(y),v=xt(l),R=[...new Set([...m,y?.dir].filter(Boolean))].filter(Ge=>v.includes(Ge)),N=v,_=R.length?R:N,we=wn(l,_),Ne=R.length?R.filter(Ge=>Ge!==we):N.filter(Ge=>Ge!==we);return y&&(y.outDirs=m.filter(Ge=>v.includes(Ge)),y.dir&&!v.includes(y.dir)&&(y.dir=y.outDirs[0]||null),y.branchMode!=="random"&&!v.includes(y.branchMode)&&(y.branchMode="random")),Ne}function Yn(s){if(!e.conveyorTiles.has(s))return[];let l=re(s),y=xt(l);return Le(l)?y:No(s)}function Lt(s){let l=re(s),y=Yn(s);if(y.length<3)return[];let m=e.conveyorMeta.get(s)||{},v=new Set(y.filter(_=>qn(l,_))),R=y.filter(_=>!v.has(_));if(v.size)return R.length>=2?R:[];let N=[...new Set([...Array.isArray(m.outDirs)?m.outDirs:[],m.dir].filter(Boolean))].filter(_=>y.includes(_));return N.length>=2?N:y}function Sn(s,l){let y=ut(s,l);if(!y)return!1;let m=I(s.col,s.row),v=I(l.col,l.row),R=e.conveyorMeta.get(m),N=e.conveyorMeta.get(v);if(!R||!N)return!1;let _=ct(R),we=!_.includes(y)||R.dir!==y||!N.dir;return _.includes(y)||_.push(y),R.dir=y,N.dir||(N.dir=y),we}function Tt(s){if(kn(s).length===0)return Vn(s);let l=_o(s);return l.length<2?Vn(s):(_e(e),zn(l),Me(e),i(),!0)}function Vn(s){if(!s)return!1;let l=I(s.col,s.row),y=e.conveyorMeta.get(l);if(!y||Le(s))return!1;let m=wn(s,fe.map(_=>_.name)),v=fe.map(_=>_.name).filter(_=>_!==m),R=y.dir&&v.includes(y.dir)?y.dir:null,N=v[(Math.max(-1,v.indexOf(R))+1)%v.length];return _e(e),y.dir=N,y.outDirs=[N],y.branchMode="random",Me(e),i(),!0}function kn(s){return s?fe.map(l=>({col:s.col+l.dc,row:s.row+l.dr})).filter(l=>e.conveyorTiles.has(I(l.col,l.row))):[]}function _o(s){if(!s||!e.conveyorTiles.has(I(s.col,s.row))||Le(s))return[];let l=kn(s);if(!l.length||l.length>2)return[];let y=R=>{let N=[],_=new Set([I(s.col,s.row)]),we=s,Ne=R,Ge=0;for(;Ne&&Ge<200;){Ge+=1;let qe=I(Ne.col,Ne.row);if(_.has(qe)||(_.add(qe),N.push(Ne),Le(Ne)))break;let ri=kn(Ne).filter(ii=>!(ii.col===we.col&&ii.row===we.row));if(ri.length!==1)break;we=Ne,Ne=ri[0]}return N},m=l[0]?y(l[0]).reverse():[],v=l[1]?y(l[1]):[];return[...m,s,...v]}function gn(s,l){return!!s&&[...new Set([...Array.isArray(s.outDirs)?s.outDirs:[],s.dir].filter(Boolean))].includes(l)}function zn(s){let l=0,y=0;for(let v=0;vy?[...s].reverse():s;for(let v=0;v=2){let v=m[m.length-2],R=m[m.length-1];if(!Le(R)){let N=e.conveyorMeta.get(I(R.col,R.row)),_=ut(v,R);N&&_&&(N.dir=_,N.outDirs=[_],N.branchMode="random")}}}function Cn(){return V.facilities[e.buildTool==="boostConveyor"?"boostConveyor":"conveyor"]}function Xn(s,l=null){if(!s)return{ok:!1,reason:ce.fail.outOfGrid};let{col:y,row:m}=s,v=I(y,m);if(e.conveyorTiles.has(v))return{ok:!1,exists:!0};if(G(y,m))return{ok:!1,reason:"Cannot build on blocked ground."};if(me(y,m))return{ok:!1,reason:ce.fail.cellOccupied};let R=Cn(),N=R.id||"conveyor",_=He(N,e);if(e.cash<_)return{ok:!1,reason:ce.fail.notEnoughCash};_e(e),Dt(e,_),e.conveyorTiles.add(v);let we=B();return e.conveyorMeta.set(v,{price:_,builtSession:e.buildSession,uses:0,durability:wo(e,"conveyor",we.durabilityBaseMultiplier),maintenanceType:"conveyor",kind:N,speedMultiplier:R.speedMultiplier||1,dir:l||null,outDirs:[],branchMode:"random",...we}),e.selected={type:"conveyor",id:v},H(e,$(y,m).x,$(y,m).y,`-${x(_)}`,b.ink),{ok:!0,cell:s,key:v}}function Mn(s){if(!s)return de(ce.fail.outOfGrid);let l=I(s.col,s.row),y=e.conveyorTiles.has(l),m=a;if(m&&m.col===s.col&&m.row===s.row)return;if(m&&(g=!0),y){m&&Sn(m,s)&&(c||(_e(e),c=!0),Me(e)),e.selected={type:"conveyor",id:l},a={col:s.col,row:s.row};return}let v=m?ut(m,s):null,R=Xn(s,v);if(!R.ok)return de(R.reason||ce.fail.cellOccupied);m&&Sn(m,s),a={col:s.col,row:s.row},Me(e)}function Zt(s,l){if(!s||!l)return l;let y=l.col-s.col,m=l.row-s.row;return y===0&&m===0?s:Math.abs(y)>=Math.abs(m)?{col:s.col+Math.sign(y),row:s.row}:{col:s.col,row:s.row+Math.sign(m)}}function Go(s){c=!1,h=s?{col:s.col,row:s.row}:null,g=!1,a=null,Mn(s)}function Uo(s){if(!s)return;if(!a)return Mn(s);let l=a,y=0;for(;(l.col!==s.col||l.row!==s.row)&&y<64;){let m=Zt(l,s);if(Mn(m),l=a||m,y+=1,!a)break}}function Nt(){!g&&h&&e.conveyorTiles.has(I(h.col,h.row))&&Tt(h),h=null,g=!1,a=null,c=!1}function jn(s){if(!s)return de(ce.fail.outOfGrid);let{col:l,row:y}=s;if(e.buildTool==="conveyor"||e.buildTool==="boostConveyor"){let m=Xn(s,null);if(!m.ok)return de(m.reason||ce.fail.cellOccupied);Me(e);return}if(G(l,y))return de("Cannot build on blocked ground.");if(T(l,y)&&!["conveyor","boostConveyor"].includes(e.buildTool))return de("Machine port must remain open for a conveyor.");if(e.buildTool==="maintenanceRoom")return q(l,y)?de(ce.fail.cellOccupied):p(l,y);if(to.includes(e.buildTool))return oe(e.buildTool,l,y)?de("3x3 machine or its ports do not fit here."):k(l,y,e.buildTool);if(e.buildTool==="manualScanner"||e.buildTool==="autoScanner"?ne(l,y):me(l,y))return de(ce.fail.cellOccupied);e.buildTool==="eggFarm"?Wo(l,y):e.buildTool==="manualScanner"?d(l,y,"manual"):e.buildTool==="autoScanner"&&d(l,y,"auto")}function xn(s){let l=tt(s.x,s.y);if(["conveyor","boostConveyor","eggFarm","manualScanner","autoScanner","maintenanceRoom",...to].includes(e.buildTool))return jn(l);if(eo.includes(e.buildTool))return S(s,e.buildTool)}function Wo(s,l){let y=He("eggFarm",e);if(e.cashR.kind==="manual").length>=8)return de("Manual Scanner limit reached (8 max).");let m=y==="auto"?He("autoScanner",e):He("manualScanner",e);if(e.cashv.id!==l.ref.id),vt(e,m.x,m.y),Me(e)}if(l.type==="scanner"){let m=ge(l.ref);A(l,m.x,m.y),e.scanners=e.scanners.filter(v=>v.id!==l.ref.id),vt(e,m.x,m.y),Me(e)}if(l.type==="facility"){let m=l.ref;A(l,m.x+m.w/2,m.y+m.h/2),delete e.facilities[m.id],vt(e,m.x+m.w/2,m.y+m.h/2),Me(e)}if(l.type==="maintenanceRoom"){let m=l.ref,v=w(m);A(l,v.x,v.y),e.maintenanceRooms=(e.maintenanceRooms||[]).filter(R=>R.id!==m.id),vt(e,v.x,v.y)}e.selected=null,e.multiSelected=[],i()}function W(s){let l=Object.values(e.facilities).find(_=>{if(s.x>=_.x&&s.x<=_.x+_.w&&s.y>=_.y&&s.y<=_.y+_.h)return!0;if(!_.entry)return!1;let Ne=$(_.entry.col,_.entry.row);return Math.abs(s.x-Ne.x)<=f.cell*.46&&Math.abs(s.y-Ne.y)<=f.cell*.46});if(l)return{type:"facility",ref:l};let y=tt(s.x,s.y);if(!y)return null;let m=it(e,y.col,y.row);if(m)return{type:"eggFarm",ref:m};let v=st(e,y.col,y.row);if(v)return{type:"scanner",ref:v};let R=M(e,y.col,y.row);if(R)return{type:"maintenanceRoom",ref:R};let N=I(y.col,y.row);return e.conveyorTiles.has(N)?{type:"conveyor",oldKey:N,ref:{type:"conveyor",id:N}}:null}let ae=fa({game:e,canvasPoint:o,updatePanels:i,equipmentAtPoint:W,fail:de,pointInGrid:O,rectOfFacility:Y,rectsOverlap:ie});function ve(s){return null}function en(){let s=se();s&&(s.type==="conveyor"?E($(...Object.values(re(s.id)))):s.type==="eggFarm"?E($(s.col,s.row)):s.type==="scanner"?E(ge(s)):s.type==="facility"?E({x:s.x+s.w/2,y:s.y+s.h/2}):s.type==="maintenanceRoom"&&E(w(s)))}function ze(s,l,y="primary-button"){let m=document.createElement("button");return m.type="button",m.className=y,m.textContent=s,m.addEventListener("click",l),m}function _t(){e.cardTargetPick?.mode==="autoScannerMenu"&&(e.cardTargetPick=null),t.modal.classList.remove("visible","equipment-popover"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function Tn(s){t.modalTitle.textContent="Auto Scanner",e.cardTargetPick={pending:!0,mode:"autoScannerMenu",cardId:null,targetKeys:[`scanner:${s.id}`],remaining:1},t.modalBody.innerHTML=` +var _={version:"v29.00",time:{daySeconds:60,farmShutdownGraceSeconds:10},cash:{starting:250},grid:{x:170,y:78,cols:20,rows:10,cell:46,expansion:{colsPerPurchase:10,rowsPerPurchase:10,costBase:850,costGrowthRate:.75,truncateUnit:50}},map:{blockedRatio:0,blockedExpansionIncrement:.0075,blockedRatioMax:.12},economy:{income:{mixer:5,truck:10,sausage:26},poopFine:10,fairiesTribute:{perDay:10,profitExemption:300,legalWorkExemptionBonus:250,profitRate:.12},incomeUpgradeRate:1.1,explosionDamageDivisor:30,maleTruckFinePerHalfDay:30,shredderBonus:{maxCards:30,payoutCoefficient:1.6,payoutExponent:1.25,baseHitChance:.28,hitChancePerUpgrade:.018,maxHitChance:.82,jackpotBaseChance:.01,jackpotChancePerUpgrade:.0025,jackpotMaxChance:.08,bigWinBaseChance:.07,bigWinChancePerUpgrade:.0015,bigWinMaxChance:.12,doubleChance:.2,jackpotMultiplier:10,bigWinMultiplier:4,doubleMultiplier:2},chemicalWeaponSubsidy:{poopPerBlock:70,yenPerBlock:1200}},production:{poopRate:.08,autoScannerCooldown:1.5,autoScannerUpgradeRate:.95,autoScannerCardUpgradeRate:.95,autoScannerMinCooldown:.5,poopRateCardBonus:.04,eggSpawnRanges:[[1.95,4.35],[1.55,3.45],[1.25,2.8],[1.05,2.35]]},conveyor:{baseSpeed:52,maxSpeed:300,bearingSpeedMultiplier:1.075,minimumItemSpacingPx:25},power:{recalcHz:10,maxAssignmentPasses:8,wires:{powerWire:{id:"powerWire",name:"Power Wire",shortName:"WIRE",price:10,lossV:.5},insulatedPowerWire:{id:"insulatedPowerWire",name:"Insulated Wire",shortName:"INS WIRE",price:22,lossV:.15}},exempt:["manualScanner","eggFarm","conveyor","boostConveyor","powerWire","insulatedPowerWire","footbridge","starterGenerator","biomassGenerator","coalGenerator"],machines:{mixer:{minVoltage:10,drawV:4,relayDropV:4,powerPriority:100},trash:{minVoltage:8,drawV:3,relayDropV:3,powerPriority:100},truck:{minVoltage:6,drawV:2,relayDropV:2,powerPriority:100},autoScanner:{minVoltage:8,drawV:2,relayDropV:2,powerPriority:50},sausageMaker:{minVoltage:12,drawV:5,relayDropV:5,powerPriority:50},maintenanceRoom:{minVoltage:6,drawV:1,relayDropV:1,powerPriority:50},inboundTruck:{minVoltage:5,drawV:1,relayDropV:1,powerPriority:50}},generators:{starterGenerator:{outputV:25},biomassGenerator:{baseOutputV:0,pulseVoltage:5,pulseSeconds:2},coalGenerator:{baseOutputV:0,pulseVoltage:15,pulseSeconds:3}}},imports:{combinedLimitPerTruck:80,prices:{coal:2,zundaMochi:4},jitterRatio:.15},farmQuality:{overflowCoefficient:.45,overflowExponent:.85,minMultiplier:1,maxMultiplier:2.5,zundaSeconds:8,zundaMaxSeconds:30,zundaIntervalMultiplier:.55,safeMinIntervalSeconds:.25},effects:{explosionHorizontalVelocityMultiplier:.82},cards:{definitions:[{id:"upgradeEgg",title:"EGG Improvement",rarity:"common",type:"equipmentUpgrade",target:"eggFarm",description:"Choose one EGG FARM on the map and raise it by 1 level.",tags:["EGG","ACTIVE"]},{id:"upgradeAutoScanner",title:"AUTO SCANNER Improvement",rarity:"common",type:"equipmentUpgrade",target:"autoScanner",description:"Choose one AUTO SCANNER on the map and raise it by 1 level.",tags:["SCANNER","ACTIVE"]},{id:"autoScannerTuning",title:"AUTO SCANNER Tuning",rarity:"common",type:"instant",description:"All AUTO SCANNER cooldowns use default cooldown x0.95 per copy.",requiresFacility:"autoScanner",tags:["SCANNER","PASSIVE"]},{id:"upgradeMixer",title:"MIXER Improvement",rarity:"common",type:"equipmentUpgrade",target:"mixer",description:"Choose one MIXER. Each level improves meat quality and raises sausage sale value by 10%.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeTruck",title:"TRUCK Improvement",rarity:"common",type:"equipmentUpgrade",target:"truck",description:"Choose TRUCK on the map and raise it by 1 level.",tags:["ECONOMY","ACTIVE"]},{id:"upgradeSausageMaker",title:"SAUSAGE MACHINE Improvement",rarity:"common",type:"equipmentUpgrade",target:"sausageMaker",description:"Choose one SAUSAGE MACHINE. Each level raises sausage sale value by 10%.",tags:["ECONOMY","SAUSAGE","ACTIVE"]},{id:"upgradeTrash",title:"SHREDDER Improvement",rarity:"common",type:"equipmentUpgrade",target:"trash",description:"Adds a nonlinear scrap-lottery upgrade. More copies raise both payout and win chance; max 30.",tags:["POOP","ACTIVE"]},{id:"crowdedFarming",title:"Crowded Farming",rarity:"common",type:"instant",description:"EGG production interval -5%. Equipment deterioration +4%. Max 10 cards.",requiresFacility:"eggFarm",tags:["EGG","RISK","PASSIVE"]},{id:"hatchingFeed",title:"Hatching Feed",rarity:"common",type:"instant",description:"EGG production interval -4%. Poop rate +3%. No card limit.",requiresFacility:"eggFarm",tags:["EGG","POOP","PASSIVE"]},{id:"poopRateBooster",title:"Poop Culture",rarity:"common",type:"instant",description:"Base poop rate +4 percentage points. No card limit.",tags:["POOP","PASSIVE"]},{id:"safetyCover",title:"Safety Cover",rarity:"common",type:"instant",description:"Explosion damage -5%. No card limit.",tags:["RISK","PASSIVE"]},{id:"preventiveMaintenance",title:"Preventive Maintenance Manual",rarity:"common",type:"instant",description:"All equipment deterioration speed -5%. No card limit.",requiresAnyFacility:["conveyor","eggFarm","autoScanner","manualScanner","mixer","trash","sausageMaker"],tags:["MAINTENANCE","PASSIVE"]},{id:"dudFilter",title:"DUD Filter",rarity:"common",type:"instant",description:"DUD chance -5 percentage points. Stacks until DUD chance reaches 0%.",tags:["CARD","PASSIVE"]},{id:"durabilityCoating",title:"Durability Coating",rarity:"common",type:"instant",description:"All equipment maximum durability +3%. No card limit.",requiresAnyFacility:["conveyor","eggFarm","autoScanner","manualScanner","mixer","trash","sausageMaker"],tags:["MAINTENANCE","PASSIVE"]},{id:"bearing",title:"High-Quality Bearing",rarity:"common",type:"instant",description:"Conveyor speed +7.5%.",requiresFacility:"conveyor",tags:["CONVEYOR","PASSIVE"]},{id:"sparePartsBin",title:"SPARE PARTS BIN",rarity:"common",type:"instant",description:"Restores 2% durability to every machine. A box of almost-compatible parts.",requiresAnyFacility:["conveyor","eggFarm","autoScanner","manualScanner","mixer","trash","sausageMaker"],tags:["MAINTENANCE","ACTIVE"]},{id:"dudRefund",title:"DUD REFUND",rarity:"common",type:"instant",description:"DUDs now come with paperwork. Gain JPY 50 per copy when you pick a DUD.",tags:["CARD","ECONOMY","PASSIVE"]},{id:"freeReroll",title:"FREE REROLL",rarity:"common",type:"instant",description:"The first bad ideas are free.",tags:["CARD","PASSIVE"]},{id:"composter",title:"COMPOSTER",rarity:"common",type:"instant",description:"Turns shredder waste into suspicious fertilizer. Gain JPY 3 per copy when SHREDDER processes poop.",requiresFacility:"trash",tags:["POOP","ECONOMY","PASSIVE"]},{id:"scannerQueueSpacing",title:"Scanner Queue Spacing",rarity:"common",type:"instant",description:"Manual and Auto Scanner queue spacing -15%. No card limit.",requiresAnyFacility:["manualScanner","autoScanner"],tags:["SCANNER","PASSIVE"]},{id:"extraEggOutlet",title:"Extra Egg Outlet",rarity:"rare",type:"equipmentUpgrade",target:"eggOutlet",description:"Choose one EGG FARM and add +1 output port to that EGG. Max +3 per EGG.",tags:["EGG","RARE","ACTIVE"]},{id:"recyclingSubsidy",title:"Recycling Subsidy",rarity:"rare",type:"instant",description:"SELL refund rate +10 points. Max 3 cards; normal SELL can reach 80%.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"dynamite",title:"Dynamite",rarity:"rare",type:"cellAction",target:"blockedCell",description:"Choose and remove up to 3 unbuildable cells.",tags:["RISK","RARE","ONE-SHOT"]},{id:"usedMachine",title:"Used Machines",rarity:"rare",type:"instant",description:"Future equipment costs half. New purchases have no refund and 60% durability. New Machines cancels it.",tags:["ECONOMY","RISK","RARE"]},{id:"newMachine",title:"New Machines",rarity:"common",type:"instant",description:"Cancel Used Machines and restore normal prices, refunds, and durability.",tags:["ECONOMY","ONE-SHOT"]},{id:"flattery",title:"Flattery",rarity:"rare",type:"instant",description:"Next Fairies tribute -50%.",tags:["ECONOMY","RARE","ONE-SHOT"]},{id:"extraCards",title:"Extra Cards",rarity:"rare",type:"instant",description:"Draw 2 cards now and choose both.",tags:["RARE","ACTIVE"]},{id:"legalWork",title:"Legal Work",rarity:"rare",type:"instant",description:"Fairies tribute profit exemption +JPY 250.",tags:["ECONOMY","RARE","PASSIVE"]},{id:"chemicalWeaponSubsidy",title:"Chemical Weapons Subsidy",rarity:"ultraRare",type:"instant",description:"Each day, gain JPY 1200 per 70 poop shipped by truck. No card limit.",tags:["POOP","ULTRA RARE","PASSIVE"]},{id:"laborExploitation",title:"Motivational Exploitation",rarity:"ultraRare",type:"instant",description:"Repair room work time -30%. The repairman smiles with bloodshot eyes. One time only.",tags:["MAINTENANCE","ULTRA RARE","PASSIVE"]},{id:"rescueLoan",title:"Emergency Loan",rarity:"ultraRare",type:"instant",description:"If cash is below JPY 0 at day-end settlement, gain JPY 500. Consumed on use.",tags:["ECONOMY","ULTRA RARE","ONE-SHOT"]}],defaultEffects:{bearing:0,legalWork:0,fairiesFlatteryNext:0,autoScannerTuning:0,poopRateBooster:0,crowdedFarming:0,hatchingFeed:0,safetyCover:0,recyclingSubsidy:0,chemicalWeaponSubsidy:0,preventiveMaintenance:0,dudFilter:0,durabilityCoating:0,sparePartsBin:0,dudRefund:0,freeReroll:0,composter:0,scannerQueueSpacing:0,laborExploitation:0,usedMachineActive:!1,rescueLoanCharges:0},commonWeight:8,rareWeight:2,ultraRareWeight:.45,baseDraftSize:3,maxDudsPerDraft:2,dudChancePerCard:.3,dudChanceReductionPerFilter:.05,extraCardsAddedPicks:2,rerollCost:{dayDivisor:2,multiplier:100}},events:{eventChance:.1,firstTurn:8},maintenance:{fullPerformanceUntilWear:.5,minimumPerformance:.5,durability:{conveyor:1300,eggFarm:475,autoScanner:850,mixer:775,trash:950,sausageMaker:825,starterGenerator:1e3,biomassGenerator:900,coalGenerator:900,inboundTruck:850},processingDelayMaxSeconds:{mixer:1.2,trash:1,sausageMaker:.9},repairman:{secondsPerOnePercent:.5,walkSpeed:90}},facilities:{conveyor:{id:"conveyor",type:"conveyor",name:"Conveyor",shortName:"Belt",price:30,buildable:!0,upgradeable:!1},boostConveyor:{id:"boostConveyor",type:"conveyor",name:"Boost Conveyor",shortName:"BOOST BELT",price:75,buildable:!0,upgradeable:!1,speedMultiplier:2},powerWire:{id:"powerWire",type:"powerWire",name:"Power Wire",shortName:"WIRE",price:10,buildable:!0,upgradeable:!1},insulatedPowerWire:{id:"insulatedPowerWire",type:"powerWire",name:"Insulated Power Wire",shortName:"INS WIRE",price:22,buildable:!0,upgradeable:!1},footbridge:{id:"footbridge",type:"footbridge",name:"Footbridge",shortName:"BRIDGE",price:90,buildable:!0,upgradeable:!1,footprint:{cols:1,rows:3}},eggFarm:{id:"eggFarm",type:"eggFarm",name:"Egg Farm",shortName:"EGG",price:250,buildable:!0,upgradeable:!0,maxLevel:4},manualScanner:{id:"manualScanner",type:"scanner",kind:"manual",name:"Manual Scanner",shortName:"Manual Scanner",price:260,buildable:!0,upgradeable:!1},autoScanner:{id:"autoScanner",type:"scanner",kind:"auto",name:"Auto Scanner",shortName:"Auto Scanner",price:180,buildable:!0,upgradeable:!1},mixer:{id:"mixer",type:"facility",name:"Mixer",shortName:"MIXER",price:450,buildable:!0,upgradeable:!0,incomeKey:"mixer",body:{w:164,h:126}},trash:{id:"trash",type:"facility",name:"Waste Shredder",shortName:"SHREDDER",price:240,buildable:!0,upgradeable:!0,body:{w:180,h:100}},truck:{id:"truck",type:"facility",name:"Shipping Truck",shortName:"SHIP TRUCK",price:450,buildable:!0,upgradeable:!0,incomeKey:"truck",body:{w:176,h:138}},sausageMaker:{id:"sausageMaker",type:"facility",name:"Sausage Machine",shortName:"SAUSAGE",price:380,buildable:!0,upgradeable:!0,incomeKey:"sausage",footprint:{cols:3,rows:3},body:{w:138,h:138},outputProduct:"sausage"},starterGenerator:{id:"starterGenerator",type:"facility",name:"Starter Generator",shortName:"STARTER",price:0,buildable:!1,upgradeable:!1,footprint:{cols:2,rows:2},body:{w:92,h:92}},biomassGenerator:{id:"biomassGenerator",type:"facility",name:"Biomass Generator",shortName:"BIOMASS",price:520,buildable:!0,upgradeable:!1,footprint:{cols:3,rows:3},body:{w:138,h:138}},coalGenerator:{id:"coalGenerator",type:"facility",name:"Coal Generator",shortName:"COAL GEN",price:680,buildable:!0,upgradeable:!1,footprint:{cols:2,rows:3},body:{w:92,h:138}},inboundTruck:{id:"inboundTruck",type:"facility",name:"Inbound Truck",shortName:"INBOUND",price:350,buildable:!0,upgradeable:!1,body:{w:176,h:120}},maintenanceRoom:{id:"maintenanceRoom",type:"maintenanceRoom",name:"Maintenance Room",shortName:"REPAIR ROOM",price:220,buildable:!0,upgradeable:!1,footprint:{cols:2,rows:2}}}};var Ai=_.version,yt=_.time.daySeconds,Un=_.cash.starting,Ie=_.economy,$i=_.time.farmShutdownGraceSeconds,bo=_.production.autoScannerCooldown,Fi=_.production.autoScannerUpgradeRate,wr=_.production.autoScannerCardUpgradeRate||_.production.autoScannerUpgradeRate,mr=_.production.autoScannerMinCooldown,Oi=_.events.eventChance,Vn=_.events.firstTurn,vr=_.production.poopRate,Sr=_.production.poopRateCardBonus||0,wo=_.conveyor.baseSpeed,yn=_.conveyor.maxSpeed,mo=_.conveyor.bearingSpeedMultiplier,qe=_.cards,Bi=_.cards.definitions,kr=_.cards.defaultEffects,Gt=_.production.eggSpawnRanges,p=_.grid,Te=_.facilities,Mr=["conveyor","boostConveyor","powerWire","insulatedPowerWire","footbridge","eggFarm","autoScanner","manualScanner","mixer","trash","truck","inboundTruck","sausageMaker","biomassGenerator","coalGenerator","maintenanceRoom"],vo=["mixer","trash","truck","inboundTruck"],So=["sausageMaker","starterGenerator","biomassGenerator","coalGenerator"],Cr=[...vo,...So],Di=["mixer","trash","truck"],Li=["mixer","truck","sausageMaker"],_t=Object.fromEntries(Object.entries(Te).map(([e,t])=>[e,t.price])),fe=[{name:"right",dc:1,dr:0,angle:0,opposite:"left"},{name:"left",dc:-1,dr:0,angle:Math.PI,opposite:"right"},{name:"down",dc:0,dr:1,angle:Math.PI/2,opposite:"up"},{name:"up",dc:0,dr:-1,angle:-Math.PI/2,opposite:"down"}],w={bg:"#111318",ink:"#090a0d",muted:"#8f9bab",green:"#7bd84f",greenSoft:"#273c24",mixerBlue:"#4aa3ff",truckPink:"#ffb33e",wasteGreen:"#88d35a",meatRed:"#d96b72",sausageOrange:"#d78b3f",danger:"#e34a36",warn:"#ffb827",white:"#e6edf2",poop:"#7b4a23",male:"#4aa3ff",female:"#ff6fae"},_e={ambient:0,important:1,critical:2};function R(e){let t=Number(e)||0;return`${t<0?"-":""}\uFFE5${Math.ceil(Math.abs(t)).toLocaleString("ja-JP")}`}function E(e,t){return`${e},${t}`}function X(e){let[t,n]=String(e).split(",").map(Number);return{col:t,row:n}}function Kn(e,t,n){return Math.max(t,Math.min(n,e))}function ne(e,t){return e+Math.random()*(t-e)}function Re(e,t){return e>=0&&e=0&&tMath.round(Kn(r,0,255)).toString(16).padStart(2,"0");return`#${o(e)}${o(t)}${o(n)}`}function qn(e,t,n){let o=Ni(e),r=Ni(t);return Tl(gr(o.r,r.r,n),gr(o.g,r.g,n),gr(o.b,r.b,n))}var pe={appTitle:"Chick Sorter",versionTitle:`Chick Sorter ${Ai}`,currency:"\uFFE5",phases:{title:"Title",build:"Build",running:"Sorting",clearing:"Clearing",loanDecision:"Emergency Loan",gameover:"Game Over"},actions:{startGame:"Start Game",nextDay:"Next Day",buildPhase:"Build Phase",restart:"Restart",close:"Close",remove:"Remove",refund:"Refund",autoMenu:"Auto Menu"},status:{build:e=>`BUILD: ${(e==="erase"?"SELL":e||"SELECT").toUpperCase()} | Right-drag pan | Hover equipment for info`,sorting:"Sorting: use scanner keys. Build after clearing the day.",allPortsConnected:"Start condition met: one EGG route reaches an exit.",equipmentPanelEmpty:"Hover equipment in Build phase."},routeLabels:{mixer:"MIXER",truck:"TRUCK",inboundTruck:"INBOUND",trash:"WASTE",sausageMaker:"SAUSAGE",biomassGenerator:"BIOMASS",coalGenerator:"COAL GEN",scanner:"NEXT","scanner-role-1":"NEXT",input:"IN"},fail:{outOfGrid:"Out of grid",cellOccupied:"Cell occupied",notEnoughCash:"Not enough cash",facilityExists:"Facility already exists",facilityOverlap:"Facility overlap",nothingToErase:"Nothing to sell",noUpgrade:"No upgrade available"}};function ht(e){return Te[e]?.name||String(e||"").replace(/^[a-z]/,t=>t.toUpperCase())}function El(e){let t=Te[e];return t?e==="conveyor"||e==="boostConveyor"?`${R(t.price)} / tile`:e==="autoScanner"?`${R(t.price)} / ${bo.toFixed(1)}s cooldown`:e==="trash"?R(t.price):R(t.price):""}function Pl(e){return{conveyor:"A narrow green belt. Routes decide whether chicks live, ship, or become invoices.",boostConveyor:"Moves chicks twice as fast. Wears down like a normal belt.",eggFarm:"A tiny gatehouse producing questionable eggs on schedule.",autoScanner:"Processes about 40 items per day at Lv1, roughly 2.1 Lv1 farms.",manualScanner:"A manual checkpoint. The operator is the algorithm.",mixer:"Makes meat when OUT is clear; otherwise falls back to direct sale.",trash:"A polite shredder for poop and other regrets.",truck:"Shipping Truck. Ships target chicks and all sausages.",powerWire:"Overlay wire. Loses 0.5V per tile.",insulatedPowerWire:"Overlay wire. Loses 0.15V per tile.",footbridge:"Lets repair workers cross conveyor cells.",inboundTruck:"Imports coal and zunda mochi during the day.",biomassGenerator:"Fuel generator. Chicks and poop add timed voltage.",coalGenerator:"Fuel generator. Coal adds timed voltage.",sausageMaker:"A 3\xD73 grid machine. Left inlet takes 2 meat; right outlet emits 1 sausage.",maintenanceRoom:"2\xD72 repair bay. Each room dispatches one repairman during the day."}[e]||""}function Rl(e){return{conveyor:"./assets/dark_factory/facilities/conveyor/conveyor_straight_h_16.png",boostConveyor:"./assets/dark_factory/facilities/conveyor/boost_conveyor_straight_h_16.png",eggFarm:"./assets/dark_factory/facilities/machines/egg_farm_16.png?v=dark_factory",autoScanner:"./assets/dark_factory/facilities/machines/auto_scanner_32x48.png",manualScanner:"./assets/dark_factory/facilities/machines/manual_scanner_32x48.png",mixer:"./assets/dark_factory/facilities/machines/mixer_32.png",trash:"./assets/dark_factory/facilities/machines/shredder_32.png",truck:"./assets/dark_factory/facilities/vehicles/truck_32.png",sausageMaker:"./assets/dark_factory/facilities/machines/mixer_32.png",maintenanceRoom:"./assets/dark_factory/facilities/utility/maintenance_room_32.png"}[e]||""}function _i(e){let t=Pl(e),n=Rl(e);return`${n?``:""}${ht(e)}${El(e)}${t?`${t}`:""}`}function Wi(e){return pe.routeLabels[e]||String(e).toUpperCase()}function Ui(e){let t=2166136261;for(let n=0;n>>0}function Vi(e){let t=e>>>0;return()=>{t+=1831565813;let n=Math.imul(t^t>>>15,1|t);return n^=n+Math.imul(n^n>>>7,61|n),((n^n>>>14)>>>0)/4294967296}}function Ki(e,{base:t=0,increment:n=.0075,max:o=.12}={}){let r=Math.max(0,Math.floor(Number(e)||0));return Number(Math.min(o,t+r*n).toFixed(6))}function Mo(){return`RUN-${Date.now().toString(36)}-${Math.floor(Math.random()*1e6).toString(36)}`.toUpperCase()}function qi({seed:e,targetRatio:t=.2,reserved:n=[]}={}){let o=Vi(Ui(e||Mo())),r=new Set(n.map(c=>typeof c=="string"?c:E(c.col,c.row))),i=[];for(let c=0;c0;c-=1){let b=Math.floor(o()*(c+1));[i[c],i[b]]=[i[b],i[c]]}let a=Math.round(p.cols*p.rows*t+1e-9);return new Set(i.slice(0,Math.min(a,i.length)).map(c=>c.k))}function zi({seed:e,colStart:t=0,colEnd:n=p.cols,rowStart:o=0,rowEnd:r=p.rows,targetRatio:i=.2,reserved:a=[]}={}){let c=Vi(Ui(e||Mo())),b=new Set(a.map(z=>typeof z=="string"?z:E(z.col,z.row))),M=[],C=Math.max(0,Math.floor(t)),$=Math.max(C,Math.floor(n)),W=Math.max(0,Math.floor(o)),K=Math.max(W,Math.floor(r));for(let z=W;z0;z-=1){let Q=Math.floor(c()*(z+1));[M[z],M[Q]]=[M[Q],M[z]]}let G=Math.round(($-C)*(K-W)*i+1e-9);return new Set(M.slice(0,Math.min(G,M.length)).map(z=>z.k))}var hn=10,Hi=2,Yi=1;function bn(e,t){return`${e},${t}`}function Il(e){let[t,n]=String(e).split(",").map(Number);return{chunkX:t,chunkY:n}}function Co(e){let t=_.grid.expansion||{},n=Math.max(1,(e.gridExpansionPurchases||0)+1),o=Math.max(0,Number(t.costBase)||850),r=Math.max(0,Number(t.costGrowthRate)||.75),i=o*(1+r*(n-1)),a=Math.max(1,t.truncateUnit||50);return Math.floor(i/a)*a}function Qi(e){e.ownedCells=new Set,e.ownedChunks=new Set,e.gridChunkOriginX=0,e.gridChunkOriginY=0,e.gridExpansionPurchases=0,e.gridExpansionPurchasesByDirection={left:0,right:0,up:0,down:0};for(let t=0;t=0&&t=0&&n{let a=(o[r.direction]??9)-(o[i.direction]??9);return a||(r.chunkY!==i.chunkY?r.chunkY-i.chunkY:r.chunkX-i.chunkX)})}function Ji(e,t="right"){let n=jt(e);return n.find(o=>o.direction===t)||n[0]||null}function Et(e){return{x:p.x+e.colStart*p.cell,y:p.y+e.rowStart*p.cell,w:e.cols*p.cell,h:e.rows*p.cell}}function Tr(e){let t=Et(e);return{x:t.x+t.w/2-116,y:t.y+t.h/2-36,w:232,h:72,cx:t.x+t.w/2,cy:t.y+t.h/2}}function Zi(e,t){let n=Tr(e);return t.x>=n.x&&t.x<=n.x+n.w&&t.y>=n.y&&t.y<=n.y+n.h}function es(e){let t=[];for(let n=e.rowStart;nRe(t.col,t.row))}function Nl(e){return[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row}].filter(t=>Re(t.col,t.row))}function Gl(e){return[{col:e.col,row:e.row+1},{col:e.col-1,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row-1}].filter(t=>Re(t.col,t.row))}function ss(e){let t=new Set([...e.conveyorTiles]),n=o=>{o&&Re(o.col,o.row)&&t.add(E(o.col,o.row))};for(let o of e.scanners){for(let r of Nl(o))n(r);for(let r of Ll(o))n(r)}for(let o of e.eggFarms){n(o);for(let r of Gl(o))n(r)}for(let o of Object.values(e.facilities))n(o.entry);for(let o of Object.values(e.facilities))if(o.gridPlaced)for(let r=0;r<(o.hCells||1);r+=1)for(let i=0;i<(o.wCells||1);i+=1)n({col:o.col+i,row:o.row+r});return t}function _l(e,t,n,o="powerWire",r=!1){Re(t,n)&&e.powerWires.set(E(t,n),{kind:o,price:r?0:_.power.wires[o]?.price||0,builtSession:r?null:e.buildSession})}function Wl(e){let t=Te.starterGenerator,n={type:"facility",id:"starterGenerator",baseId:"starterGenerator",name:t.name,col:6,row:6,wCells:t.footprint.cols,hCells:t.footprint.rows,gridPlaced:!0,level:1,price:0,builtSession:null,unsellable:!0};n.x=p.x+n.col*p.cell,n.y=p.y+n.row*p.cell,n.w=n.wCells*p.cell,n.h=n.hCells*p.cell,e.facilities.starterGenerator=n}function os(e){e.powerWires=new Map;let t=[[5,6],[4,6],[3,6],[2,6],[1,6],[0,6],[0,5],[0,4],[8,7],[8,8],[9,8],[10,8],[11,8],[12,8],[12,9],[13,8],[14,8],[15,8],[16,8],[17,8],[18,8],[18,9]];for(let[n,o]of t)_l(e,n,o,"powerWire",!0)}function Ul(e){let t=new Set;for(let n of Object.values(e.facilities||{}))if(n.gridPlaced)for(let o=0;o<(n.hCells||1);o+=1)for(let r=0;r<(n.wCells||1);r+=1)t.add(E(n.col+r,n.row+o));for(let n of e.powerWires.keys())if(e.blockedCells.has(n)||t.has(n))throw new Error(`Invalid starter power wire at ${n}`);for(let n of["starterGenerator","mixer","trash","truck"])if(!e.facilities[n])throw new Error(`Missing starter power facility: ${n}`)}function rs(e){let t=Fl.map(([n,o])=>({col:n,row:o}));for(let{col:n,row:o}of t)is(e,n,o);for(let n=0;n({...n,keys:n.keys?{left:{...n.keys.left},right:{...n.keys.right}}:null,queue:[]})),e.eggFarms=Bl.map(n=>{let o=Jt(n);return{...n,nextSpawn:o,lastInterval:o}}),os(e);let t=ss(e);for(let n of e.powerWires.keys())t.add(n);e.blockedCells=qi({seed:e.runSeed,targetRatio:_.map.blockedRatio,reserved:[...t]}),Vl(e),rs(e),os(e),Ul(e),e.power={dirty:!0,elapsed:0,routes:new Map,assignments:new Map,sources:new Map,underVoltage:new Set},e.walkabilityVersion=(e.walkabilityVersion||0)+1,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function Pt(e){return e?[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row}]:[]}function ge(e){let t=B(e.col,e.row);return{x:t.x+p.cell/2,y:t.y-p.cell/2}}function it(e,t,n){return e.eggFarms.find(o=>o.col===t&&o.row===n)||null}function st(e,t,n){return e.scanners.find(o=>Pt(o).some(r=>r.col===t&&r.row===n))||null}function Zt(e,t){return e.scanners.find(n=>n.id===t)||null}function $r(e,t){return e.scanners.find(n=>n.kind==="manual"&&n.slot===t)||null}function mn(e){return e?.baseId||e?.id||""}function Fr(e,t){return Object.entries(e.facilities||{}).filter(([,n])=>mn(n)===t)}function Ro(e,t){return!!(t&&Re(t.col,t.row)&&(!e?.ownedCells?.size||e.ownedCells.has(E(t.col,t.row))))}function bt(e,t,n){return Object.values(e?.facilities||{}).find(o=>o?.gridPlaced?t>=o.col&&t=o.row&&n({col:e.col+t.dc,row:e.row+t.dr})).filter(t=>Re(t.col,t.row)):[]}function cs(e,t,n=[],o=[]){if(!t||!Re(t.col,t.row))return[];let r=[],i=a=>{!a||!Re(a.col,a.row)||!e.conveyorTiles.has(E(a.col,a.row))||n.some(c=>c&&ko(a,c))||r.some(c=>ko(c,a))||r.push({...a,viaTolerance:!ko(a,t)})};i(t);for(let a of o)i(a);for(let a of ls(t))i(a);return r}function Ar(e,t,n=[],o=[]){let r=cs(e,t,n,o),i=r.filter(a=>!a.viaTolerance);return i.length?i:r}function Kl(e,t){let n=We(t,"inputA");return!n||!Re(n.col,n.row)?[]:Ar(e,n,Pt(t))}function ql(e,t,n){let o=We(t,n);return cs(e,o,Pt(t))}function zl(e,t){let n=e.facilities[t]||Fr(e,t)[0]?.[1];if(!n)return null;let o=wt(e,n);if(o)return B(o.col,o.row);let r=mn(n)||t;return r==="mixer"?{x:n.x+n.w,y:n.y+n.h*.52}:r==="truck"?{x:n.x,y:n.y+n.h*.52}:r==="trash"?{x:n.x+n.w/2,y:n.y+8}:{x:n.x+n.w/2,y:n.y+n.h/2}}function us(e,t,n){return n==="inputA"?Kl(e,t).length>0:ql(e,t,n).length>0}function Ee(e){e.branchCounters?.clear?.(),e.routeCache=null,e.routingVersion=(e.routingVersion||0)+1,e.factoryGraph=null,e.factoryGraphCommittedVersion=-1,e.frameCache&&(e.frameCache.routingVersion=-1,e.frameCache.congestionFrame=-1,e.frameCache.draw={})}function ze(e,t){return E(e,t)}function wn(e){return X(e)}function Hl(e,t){let n=e.conveyorMeta?.get?.(t)||{},o=[];return Array.isArray(n.outDirs)&&o.push(...n.outDirs),n.dir&&o.push(n.dir),[...new Set(o)].filter(r=>fe.some(i=>i.name===r))}function as(e,t,n){let o=fe.find(a=>a.name===n);if(!o)return!1;let r=e.conveyorMeta?.get?.(ze(t.col+o.dc,t.row+o.dr));return r?[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))].includes(o.opposite):!1}function Yl(e,t){let n=wn(t),o=e.conveyorMeta?.get?.(t)||{},r=fe.filter(C=>e.conveyorTiles.has(ze(n.col+C.dc,n.row+C.dr))).map(C=>C.name),i=Hl(e,t).filter(C=>r.includes(C)),a=i.length?i:r;if(r.length===1&&(!i.length||i.includes(r[0]))&&as(e,n,r[0]))return[];if(r.length<3)return a;let c=new Set(r.filter(C=>as(e,n,C))),b=r.filter(C=>!c.has(C)),M=c.size?b:[...new Set(a)];return!M.length&&!c.size&&(M=r),o.branchMode&&o.branchMode!=="random"&&M.length>=2&&M.includes(o.branchMode)?[o.branchMode]:M}function Ql(e){return{version:e.routingVersion||0,cells:new Set,adjacency:new Map,components:new Map,cellToComponent:new Map,scannerInputs:new Map,scannerPorts:new Map,facilityPorts:new Map,farmOutputs:new Map,pathCache:new Map,metrics:{conveyorCells:0,edges:0,components:0,deadEnds:0,crosses:0,scannerPorts:0,connectedScannerPorts:0,facilityPorts:0,connectedFacilityPorts:0,farmOutputs:0},issues:[]}}function Xl(e){let t=Ql(e);for(let o of e.conveyorTiles)t.cells.add(o),t.adjacency.set(o,[]);for(let o of t.cells){let r=wn(o),i=Yl(e,o),a=fe.filter(c=>i.includes(c.name));for(let c of a){let b=ze(r.col+c.dc,r.row+c.dr);t.cells.has(b)&&t.adjacency.get(o).push({key:b,dir:c.name})}}let n=0;for(let[o,r]of t.adjacency.entries()){n+=r.length;let i=new Set(r.map(a=>a.dir));r.length===1&&(t.metrics.deadEnds+=1),r.length===4&&i.has("left")&&i.has("right")&&i.has("up")&&i.has("down")&&(t.metrics.crosses+=1)}return t.metrics.conveyorCells=t.cells.size,t.metrics.edges=Math.floor(n/2),jl(t),Jl(e,t),t.issues=uc(e,t,{includeRoutes:!1}),t}function jl(e){let t=1;for(let n of e.cells){if(e.cellToComponent.has(n))continue;let o=t++,r=[n],i=[];for(e.cellToComponent.set(n,o);r.length;){let a=r.shift();i.push(a);for(let c of e.adjacency.get(a)||[])e.cellToComponent.has(c.key)||(e.cellToComponent.set(c.key,o),r.push(c.key))}e.components.set(o,{id:o,cells:i,capacity:Math.max(1,i.length),count:0,ratio:0})}e.metrics.components=e.components.size}function Jl(e,t){for(let n of e.scanners){let o={};for(let r of["inputA","left","right"]){let i=We(n,r),a=Ar(e,i,Pt(n)).filter(M=>t.cells.has(ze(M.col,M.row))),c=a.map(M=>ze(M.col,M.row)),b=c.length>0;if(o[r]={type:r,cell:i,cells:a,keys:c,key:c[0]||null,connected:b},t.metrics.scannerPorts+=1,b&&(t.metrics.connectedScannerPorts+=1),r==="inputA")for(let M of c)t.scannerInputs.set(M,n.id)}t.scannerPorts.set(n.id,o)}for(let[n,o]of Object.entries(e.facilities)){let r=wt(e,o);if(!r)continue;let i=Ar(e,r).filter(b=>t.cells.has(ze(b.col,b.row))),a=i.map(b=>ze(b.col,b.row)),c=a.length>0;t.facilityPorts.set(n,{id:n,cell:{...r},cells:i,keys:a,key:a[0]||null,connected:c}),t.metrics.facilityPorts+=1,c&&(t.metrics.connectedFacilityPorts+=1)}for(let n of e.eggFarms){let o=ls({col:n.col,row:n.row}).map(r=>ze(r.col,r.row)).filter(r=>t.cells.has(r));t.farmOutputs.set(n.id,o),t.metrics.farmOutputs+=o.length}}function at(e){let t=e.routingVersion||0;return(!e.factoryGraph||e.factoryGraph.version!==t)&&(e.factoryGraph=Xl(e)),e.factoryGraph}function ds(e){let t=at(e);return e.factoryGraphCommittedVersion=t.version,e.factoryGraphSnapshot=Zl(t),t}function Zl(e){return e?{version:e.version,conveyorCells:e.metrics.conveyorCells,edges:e.metrics.edges,components:e.metrics.components,deadEnds:e.metrics.deadEnds,crosses:e.metrics.crosses,scannerPorts:`${e.metrics.connectedScannerPorts}/${e.metrics.scannerPorts}`,facilityPorts:`${e.metrics.connectedFacilityPorts}/${e.metrics.facilityPorts}`,farmOutputs:e.metrics.farmOutputs,issues:[...e.issues||[]]}:null}function ec(e,t){let n=t.col-e.col,o=t.row-e.row;return fe.find(r=>r.dc===n&&r.dr===o)?.name||null}function Or(e,t,n){let o=at(e),r=ze(t.col,t.row);if(!o.cells.has(r))return[];let i=`${r}|${n.cacheKey||"dynamic"}`;if(n.cacheKey&&o.pathCache.has(i))return o.pathCache.get(i).map(ae=>ae.map(ye=>({...ye})));let a=`${r}|none`,c=[{key:r,col:t.col,row:t.row,incoming:"none",depth:0}],b=new Map([[a,0]]),M=new Map,C=[],$=1/0,W=8,K=24,G=80;for(;c.length;){let ae=c.shift();if(ae.depth>$)break;let ye=`${ae.key}|${ae.incoming}`;if(n(ae)){if(C.push(ye),$=ae.depth,C.length>=K)break;continue}for(let L of o.adjacency.get(ae.key)||[]){let V=wn(L.key),se=ec(ae,V),O=ae.depth+1;if(O>$)continue;let H=`${L.key}|${se}`,oe=b.get(H);if(oe==null)b.set(H,O),M.set(H,[ye]),c.push({key:L.key,col:V.col,row:V.row,incoming:se,depth:O});else if(oe===O){let ue=M.get(H)||[];ue.length{if(z.length>=G)return;let[L]=ae.split("|"),V=[wn(L),...ye];if(ae===a||L===r){z.push(V);return}for(let se of M.get(ae)||[])Q(se,V)};for(let ae of C)Q(ae,[]);let ie=[],J=new Set;for(let ae of z){let ye=ae.map(L=>ze(L.col,L.row)).join(">");J.has(ye)||(J.add(ye),ie.push(ae))}return n.cacheKey&&o.pathCache.set(i,ie.map(ae=>ae.map(ye=>({...ye})))),ie}function fs(e){let t=at(e),n=new Map;for(let[o,r]of t.components.entries())n.set(o,{id:o,cells:[...r.cells],capacity:r.capacity,count:0,ratio:0});return{components:n,cellToComponent:new Map(t.cellToComponent)}}function Ao(e,t=null){let n=e.map(o=>B(o.col,o.row));return t&&n.push(t),n}function Wt(e,t){t&&(!e.length||Gi(e[e.length-1],t)>1)&&e.push(t)}function tc(e,t,n,o=null){let r=[{x:e.x,y:e.y}];Wt(r,B(t.col,t.row));for(let i of Ao(n,o))Wt(r,i);return r}function nc(e,t){let n=Ao(e),o=We(t,"inputA");return o&&Wt(n,B(o.col,o.row)),Wt(n,ge(t)),n}function oc(e,t,n,o){let r=[{x:e.x,y:e.y}];Wt(r,B(t.col,t.row));for(let a of Ao(n))Wt(r,a);let i=We(o,"inputA");return i&&Wt(r,B(i.col,i.row)),Wt(r,ge(o)),r}function rc(e,t,n=0){let o=B(t.col,t.row),r=0;for(let i of e.chicks||[]){if(i.stage==="flying"||i.stage==="queued")continue;Math.hypot(i.x-o.x,i.y-o.y){let W=C.roleBias??0,K=$.roleBias??0;if(W!==K)return W-K;let G=C.cells?.length??C.route?.length??Number.POSITIVE_INFINITY,z=$.cells?.length??$.route?.length??Number.POSITIVE_INFINITY;if(G!==z)return G-z;let Q=C.key||JSON.stringify(C.route||C.cells||C),ie=$.key||JSON.stringify($.route||$.cells||$);return Q.localeCompare(ie)});if(!o||r.length===1)return r[0];let i=r[0].roleBias??0,a=r.filter(C=>(C.roleBias??0)===i),c=a.map(C=>({item:C,score:ic(e,C)})),b=Math.min(...c.map(C=>C.score));a=c.filter(C=>C.score===b).map(C=>C.item);let M=e.branchCounters.get(t)||0;return e.branchCounters.set(t,M+1),a[Math.floor(Math.random()*a.length)]}function ps(e){return e.role===0?{left:{match:"male",destination:"mixer"},right:{match:"default",destination:"scanner-role-1"}}:{left:{match:"poop",destination:"trash"},right:{match:"default",destination:"truck"}}}function Br(e){let t=ps(e);return{left:t.left.destination,right:t.right.destination}}function Dr(e,t){return ps(e).left.match===t.sex?"left":"right"}function Lr(e){return Wi(e)}function Nr(e){return{mixer:"#2477ff",truck:"#ff6aa8",inboundTruck:"#8bd0ff",trash:"#22b94f",sausageMaker:"#d78b3f",biomassGenerator:"#7bd84f",coalGenerator:"#d0d5dc","scanner-role-1":"#526456",scanner:"#526456",input:"#526456"}[e]||"#102015"}function en(e,t,n=!1){let o=at(e),r=(o.farmOutputs.get(t.id)||[]).map(wn),i=[];for(let b of r){let M=$=>o.scannerInputs.has(ze($.col,$.row));M.cacheKey=`farmInput:${b.col},${b.row}:v${o.version}`;let C=Or(e,b,M);for(let $ of C){let W=$[$.length-1],K=o.scannerInputs.get(ze(W.col,W.row)),G=Zt(e,K);G&&i.push({key:`${G.id}:${W.col},${W.row}:${$.length}`,scanner:G,cells:$})}}let a=Io(e,`farm:${t.id}`,i,n);if(a)return{scannerId:a.scanner.id,route:nc(a.cells,a.scanner)};let c=Io(e,`farm:${t.id}:output`,r.map(b=>({key:E(b.col,b.row),cells:[b]})),n);return c?{scannerId:null,route:Ao(c.cells)}:null}function ys(e,t,n,o,r=!1){let i=Zt(e,o);if(!i)return null;let c=at(e).scannerPorts.get(i.id)?.[t],b=We(i,t),M=c?.connected?(c.keys||[c.key]).filter(Boolean).map(wn):[];if(!b||!M.length)return null;let C=Br(i)[t];return C==="scanner-role-1"?sc(e,i,t,n,b,M,r):ac(e,i,t,n,b,M,C,r)}function sc(e,t,n,o,r,i,a){let c=at(e),b=e.scanners.filter($=>$.id!==t.id&&c.scannerPorts.get($.id)?.inputA?.connected),M=[];for(let $ of i)for(let W of b){let K=c.scannerPorts.get(W.id)?.inputA?.key;if(!K)continue;let G=(c.scannerPorts.get(W.id)?.inputA?.keys||[K]).filter(Boolean),z=J=>G.includes(ze(J.col,J.row));z.cacheKey=`toScanner:${$.col},${$.row}:${W.id}:v${c.version}`;let Q=Or(e,$,z),ie=W.role===1?0:1;for(let J of Q)M.push({key:`${ie}:start${E($.col,$.row)}:s${W.id}:${J.length}:${E(J[J.length-1].col,J[J.length-1].row)}`,target:W,cells:J,roleBias:ie})}let C=Io(e,`scanner:${t.id}:${n}:toRole1`,M,a);return C?{destination:"scanner",nextScannerId:C.target.id,route:oc(o,r,C.cells,C.target)}:null}function ac(e,t,n,o,r,i,a,c){let b=at(e),M=[...b.facilityPorts.entries()].filter(([W,K])=>K?.connected&&mn(e.facilities?.[W])===a);if(!M.length)return null;let C=[];for(let W of i)for(let[K,G]of M){let z=(G.keys||[G.key]).filter(Boolean);if(!z.length)continue;let Q=J=>z.includes(ze(J.col,J.row));Q.cacheKey=`toFacility:${W.col},${W.row}:${K}:v${b.version}`;let ie=Or(e,W,Q);for(let J of ie)C.push({key:`start${E(W.col,W.row)}:${K}:${J.length}:${E(J[J.length-1].col,J[J.length-1].row)}`,cells:J,facilityId:K})}let $=Io(e,`scanner:${t.id}:${n}:${a}`,C,c);return $?{destination:a,facilityId:$.facilityId,route:tc(o,r,$.cells,zl(e,$.facilityId))}:null}function hs(e,t,n=new Set){if(!t||n.has(t.id))return!1;n.add(t.id);for(let o of["left","right"]){let r=ys(e,o,ge(t),t.id,!1);if(r){if(["mixer","trash","truck","sausageMaker"].includes(r.destination))return!0;if(r.destination==="scanner"){let i=Zt(e,r.nextScannerId);if(hs(e,i,n))return!0}}}return!1}function lc(e,t){return!!en(e,t,!1)?.scannerId}function vn(e){if(e.phase!=="build")return[];let t=[];for(let n of e.eggFarms||[])lc(e,n)||t.push({type:"eggFarm",id:n.id,ref:n,message:"This Egg will not produce chicks"});for(let n of Cr)for(let[o,r]of Fr(e,n))at(e).facilityPorts.get(o)?.connected||t.push({type:"facility",id:o,ref:r,message:"This facility cannot receive items"});return t}function cc(e){let t=at(e);for(let r of e.eggFarms||[]){let i=en(e,r,!1);if(!i?.scannerId)continue;let a=Zt(e,i.scannerId);if(hs(e,a))return[]}let n=e.eggFarms?.length||0,o=[...t.facilityPorts.entries()].filter(([r,i])=>i?.connected&&["mixer","trash","truck"].includes(mn(e.facilities?.[r]))).length;return n?t.metrics.farmOutputs?e.scanners?.length?o?["No route from an EGG scanner to a receiver."]:["Connect at least one receiver exit: Mixer, Shredder, or Truck."]:["Build at least one scanner and connect it to an EGG route."]:["Connect at least one EGG to a conveyor."]:["Build at least one EGG before starting the next day."]}function Po(e){return e.kind==="manual"?`S${(e.slot??0)+1}`:`Auto Scanner #${e.id}`}function uc(e,t=at(e),n={}){let o=n.includeRoutes!==!1,r=[],i={mixer:"Mixer",trash:"Shredder",truck:"Truck",sausageMaker:"Sausage Machine"};for(let a of Cr){let c=Fr(e,a);if(!c.length){Di.includes(a)&&r.push(`${i[a]||a} is missing`);continue}for(let[b]of c)t.facilityPorts.get(b)?.connected||r.push(`${i[a]||a} receiver has no conveyor`)}for(let a of e.scanners){let c=t.scannerPorts.get(a.id)||{};if(c.inputA?.connected||r.push(`${Po(a)} input has no conveyor`),c.left?.connected||r.push(`${Po(a)} left output has no conveyor`),c.right?.connected||r.push(`${Po(a)} right output has no conveyor`),!!o)for(let b of["left","right"])c[b]?.connected&&!ys(e,b,ge(a),a.id)&&r.push(`${Po(a)} ${b} route is incomplete`)}if(o)for(let a of e.eggFarms)en(e,a)?.scannerId||r.push(`Egg Farm #${a.id} has no scanner route`);else for(let a of e.eggFarms)(t.farmOutputs.get(a.id)||[]).length||r.push(`Egg Farm #${a.id} has no output conveyor`);return[...new Set(r)]}function $o(e){return cc(e)}var Hn=[{key:"premiumFemaleShipment",target:"female",truckTarget:"female",title:"Premium Female Shipment",route:"Female -> Truck",note:"Today only: ship female chicks to Truck. Meet the export target for a bonus.",objective:"truckTarget"},{key:"contaminantSampleExport",target:"poop",truckTarget:"poop",title:"Contaminant Sample Export",route:"Poop value x2",note:"Today only: poop is valid Truck cargo and all poop income is doubled.",objective:"truckTarget",poopValueMultiplier:2},{key:"healthInspection",title:"Health Inspection",route:"Poop -> Shredder",note:"Today only: poop mistakes are fined double. Shred enough poop for an inspection bonus.",objective:"poopTrash",poopFineMultiplier:2},{key:"conveyorJamWarning",title:"Conveyor Jam Warning",route:"No explosions",note:"Today only: jam explosions trigger at 85% congestion. Finish with zero explosions for a bonus.",objective:"noExplosion",congestionExplosionThreshold:.85,congestionWarningThreshold:.68},{key:"powerSavingOrder",title:"Power Saving Order",route:"Slow factory subsidy",note:"Today only: conveyors -20% speed and Auto Scanners +20% cooldown. A subsidy is paid at settlement.",objective:"flatBonus",conveyorSpeedMultiplier:.8,autoScannerCooldownMultiplier:1.2},{key:"overtimeDay",title:"Overtime Day",route:"80 second day",note:"Today only: the work day is longer. No extra reward or penalty.",objective:"none",daySeconds:80},{key:"shortShift",title:"Short Shift",route:"40 second day",note:"Today only: the work day is shorter. The next Fairies tribute is reduced by 10%.",objective:"none",daySeconds:40,fairiesTributeMultiplier:.9},{key:"chickBoom",title:"Chick Boom",route:"EGG interval x0.65",note:"Today only: eggs hatch faster and poop rate rises by 5 percentage points.",objective:"none",productionMultiplier:1/.65,poopRateAdd:.05},{key:"rottenFeed",title:"Rotten Feed",route:"Poop surge",note:"Today only: poop rate rises by 20 percentage points and Shredder poop income is multiplied by 1.5.",objective:"none",poopRateAdd:.2,shredderIncomeMultiplier:1.5},{key:"maintenanceAudit",title:"Maintenance Audit",route:"Durability check",note:"Today only: machines below 50% remaining durability fail the audit. Passing with none below 50% pays a bonus.",objective:"maintenanceAudit"}];function Fe(e,t=0){let n=Number(e);return Number.isFinite(n)?n:t}function dc(e,t=0,n=1){let o=Math.max(1,Number(e?.turn||1)+1),r=Math.floor(Gr(e)*(.08+Math.random()*.08)),i=Math.floor(Math.max(0,e.cash||0)*.25),a=Math.floor(Math.max(0,t)*Math.max(1,o)*.75);return Math.max(120,Math.ceil(Math.max(r,i,a)*n))}function bs(e){return Math.max(0,Math.ceil(500+Math.max(1,e?.turn||1)*25))}function Gr(e){return[...e.eggFarms.map(t=>t.price||0),...e.scanners.map(t=>t.price||0),...Object.values(e.facilities).map(t=>t.price||0),...[...e.conveyorMeta.values()].map(t=>t.price||0)].reduce((t,n)=>t+n,0)}function fc(e,t=1,n=yt){return e.eggFarms.reduce((o,r)=>{let[i,a]=zn(r),c=Math.max(.1,(i+a)/2);return o+Math.max(1,n)/c*Math.max(.01,t||1)},0)}function pc(e,t){let n=Fe(t.productionMultiplier,1),o=Fe(t.daySeconds,yt),r=fc(e,n,o),i=Math.max(0,Number(e?.cardEffects?.hatchingFeed)||0),a=Math.max(0,Number(e?.cardEffects?.poopRateBooster)||0),c=Math.pow(1.03,i),b=vr+Sr*a,M=Math.min(.95,Math.max(0,(b+Fe(t.poopRateAdd,0))*Fe(t.poopMultiplier,1)*c));return{estimate:r,poopRate:M}}function _r(e,t){let n=typeof t=="string"?Hn.find(c=>c.key===t):t;if(!n)return null;let{estimate:o,poopRate:r}=pc(e,n),i=0;n.objective==="truckTarget"?i=Math.max(1,Math.ceil(o*.3)):n.objective==="poopTrash"&&(i=Math.max(1,Math.ceil(o*r*.8)));let a=0;return["truckTarget","poopTrash","noExplosion"].includes(n.objective)&&(a=dc(e,o)),n.objective==="flatBonus"&&(a=bs(e)),n.objective==="maintenanceAudit"&&(a=bs(e)),{id:`event-${e.turn}-${Date.now()}-${Math.floor(Math.random()*9999)}`,...n,target:n.target||null,truckTarget:n.truckTarget||null,forced:!0,productionMultiplier:Fe(n.productionMultiplier,1),poopMultiplier:Fe(n.poopMultiplier,1),poopRateAdd:Fe(n.poopRateAdd,0),daySeconds:Fe(n.daySeconds,yt),targetAmount:i,estimatedOutput:Math.round(o),reward:a,createdTurn:e.turn,oneTurnOnly:!0}}function ws(e){if(e.turn+1Oi)return null;let n=Hn[Math.floor(Math.random()*Hn.length)];return _r(e,n)}function ms(e){e.eventActive=e.eventOffer?{...e.eventOffer}:null,e.eventOffer=null}function vs(e){e.eventActive=null}function Ss(e){return Math.max(1,Fe(e.eventActive?.daySeconds,yt))}function ks(e){return Fe(e.eventActive?.productionMultiplier,1)}function Ms(e){let t=Math.max(0,Number(e?.cardEffects?.hatchingFeed)||0),n=Math.max(0,Number(e?.cardEffects?.poopRateBooster)||0),o=Math.pow(1.03,t),r=vr+Sr*n,i=Fe(e.eventActive?.poopRateAdd,0);return Math.min(.95,Math.max(0,(r+i)*Fe(e.eventActive?.poopMultiplier,1)*o))}function Sn(e){return e.eventActive?.truckTarget||e.eventActive?.target||"female"}function Wr(e,t){return t==="male"?e.truckMale||0:t==="poop"?e.poopTruck||0:e.truckFemale||0}function Cs(e,t){return Sn(e)===t}function gs(e){return Sn(e)!=="male"}function Ur(e){return Math.max(.01,Fe(e.eventActive?.poopValueMultiplier,1))}function Fo(e){return Math.max(.01,Ur(e)*Fe(e.eventActive?.shredderIncomeMultiplier,1))}function Vr(e){return Math.max(.01,Fe(e.eventActive?.poopFineMultiplier,1))}function Kr(e){return Math.max(.1,Math.min(1,Fe(e.eventActive?.congestionExplosionThreshold,1)))}function xs(e){return Math.max(.1,Math.min(1,Fe(e.eventActive?.congestionWarningThreshold,.8)))}function Ts(e){return Math.max(.01,Fe(e?.fairiesTributeMultiplier,1))}function yc(e){let t=0,n=(o,r)=>{let i=Math.max(1,Fe(r,1)),a=Math.max(0,Fe(o,0));1-Math.min(1,a/i)<.5&&(t+=1)};for(let o of e.conveyorMeta?.values?.()||[])n(o.uses,o.durability);for(let o of e.eggFarms||[])n(o.maintenance?.uses,o.maintenance?.durability);for(let o of e.scanners||[])o.kind==="auto"&&n(o.maintenance?.uses,o.maintenance?.durability);for(let o of Object.values(e.facilities||{})){let r=o?.baseId||o?.id;(r==="mixer"||r==="trash"||r==="sausageMaker")&&n(o.maintenance?.uses,o.maintenance?.durability)}return t}function Es(e){let t=e.eventActive;if(!t)return null;let n=0,o=!0,r=0,i="";t.objective==="truckTarget"?(n=Wr(e.stats,t.target),o=n>=t.targetAmount,r=o?t.reward:0):t.objective==="poopTrash"?(n=e.stats.poopTrash||0,o=n>=t.targetAmount,r=o?t.reward:0):t.objective==="noExplosion"?(n=e.stats.explosions||0,o=n===0,r=o?t.reward:0,i=`${n} explosion(s)`):t.objective==="flatBonus"?(o=!0,r=t.reward):t.objective==="maintenanceAudit"?(n=yc(e),o=n===0,o&&(r=t.reward),i=`${n} machine(s) below 50%`):o=!0,r>0?(tt(e,r),e.stats.eventBonus=(e.stats.eventBonus||0)+r,e.totals.eventBonus+=r,e.totals.eventSuccess+=1):t.objective&&t.objective!=="none"&&(e.stats.eventBonus=e.stats.eventBonus||0,e.totals.eventFailed+=o?0:1,o&&(e.totals.eventSuccess+=1));let a={title:t.title,key:t.key,target:t.target,route:t.route,objective:t.objective,targetAmount:t.targetAmount||0,count:n,success:o,bonus:r,reward:t.reward||0,productionMultiplier:t.productionMultiplier,poopMultiplier:t.poopMultiplier,daySeconds:t.daySeconds,detail:i};return e.stats.eventResult=a,a}function qr(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function hc(e){return!!e?.cardEffects?.usedMachineActive}function bc(e,t){return t?1:Math.min(.8,.5+.1*Math.min(3,qr(e,"recyclingSubsidy")))}function wc(e){return Math.pow(.95,qr(e,"safetyCover"))}function Oo(e){let t=e?.ref||e||{},n=e?.type||t.type;return n==="conveyor"?t.price||Te[t.kind]?.price||Te.conveyor.price:n==="eggFarm"?t.price||Te.eggFarm.price:n==="scanner"?t.price||(t.kind==="auto"?Te.autoScanner.price:Te.manualScanner.price):n==="facility"?t.price||Te[t.id]?.price||0:n==="maintenanceRoom"?t.price||Te.maintenanceRoom.price:Te[t.id]?.price||0}function Le(e,t=null){let n=Te[e]?.price||0;return hc(t)?Math.ceil(n*.5):n}function mc(e,t){return e?.facilities?Object.values(e.facilities).filter(n=>(n?.baseId||n?.id)===t).reduce((n,o)=>n+Math.max(0,(o.level||1)-1),0):0}function Rt(e,t){return Li.includes(t)?Math.pow(Ie.incomeUpgradeRate,mc(e,t)):1}function Je(e){return Math.ceil(Ie.income.truck*Rt(e,"truck"))}function lt(e){return Math.ceil((Ie.income.sausage||26)*Rt(e,"mixer")*Rt(e,"sausageMaker"))}function Yn(e){return Math.ceil(Ie.poopFine*Rt(e,"mixer")*Vr(e))}function Qn(e){return Math.ceil(Ie.poopFine*Rt(e,"truck")*Vr(e))}function zr(e){let t=Ie.maleTruckFinePerHalfDay*(e.turn/2);return Math.ceil(t*Rt(e,"truck"))}function Hr(e){return e?.facilities?Object.values(e.facilities).filter(t=>(t?.baseId||t?.id)==="trash").reduce((t,n)=>t+Math.max(0,(n.level||1)-1),0):0}function At(e){return Math.min(Ie.shredderBonus.maxCards,Hr(e))}function kn(){return Ie.shredderBonus.maxCards}function Bo(){return Ie.shredderBonus||{}}function Ps(e){let t=typeof e=="number"?e:At(e),n=Bo(),o=Math.min(n.maxCards||30,Math.max(0,t));return o>0?Math.ceil((n.payoutCoefficient||1.6)*Math.pow(o,n.payoutExponent||1.25)):0}function tn(e){let t=typeof e=="number"?e:At(e);if(t<=0)return 0;let n=Bo();return Math.min(n.maxHitChance||.82,(n.baseHitChance||.28)+t*(n.hitChancePerUpgrade||.018))}function vc(e){let t=Bo(),n=Math.min(t.jackpotMaxChance||.08,(t.jackpotBaseChance||.01)+e*(t.jackpotChancePerUpgrade||.0025)),o=Math.min(t.bigWinMaxChance||.12,(t.bigWinBaseChance||.07)+e*(t.bigWinChancePerUpgrade||.0015)),r=Math.min(1-n-o,t.doubleChance||.2),i=Math.max(0,1-n-o-r);return n*(t.jackpotMultiplier||10)+o*(t.bigWinMultiplier||4)+r*(t.doubleMultiplier||2)+i}function It(e){let t=typeof e=="number"?e:At(e);return Math.round(Ps(t)*tn(t)*vc(t))}function Sc(e){let t=At(e),n=tn(t),o=Ps(t);if(t<=0||Math.random()>=n)return{cards:t,chance:n,amount:0,expected:It(t),baseAmount:o,multiplier:0,tier:"miss"};let r=Bo(),i=Math.min(r.jackpotMaxChance||.08,(r.jackpotBaseChance||.01)+t*(r.jackpotChancePerUpgrade||.0025)),a=Math.min(r.bigWinMaxChance||.12,(r.bigWinBaseChance||.07)+t*(r.bigWinChancePerUpgrade||.0015)),c=Math.min(1-i-a,r.doubleChance||.2),b=Math.random(),M=1,C="normal";b0&&(e.stats.shredderBonus=(e.stats.shredderBonus||0)+t.amount,e.totals.shredderBonus=(e.totals.shredderBonus||0)+t.amount,tt(e,t.amount)),t}function Yr(e,t=e.turn,n=null){let o=Math.max(1,Math.floor(Number(t)||1)),r=Ie.fairiesTribute||{perDay:10,profitExemption:300,legalWorkExemptionBonus:250,profitRate:.12},i=Math.ceil(o*(r.perDay||10)),a=Math.max(0,Math.floor(Number(n??e?.lastResult?.profit??e?.stats?.profit??0)||0)),c=Math.max(0,e?.cardEffects?.legalWork||0),b=Math.max(0,(r.profitExemption||0)+c*(r.legalWorkExemptionBonus||0)),M=Math.max(0,a-b),C=Math.ceil(M*Math.max(0,Number(r.profitRate)||0)),$=i+C,W=Math.max(0,e?.cardEffects?.fairiesFlatteryNext||e?.cardEffects?.flattery||0),K=W>0?Math.pow(.5,W):1,G=Math.max(.01,Number(e?.pendingFairiesTributeMultiplier)||1),z=K*G,Q=Math.max(0,Math.ceil($*z)),ie=Math.max(0,$-Q);return{day:o,base:i,profit:a,legalWork:c,profitExemption:b,taxableProfit:M,profitTribute:C,gross:$,flatteryCount:W,eventMultiplier:G,perCardReduction:Math.ceil($*.5),reduction:ie,amount:Q}}function Ut(e,t){let n=e?.ref||e||{},o=e?.type==="conveyor"?t?.conveyorMeta?.get(e.oldKey||n.id):n,r=o?.price||Oo(e||n),i=o?.builtSession===t?.buildSession;if(o?.noRefund||n?.noRefund)return{amount:0,sameBuild:i,price:r,rate:0,noRefund:!0};let a=bc(t,i);return{amount:Math.max(0,Math.ceil(r*a)),sameBuild:i,price:r,rate:a,noRefund:!1}}function kc(e,t=null){let n=Math.max(1,Math.ceil((Number(e)||0)/Ie.explosionDamageDivisor));return Math.max(1,Math.ceil(n*wc(t)))}function Mc(e,t){return Math.max(0,Math.ceil(t))}function Is(e,t){e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,t>=0?(e.stats.revenue+=t,e.totals.revenue+=t):(e.stats.penalty+=Math.abs(t),e.totals.penalty+=Math.abs(t)),e.totals.maxCash=Math.max(e.totals.maxCash,e.cash)}function tt(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&Is(e,n),n}function Mt(e,t){let n=Math.max(0,Math.ceil(t));return n>0&&Is(e,-n),n}function Ct(e,t){Mt(e,t)}function Qr(e,t){t<=0||(e.cash+=t,e.stats.profit+=t,e.totals.profit+=t,e.totals.maxCash=Math.max(e.totals.maxCash,e.cash))}function As(e){let t=Ie.income.mixer;return e.stats.mixerRevenue+=t,tt(e,t),t}function $s(e){let t=Yn(e);return e.stats.mixerPoopFine+=t,e.totals.mixerPoopFine+=t,Mt(e,t),t}function Fs(e){let t=Qn(e);return e.stats.truckPoopFine+=t,e.totals.truckPoopFine+=t,Mt(e,t),t}function Os(e){let t=zr(e);return e.stats.maleTruckFine+=t,e.totals.maleTruckFine+=t,Mt(e,t),t}function Bs(e,t){let n=kc(t,e);return e.stats.explosionDamage+=n,e.totals.explosionDamage+=n,Mt(e,n),n}function Ds(e){let t=Sn(e),n=t==="poop"?Math.ceil(Je(e)*Ur(e)):Je(e),o=Array.isArray(e.shippedCargo)?e.shippedCargo:Array.isArray(e.truckCargo)?e.truckCargo:[],r=o.filter(G=>G.sex===t),i=r.length||Wr(e.stats,t),a=r.length?r.reduce((G,z)=>G+Math.ceil(n*(t==="female"?Math.max(1,z.sourceQuality||1):1)),0):i*n,c=o.filter(G=>G.sex==="sausage"),b=c.length||Math.max(0,e?.stats?.sausageShipped||0),M=lt(e),C=c.length?c.reduce((G,z)=>G+Math.ceil(M*Math.max(1,z.sourceQuality||1)),0):b*M,$=i*n+b*M,W=Math.max(0,a+C-$);e.stats.qualityRevenue=(e.stats.qualityRevenue||0)+W,e.totals.qualityRevenue=(e.totals.qualityRevenue||0)+W;let K=Mc(e,a+C);return e.stats.pendingTruckRevenue=K,e.stats.truckRevenue=K,e.stats.sausageRevenue=C,t==="poop"?e.stats.poopShipmentIncome=a:e.stats.chickShipmentIncome=a,K>0&&tt(e,K),{base:a,adjusted:K,target:t,targetCount:i,unitPrice:n,sausageCount:b,sausageUnitPrice:M,sausageRevenue:C}}function Ls(e,t=e.turn,n=null,o={}){let r=Yr(e,t,n);return e.cardEffects&&(e.cardEffects.fairiesFlatteryNext=0,e.cardEffects.flattery!=null&&delete e.cardEffects.flattery),e.pendingFairiesTributeMultiplier!=null&&(e.pendingFairiesTributeMultiplier=1),r.amount<=0||(o.recordStats?(e.stats.fairiesTribute=(e.stats.fairiesTribute||0)+r.amount,e.totals.fairiesTribute=(e.totals.fairiesTribute||0)+r.amount,Mt(e,r.amount)):(e.totals.fairiesTribute=(e.totals.fairiesTribute||0)+r.amount,e.totals.penalty=(e.totals.penalty||0)+r.amount,e.totals.profit=(e.totals.profit||0)-r.amount,e.cash-=r.amount)),r}function Ns(e){let t=qr(e,"chemicalWeaponSubsidy"),n=Math.max(0,e?.stats?.poopTruck||0),o=Ie.chemicalWeaponSubsidy||{poopPerBlock:70,yenPerBlock:1200},r=Math.floor(n/Math.max(1,o.poopPerBlock||70)),i=t>0&&r>0?r*Math.max(0,o.yenPerBlock||1200)*t:0;return i>0&&(e.stats.chemicalWeaponSubsidy=(e.stats.chemicalWeaponSubsidy||0)+i,e.totals.chemicalWeaponSubsidy=(e.totals.chemicalWeaponSubsidy||0)+i,tt(e,i)),{cards:t,poopTruck:n,blocks:r,amount:i}}function Gs(e){let t=Gr(e),n=Math.max(1,e.totals.turnsCompleted||e.turn||1),o=Math.max(0,e.cash+e.totals.revenue+t*.5+e.totals.eventBonus*.5),r=Math.ceil(o/n),i=Math.floor(n*35+Math.max(0,n-5)*15),a=e.totals.correct*5,c=e.totals.explosionDamage;return{score:Math.max(0,Math.floor(o+r+a-e.totals.penalty-i)),factoryValue:t,base:o,dailyEarned:r,dayPenalty:i,correctBonus:a,explosionPenalty:c,days:n}}function Cc(e){return{...e,keys:e.keys?{left:{...e.keys.left},right:{...e.keys.right}}:null,queue:[],cooldown:e.cooldown||0}}function Xn(e){return JSON.stringify({cash:e.cash,stats:e.stats,totals:e.totals,nextId:e.nextId,gridX:p.x,gridY:p.y,gridCols:e.gridCols||p.cols,gridRows:e.gridRows||p.rows,gridExpansionPurchases:e.gridExpansionPurchases||0,gridExpansionPurchasesByDirection:e.gridExpansionPurchasesByDirection||{left:0,right:0,up:0,down:0},gridChunkOriginX:e.gridChunkOriginX||0,gridChunkOriginY:e.gridChunkOriginY||0,ownedCells:[...e.ownedCells||[]],ownedChunks:[...e.ownedChunks||[]],blockedCells:[...e.blockedCells||[]],selected:e.selected,multiSelected:e.multiSelected||[],buildTool:e.buildTool,view:e.view,facilities:e.facilities,eggFarms:e.eggFarms,scanners:e.scanners.map(Cc),conveyorTiles:[...e.conveyorTiles],conveyorMeta:[...e.conveyorMeta.entries()],powerWires:[...(e.powerWires||new Map).entries()],footbridges:[...(e.footbridges||new Map).entries()],footbridgeOrientation:e.footbridgeOrientation||"vertical",powerOverlay:!!e.powerOverlay,imports:{schedules:[...(e.imports?.schedules||new Map).entries()]},branchCounters:[...e.branchCounters.entries()],cardEffects:e.cardEffects,cardDraft:e.cardDraft,cardTargetPick:e.cardTargetPick})}function _s(e,t){let n=JSON.parse(t);e.cash=n.cash,e.stats=n.stats,e.totals=n.totals,e.nextId=n.nextId,p.x=n.gridX??_.grid.x,p.y=n.gridY??_.grid.y,p.cols=n.gridCols||_.grid.cols,p.rows=n.gridRows||_.grid.rows,e.gridCols=p.cols,e.gridRows=p.rows,e.gridExpansionPurchases=n.gridExpansionPurchases||0,e.gridExpansionPurchasesByDirection=n.gridExpansionPurchasesByDirection||{left:0,right:0,up:0,down:0},e.gridExpansionPurchasesByDirection.left==null&&(e.gridExpansionPurchasesByDirection.left=0),e.gridExpansionPurchasesByDirection.down==null&&(e.gridExpansionPurchasesByDirection.down=0),e.gridChunkOriginX=n.gridChunkOriginX||0,e.gridChunkOriginY=n.gridChunkOriginY||0,e.ownedCells=new Set(n.ownedCells||[]),e.ownedChunks=new Set(n.ownedChunks||[]),e.gridOwnedCells=e.ownedCells.size||p.cols*p.rows,e.blockedCells=new Set(n.blockedCells||[]),e.selected=n.selected,e.multiSelected=n.multiSelected||[],e.buildTool=n.buildTool,e.view=n.view||{x:0,y:0,scale:1},e.view.scale==null&&(e.view.scale=1),e.facilities=n.facilities||{},e.eggFarms=n.eggFarms||[],e.scanners=(n.scanners||[]).map(o=>({...o,queue:[],cooldown:o.cooldown||0})),e.conveyorTiles=new Set(n.conveyorTiles||[]),e.conveyorMeta=new Map(n.conveyorMeta||[]),e.powerWires=new Map(n.powerWires||[]),e.footbridges=new Map(n.footbridges||[]),e.footbridgeOrientation=n.footbridgeOrientation||"vertical",e.powerOverlay=!!n.powerOverlay,e.imports={schedules:new Map(n.imports?.schedules||[])},e.branchCounters=new Map(n.branchCounters||[]),e.cardEffects=n.cardEffects||{bearing:0,legalWork:0,fairiesFlatteryNext:0,scannerQueueSpacing:0},e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft=n.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardTargetPick=n.cardTargetPick||null,e.groupDrag=null,e.selectionBox=null,e.pan=null,e.routingVersion=(e.routingVersion||0)+1,e.walkabilityVersion=(e.walkabilityVersion||0)+1,e.power={...e.power||{},dirty:!0},e.factoryGraph=null,e.factoryGraphCommittedVersion=-1}function Oe(e){e.phase==="build"&&(e.undoStack.push(Xn(e)),e.undoStack.length>80&&e.undoStack.shift(),e.redoStack=[])}function Xr(e){return e.phase!=="build"||!e.undoStack.length?!1:(e.redoStack.push(Xn(e)),_s(e,e.undoStack.pop()),!0)}function jr(e){return e.phase!=="build"||!e.redoStack.length?!1:(e.undoStack.push(Xn(e)),_s(e,e.redoStack.pop()),!0)}function Y(e,t,n,o,r=w.ink){e.floatingTexts.push({x:t,y:n,text:o,color:r,life:1,maxLife:1})}function nn(e,t,n){e.shake.strength=Math.max(e.shake.strength,t),e.shake.time=Math.max(e.shake.time,n)}function Ws(e,t,n){e.effects.push({type:"spawn",priority:_e.ambient,x:t,y:n,life:.42,maxLife:.42,size:12})}function Us(e,t,n,o=w.green){e.effects.push({type:"scannerPulse",priority:_e.important,x:t,y:n,color:o,life:.42,maxLife:.42,size:24})}function Vs(e,t,n){for(let o=0;o<12;o+=1)e.effects.push({type:"meat",priority:_e.important,x:t+ne(-18,18),y:n+ne(-12,16),vx:ne(-60,60),vy:ne(-90,-25),life:ne(.45,.85),maxLife:.85,size:ne(4,8)})}function Ks(e,t,n){for(let o=0;o<16;o+=1)e.effects.push({type:"sludge",priority:_e.important,x:t+ne(-18,18),y:n+ne(-12,16),vx:ne(-46,46),vy:ne(-70,-20),life:ne(.45,.9),maxLife:.9,size:ne(4,8)})}function qs(e,t,n,o){let r=o==="poop"?w.poop:o==="male"?w.male:w.female;for(let i=0;i<22;i+=1)e.effects.push({type:"shred",priority:_e.important,x:t+ne(-16,16),y:n+ne(-8,8),vx:ne(-70,70),vy:ne(40,160),color:i%3===0?w.white:r,life:ne(.45,.95),maxLife:.95,w:ne(3,7),h:ne(10,24),rot:ne(-Math.PI,Math.PI)});gt(e,t,n,w.green,34,_e.important)}function zs(e,t,n,o){let r=o==="poop"?w.poop:o==="male"?w.danger:w.green;for(let i=0;i<8;i+=1)e.effects.push({type:"load",priority:_e.important,x:t+ne(-18,18),y:n+ne(-18,18),vx:ne(-42,42),vy:ne(-90,-25),color:r,life:ne(.35,.65),maxLife:.65,size:8})}function gt(e,t,n,o=w.danger,r=52,i=_e.critical){e.effects.push({type:"shockwave",priority:i,x:t,y:n,color:o,life:.55,maxLife:.55,size:8,maxSize:r})}function $t(e,t,n,o=12,r=w.danger,i=_e.critical){for(let a=0;a0&&(e.shake.time=Math.max(0,e.shake.time-t),e.shake.time<=0&&(e.shake.strength=0));for(let r of e.effects)if(r.life-=t,["meat","sludge","spark","smoke","shred","load","rage"].includes(r.type))r.x+=(r.vx||0)*t,r.y+=(r.vy||0)*t,r.vy=(r.vy||0)+150*t;else if(r.type==="flyingChick"){r.x+=r.vx*t,r.y+=r.vy*t,r.vy+=360*t,r.noDamage||gc(e,r,o);let i=r.x+e.view.x,a=r.y+e.view.y;(i<-100||a<-100||i>n.width+100||a>n.height+100)&&(r.life=0)}e.effects=e.effects.filter(r=>r.life>0);for(let r of e.floatingTexts)r.life-=t,r.y-=34*t;e.floatingTexts=e.floatingTexts.filter(r=>r.life>0)}function gc(e,t,n){t.hit||(t.hit=new Set);for(let o of n()){if(t.hit.has(o.id)||t.xo.x+o.w||t.yo.y+o.h)continue;t.hit.add(o.id);let r=Bs(e,o.price);Y(e,t.x,t.y-10,`-${R(r)}`,w.danger),gt(e,t.x,t.y,w.danger,30),$t(e,t.x,t.y,5,w.danger),nn(e,5,.18)}}var Qs=[[{key:"a",code:"KeyA",label:"A"},{key:"d",code:"KeyD",label:"D"}],[{key:"arrowleft",code:"ArrowLeft",label:"Left"},{key:"arrowright",code:"ArrowRight",label:"Right"}],[{key:"j",code:"KeyJ",label:"J"},{key:"l",code:"KeyL",label:"L"}],[{key:"f",code:"KeyF",label:"F"},{key:"h",code:"KeyH",label:"H"}],[{key:"q",code:"KeyQ",label:"Q"},{key:"e",code:"KeyE",label:"E"}],[{key:"z",code:"KeyZ",label:"Z"},{key:"x",code:"KeyX",label:"X"}],[{key:"u",code:"KeyU",label:"U"},{key:"o",code:"KeyO",label:"O"}],[{key:"n",code:"KeyN",label:"N"},{key:"m",code:"KeyM",label:"M"}]];function xc(e){let t=Qs[e]||Qs[0];return{left:{...t[0]},right:{...t[1]}}}function Xs(e,t,n){let o={type:"eggFarm",id:e.nextId++,col:t,row:n,level:1,nextSpawn:2,lastInterval:2,extraEggOutlet:0,price:_t.eggFarm,builtSession:e.buildSession};return o.nextSpawn=Jt(o),o.lastInterval=o.nextSpawn,o}function js(e,t,n,o){let r=o==="auto"?Te.autoScanner.price:Te.manualScanner.price,i=new Set(e.scanners.filter(c=>c.kind==="manual").map(c=>c.slot)),a=0;for(;i.has(a);)a+=1;return{type:"scanner",id:e.nextId++,kind:o,slot:o==="manual"?a:null,role:o==="manual"?a%2:0,col:t,row:n,level:1,queue:[],cooldown:0,price:r,builtSession:e.buildSession,autoMode:"standard",keys:o==="manual"?xc(a):null}}function Tc(e,t,n){let o=n.x-t.x,r=n.y-t.y,i=o*o+r*r,a=i>0?Math.max(0,Math.min(1,((e.x-t.x)*o+(e.y-t.y)*r)/i)):0,c=t.x+o*a,b=t.y+r*a;return Math.hypot(e.x-c,e.y-b)}function Ec(e){let t=[],n=e?.ownedCells?.size?[...e.ownedCells].map(o=>{let[r,i]=String(o).split(",").map(Number);return{col:r,row:i}}):Array.from({length:p.cols*p.rows},(o,r)=>({col:r%p.cols,row:Math.floor(r/p.cols)}));for(let o of n){let r=p.x+o.col*p.cell,i=p.y+o.row*p.cell,a=r+p.cell,c=i+p.cell;je(e,o.col-1,o.row)||t.push({side:"left",entry:o,a:{x:r,y:i},b:{x:r,y:c}}),je(e,o.col+1,o.row)||t.push({side:"right",entry:o,a:{x:a,y:i},b:{x:a,y:c}}),je(e,o.col,o.row-1)||t.push({side:"top",entry:o,a:{x:r,y:i},b:{x:a,y:i}}),je(e,o.col,o.row+1)||t.push({side:"bottom",entry:o,a:{x:r,y:c},b:{x:a,y:c}})}return t}function Lo(e,t=null){let n=Ec(t);if(n.length){let W=n.map(K=>({...K,distance:Tc(e,K.a,K.b)})).sort((K,G)=>K.distance-G.distance)[0];return{side:W.side,entry:{...W.entry}}}let o=(e.x-p.x)/p.cell,r=(e.y-p.y)/p.cell,i=Math.max(0,Math.min(p.cols-1,Math.round(o-.5))),a=Math.max(0,Math.min(p.rows-1,Math.round(r-.5))),c=Math.abs(e.x-p.x),b=Math.abs(e.x-(p.x+p.cols*p.cell)),M=Math.abs(e.y-p.y),C=Math.abs(e.y-(p.y+p.rows*p.cell)),$=[["left",c],["right",b],["top",M],["bottom",C]].sort((W,K)=>W[1]-K[1])[0][0];return $==="left"?{side:$,entry:{col:0,row:a}}:$==="right"?{side:$,entry:{col:p.cols-1,row:a}}:$==="top"?{side:$,entry:{col:i,row:0}}:{side:$,entry:{col:i,row:p.rows-1}}}function Mn(e){return e?.baseId||e?.id||""}function Cn(e){if(!e?.gridPlaced)return e;let t=Te[Mn(e)]||{};return e.wCells=Math.max(1,e.wCells||t.footprint?.cols||3),e.hCells=Math.max(1,e.hCells||t.footprint?.rows||3),e.x=p.x+e.col*p.cell,e.y=p.y+e.row*p.cell,e.w=e.wCells*p.cell,e.h=e.hCells*p.cell,Mn(e)==="sausageMaker"&&(e.entry={col:e.col-1,row:e.row+Math.floor(e.hCells/2)},e.side="grid"),(Mn(e)==="biomassGenerator"||Mn(e)==="coalGenerator")&&(e.entry={col:e.col-1,row:e.row+Math.floor(e.hCells/2)},e.side="grid"),e}function gn(e){if(!e?.gridPlaced)return[];let t=[];for(let n=0;n<(e.hCells||3);n+=1)for(let o=0;o<(e.wCells||3);o+=1)t.push({col:e.col+o,row:e.row+n});return t}function Pc(e,t){if(Mn(e)!=="mixer")return;let n=e.baseW||e.w||168,o=e.baseH||e.h||110;e.baseW=n,e.baseH=o;let r=t==="top"||t==="bottom";e.w=r?Math.max(n,o):Math.min(n,o),e.h=r?Math.min(n,o):Math.max(n,o)}function No(e,t="input"){if(!e)return null;let n=Mn(e);return n==="mixer"?e.side==="top"||e.side==="bottom"?t==="input"?{x:e.x+e.w/2,y:e.y}:{x:e.x+e.w/2,y:e.y+e.h}:t==="input"?{x:e.x,y:e.y+e.h/2}:{x:e.x+e.w,y:e.y+e.h/2}:n==="sausageMaker"&&e.gridPlaced?t==="input"?{x:e.x,y:e.y+e.h/2}:{x:e.x+e.w,y:e.y+e.h/2}:{x:e.x+e.w/2,y:e.y+e.h/2}}function Go(e,t,n){Pc(e,n);let o={x0:p.x+t.col*p.cell,y0:p.y+t.row*p.cell,x1:p.x+(t.col+1)*p.cell,y1:p.y+(t.row+1)*p.cell},r={x:(o.x0+o.x1)/2,y:(o.y0+o.y1)/2};return e.entry={...t},e.side=n,n==="left"?(e.x=o.x0-e.w-18,e.y=r.y-e.h/2):n==="right"?(e.x=o.x1+18,e.y=r.y-e.h/2):n==="top"?(e.x=r.x-e.w/2,e.y=o.y0-e.h-18):(e.x=r.x-e.w/2,e.y=o.y1+18),e}function Js(e,t,n,o){let{entry:r,side:i}=Lo(n,e),a=Te[t],c=a?{name:a.name,w:a.body?.w||168,h:a.body?.h||110,price:a.price}:{name:t[0].toUpperCase()+t.slice(1),w:168,h:110,price:o},b={type:"facility",id:t,name:c.name,x:0,y:0,w:c.w,h:c.h,baseW:c.w,baseH:c.h,level:1,price:o||c.price,builtSession:e.buildSession};return t==="inboundTruck"&&(b.inboundOrder={coalPerDay:0,zundaMochiPerDay:0}),Go(b,r,i)}function Zs(e,t,n,o,r){let i=Te[t],a={type:"facility",id:t,name:i?.name||t,baseId:t,col:n,row:o,wCells:i?.footprint?.cols||(t==="sausageMaker"?3:1),hCells:i?.footprint?.rows||(t==="sausageMaker"?3:1),gridPlaced:!0,level:1,price:r||i?.price||0,builtSession:e.buildSession};return(t==="biomassGenerator"||t==="coalGenerator")&&(a.fuelPulses=[]),Cn(a)}function xt(e){return e?[{col:e.col,row:e.row},{col:e.col+1,row:e.row},{col:e.col,row:e.row+1},{col:e.col+1,row:e.row+1}]:[]}function ea(e,t,n){return{type:"maintenanceRoom",id:e.nextId++,col:t,row:n,price:_t.maintenanceRoom,builtSession:e.buildSession,wCells:2,hCells:2}}function Rc(e){return Math.random()({x:i.x,y:i.y})),r=o[0];return{id:e.nextId++,sex:n,x:r.x,y:r.y,route:o,targetIndex:o.length>1?1:o.length,stage:t.stage||"belt",scannerId:t.scannerId??null,nextScannerId:null,pendingScannerId:null,radius:n==="poop"?15:17,bob:Math.random()*Math.PI*2,queueIndex:-1,queueRoute:null}}function jn(e){return e?.baseId||e?.id||""}function xn(e){if(!e)return null;let t=e.type==="scanner"?`${e.kind}Scanner`:jn(e)||e.type;return _.power.exempt.includes(t)?null:_.power.machines[t]||null}function ra(e){return _.power.generators[jn(e)]||null}function Tn(e){let t=ra(e);if(!t)return 0;let n=t.outputV||t.baseOutputV||0,o=(e.fuelPulses||[]).reduce((r,i)=>r+Math.max(0,i.voltage||0),0);return n+o}function Ic(e){return e?.gridPlaced?gn(e):[]}function Ac(e){if(!e)return[];if(e.type==="scanner")return[{col:e.col,row:e.row-1},{col:e.col+1,row:e.row-1},{col:e.col,row:e.row},{col:e.col+1,row:e.row}];if(e.type==="maintenanceRoom")return xt(e);if(e.gridPlaced){let t=jn(e),n=e.row+Math.floor((e.hCells||1)/2);return t==="sausageMaker"?[{col:e.col-1,row:n},{col:e.col+(e.wCells||3),row:n}]:[{col:e.col-1,row:n},{col:e.col+(e.wCells||1),row:n},{col:e.col+Math.floor((e.wCells||1)/2),row:e.row-1},{col:e.col+Math.floor((e.wCells||1)/2),row:e.row+(e.hCells||1)}]}return e.entry?[e.entry]:[]}function $c(e,t,n){let o=1/0;for(let r of t){for(let a of fe){let c=E(r.col+a.dc,r.row+a.dr),b=n.get(c);b!=null&&(o=Math.min(o,b))}let i=n.get(E(r.col,r.row));i!=null&&(o=Math.min(o,i))}return Number.isFinite(o)?o:null}function Fc(e,t){let n=new Map,o=[],r=(i,a)=>{a<0||a>=Tn(t)||n.has(i)&&n.get(i)<=a||(n.set(i,a),o.push({k:i,loss:a}))};for(let i of Ic(t))for(let a of fe){let c=E(i.col+a.dc,i.row+a.dr);e.powerWires?.has(c)&&r(c,_.power.wires[e.powerWires.get(c).kind]?.lossV||0)}for(;o.length;){o.sort((c,b)=>c.loss-b.loss);let i=o.shift();if(n.get(i.k)!==i.loss)continue;let a=X(i.k);for(let c of fe){let b=E(a.col+c.dc,a.row+c.dr),M=e.powerWires?.get(b);if(!M)continue;let C=_.power.wires[M.kind]?.lossV??.5;r(b,i.loss+C)}}return n}function na(e){let t=[];for(let n of Object.values(e.facilities||{}))xn(n)&&t.push(n);for(let n of e.scanners||[])xn(n)&&t.push(n);for(let n of e.maintenanceRooms||[])xn(n)&&t.push(n);return t}function ia(e){return Object.values(e.facilities||{}).filter(ra)}function Ft(e){return String(e.id??`${e.type}:${e.col},${e.row}`)}function oa(e){return e.builtSession==null?-1:e.builtSession}function _o(e){if(!e)return{dirty:!1,routes:new Map,assignments:new Map,sources:new Map,underVoltage:new Set};let t=new Map,n=ia(e).map(G=>{let z=Fc(e,G);return t.set(G.id,z),{generator:G,outputV:Tn(G),admitted:[],busVoltage:Tn(G)}}),o=[];for(let G of na(e)){let z=xn(G),Q=[];for(let ie of n){let J=$c(e,Ac(G),t.get(ie.generator.id));J!=null&&Q.push({source:ie,loss:J,openCircuit:ie.outputV-J})}Q.sort((ie,J)=>J.openCircuit-ie.openCircuit||ie.loss-J.loss||Ft(ie.source.generator).localeCompare(Ft(J.source.generator))),Q[0]&&o.push({item:G,spec:z,routes:Q})}o.sort((G,z)=>(z.spec.powerPriority||50)-(G.spec.powerPriority||50)||G.routes[0].loss-z.routes[0].loss||oa(G.item)-oa(z.item)||Ft(G.item).localeCompare(Ft(z.item)));let r=new Map,i="",a=0,c=Math.max(1,_.power.maxAssignmentPasses||8);for(let G=0;GO+H.spec.drawV,0)+ie.spec.drawV,L=ae.outputV-ye,V=ae.admitted.every(O=>L-O.loss>=O.spec.minVoltage),se=L-J.loss>=ie.spec.minVoltage;if(!(!V||!se)){ae.admitted.push({item:ie.item,spec:ie.spec,loss:J.loss}),ae.busVoltage=L,z.set(Ft(ie.item),{sourceId:ae.generator.id,sourceName:ae.generator.name||ae.generator.shortName||ae.generator.id,sourceBusV:L,routeLossV:J.loss,receivedV:L-J.loss,minVoltage:ie.spec.minVoltage,drawV:ie.spec.drawV});break}}let Q=[...z.entries()].map(([ie,J])=>`${ie}:${J.sourceId}:${J.receivedV.toFixed(3)}`).join("|");if(r=z,Q===i)break;i=Q}let b=new Map,M=new Map;for(let G of n)M.set(G.generator.id,{outputV:G.outputV,busVoltage:G.busVoltage,admitted:G.admitted.length,stablePasses:a});for(let[G,z]of r)b.set(G,z);let C=e.power?.underVoltage||new Set,$=new Set;for(let G of na(e))r.has(Ft(G))||$.add(Ft(G));let W=e.power?.assignments||new Map,K=0;for(let[G,z]of r)W.get(G)?.sourceId!==z.sourceId&&(K+=1);return e.phase==="running"&&e.stats&&(e.stats.generatorAssignmentChanges=(e.stats.generatorAssignmentChanges||0)+K,e.totals&&(e.totals.generatorAssignmentChanges=(e.totals.generatorAssignmentChanges||0)+K)),e.power={...e.power||{},dirty:!1,routes:b,assignments:r,sources:M,underVoltage:$,previousUnder:C},e.power}function Wo(e){return(!e.power||e.power.dirty)&&_o(e),e.power}function Ye(e){e.power||(e.power={}),e.power.dirty=!0}function sa(e,t){let n=!1;for(let i of ia(e)){if(e.stats){e.stats.maxGeneratorOutput=e.stats.maxGeneratorOutput||{};let c=i.id||jn(i);e.stats.maxGeneratorOutput[c]=Math.max(e.stats.maxGeneratorOutput[c]||0,Tn(i))}if(!i.fuelPulses?.length)continue;for(let c of i.fuelPulses)c.timeLeft-=t;let a=i.fuelPulses.length;i.fuelPulses=i.fuelPulses.filter(c=>c.timeLeft>0),i.fuelPulses.length!==a&&(n=!0)}n&&Ye(e),e.power||(e.power={dirty:!0,elapsed:0}),e.power.elapsed=(e.power.elapsed||0)+t;let o=1/Math.max(1,_.power.recalcHz||10);(e.power.dirty||e.power.elapsed>=o)&&(e.power.elapsed=0,_o(e));let r=Wo(e);if(e.phase==="running"){let i=r.underVoltage?.size||0;if(i){e.stats.underVoltageSeconds=(e.stats.underVoltageSeconds||0)+i*t,e.stats.underVoltageSecondsByMachine=e.stats.underVoltageSecondsByMachine||{};for(let a of r.underVoltage)e.stats.underVoltageSecondsByMachine[a]=(e.stats.underVoltageSecondsByMachine[a]||0)+t;e.totals.underVoltageSeconds=(e.totals.underVoltageSeconds||0)+i*t}}}function nt(e,t){return xn(t)?Wo(e).assignments.has(Ft(t)):!0}function En(e,t){let n=xn(t);return n?Wo(e).assignments.get(Ft(t))||{sourceName:"None",sourceBusV:0,routeLossV:0,receivedV:0,minVoltage:n.minVoltage,drawV:n.drawV}:null}function aa(e){let t=Wo(e);return`POWER: ${[...(t.sources||new Map).entries()].map(([o,r])=>`${o} ${r.outputV.toFixed(0)}V / ${r.admitted} powered`).join(" | ")||"none"} / ${t.underVoltage?.size||0} under-voltage`}function la(e,t){let n=jn(e),o=_.power.generators[n];return!o||n==="biomassGenerator"&&!["male","female","poop"].includes(t)||n==="coalGenerator"&&t!=="coal"?!1:(e.fuelPulses=e.fuelPulses||[],e.fuelPulses.push({voltage:o.pulseVoltage,timeLeft:o.pulseSeconds}),!0)}var Ze=_.maintenance;function Zr(e,t){return Math.max(0,Number(e?.cardEffects?.[t])||0)}function Ko(e){let t=Math.min(1.4,1+.04*Math.min(10,Zr(e,"crowdedFarming"))),n=Math.pow(.95,Zr(e,"preventiveMaintenance"));return t*n}function Oc(e){return Math.pow(1.03,Zr(e,"durabilityCoating"))}function qo(e,t,n=1){let o=Ze.durability[t]||1e3;return Math.max(1,Math.ceil(o*Math.max(.1,n||1)*Oc(e)))}function ca(e){return Math.max(.1,Number(e?.durabilityBaseMultiplier)||1)}function Bc(e,t=0){if(!e)return{x:p.x+p.cell*(.5+t*.55),y:p.y+p.rows*p.cell+84};let n=p.x+e.col*p.cell+p.cell,o=p.y+e.row*p.cell+p.cell;return{x:n,y:o}}function Dc(e,t=0){let n=(e.maintenanceRooms||[])[t];return Bc(n,t)}function Be(e){e.repairman||(e.repairman={active:!1,x:p.x+p.cell*.5,y:p.y+p.rows*p.cell+84,target:null,repairedToday:0}),Array.isArray(e.maintenanceRooms)||(e.maintenanceRooms=[]),Array.isArray(e.repairmen)||(e.repairmen=[]);for(let[t,n]of e.conveyorMeta||[]){n.uses==null&&(n.uses=0),n.maintenanceType==null&&(n.maintenanceType="conveyor"),n.kind||(n.kind="conveyor"),n.speedMultiplier||(n.speedMultiplier=n.kind==="boostConveyor"?2:1),n.branchMode||(n.branchMode="random");let o=qo(e,"conveyor",ca(n));(n.durability==null||n.durability0&&(n.processingCooldown=Math.max(0,n.processingCooldown-t))}function to(e){Be(e);let t=[];for(let[n,o]of e.conveyorMeta||[])t.push({type:"conveyor",key:n,meta:o,label:`${o.kind==="boostConveyor"?"Boost Belt":"Belt"} ${n}`,center:B(X(n).col,X(n).row)});for(let n of e.eggFarms||[])t.push({type:"eggFarm",ref:n,label:`EGG #${n.id}`,center:B(n.col,n.row)});for(let n of(e.scanners||[]).filter(o=>o.kind==="auto"))t.push({type:"autoScanner",ref:n,label:`AUTO #${n.id}`,center:B(n.col,n.row)});for(let n of Object.values(e.facilities||{})){let o=Qo(n);["mixer","trash","sausageMaker","starterGenerator","biomassGenerator","coalGenerator","inboundTruck"].includes(o)&&t.push({type:o,ref:n,label:`${n.shortName||n.name||o} #${n.id}`,center:{x:n.x+n.w/2,y:n.y+n.h/2}})}return t}function on(e){return e.meta?Pn(e):Pn(e.ref)}function Jn(e){return e.meta?ei(e):ei(e.ref)}function Uo(e){return e.meta?ti(e):ti(e.ref)}function ya(e,t){Lc(e.meta?e:e.ref,Math.max(0,Jn(e)-t))}function si(e){return e.type==="conveyor"?`conveyor:${e.key}`:`${e.type}:${e.ref?.id||e.ref?.type||e.type}`}function ha(e,t=.02){Be(e);let n=Math.max(0,Number(t)||0),o=0;for(let r of to(e)){let i=Jn(r);ya(r,Uo(r)*n),o+=Math.max(0,i-Jn(r))/Uo(r)*100}return o}function ba(e){Be(e);let t=e.maintenanceRooms||[];e.repairmen=t.map((o,r)=>{let i=ai(e,o),a=i?B(i.col,i.row):Dc(e,r);return{id:`room-${o.id}`,roomId:o.id,active:!0,x:a.x,y:a.y,target:null,repairedToday:0}});let n=e.repairmen[0];e.repairman.active=!!n,e.repairman.target=n?.target||null,e.repairman.repairedToday=0,n&&(e.repairman.x=n.x,e.repairman.y=n.y)}function wa(e){Be(e);for(let t of e.repairmen||[])t.active=!1,t.target=null;e.repairmen=[],e.repairman.active=!1,e.repairman.target=null}function Gc(e,t){return t&&to(e).find(o=>si(o)===t.key)||null}function _c(e){let t=null;for(let n of to(e)){if(!Vo(e,n))continue;let o=on(n);o<=.001||(!t||o>on(t))&&(t=n)}return t}function ma(e,t){Be(e);let n=e.repairmen?.length?e.repairmen:e.repairman?.active?[e.repairman]:[];if(!n.length||e.phase!=="running")return;let o=new Set(n.map(i=>i.target?.key).filter(Boolean));for(let i of n)Wc(e,i,t,o);let r=n[0];r&&e.repairman!==r&&(e.repairman.active=!0,e.repairman.x=r.x,e.repairman.y=r.y,e.repairman.target=r.target,e.repairman.repairedToday=r.repairedToday||0)}function Wc(e,t,n,o){if(!t.active)return;let r=(e.maintenanceRooms||[]).find(J=>J.id===t.roomId);if(r&&!nt(e,r))return;let i=Gc(e,t.target);if((!i||on(i)<=.001||!Vo(e,i))&&(t.target?.key&&o.delete(t.target.key),i=Uc(e,o)),!i){t.target=null;return}let a=si(i);o.add(a);let c=Vo(e,i,t);if(!c){e.stats.unreachableRepairTargets=(e.stats.unreachableRepairTargets||0)+1,e.totals.unreachableRepairTargets=(e.totals.unreachableRepairTargets||0)+1,o.delete(a),t.target=null;return}if(t.target={key:a,label:i.label,workKey:E(c.col,c.row)},zc(e,t,c),t.path?.length&&t.pathIndex4){let V=Math.min(L,Ze.repairman.walkSpeed*n);t.x+=ae/L*V,t.y+=ye/L*V;return}t.pathIndex+=1;return}let b=Ze.repairman.walkSpeed,M=B(c.col,c.row),C=M.x-t.x,$=M.y-t.y,W=Math.hypot(C,$);if(W>8){let J=Math.min(W,b*n);t.x+=C/W*J,t.y+=$/W*J;return}let K=e?.cardEffects?.laborExploitation?.7:1,G=n/(Ze.repairman.secondsPerOnePercent*K*100),z=Jn(i),Q=G*Uo(i);ya(i,Q);let ie=Math.max(0,(z-Jn(i))/Uo(i)*100);t.repairedToday=(t.repairedToday||0)+ie,ie>0&&Math.random()<.02&&Y(e,t.x,t.y-28,"REPAIR",w.green),on(i)<=.001&&(o.delete(a),t.target=null)}function Uc(e,t=new Set){let n=null;for(let o of to(e)){if(t.has(si(o))||!Vo(e,o))continue;let r=on(o);r<=.001||(!n||r>on(n))&&(n=o)}return n||_c(e)}function Vc(e){if(e.type==="conveyor")return[X(e.key)];if(e.type==="eggFarm")return[{col:e.ref.col,row:e.ref.row}];if(e.type==="autoScanner"){let n=e.ref;return[{col:n.col,row:n.row-1},{col:n.col+1,row:n.row-1},{col:n.col,row:n.row},{col:n.col+1,row:n.row}]}let t=e.ref;if(t?.gridPlaced){let n=[];for(let o=0;o<(t.hCells||1);o+=1)for(let r=0;r<(t.wCells||1);r+=1)n.push({col:t.col+r,row:t.row+o});return n}return t?.entry?[t.entry]:[]}function Kc(e){let t=new Set;for(let n of e.eggFarms||[])t.add(E(n.col,n.row));for(let n of e.scanners||[])for(let o of[{col:n.col,row:n.row-1},{col:n.col+1,row:n.row-1},{col:n.col,row:n.row},{col:n.col+1,row:n.row}])t.add(E(o.col,o.row));for(let n of e.maintenanceRooms||[])for(let o=0;o<2;o+=1)for(let r=0;r<2;r+=1)t.add(E(n.col+r,n.row+o));for(let n of Object.values(e.facilities||{}))if(n.gridPlaced)for(let o=0;o<(n.hCells||1);o+=1)for(let r=0;r<(n.wCells||1);r+=1)t.add(E(n.col+r,n.row+o));return t}function Rn(e,t,n){if(!Re(t,n)||!e.ownedCells?.has?.(E(t,n))||e.blockedCells?.has?.(E(t,n)))return!1;let o=E(t,n);return!(Kc(e).has(o)||e.conveyorTiles?.has(o)&&!e.footbridges?.has(o))}function ai(e,t){if(!t)return{col:0,row:Math.max(0,p.rows-1)};let n=[];for(let o=0;o<2;o+=1)n.push({col:t.col+o,row:t.row-1},{col:t.col+o,row:t.row+2});for(let o=0;o<2;o+=1)n.push({col:t.col-1,row:t.row+o},{col:t.col+2,row:t.row+o});return n.find(o=>Rn(e,o.col,o.row))||null}function va(e,t,n){if(!t)return null;let o=new Set(n.map(c=>E(c.col,c.row))),r=E(t.col,t.row),i=[t],a=new Map([[r,null]]);for(;i.length;){let c=i.shift(),b=E(c.col,c.row);if(o.has(b)){let M=[],C=b;for(;C;){let $=X(C);M.push($),C=a.get(C)}return M.reverse()}for(let M of fe){let C={col:c.col+M.dc,row:c.row+M.dr},$=E(C.col,C.row);a.has($)||!Rn(e,C.col,C.row)||(a.set($,b),i.push(C))}}return null}function qc(e,t){let n=[];for(let r of Vc(t)){t.type==="conveyor"&&e.footbridges?.has(E(r.col,r.row))&&Rn(e,r.col,r.row)&&n.push(r);for(let i of fe){let a={col:r.col+i.dc,row:r.row+i.dr};Rn(e,a.col,a.row)&&n.push(a)}}let o=new Set;return n.filter(r=>{let i=E(r.col,r.row);return o.has(i)?!1:(o.add(i),!0)})}function Vo(e,t,n=null){let o=qc(e,t);if(!o.length)return null;let r=(e.maintenanceRooms||[]).find(c=>c.id===n?.roomId)||(e.maintenanceRooms||[])[0],i=n?ka(e,n,r):ai(e,r),a=va(e,i,o);return a?.[a.length-1]||null}function Sa(e,t){let n=Math.floor((e-p.x)/p.cell),o=Math.floor((t-p.y)/p.cell);return Re(n,o)?{col:n,row:o}:null}function ka(e,t,n){let o=Sa(t.x,t.y);return o&&Rn(e,o.col,o.row)?o:ai(e,n)}function zc(e,t,n){let o=E(n.col,n.row);if(t.path&&t.pathVersion===e.walkabilityVersion&&t.target?.workKey===o&&t.pathIndexb.id===t.roomId),i=ka(e,t,r);t.path=va(e,i,[n])||[];let a=Sa(t.x,t.y),c=a&&i&&a.col===i.col&&a.row===i.row&&Rn(e,a.col,a.row);t.pathIndex=c&&t.path.length>1?1:0,t.pathVersion=e.walkabilityVersion||0}function Hc(e){let t=0,n="none";for(let o of to(e)){let r=on(o);r>t&&(t=r,n=o.label)}return{ratio:t,percent:Math.round(t*100),label:n}}function li(e){let t=Hc(e),n=ni(e);return{worst:t,avgBeltPerformance:n,repairman:e.repairman||null,repairmen:e.repairmen||[],rooms:e.maintenanceRooms||[]}}var Yc=qe.commonWeight,Qc=qe.rareWeight,Xc=qe.ultraRareWeight||.45,sn=qe.baseDraftSize,An=Bi;function In(e,t){let n=Qe(e);return Math.max(0,Number(n[t])||0)}function Qe(e){e.cardEffects||(e.cardEffects={...kr});for(let[t,n]of Object.entries(kr))e.cardEffects[t]==null&&(e.cardEffects[t]=Array.isArray(n)?[]:n);return e.cardEffects.flattery!=null&&(e.cardEffects.fairiesFlatteryNext=Math.max(0,e.cardEffects.fairiesFlatteryNext||0)+Math.max(0,e.cardEffects.flattery||0),delete e.cardEffects.flattery),e.cardEffects.drawBonus!=null&&delete e.cardEffects.drawBonus,e.cardDraft||(e.cardDraft={pending:!1,choices:[],rerolls:0,picksRemaining:0}),e.cardDraft.picksRemaining==null&&(e.cardDraft.picksRemaining=e.cardDraft.pending?1:0),e.cardDraft.freeRerolls==null&&(e.cardDraft.freeRerolls=0),e.cardEffects}function Ra(e){let t=Math.max(.5,1-.05*Math.min(10,In(e,"crowdedFarming"))),n=Math.pow(.96,In(e,"hatchingFeed"));return t*n}function Ia(e,t=null){return Math.min(3,Math.max(0,Number(t?.extraEggOutlet)||0))}function Aa(e){return Math.pow(.85,In(e,"scannerQueueSpacing"))}function Vt(e,t=null){let n=Qe(e),o=wo*Math.pow(mo,Math.max(0,n.bearing||0)),r=t?Math.max(.1,Number(e?.conveyorMeta?.get?.(t)?.speedMultiplier)||1):1,i=t?1:ni(e),a=Math.max(.01,Number(e?.eventActive?.conveyorSpeedMultiplier)||1);return Math.min(yn,o*i)*r*a}function Bt(e,t=null){let n=Math.max(0,(e?.level||1)-1),o=t?In(t,"autoScannerTuning"):0,r=bo*Math.pow(Fi,n)*Math.pow(wr,o),i=Math.max(mr,r),a=t?Math.max(.01,Number(t?.eventActive?.autoScannerCooldownMultiplier)||1):1;return t?Math.max(mr,i*Ho(e)*a):i}function Ma(e){let t=e.cardDraft||{rerolls:0},n=Math.max(1,(t.rerolls||0)+1);return Math.ceil(Math.max(1,e.turn||1)/qe.rerollCost.dayDivisor*n*qe.rerollCost.multiplier)}function an(e){return An.find(t=>t.id===e)||null}function $a(e,t){let n=typeof t=="string"?an(t):t;return Qe(e),!n||!(n.type==="equipmentUpgrade"||n.type==="cellAction")?[]:dt(e,n).map(o=>({key:Ot(o),label:fi(e,o),type:o.type}))}function di(e,t,n={}){let o=typeof t=="string"?an(t):t;if(Qe(e),!o||o.type==="dud")return{ok:!1,reason:"Card not found."};if(o.id==="extraCards")return e.cardDraft=e.cardDraft||{pending:!1,choices:[],rerolls:0,picksRemaining:0},e.cardDraft.choices.push(...jo(e,2)),{ok:!0,reason:`${o.title} added 2 draft cards.`};if(o.type==="instant")return Oa(e,o),{ok:!0,reason:`${o.title} granted.`};if(o.type==="equipmentUpgrade"){let r=dt(e,o);if(!r.length)return{ok:!1,reason:`No valid target for ${o.title}.`};let i=n.targetKey&&n.targetKey!=="__auto__"?String(n.targetKey):"",a=i?r.find(c=>Ot(c)===i):r[0];return a?(Fa(e,a),{ok:!0,reason:`${o.title} applied to ${fi(e,a)}.`}):{ok:!1,reason:`Selected target is no longer valid for ${o.title}.`}}if(o.type==="cellAction"&&o.target==="blockedCell"){let r=dt(e,o);if(!r.length)return{ok:!1,reason:"No blocked cells to remove."};let i=new Set((Array.isArray(n.targetKeys)?n.targetKeys:[n.targetKey]).filter(c=>c&&c!=="__auto__").map(String)),a=i.size?r.filter(c=>i.has(Ot(c))):r.slice(0,10);if(!a.length)return{ok:!1,reason:`Selected target is no longer valid for ${o.title}.`};for(let c of a.slice(0,3)){e.blockedCells.delete(E(c.col,c.row));let b=B(c.col,c.row);ct(e,b.x,b.y),gt(e,b.x,b.y,w.danger,42),$t(e,b.x,b.y,8,w.warn)}return Ee(e),{ok:!0,reason:`${o.title} removed ${Math.min(10,a.length)} blocked cell(s).`}}return{ok:!1,reason:`${o.title} cannot be debug-granted.`}}function fi(e,t){if(t.type==="blockedCell")return`Blocked cell ${t.col},${t.row}`;if(t.type==="eggFarm")return`EGG #${t.id} L${t.level} -> L${t.level+1}`;if(t.type==="eggOutlet"){let n=Math.max(0,Number(t.farm?.extraEggOutlet)||0);return`EGG #${t.id} OUTLET ${1+n} -> ${2+n}`}if(t.type==="scanner")return`AUTO #${t.id} L${t.level} -> L${t.level+1} | CD ${Bt(t,e).toFixed(1)}s -> ${Bt({...t,level:t.level+1},e).toFixed(1)}s`;if(t.type==="facility"&&["mixer","sausageMaker"].includes(t.baseId||t.id)){let n=t.baseId||t.id,o=t.level||1,r=lt(e);t.level=o+1;let i=lt(e);return t.level=o,`${n==="mixer"?"MIXER":"SAUSAGE MACHINE"} L${t.level} -> L${t.level+1} | sausage ${R(r)} -> ${R(i)}`}if(t.type==="facility"&&(t.baseId||t.id)==="truck"){let n=t.level,o=Je(e);t.level=n+1;let r=Je(e);return t.level=n,`TRUCK L${t.level} -> L${t.level+1} | ${R(o)} -> ${R(r)}`}if(t.type==="facility"&&(t.baseId||t.id)==="trash"){let n=At(e),o=Math.min(kn(),n+1),r=It(n),i=It(o);return`SHREDDER L${t.level||1} -> L${(t.level||1)+1} | expected ${R(r)} -> ${R(i)} per poop`}return`${t.name||t.id} L${t.level||1} -> L${(t.level||1)+1}`}function jc(e){return[...e.blockedCells||[]].map(t=>{let[n,o]=String(t).split(",").map(Number);return{type:"blockedCell",id:t,col:n,row:o}}).filter(t=>Number.isFinite(t.col)&&Number.isFinite(t.row))}function dt(e,t){let n=typeof t=="string"?an(t):t;return Qe(e),n?n.target==="blockedCell"?jc(e):n.target==="eggFarm"?e.eggFarms.filter(o=>(o.level||1)<4):n.target==="eggOutlet"?e.eggFarms.filter(o=>Math.max(0,Number(o.extraEggOutlet)||0)<3).map(o=>({type:"eggOutlet",id:o.id,col:o.col,row:o.row,farm:o})):n.target==="autoScanner"?e.scanners.filter(o=>o.kind==="auto"):n.target==="mixer"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="mixer"):n.target==="truck"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="truck"):n.target==="sausageMaker"?Object.values(e.facilities||{}).filter(o=>(o.baseId||o.id)==="sausageMaker"):n.target==="trash"?Hr(e)(o.baseId||o.id)==="trash"):[]:[]:[]}function Jc(e,t){let n=Qe(e);if(t.id==="crowdedFarming")return(n.crowdedFarming||0)>=10;if(t.id==="recyclingSubsidy")return(n.recyclingSubsidy||0)>=3;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,qe.dudChancePerCard||0)),r=Math.max(1e-4,Math.min(1,qe.dudChanceReductionPerFilter||.05));return(n.dudFilter||0)>=Math.ceil(o/r)}return t.id==="laborExploitation"?!!n.laborExploitation:t.id==="usedMachine"?!!n.usedMachineActive:t.id==="newMachine"?!n.usedMachineActive:!1}function Zc(e){return!!((e.maintenanceRooms||[]).length||(e.repairmen||[]).length||e.repairman?.active)}function Ca(e,t){return t==="conveyor"?(e.conveyorTiles?.size||0)>0:t==="autoScanner"?(e.scanners||[]).some(n=>n.kind==="auto"):t==="manualScanner"?(e.scanners||[]).some(n=>n.kind==="manual"):t==="eggFarm"?(e.eggFarms||[]).length>0:Object.values(e.facilities||{}).some(n=>(n.baseId||n.id)===t)}function eu(e,t){return!(t.requiresFacility&&!Ca(e,t.requiresFacility)||Array.isArray(t.requiresAnyFacility)&&!t.requiresAnyFacility.some(n=>Ca(e,n)))}function tu(e){return An.filter(t=>!(t.id==="laborExploitation"&&!Zc(e)||!eu(e,t)||Jc(e,t)||(t.type==="equipmentUpgrade"||t.type==="cellAction")&&dt(e,t).length<=0))}function ga(e,t){return t.rarity==="ultraRare"?Xc:t.rarity==="rare"?Qc:Yc}function nu(e,t){let n=t.reduce((r,i)=>r+ga(e,i),0);if(n<=0)return t[Math.floor(Math.random()*t.length)];let o=Math.random()*n;for(let r of t)if(o-=ga(e,r),o<=0)return r;return t[t.length-1]}var xa=0;function ou(){return xa+=1,{id:`dud:${Date.now()}:${xa}`,title:"Dud",rarity:"dud",type:"dud",description:"Click to flick this dud away. It does not consume a pick."}}function ru(e){let t=Qe(e),n=Math.max(0,Math.min(1,qe.dudChancePerCard||0)),o=Math.max(0,Math.min(1,qe.dudChanceReductionPerFilter||0));return Math.max(0,n-o*Math.max(0,t.dudFilter||0))}function iu(e,t){let n=[...t],o=0,r=Math.max(0,qe.maxDudsPerDraft||0),i=ru(e);for(let a=0;ac.id===i.id);a>=0&&r.splice(a,1)}return iu(e,o)}function Ot(e){return e?e.type==="blockedCell"?`blockedCell:${e.id}`:e.type==="eggFarm"?`eggFarm:${e.id}`:e.type==="eggOutlet"?`eggOutlet:${e.id}`:e.type==="scanner"?`scanner:${e.id}`:e.type==="facility"?`facility:${e.id}`:`${e.type}:${e.id}`:""}function Ta(e){if(!e)return null;if(e.type==="blockedCell"){let t=B(e.col,e.row);return{x:t.x-p.cell*.48,y:t.y-p.cell*.48,w:p.cell*.96,h:p.cell*.96,cx:t.x,cy:t.y}}if(e.type==="eggFarm"||e.type==="eggOutlet"){let t=B(e.col,e.row);return{x:t.x-34,y:t.y-34,w:68,h:68,cx:t.x,cy:t.y}}if(e.type==="scanner"){let t=ge(e);return{x:t.x-48,y:t.y-48,w:96,h:96,cx:t.x,cy:t.y}}return e.type==="facility"?{x:e.x,y:e.y,w:e.w,h:e.h,cx:e.x+e.w/2,cy:e.y+e.h/2}:null}function pi(e){if(!e.cardTargetPick?.pending)return[];if(e.cardTargetPick.mode==="autoScannerMenu"){let n=new Set(e.cardTargetPick.targetKeys||[]);return e.scanners.filter(o=>o.kind==="auto"&&n.has(Ot(o))).map(o=>({key:Ot(o),label:"AUTO ROUTE SETTINGS",target:o,bounds:Ta(o)})).filter(o=>o.bounds)}let t=new Set(e.cardTargetPick.targetKeys||[]);return dt(e,e.cardTargetPick.cardId).filter(n=>t.has(Ot(n))).map(n=>({key:Ot(n),label:fi(e,n),target:n,bounds:Ta(n)})).filter(n=>n.bounds)}function su(e,t){let n=pi(e);for(let o of n){let r=o.bounds;if(t.x>=r.x&&t.x<=r.x+r.w&&t.y>=r.y&&t.y<=r.y+r.h)return o.target}return null}function Fa(e,t){if(t.type==="eggOutlet"){let n=t.farm||e.eggFarms.find(r=>r.id===t.id);if(!n)return;n.extraEggOutlet=Math.min(3,Math.max(0,Number(n.extraEggOutlet)||0)+1);let o=B(n.col,n.row);Y(e,o.x,o.y-30,`OUTLET ${1+n.extraEggOutlet}`,w.green),Ee(e);return}if(t.level=(t.level||1)+1,t.type==="eggFarm"){t.nextSpawn=Jt(t),t.lastInterval=t.nextSpawn;let n=B(t.col,t.row);Y(e,n.x,n.y-30,`LV ${t.level}`,w.green);return}if(t.type==="scanner"){let n=ge(t);Y(e,n.x,n.y-34,`LV ${t.level}`,w.green);return}t.type==="facility"&&Y(e,t.x+t.w/2,t.y+18,`LV ${t.level}`,w.green)}function Oa(e,t){let n=Qe(e),o=r=>{n[r]=Math.max(0,n[r]||0)+1};if(t.id==="bearing"&&o("bearing"),t.id==="autoScannerTuning"&&o("autoScannerTuning"),t.id==="legalWork"&&o("legalWork"),t.id==="crowdedFarming"&&(n.crowdedFarming=Math.min(10,(n.crowdedFarming||0)+1)),t.id==="hatchingFeed"&&o("hatchingFeed"),t.id==="poopRateBooster"&&o("poopRateBooster"),t.id==="safetyCover"&&o("safetyCover"),t.id==="recyclingSubsidy"&&(n.recyclingSubsidy=Math.min(3,(n.recyclingSubsidy||0)+1)),t.id==="chemicalWeaponSubsidy"&&o("chemicalWeaponSubsidy"),t.id==="preventiveMaintenance"&&o("preventiveMaintenance"),t.id==="dudFilter"&&o("dudFilter"),t.id==="durabilityCoating"&&(o("durabilityCoating"),Be(e)),t.id==="sparePartsBin"){o("sparePartsBin");let r=ha(e,.02);e.stats.sparePartsRepair=(e.stats.sparePartsRepair||0)+r,e.totals.sparePartsRepair=(e.totals.sparePartsRepair||0)+r,Y(e,p.x+p.cols*p.cell/2,p.y-30,"REPAIR +2%",w.green)}t.id==="dudRefund"&&o("dudRefund"),t.id==="freeReroll"&&o("freeReroll"),t.id==="composter"&&o("composter"),t.id==="scannerQueueSpacing"&&o("scannerQueueSpacing"),t.id==="flattery"&&o("fairiesFlatteryNext"),t.id==="usedMachine"&&(n.usedMachineActive=!0),t.id==="newMachine"&&(n.usedMachineActive=!1),t.id==="laborExploitation"&&(n.laborExploitation=1),t.id==="rescueLoan"&&(o("rescueLoanCharges"),Y(e,p.x+p.cols*p.cell/2,p.y-30,"RESCUE HELD",w.green))}function mt(e){return`${Math.round(Number(e||0)*100)}%`}function Ea(e){let t=Gt[Math.max(0,Math.min(Gt.length-1,e-1))]||Gt[0]||[0,0];return`${t[0].toFixed(2)}-${t[1].toFixed(2)}s`}function Pa(e,t){return Math.ceil(e*Math.pow(Ie.incomeUpgradeRate,Math.max(0,t-1)))}function ci(e,t,n){let r=dt(e,t==="mixer"?"upgradeMixer":t==="sausageMaker"?"upgradeSausageMaker":"upgradeTruck")[0];if(!r)return{before:Pa(n,1),after:Pa(n,2)};let i=()=>t==="truck"?Je(e):lt(e),a=i(),c=r.level||1;r.level=c+1;let b=i();return r.level=c,{before:a,after:b}}function au(e,t){let n=Qe(e);if(t.id==="upgradeEgg"){let o=dt(e,t),r=Math.min(3,Math.max(1,o[0]?.level||1));return`Choose one EGG. Level +1. Production interval ${Ea(r)} -> ${Ea(r+1)}.`}if(t.id==="upgradeAutoScanner"){let o=dt(e,t)[0]||{level:1},r=Bt(o,e),i=Bt({...o,level:(o.level||1)+1},e);return`Choose one AUTO SCANNER. Level +1. Cooldown ${r.toFixed(2)}s -> ${i.toFixed(2)}s.`}if(t.id==="upgradeMixer"){let o=ci(e,"mixer",Ie.income.sausage);return`Choose one MIXER. Meat quality +10%. Sausage sale value ${R(o.before)} -> ${R(o.after)}.`}if(t.id==="upgradeSausageMaker"){let o=ci(e,"sausageMaker",Ie.income.sausage);return`Choose one SAUSAGE MACHINE. Product value +10%. Sausage sale value ${R(o.before)} -> ${R(o.after)}.`}if(t.id==="upgradeTruck"){let o=ci(e,"truck",Ie.income.truck);return`Choose one TRUCK. Earning +10%. Correct shipment income ${R(o.before)} -> ${R(o.after)}.`}if(t.id==="upgradeTrash"){let o=At(e),r=Math.min(kn(),o+1),i=It(o),a=It(r),c=Math.round(tn(o)*100),b=Math.round(tn(r)*100);return`SHREDDER level +1. Expected value ${R(i)} -> ${R(a)} per poop; hit chance ${c}% -> ${b}%.`}if(t.id==="bearing"){let o=Math.min(yn,wo*Math.pow(mo,Math.max(0,n.bearing||0))),r=Math.min(yn,wo*Math.pow(mo,Math.max(0,(n.bearing||0)+1)));return`Conveyor speed +7.5%. After pick: ${o.toFixed(1)} -> ${r.toFixed(1)} px/s.`}if(t.id==="legalWork"){let o=Math.max(0,n.legalWork||0);return`Fairies tribute profit exemption +${R(250)}. After pick: exemption bonus ${R(250*(o+1))}.`}if(t.id==="crowdedFarming"){let o=Math.min(10,(n.crowdedFarming||0)+1);return`Held ${n.crowdedFarming||0}/10. After pick: EGG interval ${mt(Math.max(.5,1-.05*o))}, deterioration ${mt(Math.min(1.4,1+.04*o))}.`}if(t.id==="extraEggOutlet"){let o=dt(e,t),r=Math.max(0,Number(o[0]?.farm?.extraEggOutlet)||0);return`Choose one EGG. Output ports ${1+r} -> ${2+r}. Max 4 ports per EGG.`}if(t.id==="hatchingFeed")return`Held ${n.hatchingFeed||0}. After pick: EGG interval ${mt(Math.pow(.96,(n.hatchingFeed||0)+1))}, poop rate multiplier ${mt(Math.pow(1.03,(n.hatchingFeed||0)+1))}.`;if(t.id==="poopRateBooster")return`Held ${n.poopRateBooster||0}. After pick: base poop rate +${Math.round((n.poopRateBooster||0)+1)*4} percentage points.`;if(t.id==="autoScannerTuning")return`Held ${n.autoScannerTuning||0}. After pick: all AUTO SCANNER default cooldown ${mt(Math.pow(wr,(n.autoScannerTuning||0)+1))}.`;if(t.id==="safetyCover")return`Held ${n.safetyCover||0}. After pick: explosion damage ${mt(Math.pow(.95,(n.safetyCover||0)+1))}.`;if(t.id==="recyclingSubsidy")return`Held ${n.recyclingSubsidy||0}/3. After pick: normal SELL refund ${Math.round(Math.min(.8,.5+.1*((n.recyclingSubsidy||0)+1))*100)}%.`;if(t.id==="chemicalWeaponSubsidy")return`Held ${n.chemicalWeaponSubsidy||0}. After pick: ${R(1200*((n.chemicalWeaponSubsidy||0)+1))} per 70 truck-shipped poop each day.`;if(t.id==="preventiveMaintenance")return`Held ${n.preventiveMaintenance||0}. After pick: deterioration speed ${mt(Math.pow(.95,(n.preventiveMaintenance||0)+1))}.`;if(t.id==="dudFilter"){let o=Math.max(0,Math.min(1,qe.dudChancePerCard||0)),r=Math.max(0,Math.min(1,qe.dudChanceReductionPerFilter||.05)),i=Math.max(0,n.dudFilter||0),a=Math.max(0,o-r*i),c=Math.max(0,o-r*(i+1));return`Held ${i}. DUD chance per card ${mt(a)} -> ${mt(c)}.`}return t.id==="durabilityCoating"?`Held ${n.durabilityCoating||0}. After pick: maximum durability ${mt(Math.pow(1.03,(n.durabilityCoating||0)+1))}.`:t.id==="sparePartsBin"?`Held ${n.sparePartsBin||0}. Immediately restores 2% durability to every maintained machine. Common card weight.`:t.id==="dudRefund"?`Held ${n.dudRefund||0}. After pick: DUD clicks award ${R(50*((n.dudRefund||0)+1))}.`:t.id==="freeReroll"?`Held ${n.freeReroll||0}. After pick: each card screen starts with ${(n.freeReroll||0)+1} free reroll${(n.freeReroll||0)+1===1?"":"s"}.`:t.id==="composter"?`Held ${n.composter||0}. After pick: SHREDDER poop grants ${R(3*((n.composter||0)+1))}.`:t.id==="scannerQueueSpacing"?`Held ${n.scannerQueueSpacing||0}. After pick: Manual/Auto Scanner queue spacing ${mt(Math.pow(.85,(n.scannerQueueSpacing||0)+1))}.`:t.id==="flattery"?`Next Fairies tribute -50%. Held for next tribute: ${n.fairiesFlatteryNext||0}.`:t.id==="usedMachine"?"Enable Used Machines: future equipment costs 50%, has no SELL refund, and starts with 60% durability.":t.id==="newMachine"?"Cancel Used Machines. Future equipment returns to normal price, refund, and durability.":t.id==="laborExploitation"?"Repairman dispatch paperwork is streamlined. Repair rooms keep operating; one time only.":t.id==="rescueLoan"?`At day-end bankruptcy check, gain ${R(500)} if cash is below ${R(0)}. Held: ${n.rescueLoanCharges||0}.`:t.id==="dynamite"?"Choose any blocked tiles on the map and destroy up to 3. Empty-space clicks are ignored; press Esc to finish after at least one blast.":t.description}function ui(e,t){let n=e.cardDraft?.choices||[],o=n.findIndex(r=>r.id===t.id);o>=0&&n.splice(o,1)}function Ba({game:e,ui:t,onUpdatePanels:n}){function o(){n&&n()}function r(){Qe(e),e.cardTargetPick=null,e.cardDraft={pending:!0,choices:jo(e,sn),rerolls:0,freeRerolls:In(e,"freeReroll"),picksRemaining:1}}function i(){Qe(e),e.cardDraft.pending=!1,e.cardDraft.choices=[],e.cardDraft.picksRemaining=0,e.cardTargetPick=null,t.modal.classList.remove("visible","equipment-popover"),o()}function a(L=sn){Qe(e),e.cardDraft.choices=jo(e,L)}function c(){Qe(e),!e.cardDraft.choices.length&&e.cardDraft.picksRemaining>0&&a(sn)}function b(L){ui(e,L),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1),e.cardTargetPick=null,c(),e.cardDraft.picksRemaining<=0?i():ye()}function M(L){ui(e,L),e.cardDraft.picksRemaining=Math.max(0,(e.cardDraft.picksRemaining||1)-1)+qe.extraCardsAddedPicks,e.cardDraft.choices.push(...jo(e,2)),ye()}function C(L,V){let se=In(e,"dudRefund")*50;if(se>0){let O=tt(e,se);e.stats.dudRefundIncome=(e.stats.dudRefundIncome||0)+O,e.totals.dudRefundIncome=(e.totals.dudRefundIncome||0)+O,Y(e,p.x+p.cols*p.cell/2,p.y-30,`DUD REFUND +${R(O)}`,w.green)}nn(e,34,.62),document.body?.animate&&document.body.animate([{transform:"translate(0, 0)"},{transform:"translate(-10px, 7px)"},{transform:"translate(12px, -8px)"},{transform:"translate(-8px, -5px)"},{transform:"translate(9px, 6px)"},{transform:"translate(0, 0)"}],{duration:260,easing:"steps(5, end)"}),V&&(V.style.setProperty("--fling-x",`${260+Math.random()*260}px`),V.style.setProperty("--fling-y",`${-260-Math.random()*170}px`),V.style.setProperty("--fling-r",`${(Math.random()<.5?-1:1)*(52+Math.random()*38)}deg`),V.classList.add("flung")),window.setTimeout(()=>{ui(e,L),c(),ye()},340)}function $(L,V=null){if(L.type==="dud")return C(L,V);if(L.id==="extraCards")return M(L);if(L.type==="equipmentUpgrade"||L.type==="cellAction")return W(L);Oa(e,L),b(L)}function W(L){let V=dt(e,L);V.length&&(e.cardTargetPick={pending:!0,cardId:L.id,mode:L.target==="blockedCell"?"blockedCell":"equipment",targetKeys:V.map(Ot),remaining:L.id==="dynamite"?Math.min(10,V.length):1,used:0},t.modal.classList.remove("visible","equipment-popover"),o())}function K(L){if(!L||L.type!=="blockedCell")return!1;let V=E(L.col,L.row);if(!e.blockedCells?.has(V))return!1;e.blockedCells.delete(V);let se=B(L.col,L.row);return ct(e,se.x,se.y),gt(e,se.x,se.y,w.danger,62),$t(e,se.x,se.y,18,w.warn),Do(e,se.x,se.y,8),nn(e,16,.35),Y(e,se.x,se.y-18,"BOOM",w.danger),Ee(e),e.cardTargetPick.remaining=Math.max(0,(e.cardTargetPick.remaining||1)-1),e.cardTargetPick.used=Math.max(0,e.cardTargetPick.used||0)+1,e.cardTargetPick.targetKeys=dt(e,"dynamite").map(Ot),o(),!0}function G(L){if(!e.cardTargetPick?.pending)return!1;let V=an(e.cardTargetPick.cardId),se=su(e,L);return V?V.id==="dynamite"?(!se||!K(se)||((e.cardTargetPick.remaining||0)<=0||!dt(e,"dynamite").length)&&b(V),!0):se?(Fa(e,se),b(V),!0):(z(),!0):(z(),!0)}function z(){if(!e.cardTargetPick?.pending)return;let L=e.cardTargetPick,V=an(L.cardId);if(V?.id==="dynamite"&&(L.used||0)>0){b(V);return}e.cardTargetPick=null,ye()}function Q(){let L=Math.max(0,e.cardDraft?.freeRerolls||0);if(L>0){e.cardDraft.freeRerolls=L-1,e.cardDraft.rerolls+=1,a(sn),ye();return}let V=Ma(e);e.cash${V.alt||`:``}function ae(L,V){let se=document.createElement("button");se.type="button";let O=L.type==="dud"?"dud":L.rarity==="ultraRare"?"ultra-rare":L.rarity==="rare"?"rare":"common";se.className=`card-choice ${O}`;let H=L.type==="dud"?"MISS":L.rarity==="ultraRare"?"ULTRA RARE":L.rarity==="rare"?"RARE":"COMMON",oe=[H,...(L.tags||[]).filter(ue=>ue!==H)].slice(0,5);return se.innerHTML=`${J(L)}
${L.title}
${oe.map(ue=>`${ue}`).join("")}
${au(e,L)}
`,se.addEventListener("click",()=>$(L,se)),se.dataset.index=String(V),se}function ye(){Qe(e),e.cardTargetPick=null,e.cardDraft?.pending||r(),e.cardDraft.choices?.length||a(sn);let L=e.cardDraft.choices||[],V=Ma(e),se=Math.max(0,e.cardDraft?.freeRerolls||0),O=Math.max(1,e.cardDraft.picksRemaining||1);t.modalTitle.textContent="Choose Upgrade Card",t.modalBody.innerHTML=`

Choose ${O} card${O===1?"":"s"} before Build phase. Dud cards can be flicked away without consuming a pick. Equipment cards target machines; Dynamite targets blocked cells.

`;let H=t.modalBody.querySelector("#cardChoices");L.forEach((Ve,xe)=>H.appendChild(ae(Ve,xe))),t.modalActions.innerHTML="";let oe=document.createElement("button");oe.type="button",oe.className="facility-action warn reroll-button",oe.textContent=se>0?`Reroll (FREE x${se})`:`Reroll ${R(V)}`,oe.disabled=se<=0&&e.cash0?`${se} free reroll${se===1?"":"s"} remaining.`:oe.disabled?"Not enough cash":"",oe.addEventListener("click",Q),t.modalActions.appendChild(oe);let ue=document.createElement("button");ue.type="button",ue.className="facility-action",ue.textContent="No Card",ue.title="Skip this upgrade pick and enter Build phase.",ue.addEventListener("click",i),t.modalActions.appendChild(ue),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible")}return{prepareDraft:r,showDraft:ye,finishDraft:i,chooseTargetAtPoint:G,cancelTargetPick:z}}var lu=!0,cu={chickMale:"./assets/images/chick_male.png",chickFemale:"./assets/images/chick_female.png",poop:"./assets/images/poop.png",conveyorStraightH:"./assets/dark_factory/facilities/conveyor/conveyor_straight_h_16.png",conveyorStraightV:"./assets/dark_factory/facilities/conveyor/conveyor_straight_v_16.png",conveyorTurnNe:"./assets/dark_factory/facilities/conveyor/conveyor_turn_ne_16.png",conveyorTurnNw:"./assets/dark_factory/facilities/conveyor/conveyor_turn_nw_16.png",conveyorTurnSe:"./assets/dark_factory/facilities/conveyor/conveyor_turn_se_16.png",conveyorTurnSw:"./assets/dark_factory/facilities/conveyor/conveyor_turn_sw_16.png",boostConveyorStraightH:"./assets/dark_factory/facilities/conveyor/boost_conveyor_straight_h_16.png",boostConveyorStraightV:"./assets/dark_factory/facilities/conveyor/boost_conveyor_straight_v_16.png",boostConveyorTurnNe:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_ne_16.png",boostConveyorTurnNw:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_nw_16.png",boostConveyorTurnSe:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_se_16.png",boostConveyorTurnSw:"./assets/dark_factory/facilities/conveyor/boost_conveyor_turn_sw_16.png",scannerManual:"./assets/dark_factory/facilities/machines/manual_scanner_32x48.png",scannerAuto:"./assets/dark_factory/facilities/machines/auto_scanner_32x48.png",eggFarm:"./assets/dark_factory/facilities/machines/egg_farm_16.png",mixer:"./assets/dark_factory/facilities/machines/mixer_32.png",shredder:"./assets/dark_factory/facilities/machines/shredder_32.png",truck:"./assets/dark_factory/facilities/vehicles/truck_32.png",maintenanceRoom:"./assets/dark_factory/facilities/utility/maintenance_room_32.png",repairman:"./assets/dark_factory/facilities/utility/repairman_16.png",obstacleCrate:"./assets/dark_factory/facilities/utility/obstacle_crate_16.png"},De={};for(let[e,t]of Object.entries(cu)){let n=new Image;n.loaded=!1,n.onerror=()=>{n.loaded=!1},lu&&t&&(n.onload=()=>{n.loaded=!0},n.src=t),De[e]=n}function bi(e){return e.frameCache||(e.frameCache={}),e.frameCache.draw||(e.frameCache.draw={}),e.frameCache.draw}function wi(e,t){let n=document.createElement("canvas");return n.width=Math.max(1,Math.ceil(e)),n.height=Math.max(1,Math.ceil(t)),n}function Ga(e,t,n,o){e.__gameRef=n,e.imageSmoothingEnabled=!1,e.clearRect(0,0,t.width,t.height),hu(e,t,n),e.save();let r=n.shake.time>0?ne(-n.shake.strength,n.shake.strength):0,i=n.shake.time>0?ne(-n.shake.strength,n.shake.strength):0,a=n.view?.scale||1;e.translate((n.view?.x||0)+r,(n.view?.y||0)+i),e.scale(a,a),vu(e,n),Su(e,n),Tu(e,n),Eu(e,n),Pu(e,n),Nu(e,n),Yu(e,n),Qu(e,n),Gu(e,n),Wu(e,n),du(e,n),od(e,n,o.activeQueuedChick),yd(e,n),ud(e,t,n),cd(e,n,o.selectedObject,o.selectedTitle),dd(e,n),fd(e,n),pd(e,n),e.restore(),bd(e,n,t)}function uu(e){if(e.type==="eggFarm"){let n=B(e.ref.col,e.ref.row);return{x:n.x-34,y:n.y-34,w:68,h:68,cx:n.x,cy:n.y}}let t=e.ref;return{x:t.x,y:t.y,w:t.w,h:t.h,cx:t.x+t.w/2,cy:t.y+t.h/2}}function du(e,t){if(t.phase!=="build")return;let n=vn(t);for(let o of n){let r=uu(o);e.save(),e.fillStyle="rgba(196,36,36,.22)",e.strokeStyle=w.danger,e.lineWidth=5,e.setLineDash([10,6]),ee(e,r.x,r.y,r.w,r.h,!0,!0),e.setLineDash([]),e.fillStyle=w.danger,e.strokeStyle=w.white,e.lineWidth=4,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.strokeText("!",r.cx,r.y+24),e.fillText("!",r.cx,r.y+24),e.font="900 11px ui-monospace, monospace",e.strokeText("NO ROUTE",r.cx,r.y+r.h-8),e.fillText("NO ROUTE",r.cx,r.y+r.h-8),e.restore()}}function ee(e,t,n,o,r,i=!0,a=!0){e.beginPath(),e.rect(t,n,o,r),i&&e.fill(),a&&e.stroke()}function oo(e,t,n,o,r=w.ink){e.save(),e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.lineWidth=4,e.strokeStyle=w.white,e.fillStyle=r,e.strokeText(o,t,n),e.fillText(o,t,n),e.restore()}function ln(e,t,n,o,r,i){if(!t?.loaded)return!1;let a=e.imageSmoothingEnabled;return e.imageSmoothingEnabled=!1,e.drawImage(t,Math.round(n),Math.round(o),Math.round(r),Math.round(i)),e.imageSmoothingEnabled=a,!0}function fu(e,t,n,o,r,i,a=null,c=1){e.fillStyle=i,e.fillRect(Math.round(t),Math.round(n),Math.round(o),Math.round(r)),a&&(e.strokeStyle=a,e.lineWidth=c,e.strokeRect(Math.round(t)+.5,Math.round(n)+.5,Math.round(o)-1,Math.round(r)-1))}function pu(e,t){let n=(Math.imul(e+37,73856093)^Math.imul(t+71,19349663))>>>0;return n^=n>>>13,n>>>0}function yu(e,t,n,o,r){let i=pu(o,r);if(i%67!==0)return;let a=10+(i>>>4)%Math.max(1,p.cell-22),c=10+(i>>>9)%Math.max(1,p.cell-22),b=(i>>>14)%16*Math.PI/16;e.save(),e.globalAlpha=.38,e.fillStyle="#4a8d37",e.strokeStyle="rgba(30,66,27,.34)",e.lineWidth=1,e.beginPath();for(let C=0;C<8;C+=1){let $=b+C*Math.PI/4,W=3.5+(i>>>C+2&3),K=t+a+Math.cos($)*W*1.35,G=n+c+Math.sin($)*W*.75;C===0?e.moveTo(K,G):e.lineTo(K,G)}e.closePath(),e.fill(),e.stroke();let M=4+(i>>>24)%5;for(let C=0;C>>C+8&3)*.18,W=10+(i>>>C+11&10),K=.9+(i>>>C+17&3)*.35;e.beginPath(),e.arc(t+a+Math.cos($)*W,n+c+Math.sin($)*W*.72,K,0,Math.PI*2),e.fill()}e.fillStyle="rgba(151,218,101,.26)",e.beginPath(),e.arc(t+a-2,n+c-2,1.7,0,Math.PI*2),e.fill(),e.restore()}function Da(e,t){e.fillStyle=w.bg,e.fillRect(0,0,t.width,t.height),e.save(),e.globalAlpha=.85;for(let n=0;na.col)),o=Math.max(...t.map(a=>a.col)),r=Math.min(...t.map(a=>a.row)),i=Math.max(...t.map(a=>a.row));return{x:p.x+n*p.cell-6,y:p.y+r*p.cell-6,w:(o-n+1)*p.cell+12,h:(i-r+1)*p.cell+12}}function vu(e,t){let n=bi(t),o=wu(t);if(!n.grid||n.grid.signature!==o){let a=mu(t),c=wi(a.w,a.h),b=c.getContext("2d");b.translate(-a.x,-a.y),bu(b,t),n.grid={signature:o,bounds:a,layer:c}}let{bounds:r,layer:i}=n.grid;e.drawImage(i,r.x,r.y)}function Su(e,t){if(t.phase!=="build"||t.cardDraft?.pending||t.cardTargetPick?.pending)return;let n=Co(t),o=t.cash>=n,r=i=>{let a=Et(i);return Object.values(t.facilities||{}).some(c=>{let b=c?.baseId||c?.id;return["mixer","trash","truck"].includes(b)?!(a.x+a.w<=c.x||c.x+c.w<=a.x||a.y+a.h<=c.y||c.y+c.h<=a.y):!1})};for(let i of jt(t)){let a=r(i),c=Et(i);e.save(),e.fillStyle=a?"rgba(112,130,118,.34)":o?"rgba(118,226,142,.36)":"rgba(255,255,255,.18)",e.strokeStyle=a?"#708278":o?"#6bd579":w.muted,e.lineWidth=5,e.setLineDash([16,10]),ee(e,c.x,c.y,c.w,c.h,!0,!0),e.setLineDash([]);let b=Tr(i),M=b.cx,C=b.cy;e.fillStyle="rgba(255,255,255,.94)",e.strokeStyle=w.ink,e.lineWidth=4,ee(e,b.x,b.y,b.w,b.h,!0,!0),e.fillStyle=a?"#7c9285":o?w.green:w.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center";let $=i.direction==="left"?"BUY LEFT LOT":i.direction==="right"?"BUY RIGHT LOT":i.direction==="down"?"BUY LOWER LOT":"BUY UPPER LOT";e.fillText($,M,C-12),e.fillStyle=w.ink,e.font="900 16px ui-monospace, monospace",e.fillText(`${R(n)} / 10\xD710`,M,C+15),e.restore()}}function Dt(e,t,n,o,r,i,a=0){let c=Pn(i);c<.5||(e.save(),e.globalAlpha=Math.min(.62,.12+c*.54),e.fillStyle="#6b4a23",a>0?(e.beginPath(),e.roundRect?.(t,n,o,r,a),e.roundRect?e.fill():ee(e,t,n,o,r,!0,!1)):ee(e,t,n,o,r,!0,!1),e.globalAlpha=Math.min(.9,.25+c*.6),e.strokeStyle="#3a2a16",e.lineWidth=Math.max(2,Math.floor(2+c*5)),e.setLineDash([5,6]),ee(e,t+3,n+3,o-6,r-6,!1,!0),e.restore())}function yi(e,t){let n=e.componentLookup?.get(t);return(n?e.congestion.get(n):null)?.ratio||0}function ku(e,t,n={}){let o=ro(e,t).sort(),i=n.kind==="boostConveyor"?"boostConveyor":"conveyor",a=c=>o.includes(c);if(o.length===2){if(a("left")&&a("right"))return De[`${i}StraightH`];if(a("up")&&a("down"))return De[`${i}StraightV`];if(a("up")&&a("right"))return De[`${i}TurnNe`];if(a("up")&&a("left"))return De[`${i}TurnNw`];if(a("down")&&a("right"))return De[`${i}TurnSe`];if(a("down")&&a("left"))return De[`${i}TurnSw`]}return o.length===1?a("up")||a("down")?De[`${i}StraightV`]:De[`${i}StraightH`]:a("up")||a("down")?De[`${i}StraightV`]:De[`${i}StraightH`]}function Mu(e){let t=Object.entries(De).filter(([o])=>o.includes("conveyor")||o.includes("Conveyor")).map(([o,r])=>`${o}:${r.loaded?1:0}`).join("|"),n=[...e.conveyorTiles].sort().map(o=>{let r=e.conveyorMeta.get(o)||{};return`${o}:${r.kind||""}:${r.dir||""}:${(r.outDirs||[]).join(",")}:${r.branchMode||""}`}).join("|");return`${e.routingVersion||0};${t};${n}`}function Cu(e){if(!e.conveyorTiles?.size)return{x:0,y:0,w:1,h:1};let t=[...e.conveyorTiles].map(X),n=Math.min(...t.map(a=>a.col)),o=Math.max(...t.map(a=>a.col)),r=Math.min(...t.map(a=>a.row)),i=Math.max(...t.map(a=>a.row));return{x:p.x+n*p.cell-36,y:p.y+r*p.cell-36,w:(o-n+1)*p.cell+72,h:(i-r+1)*p.cell+72}}function gu(e){let t=[],n=new Set;for(let i of e.conveyorTiles){let{col:a,row:c}=X(i);for(let b of fe){let M={col:a+b.dc,row:c+b.dr},C=E(M.col,M.row);if(!e.conveyorTiles.has(C))continue;let $=[i,C].sort().join("|");n.has($)||(n.add($),t.push({fromKey:i,toKey:C,a:B(a,c),b:B(M.col,M.row)}))}}let o=Bu(e),r=[...e.conveyorTiles].map(i=>{let a=X(i),c=B(a.col,a.row),b=e.conveyorMeta.get(i)||{},M=ro(e,i);return{k:i,c,meta:b,connectedDirs:M,branchDirs:Au(e,i,M),markers:o.get(i)||[],sprite:ku(e,i,b)}});return{edges:t,tiles:r}}function xu(e,t){e.save(),e.lineCap="round",e.lineJoin="round";for(let n of[{width:31,color:"#0b0c0f",alpha:1},{width:23,color:"#444b56",alpha:1},{width:15,color:"#171a1f",alpha:1}]){e.globalAlpha=n.alpha,e.strokeStyle=n.color,e.lineWidth=n.width;for(let o of t.edges)e.beginPath(),e.moveTo(o.a.x,o.a.y),e.lineTo(o.b.x,o.b.y),e.stroke()}e.globalAlpha=1;for(let n of t.tiles){let{c:o,meta:r,sprite:i}=n;e.fillStyle="rgba(0,0,0,.35)",e.strokeStyle="rgba(255,184,39,.34)",e.lineWidth=1,ee(e,o.x-20,o.y-20,40,40,!0,!0),ln(e,i,o.x-19,o.y-19,38,38)||(e.fillStyle=r.kind==="boostConveyor"?"#315e92":"#454b55",e.strokeStyle=w.ink,e.lineWidth=2,ee(e,o.x-18,o.y-18,36,36,!0,!0))}e.restore()}function Tu(e,t){let n=bi(t),o=Mu(t);if(!n.conveyors||n.conveyors.signature!==o){let c=gu(t),b=Cu(t),M=wi(b.w,b.h),C=M.getContext("2d");C.translate(-b.x,-b.y),xu(C,c),n.conveyors={signature:o,bounds:b,layer:M,data:c}}let{bounds:r,layer:i,data:a}=n.conveyors;e.drawImage(i,r.x,r.y),e.save(),e.lineCap="round",e.lineJoin="round";for(let c of a.edges){let b=Math.max(yi(t,c.fromKey),yi(t,c.toKey)),M=Math.max(0,(b-.5)/.5);e.strokeStyle=qn(w.green,w.danger,M),e.globalAlpha=b>.5?.35+M*.55:.8,e.lineWidth=6,e.beginPath(),e.moveTo(c.a.x,c.a.y),e.lineTo(c.b.x,c.b.y),e.stroke()}e.globalAlpha=1;for(let c of a.tiles){let{k:b,c:M,meta:C}=c,$=yi(t,b);$>.5&&(e.fillStyle="rgba(196,36,36,.28)",e.strokeStyle=w.danger,e.lineWidth=3,ee(e,M.x-20,M.y-20,40,40,!0,!0)),Ru(e,t,M,b,C,$),Dt(e,M.x-18,M.y-18,36,36,{meta:C}),ft(e,t,"conveyor",b,M.x,M.y,38,38),Du(e,M,c.markers),Fu(e,M,C,c.branchDirs,c.connectedDirs),$>.5&&oo(e,M.x,M.y-15,`${Math.floor($*100)}%`,w.danger)}e.restore()}function Eu(e,t){if(t.powerWires?.size){e.save();for(let[n,o]of t.powerWires){let r=X(n),i=B(r.col,r.row),a=o.kind==="insulatedPowerWire";e.globalAlpha=t.powerOverlay||t.phase==="build"?.95:.32,e.strokeStyle=a?"#d7eef7":"#1e252b",e.lineWidth=a?8:5,e.lineCap="round",e.beginPath(),e.moveTo(i.x-15,i.y),e.lineTo(i.x+15,i.y),e.moveTo(i.x,i.y-15),e.lineTo(i.x,i.y+15),e.stroke(),e.strokeStyle=a?"#2c8ec4":"#f3c33d",e.lineWidth=a?3:2,e.stroke(),t.powerOverlay&&oo(e,i.x,i.y-14,a?"I":"V",a?"#2c8ec4":w.warn)}e.restore()}}function Pu(e,t){if(t.footbridges?.size){e.save();for(let n of t.footbridges.keys()){let o=X(n),r=B(o.col,o.row);e.fillStyle="rgba(210,222,228,.52)",e.strokeStyle="#e6edf2",e.lineWidth=3,ee(e,r.x-20,r.y-14,40,28,!0,!0),e.strokeStyle="#34404a",e.lineWidth=2,e.beginPath(),e.moveTo(r.x-18,r.y-9),e.lineTo(r.x+18,r.y-9),e.moveTo(r.x-18,r.y+9),e.lineTo(r.x+18,r.y+9),e.stroke(),ft(e,t,"footbridge",n,r.x,r.y,44,34)}e.restore()}}function Ru(e,t,n,o,r={},i=0){let a=r.kind==="boostConveyor",b=[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))][0]||"right",M=b==="up"||b==="down",C=b==="left"||b==="up",$=Vt(t,o)*eo(t,o),K=(typeof performance<"u"?performance.now()/1e3:0)*$,G=((C?-K:K)%10+10)%10;e.save(),e.beginPath(),e.rect(n.x-18,n.y-18,36,36),e.clip();let z=a?"rgba(20,126,124,.62)":"rgba(42,47,54,.72)";if(e.fillStyle=z,e.fillRect(n.x-18,n.y-18,36,36),e.strokeStyle=i>.5?"rgba(238,83,61,.90)":"rgba(184,190,198,.92)",e.lineWidth=4,M)for(let Q=n.y-28+G;Qe.conveyorTiles.has(E(n.col+o.dc,n.row+o.dr))).map(o=>o.name)}function Wa(e,t,n){let o=fe.find(a=>a.name===n);if(!o)return!1;let r=e.conveyorMeta?.get?.(E(t.col+o.dc,t.row+o.dr));return r?[...new Set([...Array.isArray(r.outDirs)?r.outDirs:[],r.dir].filter(Boolean))].includes(o.opposite):!1}function Ua(e,t,n,o=ro(e,t)){if(o.length<3)return n;let r=X(t),i=new Set(o.filter(b=>Wa(e,r,b))),a=o.filter(b=>!i.has(b));if(i.size)return a;let c=n.filter(b=>o.includes(b));return c.length>=2?[...new Set(c)]:o}function Iu(e,t,n,o=ro(e,t),r="random"){let i=Ua(e,t,n,o);return o.length>=3&&r&&r!=="random"&&i.includes(r)?[r]:i}function Au(e,t,n=ro(e,t)){let o=e.conveyorMeta?.get?.(t)||{},r=[...new Set([...Array.isArray(o.outDirs)?o.outDirs:[],o.dir].filter(Boolean))];return n.length<3?[]:Ua(e,t,r,n)}function $u(e,t,n){let o=X(t),r=fe.filter(c=>e.conveyorTiles.has(E(o.col+c.dc,o.row+c.dr))).map(c=>c.name),i=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(c=>r.includes(c));if(r.length===1&&(!i.length||i.includes(r[0]))&&Wa(e,o,r[0]))return[];let a=r;return i.length?i:a}function Fu(e,t,n,o,r=o){if(r.length<3||o.length<2)return;e.save();let i=o.includes(n.branchMode)?n.branchMode:"random",a=i!=="random";if(e.lineJoin="round",e.lineCap="round",e.lineWidth=2,e.fillStyle="rgba(18,21,26,.94)",e.strokeStyle=a?w.warn:w.green,e.lineWidth=4,ee(e,t.x-18,t.y-18,36,36,!0,!0),e.strokeStyle="#ffd36a",e.lineWidth=3,e.fillStyle="#020304",i!=="random"){let c=fe.find(b=>b.name===i);no(e,t.x,t.y-4,c?.angle||0,8,5)}else e.beginPath(),e.moveTo(t.x-10,t.y),e.lineTo(t.x-2,t.y),e.lineTo(t.x+8,t.y-8),e.moveTo(t.x-2,t.y),e.lineTo(t.x+8,t.y+8),e.stroke(),no(e,t.x+9,t.y-9,-Math.PI/4,4,3),no(e,t.x+9,t.y+9,Math.PI/4,4,3);i==="random"&&(e.font="900 9px ui-monospace, monospace",e.textAlign="center",e.textBaseline="middle",e.lineWidth=3,e.strokeStyle="#020304",e.fillStyle=w.warn,e.strokeText("RND",t.x,t.y+11),e.fillText("RND",t.x,t.y+11)),e.restore()}function Ou(e,t,n){if(!n)return[];let o=X(t),r=fe.filter(c=>e.conveyorTiles.has(E(o.col+c.dc,o.row+c.dr))).map(c=>c.name),i=[...new Set([...Array.isArray(n.outDirs)?n.outDirs:[],n.dir].filter(Boolean))].filter(c=>r.includes(c));return Iu(e,t,i.length?i:$u(e,t,n),r,n.branchMode||"random").map(c=>fe.find(b=>b.name===c)).filter(Boolean)}function Bu(e){let t=new Map;for(let[n,o]of e.conveyorMeta||[]){let r=Ou(e,n,o);r.length&&t.set(n,r)}return t}function Du(e,t,n){let o=n.slice(0,4);o.length&&(e.save(),e.globalAlpha=1,o.forEach(r=>{let i=t.x+r.dc*11,a=t.y+r.dr*11;e.fillStyle="rgba(255,205,83,.96)",no(e,i,a,r.angle,9,7),e.fillStyle="#020304",no(e,i,a,r.angle,6.5,4.6)}),e.restore())}function no(e,t,n,o,r=11,i=8){e.save(),e.translate(t,n),e.rotate(o),e.beginPath(),e.moveTo(r,0),e.lineTo(-r*.72,-i),e.lineTo(-r*.72,i),e.closePath(),e.fill(),e.restore()}function Lu(e,t,n,o,r){let i=ge(t),a=null;if(n==="inputA"&&(a={x:i.x,y:i.y-40}),n==="left"&&(a={x:i.x-42,y:i.y+10}),n==="right"&&(a={x:i.x+42,y:i.y+10}),!a)return;let c=n==="inputA"?{x:o.x,y:a.y}:{x:a.x,y:o.y};e.save(),e.lineCap="square",e.lineJoin="bevel",e.strokeStyle="#050609",e.lineWidth=15,e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(c.x,c.y),e.lineTo(a.x,a.y),e.stroke(),e.strokeStyle="#596473",e.lineWidth=9,e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(c.x,c.y),e.lineTo(a.x,a.y),e.stroke(),e.strokeStyle=r||"#7b8795",e.lineWidth=3,e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(c.x,c.y),e.lineTo(a.x,a.y),e.stroke(),e.fillStyle=r||"#7b8795",e.strokeStyle="#050609",e.lineWidth=3,ee(e,a.x-9,a.y-7,18,14,!0,!0),e.restore()}function Nu(e,t){e.save(),e.lineWidth=2,e.font="900 12px ui-monospace, monospace",e.textAlign="center";for(let n of t.scanners){let o=Br(n),r=[{type:"inputA",p:We(n,"inputA"),label:"IN",color:w.green},{type:"left",p:We(n,"left"),label:Lr(o.left),color:Nr(o.left)},{type:"right",p:We(n,"right"),label:Lr(o.right),color:Nr(o.right)}];for(let i of r){if(!i.p)continue;let a=B(i.p.col,i.p.row);Lu(e,n,i.type,a,i.color);let c=us(t,n,i.type||(i.label==="IN"?"inputA":null))||t.conveyorTiles.has(E(i.p.col,i.p.row));e.fillStyle=c?qn("#1a1d23",i.color,.24):"#3a1e22",e.strokeStyle=c?i.color:w.danger,ee(e,a.x-18,a.y-12,36,24,!0,!0),e.fillStyle=w.white,e.fillText(i.label,a.x,a.y+4)}}e.restore()}function Gu(e,t){for(let n of t.eggFarms)_u(e,n,t)}function _u(e,t,n){let o=B(t.col,t.row);e.save(),e.fillStyle="#5a6470",e.strokeStyle=w.ink,e.lineWidth=3,ee(e,o.x-27,o.y-27,54,54,!0,!0),e.fillStyle="#6f5130",e.strokeStyle="#2f2112",e.lineWidth=3,e.beginPath(),e.ellipse(o.x,o.y+3,19,12,0,0,Math.PI*2),e.fill(),e.stroke(),e.strokeStyle="#a77b4b",e.lineWidth=2;for(let c=-16;c<=16;c+=6)e.beginPath(),e.moveTo(o.x-18,o.y+c*.1),e.quadraticCurveTo(o.x+c,o.y-10+Math.abs(c)*.2,o.x+18,o.y+c*.08),e.stroke();let r=[{x:-8,y:1},{x:0,y:-3},{x:8,y:2}];for(let c of r)e.fillStyle="#e8e2cf",e.strokeStyle="#8d8475",e.lineWidth=1.5,e.beginPath(),e.ellipse(o.x+c.x,o.y+c.y,4.8,6.2,.2,0,Math.PI*2),e.fill(),e.stroke();let i=1+Math.max(0,Number(t.extraEggOutlet)||0);e.fillStyle="rgba(255,255,255,.92)",e.strokeStyle=w.ink,e.lineWidth=2,ee(e,o.x+8,o.y+11,30,18,!0,!0),e.fillStyle=w.ink,e.font="900 10px ui-monospace, monospace",e.textAlign="center",e.fillText(`O${i}`,o.x+23,o.y+23),e.fillStyle="#d5e35a",e.font="900 9px ui-monospace, monospace",e.fillText(`L${t.level}`,o.x-13,o.y-15);let a=Math.max(0,Math.min(1,t.shutterProgress||0));if(a>0){let c=54*a;e.fillStyle="rgba(10,12,15,.86)",ee(e,o.x-27,o.y-27,54,c,!0,!1),e.strokeStyle="rgba(230,237,242,.64)",e.lineWidth=2;for(let b=o.y-23;b=1&&(e.fillStyle=w.white,e.font="900 12px ui-monospace, monospace",e.fillText("SHUT",o.x,o.y+4))}Dt(e,o.x-28,o.y-28,56,56,t),ft(e,n,"eggFarm",t.id,o.x,o.y,68,68),e.restore()}function Wu(e,t){for(let n of t.scanners)Uu(e,n,t)}function Uu(e,t,n){let o=ge(t);if(e.save(),t.kind==="manual"&&(n.manualCombo?.count||0)>=10){let b=n.manualCombo.count;e.save(),e.globalAlpha=Math.min(.55,.16+b/120),e.strokeStyle=b>=30?w.warn:w.green,e.lineWidth=Math.min(12,4+Math.floor(b/10)),e.shadowColor=e.strokeStyle,e.shadowBlur=Math.min(24,8+b),ee(e,o.x-48,o.y-48,96,96,!1,!0),e.restore()}let r=t.kind==="auto"?De.scannerAuto:De.scannerManual;if(ln(e,r,o.x-44,o.y-44,88,88)){t.kind==="auto"?Dt(e,o.x-44,o.y-44,88,88,t):La(e,t,o),ft(e,n,"scanner",t.id,o.x,o.y,96,96),e.restore();return}e.fillStyle=t.kind==="auto"?"#d8ffe2":w.white,e.strokeStyle=w.ink,e.lineWidth=4,ee(e,o.x-44,o.y-44,88,88,!0,!0),e.fillStyle=t.kind==="auto"?w.green:w.ink,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText(t.kind==="auto"?"AUTO":`S${(t.slot??0)+1}`,o.x,o.y-24),e.font="900 9px ui-monospace, monospace";let i=t.keys?.left?.label||(t.slot===0?"A":"Left"),a=t.keys?.right?.label||(t.slot===0?"D":"Right");e.fillText(t.kind==="auto"?"2.1 FARMS":`${i}/${a}`,o.x,o.y-8);let c=t.queue.length;t.kind==="manual"?La(e,t,o):(e.fillStyle=c>0?w.green:w.muted,e.font="900 10px ui-monospace, monospace",e.fillText(`Q:${c} CD:${t.cooldown.toFixed(1)}`,o.x,o.y+35),Dt(e,o.x-44,o.y-44,88,88,t)),ft(e,n,"scanner",t.id,o.x,o.y,96,96),e.restore()}function La(e,t,n){if(t.kind!=="manual")return;let r=(t.slot??0)===0?[{side:"left",text:"A"},{side:"right",text:"D"}]:[{side:"left",text:"\u2190"},{side:"right",text:"\u2192"}];r[0].text=t.keys?.left?.label||r[0].text,r[1].text=t.keys?.right?.label||r[1].text;let i=t.keyPressTime>0?t.keyPressSide:null,a=n.x-30,c=n.y+8;e.save(),e.lineWidth=3,e.fillStyle="#f7fff5",e.strokeStyle=w.ink,ee(e,a-4,c-4,68,25,!0,!0),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let b=0;b MEAT","meat","connect OUT to sausage machine"),Dt(e,n.x,n.y,n.w,n.h,n),ft(e,t,"facility",n.id,n.x+n.w/2,n.y+n.h/2,n.w+12,n.h+12),e.restore()}function ed(e,t,n=t.facilities.trash){e.save(),er(e,n),cn(e,n.x,n.y,n.w,n.h,"#29342d",w.ink,w.wasteGreen),$n(e,n,w.wasteGreen),e.fillStyle=w.white,e.font="900 14px ui-monospace, monospace",e.textAlign="left",e.fillText(`SHREDDER L${n.level}`,n.x+14,n.y+18),e.fillStyle="#181d20",e.strokeStyle="#9fd473",e.lineWidth=4,ee(e,n.x+38,n.y+36,92,22,!0,!0),e.fillStyle="#262d30",e.strokeStyle="#0d1014",ee(e,n.x+46,n.y+58,76,18,!0,!0),e.fillStyle="#111418";for(let o=0;o<7;o+=1){let r=n.x+51+o*10;e.beginPath(),e.moveTo(r,n.y+58),e.lineTo(r+5,n.y+68),e.lineTo(r+10,n.y+58),e.closePath(),e.fill()}e.fillStyle="#6f7e8d",ee(e,n.x+54,n.y+27,16,9,!0,!0),ee(e,n.x+98,n.y+27,16,9,!0,!0),Jo(e,n.x+14,n.y+n.h-42,n.w-28,"SEND POOP","poop","shredder"),Dt(e,n.x,n.y,n.w,n.h,n),ft(e,t,"facility",n.id,n.x+n.w/2,n.y+n.h/2,n.w+12,n.h+12),e.restore()}function td(e,t,n){e.save(),cn(e,n.x,n.y,n.w,n.h,"#3b3029",w.ink,w.sausageOrange),$n(e,n,w.sausageOrange),e.fillStyle=w.white,e.font="900 14px ui-monospace, monospace",e.textAlign="left",e.fillText(`SAUSAGE L${n.level}`,n.x+14,n.y+18),e.fillStyle=w.muted,e.font="900 10px ui-monospace, monospace",e.fillText(`2 MEAT -> 1 | ${R(lt(t))}`,n.x+14,n.y+34),e.fillStyle="#211915",e.strokeStyle=w.sausageOrange,e.lineWidth=4,ee(e,n.x+20,n.y+43,n.w-40,38,!0,!0);for(let o=0;o<3;o+=1)tr(e,n.x+n.w/2-28+o*28,n.y+62,9);e.fillStyle=w.meatRed,e.fillRect(n.x,n.y+n.h/2-8,8,16),e.fillStyle=w.sausageOrange,e.fillRect(n.x+n.w-8,n.y+n.h/2-8,8,16),Jo(e,n.x+10,n.y+n.h-42,n.w-20,"2 MEAT -> SAUSAGE","sausage",`buffer ${n.meatBuffer||0}/2`),Dt(e,n.x,n.y,n.w,n.h,n),ft(e,t,"facility",n.id,n.x+n.w/2,n.y+n.h/2,n.w+12,n.h+12),e.restore()}function nd(e,t,n=t.facilities.truck){e.save(),er(e,n),cn(e,n.x,n.y,n.w,n.h,"#343128",w.ink,w.truckPink),$n(e,n,w.truckPink),e.fillStyle=w.white,e.font="900 14px ui-monospace, monospace",e.textAlign="left",e.fillText(`SHIP TRUCK L${n.level}`,n.x+14,n.y+18),e.fillStyle=w.muted,e.font="900 10px ui-monospace, monospace",e.fillText(`UNIT ${R(Je(t))}`,n.x+14,n.y+34),zu(e,De.truck,n,2);let o=hi(t);Jo(e,n.x+15,n.y+50,n.w-30,`SEND ${o.toUpperCase()}`,o,t.eventOffer&&!t.eventActive?"next event":"truck cargo"),e.fillStyle="rgba(39,60,36,.9)",ee(e,n.x+13,n.y+88,n.w-26,Math.max(18,n.h-103),!0,!1);for(let r of t.truckCargo)r.sex==="poop"?Va(e,n.x+r.x,n.y+r.y):r.sex==="sausage"?tr(e,n.x+r.x,n.y+r.y,7):Si(e,n.x+r.x,n.y+r.y,r.sex,r.sex==="male");Dt(e,n.x,n.y,n.w,n.h,n),ft(e,t,"facility",n.id,n.x+n.w/2,n.y+n.h/2,n.w+12,n.h+12),e.restore()}function od(e,t,n){let o=n(0),r=n(1);for(let i of t.chicks){let a=o&&o.id===i.id||r&&r.id===i.id||i.queueIndex===0;rd(e,i,a,t)}}function rd(e,t,n,o){let r=o.componentLookup&&id(o,t)>.8,i=t.y+Math.sin(t.bob)*(r?5:1.5);if(e.save(),n&&(e.strokeStyle=w.green,e.lineWidth=5,e.beginPath(),e.arc(t.x,i,t.radius+8,0,Math.PI*2),e.stroke()),r&&(e.strokeStyle=w.danger,e.lineWidth=3,e.beginPath(),e.arc(t.x,i,t.radius+12+Math.sin(t.bob*2)*4,0,Math.PI*2),e.stroke()),t.sex==="poop")vi(e,t.x,i,t.radius);else if(t.sex==="meat")Ka(e,t.x,i,t.radius);else if(t.sex==="sausage")tr(e,t.x,i,t.radius);else if(t.sex==="coal")sd(e,t.x,i,t.radius);else if(t.sex==="zundaMochi")ad(e,t.x,i,t.radius);else{let a=t.sex==="male"?De.chickMale:De.chickFemale;if(!ln(e,a,t.x-t.radius,i-t.radius,t.radius*2,t.radius*2)){let M=t.sex==="male"?w.male:w.female,C=t.sex==="male"?"#164f8f":"#8b2252";e.fillStyle=M,e.strokeStyle=w.ink,e.lineWidth=5,e.beginPath(),e.arc(t.x,i,t.radius,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle="rgba(255,255,255,.24)",e.beginPath(),e.arc(t.x-5,i-7,t.radius*.36,0,Math.PI*2),e.fill(),e.fillStyle=w.ink,e.beginPath(),e.arc(t.x-6,i-5,2.5,0,Math.PI*2),e.arc(t.x+6,i-5,2.5,0,Math.PI*2),e.fill(),e.fillStyle="#ffaa2e",e.beginPath(),e.moveTo(t.x,i+2),e.lineTo(t.x+9,i+6),e.lineTo(t.x,i+10),e.closePath(),e.fill(),e.strokeStyle=C,e.lineWidth=3,t.sex==="male"?(e.beginPath(),e.moveTo(t.x-8,i-t.radius-2),e.lineTo(t.x+8,i-t.radius-2),e.stroke()):(e.beginPath(),e.moveTo(t.x-9,i-t.radius+2),e.lineTo(t.x,i-t.radius-6),e.lineTo(t.x+9,i-t.radius+2),e.stroke())}e.fillStyle=t.sex==="male"?"#dff1ff":"#fff0f7",e.strokeStyle="#050609",e.lineWidth=3,e.font=`900 ${Math.max(10,Math.round(t.radius*.72))}px ui-monospace, monospace`,e.textAlign="center";let b=t.sex==="male"?"\u2642":"\u2640";e.strokeText(b,t.x+t.radius*.54,i+t.radius*.7),e.fillText(b,t.x+t.radius*.54,i+t.radius*.7)}e.restore()}function id(e,t){let n=null,o=1/0;for(let[r,i]of e.componentLookup.entries()){let a=X(r),c=B(a.col,a.row),b=Math.hypot(t.x-c.x,t.y-c.y);bNa(o.type,o.id)===Na(t,n))}function ft(e,t,n,o,r,i,a,c){ld(t,n,o)&&(e.save(),e.fillStyle="rgba(34,185,79,.18)",e.strokeStyle=w.green,e.lineWidth=(t.multiSelected||[]).length>1?6:4,e.setLineDash((t.multiSelected||[]).length>1?[]:[8,5]),ee(e,r-a/2,i-c/2,a,c,!0,!0),e.restore())}function cd(e,t,n,o){if(t.phase==="build"&&(t.multiSelected||[]).length>1){e.save(),e.fillStyle="rgba(255,255,255,.96)",e.strokeStyle=w.ink,e.lineWidth=3,ee(e,54-t.view.x,66-t.view.y,214,42,!0,!0),e.fillStyle=w.ink,e.font="900 11px ui-monospace, monospace",e.fillText(`${t.multiSelected.length} ITEMS SELECTED`,65-t.view.x,83-t.view.y),e.fillStyle=w.muted,e.font="900 11px ui-monospace, monospace",e.fillText("drag any selected item to move group",65-t.view.x,99-t.view.y),e.restore();return}}function ud(e,t,n){if(!n.cardTargetPick?.pending)return;let o=pi(n);e.save(),e.fillStyle="rgba(0,0,0,.66)",e.beginPath();let r=n.view?.scale||1;e.rect(-(n.view?.x||0)/r,-(n.view?.y||0)/r,t.width/r,t.height/r);for(let M of o){let C=M.bounds,$=8;e.rect(C.x-$,C.y-$,C.w+$*2,C.h+$*2)}e.fill("evenodd");let i=n.cardTargetPick?.mode==="blockedCell";if(!o.length){e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=w.ink,e.lineWidth=3,ee(e,(260-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,420/r,42/r,!0,!0),e.fillStyle=w.danger,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(i?"NO BLOCKED CELL. PRESS ESC.":"NO VALID UPGRADE TARGET. PRESS ESC.",(470-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore();return}e.fillStyle="rgba(255,255,255,.95)",e.strokeStyle=w.ink,e.lineWidth=3;let a=Math.max(1,n.cardTargetPick?.remaining||1),c=Math.max(0,n.cardTargetPick?.used||0),b=n.cardTargetPick?.mode==="autoScannerMenu"?"AUTO SCANNER ROUTE SETTINGS. CLICK EMPTY AREA TO CLOSE.":i?`DYNAMITE: CLICK ANY BLOCKED TILE (${a} LEFT). ESC ${c>0?"FINISHES":"CANCELS"}.`:"CLICK AN UPGRADEABLE MACHINE. PRESS ESC TO CANCEL.";ee(e,(216-(n.view?.x||0))/r,(96-(n.view?.y||0))/r,560/r,42/r,!0,!0),e.fillStyle=w.ink,e.font="900 12px ui-monospace, monospace",e.textAlign="center",e.fillText(b,(496-(n.view?.x||0))/r,(122-(n.view?.y||0))/r),e.restore()}function dd(e,t){if(t.phase!=="build"||!t.selectionBox)return;let n=t.selectionBox,o=Math.min(n.x1,n.x2),r=Math.min(n.y1,n.y2),i=Math.abs(n.x2-n.x1),a=Math.abs(n.y2-n.y1);e.save(),e.fillStyle="rgba(34,185,79,.12)",e.strokeStyle=w.green,e.lineWidth=2,e.setLineDash([7,4]),ee(e,o,r,i,a,!0,!0),e.restore()}function fd(e,t){let n=[...t.effects].sort((o,r)=>(o.priority??_e.ambient)-(r.priority??_e.ambient));for(let o of n){let r=Math.max(0,o.life/o.maxLife);e.save(),e.globalAlpha=r,o.type==="meat"?(e.fillStyle=w.green,ee(e,o.x-o.size/2,o.y-o.size/2,o.size*1.5,o.size,!0,!1)):o.type==="sludge"?(e.fillStyle=w.poop,ee(e,o.x-o.size/2,o.y-o.size/2,o.size*1.4,o.size,!0,!1)):o.type==="spawn"?(e.strokeStyle=w.green,e.lineWidth=3,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*20,0,Math.PI*2),e.stroke()):o.type==="spark"?(e.fillStyle=o.color||w.danger,ee(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!0,!1)):o.type==="smoke"?(e.fillStyle="rgba(16,32,21,.24)",e.beginPath(),e.arc(o.x,o.y,o.size*(1.2-r*.2),0,Math.PI*2),e.fill()):o.type==="shockwave"?(e.strokeStyle=o.color||w.danger,e.lineWidth=4,e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*(o.maxSize||44),0,Math.PI*2),e.stroke()):o.type==="scannerPulse"?(e.strokeStyle=o.color||w.green,e.lineWidth=5,e.setLineDash([8,6]),e.beginPath(),e.arc(o.x,o.y,o.size+(1-r)*38,0,Math.PI*2),e.stroke()):o.type==="shred"?(e.fillStyle=o.color||w.ink,e.save(),e.translate(o.x,o.y),e.rotate(o.rot||0),ee(e,-o.w/2,-o.h/2,o.w,o.h,!0,!1),e.restore()):o.type==="load"?(e.strokeStyle=o.color||w.green,e.lineWidth=3,e.beginPath(),e.moveTo(o.x-14,o.y),e.lineTo(o.x+14,o.y),e.moveTo(o.x,o.y-14),e.lineTo(o.x,o.y+14),e.stroke()):o.type==="erase"?(e.strokeStyle=w.ink,e.lineWidth=3,e.setLineDash([4,4]),ee(e,o.x-o.size/2,o.y-o.size/2,o.size,o.size,!1,!0)):o.type==="rage"?(e.fillStyle=o.color||w.danger,e.font="900 16px ui-monospace, monospace",e.textAlign="center",e.fillText("!",o.x,o.y)):o.type==="flyingChick"&&(o.sex==="poop"?vi(e,o.x,o.y,o.radius||11):Si(e,o.x,o.y,o.sex,o.sex==="male")),e.restore()}}function pd(e,t){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="center";for(let n of t.floatingTexts){let o=Math.max(0,n.life/n.maxLife);e.globalAlpha=o,e.lineWidth=5,e.strokeStyle=w.white,e.fillStyle=n.color,e.strokeText(n.text,n.x,n.y),e.fillText(n.text,n.x,n.y)}e.restore()}function yd(e,t){let n=t.repairmen&&t.repairmen.length?t.repairmen:t.repairman?[t.repairman]:[];for(let o of n)hd(e,t,o)}function hd(e,t,n){if(!!!n?.active)return;if(e.save(),ln(e,De.repairman,n.x-18,n.y-18,36,36)){n.target?.label&&oo(e,n.x,n.y-24,n.target.label,w.green),e.restore();return}e.lineWidth=3,e.fillStyle="#fff0d1",e.strokeStyle=w.ink,e.beginPath(),e.arc(n.x,n.y,17,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle="#ffd6e7",e.beginPath(),e.arc(n.x-6,n.y-2,3.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+6,n.y-2,3.2,0,Math.PI*2),e.fill();let r=!!t.cardEffects?.laborExploitation;e.fillStyle=r?w.danger:w.ink,e.beginPath(),e.arc(n.x-5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(n.x+5,n.y-5,r?2.8:2.2,0,Math.PI*2),e.fill(),e.strokeStyle=w.ink,e.lineWidth=r?3:2,e.beginPath(),e.arc(n.x,n.y+(r?0:1),r?8:7,.1*Math.PI,.9*Math.PI),e.stroke(),e.fillStyle=w.green,ee(e,n.x-9,n.y+14,18,8,!0,!0),e.strokeStyle=w.ink,e.lineWidth=3,e.beginPath(),e.moveTo(n.x-11,n.y+18),e.lineTo(n.x-20,n.y+24),e.stroke(),e.beginPath(),e.moveTo(n.x+11,n.y+18),e.lineTo(n.x+20,n.y+24),e.stroke(),e.fillStyle=w.ink,e.font="900 11px ui-monospace, monospace",e.textAlign="center",e.fillText("FIX",n.x,n.y+33),n.target?.label&&oo(e,n.x,n.y-24,n.target.label,w.green),e.restore()}function bd(e,t,n){e.save(),e.font="900 19px ui-monospace, monospace",e.textAlign="left",e.fillStyle=w.ink,e.font="900 19px ui-monospace, monospace",e.fillStyle=w.ink;let o=[];t.phase==="running"&&o.push(t.timeLeft<=0?"TIME UP: FARMS SHUT. CLEAR LINE.":"A/D: S1 \u2190/\u2192: S2"),t.phase==="build"&&o.push(`BUILD: ${t.buildTool||"SELECT"} | connect 1 EGG route to any exit`);let r=76;for(let i of o)e.strokeStyle=w.white,e.lineWidth=4,e.strokeText(i,24,r),e.fillText(i,24,r),r+=20;e.restore()}function qa({game:e,canvasPoint:t,updatePanels:n,equipmentAtPoint:o,fail:r,pointInGrid:i,rectOfFacility:a,rectsOverlap:c}){function b(x){return x?x.type==="conveyor"?`conveyor:${x.id||x.oldKey}`:x.type==="facility"?`facility:${x.id||x.ref?.id}`:x.type==="maintenanceRoom"?`maintenanceRoom:${x.id||x.ref?.id}`:`${x.type}:${x.id||x.ref?.id}`:""}function M(x){return x?x.type==="conveyor"?{type:"conveyor",id:x.oldKey}:{type:x.type,id:x.ref.id}:null}function C(x){let g=b(M(x));return(e.multiSelected||[]).some(D=>b(D)===g)}function $(x){return x?x.type==="eggFarm"?e.eggFarms.find(g=>g.id===x.id)||null:x.type==="scanner"?e.scanners.find(g=>g.id===x.id)||null:x.type==="facility"?e.facilities[x.id]||null:x.type==="maintenanceRoom"?(e.maintenanceRooms||[]).find(g=>g.id===x.id)||null:x.type==="conveyor"?e.conveyorTiles.has(x.id)?{type:"conveyor",id:x.id}:null:x.type==="powerWire"?e.powerWires?.has(x.id)?{type:"powerWire",id:x.id}:null:x.type==="footbridge"&&e.footbridges?.has(x.id)?{type:"footbridge",id:x.id}:null:null}function W(){let x=[];for(let g of e.conveyorTiles){let D=X(g),Z=B(D.col,D.row);x.push({type:"conveyor",id:g,center:Z,cell:D})}if(e.powerOverlay)for(let[g]of e.powerWires||new Map){let D=X(g);x.push({type:"powerWire",id:g,center:B(D.col,D.row),cell:D})}for(let[g]of e.footbridges||new Map){let D=X(g);x.push({type:"footbridge",id:g,center:B(D.col,D.row),cell:D})}for(let g of e.eggFarms)x.push({type:"eggFarm",id:g.id,ref:g,center:B(g.col,g.row),cell:{col:g.col,row:g.row}});for(let g of e.scanners)x.push({type:"scanner",id:g.id,ref:g,center:ge(g),cell:{col:g.col,row:g.row}});for(let g of e.maintenanceRooms||[]){let D=B(g.col,g.row);x.push({type:"maintenanceRoom",id:g.id,ref:g,center:{x:D.x+p.cell/2,y:D.y+p.cell/2},cell:{col:g.col,row:g.row}})}for(let g of Object.values(e.facilities)){let D={x:g.x+g.w/2,y:g.y+g.h/2},Z=g.entry?B(g.entry.col,g.entry.row):D;x.push({type:"facility",id:g.id,ref:g,center:D,portCenter:Z})}return x}function K(x,g){let D=Math.min(g.x1,g.x2),Z=Math.max(g.x1,g.x2),j=Math.min(g.y1,g.y2),le=Math.max(g.y1,g.y2);return x.x>=D&&x.x<=Z&&x.y>=j&&x.y<=le}function G(x){let g=[];for(let D of W())(K(D.center,x)||D.portCenter&&K(D.portCenter,x))&&g.push({type:D.type,id:D.id});return e.multiSelected=g,e.selected=g[0]||null,n(),g.length}function z(){e.multiSelected=[],e.selected=null,n()}function Q(x){let g=t(x);return e.selectionBox={x1:g.x,y1:g.y,x2:g.x,y2:g.y},e.multiSelected=[],e.selected=null,n(),!0}function ie(x){if(!e.selectionBox)return;let g=t(x);e.selectionBox.x2=g.x,e.selectionBox.y2=g.y}function J(){if(!e.selectionBox)return 0;let x=e.selectionBox,g=Math.abs(x.x2-x.x1),D=Math.abs(x.y2-x.y1);return e.selectionBox=null,g<6&&D<6?(z(),0):G(x)}function ae(x){let g=M(x);return g?(e.multiSelected||[]).length&&C(x)?[...e.multiSelected]:[g]:[]}function ye(x){let g=$(x);if(!g)return null;if(x.type==="conveyor"){let D=X(x.id);return{...x,obj:g,oldKey:x.id,currentKey:x.id,meta:e.conveyorMeta.get(x.id)||{price:Le("conveyor"),builtSession:null},col:D.col,row:D.row}}if(x.type==="powerWire"){let D=X(x.id);return{...x,obj:g,oldKey:x.id,currentKey:x.id,meta:{...e.powerWires?.get(x.id)||{}},col:D.col,row:D.row}}if(x.type==="footbridge"){let D=X(x.id),Z=e.footbridges?.get(x.id)||{},j=[];for(let[le,ce]of e.footbridges||new Map)if(Z.bridgeId&&ce.bridgeId===Z.bridgeId||le===x.id){let ve=X(le);j.push({key:le,dc:ve.col-D.col,dr:ve.row-D.row,meta:{...ce}})}return{...x,obj:g,oldKey:x.id,currentKey:x.id,meta:{...Z},cells:j,dragToken:`footbridge:${Z.bridgeId||x.id}`,col:D.col,row:D.row}}return x.type==="eggFarm"||x.type==="scanner"||x.type==="maintenanceRoom"?{...x,obj:g,col:g.col,row:g.row}:x.type==="facility"?g.gridPlaced?{...x,obj:g,gridPlaced:!0,col:g.col,row:g.row,x:g.x,y:g.y,w:g.w,h:g.h,entry:g.entry?{...g.entry}:null,side:g.side,center:{x:g.x+g.w/2,y:g.y+g.h/2}}:{...x,obj:g,gridPlaced:!1,x:g.x,y:g.y,w:g.w,h:g.h,entry:g.entry?{...g.entry}:null,side:g.side,center:{x:g.x+g.w/2,y:g.y+g.h/2}}:null}function L(x){let g=t(x),D=o(g);if(!D)return!1;let Z=ae(D),j=[],le=new Set;for(let ce of Z.map(ye).filter(Boolean)){let ve=ce.dragToken||b(ce);le.has(ve)||(le.add(ve),j.push(ce))}return j.length?(e.groupDrag={start:g,selections:Z,origins:j,historySnapshot:Xn(e),committed:!1,lastDCol:0,lastDRow:0},e.multiSelected=Z,e.selected=Z[0]||null,n(),!0):!1}function V(){!e.groupDrag||e.groupDrag.committed||(e.undoStack.push(e.groupDrag.historySnapshot),e.redoStack=[],e.groupDrag.committed=!0)}function se(x,g,D){let Z=E(x,g),j=it(e,x,g);if(j&&!D.has(`eggFarm:${j.id}`))return!0;let le=st(e,x,g);if(le&&!D.has(`scanner:${le.id}`))return!0;let ce=(e.maintenanceRooms||[]).find(Me=>xt(Me).some(Se=>Se.col===x&&Se.row===g));if(ce&&!D.has(`maintenanceRoom:${ce.id}`))return!0;let ve=bt(e,x,g);return!!(ve&&!D.has(`facility:${ve.id}`)||e.conveyorTiles.has(Z)&&!D.has(`conveyor:${Z}`))}function O(x,g,D){for(let Z of Object.values(e.facilities||{})){if(D.has(`facility:${Z.id}`))continue;let j=wt(e,Z),le=He(e,Z);if(j&&j.col===x&&j.row===g||le&&le.col===x&&le.row===g)return!0}return!1}function H(x,g,D,Z){let j=it(e,g,D);if(j&&!Z.has(`eggFarm:${j.id}`))return!0;let le=st(e,g,D);if(le&&!Z.has(`scanner:${le.id}`))return!0;let ce=(e.maintenanceRooms||[]).find(Me=>xt(Me).some(Se=>Se.col===g&&Se.row===D));if(ce&&!Z.has(`maintenanceRoom:${ce.id}`))return!0;let ve=bt(e,g,D);if(ve&&ve.id!==x.id&&!Z.has(`facility:${ve.id}`))return!0;for(let Me of Object.values(e.facilities||{})){if(Me.id===x.id||Z.has(`facility:${Me.id}`))continue;let Se=wt(e,Me),Ke=He(e,Me);if(Se&&Se.col===g&&Se.row===D||Ke&&Ke.col===g&&Ke.row===D)return!0}return!1}function oe(x,g,D,Z){let j=E(g,D);if(!i(g,D)||e.blockedCells?.has?.(j))return"Selection hits blocked ground";if(it(e,g,D)||st(e,g,D))return"Cell occupied";let le=(e.maintenanceRooms||[]).find(Me=>xt(Me).some(Se=>Se.col===g&&Se.row===D));if(le&&!Z.has(`maintenanceRoom:${le.id}`))return"Cell occupied";let ce=bt(e,g,D);if(ce&&!Z.has(`facility:${ce.id}`))return"Cell occupied";let ve=x.cells?.some(Me=>Me.key===j);return x.type==="powerWire"&&e.powerWires?.has(j)&&!Z.has(`powerWire:${j}`)?"Power wire already covers that cell":x.type==="footbridge"&&e.footbridges?.has(j)&&!Z.has(`footbridge:${j}`)&&!ve?"Footbridge already covers that cell":""}function ue(x,g,D){let Z=[];for(let j of e.groupDrag.origins){if(j.type!=="facility"||j.gridPlaced)continue;let le={x:j.center.x+x,y:j.center.y+g},{entry:ce,side:ve}=Lo(le,e);if(!i(ce.col,ce.row)||e.blockedCells?.has?.(E(ce.col,ce.row)))return!0;let Me={...j.obj,entry:{...ce},side:ve};Go(Me,ce,ve),Z.push({id:j.id,rect:a(Me)})}for(let j of Z)for(let le of Object.values(e.facilities))if(!D.has(`facility:${le.id}`)&&c(j.rect,a(le),12))return!0;for(let j=0;jE(D.col,D.row)));for(let D of["left","right"]){let Z=We(x,D),j=E(Z.col,Z.row);if(!e.conveyorTiles.has(j))continue;let le=e.conveyorMeta.get(j);if(!le)continue;let ce=fe.find(Se=>Se.name===D),ve=fe.filter(Se=>{let Ke=E(Z.col+Se.dc,Z.row+Se.dr);return e.conveyorTiles.has(Ke)&&!g.has(Ke)}),Me=ve.find(Se=>Se.name===ce?.name)||ve[0]||ce;Me&&(le.dir=Me.name,le.outDirs=[Me.name],le.branchMode="random")}}function xe(x){if(!e.groupDrag)return;let g=t(x),D=g.x-e.groupDrag.start.x,Z=g.y-e.groupDrag.start.y;if(Math.hypot(D,Z)<3)return;let j=Math.round(D/p.cell),le=Math.round(Z/p.cell),ce=new Set(e.groupDrag.selections.map(b)),ve=new Set;for(let T of e.groupDrag.origins){if(T.type==="facility"&&!T.gridPlaced)continue;let ke=T.col+j,Ae=T.row+le;if(T.type==="powerWire"||T.type==="footbridge"){let Ce=T.type==="footbridge"&&T.cells?.length?T.cells.map(Ue=>({col:ke+Ue.dc,row:Ae+Ue.dr})):[{col:ke,row:Ae}];for(let Ue of Ce){let St=oe(T,Ue.col,Ue.row,ce);if(St)return r(St);let et=`${T.type}:${E(Ue.col,Ue.row)}`;if(ve.has(et))return r("Selection overlap");ve.add(et)}continue}let ot=T.type==="scanner"?Pt({col:ke,row:Ae}):T.type==="maintenanceRoom"?xt({col:ke,row:Ae}):T.type==="facility"?gn({...T.obj,col:ke,row:Ae}):[{col:ke,row:Ae}];for(let Ce of ot){if(!i(Ce.col,Ce.row))return r("Selection outside grid");if(e.blockedCells?.has?.(E(Ce.col,Ce.row)))return r("Selection hits blocked ground");let Ue=E(Ce.col,Ce.row);if(ve.has(Ue))return r("Selection overlap");if(se(Ce.col,Ce.row,ce))return r("Cell occupied");if(T.type!=="conveyor"&&O(Ce.col,Ce.row,ce))return r("Machine port must remain open");ve.add(Ue)}if(T.type==="facility"&&T.gridPlaced){let Ce={...T.obj,col:ke,row:Ae},Ue={col:ke-1,row:Ae+Math.floor((Ce.hCells||3)/2)},St={col:ke+(Ce.wCells||3),row:Ae+Math.floor((Ce.hCells||3)/2)};for(let et of[Ue,St]){if(!i(et.col,et.row)||e.blockedCells?.has?.(E(et.col,et.row)))return r("Machine port outside usable grid");if(H(T.obj,et.col,et.row,ce))return r("Machine port is occupied")}}}if(ue(D,Z,ce))return r("Facility overlap");V();let Me=e.groupDrag.origins.filter(T=>T.type==="conveyor");for(let T of Me){let ke=T.currentKey||T.oldKey;e.conveyorTiles.delete(ke),e.conveyorMeta.delete(ke)}for(let T of Me){let ke=E(T.col+j,T.row+le);e.conveyorTiles.add(ke),e.conveyorMeta.set(ke,T.meta||{price:Le("conveyor"),builtSession:null,uses:0}),T.currentKey=ke}let Se=e.groupDrag.origins.filter(T=>T.type==="powerWire");for(let T of Se)e.powerWires.delete(T.currentKey||T.oldKey);for(let T of Se){let ke=E(T.col+j,T.row+le);e.powerWires.set(ke,T.meta||{}),T.currentKey=ke}let Ke=e.groupDrag.origins.filter(T=>T.type==="footbridge");for(let T of Ke)for(let ke of T.cells||[{key:T.currentKey||T.oldKey}])e.footbridges.delete(ke.key);for(let T of Ke){let ke=E(T.col+j,T.row+le);for(let Ae of T.cells||[{dc:0,dr:0,meta:T.meta||{}}]){let ot=E(T.col+j+(Ae.dc||0),T.row+le+(Ae.dr||0));e.footbridges.set(ot,{...Ae.meta||T.meta||{}})}T.currentKey=ke}for(let T of e.groupDrag.origins)if(T.type==="eggFarm")T.obj.col=T.col+j,T.obj.row=T.row+le;else if(T.type==="scanner")T.obj.col=T.col+j,T.obj.row=T.row+le,Ve(T.obj);else if(T.type==="maintenanceRoom")T.obj.col=T.col+j,T.obj.row=T.row+le;else if(T.type==="facility"&&T.gridPlaced)T.obj.col=T.col+j,T.obj.row=T.row+le,Cn(T.obj);else if(T.type==="facility"){let ke={x:T.center.x+D,y:T.center.y+Z},{entry:Ae,side:ot}=Lo(ke,e);Go(T.obj,Ae,ot)}e.groupDrag.selections=e.groupDrag.origins.map(T=>["conveyor","powerWire","footbridge"].includes(T.type)?{type:T.type,id:T.currentKey||T.oldKey}:{type:T.type,id:T.id}),e.multiSelected=[...e.groupDrag.selections],e.selected=e.multiSelected[0]||null,Ee(e),e.groupDrag.origins.some(T=>T.type!=="powerWire")&&(e.walkabilityVersion=(e.walkabilityVersion||0)+1),e.groupDrag.origins.some(T=>T.type==="powerWire"||T.type!=="conveyor"&&T.type!=="footbridge")&&Ye(e),n()}function Ge(){e.groupDrag&&(Ee(e),e.groupDrag=null,n())}return{selectionFromHit:M,startSelectionBox:Q,updateSelectionBox:ie,finishSelectionBox:J,startGroupDrag:L,updateGroupDrag:xe,finishGroupDrag:Ge}}function Kt(e){return Vt(e)*(_.facilities.boostConveyor.speedMultiplier||2)/Math.max(1,_.conveyor.minimumItemSpacingPx||25)}function io(e,t,n){let o=Math.max(_.farmQuality.safeMinIntervalSeconds,Number(n)||1),r=(t.zundaBoostTime||0)>0?_.farmQuality.zundaIntervalMultiplier:1;return 1/Math.max(_.farmQuality.safeMinIntervalSeconds,o*r)}function so(e,t){let n=_.farmQuality,o=Math.max(1e-4,t),r=Math.max(0,e/o-1);return Math.max(n.minMultiplier,Math.min(n.maxMultiplier,1+n.overflowCoefficient*Math.pow(r,n.overflowExponent)))}function za(e,t){return 1/Math.max(1e-4,Math.min(e,t))}function Ha(e){return e>=1.75?"Luxury":e>=1.35?"Premium":e>=1.15?"Select":"Standard"}function Ya(e,t){let n=t.zundaBoostTime||0;t.zundaBoostTime=Math.min(_.farmQuality.zundaMaxSeconds,n+_.farmQuality.zundaSeconds);let o=Math.max(0,t.zundaBoostTime-n);e.stats.zundaConsumed=(e.stats.zundaConsumed||0)+1,e.stats.zundaBoostSeconds=(e.stats.zundaBoostSeconds||0)+o,e.totals.zundaConsumed=(e.totals.zundaConsumed||0)+1,e.totals.zundaBoostSeconds=(e.totals.zundaBoostSeconds||0)+o,e.stats.zundaBoostSecondsByFarm=e.stats.zundaBoostSecondsByFarm||{},e.stats.zundaBoostSecondsByFarm[t.id]=(e.stats.zundaBoostSecondsByFarm[t.id]||0)+o}function Qa({game:e,ui:t,canvas:n,canvasPoint:o,onUpdatePanels:r}){function i(){r&&r()}let a=null,c=!1,b=null,M=!1,C=["random","up","right","down","left"],$={random:"RND",up:"\u25B2",right:"\u25B6",down:"\u25BC",left:"\u25C0"},W={w:40,h:40,y:0};function K(){return Co(e)}function G(){e.gridCols=p.cols,e.gridRows=p.rows,e.gridOwnedCells=ji(e)}function z(s){if(s){p.y-=s*p.cell,p.rows+=s,e.gridChunkOriginY=(e.gridChunkOriginY||0)-Math.floor(s/10),e.ownedCells=go(e.ownedCells,s),e.blockedCells=go(e.blockedCells,s),e.conveyorTiles=go(e.conveyorTiles,s),e.conveyorMeta=xo(e.conveyorMeta,s),e.powerWires=xo(e.powerWires||new Map,s),e.footbridges=xo(e.footbridges||new Map,s);for(let l of e.eggFarms||[])l.row+=s;for(let l of e.scanners||[])l.row+=s;for(let l of Object.values(e.facilities||{}))l.gridPlaced?(l.row+=s,Cn(l)):l.entry&&(l.entry.row+=s)}}function Q(s){if(s){p.x-=s*p.cell,p.cols+=s,e.gridChunkOriginX=(e.gridChunkOriginX||0)-Math.floor(s/10),e.ownedCells=To(e.ownedCells,s),e.blockedCells=To(e.blockedCells,s),e.conveyorTiles=To(e.conveyorTiles,s),e.conveyorMeta=Eo(e.conveyorMeta,s),e.powerWires=Eo(e.powerWires||new Map,s),e.footbridges=Eo(e.footbridges||new Map,s);for(let l of e.eggFarms||[])l.col+=s;for(let l of e.scanners||[])l.col+=s;for(let l of e.maintenanceRooms||[])l.col+=s;for(let l of Object.values(e.facilities||{}))l.gridPlaced?(l.col+=s,Cn(l)):l.entry&&(l.entry.col+=s)}}function ie(s){e.ownedCells=e.ownedCells||new Set;for(let l of es(s))e.ownedCells.add(E(l.col,l.row))}function J(s){return e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending?null:jt(e).map(l=>L(l)).find(l=>l&&Zi(l,s))||null}function ae(s){let l=Et(s);return{x:l.x,y:l.y,w:l.w,h:l.h}}function ye(s){let l=ae(s);return Object.values(e.facilities||{}).some(y=>{let h=y?.baseId||y?.id;return!vo.includes(h)||y.gridPlaced?!1:ue(l,oe(y),0)})}function L(s){if(!s)return null;let l=ye(s);return{...s,disabled:l,disabledReason:l?"Move edge facilities before buying this lot.":""}}function V(s="right"){if(s&&typeof s=="object"&&Number.isFinite(s.chunkX)&&Number.isFinite(s.chunkY))return s;let l=["left","right","up","down"].includes(s)?s:"right";return Ji(e,l)}function se(s="right"){let l=V(s);if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return{ok:!1,reason:"Cannot expand now."};if(!l)return{ok:!1,reason:"Invalid expansion lot."};if(ye(l)){let $e="Move edge facilities before buying this lot.";return T($e),{ok:!1,reason:$e}}let y=l.direction||"right",h=K();if(e.cashp.cols&&(p.cols=F.colStart+F.cols),F.rowStart+F.rows>p.rows&&(p.rows=F.rowStart+F.rows),ie(F),ts(e,F.chunkX,F.chunkY),e.gridExpansionPurchases=(e.gridExpansionPurchases||0)+1,e.gridExpansionPurchasesByDirection[y]=(e.gridExpansionPurchasesByDirection[y]||0)+1,G();let q=Ki(e.gridExpansionPurchases,{base:_.map.blockedRatio??0,increment:_.map.blockedExpansionIncrement??.0075,max:_.map.blockedRatioMax??.12}),be=zi({seed:`${e.runSeed}:grid-expansion:${F.chunkX},${F.chunkY}:${e.gridExpansionPurchases}`,colStart:F.colStart,colEnd:F.colStart+F.cols,rowStart:F.rowStart,rowEnd:F.rowStart+F.rows,targetRatio:q});for(let $e of be)e.blockedCells.add($e);Ee(e);let Pe=F.cols*F.rows,we=Et(F);return Y(e,we.x+we.w/2,we.y+we.h/2,`${y.toUpperCase()} +${Pe} CELLS -${R(h)}`,w.green),i(),{ok:!0,direction:y,cost:h,addedCells:Pe,blocked:be.size,blockedRatio:q,chunkX:F.chunkX,chunkY:F.chunkY}}function O(s,l){return s>=0&&s=0&&l!l.has(h.id)&&ue(y,oe(h),12))}function xe(s,l,y=null){if(!O(s,l))return!1;if(H(s,l))return!0;let h=E(s,l),m=it(e,s,l);if(m&&!(y?.type==="eggFarm"&&y.ref?.id===m.id))return!0;let P=st(e,s,l);if(P&&!(y?.type==="scanner"&&y.ref?.id===P.id))return!0;let F=x(e,s,l);if(F&&!(y?.type==="maintenanceRoom"&&y.ref?.id===F.id))return!0;let q=bt(e,s,l);return!!(q&&!(y?.type==="facility"&&y.ref?.id===q.id)||e.conveyorTiles.has(h)&&!(y?.type==="conveyor"&&y.oldKey===h))}function Ge(s,l,y=null){return Object.values(e.facilities||{}).find(h=>{if(y?.type==="facility"&&y.ref?.id===h.id)return!1;let m=wt(e,h),P=He(e,h);return m&&m.col===s&&m.row===l||P&&P.col===s&&P.row===l})||null}function x(s,l,y){return(s.maintenanceRooms||[]).find(h=>xt(h).some(m=>m.col===l&&m.row===y))||null}function g(s,l,y=null){let h={col:s,row:l};for(let m of xt(h)){if(!O(m.col,m.row)||H(m.col,m.row))return!0;let P=E(m.col,m.row);if(it(e,m.col,m.row)||st(e,m.col,m.row))return!0;let be=x(e,m.col,m.row);if(be&&!(y?.type==="maintenanceRoom"&&y.ref?.id===be.id)||bt(e,m.col,m.row)||Ge(m.col,m.row,y)||e.conveyorTiles.has(P))return!0}return!1}function D(s,l,y=null){let h={col:s,row:l};for(let m of Pt(h)){if(!O(m.col,m.row)||H(m.col,m.row))return!0;let P=E(m.col,m.row);if(it(e,m.col,m.row))return!0;let q=st(e,m.col,m.row);if(q&&!(y?.type==="scanner"&&y.ref?.id===q.id)||bt(e,m.col,m.row)||Ge(m.col,m.row,y)||e.conveyorTiles.has(P))return!0}return!1}function Z(s,l,y,h=null){let m=_.facilities[s]||{},P={baseId:s,id:s,gridPlaced:!0,col:l,row:y,wCells:m.footprint?.cols||(s==="sausageMaker"?3:1),hCells:m.footprint?.rows||(s==="sausageMaker"?3:1)};for(let F of gn(P))if(!O(F.col,F.row)||H(F.col,F.row)||xe(F.col,F.row,h)||Ge(F.col,F.row,h))return!0;if(s==="sausageMaker"||s==="biomassGenerator"||s==="coalGenerator"){let F={col:l-1,row:y+1},q={col:l+(P.wCells||1),row:y+1},be=[F,{col:l+1,row:y-1},{col:l+1,row:y+(P.hCells||3)}],Pe=s==="sausageMaker"?[F,q]:s==="biomassGenerator"?be:[F];for(let we of Pe){if(!O(we.col,we.row)||H(we.col,we.row))return!0;let $e=bt(e,we.col,we.row);if($e&&$e.id!==h?.ref?.id||it(e,we.col,we.row)||st(e,we.col,we.row)||x(e,we.col,we.row)||Ge(we.col,we.row,h))return!0}}return!1}function j(){return e.selected?e.selected.type==="eggFarm"?e.eggFarms.find(s=>s.id===e.selected.id)||null:e.selected.type==="scanner"?e.scanners.find(s=>s.id===e.selected.id)||null:e.selected.type==="conveyor"?e.conveyorTiles.has(e.selected.id)?{type:"conveyor",id:e.selected.id}:null:e.selected.type==="powerWire"?e.powerWires?.has(e.selected.id)?{type:"powerWire",id:e.selected.id}:null:e.selected.type==="footbridge"?e.footbridges?.has(e.selected.id)?{type:"footbridge",id:e.selected.id}:null:e.selected.type==="facility"?e.facilities[e.selected.id]||null:e.selected.type==="maintenanceRoom"&&(e.maintenanceRooms||[]).find(s=>s.id===e.selected.id)||null:null}function le(s){return s?s.type==="eggFarm"?`${ht("eggFarm")} #${s.id}`:s.type==="scanner"?`${s.kind==="auto"?ht("autoScanner"):ht("manualScanner")} #${s.id}`:s.type==="conveyor"?e.conveyorMeta.get(s.id)?.kind==="boostConveyor"?ht("boostConveyor"):ht("conveyor"):s.type==="powerWire"?e.powerWires?.get(s.id)?.kind==="insulatedPowerWire"?ht("insulatedPowerWire"):ht("powerWire"):s.type==="footbridge"?ht("footbridge"):s.type==="facility"?s.name:s.type==="maintenanceRoom"?`${ht("maintenanceRoom")} #${s.id}`:"Equipment":"Equipment"}function ce(s){return s?.type==="conveyor"?e.conveyorMeta?.get(s.oldKey||s.ref?.id)?.price||Oo(s):s?.type==="powerWire"?e.powerWires?.get(s.oldKey||s.ref?.id)?.price||0:s?.type==="footbridge"?e.footbridges?.get(s.oldKey||s.ref?.id)?.price||_.facilities.footbridge.price:Oo(s)}function ve(){return!!e.cardEffects?.usedMachineActive}function Me(){return ve()?{usedMachine:!0,noRefund:!0,durabilityBaseMultiplier:.6}:{usedMachine:!1,noRefund:!1,durabilityBaseMultiplier:1}}function Se(s){let l=Me();return Object.assign(s,l),s}function Ke(s){let l=s?.ref||s||{};if(l.unsellable||(l.baseId||l.id)==="starterGenerator")return"Starter Generator cannot be sold.";if(s?.type==="eggFarm"||l.type==="eggFarm")return e.eggFarms.length<=1?"Cannot sell the last EGG FARM.":"";if((s?.type==="facility"||l.type==="facility")&&["mixer","trash","truck"].includes(l.baseId||l.id)){let y=l.baseId||l.id;if(Object.values(e.facilities).filter(m=>(m.baseId||m.id)===y).length<=1)return`Cannot sell the last ${l.shortName||l.name||l.id}.`}return""}function T(s){t.buildStatus.textContent=s,Y(e,n.width/2-e.view.x,86-e.view.y,s.toUpperCase(),w.danger)}function ke(s){if(!s)return null;let l=E(s.col,s.row);return e.conveyorMeta.get(l)||null}function Ae(s){return s?(Array.isArray(s.outDirs)||(s.outDirs=[]),s.outDirs=[...new Set(s.outDirs.filter(l=>["right","left","down","up"].includes(l)))],C.includes(s.branchMode)||(s.branchMode="random"),s.kind||(s.kind="conveyor"),s.speedMultiplier||(s.speedMultiplier=s.kind==="boostConveyor"?2:1),s.outDirs):[]}function ot(s){return s?fe.filter(l=>e.conveyorTiles.has(E(s.col+l.dc,s.row+l.dr))).map(l=>l.name):[]}function Ce(s){return ot(s).length>=3}function Ue(s,l){let y=fe.find(q=>q.name===l);if(!s||!y)return!1;let h=E(s.col+y.dc,s.row+y.dr),m=e.conveyorMeta.get(h);if(!m)return!1;let P=y.opposite;return[...new Set([...Array.isArray(m.outDirs)?m.outDirs:[],m.dir].filter(Boolean))].includes(P)}function St(s,l){let y=ot(s);if(y.length!==1)return null;let h=y[0];return l.includes(h)&&Ue(s,h)?h:null}function et(s){if(!e.conveyorTiles.has(s))return[];let l=X(s),y=e.conveyorMeta.get(s),h=Ae(y),m=ot(l),P=[...new Set([...h,y?.dir].filter(Boolean))].filter(we=>m.includes(we)),F=m,q=P.length?P:F,be=St(l,q),Pe=P.length?P.filter(we=>we!==be):F.filter(we=>we!==be);return y&&(y.outDirs=h.filter(we=>m.includes(we)),y.dir&&!m.includes(y.dir)&&(y.dir=y.outDirs[0]||null),y.branchMode!=="random"&&!m.includes(y.branchMode)&&(y.branchMode="random")),Pe}function Ln(s){if(!e.conveyorTiles.has(s))return[];let l=X(s),y=ot(l);return Ce(l)?y:et(s)}function Ht(s){let l=X(s),y=Ln(s);if(y.length<3)return[];let h=e.conveyorMeta.get(s)||{},m=new Set(y.filter(q=>Ue(l,q))),P=y.filter(q=>!m.has(q));if(m.size)return P.length>=2?P:[];let F=[...new Set([...Array.isArray(h.outDirs)?h.outDirs:[],h.dir].filter(Boolean))].filter(q=>y.includes(q));return F.length>=2?F:y}function lo(s,l){let y=Tt(s,l);if(!y)return!1;let h=E(s.col,s.row),m=E(l.col,l.row),P=e.conveyorMeta.get(h),F=e.conveyorMeta.get(m);if(!P||!F)return!1;let q=Ae(P),be=!q.includes(y)||P.dir!==y||!F.dir;return q.includes(y)||q.push(y),P.dir=y,F.dir||(F.dir=y),be}function co(s){if(pt(s).length===0)return Nn(s);let l=ir(s);return l.length<2?Nn(s):(Oe(e),sr(l),Ee(e),i(),!0)}function Nn(s){if(!s)return!1;let l=E(s.col,s.row),y=e.conveyorMeta.get(l);if(!y||Ce(s))return!1;let h=St(s,fe.map(q=>q.name)),m=fe.map(q=>q.name).filter(q=>q!==h),P=y.dir&&m.includes(y.dir)?y.dir:null,F=m[(Math.max(-1,m.indexOf(P))+1)%m.length];return Oe(e),y.dir=F,y.outDirs=[F],y.branchMode="random",Ee(e),i(),!0}function pt(s){return s?fe.map(l=>({col:s.col+l.dc,row:s.row+l.dr})).filter(l=>e.conveyorTiles.has(E(l.col,l.row))):[]}function ir(s){if(!s||!e.conveyorTiles.has(E(s.col,s.row))||Ce(s))return[];let l=pt(s);if(!l.length||l.length>2)return[];let y=P=>{let F=[],q=new Set([E(s.col,s.row)]),be=s,Pe=P,we=0;for(;Pe&&we<200;){we+=1;let $e=E(Pe.col,Pe.row);if(q.has($e)||(q.add($e),F.push(Pe),Ce(Pe)))break;let Ri=pt(Pe).filter(Ii=>!(Ii.col===be.col&&Ii.row===be.row));if(Ri.length!==1)break;be=Pe,Pe=Ri[0]}return F},h=l[0]?y(l[0]).reverse():[],m=l[1]?y(l[1]):[];return[...h,s,...m]}function uo(s,l){return!!s&&[...new Set([...Array.isArray(s.outDirs)?s.outDirs:[],s.dir].filter(Boolean))].includes(l)}function sr(s){let l=0,y=0;for(let m=0;my?[...s].reverse():s;for(let m=0;m=2){let m=h[h.length-2],P=h[h.length-1];if(!Ce(P)){let F=e.conveyorMeta.get(E(P.col,P.row)),q=Tt(m,P);F&&q&&(F.dir=q,F.outDirs=[q],F.branchMode="random")}}}function fo(){return _.facilities[e.buildTool==="boostConveyor"?"boostConveyor":"conveyor"]}function Gn(s,l=null){if(!s)return{ok:!1,reason:pe.fail.outOfGrid};let{col:y,row:h}=s,m=E(y,h);if(e.conveyorTiles.has(m))return{ok:!1,exists:!0};if(H(y,h))return{ok:!1,reason:"Cannot build on blocked ground."};if(xe(y,h))return{ok:!1,reason:pe.fail.cellOccupied};let P=fo(),F=P.id||"conveyor",q=Le(F,e);if(e.cash=Math.abs(h)?{col:s.col+Math.sign(y),row:s.row}:{col:s.col,row:s.row+Math.sign(h)}}function lr(s){c=!1,b=s?{col:s.col,row:s.row}:null,M=!1,a=null,Yt(s)}function cr(s){if(!s)return;if(!a)return Yt(s);let l=a,y=0;for(;(l.col!==s.col||l.row!==s.row)&&y<64;){let h=ar(l,s);if(Yt(h),l=a||h,y+=1,!a)break}}function Qt(){!M&&b&&e.conveyorTiles.has(E(b.col,b.row))&&co(b),b=null,M=!1,a=null,c=!1}function Xt(s,l){return!O(s,l)||H(s,l)||it(e,s,l)||st(e,s,l)||x(e,s,l)||bt(e,s,l)}function dn(s,l){if(!s)return{ok:!1,reason:pe.fail.outOfGrid};if(Xt(s.col,s.row))return{ok:!1,reason:"Power wire cannot cross equipment or blocked ground."};let y=E(s.col,s.row),h=_.power.wires[l]?.price||Le(l,e),m=e.powerWires?.get(y),P=m&&_.power.wires[m.kind]?.price||0,F=h-P;return F>0&&e.cash0&&Ct(e,F),F<0&&Qr(e,-F),e.powerWires=e.powerWires||new Map,e.powerWires.set(y,{kind:l,price:h,builtSession:e.buildSession}),Ye(e),e.selected={type:"powerWire",id:y},i(),{ok:!0})}function ur(s){if(!s)return T(pe.fail.outOfGrid);let l=(e.footbridgeOrientation||"vertical")!=="horizontal",y=l?[s.row-1,s.row,s.row+1].map(P=>({col:s.col,row:P})):[s.col-1,s.col,s.col+1].map(P=>({col:P,row:s.row}));if(y.some(P=>Xt(P.col,P.row)))return T("Footbridge cannot cross equipment or blocked ground.");if(y.some(P=>e.footbridges?.has(E(P.col,P.row))))return T("Footbridge already covers that cell.");let h=Le("footbridge",e);if(e.cashy!=="starterGenerator")].includes(e.buildTool))return po(l);if(vo.includes(e.buildTool))return v(s,e.buildTool)}function dr(s,l){let y=Le("eggFarm",e);if(e.cashP.kind==="manual").length>=8)return T("Manual Scanner limit reached (8 max).");let h=y==="auto"?Le("autoScanner",e):Le("manualScanner",e);if(e.cashm.id!==l.ref.id),ct(e,h.x,h.y),Ee(e),e.walkabilityVersion=(e.walkabilityVersion||0)+1}else if(l.type==="scanner"){let h=ge(l.ref);k(l,h.x,h.y),e.scanners=e.scanners.filter(m=>m.id!==l.ref.id),ct(e,h.x,h.y),Ee(e),Ye(e),e.walkabilityVersion=(e.walkabilityVersion||0)+1}else if(l.type==="facility"){let h=l.ref;k(l,h.x+h.w/2,h.y+h.h/2),delete e.facilities[h.id],ct(e,h.x+h.w/2,h.y+h.h/2),Ee(e),Ye(e),e.walkabilityVersion=(e.walkabilityVersion||0)+1}else if(l.type==="maintenanceRoom"){let h=l.ref,m=u(h);k(l,m.x,m.y),e.maintenanceRooms=(e.maintenanceRooms||[]).filter(P=>P.id!==h.id),ct(e,m.x,m.y),Ye(e),e.walkabilityVersion=(e.walkabilityVersion||0)+1}e.selected=null,e.multiSelected=[],i()}function I(s){let l=Object.values(e.facilities).find(q=>{if(s.x>=q.x&&s.x<=q.x+q.w&&s.y>=q.y&&s.y<=q.y+q.h)return!0;if(!q.entry)return!1;let Pe=B(q.entry.col,q.entry.row);return Math.abs(s.x-Pe.x)<=p.cell*.46&&Math.abs(s.y-Pe.y)<=p.cell*.46});if(l)return{type:"facility",ref:l};let y=rt(s.x,s.y);if(!y)return null;let h=it(e,y.col,y.row);if(h)return{type:"eggFarm",ref:h};let m=st(e,y.col,y.row);if(m)return{type:"scanner",ref:m};let P=x(e,y.col,y.row);if(P)return{type:"maintenanceRoom",ref:P};let F=E(y.col,y.row);return e.footbridges?.has(F)?{type:"footbridge",oldKey:F,ref:{type:"footbridge",id:F}}:e.powerOverlay&&e.powerWires?.has(F)?{type:"powerWire",oldKey:F,ref:{type:"powerWire",id:F}}:e.conveyorTiles.has(F)?{type:"conveyor",oldKey:F,ref:{type:"conveyor",id:F}}:null}let A=qa({game:e,canvasPoint:o,updatePanels:i,equipmentAtPoint:I,fail:T,pointInGrid:O,rectOfFacility:oe,rectsOverlap:ue});function U(s){return null}function he(){let s=j();if(s)if(s.type==="conveyor")S(B(...Object.values(X(s.id))));else if(s.type==="powerWire"){let l=X(s.id),y=e.powerWires?.get(s.id);if(!y)return;Oe(e);let h=B(l.col,l.row);k({type:"powerWire",oldKey:s.id,ref:{id:s.id,price:y.price||0,builtSession:y.builtSession}},h.x,h.y),e.powerWires.delete(s.id),Ye(e),ct(e,h.x,h.y),e.selected=null,e.multiSelected=[],i()}else if(s.type==="footbridge"){let l=X(s.id);S(B(l.col,l.row))}else s.type==="eggFarm"?S(B(s.col,s.row)):s.type==="scanner"?S(ge(s)):s.type==="facility"?S({x:s.x+s.w/2,y:s.y+s.h/2}):s.type==="maintenanceRoom"&&S(u(s))}function de(s,l,y="primary-button"){let h=document.createElement("button");return h.type="button",h.className=y,h.textContent=s,h.addEventListener("click",l),h}function Xe(){e.cardTargetPick?.mode==="autoScannerMenu"&&(e.cardTargetPick=null),t.modal.classList.remove("visible","equipment-popover"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function _n(s){t.modalTitle.textContent="Auto Scanner",e.cardTargetPick={pending:!0,mode:"autoScannerMenu",cardId:null,targetKeys:[`scanner:${s.id}`],remaining:1},t.modalBody.innerHTML=`

Left / right output routing for this AUTO scanner.

Current: ${s.role===0?"Male left / others right":"Poop left / others right"}

-

Cooldown: ${St(s).toFixed(1)}s.

-
`,t.modalActions.innerHTML="";let l=ze("Male Left / Others Right",()=>{_e(e),s.role=0,_t(),i()},s.role===0?"facility-action warn":"facility-action"),y=ze("Poop Left / Others Right",()=>{_e(e),s.role=1,_t(),i()},s.role===1?"facility-action warn":"facility-action");t.modalActions.append(l,y,ze("Close",_t,"facility-action")),Ho(s),t.modal.classList.add("visible","equipment-popover"),i()}function Jr(s){return s?.label||s?.key||"?"}function $a(s){let l=s.key===" "?"Space":s.key.length===1?s.key.toUpperCase():s.key.replace(/^Arrow/,"");return{key:s.key.toLowerCase(),code:s.code,label:l}}function Fa(s,l,y){for(let m of e.scanners.filter(v=>v.kind==="manual"))for(let v of["left","right"]){if(m.id===s.id&&v===l)continue;let R=m.keys?.[v];if(R&&(R.code===y.code||R.key===y.key))return!0}return!1}function En(s,l=""){if(!s||s.kind!=="manual")return;t.modalTitle.textContent=`Manual Scanner #${s.id}`;let y=Jr(s.keys?.left),m=Jr(s.keys?.right),v=Da(s);t.modalBody.innerHTML=` +

Cooldown: ${Bt(s).toFixed(1)}s.

+ `,t.modalActions.innerHTML="";let l=de("Male Left / Others Right",()=>{Oe(e),s.role=0,Xe(),i()},s.role===0?"facility-action warn":"facility-action"),y=de("Poop Left / Others Right",()=>{Oe(e),s.role=1,Xe(),i()},s.role===1?"facility-action warn":"facility-action");t.modalActions.append(l,y,de("Close",Xe,"facility-action")),ho(s),t.modal.classList.add("visible","equipment-popover"),i()}function yo(s){return s?.label||s?.key||"?"}function pr(s){let l=s.key===" "?"Space":s.key.length===1?s.key.toUpperCase():s.key.replace(/^Arrow/,"");return{key:s.key.toLowerCase(),code:s.code,label:l}}function wl(s,l,y){for(let h of e.scanners.filter(m=>m.kind==="manual"))for(let m of["left","right"]){if(h.id===s.id&&m===l)continue;let P=h.keys?.[m];if(P&&(P.code===y.code||P.key===y.key))return!0}return!1}function Wn(s,l=""){if(!s||s.kind!=="manual")return;t.modalTitle.textContent=`Manual Scanner #${s.id}`;let y=yo(s.keys?.left),h=yo(s.keys?.right),m=ml(s);t.modalBody.innerHTML=`

Left route key: ${y}

-

Right route key: ${m}

+

Right route key: ${h}

${l?`

${l}

`:""} - ${v?`

${v}

`:""} -
`,t.modalActions.innerHTML="",t.modalActions.appendChild(ze("Set Left Key",()=>Zr(s,"left"),"facility-action warn")),t.modalActions.appendChild(ze("Set Right Key",()=>Zr(s,"right"),"facility-action warn")),t.modalActions.appendChild(ze("Close",_t,"facility-action")),Ho(s),t.modal.classList.add("visible","equipment-popover")}function Da(s){let l=[{side:"left",binding:s.keys?.left},{side:"right",binding:s.keys?.right}];if(l[0].binding&&l[1].binding&&(l[0].binding.code===l[1].binding.code||l[0].binding.key===l[1].binding.key))return"Left and right keys conflict.";for(let y of l)if(y.binding)for(let m of e.scanners.filter(v=>v.kind==="manual"&&v.id!==s.id)){if(m.keys?.left&&(m.keys.left.code===y.binding.code||m.keys.left.key===y.binding.key))return`Key conflicts with Manual Scanner #${m.id} left.`;if(m.keys?.right&&(m.keys.right.code===y.binding.code||m.keys.right.key===y.binding.key))return`Key conflicts with Manual Scanner #${m.id} right.`}return""}function Zr(s,l){t.modalBody.innerHTML=`

Press a key for ${l.toUpperCase()} route.

Esc cancels.

`,t.modalActions.innerHTML="";let y=m=>{if(m.preventDefault(),m.stopPropagation(),window.removeEventListener("keydown",y,!0),m.key==="Escape")return En(s);let v=$a(m),R=Fa(s,l,v);_e(e),s.keys=s.keys||{left:null,right:null},s.keys[l]=v,i(),En(s,R?`${v.label} assigned, but another scanner already uses it.`:`${l.toUpperCase()} set to ${v.label}.`)};window.addEventListener("keydown",y,!0)}function Ba(){let s=se();if(!(!s||s.type!=="scanner"))return s.kind==="auto"?Tn(s):En(s)}function Oa(s){if(!s)return{x:80,y:80};if(s.type==="conveyor"){let l=re(s.id);return $(l.col,l.row)}return s.type==="eggFarm"?$(s.col,s.row):s.type==="scanner"?ge(s):s.type==="facility"?{x:s.x+s.w/2,y:s.y+10}:{x:80,y:80}}function Ho(s){let l=n.getBoundingClientRect(),y=Oa(s),m=e.view?.scale||1,v=l.left+(y.x*m+(e.view?.x||0))/n.width*l.width+18,R=l.top+(y.y*m+(e.view?.y||0))/n.height*l.height-12,N=Math.max(12,window.innerWidth-274),_=Math.max(12,window.innerHeight-220);t.modal.style.setProperty("--popover-x",`${Math.max(12,Math.min(N,v))}px`),t.modal.style.setProperty("--popover-y",`${Math.max(12,Math.min(_,R))}px`)}function ei(){let s=se();if(!s)return;let l=oi(s);if(t.modalTitle.textContent=Se(s),t.modalBody.innerHTML=` -
${l.map(v=>`

${v}

`).join("")}
- ${["mixer","truck"].includes(s.baseId||s.id)?'

Income/Fine = ceil(base x 1.10^upgrades)

':""}`,t.modalActions.innerHTML="",s.type==="scanner"&&s.kind==="auto"&&t.modalActions.appendChild(ze("Auto Menu",()=>Tn(s),"facility-action warn")),s.type==="scanner"&&s.kind==="manual"&&t.modalActions.appendChild(ze("Set Keys",()=>En(s),"facility-action warn")),s.type==="conveyor"&&Ko(s.id)&&Lt(s.id).length>=2){let v=e.conveyorMeta.get(s.id)?.branchMode||"random";t.modalActions.appendChild(ze(`Branch: ${ti(v)}`,()=>{qo(s.id),e.selected={type:"conveyor",id:s.id},ei()},"facility-action warn branch-action"))}let y=s.type==="conveyor"?{type:"conveyor",oldKey:s.id,ref:s}:{type:s.type,ref:s},m=Be(y);if(m){let v=ze(m,()=>{},"facility-action danger disabled");v.disabled=!0,t.modalActions.appendChild(v)}else{let v=$t(y,e),R=v.sameBuild?`Remove / Refund ${x(v.amount)}`:`Sell ${x(v.amount)}`;t.modalActions.appendChild(ze(R,()=>{en(),_t()},"facility-action danger"))}Ho(s),t.modal.classList.add("visible","equipment-popover")}function La(s){e.phase==="build"&&(Nt(),e.buildTool=e.buildTool===s?null:s,e.selected=null,e.multiSelected=[],e.selectionBox=null,i())}function Na(){let s=[];for(let[l,y]of Object.entries(e.facilities))if(s.push({id:`facility:${l}`,price:be({type:"facility",ref:y}),x:y.x,y:y.y,w:y.w,h:y.h}),y.entry){let m=$(y.entry.col,y.entry.row);s.push({id:`facilityPort:${l}`,price:be({type:"facility",ref:y}),x:m.x-18,y:m.y-18,w:36,h:36})}for(let l of e.maintenanceRooms||[]){let y=w(l);s.push({id:`maintenanceRoom:${l.id}`,price:be({type:"maintenanceRoom",ref:l}),x:y.x-f.cell,y:y.y-f.cell,w:f.cell*2,h:f.cell*2})}for(let l of e.eggFarms){let y=$(l.col,l.row);s.push({id:`eggFarm:${l.id}`,price:be({type:"eggFarm",ref:l}),x:y.x-24,y:y.y-24,w:48,h:48})}for(let l of e.scanners){let y=ge(l);s.push({id:`scanner:${l.id}`,price:be({type:"scanner",ref:l}),x:y.x-50,y:y.y-73,w:100,h:146})}for(let l of e.conveyorTiles){let y=re(l),m=$(y.col,y.row),v=e.conveyorMeta.get(l)||{};s.push({id:`conveyor:${l}`,price:v.price||He(v.kind==="boostConveyor"?"boostConveyor":"conveyor",e),x:m.x-22,y:m.y-22,w:44,h:44})}return s}function ti(s){return P[s]||P.random}function Vu(s){return Yn(s)}function Ko(s){return e.conveyorTiles.has(s)?Le(re(s)):!1}function ni(s){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return null;for(let l of e.conveyorTiles){if(!Ko(l)||Lt(l).length<2)continue;let y=re(l),m=$(y.col,y.row),v=m.x-L.w/2,R=m.y+L.y-L.h/2;if(s.x>=v&&s.x<=v+L.w&&s.y>=R&&s.y<=R+L.h)return l}return null}function _a(s){let l=ni(s);return l?qo(l):!1}function qo(s){let l=e.conveyorMeta.get(s);if(!l)return!1;let y=Lt(s);if(y.length<2)return!1;_e(e);let m=C.includes(l.branchMode)?l.branchMode:"random",v=["random",...fe.map(R=>R.name).filter(R=>y.includes(R))];return l.branchMode=v[(Math.max(0,v.indexOf(m))+1)%v.length],Me(e),e.selected=null,e.multiSelected=[],i(),!0}function oi(s){Re(e);let l=[],y=s?.type==="facility"?s.baseId||s.id:"";if(s.type==="eggFarm"){let[m,v]=$n(s);l.push(`Price: ${x(be(s))}`);{let R=Be({type:s.type,ref:s});l.push(R?`Sale: blocked (${R})`:`Sale value: ${x($t({type:s.type,ref:s},e).amount)}`)}l.push(`Level: ${s.level}/4`),l.push(`Random interval: ${m.toFixed(2)}-${v.toFixed(2)}s`),l.push(`Durability: ${Nn(s)}% | Spawn delay x${go(s).toFixed(2)}`)}else if(s.type==="scanner")l.push(`Price: ${x(be(s))}`),l.push(`Sale value: ${x($t({type:s.type,ref:s},e).amount)}`),l.push(`Type: ${s.kind.toUpperCase()} / Standard`),s.kind==="auto"&&l.push(`Role: ${s.role===0?"Male left / Others right":"Poop left / Others right"}`),l.push(`Queue: ${s.queue.length}`),s.kind==="auto"&&l.push(`Cooldown: ${s.cooldown.toFixed(1)}s / ${St(s,e).toFixed(1)}s`),s.kind==="auto"&&l.push(`Durability: ${Nn(s)}% | Delay x${ko(s).toFixed(2)}`),s.kind==="manual"&&l.push("Durability: none | Always normal");else if(s.type==="conveyor"){let m=e.conveyorMeta.get(s.id),v=e.componentLookup?.get(s.id),R=v?e.congestion.get(v):null;l.push(`Price: ${x(be({type:"conveyor",oldKey:s.id,ref:s}))}`),l.push(`Cell: ${s.id}`),l.push(`Type: ${m?.kind==="boostConveyor"?"BOOST BELT":"Normal Belt"} | Speed x${Number(m?.speedMultiplier||1).toFixed(1)}`),l.push(`Congestion: ${R?Math.floor(R.ratio*100):0}%`),l.push(`Durability: ${Nn({meta:m})}% | Speed x${So({meta:m}).toFixed(2)}`),Ko(s.id)?Lt(s.id).length>=2?(l.push(`Branch mode: ${ti(m?.branchMode||"random")}`),l.push("Click the Branch button or the on-belt triangle to cycle RANDOM / fixed exit.")):l.push("Branch mode: unavailable \u2014 fewer than two outgoing conveyors."):l.push("Branch mode: needs 3+ conveyor connections."),l.push(`Sale value: ${x($t({type:"conveyor",oldKey:s.id,ref:s},e).amount)}`)}else if(s.type==="maintenanceRoom")l.push(`Price: ${x(be({type:"maintenanceRoom",ref:s}))}`),l.push(`Sale value: ${x($t({type:"maintenanceRoom",ref:s},e).amount)}`),l.push("Size: 2\xD72 grid cells"),l.push("Dispatch: 1 repairman during each production day");else if(s.type==="facility"){l.push(`Price: ${x(be(s))}`);{let m=Be({type:s.type,ref:s});l.push(m?`Sale: blocked (${m})`:`Sale value: ${x($t({type:s.type,ref:s},e).amount)}`)}if(l.push(["mixer","truck","trash","sausageMaker"].includes(y)?`Level: ${s.level} / no cap`:`Level: ${s.level}`),y==="truck"&&l.push("Durability: none | Always normal"),["mixer","trash","sausageMaker"].includes(y)&&l.push(`Durability: ${Nn(s)}% | Extra delay ${Fr(e,s).toFixed(2)}s`),y==="mixer"){l.push(`Output: 1 meat per non-poop chick | meat buffer ${s.meatBuffer||0}`),l.push(`Meat quality: x${yt(e,"mixer").toFixed(3)} to sausage value`);let m=Xe(e,s);l.push(`OUT: ${m?`${m.col},${m.row}`:"none"} | conveyor ${It(e,s)?"connected":"missing"}`),l.push(`Fallback sale: ${x(xe.income.mixer)} when OUT is missing or blocked`),l.push(`Poop fine: -${x(Dn(e))}`)}if(y==="truck"&&(l.push(`Income: ${x(Ve(e))} per target cargo | upgrade x${yt(e,"truck").toFixed(3)}`),l.push(`Poop shipment fine: -${x(Bn(e))}`)),y==="trash"){let m=mt(e),v=ht(m),R=qt(m);l.push(`Bonus cards: ${m}/${cn()}`),l.push(`Expected poop bonus: ${x(v)} | hit chance ${Math.round(R*100)}%`),l.push("Winning payouts roll 1x / 2x / 4x / 10x, with jackpot odds rising per card."),l.push("With enough upgrades, poop can out-earn male/female routes.")}if(y==="sausageMaker"){let m=nt(e,s),v=Xe(e,s);l.push("Size: 3\xD73 grid cells | IN left / OUT right"),l.push(`Recipe: 2 meat -> 1 sausage | meat buffer ${s.meatBuffer||0} | sausage buffer ${s.sausageBuffer||0}`),l.push(`Sausage sale value: ${x(Ze(e))}`),l.push(`IN: ${m?`${m.col},${m.row}`:"none"} | OUT: ${v?`${v.col},${v.row}`:"none"} | conveyor ${It(e,s)?"connected":"missing"}`)}s.entry&&l.push(`Receiver: edge cell ${s.entry.col},${s.entry.row} (${s.side})`)}return l}function Ga(s){if(!s||e.phase!=="build")return"";let l=an(e).find(y=>y.type===s.type&&y.id===s.id);return l?l.message||"Not connected to conveyor route":""}function Ua(s){return s?s.type==="conveyor"&&e.conveyorMeta.get(s.id)?.kind==="boostConveyor"?"Moves chicks twice as fast. Wears down like a normal belt.":s.type==="conveyor"?"A stubborn belt tile. It only cares about the next cell.":s.type==="eggFarm"?"A tiny gatehouse producing questionable eggs on schedule.":s.type==="scanner"&&s.kind==="auto"?"A compact 2\xD72 scanner sized for roughly 2.1 level-1 farms.":s.type==="scanner"?"A manual checkpoint. The operator is the algorithm.":s.type==="facility"&&(s.baseId||s.id)==="mixer"?"Chicks become meat when OUT is clear; a blocked OUT falls back to direct sale.":s.type==="facility"&&(s.baseId||s.id)==="trash"?"Poop goes in. Sometimes coins come out, for reasons best left unaudited.":s.type==="facility"&&(s.baseId||s.id)==="truck"?"The shipping endpoint. Correct cargo and sausages pay; wrong cargo complains.":s.type==="facility"&&(s.baseId||s.id)==="sausageMaker"?"A 3\xD73 in-grid machine with one meat inlet on the left and one sausage outlet on the right.":s.type==="maintenanceRoom"?"A cramped 2\xD72 storage and break room with lockers, spare parts, a bench and one dispatched repairman.":"Factory equipment.":""}return{buildAtCell:jn,buildAtPoint:xn,eraseAtPoint:E,equipmentAtPoint:W,startSelectionBox:ae.startSelectionBox,updateSelectionBox:ae.updateSelectionBox,finishSelectionBox:ae.finishSelectionBox,startGroupDrag:ae.startGroupDrag,updateGroupDrag:ae.updateGroupDrag,finishGroupDrag:ae.finishGroupDrag,selectedObject:se,selectedTitle:Se,equipmentPrice:be,selectedUpgradeCost:ve,selectedInfoLines:oi,flavorText:Ua,disconnectedWarningFor:Ga,gridExpansionCost:K,buyGridExpansion:ee,expansionOfferAtPoint:pe,beginConveyorDrag:Go,continueConveyorDrag:Uo,endConveyorDrag:Nt,cycleSingleConveyorDirection:Tt,branchSwitcherAtPoint:ni,cycleBranchModeAtPoint:_a,cycleBranchModeForKey:qo,branchSelectableExitDirsForKey:Lt,removeSelected:en,switchScannerRole:Ba,showManualScannerMenu:En,showAutoScannerMenu:Tn,showSelectedMenu:ei,setBuildTool:La,fail:de,isEquipmentCell:me,equipmentHitBoxes:Na,routeFromFarmToScanner:Kt}}function ya({game:e,ui:t,build:n,startGame:o,beginCardDraft:r,activeQueuedChick:i}){function a(O){return String(O).replace(/[&<>"']/g,G=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[G])}function c(){return Math.round(pn(e))}function h(){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return!1;let O=!1;for(let G of Qo)if(O=!0,e.cash>=He(G,e))return!1;return O}function g(){C(),P(),K(),L()}function C(){for(let[G,Y]of Object.entries(t.buttons))Y?.classList?.contains("tool-button")&&Y.classList.toggle("active",e.buildTool===G);for(let G of Qo){let Y=t.buttons[G];if(!Y)continue;let ie=He(G,e),De=Y.querySelector("span");De&&(De.textContent=G==="conveyor"||G==="boostConveyor"?`${x(ie)} / tile`:x(ie));let me=G==="manualScanner"&&e.scanners.filter(M=>M.kind==="manual").length>=8,T=e.cashKt(e,Y)?.scannerId).length,G=fo(e);t.turnSummary.innerHTML=[`Seed: ${a(e.runSeed||"none")} | Grid box: ${e.gridRows||10}x${e.gridCols||20} | Owned: ${e.gridOwnedCells||e.ownedCells?.size||(e.gridRows||10)*(e.gridCols||20)} cells | Blocked: ${e.blockedCells?.size||0} cells`,`Penalties: wrong shipment -${x(kr(e))} | Mixer poop -${x(Dn(e))} | Shipment poop -${x(Bn(e))}`,`Maintenance: worst ${Br(e).worst.percent}% dirty (${Br(e).worst.label}) | Rooms: ${(e.maintenanceRooms||[]).length} | Repairmen: ${(e.repairmen||[]).length}`,`Card draft: ${e.cardDraft?.pending?Math.max(1,e.cardDraft.picksRemaining||1)+" pick(s) left":"ready after each day"} | Farms with scanner route: ${O}/${e.eggFarms.length}`,e.cardEffects?.usedMachineActive?'Procurement: USED MACHINE MODE / no refunds / 60% durability':"",G.length?`Blocked: ${G[0]}`:`${ce.status.allPortsConnected}`].filter(Boolean).join("
")}function j(){C(),t.shell.classList.toggle("phase-running",e.phase==="running"),t.shell.classList.toggle("phase-build",e.phase==="build"),t.shell.classList.toggle("phase-gameover",e.phase==="gameover"),t.shell.classList.toggle("phase-title",e.phase==="title"),t.shell.classList.toggle("phase-loanDecision",e.phase==="loanDecision"),t.money.textContent=x(e.cash),t.money.classList.toggle("cash-negative",e.cash<0),t.money.classList.toggle("cash-positive",e.cash>Rn),t.turn.textContent=e.turn,t.timeLeft.textContent=e.phase==="running"&&e.timeLeft<=0&&e.shutdownTimeLeft>0?`+${e.shutdownTimeLeft.toFixed(1)}s`:`${Math.max(0,e.timeLeft).toFixed(1)}s`,t.timeLeft.closest?.(".hud-card")?.classList.toggle("time-critical",e.phase==="running"&&(e.timeLeft<=10||e.timeLeft<=0&&e.shutdownTimeLeft>0)),t.phase.textContent=Q(),t.comboCount&&(t.comboCount.textContent=e.manualCombo?.count||0),Z(),t.turnProfit.textContent=x(e.stats.profit),t.turnProfit.classList.toggle("cash-negative",e.stats.profit<0),t.turnProfit.classList.toggle("cash-positive",e.stats.profit>0),t.mixerCount.textContent=e.stats.mixerCount,t.truckFemaleCount.textContent=e.stats.truckFemale,t.truckMaleCount.textContent=e.stats.truckMale,t.poopCount.textContent=e.stats.poopSpawned,t.buttons.s1Left.disabled=e.phase!=="running"||!i(0),t.buttons.s1Right.disabled=e.phase!=="running"||!i(0),t.buttons.s2Left.disabled=e.phase!=="running"||!i(1),t.buttons.s2Right.disabled=e.phase!=="running"||!i(1);let O=e.scanners.find(me=>me.kind==="manual"&&me.slot===0),G=e.scanners.find(me=>me.kind==="manual"&&me.slot===1);O&&(t.buttons.s1Left.textContent=`S1 ${O.keys?.left?.label||"A"} -> Mixer`,t.buttons.s1Right.textContent=`S1 ${O.keys?.right?.label||"D"} -> S2`),G&&(t.buttons.s2Left.textContent=`S2 ${G.keys?.left?.label||"Left"} -> Waste`,t.buttons.s2Right.textContent=`S2 ${G.keys?.right?.label||"Right"} -> Truck`);let Y=Math.max(0,Math.floor(e.lastResult?.profit??e.stats?.profit??0)),ie=Cr(e,Math.max(1,Number(e.turn)||1),Y).amount,De=e.phase==="build"&&ie>0?`NEXT DAYFAIRIES -${x(ie)}`:`${ce.actions.nextDay}`;t.buttons.nextTurn.dataset.renderedHtml!==De&&(t.buttons.nextTurn.innerHTML=De,t.buttons.nextTurn.dataset.renderedHtml=De),t.buttons.nextTurn.disabled=e.phase!=="build"||!!e.cardDraft?.pending||!!e.cardTargetPick?.pending}function Z(){if(!t.eventBrief||!t.speedBrief)return;t.speedBrief.textContent=`BELT SPEED: ${c()} px/s`,t.speedBrief.title=`Conveyor speed does not increase by day. Degraded belts reduce speed. Cap: ${tn}px/s.`;let O=e.eventActive,G=e.eventOffer;O?(t.eventBrief.textContent=`ACTIVE EVENT: ${O.title} | ${O.route}`,t.eventBrief.className="event-brief active"):e.phase==="build"&&G?(t.eventBrief.textContent=`NEXT DAY EVENT: ${G.title} | ${G.route}${G.targetAmount?` | Target ${G.targetAmount}`:""}${G.reward?` | Reward ${x(G.reward)}`:""}`,t.eventBrief.className="event-brief next"):e.phase==="build"&&e.turn+1
\u2642Male->Mixer -> MeatS1: A
\u2640Female->TruckS1: D, then S2: right
\u{1F4A9}Poop->ShredderS1: D, then S2: left

Build phase: connect at least one EGG through a scanner to Mixer, Shredder, or Truck before Next Day. One day is one run.

',t.modalActions.innerHTML="",t.modalActions.appendChild(D(ce.actions.startGame,o,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function pe(O){let G=me=>`${me>0?"+":""}${x(me)}`,Y=me=>`${me>0?"-":""}${x(me)}`,ie=O.profit>=0?"cash-positive":"cash-negative",De=(O.mixerPoopFine||0)+(O.truckPoopFine||0)+(O.maleTruckFine||0)+(O.explosionDamage||0)+(O.cardRerollCost||0);t.modalTitle.textContent=`Day ${O.turn} Settlement`,t.modalBody.innerHTML=` -
Net result${x(O.profit)}
+ ${m?`

${m}

`:""} + `,t.modalActions.innerHTML="",t.modalActions.appendChild(de("Set Left Key",()=>gi(s,"left"),"facility-action warn")),t.modalActions.appendChild(de("Set Right Key",()=>gi(s,"right"),"facility-action warn")),t.modalActions.appendChild(de("Close",Xe,"facility-action")),ho(s),t.modal.classList.add("visible","equipment-popover")}function Ci(s){if(!s||(s.baseId||s.id)!=="inboundTruck")return;s.inboundOrder=s.inboundOrder||{coalPerDay:0,zundaMochiPerDay:0};let l=_.imports.combinedLimitPerTruck,y=Math.max(0,Math.floor(s.inboundOrder.coalPerDay||0)),h=Math.max(0,Math.floor(s.inboundOrder.zundaMochiPerDay||0)),m=y*_.imports.prices.coal+h*_.imports.prices.zundaMochi,P=y+h,F=P>0?(_.time.daySeconds/P).toFixed(1):"none";t.modalTitle.textContent=`Inbound Truck #${s.id}`,t.modalBody.innerHTML=` +
+ + +

Combined total: ${P}/${l}

+

Daily purchase cost: ${R(m)}

+

Average release interval: ${F}${P>0?"s":""}

+

Output queue: ${s.inboundQueue?.length||0}

+
`,t.modalActions.innerHTML="";let q=de("Apply",()=>{if(e.phase!=="build")return;let be=Math.max(0,Math.floor(Number(document.getElementById("inboundCoalInput")?.value)||0)),Pe=Math.max(0,Math.floor(Number(document.getElementById("inboundZundaInput")?.value)||0)),we=be+Pe,$e=we>l?l/we:1;Oe(e),s.inboundOrder={coalPerDay:Math.floor(be*$e),zundaMochiPerDay:Math.floor(Pe*$e)},Ci(s),i()},"primary-button");q.disabled=e.phase!=="build",t.modalActions.appendChild(q),t.modalActions.appendChild(de("Close",Xe,"facility-action")),ho(s),t.modal.classList.add("visible","equipment-popover")}function ml(s){let l=[{side:"left",binding:s.keys?.left},{side:"right",binding:s.keys?.right}];if(l[0].binding&&l[1].binding&&(l[0].binding.code===l[1].binding.code||l[0].binding.key===l[1].binding.key))return"Left and right keys conflict.";for(let y of l)if(y.binding)for(let h of e.scanners.filter(m=>m.kind==="manual"&&m.id!==s.id)){if(h.keys?.left&&(h.keys.left.code===y.binding.code||h.keys.left.key===y.binding.key))return`Key conflicts with Manual Scanner #${h.id} left.`;if(h.keys?.right&&(h.keys.right.code===y.binding.code||h.keys.right.key===y.binding.key))return`Key conflicts with Manual Scanner #${h.id} right.`}return""}function gi(s,l){t.modalBody.innerHTML=`

Press a key for ${l.toUpperCase()} route.

Esc cancels.

`,t.modalActions.innerHTML="";let y=h=>{if(h.preventDefault(),h.stopPropagation(),window.removeEventListener("keydown",y,!0),h.key==="Escape")return Wn(s);let m=pr(h),P=wl(s,l,m);Oe(e),s.keys=s.keys||{left:null,right:null},s.keys[l]=m,i(),Wn(s,P?`${m.label} assigned, but another scanner already uses it.`:`${l.toUpperCase()} set to ${m.label}.`)};window.addEventListener("keydown",y,!0)}function vl(){let s=j();if(!(!s||s.type!=="scanner"))return s.kind==="auto"?_n(s):Wn(s)}function Sl(s){if(!s)return{x:80,y:80};if(s.type==="conveyor"){let l=X(s.id);return B(l.col,l.row)}return s.type==="eggFarm"?B(s.col,s.row):s.type==="scanner"?ge(s):s.type==="facility"?{x:s.x+s.w/2,y:s.y+10}:{x:80,y:80}}function ho(s){let l=n.getBoundingClientRect(),y=Sl(s),h=e.view?.scale||1,m=l.left+(y.x*h+(e.view?.x||0))/n.width*l.width+18,P=l.top+(y.y*h+(e.view?.y||0))/n.height*l.height-12,F=Math.max(12,window.innerWidth-274),q=Math.max(12,window.innerHeight-220);t.modal.style.setProperty("--popover-x",`${Math.max(12,Math.min(F,m))}px`),t.modal.style.setProperty("--popover-y",`${Math.max(12,Math.min(q,P))}px`)}function xi(){let s=j();if(!s)return;let l=Pi(s);if(t.modalTitle.textContent=le(s),t.modalBody.innerHTML=` +
${l.map(m=>`

${m}

`).join("")}
+ ${["mixer","truck"].includes(s.baseId||s.id)?'

Income/Fine = ceil(base x 1.10^upgrades)

':""}`,t.modalActions.innerHTML="",s.type==="scanner"&&s.kind==="auto"&&t.modalActions.appendChild(de("Auto Menu",()=>_n(s),"facility-action warn")),s.type==="scanner"&&s.kind==="manual"&&t.modalActions.appendChild(de("Set Keys",()=>Wn(s),"facility-action warn")),s.type==="conveyor"&&yr(s.id)&&Ht(s.id).length>=2){let m=e.conveyorMeta.get(s.id)?.branchMode||"random";t.modalActions.appendChild(de(`Branch: ${Ti(m)}`,()=>{hr(s.id),e.selected={type:"conveyor",id:s.id},xi()},"facility-action warn branch-action"))}let y=s.type==="conveyor"?{type:"conveyor",oldKey:s.id,ref:s}:{type:s.type,ref:s},h=Ke(y);if(h){let m=de(h,()=>{},"facility-action danger disabled");m.disabled=!0,t.modalActions.appendChild(m)}else{let m=Ut(y,e),P=m.sameBuild?`Remove / Refund ${R(m.amount)}`:`Sell ${R(m.amount)}`;t.modalActions.appendChild(de(P,()=>{he(),Xe()},"facility-action danger"))}ho(s),t.modal.classList.add("visible","equipment-popover")}function kl(s){e.phase==="build"&&(Qt(),e.buildTool=e.buildTool===s?null:s,e.selected=null,e.multiSelected=[],e.selectionBox=null,i())}function Ml(){let s=[];for(let[l,y]of Object.entries(e.facilities))if(s.push({id:`facility:${l}`,price:ce({type:"facility",ref:y}),x:y.x,y:y.y,w:y.w,h:y.h}),y.entry){let h=B(y.entry.col,y.entry.row);s.push({id:`facilityPort:${l}`,price:ce({type:"facility",ref:y}),x:h.x-18,y:h.y-18,w:36,h:36})}for(let l of e.maintenanceRooms||[]){let y=u(l);s.push({id:`maintenanceRoom:${l.id}`,price:ce({type:"maintenanceRoom",ref:l}),x:y.x-p.cell,y:y.y-p.cell,w:p.cell*2,h:p.cell*2})}for(let l of e.eggFarms){let y=B(l.col,l.row);s.push({id:`eggFarm:${l.id}`,price:ce({type:"eggFarm",ref:l}),x:y.x-24,y:y.y-24,w:48,h:48})}for(let l of e.scanners){let y=ge(l);s.push({id:`scanner:${l.id}`,price:ce({type:"scanner",ref:l}),x:y.x-50,y:y.y-73,w:100,h:146})}for(let l of e.conveyorTiles){let y=X(l),h=B(y.col,y.row),m=e.conveyorMeta.get(l)||{};s.push({id:`conveyor:${l}`,price:m.price||Le(m.kind==="boostConveyor"?"boostConveyor":"conveyor",e),x:h.x-22,y:h.y-22,w:44,h:44})}if(e.powerOverlay)for(let[l,y]of e.powerWires||new Map){let h=X(l),m=B(h.col,h.row);s.push({id:`powerWire:${l}`,price:y.price||0,x:m.x-18,y:m.y-18,w:36,h:36})}for(let[l,y]of e.footbridges||new Map){let h=X(l),m=B(h.col,h.row);s.push({id:`footbridge:${l}`,price:y.price||Le("footbridge",e),x:m.x-22,y:m.y-22,w:44,h:44})}return s}function Ti(s){return $[s]||$.random}function ef(s){return Ln(s)}function yr(s){return e.conveyorTiles.has(s)?Ce(X(s)):!1}function Ei(s){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return null;for(let l of e.conveyorTiles){if(!yr(l)||Ht(l).length<2)continue;let y=X(l),h=B(y.col,y.row),m=h.x-W.w/2,P=h.y+W.y-W.h/2;if(s.x>=m&&s.x<=m+W.w&&s.y>=P&&s.y<=P+W.h)return l}return null}function Cl(s){let l=Ei(s);return l?hr(l):!1}function hr(s){let l=e.conveyorMeta.get(s);if(!l)return!1;let y=Ht(s);if(y.length<2)return!1;Oe(e);let h=C.includes(l.branchMode)?l.branchMode:"random",m=["random",...fe.map(P=>P.name).filter(P=>y.includes(P))];return l.branchMode=m[(Math.max(0,m.indexOf(h))+1)%m.length],Ee(e),e.selected=null,e.multiSelected=[],i(),!0}function Pi(s){Be(e);let l=[],y=s?.type==="facility"?s.baseId||s.id:"";if(s.type==="eggFarm"){let[h,m]=zn(s);l.push(`Price: ${R(ce(s))}`);{let be=Ke({type:s.type,ref:s});l.push(be?`Sale: blocked (${be})`:`Sale value: ${R(Ut({type:s.type,ref:s},e).amount)}`)}l.push(`Level: ${s.level}/4`),l.push(`Random interval: ${h.toFixed(2)}-${m.toFixed(2)}s`),l.push(`Durability: ${Zn(s)}% | Spawn delay x${Yo(s).toFixed(2)}`);let P=Kt(e),F=s.theoreticalRate||io(e,s,s.lastInterval||1),q=so(F,P);l.push(`Rate: ${F.toFixed(2)}/s theoretical | ${Math.min(F,P).toFixed(2)}/s actual`),l.push(`Boost cap: ${P.toFixed(2)}/s | Quality: x${q.toFixed(2)} ${Ha(q)}`),s.zundaBoostTime>0&&l.push(`Zunda boost: ${s.zundaBoostTime.toFixed(1)}s`)}else if(s.type==="scanner"){l.push(`Price: ${R(ce(s))}`),l.push(`Sale value: ${R(Ut({type:s.type,ref:s},e).amount)}`),l.push(`Type: ${s.kind.toUpperCase()} / Standard`),s.kind==="auto"&&l.push(`Role: ${s.role===0?"Male left / Others right":"Poop left / Others right"}`),l.push(`Queue: ${s.queue.length}`),s.kind==="auto"&&l.push(`Cooldown: ${s.cooldown.toFixed(1)}s / ${Bt(s,e).toFixed(1)}s`),s.kind==="auto"&&l.push(`Durability: ${Zn(s)}% | Delay x${Ho(s).toFixed(2)}`),s.kind==="manual"&&l.push("Durability: none | Always normal");let h=En(e,s);h&&br(l,h)}else if(s.type==="conveyor"){let h=e.conveyorMeta.get(s.id),m=e.componentLookup?.get(s.id),P=m?e.congestion.get(m):null;l.push(`Price: ${R(ce({type:"conveyor",oldKey:s.id,ref:s}))}`),l.push(`Cell: ${s.id}`),l.push(`Type: ${h?.kind==="boostConveyor"?"BOOST BELT":"Normal Belt"} | Speed x${Number(h?.speedMultiplier||1).toFixed(1)}`),l.push(`Congestion: ${P?Math.floor(P.ratio*100):0}%`),l.push(`Durability: ${Zn({meta:h})}% | Speed x${zo({meta:h}).toFixed(2)}`),yr(s.id)?Ht(s.id).length>=2?(l.push(`Branch mode: ${Ti(h?.branchMode||"random")}`),l.push("Click the Branch button or the on-belt triangle to cycle RANDOM / fixed exit.")):l.push("Branch mode: unavailable \u2014 fewer than two outgoing conveyors."):l.push("Branch mode: needs 3+ conveyor connections."),l.push(`Sale value: ${R(Ut({type:"conveyor",oldKey:s.id,ref:s},e).amount)}`)}else if(s.type==="powerWire"){let h=e.powerWires?.get(s.id),m=_.power.wires[h?.kind||"powerWire"];l.push(`Price: ${R(h?.price||m.price)}`),l.push(`Cell: ${s.id}`),l.push(`Type: ${m.name} | Loss ${m.lossV}V/tile`)}else if(s.type==="footbridge"){let h=e.footbridges?.get(s.id);l.push(`Price: ${R(h?.price||Le("footbridge",e))}`),l.push(`Cell: ${s.id}`),l.push(`Orientation: ${h?.orientation||"vertical"}`),l.push("Repair workers may cross this conveyor cell.")}else if(s.type==="maintenanceRoom"){l.push(`Price: ${R(ce({type:"maintenanceRoom",ref:s}))}`),l.push(`Sale value: ${R(Ut({type:"maintenanceRoom",ref:s},e).amount)}`),l.push("Size: 2\xD72 grid cells"),l.push("Dispatch: 1 repairman during each production day");let h=En(e,s);h&&br(l,h)}else if(s.type==="facility"){l.push(`Price: ${R(ce(s))}`);{let m=Ke({type:s.type,ref:s});l.push(m?`Sale: blocked (${m})`:`Sale value: ${R(Ut({type:s.type,ref:s},e).amount)}`)}if(l.push(["mixer","truck","trash","sausageMaker"].includes(y)?`Level: ${s.level} / no cap`:`Level: ${s.level}`),y==="truck"&&l.push("Durability: none | Always normal"),["mixer","trash","sausageMaker"].includes(y)&&l.push(`Durability: ${Zn(s)}% | Extra delay ${ii(e,s).toFixed(2)}s`),y==="mixer"){l.push(`Output: 1 meat per non-poop chick | meat buffer ${s.meatBuffer||0}`),l.push(`Meat quality: x${Rt(e,"mixer").toFixed(3)} to sausage value`);let m=He(e,s);l.push(`OUT: ${m?`${m.col},${m.row}`:"none"} | conveyor ${kt(e,s)?"connected":"missing"}`),l.push(`Fallback sale: ${R(Ie.income.mixer)} when OUT is missing or blocked`),l.push(`Poop fine: -${R(Yn(e))}`)}if(y==="truck"&&(l.push(`Income: ${R(Je(e))} per target cargo | upgrade x${Rt(e,"truck").toFixed(3)}`),l.push(`Poop shipment fine: -${R(Qn(e))}`)),y==="trash"){let m=At(e),P=It(m),F=tn(m);l.push(`Bonus cards: ${m}/${kn()}`),l.push(`Expected poop bonus: ${R(P)} | hit chance ${Math.round(F*100)}%`),l.push("Winning payouts roll 1x / 2x / 4x / 10x, with jackpot odds rising per card."),l.push("With enough upgrades, poop can out-earn male/female routes.")}if(y==="sausageMaker"){let m=wt(e,s),P=He(e,s);l.push("Size: 3\xD73 grid cells | IN left / OUT right"),l.push(`Recipe: 2 meat -> 1 sausage | meat buffer ${s.meatBuffer||0} | sausage buffer ${s.sausageBuffer||0}`),l.push(`Sausage sale value: ${R(lt(e))}`),l.push(`IN: ${m?`${m.col},${m.row}`:"none"} | OUT: ${P?`${P.col},${P.row}`:"none"} | conveyor ${kt(e,s)?"connected":"missing"}`)}s.entry&&l.push(`Receiver: edge cell ${s.entry.col},${s.entry.row} (${s.side})`);let h=En(e,s);h&&br(l,h)}return l}function br(s,l){s.push(`Power: ${l.receivedV.toFixed(1)}V / ${l.minVoltage}V`),s.push(`Source: ${l.sourceName} | Source bus: ${l.sourceBusV.toFixed(1)}V`),s.push(`Route loss: ${l.routeLossV.toFixed(1)}V | Voltage Load: ${l.drawV}V`),l.receivedVy.type===s.type&&y.id===s.id);return l?l.message||"Not connected to conveyor route":""}function xl(s){return s?s.type==="conveyor"&&e.conveyorMeta.get(s.id)?.kind==="boostConveyor"?"Moves chicks twice as fast. Wears down like a normal belt.":s.type==="conveyor"?"A stubborn belt tile. It only cares about the next cell.":s.type==="eggFarm"?"A tiny gatehouse producing questionable eggs on schedule.":s.type==="scanner"&&s.kind==="auto"?"A compact 2\xD72 scanner sized for roughly 2.1 level-1 farms.":s.type==="scanner"?"A manual checkpoint. The operator is the algorithm.":s.type==="facility"&&(s.baseId||s.id)==="mixer"?"Chicks become meat when OUT is clear; a blocked OUT falls back to direct sale.":s.type==="facility"&&(s.baseId||s.id)==="trash"?"Poop goes in. Sometimes coins come out, for reasons best left unaudited.":s.type==="facility"&&(s.baseId||s.id)==="truck"?"The shipping endpoint. Correct cargo and sausages pay; wrong cargo complains.":s.type==="facility"&&(s.baseId||s.id)==="sausageMaker"?"A 3\xD73 in-grid machine with one meat inlet on the left and one sausage outlet on the right.":s.type==="maintenanceRoom"?"A cramped 2\xD72 storage and break room with lockers, spare parts, a bench and one dispatched repairman.":"Factory equipment.":""}return{buildAtCell:po,buildAtPoint:fn,eraseAtPoint:S,equipmentAtPoint:I,startSelectionBox:A.startSelectionBox,updateSelectionBox:A.updateSelectionBox,finishSelectionBox:A.finishSelectionBox,startGroupDrag:A.startGroupDrag,updateGroupDrag:A.updateGroupDrag,finishGroupDrag:A.finishGroupDrag,selectedObject:j,selectedTitle:le,equipmentPrice:ce,selectedUpgradeCost:U,selectedInfoLines:Pi,flavorText:xl,disconnectedWarningFor:gl,gridExpansionCost:K,buyGridExpansion:se,expansionOfferAtPoint:J,beginConveyorDrag:lr,continueConveyorDrag:cr,endConveyorDrag:Qt,cycleSingleConveyorDirection:co,branchSwitcherAtPoint:Ei,cycleBranchModeAtPoint:Cl,cycleBranchModeForKey:hr,branchSelectableExitDirsForKey:Ht,removeSelected:he,switchScannerRole:vl,showManualScannerMenu:Wn,showInboundTruckMenu:Ci,showAutoScannerMenu:_n,showSelectedMenu:xi,setBuildTool:kl,fail:T,isEquipmentCell:xe,equipmentHitBoxes:Ml,routeFromFarmToScanner:en}}function Xa({game:e,ui:t,build:n,startGame:o,beginCardDraft:r,activeQueuedChick:i}){function a(O){return String(O).replace(/[&<>"']/g,H=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[H])}function c(){return Math.round(Vt(e))}function b(){if(e.phase!=="build"||e.cardDraft?.pending||e.cardTargetPick?.pending)return!1;let O=!1;for(let H of Mr)if(O=!0,e.cash>=Le(H,e))return!1;return O}function M(){C(),$(),K(),W()}function C(){for(let[H,oe]of Object.entries(t.buttons))oe?.classList?.contains("tool-button")&&oe.classList.toggle("active",e.buildTool===H);t.buttons.powerOverlay?.classList.toggle("active",!!e.powerOverlay),t.buttons.powerOverlay&&(t.buttons.powerOverlay.disabled=e.phase!=="build"||!!e.cardDraft?.pending||!!e.cardTargetPick?.pending);for(let H of Mr){let oe=t.buttons[H];if(!oe)continue;let ue=Le(H,e),Ve=oe.querySelector("span");Ve&&(Ve.textContent=H==="conveyor"||H==="boostConveyor"?`${R(ue)} / tile`:R(ue));let xe=H==="manualScanner"&&e.scanners.filter(x=>x.kind==="manual").length>=8,Ge=e.cashen(e,oe)?.scannerId).length,H=$o(e);t.turnSummary.innerHTML=[`Seed: ${a(e.runSeed||"none")} | Grid box: ${e.gridRows||10}x${e.gridCols||20} | Owned: ${e.gridOwnedCells||e.ownedCells?.size||(e.gridRows||10)*(e.gridCols||20)} cells | Blocked: ${e.blockedCells?.size||0} cells`,`Penalties: wrong shipment -${R(zr(e))} | Mixer poop -${R(Yn(e))} | Shipment poop -${R(Qn(e))}`,aa(e),`Maintenance: worst ${li(e).worst.percent}% dirty (${li(e).worst.label}) | Rooms: ${(e.maintenanceRooms||[]).length} | Repairmen: ${(e.repairmen||[]).length}`,`Card draft: ${e.cardDraft?.pending?Math.max(1,e.cardDraft.picksRemaining||1)+" pick(s) left":"ready after each day"} | Farms with scanner route: ${O}/${e.eggFarms.length}`,e.cardEffects?.usedMachineActive?'Procurement: USED MACHINE MODE / no refunds / 60% durability':"",H.length?`Blocked: ${H[0]}`:`${pe.status.allPortsConnected}`].filter(Boolean).join("
")}function G(){C(),t.shell.classList.toggle("phase-running",e.phase==="running"),t.shell.classList.toggle("phase-build",e.phase==="build"),t.shell.classList.toggle("phase-gameover",e.phase==="gameover"),t.shell.classList.toggle("phase-title",e.phase==="title"),t.shell.classList.toggle("phase-loanDecision",e.phase==="loanDecision"),t.money.textContent=R(e.cash),t.money.classList.toggle("cash-negative",e.cash<0),t.money.classList.toggle("cash-positive",e.cash>Un),t.turn.textContent=e.turn,t.timeLeft.textContent=e.phase==="running"&&e.timeLeft<=0&&e.shutdownTimeLeft>0?`+${e.shutdownTimeLeft.toFixed(1)}s`:`${Math.max(0,e.timeLeft).toFixed(1)}s`,t.timeLeft.closest?.(".hud-card")?.classList.toggle("time-critical",e.phase==="running"&&(e.timeLeft<=10||e.timeLeft<=0&&e.shutdownTimeLeft>0)),t.phase.textContent=Q(),t.comboCount&&(t.comboCount.textContent=e.manualCombo?.count||0),z(),t.turnProfit.textContent=R(e.stats.profit),t.turnProfit.classList.toggle("cash-negative",e.stats.profit<0),t.turnProfit.classList.toggle("cash-positive",e.stats.profit>0),t.mixerCount.textContent=e.stats.mixerCount,t.truckFemaleCount.textContent=e.stats.truckFemale,t.truckMaleCount.textContent=e.stats.truckMale,t.poopCount.textContent=e.stats.poopSpawned,t.buttons.s1Left.disabled=e.phase!=="running"||!i(0),t.buttons.s1Right.disabled=e.phase!=="running"||!i(0),t.buttons.s2Left.disabled=e.phase!=="running"||!i(1),t.buttons.s2Right.disabled=e.phase!=="running"||!i(1);let O=e.scanners.find(xe=>xe.kind==="manual"&&xe.slot===0),H=e.scanners.find(xe=>xe.kind==="manual"&&xe.slot===1);O&&(t.buttons.s1Left.textContent=`S1 ${O.keys?.left?.label||"A"} -> Mixer`,t.buttons.s1Right.textContent=`S1 ${O.keys?.right?.label||"D"} -> S2`),H&&(t.buttons.s2Left.textContent=`S2 ${H.keys?.left?.label||"Left"} -> Waste`,t.buttons.s2Right.textContent=`S2 ${H.keys?.right?.label||"Right"} -> Truck`);let oe=Math.max(0,Math.floor(e.lastResult?.profit??e.stats?.profit??0)),ue=Yr(e,Math.max(1,Number(e.turn)||1),oe).amount,Ve=e.phase==="build"&&ue>0?`NEXT DAYFAIRIES -${R(ue)}`:`${pe.actions.nextDay}`;t.buttons.nextTurn.dataset.renderedHtml!==Ve&&(t.buttons.nextTurn.innerHTML=Ve,t.buttons.nextTurn.dataset.renderedHtml=Ve),t.buttons.nextTurn.disabled=e.phase!=="build"||!!e.cardDraft?.pending||!!e.cardTargetPick?.pending}function z(){if(!t.eventBrief||!t.speedBrief)return;t.speedBrief.textContent=`BELT SPEED: ${c()} px/s`,t.speedBrief.title=`Conveyor speed does not increase by day. Degraded belts reduce speed. Cap: ${yn}px/s.`;let O=e.eventActive,H=e.eventOffer;O?(t.eventBrief.textContent=`ACTIVE EVENT: ${O.title} | ${O.route}`,t.eventBrief.className="event-brief active"):e.phase==="build"&&H?(t.eventBrief.textContent=`NEXT DAY EVENT: ${H.title} | ${H.route}${H.targetAmount?` | Target ${H.targetAmount}`:""}${H.reward?` | Reward ${R(H.reward)}`:""}`,t.eventBrief.className="event-brief next"):e.phase==="build"&&e.turn+1
\u2642Male->Mixer -> MeatS1: A
\u2640Female->TruckS1: D, then S2: right
\u{1F4A9}Poop->ShredderS1: D, then S2: left

Build phase: connect at least one EGG through a scanner to Mixer, Shredder, or Truck before Next Day. One day is one run.

',t.modalActions.innerHTML="",t.modalActions.appendChild(L(pe.actions.startGame,o,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function J(O){let H=D=>`${D>0?"+":""}${R(D)}`,oe=D=>`${D>0?"-":""}${R(D)}`,ue=O.profit>=0?"cash-positive":"cash-negative",Ve=(O.mixerPoopFine||0)+(O.truckPoopFine||0)+(O.maleTruckFine||0)+(O.explosionDamage||0)+(O.cardRerollCost||0),xe=O.qualityMultiplierCount?(O.qualityMultiplierSum||0)/O.qualityMultiplierCount:1,Ge=O.qualityRevenue||0,x=Ge>0?"cash-positive":"",g=Object.values(O.maxGeneratorOutput||{}).reduce((D,Z)=>Math.max(D,Number(Z)||0),0);t.modalTitle.textContent=`Day ${O.turn} Settlement`,t.modalBody.innerHTML=` +
Net result${R(O.profit)}
-
Chick shipment income${G(O.chickShipmentIncome||0)}
-
Poop shipment income${G(O.poopShipmentIncome||0)}
-
Sausage shipment income${G(O.sausageRevenue||0)}
+
Chick shipment income${H(O.chickShipmentIncome||0)}
+
Poop shipment income${H(O.poopShipmentIncome||0)}
+
Sausage shipment income${H(O.sausageRevenue||0)}
Meat / sausages${O.meatProduced||0} meat -> ${O.sausageProduced||0} made / ${O.sausageShipped||0} shipped
-
Composter income${G(O.composterIncome||0)}
-
DUD refund income${G(O.dudRefundIncome||0)}
-
Manual combo bonus${G(O.manualComboBonus||0)}
-
Chemical subsidy${G(O.chemicalWeaponSubsidy||0)}
-
Event bonus${G(O.eventBonus||0)}
-
Penalties${Y(De)}
-
Fairies fee${Y(O.fairiesTribute?.amount||O.fairiesTribute||0)}
+
Importscoal ${O.coalReleased||0}/${O.coalOrdered||0}, zunda ${O.zundaReleased||0}/${O.zundaOrdered||0}
+
Import usecoal fuel ${O.coalConsumed||0}, zunda used ${O.zundaConsumed||0}, undelivered ${O.coalUndelivered||0}/${O.zundaUndelivered||0}
+
Import cost${oe(O.importPurchaseCost||0)}
+
Generator fuelbiomass ${O.biomassFuelConsumed||0}, max output ${g.toFixed(0)}V
+
Quality revenue${Ge>0?"+":""}${R(Ge)} avg x${xe.toFixed(2)} / max x${(O.maxQualityMultiplier||1).toFixed(2)}
+
Zunda boost${(O.zundaBoostSeconds||0).toFixed(1)} farm-seconds
+
Power trouble${(O.underVoltageSeconds||0).toFixed(1)} machine-seconds / ${O.generatorAssignmentChanges||0} source changes
+
Repair access${O.unreachableRepairTargets||0} unreachable target checks
+
Composter income${H(O.composterIncome||0)}
+
DUD refund income${H(O.dudRefundIncome||0)}
+
Manual combo bonus${H(O.manualComboBonus||0)}
+
Chemical subsidy${H(O.chemicalWeaponSubsidy||0)}
+
Event bonus${H(O.eventBonus||0)}
+
Penalties${oe(Ve)}
+
Fairies fee${oe(O.fairiesTribute?.amount||O.fairiesTribute||0)}
-

Income ${x(O.revenue)} - losses ${x(O.penalty)} = ${x(O.profit)}

`,t.modalActions.innerHTML="",t.modalActions.appendChild(D("Choose Upgrade Card",r||U,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function le(O,G){let Y=Math.max(0,e.cardEffects?.rescueLoanCharges||0);t.modalTitle.textContent="Emergency Loan Available",t.modalBody.innerHTML=` -

End-of-day cash is below ${x(0)}.

+

Income ${R(O.revenue)} - losses ${R(O.penalty)} = ${R(O.profit)}

`,t.modalActions.innerHTML="",t.modalActions.appendChild(L("Choose Upgrade Card",r||V,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function ae(O,H){let oe=Math.max(0,e.cardEffects?.rescueLoanCharges||0);t.modalTitle.textContent="Emergency Loan Available",t.modalBody.innerHTML=` +

End-of-day cash is below ${R(0)}.

-
Current money${x(e.cash)}
-
Emergency Loan+${x(500)}
-
Cards remaining${Y}
+
Current money${R(e.cash)}
+
Emergency Loan+${R(500)}
+
Cards remaining${oe}
-

Use one Emergency Loan to gain ${x(500)} immediately. If cash is still negative, another decision will be shown if another card remains.

`,t.modalActions.innerHTML="",t.modalActions.appendChild(D("Accept Game Over",G,"facility-action danger")),t.modalActions.appendChild(D("Use Emergency Loan",O,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function ue(){let O=e.totals.processed,G=O?Math.round(e.totals.correct/O*100):0,Y=ms(e);t.modalTitle.textContent=ce.phases.gameover,t.modalBody.innerHTML=`

Your cash went negative.

-
Final Score${Y.score}
Survival${e.totals.turnsCompleted} days
Final Cash${x(e.cash)}
Accuracy${G}%
+

Use one Emergency Loan to gain ${R(500)} immediately. If cash is still negative, another decision will be shown if another card remains.

`,t.modalActions.innerHTML="",t.modalActions.appendChild(L("Accept Game Over",H,"facility-action danger")),t.modalActions.appendChild(L("Use Emergency Loan",O,"primary-button")),t.modal.classList.remove("equipment-popover","gameover-modal"),t.modal.classList.add("visible")}function ye(){let O=e.totals.processed,H=O?Math.round(e.totals.correct/O*100):0,oe=Gs(e);t.modalTitle.textContent=pe.phases.gameover,t.modalBody.innerHTML=`

Your cash went negative.

+
Final Score${oe.score}
Survival${e.totals.turnsCompleted} days
Final Cash${R(e.cash)}
Accuracy${H}%
Score breakdown -
Formula
Base = Cash + Total revenue + Factory value \xD70.5 + Event bonus \xD70.5 = ${x(Y.base)}
Daily earned = ceil(Base \xF7 Days) = ${x(Y.dailyEarned)}
Score = max(0, floor(Base + Daily earned + Correct bonus - Total outflow - Day penalty)) = ${Y.score}
-
Factory Value${x(Y.factoryValue)}
Total Revenue${x(e.totals.revenue)}
Daily Earned${x(Y.dailyEarned)} / day
Total Outflow${x(e.totals.penalty)}
Fairies Tribute${x(e.totals.fairiesTribute||0)}
Correct Sorts${e.totals.correct}
Auto Sorted${e.totals.autoSorted}
Poop Control${e.totals.poopTrash} trashed / ${e.totals.poopTruck} shipped / ${e.totals.poopMixer} mixer
Explosion Penalty${x(e.totals.explosionDamage)}
Event Bonus${x(e.totals.eventBonus)}
Day Penalty-${Y.dayPenalty}
Events${e.totals.eventSuccess} success / ${e.totals.eventFailed} failed
-
`,t.modalActions.innerHTML="",t.modalActions.appendChild(D(ce.actions.restart||"Restart",o,"primary-button restart-button")),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible","gameover-modal")}function D(O,G,Y="primary-button"){let ie=document.createElement("button");return ie.type="button",ie.className=Y,ie.textContent=O,ie.addEventListener("click",G),ie}function U(){t.modal.classList.remove("visible","equipment-popover","gameover-modal"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function ee(){}return{updatePanels:g,updateUI:j,showTitle:ke,showTurnResult:pe,showEmergencyLoanDecision:le,showGameOver:ue,hideModal:U,checkGameOver:ee}}function Qr(e){e.totals.processed+=1}function hn(e){e.stats.correct+=1,e.totals.correct+=1}function rt(e){e.stats.mistakes+=1,e.totals.mistakes+=1}function ha(e){e.stats.autoSorted+=1,e.totals.autoSorted+=1}function ma(e){e.stats.poopSpawned+=1}function ba(e){e.stats.mixerCount+=1,Qr(e)}function va(e){e.stats.trashCount+=1,Qr(e)}function wa(e,t){t==="female"?e.stats.truckFemale+=1:t==="male"&&(e.stats.truckMale+=1),Qr(e)}function Bo(e,t){let n=t==="truck"?"poopTruck":t==="trash"?"poopTrash":t==="mixer"?"poopMixer":null;n&&(e.stats[n]+=1,e.totals[n]+=1)}function Sa({game:e,currentConveyorSpeed:t,onGameOverCheck:n}){function o(){return e.frameCache||(e.frameCache={frameId:-1,routingVersion:-1,chickRevision:0,spatialRevision:-1,spatial:new Map,congestionFrame:-1,componentChicks:new Map,manualMonitorSignature:"",draw:{}}),e.frameCache}function r(){let d=o();d.chickRevision=(d.chickRevision||0)+1,d.congestionFrame=-1}function i(){o().congestionFrame=-1}function a(d){let p=o();p.frameId!==d&&(p.frameId=d,p.spatialRevision=-1,p.congestionFrame=-1)}function c(d,p){return`${Math.floor(d/f.cell)},${Math.floor(p/f.cell)}`}function h(){let d=o();if(d.spatialRevision===d.chickRevision)return d.spatial;let p=new Map;for(let w of e.chicks){if(w.stage==="flying")continue;let k=c(w.x,w.y);p.has(k)||p.set(k,[]),p.get(k).push(w)}return d.spatial=p,d.spatialRevision=d.chickRevision,p}function g(d){let p=h(),w=Math.floor(d.x/f.cell),k=Math.floor(d.y/f.cell),S=[];for(let A=k-1;A<=k+1;A+=1)for(let E=w-1;E<=w+1;E+=1){let W=p.get(`${E},${A}`);W&&S.push(...W)}return S}function C(d){return Wt(d)*go(d)*Hs(e)/Qi(e)}function P(d){let p=$(d.col,d.row),w=1+Ks(e,d),k=K(d,w);if(!k.length)return L(d,p),!0;let S=0,A=0;for(let E of k){let W=$(E.col,E.row),ae=j(W);if(ae){ae.stoppedTimer=.85,A+=1;continue}let ve=na(e,{stage:"belt",scannerId:null,route:[W]});ve.sex==="poop"&&ma(e),e.chicks.push(ve),r(),Rs(e,d),S+=1}return S>0?(vs(e,p.x,p.y),S>1&&H(e,p.x,p.y-28,`x${S}`,b.green),!0):A===0}function L(d,p){(d.noRouteNoticeCooldown||0)<=0&&(H(e,p.x,p.y-24,"NO BELT: PAUSED",b.warn),d.noRouteNoticeCooldown=2.5)}function K(d,p){let k=fe.map(S=>({col:d.col+S.dc,row:d.row+S.dr})).filter(S=>$e(S.col,S.row)&&e.conveyorTiles.has(I(S.col,S.row))).map(S=>({p:S,blocked:le(null,$(S.col,S.row))?1:0,roll:Math.random()}));return k.sort((S,A)=>S.blocked-A.blocked||S.roll-A.roll),k.slice(0,Math.max(1,p||1)).map(S=>S.p)}function j(d){return g(d).find(p=>Math.hypot(p.x-d.x,p.y-d.y)0;if(e.timeLeft=Math.max(0,e.timeLeft-d),k&&e.timeLeft<=0&&p(),e.timeLeft<=0){e.shutdownTimeLeft>0&&(e.shutdownTimeLeft=Math.max(0,e.shutdownTimeLeft-d));for(let S of e.eggFarms)S.shutterProgress=Math.min(1,(S.shutterProgress||0)+d*2.8)}if(k&&e.timeLeft>0){for(let S of e.eggFarms)if(S.noRouteNoticeCooldown>0&&(S.noRouteNoticeCooldown=Math.max(0,S.noRouteNoticeCooldown-d)),S.nextSpawn-=d,S.nextSpawn<=0){let A=P(S);S.nextSpawn=A?C(S):.15,S.lastInterval=S.nextSpawn}}for(let S=e.chicks.length-1;S>=0;S-=1){let A=e.chicks[S];A.bob+=d*7,A.stoppedTimer>0&&(A.stoppedTimer=Math.max(0,A.stoppedTimer-d)),A.stage!=="queued"&&ke(A,S,d)}Oe(d),Nt(e.frameId),jn(),e.timeLeft<=0&&(e.chicks.length===0?w():e.shutdownTimeLeft<=0&&Q())}function Q(){if(e.cleanupBlown)return;e.cleanupBlown=!0,e.cleanupTimer=1;let d=[...e.chicks];for(let p of d)Tr(e,p.sex,p.x,p.y,-Math.PI/2,!0);e.chicks=[];for(let p of e.scanners)p.queue=[];if(r(),Nt(e.frameId),d.length){let p=d.reduce((k,S)=>k+S.x,0)/d.length,w=d.reduce((k,S)=>k+S.y,0)/d.length;at(e,p,w,b.warn,58),H(e,p,w-24,"CLEANUP",b.warn)}}function ke(d,p,w){if(pe(d)){d.stoppedTimer=.35;return}if(B(d,w),!(d.route&&d.targetIndex=d.route.length)return!1;let p=d.route[d.targetIndex];return le(d,p)}function le(d,p){if(!p)return!1;for(let w of g(p))if(!(d&&w.id===d.id)&&Math.hypot(w.x-p.x,w.y-p.y)1)&&d.push({x:p.x,y:p.y})}function D(d){let p=e.conveyorMeta?.get?.(d)||{},w=[];Array.isArray(p.outDirs)&&w.push(...p.outDirs),p.dir&&w.push(p.dir);let k=[...new Set(w)].filter(ve=>fe.some(en=>en.name===ve)),S=re(d),A=fe.filter(ve=>De(S,ve.name,null)).map(ve=>ve.name),E=k.filter(ve=>A.includes(ve)),W=fe.filter(ve=>e.conveyorTiles.has(I(S.col+ve.dc,S.row+ve.dr))).map(ve=>ve.name);if(W.length===1&&(!E.length||E.includes(W[0]))&&me(S,W[0]))return E.filter(ve=>ve!==W[0]);let ae=A;return E.length?E:ae}function U(d){return fe.find(p=>p.name===d)||null}function ee(d,p){return e.scanners.find(w=>w.col<=d&&d<=w.col+1&&w.row-1<=p&&p<=w.row)||null}function O(d,p){let w=U(p);if(!w)return null;let k=ee(d.col+w.dc,d.row+w.dr);if(!k)return null;let S=Fe(k,"inputA");return S&&S.col===d.col&&S.row===d.row?k:null}function G(d){return Object.entries(e.facilities||{}).find(([,p])=>p?.entry&&p.entry.col===d.col&&p.entry.row===d.row)||null}function Y(d){return d?.baseId||d?.id||""}function ie(d,p){return d?.gridPlaced&&Y(d)==="sausageMaker"?p==="right":d.side==="left"&&p==="left"||d.side==="right"&&p==="right"||d.side==="top"&&p==="up"||d.side==="bottom"&&p==="down"}function De(d,p,w=null){let k=U(p);if(!k)return null;let S={col:d.col+k.dc,row:d.row+k.dr};if($e(S.col,S.row)&&e.conveyorTiles.has(I(S.col,S.row)))return{type:"conveyor",dirName:p,target:$(S.col,S.row),nextCell:S};let A=O(d,p);if(A&&!["meat","sausage"].includes(w?.sex))return{type:"scanner",dirName:p,target:ge(A),scanner:A};let E=G(d);return E&&ie(E[1],p)?{type:"facility",dirName:p,facilityId:E[0],facility:E[1],target:$(d.col,d.row)}:null}function me(d,p){let w=U(p);if(!w)return!1;let k=e.conveyorMeta?.get?.(I(d.col+w.dc,d.row+w.dr));return k?[...new Set([...Array.isArray(k.outDirs)?k.outDirs:[],k.dir].filter(Boolean))].includes(w.opposite):!1}function T(d){return fe.filter(p=>$e(d.col+p.dc,d.row+p.dr)&&e.conveyorTiles.has(I(d.col+p.dc,d.row+p.dr))).map(p=>p.name)}function M(d,p,w="random"){let k=T(d);if(k.length<3)return p;let S=new Set(k.filter(W=>me(d,W))),A=k.filter(W=>!S.has(W)),E=S.size?A:[...new Set(p.filter(W=>k.includes(W)))];return!E.length&&!S.size&&(E=k),w&&w!=="random"&&w!=="pass"&&E.length>=2&&E.includes(w)?[w]:E}function q(d,p){return p&&(p.type==="facility"||!le(d,p.target))}function ne(d,p,w,k="random"){let S=w.map(ae=>De(p,ae,d)).filter(Boolean);if(!S.length)return null;let E=S.filter(ae=>ae.type!=="facility").filter(ae=>!le(d,ae.target)),W=E.length?E:S.filter(ae=>ae.type==="facility");return W.length?W[Math.floor(Math.random()*W.length)]:null}function oe(d,p){let w=[];ue(w,{x:d.x,y:d.y}),ue(w,p),d.route=w.length?w:[{x:d.x,y:d.y}],d.targetIndex=d.route.length>1?1:d.route.length}function se(d,p){let w=tt(d.x,d.y);if(!w)return Zt(p,"OFF GRID");let k=I(w.col,w.row);if(!e.conveyorTiles.has(k))return Zt(p,"OFF BELT");let S=e.conveyorMeta?.get(k)||{},A=M(w,D(k),S.branchMode||"random");if(!A.length){d.stoppedTimer=.25;return}let E=ne(d,w,A,S.branchMode||"random");if(!E){d.stoppedTimer=.25;return}if(E.type==="facility"){let W=Y(E.facility);W==="mixer"?Vn(p,E.facility):W==="truck"?kn(p,E.facility):W==="trash"?Mn(p,E.facility):W==="sausageMaker"?Xn(p,E.facility):Zt(p,"DONE");return}E.type==="scanner"&&(d.pendingScannerId=E.scanner.id),d.prevConveyorCell=k,oe(d,E.target)}function Se(d){let p=tt(d.x,d.y);if(!p)return null;let w=I(p.col,p.row);return e.conveyorTiles.has(w)?w:null}function be(d){let p=Se(d)||Se(d.route?.[d.targetIndex]||d);return t(p)}function Ce(d,p){let w=Se(p);!w||d.lastWearKey===w||(d.lastWearKey=w,Es(e,w))}function B(d,p){let w=be(d)*p;for(;w>0&&d.targetIndex=E?(d.x=k.x,d.y=k.y,Ce(d,k),d.targetIndex+=1,w-=E,i()):(d.x+=S/E*w,d.y+=A/E*w,w=0,i())}}function ye(d,p,w){d.stage="queued",d.route=null,d.queueRoute=w?w.map(k=>({x:k.x,y:k.y})):[ge(p)],d.scannerId=p.id,p.queue.includes(d.id)||p.queue.push(d.id),r(),Be(p)}function Be(d){d.queue=d.queue.filter(w=>e.chicks.some(k=>k.id===w&&k.stage==="queued"));let p=f.cell*.86*qs(e);d.queue.forEach((w,k)=>{let S=e.chicks.find(A=>A.id===w);S&&(de(S,S.queueRoute||[ge(d)],k*p),S.queueIndex=k)})}function de(d,p,w){if(!p||!p.length)return;if(p.length===1||w<=0){let A=p[p.length-1];d.x=A.x,d.y=A.y,i();return}let k=w;for(let A=p.length-1;A>0;A-=1){let E=p[A-1],W=p[A],ae=Math.hypot(W.x-E.x,W.y-E.y);if(k<=ae){let ve=1-k/ae;d.x=E.x+(W.x-E.x)*ve,d.y=E.y+(W.y-E.y)*ve,i();return}k-=ae}let S=p[0];d.x=S.x,d.y=S.y,i()}function Oe(d){for(let p of e.scanners){if(p.cooldown>0&&(p.cooldown=Math.max(0,p.cooldown-d)),p.keyPressTime>0&&(p.keyPressTime=Math.max(0,p.keyPressTime-d)),Be(p),p.kind!=="auto"||p.cooldown>0||!p.queue.length)continue;let w=p.queue[0],k=e.chicks.findIndex(S=>S.id===w);if(k<0){p.queue.shift();continue}Sn(k,dr(p,e.chicks[k]),!0)&&(Ps(e,p),p.cooldown=St(p,e),ha(e))}}function ct(d){let p=ar(e,d);return!p||!p.queue.length?null:e.chicks.find(w=>w.id===p.queue[0])||null}function xt(d,p){if(e.phase!=="running")return;let w=ar(e,d);Le(w,p)}function Le(d,p){if(e.phase!=="running"||!d||d.kind!=="manual"||(d.keyPressTime=.18,d.keyPressSide=p,!d.queue.length))return;let w=e.chicks.findIndex(k=>k.id===d.queue[0]);w>=0&&Sn(w,p,!1)}function qn(d,p,w){return d.kind==="manual"&&dr(d,p)===w}function wn(d){let p=e.manualCombo?.count||0;if(e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=0,e.manualCombo.lastBonus=0,e.stats.manualComboFailure=(e.stats.manualComboFailure||0)+1,e.totals.manualComboFailure=(e.totals.manualComboFailure||0)+1,p>=10){let w=ge(d);Yt(e,10,.25),H(e,w.x,w.y-36,"COMBO RESET",b.danger)}}function No(d){e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=Math.max(0,e.manualCombo.count||0)+1,e.stats.manualComboSuccess=(e.stats.manualComboSuccess||0)+1,e.totals.manualComboSuccess=(e.totals.manualComboSuccess||0)+1;let p=e.manualCombo.count;if(e.manualCombo.lastBonus=0,p<10)return 0;let w=Math.max(1,Math.floor(p/10)),k=e.scanners.filter(W=>W.kind==="manual").length,S=Math.min(1,(20+k*10)/100),A=0;for(let W=0;W0){je(e,E),e.stats.manualComboBonus=(e.stats.manualComboBonus||0)+E,e.totals.manualComboBonus=(e.totals.manualComboBonus||0)+E,e.manualCombo.lastBonus=E;let W=ge(d);H(e,W.x,W.y-42,`COMBO +${x(E)}`,b.green)}return E}function Yn(d,p){let w=Fe(d,p);if(!w)return null;let k=I(w.col,w.row);if(e.conveyorTiles.has(k))return{...w};let A=(Je(e).scannerPorts.get(d.id)?.[p]?.keys||[]).filter(Boolean);if(!A.length)return null;let E=A.map(re).sort((ae,ve)=>{let en=$(ae.col,ae.row),ze=$(ve.col,ve.row),_t=le(null,en)?1:0,Tn=le(null,ze)?1:0;return _t-Tn});return E.find(ae=>ae.col===w.col&&ae.row===w.row)||E[0]||null}function Lt(d,p,w,k){let S=[];ue(S,{x:d.x,y:d.y});let A=Fe(p,w);return A&&ue(S,$(A.col,A.row)),ue(S,$(k.col,k.row)),S}function Sn(d,p,w){let k=e.chicks[d];if(!k||k.stage!=="queued")return!1;let S=Ht(e,k.scannerId);if(!S)return!1;let A=Yn(S,p);if(!A)return!w&&S.kind==="manual"&&wn(S),H(e,k.x,k.y-16,p==="left"?"NO LEFT BELT":"NO RIGHT BELT",b.danger),!1;!w&&S.kind==="manual"&&(qn(S,k,p)?No(S):wn(S)),S.queue=S.queue.filter(W=>W!==k.id),k.stage="belt",k.route=Lt(k,S,p,A),k.targetIndex=k.route.length>1?1:k.route.length,k.scannerId=null,k.nextScannerId=null,k.pendingScannerId=null,k.queueRoute=null,k.queueIndex=-1,r();let E=w?b.green:p==="left"?b.mixerBlue:b.truckPink;return ws(e,ge(S).x,ge(S).y,E),H(e,k.x,k.y-20,w?"AUTO":p.toUpperCase(),E),!0}function Tt(d){let p=e.chicks[d];return p?(e.chicks.splice(d,1),r(),p):null}function Vn(d,p=e.facilities.mixer){if(p?.processingCooldown>0){let E=e.chicks[d];E&&(E.stoppedTimer=.25);return}let w=Tt(d);if(!w)return;let{x:k,y:S}=w;if(ba(e),Mo(e,p),xo(e,p),w.sex==="meat"||w.sex==="sausage"){rt(e),H(e,k,S-18,"CHICKS ONLY",b.warn);return}if(w.sex==="poop"){let E=cs(e);Bo(e,"mixer"),rt(e),ks(e,k,S),H(e,k,S-18,`-${x(E)}`,b.danger);return}w.sex==="male"?hn(e):rt(e);let A=Xe(e,p);if(!A||!It(e,p)||!gn(A)){let E=ls(e);H(e,k,S-18,`DIRECT +${x(E)}`,b.green);return}p.meatBuffer=Math.max(0,p.meatBuffer||0)+1,e.stats.meatProduced=(e.stats.meatProduced||0)+1,e.totals.meatProduced=(e.totals.meatProduced||0)+1,Ss(e,k,S),H(e,k,S-18,"MEAT +1",b.meatRed),Cn()}function kn(d,p=e.facilities.truck){let w=Tt(d);if(!w)return;let{x:k,y:S}=w;Go(w.sex,p),Cs(e,k,S,w.sex),wa(e,w.sex);let A=ln(e),E=Zi(e,w.sex);if(w.sex==="sausage"){e.stats.sausageShipped=(e.stats.sausageShipped||0)+1,e.totals.sausageShipped=(e.totals.sausageShipped||0)+1,H(e,k,S-18,`SAUSAGE +${x(Ze(e))}`,b.sausageOrange);return}if(w.sex==="meat"){rt(e),H(e,k,S-18,"RAW MEAT REJECT",b.warn);return}if(w.sex==="poop"){if(Bo(e,"truck"),E)hn(e),H(e,k,S-18,`+${x(Ve(e))}`,b.green);else{let W=us(e);rt(e),H(e,k,S-18,`-${x(W)}`,b.danger)}return}if(w.sex==="female"){E?(hn(e),H(e,k,S-18,`+${x(Ve(e))}`,b.green)):(rt(e),H(e,k,S-18,A==="male"?"REJECT":"NO SALE",b.warn));return}if(E){hn(e),H(e,k,S-18,`+${x(Ve(e))}`,b.green);return}if(es(e)){let W=ds(e);rt(e),H(e,k,S-18,`-${x(W)}`,b.danger)}else rt(e),H(e,k,S-18,"REJECT",b.warn)}function _o(d,p){let w=$(p.col,p.row);return{id:e.nextId++,sex:d,x:w.x,y:w.y,route:[{x:w.x,y:w.y}],targetIndex:1,stage:"belt",scannerId:null,nextScannerId:null,pendingScannerId:null,radius:d==="sausage"?11:10,bob:Math.random()*Math.PI*2,queueIndex:-1,queueRoute:null,stoppedTimer:0}}function gn(d){if(!d||!e.conveyorTiles.has(I(d.col,d.row)))return!1;let p=$(d.col,d.row);return!le(null,p)}function zn(d,p,w){let k=Xe(e,d);if(!k||!It(e,d)||!gn(k)||Math.max(0,d[w]||0)<=0)return!1;d[w]-=1,e.chicks.push(_o(p,k)),r();let S=$(k.col,k.row);return H(e,S.x,S.y-16,p==="meat"?"MEAT OUT":"SAUSAGE OUT",p==="meat"?b.meatRed:b.sausageOrange),!0}function Cn(){for(let d of Object.values(e.facilities||{})){let p=Y(d);p==="mixer"&&zn(d,"meat","meatBuffer"),p==="sausageMaker"&&zn(d,"sausage","sausageBuffer")}}function Xn(d,p){if(p?.processingCooldown>0){let A=e.chicks[d];A&&(A.stoppedTimer=.25);return}let w=Tt(d);if(!w)return;let{x:k,y:S}=w;if(w.sex!=="meat"){rt(e),H(e,k,S-18,"MEAT ONLY",b.warn);return}Mo(e,p),xo(e,p),p.meatBuffer=Math.max(0,p.meatBuffer||0)+1,p.meatBuffer>=2?(p.meatBuffer-=2,p.sausageBuffer=Math.max(0,p.sausageBuffer||0)+1,e.stats.sausageProduced=(e.stats.sausageProduced||0)+1,e.totals.sausageProduced=(e.totals.sausageProduced||0)+1,H(e,k,S-18,"SAUSAGE +1",b.sausageOrange)):H(e,k,S-18,"MEAT 1/2",b.meatRed),Cn()}function Mn(d,p=e.facilities.trash){if(p?.processingCooldown>0){let W=e.chicks[d];W&&(W.stoppedTimer=.25);return}let w=Tt(d);if(!w)return;let{x:k,y:S}=w;gs(e,k,S,w.sex),va(e),Mo(e,p),xo(e,p);let A={amount:0},E="";if(w.sex==="poop"){A=is(e),E=A.amount>0?` ${A.tier==="jackpot"?"JACKPOT ":"+"}${x(A.amount)}`:" MISS",Bo(e,"trash"),hn(e);let W=Math.ceil(Math.max(0,Number(e.cardEffects?.composter)||0)*3*po(e));if(W>0){let ae=je(e,W);e.stats.composterIncome=(e.stats.composterIncome||0)+ae,e.totals.composterIncome=(e.totals.composterIncome||0)+ae,H(e,k,S-36,`COMPOST +${x(ae)}`,b.green)}H(e,k,S-18,`CLEAN${E}`,A.amount>0?b.green:b.green)}else rt(e),H(e,k,S-18,A.amount>0?`WASTE${E}`:"WASTE",A.amount>0?b.green:b.ink)}function Zt(d,p){let w=Tt(d);w&&H(e,w.x,w.y-12,p,b.muted)}function Go(d,p=e.facilities.truck){let w=p||e.facilities.truck;w&&(e.truckCargo.push({sex:d,x:z(22,w.w-22),y:z(66,w.h-24)}),e.truckCargo.length>45&&e.truckCargo.shift())}function Uo(d){let p=tt(d.x,d.y);if(p){let S=I(p.col,p.row);if(e.conveyorTiles.has(S))return S}if(!p)return null;let w=null,k=1/0;for(let S of[p,...fe.map(A=>({col:p.col+A.dc,row:p.row+A.dr}))]){if(!$e(S.col,S.row))continue;let A=I(S.col,S.row);if(!e.conveyorTiles.has(A))continue;let E=$(S.col,S.row),W=Math.hypot(d.x-E.x,d.y-E.y);Ww&&d.ratio=p){let k=xn(d.id);if(!k.length||k.some(E=>E.stage!=="queued"&&E.stoppedTimer<=.2))continue;let S=e.lastExplodedComponent.get(d.id)||0,A=performance.now();A-S>900&&(e.lastExplodedComponent.set(d.id,A),Wo(d))}}}function xn(d){return Nt(e.frameId||0),e.frameCache?.componentChicks?.get(d)||[]}function Wo(d){let p=xn(d.id);if(!p.length)return;for(let S of p)Tr(e,S.sex,S.x,S.y);e.chicks=e.chicks.filter(S=>!p.some(A=>A.id===S.id));for(let S of e.scanners)S.queue=S.queue.filter(A=>e.chicks.some(E=>E.id===A));r();for(let S of d.cells){let A=re(S),E=$(A.col,A.row);at(e,E.x,E.y,b.danger),bt(e,E.x,E.y,6),mo(e,E.x,E.y,4)}Yt(e,18,.75);let w=re(d.cells[0]),k=$(w.col,w.row);e.stats.explosions=(e.stats.explosions||0)+1,e.totals.explosions=(e.totals.explosions||0)+1,H(e,k.x,k.y-22,`${Math.round(wr(e)*100)}% JAM EXPLOSION`,b.danger)}return{activeQueuedChick:ct,beginFrame:a,currentSpawnDelay:C,sortSlot:xt,updateCongestion:Nt,sortScanner:Le,updateRunning:Z}}var he=document.getElementById("gameCanvas"),hu=he.getContext("2d"),F={shell:document.getElementById("gameShell"),money:document.getElementById("money"),turn:document.getElementById("turn"),timeLeft:document.getElementById("timeLeft"),phase:document.getElementById("phaseLabel"),comboCount:document.getElementById("comboCount"),eventBrief:document.getElementById("eventBrief"),speedBrief:document.getElementById("speedBrief"),turnProfit:document.getElementById("turnProfit"),mixerCount:document.getElementById("mixerCount"),truckFemaleCount:document.getElementById("truckFemaleCount"),truckMaleCount:document.getElementById("truckMaleCount"),poopCount:document.getElementById("poopCount"),buildStatus:document.getElementById("buildStatus"),turnSummary:document.getElementById("turnSummary"),modal:document.getElementById("modal"),modalTitle:document.getElementById("modalTitle"),modalBody:document.getElementById("modalBody"),modalActions:document.getElementById("modalActions"),hoverTooltip:document.getElementById("hoverTooltip"),manualScannerMonitor:document.getElementById("manualScannerMonitor"),debug:{panel:document.getElementById("debugPanel"),infiniteCash:document.getElementById("debugInfiniteCash"),dayInput:document.getElementById("debugDayInput"),setDay:document.getElementById("debugSetDayButton"),zeroTimer:document.getElementById("debugZeroTimerButton"),cardSelect:document.getElementById("debugCardSelect"),targetSelect:document.getElementById("debugTargetSelect"),eventSelect:document.getElementById("debugEventSelect"),grantCard:document.getElementById("debugGrantCardButton"),grantAllCards:document.getElementById("debugGrantAllCardsButton"),readout:document.getElementById("debugReadout")},buttons:{s1Left:document.getElementById("scanner1MixerButton"),s1Right:document.getElementById("scanner1TruckButton"),s2Left:document.getElementById("scanner2MixerButton"),s2Right:document.getElementById("scanner2TruckButton"),nextTurn:document.getElementById("nextTurnButton"),conveyor:document.getElementById("buildConveyorButton"),boostConveyor:document.getElementById("buildBoostConveyorButton"),eggFarm:document.getElementById("buildEggFarmButton"),autoScanner:document.getElementById("buildAutoScannerButton"),manualScanner:document.getElementById("buildManualScannerButton"),mixer:document.getElementById("buildMixerButton"),trash:document.getElementById("buildTrashButton"),truck:document.getElementById("buildTruckButton"),sausageMaker:document.getElementById("buildSausageMakerButton"),maintenanceRoom:document.getElementById("buildMaintenanceRoomButton"),erase:document.getElementById("eraseButton"),undo:document.getElementById("undoButton"),redo:document.getElementById("redoButton")}};function mu(){let e={conveyor:"conveyor",boostConveyor:"boostConveyor",eggFarm:"eggFarm",autoScanner:"autoScanner",manualScanner:"manualScanner",mixer:"mixer",trash:"trash",truck:"truck",sausageMaker:"sausageMaker",maintenanceRoom:"maintenanceRoom"};for(let[t,n]of Object.entries(e))F.buttons[t]&&(F.buttons[t].innerHTML=hi(n))}function bu(e){let t=new Set(e.tags||[]);return["upgradeEgg","crowdedFarming","hatchingFeed","extraEggOutlet"].includes(e.id)||t.has("EGG")?"Production / EGG":["upgradeTrash","poopRateBooster","composter","chemicalWeaponSubsidy"].includes(e.id)||t.has("POOP")?"Poop / Shredder":["upgradeAutoScanner","autoScannerTuning","scannerQueueSpacing"].includes(e.id)||t.has("SCANNER")?"Scanner":["bearing","dynamite"].includes(e.id)||t.has("CONVEYOR")?"Conveyor / Map":["safetyCover","preventiveMaintenance","durabilityCoating","sparePartsBin","laborExploitation"].includes(e.id)||t.has("MAINTENANCE")?"Maintenance / Risk":["dudFilter","dudRefund","freeReroll","extraCards"].includes(e.id)||t.has("CARD")?"Card Engine":t.has("ULTRA RARE")?"Ultra Rare":t.has("ECONOMY")||["upgradeMixer","upgradeTruck","upgradeSausageMaker","recyclingSubsidy","usedMachine","newMachine","flattery","legalWork","rescueLoan"].includes(e.id)?"Economy / Shipment":"Other"}function vu(){if(!F.debug?.panel||!F.debug.cardSelect)return;let e=["Production / EGG","Poop / Shredder","Scanner","Conveyor / Map","Maintenance / Risk","Card Engine","Economy / Shipment","Ultra Rare","Other"],t=new Map(e.map(n=>[n,[]]));for(let n of fn){let o=bu(n);t.has(o)||t.set(o,[]),t.get(o).push(n)}F.debug.cardSelect.innerHTML="";for(let n of e){let o=t.get(n)||[];if(!o.length)continue;let r=document.createElement("optgroup");r.label=n;for(let i of o){let a=document.createElement("option");a.value=i.id;let c=i.rarity==="ultraRare"?"UR":i.rarity==="rare"?"R":"C";a.textContent=`[${c}] ${i.title}`,r.appendChild(a)}F.debug.cardSelect.appendChild(r)}F.debug.cardSelect.addEventListener("change",Jt),wu(),Jt()}function wu(){if(!F.debug?.eventSelect)return;F.debug.eventSelect.innerHTML="";let e=document.createElement("option");e.value="__roll__",e.textContent="Roll normally",F.debug.eventSelect.appendChild(e);let t=document.createElement("option");t.value="__none__",t.textContent="No event",F.debug.eventSelect.appendChild(t);for(let n of Fn){let o=document.createElement("option");o.value=n.key,o.textContent=n.title,F.debug.eventSelect.appendChild(o)}F.debug.eventSelect.value=u.debugNextEventKey||"__roll__",F.debug.eventSelect.addEventListener("change",ku)}function Ma(){let e=u.debugNextEventKey||"__roll__";return e==="__none__"?null:e==="__roll__"?Vi(u):hr(u,e)}function Jt(){if(!F.debug?.targetSelect)return;let e=F.debug.cardSelect?.value,t=Xt(e),n=t?Ys(u,t):[];if(F.debug.targetSelect.innerHTML="",!n.length){let r=document.createElement("option");r.value="__none__",r.textContent=t?"No target required":"No card selected",F.debug.targetSelect.appendChild(r),F.debug.targetSelect.disabled=!0;return}let o=document.createElement("option");o.value="__auto__",o.textContent=t?.id==="dynamite"?"Auto: first 10 blocked cells":"Auto: first valid target",F.debug.targetSelect.appendChild(o);for(let r of n){let i=document.createElement("option");i.value=r.key,i.textContent=r.label,F.debug.targetSelect.appendChild(i)}F.debug.targetSelect.disabled=!1}function Su(){let e=Math.max(1,Math.floor(Number(F.debug.dayInput?.value)||1));u.turn=e,F.debug.dayInput&&(F.debug.dayInput.value=String(e)),H(u,he.width/2-u.view.x,86-u.view.y,`DAY ${e}`,b.green),J.updatePanels(),J.updateUI(),Jt(),Ot(`Day set to ${e}.`)}function ku(){u.debugNextEventKey=F.debug.eventSelect?.value||"__roll__",u.phase==="build"&&(u.eventOffer=Ma(),J.updatePanels(),J.updateUI());let e=F.debug.eventSelect?.selectedOptions?.[0]?.textContent||"Roll normally";Ot(`Next event: ${e}.`)}function gu(){let e=u.phase==="running"&&(u.timeLeft<=0||u.shutdownTimeLeft>0||u.cleanupTimer!==null);u.timeLeft=0,u.cleanupTimer!==null&&(u.cleanupTimer=0),e?u.shutdownTimeLeft=0:u.phase==="running"&&Ea(),H(u,he.width/2-u.view.x,86-u.view.y,"TIMER 0",b.warn),J.updatePanels(),J.updateUI(),Ot("Timer set to 0.")}function Cu(){let e=F.debug.cardSelect?.value,t=F.debug.targetSelect?.disabled?void 0:F.debug.targetSelect?.value,n=Nr(u,e,{targetKey:t});F.debug.grantCard&&(F.debug.grantCard.textContent=n.ok?"Granted":"Failed",window.setTimeout(()=>{F.debug.grantCard&&(F.debug.grantCard.textContent="Grant Selected")},900)),Ae?.updateCongestion?.(u.frameId||0),J.updatePanels(),J.updateUI(),Jt(),Ot(n.reason)}function Mu(){let t=fn.map(n=>Nr(u,n,{targetKey:"__auto__"})).filter(n=>n.ok).length;Ae?.updateCongestion?.(u.frameId||0),J.updatePanels(),J.updateUI(),Jt(),Ot(`Granted ${t}/${fn.length} cards.`)}function xu(){F.debug?.infiniteCash?.checked&&u.cash<999999&&(u.cash=999999,u.totals.maxCash=Math.max(u.totals.maxCash,u.cash))}function Ot(e=""){F.debug?.readout&&(F.debug.readout.textContent=[e,`D${u.turn}`,x(u.cash),`Combo ${u.manualCombo?.count||0}`,`Event ${u.eventActive?.title||u.eventOffer?.title||"none"}`,`Next ${F.debug?.eventSelect?.selectedOptions?.[0]?.textContent||"Roll normally"}`,`Rescue ${u.cardEffects?.rescueLoanCharges||0}`,`Chem ${u.cardEffects?.chemicalWeaponSubsidy||0}`].filter(Boolean).join(" | "))}var u=rr(),te,J,Ae,bn;function Tu(e=null){let t=pn(u,e);return e?t*_n(u,e):t}function Eu(){Object.assign(u,rr()),u.phase="running",u.view={x:0,y:0,scale:1},ir(u),Pa(),Re(u),J.hideModal(),Ae.updateCongestion(u.frameId||0),J.updatePanels(),J.updateUI(),Ot()}function Ru(){if(u.phase!=="build")return;if(u.cardDraft?.pending||u.cardTargetPick?.pending){te.fail(u.cardTargetPick?.pending?"Choose upgrade target first.":"Choose an upgrade card first."),J.updatePanels();return}let e=fo(u);if(e.length){Du(),te.fail(`Cannot start: ${e[0]}`),J.updatePanels();return}Re(u),Ui(u),Fs(u);let t=Math.max(0,Math.floor(u.lastResult?.profit??u.stats?.profit??0)),n=ys(u,Math.max(1,u.turn||1),t);u.lastStartFees={fairiesTribute:n.amount||0,tribute:n},n.amount>0&&H(u,he.width/2-u.view.x,116-u.view.y,`FAIRIES -${x(n.amount)}`,b.danger),zi(u),u.phase="running",u.turn+=1,u.timeLeft=ji(u),u.shutdownTimeLeft=0,u.cleanupTimer=null,u.cleanupBlown=!1,u.chicks=[],u.effects=[],u.floatingTexts=[],u.shake={time:0,strength:0},u.truckCargo=[],Pa(),u.stats=or(),u.stats.fairiesTribute=u.lastStartFees?.fairiesTribute||0,u.stats.fairiesTribute>0&&(u.stats.penalty+=u.stats.fairiesTribute,u.stats.profit-=u.stats.fairiesTribute);for(let o of u.scanners)o.queue=[],o.cooldown=0;for(let o of u.eggFarms)o.nextSpawn=Ae.currentSpawnDelay(o),o.lastInterval=o.nextSpawn,o.shutterProgress=0,o.shutterSparked=!1;u.buildTool=null,u.selected=null,u.groupDrag=null,u.selectionBox=null,u.pan=null,Ae.updateCongestion(u.frameId||0),J.updatePanels(),J.updateUI()}function Pu(){if(u.phase!=="running")return;let e=ps(u),t=u.eventActive?{...u.eventActive}:null,n=os(u),o=hs(u);if(e.adjusted>0){let i=u.facilities.truck,a=i?i.x+i.w/2:he.width/2-u.view.x,c=i?i.y+26:96-u.view.y;H(u,a,c,`${e.target==="poop"?"POOP SHIP":"SHIP"} +${x(e.adjusted)}`,b.green)}n?.bonus>0&&H(u,he.width/2-u.view.x,96-u.view.y,`EVENT +${x(n.bonus)}`,b.green),o.amount>0&&H(u,he.width/2-u.view.x,116-u.view.y,`CHEM SUBSIDY +${x(o.amount)}`,b.green),Xi(u),u.totals.turnsCompleted+=1;let r=ns(t);if(r!==1&&(u.pendingFairiesTributeMultiplier=r),u.lastResult={...u.stats,ship:e,event:n,chemical:o,rescue:{amount:0,used:0,remaining:u.cardEffects?.rescueLoanCharges||0},fairiesTribute:{amount:u.stats.fairiesTribute||0},tributeMultiplier:r,turn:u.turn,cash:u.cash},u.cash<0){if((u.cardEffects?.rescueLoanCharges||0)>0){u.phase="loanDecision",J.showEmergencyLoanDecision(Ta,Oo);return}u.phase="gameover",J.showGameOver();return}xa()}function xa(){u.phase="build",u.truckCargo=[],u.chicks=[],u.shutdownTimeLeft=0,u.cleanupTimer=null,u.cleanupBlown=!1,u.buildSession+=1,u.undoStack=[],u.redoStack=[],u.timeLeft=0;for(let e of u.scanners)e.queue=[];for(let e of u.eggFarms)e.shutterProgress=0,e.shutterSparked=!1;Ds(u),u.eventOffer=Ma(),bn&&bn.prepareDraft(),u.cardTargetPick=null,u.buildTool=null,u.groupDrag=null,u.selectionBox=null,u.pan=null,J.updatePanels(),J.showTurnResult(u.lastResult)}function Ta(){if((u.cardEffects?.rescueLoanCharges||0)<=0)return Oo();u.cardEffects.rescueLoanCharges-=1,u.stats.rescueLoan=(u.stats.rescueLoan||0)+500,u.totals.rescueLoan=(u.totals.rescueLoan||0)+500;let e=je(u,500);u.lastResult={...u.lastResult||{},...u.stats,rescue:{amount:(u.lastResult?.rescue?.amount||0)+e,used:(u.lastResult?.rescue?.used||0)+1,remaining:u.cardEffects.rescueLoanCharges},cash:u.cash},H(u,he.width/2-u.view.x,176-u.view.y,`RESCUE +${x(e)}`,b.green),u.cash>=0?xa():(u.cardEffects?.rescueLoanCharges||0)>0?(u.phase="loanDecision",J.showEmergencyLoanDecision(Ta,Oo)):Oo()}function Oo(){u.phase="gameover",J.showGameOver()}function Ea(){u.shutdownTimeLeft<=0&&(u.shutdownTimeLeft=u.shutdownGraceSeconds||10);for(let e of u.eggFarms){if(e.shutterSparked)continue;e.shutterProgress=.02,e.shutterSparked=!0;let t=$(e.col,e.row);at(u,t.x,t.y,b.ink),bt(u,t.x,t.y+10,10),H(u,t.x,t.y-34,"SHUT +10s",b.ink)}}function Ra(e){u.lastTimestamp||(u.lastTimestamp=e);let t=Math.min((e-u.lastTimestamp)/1e3,.05);u.lastTimestamp=e,u.frameId=(u.frameId||0)+1,Ae.beginFrame?.(u.frameId),u.phase==="running"&&Ae.updateRunning(t,{closeFarmShutters:Ea,completeTurn:Pu}),xs(u,t,he,te.equipmentHitBoxes),Ae.updateCongestion(u.frameId),sa(hu,he,u,{activeQueuedChick:Ae.activeQueuedChick,selectedObject:te.selectedObject,selectedTitle:te.selectedTitle}),xu(),J.updateUI(),Ia(),Ot(),requestAnimationFrame(Ra)}function Kn(){return u.view?.scale||1}function vn(){u.view||(u.view={x:0,y:0,scale:1}),u.view.scale==null&&(u.view.scale=1)}function Lo(e){let t=he.getBoundingClientRect();return{x:(e.clientX-t.left)*he.width/t.width,y:(e.clientY-t.top)*he.height/t.height}}function Bt(e){let t=Lo(e),n=Kn();return{x:(t.x-(u.view?.x||0))/n,y:(t.y-(u.view?.y||0))/n}}function Au(e){let t=Kn();return{x:e.x*t+(u.view?.x||0),y:e.y*t+(u.view?.y||0)}}function Iu(){let e={left:f.x-90,top:f.y-130,right:f.x+f.cols*f.cell+260,bottom:f.y+f.rows*f.cell+220};if(u.phase==="build")for(let t of Ut(u)){let n=dt(t);e.left=Math.min(e.left,n.x-60),e.top=Math.min(e.top,n.y-80),e.right=Math.max(e.right,n.x+n.w+80),e.bottom=Math.max(e.bottom,n.y+n.h+80)}return e}function ka(e,t){if(e<=t)return[e,t];let n=(e+t)/2;return[n,n]}function Ct(){vn();let e=Kn(),t=Iu(),[n,o]=ka(he.width-160-t.right*e,110-t.left*e),[r,i]=ka(he.height-150-t.bottom*e,150-t.top*e);u.view.x=An(u.view.x,n,o),u.view.y=An(u.view.y,r,i)}function Pa(){vn(),u.view.scale=1;let e=u.eggFarms?.[0],t=e?$(e.col,e.row):{x:f.x,y:f.y};u.view.x=280-t.x,u.view.y=190-t.y,Ct()}function $u(e){if(!e)return!1;vn();let t=Kn();return u.view.x=he.width/2-e.x*t,u.view.y=he.height/2-e.y*t,Ct(),!0}function Fu(e){let t=e?.ref;return t?e.type==="facility"?{x:t.x+t.w/2,y:t.y+t.h/2}:e.type==="eggFarm"?$(t.col,t.row):e.type==="scanner"?{x:$(t.col,t.row).x+f.cell/2,y:$(t.col,t.row).y}:e.type==="maintenanceRoom"?{x:$(t.col,t.row).x+f.cell/2,y:$(t.col,t.row).y+f.cell/2}:null:null}function Du(){let e=an(u),t=e.find(o=>o.type==="facility")||e[0]||Bu(),n=Fu(t);$u(n)&&t&&(u.selected={type:t.type,id:t.id})}function Bu(){let e=Object.values(u.facilities||{}).find(o=>o?.entry&&u.conveyorTiles.has(I(o.entry.col,o.entry.row)))||Object.values(u.facilities||{})[0];if(e)return{type:"facility",id:e.id,ref:e};let t=u.scanners?.find(o=>o);if(t)return{type:"scanner",id:t.id,ref:t};let n=u.eggFarms?.[0];return n?{type:"eggFarm",id:n.id,ref:n}:null}function Ou(e){let t=Lo(e);vn(),u.pan={start:t,viewX:u.view.x,viewY:u.view.y,moved:!1}}function Lu(e){if(!u.pan)return;let t=Lo(e);Math.hypot(t.x-u.pan.start.x,t.y-u.pan.start.y)>5&&(u.pan.moved=!0),vn(),u.view.x=u.pan.viewX+t.x-u.pan.start.x,u.view.y=u.pan.viewY+t.y-u.pan.start.y,Ct()}function Nu(e){e.preventDefault(),vn();let t=Lo(e),n=Bt(e),o=Math.exp(-e.deltaY*.0012),r=An(Kn()*o,.55,1.8);u.view.scale=r,u.view.x=t.x-n.x*r,u.view.y=t.y-n.y*r,Ct(),Mt()}function _u(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:{type:e.type,id:e.ref.id}:null}function Gu(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:e.ref||null:null}function Mt(){F.hoverTooltip&&(F.hoverTooltip.classList.remove("visible"),F.hoverTooltip.setAttribute("aria-hidden","true"),u.hover=null)}function Uu(e,t){if(!F.hoverTooltip||u.phase!=="build"||u.cardTargetPick?.pending||u.groupDrag||u.selectionBox||u.pan)return Mt();let n=Gu(t);if(!n)return Mt();let o=te.selectedTitle(n),r=te.flavorText?te.flavorText(n):"",i=te.disconnectedWarningFor?te.disconnectedWarningFor(n):"",a=te.selectedInfoLines(n).slice(0,7);F.hoverTooltip.innerHTML=`${o}${i?`${i}`:r?`${r}`:""}${a.map(g=>`${g}`).join("")}`;let c=Math.min(window.innerWidth-330,e.clientX+18),h=Math.min(window.innerHeight-220,e.clientY+18);F.hoverTooltip.style.left=`${Math.max(8,c)}px`,F.hoverTooltip.style.top=`${Math.max(8,h)}px`,F.hoverTooltip.classList.add("visible"),F.hoverTooltip.setAttribute("aria-hidden","false"),u.hover={type:t.type,id:t.oldKey||t.ref?.id||null}}function Wu(e){if(u.phase!=="build")return Mt();Uu(e,te.equipmentAtPoint(Bt(e)))}function Aa(e){Mt();let t=Bt(e),n=te.equipmentAtPoint(t),o=_u(n);if(!o){u.selected=null,u.multiSelected=[],J.updatePanels();return}u.selected=o,u.multiSelected=[o],J.updatePanels();let r=te.selectedObject();r?.type==="scanner"&&r.kind==="manual"&&te.showManualScannerMenu(r),r?.type==="scanner"&&r.kind==="auto"&&te.showAutoScannerMenu(r)}function mn(){u.buildTool=null,u.selected=null,u.multiSelected=[],u.selectionBox=null,u.cardTargetPick?.mode==="autoScannerMenu"&&(u.cardTargetPick=null),J.hideModal(),Mt(),J.updatePanels(),J.updateUI()}function ga(e){return String(e).replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function Hu(e){let t=e?.queue?.[0];return t==null?null:u.chicks.find(n=>n.id===t)||null}function Ku(e){if(!e)return'WAIT';let t=e.sex==="poop"?"POOP":e.sex==="male"?"M MALE":"F FEMALE";return`${t}`}function qu(e,t){let n=new Set(u.eggFarms.map(C=>I(C.col,C.row))),o=new Map(u.scanners.map(C=>[I(C.col,C.row),C])),r=Fe(e,"inputA"),i=r?I(r.col,r.row):null,a=new Set(Object.values(u.facilities||{}).map(C=>C.entry?I(C.entry.col,C.entry.row):null).filter(Boolean)),c=t?.sex||"",h=c==="poop"?"P":c==="male"?"M":c==="female"?"F":"",g=[];for(let C=e.row-2;C<=e.row+2;C+=1)for(let P=e.col-2;P<=e.col+2;P+=1){let L=I(P,C),K=["mini-cell"],j="";P===e.col&&C===e.row?(K.push("scanner"),c&&K.push(c),j=h||"S"):L===i?(K.push("input"),j="IN"):n.has(L)?(K.push("egg"),j="E"):o.has(L)?(K.push("scanner-other"),j="S"):a.has(L)?(K.push("port"),j="P"):u.conveyorTiles.has(L)?(K.push("belt"),j="."):u.blockedCells?.has?.(L)&&(K.push("blocked"),j="X"),g.push(`${j}`)}return`
${g.join("")}
`}function Yu(e){let t=Au($(e.col,e.row)),n=76;return t.x<-n||t.y<-n||t.x>he.width+n||t.y>he.height+n}function Ia(){if(!F.manualScannerMonitor)return;let e=u.frameCache||(u.frameCache={}),t=u.view||{},n=[u.phase,Math.round((t.x||0)*10),Math.round((t.y||0)*10),Math.round((t.scale||1)*100),u.chicks.length,u.scanners.map(r=>[r.id,r.kind,r.col,r.row,r.queue?.join(",")||"",r.keyPressSide||"",Math.ceil((r.keyPressTime||0)*10)].join(":")).join("|")].join(";");if(e.manualMonitorSignature===n)return;if(e.manualMonitorSignature=n,u.phase!=="running"){F.manualScannerMonitor.classList.remove("visible"),F.manualScannerMonitor.innerHTML="";return}let o=u.scanners.filter(r=>r.kind==="manual"&&Yu(r));if(!o.length){F.manualScannerMonitor.classList.remove("visible"),F.manualScannerMonitor.innerHTML="";return}F.manualScannerMonitor.innerHTML=o.map(r=>{let i=Hu(r),a=r.keys?.left?.label||(r.slot===0?"A":"Left"),c=r.keys?.right?.label||(r.slot===0?"D":"Right"),h=r.role===0?"MIXER":"WASTE",g=r.role===0?"S2":"TRUCK",C=i?"":" disabled";return` +
Formula
Base = Cash + Total revenue + Factory value \xD70.5 + Event bonus \xD70.5 = ${R(oe.base)}
Daily earned = ceil(Base \xF7 Days) = ${R(oe.dailyEarned)}
Score = max(0, floor(Base + Daily earned + Correct bonus - Total outflow - Day penalty)) = ${oe.score}
+
Factory Value${R(oe.factoryValue)}
Total Revenue${R(e.totals.revenue)}
Daily Earned${R(oe.dailyEarned)} / day
Total Outflow${R(e.totals.penalty)}
Fairies Tribute${R(e.totals.fairiesTribute||0)}
Correct Sorts${e.totals.correct}
Auto Sorted${e.totals.autoSorted}
Poop Control${e.totals.poopTrash} trashed / ${e.totals.poopTruck} shipped / ${e.totals.poopMixer} mixer
Explosion Penalty${R(e.totals.explosionDamage)}
Event Bonus${R(e.totals.eventBonus)}
Day Penalty-${oe.dayPenalty}
Events${e.totals.eventSuccess} success / ${e.totals.eventFailed} failed
+ `,t.modalActions.innerHTML="",t.modalActions.appendChild(L(pe.actions.restart||"Restart",o,"primary-button restart-button")),t.modal.classList.remove("equipment-popover"),t.modal.classList.add("visible","gameover-modal")}function L(O,H,oe="primary-button"){let ue=document.createElement("button");return ue.type="button",ue.className=oe,ue.textContent=O,ue.addEventListener("click",H),ue}function V(){t.modal.classList.remove("visible","equipment-popover","gameover-modal"),t.modal.style.removeProperty("--popover-x"),t.modal.style.removeProperty("--popover-y")}function se(){}return{updatePanels:M,updateUI:G,showTitle:ie,showTurnResult:J,showEmergencyLoanDecision:ae,showGameOver:ye,hideModal:V,checkGameOver:se}}function ki(e){e.totals.processed+=1}function Fn(e){e.stats.correct+=1,e.totals.correct+=1}function vt(e){e.stats.mistakes+=1,e.totals.mistakes+=1}function ja(e){e.stats.autoSorted+=1,e.totals.autoSorted+=1}function Ja(e){e.stats.poopSpawned+=1}function Za(e){e.stats.mixerCount+=1,ki(e)}function el(e){e.stats.trashCount+=1,ki(e)}function tl(e,t){t==="female"?e.stats.truckFemale+=1:t==="male"&&(e.stats.truckMale+=1),ki(e)}function nr(e,t){let n=t==="truck"?"poopTruck":t==="trash"?"poopTrash":t==="mixer"?"poopMixer":null;n&&(e.stats[n]+=1,e.totals[n]+=1)}function wd(e){let t=2166136261;for(let n=0;n>>0)%1e5/1e5}function Mi(e={}){let t=_.imports.combinedLimitPerTruck,n=Math.max(0,Math.floor(Number(e.coalPerDay)||0)),o=Math.max(0,Math.floor(Number(e.zundaMochiPerDay)||0));if(n+o>t){let r=t/Math.max(1,n+o);n=Math.floor(n*r),o=Math.max(0,t-n)}return{coalPerDay:n,zundaMochiPerDay:o}}function md(e={}){let t=Mi(e);return t.coalPerDay*_.imports.prices.coal+t.zundaMochiPerDay*_.imports.prices.zundaMochi}function vd(e,t="imports"){let n=Mi(e),o=[...Array.from({length:n.coalPerDay},()=>({type:"coal"})),...Array.from({length:n.zundaMochiPerDay},()=>({type:"zundaMochi"}))],r=Math.max(1,o.length);return o.map((i,a)=>{let c=yt/r,b=(a+.5)/r*yt,M=(wd(`${t}:${i.type}:${a}`)*2-1)*_.imports.jitterRatio*c;return{type:i.type,due:Math.max(0,Math.min(yt,b+M)),released:!1}}).sort((i,a)=>i.due-a.due||i.type.localeCompare(a.type))}function nl(e){e.imports={schedules:new Map};for(let t of Object.values(e.facilities||{})){if((t.baseId||t.id)!=="inboundTruck")continue;t.inboundOrder=Mi(t.inboundOrder),t.inboundQueue=[],t.importClock=0;let n=md(t.inboundOrder);n>0&&(Mt(e,n),e.stats.importPurchaseCost=(e.stats.importPurchaseCost||0)+n,e.stats.coalOrdered=(e.stats.coalOrdered||0)+t.inboundOrder.coalPerDay,e.stats.zundaOrdered=(e.stats.zundaOrdered||0)+t.inboundOrder.zundaMochiPerDay,e.totals.importPurchaseCost=(e.totals.importPurchaseCost||0)+n,e.totals.coalOrdered=(e.totals.coalOrdered||0)+t.inboundOrder.coalPerDay,e.totals.zundaOrdered=(e.totals.zundaOrdered||0)+t.inboundOrder.zundaMochiPerDay),e.imports.schedules.set(t.id,vd(t.inboundOrder,`${e.runSeed}:${e.turn}:${t.id}`))}}function Sd(e,t){if(!t||!e.conveyorTiles.has(E(t.col,t.row)))return!1;let n=B(t.col,t.row);return!e.chicks.some(o=>o.stage!=="flying"&&Math.hypot(o.x-n.x,o.y-n.y)<25)}function kd(e,t,n){let o=B(n.col,n.row);return{id:e.nextId++,sex:t,x:o.x,y:o.y,route:[{x:o.x,y:o.y}],targetIndex:1,stage:"belt",scannerId:null,nextScannerId:null,pendingScannerId:null,radius:t==="coal"?10:11,bob:0,queueIndex:-1,queueRoute:null,stoppedTimer:0}}function ol(e,t,n=()=>{}){if(e.phase==="running")for(let o of Object.values(e.facilities||{})){if((o.baseId||o.id)!=="inboundTruck"||!nt(e,o))continue;o.importClock=(o.importClock||0)+t;let r=e.imports?.schedules?.get(o.id)||[];for(let b of r)!b.released&&b.due<=o.importClock&&(o.inboundQueue=o.inboundQueue||[],o.inboundQueue.push(b),b.released=!0);let i=He(e,o);if(!o.inboundQueue?.length||!kt(e,o)||!Sd(e,i))continue;let a=o.inboundQueue.shift(),c=a.type;a.delivered=!0,e.chicks.push(kd(e,c,i)),c==="coal"&&(e.stats.coalReleased=(e.stats.coalReleased||0)+1,e.totals.coalReleased=(e.totals.coalReleased||0)+1),c==="zundaMochi"&&(e.stats.zundaReleased=(e.stats.zundaReleased||0)+1,e.totals.zundaReleased=(e.totals.zundaReleased||0)+1),rn(e,o),n()}}function rl(e){for(let t of Object.values(e.facilities||{})){if((t.baseId||t.id)!=="inboundTruck")continue;let n=e.imports?.schedules?.get(t.id)||[];for(let o of n)o.delivered||(o.type==="coal"&&(e.stats.coalUndelivered=(e.stats.coalUndelivered||0)+1,e.totals.coalUndelivered=(e.totals.coalUndelivered||0)+1),o.type==="zundaMochi"&&(e.stats.zundaUndelivered=(e.stats.zundaUndelivered||0)+1,e.totals.zundaUndelivered=(e.totals.zundaUndelivered||0)+1));t.inboundQueue=[]}}function il({game:e,currentConveyorSpeed:t,onGameOverCheck:n}){function o(){return e.frameCache||(e.frameCache={frameId:-1,routingVersion:-1,chickRevision:0,spatialRevision:-1,spatial:new Map,congestionFrame:-1,componentChicks:new Map,manualMonitorSignature:"",draw:{}}),e.frameCache}function r(){let u=o();u.chickRevision=(u.chickRevision||0)+1,u.congestionFrame=-1}function i(){o().congestionFrame=-1}function a(u){let f=o();f.frameId!==u&&(f.frameId=u,f.spatialRevision=-1,f.congestionFrame=-1)}function c(u,f){return`${Math.floor(u/p.cell)},${Math.floor(f/p.cell)}`}function b(){let u=o();if(u.spatialRevision===u.chickRevision)return u.spatial;let f=new Map;for(let v of e.chicks){if(v.stage==="flying")continue;let k=c(v.x,v.y);f.has(k)||f.set(k,[]),f.get(k).push(v)}return u.spatial=f,u.spatialRevision=u.chickRevision,f}function M(u){let f=b(),v=Math.floor(u.x/p.cell),k=Math.floor(u.y/p.cell),S=[];for(let I=k-1;I<=k+1;I+=1)for(let A=v-1;A<=v+1;A+=1){let U=f.get(`${A},${I}`);U&&S.push(...U)}return S}function C(u){let f=Jt(u)*Yo(u)*Ra(e)/ks(e),v=io(e,u,f);return u.theoreticalRate=v,u.actualOutputRate=Math.min(v,Kt(e)),u.qualityMultiplier=so(v,Kt(e)),Math.max(.25,za(v,Kt(e)))}function $(u){let f=B(u.col,u.row),v=1+Ia(e,u),k=K(u,v).slice(0,1);if(!k.length)return W(u,f),!0;let S=0,I=0;for(let A of k){let U=B(A.col,A.row),he=G(U);if(he){he.stoppedTimer=.85,I+=1;continue}let de=ta(e,{stage:"belt",scannerId:null,route:[U]}),Xe=u.theoreticalRate||io(e,u,u.lastInterval||C(u));de.sourceQuality=so(Xe,Kt(e)),e.stats.farmTheoreticalRate=Math.max(e.stats.farmTheoreticalRate||0,Xe),e.stats.farmActualOutputRate=Math.max(e.stats.farmActualOutputRate||0,Math.min(Xe,Kt(e))),e.stats.qualityMultiplierSum=(e.stats.qualityMultiplierSum||0)+de.sourceQuality,e.stats.qualityMultiplierCount=(e.stats.qualityMultiplierCount||0)+1,e.stats.maxQualityMultiplier=Math.max(e.stats.maxQualityMultiplier||1,de.sourceQuality),de.sex==="poop"&&Ja(e),e.chicks.push(de),r(),da(e,u),S+=1}return S>0?(Ws(e,f.x,f.y),S>1&&Y(e,f.x,f.y-28,`x${S}`,w.green),!0):I===0}function W(u,f){(u.noRouteNoticeCooldown||0)<=0&&(Y(e,f.x,f.y-24,"NO BELT: PAUSED",w.warn),u.noRouteNoticeCooldown=2.5)}function K(u,f){let k=fe.map(S=>({col:u.col+S.dc,row:u.row+S.dr})).filter(S=>Re(S.col,S.row)&&e.conveyorTiles.has(E(S.col,S.row))).map(S=>({p:S,blocked:ae(null,B(S.col,S.row))?1:0,roll:Math.random()}));return k.sort((S,I)=>S.blocked-I.blocked||S.roll-I.roll),k.slice(0,Math.max(1,f||1)).map(S=>S.p)}function G(u){return M(u).find(f=>Math.hypot(f.x-u.x,f.y-u.y)0;if(e.timeLeft=Math.max(0,e.timeLeft-u),k&&e.timeLeft<=0&&f(),e.timeLeft<=0){e.shutdownTimeLeft>0&&(e.shutdownTimeLeft=Math.max(0,e.shutdownTimeLeft-u));for(let S of e.eggFarms)S.shutterProgress=Math.min(1,(S.shutterProgress||0)+u*2.8)}if(k&&e.timeLeft>0){for(let S of e.eggFarms)if(S.noRouteNoticeCooldown>0&&(S.noRouteNoticeCooldown=Math.max(0,S.noRouteNoticeCooldown-u)),S.zundaBoostTime>0&&(S.zundaBoostTime=Math.max(0,S.zundaBoostTime-u)),S.nextSpawn-=u,S.nextSpawn<=0){let I=$(S);S.nextSpawn=I?C(S):.15,S.lastInterval=S.nextSpawn}}for(let S=e.chicks.length-1;S>=0;S-=1){let I=e.chicks[S];I.bob+=u*7,I.stoppedTimer>0&&(I.stoppedTimer=Math.max(0,I.stoppedTimer-u)),I.stage!=="queued"&&(ce(I,S)||ie(I,S,u))}ot(u),fn(e.frameId),dr(),e.timeLeft<=0&&(e.chicks.length===0?v():e.shutdownTimeLeft<=0&&Q())}function Q(){if(e.cleanupBlown)return;e.cleanupBlown=!0,e.cleanupTimer=1;let u=[...e.chicks];for(let f of u)Jr(e,f.sex,f.x,f.y,-Math.PI/2,!0);e.chicks=[];for(let f of e.scanners)f.queue=[];if(r(),fn(e.frameId),u.length){let f=u.reduce((k,S)=>k+S.x,0)/u.length,v=u.reduce((k,S)=>k+S.y,0)/u.length;gt(e,f,v,w.warn,58),Y(e,f,v-24,"CLEANUP",w.warn)}}function ie(u,f,v){if(J(u)){u.stoppedTimer=.35;return}if(Ke(u,v),!(u.route&&u.targetIndex=u.route.length)return!1;let f=u.route[u.targetIndex];return ae(u,f)}function ae(u,f){if(!f)return!1;for(let v of M(f))if(!(u&&v.id===u.id)&&Math.hypot(v.x-f.x,v.y-f.y)1)&&u.push({x:f.x,y:f.y})}function L(u){let f=e.conveyorMeta?.get?.(u)||{},v=[];Array.isArray(f.outDirs)&&v.push(...f.outDirs),f.dir&&v.push(f.dir);let k=[...new Set(v)].filter(de=>fe.some(Xe=>Xe.name===de)),S=X(u),I=fe.filter(de=>xe(S,de.name,null)).map(de=>de.name),A=k.filter(de=>I.includes(de)),U=fe.filter(de=>e.conveyorTiles.has(E(S.col+de.dc,S.row+de.dr))).map(de=>de.name);if(U.length===1&&(!A.length||A.includes(U[0]))&&Ge(S,U[0]))return A.filter(de=>de!==U[0]);let he=I;return A.length?A:he}function V(u){return fe.find(f=>f.name===u)||null}function se(u,f){return e.scanners.find(v=>v.col<=u&&u<=v.col+1&&v.row-1<=f&&f<=v.row)||null}function O(u,f){let v=V(f);if(!v)return null;let k=se(u.col+v.dc,u.row+v.dr);if(!k)return null;let S=We(k,"inputA");return S&&S.col===u.col&&S.row===u.row?k:null}function H(u){return Object.entries(e.facilities||{}).find(([,f])=>f?.entry&&f.entry.col===u.col&&f.entry.row===u.row)||null}function oe(u,f){for(let v of Object.values(e.facilities||{})){let k=ue(v);if(!v.gridPlaced||!["biomassGenerator","coalGenerator"].includes(k))continue;if((k==="biomassGenerator"?[{col:v.col-1,row:v.row+1,dir:"right"},{col:v.col+1,row:v.row-1,dir:"down"},{col:v.col+1,row:v.row+(v.hCells||3),dir:"up"}]:[{col:v.col-1,row:v.row+1,dir:"right"}]).some(I=>I.col===u.col&&I.row===u.row&&I.dir===f))return v}return null}function ue(u){return u?.baseId||u?.id||""}function Ve(u,f){return u?.gridPlaced&&ue(u)==="sausageMaker"||u?.gridPlaced&&["biomassGenerator","coalGenerator"].includes(ue(u))?f==="right":u.side==="left"&&f==="left"||u.side==="right"&&f==="right"||u.side==="top"&&f==="up"||u.side==="bottom"&&f==="down"}function xe(u,f,v=null){let k=V(f);if(!k)return null;let S={col:u.col+k.dc,row:u.row+k.dr};if(Re(S.col,S.row)&&e.conveyorTiles.has(E(S.col,S.row)))return{type:"conveyor",dirName:f,target:B(S.col,S.row),nextCell:S};let I=O(u,f);if(I&&!["meat","sausage","coal","zundaMochi"].includes(v?.sex))return{type:"scanner",dirName:f,target:ge(I),scanner:I};let A=oe(u,f);if(A)return{type:"facility",dirName:f,facilityId:A.id,facility:A,target:B(u.col,u.row)};let U=H(u);return U&&Ve(U[1],f)?{type:"facility",dirName:f,facilityId:U[0],facility:U[1],target:B(u.col,u.row)}:null}function Ge(u,f){let v=V(f);if(!v)return!1;let k=e.conveyorMeta?.get?.(E(u.col+v.dc,u.row+v.dr));return k?[...new Set([...Array.isArray(k.outDirs)?k.outDirs:[],k.dir].filter(Boolean))].includes(v.opposite):!1}function x(u){return fe.filter(f=>Re(u.col+f.dc,u.row+f.dr)&&e.conveyorTiles.has(E(u.col+f.dc,u.row+f.dr))).map(f=>f.name)}function g(u,f,v="random"){let k=x(u);if(k.length<3)return f;let S=new Set(k.filter(U=>Ge(u,U))),I=k.filter(U=>!S.has(U)),A=S.size?I:[...new Set(f.filter(U=>k.includes(U)))];return!A.length&&!S.size&&(A=k),v&&v!=="random"&&v!=="pass"&&A.length>=2&&A.includes(v)?[v]:A}function D(u,f){return f&&(f.type==="facility"||!ae(u,f.target))}function Z(u,f,v,k="random"){let S=v.map(he=>xe(f,he,u)).filter(Boolean);if(!S.length)return null;let A=S.filter(he=>he.type!=="facility").filter(he=>!ae(u,he.target)),U=A.length?A:S.filter(he=>he.type==="facility");return U.length?U[Math.floor(Math.random()*U.length)]:null}function j(u,f){let v=[];ye(v,{x:u.x,y:u.y}),ye(v,f),u.route=v.length?v:[{x:u.x,y:u.y}],u.targetIndex=u.route.length>1?1:u.route.length}function le(u,f){let v=rt(u.x,u.y);if(!v)return Qt(f,"OFF GRID");let k=E(v.col,v.row);if(!e.conveyorTiles.has(k))return Qt(f,"OFF BELT");let S=e.conveyorMeta?.get(k)||{},I=g(v,L(k),S.branchMode||"random");if(!I.length){u.stoppedTimer=.25;return}let A=Z(u,v,I,S.branchMode||"random");if(!A){u.stoppedTimer=.25;return}if(A.type==="facility"){let U=ue(A.facility);if(U==="mixer")ir(f,A.facility);else if(U==="truck")uo(f,A.facility);else if(U==="trash")lr(f,A.facility);else if(U==="sausageMaker")ar(f,A.facility);else if(U==="biomassGenerator"||U==="coalGenerator")cr(f,A.facility);else if(U==="inboundTruck"){let he=e.chicks[f];he&&(he.stoppedTimer=.25)}else Qt(f,"DONE");return}A.type==="scanner"&&(u.pendingScannerId=A.scanner.id),u.prevConveyorCell=k,j(u,A.target)}function ce(u,f){if(u.sex!=="zundaMochi")return!1;let v=rt(u.x,u.y);if(!v)return!1;let k=e.eggFarms.find(I=>Math.abs(I.col-v.col)+Math.abs(I.row-v.row)===1);if(!k)return!1;Ya(e,k),pt(f);let S=B(k.col,k.row);return Y(e,S.x,S.y-24,"ZUNDA BOOST",w.green),!0}function ve(u){let f=rt(u.x,u.y);if(!f)return null;let v=E(f.col,f.row);return e.conveyorTiles.has(v)?v:null}function Me(u){let f=ve(u)||ve(u.route?.[u.targetIndex]||u);return t(f)}function Se(u,f){let v=ve(f);!v||u.lastWearKey===v||(u.lastWearKey=v,ua(e,v))}function Ke(u,f){let v=Me(u)*f;for(;v>0&&u.targetIndex=A?(u.x=k.x,u.y=k.y,Se(u,k),u.targetIndex+=1,v-=A,i()):(u.x+=S/A*v,u.y+=I/A*v,v=0,i())}}function T(u,f,v){u.stage="queued",u.route=null,u.queueRoute=v?v.map(k=>({x:k.x,y:k.y})):[ge(f)],u.scannerId=f.id,f.queue.includes(u.id)||f.queue.push(u.id),r(),ke(f)}function ke(u){u.queue=u.queue.filter(v=>e.chicks.some(k=>k.id===v&&k.stage==="queued"));let f=p.cell*.86*Aa(e);u.queue.forEach((v,k)=>{let S=e.chicks.find(I=>I.id===v);S&&(Ae(S,S.queueRoute||[ge(u)],k*f),S.queueIndex=k)})}function Ae(u,f,v){if(!f||!f.length)return;if(f.length===1||v<=0){let I=f[f.length-1];u.x=I.x,u.y=I.y,i();return}let k=v;for(let I=f.length-1;I>0;I-=1){let A=f[I-1],U=f[I],he=Math.hypot(U.x-A.x,U.y-A.y);if(k<=he){let de=1-k/he;u.x=A.x+(U.x-A.x)*de,u.y=A.y+(U.y-A.y)*de,i();return}k-=he}let S=f[0];u.x=S.x,u.y=S.y,i()}function ot(u){for(let f of e.scanners){let v=f.kind!=="auto"||nt(e,f);if(f.keyPressTime>0&&(f.keyPressTime=Math.max(0,f.keyPressTime-u)),ke(f),!v||(f.cooldown>0&&(f.cooldown=Math.max(0,f.cooldown-u)),f.kind!=="auto"||f.cooldown>0||!f.queue.length))continue;let k=f.queue[0],S=e.chicks.findIndex(I=>I.id===k);if(S<0){f.queue.shift();continue}Nn(S,Dr(f,e.chicks[S]),!0)&&(fa(e,f),f.cooldown=Bt(f,e),ja(e))}}function Ce(u){let f=$r(e,u);return!f||!f.queue.length?null:e.chicks.find(v=>v.id===f.queue[0])||null}function Ue(u,f){if(e.phase!=="running")return;let v=$r(e,u);St(v,f)}function St(u,f){if(e.phase!=="running"||!u||u.kind!=="manual"||(u.keyPressTime=.18,u.keyPressSide=f,!u.queue.length))return;let v=e.chicks.findIndex(k=>k.id===u.queue[0]);v>=0&&Nn(v,f,!1)}function et(u,f,v){return u.kind==="manual"&&Dr(u,f)===v}function Ln(u){let f=e.manualCombo?.count||0;if(e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=0,e.manualCombo.lastBonus=0,e.stats.manualComboFailure=(e.stats.manualComboFailure||0)+1,e.totals.manualComboFailure=(e.totals.manualComboFailure||0)+1,f>=10){let v=ge(u);nn(e,10,.25),Y(e,v.x,v.y-36,"COMBO RESET",w.danger)}}function Ht(u){e.manualCombo||(e.manualCombo={count:0,lastBonus:0}),e.manualCombo.count=Math.max(0,e.manualCombo.count||0)+1,e.stats.manualComboSuccess=(e.stats.manualComboSuccess||0)+1,e.totals.manualComboSuccess=(e.totals.manualComboSuccess||0)+1;let f=e.manualCombo.count;if(e.manualCombo.lastBonus=0,f<10)return 0;let v=Math.max(1,Math.floor(f/10)),k=e.scanners.filter(U=>U.kind==="manual").length,S=Math.min(1,(20+k*10)/100),I=0;for(let U=0;U0){tt(e,A),e.stats.manualComboBonus=(e.stats.manualComboBonus||0)+A,e.totals.manualComboBonus=(e.totals.manualComboBonus||0)+A,e.manualCombo.lastBonus=A;let U=ge(u);Y(e,U.x,U.y-42,`COMBO +${R(A)}`,w.green)}return A}function lo(u,f){let v=We(u,f);if(!v)return null;let k=E(v.col,v.row);if(e.conveyorTiles.has(k))return{...v};let I=(at(e).scannerPorts.get(u.id)?.[f]?.keys||[]).filter(Boolean);if(!I.length)return null;let A=I.map(X).sort((he,de)=>{let Xe=B(he.col,he.row),_n=B(de.col,de.row),yo=ae(null,Xe)?1:0,pr=ae(null,_n)?1:0;return yo-pr});return A.find(he=>he.col===v.col&&he.row===v.row)||A[0]||null}function co(u,f,v,k){let S=[];ye(S,{x:u.x,y:u.y});let I=We(f,v);return I&&ye(S,B(I.col,I.row)),ye(S,B(k.col,k.row)),S}function Nn(u,f,v){let k=e.chicks[u];if(!k||k.stage!=="queued")return!1;let S=Zt(e,k.scannerId);if(!S||S.kind==="auto"&&!nt(e,S))return!1;if(["coal","zundaMochi"].includes(k.sex))return Y(e,k.x,k.y-16,"NOT SCANNABLE",w.warn),!1;let I=lo(S,f);if(!I)return!v&&S.kind==="manual"&&Ln(S),Y(e,k.x,k.y-16,f==="left"?"NO LEFT BELT":"NO RIGHT BELT",w.danger),!1;!v&&S.kind==="manual"&&(et(S,k,f)?Ht(S):Ln(S)),S.queue=S.queue.filter(U=>U!==k.id),k.stage="belt",k.route=co(k,S,f,I),k.targetIndex=k.route.length>1?1:k.route.length,k.scannerId=null,k.nextScannerId=null,k.pendingScannerId=null,k.queueRoute=null,k.queueIndex=-1,r();let A=v?w.green:f==="left"?w.mixerBlue:w.truckPink;return Us(e,ge(S).x,ge(S).y,A),Y(e,k.x,k.y-20,v?"AUTO":f.toUpperCase(),A),!0}function pt(u){let f=e.chicks[u];return f?(e.chicks.splice(u,1),r(),f):null}function ir(u,f=e.facilities.mixer){if(!nt(e,f)){let A=e.chicks[u];A&&(A.stoppedTimer=.25);return}if(f?.processingCooldown>0){let A=e.chicks[u];A&&(A.stoppedTimer=.25);return}if(Xt(e.chicks[u]))return dn(u,"CHICKS ONLY");let v=pt(u);if(!v)return;let{x:k,y:S}=v;if(Za(e),rn(e,f),Xo(e,f),v.sex==="meat"||v.sex==="sausage"){vt(e),Y(e,k,S-18,"CHICKS ONLY",w.warn);return}if(v.sex==="poop"){let A=$s(e);nr(e,"mixer"),vt(e),Ks(e,k,S),Y(e,k,S-18,`-${R(A)}`,w.danger);return}v.sex==="male"?Fn(e):vt(e);let I=He(e,f);if(!I||!kt(e,f)||!fo(I)){let A=As(e);Y(e,k,S-18,`DIRECT +${R(A)}`,w.green);return}f.meatBuffer=Math.max(0,f.meatBuffer||0)+1,f.meatQualityQueue=f.meatQualityQueue||[],f.meatQualityQueue.push(v.sourceQuality||1),e.stats.meatProduced=(e.stats.meatProduced||0)+1,e.totals.meatProduced=(e.totals.meatProduced||0)+1,Vs(e,k,S),Y(e,k,S-18,"MEAT +1",w.meatRed),Yt()}function uo(u,f=e.facilities.truck){if(!nt(e,f)){let U=e.chicks[u];U&&(U.stoppedTimer=.25);return}if(Xt(e.chicks[u]))return dn(u,"NO IMPORTS");let v=pt(u);if(!v)return;let{x:k,y:S}=v;ur(v.sex,f,v.sourceQuality||1),zs(e,k,S,v.sex),tl(e,v.sex);let I=Sn(e),A=Cs(e,v.sex);if(v.sex==="sausage"){e.stats.sausageShipped=(e.stats.sausageShipped||0)+1,e.totals.sausageShipped=(e.totals.sausageShipped||0)+1,Y(e,k,S-18,`SAUSAGE +${R(lt(e))}`,w.sausageOrange);return}if(v.sex==="meat"){vt(e),Y(e,k,S-18,"RAW MEAT REJECT",w.warn);return}if(v.sex==="poop"){if(nr(e,"truck"),A)Fn(e),Y(e,k,S-18,`+${R(Je(e))}`,w.green);else{let U=Fs(e);vt(e),Y(e,k,S-18,`-${R(U)}`,w.danger)}return}if(v.sex==="female"){A?(Fn(e),Y(e,k,S-18,`+${R(Je(e))}`,w.green)):(vt(e),Y(e,k,S-18,I==="male"?"REJECT":"NO SALE",w.warn));return}if(A){Fn(e),Y(e,k,S-18,`+${R(Je(e))}`,w.green);return}if(gs(e)){let U=Os(e);vt(e),Y(e,k,S-18,`-${R(U)}`,w.danger)}else vt(e),Y(e,k,S-18,"REJECT",w.warn)}function sr(u,f){let v=B(f.col,f.row);return{id:e.nextId++,sex:u,x:v.x,y:v.y,route:[{x:v.x,y:v.y}],targetIndex:1,stage:"belt",scannerId:null,nextScannerId:null,pendingScannerId:null,radius:u==="sausage"?11:10,bob:Math.random()*Math.PI*2,queueIndex:-1,queueRoute:null,stoppedTimer:0}}function fo(u){if(!u||!e.conveyorTiles.has(E(u.col,u.row)))return!1;let f=B(u.col,u.row);return!ae(null,f)}function Gn(u,f,v){if(!nt(e,u))return!1;let k=He(e,u);if(!k||!kt(e,u)||!fo(k)||Math.max(0,u[v]||0)<=0)return!1;u[v]-=1;let S=sr(f,k);f==="meat"&&(S.sourceQuality=(u.meatQualityQueue||[]).shift()||1),f==="sausage"&&(S.sourceQuality=(u.sausageQualityQueue||[]).shift()||1),e.chicks.push(S),r();let I=B(k.col,k.row);return Y(e,I.x,I.y-16,f==="meat"?"MEAT OUT":"SAUSAGE OUT",f==="meat"?w.meatRed:w.sausageOrange),!0}function Yt(){for(let u of Object.values(e.facilities||{})){let f=ue(u);f==="mixer"&&Gn(u,"meat","meatBuffer"),f==="sausageMaker"&&Gn(u,"sausage","sausageBuffer")}}function ar(u,f){if(!nt(e,f)){let I=e.chicks[u];I&&(I.stoppedTimer=.25);return}if(f?.processingCooldown>0){let I=e.chicks[u];I&&(I.stoppedTimer=.25);return}if(Xt(e.chicks[u]))return dn(u,"MEAT ONLY");let v=pt(u);if(!v)return;let{x:k,y:S}=v;if(v.sex!=="meat"){vt(e),Y(e,k,S-18,"MEAT ONLY",w.warn);return}if(rn(e,f),Xo(e,f),f.meatBuffer=Math.max(0,f.meatBuffer||0)+1,f.meatQualityQueue=f.meatQualityQueue||[],f.meatQualityQueue.push(v.sourceQuality||1),f.meatBuffer>=2){f.meatBuffer-=2,f.sausageBuffer=Math.max(0,f.sausageBuffer||0)+1;let I=f.meatQualityQueue.shift()||1,A=f.meatQualityQueue.shift()||1;f.sausageQualityQueue=f.sausageQualityQueue||[],f.sausageQualityQueue.push((I+A)/2),e.stats.sausageProduced=(e.stats.sausageProduced||0)+1,e.totals.sausageProduced=(e.totals.sausageProduced||0)+1,Y(e,k,S-18,"SAUSAGE +1",w.sausageOrange)}else Y(e,k,S-18,"MEAT 1/2",w.meatRed);Yt()}function lr(u,f=e.facilities.trash){if(!nt(e,f)){let U=e.chicks[u];U&&(U.stoppedTimer=.25);return}if(f?.processingCooldown>0){let U=e.chicks[u];U&&(U.stoppedTimer=.25);return}if(Xt(e.chicks[u]))return dn(u,"NO IMPORTS");let v=pt(u);if(!v)return;let{x:k,y:S}=v;qs(e,k,S,v.sex),el(e),rn(e,f),Xo(e,f);let I={amount:0},A="";if(v.sex==="poop"){I=Rs(e),A=I.amount>0?` ${I.tier==="jackpot"?"JACKPOT ":"+"}${R(I.amount)}`:" MISS",nr(e,"trash"),Fn(e);let U=Math.ceil(Math.max(0,Number(e.cardEffects?.composter)||0)*3*Fo(e));if(U>0){let he=tt(e,U);e.stats.composterIncome=(e.stats.composterIncome||0)+he,e.totals.composterIncome=(e.totals.composterIncome||0)+he,Y(e,k,S-36,`COMPOST +${R(he)}`,w.green)}Y(e,k,S-18,`CLEAN${A}`,I.amount>0?w.green:w.green)}else vt(e),Y(e,k,S-18,I.amount>0?`WASTE${A}`:"WASTE",I.amount>0?w.green:w.ink)}function cr(u,f){let v=e.chicks[u];if(!v)return;if(!la(f,v.sex)){v.stoppedTimer=.25;return}let k=pt(u);k&&((f.baseId||f.id)==="biomassGenerator"&&(e.stats.biomassFuelConsumed=(e.stats.biomassFuelConsumed||0)+1,e.totals.biomassFuelConsumed=(e.totals.biomassFuelConsumed||0)+1),(f.baseId||f.id)==="coalGenerator"&&(e.stats.coalConsumed=(e.stats.coalConsumed||0)+1,e.totals.coalConsumed=(e.totals.coalConsumed||0)+1),rn(e,f),Ye(e),Y(e,k.x,k.y-18,"FUEL +V",w.green))}function Qt(u,f){let v=pt(u);v&&Y(e,v.x,v.y-12,f,w.muted)}function Xt(u){return u?.sex==="coal"||u?.sex==="zundaMochi"}function dn(u,f){let v=e.chicks[u];v&&(v.stoppedTimer=.25,Y(e,v.x,v.y-18,f,w.warn))}function ur(u,f=e.facilities.truck,v=1){let k=f||e.facilities.truck;k&&(e.shippedCargo=e.shippedCargo||[],e.shippedCargo.push({sex:u,sourceQuality:v}),e.truckCargo.push({sex:u,sourceQuality:v,x:ne(22,k.w-22),y:ne(66,k.h-24)}),e.truckCargo.length>45&&e.truckCargo.shift())}function po(u){let f=rt(u.x,u.y);if(f){let S=E(f.col,f.row);if(e.conveyorTiles.has(S))return S}if(!f)return null;let v=null,k=1/0;for(let S of[f,...fe.map(I=>({col:f.col+I.dc,row:f.row+I.dr}))]){if(!Re(S.col,S.row))continue;let I=E(S.col,S.row);if(!e.conveyorTiles.has(I))continue;let A=B(S.col,S.row),U=Math.hypot(u.x-A.x,u.y-A.y);Uv&&u.ratio=f){let k=pn(u.id);if(!k.length||k.some(A=>A.stage!=="queued"&&A.stoppedTimer<=.2))continue;let S=e.lastExplodedComponent.get(u.id)||0,I=performance.now();I-S>900&&(e.lastExplodedComponent.set(u.id,I),fr(u))}}}function pn(u){return fn(e.frameId||0),e.frameCache?.componentChicks?.get(u)||[]}function fr(u){let f=pn(u.id);if(!f.length)return;for(let S of f)Jr(e,S.sex,S.x,S.y);e.chicks=e.chicks.filter(S=>!f.some(I=>I.id===S.id));for(let S of e.scanners)S.queue=S.queue.filter(I=>e.chicks.some(A=>A.id===I));r();for(let S of u.cells){let I=X(S),A=B(I.col,I.row);gt(e,A.x,A.y,w.danger),$t(e,A.x,A.y,6),Do(e,A.x,A.y,4)}nn(e,18,.75);let v=X(u.cells[0]),k=B(v.col,v.row);e.stats.explosions=(e.stats.explosions||0)+1,e.totals.explosions=(e.totals.explosions||0)+1,Y(e,k.x,k.y-22,`${Math.round(Kr(e)*100)}% JAM EXPLOSION`,w.danger)}return{activeQueuedChick:Ce,beginFrame:a,currentSpawnDelay:C,sortSlot:Ue,updateCongestion:fn,sortScanner:St,updateRunning:z}}var me=document.getElementById("gameCanvas"),Md=me.getContext("2d"),N={shell:document.getElementById("gameShell"),money:document.getElementById("money"),turn:document.getElementById("turn"),timeLeft:document.getElementById("timeLeft"),phase:document.getElementById("phaseLabel"),comboCount:document.getElementById("comboCount"),eventBrief:document.getElementById("eventBrief"),speedBrief:document.getElementById("speedBrief"),turnProfit:document.getElementById("turnProfit"),mixerCount:document.getElementById("mixerCount"),truckFemaleCount:document.getElementById("truckFemaleCount"),truckMaleCount:document.getElementById("truckMaleCount"),poopCount:document.getElementById("poopCount"),buildStatus:document.getElementById("buildStatus"),turnSummary:document.getElementById("turnSummary"),modal:document.getElementById("modal"),modalTitle:document.getElementById("modalTitle"),modalBody:document.getElementById("modalBody"),modalActions:document.getElementById("modalActions"),hoverTooltip:document.getElementById("hoverTooltip"),manualScannerMonitor:document.getElementById("manualScannerMonitor"),debug:{panel:document.getElementById("debugPanel"),infiniteCash:document.getElementById("debugInfiniteCash"),dayInput:document.getElementById("debugDayInput"),setDay:document.getElementById("debugSetDayButton"),zeroTimer:document.getElementById("debugZeroTimerButton"),cardSelect:document.getElementById("debugCardSelect"),targetSelect:document.getElementById("debugTargetSelect"),eventSelect:document.getElementById("debugEventSelect"),grantCard:document.getElementById("debugGrantCardButton"),grantAllCards:document.getElementById("debugGrantAllCardsButton"),readout:document.getElementById("debugReadout")},buttons:{s1Left:document.getElementById("scanner1MixerButton"),s1Right:document.getElementById("scanner1TruckButton"),s2Left:document.getElementById("scanner2MixerButton"),s2Right:document.getElementById("scanner2TruckButton"),nextTurn:document.getElementById("nextTurnButton"),conveyor:document.getElementById("buildConveyorButton"),boostConveyor:document.getElementById("buildBoostConveyorButton"),powerWire:document.getElementById("buildPowerWireButton"),insulatedPowerWire:document.getElementById("buildInsulatedPowerWireButton"),powerOverlay:document.getElementById("powerOverlayButton"),footbridge:document.getElementById("buildFootbridgeButton"),eggFarm:document.getElementById("buildEggFarmButton"),autoScanner:document.getElementById("buildAutoScannerButton"),manualScanner:document.getElementById("buildManualScannerButton"),mixer:document.getElementById("buildMixerButton"),trash:document.getElementById("buildTrashButton"),truck:document.getElementById("buildTruckButton"),inboundTruck:document.getElementById("buildInboundTruckButton"),sausageMaker:document.getElementById("buildSausageMakerButton"),biomassGenerator:document.getElementById("buildBiomassGeneratorButton"),coalGenerator:document.getElementById("buildCoalGeneratorButton"),maintenanceRoom:document.getElementById("buildMaintenanceRoomButton"),erase:document.getElementById("eraseButton"),undo:document.getElementById("undoButton"),redo:document.getElementById("redoButton")}};function Cd(){let e={conveyor:"conveyor",boostConveyor:"boostConveyor",powerWire:"powerWire",insulatedPowerWire:"insulatedPowerWire",footbridge:"footbridge",eggFarm:"eggFarm",autoScanner:"autoScanner",manualScanner:"manualScanner",mixer:"mixer",trash:"trash",truck:"truck",inboundTruck:"inboundTruck",sausageMaker:"sausageMaker",biomassGenerator:"biomassGenerator",coalGenerator:"coalGenerator",maintenanceRoom:"maintenanceRoom"};for(let[t,n]of Object.entries(e))N.buttons[t]&&(N.buttons[t].innerHTML=_i(n))}function gd(e){let t=new Set(e.tags||[]);return["upgradeEgg","crowdedFarming","hatchingFeed","extraEggOutlet"].includes(e.id)||t.has("EGG")?"Production / EGG":["upgradeTrash","poopRateBooster","composter","chemicalWeaponSubsidy"].includes(e.id)||t.has("POOP")?"Poop / Shredder":["upgradeAutoScanner","autoScannerTuning","scannerQueueSpacing"].includes(e.id)||t.has("SCANNER")?"Scanner":["bearing","dynamite"].includes(e.id)||t.has("CONVEYOR")?"Conveyor / Map":["safetyCover","preventiveMaintenance","durabilityCoating","sparePartsBin","laborExploitation"].includes(e.id)||t.has("MAINTENANCE")?"Maintenance / Risk":["dudFilter","dudRefund","freeReroll","extraCards"].includes(e.id)||t.has("CARD")?"Card Engine":t.has("ULTRA RARE")?"Ultra Rare":t.has("ECONOMY")||["upgradeMixer","upgradeTruck","upgradeSausageMaker","recyclingSubsidy","usedMachine","newMachine","flattery","legalWork","rescueLoan"].includes(e.id)?"Economy / Shipment":"Other"}function xd(){if(!N.debug?.panel||!N.debug.cardSelect)return;let e=["Production / EGG","Poop / Shredder","Scanner","Conveyor / Map","Maintenance / Risk","Card Engine","Economy / Shipment","Ultra Rare","Other"],t=new Map(e.map(n=>[n,[]]));for(let n of An){let o=gd(n);t.has(o)||t.set(o,[]),t.get(o).push(n)}N.debug.cardSelect.innerHTML="";for(let n of e){let o=t.get(n)||[];if(!o.length)continue;let r=document.createElement("optgroup");r.label=n;for(let i of o){let a=document.createElement("option");a.value=i.id;let c=i.rarity==="ultraRare"?"UR":i.rarity==="rare"?"R":"C";a.textContent=`[${c}] ${i.title}`,r.appendChild(a)}N.debug.cardSelect.appendChild(r)}N.debug.cardSelect.addEventListener("change",un),Td(),un()}function Td(){if(!N.debug?.eventSelect)return;N.debug.eventSelect.innerHTML="";let e=document.createElement("option");e.value="__roll__",e.textContent="Roll normally",N.debug.eventSelect.appendChild(e);let t=document.createElement("option");t.value="__none__",t.textContent="No event",N.debug.eventSelect.appendChild(t);for(let n of Hn){let o=document.createElement("option");o.value=n.key,o.textContent=n.title,N.debug.eventSelect.appendChild(o)}N.debug.eventSelect.value=d.debugNextEventKey||"__roll__",N.debug.eventSelect.addEventListener("change",Pd)}function cl(){let e=d.debugNextEventKey||"__roll__";return e==="__none__"?null:e==="__roll__"?ws(d):_r(d,e)}function un(){if(!N.debug?.targetSelect)return;let e=N.debug.cardSelect?.value,t=an(e),n=t?$a(d,t):[];if(N.debug.targetSelect.innerHTML="",!n.length){let r=document.createElement("option");r.value="__none__",r.textContent=t?"No target required":"No card selected",N.debug.targetSelect.appendChild(r),N.debug.targetSelect.disabled=!0;return}let o=document.createElement("option");o.value="__auto__",o.textContent=t?.id==="dynamite"?"Auto: first 10 blocked cells":"Auto: first valid target",N.debug.targetSelect.appendChild(o);for(let r of n){let i=document.createElement("option");i.value=r.key,i.textContent=r.label,N.debug.targetSelect.appendChild(i)}N.debug.targetSelect.disabled=!1}function Ed(){let e=Math.max(1,Math.floor(Number(N.debug.dayInput?.value)||1));d.turn=e,N.debug.dayInput&&(N.debug.dayInput.value=String(e)),Y(d,me.width/2-d.view.x,86-d.view.y,`DAY ${e}`,w.green),re.updatePanels(),re.updateUI(),un(),zt(`Day set to ${e}.`)}function Pd(){d.debugNextEventKey=N.debug.eventSelect?.value||"__roll__",d.phase==="build"&&(d.eventOffer=cl(),re.updatePanels(),re.updateUI());let e=N.debug.eventSelect?.selectedOptions?.[0]?.textContent||"Roll normally";zt(`Next event: ${e}.`)}function Rd(){let e=d.phase==="running"&&(d.timeLeft<=0||d.shutdownTimeLeft>0||d.cleanupTimer!==null);d.timeLeft=0,d.cleanupTimer!==null&&(d.cleanupTimer=0),e?d.shutdownTimeLeft=0:d.phase==="running"&&fl(),Y(d,me.width/2-d.view.x,86-d.view.y,"TIMER 0",w.warn),re.updatePanels(),re.updateUI(),zt("Timer set to 0.")}function Id(){let e=N.debug.cardSelect?.value,t=N.debug.targetSelect?.disabled?void 0:N.debug.targetSelect?.value,n=di(d,e,{targetKey:t});N.debug.grantCard&&(N.debug.grantCard.textContent=n.ok?"Granted":"Failed",window.setTimeout(()=>{N.debug.grantCard&&(N.debug.grantCard.textContent="Grant Selected")},900)),Ne?.updateCongestion?.(d.frameId||0),re.updatePanels(),re.updateUI(),un(),zt(n.reason)}function Ad(){let t=An.map(n=>di(d,n,{targetKey:"__auto__"})).filter(n=>n.ok).length;Ne?.updateCongestion?.(d.frameId||0),re.updatePanels(),re.updateUI(),un(),zt(`Granted ${t}/${An.length} cards.`)}function $d(){N.debug?.infiniteCash?.checked&&d.cash<999999&&(d.cash=999999,d.totals.maxCash=Math.max(d.totals.maxCash,d.cash))}function zt(e=""){N.debug?.readout&&(N.debug.readout.textContent=[e,`D${d.turn}`,R(d.cash),`Combo ${d.manualCombo?.count||0}`,`Event ${d.eventActive?.title||d.eventOffer?.title||"none"}`,`Next ${N.debug?.eventSelect?.selectedOptions?.[0]?.textContent||"Roll normally"}`,`Rescue ${d.cardEffects?.rescueLoanCharges||0}`,`Chem ${d.cardEffects?.chemicalWeaponSubsidy||0}`].filter(Boolean).join(" | "))}var d=Rr(),te,re,Ne,Bn;function Fd(e=null){let t=Vt(d,e);return e?t*eo(d,e):t}function Od(){Object.assign(d,Rr()),d.phase="running",d.view={x:0,y:0,scale:1},Ir(d),yl(),Be(d),re.hideModal(),Ne.updateCongestion(d.frameId||0),re.updatePanels(),re.updateUI(),zt()}function Bd(){if(d.phase!=="build")return;if(d.cardDraft?.pending||d.cardTargetPick?.pending){te.fail(d.cardTargetPick?.pending?"Choose upgrade target first.":"Choose an upgrade card first."),re.updatePanels();return}let e=$o(d);if(e.length){Wd(),te.fail(`Cannot start: ${e[0]}`),re.updatePanels();return}Be(d),ds(d);let t=_o(d);t.underVoltage?.size&&Y(d,me.width/2-d.view.x,136-d.view.y,`${t.underVoltage.size} UNDER-VOLTAGE`,w.warn),ba(d);let n=Math.max(0,Math.floor(d.lastResult?.profit??d.stats?.profit??0)),o=Ls(d,Math.max(1,d.turn||1),n);d.lastStartFees={fairiesTribute:o.amount||0,tribute:o},o.amount>0&&Y(d,me.width/2-d.view.x,116-d.view.y,`FAIRIES -${R(o.amount)}`,w.danger),ms(d),d.phase="running",d.turn+=1,d.timeLeft=Ss(d),d.shutdownTimeLeft=0,d.cleanupTimer=null,d.cleanupBlown=!1,d.chicks=[],d.effects=[],d.floatingTexts=[],d.shake={time:0,strength:0},d.truckCargo=[],d.shippedCargo=[],yl(),d.stats=Pr(),nl(d),d.stats.fairiesTribute=d.lastStartFees?.fairiesTribute||0,d.stats.fairiesTribute>0&&(d.stats.penalty+=d.stats.fairiesTribute,d.stats.profit-=d.stats.fairiesTribute);for(let r of d.scanners)r.queue=[],r.cooldown=0;for(let r of d.eggFarms)r.nextSpawn=Ne.currentSpawnDelay(r),r.lastInterval=r.nextSpawn,r.shutterProgress=0,r.shutterSparked=!1,r.zundaBoostTime=0;d.buildTool=null,d.selected=null,d.groupDrag=null,d.selectionBox=null,d.pan=null,Ne.updateCongestion(d.frameId||0),re.updatePanels(),re.updateUI()}function Dd(){if(d.phase!=="running")return;rl(d);for(let i of Object.values(d.facilities||{}))i.fuelPulses&&(i.fuelPulses=[]);for(let i of d.eggFarms||[])i.zundaBoostTime=0;let e=Ds(d),t=d.eventActive?{...d.eventActive}:null,n=Es(d),o=Ns(d);if(e.adjusted>0){let i=d.facilities.truck,a=i?i.x+i.w/2:me.width/2-d.view.x,c=i?i.y+26:96-d.view.y;Y(d,a,c,`${e.target==="poop"?"POOP SHIP":"SHIP"} +${R(e.adjusted)}`,w.green)}n?.bonus>0&&Y(d,me.width/2-d.view.x,96-d.view.y,`EVENT +${R(n.bonus)}`,w.green),o.amount>0&&Y(d,me.width/2-d.view.x,116-d.view.y,`CHEM SUBSIDY +${R(o.amount)}`,w.green),vs(d),d.totals.turnsCompleted+=1;let r=Ts(t);if(r!==1&&(d.pendingFairiesTributeMultiplier=r),d.lastResult={...d.stats,ship:e,event:n,chemical:o,rescue:{amount:0,used:0,remaining:d.cardEffects?.rescueLoanCharges||0},fairiesTribute:{amount:d.stats.fairiesTribute||0},tributeMultiplier:r,turn:d.turn,cash:d.cash},d.cash<0){if((d.cardEffects?.rescueLoanCharges||0)>0){d.phase="loanDecision",re.showEmergencyLoanDecision(dl,or);return}d.phase="gameover",re.showGameOver();return}ul()}function ul(){d.phase="build",d.truckCargo=[],d.shippedCargo=[],d.chicks=[],d.shutdownTimeLeft=0,d.cleanupTimer=null,d.cleanupBlown=!1,d.buildSession+=1,d.undoStack=[],d.redoStack=[],d.timeLeft=0;for(let e of d.scanners)e.queue=[];for(let e of d.eggFarms)e.shutterProgress=0,e.shutterSparked=!1;wa(d),d.eventOffer=cl(),Bn&&Bn.prepareDraft(),d.cardTargetPick=null,d.buildTool=null,d.groupDrag=null,d.selectionBox=null,d.pan=null,re.updatePanels(),re.showTurnResult(d.lastResult)}function dl(){if((d.cardEffects?.rescueLoanCharges||0)<=0)return or();d.cardEffects.rescueLoanCharges-=1,d.stats.rescueLoan=(d.stats.rescueLoan||0)+500,d.totals.rescueLoan=(d.totals.rescueLoan||0)+500;let e=tt(d,500);d.lastResult={...d.lastResult||{},...d.stats,rescue:{amount:(d.lastResult?.rescue?.amount||0)+e,used:(d.lastResult?.rescue?.used||0)+1,remaining:d.cardEffects.rescueLoanCharges},cash:d.cash},Y(d,me.width/2-d.view.x,176-d.view.y,`RESCUE +${R(e)}`,w.green),d.cash>=0?ul():(d.cardEffects?.rescueLoanCharges||0)>0?(d.phase="loanDecision",re.showEmergencyLoanDecision(dl,or)):or()}function or(){d.phase="gameover",re.showGameOver()}function fl(){d.shutdownTimeLeft<=0&&(d.shutdownTimeLeft=d.shutdownGraceSeconds||10);for(let e of d.eggFarms){if(e.shutterSparked)continue;e.shutterProgress=.02,e.shutterSparked=!0;let t=B(e.col,e.row);gt(d,t.x,t.y,w.ink),$t(d,t.x,t.y+10,10),Y(d,t.x,t.y-34,"SHUT +10s",w.ink)}}function pl(e){d.lastTimestamp||(d.lastTimestamp=e);let t=Math.min((e-d.lastTimestamp)/1e3,.05);d.lastTimestamp=e,d.frameId=(d.frameId||0)+1,Ne.beginFrame?.(d.frameId),sa(d,t),d.phase==="running"&&Ne.updateRunning(t,{closeFarmShutters:fl,completeTurn:Dd}),Ys(d,t,me,te.equipmentHitBoxes),Ne.updateCongestion(d.frameId),Ga(Md,me,d,{activeQueuedChick:Ne.activeQueuedChick,selectedObject:te.selectedObject,selectedTitle:te.selectedTitle}),$d(),re.updateUI(),bl(),zt(),requestAnimationFrame(pl)}function ao(){return d.view?.scale||1}function Dn(){d.view||(d.view={x:0,y:0,scale:1}),d.view.scale==null&&(d.view.scale=1)}function rr(e){let t=me.getBoundingClientRect();return{x:(e.clientX-t.left)*me.width/t.width,y:(e.clientY-t.top)*me.height/t.height}}function qt(e){let t=rr(e),n=ao();return{x:(t.x-(d.view?.x||0))/n,y:(t.y-(d.view?.y||0))/n}}function Ld(e){let t=ao();return{x:e.x*t+(d.view?.x||0),y:e.y*t+(d.view?.y||0)}}function Nd(){let e={left:p.x-90,top:p.y-130,right:p.x+p.cols*p.cell+260,bottom:p.y+p.rows*p.cell+220};if(d.phase==="build")for(let t of jt(d)){let n=Et(t);e.left=Math.min(e.left,n.x-60),e.top=Math.min(e.top,n.y-80),e.right=Math.max(e.right,n.x+n.w+80),e.bottom=Math.max(e.bottom,n.y+n.h+80)}return e}function sl(e,t){if(e<=t)return[e,t];let n=(e+t)/2;return[n,n]}function Lt(){Dn();let e=ao(),t=Nd(),[n,o]=sl(me.width-160-t.right*e,110-t.left*e),[r,i]=sl(me.height-150-t.bottom*e,150-t.top*e);d.view.x=Kn(d.view.x,n,o),d.view.y=Kn(d.view.y,r,i)}function yl(){Dn(),d.view.scale=1;let e=d.eggFarms?.[0],t=e?B(e.col,e.row):{x:p.x,y:p.y};d.view.x=280-t.x,d.view.y=190-t.y,Lt()}function Gd(e){if(!e)return!1;Dn();let t=ao();return d.view.x=me.width/2-e.x*t,d.view.y=me.height/2-e.y*t,Lt(),!0}function _d(e){let t=e?.ref;return t?e.type==="facility"?{x:t.x+t.w/2,y:t.y+t.h/2}:e.type==="eggFarm"?B(t.col,t.row):e.type==="scanner"?{x:B(t.col,t.row).x+p.cell/2,y:B(t.col,t.row).y}:e.type==="maintenanceRoom"?{x:B(t.col,t.row).x+p.cell/2,y:B(t.col,t.row).y+p.cell/2}:null:null}function Wd(){let e=vn(d),t=e.find(o=>o.type==="facility")||e[0]||Ud(),n=_d(t);Gd(n)&&t&&(d.selected={type:t.type,id:t.id})}function Ud(){let e=Object.values(d.facilities||{}).find(o=>o?.entry&&d.conveyorTiles.has(E(o.entry.col,o.entry.row)))||Object.values(d.facilities||{})[0];if(e)return{type:"facility",id:e.id,ref:e};let t=d.scanners?.find(o=>o);if(t)return{type:"scanner",id:t.id,ref:t};let n=d.eggFarms?.[0];return n?{type:"eggFarm",id:n.id,ref:n}:null}function Vd(e){let t=rr(e);Dn(),d.pan={start:t,viewX:d.view.x,viewY:d.view.y,moved:!1}}function Kd(e){if(!d.pan)return;let t=rr(e);Math.hypot(t.x-d.pan.start.x,t.y-d.pan.start.y)>5&&(d.pan.moved=!0),Dn(),d.view.x=d.pan.viewX+t.x-d.pan.start.x,d.view.y=d.pan.viewY+t.y-d.pan.start.y,Lt()}function qd(e){e.preventDefault(),Dn();let t=rr(e),n=qt(e),o=Math.exp(-e.deltaY*.0012),r=Kn(ao()*o,.55,1.8);d.view.scale=r,d.view.x=t.x-n.x*r,d.view.y=t.y-n.y*r,Lt(),Nt()}function zd(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:{type:e.type,id:e.ref.id}:null}function Hd(e){return e?e.type==="conveyor"?{type:"conveyor",id:e.oldKey}:e.ref||null:null}function Nt(){N.hoverTooltip&&(N.hoverTooltip.classList.remove("visible"),N.hoverTooltip.setAttribute("aria-hidden","true"),d.hover=null)}function Yd(e,t){if(!N.hoverTooltip||d.phase!=="build"||d.cardTargetPick?.pending||d.groupDrag||d.selectionBox||d.pan)return Nt();let n=Hd(t);if(!n)return Nt();let o=te.selectedTitle(n),r=te.flavorText?te.flavorText(n):"",i=te.disconnectedWarningFor?te.disconnectedWarningFor(n):"",a=te.selectedInfoLines(n).slice(0,7);N.hoverTooltip.innerHTML=`${o}${i?`${i}`:r?`${r}`:""}${a.map(M=>`${M}`).join("")}`;let c=Math.min(window.innerWidth-330,e.clientX+18),b=Math.min(window.innerHeight-220,e.clientY+18);N.hoverTooltip.style.left=`${Math.max(8,c)}px`,N.hoverTooltip.style.top=`${Math.max(8,b)}px`,N.hoverTooltip.classList.add("visible"),N.hoverTooltip.setAttribute("aria-hidden","false"),d.hover={type:t.type,id:t.oldKey||t.ref?.id||null}}function Qd(e){if(d.phase!=="build")return Nt();Yd(e,te.equipmentAtPoint(qt(e)))}function hl(e){Nt();let t=qt(e),n=te.equipmentAtPoint(t),o=zd(n);if(!o){d.selected=null,d.multiSelected=[],re.updatePanels();return}d.selected=o,d.multiSelected=[o],re.updatePanels();let r=te.selectedObject();r?.type==="scanner"&&r.kind==="manual"&&te.showManualScannerMenu(r),r?.type==="scanner"&&r.kind==="auto"&&te.showAutoScannerMenu(r),r?.type==="facility"&&(r.baseId||r.id)==="inboundTruck"&&te.showInboundTruckMenu(r)}function On(){d.buildTool=null,d.selected=null,d.multiSelected=[],d.selectionBox=null,d.cardTargetPick?.mode==="autoScannerMenu"&&(d.cardTargetPick=null),re.hideModal(),Nt(),re.updatePanels(),re.updateUI()}function al(e){return String(e).replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function Xd(e){let t=e?.queue?.[0];return t==null?null:d.chicks.find(n=>n.id===t)||null}function jd(e){if(!e)return'WAIT';let t=e.sex==="poop"?"POOP":e.sex==="male"?"M MALE":"F FEMALE";return`${t}`}function Jd(e,t){let n=new Set(d.eggFarms.map(C=>E(C.col,C.row))),o=new Map(d.scanners.map(C=>[E(C.col,C.row),C])),r=We(e,"inputA"),i=r?E(r.col,r.row):null,a=new Set(Object.values(d.facilities||{}).map(C=>C.entry?E(C.entry.col,C.entry.row):null).filter(Boolean)),c=t?.sex||"",b=c==="poop"?"P":c==="male"?"M":c==="female"?"F":"",M=[];for(let C=e.row-2;C<=e.row+2;C+=1)for(let $=e.col-2;$<=e.col+2;$+=1){let W=E($,C),K=["mini-cell"],G="";$===e.col&&C===e.row?(K.push("scanner"),c&&K.push(c),G=b||"S"):W===i?(K.push("input"),G="IN"):n.has(W)?(K.push("egg"),G="E"):o.has(W)?(K.push("scanner-other"),G="S"):a.has(W)?(K.push("port"),G="P"):d.conveyorTiles.has(W)?(K.push("belt"),G="."):d.blockedCells?.has?.(W)&&(K.push("blocked"),G="X"),M.push(`${G}`)}return`
${M.join("")}
`}function Zd(e){let t=Ld(B(e.col,e.row)),n=76;return t.x<-n||t.y<-n||t.x>me.width+n||t.y>me.height+n}function bl(){if(!N.manualScannerMonitor)return;let e=d.frameCache||(d.frameCache={}),t=d.view||{},n=[d.phase,Math.round((t.x||0)*10),Math.round((t.y||0)*10),Math.round((t.scale||1)*100),d.chicks.length,d.scanners.map(r=>[r.id,r.kind,r.col,r.row,r.queue?.join(",")||"",r.keyPressSide||"",Math.ceil((r.keyPressTime||0)*10)].join(":")).join("|")].join(";");if(e.manualMonitorSignature===n)return;if(e.manualMonitorSignature=n,d.phase!=="running"){N.manualScannerMonitor.classList.remove("visible"),N.manualScannerMonitor.innerHTML="";return}let o=d.scanners.filter(r=>r.kind==="manual"&&Zd(r));if(!o.length){N.manualScannerMonitor.classList.remove("visible"),N.manualScannerMonitor.innerHTML="";return}N.manualScannerMonitor.innerHTML=o.map(r=>{let i=Xd(r),a=r.keys?.left?.label||(r.slot===0?"A":"Left"),c=r.keys?.right?.label||(r.slot===0?"D":"Right"),b=r.role===0?"MIXER":"WASTE",M=r.role===0?"S2":"TRUCK",C=i?"":" disabled";return`
S${(r.slot??0)+1}OFFSCREEN / Q:${r.queue.length}
- IN${Ku(i)}SCANNER + IN${jd(i)}SCANNER
- ${qu(r,i)} + ${Jd(r,i)}
- - + +
-
`}).join(""),F.manualScannerMonitor.classList.add("visible")}F.manualScannerMonitor?.addEventListener("click",e=>{let t=e.target.closest("button[data-scanner-id]");if(!t||t.disabled)return;let n=u.scanners.find(o=>o.id===Number(t.dataset.scannerId));n&&(Ae.sortScanner(n,t.dataset.side),Ia())});he.addEventListener("contextmenu",e=>e.preventDefault());he.addEventListener("wheel",Nu,{passive:!1});he.addEventListener("pointerdown",e=>{if(!["build","running"].includes(u.phase))return;if(e.button===2||e.button===1||u.phase==="running"&&e.button===0){he.setPointerCapture(e.pointerId),Ou(e);return}if(u.phase!=="build"||e.button!==0)return;he.setPointerCapture(e.pointerId);let t=Bt(e);if(u.cardTargetPick?.mode==="autoScannerMenu"){mn();return}if(u.cardTargetPick?.pending){bn.chooseTargetAtPoint(t);return}let n=te.expansionOfferAtPoint?.(t);if(n){te.buyGridExpansion(n),Ct(),J.updatePanels(),J.updateUI();return}if(te.cycleBranchModeAtPoint?.(t)){J.updatePanels(),J.updateUI();return}let o=tt(t.x,t.y),r=te.equipmentAtPoint(t);if(!u.buildTool&&r?.type==="conveyor"&&o&&te.cycleSingleConveyorDirection?.(o)){J.updatePanels(),J.updateUI();return}if(u.buildTool==="erase"){if(!te.equipmentAtPoint(t)){mn();return}te.eraseAtPoint(t);return}if(u.buildTool){let i=tt(t.x,t.y);if(!i&&!["mixer","trash","truck"].includes(u.buildTool)){mn();return}if(u.buildTool==="conveyor"||u.buildTool==="boostConveyor"){te.beginConveyorDrag(i);return}if(te.equipmentAtPoint(t)){u.buildTool=null,Aa(e);return}te.buildAtPoint(t);return}te.startGroupDrag(e)||te.startSelectionBox(e)});he.addEventListener("pointermove",e=>{if(u.pan&&e.buttons&7&&Lu(e),u.phase!=="build"){Mt();return}Wu(e),u.groupDrag&&e.buttons&1&&te.updateGroupDrag(e),u.selectionBox&&e.buttons&1&&te.updateSelectionBox(e),(u.buildTool==="conveyor"||u.buildTool==="boostConveyor")&&e.buttons&1&&te.continueConveyorDrag(tt(Bt(e).x,Bt(e).y)),u.buildTool==="erase"&&e.buttons&1&&te.eraseAtPoint(Bt(e))});he.addEventListener("pointerup",e=>{u.selectionBox?te.finishSelectionBox():u.groupDrag&&(u.groupDrag.committed||Aa(e),te.finishGroupDrag()),(e.button===2||e.button===1)&&u.pan&&!u.pan.moved&&u.buildTool&&u.phase==="build"&&mn(),(u.buildTool==="conveyor"||u.buildTool==="boostConveyor")&&te.endConveyorDrag?.(),u.groupDrag=null,u.pan=null;try{he.releasePointerCapture(e.pointerId)}catch{}});he.addEventListener("pointerleave",Mt);he.addEventListener("pointercancel",()=>{te?.endConveyorDrag?.(),u.groupDrag=null,u.selectionBox=null,u.pan=null,Mt()});document.addEventListener("pointerdown",e=>{!F.modal.classList.contains("visible")||!F.modal.classList.contains("equipment-popover")||e.target.closest("#modal .modal-card")||mn()},!0);F.buttons.s1Left.addEventListener("click",()=>Ae.sortSlot(0,"left"));F.buttons.s1Right.addEventListener("click",()=>Ae.sortSlot(0,"right"));F.buttons.s2Left.addEventListener("click",()=>Ae.sortSlot(1,"left"));F.buttons.s2Right.addEventListener("click",()=>Ae.sortSlot(1,"right"));F.buttons.nextTurn.addEventListener("click",Ru);F.buttons.conveyor.addEventListener("click",()=>te.setBuildTool("conveyor"));F.buttons.boostConveyor.addEventListener("click",()=>te.setBuildTool("boostConveyor"));F.buttons.eggFarm.addEventListener("click",()=>te.setBuildTool("eggFarm"));F.buttons.autoScanner.addEventListener("click",()=>te.setBuildTool("autoScanner"));F.buttons.manualScanner.addEventListener("click",()=>te.setBuildTool("manualScanner"));F.buttons.mixer.addEventListener("click",()=>te.setBuildTool("mixer"));F.buttons.trash.addEventListener("click",()=>te.setBuildTool("trash"));F.buttons.truck.addEventListener("click",()=>te.setBuildTool("truck"));F.buttons.sausageMaker.addEventListener("click",()=>te.setBuildTool("sausageMaker"));F.buttons.maintenanceRoom.addEventListener("click",()=>te.setBuildTool("maintenanceRoom"));F.buttons.erase.addEventListener("click",()=>te.setBuildTool("erase"));F.debug.setDay?.addEventListener("click",Su);F.debug.zeroTimer?.addEventListener("click",gu);F.debug.grantCard?.addEventListener("click",Cu);F.debug.grantAllCards?.addEventListener("click",Mu);F.buttons.undo.addEventListener("click",()=>{Mr(u)&&(Ct(),J.updatePanels(),J.updateUI(),Jt())});F.buttons.redo.addEventListener("click",()=>{xr(u)&&(Ct(),J.updatePanels(),J.updateUI(),Jt())});function Ca(e,t,n){let o=e.keys?.[t];return o?o.code&&n.code===o.code||o.key&&n.key.toLowerCase()===o.key:!1}window.addEventListener("keydown",e=>{if(e.repeat)return;let t=e.key.toLowerCase();if(u.phase==="running")for(let n of u.scanners.filter(o=>o.kind==="manual")){if(Ca(n,"left",e)){e.preventDefault(),Ae.sortScanner(n,"left");return}if(Ca(n,"right",e)){e.preventDefault(),Ae.sortScanner(n,"right");return}}u.phase==="build"&&(e.ctrlKey||e.metaKey)&&t==="z"&&(e.preventDefault(),Mr(u)&&(Ct(),J.updatePanels(),J.updateUI())),u.phase==="build"&&(e.ctrlKey||e.metaKey)&&(t==="y"||e.shiftKey&&t==="z")&&(e.preventDefault(),xr(u)&&(Ct(),J.updatePanels(),J.updateUI())),e.key==="Escape"&&u.cardTargetPick?.pending&&(e.preventDefault(),u.cardTargetPick.mode==="autoScannerMenu"?mn():bn.cancelTargetPick())});te=pa({game:u,ui:F,canvas:he,canvasPoint:Bt,onUpdatePanels:()=>J?.updatePanels()});Ae=Sa({game:u,currentConveyorSpeed:Tu,onGameOverCheck:()=>J?.checkGameOver()});bn=Xs({game:u,ui:F,onUpdatePanels:()=>J?.updatePanels()});J=ya({game:u,ui:F,build:te,startGame:Eu,beginCardDraft:()=>bn.showDraft(),activeQueuedChick:Ae.activeQueuedChick});mu();vu();ir(u);Re(u);Ae.updateCongestion(u.frameId||0);J.updatePanels();J.updateUI();J.showTitle();Ot();requestAnimationFrame(Ra); +
`}).join(""),N.manualScannerMonitor.classList.add("visible")}N.manualScannerMonitor?.addEventListener("click",e=>{let t=e.target.closest("button[data-scanner-id]");if(!t||t.disabled)return;let n=d.scanners.find(o=>o.id===Number(t.dataset.scannerId));n&&(Ne.sortScanner(n,t.dataset.side),bl())});me.addEventListener("contextmenu",e=>e.preventDefault());me.addEventListener("wheel",qd,{passive:!1});me.addEventListener("pointerdown",e=>{if(!["build","running"].includes(d.phase))return;if(e.button===2||e.button===1||d.phase==="running"&&e.button===0){me.setPointerCapture(e.pointerId),Vd(e);return}if(d.phase!=="build"||e.button!==0)return;me.setPointerCapture(e.pointerId);let t=qt(e);if(d.cardTargetPick?.mode==="autoScannerMenu"){On();return}if(d.cardTargetPick?.pending){Bn.chooseTargetAtPoint(t);return}let n=te.expansionOfferAtPoint?.(t);if(n){te.buyGridExpansion(n),Lt(),re.updatePanels(),re.updateUI();return}if(te.cycleBranchModeAtPoint?.(t)){re.updatePanels(),re.updateUI();return}let o=rt(t.x,t.y),r=te.equipmentAtPoint(t);if(!d.buildTool&&r?.type==="conveyor"&&o&&te.cycleSingleConveyorDirection?.(o)){re.updatePanels(),re.updateUI();return}if(d.buildTool==="erase"){if(!te.equipmentAtPoint(t)){On();return}te.eraseAtPoint(t);return}if(d.buildTool){let i=rt(t.x,t.y);if(!i&&!["mixer","trash","truck"].includes(d.buildTool)){On();return}if(d.buildTool==="conveyor"||d.buildTool==="boostConveyor"){te.beginConveyorDrag(i);return}if(te.equipmentAtPoint(t)){d.buildTool=null,hl(e);return}te.buildAtPoint(t);return}te.startGroupDrag(e)||te.startSelectionBox(e)});me.addEventListener("pointermove",e=>{if(d.pan&&e.buttons&7&&Kd(e),d.phase!=="build"){Nt();return}Qd(e),d.groupDrag&&e.buttons&1&&te.updateGroupDrag(e),d.selectionBox&&e.buttons&1&&te.updateSelectionBox(e),(d.buildTool==="conveyor"||d.buildTool==="boostConveyor")&&e.buttons&1&&te.continueConveyorDrag(rt(qt(e).x,qt(e).y)),d.buildTool==="erase"&&e.buttons&1&&te.eraseAtPoint(qt(e))});me.addEventListener("pointerup",e=>{d.selectionBox?te.finishSelectionBox():d.groupDrag&&(d.groupDrag.committed||hl(e),te.finishGroupDrag()),(e.button===2||e.button===1)&&d.pan&&!d.pan.moved&&d.buildTool&&d.phase==="build"&&On(),(d.buildTool==="conveyor"||d.buildTool==="boostConveyor")&&te.endConveyorDrag?.(),d.groupDrag=null,d.pan=null;try{me.releasePointerCapture(e.pointerId)}catch{}});me.addEventListener("pointerleave",Nt);me.addEventListener("pointercancel",()=>{te?.endConveyorDrag?.(),d.groupDrag=null,d.selectionBox=null,d.pan=null,Nt()});document.addEventListener("pointerdown",e=>{!N.modal.classList.contains("visible")||!N.modal.classList.contains("equipment-popover")||e.target.closest("#modal .modal-card")||On()},!0);N.buttons.s1Left.addEventListener("click",()=>Ne.sortSlot(0,"left"));N.buttons.s1Right.addEventListener("click",()=>Ne.sortSlot(0,"right"));N.buttons.s2Left.addEventListener("click",()=>Ne.sortSlot(1,"left"));N.buttons.s2Right.addEventListener("click",()=>Ne.sortSlot(1,"right"));N.buttons.nextTurn.addEventListener("click",Bd);N.buttons.conveyor.addEventListener("click",()=>te.setBuildTool("conveyor"));N.buttons.boostConveyor.addEventListener("click",()=>te.setBuildTool("boostConveyor"));N.buttons.powerWire?.addEventListener("click",()=>te.setBuildTool("powerWire"));N.buttons.insulatedPowerWire?.addEventListener("click",()=>te.setBuildTool("insulatedPowerWire"));N.buttons.powerOverlay?.addEventListener("click",()=>{d.powerOverlay=!d.powerOverlay,re.updatePanels()});N.buttons.footbridge?.addEventListener("click",()=>te.setBuildTool("footbridge"));N.buttons.eggFarm.addEventListener("click",()=>te.setBuildTool("eggFarm"));N.buttons.autoScanner.addEventListener("click",()=>te.setBuildTool("autoScanner"));N.buttons.manualScanner.addEventListener("click",()=>te.setBuildTool("manualScanner"));N.buttons.mixer.addEventListener("click",()=>te.setBuildTool("mixer"));N.buttons.trash.addEventListener("click",()=>te.setBuildTool("trash"));N.buttons.truck.addEventListener("click",()=>te.setBuildTool("truck"));N.buttons.inboundTruck?.addEventListener("click",()=>te.setBuildTool("inboundTruck"));N.buttons.sausageMaker.addEventListener("click",()=>te.setBuildTool("sausageMaker"));N.buttons.biomassGenerator?.addEventListener("click",()=>te.setBuildTool("biomassGenerator"));N.buttons.coalGenerator?.addEventListener("click",()=>te.setBuildTool("coalGenerator"));N.buttons.maintenanceRoom.addEventListener("click",()=>te.setBuildTool("maintenanceRoom"));N.buttons.erase.addEventListener("click",()=>te.setBuildTool("erase"));N.debug.setDay?.addEventListener("click",Ed);N.debug.zeroTimer?.addEventListener("click",Rd);N.debug.grantCard?.addEventListener("click",Id);N.debug.grantAllCards?.addEventListener("click",Ad);N.buttons.undo.addEventListener("click",()=>{Xr(d)&&(Lt(),re.updatePanels(),re.updateUI(),un())});N.buttons.redo.addEventListener("click",()=>{jr(d)&&(Lt(),re.updatePanels(),re.updateUI(),un())});function ll(e,t,n){let o=e.keys?.[t];return o?o.code&&n.code===o.code||o.key&&n.key.toLowerCase()===o.key:!1}window.addEventListener("keydown",e=>{if(e.repeat)return;let t=e.key.toLowerCase();if(d.phase==="running")for(let n of d.scanners.filter(o=>o.kind==="manual")){if(ll(n,"left",e)){e.preventDefault(),Ne.sortScanner(n,"left");return}if(ll(n,"right",e)){e.preventDefault(),Ne.sortScanner(n,"right");return}}if(d.phase==="build"&&(e.ctrlKey||e.metaKey)&&t==="z"&&(e.preventDefault(),Xr(d)&&(Lt(),re.updatePanels(),re.updateUI())),d.phase==="build"&&(e.ctrlKey||e.metaKey)&&(t==="y"||e.shiftKey&&t==="z")&&(e.preventDefault(),jr(d)&&(Lt(),re.updatePanels(),re.updateUI())),d.phase==="build"&&d.buildTool==="footbridge"&&t==="r"){e.preventDefault(),d.footbridgeOrientation=d.footbridgeOrientation==="horizontal"?"vertical":"horizontal",Y(d,me.width/2-d.view.x,86-d.view.y,`FOOTBRIDGE ${d.footbridgeOrientation.toUpperCase()}`,w.green),re.updatePanels();return}e.key==="Escape"&&d.cardTargetPick?.pending&&(e.preventDefault(),d.cardTargetPick.mode==="autoScannerMenu"?On():Bn.cancelTargetPick())});te=Qa({game:d,ui:N,canvas:me,canvasPoint:qt,onUpdatePanels:()=>re?.updatePanels()});Ne=il({game:d,currentConveyorSpeed:Fd,onGameOverCheck:()=>re?.checkGameOver()});Bn=Ba({game:d,ui:N,onUpdatePanels:()=>re?.updatePanels()});re=Xa({game:d,ui:N,build:te,startGame:Od,beginCardDraft:()=>Bn.showDraft(),activeQueuedChick:Ne.activeQueuedChick});Cd();xd();Ir(d);Be(d);Ne.updateCongestion(d.frameId||0);re.updatePanels();re.updateUI();re.showTitle();zt();requestAnimationFrame(pl); diff --git a/index.html b/index.html index 3197a04..02699e2 100644 --- a/index.html +++ b/index.html @@ -6,13 +6,13 @@ - Chick Sorter v28.21 — Boost Draw Hotfix + Chick Sorter v29.00
-
-
v28.21 VERIFIED
+
+
v29.00
@@ -39,7 +39,7 @@
-

CHICK SORTER v28.21

+

CHICK SORTER v29.00

@@ -50,13 +50,20 @@
+ + + + - + + + +
@@ -110,6 +117,6 @@
- + diff --git a/package-lock.json b/package-lock.json index 2c9dd91..cd9545f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "zunda-shiwake", - "version": "28.2.1", + "version": "29.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "zunda-shiwake", - "version": "28.2.1", + "version": "29.0.0", "devDependencies": { "esbuild": "^0.25.0" } diff --git a/package.json b/package.json index 8d03f46..49e6e46 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "name": "zunda-shiwake", - "version": "28.2.1", + "version": "29.0.0", "private": true, "type": "module", "scripts": { "clean": "node -e \"require('fs').rmSync('dist', { recursive: true, force: true })\"", - "build": "npm run clean && esbuild src/game.js --bundle --format=esm --target=es2020 --minify --outfile=dist/game.js", - "test": "node test_v28_21.mjs" + "build": "npm run clean && node scripts/build.mjs", + "test": "node -e \"const fs=require('fs'); const cp=require('child_process'); if (fs.existsSync('test_v28_21.mjs')) cp.execFileSync(process.execPath, ['test_v28_21.mjs'], { stdio: 'inherit' }); cp.execFileSync(process.execPath, ['test_v29_00.mjs'], { stdio: 'inherit' });\"" }, "devDependencies": { "esbuild": "^0.25.0" diff --git a/scripts/build.mjs b/scripts/build.mjs new file mode 100644 index 0000000..a345a7a --- /dev/null +++ b/scripts/build.mjs @@ -0,0 +1,15 @@ +import { build } from 'esbuild'; +import { dirname, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const root = resolve(dirname(fileURLToPath(import.meta.url)), '..'); + +await build({ + absWorkingDir: root, + entryPoints: [resolve(root, 'src/game.js')], + bundle: true, + format: 'esm', + target: 'es2020', + minify: true, + outfile: resolve(root, 'dist/game.js') +}); diff --git a/src/core/balance.js b/src/core/balance.js index 2de476e..b096bca 100644 --- a/src/core/balance.js +++ b/src/core/balance.js @@ -1,7 +1,7 @@ // Central balance sheet for tuning gameplay. // Edit this file first when adjusting prices, income, penalties, timing, card rates, or caps. export const BALANCE = { - version: 'v28.21 BOOST DRAW HOTFIX', + version: 'v29.00', time: { daySeconds: 60, farmShutdownGraceSeconds: 10 @@ -84,7 +84,46 @@ export const BALANCE = { conveyor: { baseSpeed: 52, maxSpeed: 300, - bearingSpeedMultiplier: 1.075 + bearingSpeedMultiplier: 1.075, + minimumItemSpacingPx: 25 + }, + power: { + recalcHz: 10, + maxAssignmentPasses: 8, + wires: { + powerWire: { id: 'powerWire', name: 'Power Wire', shortName: 'WIRE', price: 10, lossV: 0.5 }, + insulatedPowerWire: { id: 'insulatedPowerWire', name: 'Insulated Wire', shortName: 'INS WIRE', price: 22, lossV: 0.15 } + }, + exempt: ['manualScanner', 'eggFarm', 'conveyor', 'boostConveyor', 'powerWire', 'insulatedPowerWire', 'footbridge', 'starterGenerator', 'biomassGenerator', 'coalGenerator'], + machines: { + mixer: { minVoltage: 10, drawV: 4, relayDropV: 4, powerPriority: 100 }, + trash: { minVoltage: 8, drawV: 3, relayDropV: 3, powerPriority: 100 }, + truck: { minVoltage: 6, drawV: 2, relayDropV: 2, powerPriority: 100 }, + autoScanner: { minVoltage: 8, drawV: 2, relayDropV: 2, powerPriority: 50 }, + sausageMaker: { minVoltage: 12, drawV: 5, relayDropV: 5, powerPriority: 50 }, + maintenanceRoom: { minVoltage: 6, drawV: 1, relayDropV: 1, powerPriority: 50 }, + inboundTruck: { minVoltage: 5, drawV: 1, relayDropV: 1, powerPriority: 50 } + }, + generators: { + starterGenerator: { outputV: 25 }, + biomassGenerator: { baseOutputV: 0, pulseVoltage: 5, pulseSeconds: 2 }, + coalGenerator: { baseOutputV: 0, pulseVoltage: 15, pulseSeconds: 3 } + } + }, + imports: { + combinedLimitPerTruck: 80, + prices: { coal: 2, zundaMochi: 4 }, + jitterRatio: 0.15 + }, + farmQuality: { + overflowCoefficient: 0.45, + overflowExponent: 0.85, + minMultiplier: 1, + maxMultiplier: 2.5, + zundaSeconds: 8, + zundaMaxSeconds: 30, + zundaIntervalMultiplier: 0.55, + safeMinIntervalSeconds: 0.25 }, effects: { explosionHorizontalVelocityMultiplier: 0.82 @@ -406,7 +445,11 @@ export const BALANCE = { autoScanner: 850, mixer: 775, trash: 950, - sausageMaker: 825 + sausageMaker: 825, + starterGenerator: 1000, + biomassGenerator: 900, + coalGenerator: 900, + inboundTruck: 850 }, processingDelayMaxSeconds: { mixer: 1.20, @@ -427,6 +470,18 @@ export const BALANCE = { id: 'boostConveyor', type: 'conveyor', name: 'Boost Conveyor', shortName: 'BOOST BELT', price: 75, buildable: true, upgradeable: false, speedMultiplier: 2 }, + powerWire: { + id: 'powerWire', type: 'powerWire', name: 'Power Wire', shortName: 'WIRE', price: 10, + buildable: true, upgradeable: false + }, + insulatedPowerWire: { + id: 'insulatedPowerWire', type: 'powerWire', name: 'Insulated Power Wire', shortName: 'INS WIRE', price: 22, + buildable: true, upgradeable: false + }, + footbridge: { + id: 'footbridge', type: 'footbridge', name: 'Footbridge', shortName: 'BRIDGE', price: 90, + buildable: true, upgradeable: false, footprint: { cols: 1, rows: 3 } + }, eggFarm: { id: 'eggFarm', type: 'eggFarm', name: 'Egg Farm', shortName: 'EGG', price: 250, buildable: true, upgradeable: true, maxLevel: 4 @@ -448,13 +503,29 @@ export const BALANCE = { buildable: true, upgradeable: true, body: { w: 180, h: 100 } }, truck: { - id: 'truck', type: 'facility', name: 'Truck', shortName: 'TRUCK', price: 450, + id: 'truck', type: 'facility', name: 'Shipping Truck', shortName: 'SHIP TRUCK', price: 450, buildable: true, upgradeable: true, incomeKey: 'truck', body: { w: 176, h: 138 } }, sausageMaker: { id: 'sausageMaker', type: 'facility', name: 'Sausage Machine', shortName: 'SAUSAGE', price: 380, buildable: true, upgradeable: true, incomeKey: 'sausage', footprint: { cols: 3, rows: 3 }, body: { w: 138, h: 138 }, outputProduct: 'sausage' }, + starterGenerator: { + id: 'starterGenerator', type: 'facility', name: 'Starter Generator', shortName: 'STARTER', price: 0, + buildable: false, upgradeable: false, footprint: { cols: 2, rows: 2 }, body: { w: 92, h: 92 } + }, + biomassGenerator: { + id: 'biomassGenerator', type: 'facility', name: 'Biomass Generator', shortName: 'BIOMASS', price: 520, + buildable: true, upgradeable: false, footprint: { cols: 3, rows: 3 }, body: { w: 138, h: 138 } + }, + coalGenerator: { + id: 'coalGenerator', type: 'facility', name: 'Coal Generator', shortName: 'COAL GEN', price: 680, + buildable: true, upgradeable: false, footprint: { cols: 2, rows: 3 }, body: { w: 92, h: 138 } + }, + inboundTruck: { + id: 'inboundTruck', type: 'facility', name: 'Inbound Truck', shortName: 'INBOUND', price: 350, + buildable: true, upgradeable: false, body: { w: 176, h: 120 } + }, maintenanceRoom: { id: 'maintenanceRoom', type: 'maintenanceRoom', name: 'Maintenance Room', shortName: 'REPAIR ROOM', price: 220, buildable: true, upgradeable: false, footprint: { cols: 2, rows: 2 } diff --git a/src/core/config.js b/src/core/config.js index 60aa59a..5857359 100644 --- a/src/core/config.js +++ b/src/core/config.js @@ -26,9 +26,9 @@ export const EGG_SPAWN_RANGES = BALANCE.production.eggSpawnRanges; export const GRID = BALANCE.grid; export const FACILITY_DEFS = BALANCE.facilities; -export const BUILD_TOOL_IDS = ['conveyor', 'boostConveyor', 'eggFarm', 'autoScanner', 'manualScanner', 'mixer', 'trash', 'truck', 'sausageMaker', 'maintenanceRoom']; -export const EDGE_FACILITY_IDS = ['mixer', 'trash', 'truck']; -export const GRID_FACILITY_IDS = ['sausageMaker']; +export const BUILD_TOOL_IDS = ['conveyor', 'boostConveyor', 'powerWire', 'insulatedPowerWire', 'footbridge', 'eggFarm', 'autoScanner', 'manualScanner', 'mixer', 'trash', 'truck', 'inboundTruck', 'sausageMaker', 'biomassGenerator', 'coalGenerator', 'maintenanceRoom']; +export const EDGE_FACILITY_IDS = ['mixer', 'trash', 'truck', 'inboundTruck']; +export const GRID_FACILITY_IDS = ['sausageMaker', 'starterGenerator', 'biomassGenerator', 'coalGenerator']; export const MACHINE_FACILITY_IDS = [...EDGE_FACILITY_IDS, ...GRID_FACILITY_IDS]; export const REQUIRED_RECEIVER_FACILITY_IDS = ['mixer', 'trash', 'truck']; export const INCOME_FACILITY_IDS = ['mixer', 'truck', 'sausageMaker']; diff --git a/src/core/entities.js b/src/core/entities.js index 9faf1dc..a39ac49 100644 --- a/src/core/entities.js +++ b/src/core/entities.js @@ -108,8 +108,9 @@ function facilityKind(facility) { return facility?.baseId || facility?.id || ''; export function syncGridFacilityGeometry(facility) { if (!facility?.gridPlaced) return facility; - facility.wCells = Math.max(1, facility.wCells || 3); - facility.hCells = Math.max(1, facility.hCells || 3); + const def = FACILITY_DEFS[facilityKind(facility)] || {}; + facility.wCells = Math.max(1, facility.wCells || def.footprint?.cols || 3); + facility.hCells = Math.max(1, facility.hCells || def.footprint?.rows || 3); facility.x = GRID.x + facility.col * GRID.cell; facility.y = GRID.y + facility.row * GRID.cell; facility.w = facility.wCells * GRID.cell; @@ -118,6 +119,10 @@ export function syncGridFacilityGeometry(facility) { facility.entry = { col: facility.col - 1, row: facility.row + Math.floor(facility.hCells / 2) }; facility.side = 'grid'; } + if (facilityKind(facility) === 'biomassGenerator' || facilityKind(facility) === 'coalGenerator') { + facility.entry = { col: facility.col - 1, row: facility.row + Math.floor(facility.hCells / 2) }; + facility.side = 'grid'; + } return facility; } @@ -193,6 +198,7 @@ export function createFacility(game, id, p, price) { price: price || spec.price, builtSession: game.buildSession }; + if (id === 'inboundTruck') f.inboundOrder = { coalPerDay: 0, zundaMochiPerDay: 0 }; return layoutFacilityOnEdge(f, entry, side); } @@ -204,13 +210,14 @@ export function createGridFacility(game, id, col, row, price) { name: def?.name || id, baseId: id, col, row, - wCells: id === 'sausageMaker' ? 3 : 1, - hCells: id === 'sausageMaker' ? 3 : 1, + wCells: def?.footprint?.cols || (id === 'sausageMaker' ? 3 : 1), + hCells: def?.footprint?.rows || (id === 'sausageMaker' ? 3 : 1), gridPlaced: true, level: 1, price: price || def?.price || 0, builtSession: game.buildSession }; + if (id === 'biomassGenerator' || id === 'coalGenerator') f.fuelPulses = []; return syncGridFacilityGeometry(f); } diff --git a/src/core/state.js b/src/core/state.js index 0e87cde..33ccc29 100644 --- a/src/core/state.js +++ b/src/core/state.js @@ -48,7 +48,30 @@ export function newTurnStats() { explosions: 0, eventResult: null, conveyorPasses: 0, - eggProduced: 0 + eggProduced: 0, + coalOrdered: 0, + coalReleased: 0, + coalConsumed: 0, + coalUndelivered: 0, + zundaOrdered: 0, + zundaReleased: 0, + zundaConsumed: 0, + zundaUndelivered: 0, + zundaBoostSeconds: 0, + zundaBoostSecondsByFarm: {}, + importPurchaseCost: 0, + biomassFuelConsumed: 0, + maxGeneratorOutput: {}, + qualityRevenue: 0, + farmTheoreticalRate: 0, + farmActualOutputRate: 0, + qualityMultiplierSum: 0, + qualityMultiplierCount: 0, + maxQualityMultiplier: 1, + generatorAssignmentChanges: 0, + underVoltageSeconds: 0, + underVoltageSecondsByMachine: {}, + unreachableRepairTargets: 0 }; } @@ -89,7 +112,22 @@ export function newTotalStats() { eventSuccess: 0, eventFailed: 0, conveyorPasses: 0, - eggProduced: 0 + eggProduced: 0, + coalOrdered: 0, + coalReleased: 0, + coalConsumed: 0, + coalUndelivered: 0, + zundaOrdered: 0, + zundaReleased: 0, + zundaConsumed: 0, + zundaUndelivered: 0, + zundaBoostSeconds: 0, + importPurchaseCost: 0, + biomassFuelConsumed: 0, + qualityRevenue: 0, + generatorAssignmentChanges: 0, + underVoltageSeconds: 0, + unreachableRepairTargets: 0 }; } @@ -115,6 +153,7 @@ export function createGame() { ownedCells: new Set(), blockedCells: new Set(), buildTool: null, + footbridgeOrientation: 'vertical', buildSession: 0, undoStack: [], redoStack: [], @@ -130,8 +169,15 @@ export function createGame() { floatingTexts: [], shake: { time: 0, strength: 0 }, truckCargo: [], + shippedCargo: [], conveyorTiles: new Set(), conveyorMeta: new Map(), + powerWires: new Map(), + footbridges: new Map(), + powerOverlay: false, + power: { dirty: true, elapsed: 0, routes: new Map(), assignments: new Map(), sources: new Map(), underVoltage: new Set() }, + imports: { schedules: new Map() }, + walkabilityVersion: 0, eggFarms: [], scanners: [], facilities: {}, @@ -316,9 +362,73 @@ function protectedInitialCells(game) { for (const p of farmOutputCells(farm)) add(p); } for (const f of Object.values(game.facilities)) add(f.entry); + for (const f of Object.values(game.facilities)) { + if (f.gridPlaced) { + for (let dr = 0; dr < (f.hCells || 1); dr += 1) for (let dc = 0; dc < (f.wCells || 1); dc += 1) add({ col: f.col + dc, row: f.row + dr }); + } + } return reserved; } +function addPowerWire(game, col, row, kind = 'powerWire', free = false) { + if (!inGrid(col, row)) return; + game.powerWires.set(key(col, row), { + kind, + price: free ? 0 : (BALANCE.power.wires[kind]?.price || 0), + builtSession: free ? null : game.buildSession + }); +} + +function installStarterGenerator(game) { + const def = FACILITY_DEFS.starterGenerator; + const starter = { + type: 'facility', + id: 'starterGenerator', + baseId: 'starterGenerator', + name: def.name, + col: 6, + row: 6, + wCells: def.footprint.cols, + hCells: def.footprint.rows, + gridPlaced: true, + level: 1, + price: 0, + builtSession: null, + unsellable: true + }; + starter.x = GRID.x + starter.col * GRID.cell; + starter.y = GRID.y + starter.row * GRID.cell; + starter.w = starter.wCells * GRID.cell; + starter.h = starter.hCells * GRID.cell; + game.facilities.starterGenerator = starter; +} + +function createStarterPowerLayout(game) { + game.powerWires = new Map(); + const routeCells = [ + [5, 6], [4, 6], [3, 6], [2, 6], [1, 6], [0, 6], [0, 5], [0, 4], + [8, 7], [8, 8], [9, 8], [10, 8], [11, 8], [12, 8], [12, 9], + [13, 8], [14, 8], [15, 8], [16, 8], [17, 8], [18, 8], [18, 9] + ]; + for (const [col, row] of routeCells) addPowerWire(game, col, row, 'powerWire', true); +} + +function validateStarterPowerLayout(game) { + const bodyCells = new Set(); + for (const f of Object.values(game.facilities || {})) { + if (!f.gridPlaced) continue; + for (let dr = 0; dr < (f.hCells || 1); dr += 1) { + for (let dc = 0; dc < (f.wCells || 1); dc += 1) bodyCells.add(key(f.col + dc, f.row + dr)); + } + } + for (const k of game.powerWires.keys()) { + if (game.blockedCells.has(k) || bodyCells.has(k)) throw new Error(`Invalid starter power wire at ${k}`); + } + for (const id of ['starterGenerator', 'mixer', 'trash', 'truck']) { + if (!game.facilities[id]) throw new Error(`Missing starter power facility: ${id}`); + } +} + function installInitialConveyorBackbone(game) { const cells = INITIAL_CONVEYOR_BACKBONE.map(([col, row]) => ({ col, row })); for (const { col, row } of cells) addConveyorTile(game, col, row); @@ -347,11 +457,14 @@ export function resetLayout(game) { } game.conveyorTiles.clear(); game.conveyorMeta.clear(); + game.powerWires = new Map(); + game.footbridges = new Map(); game.maintenanceRooms = []; game.repairmen = []; game.blockedCells = new Set(); installInitialConveyorBackbone(game); game.facilities = defaultFacilities(); + installStarterGenerator(game); game.scanners = INITIAL_SCANNERS.map(scanner => ({ ...scanner, keys: scanner.keys ? { left: { ...scanner.keys.left }, right: { ...scanner.keys.right } } : null, queue: [] })); game.eggFarms = INITIAL_EGG_FARMS.map(farm => { const nextSpawn = nextSpawnDelay(farm); @@ -363,10 +476,16 @@ export function resetLayout(game) { // scanner body/ports, farm output, and machine receiver. This guarantees that // the starter line is always continuous from Egg Farm -> S1 -> S2 -> exits even // when roughly 3% of the initial map is blocked. + createStarterPowerLayout(game); const reserved = protectedInitialCells(game); + for (const k of game.powerWires.keys()) reserved.add(k); game.blockedCells = generateBlockedCells({ seed: game.runSeed, targetRatio: BALANCE.map.blockedRatio, reserved: [...reserved] }); scrubBlockedCellsFromInitialBackbone(game); installInitialConveyorBackbone(game); + createStarterPowerLayout(game); + validateStarterPowerLayout(game); + game.power = { dirty: true, elapsed: 0, routes: new Map(), assignments: new Map(), sources: new Map(), underVoltage: new Set() }; + game.walkabilityVersion = (game.walkabilityVersion || 0) + 1; game.routingVersion = (game.routingVersion || 0) + 1; game.factoryGraph = null; game.factoryGraphCommittedVersion = -1; diff --git a/src/core/text.js b/src/core/text.js index 1835764..11de26e 100644 --- a/src/core/text.js +++ b/src/core/text.js @@ -32,8 +32,11 @@ export const TEXT = { routeLabels: { mixer: 'MIXER', truck: 'TRUCK', + inboundTruck: 'INBOUND', trash: 'WASTE', sausageMaker: 'SAUSAGE', + biomassGenerator: 'BIOMASS', + coalGenerator: 'COAL GEN', scanner: 'NEXT', 'scanner-role-1': 'NEXT', input: 'IN' @@ -71,7 +74,13 @@ export function buildToolFlavorText(id) { manualScanner: 'A manual checkpoint. The operator is the algorithm.', mixer: 'Makes meat when OUT is clear; otherwise falls back to direct sale.', trash: 'A polite shredder for poop and other regrets.', - truck: 'Ships target chicks and all sausages. Wrong live cargo still leaves a paper trail.', + truck: 'Shipping Truck. Ships target chicks and all sausages.', + powerWire: 'Overlay wire. Loses 0.5V per tile.', + insulatedPowerWire: 'Overlay wire. Loses 0.15V per tile.', + footbridge: 'Lets repair workers cross conveyor cells.', + inboundTruck: 'Imports coal and zunda mochi during the day.', + biomassGenerator: 'Fuel generator. Chicks and poop add timed voltage.', + coalGenerator: 'Fuel generator. Coal adds timed voltage.', sausageMaker: 'A 3×3 grid machine. Left inlet takes 2 meat; right outlet emits 1 sausage.', maintenanceRoom: '2×2 repair bay. Each room dispatches one repairman during the day.' }; diff --git a/src/game.js b/src/game.js index 2b73711..1852aed 100644 --- a/src/game.js +++ b/src/game.js @@ -14,6 +14,8 @@ import { CARD_DEFS, cardById, conveyorSpeedForGame, createCardSystem, debugCardT import { floating, shockwave, sparkBurst, updateEffects } from './systems/effects.js'; import { EVENT_TARGETS, createEventOffer, rollEventOffer, activateEventOffer, clearActiveEvent, resolveEvent, eventDaySeconds, fairiesTributeMultiplierFromEvent } from './systems/events.js'; import { ensureMaintenanceState, activateRepairmanForDay, deactivateRepairman, conveyorSpeedFactorForKey } from './systems/maintenance.js'; +import { updatePowerSystem, recalculatePowerNetwork } from './systems/power.js'; +import { startInboundOrders, settleUndeliveredImports } from './systems/imports.js'; const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); @@ -42,7 +44,7 @@ const ui = { }, buttons: { s1Left: document.getElementById('scanner1MixerButton'), s1Right: document.getElementById('scanner1TruckButton'), s2Left: document.getElementById('scanner2MixerButton'), s2Right: document.getElementById('scanner2TruckButton'), - nextTurn: document.getElementById('nextTurnButton'), conveyor: document.getElementById('buildConveyorButton'), boostConveyor: document.getElementById('buildBoostConveyorButton'), eggFarm: document.getElementById('buildEggFarmButton'), autoScanner: document.getElementById('buildAutoScannerButton'), manualScanner: document.getElementById('buildManualScannerButton'), mixer: document.getElementById('buildMixerButton'), trash: document.getElementById('buildTrashButton'), truck: document.getElementById('buildTruckButton'), sausageMaker: document.getElementById('buildSausageMakerButton'), maintenanceRoom: document.getElementById('buildMaintenanceRoomButton'), erase: document.getElementById('eraseButton'), undo: document.getElementById('undoButton'), redo: document.getElementById('redoButton') + nextTurn: document.getElementById('nextTurnButton'), conveyor: document.getElementById('buildConveyorButton'), boostConveyor: document.getElementById('buildBoostConveyorButton'), powerWire: document.getElementById('buildPowerWireButton'), insulatedPowerWire: document.getElementById('buildInsulatedPowerWireButton'), powerOverlay: document.getElementById('powerOverlayButton'), footbridge: document.getElementById('buildFootbridgeButton'), eggFarm: document.getElementById('buildEggFarmButton'), autoScanner: document.getElementById('buildAutoScannerButton'), manualScanner: document.getElementById('buildManualScannerButton'), mixer: document.getElementById('buildMixerButton'), trash: document.getElementById('buildTrashButton'), truck: document.getElementById('buildTruckButton'), inboundTruck: document.getElementById('buildInboundTruckButton'), sausageMaker: document.getElementById('buildSausageMakerButton'), biomassGenerator: document.getElementById('buildBiomassGeneratorButton'), coalGenerator: document.getElementById('buildCoalGeneratorButton'), maintenanceRoom: document.getElementById('buildMaintenanceRoomButton'), erase: document.getElementById('eraseButton'), undo: document.getElementById('undoButton'), redo: document.getElementById('redoButton') } }; @@ -51,13 +53,19 @@ function initializeStaticText() { const buttonToolMap = { conveyor: 'conveyor', boostConveyor: 'boostConveyor', + powerWire: 'powerWire', + insulatedPowerWire: 'insulatedPowerWire', + footbridge: 'footbridge', eggFarm: 'eggFarm', autoScanner: 'autoScanner', manualScanner: 'manualScanner', mixer: 'mixer', trash: 'trash', truck: 'truck', + inboundTruck: 'inboundTruck', sausageMaker: 'sausageMaker', + biomassGenerator: 'biomassGenerator', + coalGenerator: 'coalGenerator', maintenanceRoom: 'maintenanceRoom' }; for (const [buttonKey, toolId] of Object.entries(buttonToolMap)) { @@ -285,6 +293,10 @@ function startNextTurn() { } ensureMaintenanceState(game); commitFactoryGraphForDay(game); + const powerState = recalculatePowerNetwork(game); + if (powerState.underVoltage?.size) { + floating(game, canvas.width / 2 - game.view.x, 136 - game.view.y, `${powerState.underVoltage.size} UNDER-VOLTAGE`, THEME.warn); + } activateRepairmanForDay(game); const priorProfit = Math.max(0, Math.floor(game.lastResult?.profit ?? game.stats?.profit ?? 0)); const tribute = collectFairiesTribute(game, Math.max(1, game.turn || 1), priorProfit); @@ -303,15 +315,17 @@ function startNextTurn() { game.floatingTexts = []; game.shake = { time: 0, strength: 0 }; game.truckCargo = []; + game.shippedCargo = []; resetCameraToFactoryStart(); game.stats = newTurnStats(); + startInboundOrders(game); game.stats.fairiesTribute = game.lastStartFees?.fairiesTribute || 0; if (game.stats.fairiesTribute > 0) { game.stats.penalty += game.stats.fairiesTribute; game.stats.profit -= game.stats.fairiesTribute; } for (const scanner of game.scanners) { scanner.queue = []; scanner.cooldown = 0; } - for (const farm of game.eggFarms) { farm.nextSpawn = chicks.currentSpawnDelay(farm); farm.lastInterval = farm.nextSpawn; farm.shutterProgress = 0; farm.shutterSparked = false; } + for (const farm of game.eggFarms) { farm.nextSpawn = chicks.currentSpawnDelay(farm); farm.lastInterval = farm.nextSpawn; farm.shutterProgress = 0; farm.shutterSparked = false; farm.zundaBoostTime = 0; } game.buildTool = null; game.selected = null; game.groupDrag = null; @@ -325,6 +339,11 @@ function startNextTurn() { function completeTurn() { if (game.phase !== 'running') return; + settleUndeliveredImports(game); + for (const facility of Object.values(game.facilities || {})) { + if (facility.fuelPulses) facility.fuelPulses = []; + } + for (const farm of game.eggFarms || []) farm.zundaBoostTime = 0; const ship = settleTruckRevenue(game); const activeEvent = game.eventActive ? { ...game.eventActive } : null; const eventResult = resolveEvent(game); @@ -356,6 +375,7 @@ function completeTurn() { function enterBuildPhase() { game.phase = 'build'; game.truckCargo = []; + game.shippedCargo = []; game.chicks = []; game.shutdownTimeLeft = 0; game.cleanupTimer = null; @@ -415,6 +435,7 @@ function update(timestamp) { game.lastTimestamp = timestamp; game.frameId = (game.frameId || 0) + 1; chicks.beginFrame?.(game.frameId); + updatePowerSystem(game, dt); if (game.phase === 'running') chicks.updateRunning(dt, { closeFarmShutters, completeTurn }); updateEffects(game, dt, canvas, build.equipmentHitBoxes); chicks.updateCongestion(game.frameId); @@ -591,6 +612,7 @@ function clickSelect(event) { const obj = build.selectedObject(); if (obj?.type === 'scanner' && obj.kind === 'manual') build.showManualScannerMenu(obj); if (obj?.type === 'scanner' && obj.kind === 'auto') build.showAutoScannerMenu(obj); + if (obj?.type === 'facility' && (obj.baseId || obj.id) === 'inboundTruck') build.showInboundTruckMenu(obj); } function cancelBuildAction() { @@ -807,7 +829,7 @@ document.addEventListener('pointerdown', event => { }, true); ui.buttons.s1Left.addEventListener('click', () => chicks.sortSlot(0, 'left')); ui.buttons.s1Right.addEventListener('click', () => chicks.sortSlot(0, 'right')); ui.buttons.s2Left.addEventListener('click', () => chicks.sortSlot(1, 'left')); ui.buttons.s2Right.addEventListener('click', () => chicks.sortSlot(1, 'right')); -ui.buttons.nextTurn.addEventListener('click', startNextTurn); ui.buttons.conveyor.addEventListener('click', () => build.setBuildTool('conveyor')); ui.buttons.boostConveyor.addEventListener('click', () => build.setBuildTool('boostConveyor')); ui.buttons.eggFarm.addEventListener('click', () => build.setBuildTool('eggFarm')); ui.buttons.autoScanner.addEventListener('click', () => build.setBuildTool('autoScanner')); ui.buttons.manualScanner.addEventListener('click', () => build.setBuildTool('manualScanner')); ui.buttons.mixer.addEventListener('click', () => build.setBuildTool('mixer')); ui.buttons.trash.addEventListener('click', () => build.setBuildTool('trash')); ui.buttons.truck.addEventListener('click', () => build.setBuildTool('truck')); ui.buttons.sausageMaker.addEventListener('click', () => build.setBuildTool('sausageMaker')); ui.buttons.maintenanceRoom.addEventListener('click', () => build.setBuildTool('maintenanceRoom')); ui.buttons.erase.addEventListener('click', () => build.setBuildTool('erase')); +ui.buttons.nextTurn.addEventListener('click', startNextTurn); ui.buttons.conveyor.addEventListener('click', () => build.setBuildTool('conveyor')); ui.buttons.boostConveyor.addEventListener('click', () => build.setBuildTool('boostConveyor')); ui.buttons.powerWire?.addEventListener('click', () => build.setBuildTool('powerWire')); ui.buttons.insulatedPowerWire?.addEventListener('click', () => build.setBuildTool('insulatedPowerWire')); ui.buttons.powerOverlay?.addEventListener('click', () => { game.powerOverlay = !game.powerOverlay; uiSystem.updatePanels(); }); ui.buttons.footbridge?.addEventListener('click', () => build.setBuildTool('footbridge')); ui.buttons.eggFarm.addEventListener('click', () => build.setBuildTool('eggFarm')); ui.buttons.autoScanner.addEventListener('click', () => build.setBuildTool('autoScanner')); ui.buttons.manualScanner.addEventListener('click', () => build.setBuildTool('manualScanner')); ui.buttons.mixer.addEventListener('click', () => build.setBuildTool('mixer')); ui.buttons.trash.addEventListener('click', () => build.setBuildTool('trash')); ui.buttons.truck.addEventListener('click', () => build.setBuildTool('truck')); ui.buttons.inboundTruck?.addEventListener('click', () => build.setBuildTool('inboundTruck')); ui.buttons.sausageMaker.addEventListener('click', () => build.setBuildTool('sausageMaker')); ui.buttons.biomassGenerator?.addEventListener('click', () => build.setBuildTool('biomassGenerator')); ui.buttons.coalGenerator?.addEventListener('click', () => build.setBuildTool('coalGenerator')); ui.buttons.maintenanceRoom.addEventListener('click', () => build.setBuildTool('maintenanceRoom')); ui.buttons.erase.addEventListener('click', () => build.setBuildTool('erase')); ui.debug.setDay?.addEventListener('click', debugSetDay); ui.debug.zeroTimer?.addEventListener('click', debugZeroTimer); ui.debug.grantCard?.addEventListener('click', debugGrantSelectedCard); @@ -830,6 +852,13 @@ window.addEventListener('keydown', event => { } if (game.phase === 'build' && (event.ctrlKey || event.metaKey) && name === 'z') { event.preventDefault(); if (undo(game)) { clampCamera(); uiSystem.updatePanels(); uiSystem.updateUI(); } } if (game.phase === 'build' && (event.ctrlKey || event.metaKey) && (name === 'y' || (event.shiftKey && name === 'z'))) { event.preventDefault(); if (redo(game)) { clampCamera(); uiSystem.updatePanels(); uiSystem.updateUI(); } } + if (game.phase === 'build' && game.buildTool === 'footbridge' && name === 'r') { + event.preventDefault(); + game.footbridgeOrientation = game.footbridgeOrientation === 'horizontal' ? 'vertical' : 'horizontal'; + floating(game, canvas.width / 2 - game.view.x, 86 - game.view.y, `FOOTBRIDGE ${game.footbridgeOrientation.toUpperCase()}`, THEME.green); + uiSystem.updatePanels(); + return; + } if (event.key === 'Escape' && game.cardTargetPick?.pending) { event.preventDefault(); if (game.cardTargetPick.mode === 'autoScannerMenu') cancelBuildAction(); diff --git a/src/render/draw.js b/src/render/draw.js index e5111b2..7042e77 100644 --- a/src/render/draw.js +++ b/src/render/draw.js @@ -6,6 +6,7 @@ import { upgradedTruckPrice, upgradedSausagePrice } from '../systems/economy.js' import { cardTargetBounds, conveyorSpeedForGame } from '../systems/cards.js'; import { wearRatio, conveyorSpeedFactorForKey } from '../systems/maintenance.js'; import { facilityBodyPortPoint } from '../core/entities.js'; +import { powerDetailsFor, currentGeneratorOutputV } from '../systems/power.js'; // Optional art overlay hook. // Keep external art probing disabled by default so a clean checkout does not emit 404s for missing PNGs. @@ -67,6 +68,7 @@ function makeCanvas(width, height) { } export function drawAll(ctx, canvas, game, helpers) { + ctx.__gameRef = game; ctx.imageSmoothingEnabled = false; ctx.clearRect(0, 0, canvas.width, canvas.height); drawBackground(ctx, canvas, game); @@ -79,6 +81,8 @@ export function drawAll(ctx, canvas, game, helpers) { drawGrid(ctx, game); drawExpansionOffers(ctx, game); drawConveyors(ctx, game); + drawPowerWires(ctx, game); + drawFootbridges(ctx, game); drawScannerConnectors(ctx, game); drawMaintenanceRooms(ctx, game); drawFacilities(ctx, game); @@ -565,6 +569,54 @@ function drawConveyors(ctx, game) { ctx.restore(); } +function drawPowerWires(ctx, game) { + if (!game.powerWires?.size) return; + ctx.save(); + for (const [k, wire] of game.powerWires) { + const p = parseKey(k); + const c = cellCenter(p.col, p.row); + const insulated = wire.kind === 'insulatedPowerWire'; + ctx.globalAlpha = game.powerOverlay || game.phase === 'build' ? 0.95 : 0.32; + ctx.strokeStyle = insulated ? '#d7eef7' : '#1e252b'; + ctx.lineWidth = insulated ? 8 : 5; + ctx.lineCap = 'round'; + ctx.beginPath(); + ctx.moveTo(c.x - 15, c.y); + ctx.lineTo(c.x + 15, c.y); + ctx.moveTo(c.x, c.y - 15); + ctx.lineTo(c.x, c.y + 15); + ctx.stroke(); + ctx.strokeStyle = insulated ? '#2c8ec4' : '#f3c33d'; + ctx.lineWidth = insulated ? 3 : 2; + ctx.stroke(); + if (game.powerOverlay) label(ctx, c.x, c.y - 14, insulated ? 'I' : 'V', insulated ? '#2c8ec4' : THEME.warn); + } + ctx.restore(); +} + +function drawFootbridges(ctx, game) { + if (!game.footbridges?.size) return; + ctx.save(); + for (const k of game.footbridges.keys()) { + const p = parseKey(k); + const c = cellCenter(p.col, p.row); + ctx.fillStyle = 'rgba(210,222,228,.52)'; + ctx.strokeStyle = '#e6edf2'; + ctx.lineWidth = 3; + rect(ctx, c.x - 20, c.y - 14, 40, 28, true, true); + ctx.strokeStyle = '#34404a'; + ctx.lineWidth = 2; + ctx.beginPath(); + ctx.moveTo(c.x - 18, c.y - 9); + ctx.lineTo(c.x + 18, c.y - 9); + ctx.moveTo(c.x - 18, c.y + 9); + ctx.lineTo(c.x + 18, c.y + 9); + ctx.stroke(); + drawSelection(ctx, game, 'footbridge', k, c.x, c.y, 44, 34); + } + ctx.restore(); +} + export function drawAnimatedConveyorStripes(ctx, game, center, tileKey, meta = {}, ratio = 0) { const boost = meta.kind === 'boostConveyor'; @@ -1065,11 +1117,22 @@ function drawFacilityDetails(ctx, f, accent = THEME.green) { rect(ctx, f.x + f.w - 44, f.y + 12, 30, 22, true, true); ctx.fillStyle = accent; ctx.fillRect(f.x + f.w - 38, f.y + 18, 6, 6); ctx.fillStyle = THEME.danger; ctx.fillRect(f.x + f.w - 27, f.y + 18, 6, 6); + const power = powerDetailsFor(nullSafeGame(ctx), f); + if (power && power.receivedV < power.minVoltage) { + ctx.fillStyle = THEME.danger; + ctx.font = '900 18px ui-monospace, monospace'; + ctx.textAlign = 'center'; + ctx.fillText('X⚡', f.x + f.w - 28, f.y + 52); + } ctx.strokeStyle = '#47515f'; ctx.lineWidth = 3; ctx.beginPath(); ctx.moveTo(f.x + 12, f.y + f.h - 35); ctx.bezierCurveTo(f.x + 42, f.y + f.h - 52, f.x + 60, f.y + f.h - 20, f.x + 88, f.y + f.h - 38); ctx.stroke(); ctx.restore(); } +function nullSafeGame(ctx) { + return ctx.__gameRef || {}; +} + function drawFacilityTexture(ctx, image, f, maxCells = 1.45) { if (!image?.loaded) return false; // Keep external-machine sprites at roughly the same pixel density as a grid object. @@ -1122,12 +1185,53 @@ function drawFacilities(ctx, game) { else if (kind === 'trash') drawTrash(ctx, game, f); else if (kind === 'truck') drawTruck(ctx, game, f); else if (kind === 'sausageMaker') drawSausageMaker(ctx, game, f); + else if (kind === 'starterGenerator' || kind === 'biomassGenerator' || kind === 'coalGenerator') drawGenerator(ctx, game, f, kind); + else if (kind === 'inboundTruck') drawInboundTruck(ctx, game, f); } for (const f of Object.values(game.facilities || {})) { drawFacilityReceiver(ctx, game, f); drawFacilityOutput(ctx, game, f); } } + +function drawGenerator(ctx, game, f, kind) { + ctx.save(); + const accent = kind === 'starterGenerator' ? THEME.warn : (kind === 'biomassGenerator' ? THEME.green : '#d0d5dc'); + drawMetalPanel(ctx, f.x, f.y, f.w, f.h, '#252b31', THEME.ink, accent); + drawFacilityDetails(ctx, f, accent); + ctx.fillStyle = THEME.white; + ctx.font = '900 13px ui-monospace, monospace'; + ctx.textAlign = 'left'; + const title = kind === 'starterGenerator' ? 'STARTER' : (kind === 'biomassGenerator' ? 'BIOMASS' : 'COAL GEN'); + ctx.fillText(title, f.x + 12, f.y + 18); + ctx.font = '900 18px ui-monospace, monospace'; + ctx.textAlign = 'center'; + ctx.fillStyle = accent; + ctx.fillText(kind === 'biomassGenerator' ? 'LEAF' : '⚡', f.x + f.w / 2, f.y + f.h / 2 - 4); + ctx.font = '900 12px ui-monospace, monospace'; + ctx.fillText(`${currentGeneratorOutputV(f).toFixed(0)}V`, f.x + f.w / 2, f.y + f.h / 2 + 20); + drawSelection(ctx, game, 'facility', f.id, f.x + f.w / 2, f.y + f.h / 2, f.w + 12, f.h + 12); + ctx.restore(); +} + +function drawInboundTruck(ctx, game, t) { + ctx.save(); + drawExternalDuct(ctx, t); + drawMetalPanel(ctx, t.x, t.y, t.w, t.h, '#29313a', THEME.ink, '#8bd0ff'); + drawFacilityDetails(ctx, t, '#8bd0ff'); + ctx.fillStyle = THEME.white; + ctx.font = '900 14px ui-monospace, monospace'; + ctx.textAlign = 'left'; + ctx.fillText('INBOUND', t.x + 14, t.y + 18); + ctx.fillStyle = '#8bd0ff'; + ctx.font = '900 11px ui-monospace, monospace'; + ctx.fillText(`COAL ${t.inboundOrder?.coalPerDay || 0} / ZUNDA ${t.inboundOrder?.zundaMochiPerDay || 0}`, t.x + 14, t.y + 36); + ctx.fillStyle = 'rgba(10,18,24,.9)'; + rect(ctx, t.x + 18, t.y + 54, t.w - 36, t.h - 70, true, true); + label(ctx, t.x + t.w / 2, t.y + t.h - 18, `Q ${t.inboundQueue?.length || 0}`, '#8bd0ff'); + drawSelection(ctx, game, 'facility', t.id, t.x + t.w / 2, t.y + t.h / 2, t.w + 12, t.h + 12); + ctx.restore(); +} function drawFacilityOutput(ctx, game, f) { const p = facilityOutputCell(game, f); if (!p) return; @@ -1263,7 +1367,7 @@ function drawTruck(ctx, game, t = game.facilities.truck) { drawMetalPanel(ctx, t.x, t.y, t.w, t.h, '#343128', THEME.ink, THEME.truckPink); drawFacilityDetails(ctx, t, THEME.truckPink); ctx.fillStyle = THEME.white; ctx.font = '900 14px ui-monospace, monospace'; ctx.textAlign = 'left'; - ctx.fillText(`TRUCK L${t.level}`, t.x + 14, t.y + 18); + ctx.fillText(`SHIP TRUCK L${t.level}`, t.x + 14, t.y + 18); ctx.fillStyle = THEME.muted; ctx.font = '900 10px ui-monospace, monospace'; ctx.fillText(`UNIT ${yen(upgradedTruckPrice(game))}`, t.x + 14, t.y + 34); drawFacilityTexture(ctx, assets.truck, t, 2.0); @@ -1296,6 +1400,8 @@ function drawChick(ctx, chick, active, game) { if (chick.sex === 'poop') drawPoop(ctx, chick.x, y, chick.radius); else if (chick.sex === 'meat') drawMeatItem(ctx, chick.x, y, chick.radius); else if (chick.sex === 'sausage') drawSausageItem(ctx, chick.x, y, chick.radius); + else if (chick.sex === 'coal') drawCoalItem(ctx, chick.x, y, chick.radius); + else if (chick.sex === 'zundaMochi') drawZundaItem(ctx, chick.x, y, chick.radius); else { const img = chick.sex === 'male' ? assets.chickMale : assets.chickFemale; const spriteDrawn = drawImageIfLoaded(ctx, img, chick.x - chick.radius, y - chick.radius, chick.radius * 2, chick.radius * 2); @@ -1367,6 +1473,31 @@ function drawSausageItem(ctx, x, y, radius = 10) { } ctx.restore(); } +function drawCoalItem(ctx, x, y, radius = 10) { + ctx.save(); + ctx.fillStyle = '#111318'; + ctx.strokeStyle = '#050609'; + ctx.lineWidth = 3; + rect(ctx, x - radius, y - radius * 0.85, radius * 2, radius * 1.7, true, true); + ctx.fillStyle = '#3b424b'; + ctx.fillRect(x - radius * 0.5, y - radius * 0.5, radius * 0.8, radius * 0.35); + ctx.restore(); +} +function drawZundaItem(ctx, x, y, radius = 10) { + ctx.save(); + ctx.fillStyle = '#6fce57'; + ctx.strokeStyle = THEME.ink; + ctx.lineWidth = 3; + ctx.beginPath(); + ctx.moveTo(x, y - radius); + ctx.lineTo(x + radius, y); + ctx.lineTo(x, y + radius); + ctx.lineTo(x - radius, y); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); +} function drawTinyChick(ctx, x, y, sex, warning = false) { ctx.save(); const bodyColor = sex === 'male' ? THEME.male : THEME.female; diff --git a/src/systems/buildSystem.js b/src/systems/buildSystem.js index 425d4bc..07224cd 100644 --- a/src/systems/buildSystem.js +++ b/src/systems/buildSystem.js @@ -13,6 +13,8 @@ import { record } from './history.js'; import { floating, eraseEffect } from './effects.js'; import { createSelectionSystem } from './selectionSystem.js'; import { ensureMaintenanceState, remainingPercent, performanceFactor, autoScannerDelayMultiplier, eggSpawnDelayMultiplier, facilityProcessingDelay, durabilityCapFor } from './maintenance.js'; +import { markPowerDirty, powerDetailsFor } from './power.js'; +import { boostOutputCapacityPerSecond, farmTheoreticalRatePerSecond, qualityForRate, qualityGrade } from './farmQuality.js'; export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanels }) { function updatePanels() { if (onUpdatePanels) onUpdatePanels(); } @@ -42,6 +44,8 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel game.blockedCells = shiftRowIndexedSet(game.blockedCells, rowDelta); game.conveyorTiles = shiftRowIndexedSet(game.conveyorTiles, rowDelta); game.conveyorMeta = shiftRowIndexedMap(game.conveyorMeta, rowDelta); + game.powerWires = shiftRowIndexedMap(game.powerWires || new Map(), rowDelta); + game.footbridges = shiftRowIndexedMap(game.footbridges || new Map(), rowDelta); for (const farm of game.eggFarms || []) farm.row += rowDelta; for (const scanner of game.scanners || []) scanner.row += rowDelta; for (const facility of Object.values(game.facilities || {})) { @@ -59,6 +63,8 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel game.blockedCells = shiftColIndexedSet(game.blockedCells, colDelta); game.conveyorTiles = shiftColIndexedSet(game.conveyorTiles, colDelta); game.conveyorMeta = shiftColIndexedMap(game.conveyorMeta, colDelta); + game.powerWires = shiftColIndexedMap(game.powerWires || new Map(), colDelta); + game.footbridges = shiftColIndexedMap(game.footbridges || new Map(), colDelta); for (const farm of game.eggFarms || []) farm.col += colDelta; for (const scanner of game.scanners || []) scanner.col += colDelta; for (const room of game.maintenanceRooms || []) room.col += colDelta; @@ -245,16 +251,22 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel } function gridFacilityPlacementBlocked(id, col, row, moving = null) { - const draft = { baseId: id, id, gridPlaced: true, col, row, wCells: id === 'sausageMaker' ? 3 : 1, hCells: id === 'sausageMaker' ? 3 : 1 }; + const def = BALANCE.facilities[id] || {}; + const draft = { baseId: id, id, gridPlaced: true, col, row, wCells: def.footprint?.cols || (id === 'sausageMaker' ? 3 : 1), hCells: def.footprint?.rows || (id === 'sausageMaker' ? 3 : 1) }; for (const cell of gridFacilityFootprintCells(draft)) { if (!pointInGrid(cell.col, cell.row) || isBlockedCell(cell.col, cell.row) || isEquipmentCell(cell.col, cell.row, moving) || facilityPortAt(cell.col, cell.row, moving)) return true; } - if (id === 'sausageMaker') { + if (id === 'sausageMaker' || id === 'biomassGenerator' || id === 'coalGenerator') { const input = { col: col - 1, row: row + 1 }; - const output = { col: col + 3, row: row + 1 }; - if (!pointInGrid(input.col, input.row) || !pointInGrid(output.col, output.row)) return true; - if (isBlockedCell(input.col, input.row) || isBlockedCell(output.col, output.row)) return true; - for (const port of [input, output]) { + const output = { col: col + (draft.wCells || 1), row: row + 1 }; + const biomassPorts = [ + input, + { col: col + 1, row: row - 1 }, + { col: col + 1, row: row + (draft.hCells || 3) } + ]; + const ports = id === 'sausageMaker' ? [input, output] : (id === 'biomassGenerator' ? biomassPorts : [input]); + for (const port of ports) { + if (!pointInGrid(port.col, port.row) || isBlockedCell(port.col, port.row)) return true; const portGridFacility = gridFacilityAt(game, port.col, port.row); if (portGridFacility && portGridFacility.id !== moving?.ref?.id) return true; if (farmAt(game, port.col, port.row) || scannerAt(game, port.col, port.row) || maintenanceRoomAt(game, port.col, port.row)) return true; @@ -269,6 +281,8 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel if (game.selected.type === 'eggFarm') return game.eggFarms.find(f => f.id === game.selected.id) || null; if (game.selected.type === 'scanner') return game.scanners.find(s => s.id === game.selected.id) || null; if (game.selected.type === 'conveyor') return game.conveyorTiles.has(game.selected.id) ? { type: 'conveyor', id: game.selected.id } : null; + if (game.selected.type === 'powerWire') return game.powerWires?.has(game.selected.id) ? { type: 'powerWire', id: game.selected.id } : null; + if (game.selected.type === 'footbridge') return game.footbridges?.has(game.selected.id) ? { type: 'footbridge', id: game.selected.id } : null; if (game.selected.type === 'facility') return game.facilities[game.selected.id] || null; if (game.selected.type === 'maintenanceRoom') return (game.maintenanceRooms || []).find(r => r.id === game.selected.id) || null; return null; @@ -279,6 +293,8 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel if (obj.type === 'eggFarm') return `${equipmentName('eggFarm')} #${obj.id}`; if (obj.type === 'scanner') return `${obj.kind === 'auto' ? equipmentName('autoScanner') : equipmentName('manualScanner')} #${obj.id}`; if (obj.type === 'conveyor') return game.conveyorMeta.get(obj.id)?.kind === 'boostConveyor' ? equipmentName('boostConveyor') : equipmentName('conveyor'); + if (obj.type === 'powerWire') return game.powerWires?.get(obj.id)?.kind === 'insulatedPowerWire' ? equipmentName('insulatedPowerWire') : equipmentName('powerWire'); + if (obj.type === 'footbridge') return equipmentName('footbridge'); if (obj.type === 'facility') return obj.name; if (obj.type === 'maintenanceRoom') return `${equipmentName('maintenanceRoom')} #${obj.id}`; return 'Equipment'; @@ -286,6 +302,8 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel function equipmentPrice(hit) { if (hit?.type === 'conveyor') return game.conveyorMeta?.get(hit.oldKey || hit.ref?.id)?.price || equipmentBasePrice(hit); + if (hit?.type === 'powerWire') return game.powerWires?.get(hit.oldKey || hit.ref?.id)?.price || 0; + if (hit?.type === 'footbridge') return game.footbridges?.get(hit.oldKey || hit.ref?.id)?.price || BALANCE.facilities.footbridge.price; return equipmentBasePrice(hit); } @@ -307,6 +325,7 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel function lastProtectedSaleReason(hit) { const obj = hit?.ref || hit || {}; + if (obj.unsellable || (obj.baseId || obj.id) === 'starterGenerator') return 'Starter Generator cannot be sold.'; if (hit?.type === 'eggFarm' || obj.type === 'eggFarm') { return game.eggFarms.length <= 1 ? 'Cannot sell the last EGG FARM.' : ''; } @@ -643,6 +662,50 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel conveyorDragRecordedDirectionEdit = false; } + function overlayPlacementBlocked(col, row) { + return !pointInGrid(col, row) || isBlockedCell(col, row) || farmAt(game, col, row) || scannerAt(game, col, row) || maintenanceRoomAt(game, col, row) || gridFacilityAt(game, col, row); + } + + function buildPowerWireCell(cell, kind) { + if (!cell) return { ok: false, reason: TEXT.fail.outOfGrid }; + if (overlayPlacementBlocked(cell.col, cell.row)) return { ok: false, reason: 'Power wire cannot cross equipment or blocked ground.' }; + const k = key(cell.col, cell.row); + const price = BALANCE.power.wires[kind]?.price || buildPrice(kind, game); + const existing = game.powerWires?.get(k); + const existingPrice = existing ? (BALANCE.power.wires[existing.kind]?.price || 0) : 0; + const delta = price - existingPrice; + if (delta > 0 && game.cash < delta) return { ok: false, reason: TEXT.fail.notEnoughCash }; + record(game); + if (delta > 0) spendCash(game, delta); + if (delta < 0) refundCash(game, -delta); + game.powerWires = game.powerWires || new Map(); + game.powerWires.set(k, { kind, price, builtSession: game.buildSession }); + markPowerDirty(game); + game.selected = { type: 'powerWire', id: k }; + updatePanels(); + return { ok: true }; + } + + function buildFootbridgeCell(cell) { + if (!cell) return fail(TEXT.fail.outOfGrid); + const vertical = (game.footbridgeOrientation || 'vertical') !== 'horizontal'; + const cells = vertical + ? [cell.row - 1, cell.row, cell.row + 1].map(row => ({ col: cell.col, row })) + : [cell.col - 1, cell.col, cell.col + 1].map(col => ({ col, row: cell.row })); + if (cells.some(part => overlayPlacementBlocked(part.col, part.row))) return fail('Footbridge cannot cross equipment or blocked ground.'); + if (cells.some(part => game.footbridges?.has(key(part.col, part.row)))) return fail('Footbridge already covers that cell.'); + const cost = buildPrice('footbridge', game); + if (game.cash < cost) return fail(TEXT.fail.notEnoughCash); + const bridgeId = `footbridge:${game.nextId++}`; + record(game); + spendCash(game, cost); + game.footbridges = game.footbridges || new Map(); + for (const part of cells) game.footbridges.set(key(part.col, part.row), { kind: 'footbridge', bridgeId, orientation: vertical ? 'vertical' : 'horizontal', price: cost, builtSession: game.buildSession }); + game.walkabilityVersion = (game.walkabilityVersion || 0) + 1; + game.selected = { type: 'footbridge', id: key(cell.col, cell.row) }; + updatePanels(); + } + function buildAtCell(cell) { if (!cell) return fail(TEXT.fail.outOfGrid); const { col, row } = cell; @@ -652,6 +715,12 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel refreshRoutingAfterEdit(game); return; } + if (game.buildTool === 'powerWire' || game.buildTool === 'insulatedPowerWire') { + const result = buildPowerWireCell(cell, game.buildTool); + if (!result.ok) return fail(result.reason || TEXT.fail.cellOccupied); + return; + } + if (game.buildTool === 'footbridge') return buildFootbridgeCell(cell); if (isBlockedCell(col, row)) return fail('Cannot build on blocked ground.'); if (facilityPortAt(col, row) && !['conveyor', 'boostConveyor'].includes(game.buildTool)) return fail('Machine port must remain open for a conveyor.'); if (game.buildTool === 'maintenanceRoom') { @@ -670,7 +739,7 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel function buildAtPoint(p) { const cell = pointToCell(p.x, p.y); - if (['conveyor', 'boostConveyor', 'eggFarm', 'manualScanner', 'autoScanner', 'maintenanceRoom', ...GRID_FACILITY_IDS].includes(game.buildTool)) return buildAtCell(cell); + if (['conveyor', 'boostConveyor', 'powerWire', 'insulatedPowerWire', 'footbridge', 'eggFarm', 'manualScanner', 'autoScanner', 'maintenanceRoom', ...GRID_FACILITY_IDS.filter(id => id !== 'starterGenerator')].includes(game.buildTool)) return buildAtCell(cell); if (EDGE_FACILITY_IDS.includes(game.buildTool)) return buildFacility(p, game.buildTool); } @@ -712,6 +781,8 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel room.price = cost; game.maintenanceRooms = game.maintenanceRooms || []; game.maintenanceRooms.push(room); + markPowerDirty(game); + game.walkabilityVersion = (game.walkabilityVersion || 0) + 1; game.selected = { type: 'maintenanceRoom', id: room.id }; const center = roomCenter(room); floating(game, center.x, center.y, `-${yen(cost)}`, THEME.ink); @@ -734,6 +805,8 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel spendCash(game, cost); game.facilities[storageId] = f; refreshRoutingAfterEdit(game); + markPowerDirty(game); + game.walkabilityVersion = (game.walkabilityVersion || 0) + 1; game.selected = { type: 'facility', id: storageId }; floating(game, f.x + f.w / 2, f.y + f.h / 2, `-${yen(cost)}`, THEME.ink); } @@ -754,6 +827,8 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel spendCash(game, cost); game.facilities[storageId] = f; refreshRoutingAfterEdit(game); + markPowerDirty(game); + game.walkabilityVersion = (game.walkabilityVersion || 0) + 1; game.selected = { type: 'facility', id: storageId }; floating(game, p.x, p.y - 14, `-${yen(cost)}`, THEME.ink); } @@ -772,7 +847,24 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel const saleReason = lastProtectedSaleReason(hit); if (saleReason) return fail(saleReason); record(game); - if (hit.type === 'conveyor') { + if (hit.type === 'footbridge') { + const c = parseKey(hit.oldKey); + const center = cellCenter(c.col, c.row); + refundOrSell(hit, center.x, center.y); + const bridgeId = game.footbridges.get(hit.oldKey)?.bridgeId; + for (const [k, bridge] of game.footbridges || new Map()) { + if (!bridgeId || bridge.bridgeId === bridgeId) game.footbridges.delete(k); + } + game.walkabilityVersion = (game.walkabilityVersion || 0) + 1; + eraseEffect(game, center.x, center.y); + } else if (hit.type === 'powerWire') { + const c = parseKey(hit.oldKey); + const center = cellCenter(c.col, c.row); + refundOrSell(hit, center.x, center.y); + game.powerWires.delete(hit.oldKey); + markPowerDirty(game); + eraseEffect(game, center.x, center.y); + } else if (hit.type === 'conveyor') { const c = parseKey(hit.oldKey); const center = cellCenter(c.col, c.row); refundOrSell(hit, center.x, center.y); @@ -780,34 +872,38 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel game.conveyorMeta.delete(hit.oldKey); eraseEffect(game, center.x, center.y); refreshRoutingAfterEdit(game); - } - if (hit.type === 'eggFarm') { + game.walkabilityVersion = (game.walkabilityVersion || 0) + 1; + } else if (hit.type === 'eggFarm') { const c = cellCenter(hit.ref.col, hit.ref.row); refundOrSell(hit, c.x, c.y); game.eggFarms = game.eggFarms.filter(f => f.id !== hit.ref.id); eraseEffect(game, c.x, c.y); refreshRoutingAfterEdit(game); - } - if (hit.type === 'scanner') { + game.walkabilityVersion = (game.walkabilityVersion || 0) + 1; + } else if (hit.type === 'scanner') { const c = scannerCenter(hit.ref); refundOrSell(hit, c.x, c.y); game.scanners = game.scanners.filter(s => s.id !== hit.ref.id); eraseEffect(game, c.x, c.y); refreshRoutingAfterEdit(game); - } - if (hit.type === 'facility') { + markPowerDirty(game); + game.walkabilityVersion = (game.walkabilityVersion || 0) + 1; + } else if (hit.type === 'facility') { const f = hit.ref; refundOrSell(hit, f.x + f.w / 2, f.y + f.h / 2); delete game.facilities[f.id]; eraseEffect(game, f.x + f.w / 2, f.y + f.h / 2); refreshRoutingAfterEdit(game); - } - if (hit.type === 'maintenanceRoom') { + markPowerDirty(game); + game.walkabilityVersion = (game.walkabilityVersion || 0) + 1; + } else if (hit.type === 'maintenanceRoom') { const room = hit.ref; const center = roomCenter(room); refundOrSell(hit, center.x, center.y); game.maintenanceRooms = (game.maintenanceRooms || []).filter(r => r.id !== room.id); eraseEffect(game, center.x, center.y); + markPowerDirty(game); + game.walkabilityVersion = (game.walkabilityVersion || 0) + 1; } game.selected = null; game.multiSelected = []; @@ -832,6 +928,8 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel const room = maintenanceRoomAt(game, cell.col, cell.row); if (room) return { type: 'maintenanceRoom', ref: room }; const k = key(cell.col, cell.row); + if (game.footbridges?.has(k)) return { type: 'footbridge', oldKey: k, ref: { type: 'footbridge', id: k } }; + if (game.powerOverlay && game.powerWires?.has(k)) return { type: 'powerWire', oldKey: k, ref: { type: 'powerWire', id: k } }; if (game.conveyorTiles.has(k)) return { type: 'conveyor', oldKey: k, ref: { type: 'conveyor', id: k } }; return null; } @@ -846,6 +944,24 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel const obj = selectedObject(); if (!obj) return; if (obj.type === 'conveyor') eraseAtPoint(cellCenter(...Object.values(parseKey(obj.id)))); + else if (obj.type === 'powerWire') { + const cell = parseKey(obj.id); + const meta = game.powerWires?.get(obj.id); + if (!meta) return; + record(game); + const center = cellCenter(cell.col, cell.row); + refundOrSell({ type: 'powerWire', oldKey: obj.id, ref: { id: obj.id, price: meta.price || 0, builtSession: meta.builtSession } }, center.x, center.y); + game.powerWires.delete(obj.id); + markPowerDirty(game); + eraseEffect(game, center.x, center.y); + game.selected = null; + game.multiSelected = []; + updatePanels(); + } + else if (obj.type === 'footbridge') { + const cell = parseKey(obj.id); + eraseAtPoint(cellCenter(cell.col, cell.row)); + } else if (obj.type === 'eggFarm') eraseAtPoint(cellCenter(obj.col, obj.row)); else if (obj.type === 'scanner') eraseAtPoint(scannerCenter(obj)); else if (obj.type === 'facility') eraseAtPoint({ x: obj.x + obj.w / 2, y: obj.y + obj.h / 2 }); @@ -933,6 +1049,47 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel ui.modal.classList.add('visible', 'equipment-popover'); } + function showInboundTruckMenu(truck) { + if (!truck || (truck.baseId || truck.id) !== 'inboundTruck') return; + truck.inboundOrder = truck.inboundOrder || { coalPerDay: 0, zundaMochiPerDay: 0 }; + const limit = BALANCE.imports.combinedLimitPerTruck; + const coal = Math.max(0, Math.floor(truck.inboundOrder.coalPerDay || 0)); + const zunda = Math.max(0, Math.floor(truck.inboundOrder.zundaMochiPerDay || 0)); + const cost = coal * BALANCE.imports.prices.coal + zunda * BALANCE.imports.prices.zundaMochi; + const total = coal + zunda; + const avgInterval = total > 0 ? (BALANCE.time.daySeconds / total).toFixed(1) : 'none'; + ui.modalTitle.textContent = `Inbound Truck #${truck.id}`; + ui.modalBody.innerHTML = ` +
+ + +

Combined total: ${total}/${limit}

+

Daily purchase cost: ${yen(cost)}

+

Average release interval: ${avgInterval}${total > 0 ? 's' : ''}

+

Output queue: ${truck.inboundQueue?.length || 0}

+
`; + ui.modalActions.innerHTML = ''; + const applyButton = modalButton('Apply', () => { + if (game.phase !== 'build') return; + const nextCoal = Math.max(0, Math.floor(Number(document.getElementById('inboundCoalInput')?.value) || 0)); + const nextZunda = Math.max(0, Math.floor(Number(document.getElementById('inboundZundaInput')?.value) || 0)); + const total = nextCoal + nextZunda; + const scale = total > limit ? limit / total : 1; + record(game); + truck.inboundOrder = { + coalPerDay: Math.floor(nextCoal * scale), + zundaMochiPerDay: Math.floor(nextZunda * scale) + }; + showInboundTruckMenu(truck); + updatePanels(); + }, 'primary-button'); + applyButton.disabled = game.phase !== 'build'; + ui.modalActions.appendChild(applyButton); + ui.modalActions.appendChild(modalButton('Close', hideModal, 'facility-action')); + positionEquipmentPopover(truck); + ui.modal.classList.add('visible', 'equipment-popover'); + } + function manualKeyConflicts(scanner) { const own = [ { side: 'left', binding: scanner.keys?.left }, @@ -1055,6 +1212,18 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel const meta = game.conveyorMeta.get(k) || {}; boxes.push({ id: `conveyor:${k}`, price: meta.price || buildPrice(meta.kind === 'boostConveyor' ? 'boostConveyor' : 'conveyor', game), x: c.x - 22, y: c.y - 22, w: 44, h: 44 }); } + if (game.powerOverlay) { + for (const [k, wire] of game.powerWires || new Map()) { + const p = parseKey(k); + const c = cellCenter(p.col, p.row); + boxes.push({ id: `powerWire:${k}`, price: wire.price || 0, x: c.x - 18, y: c.y - 18, w: 36, h: 36 }); + } + } + for (const [k, bridge] of game.footbridges || new Map()) { + const p = parseKey(k); + const c = cellCenter(p.col, p.row); + boxes.push({ id: `footbridge:${k}`, price: bridge.price || buildPrice('footbridge', game), x: c.x - 22, y: c.y - 22, w: 44, h: 44 }); + } return boxes; } @@ -1117,6 +1286,12 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel lines.push(`Level: ${obj.level}/4`); lines.push(`Random interval: ${min.toFixed(2)}-${max.toFixed(2)}s`); lines.push(`Durability: ${remainingPercent(obj)}% | Spawn delay x${eggSpawnDelayMultiplier(obj).toFixed(2)}`); + const cap = boostOutputCapacityPerSecond(game); + const theoretical = obj.theoreticalRate || farmTheoreticalRatePerSecond(game, obj, obj.lastInterval || 1); + const quality = qualityForRate(theoretical, cap); + lines.push(`Rate: ${theoretical.toFixed(2)}/s theoretical | ${Math.min(theoretical, cap).toFixed(2)}/s actual`); + lines.push(`Boost cap: ${cap.toFixed(2)}/s | Quality: x${quality.toFixed(2)} ${qualityGrade(quality)}`); + if (obj.zundaBoostTime > 0) lines.push(`Zunda boost: ${obj.zundaBoostTime.toFixed(1)}s`); } else if (obj.type === 'scanner') { lines.push(`Price: ${yen(equipmentPrice(obj))}`); lines.push(`Sale value: ${yen(resaleValueFor({ type: obj.type, ref: obj }, game).amount)}`); @@ -1126,7 +1301,8 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel if (obj.kind === 'auto') lines.push(`Cooldown: ${obj.cooldown.toFixed(1)}s / ${autoScannerCooldownSeconds(obj, game).toFixed(1)}s`); if (obj.kind === 'auto') lines.push(`Durability: ${remainingPercent(obj)}% | Delay x${autoScannerDelayMultiplier(obj).toFixed(2)}`); if (obj.kind === 'manual') lines.push('Durability: none | Always normal'); - + const power = powerDetailsFor(game, obj); + if (power) appendPowerLines(lines, power); } else if (obj.type === 'conveyor') { const meta = game.conveyorMeta.get(obj.id); const comp = game.componentLookup?.get(obj.id); @@ -1148,11 +1324,25 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel lines.push('Branch mode: needs 3+ conveyor connections.'); } lines.push(`Sale value: ${yen(resaleValueFor({ type: 'conveyor', oldKey: obj.id, ref: obj }, game).amount)}`); + } else if (obj.type === 'powerWire') { + const meta = game.powerWires?.get(obj.id); + const def = BALANCE.power.wires[meta?.kind || 'powerWire']; + lines.push(`Price: ${yen(meta?.price || def.price)}`); + lines.push(`Cell: ${obj.id}`); + lines.push(`Type: ${def.name} | Loss ${def.lossV}V/tile`); + } else if (obj.type === 'footbridge') { + const meta = game.footbridges?.get(obj.id); + lines.push(`Price: ${yen(meta?.price || buildPrice('footbridge', game))}`); + lines.push(`Cell: ${obj.id}`); + lines.push(`Orientation: ${meta?.orientation || 'vertical'}`); + lines.push('Repair workers may cross this conveyor cell.'); } else if (obj.type === 'maintenanceRoom') { lines.push(`Price: ${yen(equipmentPrice({ type: 'maintenanceRoom', ref: obj }))}`); lines.push(`Sale value: ${yen(resaleValueFor({ type: 'maintenanceRoom', ref: obj }, game).amount)}`); lines.push('Size: 2×2 grid cells'); lines.push('Dispatch: 1 repairman during each production day'); + const power = powerDetailsFor(game, obj); + if (power) appendPowerLines(lines, power); } else if (obj.type === 'facility') { lines.push(`Price: ${yen(equipmentPrice(obj))}`); { const reason = lastProtectedSaleReason({ type: obj.type, ref: obj }); lines.push(reason ? `Sale: blocked (${reason})` : `Sale value: ${yen(resaleValueFor({ type: obj.type, ref: obj }, game).amount)}`); } @@ -1189,10 +1379,19 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel lines.push(`IN: ${input ? `${input.col},${input.row}` : 'none'} | OUT: ${out ? `${out.col},${out.row}` : 'none'} | conveyor ${facilityOutputHasConveyor(game, obj) ? 'connected' : 'missing'}`); } if (obj.entry) lines.push(`Receiver: edge cell ${obj.entry.col},${obj.entry.row} (${obj.side})`); + const power = powerDetailsFor(game, obj); + if (power) appendPowerLines(lines, power); } return lines; } + function appendPowerLines(lines, power) { + lines.push(`Power: ${power.receivedV.toFixed(1)}V / ${power.minVoltage}V`); + lines.push(`Source: ${power.sourceName} | Source bus: ${power.sourceBusV.toFixed(1)}V`); + lines.push(`Route loss: ${power.routeLossV.toFixed(1)}V | Voltage Load: ${power.drawV}V`); + if (power.receivedV < power.minVoltage) lines.push('Status: UNDER VOLTAGE'); + } + function disconnectedWarningFor(obj) { if (!obj || game.phase !== 'build') return ''; const match = disconnectedBuildWarnings(game).find(item => item.type === obj.type && item.id === obj.id); @@ -1230,7 +1429,7 @@ export function createBuildSystem({ game, ui, canvas, canvasPoint, onUpdatePanel beginConveyorDrag, continueConveyorDrag, endConveyorDrag, cycleSingleConveyorDirection, branchSwitcherAtPoint, cycleBranchModeAtPoint, cycleBranchModeForKey, branchSelectableExitDirsForKey, - removeSelected, switchScannerRole, showManualScannerMenu, + removeSelected, switchScannerRole, showManualScannerMenu, showInboundTruckMenu, showAutoScannerMenu, showSelectedMenu, setBuildTool, fail, isEquipmentCell, equipmentHitBoxes, routeFromFarmToScanner diff --git a/src/systems/chickSystem.js b/src/systems/chickSystem.js index c39320b..601f528 100644 --- a/src/systems/chickSystem.js +++ b/src/systems/chickSystem.js @@ -9,6 +9,9 @@ import { productionMultiplier, truckTarget, isTargetTruckCargo, shouldFineMaleTr import { floating, shake, spawnPulse, scannerPulse, meatEffect, sludgeEffect, shredEffect, truckLoadEffect, shockwave, sparkBurst, smokeBurst, flyingDebris, rageEffect } from './effects.js'; import { countAutoSorted, countCorrect, countMistake, countMixer, countPoopDestination, countPoopSpawned, countTrash, countTruckCargo } from './stats.js'; import { eggSpawnDelayMultiplier, recordFarmProduction, recordConveyorPass, recordAutoScan, recordFacilityProcess, updateProcessingCooldowns, setFacilityCooldownAfterProcess, updateRepairman } from './maintenance.js'; +import { isEquipmentPowered, addFuelPulse, markPowerDirty } from './power.js'; +import { updateInboundTrucks } from './imports.js'; +import { addZundaBoost, actualSpawnIntervalForRate, boostOutputCapacityPerSecond, farmTheoreticalRatePerSecond, qualityForRate } from './farmQuality.js'; export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck }) { function frameCache() { @@ -80,13 +83,18 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck } function currentSpawnDelay(farm) { - return nextSpawnDelay(farm) * eggSpawnDelayMultiplier(farm) * eggProductionDelayMultiplier(game) / productionMultiplier(game); + const base = nextSpawnDelay(farm) * eggSpawnDelayMultiplier(farm) * eggProductionDelayMultiplier(game) / productionMultiplier(game); + const rate = farmTheoreticalRatePerSecond(game, farm, base); + farm.theoreticalRate = rate; + farm.actualOutputRate = Math.min(rate, boostOutputCapacityPerSecond(game)); + farm.qualityMultiplier = qualityForRate(rate, boostOutputCapacityPerSecond(game)); + return Math.max(0.25, actualSpawnIntervalForRate(rate, boostOutputCapacityPerSecond(game))); } function spawnChick(farm) { const farmCenter = cellCenter(farm.col, farm.row); const maxOutputs = 1 + extraEggOutletCount(game, farm); - const starts = farmOutputStarts(farm, maxOutputs); + const starts = farmOutputStarts(farm, maxOutputs).slice(0, 1); if (!starts.length) { suppressUnconnectedFarmSpawn(farm, farmCenter); return true; @@ -102,6 +110,13 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck continue; } const chick = createChick(game, { stage: 'belt', scannerId: null, route: [start] }); + const theoretical = farm.theoreticalRate || farmTheoreticalRatePerSecond(game, farm, farm.lastInterval || currentSpawnDelay(farm)); + chick.sourceQuality = qualityForRate(theoretical, boostOutputCapacityPerSecond(game)); + game.stats.farmTheoreticalRate = Math.max(game.stats.farmTheoreticalRate || 0, theoretical); + game.stats.farmActualOutputRate = Math.max(game.stats.farmActualOutputRate || 0, Math.min(theoretical, boostOutputCapacityPerSecond(game))); + game.stats.qualityMultiplierSum = (game.stats.qualityMultiplierSum || 0) + chick.sourceQuality; + game.stats.qualityMultiplierCount = (game.stats.qualityMultiplierCount || 0) + 1; + game.stats.maxQualityMultiplier = Math.max(game.stats.maxQualityMultiplier || 1, chick.sourceQuality); if (chick.sex === 'poop') countPoopSpawned(game); game.chicks.push(chick); markChicksChanged(); @@ -140,6 +155,7 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck function updateRunning(dt, { closeFarmShutters, completeTurn }) { updateRepairman(game, dt); updateProcessingCooldowns(game, dt); + updateInboundTrucks(game, dt, markChicksChanged); flushFacilityOutputs(); if (game.cleanupTimer !== null) { game.cleanupTimer = Math.max(0, game.cleanupTimer - dt); @@ -157,6 +173,7 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck if (producing && game.timeLeft > 0) { for (const farm of game.eggFarms) { if (farm.noRouteNoticeCooldown > 0) farm.noRouteNoticeCooldown = Math.max(0, farm.noRouteNoticeCooldown - dt); + if (farm.zundaBoostTime > 0) farm.zundaBoostTime = Math.max(0, farm.zundaBoostTime - dt); farm.nextSpawn -= dt; if (farm.nextSpawn <= 0) { const spawned = spawnChick(farm); @@ -170,6 +187,7 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck chick.bob += dt * 7; if (chick.stoppedTimer > 0) chick.stoppedTimer = Math.max(0, chick.stoppedTimer - dt); if (chick.stage === 'queued') continue; + if (consumeAdjacentZunda(chick, i)) continue; updateRoutedChick(chick, i, dt); } updateScannerQueues(dt); @@ -279,12 +297,29 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck return Object.entries(game.facilities || {}).find(([, f]) => f?.entry && f.entry.col === cell.col && f.entry.row === cell.row) || null; } + function gridGeneratorReceivingFrom(cell, dirName) { + for (const facility of Object.values(game.facilities || {})) { + const kind = facilityKind(facility); + if (!facility.gridPlaced || !['biomassGenerator', 'coalGenerator'].includes(kind)) continue; + const ports = kind === 'biomassGenerator' + ? [ + { col: facility.col - 1, row: facility.row + 1, dir: 'right' }, + { col: facility.col + 1, row: facility.row - 1, dir: 'down' }, + { col: facility.col + 1, row: facility.row + (facility.hCells || 3), dir: 'up' } + ] + : [{ col: facility.col - 1, row: facility.row + 1, dir: 'right' }]; + if (ports.some(port => port.col === cell.col && port.row === cell.row && port.dir === dirName)) return facility; + } + return null; + } + function facilityKind(f) { return f?.baseId || f?.id || ''; } function dirExitsToFacility(facility, dirName) { if (facility?.gridPlaced && facilityKind(facility) === 'sausageMaker') return dirName === 'right'; + if (facility?.gridPlaced && ['biomassGenerator', 'coalGenerator'].includes(facilityKind(facility))) return dirName === 'right'; return (facility.side === 'left' && dirName === 'left') || (facility.side === 'right' && dirName === 'right') || (facility.side === 'top' && dirName === 'up') @@ -299,7 +334,9 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck return { type: 'conveyor', dirName, target: cellCenter(next.col, next.row), nextCell: next }; } const scanner = scannerReceivingFrom(cell, dirName); - if (scanner && !['meat', 'sausage'].includes(item?.sex)) return { type: 'scanner', dirName, target: scannerCenter(scanner), scanner }; + if (scanner && !['meat', 'sausage', 'coal', 'zundaMochi'].includes(item?.sex)) return { type: 'scanner', dirName, target: scannerCenter(scanner), scanner }; + const generator = gridGeneratorReceivingFrom(cell, dirName); + if (generator) return { type: 'facility', dirName, facilityId: generator.id, facility: generator, target: cellCenter(cell.col, cell.row) }; const facilityPair = facilityAtEntryCell(cell); if (facilityPair && dirExitsToFacility(facilityPair[1], dirName)) { return { type: 'facility', dirName, facilityId: facilityPair[0], facility: facilityPair[1], target: cellCenter(cell.col, cell.row) }; @@ -379,6 +416,8 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck else if (kind === 'truck') resolveTruck(index, option.facility); else if (kind === 'trash') resolveTrash(index, option.facility); else if (kind === 'sausageMaker') resolveSausageMaker(index, option.facility); + else if (kind === 'biomassGenerator' || kind === 'coalGenerator') resolveGenerator(index, option.facility); + else if (kind === 'inboundTruck') { const chick = game.chicks[index]; if (chick) chick.stoppedTimer = 0.25; } else removeChick(index, 'DONE'); return; } @@ -387,6 +426,19 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck setSingleSegmentRoute(chick, option.target); } + function consumeAdjacentZunda(chick, index) { + if (chick.sex !== 'zundaMochi') return false; + const cell = pointToCell(chick.x, chick.y); + if (!cell) return false; + const farm = game.eggFarms.find(candidate => Math.abs(candidate.col - cell.col) + Math.abs(candidate.row - cell.row) === 1); + if (!farm) return false; + addZundaBoost(game, farm); + takeChick(index); + const c = cellCenter(farm.col, farm.row); + floating(game, c.x, c.y - 24, 'ZUNDA BOOST', THEME.green); + return true; + } + function conveyorKeyFromPoint(p) { const cell = pointToCell(p.x, p.y); if (!cell) return null; @@ -484,9 +536,11 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck function updateScannerQueues(dt) { for (const scanner of game.scanners) { - if (scanner.cooldown > 0) scanner.cooldown = Math.max(0, scanner.cooldown - dt); + const powered = scanner.kind !== 'auto' || isEquipmentPowered(game, scanner); if (scanner.keyPressTime > 0) scanner.keyPressTime = Math.max(0, scanner.keyPressTime - dt); positionScannerQueue(scanner); + if (!powered) continue; + if (scanner.cooldown > 0) scanner.cooldown = Math.max(0, scanner.cooldown - dt); if (scanner.kind !== 'auto' || scanner.cooldown > 0 || !scanner.queue.length) continue; const id = scanner.queue[0]; const index = game.chicks.findIndex(c => c.id === id); @@ -601,6 +655,11 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck if (!chick || chick.stage !== 'queued') return false; const scanner = scannerById(game, chick.scannerId); if (!scanner) return false; + if (scanner.kind === 'auto' && !isEquipmentPowered(game, scanner)) return false; + if (['coal', 'zundaMochi'].includes(chick.sex)) { + floating(game, chick.x, chick.y - 16, 'NOT SCANNABLE', THEME.warn); + return false; + } const startCell = scannerOutputStartCell(scanner, side); if (!startCell) { if (!auto && scanner.kind === 'manual') resetManualCombo(scanner); @@ -636,11 +695,17 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck } function resolveMixer(index, mixer = game.facilities.mixer) { + if (!isEquipmentPowered(game, mixer)) { + const chick = game.chicks[index]; + if (chick) chick.stoppedTimer = 0.25; + return; + } if (mixer?.processingCooldown > 0) { const chick = game.chicks[index]; if (chick) chick.stoppedTimer = 0.25; return; } + if (isImportItem(game.chicks[index])) return rejectImportItem(index, 'CHICKS ONLY'); const chick = takeChick(index); if (!chick) return; const { x, y } = chick; @@ -669,6 +734,8 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck return; } mixer.meatBuffer = Math.max(0, mixer.meatBuffer || 0) + 1; + mixer.meatQualityQueue = mixer.meatQualityQueue || []; + mixer.meatQualityQueue.push(chick.sourceQuality || 1); game.stats.meatProduced = (game.stats.meatProduced || 0) + 1; game.totals.meatProduced = (game.totals.meatProduced || 0) + 1; meatEffect(game, x, y); @@ -677,10 +744,16 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck } function resolveTruck(index, truck = game.facilities.truck) { + if (!isEquipmentPowered(game, truck)) { + const chick = game.chicks[index]; + if (chick) chick.stoppedTimer = 0.25; + return; + } + if (isImportItem(game.chicks[index])) return rejectImportItem(index, 'NO IMPORTS'); const chick = takeChick(index); if (!chick) return; const { x, y } = chick; - addTruckCargo(chick.sex, truck); + addTruckCargo(chick.sex, truck, chick.sourceQuality || 1); truckLoadEffect(game, x, y, chick.sex); countTruckCargo(game, chick.sex); const target = truckTarget(game); @@ -751,11 +824,15 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck } function emitFromFacility(facility, product, bufferKey) { + if (!isEquipmentPowered(game, facility)) return false; const out = facilityOutputCell(game, facility); if (!out || !facilityOutputHasConveyor(game, facility) || !outputCellFree(out)) return false; if (Math.max(0, facility[bufferKey] || 0) <= 0) return false; facility[bufferKey] -= 1; - game.chicks.push(createProduct(product, out)); + const created = createProduct(product, out); + if (product === 'meat') created.sourceQuality = (facility.meatQualityQueue || []).shift() || 1; + if (product === 'sausage') created.sourceQuality = (facility.sausageQualityQueue || []).shift() || 1; + game.chicks.push(created); markChicksChanged(); const c = cellCenter(out.col, out.row); floating(game, c.x, c.y - 16, product === 'meat' ? 'MEAT OUT' : 'SAUSAGE OUT', product === 'meat' ? THEME.meatRed : THEME.sausageOrange); @@ -771,11 +848,17 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck } function resolveSausageMaker(index, machine) { + if (!isEquipmentPowered(game, machine)) { + const item = game.chicks[index]; + if (item) item.stoppedTimer = 0.25; + return; + } if (machine?.processingCooldown > 0) { const item = game.chicks[index]; if (item) item.stoppedTimer = 0.25; return; } + if (isImportItem(game.chicks[index])) return rejectImportItem(index, 'MEAT ONLY'); const item = takeChick(index); if (!item) return; const { x, y } = item; @@ -787,9 +870,15 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck recordFacilityProcess(game, machine); setFacilityCooldownAfterProcess(game, machine); machine.meatBuffer = Math.max(0, machine.meatBuffer || 0) + 1; + machine.meatQualityQueue = machine.meatQualityQueue || []; + machine.meatQualityQueue.push(item.sourceQuality || 1); if (machine.meatBuffer >= 2) { machine.meatBuffer -= 2; machine.sausageBuffer = Math.max(0, machine.sausageBuffer || 0) + 1; + const q1 = machine.meatQualityQueue.shift() || 1; + const q2 = machine.meatQualityQueue.shift() || 1; + machine.sausageQualityQueue = machine.sausageQualityQueue || []; + machine.sausageQualityQueue.push((q1 + q2) / 2); game.stats.sausageProduced = (game.stats.sausageProduced || 0) + 1; game.totals.sausageProduced = (game.totals.sausageProduced || 0) + 1; floating(game, x, y - 18, 'SAUSAGE +1', THEME.sausageOrange); @@ -800,11 +889,17 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck } function resolveTrash(index, trash = game.facilities.trash) { + if (!isEquipmentPowered(game, trash)) { + const chick = game.chicks[index]; + if (chick) chick.stoppedTimer = 0.25; + return; + } if (trash?.processingCooldown > 0) { const chick = game.chicks[index]; if (chick) chick.stoppedTimer = 0.25; return; } + if (isImportItem(game.chicks[index])) return rejectImportItem(index, 'NO IMPORTS'); const chick = takeChick(index); if (!chick) return; const { x, y } = chick; @@ -833,16 +928,51 @@ export function createChickSystem({ game, currentConveyorSpeed, onGameOverCheck } } + function resolveGenerator(index, generator) { + const item = game.chicks[index]; + if (!item) return; + if (!addFuelPulse(generator, item.sex)) { + item.stoppedTimer = 0.25; + return; + } + const used = takeChick(index); + if (!used) return; + if ((generator.baseId || generator.id) === 'biomassGenerator') { + game.stats.biomassFuelConsumed = (game.stats.biomassFuelConsumed || 0) + 1; + game.totals.biomassFuelConsumed = (game.totals.biomassFuelConsumed || 0) + 1; + } + if ((generator.baseId || generator.id) === 'coalGenerator') { + game.stats.coalConsumed = (game.stats.coalConsumed || 0) + 1; + game.totals.coalConsumed = (game.totals.coalConsumed || 0) + 1; + } + recordFacilityProcess(game, generator); + markPowerDirty(game); + floating(game, used.x, used.y - 18, 'FUEL +V', THEME.green); + } + function removeChick(index, label) { const chick = takeChick(index); if (!chick) return; floating(game, chick.x, chick.y - 12, label, THEME.muted); } - function addTruckCargo(sex, truck = game.facilities.truck) { + function isImportItem(item) { + return item?.sex === 'coal' || item?.sex === 'zundaMochi'; + } + + function rejectImportItem(index, label) { + const item = game.chicks[index]; + if (!item) return; + item.stoppedTimer = 0.25; + floating(game, item.x, item.y - 18, label, THEME.warn); + } + + function addTruckCargo(sex, truck = game.facilities.truck, sourceQuality = 1) { const t = truck || game.facilities.truck; if (!t) return; - game.truckCargo.push({ sex, x: randomBetween(22, t.w - 22), y: randomBetween(66, t.h - 24) }); + game.shippedCargo = game.shippedCargo || []; + game.shippedCargo.push({ sex, sourceQuality }); + game.truckCargo.push({ sex, sourceQuality, x: randomBetween(22, t.w - 22), y: randomBetween(66, t.h - 24) }); if (game.truckCargo.length > 45) game.truckCargo.shift(); } diff --git a/src/systems/economy.js b/src/systems/economy.js index 0733147..3ff303e 100644 --- a/src/systems/economy.js +++ b/src/systems/economy.js @@ -257,12 +257,23 @@ export function applyExplosionDamage(game, price) { export function settleTruckRevenue(game) { const target = truckTarget(game); - const targetCount = targetTruckCount(game.stats, target); const unitPrice = target === 'poop' ? Math.ceil(upgradedTruckPrice(game) * poopValueMultiplier(game)) : upgradedTruckPrice(game); - const base = targetCount * unitPrice; - const sausageCount = Math.max(0, game?.stats?.sausageShipped || 0); + const cargo = Array.isArray(game.shippedCargo) ? game.shippedCargo : (Array.isArray(game.truckCargo) ? game.truckCargo : []); + const targetCargo = cargo.filter(item => item.sex === target); + const targetCount = targetCargo.length || targetTruckCount(game.stats, target); + const base = targetCargo.length + ? targetCargo.reduce((sum, item) => sum + Math.ceil(unitPrice * (target === 'female' ? Math.max(1, item.sourceQuality || 1) : 1)), 0) + : targetCount * unitPrice; + const sausageCargo = cargo.filter(item => item.sex === 'sausage'); + const sausageCount = sausageCargo.length || Math.max(0, game?.stats?.sausageShipped || 0); const sausageUnitPrice = upgradedSausagePrice(game); - const sausageRevenue = sausageCount * sausageUnitPrice; + const sausageRevenue = sausageCargo.length + ? sausageCargo.reduce((sum, item) => sum + Math.ceil(sausageUnitPrice * Math.max(1, item.sourceQuality || 1)), 0) + : sausageCount * sausageUnitPrice; + const qualityBaseline = targetCount * unitPrice + sausageCount * sausageUnitPrice; + const qualityRevenue = Math.max(0, base + sausageRevenue - qualityBaseline); + game.stats.qualityRevenue = (game.stats.qualityRevenue || 0) + qualityRevenue; + game.totals.qualityRevenue = (game.totals.qualityRevenue || 0) + qualityRevenue; const adjusted = positivePayout(game, base + sausageRevenue); game.stats.pendingTruckRevenue = adjusted; game.stats.truckRevenue = adjusted; diff --git a/src/systems/farmQuality.js b/src/systems/farmQuality.js new file mode 100644 index 0000000..4e43383 --- /dev/null +++ b/src/systems/farmQuality.js @@ -0,0 +1,42 @@ +import { BALANCE } from '../core/balance.js'; +import { conveyorSpeedForGame } from './cards.js'; + +export function boostOutputCapacityPerSecond(game) { + return conveyorSpeedForGame(game) * (BALANCE.facilities.boostConveyor.speedMultiplier || 2) / Math.max(1, BALANCE.conveyor.minimumItemSpacingPx || 25); +} + +export function farmTheoreticalRatePerSecond(game, farm, currentSpawnDelay) { + const delay = Math.max(BALANCE.farmQuality.safeMinIntervalSeconds, Number(currentSpawnDelay) || 1); + const zunda = (farm.zundaBoostTime || 0) > 0 ? BALANCE.farmQuality.zundaIntervalMultiplier : 1; + return 1 / Math.max(BALANCE.farmQuality.safeMinIntervalSeconds, delay * zunda); +} + +export function qualityForRate(rate, capacity) { + const rules = BALANCE.farmQuality; + const c = Math.max(0.0001, capacity); + const overflowRatio = Math.max(0, rate / c - 1); + return Math.max(rules.minMultiplier, Math.min(rules.maxMultiplier, 1 + rules.overflowCoefficient * Math.pow(overflowRatio, rules.overflowExponent))); +} + +export function actualSpawnIntervalForRate(rate, capacity) { + return 1 / Math.max(0.0001, Math.min(rate, capacity)); +} + +export function qualityGrade(multiplier) { + if (multiplier >= 1.75) return 'Luxury'; + if (multiplier >= 1.35) return 'Premium'; + if (multiplier >= 1.15) return 'Select'; + return 'Standard'; +} + +export function addZundaBoost(game, farm) { + const before = farm.zundaBoostTime || 0; + farm.zundaBoostTime = Math.min(BALANCE.farmQuality.zundaMaxSeconds, before + BALANCE.farmQuality.zundaSeconds); + const added = Math.max(0, farm.zundaBoostTime - before); + game.stats.zundaConsumed = (game.stats.zundaConsumed || 0) + 1; + game.stats.zundaBoostSeconds = (game.stats.zundaBoostSeconds || 0) + added; + game.totals.zundaConsumed = (game.totals.zundaConsumed || 0) + 1; + game.totals.zundaBoostSeconds = (game.totals.zundaBoostSeconds || 0) + added; + game.stats.zundaBoostSecondsByFarm = game.stats.zundaBoostSecondsByFarm || {}; + game.stats.zundaBoostSecondsByFarm[farm.id] = (game.stats.zundaBoostSecondsByFarm[farm.id] || 0) + added; +} diff --git a/src/systems/history.js b/src/systems/history.js index c86e9c0..bd42646 100644 --- a/src/systems/history.js +++ b/src/systems/history.js @@ -29,6 +29,13 @@ export function snapshot(game) { scanners: game.scanners.map(cleanScanner), conveyorTiles: [...game.conveyorTiles], conveyorMeta: [...game.conveyorMeta.entries()], + powerWires: [...(game.powerWires || new Map()).entries()], + footbridges: [...(game.footbridges || new Map()).entries()], + footbridgeOrientation: game.footbridgeOrientation || 'vertical', + powerOverlay: !!game.powerOverlay, + imports: { + schedules: [...(game.imports?.schedules || new Map()).entries()] + }, branchCounters: [...game.branchCounters.entries()], cardEffects: game.cardEffects, cardDraft: game.cardDraft, @@ -67,6 +74,11 @@ export function restore(game, text) { game.scanners = (data.scanners || []).map(s => ({ ...s, queue: [], cooldown: s.cooldown || 0 })); game.conveyorTiles = new Set(data.conveyorTiles || []); game.conveyorMeta = new Map(data.conveyorMeta || []); + game.powerWires = new Map(data.powerWires || []); + game.footbridges = new Map(data.footbridges || []); + game.footbridgeOrientation = data.footbridgeOrientation || 'vertical'; + game.powerOverlay = !!data.powerOverlay; + game.imports = { schedules: new Map(data.imports?.schedules || []) }; game.branchCounters = new Map(data.branchCounters || []); game.cardEffects = data.cardEffects || { bearing: 0, legalWork: 0, fairiesFlatteryNext: 0, scannerQueueSpacing: 0 }; if (game.cardEffects.drawBonus != null) delete game.cardEffects.drawBonus; @@ -78,6 +90,8 @@ export function restore(game, text) { game.selectionBox = null; game.pan = null; game.routingVersion = (game.routingVersion || 0) + 1; + game.walkabilityVersion = (game.walkabilityVersion || 0) + 1; + game.power = { ...(game.power || {}), dirty: true }; game.factoryGraph = null; game.factoryGraphCommittedVersion = -1; } diff --git a/src/systems/imports.js b/src/systems/imports.js new file mode 100644 index 0000000..0b33dca --- /dev/null +++ b/src/systems/imports.js @@ -0,0 +1,149 @@ +import { BALANCE } from '../core/balance.js'; +import { TURN_SECONDS } from '../core/config.js'; +import { cellCenter, key } from '../core/utils.js'; +import { applyPenalty } from './economy.js'; +import { facilityOutputCell, facilityOutputHasConveyor } from './routing.js'; +import { isEquipmentPowered } from './power.js'; +import { recordFacilityProcess } from './maintenance.js'; + +function hash01(seed) { + let h = 2166136261; + for (let i = 0; i < String(seed).length; i += 1) { + h ^= String(seed).charCodeAt(i); + h = Math.imul(h, 16777619); + } + return ((h >>> 0) % 100000) / 100000; +} + +export function clampInboundOrder(order = {}) { + const limit = BALANCE.imports.combinedLimitPerTruck; + let coal = Math.max(0, Math.floor(Number(order.coalPerDay) || 0)); + let zunda = Math.max(0, Math.floor(Number(order.zundaMochiPerDay) || 0)); + if (coal + zunda > limit) { + const scale = limit / Math.max(1, coal + zunda); + coal = Math.floor(coal * scale); + zunda = Math.max(0, limit - coal); + } + return { coalPerDay: coal, zundaMochiPerDay: zunda }; +} + +export function inboundOrderCost(order = {}) { + const clean = clampInboundOrder(order); + return clean.coalPerDay * BALANCE.imports.prices.coal + clean.zundaMochiPerDay * BALANCE.imports.prices.zundaMochi; +} + +export function createImportSchedule(order, seed = 'imports') { + const clean = clampInboundOrder(order); + const items = [ + ...Array.from({ length: clean.coalPerDay }, () => ({ type: 'coal' })), + ...Array.from({ length: clean.zundaMochiPerDay }, () => ({ type: 'zundaMochi' })) + ]; + const total = Math.max(1, items.length); + return items.map((item, i) => { + const interval = TURN_SECONDS / total; + const baseTime = ((i + 0.5) / total) * TURN_SECONDS; + const jitter = (hash01(`${seed}:${item.type}:${i}`) * 2 - 1) * BALANCE.imports.jitterRatio * interval; + return { type: item.type, due: Math.max(0, Math.min(TURN_SECONDS, baseTime + jitter)), released: false }; + }).sort((a, b) => a.due - b.due || a.type.localeCompare(b.type)); +} + +export function startInboundOrders(game) { + game.imports = { schedules: new Map() }; + for (const facility of Object.values(game.facilities || {})) { + if ((facility.baseId || facility.id) !== 'inboundTruck') continue; + facility.inboundOrder = clampInboundOrder(facility.inboundOrder); + facility.inboundQueue = []; + facility.importClock = 0; + const cost = inboundOrderCost(facility.inboundOrder); + if (cost > 0) { + applyPenalty(game, cost); + game.stats.importPurchaseCost = (game.stats.importPurchaseCost || 0) + cost; + game.stats.coalOrdered = (game.stats.coalOrdered || 0) + facility.inboundOrder.coalPerDay; + game.stats.zundaOrdered = (game.stats.zundaOrdered || 0) + facility.inboundOrder.zundaMochiPerDay; + game.totals.importPurchaseCost = (game.totals.importPurchaseCost || 0) + cost; + game.totals.coalOrdered = (game.totals.coalOrdered || 0) + facility.inboundOrder.coalPerDay; + game.totals.zundaOrdered = (game.totals.zundaOrdered || 0) + facility.inboundOrder.zundaMochiPerDay; + } + game.imports.schedules.set(facility.id, createImportSchedule(facility.inboundOrder, `${game.runSeed}:${game.turn}:${facility.id}`)); + } +} + +function outputCellFree(game, cell) { + if (!cell || !game.conveyorTiles.has(key(cell.col, cell.row))) return false; + const c = cellCenter(cell.col, cell.row); + return !game.chicks.some(item => item.stage !== 'flying' && Math.hypot(item.x - c.x, item.y - c.y) < 25); +} + +function createImportItem(game, type, cell) { + const c = cellCenter(cell.col, cell.row); + return { + id: game.nextId++, + sex: type, + x: c.x, + y: c.y, + route: [{ x: c.x, y: c.y }], + targetIndex: 1, + stage: 'belt', + scannerId: null, + nextScannerId: null, + pendingScannerId: null, + radius: type === 'coal' ? 10 : 11, + bob: 0, + queueIndex: -1, + queueRoute: null, + stoppedTimer: 0 + }; +} + +export function updateInboundTrucks(game, dt, markChicksChanged = () => {}) { + if (game.phase !== 'running') return; + for (const facility of Object.values(game.facilities || {})) { + if ((facility.baseId || facility.id) !== 'inboundTruck') continue; + if (!isEquipmentPowered(game, facility)) continue; + facility.importClock = (facility.importClock || 0) + dt; + const schedule = game.imports?.schedules?.get(facility.id) || []; + for (const item of schedule) { + if (!item.released && item.due <= facility.importClock) { + facility.inboundQueue = facility.inboundQueue || []; + facility.inboundQueue.push(item); + item.released = true; + } + } + const out = facilityOutputCell(game, facility); + if (!facility.inboundQueue?.length || !facilityOutputHasConveyor(game, facility) || !outputCellFree(game, out)) continue; + const queued = facility.inboundQueue.shift(); + const type = queued.type; + queued.delivered = true; + game.chicks.push(createImportItem(game, type, out)); + if (type === 'coal') { + game.stats.coalReleased = (game.stats.coalReleased || 0) + 1; + game.totals.coalReleased = (game.totals.coalReleased || 0) + 1; + } + if (type === 'zundaMochi') { + game.stats.zundaReleased = (game.stats.zundaReleased || 0) + 1; + game.totals.zundaReleased = (game.totals.zundaReleased || 0) + 1; + } + recordFacilityProcess(game, facility); + markChicksChanged(); + } +} + +export function settleUndeliveredImports(game) { + for (const facility of Object.values(game.facilities || {})) { + if ((facility.baseId || facility.id) !== 'inboundTruck') continue; + const schedule = game.imports?.schedules?.get(facility.id) || []; + for (const item of schedule) { + const undelivered = !item.delivered; + if (!undelivered) continue; + if (item.type === 'coal') { + game.stats.coalUndelivered = (game.stats.coalUndelivered || 0) + 1; + game.totals.coalUndelivered = (game.totals.coalUndelivered || 0) + 1; + } + if (item.type === 'zundaMochi') { + game.stats.zundaUndelivered = (game.stats.zundaUndelivered || 0) + 1; + game.totals.zundaUndelivered = (game.totals.zundaUndelivered || 0) + 1; + } + } + facility.inboundQueue = []; + } +} diff --git a/src/systems/maintenance.js b/src/systems/maintenance.js index f343832..3023d11 100644 --- a/src/systems/maintenance.js +++ b/src/systems/maintenance.js @@ -1,7 +1,8 @@ import { BALANCE } from '../core/balance.js'; -import { GRID, THEME } from '../core/config.js'; -import { cellCenter, parseKey, key } from '../core/utils.js'; +import { DIRS, GRID, THEME } from '../core/config.js'; +import { cellCenter, parseKey, key, inGrid } from '../core/utils.js'; import { floating } from './effects.js'; +import { isEquipmentPowered } from './power.js'; const RULES = BALANCE.maintenance; @@ -69,6 +70,8 @@ export function ensureMaintenanceState(game) { const kind = facilityKind(f); if (kind === 'mixer') attachMaintenance(f, 'mixer', game); if (kind === 'trash') attachMaintenance(f, 'trash', game); + if (kind === 'sausageMaker') attachMaintenance(f, 'sausageMaker', game); + if (['starterGenerator', 'biomassGenerator', 'coalGenerator', 'inboundTruck'].includes(kind)) attachMaintenance(f, kind, game); } } @@ -195,7 +198,7 @@ export function recordFacilityProcess(game, target) { ensureMaintenanceState(game); const f = facilityFromTarget(game, target); const id = facilityKind(f || target); - if (!f || !['mixer', 'trash', 'sausageMaker'].includes(id)) return; + if (!f || !['mixer', 'trash', 'sausageMaker', 'starterGenerator', 'biomassGenerator', 'coalGenerator', 'inboundTruck'].includes(id)) return; attachMaintenance(f, id); f.maintenance.uses = Math.min(f.maintenance.durability, (f.maintenance.uses || 0) + degradationUseMultiplier(game)); } @@ -211,6 +214,7 @@ export function setFacilityCooldownAfterProcess(game, target) { export function updateProcessingCooldowns(game, dt) { for (const f of Object.values(game.facilities || {})) { if (!['mixer', 'trash', 'sausageMaker'].includes(f.baseId || f.id)) continue; + if (!isEquipmentPowered(game, f)) continue; if (f?.processingCooldown > 0) f.processingCooldown = Math.max(0, f.processingCooldown - dt); } } @@ -223,7 +227,7 @@ export function equipmentMaintenanceTargets(game) { for (const scanner of (game.scanners || []).filter(s => s.kind === 'auto')) targets.push({ type: 'autoScanner', ref: scanner, label: `AUTO #${scanner.id}`, center: cellCenter(scanner.col, scanner.row) }); for (const f of Object.values(game.facilities || {})) { const kind = facilityKind(f); - if (!['mixer', 'trash', 'sausageMaker'].includes(kind)) continue; + if (!['mixer', 'trash', 'sausageMaker', 'starterGenerator', 'biomassGenerator', 'coalGenerator', 'inboundTruck'].includes(kind)) continue; targets.push({ type: kind, ref: f, label: `${f.shortName || f.name || kind} #${f.id}`, center: { x: f.x + f.w / 2, y: f.y + f.h / 2 } }); } return targets; @@ -251,7 +255,8 @@ export function activateRepairmanForDay(game) { ensureMaintenanceState(game); const rooms = game.maintenanceRooms || []; game.repairmen = rooms.map((room, index) => { - const home = repairmanHome(game, index); + const exitCell = nearestWalkableFromRoom(game, room); + const home = exitCell ? cellCenter(exitCell.col, exitCell.row) : repairmanHome(game, index); return { id: `room-${room.id}`, roomId: room.id, @@ -286,6 +291,7 @@ function resolveStoredTarget(game, stored) { function chooseRepairTarget(game) { let best = null; for (const t of equipmentMaintenanceTargets(game)) { + if (!repairWorkCell(game, t)) continue; const w = targetWear(t); if (w <= 0.001) continue; if (!best || w > targetWear(best)) best = t; @@ -311,8 +317,10 @@ export function updateRepairman(game, dt) { function updateSingleRepairman(game, r, dt, assigned) { if (!r.active) return; + const room = (game.maintenanceRooms || []).find(item => item.id === r.roomId); + if (room && !isEquipmentPowered(game, room)) return; let target = resolveStoredTarget(game, r.target); - if (!target || targetWear(target) <= 0.001) { + if (!target || targetWear(target) <= 0.001 || !repairWorkCell(game, target)) { if (r.target?.key) assigned.delete(r.target.key); target = chooseRepairTargetAvoiding(game, assigned); } @@ -322,10 +330,34 @@ function updateSingleRepairman(game, r, dt, assigned) { } const tKey = targetKey(target); assigned.add(tKey); - r.target = { key: tKey, label: target.label }; + const workCell = repairWorkCell(game, target, r); + if (!workCell) { + game.stats.unreachableRepairTargets = (game.stats.unreachableRepairTargets || 0) + 1; + game.totals.unreachableRepairTargets = (game.totals.unreachableRepairTargets || 0) + 1; + assigned.delete(tKey); + r.target = null; + return; + } + r.target = { key: tKey, label: target.label, workKey: key(workCell.col, workCell.row) }; + ensureRepairPath(game, r, workCell); + if (r.path?.length && r.pathIndex < r.path.length) { + const next = cellCenter(r.path[r.pathIndex].col, r.path[r.pathIndex].row); + const dx = next.x - r.x; + const dy = next.y - r.y; + const dist = Math.hypot(dx, dy); + if (dist > 4) { + const step = Math.min(dist, RULES.repairman.walkSpeed * dt); + r.x += dx / dist * step; + r.y += dy / dist * step; + return; + } + r.pathIndex += 1; + return; + } const speed = RULES.repairman.walkSpeed; - const dx = target.center.x - r.x; - const dy = target.center.y - r.y; + const workCenter = cellCenter(workCell.col, workCell.row); + const dx = workCenter.x - r.x; + const dy = workCenter.y - r.y; const dist = Math.hypot(dx, dy); if (dist > 8) { const step = Math.min(dist, speed * dt); @@ -351,6 +383,7 @@ function chooseRepairTargetAvoiding(game, assigned = new Set()) { let best = null; for (const t of equipmentMaintenanceTargets(game)) { if (assigned.has(targetKey(t))) continue; + if (!repairWorkCell(game, t)) continue; const w = targetWear(t); if (w <= 0.001) continue; if (!best || w > targetWear(best)) best = t; @@ -358,6 +391,135 @@ function chooseRepairTargetAvoiding(game, assigned = new Set()) { return best || chooseRepairTarget(game); } +function cellsForTarget(target) { + if (target.type === 'conveyor') return [parseKey(target.key)]; + if (target.type === 'eggFarm') return [{ col: target.ref.col, row: target.ref.row }]; + if (target.type === 'autoScanner') { + const s = target.ref; + return [{ col: s.col, row: s.row - 1 }, { col: s.col + 1, row: s.row - 1 }, { col: s.col, row: s.row }, { col: s.col + 1, row: s.row }]; + } + const f = target.ref; + if (f?.gridPlaced) { + const cells = []; + for (let dr = 0; dr < (f.hCells || 1); dr += 1) for (let dc = 0; dc < (f.wCells || 1); dc += 1) cells.push({ col: f.col + dc, row: f.row + dr }); + return cells; + } + return f?.entry ? [f.entry] : []; +} + +function equipmentCellKeys(game) { + const blocked = new Set(); + for (const farm of game.eggFarms || []) blocked.add(key(farm.col, farm.row)); + for (const s of game.scanners || []) for (const cell of [{ col: s.col, row: s.row - 1 }, { col: s.col + 1, row: s.row - 1 }, { col: s.col, row: s.row }, { col: s.col + 1, row: s.row }]) blocked.add(key(cell.col, cell.row)); + for (const room of game.maintenanceRooms || []) for (let dr = 0; dr < 2; dr += 1) for (let dc = 0; dc < 2; dc += 1) blocked.add(key(room.col + dc, room.row + dr)); + for (const f of Object.values(game.facilities || {})) { + if (!f.gridPlaced) continue; + for (let dr = 0; dr < (f.hCells || 1); dr += 1) for (let dc = 0; dc < (f.wCells || 1); dc += 1) blocked.add(key(f.col + dc, f.row + dr)); + } + return blocked; +} + +function walkable(game, col, row) { + if (!inGrid(col, row) || !game.ownedCells?.has?.(key(col, row)) || game.blockedCells?.has?.(key(col, row))) return false; + const k = key(col, row); + if (equipmentCellKeys(game).has(k)) return false; + if (game.conveyorTiles?.has(k) && !game.footbridges?.has(k)) return false; + return true; +} + +function nearestWalkableFromRoom(game, room) { + if (!room) return { col: 0, row: Math.max(0, GRID.rows - 1) }; + const candidates = []; + for (let dc = 0; dc < 2; dc += 1) { + candidates.push({ col: room.col + dc, row: room.row - 1 }, { col: room.col + dc, row: room.row + 2 }); + } + for (let dr = 0; dr < 2; dr += 1) { + candidates.push({ col: room.col - 1, row: room.row + dr }, { col: room.col + 2, row: room.row + dr }); + } + return candidates.find(cell => walkable(game, cell.col, cell.row)) || null; +} + +function bfsPath(game, start, goals) { + if (!start) return null; + const goalKeys = new Set(goals.map(cell => key(cell.col, cell.row))); + const startKey = key(start.col, start.row); + const queue = [start]; + const cameFrom = new Map([[startKey, null]]); + while (queue.length) { + const current = queue.shift(); + const currentKey = key(current.col, current.row); + if (goalKeys.has(currentKey)) { + const path = []; + let cursor = currentKey; + while (cursor) { + const cell = parseKey(cursor); + path.push(cell); + cursor = cameFrom.get(cursor); + } + return path.reverse(); + } + for (const d of DIRS) { + const next = { col: current.col + d.dc, row: current.row + d.dr }; + const nk = key(next.col, next.row); + if (cameFrom.has(nk) || !walkable(game, next.col, next.row)) continue; + cameFrom.set(nk, currentKey); + queue.push(next); + } + } + return null; +} + +function repairCandidateCells(game, target) { + const candidates = []; + for (const cell of cellsForTarget(target)) { + if (target.type === 'conveyor' && game.footbridges?.has(key(cell.col, cell.row)) && walkable(game, cell.col, cell.row)) candidates.push(cell); + for (const d of DIRS) { + const candidate = { col: cell.col + d.dc, row: cell.row + d.dr }; + if (walkable(game, candidate.col, candidate.row)) candidates.push(candidate); + } + } + const seen = new Set(); + return candidates.filter(cell => { + const k = key(cell.col, cell.row); + if (seen.has(k)) return false; + seen.add(k); + return true; + }); +} + +function repairWorkCell(game, target, repairman = null) { + const goals = repairCandidateCells(game, target); + if (!goals.length) return null; + const room = (game.maintenanceRooms || []).find(item => item.id === repairman?.roomId) || (game.maintenanceRooms || [])[0]; + const start = repairman ? repairmanPathStart(game, repairman, room) : nearestWalkableFromRoom(game, room); + const path = bfsPath(game, start, goals); + return path?.[path.length - 1] || null; +} + +function pointCell(x, y) { + const col = Math.floor((x - GRID.x) / GRID.cell); + const row = Math.floor((y - GRID.y) / GRID.cell); + return inGrid(col, row) ? { col, row } : null; +} + +function repairmanPathStart(game, repairman, room) { + const current = pointCell(repairman.x, repairman.y); + if (current && walkable(game, current.col, current.row)) return current; + return nearestWalkableFromRoom(game, room); +} + +function ensureRepairPath(game, r, workCell) { + const workKey = key(workCell.col, workCell.row); + if (r.path && r.pathVersion === game.walkabilityVersion && r.target?.workKey === workKey && r.pathIndex < r.path.length) return; + const room = (game.maintenanceRooms || []).find(item => item.id === r.roomId); + const start = repairmanPathStart(game, r, room); + r.path = bfsPath(game, start, [workCell]) || []; + const current = pointCell(r.x, r.y); + const startsOnWalkablePath = current && start && current.col === start.col && current.row === start.row && walkable(game, current.col, current.row); + r.pathIndex = startsOnWalkablePath && r.path.length > 1 ? 1 : 0; + r.pathVersion = game.walkabilityVersion || 0; +} + function worstDegradation(game) { let worst = 0; diff --git a/src/systems/power.js b/src/systems/power.js new file mode 100644 index 0000000..2e4b1ff --- /dev/null +++ b/src/systems/power.js @@ -0,0 +1,302 @@ +import { BALANCE } from '../core/balance.js'; +import { DIRS } from '../core/config.js'; +import { key, parseKey } from '../core/utils.js'; +import { gridFacilityFootprintCells, maintenanceRoomFootprint } from '../core/entities.js'; + +function facilityKind(item) { + return item?.baseId || item?.id || ''; +} + +export function powerSpecFor(item) { + if (!item) return null; + const kind = item.type === 'scanner' ? `${item.kind}Scanner` : facilityKind(item) || item.type; + if (BALANCE.power.exempt.includes(kind)) return null; + return BALANCE.power.machines[kind] || null; +} + +export function generatorSpecFor(item) { + return BALANCE.power.generators[facilityKind(item)] || null; +} + +export function currentGeneratorOutputV(generator) { + const spec = generatorSpecFor(generator); + if (!spec) return 0; + const base = spec.outputV || spec.baseOutputV || 0; + const pulses = (generator.fuelPulses || []).reduce((sum, pulse) => sum + Math.max(0, pulse.voltage || 0), 0); + return base + pulses; +} + +function sourceCells(generator) { + if (!generator?.gridPlaced) return []; + return gridFacilityFootprintCells(generator); +} + +function contactCellsFor(item) { + if (!item) return []; + if (item.type === 'scanner') { + return [ + { col: item.col, row: item.row - 1 }, + { col: item.col + 1, row: item.row - 1 }, + { col: item.col, row: item.row }, + { col: item.col + 1, row: item.row } + ]; + } + if (item.type === 'maintenanceRoom') return maintenanceRoomFootprint(item); + if (item.gridPlaced) { + const kind = facilityKind(item); + const midRow = item.row + Math.floor((item.hCells || 1) / 2); + if (kind === 'sausageMaker') return [ + { col: item.col - 1, row: midRow }, + { col: item.col + (item.wCells || 3), row: midRow } + ]; + return [ + { col: item.col - 1, row: midRow }, + { col: item.col + (item.wCells || 1), row: midRow }, + { col: item.col + Math.floor((item.wCells || 1) / 2), row: item.row - 1 }, + { col: item.col + Math.floor((item.wCells || 1) / 2), row: item.row + (item.hCells || 1) } + ]; + } + if (item.entry) return [item.entry]; + return []; +} + +function adjacentWireLosses(game, cells, distances) { + let best = Infinity; + for (const cell of cells) { + for (const d of DIRS) { + const nk = key(cell.col + d.dc, cell.row + d.dr); + const distance = distances.get(nk); + if (distance != null) best = Math.min(best, distance); + } + const same = distances.get(key(cell.col, cell.row)); + if (same != null) best = Math.min(best, same); + } + return Number.isFinite(best) ? best : null; +} + +function propagateFromGenerator(game, generator) { + const distances = new Map(); + const queue = []; + const push = (k, loss) => { + if (loss < 0 || loss >= currentGeneratorOutputV(generator)) return; + if (distances.has(k) && distances.get(k) <= loss) return; + distances.set(k, loss); + queue.push({ k, loss }); + }; + for (const cell of sourceCells(generator)) { + for (const d of DIRS) { + const nk = key(cell.col + d.dc, cell.row + d.dr); + if (game.powerWires?.has(nk)) push(nk, BALANCE.power.wires[game.powerWires.get(nk).kind]?.lossV || 0); + } + } + while (queue.length) { + queue.sort((a, b) => a.loss - b.loss); + const current = queue.shift(); + if (distances.get(current.k) !== current.loss) continue; + const cell = parseKey(current.k); + for (const d of DIRS) { + const nk = key(cell.col + d.dc, cell.row + d.dr); + const wire = game.powerWires?.get(nk); + if (!wire) continue; + const step = BALANCE.power.wires[wire.kind]?.lossV ?? 0.5; + push(nk, current.loss + step); + } + } + return distances; +} + +function poweredItems(game) { + const items = []; + for (const facility of Object.values(game.facilities || {})) if (powerSpecFor(facility)) items.push(facility); + for (const scanner of game.scanners || []) if (powerSpecFor(scanner)) items.push(scanner); + for (const room of game.maintenanceRooms || []) if (powerSpecFor(room)) items.push(room); + return items; +} + +function generatorItems(game) { + return Object.values(game.facilities || {}).filter(generatorSpecFor); +} + +function stableId(item) { + return String(item.id ?? `${item.type}:${item.col},${item.row}`); +} + +function buildOrder(item) { + return item.builtSession == null ? -1 : item.builtSession; +} + +export function recalculatePowerNetwork(game) { + if (!game) return { dirty: false, routes: new Map(), assignments: new Map(), sources: new Map(), underVoltage: new Set() }; + const routesBySource = new Map(); + const sources = generatorItems(game).map(generator => { + const distances = propagateFromGenerator(game, generator); + routesBySource.set(generator.id, distances); + return { generator, outputV: currentGeneratorOutputV(generator), admitted: [], busVoltage: currentGeneratorOutputV(generator) }; + }); + const candidates = []; + for (const item of poweredItems(game)) { + const spec = powerSpecFor(item); + const routesForItem = []; + for (const source of sources) { + const loss = adjacentWireLosses(game, contactCellsFor(item), routesBySource.get(source.generator.id)); + if (loss == null) continue; + routesForItem.push({ source, loss, openCircuit: source.outputV - loss }); + } + routesForItem.sort((a, b) => b.openCircuit - a.openCircuit || a.loss - b.loss || stableId(a.source.generator).localeCompare(stableId(b.source.generator))); + if (routesForItem[0]) candidates.push({ item, spec, routes: routesForItem }); + } + candidates.sort((a, b) => + (b.spec.powerPriority || 50) - (a.spec.powerPriority || 50) + || a.routes[0].loss - b.routes[0].loss + || buildOrder(a.item) - buildOrder(b.item) + || stableId(a.item).localeCompare(stableId(b.item)) + ); + let assignments = new Map(); + let previousSignature = ''; + let stablePasses = 0; + const maxPasses = Math.max(1, BALANCE.power.maxAssignmentPasses || 8); + for (let pass = 0; pass < maxPasses; pass += 1) { + stablePasses = pass + 1; + for (const source of sources) { + source.admitted = []; + source.busVoltage = source.outputV; + } + const nextAssignments = new Map(); + for (const candidate of candidates) { + for (const route of candidate.routes) { + const source = route.source; + const nextLoad = source.admitted.reduce((sum, entry) => sum + entry.spec.drawV, 0) + candidate.spec.drawV; + const nextBus = source.outputV - nextLoad; + const admittedRemainPowered = source.admitted.every(entry => nextBus - entry.loss >= entry.spec.minVoltage); + const candidatePowered = nextBus - route.loss >= candidate.spec.minVoltage; + if (!admittedRemainPowered || !candidatePowered) continue; + source.admitted.push({ item: candidate.item, spec: candidate.spec, loss: route.loss }); + source.busVoltage = nextBus; + nextAssignments.set(stableId(candidate.item), { + sourceId: source.generator.id, + sourceName: source.generator.name || source.generator.shortName || source.generator.id, + sourceBusV: nextBus, + routeLossV: route.loss, + receivedV: nextBus - route.loss, + minVoltage: candidate.spec.minVoltage, + drawV: candidate.spec.drawV + }); + break; + } + } + const signature = [...nextAssignments.entries()].map(([id, assignment]) => `${id}:${assignment.sourceId}:${assignment.receivedV.toFixed(3)}`).join('|'); + assignments = nextAssignments; + if (signature === previousSignature) break; + previousSignature = signature; + } + const routes = new Map(); + const sourceSummary = new Map(); + for (const source of sources) { + sourceSummary.set(source.generator.id, { + outputV: source.outputV, + busVoltage: source.busVoltage, + admitted: source.admitted.length, + stablePasses + }); + } + for (const [id, data] of assignments) routes.set(id, data); + const previousUnder = game.power?.underVoltage || new Set(); + const underVoltage = new Set(); + for (const item of poweredItems(game)) if (!assignments.has(stableId(item))) underVoltage.add(stableId(item)); + const previousAssignments = game.power?.assignments || new Map(); + let assignmentChanges = 0; + for (const [id, assignment] of assignments) { + if (previousAssignments.get(id)?.sourceId !== assignment.sourceId) assignmentChanges += 1; + } + if (game.phase === 'running' && game.stats) { + game.stats.generatorAssignmentChanges = (game.stats.generatorAssignmentChanges || 0) + assignmentChanges; + if (game.totals) game.totals.generatorAssignmentChanges = (game.totals.generatorAssignmentChanges || 0) + assignmentChanges; + } + game.power = { ...(game.power || {}), dirty: false, routes, assignments, sources: sourceSummary, underVoltage, previousUnder }; + return game.power; +} + +export function ensurePowerState(game) { + if (!game.power || game.power.dirty) recalculatePowerNetwork(game); + return game.power; +} + +export function markPowerDirty(game) { + if (!game.power) game.power = {}; + game.power.dirty = true; +} + +export function updatePowerSystem(game, dt) { + let pulseChanged = false; + for (const generator of generatorItems(game)) { + if (game.stats) { + game.stats.maxGeneratorOutput = game.stats.maxGeneratorOutput || {}; + const id = generator.id || facilityKind(generator); + game.stats.maxGeneratorOutput[id] = Math.max(game.stats.maxGeneratorOutput[id] || 0, currentGeneratorOutputV(generator)); + } + if (!generator.fuelPulses?.length) continue; + for (const pulse of generator.fuelPulses) pulse.timeLeft -= dt; + const before = generator.fuelPulses.length; + generator.fuelPulses = generator.fuelPulses.filter(pulse => pulse.timeLeft > 0); + if (generator.fuelPulses.length !== before) pulseChanged = true; + } + if (pulseChanged) markPowerDirty(game); + if (!game.power) game.power = { dirty: true, elapsed: 0 }; + game.power.elapsed = (game.power.elapsed || 0) + dt; + const interval = 1 / Math.max(1, BALANCE.power.recalcHz || 10); + if (game.power.dirty || game.power.elapsed >= interval) { + game.power.elapsed = 0; + recalculatePowerNetwork(game); + } + const powered = ensurePowerState(game); + if (game.phase === 'running') { + const count = powered.underVoltage?.size || 0; + if (count) { + game.stats.underVoltageSeconds = (game.stats.underVoltageSeconds || 0) + count * dt; + game.stats.underVoltageSecondsByMachine = game.stats.underVoltageSecondsByMachine || {}; + for (const id of powered.underVoltage) { + game.stats.underVoltageSecondsByMachine[id] = (game.stats.underVoltageSecondsByMachine[id] || 0) + dt; + } + game.totals.underVoltageSeconds = (game.totals.underVoltageSeconds || 0) + count * dt; + } + } +} + +export function receivedVoltageFor(game, equipment) { + return ensurePowerState(game).assignments.get(stableId(equipment))?.receivedV || 0; +} + +export function isEquipmentPowered(game, equipment) { + if (!powerSpecFor(equipment)) return true; + return ensurePowerState(game).assignments.has(stableId(equipment)); +} + +export function powerDetailsFor(game, equipment) { + const spec = powerSpecFor(equipment); + if (!spec) return null; + return ensurePowerState(game).assignments.get(stableId(equipment)) || { + sourceName: 'None', + sourceBusV: 0, + routeLossV: 0, + receivedV: 0, + minVoltage: spec.minVoltage, + drawV: spec.drawV + }; +} + +export function powerSummary(game) { + const state = ensurePowerState(game); + const sources = [...(state.sources || new Map()).entries()].map(([id, data]) => `${id} ${data.outputV.toFixed(0)}V / ${data.admitted} powered`); + return `POWER: ${sources.join(' | ') || 'none'} / ${state.underVoltage?.size || 0} under-voltage`; +} + +export function addFuelPulse(generator, itemType) { + const kind = facilityKind(generator); + const spec = BALANCE.power.generators[kind]; + if (!spec) return false; + if (kind === 'biomassGenerator' && !['male', 'female', 'poop'].includes(itemType)) return false; + if (kind === 'coalGenerator' && itemType !== 'coal') return false; + generator.fuelPulses = generator.fuelPulses || []; + generator.fuelPulses.push({ voltage: spec.pulseVoltage, timeLeft: spec.pulseSeconds }); + return true; +} diff --git a/src/systems/routing.js b/src/systems/routing.js index c9074e5..34c8289 100644 --- a/src/systems/routing.js +++ b/src/systems/routing.js @@ -51,7 +51,7 @@ export function facilityInputCell(game, facility) { export function facilityOutputCell(game, facility) { const f = typeof facility === 'string' ? game?.facilities?.[facility] : facility; const kind = facilityKind(f); - if (!f || !['mixer', 'sausageMaker'].includes(kind)) return null; + if (!f || !['mixer', 'sausageMaker', 'inboundTruck'].includes(kind)) return null; if (kind === 'sausageMaker' && f.gridPlaced) { const p = { col: f.col + (f.wCells || 3), row: f.row + Math.floor((f.hCells || 3) / 2) }; return usableOwnedCell(game, p) ? p : null; @@ -559,7 +559,7 @@ export function autoSideFor(scanner, chick) { export function destinationLabel(dest) { return routeLabel(dest); } export function destinationColor(dest) { - return { mixer: '#2477ff', truck: '#ff6aa8', trash: '#22b94f', sausageMaker: '#d78b3f', 'scanner-role-1': '#526456', scanner: '#526456', input: '#526456' }[dest] || '#102015'; + return { mixer: '#2477ff', truck: '#ff6aa8', inboundTruck: '#8bd0ff', trash: '#22b94f', sausageMaker: '#d78b3f', biomassGenerator: '#7bd84f', coalGenerator: '#d0d5dc', 'scanner-role-1': '#526456', scanner: '#526456', input: '#526456' }[dest] || '#102015'; } export function routeFromFarmToScanner(game, farm, advance = false) { diff --git a/src/systems/selectionSystem.js b/src/systems/selectionSystem.js index 5f501b6..eb6bbb1 100644 --- a/src/systems/selectionSystem.js +++ b/src/systems/selectionSystem.js @@ -4,6 +4,7 @@ import { nearestGridEdge, layoutFacilityOnEdge, maintenanceRoomFootprint, gridFa import { farmAt, scannerAt, scannerCenter, scannerConnector, scannerFootprintCells, gridFacilityAt, facilityInputCell, facilityOutputCell, refreshRoutingAfterEdit } from './routing.js'; import { snapshot } from './history.js'; import { buildPrice } from './economy.js'; +import { markPowerDirty } from './power.js'; export function createSelectionSystem({ game, canvasPoint, updatePanels, equipmentAtPoint, fail, pointInGrid, rectOfFacility, rectsOverlap }) { function selectionToken(item) { @@ -32,6 +33,8 @@ export function createSelectionSystem({ game, canvasPoint, updatePanels, equipme if (sel.type === 'facility') return game.facilities[sel.id] || null; if (sel.type === 'maintenanceRoom') return (game.maintenanceRooms || []).find(r => r.id === sel.id) || null; if (sel.type === 'conveyor') return game.conveyorTiles.has(sel.id) ? { type: 'conveyor', id: sel.id } : null; + if (sel.type === 'powerWire') return game.powerWires?.has(sel.id) ? { type: 'powerWire', id: sel.id } : null; + if (sel.type === 'footbridge') return game.footbridges?.has(sel.id) ? { type: 'footbridge', id: sel.id } : null; return null; } @@ -42,6 +45,16 @@ export function createSelectionSystem({ game, canvasPoint, updatePanels, equipme const c = cellCenter(p.col, p.row); items.push({ type: 'conveyor', id: k, center: c, cell: p }); } + if (game.powerOverlay) { + for (const [k] of game.powerWires || new Map()) { + const p = parseKey(k); + items.push({ type: 'powerWire', id: k, center: cellCenter(p.col, p.row), cell: p }); + } + } + for (const [k] of game.footbridges || new Map()) { + const p = parseKey(k); + items.push({ type: 'footbridge', id: k, center: cellCenter(p.col, p.row), cell: p }); + } for (const farm of game.eggFarms) items.push({ type: 'eggFarm', id: farm.id, ref: farm, center: cellCenter(farm.col, farm.row), cell: { col: farm.col, row: farm.row } }); for (const scanner of game.scanners) items.push({ type: 'scanner', id: scanner.id, ref: scanner, center: scannerCenter(scanner), cell: { col: scanner.col, row: scanner.row } }); for (const room of game.maintenanceRooms || []) { @@ -123,6 +136,22 @@ export function createSelectionSystem({ game, canvasPoint, updatePanels, equipme const cell = parseKey(sel.id); return { ...sel, obj, oldKey: sel.id, currentKey: sel.id, meta: game.conveyorMeta.get(sel.id) || { price: buildPrice('conveyor'), builtSession: null }, col: cell.col, row: cell.row }; } + if (sel.type === 'powerWire') { + const cell = parseKey(sel.id); + return { ...sel, obj, oldKey: sel.id, currentKey: sel.id, meta: { ...(game.powerWires?.get(sel.id) || {}) }, col: cell.col, row: cell.row }; + } + if (sel.type === 'footbridge') { + const cell = parseKey(sel.id); + const meta = game.footbridges?.get(sel.id) || {}; + const cells = []; + for (const [k, bridge] of game.footbridges || new Map()) { + if ((meta.bridgeId && bridge.bridgeId === meta.bridgeId) || k === sel.id) { + const part = parseKey(k); + cells.push({ key: k, dc: part.col - cell.col, dr: part.row - cell.row, meta: { ...bridge } }); + } + } + return { ...sel, obj, oldKey: sel.id, currentKey: sel.id, meta: { ...meta }, cells, dragToken: `footbridge:${meta.bridgeId || sel.id}`, col: cell.col, row: cell.row }; + } if (sel.type === 'eggFarm' || sel.type === 'scanner' || sel.type === 'maintenanceRoom') return { ...sel, obj, col: obj.col, row: obj.row }; if (sel.type === 'facility') return obj.gridPlaced ? { ...sel, obj, gridPlaced: true, col: obj.col, row: obj.row, x: obj.x, y: obj.y, w: obj.w, h: obj.h, entry: obj.entry ? { ...obj.entry } : null, side: obj.side, center: { x: obj.x + obj.w / 2, y: obj.y + obj.h / 2 } } @@ -135,7 +164,14 @@ export function createSelectionSystem({ game, canvasPoint, updatePanels, equipme const hit = equipmentAtPoint(p); if (!hit) return false; const selections = selectedSetForDrag(hit); - const origins = selections.map(selectionOrigin).filter(Boolean); + const origins = []; + const seenOrigins = new Set(); + for (const origin of selections.map(selectionOrigin).filter(Boolean)) { + const token = origin.dragToken || selectionToken(origin); + if (seenOrigins.has(token)) continue; + seenOrigins.add(token); + origins.push(origin); + } if (!origins.length) return false; game.groupDrag = { start: p, selections, origins, historySnapshot: snapshot(game), committed: false, lastDCol: 0, lastDRow: 0 }; game.multiSelected = selections; @@ -194,6 +230,20 @@ export function createSelectionSystem({ game, canvasPoint, updatePanels, equipme return false; } + function overlayTargetBlocked(origin, col, row, selectedTokens) { + const k = key(col, row); + if (!pointInGrid(col, row) || game.blockedCells?.has?.(k)) return 'Selection hits blocked ground'; + if (farmAt(game, col, row) || scannerAt(game, col, row)) return 'Cell occupied'; + const room = (game.maintenanceRooms || []).find(item => maintenanceRoomFootprint(item).some(cell => cell.col === col && cell.row === row)); + if (room && !selectedTokens.has(`maintenanceRoom:${room.id}`)) return 'Cell occupied'; + const gridFacility = gridFacilityAt(game, col, row); + if (gridFacility && !selectedTokens.has(`facility:${gridFacility.id}`)) return 'Cell occupied'; + const originOwnsCell = origin.cells?.some(part => part.key === k); + if (origin.type === 'powerWire' && game.powerWires?.has(k) && !selectedTokens.has(`powerWire:${k}`)) return 'Power wire already covers that cell'; + if (origin.type === 'footbridge' && game.footbridges?.has(k) && !selectedTokens.has(`footbridge:${k}`) && !originOwnsCell) return 'Footbridge already covers that cell'; + return ''; + } + function facilityDragWouldOverlap(dx, dy, selectedTokens) { const candidateRects = []; for (const origin of game.groupDrag.origins) { @@ -254,6 +304,19 @@ export function createSelectionSystem({ game, canvasPoint, updatePanels, equipme for (const origin of game.groupDrag.origins) { if (origin.type === 'facility' && !origin.gridPlaced) continue; const col = origin.col + dcol, row = origin.row + drow; + if (origin.type === 'powerWire' || origin.type === 'footbridge') { + const parts = origin.type === 'footbridge' && origin.cells?.length + ? origin.cells.map(part => ({ col: col + part.dc, row: row + part.dr })) + : [{ col, row }]; + for (const part of parts) { + const reason = overlayTargetBlocked(origin, part.col, part.row, selectedTokens); + if (reason) return fail(reason); + const tk = `${origin.type}:${key(part.col, part.row)}`; + if (targetCells.has(tk)) return fail('Selection overlap'); + targetCells.add(tk); + } + continue; + } const cells = origin.type === 'scanner' ? scannerFootprintCells({ col, row }) : (origin.type === 'maintenanceRoom' @@ -293,6 +356,25 @@ export function createSelectionSystem({ game, canvasPoint, updatePanels, equipme game.conveyorMeta.set(newK, o.meta || { price: buildPrice('conveyor'), builtSession: null, uses: 0 }); o.currentKey = newK; } + const wireOrigins = game.groupDrag.origins.filter(o => o.type === 'powerWire'); + for (const o of wireOrigins) game.powerWires.delete(o.currentKey || o.oldKey); + for (const o of wireOrigins) { + const newK = key(o.col + dcol, o.row + drow); + game.powerWires.set(newK, o.meta || {}); + o.currentKey = newK; + } + const footbridgeOrigins = game.groupDrag.origins.filter(o => o.type === 'footbridge'); + for (const o of footbridgeOrigins) { + for (const part of o.cells || [{ key: o.currentKey || o.oldKey }]) game.footbridges.delete(part.key); + } + for (const o of footbridgeOrigins) { + const newK = key(o.col + dcol, o.row + drow); + for (const part of o.cells || [{ dc: 0, dr: 0, meta: o.meta || {} }]) { + const partKey = key(o.col + dcol + (part.dc || 0), o.row + drow + (part.dr || 0)); + game.footbridges.set(partKey, { ...(part.meta || o.meta || {}) }); + } + o.currentKey = newK; + } for (const origin of game.groupDrag.origins) { if (origin.type === 'eggFarm') { origin.obj.col = origin.col + dcol; @@ -314,10 +396,12 @@ export function createSelectionSystem({ game, canvasPoint, updatePanels, equipme layoutFacilityOnEdge(origin.obj, entry, side); } } - game.groupDrag.selections = game.groupDrag.origins.map(o => o.type === 'conveyor' ? { type: 'conveyor', id: o.currentKey || o.oldKey } : { type: o.type, id: o.id }); + game.groupDrag.selections = game.groupDrag.origins.map(o => ['conveyor', 'powerWire', 'footbridge'].includes(o.type) ? { type: o.type, id: o.currentKey || o.oldKey } : { type: o.type, id: o.id }); game.multiSelected = [...game.groupDrag.selections]; game.selected = game.multiSelected[0] || null; refreshRoutingAfterEdit(game); + if (game.groupDrag.origins.some(origin => origin.type !== 'powerWire')) game.walkabilityVersion = (game.walkabilityVersion || 0) + 1; + if (game.groupDrag.origins.some(origin => origin.type === 'powerWire' || (origin.type !== 'conveyor' && origin.type !== 'footbridge'))) markPowerDirty(game); updatePanels(); } diff --git a/src/systems/uiSystem.js b/src/systems/uiSystem.js index 180ef58..fd71ce4 100644 --- a/src/systems/uiSystem.js +++ b/src/systems/uiSystem.js @@ -5,6 +5,7 @@ import { routeFromFarmToScanner, facilityConnectionIssues } from './routing.js'; import { buildPrice, fairiesTributeInfo, finalScore, maleTruckPenalty, mixerPoopPenalty, truckPoopPenalty } from './economy.js'; import { conveyorSpeedForGame } from './cards.js'; import { maintenanceSummary } from './maintenance.js'; +import { powerSummary } from './power.js'; export function createUISystem({ game, ui, build, startGame, beginCardDraft, activeQueuedChick }) { function escapeHtml(value) { @@ -35,6 +36,8 @@ export function createUISystem({ game, ui, build, startGame, beginCardDraft, act if (!btn?.classList?.contains('tool-button')) continue; btn.classList.toggle('active', game.buildTool === name); } + ui.buttons.powerOverlay?.classList.toggle('active', !!game.powerOverlay); + if (ui.buttons.powerOverlay) ui.buttons.powerOverlay.disabled = game.phase !== 'build' || !!game.cardDraft?.pending || !!game.cardTargetPick?.pending; for (const id of BUILD_TOOL_IDS) { const btn = ui.buttons[id]; if (!btn) continue; @@ -81,6 +84,7 @@ export function createUISystem({ game, ui, build, startGame, beginCardDraft, act ui.turnSummary.innerHTML = [ `Seed: ${escapeHtml(game.runSeed || 'none')} | Grid box: ${game.gridRows || 10}x${game.gridCols || 20} | Owned: ${game.gridOwnedCells || game.ownedCells?.size || ((game.gridRows || 10) * (game.gridCols || 20))} cells | Blocked: ${game.blockedCells?.size || 0} cells`, `Penalties: wrong shipment -${yen(maleTruckPenalty(game))} | Mixer poop -${yen(mixerPoopPenalty(game))} | Shipment poop -${yen(truckPoopPenalty(game))}`, + powerSummary(game), `Maintenance: worst ${maintenanceSummary(game).worst.percent}% dirty (${maintenanceSummary(game).worst.label}) | Rooms: ${(game.maintenanceRooms || []).length} | Repairmen: ${(game.repairmen || []).length}`, `Card draft: ${game.cardDraft?.pending ? Math.max(1, game.cardDraft.picksRemaining || 1) + ' pick(s) left' : 'ready after each day'} | Farms with scanner route: ${connected}/${game.eggFarms.length}`, game.cardEffects?.usedMachineActive ? 'Procurement: USED MACHINE MODE / no refunds / 60% durability' : '', @@ -184,6 +188,10 @@ export function createUISystem({ game, ui, build, startGame, beginCardDraft, act const negative = value => `${value > 0 ? '-' : ''}${yen(value)}`; const netClass = r.profit >= 0 ? 'cash-positive' : 'cash-negative'; const penalties = (r.mixerPoopFine || 0) + (r.truckPoopFine || 0) + (r.maleTruckFine || 0) + (r.explosionDamage || 0) + (r.cardRerollCost || 0); + const avgQuality = r.qualityMultiplierCount ? (r.qualityMultiplierSum || 0) / r.qualityMultiplierCount : 1; + const qualityRevenue = r.qualityRevenue || 0; + const qualityClass = qualityRevenue > 0 ? 'cash-positive' : ''; + const maxGeneratorOutput = Object.values(r.maxGeneratorOutput || {}).reduce((max, value) => Math.max(max, Number(value) || 0), 0); ui.modalTitle.textContent = `Day ${r.turn} Settlement`; ui.modalBody.innerHTML = `
Net result${yen(r.profit)}
@@ -192,6 +200,14 @@ export function createUISystem({ game, ui, build, startGame, beginCardDraft, act
Poop shipment income${positive(r.poopShipmentIncome || 0)}
Sausage shipment income${positive(r.sausageRevenue || 0)}
Meat / sausages${r.meatProduced || 0} meat -> ${r.sausageProduced || 0} made / ${r.sausageShipped || 0} shipped
+
Importscoal ${r.coalReleased || 0}/${r.coalOrdered || 0}, zunda ${r.zundaReleased || 0}/${r.zundaOrdered || 0}
+
Import usecoal fuel ${r.coalConsumed || 0}, zunda used ${r.zundaConsumed || 0}, undelivered ${r.coalUndelivered || 0}/${r.zundaUndelivered || 0}
+
Import cost${negative(r.importPurchaseCost || 0)}
+
Generator fuelbiomass ${r.biomassFuelConsumed || 0}, max output ${maxGeneratorOutput.toFixed(0)}V
+
Quality revenue${qualityRevenue > 0 ? '+' : ''}${yen(qualityRevenue)} avg x${avgQuality.toFixed(2)} / max x${(r.maxQualityMultiplier || 1).toFixed(2)}
+
Zunda boost${(r.zundaBoostSeconds || 0).toFixed(1)} farm-seconds
+
Power trouble${(r.underVoltageSeconds || 0).toFixed(1)} machine-seconds / ${r.generatorAssignmentChanges || 0} source changes
+
Repair access${r.unreachableRepairTargets || 0} unreachable target checks
Composter income${positive(r.composterIncome || 0)}
DUD refund income${positive(r.dudRefundIncome || 0)}
Manual combo bonus${positive(r.manualComboBonus || 0)}
diff --git a/test_v29_00.mjs b/test_v29_00.mjs new file mode 100644 index 0000000..da5c8fb --- /dev/null +++ b/test_v29_00.mjs @@ -0,0 +1,177 @@ +import assert from 'node:assert/strict'; +import { BALANCE } from './src/core/balance.js'; +import { createGame, resetLayout } from './src/core/state.js'; +import { key } from './src/core/utils.js'; +import { recalculatePowerNetwork, isEquipmentPowered, currentGeneratorOutputV, addFuelPulse, receivedVoltageFor, updatePowerSystem } from './src/systems/power.js'; +import { clampInboundOrder, createImportSchedule, inboundOrderCost } from './src/systems/imports.js'; +import { boostOutputCapacityPerSecond, qualityForRate } from './src/systems/farmQuality.js'; + +function approx(actual, expected, epsilon = 1e-6) { + assert.ok(Math.abs(actual - expected) <= epsilon, `expected ${actual} to be within ${epsilon} of ${expected}`); +} + +function emptyPowerGame() { + const game = createGame(); + resetLayout(game); + game.facilities = {}; + game.scanners = []; + game.maintenanceRooms = []; + game.powerWires = new Map(); + game.power = { dirty: true, elapsed: 0, routes: new Map(), assignments: new Map(), sources: new Map(), underVoltage: new Set() }; + return game; +} + +function starter(id, col, row, outputV = 25) { + const generator = { + type: 'facility', + id, + baseId: 'starterGenerator', + name: id, + col, + row, + wCells: 2, + hCells: 2, + gridPlaced: true, + fuelPulses: [] + }; + if (outputV !== 25) generator.fuelPulses = [{ voltage: outputV - 25, timeLeft: 10 }]; + return generator; +} + +function biomass(id, col, row) { + return { type: 'facility', id, baseId: 'biomassGenerator', name: id, col, row, wCells: 3, hCells: 3, gridPlaced: true, fuelPulses: [] }; +} + +function edgeMachine(id, baseId, col, row, builtSession = 1) { + return { type: 'facility', id, baseId, name: id, entry: { col, row }, side: 'left', builtSession }; +} + +function wireLine(game, row, fromCol, toCol, kind = 'powerWire') { + const step = fromCol <= toCol ? 1 : -1; + for (let col = fromCol; col !== toCol + step; col += step) game.powerWires.set(key(col, row), { kind, price: 0, builtSession: null }); +} + +{ + assert.equal(BALANCE.version, 'v29.00'); + assert.equal(BALANCE.power.wires.powerWire.lossV, 0.5); + assert.equal(BALANCE.power.wires.insulatedPowerWire.lossV, 0.15); + assert.equal(BALANCE.imports.prices.coal, 2); + assert.equal(BALANCE.imports.prices.zundaMochi, 4); +} + +{ + const game = createGame(); + resetLayout(game); + recalculatePowerNetwork(game); + assert.ok(game.facilities.starterGenerator, 'new games include starter generator'); + assert.ok(game.powerWires.size > 0, 'new games include starter wires'); + assert.ok(isEquipmentPowered(game, game.facilities.mixer), 'initial mixer is powered'); + assert.ok(isEquipmentPowered(game, game.facilities.trash), 'initial shredder is powered'); + assert.ok(isEquipmentPowered(game, game.facilities.truck), 'initial shipping truck is powered'); + const loads = ['mixer', 'trash', 'truck'].reduce((sum, id) => sum + BALANCE.power.machines[id].drawV, 0); + assert.equal(loads, 9); + for (const [wireKey, wire] of game.powerWires) { + assert.equal(wire.price, 0, `starter wire ${wireKey} is free`); + assert.equal(game.blockedCells.has(wireKey), false, `starter wire ${wireKey} avoids obstacles`); + } + assert.equal(game.facilities.starterGenerator.price, 0); + assert.equal(game.facilities.starterGenerator.unsellable, true); +} + +{ + const game = emptyPowerGame(); + game.facilities.gen = starter('gen', 5, 5); + game.facilities.mixer = edgeMachine('mixer', 'mixer', 3, 5); + wireLine(game, 5, 4, 4, 'powerWire'); + game.phase = 'build'; + recalculatePowerNetwork(game); + approx(receivedVoltageFor(game, game.facilities.mixer), 20.5); + assert.equal(game.stats.generatorAssignmentChanges, 0, 'build-mode power summaries do not affect daily assignment stats'); + game.phase = 'running'; + game.powerWires.set(key(4, 4), { kind: 'powerWire', price: 0, builtSession: null }); + game.power.dirty = true; + recalculatePowerNetwork(game); + assert.equal(game.stats.generatorAssignmentChanges, 0, 'unchanged running assignment does not increment source changes'); +} + +{ + const game = emptyPowerGame(); + game.facilities.gen = starter('gen', 12, 5); + game.facilities.mixer = edgeMachine('mixer', 'mixer', 1, 5); + wireLine(game, 5, 11, 2, 'powerWire'); + recalculatePowerNetwork(game); + approx(receivedVoltageFor(game, game.facilities.mixer), 16); +} + +{ + const game = emptyPowerGame(); + game.facilities.gen = starter('gen', 12, 5); + game.facilities.mixer = edgeMachine('mixer', 'mixer', 1, 5); + wireLine(game, 5, 11, 2, 'insulatedPowerWire'); + recalculatePowerNetwork(game); + approx(receivedVoltageFor(game, game.facilities.mixer), 19.5); +} + +{ + const game = emptyPowerGame(); + game.facilities.gen = starter('gen', 12, 5); + game.facilities.mixer = edgeMachine('mixer', 'mixer', 1, 5); + for (let col = 11; col >= 7; col -= 1) game.powerWires.set(key(col, 5), { kind: 'powerWire', price: 0, builtSession: null }); + for (let col = 6; col >= 2; col -= 1) game.powerWires.set(key(col, 5), { kind: 'insulatedPowerWire', price: 0, builtSession: null }); + recalculatePowerNetwork(game); + approx(receivedVoltageFor(game, game.facilities.mixer), 17.75); +} + +{ + const game = emptyPowerGame(); + game.facilities.genA = biomass('genA', 2, 2); + game.facilities.genB = biomass('genB', 7, 3); + addFuelPulse(game.facilities.genA, 'male'); + addFuelPulse(game.facilities.genB, 'female'); + game.facilities.truck = edgeMachine('truck', 'truck', 5, 5); + game.powerWires.set(key(5, 4), { kind: 'powerWire', price: 0, builtSession: null }); + game.powerWires.set(key(6, 5), { kind: 'powerWire', price: 0, builtSession: null }); + recalculatePowerNetwork(game); + assert.equal(isEquipmentPowered(game, game.facilities.truck), false, 'separate generators do not sum voltage'); + addFuelPulse(game.facilities.genA, 'poop'); + recalculatePowerNetwork(game); + assert.equal(isEquipmentPowered(game, game.facilities.truck), true, 'one source with enough stacked pulse can power the truck'); +} + +{ + const generator = { baseId: 'biomassGenerator', fuelPulses: [] }; + addFuelPulse(generator, 'male'); + addFuelPulse(generator, 'female'); + addFuelPulse(generator, 'poop'); + assert.equal(currentGeneratorOutputV(generator), 15); + const coal = { baseId: 'coalGenerator', fuelPulses: [] }; + addFuelPulse(coal, 'coal'); + assert.equal(currentGeneratorOutputV(coal), 15); + updatePowerSystem({ facilities: { coal }, stats: {}, totals: {}, power: { dirty: false, elapsed: 0 } }, 3.1); + assert.equal(currentGeneratorOutputV(coal), 0); + assert.equal(addFuelPulse(coal, 'poop'), false); +} + +{ + assert.deepEqual(clampInboundOrder({ coalPerDay: 100, zundaMochiPerDay: 100 }), { coalPerDay: 40, zundaMochiPerDay: 40 }); + assert.equal(inboundOrderCost({ coalPerDay: 10, zundaMochiPerDay: 5 }), 40); + const sixty = createImportSchedule({ coalPerDay: 60 }, 'test'); + assert.equal(sixty.length, 60); + approx(sixty[1].due - sixty[0].due, 1, 0.35); + const six = createImportSchedule({ coalPerDay: 6 }, 'test'); + approx(six[1].due - six[0].due, 10, 3.1); + const mixed = createImportSchedule({ coalPerDay: 40, zundaMochiPerDay: 40 }, 'test'); + assert.equal(mixed.length, BALANCE.imports.combinedLimitPerTruck); + approx(mixed[1].due - mixed[0].due, 0.75, 0.3); +} + +{ + const game = createGame(); + const cap = boostOutputCapacityPerSecond(game); + assert.ok(cap > 0); + assert.equal(qualityForRate(cap, cap), 1); + assert.ok(qualityForRate(cap * 2, cap) > qualityForRate(cap * 1.5, cap)); + assert.equal(qualityForRate(cap * 100, cap), BALANCE.farmQuality.maxMultiplier); +} + +console.log('v29.00 tests passed');