Pyroflame

Autonomous Ultra City Builder v2.0

Aug 26th, 2025
200
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 64.13 KB | None | 0 0
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>Autonomous Ultra City Builder</title>
  7.     <style>
  8.         * {
  9.             margin: 0;
  10.             padding: 0;
  11.             box-sizing: border-box;
  12.         }
  13.  
  14.         body {
  15.             font-family: 'Arial', sans-serif;
  16.             background: linear-gradient(135deg, #1e3c72, #2a5298);
  17.             color: white;
  18.             overflow: hidden;
  19.         }
  20.  
  21.         .game-container {
  22.             width: 100vw;
  23.             height: 100vh;
  24.             display: flex;
  25.             flex-direction: column;
  26.         }
  27.  
  28.         .header {
  29.             height: 80px;
  30.             background: rgba(0, 0, 0, 0.8);
  31.             display: flex;
  32.             align-items: center;
  33.             justify-content: space-between;
  34.             padding: 0 20px;
  35.             box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
  36.         }
  37.  
  38.         .logo {
  39.             font-size: 24px;
  40.             font-weight: bold;
  41.             background: linear-gradient(45deg, #ff6b6b, #4ecdc4);
  42.             -webkit-background-clip: text;
  43.             -webkit-text-fill-color: transparent;
  44.             text-shadow: 0 0 20px rgba(255, 107, 107, 0.5);
  45.         }
  46.  
  47.         .stats {
  48.             display: flex;
  49.             gap: 30px;
  50.             font-size: 16px;
  51.         }
  52.  
  53.         .stat {
  54.             display: flex;
  55.             align-items: center;
  56.             gap: 8px;
  57.         }
  58.  
  59.         .stat-icon {
  60.             width: 20px;
  61.             height: 20px;
  62.             background: linear-gradient(45deg, #ff6b6b, #4ecdc4);
  63.             border-radius: 50%;
  64.             display: flex;
  65.             align-items: center;
  66.             justify-content: center;
  67.             font-size: 12px;
  68.         }
  69.  
  70.         .controls {
  71.             display: flex;
  72.             gap: 15px;
  73.         }
  74.  
  75.         .control-btn {
  76.             padding: 8px 16px;
  77.             background: linear-gradient(45deg, #667eea, #764ba2);
  78.             border: none;
  79.             border-radius: 20px;
  80.             color: white;
  81.             cursor: pointer;
  82.             font-weight: bold;
  83.             transition: all 0.3s ease;
  84.         }
  85.  
  86.         .control-btn:hover {
  87.             transform: translateY(-2px);
  88.             box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
  89.         }
  90.  
  91.         .game-area {
  92.             flex: 1;
  93.             position: relative;
  94.             overflow: hidden;
  95.         }
  96.  
  97.         .city-grid {
  98.             position: absolute;
  99.             top: 0;
  100.             left: 0;
  101.             width: 100%;
  102.             height: 100%;
  103.             display: grid;
  104.             grid-template-columns: repeat(20, 1fr);
  105.             grid-template-rows: repeat(15, 1fr);
  106.             gap: 1px;
  107.             background: rgba(0, 0, 0, 0.2);
  108.             padding: 10px;
  109.         }
  110.  
  111.         .cell {
  112.             background: rgba(255, 255, 255, 0.1);
  113.             border: 1px solid rgba(255, 255, 255, 0.2);
  114.             border-radius: 4px;
  115.             position: relative;
  116.             transition: all 0.3s ease;
  117.             cursor: pointer;
  118.         }
  119.  
  120.         .cell:hover {
  121.             background: rgba(255, 255, 255, 0.2);
  122.             transform: scale(1.05);
  123.         }
  124.  
  125.         .cell.residential {
  126.             background: linear-gradient(45deg, #4ecdc4, #44a08d);
  127.             box-shadow: 0 0 10px rgba(78, 205, 196, 0.3);
  128.         }
  129.  
  130.         .cell.commercial {
  131.             background: linear-gradient(45deg, #f093fb, #f5576c);
  132.             box-shadow: 0 0 10px rgba(240, 147, 251, 0.3);
  133.         }
  134.  
  135.         .cell.industrial {
  136.             background: linear-gradient(45deg, #ffecd2, #fcb69f);
  137.             box-shadow: 0 0 10px rgba(252, 182, 159, 0.3);
  138.         }
  139.  
  140.         .cell.park {
  141.             background: linear-gradient(45deg, #a8edea, #fed6e3);
  142.             box-shadow: 0 0 10px rgba(168, 237, 234, 0.3);
  143.         }
  144.  
  145.         .cell.road {
  146.             background: linear-gradient(45deg, #606c88, #3f4c6b);
  147.             box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.3);
  148.         }
  149.  
  150.         .cell.power {
  151.             background: linear-gradient(45deg, #ff9a9e, #fecfef);
  152.             box-shadow: 0 0 15px rgba(255, 154, 158, 0.5);
  153.             animation: pulse 2s infinite;
  154.         }
  155.  
  156.         .cell.water {
  157.             background: linear-gradient(45deg, #00b4db, #0083b0);
  158.             box-shadow: 0 0 15px rgba(0, 180, 219, 0.5);
  159.             animation: pulse 2s infinite;
  160.         }
  161.  
  162.         @keyframes pulse {
  163.             0%, 100% { opacity: 1; }
  164.             50% { opacity: 0.7; }
  165.         }
  166.  
  167.         .building {
  168.             position: absolute;
  169.             top: 50%;
  170.             left: 50%;
  171.             transform: translate(-50%, -50%);
  172.             font-size: 20px;
  173.             text-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
  174.         }
  175.  
  176.         .sim {
  177.             position: absolute;
  178.             width: 10px;
  179.             height: 10px;
  180.             background: #ffff00;
  181.             border-radius: 50%;
  182.             box-shadow: 0 0 8px rgba(255, 255, 0, 0.8);
  183.             transition: all 0.5s ease;
  184.             z-index: 10;
  185.         }
  186.  
  187.         .sim.happy {
  188.             background: #00ff00;
  189.             box-shadow: 0 0 8px rgba(0, 255, 0, 0.8);
  190.         }
  191.  
  192.         .sim.unhappy {
  193.             background: #ff0000;
  194.             box-shadow: 0 0 8px rgba(255, 0, 0, 0.8);
  195.         }
  196.  
  197.         .sim.working {
  198.             background: #4169e1;
  199.             box-shadow: 0 0 8px rgba(65, 105, 225, 0.8);
  200.         }
  201.  
  202.         .sim.shopping {
  203.             background: #ff69b4;
  204.             box-shadow: 0 0 8px rgba(255, 105, 180, 0.8);
  205.         }
  206.  
  207.         .sim.relaxing {
  208.             background: #9370db;
  209.             box-shadow: 0 0 8px rgba(147, 112, 219, 0.8);
  210.         }
  211.  
  212.         .notification {
  213.             position: absolute;
  214.             top: 100px;
  215.             right: 20px;
  216.             background: rgba(0, 0, 0, 0.8);
  217.             padding: 15px;
  218.             border-radius: 10px;
  219.             border-left: 4px solid #4ecdc4;
  220.             max-width: 300px;
  221.             animation: slideIn 0.5s ease;
  222.             z-index: 100;
  223.         }
  224.  
  225.         @keyframes slideIn {
  226.             from { transform: translateX(100%); }
  227.             to { transform: translateX(0); }
  228.         }
  229.  
  230.         .speed-control {
  231.             position: absolute;
  232.             bottom: 20px;
  233.             right: 20px;
  234.             background: rgba(0, 0, 0, 0.8);
  235.             padding: 10px;
  236.             border-radius: 10px;
  237.             display: flex;
  238.             gap: 10px;
  239.         }
  240.  
  241.         .speed-btn {
  242.             width: 40px;
  243.             height: 40px;
  244.             border: none;
  245.             border-radius: 50%;
  246.             background: linear-gradient(45deg, #667eea, #764ba2);
  247.             color: white;
  248.             cursor: pointer;
  249.             font-weight: bold;
  250.             transition: all 0.3s ease;
  251.         }
  252.  
  253.         .speed-btn:hover {
  254.             transform: scale(1.1);
  255.         }
  256.  
  257.         .speed-btn.active {
  258.             background: linear-gradient(45deg, #ff6b6b, #4ecdc4);
  259.             box-shadow: 0 0 20px rgba(255, 107, 107, 0.5);
  260.         }
  261.  
  262.         .info-panel {
  263.             position: absolute;
  264.             bottom: 20px;
  265.             left: 20px;
  266.             background: rgba(0, 0, 0, 0.8);
  267.             padding: 15px;
  268.             border-radius: 10px;
  269.             min-width: 200px;
  270.             font-size: 14px;
  271.         }
  272.  
  273.         .building-queue {
  274.             position: absolute;
  275.             top: 100px;
  276.             left: 20px;
  277.             background: rgba(0, 0, 0, 0.8);
  278.             padding: 15px;
  279.             border-radius: 10px;
  280.             max-width: 250px;
  281.         }
  282.  
  283.         .queue-item {
  284.             padding: 8px;
  285.             margin: 5px 0;
  286.             background: rgba(255, 255, 255, 0.1);
  287.             border-radius: 5px;
  288.             display: flex;
  289.             justify-content: space-between;
  290.             align-items: center;
  291.         }
  292.  
  293.         .progress-bar {
  294.             width: 100%;
  295.             height: 4px;
  296.             background: rgba(255, 255, 255, 0.2);
  297.             border-radius: 2px;
  298.             margin-top: 5px;
  299.             overflow: hidden;
  300.         }
  301.  
  302.         .progress-fill {
  303.             height: 100%;
  304.             background: linear-gradient(90deg, #4ecdc4, #44a08d);
  305.             transition: width 0.3s ease;
  306.         }
  307.        
  308.         .weather {
  309.             position: absolute;
  310.             top: 0;
  311.             left: 0;
  312.             width: 100%;
  313.             height: 100%;
  314.             pointer-events: none;
  315.             z-index: 5;
  316.         }
  317.        
  318.         .rain-drop {
  319.             position: absolute;
  320.             width: 2px;
  321.             height: 15px;
  322.             background: linear-gradient(transparent, rgba(255, 255, 255, 0.6));
  323.             animation: rain linear infinite;
  324.         }
  325.        
  326.         @keyframes rain {
  327.             from { transform: translateY(-100px); }
  328.             to { transform: translateY(calc(100vh + 100px)); }
  329.         }
  330.        
  331.         .snow-flake {
  332.             position: absolute;
  333.             width: 5px;
  334.             height: 5px;
  335.             background: white;
  336.             border-radius: 50%;
  337.             animation: snow linear infinite;
  338.         }
  339.        
  340.         @keyframes snow {
  341.             from { transform: translateY(-100px); }
  342.             to { transform: translateY(calc(100vh + 100px)); }
  343.         }
  344.        
  345.         .building-menu {
  346.             position: absolute;
  347.             background: rgba(0, 0, 0, 0.9);
  348.             border-radius: 10px;
  349.             padding: 10px;
  350.             display: none;
  351.             flex-wrap: wrap;
  352.             width: 180px;
  353.             z-index: 20;
  354.             box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
  355.         }
  356.        
  357.         .building-option {
  358.             width: 50px;
  359.             height: 50px;
  360.             margin: 5px;
  361.             border-radius: 8px;
  362.             display: flex;
  363.             align-items: center;
  364.             justify-content: center;
  365.             font-size: 20px;
  366.             cursor: pointer;
  367.             transition: all 0.2s ease;
  368.         }
  369.        
  370.         .building-option:hover {
  371.             transform: scale(1.1);
  372.         }
  373.        
  374.         .building-option.disabled {
  375.             opacity: 0.3;
  376.             cursor: not-allowed;
  377.         }
  378.        
  379.         .happiness-effect {
  380.             position: absolute;
  381.             width: 30px;
  382.             height: 30px;
  383.             background: rgba(0, 255, 0, 0.2);
  384.             border-radius: 50%;
  385.             border: 2px solid rgba(0, 255, 0, 0.5);
  386.             z-index: 5;
  387.             pointer-events: none;
  388.         }
  389.        
  390.         .cash-flow {
  391.             position: absolute;
  392.             top: 100px;
  393.             right: 20px;
  394.             background: rgba(0, 0, 0, 0.8);
  395.             padding: 15px;
  396.             border-radius: 10px;
  397.             max-width: 300px;
  398.             z-index: 90;
  399.         }
  400.        
  401.         .cash-positive {
  402.             color: #4ecdc4;
  403.         }
  404.        
  405.         .cash-negative {
  406.             color: #ff6b6b;
  407.         }
  408.        
  409.         .water-profit-indicator {
  410.             position: absolute;
  411.             font-size: 12px;
  412.             color: #4ecdc4;
  413.             font-weight: bold;
  414.             text-shadow: 0 0 5px rgba(0, 0, 0, 0.8);
  415.             animation: floatUp 2s ease-out;
  416.             z-index: 15;
  417.             pointer-events: none;
  418.         }
  419.        
  420.         @keyframes floatUp {
  421.             0% { transform: translateY(0); opacity: 1; }
  422.             100% { transform: translateY(-30px); opacity: 0; }
  423.         }
  424.     </style>
  425. </head>
  426. <body>
  427.     <div class="game-container">
  428.         <div class="header">
  429.             <div class="logo">🏙️ Ultra City Builder</div>
  430.             <div class="stats">
  431.                 <div class="stat">
  432.                     <div class="stat-icon">👥</div>
  433.                     <span id="population">0</span>
  434.                 </div>
  435.                 <div class="stat">
  436.                     <div class="stat-icon">💰</div>
  437.                     <span id="money">1000000</span>
  438.                 </div>
  439.                 <div class="stat">
  440.                     <div class="stat-icon">😊</div>
  441.                     <span id="happiness">100</span>%
  442.                 </div>
  443.                 <div class="stat">
  444.                     <div class="stat-icon"></div>
  445.                     <span id="power">50</span>
  446.                 </div>
  447.                 <div class="stat">
  448.                     <div class="stat-icon">💧</div>
  449.                     <span id="water">0</span>
  450.                 </div>
  451.             </div>
  452.             <div class="controls">
  453.                 <button class="control-btn" onclick="toggleAutoMode(this)">Auto: ON</button>
  454.                 <button class="control-btn" onclick="addRandomEvent()">Random Event</button>
  455.                 <button class="control-btn" onclick="resetCity()">Reset</button>
  456.             </div>
  457.         </div>
  458.  
  459.         <div class="game-area">
  460.             <div class="city-grid" id="cityGrid"></div>
  461.             <div class="weather" id="weatherContainer"></div>
  462.             <div class="building-menu" id="buildingMenu">
  463.                 <div class="building-option" style="background: linear-gradient(45deg, #4ecdc4, #44a08d);" onclick="buildSelected('residential')">🏠</div>
  464.                 <div class="building-option" style="background: linear-gradient(45deg, #f093fb, #f5576c);" onclick="buildSelected('commercial')">🏢</div>
  465.                 <div class="building-option" style="background: linear-gradient(45deg, #ffecd2, #fcb69f);" onclick="buildSelected('industrial')">🏭</div>
  466.                 <div class="building-option disabled" style="background: linear-gradient(45deg, #a8edea, #fed6e3);" onclick="buildSelected('park')" id="parkOption">🌳</div>
  467.                 <div class="building-option" style="background: linear-gradient(45deg, #606c88, #3f4c6b);" onclick="buildSelected('road')">🛣️</div>
  468.                 <div class="building-option" style="background: linear-gradient(45deg, #ff9a9e, #fecfef);" onclick="buildSelected('power')"></div>
  469.                 <div class="building-option" style="background: linear-gradient(45deg, #00b4db, #0083b0);" onclick="buildSelected('water')">💧</div>
  470.             </div>
  471.            
  472.             <div class="speed-control">
  473.                 <button class="speed-btn active" onclick="setSpeed(1, this)">1x</button>
  474.                 <button class="speed-btn" onclick="setSpeed(2, this)">2x</button>
  475.                 <button class="speed-btn" onclick="setSpeed(4, this)">4x</button>
  476.                 <button class="speed-btn" onclick="setSpeed(0, this)"></button>
  477.             </div>
  478.  
  479.             <div class="info-panel" id="infoPanel">
  480.                 <h3>City Status</h3>
  481.                 <div>Residential: <span id="residentialCount">0</span></div>
  482.                 <div>Commercial: <span id="commercialCount">0</span></div>
  483.                 <div>Industrial: <span id="industrialCount">0</span></div>
  484.                 <div>Parks: <span id="parkCount">0</span></div>
  485.                 <div>Roads: <span id="roadCount">0</span></div>
  486.                 <div>Power Plants: <span id="powerCount">0</span></div>
  487.                 <div>Water Plants: <span id="waterCount">0</span></div>
  488.                 <div>Ultra Sims™: <span id="simCount">0</span>/<span id="simCapacity">0</span></div>
  489.                 <div>Income: <span id="income">0</span>/sec</div>
  490.                 <div>Expenses: <span id="expenses">0</span>/sec</div>
  491.                 <div>Net: <span id="netCashflow">0</span>/sec</div>
  492.             </div>
  493.  
  494.             <div class="building-queue" id="buildingQueue">
  495.                 <h3>🏗️ Auto Construction</h3>
  496.                 <div id="queueList"></div>
  497.             </div>
  498.            
  499.             <div class="cash-flow">
  500.                 <h3>💰 Cash Flow</h3>
  501.                 <div>Income: +<span id="cashIncome">0</span>/sec</div>
  502.                 <div>Expenses: -<span id="cashExpenses">0</span>/sec</div>
  503.                 <div>Net: <span id="cashNet" class="cash-positive">+0</span>/sec</div>
  504.             </div>
  505.         </div>
  506.     </div>
  507.  
  508.     <script>
  509.         class WeatherSystem {
  510.             constructor(city) {
  511.                 this.city = city;
  512.                 this.currentWeather = 'clear';
  513.                 this.container = document.getElementById('weatherContainer');
  514.                 this.weatherEffects = {
  515.                     'rain': this.createRain.bind(this),
  516.                     'snow': this.createSnow.bind(this),
  517.                     'clear': this.clearWeather.bind(this)
  518.                 };
  519.                 this.interval = null;
  520.                 this.startRandomWeather();
  521.             }
  522.            
  523.             startRandomWeather() {
  524.                 // Change weather randomly every 30-60 seconds
  525.                 this.interval = setInterval(() => {
  526.                     const weatherTypes = ['clear', 'rain', 'snow'];
  527.                     const newWeather = weatherTypes[Math.floor(Math.random() * weatherTypes.length)];
  528.                     this.changeWeather(newWeather);
  529.                 }, 30000 + Math.random() * 30000);
  530.             }
  531.            
  532.             changeWeather(type) {
  533.                 this.currentWeather = type;
  534.                 this.container.innerHTML = '';
  535.                
  536.                 if (type !== 'clear') {
  537.                     this.weatherEffects[type]();
  538.                    
  539.                     // Weather effects on city
  540.                     if (type === 'rain') {
  541.                         this.city.happiness -= 5;
  542.                         this.city.showNotification('🌧️ Rainy weather - Sims are less happy');
  543.                     } else if (type === 'snow') {
  544.                         this.city.happiness += 5;
  545.                         this.city.showNotification('❄️ Snowy weather - Sims are happier');
  546.                     }
  547.                 }
  548.             }
  549.            
  550.             createRain() {
  551.                 for (let i = 0; i < 100; i++) {
  552.                    const drop = document.createElement('div');
  553.                    drop.className = 'rain-drop';
  554.                    drop.style.left = Math.random() * 100 + '%';
  555.                    drop.style.animationDuration = (0.5 + Math.random() * 0.5) + 's';
  556.                    drop.style.animationDelay = Math.random() * 5 + 's';
  557.                    this.container.appendChild(drop);
  558.                }
  559.            }
  560.            
  561.            createSnow() {
  562.                for (let i = 0; i < 50; i++) {
  563.                    const flake = document.createElement('div');
  564.                    flake.className = 'snow-flake';
  565.                    flake.style.left = Math.random() * 100 + '%';
  566.                    flake.style.animationDuration = (3 + Math.random() * 2) + 's';
  567.                    flake.style.animationDelay = Math.random() * 5 + 's';
  568.                    this.container.appendChild(flake);
  569.                }
  570.            }
  571.            
  572.            clearWeather() {
  573.                // Already cleared the container
  574.            }
  575.        }
  576.  
  577.        class DisasterSystem {
  578.            constructor(city) {
  579.                this.city = city;
  580.                this.disasters = [
  581.                    {
  582.                        name: 'Earthquake',
  583.                        chance: 0.001,
  584.                        effect: () => this.earthquake()
  585.                     },
  586.                     {
  587.                         name: 'Tornado',
  588.                         chance: 0.0005,
  589.                         effect: () => this.tornado()
  590.                     },
  591.                     {
  592.                         name: 'Fire',
  593.                         chance: 0.002,
  594.                         effect: () => this.fire()
  595.                     }
  596.                 ];
  597.             }
  598.            
  599.             checkForDisasters() {
  600.                 this.disasters.forEach(disaster => {
  601.                     if (Math.random() < disaster.chance * this.city.gameSpeed) {
  602.                        disaster.effect();
  603.                    }
  604.                });
  605.            }
  606.            
  607.            earthquake() {
  608.                this.city.showNotification('⚠️ Earthquake! Buildings damaged');
  609.                
  610.                // Damage random buildings
  611.                for (let row = 0; row < 15; row++) {
  612.                    for (let col = 0; col < 20; col++) {
  613.                        if (this.city.grid[row][col] && Math.random() < 0.2) {
  614.                            // 20% chance to damage each building
  615.                            if (Math.random() < 0.3) { // 30% chance to destroy completely
  616.                                this.city.grid[row][col] = null;
  617.                                const cell = document.querySelector(`[data-row="${row}"][data-col="${col}"]`);
  618.                                cell.className = 'cell';
  619.                                cell.innerHTML = '';
  620.                            }
  621.                        }
  622.                    }
  623.                }
  624.                
  625.                this.city.happiness -= 10;
  626.            }
  627.            
  628.            tornado() {
  629.                this.city.showNotification('🌪️ Tornado! Path of destruction');
  630.                
  631.                // Create a path of destruction
  632.                const startCol = Math.floor(Math.random() * 20);
  633.                for (let row = 0; row < 15; row++) {
  634.                    const col = Math.max(0, Math.min(19, startCol + Math.floor(Math.random() * 5) - 2));
  635.                    
  636.                    if (this.city.grid[row][col]) {
  637.                        this.city.grid[row][col] = null;
  638.                        const cell = document.querySelector(`[data-row="${row}"][data-col="${col}"]`);
  639.                        cell.className = 'cell';
  640.                        cell.innerHTML = '';
  641.                    }
  642.                }
  643.                
  644.                this.city.happiness -= 15;
  645.            }
  646.            
  647.            fire() {
  648.                this.city.showNotification('🔥 Fire! Spreads to adjacent buildings');
  649.                
  650.                // Start a fire at a random building
  651.                const startRow = Math.floor(Math.random() * 15);
  652.                const startCol = Math.floor(Math.random() * 20);
  653.                
  654.                if (this.city.grid[startRow][startCol]) {
  655.                    this.spreadFire(startRow, startCol, 3);
  656.                }
  657.            }
  658.            
  659.            spreadFire(row, col, intensity) {
  660.                if (intensity <= 0 || row < 0 || row >= 15 || col < 0 || col >= 20 || !this.city.grid[row][col]) {
  661.                     return;
  662.                 }
  663.                
  664.                 // Destroy this building
  665.                 this.city.grid[row][col] = null;
  666.                 const cell = document.querySelector(`[data-row="${row}"][data-col="${col}"]`);
  667.                 cell.className = 'cell';
  668.                 cell.innerHTML = '';
  669.                
  670.                 // Spread to adjacent cells with decreasing intensity
  671.                 const directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
  672.                 for (const [dRow, dCol] of directions) {
  673.                     if (Math.random() < 0.6) { // 60% chance to spread in each direction
  674.                        this.spreadFire(row + dRow, col + dCol, intensity - 1);
  675.                    }
  676.                }
  677.            }
  678.        }
  679.  
  680.        class SimAI {
  681.            static processSimBehaviors(city) {
  682.                // Advanced AI behaviors for sims
  683.                city.sims.forEach(sim => {
  684.                     // Sims with homes and jobs have higher happiness
  685.                     if (sim.home && sim.work) {
  686.                        sim.happiness += 0.1;
  687.                     }
  688.                    
  689.                     // Sims without homes or jobs get unhappy
  690.                     if (!sim.home || !sim.work) {
  691.                         sim.happiness -= 0.2;
  692.                     }
  693.                    
  694.                     // If sim is very unhappy, they might leave the city
  695.                     if (sim.happiness < 10 && Math.random() < 0.01) {
  696.                        const index = city.sims.indexOf(sim);
  697.                        if (index > -1) {
  698.                             city.sims.splice(index, 1);
  699.                             const simEl = document.getElementById(`sim-${sim.id}`);
  700.                             if (simEl) simEl.remove();
  701.                             city.population--;
  702.                             city.showNotification('😢 A sim left the city due to unhappiness');
  703.                         }
  704.                     }
  705.                    
  706.                     // Sims interact with commercial/industrial buildings
  707.                     if (sim.state === 'wandering' && Math.random() < 0.05) {
  708.                        const buildingTypes = ['commercial', 'industrial'];
  709.                         const randomType = buildingTypes[Math.floor(Math.random() * buildingTypes.length)];
  710.                         const building = city.findNearestBuilding(sim, randomType);
  711.                        
  712.                         if (building && Math.random() < 0.3) {
  713.                            sim.targetX = (building.col * 5) + Math.random() * 5;
  714.                             sim.targetY = (building.row * 6.67) + Math.random() * 6.67;
  715.                             sim.state = randomType === 'commercial' ? 'shopping' : 'working';
  716.                            
  717.                             // Change sim appearance based on activity
  718.                             const simEl = document.getElementById(`sim-${sim.id}`);
  719.                             if (simEl) {
  720.                                 simEl.classList.remove('happy', 'unhappy');
  721.                                 simEl.classList.add(randomType === 'commercial' ? 'shopping' : 'working');
  722.                             }
  723.                            
  724.                             // Set timeout to return to normal state
  725.                             setTimeout(() => {
  726.                                 sim.state = 'wandering';
  727.                                 if (simEl) {
  728.                                     simEl.classList.remove('shopping', 'working');
  729.                                     if (sim.happiness > 70) simEl.classList.add('happy');
  730.                                     else if (sim.happiness < 30) simEl.classList.add('unhappy');
  731.                                }
  732.                                
  733.                                // Increase happiness from shopping or working
  734.                                sim.happiness += randomType === 'commercial' ? 5 : 3;
  735.                                sim.happiness = Math.min(100, sim.happiness);
  736.                            }, 5000 + Math.random() * 5000);
  737.                        }
  738.                    }
  739.                    
  740.                    // Sims visit parks if available
  741.                    if (sim.state === 'wandering' && Math.random() < 0.03 && city.getBuildingCounts().park > 0) {
  742.                         const park = city.findNearestBuilding(sim, 'park');
  743.                         if (park) {
  744.                             sim.targetX = (park.col * 5) + Math.random() * 5;
  745.                             sim.targetY = (park.row * 6.67) + Math.random() * 6.67;
  746.                             sim.state = 'relaxing';
  747.                            
  748.                             // Change sim appearance
  749.                             const simEl = document.getElementById(`sim-${sim.id}`);
  750.                             if (simEl) {
  751.                                 simEl.classList.remove('happy', 'unhappy', 'shopping', 'working');
  752.                                 simEl.classList.add('relaxing');
  753.                             }
  754.                            
  755.                             // Set timeout to return to normal state
  756.                             setTimeout(() => {
  757.                                 sim.state = 'wandering';
  758.                                 if (simEl) {
  759.                                     simEl.classList.remove('relaxing');
  760.                                     if (sim.happiness > 70) simEl.classList.add('happy');
  761.                                     else if (sim.happiness < 30) simEl.classList.add('unhappy');
  762.                                }
  763.                                
  764.                                // Big happiness boost from visiting parks
  765.                                sim.happiness += 15;
  766.                                sim.happiness = Math.min(100, sim.happiness);
  767.                            }, 8000 + Math.random() * 5000);
  768.                        }
  769.                    }
  770.  
  771.                    // Clever sims with coder knowledge might build their own parks
  772.                    if (sim.coder && sim.state === 'wandering' && Math.random() < 0.005 * city.gameSpeed) {
  773.                        if (city.water > 0 && city.happiness < 80 && city.money >= city.buildingTypes.park.cost) {
  774.                            const simRow = Math.floor(sim.y * 15 / 100);
  775.                             const simCol = Math.floor(sim.x * 20 / 100);
  776.                             let found = false;
  777.                             for (let dr = -2; dr <= 2 && !found; dr++) {
  778.                                for (let dc = -2; dc <= 2 && !found; dc++) {
  779.                                    const r = simRow + dr;
  780.                                    const c = simCol + dc;
  781.                                    if (r >= 0 && r < 15 && c >= 0 && c < 20 && !city.grid[r][c]) {
  782.                                        city.placeBuilding(r, c, 'park');
  783.                                         city.showNotification('🧑‍💻 A clever Ultra Sim™ coded a new park!');
  784.                                         found = true;
  785.                                     }
  786.                                 }
  787.                             }
  788.                         }
  789.                     }
  790.                 });
  791.                
  792.                 // Adjust city happiness based on average sim happiness
  793.                 if (city.sims.length > 0) {
  794.                     const totalHappiness = city.sims.reduce((sum, sim) => sum + sim.happiness, 0);
  795.                     city.happiness = totalHappiness / city.sims.length;
  796.                 }
  797.                
  798.                 // Check if we need to spawn more sims based on residential capacity
  799.                 const residentialCount = city.getBuildingCounts().residential;
  800.                 const simCapacity = residentialCount * 5;
  801.                 const currentSims = city.sims.length;
  802.                
  803.                 if (currentSims < simCapacity && city.happiness > 60 && Math.random() < 0.1) {
  804.                    const newSims = Math.min(3, simCapacity - currentSims);
  805.                     city.spawnSims(newSims);
  806.                     city.showNotification(`🏠 ${newSims} new Ultra Sims™ moved to the city!`);
  807.                 }
  808.             }
  809.         }
  810.  
  811.         class UltraCity {
  812.             constructor() {
  813.                 this.grid = Array(15).fill().map(() => Array(20).fill(null));
  814.                 this.sims = [];
  815.                 this.money = 1000000;
  816.                 this.population = 0;
  817.                 this.happiness = 100;
  818.                 this.power = 50;
  819.                 this.water = 0;
  820.                 this.gameSpeed = 1;
  821.                 this.autoMode = true;
  822.                 this.buildQueue = [];
  823.                 this.notifications = [];
  824.                 this.lastUpdate = Date.now();
  825.                 this.selectedCell = null;
  826.                 this.parkEffects = [];
  827.                 this.income = 0;
  828.                 this.expenses = 0;
  829.                 this.netCashflow = 0;
  830.                 this.waterProfitEnabled = false;
  831.                 this.waterProfitThreshold = 100; // Population needed for water to generate profit
  832.                
  833.                 this.buildingTypes = {
  834.                     residential: { cost: 2200, icon: '🏠', provides: 'population', requirement: 'power', income: 200, upkeep: 100 },
  835.                     commercial: { cost: 3300, icon: '🏢', provides: 'money', requirement: 'population', income: 52000, upkeep: 200 },
  836.                     industrial: { cost: 4400, icon: '🏭', provides: 'jobs', requirement: 'power', income: 31000, upkeep: 300 },
  837.                     park: { cost: 6500, icon: '🌳', provides: 'happiness', requirement: 'water', income: 0, upkeep: 200 },
  838.                     road: { cost: 500, icon: '🛣️', provides: 'connection', requirement: null, income: 0, upkeep: 0 },
  839.                     power: { cost: 11000, icon: '⚡', provides: 'power', requirement: null, income: 0, upkeep: 400 },
  840.                     water: { cost: 13000, icon: '💧', provides: 'water', requirement: 'power', income: 0, upkeep: 0 } // Changed upkeep to 0
  841.                 };
  842.                
  843.                 this.init();
  844.             }
  845.  
  846.             init() {
  847.                 this.createGrid();
  848.                 this.spawnInitialBuildings();
  849.                 this.updateBuildingOptions();
  850.                 this.startGameLoop();
  851.             }
  852.  
  853.             createGrid() {
  854.                 const grid = document.getElementById('cityGrid');
  855.                 grid.innerHTML = '';
  856.                
  857.                 for (let row = 0; row < 15; row++) {
  858.                    for (let col = 0; col < 20; col++) {
  859.                        const cell = document.createElement('div');
  860.                        cell.className = 'cell';
  861.                        cell.dataset.row = row;
  862.                        cell.dataset.col = col;
  863.                        cell.addEventListener('click', (e) => this.handleCellClick(e, row, col));
  864.                         grid.appendChild(cell);
  865.                     }
  866.                 }
  867.             }
  868.  
  869.             spawnInitialBuildings() {
  870.                 // Start with a power plant
  871.                 this.placeBuilding(7, 10, 'power');
  872.                
  873.                 // Add some initial roads
  874.                 for (let i = 5; i < 15; i++) {
  875.                    this.placeBuilding(7, i, 'road');
  876.                }
  877.                
  878.                // Add initial residential
  879.                this.placeBuilding(6, 8, 'residential');
  880.                this.placeBuilding(8, 12, 'residential');
  881.                
  882.                this.spawnSims(5);
  883.                this.updateDisplay();
  884.            }
  885.  
  886.            handleCellClick(e, row, col) {
  887.                if (this.autoMode) {
  888.                    // Show building menu in auto mode
  889.                    this.selectedCell = { row, col };
  890.                    const menu = document.getElementById('buildingMenu');
  891.                    menu.style.display = 'flex';
  892.                    menu.style.left = e.clientX + 'px';
  893.                    menu.style.top = e.clientY + 'px';
  894.                } else {
  895.                    const availableTypes = Object.keys(this.buildingTypes);
  896.                    const randomType = availableTypes[Math.floor(Math.random() * availableTypes.length)];
  897.                    this.placeBuilding(row, col, randomType);
  898.                }
  899.            }
  900.            
  901.            buildSelected(type) {
  902.                if (this.selectedCell) {
  903.                    this.placeBuilding(this.selectedCell.row, this.selectedCell.col, type);
  904.                    this.selectedCell = null;
  905.                    document.getElementById('buildingMenu').style.display = 'none';
  906.                }
  907.            }
  908.            
  909.            updateBuildingOptions() {
  910.                const parkOption = document.getElementById('parkOption');
  911.                parkOption.classList.add('disabled');
  912.            }
  913.  
  914.            placeBuilding(row, col, type) {
  915.                if (this.grid[row][col] || this.money < this.buildingTypes[type].cost) {
  916.                    return false;
  917.                }
  918.                
  919.                // Check if requirements are met
  920.                if (this.buildingTypes[type].requirement) {
  921.                    if (this.buildingTypes[type].requirement === 'power' && this.power <= 0) {
  922.                        this.showNotification('Need more power to build this!');
  923.                        return false;
  924.                    }
  925.                    if (this.buildingTypes[type].requirement === 'water' && this.water <= 0) {
  926.                        this.showNotification('Need water supply to build parks!');
  927.                        return false;
  928.                    }
  929.                    if (this.buildingTypes[type].requirement === 'population' && this.population <= 10) {
  930.                        this.showNotification('Need more population to build this!');
  931.                        return false;
  932.                    }
  933.                }
  934.                
  935.                this.grid[row][col] = { type, level: 1, age: 0 };
  936.                this.money -= this.buildingTypes[type].cost;
  937.                
  938.                const cell = document.querySelector(`[data-row="${row}"][data-col="${col}"]`);
  939.                cell.className = `cell ${type}`;
  940.                cell.innerHTML = `<div class="building">${this.buildingTypes[type].icon}</div>`;
  941.                
  942.                 // If it's a park, create happiness effect
  943.                 if (type === 'park') {
  944.                     this.createParkEffect(row, col);
  945.                 }
  946.                
  947.                 this.showNotification(`Built ${type} at (${row}, ${col})`);
  948.                 this.updateBuildingOptions();
  949.                 this.updateDisplay();
  950.                 return true;
  951.             }
  952.            
  953.             createParkEffect(row, col) {
  954.                 // Create visual effect for park happiness area
  955.                 const grid = document.getElementById('cityGrid');
  956.                 for (let r = Math.max(0, row-2); r <= Math.min(14, row+2); r++) {
  957.                    for (let c = Math.max(0, col-2); c <= Math.min(19, col+2); c++) {
  958.                        const effect = document.createElement('div');
  959.                        effect.className = 'happiness-effect';
  960.                        effect.style.left = (c * 5) + '%';
  961.                        effect.style.top = (r * 6.67) + '%';
  962.                        effect.dataset.row = r;
  963.                        effect.dataset.col = c;
  964.                        grid.appendChild(effect);
  965.                        this.parkEffects.push(effect);
  966.                    }
  967.                }
  968.            }
  969.  
  970.            spawnSims(count) {
  971.                for (let i = 0; i < count; i++) {
  972.                    const sim = {
  973.                        id: Date.now() + i,
  974.                        x: Math.random() * 100,
  975.                        y: Math.random() * 100,
  976.                        targetX: Math.random() * 100,
  977.                        targetY: Math.random() * 100,
  978.                        happiness: 50 + Math.random() * 50,
  979.                        home: null,
  980.                        work: null,
  981.                        state: 'wandering', // wandering, going_home, going_work, at_home, at_work, shopping, working, relaxing
  982.                        coder: Math.random() < 0.1 // 10% chance to have coder knowledge
  983.                    };
  984.                    
  985.                    this.sims.push(sim);
  986.                    this.createSimElement(sim);
  987.                }
  988.                this.population += count;
  989.            }
  990.  
  991.            createSimElement(sim) {
  992.                const simEl = document.createElement('div');
  993.                simEl.className = 'sim';
  994.                simEl.id = `sim-${sim.id}`;
  995.                simEl.style.left = sim.x + '%';
  996.                simEl.style.top = sim.y + '%';
  997.                
  998.                if (sim.happiness > 70) simEl.classList.add('happy');
  999.                 else if (sim.happiness < 30) simEl.classList.add('unhappy');
  1000.                
  1001.                document.querySelector('.city-grid').appendChild(simEl);
  1002.            }
  1003.  
  1004.            updateSims() {
  1005.                this.sims.forEach(sim => {
  1006.                     // AI decision making for sims
  1007.                     if (Math.random() < 0.1) { // 10% chance to make a decision
  1008.                        this.makeSimDecision(sim);
  1009.                    }
  1010.                    
  1011.                    // Move towards target
  1012.                    const dx = sim.targetX - sim.x;
  1013.                    const dy = sim.targetY - sim.y;
  1014.                    const distance = Math.sqrt(dx * dx + dy * dy);
  1015.                    
  1016.                    if (distance > 2) {
  1017.                         sim.x += (dx / distance) * 2;
  1018.                         sim.y += (dy / distance) * 2;
  1019.                     } else {
  1020.                         // Reached target, pick new one
  1021.                         sim.targetX = Math.random() * 100;
  1022.                         sim.targetY = Math.random() * 100;
  1023.                     }
  1024.                    
  1025.                     // Update happiness based on city conditions
  1026.                     sim.happiness += (this.happiness - 50) * 0.01;
  1027.                     sim.happiness = Math.max(0, Math.min(100, sim.happiness));
  1028.                    
  1029.                     // Update visual
  1030.                     const simEl = document.getElementById(`sim-${sim.id}`);
  1031.                     if (simEl) {
  1032.                         simEl.style.left = sim.x + '%';
  1033.                         simEl.style.top = sim.y + '%';
  1034.                        
  1035.                         simEl.className = 'sim';
  1036.                         if (sim.happiness > 70) simEl.classList.add('happy');
  1037.                         else if (sim.happiness < 30) simEl.classList.add('unhappy');
  1038.                    }
  1039.                });
  1040.            }
  1041.  
  1042.            makeSimDecision(sim) {
  1043.                const decisions = [
  1044.                    'find_home',
  1045.                    'find_work',
  1046.                    'visit_park',
  1047.                    'go_shopping',
  1048.                    'wander'
  1049.                ];
  1050.                
  1051.                const decision = decisions[Math.floor(Math.random() * decisions.length)];
  1052.                
  1053.                switch (decision) {
  1054.                    case 'find_home':
  1055.                        if (!sim.home) {
  1056.                            const residential = this.findNearestBuilding(sim, 'residential');
  1057.                            if (residential) {
  1058.                                sim.home = residential;
  1059.                                sim.targetX = (residential.col * 5) + Math.random() * 5;
  1060.                                sim.targetY = (residential.row * 6.67) + Math.random() * 6.67;
  1061.                                sim.state = 'going_home';
  1062.                            }
  1063.                        }
  1064.                        break;
  1065.                        
  1066.                    case 'find_work':
  1067.                        if (!sim.work) {
  1068.                            const workplace = this.findNearestBuilding(sim, Math.random() > 0.5 ? 'commercial' : 'industrial');
  1069.                             if (workplace) {
  1070.                                 sim.work = workplace;
  1071.                                 sim.targetX = (workplace.col * 5) + Math.random() * 5;
  1072.                                 sim.targetY = (workplace.row * 6.67) + Math.random() * 6.67;
  1073.                                 sim.state = 'going_work';
  1074.                             }
  1075.                         }
  1076.                         break;
  1077.                        
  1078.                     case 'visit_park':
  1079.                         if (this.water > 0) { // Only visit parks if water is available
  1080.                             const park = this.findNearestBuilding(sim, 'park');
  1081.                             if (park) {
  1082.                                 sim.targetX = (park.col * 5) + Math.random() * 5;
  1083.                                 sim.targetY = (park.row * 6.67) + Math.random() * 6.67;
  1084.                                 sim.state = 'relaxing';
  1085.                                
  1086.                                 // Set timeout to return to normal state
  1087.                                 setTimeout(() => {
  1088.                                     if (sim.state === 'relaxing') {
  1089.                                         sim.state = 'wandering';
  1090.                                         const simEl = document.getElementById(`sim-${sim.id}`);
  1091.                                         if (simEl) {
  1092.                                             simEl.classList.remove('relaxing');
  1093.                                             if (sim.happiness > 70) simEl.classList.add('happy');
  1094.                                             else if (sim.happiness < 30) simEl.classList.add('unhappy');
  1095.                                        }
  1096.                                        // Big happiness boost from parks
  1097.                                        sim.happiness += 15;
  1098.                                        sim.happiness = Math.min(100, sim.happiness);
  1099.                                    }
  1100.                                }, 8000 + Math.random() * 5000);
  1101.                            }
  1102.                        }
  1103.                        break;
  1104.                        
  1105.                    case 'go_shopping':
  1106.                        const commercial = this.findNearestBuilding(sim, 'commercial');
  1107.                        if (commercial) {
  1108.                            sim.targetX = (commercial.col * 5) + Math.random() * 5;
  1109.                            sim.targetY = (commercial.row * 6.67) + Math.random() * 6.67;
  1110.                            sim.state = 'shopping';
  1111.                            
  1112.                            // Set timeout to return to normal state
  1113.                            setTimeout(() => {
  1114.                                 if (sim.state === 'shopping') {
  1115.                                     sim.state = 'wandering';
  1116.                                     const simEl = document.getElementById(`sim-${sim.id}`);
  1117.                                     if (simEl) {
  1118.                                         simEl.classList.remove('shopping');
  1119.                                         if (sim.happiness > 70) simEl.classList.add('happy');
  1120.                                         else if (sim.happiness < 30) simEl.classList.add('unhappy');
  1121.                                    }
  1122.                                    sim.happiness += 5;
  1123.                                    sim.happiness = Math.min(100, sim.happiness);
  1124.                                }
  1125.                            }, 3000 + Math.random() * 3000);
  1126.                        }
  1127.                        break;
  1128.                }
  1129.            }
  1130.  
  1131.            findNearestBuilding(sim, type) {
  1132.                let nearest = null;
  1133.                let nearestDistance = Infinity;
  1134.                
  1135.                for (let row = 0; row < 15; row++) {
  1136.                    for (let col = 0; col < 20; col++) {
  1137.                        if (this.grid[row][col] && this.grid[row][col].type === type) {
  1138.                            const dx = (col * 5) - sim.x;
  1139.                            const dy = (row * 6.67) - sim.y;
  1140.                            const distance = Math.sqrt(dx * dx + dy * dy);
  1141.                            
  1142.                            if (distance < nearestDistance) {
  1143.                                nearestDistance = distance;
  1144.                                nearest = { row, col, type };
  1145.                            }
  1146.                        }
  1147.                    }
  1148.                }
  1149.                
  1150.                return nearest;
  1151.            }
  1152.  
  1153.            autoExpand() {
  1154.                if (!this.autoMode) return;
  1155.                
  1156.                const needs = this.analyzeNeeds();
  1157.                
  1158.                if (needs.length > 0 && this.money >= this.buildingTypes[needs[0]].cost) {
  1159.                    const emptySpots = this.findEmptySpots();
  1160.                     if (emptySpots.length > 0) {
  1161.                         const spot = emptySpots[Math.floor(Math.random() * emptySpots.length)];
  1162.                        
  1163.                         // Add to queue first
  1164.                         this.buildQueue.push({
  1165.                             type: needs[0],
  1166.                             row: spot.row,
  1167.                             col: spot.col,
  1168.                             progress: 0
  1169.                         });
  1170.                        
  1171.                         this.updateBuildingQueue();
  1172.                     }
  1173.                 }
  1174.                
  1175.                 // Process building queue
  1176.                 this.processBuildingQueue();
  1177.             }
  1178.  
  1179.             analyzeNeeds() {
  1180.                 const buildingCounts = this.getBuildingCounts();
  1181.                 const needs = [];
  1182.                
  1183.                 // Need more power?
  1184.                 if (buildingCounts.power < Math.ceil(this.population / 50)) {
  1185.                    needs.push('power');
  1186.                }
  1187.                
  1188.                // Need more water?
  1189.                if (buildingCounts.power > 0 && buildingCounts.water < Math.ceil(this.population / 60)) {
  1190.                    needs.push('water');
  1191.                 }
  1192.                
  1193.                 // Need more residential?
  1194.                 const residentialCapacity = buildingCounts.residential * 5;
  1195.                 if (this.sims.length >= residentialCapacity * 0.8) {
  1196.                     needs.push('residential');
  1197.                 }
  1198.                
  1199.                 // Need more commercial/industrial?
  1200.                 if (buildingCounts.commercial + buildingCounts.industrial < Math.ceil(this.population / 15)) {
  1201.                    needs.push(Math.random() > 0.5 ? 'commercial' : 'industrial');
  1202.                 }
  1203.                
  1204.                 // Need more happiness? (only if water is available)
  1205.                 if (this.water > 0 && this.happiness < 70) {
  1206.                    needs.push('park');
  1207.                 }
  1208.                
  1209.                 // Need more roads?
  1210.                 if (buildingCounts.road < (buildingCounts.residential + buildingCounts.commercial + buildingCounts.industrial)) {
  1211.                    needs.push('road');
  1212.                }
  1213.                
  1214.                return needs;
  1215.            }
  1216.  
  1217.            findEmptySpots() {
  1218.                const spots = [];
  1219.                for (let row = 0; row < 15; row++) {
  1220.                    for (let col = 0; col < 20; col++) {
  1221.                        if (!this.grid[row][col]) {
  1222.                            spots.push({ row, col });
  1223.                        }
  1224.                    }
  1225.                }
  1226.                return spots;
  1227.            }
  1228.  
  1229.            processBuildingQueue() {
  1230.                this.buildQueue = this.buildQueue.filter(item => {
  1231.                     item.progress += 2 + this.gameSpeed;
  1232.                    
  1233.                     if (item.progress >= 100) {
  1234.                         this.placeBuilding(item.row, item.col, item.type);
  1235.                         return false; // Remove from queue
  1236.                     }
  1237.                    
  1238.                     return true; // Keep in queue
  1239.                 });
  1240.                
  1241.                 this.updateBuildingQueue();
  1242.             }
  1243.  
  1244.             updateBuildingQueue() {
  1245.                 const queueList = document.getElementById('queueList');
  1246.                 queueList.innerHTML = '';
  1247.                
  1248.                 this.buildQueue.forEach(item => {
  1249.                     const queueItem = document.createElement('div');
  1250.                     queueItem.className = 'queue-item';
  1251.                     queueItem.innerHTML = `
  1252.                         <span>${this.buildingTypes[item.type].icon} ${item.type}</span>
  1253.                         <div class="progress-bar">
  1254.                             <div class="progress-fill" style="width: ${item.progress}%"></div>
  1255.                         </div>
  1256.                     `;
  1257.                     queueList.appendChild(queueItem);
  1258.                 });
  1259.             }
  1260.  
  1261.             getBuildingCounts() {
  1262.                 const counts = {
  1263.                     residential: 0, commercial: 0, industrial: 0,
  1264.                     park: 0, road: 0, power: 0, water: 0
  1265.                 };
  1266.                
  1267.                 for (let row = 0; row < 15; row++) {
  1268.                    for (let col = 0; col < 20; col++) {
  1269.                        if (this.grid[row][col]) {
  1270.                            counts[this.grid[row][col].type]++;
  1271.                        }
  1272.                    }
  1273.                }
  1274.                
  1275.                return counts;
  1276.            }
  1277.  
  1278.            updateEconomy() {
  1279.                const counts = this.getBuildingCounts();
  1280.                
  1281.                // Calculate income
  1282.                this.income = (counts.residential * this.buildingTypes.residential.income) +
  1283.                              (counts.commercial * this.buildingTypes.commercial.income) +
  1284.                              (counts.industrial * this.buildingTypes.industrial.income);
  1285.                
  1286.                // NEW: Water profit generation when enough Ultra Sims™ are present
  1287.                let waterProfit = 0;
  1288.                if (this.population >= this.waterProfitThreshold) {
  1289.                     // Enable water profit if not already enabled
  1290.                     if (!this.waterProfitEnabled) {
  1291.                         this.waterProfitEnabled = true;
  1292.                         this.showNotification("💧 Water facilities now generating income with enough Ultra Sims™!");
  1293.                     }
  1294.                    
  1295.                     // Calculate water profit (more sims = more profit)
  1296.                     waterProfit = counts.water * (this.population / 10);
  1297.                     this.income += waterProfit;
  1298.                    
  1299.                     // Show visual indicators on water buildings
  1300.                     if (waterProfit > 0 && Math.random() < 0.1) {
  1301.                        this.showWaterProfitIndicators(counts.water);
  1302.                     }
  1303.                 } else {
  1304.                     this.waterProfitEnabled = false;
  1305.                 }
  1306.                
  1307.                 // Calculate expenses (water upkeep is now 0)
  1308.                 this.expenses = (counts.residential * this.buildingTypes.residential.upkeep) +
  1309.                                (counts.commercial * this.buildingTypes.commercial.upkeep) +
  1310.                                (counts.industrial * this.buildingTypes.industrial.upkeep) +
  1311.                                (counts.park * this.buildingTypes.park.upkeep) +
  1312.                                (counts.power * this.buildingTypes.power.upkeep);
  1313.                
  1314.                 // Update money
  1315.                 this.money += (this.income - this.expenses);
  1316.                
  1317.                 // Update net cashflow
  1318.                 this.netCashflow = this.income - this.expenses;
  1319.                
  1320.                 // Update happiness
  1321.                 this.happiness = 50 + (counts.park * 15) - (counts.industrial * 2); // Parks provide more happiness
  1322.                 this.happiness = Math.max(0, Math.min(100, this.happiness));
  1323.                
  1324.                 // Update power
  1325.                 this.power = (counts.power * 100) - ((counts.residential + counts.commercial + counts.industrial) * 10);
  1326.                 this.power = Math.max(0, this.power);
  1327.                
  1328.                 // Update water
  1329.                 this.water = (counts.water * 100) - ((counts.residential + counts.commercial + counts.industrial) * 8);
  1330.                 this.water = Math.max(0, this.water);
  1331.                
  1332.                 // Update cash flow display
  1333.                 this.updateCashFlowDisplay();
  1334.             }
  1335.            
  1336.             showWaterProfitIndicators(waterCount) {
  1337.                 // Show profit indicators on water buildings
  1338.                 for (let row = 0; row < 15; row++) {
  1339.                    for (let col = 0; col < 20; col++) {
  1340.                        if (this.grid[row][col] && this.grid[row][col].type === 'water') {
  1341.                            const cell = document.querySelector(`[data-row="${row}"][data-col="${col}"]`);
  1342.                            if (cell) {
  1343.                                const indicator = document.createElement('div');
  1344.                                indicator.className = 'water-profit-indicator';
  1345.                                indicator.textContent = '+$' + Math.round(this.population / 10);
  1346.                                indicator.style.left = (col * 5 + 2.5) + '%';
  1347.                                indicator.style.top = (row * 6.67 + 3.3) + '%';
  1348.                                
  1349.                                document.querySelector('.city-grid').appendChild(indicator);
  1350.                                
  1351.                                // Remove indicator after animation completes
  1352.                                setTimeout(() => {
  1353.                                     indicator.remove();
  1354.                                 }, 2000);
  1355.                             }
  1356.                         }
  1357.                     }
  1358.                 }
  1359.             }
  1360.            
  1361.             updateCashFlowDisplay() {
  1362.                 document.getElementById('cashIncome').textContent = this.income;
  1363.                 document.getElementById('cashExpenses').textContent = this.expenses;
  1364.                
  1365.                 const netElement = document.getElementById('cashNet');
  1366.                 netElement.textContent = (this.netCashflow >= 0 ? '+' : '') + this.netCashflow;
  1367.                
  1368.                 if (this.netCashflow >= 0) {
  1369.                     netElement.className = 'cash-positive';
  1370.                 } else {
  1371.                     netElement.className = 'cash-negative';
  1372.                 }
  1373.             }
  1374.  
  1375.             showNotification(message) {
  1376.                 const notification = document.createElement('div');
  1377.                 notification.className = 'notification';
  1378.                 notification.textContent = message;
  1379.                 document.body.appendChild(notification);
  1380.                
  1381.                 setTimeout(() => {
  1382.                     notification.remove();
  1383.                 }, 3000);
  1384.             }
  1385.  
  1386.             updateDisplay() {
  1387.                 document.getElementById('population').textContent = this.population;
  1388.                 document.getElementById('money').textContent = Math.floor(this.money);
  1389.                 document.getElementById('happiness').textContent = Math.round(this.happiness);
  1390.                 document.getElementById('power').textContent = this.power;
  1391.                 document.getElementById('water').textContent = this.water;
  1392.                
  1393.                 const counts = this.getBuildingCounts();
  1394.                 document.getElementById('residentialCount').textContent = counts.residential;
  1395.                 document.getElementById('commercialCount').textContent = counts.commercial;
  1396.                 document.getElementById('industrialCount').textContent = counts.industrial;
  1397.                 document.getElementById('parkCount').textContent = counts.park;
  1398.                 document.getElementById('roadCount').textContent = counts.road;
  1399.                 document.getElementById('powerCount').textContent = counts.power;
  1400.                 document.getElementById('waterCount').textContent = counts.water;
  1401.                 document.getElementById('simCount').textContent = this.sims.length;
  1402.                 document.getElementById('simCapacity').textContent = counts.residential * 5;
  1403.                
  1404.                 document.getElementById('income').textContent = this.income;
  1405.                 document.getElementById('expenses').textContent = this.expenses;
  1406.                 document.getElementById('netCashflow').textContent = this.netCashflow;
  1407.             }
  1408.  
  1409.             startGameLoop() {
  1410.                 // Initialize systems
  1411.                 this.weatherSystem = new WeatherSystem(this);
  1412.                 this.disasterSystem = new DisasterSystem(this);
  1413.                
  1414.                 const gameLoop = () => {
  1415.                     if (this.gameSpeed > 0) {
  1416.                         const now = Date.now();
  1417.                         const deltaTime = (now - this.lastUpdate) * this.gameSpeed;
  1418.                        
  1419.                         if (deltaTime >= 1000) { // Update every second (adjusted by speed)
  1420.                             this.updateSims();
  1421.                             this.autoExpand();
  1422.                             this.updateEconomy();
  1423.                             this.updateDisplay();
  1424.                             this.disasterSystem.checkForDisasters();
  1425.                            
  1426.                             // Process advanced AI behaviors
  1427.                             SimAI.processSimBehaviors(this);
  1428.                            
  1429.                             this.lastUpdate = now;
  1430.                         }
  1431.                     }
  1432.                    
  1433.                     requestAnimationFrame(gameLoop);
  1434.                 };
  1435.                
  1436.                 gameLoop();
  1437.             }
  1438.  
  1439.             setSpeed(speed, button) {
  1440.                 this.gameSpeed = speed;
  1441.                 document.querySelectorAll('.speed-btn').forEach(btn => btn.classList.remove('active'));
  1442.                 button.classList.add('active');
  1443.             }
  1444.  
  1445.             toggleAutoMode(button) {
  1446.                 this.autoMode = !this.autoMode;
  1447.                 button.textContent = `Auto: ${this.autoMode ? 'ON' : 'OFF'}`;
  1448.             }
  1449.  
  1450.             addRandomEvent() {
  1451.                 const events = [
  1452.                     { type: 'boom', message: '💰 Economic boom! +2000 money', effect: () => this.money += 2000 },
  1453.                     { type: 'festival', message: '🎉 City festival! +20 happiness', effect: () => this.happiness += 20 },
  1454.                     { type: 'migration', message: '🏃‍♂️ New residents arrive!', effect: () => this.spawnSims(5) },
  1455.                     { type: 'blackout', message: '⚡ Power outage! -50 power', effect: () => this.power = Math.max(0, this.power - 50) },
  1456.                     { type: 'drought', message: '🏜️ Water shortage! -30 water', effect: () => this.water = Math.max(0, this.water - 30) },
  1457.                     { type: 'discovery', message: '🔬 Technology breakthrough! Buildings cost 25% less for 30 seconds', effect: () => {
  1458.                         Object.keys(this.buildingTypes).forEach(type => {
  1459.                             this.buildingTypes[type].cost *= 0.75;
  1460.                         });
  1461.                         setTimeout(() => {
  1462.                             Object.keys(this.buildingTypes).forEach(type => {
  1463.                                 this.buildingTypes[type].cost /= 0.75;
  1464.                             });
  1465.                         }, 30000);
  1466.                     }}
  1467.                 ];
  1468.                
  1469.                 const event = events[Math.floor(Math.random() * events.length)];
  1470.                 event.effect();
  1471.                 this.showNotification(event.message);
  1472.             }
  1473.  
  1474.             resetCity() {
  1475.                 this.grid = Array(15).fill().map(() => Array(20).fill(null));
  1476.                 this.sims.forEach(sim => {
  1477.                     const simEl = document.getElementById(`sim-${sim.id}`);
  1478.                     if (simEl) simEl.remove();
  1479.                 });
  1480.                 this.sims = [];
  1481.                 this.money = 1000000;
  1482.                 this.population = 0;
  1483.                 this.happiness = 100;
  1484.                 this.power = 50;
  1485.                 this.water = 0;
  1486.                 this.buildQueue = [];
  1487.                 this.income = 0;
  1488.                 this.expenses = 0;
  1489.                 this.netCashflow = 0;
  1490.                 this.waterProfitEnabled = false;
  1491.                
  1492.                 // Remove park effects
  1493.                 this.parkEffects.forEach(effect => effect.remove());
  1494.                 this.parkEffects = [];
  1495.                
  1496.                 this.createGrid();
  1497.                 this.spawnInitialBuildings();
  1498.                 this.updateBuildingOptions();
  1499.                 this.updateCashFlowDisplay();
  1500.                 this.showNotification('🏗️ City reset! Starting fresh...');
  1501.             }
  1502.         }
  1503.  
  1504.         // Global functions for buttons
  1505.         let city;
  1506.  
  1507.         function setSpeed(speed, button) {
  1508.             if (city) city.setSpeed(speed, button);
  1509.         }
  1510.  
  1511.         function toggleAutoMode(button) {
  1512.             if (city) city.toggleAutoMode(button);
  1513.         }
  1514.  
  1515.         function addRandomEvent() {
  1516.             if (city) city.addRandomEvent();
  1517.         }
  1518.  
  1519.         function resetCity() {
  1520.             if (city) city.resetCity();
  1521.         }
  1522.        
  1523.         function buildSelected(type) {
  1524.             if (city) city.buildSelected(type);
  1525.         }
  1526.  
  1527.         // Close building menu when clicking elsewhere
  1528.         document.addEventListener('click', function(e) {
  1529.             const menu = document.getElementById('buildingMenu');
  1530.             if (menu.style.display === 'flex' && !menu.contains(e.target)) {
  1531.                menu.style.display = 'none';
  1532.                 if (city) city.selectedCell = null;
  1533.             }
  1534.         });
  1535.  
  1536.         // Initialize the game when the page loads
  1537.         window.onload = function() {
  1538.             city = new UltraCity();
  1539.         };
  1540.     </script>
  1541. </body>
  1542. </html>
  1543.  
Advertisement
Add Comment
Please, Sign In to add comment