Skip to content

Instantly share code, notes, and snippets.

@zneix
Last active July 25, 2023 13:28
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save zneix/fb99059520fe94cfcfaaefe8d02af6db to your computer and use it in GitHub Desktop.
zneix's DorHUD user.lua file
-- zneix's DorHUD configuration, available @ https://gist.github.com/zneix/fb99059520fe94cfcfaaefe8d02af6db or https://cdn.zneix.eu/pdthmods/user.lua
-- note to self, view diff compared to what's online with: gh gist view fb99059520fe94cfcfaaefe8d02af6db -f user.lua | git diff - user.lua
-- some things in here might require an additional mod of mine; get it here: https://github.com/zneix/zneixs_fixes
local is_first_load = ...
local always_reload = true -- if true, always use values defined in this file and thus ignoring any dynamic changes; default false
local prioritize_gui = false -- if true, config values defined in this file won't overwrite any existing settings set with the gui; default false
-- helper functions
-- escape left square bracket in s so that they aren't parsed as colours
local function clear_string(s)
return (string.gsub(s, "%[", "%[%["))
end
-- remove leading and trailing spaces from s
local function trim(s)
return (string.gsub(s, "^%s*(.-)%s*$", "%1"))
end
-- localize an integer value to make it look prettier to a user
local function format_integer(integer) -- returns string
local reversed_integer = string.reverse(tostring(integer))
-- insert commas every three digits, remove trailing commas
local formatted_integer = reversed_integer:gsub("(%d%d%d)", "%1,"):gsub(",$", "")
-- reverse the formatted number back to its original order. keep in mind that returned type is a string
return formatted_integer:reverse()
end
-- iso for the win (to be used as a format for os.date())
local iso8601 = "%Y-%m-%d %H:%M:%S"
-- more colours
-- [name] sets the color by name, but there's only a handful defined by default (add new with e.g. Color.orange = Color("FF9900"))
-- [#aarrggbb] sets the color by hex value (I think some places actually use [#rrggbbaa], e.g. menu_waiting_is_{,not_}ready)
-- [] sets the color to the previous value
-- [[ escapes the left bracket
Color.nice_blue = Color("7DEEFF")
Color.orange = Color("FF9900")
Color.grey = Color(.7, .7, .7)
Color.blueish = Color("B3FCE5")
Color.golden = Color("FFCF7D")
Color.assault = Color(1, .9, .2, .2)
Color.assault_break = Color(.9, 0, 1, 0)
Color.cheat = Color("FF8E7C")
Color.team_ai = Color(1, 0.2, 0.8, 1)
Color.meds = Color("00EFC3")
Color.ammo = Color("A85600")
Color.regen = Color("6B00EF")
Color.down = Color("FC1B6E")
Colors = Color -- declare an alias to prevent very rare crashes in some places
-- helper variables for localization overrides
local loc_peer = "[peer_color]$PLAYER_NAME;[] "
local loc_self = "[peer_color]You[] "
local loc_meds = "[meds]took MEDS[] [DOWNS;#FC5D5D;#FFFFFF]$REGEN_PERCENT;%[], [meds]($DOWNS_DIFF;/$TOTAL_DOWNS; downs)"
local loc_ammo = "[ammo]took AMMO [AMOUNT;#FC5D5D;#FFFFFF]$AMOUNT_PERCENT%.2f;%"
local loc_down = "[down]went DOWN [DOWNS;#FFFFFF;#FC5D5D]$DOWNS;[]/$TOTAL_DOWNS;"
local localization = {
menu_setup_game = "SUFFERING",
menu_players_online = "$COUNT; POOR SOULS",
menu_start_the_game = "THROW ANOTHER RUN",
menu_play_online = "NOOBS",
menu_play_with_friends = "GOOD PLAYERS",
menu_play_campaign = "MULTIPLAYER",
menu_play_single_player = "SINGLEPLAYER",
menu_visit_forum = "FORUM",
-- mask names
menu_mask_gold = "GOLD",
menu_mask_platinum = "PLATINUM",
menu_mask_pmp1_pbm = "BAG OF SHAME", -- I use this mask whenever I feel very embarassed or sad
menu_mask_santa = "DUSSEL", -- yes
-- requires "zneixs_fixes" v1.0.2 or newer
menu_waiting_is_not_ready = "[#e53333ff]NOT READY",
menu_waiting_is_ready = "[#00ff00e5]READY",
-- handguns
debug_glock = "WATERGUN",
debug_raging_bull = "BRONCO",
debug_c45 = "CROSSKILL",
debug_beretta92 = "B9",
-- primary weapons
debug_hk21 = "BRENNER",
debug_r870_shotgun = "REINBECK",
debug_m14 = "M308",
debug_ak47 = "AK",
debug_test_raycast_weapon = "AMCAR",
debug_m4 = "AMCAR", -- used by managers.player
-- secondary weapons
debug_mossberg = "LOCO",
debug_m79 = "GL",
debug_mp5 = "COMPACT 5",
debug_mac11 = "MARK 11",
debug_upgrade_mr_nice_guy = "MS NICE GAL",
debug_russian = "RUSSIAN",
debug_american = "AMERICAN",
debug_german = "GERMAN",
debug_spanish = "SPANISH",
debug_mugshot_electrified = "TASED",
debug_mugshot_downed = "DYING",
debug_mugshot_in_custody = "DEAD",
debug_low_ammo = "FIVE BULLETS LEFT",
debug_no_ammo = "AMMUNITION DEPLETED", -- why not pretend heisters are wearing H.E.V. suits
-- heist names
debug_bank = "FIRST WORLD DANK",
debug_street = "HELL STREET",
debug_apartment = "PANIK ROOM",
debug_bridge = "GREEN FRIDGE",
--debug_diamond_heist = "",
--debug_slaughter_house = "",
debug_suburbia = "C4UNTERFEIT",
--debug_secret_stash = "",
--intro_secret_stash = "",
--debug_hospital = "",
mask_check_cheater = "Player [peer_color]$PLAYER_NAME;[] [[$PLAYER_LEVEL;] [cheat]DOES NOT[] have the $MASK; mask set!",
hint_reload = "DON'T FORGET TO RELOAD MR FREEMAN",
-- TODO: make player names in the hints below use corresponding colours, see https://discord.com/channels/575788361046818837/575793076291764230/998664262287380562
--hint_you_were_rescued (uncuffed, guessing the id)
--hint_you_were_helpedup = "[teammate_color]YOU[] HAVE BEEN HELPED UP BY [helper_color]$HELPER;[]!",
--hint_you_were_revived = "[helper_color]$HELPER;[] TRADED A HOSTAGE AND GOT [teammate_color]YOU[] OUT OF CUSTODY!",
--hint_you_rescued = "[helper_color]YOU[] UNCUFFED [teammate_color]$TEAMMATE;[]!",
--hint_you_helpedup = "",
--hint_you_revived = "[helper_color]YOU[] RELEASED [teammate_color]$TEAMMATE[] FROM CUSTODY!",
--hint_teammate_rescued = "[teammate_color]$TEAMMATE;[] HAS BEEN UNCUFFED BY [helper_color]$HELPER;[]",
--hint_teammate_helpedup = "[teammate_color]$TEAMMATE;[] HAS BEEN HELPED UP BY [helper_color]$HELPER;[]!",
--hint_teammate_revived = "[teammate_color]$TEAMMATE;[] HAS BEEN RELEASED FROM CUSTODY THANKS TO [helper_color]$HELPER;[]!",
-- hint_teammate_arrested (has been cuffed)
-- hint_teammate_downed = "$TEAMMATE; WAS DOWNED IN $LOCATION;!",
-- hint_teammate_dead = "$TEAMMATE; IS IN CUSTODY!",
-- also show amount of unacknowledged packets on the extras panel
hud_player_ping = "$PING;ms $UNACKNOWLEDGED;",
-- taking meds
hud_chat_used_med_bag = loc_peer .. loc_meds,
hud_chat_player_used_med_bag = loc_self .. loc_meds,
-- regenerating, most likely due leveling up (same result as if you'd take meds + take ammo)
hud_chat_downs_restore = loc_peer .. "[regen]has regenerated",
hud_chat_player_downs_restore = loc_self .. "[regen]have regenerated",
-- taking ammo
hud_chat_ammo_taken = loc_peer .. loc_ammo,
hud_chat_player_ammo_taken = loc_self .. loc_ammo,
-- getting downed
hud_chat_downs = loc_peer .. loc_down,
hud_chat_player_downs = loc_self .. loc_down,
}
local welcome_text = "Welcome, my lobby is using DAHM, version " .. D:version() -- re-used by the main welcome message, used in a hacky way inside pre_show_callback but works
local config = {
override_user_config_with_gui_settings = prioritize_gui, -- prioritize this file instead of the gui config if set to false
framerate_limit = 130, -- sets maximum FPS to this value; vanilla game has an cap of 130 FPS which is most optimal to use. Going far above said cap may have impact on the gameplay.
--debug_show_raw_text_strings = true, -- makes game show string IDs instead of actual strings, useful while finding string IDs to later replace them in "localization" table
banlist_path = "mods/banlist.csv", -- custom path to the banlist; I like keeping things organized under the same directory
chat_log_to_file = "logs/chat.log", -- logs ALL chat output to this file
updater_allow_beta_versions = true, -- check for beta updates / prefer beta version of dorhud
notify_outdated = true,
notify_self = true,
-- messages shown to other players (and me) whenever they join my lobby
welcome_messages = {
{
text = welcome_text,
new_peers_only = true,
host_only = true,
as_lobby = true,
options = {
--dummy_message = true,
--skip_local = false,
pre_show_callback = function(peer, is_new)
if Util:is_in_state("any_ingame_playing") then
return welcome_text .. "\n The heist has already started.", nil -- text override, options object override
end
end
}
},
-- inform peers if we're playing unpatched UC
{
text = "WARNING: this lobby has disabled DAHM's Undercover fix! Expect bugged specials.",
new_peers_only = false, -- show this to everyone regardless of whether they've already been in the lobby (similar to ovk_193/mutator motds)
host_only = true,
as_lobby = true,
options = {
priority = 10, -- better if it's sent later, I think...
visibility_fn = function(peer, is_new)
return (D:conf("disable_mission_fixes_undercover") or D:conf("disable_mission_fixes")) and (Global.level_data and Global.level_data.level_id == "secret_stash")
end,
},
},
},
--== chat interface
debug_cml_show_add_character_calls = false, -- prints calls to "add_character" game function, requires "character_n_mask_in_loadout" mod
cml_always_show_chat = true, -- always shows chat while in loadout menu, requires "character_n_mask_in_loadout" mod
chat_enable_singleplayer_input = true, -- enable chat (while in-game) in singleplayer
chat_alt_clipboard_mode = true, -- enables Ctrl+C, Ctrl+V, Ctrl+X, Ctrl+A in chat, requires DAHM 1.15.2.0 or newer
chat_input_history_limit = 80,
chat_height_multiplier = 3.6, -- general chat height multiplier
chat_height_multiplier_ingame = 5, -- chat height multiplier (ingame chat only)
chat_input_width_multiplier = 2.5, -- chat width multiplier (ingame chat only)
--chat_output_position_override = { x = 100, y = 250, is_relative_offset = false }, -- move chat output too (100;250) (ingame chat only)
invalid_chat_command_notify = true, -- don't send invalid commands to chat
chat_split_uc_sender = true, -- reference: https://discord.com/channels/575788361046818837/575793146987020292/1096352936117932123
zfx_chat_lobby_message_title_color = Color("00FFFF"), -- set custom message title's colour for non-player messages, requires "zneixs_fixes" v1.0.3 or newer
--== player verification/checking/in-game anticheat
profile_checker_ban_days_to_report = nil, -- by default, VAC bans older than 1111 days are ignored, but I don't want to ignore these at all
--profile_checker_ignore_fail_callback = true,
perform_playtime_check = true, -- check total players' playtime when we first see them
check_result_always_visible = false, -- spammy if true; show all profile check results, even the valid ones
--anticheat_extra_desync_time = 0, -- some events happen in the wrong order and desync can mess up the detection
anticheat_notify_sender = false, -- don't send a message to a cheater if we detect something, they don't need to know
anticheat_verify_bullet_damage = true, -- verify that bullet damage does not exceed weapon limits
anticheat_verify_damage_against_loadout = true, -- use equipped weapons for damage calculations
anticheat_invalid_bullet_damage_publish = true, -- publish incorrect bullet damage
--== bugfixes/mission-related
ovk_193_ammo_respawn = false, -- controls the amount of ammo clients respawn with, default: nil (ovk_193 mod explicitly checks for this being set to false to not respawn with full ammo)
bugfixes_show_time_correction_in_chat = true, -- at the end of the heist show corrected endgame time
--disable_mission_fixes = true, -- disables all DAHM's mission fixes on all heists
--disable_mission_fixes_undercover = true, -- for true hell on undercover
--== in-heist interface/misc options
ai_mask_set_override = {
--[[dallas]] russian = { "troll", "tester", "santa" },
--[[hoxton]] american = { "tester", "clowns" },
--[=[wolf]=] german = { "troll", "halloween" },
--[[chains]] spanish = { "troll", "bf3" },
}, -- makes team AI wear specified mask set (option can be set to a simple string with mask set name for all team AI)
hints_blacklist = {
"take_hostages", -- bad advice in general, it's blacklisted by default
"cant_stand_up", -- most annoying yet useless hint EVER
"civilian_escaped", -- brings more confusion (e.g. making you think a teammate was downed) than benefit
},
zfx_always_full_reload_ak = true, -- requires "zneixs_fixes" v1.0.4 or newer
skip_intro_auto_skip_on_level = true, -- always skip all intros, some people might not like it but it fits me
--== pre-heist interface options (lobby/game browser)
--create_ban_player_menu_item = true, -- bugged, TODO: I should investigate this
lobby_show_recreate_button = true, -- shows 'RE-REGISTER LOBBY' button
replace_ingame_invite = true, -- collapses 2 silly vanilla menu entries into 1
debug_add_reputation_permission = { "146", "169" }, -- adds an extra reputation requirement(s) which can be used while hosting
zfx_show_difficulty_in_lobby_browser = true, -- shows the heist difficulty in lobby browser, requires "zneixs_fixes" v1.0.3 or newer
--debug_insert_dummy_lobby = true, -- shows a fake lobby in the lobby browser
player_verification_mugshot_local_peer_color = "orange", -- sets outline of my own mugshot in the lobby/kitmenu to a nice orange colour
--== HUD-related options
hud_prefer_virtual_reps = true,
hud_present_virtual_level_up = true, -- show own virtual levelups
--hud_allow_virtual_rep_sync = true,
hud_show_all_completed_challenges = true,
--hud_show_all_completed_challenges_inclusion_list = false, -- we use an exclusion list instead to display everything except the ones below
hud_show_all_completed_challenges_exclusion_list = "civil_disobedience eagle_eyes bullet_to_bleed_out intimidating revived diplomatic arrested deploy_.+ tiedown_%w+ fall_to_bleed_out .+_no_civilians_hard .+_no_deaths_hard .+_no_bleedouts_hard .+_success_overkill .+_overkill_no_trade .+_success_overkill_%d+ christmas_present.* duck_hunting det_gadget saviour five_five_five citys_finest akimbo", -- counter stuff is ignored anyway
hud_bleedout_time_threshold = 5, -- a down is considered critical if at most this many seconds
hud_show_multikills = 3, -- minimal required amount of enemies killed at once to trigger multikill indicator (e.g. "x5") for a brief moment
hud_show_collected_money_at_max_level = true, -- show cash pickups even if at 193/194 reputation
hud_hide_name_labels_in_steelsight = false,
hud_hide_waypoints_in_steelsight = true,
-- player's hud
hud_show_loadout_deployable = true,
hud_show_loadout_weapons = true,
hud_xp_panel_style = "virtual_rep_with_progress2",
hud_hidden_gui = "-ammo_clip_icons",
hud_ammo_format = "%2$s / %1$s", -- "payday ammo" format: remaining bullets left in clip / remaining bullets total (just like in pd2)
-- mugshot
hud_show_mugshot_timers = true, -- show downed timers on the mugshots as well
hud_show_peer_ids = true, -- show ID in front of peer names on mugshots
hud_name_marker_obj_override = { use_chat_colors = true }, -- override object for showing peer IDs in respective chat colours
hud_show_host_mark = ">> ", -- add an indicator to the host's name on their mugshot (suppressed if "hud_show_peer_ids" is set to true)
hud_name_label_format = "$NAME; [[[peer_color]$LEVEL;[]]", -- add colors to the name (above player) label
hud_mugshot_name_format = "$NAME; [[[peer_color]$LEVEL;[]]", -- add colors to the mugshot (on hud) name
hud_ai_mugshot_name_format = "[team_ai]$NAME;[]",
--hud_mugshot_ai_test = true, -- makes AI's mugshots behave like regular player's while hosting or smth, for testing purposes
--hud_name_label_ai_test = true,
--hud_extras_panel_show_chat_colors = true,
hud_equipment_weapon_mark_enabled = true, -- show an indicator for currently selected weapon by the criminal on the corresponding mugshot
hud_hide_deployable_when_used = "transparent", -- accepts: "transparent", "darken", "remove"(? check hud/modhooks.lua:"OnCommand deployed")
hud_equipment_disabled_alpha = .3,
hud_equipment_disabled_rgb = .7,
-- show teammates' (and own) actions in chat
hud_show_peer_downs = "always", -- shows others' downs on mugshot
hud_show_player_downs = "always", -- shown own downs on mugshot
hud_show_downs_restore_in_chat = "all", -- show meds taken / levelup regenerations in chat (everyone)
hud_show_ammo_taken_in_chat = "all", -- shows ammo taken in chat (everyone)
hud_show_downs_in_chat = "all", -- shows downs in chat (others); can also be true
hud_show_player_downs_in_chat = "all", -- shows downs in chat (own)
hud_chat_critical_downs_only = false, -- don't ignore any downs
hud_hide_player_downs = false, -- we don't want to ignore our own downs
-- overriding all sorts of colours in the hud, only available since DAHM 1.16.1.4
hud_color_overrides = {
mugshot = {
weapon_outline = Color.orange,
weapon = Color.white:with_alpha(.7),
deployable = {}, -- seems like nested values are needed to be reposted or else tablex.merge will unset/delete dor pls fix (or not)
},
health = {
name = Color(0, 0, 0, 0), -- just give it zero opacity to simply "hide it"
},
},
--== stats line
-- hud_str vars:
-- 1: session timer
-- 2: "hud_kills_str" variable
-- 3: assault timer
-- 4: difficulty
-- 5: heist name
-- hud_kills_str vars:
-- 1: total kills
-- 2: total specials kills
-- 3: civs killed (str, conf:hud_kills_civs_str)
-- 4: total head shots
-- 5: accuracy (float)
-- 6: shield kills
-- 7: spooc kills
-- 8: taser kills
-- 9: tank kills
-- 10: total head shots ratio (float)
-- 11: kills per minute (float)
-- 12: total shots
-- 13: total hits
-- 14: weapon accuracy (float)
-- 15: weapon shots
-- 16: weapon hits
-- new variables introduced in 1.15.2.0-beta5 (on earlier versions using these will crash!)
-- 17: weapon damage
-- 18: weapon damage per minute
-- 19: weapon damage per shot
-- 20: damage
-- 21: damage per minute
-- 22: damage per shot
-- 23: weapon total kills
-- xx: weapon total specials kills -- unused(?)
-- 24: weapon head shots
-- 25: weapon head shot ratio
-- 26: weapon kills per minute
--hud_offset_x = 62, -- integer pixel offset from the left
--hud_offset_y = 30, -- integer pixel offset from the bottom
hud_str = "[white]%5$s[] %4$s %2$s %1$s %3$s",
hud_kills_str = "[blueish]kills[] [white]%1$i[] [[[orange]kpm %11$.1f[] [#00ffff]hs %10$.1f%%[]] [blueish]specs[] [white]%2$i[] [[[#adcad9]S %6$i[] [#ffff00]T %8$i[] [#00ff00]C %7$i[] [#E67300]D %9$i[]] [#80A0FF]civ %3$s[] [blueish]accuracy[] [[%16$i/%15$i [white]%14$.1f%%[] %13$i/%12$i [white]%5$.1f%%[]]",
hud_assault_timer_str = "[assault]/// [#fc9b99]%1$s[] /// ASSAULT[]", -- "/// 00:00:00 ///", everything is red, but the timer is lighter
hud_enable_assault_break_timer = true, -- makes the assault timer also count time during assault breaks
zfx_assault_break_timer_str = "[assault_break]/// [#6cfc6c]%1$s[] /// CONTROL[]", -- (check #50fc50 as well)
hud_kills_civs_relevant_str = "%2$i/%1$i", -- relevant/total (opposite of what's by default)
hud_sl_time_precision = 0, -- amount of decimal precision in the 'session timer' in "hud_str" (max 3)
zfx_disable_assault_image = true, -- we already have the assault timer on the stats line, so there's no need for an another indicator
-- short abbreviations for map names (used by stats line)
hud_level_names = {
bank = "FWB",
heat_street = "HS",
bridge = "GB",
apartment = "PR",
diamond_heist = "DH",
slaughter_house = "SH",
suburbia = "CF",
secret_stash = "UC",
hospital = "NM",
},
-- short abbreviations of difficulty names (used by stats line), colours taken from Steam statistics page (and https://pdthlbs.net/stats_hsr.php)
hud_difficulty_names = {
easy = "[#0099cc]EASY[]",
normal = "[#99cc00]NORM[]",
hard = "[#ffcc00]HARD[]",
overkill = "[#ff6600]OVKL[]",
overkill_145 = "[#cc0000]145+[]",
overkill_193 = "[#dccc00]193+[]",
},
--== rich presence, always publish all sorts of information about the currently played heist to both Discord and Steam (because why not, I have nothing to hide)
discord_rpc_set_character = true,
discord_rpc_set_time = true,
steam_publish_game_status = true,
steam_publish_party_details = true,
steam_publish_player_names_in_private_lobbies = true,
steam_publish_player_names = true,
steam_publish_game_override = true,
steam_publish_singleplayer = true,
steam_publish_details_in_singleplayer_mode = true,
--== logging options, be careful
log_level = 5, -- 6 is highest, but it's too dank, 3/4 is optimal
--hud_log_level = 3,
--debug_hook_call_logging = 45,
--debug_hook_call_orig_logging = true,
debug_print_to_log = true, -- shows output of "print" function calls
debug_hook_call_blacklist = {
module = { ["interact_toggle"] = 1 },
fname = {
["update"] = 1,
["update_queue"] = 1,
["paused_update"] = 1,
["update_timers"] = 1,
["input_multi_choice"] = 1,
["input_kitslot"] = 1,
["input_text"] = 1,
["is_active"] = 1,
["mouse_moved"] = 1,
["dropin_progress"] = 1,
},
class = {
["LocalizationManager"] = 1,
["hud:StatisticsManager"] = 1
},
class_fn = {
["MenuInput.mouse_moved"] = 1,
["MenuInput.input_item"] = 1,
["?.script_data"] = 1,
["HUDManager._update_name_labels"] = 1,
["MenuNodeGui._highlight_row_item"] = 1,
["MenuNodeGui._fade_row_item"] = 1,
["HUDManager.update_hud_text"] = 1,
["ConnectionNetworkHandler:dropin_progress"] = 1,
},
},
}
-- Explicitly disable some mods without having to remove/delete them:
local blacklisted_modules = {
"reset_stats_achievements",
"ak_for_teamai", -- only made it for SkullHD, not gonna use it personally though
"every_drill_7000", -- xd
}
-- Chat commands which just print text to chat and do nothing else
local commands = {
dz = "Watch out! Buldozer!",
escort = "when you shout at an escort once and stay close to him you don't have to shout again (as long as there's no cops near it)",
bags = "Rule #1, always double check your load out before going on a heist. One of you idiots must have switch the bag. How can you guys fucked this up?!?!?! You play this everyday.",
dussel = "Each team needs a leader. Listen to him. Do what he says. If he's an idiot you still can choose not to listen, but because you've checked his profile you know if he succeeded this heist in the past or not.",
}
-- Show in chat how much ammo I have left
D:register_chat_command("ammo", "GAME", function(args)
local player_unit = managers.player:player_unit()
if not alive(player_unit) then
return true
end
local inventory = player_unit:inventory()
if not inventory then
return true
end
local chat_msg = ""
for _, weapon in ipairs(inventory._available_selections) do
local weapon_base = weapon.unit:base()
chat_msg = chat_msg .. string.format("%s %s/%s ", localization["debug_" .. weapon_base.name_id] or weapon_base.name_id, weapon_base._ammo_total, weapon_base._ammo_max)
end
Util:chat_message(trim(chat_msg), true, false) -- change second argument to false to send the message only locally (e.g. for debugging purposes)
return true
end)
-- Sometimes, dunno why, "hud" module does not send a request to some peers for dispatching interation progress information to our client
-- This command sends such request manually, helpful if you can't see interaction progress of some players even if they have DAHM installed
D:register_chat_command("rqi", "GAME", function(args)
local peer_id = tonumber(args:match("%S+"))
if not peer_id or not managers.network or not managers.network:session() then
return
end
local peer = managers.network:session():peer(peer_id)
if peer ~= nil and not peer:is_local_user() then
DNet:send_to_peer(peer, "ModEvent", { module = "hud", event = "EnableInteractionEvents" }, false, false)
end
end)
-- little something for CZ to easily toggle vrep being shown to others
D:register_chat_command("vrep", function(args)
local vrep_setting = "hud_allow_virtual_rep_sync"
local cmd_prefix = D:conf('chat_command_prefix') or '/'
local first_arg = args:match("%S+")
local setting_value = nil
if first_arg == nil or first_arg == "" then
Util:chat_message("your vrep sync is: " .. (D:conf(vrep_setting) and "[#00ff00]enabled" or "[#ff0000]disabled"), false, "LOCAL")
return
end
if first_arg == "yes" or first_arg == "true" or first_arg == "1" or first_arg == "on" then
setting_value = true
elseif first_arg == "no" or first_arg == "false" or first_arg == "0" or first_arg == "off" then
setting_value = false
end
if setting_value == nil then
Util:chat_message("bad arguments, syntax: " .. cmd_prefix .. "vrep <on|off>", false, "LOCAL")
return
end
D:process_chat_input(cmd_prefix .. "set " .. vrep_setting .. " = " .. tostring(setting_value))
D:process_chat_input(cmd_prefix .. "persist")
end)
D:register_chat_command("calc_rep", function(args)
if not managers.experience._calculate_vrep_from_money then -- just to not make people's game crash in some places, maybe... not gonna keep this check for a long while anyway
Util:chat_message("update your DAHM, silly. this piece of code needs version 1.16.1.3 or above", false, "LOCAL")
return
end
local cmd_prefix = D:conf('chat_command_prefix') or '/'
local value = tonumber(args and args:match("^(%d+)"))
if value == nil then
Util:chat_message("bad arguments, syntax " .. cmd_prefix .. "calc_rep <cash amount|level>", false, "LOCAL")
return
end
-- assume we're giving a level and want cash if it's 5000 or below (since that's maximum vrep anyway)
-- or otherwise, giving cash and seeing which level it gets up otherwise
if value > 5000 then
local rep = managers.experience:_calculate_vrep_from_money(value)
Util:chat_message("Reputation achieved with [#00ff00]" .. format_integer(value) .. "[] cash: [#ff0000]" .. rep, false, "LOCAL")
elseif value > 0 then
local cash = managers.experience:_get_required_money_for_level(value)
Util:chat_message("Cash needed to reach rep [#ff0000]" .. tostring(value) .. "[]: [#00ff00]" .. format_integer(cash), false, "LOCAL")
else
-- silly goose, invalid value (maybe give some feedback in chat? prob not needed)
end
end)
-- /r command for reloading config
D:register_command("r", function()
local userfile, err = D:root_path() .. 'user.lua'
if io.is_readable(userfile) then
local userfile_f
userfile_f, err = loadfile(userfile)
if userfile_f then
local success, ret = pcall(userfile_f, true)
if success then
-- update some stuff to make use of newly loaded config
if managers.hud then
managers.hud:update_hud_settings()
end
Util:chat_message("Config has been reloaded.", false, "DEBUG")
else
err = ret
end
end
else
err = "user.lua file is not readable"
end
if err then
Util:chat_message("Config cannot be reloaded: " .. tostring(err), false, "DEBUG")
end
end)
-- Override existing keybinds and add new ones
local keybind_overrides = {
hud_scroll_chat_up = "left alt + k",
hud_scroll_chat_down = "left alt + j",
hud_toggle_grayscreen = "num 5",
}
--module:hook("OnKeyPressed", "hud_scroll_chat_up", nil, { run_in_chat = true }, function() scroll_chat("up") end, false)
--module:hook("OnKeyPressed", "hud_scroll_chat_down", nil, { run_in_chat = true }, function() scroll_chat("down") end, false)
D:register_keybind("toggle_sfx_mute", "f3", function()
if not MenuCallbackHandler then return end -- make sure MCH is available
D._menu_cb_handler = D._menu_cb_handler or MenuCallbackHandler:new()
D._menu_cb_handler:set_sfx_volume({ value = function()
if D._sfx_volume_level then
local lvl = D._sfx_volume_level
D._sfx_volume_level = nil
return lvl
else
D._sfx_volume_level = 3
return 0
end
end})
end)
D:register_keybind("kb_toggle_fullscreen", "f11 - left alt", function()
local fullscreen = not RenderSettings.fullscreen
managers.viewport:set_fullscreen(fullscreen)
setup:add_end_frame_clbk(function()
local brightness = managers.user:get_setting("brightness")
Application:set_brightness(brightness)
end)
end)
local fov_zoom_values = { 25, 50, 67, 75 }
local function get_fov_value(should_decrease)
local zoom_lvl
if type(D._fov_zoom_lvl) ~= "number" then
zoom_lvl = 0
elseif should_decrease then
if D._fov_zoom_lvl == 0 then
return nil -- prevent overlapping
end
zoom_lvl = (D._fov_zoom_lvl + #fov_zoom_values - 1) % #fov_zoom_values
else
if D._fov_zoom_lvl + 1 == #fov_zoom_values then
return nil -- prevent overlapping
end
zoom_lvl = (D._fov_zoom_lvl + 1) % #fov_zoom_values
end
D._fov_zoom_lvl = zoom_lvl
return fov_zoom_values[zoom_lvl + 1] -- lua indices, my favourite...
end
local function change_fov_zoom(fov)
if not fov then
return
end
if not managers.user then
dlog_ll(1, "UserLua", "> WARNING: UserManager isn't available?!")
end
dlog_ll(3, "UserLua", "> setting fov_zoom to", fov)
managers.user:set_setting("fov_zoom", fov)
-- give some visual feedback about the change we've made
managers.hud:show_hint({
text = "zoom fov set to: " .. tostring(fov),
time = 1,
})
-- update the zoom fov in game, copied from "lib/managers/menumanager.lua" MenuCallbackHandler:set_fov_zoom
if alive(managers.player:player_unit()) then
local plr_state = managers.player:player_unit():movement():current_state()
local stance = plr_state._in_steelsight and "steelsight" or plr_state._ducking and "crouched" or "standard"
plr_state._camera_unit:base():set_stance_fov_instant(stance)
end
end
-- in order for the above to work, you have to unbind the "change weapon" keybinds
D:register_keybind("kb_fov_zoom_increase", "mouse wheel down", "GAME", "PRESSED", function() change_fov_zoom(get_fov_value(false)) end)
D:register_keybind("kb_fov_zoom_decrease", "mouse wheel up", "GAME", "PRESSED", function() change_fov_zoom(get_fov_value(true)) end)
local visual_upgrades = {
["hk21"] = "hk21_recoil2", -- brenner scope
["m4"] = "m4_spread4", -- amcar scope (my beloved)
["m14"] = "m14_spread2", -- m308 scope
["ak47"] = "ak47_spread1", -- ak scope
["m79"] = "m79_expl_range2", -- gl40 range finder (thing on the left)
}
-- toggle currently held weapon's sight with a keybind
D:register_keybind("toggle_visual_weapon_upgrade", "num 4", "GAME", function()
if not MenuCallbackHandler then
return
end
local player_unit = managers.player:player_unit()
if not alive(player_unit) then
return
end
local inventory = player_unit:inventory()
if not inventory then
return
end
local weapon = inventory._available_selections[inventory._equipped_selection]
if not weapon then
return
end
local weapon_base = weapon.unit:base()
local upgrade = visual_upgrades[weapon_base.name_id]
if not upgrade then
dlog_ll(3, "UserLua", "no visual upgrade for", weapon_base.name_id)
return
end
dlog_ll(1, "UserLua", "toggling visual upgrade", upgrade)
D._menu_cb_handler = D._menu_cb_handler or MenuCallbackHandler:new()
D._menu_cb_handler:toggle_visual_upgrade({
parameters = function()
return { upgrade_id = upgrade }
end
})
end)
dlog("Loading user script")
-- list of some game-altering mods which are not suspicious and considered normal/ok to use
local GAMods_whitelist = {
["interact_toggle"] = true,
["restart_end_job"] = true,
["restore_deployables"] = true,
["corpse_despawn"] = true,
["overdrill7200"] = true,
["crybaby"] = true,
["Warmod"] = true,
["ovk_193"] = true, -- older versions of DorHUD (<=1.11) report this as a GA mod
["Flashlight"] = true, -- PlayingHazard has a mod for toggling flashlight state client-side for his testing purposes
--["wtfbm"] = true, -- I like to know whenever someone I am playing with uses this, so I keep this commented out
}
-- my hooks
-- locally show DAHM version of others when their clients send it; TODO: make it print only 1 message but reset it when chat clears
local function handle_DorHUDModVersion(peer, data)
if peer:preference("userlua_shown_version_msg") then
return
end
peer:set_preference("userlua_shown_version_msg", true)
Util:chat_message(string.format("[golden][peer_color]%s[] is using DAHM, version [][nice_blue]%s", clear_string(peer:name()), tostring(data)), false, true, { subject_peer = peer })
end
-- locally show whenever a lobby is re-registered
local function handle_UpdatedLobbyID(peer, data)
Util:chat_message("[golden]lobby has been re-registered to [nice_blue]steam://joinlobby/24240/" .. tostring(data), false, "DEBUG")
end
-- report whenever someone has some Gameplay Altering mods loaded (NOTE: it doesn't mean they're using them RIGHT NOW, but they have reported mods loaded through DAHM)
local function handle_GAMods(peer, data)
if type(data) ~= "table" then
return -- received malformed data
end
local sus_mods = "" -- string containing list of suspicious mod names
for k, _ in pairs(data) do
if not GAMods_whitelist[k] then
sus_mods = string.format("%s %q", sus_mods, k)
end
end
if sus_mods ~= "" then
dlog_ll(2, "UserLua", "> sus mods: ", trim(sus_mods))
Util:chat_message(string.format("[golden][peer_color]%s[] has suspicious Gameplay Altering mod(s) active: [nice_blue]%s", clear_string(peer:name()), trim(sus_mods)), false, "DEBUG", { subject_peer = peer })
end
end
-- use one hook for all DAHM's events to be more efficient than hooking each function separetly
D:hook("OnNetworkDataRecv", "OnNetworkDataRecv_UserLuaHooks",
{
"DorHUDModVersion",
"UpdatedLobbyID",
"GAMods",
}, function(peer, data_type, data)
if data_type == "DorHUDModVersion" then
handle_DorHUDModVersion(peer, data)
elseif data_type == "UpdatedLobbyID" then
handle_UpdatedLobbyID(peer, data)
elseif data_type == "GAMods" then
handle_GAMods(peer, data)
end
end)
-- stats logging, mostly copied from https://www.st0rm.de/dussel.lua.txt + Cloaker Hater's config
-- TODO: Make the chat output nicer, more colorful but also keep detailed logs in the chat logfile
local function stats_logger(peer, result)
dlog_ll(0, "UserLua", string.format("game_stats data from %s '%s' (%s)", peer:id(), peer:name(), peer:user_id()))
dump_table(result)
if type(peer) ~= "table" or not result.time_played then
return -- invalid or incomplete data has been received
end
local stats = table.merge({ peer_id = peer:id() }, result)
if stats.accuracy_f then
stats.accuracy = stats.accuracy_f
stats.accuracy_f = nil
end
local criminal_name_curr = managers.criminals:character_name_by_peer_id(peer:id())
local criminal_name = managers.statistics:session_criminal_assigned_to_user(peer:user_id()) -- if they left already
criminal_name = criminal_name or criminal_name_curr
local ammo_bag_use = criminal_name and managers.statistics:local_criminal_member_stat(criminal_name, "ammo_bag_interacts") or { amount = 0 }
local doctor_bag_use = criminal_name and managers.statistics:local_criminal_member_stat(criminal_name, "doctor_bag_interacts") or { amount = 0 }
stats.ammo_bag_use = ammo_bag_use.amount * 100
stats.doctor_bag_use = doctor_bag_use.amount
local msg = string.format("statistics for [peer_color]%s[] (%s) = %s", clear_string(peer:name()), peer:id(), JSON:encode(stats, nil, { decimal_precision = 2 }))
-- save to file like it was sent in the chat
-- managers.menu:_log_message_to_file(string.format("%s -- %s\n", os.date(iso8601), lobby_title .. msg))
Util:chat_message(msg, false, true, { subject_peer = peer })
peer:remove_listener("OnGameStatsEvent_LogStats")
end
do
-- handle the statistics we've requested before
D:hook("OnNetworkDataRecv", "OnNetworkDataRecv_ShowGameStats", "GameStats", function(peer, data_type, data)
dlog_ll(0, "UserLua", string.format("GameStats data from %s '%s' (%s)", peer:id(), peer:name(), peer:user_id()))
dump_table(data)
if data_type ~= "GameStats" or not data or not data.peer_id then
return -- wrong event or partial / invalid data received
end
if peer:id() ~= data.peer_id and not peer:is_server() then
return -- ignore data regarding mismatched peers as a client
end
local target_peer = peer
if peer:id() ~= data.peer_id then
target_peer = managers.network:session() and managers.network:session():peer(data.peer_id)
end
if target_peer and (not target_peer:has_statistics() or not target_peer:statistics().time_played) then
if target_peer.set_statistics2 and target_peer._stats_translation_map then
target_peer:set_statistics2(table.remap_keys(data, target_peer._stats_translation_map))
else
target_peer:set_statistics(data.kills, data.sp_kills, data.headshots, data.accuracy, data.downs, data.time, data.is_dropin)
--target_peer:set_statistics(data)
end
end
end)
-- tell our own client to send us stats later
D:hook("OnEnteredLobby", "OnEnteredLobby_LogLocalPeerStats", function(state, level)
managers.network:session():local_peer():add_listener("OnGameStatsEvent_LogStats", "game_stats", stats_logger)
end)
-- tell other clients to send us stats later
D:hook("OnPeerAdded", "OnPeerAdded_LogPeerStats", function(peer, is_new)
peer:add_listener("OnGameStatsEvent_LogStats", "game_stats", stats_logger)
-- save peer's information to chat's log file
if is_new and managers.menu and D:has_module("enhanced_chat") then
managers.menu:_log_message_to_file(string.format(
"%s -- '%s' has joined. Steam ID: %s, IP: %s\n",
os.date(iso8601),
tostring(peer:name()),
tostring(peer:user_id()),
tostring(Network:get_ip_address_from_user_id(peer:user_id()))
))
end
end)
end
-- hide some menu entries from the main menu
D:hook("OnMenuSetup", "OnMenuSetup_UserLuaHideItems", "menu_main", function(self, menu, nodes)
self:update_menu_item(nodes, "main", "forum", {
visible_callback = "hide_unless_option_set",
})
self:update_menu_item(nodes, "main", "eula", {
visible_callback = "hide_unless_option_set",
})
self:update_menu_item(nodes, "main", "group_page", {
visible_callback = "hide_unless_option_set",
})
end)
D:hook("OnModuleInit", "OnModuleLoaed_UserLuaOverwriteChatLogFormat", function(module, params)
if module:id() == "enhanced_chat" then
module.chat_log_format = function(name, message, peer, state)
return string.format("%s -- \"%s\" ", os.date(iso8601), state or "?") .. "%n%s: %s\n"
end
end
end)
do
-- Load other config options which I don't want to keep in this file - like "steam_web_api_key" or "hardcoded_verified_users"
-- file contents should be literally just: return { foo = "bar", }
dlog_ll(0, "UserLua", "Loading user script secrets")
local secret_config = dofile("mods/.user-secret.lua")
if secret_config ~= nil then
tablex.merge(config, secret_config)
else
dlog_ll(3, "UserLua", "Failed to load .user-secret.lua file")
end
-- load debug things, but only while on debug account
local steam_id = Steam and Steam:userid()
if steam_id == "76561199255798139" then
dlog_ll(1, "UserLua", "Loading debug file")
local f, err = loadfile("mods/user-debug.lua")
if f ~= nil then
err = f(...)
else
Util:chat_message("Failed to load debug file: " .. tostring(err), false, "DEBUG")
end
end
end
--- apply table values
local overwrite = not prioritize_gui and (is_first_load or always_reload)
for key, value in pairs(config) do
D:set_config_option(key, value, overwrite)
end
for key, value in pairs(localization) do
D:add_localization_override(key, value)
end
for id, key in pairs(keybind_overrides) do
D:update_keybind(id, key)
end
for key, text in pairs(commands) do
D:register_chat_command(key, function()
Util:chat_message(text)
return true
end)
end
for _, module in ipairs(blacklisted_modules) do
D:blacklist_module(module)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment