1// Cloud Manager - Randomly spawns and animates clouds 2// Creates clouds at random intervals with varying sizes and speeds 3// Only active on mainMap scene 4 5var CloudManager = (function () { 6 var cloudContainer = null; 7 var spawnTimeout = null; // Changed from interval to timeout for recursive scheduling 8 var activeClouds = []; 9 var maxClouds = 5; // Maximum number of clouds on screen at once 10 var isActive = false; // Track if clouds should be active 11 var currentScene = null; // Track current scene 12 var mapPositionWatcher = null; 13 var lastMapMarginLeft = 0; 14 var lastMapMarginTop = 0; 15 16 // Cloud size configurations 17 var cloudSizes = [ 18 { class: 'cloud-small', width: 50, height: 18, speed: 35 }, 19 { class: 'cloud-medium', width: 70, height: 25, speed: 50 }, 20 { class: 'cloud-large', width: 100, height: 40, speed: 70 } 21 ]; 22 23 /** 24 * Checks if we're currently in the main map scene 25 */ 26 function isInMainMap() { 27 // Try to get scene from GameWorld if available 28 if (typeof window !== "undefined" && window.playerController && 29 window.playerController.gameWorld) { 30 return window.playerController.gameWorld.sceneName === "mainMap"; 31 } 32 // Fallback: check if tent/cave are visible (if they're hidden, we're likely in main map) 33 var tentVisible = $("#tent1").is(":visible"); 34 var caveVisible = $("#cave").is(":visible"); 35 return !tentVisible && !caveVisible; 36 } 37 38 /** 39 * Creates a single cloud element 40 */ 41 function createCloud() { 42 if (!cloudContainer) return; 43 44 // Only create clouds if we're in main map 45 if (!isInMainMap()) return; 46 47 // Don't spawn if we have too many clouds 48 if (activeClouds.length >= maxClouds) return; 49 50 // Randomly select cloud size 51 var cloudConfig = cloudSizes[Math.floor(Math.random() * cloudSizes.length)]; 52 53 // Get current map position to sync cloud movement 54 var mapMarginLeft = parseInt($("#map").css("margin-left")) || 0; 55 var mapMarginTop = parseInt($("#map").css("margin-top")) || 0; 56 57 // Clouds spawn relative to viewport, but will move with map 58 // Spawn just off the left edge of the viewport 59 var baseLeft = -100; // Start slightly off-screen left 60 // Random vertical position in viewport (0-80% to avoid bottom UI) 61 var baseTop = Math.random() * (window.innerHeight * 0.8); 62 63 // Calculate initial position accounting for current map position 64 var left = baseLeft + mapMarginLeft; 65 var top = baseTop + mapMarginTop; 66 67 // Random animation duration (speed varies) 68 var duration = cloudConfig.speed + (Math.random() * 20 - 10); // ±10s variation 69 70 // Create cloud element - store base position for map movement tracking 71 var cloud = $('<div>') 72 .addClass('cloud') 73 .addClass(cloudConfig.class) 74 .data('base-left', baseLeft) 75 .data('base-top', baseTop) 76 .css({ 77 top: top + 'px', 78 left: left + 'px', 79 animation: 'floatCloud ' + duration + 's linear forwards' 80 }); 81 82 // Add to container 83 cloudContainer.append(cloud); 84 activeClouds.push(cloud); 85 86 // Remove cloud when animation completes 87 setTimeout(function() { 88 cloud.remove(); 89 var index = activeClouds.indexOf(cloud); 90 if (index > -1) { 91 activeClouds.splice(index, 1); 92 } 93 }, duration * 1000); 94 } 95 96 /** 97 * Randomly spawns a cloud after a random delay 98 */ 99 function scheduleNextCloud() { 100 // Clear any existing timeout 101 if (spawnTimeout) { 102 clearTimeout(spawnTimeout); 103 spawnTimeout = null; 104 } 105 106 // Only schedule if we're active and in main map 107 if (!isActive || !isInMainMap()) { 108 return; 109 } 110 111 // Random delay between 8-15 seconds 112 var delay = 8000 + Math.random() * 7000; 113 114 spawnTimeout = setTimeout(function() { 115 if (isActive && isInMainMap()) { 116 createCloud(); 117 scheduleNextCloud(); // Schedule the next one 118 } 119 }, delay); 120 } 121 122 /** 123 * Updates cloud positions when map moves 124 * Clouds move with the map to maintain their position relative to the world 125 */ 126 function updateCloudPositions() { 127 // Only update if we're active and in main map 128 if (!isActive || !isInMainMap()) return; 129 130 if (!cloudContainer || activeClouds.length === 0) return; 131 132 var mapMarginLeft = parseInt($("#map").css("margin-left")) || 0; 133 var mapMarginTop = parseInt($("#map").css("margin-top")) || 0; 134 135 // Only update if map position changed 136 if (mapMarginLeft === lastMapMarginLeft && mapMarginTop === lastMapMarginTop) { 137 return; 138 } 139 140 // Calculate delta movement 141 var deltaLeft = mapMarginLeft - lastMapMarginLeft; 142 var deltaTop = mapMarginTop - lastMapMarginTop; 143 144 lastMapMarginLeft = mapMarginLeft; 145 lastMapMarginTop = mapMarginTop; 146 147 // Update each cloud's position based on map movement 148 // The CSS animation's translateX handles horizontal movement, but we adjust base position 149 activeClouds.forEach(function(cloud) { 150 var baseLeft = cloud.data('base-left') || 0; 151 var baseTop = cloud.data('base-top') || 0; 152 153 // Update position: base position + current map margin
154 var newLeft = baseLeft + mapMarginLeft; 155 var newTop = baseTop + mapMarginTop; 156 157 cloud.css({ 158 left: newLeft + 'px', 159 top: newTop + 'px' 160 }); 161 }); 162 } 163 164 /** 165 * Initializes the cloud system (only for main map) 166 */ 167 function init() { 168 cloudContainer = $('#clouds-container'); 169 170 if (cloudContainer.length === 0) { 171 console.warn('Cloud container not found'); 172 return; 173 } 174 175 // Only initialize if we're in main map 176 if (!isInMainMap()) { 177 return; 178 } 179 180 isActive = true; 181 currentScene = "mainMap"; 182 183 // Get initial map position 184 lastMapMarginLeft = parseInt($("#map").css("margin-left")) || 0; 185 lastMapMarginTop = parseInt($("#map").css("margin-top")) || 0; 186 187 // Watch for map position changes to update cloud positions 188 if (mapPositionWatcher) { 189 clearInterval(mapPositionWatcher); 190 } 191 mapPositionWatcher = setInterval(function() { 192 updateCloudPositions(); 193 }, 50); // Check every 50ms (same as movement interval) 194 195 // Create initial clouds (2-3 clouds to start) 196 var initialCount = 2 + Math.floor(Math.random() * 2); // 2-3 clouds 197 for (var i = 0; i < initialCount; i++) { 198 setTimeout(function() { 199 if (isActive && isInMainMap()) { 200 createCloud(); 201 } 202 }, 2000 + (i * 3000)); // Stagger initial clouds by 3 seconds 203 } 204 205 // Start random spawning 206 scheduleNextCloud(); 207 } 208 209 /** 210 * Handles scene changes - starts/stops clouds based on scene 211 */ 212 function onSceneChange(sceneName) { 213 currentScene = sceneName; 214 215 if (sceneName === "mainMap") { 216 // Start clouds if not already active 217 if (!isActive) { 218 init(); 219 } 220 } else { 221 // Stop clouds when leaving main map 222 if (isActive) { 223 stop(); 224 } 225 } 226 } 227 228 /** 229 * Stops cloud spawning (cleanup) 230 */ 231 function stop() { 232 isActive = false; 233 234 if (spawnTimeout) { 235 clearTimeout(spawnTimeout); 236 spawnTimeout = null; 237 } 238 if (mapPositionWatcher) { 239 clearInterval(mapPositionWatcher); 240 mapPositionWatcher = null; 241 } 242 // Remove all active clouds 243 activeClouds.forEach(function(cloud) { 244 cloud.remove(); 245 }); 246 activeClouds = []; 247 } 248 249 return { 250 init: init, 251 stop: stop, 252 onSceneChange: onSceneChange 253 }; 254})(); 255 256// Initialize clouds when DOM is ready and integrate with GameWorld 257$(function() { 258 // Wait for game to initialize, then check if we should start clouds 259 setTimeout(function() { 260 // Check if we're in main map and start clouds 261 if (CloudManager && typeof CloudManager.onSceneChange === "function") { 262 // Try to get current scene from GameWorld 263 var sceneName = "mainMap"; // Default 264 if (typeof window !== "undefined" && window.playerController && 265 window.playerController.gameWorld) { 266 sceneName = window.playerController.gameWorld.sceneName || "mainMap"; 267 } 268 CloudManager.onSceneChange(sceneName); 269 } else { 270 // Fallback: just init if function not available 271 CloudManager.init(); 272 } 273 }, 3000); // Start clouds 3 seconds after page load 274}); 275
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.