System Controlled Random Weather

gref

New Member
Reaction score
33
Controlled Random Weather v1.12 by gref

Description:
This will create a believable weather system in one line in your map.

Leakless: Yes.
Lagless: Yes.
Multi-Instanceable: Yes
Jass/Gui: Jass (Gui can use.)

Screenshots:
Sandstorm:
Screen1.jpg


Storm:
Screen2.jpg


Blizzard:
Screen3.jpg


Moonlit:
Screen4.jpg

Readme
|======================================================================|
| Controlled Random Weather 1.12 by gref |
|======================================================================|


The purpose of this system is to allow developers a simple way to create and manipulate
believable and easily customized weather over multiple areas, to make maps better, and to make
mapmaking easier.

Table of Contents:

Credits
Functions
General Implementation
Weather Thresholds
How to use in GUI
Possible Uses
Notes for Customization



============================================>
Credits:
Vexorian for CSCache
xPheRe for his snippet which gave me the idea.


============================================>
Functions:
1.) weather_CreateWeather
weather_Create_Weather(rect Area, real Minimum Temperature, real Maximum Temperature, real
Minimum Pressure, real Maximum Pressure, real Time between updates,
boolean Feedback)
Returns integer Handle

This function is the standard function for creating weather. It can be called from any trigger
and gives you an integer Handle which can be used to pause, unpause and destroy the weather
created.
Argument explanation:
rect Area: The area you want the weather to appear over. For a standard world editor defined
region put gg_rct_ before the name and replace any spaces with underscores. ie.
gg_rct_Region_1
real Minimum Temperature: The absolute lowest point the temperature will reach. Temperature
and pressure have direct bearing on what weather occurs, and when. To see a list of
thresholds and weather types, scroll down.
real Maximum Temperature: The absolute highest point the temperature will reach.
real Minimum Pressure: The absolute lowest point the pressure will go to. 800.0 is the
minimum value
real Maximum Pressure: The absolute highest point the pressure will go to. 1200.0 is the
maximum value
real Time between updates: The amount of time the system waits before incrementing itself and
possibly changing the weather. 1.00 is the expected value. Anything less than 0.1
has a chance of causing lag, depending on pc's and what else is running in wc3.
boolean Feedback: If this is true, all players will see the weather name, region number,
temperature and pressure of a weather system when it changes weather. Useful for
testing if the weather is appropriate in a map.

2.) weather_PauseWeather
weather_Pause_Weather(integer Handle, boolean Pause)
If Pause it true, pauses the weather system given by Handle.
Otherwise unpauses it.
Pause means the the weather system will not change from its current weather, but does not mean
that the weather itself will stop as it is.

3.) weather_DestroyWeather
weather_Destroy_Weather(integer Handle)
Destroys the weather system given by Handle and all its effects.

============================================>

Implementation:
Step 1 vJass:
To run this system you need an editor that supports vJass. If you do, read on. If you don't,
here are some:
World Editor Unlimited - http://www.wc3campaigns.net/showthread.php?t=81731 (Updates the
normal world editor)
Jass NewGen Pack - http://www.wc3campaigns.net/showthread.php?t=90999 (Another editor)
Step 2 CSCache:
This system requires a recent version of CSCache. If you don't have it, or have an older
version then copy the CSCache trigger into your map.
Step 3 Weather:
This system obviously requires the weather trigger...
Copy it into your map.
Done.


============================================>
Weather Thresholds: (What displays when)

Thresholds: Pressure Temperature Time
-Sandstorm >1195 Any Any
-Heavy wind <=1195, >1185 Any Any
-Light wind <=1185, >1160 Any Any
-Sunlight <=1160, >1080 Any Day
-Moonlight <=1160, >1080 Any Night
-Clouds <=1080, >1000* Any Any
-Fog <=1000, > 970 <18, >3 Any
-Light Rain <= 970, > 870 >0 Any
-Light Snow <= 970, > 870 <=0 Any
-Heavy Rain <= 870, > 830 >0 Any
-Heavy Snow <= 870, > 830 <=0 Any
-Storm <= 830 >0 Any
-Blizzard <= 830 <=0 Any

*If fog does not occur due to temperature, then cloud will occur between 1000 and 970.



============================================>
How to use in GUI:
Creating Permanent weather:
-In the trigger you want to start the weather system with, add a new Action.
-Scroll down to Custom Script.
-Enter "call weather_CreateWeather(Region, Minimum Temperature, Maximum
Temperature, Minimum Pressure, Maximum Pressure, Rate of Change, Enable Feedback)"
-Replace the values with your choice in the brackets with your settings.

Creating Weather that can be paused:
-Create a integer variable by pressing X in your trigger editor (I will call the variable
"Var Name" for this)
-In the trigger you want to start the weather system with, add a new Action.
-Scroll down to Custom Script.
-Enter "set udg_Var_Name = call weather_CreateWeather(Region, Minimum Temperature, Maximum
Temperature, Minimum Pressure, Maximum Pressure, Rate of Change, Enable Feedback)"
-Replace the values with your choice in the brackets with your settings, and Var Name with
the name of your variable. (Remember to change spaces to underscores and put udg_ in front)

Pausing Weather:
-In the trigger you want to pause the weather system with, add a new Action.
-Scroll down to Custom Script.
-Enter "call weather_PauseWeather(udg_Var_Name, true)"
-Replace Var Name with the name of your integer variable that you stored the original weather
in.(Remember to change spaces to underscores and put udg_ in front)

Unpausing Weather:
-In the trigger you want to unpause the weather system with, add a new Action.
-Scroll down to Custom Script.
-Enter "call weather_PauseWeather(udg_Var_Name, false)"
-Replace Var Name with the name of your integer variable that you stored the original weather
in.(Remember to change spaces to underscores and put udg_ in front)

Destroying Weather:
-In the trigger you want to destroy the weather system with, add a new Action.
-Scroll down to Custom Script.
-Enter "call weather_DestroyWeather(udg_Var_Name)"
-Replace Var Name with the name of your integer variable that you stored the original weather
in.(Remember to change spaces to underscores and put udg_ in front)

============================================>
Possible Uses:

A dark and stormy island: weather_CreateWeather(whichRegion, 2.0, 10.0, 800.0, 825.0, false)
=> The island will permanently be stormed on

A continent: weather_CreateWeather(GetWorldBounds(), -10.0, 15.0, 800.0, 1200.0, false)
=> Will experience every type of weather.

A sunny island: weather_CreateWeather(whichRegion, 2.0, 25.0, 1000.0, 1150.0, false)
=> Will experience only sun, moonlight and clouds

A desert: weather_CreateWeather(whichRegion, 2.0, 25.0, 1160.0, 1200.0, false)
=> Will experience light to sandstorm level dry winds.

A frozen wasteland: weather_CreateWeather(whichRegion, -25.0, -2.0, 800.0, 970.0, false)
=> Will experience light to blizzard level snow.

A swamp: weather_CreateWeather(whichRegion, 4.0, 10.0, 850.0, 1050.0, false)
=> Will have light rain, heavy rain, fog and clouds


============================================>
Notes for Customization:

There are many constants available for manipulation that will greatly affect the behaviour of
all weather. I've tried to make almost every useful value easily manipulatable in the constants
area of the library.
Not currently easily manipulatable are the threshold levels of weather effects, however these
can be editted further into the system. I have avoided placing constants for them as I believe
the system is probably currently setup in as believable a manner as it will get. If you disagree
let me know or just go nuts.
There are many, many comments throughout the system, they should help you know where you are and
what you're doing.

Finally,
If you find leaks, need to contact me for assistance in relation to the system or anything else
pm me at WC3Campaigns or TheHelper as gref, or send me an email at [email protected]

Code:
JASS:
//===============================================================
// Controlled Random Weather 1.12 by gref  
//===============================================================     

                           
library weather initializer InitWeather requires CSCache

      
    globals 
//===============================================================
// CONSTANTS  
//===============================================================     

        //Blizzard and Lightning effects
        private constant boolean effects_on = true  
    
    //Relative temperatures at times of day
        private constant real max_time = 14.00 //Maximum at 2.00 pm
        private constant real min_time = 4.00 //Minimum at 4.00 am
        private constant real average_variation = 15.0 // The difference in degrees between 
        //max and min normally. If you want the average temperature to be between 5 and 25,
        // you would set it 20 etc.     
        
        private constant real max_allowed_pressure = 1200  
        private constant real min_allowed_pressure = 800
        
        private constant real seconds_in_day = 480.0
        private constant real dawn = 6.0
        private constant real dusk = 18.0
    
    //Determines how large the change in temperature and pressure per second can grow to
        private constant real max_temp_delta_variation = 0.2 
        private constant real max_mmHg_delta_variation = 25.0
        
    //Determines the factor of decay back towards 0 of change in pressure
        private constant real mmHg_decay = 0.9
    
    //Names and values in array of the various weather effects
        private constant integer sun = &#039;LRaa&#039;
        private constant integer cloud = &#039;FDwl&#039;
        private constant integer rain = &#039;RAlr&#039;
        private constant integer storm = &#039;RAhr&#039;         
        private constant integer snow = &#039;SNls&#039; //Rain &amp; less than 0 degrees
        private constant integer blizzard = &#039;SNbs&#039; //Storm &amp; less than 0 degrees
        private constant integer moon = &#039;LRma&#039; //Clear at night     
        private constant integer heavysnow = &#039;SNhs&#039; //Heavy rain &amp; less than 0
        private constant integer heavyrain = &#039;RLhr&#039; 
        private constant integer fog = &#039;FDwh&#039;
        private constant integer wind = &#039;WOlw&#039;
        private constant integer heavywind = &#039;WOcw&#039;
        private constant integer sandstorm = &#039;WNcw&#039;
                                                   
        private constant string sun_name = &quot;Sunlit&quot;               
        private constant string cloud_name = &quot;Overcast&quot;               
        private constant string rain_name = &quot;Light Rain&quot;               
        private constant string storm_name = &quot;Storm&quot;               
        private constant string snow_name = &quot;Light Snow&quot;               
        private constant string blizzard_name = &quot;Blizzard&quot;               
        private constant string moon_name = &quot;Moonlit&quot;               
        private constant string heavysnow_name = &quot;Heavy Snow&quot;               
        private constant string heavyrain_name = &quot;Heavy Rain&quot;               
        private constant string fog_name = &quot;Fog&quot;               
        private constant string wind_name = &quot;Light Wind&quot;               
        private constant string heavywind_name = &quot;Heavy Wind&quot;               
        private constant string sandstorm_name = &quot;Sandstorm&quot;
        
    //Lightning and Blizzard Effects
        private constant real lightning_min = 0.25 //Smallest time between lightning strikes 
        private constant real lightning_max = 2.00 //Max time between lightning strikes
        private constant real blizzard_min = 0.25  //Smallest time between ice shards
        private constant real blizzard_max = 1.00  //Max time between ice shards
    
        private constant string lightning_effect_strike = &quot;Doodads\\Cinematic\\Lightningbolt\\Lightningbolt.mdl&quot; 
        private constant string lightning_effect_impact = &quot;Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl&quot;
        private constant string blizzard_effect = &quot;Abilities\\Spells\\Human\\Blizzard\\BlizzardTarget.mdl&quot;  
        private constant string lightning_sound_effect = &quot;Abilities\\Spells\\Orc\\LightningBolt\\LightningBolt.wav&quot;

   
//===============================================================
// VARIABLES  
//===============================================================  

        private integer array weather_id             
        private real array delta_temperature  
        private string array weather_name   
  
    endglobals    

    //Weather conditions data type      
    
    struct weather_conditions
        integer current // current weather index (What the actualy weather is now)
        integer previous
        string w_name // the name of the current weather
        string temperature
        string pressure   
                                 
        // Tells you the region, weather, temperature and pressure when it changes.
        boolean feedback_on 
        boolean change_weather
        boolean enable_weather
        rect weather_rect // the rect in which the weath occurs
        timer effects_timer //The timer that ticks lightning effects
        timer main_timer // The timer that ticks the entire system
        timer weather_timer //The timer that ticks the weather effects

        real max        //maximum temperature
        real min        //minimum temperature
        real min_pressure   //minimum pressure
        real max_pressure   //maximum pressure
        real rate_of_change //time between each update of the weather
    
        real temp // temperature
        real temp_delta
        real temp_delta_i                      
        
        real mmHg // atmospheric pressure
        real mmHg_delta //change in atmospheric pressure
        real mmHg_delta_i //stimulus for chance in atmospheric pressure
        
        static method create takes nothing returns weather_conditions
            local weather_conditions w = weather_conditions.allocate()
            
            set w.effects_timer = CreateTimer()
            set w.main_timer = CreateTimer()
            set w.change_weather = true
            set w.enable_weather = false 
            
            return w       
        endmethod
             
        method onDestroy takes nothing returns nothing 
           local WeatherEffectStruct w_effect = GetAttachedInt(.weather_timer, &quot;weath_effect&quot;)
           
           call PauseTimer(.main_timer)    
           call PauseTimer(.effects_timer)
           call PauseTimer(.weather_timer)
           
           call WeatherEffectStruct.destroy(w_effect)  
           
           call CleanAttachedVars(.main_timer) 
           call CleanAttachedVars(.effects_timer)  
           call CleanAttachedVars(.weather_timer)   
                    
           call DestroyTimer(.main_timer)  
           call DestroyTimer(.effects_timer)
           call DestroyTimer(.weather_timer)
        endmethod
             
    endstruct
    
    struct EffectStruct
        effect e
        
        method onDestroy takes nothing returns nothing
            call DestroyEffect(.e)
        endmethod    
    endstruct
    
    struct WeatherEffectStruct takes nothing returns nothing
        weathereffect e
        
        method onDestroy takes nothing returns nothing
            call EnableWeatherEffect(.e, false)
            call RemoveWeatherEffect(.e)
        endmethod    
    endstruct
        
//===============================================================
// RUNTIME FUNCTIONS 
//===============================================================                  

    
    private function RemoveEffect takes nothing returns nothing
        local timer t = GetExpiredTimer()
        
        call EffectStruct.destroy(GetAttachedInt(t, &quot;effect&quot;))
        call CleanAttachedVars(t)
        call DestroyTimer(t)
        
        set t = null
    endfunction

    private function CreateEffect takes string model, real x, real y, real duration returns nothing
        local timer t = CreateTimer()
        
        local EffectStruct e = EffectStruct.create()
        
        set e.e = AddSpecialEffect(model, x, y)
        
        call AttachInt(t, &quot;effect&quot;, e)
        call TimerStart(t, duration, false, function RemoveEffect)
        
        set t = null
    endfunction


    private function LightningBolt takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local weather_conditions w = GetAttachedInt(t, &quot;w&quot;)
        local real x = GetRandomReal(GetRectMinX(w.weather_rect), GetRectMaxX(w.weather_rect)) 
        local real y = GetRandomReal(GetRectMinY(w.weather_rect), GetRectMaxY(w.weather_rect)) 
        local sound s = CreateSound(lightning_sound_effect,false, true, false, 5, 5, &quot;SpellsEAX&quot;)
        
        
        call CreateEffect(lightning_effect_strike, x, y, 0.50)       
        call CreateEffect(lightning_effect_impact, x, y, 1.00)
        
        call SetSoundPosition(s, x, y, 0)
        call SetSoundVolume(s, 127)
        call StartSound(s)
        call KillSoundWhenDone(s)
               
        call TimerStart(GetExpiredTimer(), GetRandomReal(lightning_min, lightning_max), false, function LightningBolt)
        
        set t = null
        set s = null   
    endfunction



    private function IceShard takes nothing returns nothing 
        local timer t = GetExpiredTimer() 
        local weather_conditions w = GetAttachedInt(t, &quot;w&quot;)                
        local real x = GetRandomReal(GetRectMinX(w.weather_rect), GetRectMaxX(w.weather_rect)) 
        local real y = GetRandomReal(GetRectMinY(w.weather_rect), GetRectMaxY(w.weather_rect)) 

        call CreateEffect(blizzard_effect, x, y, 1.00)

                
        call TimerStart(GetExpiredTimer(), GetRandomReal(blizzard_min, blizzard_max), false, function IceShard)
           
        set t = null
    endfunction

    private function TimedEffects takes weather_conditions w returns nothing
        //Makes pretty effects when there is a blizzard or storm
        if(w.current == 3) then
            call CleanAttachedVars(w.effects_timer)
            call AttachInt(w.effects_timer, &quot;w&quot;, w)
            call TimerStart(w.effects_timer, GetRandomReal(lightning_min, lightning_max), false, function LightningBolt)
        else                                 
            call CleanAttachedVars(w.effects_timer)
            call AttachInt(w.effects_timer, &quot;w&quot;, w)        
            call TimerStart(w.effects_timer, GetRandomReal(blizzard_min, blizzard_max), false, function IceShard)
        endif    
    endfunction
        
    private function ChangeWeatherEffect takes nothing returns nothing  
        //Recycles timer, makes and destroys effects on weather change.
       
        local timer t = GetExpiredTimer()
        local WeatherEffectStruct w_effect = GetAttachedInt(t, &quot;weath_effect&quot;)            
        local weather_conditions w = GetAttachedInt(t, &quot;w&quot;)
                
        if(w.change_weather == true) then
            call EnableWeatherEffect(w_effect.e, false)  
            call RemoveWeatherEffect(w_effect.e)
            
            call CleanAttachedVars(t) 
            
            set w_effect.e = AddWeatherEffect(w.weather_rect, weather_id[w.current])
               
            call AttachInt(t, &quot;w&quot;, w)       
            call AttachInt(t, &quot;weath_effect&quot;, w_effect)
            call TimerStart(t, .05, false, function ChangeWeatherEffect)
            set w.change_weather = false          
        else       
            call EnableWeatherEffect(w_effect.e, true)
            call TimerStart(t, w.rate_of_change, false, function ChangeWeatherEffect)              
        endif          
        
        set t = null
    endfunction
    
    private function StartWeatherEffect takes weather_conditions w returns nothing
        //Starts the weather changing process
        local WeatherEffectStruct w_effect = WeatherEffectStruct.create()
        set w_effect.e = AddWeatherEffect(w.weather_rect, weather_id[w.current]) 
    
        set w.weather_timer = CreateTimer()
        
        call AttachInt(w.weather_timer, &quot;w&quot;, w)
        call AttachInt(w.weather_timer, &quot;weath_effect&quot;, w_effect)
        call TimerStart(w.weather_timer, 0.05, false, function ChangeWeatherEffect)
        set w.change_weather = false

    endfunction
    
    private function ShowWeather takes weather_conditions w returns nothing              
        set w.previous = w.current
        // saves the previous effect, so we know if there was a change in weather this cycle
               
    //Determine current weather   
        if (w.mmHg &gt; 1195) then //Practically a Sandstorm
            set w.current = 12    
        elseif (w.mmHg &gt; 1185) then //Heavy Wind (Dry)
            set w.current = 11       
        elseif (w.mmHg &gt; 1160) then // Light Wind (Dry) 
            set w.current = 10       
        elseif (w.mmHg &gt; 1080) then // Sun   
            if(GetFloatGameState(GAME_STATE_TIME_OF_DAY)&lt;dawn)or(GetFloatGameState(GAME_STATE_TIME_OF_DAY)&gt;dusk) then
                set w.current = 6  //Moon
            else      //Sun        
                set w.current = 0            
            endif                      
        elseif (w.mmHg &gt; 1000) then // Cloud 
            set w.current = 1  
        elseif (w.mmHg &gt; 970) then // Heavy Fog or Cloud 
            if(w.temp &lt; 18)and(w.temp &gt; 3) then
                set w.current = 9   
            else
                set w.current = 1
            endif
        elseif(w.mmHg &gt; 870) then 
            if(w.temp &gt; 0) then //Rain 
                set w.current = 2
        
            else //Snow         
                set w.current = 4
        
            endif
        elseif(w.mmHg &gt; 830) then 
            if(w.temp &gt; 0) then //Heavy Rain 
                set w.current = 7
        
            else //Heavy Snow         
                set w.current = 8
        
            endif            
        else        
            if(w.temp &gt; 0) then //Storm 
                set w.current = 3
        
            else //Blizzard   
                set w.current = 5
        
            endif    
    
        endif
    
    //Update Weather Data
        set w.w_name = weather_name[w.current] 
        set w.temperature = I2S(R2I(w.temp))
        set w.pressure = I2S(R2I(w.mmHg))
    
    //Show Weather Effects
        if(w.current != w.previous) then
            //Checks if weather is different, if so change it.
        
            if (w.feedback_on == true ) then
                call DisplayTextToPlayer(GetLocalPlayer(),0,0, &quot;Region: &quot;+I2S(w)+&quot;, Weather: &quot;+w.w_name+&quot;, Temperature: &quot;+w.temperature+&quot;, Pressure: &quot;+w.pressure)
            endif

            call PauseTimer(w.effects_timer) //Stops effects in blizzard and storm   
            if((w.current == 3)or(w.current == 5))and(effects_on == true) then
                //If blizzard or storm, then start effects
                call TimedEffects(w)         
            endif
            
            set w.change_weather = true //Tells Change_Weather_Effect to remove old effect and
            // make new one
                        
            if(w.enable_weather == false) then
                set w.enable_weather = true
                call StartWeatherEffect(w) 
                //Starts the weather at creation
            endif
        endif 
    endfunction

    private function WeatherIncrement takes nothing returns nothing
    //Increments the weather system at rate of change intervals
    //Gets temperature via randomness + time of day
    //Gets atmospheric pressure via randomness and delta mmHg
    //Uses data to apply weather changes.
        local timer t = GetExpiredTimer()
        local weather_conditions w = GetAttachedInt(t, &quot;weather_var&quot;)
        
    
        local real temp_factor = (24/(seconds_in_day*GetTimeOfDayScale()))*w.rate_of_change
        //Every 20 seconds (By Default) = 1 hour, so adjust temperature change to occur at one unit per game hour
        //Rate of Change impacts.
                                      
    //Affect rates of change
        set w.temp_delta_i =  (delta_temperature[R2I(GetFloatGameState(GAME_STATE_TIME_OF_DAY))] + GetRandomReal(-0.5, 0.5))*temp_factor
        set w.temp_delta = w.temp_delta+w.temp_delta_i
    
    //Ensures that change in temperature is within max variation
        if(w.temp_delta &gt; max_temp_delta_variation)then
            set w.temp_delta = max_temp_delta_variation
        endif   
        if(w.temp_delta &lt; (0-max_temp_delta_variation))then
            set w.temp_delta = (0-max_temp_delta_variation)
        endif
    
    //Set new temperature
        set w.temp = w.temp + w.temp_delta
        if(w.temp &gt; w.max)then
            set w.temp = w.max
        endif   
        if(w.temp &lt; w.min)then
            set w.temp = w.min
        endif
    
    //Affect rates of change
        set w.mmHg_delta_i = w.mmHg_delta_i/2 + GetRandomReal(-2.5, 2.5)
        set w.mmHg_delta = (w.mmHg_delta + w.mmHg_delta_i)*mmHg_decay
           
    //Ensures that change in pressure is within max variation  
        if(w.mmHg_delta &gt; max_mmHg_delta_variation)then
            set w.mmHg_delta = max_mmHg_delta_variation
        endif   
        if(w.mmHg_delta &lt; (0-max_mmHg_delta_variation))then
            set w.mmHg_delta = (0-max_mmHg_delta_variation)
        endif     
    
    //Set new pressure
        set w.mmHg = w.mmHg + w.mmHg_delta
        if(w.mmHg &gt; w.max_pressure)then
            set w.mmHg = w.max_pressure
        endif   
        if(w.mmHg &lt; w.min_pressure)then
            set w.mmHg = w.min_pressure
        endif
    
        call ShowWeather(w) //Displays the changes
    
        set t = null         
    endfunction    
    
    public function PauseWeather takes weather_conditions w, boolean enable returns nothing
        if(enable == true) then
            call PauseTimer(w.main_timer)
        else     
            call ResumeTimer(w.main_timer)        
        endif
    endfunction
    
    public function DestroyWeather takes weather_conditions w returns nothing
        call weather_conditions.destroy(w)
    endfunction
    
    public function CreateWeather takes rect whichRect, real min_temp, real max_temp, real min_mmHg, real max_mmHg, real rate, boolean feedback returns integer 
    //Starts the weather system, uses a repeating timer to update the weather at rate_of_change intervals
 
        local weather_conditions w = weather_conditions.create()
        
        set w.current = 0
        
        set w.feedback_on = feedback
        
        set w.rate_of_change = rate // How fast the weather changes    
        set w.weather_rect = whichRect
        
        //User Error checking: 
        if(min_temp &gt; max_temp) then
            set min_temp = max_temp
        endif  
        if(min_mmHg &gt; max_mmHg) then
            set min_mmHg = max_mmHg
        endif
        
        if (min_mmHg &lt; min_allowed_pressure) then  //Absolute minimum pressure
            set w.min_pressure = min_allowed_pressure
        else                      
            set w.min_pressure = min_mmHg        
        endif         
        if (max_mmHg &gt; max_allowed_pressure) then  //Absolute maximum pressure
            set w.max_pressure = max_allowed_pressure
        else                      
            set w.max_pressure = max_mmHg        
        endif
                                                                                  
        set w.min = min_temp      //Absolute minimum temperature
        set w.max = max_temp      //Absolute maximum temperature     
        
        //End User Error checking.
        
        set w.mmHg_delta_i = GetRandomReal(-4.0, 4.0)
        set w.mmHg_delta = GetRandomReal(0-max_mmHg_delta_variation, max_mmHg_delta_variation)
        set w.mmHg = GetRandomReal(min_mmHg, max_mmHg)  
                                                         
        set w.temp_delta_i = GetRandomReal(-4.0, 4.0)
        set w.temp_delta = GetRandomReal(0-max_temp_delta_variation, max_temp_delta_variation)
        set w.temp = GetRandomReal(min_temp, max_temp) 
        
        call ShowWeather(w)
        
        call AttachInt(w.main_timer, &quot;weather_var&quot;, w)
        
        call TimerStart(w.main_timer, w.rate_of_change, true, function WeatherIncrement)
    
        
        return w
    endfunction
    
    
//===============================================================
// INITIALIZATION  
//===============================================================     
    
    private function IsNumberBetween takes integer a, integer b, integer c returns boolean
        //called by Initialize_delta_temperatures
        if (a &gt; b) then
            return (a&gt;c and c&gt;b)
        else     
            return (b&gt;c and c&gt;a)             
        endif
    endfunction 
     
    private function InitializeDeltaTemperature takes nothing returns nothing
    // Makes an approximation of the rate of change of temperature at various times of day
    // Based on globals min_time, max_time, difference.
    
        local integer i = 0
        local integer gap
        
        local integer minimum = R2I(min_time)
        local integer maximum = R2I(max_time)
        
        local real rate_per_hour 
        local real ratio
        
        local integer distance_to_max 
        local integer distance_to_min
        
        loop
            exitwhen i == 24
        
            if (IsNumberBetween(minimum, maximum, i) == true) then
                set gap = IAbsBJ(minimum - maximum)
            else 
                set gap = 24 - IAbsBJ(minimum - maximum)
            endif
            
            set distance_to_max = IAbsBJ(maximum - i) 
            if(distance_to_max &gt; 12) then
                set distance_to_max = 24 - distance_to_max            
            endif               
            set distance_to_min = IAbsBJ(minimum - i) 
            if(distance_to_min &gt; 12) then
                set distance_to_min = 24 - distance_to_min            
            endif
            
            set rate_per_hour = (average_variation)/I2R(gap)   
            
            set ratio = (I2R(IAbsBJ(distance_to_min))/I2R(gap))
            if(ratio &gt; .5) then          
                set delta_temperature<i> = (I2R(IAbsBJ(distance_to_max))/I2R(gap))*4*rate_per_hour
            else          
                set delta_temperature<i> = ratio*4*rate_per_hour
            endif
            
            if(IsNumberBetween(minimum, maximum, i) == true) then
                if(i &lt; minimum) then      
                    set delta_temperature<i> = 0 - delta_temperature<i>            
                endif
            else
                if(maximum &gt; minimum) then
                    set delta_temperature<i> = 0 - delta_temperature<i>
                endif
            endif 
            
            set i = i + 1
        endloop  
                  
    endfunction   
    
    
    private function InitWeather takes nothing returns nothing          
        
        //Initialize Variables
        
        call InitializeDeltaTemperature()
        
        set weather_name[0] = sun_name      
        set weather_name[1] = cloud_name
        set weather_name[2] = rain_name
        set weather_name[3] = storm_name
        set weather_name[4] = snow_name
        set weather_name[5] = blizzard_name
        set weather_name[6] = moon_name
        set weather_name[7] = heavyrain_name
        set weather_name[8] = heavysnow_name
        set weather_name[9] = fog_name
        set weather_name[10] = wind_name   
        set weather_name[11] = heavywind_name  
        set weather_name[12] = sandstorm_name
                                                
        set weather_id[0] = sun      
        set weather_id[1] = cloud
        set weather_id[2] = rain
        set weather_id[3] = storm
        set weather_id[4] = snow
        set weather_id[5] = blizzard
        set weather_id[6] = moon
        set weather_id[7] = heavyrain
        set weather_id[8] = heavysnow
        set weather_id[9] = fog
        set weather_id[10] = wind
        set weather_id[11] = heavywind  
        set weather_id[12] = sandstorm
        
    endfunction


endlibrary

</i></i></i></i></i></i>


Purpose of the system:
To create a random weather system that allows developers a simple way to create and manipulate
believable and easily customized weather over multiple areas, to make maps better, and to make
mapmaking easier.
Any weather system can be created, paused or destroyed in one function call, and the system is multi-instanceable so that different weather systems can be created, manipulated and destroyed at any point.

Weather effects:
-Sandstorm
-Heavy wind
-Light wind
-Sunlight
-Moonlight
-Cloud cover
-Fog
-Light Rain
-Light Snow
-Heavy Rain
-Heavy Snow
-Storm
-Blizzard


Changelog:
v1.00
Initial release

v1.10
Remade readme.
Code slightly restructured.
Pause, Unpause, Destroy, and Create_Weather_Permanent added.
Better demonstration added.

v1.11
Realised Create_Weather_Permanent was useless. Removed it.

v1.12
Optimized IsNumberBetween
Made function names "less ugly" :)
Implemented struct based attachment in CreateEffect and CreateWeatherEffect
Removed GetAttachedWeatherEffect


If you find leaks, want to give me a suggestion, or comment, then feel free to pm me here, or send me an email at [email protected]
 

gref

New Member
Reaction score
33
Updated to v1.10

Added support for pausing, unpausing and destroying weather systems.
Added a Create Weather Permanent function, to assume the old Create Weather function's, and updated Create Weather to return a handle.
Restructured code.
Restructured readme.
Demonstration of pause, unpause, destroy and create functionality added.

Any comments, suggestions etc. would be a very much appreciated.
 

hi_im_bob

......and you are?
Reaction score
44
Looks pretty cool, does the weather have any effect on units? For example in some games a blizzard deals damage to buildings.
 

cr4xzZz

Also known as azwraith_ftL.
Reaction score
51
Really nice. But you should mention that NewGen WE is needed and the attachment system you used (handle vars?).
+rep from me
 

Demi666

New Member
Reaction score
127
looks nice, btw how did u find the rawcode for the weathers?

also you could do a comment where we could edit:S couse beginners like myself might get confused
 

0zaru

Learning vJASS ;)
Reaction score
60
Well i find them too, they are easy to acces with GUI actions (You know, mark them and then convert to custom text and voila! rawcodes :D)
 

gref

New Member
Reaction score
33
The impact on the game is simply visual. As far as I know, more mapmakers dont want weather that electrecutes/freezes their units etc. I just made this so that mapmakers of maps such as td's and rpgs that don't normally use weather can, and very simply.

If there really is a desire for that kind of effect, then I will make a system that extends it.

@cr4xzZz: Thanks, I included that in the readme, but naturally don't expect people to download the map, so maybe I should put it here too.

@Demi666 What did you mean by comment where you could edit?
And the rawcodes were found by converting GUI triggers, I didn't know were else to look.

Edit:Beat me to it :)
 

Pyrogasm

There are some who would use any excuse to ban me.
Reaction score
134
Just because something returns a value doesn't mean you have to use it. That means that this function is completely and utterly useless:
JASS:
public function Create_Weather_Permanent takes rect whichRect, real min_temp, real max_temp, real min_mmHg, real max_mmHg, real rate, boolean feedback returns nothing
     local integer i = Create_Weather(whichRect, min_temp, max_temp, min_mmHg, max_mmHg, rate, feedback)    
endfunction

One could simply do this instead:
JASS:
//Somewhere in a script
call weather_Create_Weather(bj_mapInitialPlayableArea,-10.00, 15.00, 800.00, 1200.00, 1.00, false)
 

gref

New Member
Reaction score
33
Ok. Thanks.

Edit: Updated to reflect that.
Thanks for bothering to read far enough through the code to find that.
 

Pyrogasm

There are some who would use any excuse to ban me.
Reaction score
134
A couple more comments on your system:
  • Your function names are a bit obtuse. Instead of public function Create_Weather it might just be better to have function CreateRandomWeather, and so on. Public functions with underscores between everything just look ugly in my opinion.
  • You obviously have access to the struct syntax and you know how to use it... yet you still use attached variables! Stuff like creating a timed effect and attaching weather effects could easily be converted to using structs. You needn't use any struct-timer attachment system because you're using CSCache already and you can just attach the structs as integers. Here's how I would write your timed effect functions:
    JASS:
    private struct EffectStruct
        effect E
    
        method onDestroy takes nothing returns nothing
            call DestroyEffect(E)
        endmethod
    endstruct
    private function Destroy_Effect takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local EffectStruct ES = EffectStruct(GetCSData(t))
    
        call ES.destroy()
        call DestroyTimer(t)
            
        set t = null
    endfunction
    
    private function Create_Effect takes string model, real x, real y, real duration returns nothing
        local timer t = CreateTimer()
        local EffectStruct ES = EffectStruct.create()
            
        set ES.E = AddSpecialEffect(model, x, y)
        call SetCSData(t, ES)
        call TimerStart(t, duration, false, function Destroy_Effect)
            
        set t = null
    endfunction

    This will, in theory, be a more efficient way of doing this and be more safe from the handle stack corruption that occurs with I2H, etc..
  • I find your Is_Number_Between function to be quite inefficient. Instead of how you've written it now, you can do this:
    JASS:
    private function Is_Number_Between takes integer a, integer b, integer c returns boolean
        //called by Initialize_delta_temperatures
        if (a &gt; b) then
            return (a&gt;c and c&gt;b)
        else     
            return (b&gt;c and c&gt;a)
        endif
    endfunction

    In fact, since you know where you're calling this function, you should always know to put the arguments such that the min is fist, then the max, and then the number you want to check, so you could in theory do this:
    JASS:
    private function Is_Number_Between takes integer min, integer max, integer c returns boolean
        //called by Initialize_delta_temperatures
        return (max&gt;c and c&gt;min)
    endfunction

    And you could further just inline this function call because it's so simple and is only 1 line.
  • Your system uses a crapload of timers (multiple for each weather effect). It might be smart to make the entire system run off of as few timers as possible using a global struct array to hold all your data and just loop through it periodically. To be honest, though, I'm not sure how feasible that would be.
 

gref

New Member
Reaction score
33
Thanks again for the continued feedback.
-Function names have been made less ugly. (The only reason they were like was to avoid conflicts with natives)
-Structs are now also used for attaching weather_effects and effects
-IsNumberBetween got optimized, but not to the degree of your second version. I need it to function without a predefined max and min, so it has to retain the conditional. (Hence why it's still not inlined (at 5 lines))

As for the timers: The system uses 4 timers concurrently at maximum per instance. I could get away with far less if I didn't allow users to select the rate of change of the system. As it is, I believe the system could only be implemented about 4 or 5 times max in a map, all with very long periods, so I don't see it as a performance hit.

I could get rid of one timer, but that would require another to change to a period of .05 to cover both functions, and I see that as a performance hit not a bonus.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top