Note: This post is only retained for the initial incentives behind this mod. While the installation instructions still apply, the script replacements themselves are obsolete, and the ones given in post #2 should be used instead.
Introduction
One of the subtle annoyances which I have had with OMSI all along, is that all of a map's street lights go on or off simultaneously, if it gets darker or brighter than a threshold, respectively. Which is just unrealistic, since even in recent years -let alone in the 80's and 90's- the street lamps found in most EU cities are still controlled by plain timer switches (that are often not even properly synchronized) rather than modern light sensors. Similarly unrealistic is the fact that all AI-controlled cars and buses switch their headlights on or off at the same millisecond; whereas in reality -at least for the time being and until real-world AI-driven cars become the norm- human drivers exhibit quite different behaviour in that regard: some (typically younger ones) just leave their vehicle's headlights turned on all the time; some switch them on when a single cloud appears on the horizon, and some (typically older ones) only use them at night or when it actually gets really dark.
Of those two minor issues, unfortunately, no workaround that is both generic (as in that it is applicable to any map) and easy to employ is currently available for us mortal "end-users" (as in not being map or object authors) for the first of them. The second issue, on the other hand, can be combated in a multitude of ways, one of which I am going to present in this post.
Solution
So, the intention is to add some "perceived randomness" into the way AI-controlled vehicles handle their lighting-related functionality, particularly with regard to (de-)activating their headlights. Fortunately, like buses, AI-driven OMSI cars' and trucks' behavior is to a great extent scriptable. All that basically needs to be done, is to override the default condition evaluated by the vehicles' scripts in order to determine whether it is time to turn the lights on or off.
In the remainder of this post I am going to provide the proposed script and configuration file modifications, as well as installation instructions. After that I will briefly explain how the modification works. But before I get there I would first like to emphasize that what I am presenting here is a proof-of-concept modification, i.e. one that is incomplete, poorly tested and generally sub-optimal. What this means is that if you decide to use it, you will absolutely be doing so at own risk, and are certainly encouraged to take backups before proceeding with the installation. That is essentially the reason why I am posting this as a tutorial, rather than in the form of a "supported" modification.
Installation
The modification is applicable to most cars and trucks with reduced scripts; that is, vehicles which are solely destined for use by OMSI's AI. It does, obviously, not apply to buses (even "pure" AI versions of them, as their scripts generally employ a more complex structure), trains, or whatever other special kind of vehicle you might have lying around.
The targeted vehicles fall into three broad categories: a) those directly relying upon the <OMSI>\Scripts\AI_Cars\main_AI_XXX.osc and <OMSI>\Scripts\AI_Cars\lights_varlist.txt (and which constitute the vast majority); those which declare their own main script and/or variable list; and emergency vehicles. Out of all of OMSI's "standard" vehicles, only <OMSI>\Vehicles\Trabant\Trabant(_DDR).ovh is of the second kind.
In order to achieve a tangible result from this modification, you will have to modify all of the files mentioned below pertaining to all of the AI-controlled vehicles used on a particular map. Follow the instructions applicable to the vehicle you are modifying, depending on the category it belongs to (based on the distinction established above).
1. Modification installation for vehicles with reduced / minimal scripts (category #1)
1.1. Open <OMSI>\Scripts\AI_Cars\main_AI.osc or <OMSI>\Scripts\AI_Cars\main_AI_lkw.osc (for trucks).
1.1.1. Insert the following into the {init} block:
- '#########################################
- ' AI-controlled vehicle lighting behaviour initialization
- ' see also: <lights_constfile.txt>
- '#########################################
- ' unless OMSI controls AI-controlled vehicles' lighting, assign a lighting profile to the vehicle
- (C.L.AI_LIGHTING_IS_OMSI_CONTROLLED) !
- {if}
- ' try to assign profile #1
- (C.L.AI_LIGHTING_PROFILE_1_CHANCE) random 1 = s5
- ' if unsuccessful, try to assign profile #4
- l5 ! (C.L.AI_LIGHTING_PROFILE_4_CHANCE) random 1 = &&
- {if}
- 4 s5
- {endif}
- ' if unsuccessful, try to assign profile #2
- l5 ! (C.L.AI_LIGHTING_PROFILE_2_CHANCE) random 1 = &&
- {if}
- 2 s5
- {endif}
- ' if unsuccessful, assign profile #3 as the default choice
- l5 !
- {if}
- 3 s5
- {endif}
- ' unless lights are to be left switched on permanently, assign two tolerance thresholds for having them switched on and off, respectively
- l5 (S.L.ai_ovh_lighting_profile) 1 >
- {if}
- (C.L.AI_MAX_DARKNESS_TOLERANCE) random 10 + (S.L.ai_ovh_lights_darkness_tolerance)
- (C.L.AI_MAX_BRIGHTNESS_TOLERANCE) random 60 + (S.L.ai_ovh_lights_brightness_tolerance)
- {endif}
- ' perform further initialization during first frame
- 0 (S.L.ai_ovh_lighting_initialized)
- {endif}
1.1.2. In the {frame} block, find:
Insert the following below the aforementioned section:
- '#########################################
- ' AI-controlled vehicle lighting adjustment
- ' see also: <lights_constfile.txt>
- '#########################################
- ' AI-controlled venicles' lighting behavior is to be controlled by OMSI; do nothing
- (C.L.AI_LIGHTING_IS_OMSI_CONTROLLED)
- {if}
- (L.L.AI_Light) (S.L.ai_ovh_lights_on)
- {else}
- ' initialization pending; if too dark / bright, switch lights on / off without delay (because the game was just loaded).
- ' this task should normally be accomplished in the {init} block; unfortunately the <Envir_Brightness> and/or <SunAlt> variables appear
- ' to not yet have been initialized at that point.
- (L.L.ai_ovh_lighting_initialized) !
- {if}
- ' true == too dark; turn lights on
- (L.L.ai_ovh_lighting_profile) s5 1 = l5 2 = (L.L.Envir_Brightness) 0.85 < (L.S.SunAlt) 7.5 < || && || l5 3 = (L.L.Envir_Brightness) 0.7 < (L.S.SunAlt) 5 < || && || l5 4 = (L.S.SunAlt) 3 < && || (S.L.ai_ovh_lights_on)
- 1 (S.L.ai_ovh_lighting_initialized)
- ' already initialized; shall we proceed with light adjustment calculations?
- {else}
- ' profile #1 not in use, therefore proceed
- (L.L.ai_ovh_lighting_profile) 1 = !
- {if}
- ' first run since last reset of counter; set new threshold
- (L.L.ai_ovh_frame_cnt) s5 !
- {if}
- 300 300 random + (S.L.ai_ovh_frame_cnt_target) s6
- {endif}
- ' repetition threshold exceeded; must actually check if lighting needs adjustment
- l5 1 + (S.L.ai_ovh_frame_cnt) l6 >
- {if}
- ' reset repetition counter
- ! (S.L.ai_ovh_frame_cnt)
- ' adjust lighting if preconditions apply
- ' note that we disregard profile #1, as, if in use, lights would already have been turned on by the additional initialization performed above.
- (L.L.ai_ovh_lighting_profile) 2 =
- {if}
- (L.L.Envir_Brightness) 0.85 < (L.S.SunAlt) 7.5 < ||
- {if}
- ' too dark; turn lights on
- (L.L.ai_ovh_lights_on) ! (L.L.ai_ovh_lights_on_timer) (L.S.timegap) + (S.L.ai_ovh_lights_on_timer) (L.L.ai_ovh_lights_darkness_tolerance) > &&
- {if}
- 1 (S.L.ai_ovh_lights_on)
- 0 (S.L.ai_ovh_lights_on_timer)
- {endif}
- 0 (S.L.ai_ovh_lights_off_timer)
- {else}
- ' too bright; turn lights off
- (L.L.ai_ovh_lights_on) (L.L.ai_ovh_lights_off_timer) (L.S.timegap) + (S.L.ai_ovh_lights_off_timer) (L.L.ai_ovh_lights_brightness_tolerance) > &&
- {if}
- 0 (S.L.ai_ovh_lights_on)
- 0 (S.L.ai_ovh_lights_off_timer)
- {endif}
- 0 (S.L.ai_ovh_lights_on_timer)
- {endif}
- {else}
- (L.L.ai_ovh_lighting_profile) 3 =
- {if}
- (L.L.Envir_Brightness) 0.7 < (L.S.SunAlt) 5 < ||
- {if}
- ' too dark; turn lights on
- (L.L.ai_ovh_lights_on) ! (L.L.ai_ovh_lights_on_timer) (L.S.timegap) + (S.L.ai_ovh_lights_on_timer) (L.L.ai_ovh_lights_darkness_tolerance) > &&
- {if}
- 1 (S.L.ai_ovh_lights_on)
- 0 (S.L.ai_ovh_lights_on_timer)
- {endif}
- 0 (S.L.ai_ovh_lights_off_timer)
- {else}
- ' too bright; turn lights off
- (L.L.ai_ovh_lights_on) (L.L.ai_ovh_lights_off_timer) (L.S.timegap) + (S.L.ai_ovh_lights_off_timer) (L.L.ai_ovh_lights_brightness_tolerance) > &&
- {if}
- 0 (S.L.ai_ovh_lights_on)
- 0 (S.L.ai_ovh_lights_off_timer)
- {endif}
- 0 (S.L.ai_ovh_lights_on_timer)
- {endif}
- {else}
- (L.L.ai_ovh_lighting_profile) 4 =
- {if}
- (L.S.SunAlt) 3 <
- {if}
- ' too dark; turn lights on
- (L.L.ai_ovh_lights_on) ! (L.L.ai_ovh_lights_on_timer) (L.S.timegap) + (S.L.ai_ovh_lights_on_timer) (L.L.ai_ovh_lights_darkness_tolerance) > &&
- {if}
- 1 (S.L.ai_ovh_lights_on)
- 0 (S.L.ai_ovh_lights_on_timer)
- {endif}
- 0 (S.L.ai_ovh_lights_off_timer)
- {else}
- ' too bright; turn lights off
- (L.L.ai_ovh_lights_on) (L.L.ai_ovh_lights_off_timer) (L.S.timegap) + (S.L.ai_ovh_lights_off_timer) (L.L.ai_ovh_lights_brightness_tolerance) > &&
- {if}
- 0 (S.L.ai_ovh_lights_on)
- 0 (S.L.ai_ovh_lights_off_timer)
- {endif}
- 0 (S.L.ai_ovh_lights_on_timer)
- {endif}
- {endif}
- {endif}
- {endif}
- ' repetition threshold not yet reached, but tolerance timers have to be increased nonetheless
- {else}
- (L.L.ai_ovh_lights_on_timer) s5
- {if}
- l5 (L.S.timegap) + (S.L.ai_ovh_lights_on_timer)
- {else}
- (L.L.ai_ovh_lights_off_timer) s5
- {if}
- l5 (L.S.timegap) + (S.L.ai_ovh_lights_off_timer)
- {endif}
- {endif}
- {endif}
- {endif}
- {endif}
- {endif}
1.2. Open <OMSI>\Scripts\AI_Cars\lights_varlist.txt and add the following to it:
1.3. Create and open <OMSI>\Scripts\AI_Cars\lights_constfile.txt and paste the following into it:
- ################################
- # Global AI lighting constants #
- ################################
- # Enables / Disables enhanced AI lighting
- ################################
- allowed values: 0 _or_ 1
- if 1, OMSI is to control AI-controlled vehicles' lighting behaviour as usual.
- otherwise, main_AI_<XXX>.osc will influence lighting behaviour.
- [const]
- AI_LIGHTING_IS_OMSI_CONTROLLED
- 0
- ### Lighting profiles
- ### profile #3 is assigned by default if none of the remaining 3 is chosen randomly
- ################################
- # AI lighting profile #1 assignment chance
- ################################
- allowed values: integer > 3
- represents the probability of an AI-controlled vehicle always (i.e., unconditionally) having its lights turned on.
- the higher the value, the lower the probability.
- [const]
- AI_LIGHTING_PROFILE_1_CHANCE
- 10
- # AI lighting profile #2 assignment chance
- ################################
- allowed values: integer > 3
- represents the probability of an AI-controlled vehicle having its lights turned on if the environment is slightly dark;
- for example if the sky is a little bit clouded, or the time of the day is between early dusk and late dawn.
- the higher the value, the lower the probability.
- [const]
- AI_LIGHTING_PROFILE_2_CHANCE
- 5
- # AI lighting profile #4 assignment chance
- ################################
- allowed values: integer > 3
- represents the probability of an AI-controlled vehicle having its lights turned on _only_ at night.
- the higher the value, the lower the probability.
- [const]
- AI_LIGHTING_PROFILE_4_CHANCE
- 20
- # AI maximum darkness tolerance
- ################################
- allowed values: integer >= 0
- defines the maximum time (in seconds) for which an AI-controlled vehicle using a lighting profile _other than_ 1
- will "tolerate" too _dark_ conditions, i.e., without reacting during that time by turning its lights _on_.
- the actual value is chosen randomly for each vehicle, within the range [10, c], where c is this constant.
- for example, if you enter 10 here, the vehicle will react to darkness after _at most_* 20 seconds.
- * in practice it will take a bit longer, as light adjustment conditions are not evaluated during every single frame.
- [const]
- AI_MAX_DARKNESS_TOLERANCE
- 300
- # AI maximum darkness tolerance
- ################################
- allowed values: integer >= 0
- defines the maximum time (in seconds) for which an AI-controlled vehicle using a lighting profile _other than_ 1
- will "tolerate" too bright conditions, i.e., without reacting during that time by turning its lights _off_.
- the actual value is chosen randomly for each vehicle, within the range [60, c], where c is this constant.
- for example, if you enter 10 here, the vehicle will react to brightness after _at most_* 1 minute and 10 seconds.
- * in practice it will take a bit longer, as light adjustment conditions are not evaluated during every single frame.
- [const]
- AI_MAX_BRIGHTNESS_TOLERANCE
- 900
1.4. Find and open the XXX.ovh or XXX.bus file of the vehicle you are modifying. Include the path to the newly-created file (step 1.3.) in the vehicle's list of constant file declarations. As an example, consider the Citroen BX (<OMSI>\Vehicles\Citr_BX\BX.ovh), whose constant file declarations section is by default as follows:
You would in the particular case modify the above section like so:
1.5. Find and open the XXXmodelXXX.cfg of the vehicle you are modifying. In the file, search and replace all occurrences of AI_Light with ai_ovh_lights_on. Such instances are usually (but not necessarily) found within [light_enh_2] declaration blocks.
2. Modification installation for (semi-)self-sufficient vehicles (category #2)
2.1. Repeat steps 1.1. and/or 1.2. from above, editing the corresponding files, respectively, whichever those might be. You will find the path(s) listed within the vehicle's XXX.ovh or XXX.bus file.
2.2. Repeat steps 1.3. to 1.5. as above.
3. Modification installation for emergency vehicles (category #3)
3.1. Open <OMSI>\Scripts\AI_Cars\main_AI_police.osc if the common script is being reused, or the vehicle-specific main script otherwise. Add the following to its {init} block:
3.2. If the vehicle declares its own variable declaration file (XXXvarlistXXX.txt), open it and insert the name of the newly-added variable into it:
3.3. Repeat steps 1.4. and 1.5. as above.
Discussion
The additions to the main script serve to carry out two simple tasks.
The first -performed by the section added to the {init} block- is to assign a so-called "lighting profile" to the vehicle, upon its creation. Based on the profile, the vehicle is configured to either unconditionally have its headlights on 24/7, or otherwise switch them on and of with a varying degree of "strictness", depending on the environment (brightness / sun elevation angle). Furthermore, if the vehicle is to conditionally use its headlights, two additional attributes are defined for it: a "darkness" and a "lightness" level of "tolerance", which represent the maximum time that must elapse before the vehicle will adjust its headlights' state (off -> on, on -> off, respectively). Some limited control over the choosing of the profile and assignment of the thresholds is provided via the constants file.
The second task is to actually enforce the profile, and is accomplished via the code section having been introduced into the {frame} block of the script. There, if mandated by the profile, the headlights are either switched on once (and for good), or the tolerance thresholds are evaluated and, if having been exceeded, the headlights' state is negated.
Emergency vehicles, finally, always have their headlights switched on, as they usually do in real life too.
Further implementation-related details can be found in the comments included in the script and constants files.
Miscellaneous / F.A.Q.
Q: Newly-spawned vehicles always instantly seem to "adapt" to the environment
A: They indeed do; that is a known limitation. The problem is that OMSI's scripting engine does not support storage of arbitrary "static" (inter-object) state; the script "lives" as long as the corresponding vehicle is spawned, so it simply cannot know what the weather conditions were like prior to its initialization. If you'd like to see how cars / trucks truly adapt, rather than driving around, just block a street with your bus and observe the traffic jam for a few minutes.