PageSourceSearch

https://dylanlandman.com/resources/js/cloud-manager.js

js dylanlandman.com collected 2026-10-05 02:02:38 UTC 8,341 bytes, 275 lines download raw bytes

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.