--[[ Tronex 2019/10/12 Anomlous Options Menu Features: - %100 customizable, support for all kind of xml elements - Highlight pending changes - Option description support - Option presets support - Reset button to clear pending changes - Script callback on option changes - Functors capability to excute on apply or init - Precoditions capability to hide/show/execute functors To get an option value inside other scripts, use: ui_options.get(parameter) Check the options table here to see the values used See the tutorial at the bottom for adding or modifying options table --]] local enable_debug = false ------------------------------------------------------------ -- Strings and LTX management ------------------------------------------------------------ local ini_pres = ini_file("presets\\includes.ltx") local ini_loc = ini_file_ex("localization.ltx",true) local _opt_ = "/" -- For axr_options.ltx, don't touch! local opt_section = "options" -- For axr_options.ltx, don't touch! local opt_str = "ui_mm_" -- Option name: "ui_mm_(option ID)" -- Option description: "ui_mm_(option ID)_desc" local opt_str_menu = "ui_mm_menu_" -- Option menu: "ui_mm_menu_(option menu ID)" local opt_str_prst = "ui_mm_prst_" -- Option preset: "ui_mm_prst_(option preset ID)" local opt_str_lst = "ui_mm_lst_" -- List/Radio keys: "ui_mm_lst_(key)" function cc(path,opt) return (path .. _opt_ .. opt) end ------------------------------------------------------------ -- Utilities ------------------------------------------------------------ local m_floor, m_ceil, s_find, s_gsub = math.floor, math.ceil, string.find, string.gsub local clr, clamp, round_idp, str_explode = utils_xml.get_color, clamp, round_idp, str_explode local precision = 6 -- allowed number of zeros local width_factor = utils_xml.is_widescreen() and 0.8 or 1 local clr_o = GetARGB(255, 250, 150, 75) local clr_g1 = GetARGB(255, 170, 170, 170) local clr_g2 = GetARGB(255, 200, 200, 200) local clr_w = GetARGB(255, 255, 255, 255) local clr_tree = { [1] = GetARGB(255, 180, 180, 180), [2] = GetARGB(255, 180, 180, 180), [3] = GetARGB(255, 180, 180, 180), } function print_dbg(...) if enable_debug then printf(...) end end ------------------------------------------------------------ -- Options ------------------------------------------------------------ options = {} local opt_temp = {} -- stores pending changes local opt_backup = {} -- do a backup of original changes for comparison with pendings local opt_index = {} -- option index by path, so we can locate an option fast without iterating throw the whole options table local opt_val = {} -- option value type by path, to execute proper functions on different type without iterating throw the whole options table local allowed_type = { -- ignore tables from these types in temp tables ["check"] = true, ["list"] = true, ["input"] = true, ["radio_h"] = true, ["radio_v"] = true, ["track"] = true, } function init_opt_base() options = { { id= "video" ,gr={ { id= "basic" ,sh=true ,gr={ { id= "slide_vid" ,type= "slide" ,link= "ui_options_slider_video" ,text= "ui_mm_title_video_basic" ,size= {512,50} }, { id= "renderer" ,type= "list" ,val= 0 ,cmd= "renderer" ,curr= {curr_renderer} ,content= {cont_renderer} ,restart= true ,vid= true }, -- { id= "preset" ,type= "list" ,val= 0 ,cmd= "_preset" ,content= {{"Minimum","pres_minimum"} , {"Low","pres_low"} , {"Default","pres_default"} , {"High","pres_high"} , {"Extreme","pres_extreme"}} ,restart= true}, { id= "resolution" ,type= "list" ,val= 0 ,cmd= "vid_mode" ,content= {cont_vid_mode} ,no_str= true ,restart= true ,vid= true }, { id= "gamma" ,type= "track" ,val= 2 ,cmd= "rs_c_gamma" ,min= 0.5 ,max= 1.5 ,step= 0.1 ,precondition= {for_renderer,"renderer_r1"} }, { id= "contrast" ,type= "track" ,val= 2 ,cmd= "rs_c_contrast" ,min= 0.5 ,max= 1.5 ,step= 0.1 ,precondition= {for_renderer,"renderer_r1"} }, { id= "brightness" ,type= "track" ,val= 2 ,cmd= "rs_c_brightness" ,min= 0.5 ,max= 1.5 ,step= 0.1 ,precondition= {for_renderer,"renderer_r1"} }, { id= "fov" ,type= "track" ,val= 2 ,cmd= "fov" ,min= 5 ,max= 180 ,step= 1 }, { id= "hud_fov" ,type= "track" ,val= 2 ,cmd= "hud_fov" ,min= 0.1 ,max= 1 ,step= 0.01 }, { id= "screen_mode" ,type= "radio_h" ,val= 2 ,curr= {curr_screen_mode} ,content= {{1,"fullscreen"} , {2,"borderless"} , {3,"windowed"}} ,functor = {func_screen_mode} }, { id= "lighting" ,type= "button" ,functor_ui= {start_lighting_ui} ,precondition= {level_present} ,precondition_1= {for_renderer,"renderer_r2a","renderer_r2","renderer_r2.5","renderer_r3","renderer_r4"} }, },}, { id= "advanced" ,presets= {"video_extreme","video_high","video_default","video_low","video_minimum"} ,sh=true ,gr={ { id= "slide_vid_adv" ,type= "slide" ,link= "ui_options_slider_video_advanced" ,text= "ui_mm_title_video_advanced" ,size= {512,50} }, { id= "ai_torch" ,type= "check" ,val= 1 ,cmd= "ai_use_torch_dynamic_lights" }, { id= "v_sync" ,type= "check" ,val= 1 ,cmd= "rs_v_sync" }, { id= "framelimit" ,type= "track" ,val= 2 ,cmd= "r__framelimit" ,min= 0 ,max= 500 ,step= 2 }, { id= "line" ,type= "line" }, { id= "title" ,type= "title" ,text= "ui_mm_header_rendering_dist" ,align= "l" ,clr= {255,200,200,200} }, { id= "vis_distance" ,type= "track" ,val= 2 ,cmd= "rs_vis_distance" ,min= 0.4 ,max= 1.5 ,step= 0.1 ,no_str= true }, { id= "optimize_static_geom" ,type= "track" ,val= 2 ,cmd= "r__optimize_static_geom" ,min= 0 ,max= 4 ,step= 1 ,no_str= true ,invert= true }, { id= "optimize_dynamic_geom" ,type= "track" ,val= 2 ,cmd= "r__optimize_dynamic_geom" ,min= 0 ,max= 4 ,step= 1 ,no_str= true ,invert= true }, { id= "optimize_shadow_geom" ,type= "check" ,val= 1 ,cmd= "r__optimize_shadow_geom" }, { id= "line" ,type= "line" }, { id= "title" ,type= "title" ,text= "ui_mm_header_rendering_quality" ,align= "l" ,clr= {255,200,200,200} }, { id= "texture_lod" ,type= "track" ,val= 2 ,cmd= "texture_lod" ,min= 0 ,max= 4 ,step= 1 ,no_str= true ,invert= true ,vid= true ,restart= true }, { id= "geometry_lod" ,type= "track" ,val= 2 ,cmd= "r__geometry_lod" ,min= 0.1 ,max= 1.5 ,step= 0.1 }, { id= "mipbias" ,type= "track" ,val= 2 ,cmd= "r__tf_mipbias" ,min= -0.5 ,max= 0.5 ,step= 0.1 ,no_str= true ,invert= true }, { id= "tf_aniso" ,type= "list" ,val= 0 ,cmd= "r__tf_aniso" ,content={ {"0","0"},{"4","4"},{"8","8"},{"16","16"} } ,vid= true, no_str= true }, { id= "ssample" ,type= "track" ,val= 2 ,cmd= "r__supersample" ,min= 1 ,max= 8 ,step= 1 ,vid= true ,precondition= {for_renderer,"renderer_r1","renderer_r2a","renderer_r2","renderer_r2.5"} }, { id= "ssample_list" ,type= "list" ,val= 0 ,cmd= "r3_msaa" ,content={ {"st_opt_off","st_opt_off"},{"2x","x2"},{"4x","x4"},{"8x","x8"} } ,vid= true ,precondition= {for_renderer,"renderer_r3","renderer_r4"} , no_str= true }, { id= "smaa" ,type= "list" ,val= 0 ,cmd= "r2_smaa" ,content={ {"off","st_opt_off"},{"low","st_opt_low"},{"medium","st_opt_medium"},{"high","st_opt_high"},{"ultra","st_opt_ultra"} } ,precondition= {for_renderer,"renderer_r2a","renderer_r2","renderer_r2.5","renderer_r3","renderer_r4"}, no_str= true }, { id= "detail_textures" ,type= "check" ,val= 1 ,cmd= "r1_detail_textures" ,vid= true ,precondition= {for_renderer,"renderer_r1"} }, { id= "detail_bump" ,type= "check" ,val= 1 ,cmd= "r2_detail_bump" ,vid= true ,precondition= {for_renderer,"renderer_r2","renderer_r2.5","renderer_r3","renderer_r4"} }, { id= "steep_parallax" ,type= "check" ,val= 1 ,cmd= "r2_steep_parallax" ,vid= true ,precondition= {for_renderer,"renderer_r2.5","renderer_r3","renderer_r4"} }, { id= "enable_tessellation" ,type= "check" ,val= 1 ,cmd= "r4_enable_tessellation" ,vid= true ,precondition= {for_renderer,"renderer_r4"} }, { id= "line" ,type= "line" }, { id= "title" ,type= "title" ,text= "ui_mm_header_grass" ,align= "l" ,clr= {255,200,200,200} }, { id= "detail_density" ,type= "track" ,val= 2 ,cmd= "r__detail_density" ,min= 0.04 ,max= 1 ,step= 0.02 ,prec = 2 ,invert= true ,vid= true ,restart= true ,no_str= true }, { id= "detail_radius" ,type= "track" ,val= 2 ,cmd= "r__detail_radius" ,min= 50 ,max= 250 ,step= 20 ,restart= true ,vid= true }, { id= "detail_height" ,type= "track" ,val= 2 ,cmd= "r__detail_height" ,min= 0.5 ,max= 2 ,step= 0.1 ,restart= true ,vid= true }, { id= "grass_shadow" ,type= "check" ,val= 1 ,cmd= "r__enable_grass_shadow" ,vid= true ,precondition= {for_renderer,"renderer_r2","renderer_r2.5","renderer_r3","renderer_r4"} }, { id= "line" ,type= "line" ,precondition= {for_renderer,"renderer_r2a","renderer_r2","renderer_r2.5","renderer_r3","renderer_r4"} }, { id= "title" ,type= "title" ,text= "ui_mm_header_lighting" ,align= "l" ,clr= {255,200,200,200} ,precondition= {for_renderer,"renderer_r2a","renderer_r2","renderer_r2.5","renderer_r3","renderer_r4"}}, { id= "slight_fade" ,type= "track" ,val= 2 ,cmd= "r2_slight_fade" ,min= 0.2 ,max= 1 ,step= 0.1 ,vid= true ,precondition= {for_renderer,"renderer_r2a","renderer_r2","renderer_r2.5","renderer_r3","renderer_r4"} }, { id= "ls_squality" ,type= "track" ,val= 2 ,cmd= "r2_ls_squality" ,min= 0.5 ,max= 1 ,step= 0.5 ,vid= true ,precondition= {for_renderer,"renderer_r2a","renderer_r2","renderer_r2.5","renderer_r3","renderer_r4"} }, { id= "actor_shadow" ,type= "check" ,val= 1 ,cmd= "r__actor_shadow" ,precondition= {for_renderer,"renderer_r2","renderer_r2.5","renderer_r3","renderer_r4"} }, { id= "gloss_factor" ,type= "track" ,val= 2 ,cmd= "r2_gloss_factor" ,min= 0 ,max= 10 ,step= 0.5 ,precondition= {for_renderer,"renderer_r2a","renderer_r2","renderer_r2.5","renderer_r3","renderer_r4"} }, { id= "sun" ,type= "check" ,val= 1 ,cmd= "r2_sun" ,vid= true ,precondition= {for_renderer,"renderer_r2","renderer_r2.5","renderer_r3","renderer_r4"} }, { id= "sun_quality" ,type= "list" ,val= 0 ,cmd= "r2_sun_quality" ,content={cont_sun_quality} ,vid= true ,precondition= {for_renderer,"renderer_r2.5","renderer_r3","renderer_r4"} }, -- { id= "sun_details" ,type= "check" ,val= 1 ,cmd= "r2_sun_details" ,vid= true ,precondition= {for_renderer,"renderer_r2","renderer_r2.5","renderer_r3","renderer_r4"} }, { id= "sunshafts_mode" ,type= "radio_v" ,val= 0 ,cmd= "r2_sunshafts_mode" ,content={ {"off"},{"volumetric"},{"screen_space"},{"combined"} } ,vid= true ,precondition= {for_renderer,"renderer_r2.5","renderer_r3","renderer_r4"} }, { id= "sunshafts_quality" ,type= "list" ,val= 0 ,cmd= "r2_sunshafts_quality" ,content={ {"st_opt_low","low"},{"st_opt_medium","medium"},{"st_opt_high","high"} } ,vid= true ,precondition= {for_renderer,"renderer_r2.5","renderer_r3","renderer_r4"} }, { id= "sunshafts_value" ,type= "track" ,val= 2 ,cmd= "r2_sunshafts_value" ,min= 0.5 ,max= 2 ,step= 0.1 ,vid= true ,precondition= {for_renderer,"renderer_r2.5","renderer_r3","renderer_r4"} }, { id= "sunshafts_min" ,type= "track" ,val= 2 ,cmd= "r2_sunshafts_min" ,min= 0 ,max= 0.5 ,step= 0.05 ,vid= true ,precondition= {for_renderer,"renderer_r2.5","renderer_r3","renderer_r4"} }, { id= "ssao_mode" ,type= "radio_v" ,val= 0 ,cmd= "r2_ssao_mode" ,content={ {"disabled","st_opt_off"},{"default","SSDO"},{"hbao","HBAO"},{"hdao","HDAO"}} ,vid= true , no_str = true ,restart= true ,precondition= {for_renderer,"renderer_r2.5","renderer_r3","renderer_r4"} }, { id= "ssao" ,type= "list" ,val= 0 ,cmd= "r2_ssao" ,content={ {"st_opt_off","off"},{"st_opt_low","low"},{"st_opt_medium","medium"},{"st_opt_high","high"} } ,vid= true ,restart= true ,precondition= {for_renderer,"renderer_r2.5","renderer_r3","renderer_r4"} }, { id= "volumetric_lights" ,type= "check" ,val= 1 ,cmd= "r2_volumetric_lights" ,vid= true ,precondition= {for_renderer,"renderer_r2.5","renderer_r3","renderer_r4"} }, { id= "line" ,type= "line" ,precondition= {for_renderer,"renderer_r2.5","renderer_r3","renderer_r4"}}, { id= "title" ,type= "title" ,text= "ui_mm_header_effects" ,align= "l" ,clr= {255,200,200,200} ,precondition= {for_renderer,"renderer_r2.5","renderer_r3","renderer_r4"}}, { id= "soft_water" ,type= "check" ,val= 1 ,cmd= "r2_soft_water" ,vid= true ,precondition= {for_renderer,"renderer_r2.5","renderer_r3","renderer_r4"} }, { id= "soft_particles" ,type= "check" ,val= 1 ,cmd= "r2_soft_particles" ,vid= true ,precondition= {for_renderer,"renderer_r2.5","renderer_r3","renderer_r4"} }, { id= "dof_enable" ,type= "check" ,val= 1 ,cmd= "r2_dof_enable" ,precondition= {for_renderer,"renderer_r2.5","renderer_r3","renderer_r4"} }, { id= "mblur_enable" ,type= "check" ,val= 1 ,cmd= "r2_mblur_enabled" ,vid= true ,precondition= {for_renderer,"renderer_r2.5","renderer_r3","renderer_r4"} }, { id= "mblur" ,type= "track" ,val= 2 ,def= 0.4 ,cmd= "r2_mblur" ,min= 0 ,max= 1 ,step= 0.05 ,precondition= {for_renderer,"renderer_r2.5","renderer_r3","renderer_r4"} }, { id= "dynamic_wet_surfaces" ,type= "check" ,val= 1 ,cmd= "r3_dynamic_wet_surfaces" ,vid= true ,precondition= {for_renderer,"renderer_r3","renderer_r4"} }, { id= "volumetric_smoke" ,type= "check" ,val= 1 ,cmd= "r3_volumetric_smoke" ,vid= true ,precondition= {for_renderer,"renderer_r3","renderer_r4"} }, -- { id= "msaa_alphatest" ,type= "list" ,val= 0 ,cmd= "r3_msaa_alphatest" ,content={ {"st_opt_off","off"},{"st_atest_msaa_dx10_0","atest_msaa_dx10_0"},{"st_atest_msaa_dx10_1","atest_msaa_dx10_1"} } ,vid= true ,precondition= {for_renderer,"renderer_r3","renderer_r4"} }, -- { id= "msaa_opt" ,type= "check" ,val= 1 ,cmd= "r3_msaa_opt" ,vid= true ,precondition= {for_renderer,"renderer_r3","renderer_r4"} }, },}, { id= "hud" ,sh=true ,gr={ { id= "slide_hud" ,type= "slide" ,link= "ui_options_slider_hud" ,text= "ui_mm_title_hud" ,size= {512,50} ,spacing= 20 }, { id= "show_crosshair" ,type= "check" ,val= 1 ,def= false ,cmd= "hud_crosshair" }, { id= "crosshair_dist" ,type= "check" ,val= 1 ,def= false ,cmd= "hud_crosshair_dist" }, { id= "crosshair_clr_a" ,type= "track" ,val= 2 ,min= 0 ,max= 255 ,step= 1 ,curr= {curr_crosshair_clr,"a"} ,functor= {func_crosshair_clr,"a"} }, { id= "crosshair_clr_r" ,type= "track" ,val= 2 ,min= 0 ,max= 255 ,step= 1 ,curr= {curr_crosshair_clr,"r"} ,functor= {func_crosshair_clr,"r"} }, { id= "crosshair_clr_g" ,type= "track" ,val= 2 ,min= 0 ,max= 255 ,step= 1 ,curr= {curr_crosshair_clr,"g"} ,functor= {func_crosshair_clr,"g"} }, { id= "crosshair_clr_b" ,type= "track" ,val= 2 ,min= 0 ,max= 255 ,step= 1 ,curr= {curr_crosshair_clr,"b"} ,functor= {func_crosshair_clr,"b"} }, { id= "line" ,type= "line" }, { id= "show_hud" ,type= "check" ,val= 1 ,def= true ,cmd= "hud_draw" }, -- { id= "dynamic_crosshair" ,type= "check" ,val= 1 ,def= false ,cmd= "cl_dynamiccrosshair" }, { id= "show_slots" ,type= "check" ,val= 1 ,def= true ,functor= {func_slot_hud} }, { id= "show_wpn" ,type= "check" ,val= 1 ,def= true ,cmd= "hud_weapon" }, { id= "show_tracers" ,type= "check" ,val= 1 ,def= true ,cmd= "g_use_tracers" }, { id= "show_minimap" ,type= "check" ,val= 1 ,def= false ,functor= {func_hud_minimap} }, { id= "show_enemy_health" ,type= "check" ,val= 1 ,def= false }, { id= "show_identity" ,type= "check" ,val= 1 ,def= false ,cmd= "hud_info" }, { id= "autohide_stamina_bar" ,type= "check" ,val= 1 ,def= true ,functor= {func_hud_autohide_bar} }, { id= "3d_pda" ,type= "check" ,val= 1 ,def= true ,cmd= "g_3d_pda" }, { id= "ironsights_zoom_factor" ,type= "track" ,val= 2 ,min= 1 ,max= 2 ,step= 0.1 ,cmd= "g_ironsights_zoom_factor" }, { id= "head_bob_factor" ,type= "track" ,val= 2 ,min= 0 ,max= 2 ,step= 0.1 ,cmd= "head_bob_factor" }, },}, { id= "player" ,sh=true ,gr={ { id= "slide_player" ,type= "slide" ,link= "ui_options_slider_player" ,text= "ui_mm_title_effects" ,size= {512,50} }, { id= "animations" ,type= "check" ,val= 1 ,def= true }, { id= "item_swap_animation" ,type= "check" ,val= 1 ,def= true }, { id= "shoot_effects" ,type= "check" ,val= 1 ,def= false }, { id= "radiation_effect" ,type= "check" ,val= 1 ,def= true }, { id= "blood_splash" ,type= "check" ,val= 1 ,def= false }, { id= "bleed_effect" ,type= "check" ,val= 1 ,def= true }, --{ id="tiny_pfx" ,type= "check" ,val= 1 ,def= true }, { id= "slide_mask" ,type= "slide" ,link= "ui_options_slider_mask" ,text= "ui_mm_title_mask" ,size= {512,50} ,spacing= 20 }, { id= "mask_hud" ,type= "check" ,val= 1 ,def= true }, { id= "breathing_fog" ,type= "check" ,val= 1 ,def= true }, { id= "rain_droplets" ,type= "check" ,val= 1 ,def= true }, { id= "visor_reflection" ,type= "check" ,val= 1 ,def= true }, },}, { id= "weather" ,sh=true ,gr={ { id= "clear_slide" ,type= "slide" ,link= "ui_options_slider_weather_clear" ,text= "st_wthr_clear" ,size= {512,50} }, { id= "clear_period" ,type= "radio_h" ,val= 2 ,def= random_choice(4,6) ,content={ {3,"3h"},{4,"4h"},{5,"5h"},{6,"6h"},{7,"7h"},{8,"8h"},{9,"9h"},{10,"10h"},{11,"11h"},{12,"12h"} } ,hint= "video_weather_period" ,force_horz = true }, { id= "clear_occurrence" ,type= "radio_v" ,val= 2 ,def= random_choice(2,3) ,content={ {1,"none"},{2,"rare"},{3,"regular"} } ,hint= "video_weather_occurrence" }, { id= "partly_slide" ,type= "slide" ,link= "ui_options_slider_weather_partly" ,text= "st_wthr_partly" ,size= {512,50} }, { id= "partly_period" ,type= "radio_h" ,val= 2 ,def= random_choice(4,6) ,content={ {3,"3h"},{4,"4h"},{5,"5h"},{6,"6h"},{7,"7h"},{8,"8h"},{9,"9h"},{10,"10h"},{11,"11h"},{12,"12h"} } ,hint= "video_weather_period" ,force_horz = true }, { id= "partly_occurrence" ,type= "radio_v" ,val= 2 ,def= random_choice(2,3) ,content={ {1,"none"},{2,"rare"},{3,"regular"} } ,hint= "video_weather_occurrence" }, { id= "cloudy_slide" ,type= "slide" ,link= "ui_options_slider_weather_cloudy" ,text= "st_wthr_cloudy" ,size= {512,50} }, { id= "cloudy_period" ,type= "radio_h" ,val= 2 ,def= random_choice(4,6) ,content={ {3,"3h"},{4,"4h"},{5,"5h"},{6,"6h"},{7,"7h"},{8,"8h"},{9,"9h"},{10,"10h"},{11,"11h"},{12,"12h"} } ,hint= "video_weather_period" ,force_horz = true }, { id= "cloudy_occurrence" ,type= "radio_v" ,val= 2 ,def= random_choice(2,3) ,content={ {1,"none"},{2,"rare"},{3,"regular"} } ,hint= "video_weather_occurrence" }, { id= "rain_slide" ,type= "slide" ,link= "ui_options_slider_weather_rain" ,text= "st_wthr_rain" ,size= {512,50} }, { id= "rain_period" ,type= "radio_h" ,val= 2 ,def= random_choice(4,6) ,content={ {3,"3h"},{4,"4h"},{5,"5h"},{6,"6h"},{7,"7h"},{8,"8h"},{9,"9h"},{10,"10h"},{11,"11h"},{12,"12h"} } ,hint= "video_weather_period" ,force_horz = true }, { id= "rain_occurrence" ,type= "radio_v" ,val= 2 ,def= random_choice(2,3) ,content={ {1,"none"},{2,"rare"},{3,"regular"} } ,hint= "video_weather_occurrence" }, { id= "storm_slide" ,type= "slide" ,link= "ui_options_slider_weather_storm" ,text= "st_wthr_storm" ,size= {512,50} }, { id= "storm_period" ,type= "radio_h" ,val= 2 ,def= random_choice(4,6) ,content={ {3,"3h"},{4,"4h"},{5,"5h"},{6,"6h"},{7,"7h"},{8,"8h"},{9,"9h"},{10,"10h"},{11,"11h"},{12,"12h"} } ,hint= "video_weather_period" ,force_horz = true }, { id= "storm_occurrence" ,type= "radio_v" ,val= 2 ,def= random_choice(2,3) ,content={ {1,"none"},{2,"rare"},{3,"regular"} } ,hint= "video_weather_occurrence" }, { id= "foggy_slide" ,type= "slide" ,link= "ui_options_slider_weather_foggy" ,text= "st_wthr_foggy" ,size= {512,50} }, { id= "foggy_period" ,type= "radio_h" ,val= 2 ,def= random_choice(4,6) ,content={ {3,"3h"},{4,"4h"},{5,"5h"},{6,"6h"},{7,"7h"},{8,"8h"},{9,"9h"},{10,"10h"},{11,"11h"},{12,"12h"} } ,hint= "video_weather_period" ,force_horz = true }, { id= "foggy_occurrence" ,type= "radio_v" ,val= 2 ,def= random_choice(2,3) ,content={ {1,"none"},{2,"rare"},{3,"regular"} } ,hint= "video_weather_occurrence" }, },}, { id= "night" ,sh=true ,gr={ { id= "slide_night" ,type= "slide" ,link= "ui_options_slider_night" ,text= "ui_mm_title_night" ,size= {512,50} }, { id= "brightness" ,type= "list" ,val= 0 ,def= "slight" ,content= {{"dark","dark_night"} , {"slight","slight_night"} , {"medium","medium_night"} , {"bright","bright_night"}} }, { id= "moon_cycle" ,type= "radio_h" ,val= 2 ,def= 8 ,content= {{8,"8days"} , {28,"28days"}} }, { id= "moon_phase_state" ,type= "check" ,val= 1 ,def= false }, { id= "moon_phase" ,type= "radio_v" ,val= 2 ,def= 8 ,content= {{0,"moon_phase_0"} , {1,"moon_phase_1"} , {2,"moon_phase_2"} , {3,"moon_phase_3"} , {4,"moon_phase_4"} , {5,"moon_phase_5"} , {6,"moon_phase_6"} , {7,"moon_phase_7"}} }, },}, },}, { id= "sound" ,gr={ { id= "general" ,sh=true ,gr={ { id= "slide_sound" ,type= "slide" ,link= "ui_options_slider_sound" ,text= "ui_mm_title_sound" ,size= {512,50} }, { id= "master_volume" ,type= "track" ,val= 2 ,cmd= "snd_volume_eff" ,min= 0 ,max= 1 ,step= 0.1 }, { id= "music_volume" ,type= "track" ,val= 2 ,cmd= "snd_volume_music" ,min= 0 ,max= 1 ,step= 0.1 }, { id= "sound_device" ,type= "list" ,val= 0 ,cmd= "snd_device" ,no_str= true ,restart= true }, { id= "eax" ,type= "check" ,val= 1 ,cmd= "snd_efx" }, { id= "dynamic_music" ,type= "check" ,val= 1 ,cmd= "g_dynamic_music" }, { id= "caption" ,type= "radio_v" ,val= 0 ,def= "none" ,content={ {"none"},{"storyonly"},{"all"} } }, },}, { id= "environment" ,sh=true ,gr={ { id= "slide_sound" ,type= "slide" ,link= "ui_options_slider_sound_environment" ,text= "ui_mm_title_sound_environment" ,size= {512,50} }, { id= "ambient_volume" ,type= "track" ,val= 2 ,def= 1 ,min= 0 ,max= 1 ,step= 0.1 }, { id= "wind_sound" ,type= "check" ,val= 1 ,def= true }, { id= "breathing_sound" ,type= "check" ,val= 1 ,def= true }, { id= "helmet_rain_sound" ,type= "check" ,val= 1 ,def= true }, },}, { id= "radio" ,sh=true ,gr={ { id= "slide_radio" ,type= "slide" ,link= "ui_options_slider_radio" ,text= "ui_mm_title_sound_radio" ,size= {512,50} }, { id= "zone" ,type= "check" ,val= 1 ,def= true }, { id= "emission_intereferences" ,type= "check" ,val= 1 ,def= true }, { id= "underground_intereferences" ,type= "check" ,val= 1 ,def= true }, { id= "display_tracks" ,type= "check" ,val= 1 ,def= false }, -- playlist names },}, },}, { id= "control" ,gr={ { id= "general" ,sh=true ,gr={ { id= "slide_control" ,type= "slide" ,link= "ui_options_slider_control" ,text= "ui_mm_title_control" ,size= {512,50} }, { id= "mouse_sens" ,type= "track" ,val= 2 ,cmd= "mouse_sens" ,min= 0.001 ,max= 0.6 ,step= 0.01 }, { id= "mouse_sens_aim" ,type= "track" ,val= 2 ,cmd= "mouse_sens_aim" ,min= 0.5 ,max= 2 ,step= 0.05, def= 1 }, { id= "mouse_invert" ,type= "check" ,val= 1 ,cmd= "mouse_invert" ,def= false }, { id= "crouch_toggle" ,type= "check" ,val= 1 ,cmd= "g_crouch_toggle" ,def= false }, { id= "walk_toggle" ,type= "check" ,val= 1 ,cmd= "g_walk_toggle" ,def= false }, { id= "sprint_toggle" ,type= "check" ,val= 1 ,cmd= "g_sprint_toggle" ,def= true }, { id= "lookout_toggle" ,type= "check" ,val= 1 ,cmd= "g_lookout_toggle" ,def= false }, { id= "aim_toggle" ,type= "check" ,val= 1 ,cmd= "wpn_aim_toggle" ,def= false ,bool_to_num= true }, { id= "pickup_mode" ,type= "check" ,val= 1 ,cmd= "g_multi_item_pickup" ,def= true }, { id= "simple_pda_mode" ,type= "check" ,val= 1 ,cmd= "g_simple_pda" ,def= true }, { id= "disassembly_warning" ,type= "check" ,val= 1 ,def= true }, },}, { id= "keybind" ,sh=true ,gr={},}, -- ENGINE! },}, { id= "gameplay" ,gr={ { id= "general" ,sh=true ,gr={ { id= "slide_player" ,type= "slide" ,link= "ui_options_slider_player" ,text= "ui_mm_title_gameplay" ,size= {512,50} }, { id= "player_name" ,type= "input" ,val= 0 ,curr= {curr_player_name} ,functor= {func_player_name} ,precondition= {level_present} }, { id= "outfit_portrait" ,type= "check" ,val= 1 ,def= true }, { id= "hardcore_ai_aim" ,type= "check" ,val= 1 ,def= false ,functor= {func_hardcore_ai_aim} }, { id= "show_tip_reputation" ,type= "check" ,val= 1 ,def= true }, { id= "mechanic_feature" ,type= "check" ,val= 1 ,def= false }, { id= "line" ,type= "line" }, { id= "release_dropped_items" ,type= "check" ,val= 1 ,def= true }, { id= "corpse_max_count" ,type= "track" ,val= 2 ,def= 5 ,min= 5 ,max= 30 ,step= 1 }, { id= "corpse_min_dist" ,type= "track" ,val= 2 ,def= 75 ,min= 75 ,max= 200 ,step= 5 }, { id= "line" ,type= "line" }, { id= "npc_loot_distance" ,type= "track" ,val= 2 ,def= 5 ,min= 0 ,max= 25 ,step= 1 }, { id= "line" ,type= "line" }, { id= "max_tasks" ,type= "track" ,val= 2 , def= 2 ,min= 1 ,max= 10 ,step= 1 }, { id= "line" ,type= "line" }, { id= "need_equipped_hkit" ,type= "check" ,val= 1 ,def= true }, },}, { id= "silent_kills" ,sh=true ,gr={ { id= "sk_desc" ,type= "desc" ,text= "st_sk_desc" ,clr= {255,125,175,200} }, { id= "sk_enabled" ,type= "check" ,val= 1 ,def= false}, { id= "sk_melee_enabled" ,type= "check" ,val= 1 ,def= true}, { id= "sk_all_melee_ok" ,type= "check" ,val= 1 ,def= false}, { id= "sk_gun_enabled" ,type= "check" ,val= 1 ,def= true}, { id= "sk_headshot_only" ,type= "check" ,val= 1 ,def= true}, { id= "sk_fresh_time" ,type= "input" ,val= 0 ,def= 300}, { id= "sk_suspect_dist" ,type= "input" ,val= 0 ,def= 10}, { id= "sk_melee_hear_dist" ,type= "input" ,val= 0 ,def= 5}, { id= "sk_gun_hear_dist" ,type= "input" ,val= 0 ,def= 10}, },}, { id= "economy_diff" ,sh=true ,precondition = {level_present} ,output = "ui_mm_warning_economy_diff_not_level_present" ,presets= {"economy_easy","economy_medium","economy_hard"} ,gr={ { id= "slide_economy_diff" ,type= "slide" ,link= "ui_options_slider_economy_diff" ,text= "ui_mm_title_economy_diff" ,size= {512,50} }, { id= "desc_ingame_only" ,type= "desc" ,text= "ui_mm_desc_economy_diff" ,clr= {255,200,75,75} }, { id= "condition_buy_override" ,type= "track" ,val= 2 , curr = {trader_cond,'get'}, functor= {trader_cond,"set"} ,min= 0 ,max= 100 ,step= 1 }, { id= "goodwill" ,type= "track" ,val= 2 ,curr= {curr_economy,"goodwill"} ,functor= {func_economy_diff,"goodwill"} ,min= 0.5 ,max= 3 ,step= 0.1 }, { id= "rewards" ,type= "track" ,val= 2 ,curr= {curr_economy,"rewards"} ,functor= {func_economy_diff,"rewards"} ,min= 0.5 ,max= 3 ,step= 0.1 }, { id= "repair" ,type= "track" ,val= 2 ,curr= {curr_economy,"repair"} ,functor= {func_economy_diff,"repair"} ,min= 1 ,max= 2 ,step= 0.1 }, { id= "upgrade" ,type= "track" ,val= 2 ,curr= {curr_economy,"upgrade"} ,functor= {func_economy_diff,"upgrade"} ,min= 1 ,max= 3 ,step= 0.1 }, { id= "buy" ,type= "track" ,val= 2 ,curr= {curr_economy,"buy"} ,functor= {func_economy_diff,"buy"} ,min= 0.5 ,max= 2 ,step= 0.1 }, { id= "sell" ,type= "track" ,val= 2 ,curr= {curr_economy,"sell"} ,functor= {func_economy_diff,"sell"} ,min= 0.5 ,max= 2 ,step= 0.1 }, { id= "loots" ,type= "track" ,val= 2 ,curr= {curr_economy,"loots"} ,functor= {func_economy_diff,"loots"} ,min= 0.5 ,max= 3 ,step= 0.1 }, { id= "money_loots" ,type= "track" ,val= 2 ,curr= {curr_economy,"money_loots"} ,functor= {func_economy_diff,"money_loots"} ,min= 0.5 ,max= 3 ,step= 0.1 }, { id= "stash_chance" ,type= "track" ,val= 2 ,curr= {curr_economy,"stash_chance"} ,functor= {func_economy_diff,"stash_chance"} ,min= 0.1 ,max= 1 ,step= 0.05 }, { id= "weapon_degradation" ,type= "track" ,val= 2 ,curr= {curr_economy,"weapon_degradation"} ,functor= {func_economy_diff,"weapon_degradation"} ,min= 0.5 ,max= 1 ,step= 0.05 }, { id= "battery_consumption" ,type= "track" ,val= 2 ,curr= {curr_economy,"battery_consumption"} ,functor= {func_economy_diff,"battery_consumption"} ,min= 0.5 ,max= 3 ,step= 0.1 }, { id= "restock" ,type= "track" ,val= 2 ,curr= {curr_economy,"restock"} ,functor= {func_economy_diff,"restock"} ,min= 12 ,max= 168 ,step= 1 }, { id= "arty_chance" ,type= "track" ,val= 2 ,curr= {curr_economy,"arty_chance"} ,functor= {func_economy_diff,"arty_chance"} ,min= 0.1 ,max= 1 ,step= 0.05 }, { id= "percentage_parts" ,type= "check" ,val= 1 ,curr= {curr_economy,"percentage_parts"} ,functor= {func_economy_diff,"percentage_parts"} }, { id= "limited_bolts" ,type= "check" ,val= 1 ,curr= {curr_economy,"limited_bolts"} ,functor= {func_economy_diff,"limited_bolts"} }, { id= "outfit_drops" ,type= "list" ,val= 2 ,curr= {curr_economy,"outfit_drops"} ,functor= {func_economy_diff,"outfit_drops"} ,content= {{1,"off"} , {2,"progressive"} , {3,"full"}} }, },}, { id= "gameplay_diff" ,sh=true ,precondition = {level_present} ,output = "ui_mm_warning_gameplay_diff_not_level_present" ,presets= {"gameplay_easy","gameplay_medium","gameplay_hard"} ,gr={ { id= "slide_gameplay_diff" ,type= "slide" ,link= "ui_options_slider_gameplay_diff" ,text= "ui_mm_title_gameplay_diff" ,size= {512,50} }, { id= "desc_ingame_only" ,type= "desc" ,text= "ui_mm_desc_gameplay_diff" ,clr= {255,200,75,75} }, { id= "actor_immunities" ,type= "list" ,val= 2 ,curr= {curr_gameplay,"actor_immunities"} ,functor= {func_gameplay_diff,"actor_immunities"} ,content= {{1,"great"} , {2,"good"} , {3,"average"} , {4,"poor"}} }, { id= "hit_power" ,type= "track" ,val= 2 ,curr= {curr_gameplay,"hit_power"} ,functor= {func_gameplay_diff,"hit_power"} ,min= 0.5 ,max= 3 ,step= 0.1 }, { id= "dispersion_base" ,type= "track" ,val= 2 ,curr= {curr_gameplay,"dispersion_base"} ,functor= {func_gameplay_diff,"dispersion_base"} ,min= 1 ,max= 3 ,step= 0.1 }, { id= "dispersion_factor" ,type= "track" ,val= 2 ,curr= {curr_gameplay,"dispersion_factor"} ,functor= {func_gameplay_diff,"dispersion_factor"} ,min= 1 ,max= 5 ,step= 0.1 }, { id= "power_loss_bias" ,type= "track" ,val= 2 ,curr= {curr_gameplay,"power_loss_bias"} ,functor= {func_gameplay_diff,"power_loss_bias"} ,min= 0.0 ,max= 1 ,step= 0.05 }, { id= "weight" ,type= "track" ,val= 2 ,curr= {curr_gameplay,"weight"} ,functor= {func_gameplay_diff,"weight"} ,min= 10 ,max= 50 ,step= 1 }, { id= "thirst" ,type= "check" ,val= 1 ,curr= {curr_gameplay,"thirst"} ,functor= {func_gameplay_diff,"thirst"} }, { id= "sleep" ,type= "check" ,val= 1 ,curr= {curr_gameplay,"sleep"} ,functor= {func_gameplay_diff,"sleep"} }, { id= "radiation_day" ,type= "check" ,val= 1 ,curr= {curr_gameplay,"radiation_day"} ,functor= {func_gameplay_diff,"radiation_day"} }, { id= "notify_geiger" ,type= "check" ,val= 1 ,curr= {curr_gameplay,"notify_geiger"} ,functor= {func_gameplay_diff,"notify_geiger"} }, { id= "notify_anomaly" ,type= "check" ,val= 1 ,curr= {curr_gameplay,"notify_anomaly"} ,functor= {func_gameplay_diff,"notify_anomaly"} }, },}, { id= "disguise" ,sh=true ,gr={ { id= "slide_disguise" ,type= "slide" ,link= "ui_options_slider_disguise" ,text= "ui_mm_menu_disguise" ,size= {512,50} }, { id= "desc_disguise" ,type= "desc" ,text= "ui_mm_desc_disguise" ,clr= {255,125,175,200} }, { id= "line" ,type= "line" }, { id= "state" ,type= "check" ,val= 1 ,def= true }, { id= "line" ,type= "line" }, { id= "active_item" ,type= "check" ,val= 1 ,def= true }, { id= "active_item_factor" ,type= "track" ,val= 2 ,def= 1 ,min= 0.1 ,max= 2 ,step= 0.1 }, { id= "weapon" ,type= "check" ,val= 1 ,def= true }, { id= "weapon_factor" ,type= "track" ,val= 2 ,def= 1 ,min= 0.1 ,max= 2 ,step= 0.1 }, { id= "outfit" ,type= "check" ,val= 1 ,def= true }, { id= "outfit_factor" ,type= "track" ,val= 2 ,def= 1 ,min= 0.1 ,max= 2 ,step= 0.1 }, { id= "helmet" ,type= "check" ,val= 1 ,def= true }, { id= "helmet_factor" ,type= "track" ,val= 2 ,def= 1 ,min= 0.1 ,max= 2 ,step= 0.1 }, { id= "backpack" ,type= "check" ,val= 1 ,def= true }, { id= "backpack_factor" ,type= "track" ,val= 2 ,def= 1 ,min= 0.1 ,max= 2 ,step= 0.1 }, { id= "inventory" ,type= "check" ,val= 1 ,def= true }, { id= "inventory_factor" ,type= "track" ,val= 2 ,def= 1 ,min= 0.1 ,max= 2 ,step= 0.1 }, { id= "line" ,type= "line" }, { id= "speed" ,type= "check" ,val= 1 ,def= true }, { id= "speed_factor" ,type= "track" ,val= 2 ,def= 1 ,min= 0.1 ,max= 2 ,step= 0.1 }, { id= "distance" ,type= "check" ,val= 1 ,def= true }, { id= "distance_factor" ,type= "track" ,val= 2 ,def= 5 ,min= 1 ,max= 100 ,step= 1 }, { id= "stay_time" ,type= "check" ,val= 1 ,def= true }, { id= "stay_time_factor" ,type= "track" ,val= 2 ,def= 20 ,min= 1 ,max= 100 ,step= 1 }, },}, { id= "fast_travel" ,sh=true ,gr={ { id= "slide_fast_travel" ,type= "slide" ,link= "ui_options_slider_fast_travel" ,text= "ui_mm_menu_fast_travel" ,size= {512,50} }, { id= "desc_fast_travel" ,type= "desc" ,text= "ui_mm_desc_fast_travel" ,clr= {255,125,175,200} }, { id= "line" ,type= "line" }, { id= "state" ,type= "list" ,val= 2 ,def= 0 ,content= {{0,"disabled"} , {1,"visit_only"} , {2,"show_all"}} }, { id= "line" ,type= "line" }, { id= "on_combat" ,type= "check" ,val= 1 ,def= false }, { id= "on_overweight" ,type= "check" ,val= 1 ,def= false }, { id= "on_damage" ,type= "check" ,val= 1 ,def= false }, { id= "on_emission" ,type= "check" ,val= 1 ,def= false }, { id= "long_names" ,type= "check" ,val= 1 ,def= false }, { id= "visit_message" ,type= "check" ,val= 1 ,def= false }, { id= "time" ,type= "check" ,val= 1 ,def= false }, },}, { id= "backpack_travel" ,sh=true ,gr={ { id= "slide_backpack_travel" ,type= "slide" ,link= "ui_options_slider_fast_travel" ,text= "ui_mm_menu_backpack_travel" ,size= {512,50} }, { id= "desc_backpack_travel" ,type= "desc" ,text= "ui_mm_desc_backpack_travel" ,clr= {255,125,175,200} }, { id= "line" ,type= "line" }, { id= "state" ,type= "check" ,val= 1 ,def= false }, { id= "line" ,type= "line" }, { id= "on_combat" ,type= "check" ,val= 1 ,def= false }, { id= "on_overweight" ,type= "check" ,val= 1 ,def= false }, { id= "on_damage" ,type= "check" ,val= 1 ,def= false }, { id= "on_emission" ,type= "check" ,val= 1 ,def= false }, { id= "time" ,type= "check" ,val= 1 ,def= false }, },}, },}, { id= "alife" ,gr={ { id= "general" ,sh=true ,gr={ { id= "slide_alife" ,type= "slide" ,link= "ui_options_slider_alife" ,text= "ui_mm_title_alife" ,size= {512,50} }, { id= "alife_mutant_pop" ,type= "list" ,val= 2 ,def= 0.75 ,content= {{0.25} , {0.5} , {0.75} , {1}} ,no_str= true }, { id= "alife_stalker_pop" ,type= "list" ,val= 2 ,def= 0.5 ,content= {{0.25} , {0.5} , {0.75} , {1}} ,no_str= true }, { id= "offline_combat" ,type= "list" ,val= 0 ,def= "full" ,content= {{"full","full"} , {"on_smarts_only","on_smarts_only"}, {"off","off"}} }, { id= "excl_dist" ,type= "list" ,val= 2 ,def= 75 ,content= {{0} , {25} , {50} , {75} , {100}} ,no_str= true }, { id= "dynamic_anomalies" ,type= "check" ,val= 1 ,def= true }, { id= "dynamic_relations" ,type= "check" ,val= 1 ,def= false }, { id= "war_goodwill_reset" ,type= "check" ,val= 1 ,def= false }, { id= "heli_engine_sound" ,type= "check" ,val= 1 ,def= false }, { id= "heli_spawn" ,type= "check" ,val= 1 ,def= false }, },}, { id= "event" ,sh=true ,gr={ { id= "slide_emission" ,type= "slide" ,link= "ui_options_slider_emission" ,text= "ui_mm_title_emission" ,size= {512,50} }, { id= "emission_state" ,type= "check" ,val= 1 ,def= true }, { id= "emission_frequency" ,type= "list" ,val= 2 ,def= 24 ,content= {{12,"every_12h"} , {24,"every_24h"} , {48,"every_2d"} , {96,"every_4d"}} }, { id= "emission_fate" ,type= "list" ,val= 0 ,def= "kill_at_wave" ,content= {{"kill_at_end"} , {"kill_at_wave"} , {"turn_to_zombie"} , {"explode"}} }, { id= "emission_warning" ,type= "list" ,val= 0 ,def= "siren_radio" ,content= {{"siren_radio"} , {"siren"} , {"radio"} , {"no_warning"}} }, { id= "emission_task" ,type= "check" ,val= 1 ,def= true }, { id= "slide_psi_storm" ,type= "slide" ,link= "ui_options_slider_psi_storm" ,text= "ui_mm_title_psi_storm" ,size= {512,50} ,spacing= 20 }, { id= "psi_storm_state" ,type= "check" ,val= 1 ,def= true }, { id= "psi_storm_frequency" ,type= "list" ,val= 2 ,def= 24 ,content= {{12,"every_12h"} , {24,"every_24h"} , {48,"every_2d"} , {96,"every_4d"}} }, { id= "psi_storm_fate" ,type= "list" ,val= 0 ,def= "kill_at_vortex" ,content= {{"kill_at_vortex"} , {"turn_to_zombie"} , {"unhurt"}} }, { id= "psi_storm_warning" ,type= "list" ,val= 0 ,def= "siren" ,content= {{"siren"} , {"no_warning"}} }, { id= "psi_storm_task" ,type= "check" ,val= 1 ,def= true }, },}, { id= "warfare" ,presets= {"warfare_default","warfare_slow","warfare_slower"} ,gr={ { id= "general" ,sh=true ,presets= {"warfare_default","warfare_yoko"} ,gr={ { id= "slide_warfare" ,type= "slide" ,link= "ui_options_slider_warfare" ,text= "ui_mm_title_warfare" ,size= {512,50} }, { id= "all_out_war" ,type= "check" ,val= 1 ,def= false }, { id= "random_starting_locations" ,type= "check" ,val= 1 ,def= false }, { id= "random_starting_character" ,type= "check" ,val= 1 ,def= false }, { id= "random_stalker_chance" ,type= "track" ,val= 2 ,def= 50 ,min= 0 ,max= 100 ,step= 1 }, { id= "random_monster_chance" ,type= "track" ,val= 2 ,def= 50 ,min= 0 ,max= 100 ,step= 1 }, { id= "auto_capture" ,type= "check" ,val= 1 ,def= true }, { id= "auto_capture_max_distance" ,type= "track" ,val= 2 ,def= 50 ,min= 0 ,max= 100 ,step= 1 }, { id= "auto_capture_wait_time" ,type= "track" ,val= 2 ,def= 15 ,min= 0 ,max= 100 ,step= 1 }, { id= "fog_of_war" ,type= "check" ,val= 1 ,def= true }, { id= "fog_of_war_distance" ,type= "track" ,val= 2 ,def= 100 ,min= 0 ,max= 100 ,step= 1 }, { id= "hide_unfriendly_squads" ,type= "check" ,val= 1 ,def= true }, { id= "hide_smarts" ,type= "check" ,val= 1 ,def= false }, { id= "hide_underground_smarts" ,type= "check" ,val= 1 ,def= true }, { id= "enemy_new_game_bonus" ,type= "check" ,val= 1 ,def= false }, { id= "enemy_resource_boost" ,type= "track" ,val= 2 ,def= 0 ,min= 0 ,max= 100 ,step= 1 }, { id= "enemy_base_boost" ,type= "track" ,val= 2 ,def= 0 ,min= 0 ,max= 100 ,step= 1 }, { id= "actor_influence_weight" ,type= "track" ,val= 2 ,def= 250 ,min= 0 ,max= 10000 ,step= 50 }, { id= "novice_squad_price" ,type= "track" ,val= 2 ,def= 1000 ,min= 0 ,max= 100000 ,step= 1000 }, { id= "advanced_squad_price" ,type= "track" ,val= 2 ,def= 10000 ,min= 0 ,max= 100000 ,step= 1000 }, { id= "veteran_squad_price" ,type= "track" ,val= 2 ,def= 50000 ,min= 0 ,max= 100000 ,step= 1000 }, { id= "heli_price" ,type= "track" ,val= 2 ,def= 75000 ,min= 0 ,max= 100000 ,step= 1000 }, { id= "actor_support_enemy_rank_weight" ,type= "track" ,val= 2 ,def= 0 ,min= 0 ,max= 50 ,step= 1 }, { id= "actor_support_reward_money" ,type= "track" ,val= 2 ,def= 500 ,min= 0 ,max= 10000 ,step= 50 }, { id= "actor_support_reward_influence" ,type= "track" ,val= 2 ,def= 0.2 ,min= 0 ,max= 2 ,step= 0.1 }, { id= "monster_max_squads_per_level" ,type= "track" ,val= 2 ,def= 5 ,min= 1 ,max= 200 ,step= 1 }, { id= "monster_min_faction_respawn" ,type= "track" ,val= 2 ,def= 5 ,min= 1 ,max= 200 ,step= 1 }, { id= "monster_max_faction_respawn" ,type= "track" ,val= 2 ,def= 30 ,min= 1 ,max= 200 ,step= 1 }, { id= "zombies_act_as_faction" ,type= "check" ,val= 1 ,def= false }, --{ id= "offline_combat_distance" ,type= "track" ,val= 2 ,def= 100 ,min= 1 ,max= 200 ,step= 1 }, { id= "enable_mutant_offline_combat" ,type= "check" ,val= 1 ,def= true }, { id= "disable_smart_pop_cap" ,type= "check" ,val= 1 ,def= false }, { id= "purge_zone_on_emission" ,type= "check" ,val= 1 ,def= false }, { id= "purge_zone_percentage" ,type= "track" ,val= 2 ,def= 50 ,min= 1 ,max= 100 ,step= 1 }, { id= "debug_logging" ,type= "check" ,val= 1 ,def= false }, },}, { id= "azazel" ,sh=true ,presets= {"warfare_default","warfare_yoko"} ,gr={ { id= "slide_warfare" ,type= "slide" ,link= "ui_options_slider_warfare" ,text= "ui_mm_title_warfare_azazel" ,size= {512,50} }, { id="state" ,type= "check" ,val= 1 ,def= true }, { id="respawn_as_companions" ,type= "check" ,val= 1 ,def= true }, { id="respawn_as_actor_faction" ,type= "check" ,val= 1 ,def= true }, { id="respawn_as_allies" ,type= "check" ,val= 1 ,def= false }, { id="respawn_as_neutrals" ,type= "check" ,val= 1 ,def= false }, { id="respawn_as_enemies" ,type= "check" ,val= 1 ,def= false }, { id="respawn_as_nearest" ,type= "check" ,val= 1 ,def= true }, { id="companion_dist_mult" ,type= "track" ,val= 2 ,def= 1 ,min= 0 ,max= 100 ,step= 1 }, { id="actor_faction_dist_mult" ,type= "track" ,val= 2 ,def= 1 ,min= 0 ,max= 100 ,step= 1 }, { id="friend_dist_mult" ,type= "track" ,val= 2 ,def= 1 ,min= 0 ,max= 100 ,step= 1 }, { id="ally_dist_mult" ,type= "track" ,val= 2 ,def= 1 ,min= 0 ,max= 100 ,step= 1 }, { id="neutral_dist_mult" ,type= "track" ,val= 2 ,def= 1 ,min= 0 ,max= 100 ,step= 1 }, { id="enemy_dist_mult" ,type= "track" ,val= 2 ,def= 1 ,min= 0 ,max= 100 ,step= 1 }, { id="companion_min_respawn_dist" ,type= "track" ,val= 2 ,def= 0 ,min= 0 ,max= 100 ,step= 1 }, { id="companion_max_respawn_dist" ,type= "track" ,val= 2 ,def= 0 ,min= 0 ,max= 100 ,step= 1 }, { id="actor_faction_min_respawn_dist" ,type= "track" ,val= 2 ,def= 0 ,min= 0 ,max= 100 ,step= 1 }, { id="actor_faction_max_respawn_dist" ,type= "track" ,val= 2 ,def= 0 ,min= 0 ,max= 100 ,step= 1 }, { id="ally_min_respawn_dist" ,type= "track" ,val= 2 ,def= 0 ,min= 0 ,max= 100 ,step= 1 }, { id="ally_max_respawn_dist" ,type= "track" ,val= 2 ,def= 0 ,min= 0 ,max= 100 ,step= 1 }, { id="neutral_respawn_min_dist" ,type= "track" ,val= 2 ,def= 0 ,min= 0 ,max= 100 ,step= 1 }, { id="neutral_respawn_max_dist" ,type= "track" ,val= 2 ,def= 0 ,min= 0 ,max= 100 ,step= 1 }, { id="enemy_respawn_min_dist" ,type= "track" ,val= 2 ,def= 0 ,min= 0 ,max= 100 ,step= 1 }, { id="enemy_respawn_max_dist" ,type= "track" ,val= 2 ,def= 0 ,min= 0 ,max= 100 ,step= 1 }, },}, { id= "stalker" ,sh=true ,presets= {"warfare_default","warfare_yoko"}, id_gr= "warfare_faction" ,apply_to_all=true ,gr={ { id= "slide_warfare" ,type= "slide" ,link= "ui_options_slider_warfare" ,text= "ui_mm_title_warfare_faction" ,size= {512,50} }, { id="participate_in_warfare" ,type= "check" ,val= 1 ,def= true ,hint="alife_warfare_faction_participate_in_warfare" }, { id="spawn_on_new_game" ,type= "check" ,val= 1 ,def= true ,hint="alife_warfare_faction_spawn_on_new_game" }, { id="random_spawn_entries" ,type= "track" ,val= 2 ,def= 1 ,min= 0 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_random_spawn_entries" }, { id="linked_level_targeting" ,type= "check" ,val= 1 ,def= true ,hint="alife_warfare_faction_linked_level_targeting" }, { id="ignore_empty_targets" ,type= "check" ,val= 1 ,def= false ,hint="alife_warfare_faction_ignore_empty_targets" }, { id="expansion_aggression" ,type= "track" ,val= 2 ,def= 50 ,min= 0 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_expansion_aggression" }, { id="offline_power_multiplier" ,type= "track" ,val= 2 ,def= 1 ,min= 0 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_offline_power_multiplier" }, { id="night_activity_chance" ,type= "track" ,val= 2 ,def= 50 ,min= 0 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_night_activity_chance" }, { id="keep_last_base" ,type= "check" ,val= 1 ,def= false ,hint="alife_warfare_faction_keep_last_base" }, { id="min_faction_respawn" ,type= "track" ,val= 2 ,def= 15 ,min= 0 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_min_faction_respawn" }, { id="max_faction_respawn" ,type= "track" ,val= 2 ,def= 90 ,min= 0 ,max= 200 ,step= 1 ,hint="alife_warfare_faction_max_faction_respawn" }, { id="min_invasion_size" ,type= "track" ,val= 2 ,def= 1 ,min= 0 ,max= 10 ,step= 0.1 ,hint="alife_warfare_faction_min_invasion_size" }, { id="max_invasion_size" ,type= "track" ,val= 2 ,def= 2.5 ,min= 0 ,max= 10 ,step= 0.1 ,hint="alife_warfare_faction_max_invasion_size" }, { id="min_invasion_depart_time" ,type= "track" ,val= 2 ,def= 5 ,min= 0 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_min_invasion_depart_time" }, { id="max_invasion_depart_time" ,type= "track" ,val= 2 ,def= 30 ,min= 0 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_max_invasion_depart_time" }, { id="min_patrol_time" ,type= "track" ,val= 2 ,def= 60 ,min= 0 ,max= 1000 ,step= 10 ,hint="alife_warfare_faction_min_patrol_time" }, { id="max_patrol_time" ,type= "track" ,val= 2 ,def= 240 ,min= 0 ,max= 1000 ,step= 10 ,hint="alife_warfare_faction_max_patrol_time" }, { id="min_patrol_squads" ,type= "track" ,val= 2 ,def= 1 ,min= 0 ,max= 10 ,step= 1 ,hint="alife_warfare_faction_min_patrol_squads" }, { id="max_patrol_squads" ,type= "track" ,val= 2 ,def= 2 ,min= 0 ,max= 10 ,step= 1 ,hint="alife_warfare_faction_max_patrol_squads" }, { id="patrol_hunt_chance" ,type= "track" ,val= 2 ,def= 50 ,min= 0 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_patrol_hunt_chance" }, { id="min_patrol_rest_time" ,type= "track" ,val= 2 ,def= 60 ,min= 0 ,max= 1000 ,step= 10 ,hint="alife_warfare_faction_min_patrol_rest_time" }, { id="max_patrol_rest_time" ,type= "track" ,val= 2 ,def= 240 ,min= 0 ,max= 1000 ,step= 10 ,hint="alife_warfare_faction_max_patrol_rest_time" }, { id="min_resurgence_wait_time" ,type= "track" ,val= 2 ,def= 30 ,min= 0 ,max= 1000 ,step= 10 ,hint="alife_warfare_faction_min_resurgence_wait_time" }, { id="max_resurgence_wait_time" ,type= "track" ,val= 2 ,def= 120 ,min= 0 ,max= 1000 ,step= 10 ,hint="alife_warfare_faction_max_resurgence_wait_time" }, { id="random_squad_count" ,type= "check" ,val= 1 ,def= false ,hint="alife_warfare_faction_random_squad_count" }, { id="min_random_squad_count" ,type= "track" ,val= 2 ,def= 1 ,min= 0 ,max= 20 ,step= 1 ,hint="alife_warfare_faction_min_random_squad_count" }, { id="max_random_squad_count" ,type= "track" ,val= 2 ,def= 3 ,min= 0 ,max= 20 ,step= 1 ,hint="alife_warfare_faction_max_random_squad_count" }, { id="random_patrols" ,type= "check" ,val= 1 ,def= false ,hint="alife_warfare_faction_random_patrols" }, { id="max_random_patrols" ,type= "track" ,val= 2 ,def= 15 ,min= 0 ,max= 20 ,step= 1 ,hint="alife_warfare_faction_max_random_patrols" }, { id="min_random_patrol_time" ,type= "track" ,val= 2 ,def= 30 ,min= 0 ,max= 1000 ,step= 10 ,hint="alife_warfare_faction_min_random_patrol_time" }, { id="max_random_patrol_time" ,type= "track" ,val= 2 ,def= 180 ,min= 0 ,max= 1000 ,step= 10 ,hint="alife_warfare_faction_max_random_patrol_time" }, { id="base_priority" ,type= "track" ,val= 2 ,def= 10 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_base_priority" }, { id="resource_priority" ,type= "track" ,val= 2 ,def= 5 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_resource_priority" }, { id="territory_priority" ,type= "track" ,val= 2 ,def= -5 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_territory_priority" }, { id="flag_priority" ,type= "track" ,val= 2 ,def= 1 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_flag_priority" }, { id="is_being_targeted_priority" ,type= "track" ,val= 2 ,def= 2 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_is_being_targeted_priority" }, { id="target_weaker_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_target_weaker_priority" }, { id="target_stronger_priority" ,type= "track" ,val= 2 ,def= 1 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_target_stronger_priority" }, { id="target_faction_stronger_priority" ,type= "track" ,val= 2 ,def= 1 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_target_faction_stronger_priority" }, { id="target_faction_weaker_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_target_faction_weaker_priority" }, { id="target_resource_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_target_resource_priority" }, { id="target_on_same_level_priority" ,type= "track" ,val= 2 ,def= 100 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_target_on_same_level_priority" }, { id="max_smart_targets_per_base" ,type= "track" ,val= 2 ,def= 2 ,min= 0 ,max= 10 ,step= 1 ,hint="alife_warfare_faction_max_smart_targets_per_base" }, { id="resource_count_modifier" ,type= "track" ,val= 2 ,def= 0 ,min= 0 ,max= 1 ,step= 0.01 ,hint="alife_warfare_faction_resource_count_modifier" }, { id="base_count_modifier" ,type= "track" ,val= 2 ,def= 0 ,min= 0 ,max= 1 ,step= 0.01 ,hint="alife_warfare_faction_base_count_modifier" }, { id="lvl_k00_marsh_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_lvl_k00_marsh_priority" }, { id="lvl_k01_darkscape_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_lvl_k01_darkscape_priority" }, { id="lvl_l01_escape_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_lvl_l01_escape_priority" }, { id="lvl_l02_garbage_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_lvl_l02_garbage_priority" }, { id="lvl_l03_agroprom_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_lvl_l03_agroprom_priority" }, { id="lvl_l04_darkvalley_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_lvl_l04_darkvalley_priority" }, { id="lvl_l05_bar_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_lvl_l05_bar_priority" }, { id="lvl_l06_rostok_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_lvl_l06_rostok_priority" }, { id="lvl_l07_military_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_lvl_l07_military_priority" }, { id="lvl_l08_yantar_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_lvl_l08_yantar_priority" }, { id="lvl_l09_deadcity_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_lvl_l09_deadcity_priority" }, { id="lvl_l10_limansk_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_lvl_l10_limansk_priority" }, { id="lvl_l10_radar_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_lvl_l10_radar_priority" }, { id="lvl_l10_red_forest_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_lvl_l10_red_forest_priority" }, { id="lvl_l11_hospital_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_lvl_l11_hospital_priority" }, { id="lvl_l11_pripyat_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_lvl_l11_pripyat_priority" }, { id="lvl_l12_stancia_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_lvl_l12_stancia_priority" }, { id="lvl_l12u_sarcofag_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_lvl_l12u_sarcofag_priority" }, { id="lvl_l12u_control_monolith_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_lvl_l12u_control_monolith_priority" }, { id="lvl_l12_stancia_2_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_lvl_l12_stancia_2_priority" }, { id="lvl_l13_generators_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_lvl_l13_generators_priority" }, { id="lvl_zaton_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_lvl_zaton_priority" }, { id="lvl_jupiter_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_lvl_jupiter_priority" }, { id="lvl_pripyat_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_lvl_pripyat_priority" }, { id="lvl_jupiter_underground_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_lvl_jupiter_underground_priority" }, { id="lvl_k02_trucks_cemetery_priority" ,type= "track" ,val= 2 ,def= 0 ,min= -100 ,max= 100 ,step= 1 ,hint="alife_warfare_faction_lvl_k02_trucks_cemetery_priority" }, },}, },}, { id= "dynamic_news" ,sh=true ,gr={ { id= "slide_dynamic_news" ,type= "slide" ,link= "ui_options_slider_news" ,text= "ui_mm_menu_dynamic_news" ,size= {512,50} }, { id= "desc_dynamic_news" ,type= "desc" ,text= "ui_mm_desc_dynamic_news" ,clr= {255,125,175,200} }, { id= "line" ,type= "line" }, { id="message_duration" ,type= "track" ,val= 2 ,def= 10 ,min= 5 ,max= 30 ,step= 1 }, { id= "line" ,type= "line" }, { id="death_stalker_news" ,type= "check" ,val= 1 ,def= true }, { id="death_mutant_news" ,type= "check" ,val= 1 ,def= true }, { id="generic_death_news" ,type= "check" ,val= 1 ,def= false }, { id="death_report_news" ,type= "check" ,val= 1 ,def= false }, { id="kill_wounded_news" ,type= "check" ,val= 1 ,def= true }, { id="found_artifact_news" ,type= "check" ,val= 1 ,def= true }, { id="heli_call_news" ,type= "check" ,val= 1 ,def= true }, { id="loot_news" ,type= "check" ,val= 1 ,def= true }, { id= "line" ,type= "line" }, { id="reaction_news" ,type= "check" ,val= 1 ,def= true }, { id= "line" ,type= "line" }, { id="weather_news" ,type= "check" ,val= 1 ,def= true }, { id="time_news" ,type= "check" ,val= 1 ,def= true }, { id="nearby_activity_news" ,type= "check" ,val= 1 ,def= true }, { id="dumb_zombie_news" ,type= "check" ,val= 1 ,def= true }, { id="cycle_of_special_news" ,type= "track" ,val= 2 ,def= 240 ,min= 60 ,max= 1800 ,step= 60 }, { id= "line" ,type= "line" }, { id="bounty_news" ,type= "check" ,val= 1 ,def= true }, { id="cycle_of_task_news" ,type= "track" ,val= 2 ,def= 300 ,min= 60 ,max= 1800 ,step= 60 }, { id= "line" ,type= "line" }, { id="random_msg_news" ,type= "check" ,val= 1 ,def= true }, { id="factions_report_news" ,type= "check" ,val= 1 ,def= true }, { id="zone_activity_news" ,type= "check" ,val= 1 ,def= true }, { id="found_dead_news" ,type= "check" ,val= 1 ,def= true }, { id="surge_news" ,type= "check" ,val= 1 ,def= true }, { id="cycle_of_random_news" ,type= "track" ,val= 2 ,def= 240 ,min= 60 ,max= 1800 ,step= 60 }, { id= "line" ,type= "line" }, { id="companions_news" ,type= "check" ,val= 1 ,def= true }, { id="cycle_of_companions_news" ,type= "track" ,val= 2 ,def= 240 ,min= 60 ,max= 1800 ,step= 60 }, },}, },}, { id= "other" ,sh=true ,gr={ { id= "slide_other" ,type= "slide" ,link= "ui_options_slider_other" ,text= "ui_mm_title_other" ,size= {512,50} }, { id= "localization" ,type= "list" ,val= 0 ,def= "eng" ,curr= {curr_localization} ,content= {{"eng"} , {"rus"}} ,no_str= true ,functor= {func_localization} }, { id= "discord" ,type= "check" ,val= 1 ,def= true ,cmd= "discord_status" }, { id= "line" ,type= "line" ,precondition = {debug_only} }, { id= "important_save" ,type= "check" ,val= 1 ,def= true ,cmd= "g_important_save" }, -- { id= "autosave_timer" ,type= "check" ,val= 1 ,def= false ,functor= {func_autosave_timer} }, -- removed for custom value box below { id= "autosave_timer_new" ,type= "input" ,val= 0 ,def= 0, functor ={func_autosave_timer_new}}, { id= "quicksave_cnt" ,type= "list" ,val= 2 ,def= 5 ,content= {{1} , {5} , {10} , {15} , {20}} ,no_str= true }, { id= "line" ,type= "line" ,precondition = {debug_only} }, { id= "debug_hud" ,type= "check" ,val= 1 ,def= false ,precondition = {debug_only} ,functor= {func_debug_hud} }, { id= "debug_map_hud" ,type= "check" ,val= 1 ,def= false ,precondition = {debug_only} ,functor= {func_debug_map_hud} }, { id= "debug_error" ,type= "check" ,val= 1 ,def= false ,precondition = {debug_only} }, },}, } init_opt_coder() end function init_opt_coder() ------------------------------------------------------------------------ -- Auto-complete factions options for warfare local t = {} copy_table(t, options[5].gr[3].gr[3].gr) options[5].gr[3].gr[4] = { id= "bandit" ,sh=true ,presets= {"warfare_default","warfare_yoko"}, id_gr= "warfare_faction", apply_to_all=true ,gr=t } options[5].gr[3].gr[5] = { id= "csky" ,sh=true ,presets= {"warfare_default","warfare_yoko"}, id_gr= "warfare_faction", apply_to_all=true ,gr=t } options[5].gr[3].gr[6] = { id= "army" ,sh=true ,presets= {"warfare_default","warfare_yoko"}, id_gr= "warfare_faction", apply_to_all=true ,gr=t } options[5].gr[3].gr[7] = { id= "freedom" ,sh=true ,presets= {"warfare_default","warfare_yoko"}, id_gr= "warfare_faction", apply_to_all=true ,gr=t } options[5].gr[3].gr[8] = { id= "dolg" ,sh=true ,presets= {"warfare_default","warfare_yoko"}, id_gr= "warfare_faction", apply_to_all=true ,gr=t } options[5].gr[3].gr[9] = { id= "ecolog" ,sh=true ,presets= {"warfare_default","warfare_yoko"}, id_gr= "warfare_faction", apply_to_all=true ,gr=t } options[5].gr[3].gr[10] = { id= "killer" ,sh=true ,presets= {"warfare_default","warfare_yoko"}, id_gr= "warfare_faction", apply_to_all=true ,gr=t } options[5].gr[3].gr[11] = { id= "monolith" ,sh=true ,presets= {"warfare_default","warfare_yoko"}, id_gr= "warfare_faction", apply_to_all=true ,gr=t } options[5].gr[3].gr[12] = { id= "renegade" ,sh=true ,presets= {"warfare_default","warfare_yoko"}, id_gr= "warfare_faction", apply_to_all=true ,gr=t } options[5].gr[3].gr[13] = { id= "greh" ,sh=true ,presets= {"warfare_default","warfare_yoko"}, id_gr= "warfare_faction", apply_to_all=true ,gr=t } options[5].gr[3].gr[14] = { id= "isg" ,sh=true ,presets= {"warfare_default","warfare_yoko"}, id_gr= "warfare_faction", apply_to_all=true ,gr=t } options[5].gr[3].gr[15] = { id= "zombied" ,sh=true ,presets= {"warfare_default","warfare_yoko"}, id_gr= "warfare_faction", apply_to_all=true ,gr=t } ------------------------------------------------------------------------ -- Auto-complete options for radio music local ltx = ini_file("plugins\\radio_zone_fm.ltx") -- File control: reading the ltx file that controls the hotkeys local num_of_plyr = ltx:r_float_ex("trx_radio_plyr","number_of_playlists") or 2 -- Number of Music Player plylists local radio_size = #options[2].gr[3].gr for i=1,num_of_plyr do radio_size = radio_size + 1 options[2].gr[3].gr[radio_size] = { id= ("playlist_name_"..i) ,type= "input" ,val= 0 ,def= {def_radio_playlist, i} } end ------------------------------------------------------------------------ -- Coding options local function code_option(gr, id, num) local path for i=1,#gr do if allowed_type[gr[i].type] then path = cc(id , gr[i].id) opt_index[path] = cc(num , i) opt_val[path] = gr[i].val --printf("-[%s] | index: %s - type: %s", path, opt_index[path], opt_val[path]) end end end local id_1, id_2, id_3 -- Level 1 for i=1,#options do id_1 = options[i].id if options[i].sh then code_option(options[i].gr, id_1, i) else -- Level 2 for ii=1,#options[i].gr do id_2 = options[i].gr[ii].id if options[i].gr[ii].sh then code_option( (options[i].gr[ii].gr), (id_1 .._opt_.. id_2), (i .._opt_.. ii) ) else -- Level 3 for iii=1,#options[i].gr[ii].gr do id_3 = options[i].gr[ii].gr[iii].id if options[i].gr[ii].gr[iii].sh then code_option( (options[i].gr[ii].gr[iii].gr), (id_1 .._opt_.. id_2 .._opt_.. id_3), (i .._opt_.. ii .._opt_.. iii) ) else ---- end end end end end end end ------------------------------------------------------------ -- Functors ------------------------------------------------------------ -- Special function start_lighting_ui(self) self:On_Cancel() ui_ctrl_lighting.start() end -- Preconditions function level_present() return level.present() end function debug_only() return DEV_DEBUG end function for_renderer(...) local rend = {...} local curr_rend = get_console_cmd(0, "renderer") local result = false for i=1,#rend do result = result or curr_rend == rend[i] end return result end -- Default values function def_radio_playlist(i) if (i == 1) then return "OST" elseif (i == 2) then return "TRX_Special" else return "Playlist_" .. tostring(i) end end -- Contents function cont_vid_mode() local ratio = { [round_idp(5/4, 1)] = "(5:4)", [round_idp(4/3, 1)] = "(4:3)", [round_idp(16/9, 1)] = "(16:9)", [round_idp(16/10, 1)] = "(16:10)", [round_idp(21/9, 1)] = "(21:9)", [round_idp(32/9, 1)] = "(32:9)", } local ress = game.get_resolutions() -- get all res list from engine in one string ress = str_explode(ress,",") local cont = {} for i=1,#ress do local res = str_explode(ress[i],"x") local w = tonumber(res[1]) local h = tonumber(res[2]) local rat = ratio[round_idp(w/h , 1)] or "" cont[#cont + 1] = { (w.."x"..h) , (w.." x "..h.." "..rat) } end return cont end function cont_renderer() if for_renderer("renderer_r2a","renderer_r2","renderer_r2.5") then return {{"renderer_r2a"},{"renderer_r2"},{"renderer_r2.5"}} else local curr = get_console_cmd(0, "renderer") return {{curr}} end end function cont_sun_quality() local cont = { {"st_opt_low","low"},{"st_opt_medium","medium"},{"st_opt_high","high"} } if for_renderer("renderer_r3","renderer_r4") then cont[#cont + 1] = {"st_opt_ultra","ultra"} cont[#cont + 1] = {"st_opt_extreme","extreme"} end return cont end -- Functor to execute on apply function func_screen_mode() local val = opt_temp["video/basic/screen_mode"] if (val == nil) then val = axr_main.config:r_value(opt_section, "video/basic/screen_mode", 2) end if (val == 1) then exec_console_cmd("rs_screenmode fullscreen") elseif (val == 2) then exec_console_cmd("rs_screenmode borderless") else exec_console_cmd("rs_screenmode windowed") end --[[ if val == 1 then exec_console_cmd("rs_fullscreen on") exec_console_cmd("rs_borderless 0") else exec_console_cmd("rs_fullscreen off") exec_console_cmd("rs_borderless 1") end --]] end function func_localization() local val = opt_temp["other/localization"] if (val == nil) then val = axr_main.config:r_value(opt_section, "other/localization", 0) end if (ini_loc:r_value("string_table","language") ~= val) then ini_loc:w_value("string_table","language",val) ini_loc:save() reload_ini_sys() game.reload_language() if level.present() then SendScriptCallback("on_localization_change") end end end function func_slot_hud() if level.present() then local val = opt_temp["video/hud/show_slots"] if (val == nil) then val = axr_main.config:r_value(opt_section, "video/hud/show_slots", 1) end if val then item_artefact.activate_hud() else item_artefact.deactivate_hud() end end end function func_hardcore_ai_aim() if level.present() then local val = opt_temp["gameplay/general/hardcore_ai_aim"] if (val == nil) then val = axr_main.config:r_value(opt_section, "gameplay/general/hardcore_ai_aim", 1) end if val then exec_console_cmd("ai_aim_max_angle 20.0") exec_console_cmd("ai_aim_min_angle 17.0") exec_console_cmd("ai_aim_min_speed 2.5") exec_console_cmd("ai_aim_predict_time 0.28") else exec_console_cmd("ai_aim_max_angle 0.7854") exec_console_cmd("ai_aim_min_angle 0.19635") exec_console_cmd("ai_aim_min_speed 0.24") exec_console_cmd("ai_aim_predict_time 0.40") end end end -- unused -- function func_autosave_timer() -- if (level.present() and game_autosave) then -- local val = opt_temp["other/autosave_timer"] -- if (val == nil) then -- val = axr_main.config:r_value(opt_section, "other/autosave_timer", 1) -- end -- if val then -- game_autosave.activate_feature() -- else -- game_autosave.deactivate_feature() -- end -- end -- end function func_autosave_timer_new() game_autosave_new.option_updated() end function func_hud_minimap() if (level.present()) then local val = opt_temp["video/hud/show_minimap"] if (val == nil) then val = axr_main.config:r_value(opt_section, "video/hud/show_minimap", 0) end local maingameui = ActorMenu.get_maingame() if (maingameui and maingameui.UIZoneMap) then maingameui.UIZoneMap.disabled = not val maingameui.UIMotionIcon:Show(maingameui.UIZoneMap.disabled == false) end end end function func_hud_autohide_bar() if (level.present()) then local val = opt_temp["video/hud/autohide_stamina_bar"] if (val == nil) then val = axr_main.config:r_value(opt_section, "video/hud/autohide_stamina_bar", 1) end actor_effects.toggle_hud_autohide(val) end end function func_player_name() local se_actor = alife():actor() if se_actor then local curr_name = se_actor:character_name() local new_name = opt_temp["gameplay/general/player_name"] or axr_main.config:r_value(opt_section, "gameplay/general/player_name", 0) if new_name and (new_name ~= "") and (new_name ~= curr_name) then se_actor:set_character_name(new_name) printf("- Changed player name from (%s) to (%s)", curr_name, new_name) end end end function func_gameplay_diff(fac) if (opt_temp["gameplay/gameplay_diff/"..fac] ~= nil) then game_difficulties.set_game_factor(fac, opt_temp["gameplay/gameplay_diff/"..fac]) end end function func_economy_diff(fac) if (opt_temp["gameplay/economy_diff/"..fac] ~= nil) then game_difficulties.set_eco_factor(fac, opt_temp["gameplay/economy_diff/"..fac]) end end function func_debug_hud() if (level.present() and xrs_debug_tools) then local val = opt_temp["other/debug_hud"] if (val == nil) then val = axr_main.config:r_value(opt_section, "other/debug_hud", 1) end if val then xrs_debug_tools.activate_feature() else xrs_debug_tools.deactivate_feature() end end end function func_debug_map_hud() if (level.present() and ui_map_debug_ex) then local val = opt_temp["other/debug_map_hud"] if (val == nil) then val = axr_main.config:r_value(opt_section, "other/debug_map_hud", 1) end if val then ui_map_debug_ex.activate_feature() else ui_map_debug_ex.deactivate_feature() end end end function func_crosshair_clr(n) local val = opt_temp["video/hud/crosshair_clr_" .. n] if (val == nil) then return end local curr = get_console_cmd(nil, "g_crosshair_color") curr = tostring(curr) local r,g,b,a = string.match(curr,"(%d+), (%d+), (%d+), (%d+)") if n == "a" then a = val elseif n == "r" then r = val elseif n == "g" then g = val elseif n == "b" then b = val end exec_console_cmd( strformat("g_crosshair_color (%s, %s, %s, %s)",r,g,b,a) ) end -- Current value override function curr_renderer() return get_console_cmd(0, "renderer") end function curr_screen_mode() local sm = get_console_cmd(0, "rs_screenmode") if (sm == "fullscreen") then return 1 elseif (sm == "borderless") then return 2 end return 3 end function curr_player_name() return alife():actor():character_name() end function curr_economy(fact) local value = game_difficulties.get_eco_factor(fact) return value end function curr_gameplay(fact) local value = game_difficulties.get_game_factor(fact) return value end function curr_localization() local val = ini_loc:r_value("string_table","language") or axr_main.config:r_value(opt_section, "other/localization", 0) return val end function curr_crosshair_clr(n) local curr = get_console_cmd(nil, "g_crosshair_color") curr = tostring(curr) local r,g,b,a = string.match(curr,"(%d+), (%d+), (%d+), (%d+)") if n == "a" then return tonumber(a) elseif n == "r" then return tonumber(r) elseif n == "g" then return tonumber(g) elseif n == "b" then return tonumber(b) end return 255 end -- Utilities function is_int(num) return (m_floor(num) == num) end function exec(func,...) if (not func) then return false end return func(...) end function str_opt_explode(id, by_num) local nums = by_num and opt_index[id] or id local t = nums and str_explode(nums, _opt_) or {} if by_num then for i=1,#t do t[i] = tonumber(t[i]) end end return t end function get_opt_table(id) local t = str_opt_explode(id, true) if #t == 0 then return {} end if #t == 1 then return options[t[1]] elseif #t == 2 then return options[t[1]].gr[t[2]] elseif #t == 3 then return options[t[1]].gr[t[2]].gr[t[3]] elseif #t == 4 then return options[t[1]].gr[t[2]].gr[t[3]].gr[t[4]] end end function check_opt_table(id) local t = str_opt_explode(id, true) return #t > 0 end -------------------- function get(id) if (#options == 0) then init_opt_base() end local value = axr_main.config:r_value(opt_section, id, opt_val[id]) if (value ~= nil) then --print_dbg("/Got axr_option [%s] = %s", id, value) return value end -- Write in axr_main if it doesn't exist local v = get_opt_table(id) if v.cmd then if v.val == 0 then value = get_console_cmd(0, v.cmd) elseif v.val == 1 then value = get_console_cmd(1, v.cmd) elseif v.val == 2 then value = get_console_cmd(0, v.cmd) --get_console_cmd(2, v.cmd) value = tonumber(value) if v.min and v.max then value = clamp(value, v.min, v.max) end value = round_idp(value, v.prec or precision) end elseif (type(v.def) == "table") then value = exec(unpack(v.def)) axr_main.config:w_value(opt_section, id, value) axr_main.config:save() else value = v.def axr_main.config:w_value(opt_section, id, value) axr_main.config:save() end --print_dbg("/Got option [%s] = %s", id, value) if (value == nil) then printe("!Found nil option value [%s]", id) end return value end function set(id, value) axr_main.config:w_value(opt_section, id, value) axr_main.config:save() end -------------------- --=========================================================== --//////////////////////// OPTIONS ////////////////////////// --=========================================================== class "UIOptions" (CUIScriptWnd) function UIOptions:__init() super() self.last_tree = {} self.last_path = nil self.last_curr_tree = nil self._Cap = {} self._Check = {} self._List = {} self._Input = {} self._Track = {} self._Radio = {} -- Prepare the options table if (#options == 0) then init_opt_base() end self:InitControls() self:InitCallBacks() self:Reset() end function UIOptions:__finalize() end function UIOptions:InitControls() self:SetWndRect (Frect():set(0,0,1024,768)) self:Enable (true) self.xml = CScriptXmlInit() local xml = self.xml xml:ParseFile ("ui_options.xml") self.background = xml:InitStatic("background", self) self.dialog = xml:InitStatic("main", self) xml:InitStatic("main:frame", self.dialog) -- Buttons self.btn_accept = xml:Init3tButton("main:btn_accept", self.dialog) self:Register(self.btn_accept, "btn_accept") self.btn_reset = xml:Init3tButton("main:btn_reset", self.dialog) self:Register(self.btn_reset, "btn_reset") self.btn_default = xml:Init3tButton("main:btn_default", self.dialog) self:Register(self.btn_default, "btn_default") self.btn_cancel = xml:Init3tButton("main:btn_cancel", self.dialog) self:Register(self.btn_cancel, "btn_cancel") -- Pending text --xml:InitFrame("main:notify_frame", self.dialog) self.pending = xml:InitTextWnd("main:notify", self.dialog) -- Options lists self.tree = {} self.bl = {} -- Options showcase self.scroll_opt = xml:InitScrollView("main:scroll", self.dialog) -- Presets self.preset_cap = xml:InitStatic("main:cap_preset", self.dialog) self.preset = xml:InitComboBox("main:preset",self.dialog) self:Register(self.preset, "preset") self.preset:Show(false) self.preset_cap:Show(false) -- Message box self.message_box = CUIMessageBoxEx() self:Register (self.message_box, "mb") -- Hint Window self.hint_wnd = utils_ui.UIHint(self) end function UIOptions:InitCallBacks() self:AddCallback("btn_accept", ui_events.BUTTON_CLICKED, self.OnButton_Accept, self) self:AddCallback("btn_reset", ui_events.BUTTON_CLICKED, self.OnButton_Reset, self) self:AddCallback("btn_default", ui_events.BUTTON_CLICKED, self.OnButton_Default, self) self:AddCallback("btn_cancel", ui_events.BUTTON_CLICKED, self.OnButton_Cancel, self) self:AddCallback("preset", ui_events.LIST_ITEM_SELECT, self.Callback_Preset, self) self:AddCallback("mb", ui_events.MESSAGE_BOX_YES_CLICKED, self.On_Discard, self) --self:AddCallback("mb", ui_events.MESSAGE_BOX_NO_CLICKED, self.On_Discard,self) end function UIOptions:Update() CUIScriptWnd.Update(self) -- Show hint on hover for id,ctrl in pairs(self._Cap) do if ctrl:IsCursorOverWindow() then local str = opt_str .. id .. "_desc" local str_t = game.translate_string(str) if (str ~= str_t) then self.hint_wnd:Update(str_t) end return end end self.hint_wnd:Update() -- Hack to simulate tracing method for TrackBar value changes. TODO: add callback support for CUITrackBar in engine, this is just silly for id,e in pairs(self._Track) do if e.ctrl:IsCursorOverWindow() then local v = self:GetOption(id) local value = round_idp(e.ctrl:GetFValue(), v.prec or precision) if (value ~= e.value) then e.value = value self:Callback_Track(e.txt, e.path, e.opt, v, value) return end end end end function UIOptions:Reset() -- Clear all trees for i=1,3 do if self.tree[i] then if type(self.tree[i]) == table then for j=1,#self.tree[i] do self.tree[i][j]:Clear() end else self.tree[i]:Clear() end end end self:Register_Tree(1, "", options, 1) end function UIOptions:Reset_opt(curr_tree, path, flags) flags = flags or {} local xml = self.xml self.scroll_opt:Clear() -- If options tree has a precondition that must be met, don't show it if it returns false if curr_tree.precondition and (not exec(unpack(curr_tree.precondition))) then if curr_tree.output then local _txt = xml:InitTextWnd("elements:block", nil) _txt:SetText( game.translate_string(curr_tree.output) ) self.scroll_opt:AddWindow(_txt, true) _txt:SetAutoDelete(false) end else -- Keybinds if (self.dlg_controls == nil) then self.dlg_controls = opt_controls() self.dlg_controls:InitControls(0,0, xml, self) self.dlg_controls:Show (false) self.dialog:AttachChild (self.dlg_controls) xml:InitWindow ("tab_size", 0, self.dlg_controls) local opt = COptionsManager() opt:SetCurrentValues("key_binding") opt:SaveBackupValues("key_binding") end if (path == "control/keybind") then self.dlg_controls:Show(true) self.Keybinds_Shown = true else self.dlg_controls:Show(false) end -- Presets self:Register_Preset(curr_tree) if curr_tree.apply_to_all and curr_tree.id_gr then flags.apply_to_all = true flags.group = curr_tree.id_gr else flags.apply_to_all = nil end empty_table(self._Cap) empty_table(self._Check) empty_table(self._List) empty_table(self._Input) empty_table(self._Track) empty_table(self._Radio) for i=1,#curr_tree.gr do -- Check preconditions local to_hide = curr_tree.gr[i].precondition and (not exec(unpack(curr_tree.gr[i].precondition))) for j=1,10 do -- support for 10 preconditions if (not curr_tree.gr[i]["precondition_" .. j]) then break elseif (not exec(unpack(curr_tree.gr[i]["precondition_" .. j]))) then to_hide = true break end end if (not to_hide) then local opt = curr_tree.gr[i].id local v = curr_tree.gr[i] local _st = xml:InitStatic("main:st", nil) local _h = 0 ----------- Support if (v.type == "line") then _h = self:Register_Line(xml, _st) elseif (v.type == "image") then _h = self:Register_Image(xml, _st, v) elseif (v.type == "slide") then _h = self:Register_Slide(xml, _st, v) elseif (v.type == "title") then _h = self:Register_Title(xml, _st, v) elseif (v.type == "desc") then _h = self:Register_Desc(xml, _st, v) ----------- Option elseif (v.type == "check") then _h = self:Register_Check(xml, _st, path, opt, v, flags) elseif (v.type == "button") then _h = self:Register_Button(xml, _st, path, opt, v, flags) elseif (v.type == "list") then _h = self:Register_List(xml, _st, path, opt, v, flags) elseif (v.type == "input") then _h = self:Register_Input(xml, _st, path, opt, v, flags) elseif (v.type == "track") then _h = self:Register_Track(xml, _st, path, opt, v, flags) elseif (v.type == "radio_h") then _h = self:Register_Radio(xml, _st, path, opt, v, true, flags) elseif (v.type == "radio_v") then _h = self:Register_Radio(xml, _st, path, opt, v, false, flags) end _st:SetWndSize(vector2():set(_st:GetWidth(), _h + 10)) self.scroll_opt:AddWindow(_st, true) _st:SetAutoDelete(true) end end if self.Save_AXR then self.Save_AXR = false axr_main.config:save() end end end function UIOptions:Reset_last_opt() Register_UI("UIOptions") if self.last_curr_tree and self.last_path then self:Reset_opt(self.last_curr_tree, self.last_path) self:UpdatePending() end end ------------------------------------------------------------ -- Elements ------------------------------------------------------------ function UIOptions:Register_Cap(xml, handler, id, hint) id = s_gsub(id, _opt_, "_") self._Cap[id] = xml:InitStatic("elements:cap",handler) self._Cap[id]:TextControl():SetText( game.translate_string(opt_str .. (hint or id)) ) return self._Cap[id]:GetHeight() end function UIOptions:Register_Line(xml, handler) local line = xml:InitStatic("elements:line",handler) return (line:GetHeight() + 10) end function UIOptions:Register_Image(xml, handler, v) local pic = xml:InitStatic("elements:image",handler) if v.link then if (v.pos) then local pos = pic:GetWndPos() pic:SetWndPos(vector2():set( pos.x + v.pos[1] , pos.y + v.pos[2] )) end if (v.size) then pic:SetWndSize(vector2():set( v.size[1] , v.size[2] )) end pic:InitTexture(v.link) pic:SetStretchTexture(v.stretch and true or false) end return pic:GetHeight() end function UIOptions:Register_Slide(xml, handler, v) local frame = xml:InitStatic("elements:slide", handler) local _pos = frame:GetWndPos() frame:SetWndPos(vector2():set( _pos.x , _pos.y + (v.spacing or 20) )) local pic = xml:InitStatic("elements:slide:pic", frame) if v.link then pic:InitTexture(v.link) pic:SetStretchTexture(true) if (v.pos) then local pos = pic:GetWndPos() pic:SetWndPos(vector2():set( pos.x + v.pos[1] , pos.y + v.pos[2] )) end if (v.size) then pic:SetWndSize(vector2():set( v.size[1] * width_factor , v.size[2] )) end pic:InitTexture(v.link) end local txt = xml:InitTextWnd("elements:slide:txt", frame) if v.text then txt:SetText( game.translate_string(v.text) ) end xml:InitStatic("elements:slide:line_1", frame) xml:InitStatic("elements:slide:line_2", frame) return (pic:GetHeight() + 20) end function UIOptions:Register_Title(xml, handler, v) local title = xml:InitTextWnd("elements:title_" .. (v.align or "l"), handler) title:SetText( game.translate_string(v.text) ) title:AdjustHeightToText() title:SetWndSize(vector2():set(title:GetWidth(), title:GetHeight() + 20)) if v.clr and v.clr[4] then title:SetTextColor( GetARGB(v.clr[1], v.clr[2], v.clr[3], v.clr[4]) ) end return title:GetHeight() end function UIOptions:Register_Desc(xml, handler, v) local desc = xml:InitTextWnd("elements:desc", handler) desc:SetText( game.translate_string(v.text) ) desc:AdjustHeightToText() desc:SetWndSize(vector2():set(desc:GetWidth(), desc:GetHeight() + 20)) if v.clr and v.clr[4] then desc:SetTextColor( GetARGB(v.clr[1], v.clr[2], v.clr[3], v.clr[4]) ) end return desc:GetHeight() end function UIOptions:Register_Check(xml, handler, path, opt, v, flags) local id = cc(path , opt) -- Caption local h = self:Register_Cap(xml, handler, id, v.hint) -- Apply to all button if flags.apply_to_all and flags.group then self:Register_BtnAll(xml, handler, path, opt, v, flags) end -- Create control local ctrl = xml:InitCheck("elements:check",handler) if (ctrl:GetHeight() > h) then h = ctrl:GetHeight() end -- Get values local value = self:GetValue(path, opt, v, flags) ctrl:SetCheck(value) -- Register local id_ctrl = self:Stacker(path, opt, v) self:Register(ctrl, id_ctrl) local _wrapper = function(handler) -- we need wrapper in order to pass ctrl to method self:Callback_Check(ctrl, path, opt, v) end self:AddCallback(id_ctrl, ui_events.BUTTON_CLICKED, _wrapper, self) return h end function UIOptions:Callback_Check(ctrl, path, opt, v) local value = ctrl:GetCheck() self:CacheValue(path, opt, value, v) end function UIOptions:Register_Button(xml, handler, path, opt, v, flags) local id = cc(path , opt) --[[ Apply to all button if flags.apply_to_all and flags.group then self:Register_BtnAll(xml, handler, path, opt, v, flags) end --]] xml:InitFrame("elements:frame_button", handler) -- Create control local ctrl = xml:Init3tButton("elements:btn_button", handler) local h = ctrl:GetHeight() -- Caption local id_cap = s_gsub(id, _opt_, "_") self._Cap[id_cap] = xml:InitStatic("elements:cap_button",handler) self._Cap[id_cap]:TextControl():SetText( game.translate_string(opt_str .. (v.hint or id_cap)) ) if (self._Cap[id_cap]:GetHeight() > h) then h = self._Cap[id_cap]:GetHeight() end -- Register local id_ctrl = self:Stacker(path, opt, v) self:Register(ctrl, id_ctrl) local _wrapper = function(handler) -- we need wrapper in order to pass ctrl to method self:Callback_Button(ctrl, path, opt, v) end self:AddCallback(id_ctrl, ui_events.BUTTON_CLICKED, _wrapper, self) return h end function UIOptions:Callback_Button(ctrl, path, opt, v) if v.functor_ui then local id = cc(path , opt) print_dbg("- Executing functor_ui of [%s]",id) exec(unpack(v.functor_ui),self) end if v.functor then local id = cc(path , opt) print_dbg("- Executing functor of [%s]",id) exec(unpack(v.functor)) end end function UIOptions:Register_List(xml, handler, path, opt, v, flags) local id = cc(path , opt) -- Caption local h = self:Register_Cap(xml, handler, id, v.hint) -- Apply to all button if flags.apply_to_all and flags.group then self:Register_BtnAll(xml, handler, path, opt, v, flags) end -- Create control local ctrl = xml:InitComboBox("elements:list",handler) if (ctrl:GetHeight() > h) then --h = ctrl:GetHeight() end -- Get values local idx local value = self:GetValue(path, opt, v, flags) local content = self:GetContent(path, opt, v) -- Setup for i=1,#content do local str_2 = content[i][2] or tostring(content[i][1]) local str = v.no_str and str_2 or game.translate_string(opt_str_lst .. str_2) ctrl:AddItem( game.translate_string(str), i) if content[i][1] == value then idx = i end end idx = idx or 1 local str_2 = content[idx][2] or tostring(content[idx][1]) local str = v.no_str and str_2 or game.translate_string(opt_str_lst .. str_2) ctrl:enable_id( idx ) ctrl:SetText( game.translate_string(str) ) -- Register local id_ctrl = self:Stacker(path, opt, v) self:Register(ctrl, id_ctrl) local _wrapper = function(handler) -- we need wrapper in order to pass ctrl to method self:Callback_List(ctrl, path, opt, v) end self:AddCallback(id_ctrl, ui_events.LIST_ITEM_SELECT, _wrapper, self) return h end function UIOptions:Callback_List(ctrl, path, opt, v) local i = ctrl:CurrentID() local content = self:GetContent(path, opt, v) self:CacheValue(path, opt, content[i][1], v) end function UIOptions:Register_Input(xml, handler, path, opt, v, flags) local id = cc(path , opt) -- Caption local h = self:Register_Cap(xml, handler, id, v.hint) -- Apply to all button if flags.apply_to_all and flags.group then self:Register_BtnAll(xml, handler, path, opt, v, flags) end -- Create control local ctrl = xml:InitEditBox("elements:input",handler) if (ctrl:GetHeight() > h) then h = ctrl:GetHeight() end -- Get values local value = self:GetValue(path, opt, v, flags) ctrl:SetText(value) -- Register local id_ctrl = self:Stacker(path, opt, v) self:Register(ctrl, id_ctrl) local _wrapper = function(handler) -- we need wrapper in order to pass ctrl to method self:Callback_Input(ctrl, path, opt, v) end self:AddCallback(id_ctrl, ui_events.EDIT_TEXT_COMMIT, _wrapper, self) return h end function UIOptions:Callback_Input(ctrl, path, opt, v) local value = ctrl:GetText() if not (value and value ~= "") then ctrl:SetText( self:GetCurrentValue(path, opt, v) or self:GetDefaultValue(path, opt, v) ) return end if (v.val == 1) then value = tonumber(value) if (not value) then ctrl:SetText( self:GetCurrentValue(path, opt, v) or self:GetDefaultValue(path, opt, v) ) return end value = clamp(value, v.min, v.max) end self:CacheValue(path, opt, value, v) ctrl:SetText(value) end function UIOptions:Register_Track(xml, handler, path, opt, v, flags) local id = cc(path , opt) -- Caption local h = self:Register_Cap(xml, handler, id, v.hint) -- Apply to all button if flags.apply_to_all and flags.group then self:Register_BtnAll(xml, handler, path, opt, v, flags) end -- Create control self._Track[id] = {} self._Track[id].ctrl = xml:InitTrackBar("elements:track",handler) self._Track[id].path = path self._Track[id].opt = opt if (self._Track[id].ctrl:GetHeight() > h) then h = self._Track[id].ctrl:GetHeight() end self._Track[id].txt = xml:InitTextWnd("elements:track_value",handler) -- Get values local value = self:GetValue(path, opt, v, flags) value = clamp(value, v.min, v.max) value = round_idp(value, v.prec or precision) local int = false --is_int(value) and is_int(v.step) and is_int(v.min) and is_int(v.max) self._Track[id].value = value -- temp self._Track[id].ctrl:SetInvert(v.invert and true or false) self._Track[id].ctrl:SetStep(v.step) if int then self._Track[id].ctrl:SetOptIBounds(v.min, v.max) self._Track[id].ctrl:SetIValue(value) else self._Track[id].ctrl:SetOptFBounds(v.min, v.max) self._Track[id].ctrl:SetFValue(value) end if (not v.no_str) then self._Track[id].txt:SetText(value) end return h end function UIOptions:Callback_Track(ctrl, path, opt, v, value) if (not v.no_str) then ctrl:SetText(value) end self:CacheValue(path, opt, value, v) end function UIOptions:Register_Radio(xml, handler, path, opt, v, typ, flags) local id = cc(path , opt) -- Caption local h = self:Register_Cap(xml, handler, id, v.hint) -- Apply to all button if flags.apply_to_all and flags.group then self:Register_BtnAll(xml, handler, path, opt, v, flags) end -- Determine type local str = typ and "horz" or "vert" local content = self:GetContent(path, opt, v) local num = #content if num > 8 and (not v.force_horz) then typ = false str = "vert" end -- Create control local frame = xml:InitStatic("elements:radio_" .. str, handler) local ctrl = {} local txt local offset = typ and m_floor(frame:GetWidth()/num) or 30 local h_factor = typ and 1 or 0 local v_factor = typ and 0 or 1 local h1, h2 = 0, 0 --printf("offset: %s - h_factor: %s - v_factor: %s - num: %s", offset, h_factor, v_factor, num) for i=1,num do -- Buttons ctrl[i] = xml:InitCheck("elements:radio_" .. str .. ":btn", frame) local pos = ctrl[i]:GetWndPos() h1 = (h1 * v_factor) + ctrl[i]:GetHeight() ctrl[i]:SetWndPos(vector2():set( pos.x + ((i-1) * offset * h_factor) , pos.y + ((i-1) * offset * v_factor) )) -- Text txt = xml:InitTextWnd("elements:radio_" .. str .. ":txt", frame) local pos2 = txt:GetWndPos() h2 = h_factor * txt:GetHeight() txt:SetWndPos(vector2():set( pos2.x + ((i-1) * offset * h_factor) , pos2.y - (v_factor * 30) + ((i-1) * offset * v_factor) )) local str_2 = content[i][2] or tostring(content[i][1]) local str = v.no_str and game.translate_string(str_2) or game.translate_string(opt_str_lst .. str_2) txt:SetText( str ) if (h1 + h2 > h) then h = h1 + h2 end end -- Get values local value = self:GetValue(path, opt, v, flags) local id_ctrl = self:Stacker(path, opt, v) for i=1,num do if (content[i][1] == value) then ctrl[i]:SetCheck(true) else ctrl[i]:SetCheck(false) end -- Register self:Register(ctrl[i], id_ctrl .. i) local _wrapper = function(handler) -- we need wrapper in order to pass ctrl to method self:Callback_Radio(ctrl, path, opt, v, i) end self:AddCallback(id_ctrl .. i, ui_events.BUTTON_CLICKED, _wrapper, self) end return h end function UIOptions:Callback_Radio(ctrl, path, opt, v, n) local value = ctrl[n]:GetCheck() --printf("n = %s", n) if value then for i=1,#ctrl do if i ~= n then ctrl[i]:SetCheck(false) end end local content = self:GetContent(path, opt, v) self:CacheValue(path, opt, content[n][1], v) else ctrl[n]:SetCheck(true) end end function UIOptions:Register_BtnAll(xml, handler, path, opt, v, flags) local ctrl = xml:Init3tButton("elements:btn_all",handler) xml:InitStatic("elements:cap_all",handler) local id_ctrl = self:Stacker(path, opt, v) self:Register(ctrl, id_ctrl) local _wrapper = function(handler) -- we need wrapper in order to pass ctrl to method self:Callback_BtnAll(ctrl, path, opt, v, flags) end self:AddCallback(id_ctrl, ui_events.BUTTON_CLICKED, _wrapper, self) end function UIOptions:Callback_BtnAll(ctrl, path, opt, v, flags) local id = cc(path , opt) local group = flags.group local value = self:GetValue(path, opt, v, flags) -- Set same value for identical options of same group local function set_in_group(p, group, path, opt, value) print_dbg("~set_in_group | current path: %s - target opt: %s", path, opt) for i=1,#p do local path_ext = path and (path ~= "") and cc(path , p[i].id) or p[i].id if p[i].sh then print_dbg("~set_in_group | current path: %s - target opt: %s", path_ext, opt) if (p[i].id_gr == group) then local gr = p[i].gr for j=1,#gr do if gr[j].id == opt then local id_ext = cc(path_ext , opt) if check_opt_table(id_ext) then print_dbg("-set_in_group | Found match: %s", id_ext) self:CacheValue(path_ext, opt, value, gr[j]) end end end end else set_in_group(p[i].gr, group, path_ext, opt, value) end end end set_in_group(options, group, "", opt, value) end function UIOptions:Register_Preset(ct) if ct.presets then self.preset:ClearList() -- for i=1,#ct.presets do self.preset:AddItem( game.translate_string(opt_str_prst .. ct.presets[i]), i) end if (ct.curr_preset) then self.preset:SetText( game.translate_string(opt_str_prst .. ct.curr_preset) ) end self.preset:Show(true) self.preset_cap:Show(true) else self.preset:ClearList() self.preset:Show(false) self.preset_cap:Show(false) end end function UIOptions:Callback_Preset() if not (self.last_curr_tree and self.last_path) then return end local txt = self.preset:GetText() if not (txt and txt ~= "") then return end -- Retrieve the preset section local pres local presets = self.last_curr_tree.presets for i=1,#presets do if game.translate_string(opt_str_prst .. presets[i]) == txt then pres = presets[i] break end end if pres and ini_pres:section_exist(pres) then self.last_curr_tree.curr_preset = pres --self:Reset_opt(self.last_curr_tree, self.last_path, { preset = pres }) local n = ini_pres:line_count(pres) local result, id, value for i=0,n-1 do result, id, value = ini_pres:r_line_ex(pres,i,"","") -- Validate option local v = get_opt_table(id) if v and v.type then -- No need to modify options that can't be seen local to_hide = v.precondition and (not exec(unpack(v.precondition))) if (not to_hide) then -- Get proper value if v.val == 0 then elseif v.val == 1 then value = (value == "true") and true or false elseif v.val == 2 then value = tonumber(value) end -- Extract path and opt local t = str_opt_explode(id) local opt = t[#t] local path = t[1] for i=2,#t-1 do path = cc(path , t[i]) end -- Cache changes self:CacheValue(path, opt, value, v) end end end -- Update XML elements self:Reset_opt(self.last_curr_tree, self.last_path) -- Update state self:UpdatePending() end end function UIOptions:Register_Tree(tr, path, group, idx) print_dbg("-Register_Tree | tr: %s - path: %s", tr, path) local xml = self.xml if (not self.tree[tr]) then self.tree[tr] = {} end if (not self.tree[tr][path]) then self.tree[tr][path] = xml:InitScrollView("main:tree_" .. tr, self.dialog) --[[ local pos = self.tree[tr][path]:GetWndPos() if tr == 3 then idx = 1 end self.tree[tr][path]:SetWndPos(vector2():set( pos.x , pos.y + (25*(idx-1)) )) --]] if (not self.bl[tr]) then self.bl[tr] = {} end self.bl[tr][path] = {} -- Fill tree for i=1,#group do local _st = xml:InitStatic("main:st_tree", nil) self.bl[tr][path][i] = xml:InitCheck("elements:btn_list", _st) self.bl[tr][path][i]:SetCheck(false) local txt = xml:InitTextWnd("elements:txt_list", _st) txt:SetText( game.translate_string(opt_str_menu .. group[i].id) ) txt:SetTextColor( clr_tree[tr] ) self.tree[tr][path]:AddWindow(_st, true) _st:SetAutoDelete(false) end -- Set Callback for tree buttons for i=1,#self.bl[tr][path] do local path_i = (path ~= "") and cc(path , group[i].id) or group[i].id self:Register(self.bl[tr][path][i], ("tree_"..path_i)) local _wrapper = function(handler) -- we need wrapper in order to pass ctrl to method self:Callback_Tree(tr, path_i, group[i], self.bl[tr][path], i) end self:AddCallback(("tree_"..path_i), ui_events.BUTTON_CLICKED, _wrapper, self) end end self.tree[tr][path]:Show(true) self.bl[tr][path][1]:SetCheck(true) local path_1 = (path ~= "") and cc(path , group[1].id) or group[1].id self:Callback_Tree(tr, path_1, group[1], self.bl[tr][path], 1) end function UIOptions:Callback_Tree(tr, path, group, ctrl, i) print_dbg("-Callback_Tree | tr: %s - path: %s - index: %s", tr, path, i) -- Radio buttons behavior if (ctrl[i]:GetCheck() == false) then ctrl[i]:SetCheck(true) return end for k=1,#ctrl do if k ~= i then ctrl[k]:SetCheck(false) end end -- Hide all sub trees for k=tr+1,#self.tree do for _,v in pairs(self.tree[k]) do v:Show(false) end end -- If its an option list, show it if group.sh then self:Reset_opt(group, path) -- Caching current options self.last_path = path if (not self.last_curr_tree) then self.last_curr_tree = {} end empty_table(self.last_curr_tree) copy_table(self.last_curr_tree, group) else self:Register_Tree(tr+1, path, group.gr, i) end end ------------------------------------------------------------ -- Utilities ------------------------------------------------------------ function UIOptions:GetValue(path, opt, v, flags) -- NOTE: make sure to check for nil values only, since false exists as legit value for commands and check boxes local value if flags and flags.def then value = self:GetDefaultValue(path, opt, v) elseif flags and flags.preset then local pres = flags.preset local id = cc(path , opt) if v.val == 0 then value = ini_pres:r_string_ex(pres, id) elseif v.val == 1 then value = ini_pres:r_bool_ex(pres, id) elseif v.val == 2 then value = ini_pres:r_float_ex(pres, id) end end if (value ~= nil) or (flags and flags.def) then if (value ~= nil) and (v.type == "track") then value = clamp(value, v.min, v.max) end self:CacheValue(path, opt, value, v) end if (value == nil) then value = self:GetCurrentValue(path, opt, v) end if (value == nil) then value = self:GetDefaultValue(path, opt, v) end if (value ~= nil) and (v.type == "track") then value = clamp(value, v.min, v.max) end return value end function UIOptions:GetDefaultValue(path, opt, v) local id = cc(path , opt) local value if (type(v.def) == "table") then value = exec(unpack(v.def)) else value = v.def end -- We cache default values for the first time, so current values rely on them up later -- because some default values are randomized and player might not touch them, thus causing randomized effects where they are used in-game if (axr_main.config:r_value(opt_section, id, v.val) == nil) and (value ~= nil) then axr_main.config:w_value(opt_section, id, value) self.Save_AXR = true end return value end function UIOptions:GetCurrentValue(path, opt, v) local id = cc(path , opt) if (opt_temp[id] ~= nil) then local _id = s_gsub(id, _opt_, "_") if self._Cap[_id] and self._Cap[_id]:IsShown() then self._Cap[_id]:TextControl():SetTextColor( clr_o ) end return opt_temp[id] end local value if v.curr then value = exec(unpack(v.curr)) elseif v.cmd then if v.val == 0 then value = get_console_cmd(0, v.cmd) elseif v.val == 1 then value = get_console_cmd(1, v.cmd) elseif v.val == 2 then value = get_console_cmd(0, v.cmd) --get_console_cmd(2, v.cmd) -- some commands are integers, using get_float will return 0. This is a walkaround value = tonumber(value) if v.min and v.max then value = clamp(value, v.min, v.max) end value = round_idp(value, v.prec or precision) end else value = axr_main.config:r_value(opt_section, id, v.val) end return value end function UIOptions:GetContent(path, opt, v) if v.cmd and (not v.content) then local value if v.val == 0 then value = get_console_cmd(0, v.cmd) elseif v.val == 1 then value = get_console_cmd(1, v.cmd) elseif v.val == 2 then value = get_console_cmd(0, v.cmd) --get_console_cmd(2, v.cmd) value = tonumber(value) if v.min and v.max then value = clamp(value, v.min, v.max) end value = round_idp(value, v.prec or precision) end return {{value,tostring(value)}} elseif (type(v.content[1]) == "function") then return exec(unpack(v.content)) else return v.content end end function UIOptions:GetOption(id) local t = str_explode(id,_opt_ ) local v = options for i=1,#t do for j=1,#v do if v[j].id == t[i] then if i == #t then v = v[j] else v = v[j].gr end break end end end return v end function UIOptions:CacheValue(path, opt, value, v) local id = cc(path , opt) -- Do a backup of current values first if (opt_backup[id] == nil) then opt_backup[id] = self:GetValue(path, opt, v) print_dbg("# Backup [%s] = %s", id, opt_backup[id]) end -- Cache changed values if (value ~= nil) and (value ~= opt_backup[id]) then opt_temp[id] = value print_dbg("/ Cached [%s] = %s", id, value) else opt_temp[id] = nil -- no need to cache current values print_dbg("~ Cleared cache [%s]", id) end -- Change text color local _id = s_gsub(id, _opt_, "_") if self._Cap[_id] and self._Cap[_id]:IsShown() then if (opt_temp[id] ~= nil) and (opt_temp[id] ~= opt_backup[id]) then self._Cap[_id]:TextControl():SetTextColor( clr_o ) else self._Cap[_id]:TextControl():SetTextColor( clr_g1 ) end end -- Update state self:UpdatePending() end function UIOptions:Stacker(path, opt, v) -- This assure that each time a control is created, an unique callback id is given to it -- Why? because in normal case, jumping between options removes the previous ones constantly, getting back to them will create new controls and assign them to the old ids -- This is bad because callbacks are still attached to the old controls, any fresh controls that get assigned to those ids will be inactive as a result -- My solution is this function to generate unique id each time a control is created if (not v.stack) then v.stack = 0 end v.stack = v.stack + 1 return cc( cc(path , opt) , v.stack) end function UIOptions:UpdatePending() local size = size_table(opt_temp) if size > 0 then self.pending:SetText( strformat( game.translate_string("ui_mm_warning_pending"), size) ) else self.pending:SetText("") end end ------------------------------------------------------------ -- Callbacks ------------------------------------------------------------ function UIOptions:OnButton_Accept() --if self.Need_VidRestart then -- self.message_box:InitMessageBox("message_box_yes_no") -- self.message_box:SetText(string.format("%s %d% s", game.translate_string("ui_mm_confirm_changes"), 15, game.translate_string("mp_si_sec"))) -- self.message_box:ShowDialog(true) --else self:On_Accept() --end end function UIOptions:OnButton_Reset() if self.last_path and self.last_curr_tree and is_not_empty(opt_temp) then local to_reset for id, val in pairs(opt_temp) do if s_find(id,self.last_path) then to_reset = true opt_temp[id] = nil local _id = s_gsub(id, _opt_, "_") if self._Cap[_id] and self._Cap[_id]:IsShown() then self._Cap[_id]:TextControl():SetTextColor( clr_g1 ) end end end if (to_reset) then self:UpdatePending() self:Reset_opt(self.last_curr_tree, self.last_path) end end if self.dlg_controls and self.dlg_controls:IsShown() then local opt = COptionsManager() opt:SetCurrentValues ("key_binding") end end function UIOptions:OnButton_Default() if self.last_path and self.last_curr_tree then self:Reset_opt(self.last_curr_tree, self.last_path, { def = true }) end if self.dlg_controls and self.dlg_controls:IsShown() then exec_console_cmd("default_controls") local opt = COptionsManager() opt:SetCurrentValues ("key_binding") end end function UIOptions:OnButton_Cancel() if is_not_empty(opt_temp) then self.message_box:InitMessageBox("message_box_yes_no") self.message_box:SetText(game.translate_string("ui_mm_discard_changes")) self.message_box:ShowDialog(true) else self:On_Cancel() end end function UIOptions:On_Accept() for id, val in pairs(opt_temp) do local v = self:GetOption(id) -- Cache the changes if (not v.curr) then print_dbg("- Saved [%s] := %s", id, val) axr_main.config:w_value(opt_section, id, val) self.Save_AXR = true end self.Change_Done = true -- Execute functors if found if v.functor then if v.postcondition then if exec(unpack(v.postcondition))then print_dbg("- Executing postcondition functor of [%s]",id) exec(unpack(v.functor)) end else print_dbg("- Executing functor of [%s]",id) exec(unpack(v.functor)) end end -- See if it needs restart if v.restart then self.Need_Restart = true end if v.vid then self.Need_VidRestart = true end -- Send callback and apply changes if v.cmd then local cmd_value = val if type(cmd_value) == "boolean" then if v.bool_to_num then cmd_value = cmd_value and "1" or "0" else cmd_value = cmd_value and "on" or "off" end end print_dbg("- Saved CMD [%s] := %s", id, cmd_value) exec_console_cmd(v.cmd .. " " .. cmd_value) self.Save_CFG = true end end -- Save axr_options if self.Save_AXR then axr_main.config:save() self.Save_AXR = false end -- Save keybinds if self.Keybinds_Shown then local opt = COptionsManager() opt:SaveValues("key_binding") opt:OptionsPostAccept() self.Save_CFG = true end print_dbg("~ Change done: %s | Game restart: %s | Vid restart: %s | Save AXR: %s | Save CFG: %s | Keybinds: %s", self.Change_Done, self.Need_Restart, self.Need_VidRestart, self.Save_AXR, self.Save_CFG, self.Keybinds_Shown) -- appdata if self.Save_CFG then print_dbg("- Saved CFG") exec_console_cmd("cfg_save") --exec_console_cmd("cfg_save tmp") end if level.present() and self.Change_Done then print_dbg("% Sent callback (on_option_change)") SendScriptCallback("on_option_change") end -- Clear cache empty_table(opt_temp) empty_table(opt_backup) -- Exit self:On_Cancel() end function UIOptions:On_Cancel() self.owner:ShowDialog(true) self:HideDialog() self.owner:Show(true) -- Restart vid if self.Need_VidRestart then exec_console_cmd("vid_restart") end if self.Need_Restart then self.owner:SetMsg( game.translate_string("ui_mm_change_done_restart") , 7 ) self.message_box:InitMessageBox("message_box_restart_game") self.message_box:ShowDialog(true) elseif self.Change_Done then self.owner:SetMsg( game.translate_string("ui_mm_change_done") , 5 ) end self.Change_Done = false self.Need_VidRestart = false self.Need_Restart = false self.Save_CFG = false self.Keybinds_Shown = false Unregister_UI("UIOptions") end function UIOptions:On_Discard() empty_table(opt_temp) if (self.last_path and self.last_curr_tree) then self:UpdatePending() self:Reset_opt(self.last_curr_tree, self.last_path) end self:On_Cancel() end function UIOptions:OnKeyboard(dik, keyboard_action) local res = CUIScriptWnd.OnKeyboard(self,dik,keyboard_action) if (res == false) then local bind = dik_to_bind(dik) if keyboard_action == ui_events.WINDOW_KEY_PRESSED then if dik == DIK_keys.DIK_ESCAPE then self:OnButton_Cancel() end end end return res end ------------------------------------------------------------ -- Keybinds ------------------------------------------------------------ class "opt_controls" (CUIWindow) function opt_controls:__init() super() end function opt_controls:__finalize() end function opt_controls:InitControls(x, y, xml, handler) self:SetWndPos(vector2():set(x,y)) self:SetWndSize(vector2():set(738,416)) self:SetAutoDelete(true) -- self.bk = xml:InitFrame("frame", self) xml:InitFrameLine ("tab_controls:cap_keyboardsetup", self) xml:InitFrameLine ("tab_controls:cap_keyboardsetup", self) xml:InitKeyBinding ("tab_controls:key_binding", self) end function trader_cond(x) if x == 'get' then -- printf('@@@ returning %s', alife_storage_manager.get_state().trader_buy_condition_override or "0 (DEFAULT)") return alife_storage_manager.get_state().trader_buy_condition_override or 0 else -- printf('@@@ setting %s', opt_temp["gameplay/economy_diff/condition_buy_override"] or '0 (DEFAULT)') alife_storage_manager.get_state().trader_buy_condition_override = opt_temp["gameplay/economy_diff/condition_buy_override"] or 0 end end ------------------------------------------------------------ -- Tutorial: How to add new options: ------------------------------------------------------------ --[[ ------------------------------------------------------------------------------------------------ Option name: script will read option name (id) and show it automatically, naming should be like this: "ui_mm_[tree_1]_[tree_2]_[tree_...]_[option]" [tree_n] and [option] are detemined from option path inside the table Example: options["video"]["general"]["renderer"] name will come from "ui_mm_video_general_renderer" string ------------------------------------------------------------------------------------------------ Option description: option description can show up in the hint window if its defined by its name followed by "_desc" Example: option with a name of "ui_mm_video_general_renderer" will show its hint if "ui_mm_video_general_renderer_desc" exists ------------------------------------------------------------------------------------------------ Parameters of option Tree: ------------------------------------------------------------------------------------------------ - [id] - Define: (string) To give a tree its own identity - [sh] - Define: (boolean) used to detemine that the sub-tree tables are actual list of options to set and show - [precondition] - Define: ( table {function, parameters} ) don't show tree options if its precondition return false - [output] - Define: (string) Text to show when precondition fails - [gr] - Define: ( table { ... } ) Table of a sub-tree or options list - [apply_to_all] - Define: (boolean) when you have options trees with similar options and group, you can use this to add "Apply to All" button to each option clicking it will apply option changes to this option in all other trees from same group you must give these a tree a group id - [id_gr] - Define: (string) allows you to give options tree a group id, to connect them when you want to use "Apply to all" button for options ------------------------------------------------------------------------------------------------ Parameters of options: ------------------------------------------------------------------------------------------------ ---------------------- Critical parameters: -------------------- These parameters must be declared for elements [id] - Define: (string) Option identity/name. Option get stored in axr_main or called in other sripts by its path (IDs of sub trees and option): Example: ( tree_1_id/tree_2_id/.../option_id ) [type] - Define: (string) - Possible values: - Option elements: "check" : Option, check box, either ON or OFF "list" : Option, list of strings, useful for options with too many selections "input" : Option, input box, you can type a value of your choice "radio_h" : Option, radio box, select one out of many choices. Can fit up to 8 selections (Horizental layout) "radio_v" : Option, radio box, select one out of many choices. Can fit up any number of selections (Vertical layout) "track" : Option, track bar, easy way to control numric options with min/max values (can be used only if [val] = 2) - Support elements: "line" : Support element, a simple line to separate things around "image" : Support element, 563x50 px image box, full-area coverage "slide" : Support element, image box on left, text on right "title" : Support element, title (left/right/center alignment) "desc" : Support element, description (left alignment) ---------------------- Dependable parameters: ---------------------- These parameters must be declared when other specific parameters are declared already. They work along with them [val] - Define: (number) - Used by: option elements: ALL Option's value type: 0. string | 1. boolean | 2. float It tells the script what kind of value the option is storing / dealing with [cmd]: - Define: (string) - Used by: option elements: ALL (needed if you want to control a console command) Tie an option to a console command, so when the option value get changed, it get applied directly to the command The option will show command's current value NOTE: cmd options don't get cached in axr_options, instead they get stored in appdata/user.ltx [def] parameter is not needed here since we engine applies default values to commands if they don't exist in user.ltx automatically [def] - Define: (boolean) / (number) / (string) / ( table {function, parameters} ) - Used by: option elements: ALL (not needed if [cmd] is used) Default value of an option when no cached values are found in axr_options, the default value will be used [min] - Define: (number) - Used by: option elements: "input" / "track": (only if [val] = 2) Minimum viable value for an option, to make sure a value stays in range [max] - Define: (number) - Used by: option elements: "input" / "track": (only if [val] = 2) Maximum viable value for an option, to make sure a value stays in range [step] - Define: (number) - Used by: option elements: "track": (only if [val] = 2) How much a value can be increased/decreased in one step [content] - Define: ( table {double pairs} ) / ( table {function, parameters} ) - Used by: option elements: "list" / "radio_h" / "radio_v": Delcares option's selection list Pairs: { value of the selection, string to show on UI } Example: content= { {0,"off"} , {1,"half"} , {2,"full"}} So the list or radio option will show 3 selections (translated strings): (ui_mm_lst_off) and (ui_mm_lst_half) and (ui_mm_lst_full) When you select one and it get applied, the assosiated value will get applied So picking the first one will pass ( 0 ) [link] - Define: (string) - Used by: support elements: "image" / "slide" Link to texture you want to show [text] - Define: (string) - Used by: support elements: "slide" / "title" / "desc" String to show near the image, it will be translated ---------------------- Optional parameters: ---------------------- These parameters are completely optionals, and can be used for custom stuff [force_horz] - Define: (boolean) - Used by: option elements: "radio_h" Force the radio buttons into horizental layout, despite their number [no_str] - Define: (boolean) - Used by: option elements: "list" / "radio_h" / "radio_v" / "track" Usually, the 2nd key of pairs in content table are strings to show on the UI, by translating "opt_str_lst_(string)" when we set [no_str] to true, it will show the string fromm table as it is without translations or "opt_str_lst_" For TrackBars: no_str won't show value next to the slider [prec] - Define: (number) - Used by: option elements: "track" allowed number of zeros in a number [precondition] - Define: ( table {function, parameters} ) - Used by: option elements: ALL Show the option on UI if the precondition function returns true [functor] - Define: ( table {function, parameters} ) - Used by: option elements: ALL Execute a function when option's changes get applied [postcondition] - Define: ( table {function, parameters} ) - Used by: option elements: ALL, with defined [functor] Option won't execute its functor when changes are applied, unless if the postcondition function returns true [curr] - Define: ( table {function, parameters} ) - Used by: option elements: ALL get current value of an option by executing the declared function, instead of reading it from axr_options.ltx [hint] - Define: (string) - Used by: option elements: ALL Override default name / desc rule to replace the translation of an option with a custom one, should be set without "ui_mm_" and "_desc" Example: { hint = "alife_warfare_capture"} will force the script to use "ui_mm_alife_warfare_capture" and "ui_mm_alife_warfare_capture_desc" for name and desc of the option [clr] - Define: ( table {a,r,b,g} ) - Used by: support elements: "title" / "desc" determines the color of the text [stretch] - Define: (boolean) - Used by: support elements: "slide" force the texture to stretch or not [pos] - Define: ( table {x,y} ) - Used by: support elements: "slide" custom pos for the texture [size] - Define: ( table {w,z} ) - Used by: support elements: "slide" custom size for the texture [align] - Define: (string) "l" "r" "c" - Used by: support elements: "title" determines the alignment of the title [spacing] - Define: (number) - Used by: support elements: "slide" hight offset to add extra space --]]