├── Core.lua ├── OptionMenus.lua ├── README.md ├── WolfHUDTweakData.lua ├── devlua ├── AdvAssault.lua ├── BurstFire.lua ├── BuyAllAsset.lua ├── CustomHUD.lua ├── CustomWaypoints.lua ├── DamageIndicator.lua ├── DamagePopup.lua ├── DamagePopupWolf.lua ├── DownCounter.lua ├── DrivingHUD.lua ├── EnemyHealthbarAlt.lua ├── EnhancedCrewLoadout.lua ├── EnhancedObjective.lua ├── EquipmentTweaks.lua ├── FastNet.lua ├── ForceReady.lua ├── GameInfoManager.lua ├── HUDChat.lua ├── HUDList.lua ├── Interaction.lua ├── KillCounter.lua ├── MenuTweaks.lua ├── NetworkHandler.lua ├── NumbericSuspicion.lua ├── PacifiedCivs.lua ├── PrePlanManager.lua ├── ProfileMenu.lua ├── README.md ├── RichPresence.lua ├── Scripts.lua ├── TabStats.lua ├── Utils │ ├── InputDialog.lua │ ├── LoadoutPanel.lua │ ├── OutlinedText.lua │ └── QuickInputMenu.lua ├── VanillaHUD.lua ├── WaypointsManager.lua └── WeaponGadgets.lua ├── loc ├── RealWeaponNames.json ├── english.json ├── french.json ├── german.json ├── italian.json ├── japanese.json ├── korean.json ├── polish.json ├── portuguese.json ├── russian.json ├── schinese.json └── spanish.json └── mod.txt /README.md: -------------------------------------------------------------------------------- 1 | # VPlusHUD Only For Pull Requests 2 | For the working version use 3 | 4 | https://gitlab.com/steam-test1/alternative-updates/-/raw/main/update/vanhudplus.zip 5 | 6 | # HUD Compatibility Guide 7 | 8 | https://gitlab.com/steam-test1/alternative-updates/-/wikis/VanillaHUD-Plus-Compatibility-Guide 9 | -------------------------------------------------------------------------------- /WolfHUDTweakData.lua: -------------------------------------------------------------------------------- 1 | WolfHUDTweakData = WolfHUDTweakData or class() 2 | function WolfHUDTweakData:init() 3 | ---------------------------------------------------------------------------------------------------------------------- 4 | -- VHUDPlus Tweak Data -- 5 | ---------------------------------------------------------------------------------------------------------------------- 6 | -- This file enables access to advanced settings, or those I cannot really implement into ingame menus easily. -- 7 | -- If you want to save those changes, please copy this file to "Payday 2/mods/saves" and edit that copy instead. -- 8 | -- You will need to take care of that version beeing up to date on your own. -- 9 | -- It will not get changed on updates automatically. -- 10 | -- If you encounter problems, make sure the contents of this file matches the contents of your customized version. -- 11 | ---------------------------------------------------------------------------------------------------------------------- 12 | 13 | -- Determines which messages get logged 14 | self.LOG_MODE = { 15 | error = true, -- log errors 16 | warning = true, -- log warnings 17 | info = false, -- log infos 18 | to_console = true -- show messages in console (Requires DebugConsole mod) 19 | } 20 | 21 | -- Currency used ingame 22 | self.CASH_SIGN = "$" -- Dollar 23 | --self.CASH_SIGN = "\194\128" -- EUR 24 | 25 | -- Maximum amount of Plans, that can be saved per level/map. 26 | self.MAX_PRE_PLANS = 10 27 | -- Maximum Length of custom weapon names. 28 | self.MAX_WEAPON_NAME_LENGTH = 30 29 | -- Maximum Length of custom Skill set names. 30 | self.MAX_SKILLSET_NAME_LENGTH = 25 31 | -- Maximum Length of Profile names. 32 | self.MAX_PROFILE_NAME_LENGTH = 20 33 | 34 | -- Time within 2 presses of the nade button, to throw a nade in stealth. 35 | self.STEALTH_NADE_TIMEOUT = 0.25 36 | -- Time within 2 presses of the interact button, to deploy a shaped charge in stealth. 37 | self.STEALTH_SHAPED_CHARGE_TIMEOUT = 0.25 38 | -- Time within 2 presses of the interact button, to close a door using a keycard. (hoxton breakout day 2) 39 | self.KEYCARD_DOORS_TIMEOUT = 0.25 40 | -- Time between 2 automatical pickups, when the interaction button remains pressed. 41 | self.AUTO_PICKUP_DELAY = 0.2 42 | 43 | -- Component Layouts for Lobby and briefing loadout panels. 44 | -- The total width and height of those panels are fixed, so adding too many components into a row or column will make them incredibly small. 45 | -- Available components: 46 | --[[ 47 | name -> The name (+ rank in lobby) 48 | level -> The level + infamy 49 | ping -> The latency 50 | playtime -> The Steam playtime (in hours) 51 | character -> The used character 52 | skills -> The equipped skill build 53 | perk -> The equipped perkdeck 54 | primary -> The primary weapon + used mods 55 | secondary -> The secondary weapon + used mods 56 | melee_weapon -> The equipped melee weapon 57 | grenade -> The eqipped throwable 58 | mask -> The mask worn 59 | armor -> The armor worn 60 | deployable -> The equipped deployable 61 | secondary_deployable -> The eqipped secondary deployable (in case of Jack of all trades) 62 | --]] 63 | self.STD_LOBBY_LOADOUT_LAYOUT = { 64 | { "playtime", "ping" }, 65 | { "name" }, 66 | { "character" }, 67 | { "skills" }, 68 | { "perk" }, 69 | { "primary" }, 70 | { "secondary" }, 71 | { "melee_weapon" }, 72 | { "grenade", "armor" }, 73 | { "deployable", "secondary_deployable" } 74 | } 75 | self.CS_LOBBY_LOADOUT_LAYOUT = { 76 | { "playtime", "ping" }, 77 | { "name" }, 78 | { "skills" }, 79 | { "perk" }, 80 | { "primary", "secondary" }, 81 | { "grenade", "armor" }, 82 | { "deployable", "secondary_deployable" } 83 | } 84 | self.BRIEFING_LOADOUT_LAYOUT = { 85 | { "perk", "playtime" }, 86 | { "skills" }, 87 | { "primary" }, 88 | { "secondary" }, 89 | { "melee_weapon", "grenade" }, 90 | { "armor", "mask" }, 91 | { "deployable", "secondary_deployable" } 92 | } 93 | self.TAB_LOADOUT_LAYOUT = { 94 | { "name", "ping", "playtime" }, 95 | { "skills", "perk" }, 96 | } 97 | 98 | -- Color table 99 | -- Add or remove any color you want 100 | -- 'color' needs to be that colors hexadecimal code 101 | -- 'name' will be the name it appears in the selection menus 102 | self.color_table = { 103 | { color = 'FFFFFF', name = "white" }, 104 | { color = 'F2F250', name = "light_yellow" }, 105 | { color = 'F2C24E', name = "light_orange" }, 106 | { color = 'E55858', name = "light_red" }, 107 | { color = 'CC55CC', name = "light_purple" }, 108 | { color = '00FF00', name = "light_green" }, 109 | { color = '00FFFF', name = "light_blue" }, 110 | { color = 'BABABA', name = "light_gray" }, 111 | { color = 'FFFF00', name = "yellow" }, 112 | { color = 'FFA500', name = "orange" }, 113 | { color = 'FF0000', name = "red" }, 114 | { color = '800080', name = "purple" }, 115 | { color = '008000', name = "green" }, 116 | { color = '0000FF', name = "blue" }, 117 | { color = '808080', name = "gray" }, 118 | { color = '000000', name = "black" }, 119 | { color = 'FF7575', name = "debuff" }, 120 | { color = '75FF75', name = "team" }, 121 | { color = nil, name = "rainbow" }, 122 | } 123 | 124 | --Unit Name link table 125 | self.CHARACTER_NAMES = { 126 | [ "civilian" ] = { default = "wolfhud_enemy_civilian" }, 127 | [ "civilian_female" ] = { default = "wolfhud_enemy_civilian" }, 128 | [ "civilian_mariachi" ] = { default = "wolfhud_enemy_mariachi" }, 129 | [ "captain" ] = { default = "wolfhud_enemy_civilian" }, 130 | [ "civilian_no_penalty" ] = { default = "wolfhud_enemy_civilian" }, 131 | [ "gangster" ] = { default = "wolfhud_enemy_gangster" }, 132 | [ "triad" ] = { default = "wolfhud_enemy_triad" }, 133 | [ "biker" ] = { default = "wolfhud_enemy_biker" }, 134 | [ "biker_escape" ] = { default = "wolfhud_enemy_biker" }, 135 | [ "bolivian_indoors" ] = { default = "wolfhud_enemy_bolivian_security" }, 136 | [ "bolivian_indoors_mex" ] = { default = "wolfhud_enemy_bolivian_security_mex" }, 137 | [ "bolivian" ] = { default = "wolfhud_enemy_bolivian_thug" }, 138 | [ "mobster" ] = { default = "wolfhud_enemy_mobster" }, 139 | [ "security" ] = { default = "wolfhud_enemy_security" }, 140 | [ "security_undominatable" ] = { default = "wolfhud_enemy_security" }, 141 | [ "mute_security_undominatable" ] = { default = "wolfhud_enemy_security" }, 142 | [ "security_mex" ] = { default = "wolfhud_enemy_security" }, 143 | [ "security_mex_no_pager" ] = { default = "wolfhud_enemy_security" }, 144 | [ "gensec" ] = { default = "wolfhud_enemy_gensec" }, 145 | [ "cop" ] = { default = "wolfhud_enemy_cop" }, 146 | [ "cop_female" ] = { default = "wolfhud_enemy_cop" }, 147 | [ "cop_scared" ] = { default = "wolfhud_enemy_cop" }, 148 | [ "fbi" ] = { default = "wolfhud_enemy_fbi" }, 149 | [ "swat" ] = { default = "wolfhud_enemy_swat" }, 150 | [ "heavy_swat" ] = { default = "wolfhud_enemy_heavy_swat" }, 151 | [ "fbi_swat" ] = { default = "wolfhud_enemy_swat" }, 152 | [ "fbi_heavy_swat" ] = { default = "wolfhud_enemy_heavy_swat" }, 153 | [ "heavy_swat_sniper" ] = { default = "wolfhud_enemy_heavy_swat_sniper" }, 154 | [ "city_swat" ] = { default = "wolfhud_enemy_city_swat" }, 155 | [ "shield" ] = { default = "wolfhud_enemy_shield" }, 156 | [ "spooc" ] = { default = "wolfhud_enemy_spook" }, 157 | [ "shadow_spooc"] = { default = "wolfhud_enemy_shadow_spook" }, 158 | [ "taser" ] = { default = "wolfhud_enemy_taser" }, 159 | [ "sniper" ] = { default = "wolfhud_enemy_sniper" }, 160 | [ "medic" ] = { default = "wolfhud_enemy_medic" }, 161 | [ "tank" ] = { default = "wolfhud_enemy_tank" }, 162 | [ "tank_hw" ] = { default = "wolfhud_enemy_tank_hw" }, 163 | [ "tank_medic" ] = { default = "wolfhud_enemy_tank_medic" }, 164 | [ "tank_mini" ] = { default = "wolfhud_enemy_tank_mini" }, 165 | [ "phalanx_minion" ] = { default = "wolfhud_enemy_phalanx_minion" }, 166 | [ "phalanx_vip" ] = { default = "wolfhud_enemy_phalanx_vip" }, 167 | [ "swat_van_turret_module" ] = { default = "wolfhud_enemy_swat_van" }, 168 | [ "ceiling_turret_module" ] = { default = "wolfhud_enemy_ceiling_turret" }, 169 | [ "ceiling_turret_module_no_idle" ] = { default = "wolfhud_enemy_ceiling_turret" }, 170 | [ "ceiling_turret_module_longer_range" ] = { default = "wolfhud_enemy_ceiling_turret" }, 171 | [ "aa_turret_module" ] = { default = "wolfhud_enemy_aa_turret" }, 172 | [ "crate_turret_module" ] = { default = "wolfhud_enemy_crate_turret" }, 173 | [ "sentry_gun" ] = { default = "wolfhud_enemy_sentry_gun" }, 174 | [ "mobster_boss" ] = { default = "wolfhud_enemy_mobster_boss" }, 175 | [ "chavez_boss" ] = { default = "wolfhud_enemy_chavez_boss" }, 176 | [ "drug_lord_boss" ] = { default = "wolfhud_enemy_druglord_boss" }, 177 | [ "drug_lord_boss_stealth" ] = { default = "wolfhud_enemy_druglord_boss_stealth" }, 178 | [ "biker_boss" ] = { default = "wolfhud_enemy_biker_boss" }, 179 | [ "bank_manager" ] = { default = "wolfhud_enemy_bank_manager", dah = "wolfhud_enemy_dah_ralph" }, 180 | [ "inside_man" ] = { default = "wolfhud_enemy_inside_man" }, 181 | [ "escort_undercover" ] = { default = "wolfhud_enemy_escort_undercover", run = "wolfhud_enemy_escort_heatstreet", rvd1 = "wolfhud_enemy_escort_reservoirdogs" }, 182 | [ "escort_chinese_prisoner" ] = { default = "wolfhud_enemy_escort_chinese_prisoner" }, 183 | [ "escort_cfo" ] = { default = "wolfhud_enemy_escort_cfo" }, 184 | [ "drunk_pilot" ] = { default = "wolfhud_enemy_drunk_pilot", bph = "wolfhud_enemy_escort_bain_locke", bex = "wolfhud_enemy_escort_it_guy" }, 185 | [ "escort" ] = { default = "wolfhud_enemy_escort" }, 186 | [ "boris" ] = { default = "wolfhud_enemy_boris" }, 187 | [ "spa_vip" ] = { default = "wolfhud_enemy_spa_vip" }, 188 | [ "spa_vip_hurt" ] = { default = "wolfhud_enemy_spa_vip_hurt" }, 189 | [ "escort_criminal" ] = { default = "wolfhud_enemy_vlad" }, 190 | [ "old_hoxton_mission" ] = { default = "wolfhud_enemy_locke_mission", hox_1 = "wolfhud_enemy_old_hoxton_mission", hox_2 = "wolfhud_enemy_old_hoxton_mission", rvd1 = "wolfhud_enemy_reservoirdogs", rvd2 = "wolfhud_enemy_reservoirdogs" }, 191 | [ "hector_boss" ] = { default = "wolfhud_enemy_hector_boss" }, 192 | [ "hector_boss_no_armor" ] = { default = "wolfhud_enemy_hector_boss_no_armor" }, 193 | [ "triad_boss" ] = { default = "wolfhud_enemy_yufuwang_armored_boss" }, 194 | [ "triad_boss_no_armor" ] = { default = "wolfhud_enemy_yufuwang_no_armor_boss" }, 195 | [ "ranchmanager" ] = { default = "wolfhud_enemy_ranchmanager" }, 196 | [ "marshal_marksman" ] = { default = "wolfhud_enemy_marshal_marksman" }, 197 | [ "marshal_shield" ] = { default = "wolfhud_enemy_marshal_shield" }, 198 | [ "marshal_shield_break" ] = { default = "wolfhud_enemy_marshal_shield_break" }, 199 | [ "robbers_safehouse" ] = { default = "wolfhud_enemy_crew", bph = "wolfhud_enemy_kento" }, 200 | [ "butler" ] = { default = "wolfhud_enemy_butler" }, 201 | [ "vlad" ] = { default = "wolfhud_enemy_vlad" }, 202 | [ "russian" ] = { default = "menu_russian" }, 203 | [ "german" ] = { default = "menu_german" }, 204 | [ "spanish" ] = { default = "menu_spanish" }, 205 | [ "american" ] = { default = "menu_american" }, 206 | [ "jowi" ] = { default = "menu_jowi" }, 207 | [ "old_hoxton" ] = { default = "menu_old_hoxton" }, 208 | [ "female_1" ] = { default = "menu_female_1" }, 209 | [ "clover" ] = { default = "menu_female_1" }, 210 | [ "dragan" ] = { default = "menu_dragan" }, 211 | [ "jacket" ] = { default = "menu_jacket" }, 212 | [ "bonnie" ] = { default = "menu_bonnie" }, 213 | [ "sokol" ] = { default = "menu_sokol" }, 214 | [ "dragon" ] = { default = "menu_dragon" }, 215 | [ "bodhi" ] = { default = "menu_bodhi" }, 216 | [ "jimmy" ] = { default = "menu_jimmy" }, 217 | [ "sydney" ] = { default = "menu_sydney" }, 218 | [ "wild" ] = { default = "menu_wild" }, 219 | [ "chico" ] = { default = "menu_chico" }, 220 | [ "terry" ] = { default = "menu_chico" }, 221 | [ "max" ] = { default = "menu_max" }, 222 | [ "myh" ] = { default = "menu_myh" }, 223 | [ "ecp_male" ] = { default = "menu_ecp_male" }, 224 | [ "ecp_female" ] = { default = "menu_ecp_female" }, 225 | [ "joy" ] = { default = "menu_joy" }, 226 | 227 | --Restoration Overhaul Enemies 228 | ["boom"] = { default = "wolfhud_enemy_boom" }, 229 | ["omnia_lpf"] = { default = "wolfhud_enemy_omnia_lpf" }, 230 | ["summers"] = { default = "wolfhud_enemy_summers" }, 231 | ["boom_summers"] = { default = "wolfhud_enemy_boom_summers" }, 232 | ["taser_summers"] = { default = "wolfhud_enemy_taser_summers" }, 233 | ["medic_summers"] = { default = "wolfhud_enemy_medic_summers" }, 234 | ["spring"] = { default = "wolfhud_enemy_spring" }, 235 | ["fbi_vet"] = { default = "wolfhud_enemy_fbi_vet" }, 236 | 237 | --Crackdown Enemies 238 | ["deathvox_lightar"] = { default = "wolfhud_enemy_deathvox_light" }, 239 | ["deathvox_heavyar"] = { default = "wolfhud_enemy_deathvox_heavy" }, 240 | ["deathvox_lightshot"] = { default = "wolfhud_enemy_deathvox_light" }, 241 | ["deathvox_heavyshot"] = { default = "wolfhud_enemy_deathvox_heavy" }, 242 | ["deathvox_greendozer"] = { default = "wolfhud_enemy_tank" }, 243 | ["deathvox_blackdozer"] = { default = "wolfhud_enemy_tank" }, 244 | ["deathvox_lmgdozer"] = { default = "wolfhud_enemy_tank" }, 245 | ["deathvox_medicdozer"] = { default = "wolfhud_enemy_tank_medic" }, 246 | ["deathvox_cloaker"] = { default = "wolfhud_enemy_spooc" }, 247 | ["deathvox_taser"] = { default = "wolfhud_enemy_taser" }, 248 | ["deathvox_shield"] = { default = "wolfhud_enemy_shield" }, 249 | ["deathvox_sniper"] = { default = "wolfhud_enemy_sniper" }, 250 | ["deathvox_medic"] = { default = "wolfhud_enemy_medic" }, 251 | ["deathvox_grenadier"] = { default = "wolfhud_enemy_boom" }, 252 | ["deathvox_guard"] = { default = "wolfhud_enemy_security" }, 253 | } 254 | 255 | self:post_init() 256 | end 257 | 258 | ----------------------------------------- DONT EDIT BELOW THIS LINE!!! ----------------------------------------- DONT EDIT BELOW THIS LINE!!! ----------------------------------------- DONT EDIT BELOW THIS LINE!!! ----------------------------------------- 259 | 260 | function WolfHUDTweakData:post_init() 261 | for _, data in ipairs(self.color_table) do 262 | if data.name == "rainbow" then 263 | data.color_func = function(frequency) 264 | local r = Application:time() * 360 * (frequency or 1) 265 | local r, g, b = (1 + math.sin(r + 0)) / 2, (1 + math.sin(r + 120)) / 2, (1 + math.sin(r + 240)) / 2 266 | return Color(r, g, b) 267 | end 268 | end 269 | end 270 | end 271 | -------------------------------------------------------------------------------- /devlua/AdvAssault.lua: -------------------------------------------------------------------------------- 1 | if string.lower(RequiredScript) == "lib/managers/hud/hudassaultcorner" then 2 | local init_original = HUDAssaultCorner.init 3 | local _start_assault_original = HUDAssaultCorner._start_assault 4 | local _set_hostage_offseted_original = HUDAssaultCorner._set_hostage_offseted 5 | local set_buff_enabled_original = HUDAssaultCorner.set_buff_enabled 6 | local show_point_of_no_return_timer_original = HUDAssaultCorner.show_point_of_no_return_timer 7 | local hide_point_of_no_return_timer_original = HUDAssaultCorner.hide_point_of_no_return_timer 8 | local show_casing_original = HUDAssaultCorner.show_casing 9 | local hide_casing_original = HUDAssaultCorner.hide_casing 10 | local set_assault_wave_number_original = HUDAssaultCorner.set_assault_wave_number 11 | local _animate_wave_started_original = HUDAssaultCorner._animate_wave_started 12 | local _animate_wave_completed_original = HUDAssaultCorner._animate_wave_completed 13 | 14 | local enhanced_obj = VHUDPlus:getSetting({"CustomHUD", "ENABLED_ENHANCED_OBJECTIVE"}, false) 15 | local center_assault = VHUDPlus:getSetting({"AssaultBanner", "USE_CENTER_ASSAULT"}, true) 16 | local HIDE_CASING_MODE_PANEL = VHUDPlus:getSetting({"AssaultBanner", "HIDE_CASING_MODE_PANEL"}, false) 17 | 18 | function HUDAssaultCorner:init(tweak_hud, ...) 19 | init_original(self, tweak_hud, ...) 20 | 21 | if center_assault then 22 | if alive(self._hud_panel:child("assault_panel")) or alive(self._hud_panel:child("casing_panel")) or alive(self._hud_panel:child("point_of_no_return_panel")) or alive(self._hud_panel:child("buffs_panel")) or alive(self._hud_panel:child("_vip_bg_box")) then 23 | self._hud_panel:child("assault_panel"):set_right(self._hud_panel:w() / 2 + 150) 24 | -- self._hud_panel:child("assault_panel"):child("icon_assaultbox"):set_visible(false) 25 | self._hud_panel:child("casing_panel"):set_right(self._hud_panel:w() / 2 + 150) 26 | self._hud_panel:child("casing_panel"):child("icon_casingbox"):set_visible(HIDE_CASING_MODE_PANEL) 27 | self._hud_panel:child("point_of_no_return_panel"):set_right(self._hud_panel:w() / 2 + 150) 28 | -- self._hud_panel:child("point_of_no_return_panel"):child("icon_noreturnbox"):set_visible(false) 29 | self._hud_panel:child("buffs_panel"):set_x(self._hud_panel:child("assault_panel"):right()) 30 | self._vip_bg_box:set_x(0) -- left align this "buff" 31 | end 32 | if not enhanced_obj then 33 | self._last_assault_timer_size = 0 34 | self._assault_timer = HUDHeistTimer:new({ 35 | panel = self._bg_box:panel({ 36 | name = "assault_timer_panel", 37 | x = 4 38 | }) 39 | }, tweak_hud) 40 | self._assault_timer._timer_text:set_font_size(tweak_data.hud_corner.assault_size) 41 | self._assault_timer._timer_text:set_font(Idstring(tweak_data.hud_corner.assault_font)) 42 | self._assault_timer._timer_text:set_align("left") 43 | self._assault_timer._timer_text:set_vertical("center") 44 | self._assault_timer._timer_text:set_color(Color.white:with_alpha(0.9)) 45 | 46 | self._last_casing_timer_size = 0 47 | self._casing_timer = HUDHeistTimer:new({ 48 | panel = self._casing_bg_box:panel({ 49 | name = "casing_timer_panel", 50 | x = 4 51 | }) 52 | }, tweak_hud) 53 | self._casing_timer._timer_text:set_font_size(tweak_data.hud_corner.assault_size) 54 | self._casing_timer._timer_text:set_font(Idstring(tweak_data.hud_corner.assault_font)) 55 | self._casing_timer._timer_text:set_align("left") 56 | self._casing_timer._timer_text:set_vertical("center") 57 | self._casing_timer._timer_text:set_color(Color.white:with_alpha(0.9)) 58 | end 59 | end 60 | 61 | -- Waves completed are visible in Objective and overlapping with HUDList. 62 | if self:should_display_waves() and VHUDPlus:getSetting({"AssaultBanner", "WAVE_COUNTER"}, true) then 63 | local wave_panel = self._hud_panel:child("wave_panel") 64 | if alive(wave_panel) then 65 | wave_panel:set_alpha(0) 66 | end 67 | local assault_panel = self._hud_panel:child("assault_panel") 68 | if alive(assault_panel) then 69 | self._wave_text = assault_panel:text({ 70 | name = "num_waves", 71 | text = self:get_completed_waves_string(), 72 | valign = "center", 73 | vertical = "center", 74 | align = "center", 75 | halign = "right", 76 | w = self._bg_box and self._bg_box:w() - 5 or 100, 77 | h = 14, 78 | layer = 1, 79 | x = 0, 80 | y = 0, 81 | color = Color.white, 82 | alpha = 0.8, 83 | font = "fonts/font_medium_shadow_mf", 84 | font_size = tweak_data.hud.active_objective_title_font_size * 0.9, 85 | }) 86 | self._wave_text:set_top(self._bg_box and self._bg_box:bottom() or 40) 87 | self._wave_text:set_right(self._bg_box and self._bg_box:right() or 575) 88 | end 89 | end 90 | end 91 | 92 | function HUDAssaultCorner:feed_heist_time(t, ...) 93 | local time = "00:00" 94 | 95 | if t >= 60 then 96 | local m = tonumber(string.format("%d", t/60)) 97 | local s = t - m*60 98 | 99 | if m >= 60 then 100 | local h = tonumber(string.format("%d", m/60)) 101 | m = m - h*60 102 | time = string.format("%02d:%02d:%02d", h, m, s) 103 | else 104 | time = string.format("%02d:%02d", m, s) 105 | end 106 | 107 | else 108 | r = string.format("00:%02d", t) 109 | end 110 | 111 | VHUDPlus._heist_time = time 112 | 113 | if self._assault_timer and not enhanced_obj then 114 | self._assault_timer:set_time(t) 115 | local _, _, cw, _ = self._assault_timer._timer_text:text_rect() 116 | if alive(self._bg_box:child("text_panel")) and self._bg_box:w() >= 242 and cw ~= self._last_assault_timer_size then 117 | self._last_assault_timer_size = cw 118 | self._bg_box:child("text_panel"):set_w(self._bg_box:w() - (cw + 8)) 119 | self._bg_box:child("text_panel"):set_x(cw + 8) 120 | end 121 | end 122 | if self._casing_timer and not enhanced_obj then 123 | self._casing_timer:set_time(t) 124 | local _, _, aw, _ = self._casing_timer._timer_text:text_rect() 125 | if alive(self._casing_bg_box:child("text_panel")) and self._casing_bg_box:w() >= 242 and aw ~= self._last_casing_timer_size then 126 | self._last_casing_timer_size = aw 127 | self._casing_bg_box:child("text_panel"):set_w(self._casing_bg_box:w() - (aw + 8)) 128 | self._casing_bg_box:child("text_panel"):set_x(aw + 8) 129 | end 130 | end 131 | end 132 | 133 | function HUDAssaultCorner:_start_assault(text_list, ...) 134 | for i, string_id in ipairs(text_list) do 135 | if string_id == "hud_assault_assault" or string_id == "hud_assault_alpha" or string_id == "NepgearsyHUDReborn/HUD/AssaultCorner/Coming" then 136 | text_list[i] = "hud_adv_assault" 137 | end 138 | end 139 | return _start_assault_original(self, text_list, ...) 140 | end 141 | 142 | 143 | function HUDAssaultCorner:_animate_wave_started(...) 144 | if alive(self._wave_text) then 145 | self._wave_text:set_text(self:get_completed_waves_string()) 146 | end 147 | 148 | return _animate_wave_started_original(self, ...) 149 | end 150 | function HUDAssaultCorner:_animate_wave_completed(...) 151 | if alive(self._wave_text) then 152 | self._wave_text:set_text(self:get_completed_waves_string()) 153 | end 154 | 155 | return _animate_wave_completed_original(self, ...) 156 | end 157 | 158 | function HUDAssaultCorner:set_assault_wave_number(...) 159 | if alive(self._wave_text) then 160 | self._wave_text:set_text(self:get_completed_waves_string()) 161 | self._wave_text:animate(callback(self, self, "_animate_wave_text")) 162 | end 163 | 164 | return set_assault_wave_number_original(self, ...) 165 | end 166 | 167 | function HUDAssaultCorner:_animate_wave_text(object) 168 | local TOTAL_T = 2 169 | local t = TOTAL_T 170 | object:set_alpha(0.8) 171 | while t > 0 do 172 | local dt = coroutine.yield() 173 | t = t - dt 174 | object:set_alpha(0.5 + 0.5 * (0.5 * math.sin(t * 360 * 2) + 0.5)) 175 | end 176 | object:set_alpha(0.8) 177 | end 178 | 179 | function HUDAssaultCorner:locked_assault(status) 180 | local assault_panel = self._hud_panel:child("assault_panel") 181 | local icon_assaultbox = assault_panel and assault_panel:child("icon_assaultbox") 182 | local image 183 | if status then 184 | image = "guis/textures/pd2/hud_icon_padlockbox" 185 | else 186 | image = "guis/textures/pd2/hud_icon_assaultbox" 187 | end 188 | if icon_assaultbox and image then 189 | icon_assaultbox:set_image(image) 190 | end 191 | end 192 | 193 | if HIDE_CASING_MODE_PANEL then 194 | function HUDAssaultCorner:show_casing() return end 195 | function HUDAssaultCorner:hide_casing() return end 196 | end 197 | elseif string.lower(RequiredScript) == "lib/managers/hudmanagerpd2" then 198 | local feed_heist_time_original = HUDManager.feed_heist_time 199 | local show_casing_original = HUDManager.show_casing 200 | local hide_casing_original = HUDManager.hide_casing 201 | local sync_start_assault_original = HUDManager.sync_start_assault 202 | local sync_end_assault_original = HUDManager.sync_end_assault 203 | local show_point_of_no_return_timer_original = HUDManager.show_point_of_no_return_timer 204 | local hide_point_of_no_return_timer_original = HUDManager.hide_point_of_no_return_timer 205 | local _create_downed_hud_original = HUDManager._create_downed_hud 206 | local _create_custody_hud_original = HUDManager._create_custody_hud 207 | 208 | local mui_fix = VHUDPlus:getSetting({"AssaultBanner", "MUI_ASSAULT_FIX"}, false) 209 | local enhanced_obj = VHUDPlus:getSetting({"CustomHUD", "ENABLED_ENHANCED_OBJECTIVE"}, false) 210 | local center_assault = VHUDPlus:getSetting({"AssaultBanner", "USE_CENTER_ASSAULT"}, true) 211 | 212 | function HUDManager:_locked_assault(status) 213 | status = Network:is_server() and (managers.groupai:state():get_hunt_mode() or false) or status 214 | self._assault_locked = self._assault_locked or false 215 | if self._assault_locked ~= status then 216 | if self._hud_assault_corner then 217 | self._hud_assault_corner:locked_assault(status) 218 | end 219 | self._assault_locked = status 220 | end 221 | return self._assault_locked 222 | end 223 | 224 | function HUDManager:show_casing(...) 225 | if enhanced_obj and not mui_fix then 226 | self._hud_heist_timer._heist_timer_panel:set_visible(true) 227 | elseif not center_assault and not mui_fix then 228 | self._hud_heist_timer._heist_timer_panel:set_visible(true) 229 | elseif not enhanced_obj and not mui_fix then 230 | self._hud_heist_timer._heist_timer_panel:set_visible(false) 231 | end 232 | if self:alive("guis/mask_off_hud") and center_assault then 233 | self:script("guis/mask_off_hud").mask_on_text:set_y(50) 234 | end 235 | show_casing_original(self, ...) 236 | end 237 | 238 | function HUDManager:hide_casing(...) 239 | hide_casing_original(self, ...) 240 | if not mui_fix and not enhanced_obj then 241 | self._hud_heist_timer._heist_timer_panel:set_visible(true) 242 | end 243 | end 244 | 245 | function HUDManager:sync_start_assault(...) 246 | if enhanced_obj and not mui_fix then 247 | self._hud_heist_timer._heist_timer_panel:set_visible(true) 248 | elseif not center_assault and not mui_fix then 249 | self._hud_heist_timer._heist_timer_panel:set_visible(true) 250 | elseif not enhanced_obj and not mui_fix then 251 | self._hud_heist_timer._heist_timer_panel:set_visible(false) 252 | end 253 | managers.groupai:state()._wave_counter = (managers.groupai:state()._wave_counter or 0) + 1 254 | sync_start_assault_original(self, ...) 255 | end 256 | 257 | function HUDManager:sync_end_assault(...) 258 | sync_end_assault_original(self, ...) 259 | if not mui_fix then 260 | self._hud_heist_timer._heist_timer_panel:set_visible(true) 261 | end 262 | end 263 | 264 | function HUDManager:show_point_of_no_return_timer(...) 265 | if enhanced_obj and not mui_fix then 266 | self._hud_heist_timer._heist_timer_panel:set_visible(true) 267 | elseif not center_assault and not mui_fix then 268 | self._hud_heist_timer._heist_timer_panel:set_visible(true) 269 | elseif not enhanced_obj and not mui_fix then 270 | self._hud_heist_timer._heist_timer_panel:set_visible(false) 271 | end 272 | show_point_of_no_return_timer_original(self, ...) 273 | end 274 | 275 | function HUDManager:hide_point_of_no_return_timer(...) 276 | hide_point_of_no_return_timer_original(self, ...) 277 | if not mui_fix then 278 | self._hud_heist_timer._heist_timer_panel:set_visible(false ) 279 | end 280 | end 281 | 282 | function HUDManager:feed_heist_time(t, ...) 283 | 284 | if self._hud_assault_corner then 285 | self._hud_assault_corner:feed_heist_time(t) 286 | end 287 | feed_heist_time_original(self, t, ...) 288 | end 289 | 290 | function HUDManager:_create_downed_hud(...) 291 | _create_downed_hud_original(self, ...) 292 | if VHUDPlus:getSetting({"AssaultBanner", "USE_CENTER_ASSAULT"}, true) and self._hud_player_downed then 293 | local downed_panel = self._hud_player_downed._hud_panel 294 | local downed_hud = self._hud_player_downed._hud 295 | local timer_msg = downed_panel and downed_panel:child("downed_panel"):child("timer_msg") 296 | local timer = downed_hud and downed_hud.timer 297 | if timer_msg and timer then 298 | timer_msg:set_y(65) 299 | timer:set_y(math.round(timer_msg:bottom() - 6)) 300 | end 301 | end 302 | end 303 | 304 | function HUDManager:_create_custody_hud(...) 305 | _create_custody_hud_original(self, ...) 306 | if VHUDPlus:getSetting({"AssaultBanner", "USE_CENTER_ASSAULT"}, true) and self._hud_player_custody then 307 | local custody_panel = self._hud_player_custody._hud_panel 308 | local timer_msg = custody_panel and custody_panel:child("custody_panel") and custody_panel:child("custody_panel"):child("timer_msg") 309 | local timer = self._hud_player_custody._timer 310 | if timer_msg and timer then 311 | timer_msg:set_y(65) 312 | timer:set_y(math.round(timer_msg:bottom() - 6)) 313 | end 314 | end 315 | end 316 | elseif string.lower(RequiredScript) == "lib/managers/localizationmanager" then 317 | local text_original = LocalizationManager.text 318 | 319 | function LocalizationManager:text(string_id, ...) 320 | if string_id == "hud_adv_assault" or string_id == "hud_assault_alpha" or string_id == "NepgearsyHUDReborn/HUD/AssaultCorner/Coming" then 321 | return self:hud_adv_assault() 322 | end 323 | return text_original(self, string_id, ...) 324 | end 325 | 326 | function LocalizationManager:hud_adv_assault() 327 | 328 | if VHUDPlus:getSetting({"AssaultBanner", "USE_ADV_ASSAULT"}, true) then 329 | if managers.hud and managers.hud:_locked_assault() then 330 | return self:text("wolfhud_locked_assault") 331 | else 332 | local tweak = tweak_data.group_ai.besiege.assault 333 | local gai_state = managers.groupai:state() 334 | local assault_data = Network:is_server() and gai_state and gai_state._task_data.assault 335 | if tweak and gai_state and assault_data and assault_data.active then 336 | local get_value = gai_state._get_difficulty_dependent_value or function() return 0 end 337 | local get_mult = gai_state._get_balancing_multiplier or function() return 0 end 338 | local phase = self:text("wolfhud_advassault_phase_title") .. " " .. self:text("wolfhud_advassault_phase_" .. assault_data.phase) 339 | 340 | local spawns = get_value(gai_state, tweak.force_pool) * get_mult(gai_state, tweak.force_pool_balance_mul) 341 | local spawns_left = self:text("wolfhud_advassault_spawns_title") .. " " .. math.round(math.max(spawns - assault_data.force_spawned, 0)) 342 | 343 | local time_left = assault_data.phase_end_t - gai_state._t --+ 350 344 | if assault_data.phase == "build" then 345 | local sustain_duration = math.lerp(get_value(gai_state, tweak.sustain_duration_min), get_value(gai_state, tweak.sustain_duration_max), 0.5) * get_mult(gai_state, tweak.sustain_duration_balance_mul) 346 | time_left = time_left + sustain_duration + tweak.fade_duration 347 | elseif assault_data.phase == "sustain" then 348 | time_left = time_left + tweak.fade_duration 349 | end 350 | --if gai_state:_count_police_force("assault") > 7 then -- 350 = additional duration, if more than 7 assault groups are active (hardcoded values in gai_state). 351 | -- time_left = time_left + 350 352 | --end 353 | if time_left < 0 then 354 | time_left = self:text("wolfhud_advassault_time_overdue") 355 | else 356 | time_left = self:text("wolfhud_advassault_time_title") .. " " .. string.format("%.2f", time_left) 357 | end 358 | 359 | local spacer = string.rep(" ", 10) 360 | local sep = string.format("%s%s%s", spacer, self:text("hud_assault_end_line"), spacer) 361 | return string.format("%s%s%s%s%s", phase, sep, spawns_left, sep, time_left) 362 | end 363 | end 364 | end 365 | return self:text("hud_assault_assault") 366 | end 367 | end 368 | -------------------------------------------------------------------------------- /devlua/BurstFire.lua: -------------------------------------------------------------------------------- 1 | if Global.load_level == true and Global.game_settings.level_id == "modders_devmap" then 2 | return 3 | end 4 | 5 | --[[ 6 | Weapon tweak data attributes: 7 | BURST_FIRE: 8 | - Force enable burst fire using the specified number as the burst size (if weapon does not have a fire mode mod installed) 9 | nil /undef - If the weapon can toggle fire mode and does not have a fire mode mod installed, enable burst fire with default burst size (3) 10 | false - Force disable burst fire even if weapon can toggle fire mode 11 | 12 | ADAPTIVE_BURST_SIZE: 13 | nil/true - Allow abortion of ongoing burst if trigger is released 14 | false - Force entire burst to be fired before resetting 15 | 16 | BURST_FIRE_RATE_MULTIPLIER: 17 | - Apply specified multiplier to fire rate when firing in burst mode 18 | 19 | DELAYED_BURST_RECOIL: 20 | true/false - Build up and delay recoil until last shot in burst is fired 21 | ]] 22 | if not VHUDPlus:getSetting({"EQUIPMENT", "ENABLE_BURSTMODE"}, true) then 23 | return 24 | end 25 | 26 | if RequiredScript == "lib/units/weapons/newraycastweaponbase" then 27 | 28 | local _update_stats_values_original = NewRaycastWeaponBase._update_stats_values 29 | local fire_rate_multiplier_original = NewRaycastWeaponBase.fire_rate_multiplier 30 | local recoil_multiplier_original = NewRaycastWeaponBase.recoil_multiplier 31 | local on_enabled_original = NewRaycastWeaponBase.on_enabled 32 | local on_disabled_original = NewRaycastWeaponBase.on_disabled 33 | local start_reload_original = NewRaycastWeaponBase.start_reload 34 | local fire_original = NewRaycastWeaponBase.fire 35 | local toggle_firemode_original = NewRaycastWeaponBase.toggle_firemode 36 | 37 | NewRaycastWeaponBase.DEFAULT_BURST_SIZE = 3 38 | NewRaycastWeaponBase.IDSTRING_SINGLE = Idstring("single") 39 | NewRaycastWeaponBase.IDSTRING_AUTO = Idstring("auto") 40 | 41 | function NewRaycastWeaponBase:_update_stats_values(...) 42 | _update_stats_values_original(self, ...) 43 | 44 | if not self:is_npc() then 45 | self._burst_rounds_remaining = 0 46 | self._has_auto = not self._locked_fire_mode and (self:can_toggle_firemode() or self:weapon_tweak_data().FIRE_MODE == "auto") 47 | self._has_burst_fire = (self:can_toggle_firemode() or self:weapon_tweak_data().BURST_FIRE) and self:weapon_tweak_data().BURST_FIRE ~= false 48 | --self._has_burst_fire = (not self._locked_fire_mode or managers.weapon_factor:has_perk("fire_mode_burst", self._factory_id, self._blueprint) or (self:can_toggle_firemode() or self:weapon_tweak_data().BURST_FIRE) and self:weapon_tweak_data().BURST_FIRE ~= false 49 | --self._locked_fire_mode = self._locked_fire_mode or managers.weapon_factor:has_perk("fire_mode_burst", self._factory_id, self._blueprint) and Idstring("burst") 50 | self._burst_size = self:weapon_tweak_data().BURST_FIRE or NewRaycastWeaponBase.DEFAULT_BURST_SIZE 51 | self._adaptive_burst_size = self:weapon_tweak_data().ADAPTIVE_BURST_SIZE ~= false 52 | self._burst_fire_rate_multiplier = self:weapon_tweak_data().BURST_FIRE_RATE_MULTIPLIER or 1 53 | self._delayed_burst_recoil = self:weapon_tweak_data().DELAYED_BURST_RECOIL 54 | 55 | self._burst_rounds_fired = 0 56 | end 57 | end 58 | 59 | function NewRaycastWeaponBase:fire_rate_multiplier(...) 60 | local mult = 1 61 | if self:in_burst_mode() then 62 | mult = mult * (self._burst_fire_rate_multiplier or 1) 63 | end 64 | 65 | return fire_rate_multiplier_original(self, ...) * mult 66 | end 67 | 68 | function NewRaycastWeaponBase:recoil_multiplier(...) 69 | local mult = 1 70 | if self._delayed_burst_recoil and self:in_burst_mode() and self:burst_rounds_remaining() then 71 | mult = 0 72 | end 73 | 74 | return recoil_multiplier_original(self, ...) * mult 75 | end 76 | 77 | function NewRaycastWeaponBase:on_enabled(...) 78 | self:cancel_burst() 79 | return on_enabled_original(self, ...) 80 | end 81 | 82 | function NewRaycastWeaponBase:on_disabled(...) 83 | self:cancel_burst() 84 | return on_disabled_original(self, ...) 85 | end 86 | 87 | function NewRaycastWeaponBase:start_reload(...) 88 | self:cancel_burst() 89 | return start_reload_original(self, ...) 90 | end 91 | 92 | function NewRaycastWeaponBase:fire(...) 93 | local result = fire_original(self, ...) 94 | 95 | if result and not self.AKIMBO and self:in_burst_mode() then 96 | if self:clip_empty() then 97 | self:cancel_burst() 98 | else 99 | self._burst_rounds_fired = self._burst_rounds_fired + 1 100 | self._burst_rounds_remaining = (self._burst_rounds_remaining <= 0 and self._burst_size or self._burst_rounds_remaining) - 1 101 | if self._burst_rounds_remaining <= 0 then 102 | self:cancel_burst() 103 | end 104 | end 105 | end 106 | 107 | return result 108 | end 109 | 110 | --Semi-override 111 | function NewRaycastWeaponBase:toggle_firemode(...) 112 | return self:can_use_burst_mode() and not self._locked_fire_mode and not self:gadget_overrides_weapon_functions() and self:_check_toggle_burst() or toggle_firemode_original(self, ...) 113 | end 114 | 115 | function NewRaycastWeaponBase:_check_toggle_burst() 116 | if self:in_burst_mode() then 117 | self:_set_burst_mode(false, self.AKIMBO and not self._has_auto) 118 | return true 119 | elseif (self._fire_mode == Idstring("single")) or (self._fire_mode == Idstring("auto") and not self:can_toggle_firemode()) then 120 | self:_set_burst_mode(true, self.AKIMBO) 121 | return true 122 | end 123 | end 124 | 125 | function NewRaycastWeaponBase:_set_burst_mode(status, skip_sound) 126 | self._in_burst_mode = status 127 | self._fire_mode = NewRaycastWeaponBase["IDSTRING_" .. (status and "SINGLE" or self._has_auto and "AUTO" or "SINGLE")] 128 | 129 | if not skip_sound then 130 | self._sound_fire:post_event((status or self._has_auto) and "wp_auto_switch_on" or "wp_auto_switch_off") 131 | end 132 | 133 | self:cancel_burst() 134 | end 135 | 136 | function NewRaycastWeaponBase:can_use_burst_mode() 137 | return self._has_burst_fire 138 | end 139 | 140 | function NewRaycastWeaponBase:in_burst_mode() 141 | return self._fire_mode == NewRaycastWeaponBase.IDSTRING_SINGLE and self._in_burst_mode and not self:gadget_overrides_weapon_functions() 142 | end 143 | 144 | function NewRaycastWeaponBase:burst_rounds_remaining() 145 | return self._burst_rounds_remaining > 0 and self._burst_rounds_remaining or false 146 | end 147 | 148 | function NewRaycastWeaponBase:cancel_burst(soft_cancel) 149 | if self._adaptive_burst_size or not soft_cancel then 150 | self._burst_rounds_remaining = 0 151 | 152 | if self._delayed_burst_recoil and self._burst_rounds_fired > 0 then 153 | self._setup.user_unit:movement():current_state():force_recoil_kick(self, self._burst_rounds_fired) 154 | end 155 | self._burst_rounds_fired = 0 156 | end 157 | end 158 | 159 | elseif RequiredScript == "lib/units/weapons/akimboweaponbase" then 160 | 161 | local fire_original = AkimboWeaponBase.fire 162 | local toggle_firemode_original = AkimboWeaponBase.toggle_firemode 163 | 164 | function AkimboWeaponBase:_update_stats_values(...) 165 | AkimboWeaponBase.super._update_stats_values(self, ...) 166 | 167 | if not self:is_npc() then 168 | self._has_burst_fire = self._has_burst_fire or ((self:weapon_tweak_data().BURST_FIRE ~= false) and (self._fire_mode == NewRaycastWeaponBase.IDSTRING_SINGLE)) 169 | 170 | if self:can_use_burst_mode() then 171 | self:_set_burst_mode(not self._manual_fire_second_gun, true) 172 | end 173 | end 174 | end 175 | 176 | function AkimboWeaponBase:fire(...) 177 | local results = fire_original(self, ...) 178 | 179 | if not self:_in_burst_or_auto_mode() then 180 | self._fire_callbacks = {} 181 | end 182 | 183 | return results 184 | end 185 | 186 | --Override 187 | function AkimboWeaponBase:toggle_firemode(...) 188 | return self:can_use_burst_mode() and self:_check_toggle_burst() or toggle_firemode_original(self, ...) 189 | end 190 | 191 | function AkimboWeaponBase:_set_burst_mode(status, skip_sound) 192 | if alive(self._second_gun) then 193 | self._second_gun:base():_set_burst_mode(status, skip_sound) 194 | end 195 | 196 | return AkimboWeaponBase.super._set_burst_mode(self, status, skip_sound) 197 | end 198 | 199 | function AkimboWeaponBase:_in_burst_or_auto_mode() 200 | return self._fire_mode == NewRaycastWeaponBase.IDSTRING_AUTO or self:in_burst_mode() 201 | end 202 | 203 | elseif RequiredScript == "lib/units/weapons/akimboshotgunbase" then 204 | 205 | local akimbo_shotgun__update_stats_values_original = AkimboShotgunBase._update_stats_values 206 | 207 | function AkimboShotgunBase:_update_stats_values(...) 208 | akimbo_shotgun__update_stats_values_original(self, ...) 209 | 210 | if not self:is_npc() then 211 | self._has_burst_fire = self._has_burst_fire or ((self:weapon_tweak_data().BURST_FIRE ~= false) and (self._fire_mode == NewRaycastWeaponBase.IDSTRING_SINGLE)) 212 | 213 | if self._has_burst_fire then 214 | self:_set_burst_mode(not self._manual_fire_second_gun, true) 215 | end 216 | end 217 | end 218 | 219 | elseif RequiredScript == "lib/units/beings/player/states/playerstandard" then 220 | 221 | local update_original = PlayerStandard.update 222 | local _check_action_primary_attack_original = PlayerStandard._check_action_primary_attack 223 | local _check_action_deploy_underbarrel_original = PlayerStandard._check_action_deploy_underbarrel 224 | 225 | function PlayerStandard:update(t, ...) 226 | update_original(self, t, ...) 227 | self:_update_burst_fire(t) 228 | end 229 | 230 | function PlayerStandard:_check_action_primary_attack(t, input, ...) 231 | if self._trigger_down and not input.btn_primary_attack_state then 232 | self._equipped_unit:base():cancel_burst(true) 233 | end 234 | self._trigger_down = input.btn_primary_attack_state 235 | 236 | return _check_action_primary_attack_original(self, t, input, ...) 237 | end 238 | 239 | function PlayerStandard:_check_action_deploy_underbarrel(...) 240 | local new_action = _check_action_deploy_underbarrel_original(self, ...) 241 | 242 | if new_action and alive(self._equipped_unit) and self._equipped_unit:base() and self._equipped_unit:base():in_burst_mode() then 243 | managers.hud:set_teammate_weapon_firemode_burst(self._equipped_unit:base():selection_index()) 244 | end 245 | 246 | return new_action 247 | end 248 | 249 | --Override 250 | function PlayerStandard:_check_action_weapon_firemode(t, input) 251 | local wbase = self._equipped_unit:base() 252 | if input.btn_weapon_firemode_press and wbase.toggle_firemode then 253 | self:_check_stop_shooting() 254 | if wbase:toggle_firemode() then 255 | if wbase:in_burst_mode() then 256 | managers.hud:set_teammate_weapon_firemode_burst(self._unit:inventory():equipped_selection()) 257 | else 258 | managers.hud:set_teammate_weapon_firemode(HUDManager.PLAYER_PANEL, self._unit:inventory():equipped_selection(), wbase:fire_mode()) 259 | end 260 | end 261 | end 262 | end 263 | 264 | function PlayerStandard:_update_burst_fire(t) 265 | if alive(self._equipped_unit) and self._equipped_unit:base():burst_rounds_remaining() then 266 | self:_check_action_primary_attack(t, { btn_primary_attack_state = true, btn_primary_attack_press = true }) 267 | end 268 | end 269 | 270 | function PlayerStandard:force_recoil_kick(weap_base, manual_multiplier) 271 | local recoil_multiplier = (weap_base:recoil() + weap_base:recoil_addend()) * weap_base:recoil_multiplier() * (manual_multiplier or 1) 272 | local up, down, left, right = unpack(weap_base:weapon_tweak_data().kick[self._state_data.in_steelsight and "steelsight" or self._state_data.ducking and "crouching" or "standing"]) 273 | self._camera_unit:base():recoil_kick(up * recoil_multiplier, down * recoil_multiplier, left * recoil_multiplier, right * recoil_multiplier) 274 | end 275 | 276 | elseif RequiredScript == "lib/managers/playermanager" then 277 | 278 | local spawned_player_original = PlayerManager.spawned_player 279 | 280 | function PlayerManager:spawned_player(id, unit, ...) 281 | spawned_player_original(self, id, unit, ...) 282 | 283 | if unit:key() == self:player_unit():key() then 284 | for i = 1, 2, 1 do 285 | local wbase = unit:inventory():unit_by_selection(i):base() 286 | if wbase:in_burst_mode() then 287 | managers.hud:set_teammate_weapon_firemode_burst(i) 288 | end 289 | end 290 | end 291 | end 292 | 293 | elseif RequiredScript == "lib/managers/hudmanagerpd2" then 294 | 295 | HUDManager._USE_BURST_MODE = true --Custom HUD compatibility 296 | 297 | HUDManager.set_teammate_weapon_firemode_burst = HUDManager.set_teammate_weapon_firemode_burst or function(self, id) 298 | self._teammate_panels[HUDManager.PLAYER_PANEL]:set_weapon_firemode_burst(id) 299 | end 300 | 301 | elseif RequiredScript == "lib/managers/hud/hudteammate" then 302 | 303 | --Default function for vanilla HUD. If using a custom HUD that alters fire mode HUD components, make sure to implement this function in it 304 | HUDTeammate.set_weapon_firemode_burst = HUDTeammate.set_weapon_firemode_burst or function(self, id) 305 | local is_secondary = id == 1 306 | local secondary_weapon_panel = self._player_panel:child("weapons_panel"):child("secondary_weapon_panel") 307 | local primary_weapon_panel = self._player_panel:child("weapons_panel"):child("primary_weapon_panel") 308 | local weapon_selection = is_secondary and secondary_weapon_panel:child("weapon_selection") or primary_weapon_panel:child("weapon_selection") 309 | if alive(weapon_selection) then 310 | local firemode_single = weapon_selection:child("firemode_single") 311 | local firemode_auto = weapon_selection:child("firemode_auto") 312 | if alive(firemode_single) and alive(firemode_auto) then 313 | firemode_single:show() 314 | firemode_auto:show() 315 | end 316 | end 317 | end 318 | 319 | end -------------------------------------------------------------------------------- /devlua/BuyAllAsset.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steam-test1/VPlusHUD/c56193720729ca712c23bbd87af665e1447eff2a/devlua/BuyAllAsset.lua -------------------------------------------------------------------------------- /devlua/DamageIndicator.lua: -------------------------------------------------------------------------------- 1 | if _G.IS_VR then 2 | return 3 | end 4 | if not VHUDPlus:getSetting({"DamageIndicator", "ENABLED"}, true) then return end 5 | 6 | if string.lower(RequiredScript) == "lib/managers/hud/hudhitdirection" then 7 | HUDHitDirection.indicator_count = 0 8 | HUDHitDirection.DAMAGE_TYPES = {} 9 | HUDHitDirection.DAMAGE_TYPES.HEALTH = 1 10 | HUDHitDirection.DAMAGE_TYPES.ARMOUR = 2 11 | HUDHitDirection.DAMAGE_TYPES.VEHICLE = 3 12 | HUDHitDirection.DAMAGE_TYPES.CRIT = 4 13 | HUDHitDirection.DAMAGE_TYPES.FRIENDLY_FIRE = 5 14 | 15 | local init_original = HUDHitDirection.init 16 | local _add_hit_indicator_original = HUDHitDirection._add_hit_indicator 17 | local _remove_original = HUDHitDirection._remove 18 | 19 | function HUDHitDirection:init(...) 20 | init_original(self, ...) 21 | if alive(self._hud_panel) and alive(self._hit_direction_panel) then 22 | self._hit_direction_panel:set_w(self._hud_panel:w()) 23 | self._hit_direction_panel:set_h(self._hud_panel:h()) 24 | self._hit_direction_panel:set_center(self._hit_direction_panel:parent():w() * 0.5, self._hit_direction_panel:parent():h() * 0.5) 25 | end 26 | end 27 | 28 | function HUDHitDirection:_add_hit_indicator(...) 29 | HUDHitDirection.PANEL_SIZE = VHUDPlus:getSetting({"DamageIndicator", "SIZE"}, 150) 30 | if self.indicator_count < VHUDPlus:getSetting({"DamageIndicator", "MAX_AMOUNT"}, 10) then 31 | self.indicator_count = self.indicator_count + 1 32 | _add_hit_indicator_original(self, ...) 33 | end 34 | end 35 | 36 | function HUDHitDirection:_animate(indicator, data, remove_func) 37 | data.duration = VHUDPlus:getSetting({"DamageIndicator", "DURATION"}, 2) 38 | data.t = 0 39 | while data.t < data.duration do 40 | data.t = data.t + coroutine.yield() 41 | if alive(indicator) then 42 | local o = data.t / data.duration 43 | indicator:set_color(self:_get_indicator_color(data.damage_type, o)) 44 | indicator:set_alpha( math.clamp(math.sin(o * 180), 0, 1) ) 45 | if managers.player:player_unit() then 46 | local ply_camera = managers.player:player_unit():camera() 47 | if ply_camera then 48 | local target_vec = ply_camera:position() - data.origin 49 | local angle = target_vec:to_polar_with_reference(ply_camera:forward(), math.UP).spin 50 | local r = HUDHitDirection.PANEL_SIZE + (1-math.pow(o,0.5)) * (100) 51 | if data.fixed_angle ~= nil then 52 | angle = data.fixed_angle 53 | end 54 | indicator:set_rotation(90 - angle) 55 | indicator:set_center(self._hit_direction_panel:w() * 0.5 - math.sin(angle + 180) * r, self._hit_direction_panel:h() * 0.5 - math.cos(angle + 180) * r) 56 | end 57 | end 58 | end 59 | end 60 | remove_func(indicator, data) 61 | end 62 | 63 | function HUDHitDirection:_remove(...) 64 | if not self.indicator_count then 65 | return _remove_original(self, ...) 66 | end 67 | self.indicator_count = self.indicator_count - 1 68 | end 69 | 70 | function HUDHitDirection:_get_indicator_color(damage_type, t) 71 | if damage_type == HUDHitDirection.DAMAGE_TYPES.HEALTH then 72 | return VHUDPlus:getColorSetting({"DamageIndicator", "HEALTH_COLOR"}, "red") 73 | elseif damage_type == HUDHitDirection.DAMAGE_TYPES.ARMOUR then 74 | return VHUDPlus:getColorSetting({"DamageIndicator", "SHIELD_COLOR"}, "white") 75 | elseif damage_type == HUDHitDirection.DAMAGE_TYPES.VEHICLE then 76 | return VHUDPlus:getColorSetting({"DamageIndicator", "VEHICLE_COLOR"}, "yellow") 77 | elseif damage_type == HUDHitDirection.DAMAGE_TYPES.CRIT then 78 | return VHUDPlus:getColorSetting({"DamageIndicator", "CRIT_COLOR"}, "purple") 79 | elseif damage_type == HUDHitDirection.DAMAGE_TYPES.FRIENDLY_FIRE then 80 | return VHUDPlus:getColorSetting({"DamageIndicator", "FRIENDLY_FIRE_COLOR"}, "orange") 81 | else 82 | return Color(1, t, t) 83 | end 84 | end 85 | elseif string.lower(RequiredScript) == "lib/units/beings/player/playerdamage" then 86 | local PlayerDamage_damage_explosion = PlayerDamage.damage_explosion 87 | local PlayerDamage_damage_fire = PlayerDamage.damage_fire 88 | 89 | function PlayerDamage:damage_explosion(attack_data, ...) 90 | local value = PlayerDamage_damage_explosion(self, attack_data, ...) 91 | if alive(self._unit) and (attack_data.position or attack_data.col_ray.position) then 92 | local distance = mvector3.distance(attack_data.position or attack_data.col_ray.position, self._unit:position()) 93 | if self:_chk_can_take_dmg() and distance <= attack_data.range and not (self._god_mode or self._invulnerable or self._mission_damage_blockers.invulnerable or self:incapacitated() or self._bleed_out) then 94 | self:_hit_direction(attack_data.position, attack_data.col_ray and attack_data.col_ray.ray, HUDHitDirection.DAMAGE_TYPES.FRIENDLY_FIRE) 95 | end 96 | end 97 | return value 98 | end 99 | 100 | function PlayerDamage:damage_fire(attack_data, ...) 101 | local value = PlayerDamage_damage_fire(self, attack_data, ...) 102 | if alive(self._unit) and (attack_data.position or attack_data.col_ray.position) then 103 | local distance = mvector3.distance(attack_data.position or attack_data.col_ray.position, self._unit:position()) 104 | if self:_chk_can_take_dmg() and distance and not (self._god_mode or self._invulnerable or self._mission_damage_blockers.invulnerable or self:incapacitated() or self._bleed_out) then 105 | self:_hit_direction(attack_data.position, attack_data.col_ray and attack_data.col_ray.ray, HUDHitDirection.DAMAGE_TYPES.FRIENDLY_FIRE) 106 | end 107 | end 108 | return value 109 | end 110 | 111 | function PlayerDamage:_hit_direction(position_vector, direction_vector, damage_type) 112 | if position_vector then 113 | local armor_left, low_health = (self:get_real_armor() > 0), ((self:get_real_health() / self:_max_health()) <= 0.20) 114 | local dmg_type = damage_type or armor_left and HUDHitDirection.DAMAGE_TYPES.ARMOUR or low_health and HUDHitDirection.DAMAGE_TYPES.CRIT or HUDHitDirection.DAMAGE_TYPES.HEALTH 115 | managers.hud:on_hit_direction(position_vector, dmg_type) 116 | 117 | if direction_vector then 118 | local infront = math.dot(self._unit:camera():forward(), direction_vector) 119 | 120 | if infront < -0.9 then 121 | managers.environment_controller:hit_feedback_front() 122 | elseif infront > 0.9 then 123 | managers.environment_controller:hit_feedback_back() 124 | else 125 | local polar = self._unit:camera():forward():to_polar_with_reference(-direction_vector, math.UP) 126 | local direction = Vector3(polar.spin, polar.pitch, 0):normalized() 127 | 128 | if math.abs(direction.y) < math.abs(direction.x) then 129 | if direction.x < 0 then 130 | managers.environment_controller:hit_feedback_left() 131 | else 132 | managers.environment_controller:hit_feedback_right() 133 | end 134 | elseif direction.y < 0 then 135 | managers.environment_controller:hit_feedback_up() 136 | else 137 | managers.environment_controller:hit_feedback_down() 138 | end 139 | end 140 | end 141 | end 142 | end 143 | elseif string.lower(RequiredScript) == "lib/units/vehicles/vehicledamage" then 144 | --[[ -- Causes Access violation: Something with the angle calculation of the animation... 145 | function VehicleDamage:_hit_direction(position_vector, damage_type) 146 | if position_vector then 147 | local dmg_type = damage_type or HUDHitDirection.DAMAGE_TYPES.VEHICLE 148 | managers.hud:on_hit_direction(position_vector, dmg_type) 149 | end 150 | end 151 | --]] 152 | end -------------------------------------------------------------------------------- /devlua/DamagePopup.lua: -------------------------------------------------------------------------------- 1 | 2 | if RequiredScript == "lib/units/enemies/cop/copdamage" and not VHUDPlus.dmg_pop then 3 | VHUDPlus.dmg_pop = true 4 | local init_original = CopDamage.init 5 | function CopDamage.init(self, ...) 6 | self._head_body_name = self._head_body_name 7 | init_original(self, ...) 8 | self._hud = HoxPopUp:new(self._unit) 9 | end 10 | 11 | -- if blt.blt_info().platform == "mswindows" then 12 | HoxPopUp = HoxPopUp or class() 13 | -- end 14 | 15 | local _update_debug_ws_original = CopDamage._update_debug_ws 16 | 17 | function CopDamage:_update_debug_ws(damage_info, ...) 18 | self:popup_kill(damage_info) 19 | -- self:_process_popup_damage(damage_info) 20 | self._sync_ibody_popup = nil 21 | return _update_debug_ws_original(self, damage_info, ...) 22 | end 23 | 24 | function CopDamage:popup_kill(damage_info) 25 | -- if not blt.blt_info().platform == "mswindows" then return end 26 | 27 | local damage = damage_info and tonumber(damage_info.damage) or 0 28 | 29 | local attacker = damage_info and alive(damage_info.attacker_unit) and damage_info.attacker_unit 30 | local killer 31 | 32 | if alive( attacker ) and attacker:base() and attacker:base().thrower_unit then 33 | attacker = attacker:base():thrower_unit() 34 | end 35 | 36 | local damage_check = false 37 | 38 | if attacker and damage >= 0.1 and not damage_check then 39 | local body = damage_info and damage_info.col_ray and damage_info.col_ray.body 40 | local headshot = body and damage_info.headshot 41 | if damage_info and damage_info.variant == "bullet" and attacker:in_slot(2) then 42 | killer = attacker 43 | self._hud:show_damage(damage, self._dead, headshot) 44 | elseif damage_info and damage_info.variant == "melee" and attacker:in_slot(2) then 45 | killer = attacker 46 | self._hud:show_damage(damage, self._dead, headshot) 47 | elseif damage_info and damage_info.variant == "explosion" and attacker:in_slot(2) then 48 | killer = attacker 49 | self._hud:show_damage(damage, self._dead, false) 50 | elseif damage_info and damage_info.variant == "fire" and attacker:in_slot(2) then 51 | killer = attacker 52 | self._hud:show_damage(damage, self._dead, false) 53 | elseif attacker:in_slot(2) then 54 | killer = attacker 55 | self._hud:show_damage(damage, self._dead, headshot) 56 | end 57 | damage_check = true 58 | end 59 | end 60 | 61 | elseif RequiredScript == "lib/units/civilians/civiliandamage" then 62 | --Not Needed 63 | end 64 | -------------------------------------------------------------------------------- /devlua/DamagePopupWolf.lua: -------------------------------------------------------------------------------- 1 | if RequiredScript == "lib/units/enemies/cop/copdamage" and not VHUDPlus.fix2 then 2 | VHUDPlus.fix2 = true 3 | 4 | local _on_damage_received_original = CopDamage._on_damage_received 5 | --Workaround for Teammate Headshots, since col_ray doesn't get forwarded... (self._sync_ibody_popup) 6 | local sync_damage_bullet_original = CopDamage.sync_damage_bullet 7 | local sync_damage_melee_original = CopDamage.sync_damage_melee 8 | 9 | function CopDamage:_on_damage_received(data, ...) 10 | self:_process_popup_damage(data) 11 | self._sync_ibody_popup = nil 12 | return _on_damage_received_original(self, data, ...) 13 | end 14 | 15 | function CopDamage:sync_damage_bullet(attacker_unit, damage_percent, i_body, ...) 16 | if i_body then 17 | self._sync_ibody_popup = i_body 18 | end 19 | 20 | return sync_damage_bullet_original(self, attacker_unit, damage_percent, i_body, ...) 21 | end 22 | 23 | function CopDamage:sync_damage_melee(attacker_unit, damage_percent, damage_effect_percent, i_body, ...) 24 | if i_body then 25 | self._sync_ibody_popup = i_body 26 | end 27 | 28 | return sync_damage_melee_original(self, attacker_unit, damage_percent, damage_effect_percent, i_body, ...) 29 | 30 | end 31 | 32 | function CopDamage:_process_popup_damage(data) 33 | CopDamage.DMG_POPUP_SETTING = VHUDPlus:getSetting({"DamagePopupNew", "DISPLAY_MODE"}, 2) 34 | 35 | local attacker = alive(data.attacker_unit) and data.attacker_unit 36 | local damage = tonumber(data.damage) or 0 37 | 38 | if attacker and damage >= 0.1 and CopDamage.DMG_POPUP_SETTING > 1 then 39 | local killer 40 | 41 | if attacker:in_slot(3) or attacker:in_slot(5) then 42 | --Human team mate 43 | killer = attacker 44 | elseif attacker:in_slot(2) then 45 | --Player 46 | killer = attacker 47 | elseif attacker:in_slot(16) then 48 | --Bot/joker 49 | local key = tostring(attacker:key()) 50 | local minion_data = managers.gameinfo and managers.gameinfo:get_minions(key) 51 | if minion_data then 52 | -- Joker 53 | killer = minion_data.owner and managers.criminals:character_unit_by_peer_id(minion_data.owner) 54 | else 55 | -- Bot 56 | killer = attacker 57 | end 58 | elseif attacker:in_slot(12) then 59 | --Enemy 60 | elseif attacker:in_slot(25) then 61 | --Turret 62 | local owner = attacker:base():get_owner_id() 63 | if owner then 64 | killer = managers.criminals:character_unit_by_peer_id(owner) 65 | end 66 | elseif attacker:base().thrower_unit then 67 | killer = attacker:base():thrower_unit() 68 | end 69 | 70 | if alive(killer) and alive(self._unit) then 71 | local body = data.col_ray and data.col_ray.body or self._sync_ibody_popup and self._unit:body(self._sync_ibody_popup) 72 | local headshot = body and self.is_head and self:is_head(body) or false 73 | if CopDamage.DMG_POPUP_SETTING == 2 then 74 | if killer:in_slot(2) then 75 | self:show_popup(damage, self._dead, headshot, data.critical_hit) 76 | end 77 | else 78 | local color_id = managers.criminals:character_color_id_by_unit(killer) 79 | if color_id then 80 | self:show_popup(damage, self._dead, headshot, false, color_id) 81 | end 82 | end 83 | end 84 | end 85 | end 86 | 87 | function CopDamage:show_popup(damage, dead, headshot, critical, color_id) 88 | if managers.waypoints then 89 | local id = "damage_wp_" .. tostring(self._unit:key()) 90 | local waypoint = managers.waypoints:get_waypoint(id) 91 | local waypoint_color = color_id and ((color_id == 5 and VHUDPlus:getSetting({"CustomHUD", "TEAMMATE", "AI_COLOR", "USE"}, false)) and VHUDPlus:getColorSetting({"CustomHUD", "TEAMMATE", "AI_COLOR", "COLOR"}, Color.white) or tweak_data.chat_colors[color_id]) or VHUDPlus:getColorSetting({"DamagePopupNew", critical and "CRITICAL_COLOR" or headshot and "HEADSHOT_COLOR" or "COLOR"}, "yellow") 92 | waypoint_color = waypoint_color:with_alpha(VHUDPlus:getSetting({"DamagePopupNew", "ALPHA"}, 1)) 93 | local waypoint_duration = VHUDPlus:getSetting({"DamagePopupNew", "DURATION"}, 3) 94 | if waypoint and not waypoint:is_deleted() then 95 | managers.waypoints:set_waypoint_duration(id, "duration", waypoint_duration) 96 | managers.waypoints:set_waypoint_label(id, "label", self:build_popup_text(damage, headshot)) 97 | managers.waypoints:set_waypoint_setting(id, "color", waypoint_color) 98 | managers.waypoints:set_waypoint_component_setting(id, "icon", "show", dead) 99 | else 100 | local params = { 101 | unit = self._unit, 102 | offset = Vector3(10, 10, VHUDPlus:getSetting({"DamagePopupNew", "HEIGHT"}, 20)), 103 | scale = 2 * VHUDPlus:getSetting({"DamagePopupNew", "SCALE_ALT"}, 1), 104 | color = waypoint_color, 105 | visible_distance = { 106 | min = 30, 107 | max = 10000 108 | }, 109 | rescale_distance = { 110 | start_distance = 500, 111 | end_distance = 3000, 112 | final_scale = 0.5 113 | }, 114 | fade_duration = { 115 | start = 0.5, 116 | stop = 1, 117 | alpha = true, 118 | }, 119 | icon = { 120 | type = "icon", 121 | show = dead, 122 | scale = VHUDPlus:getSetting({"DamagePopupNew", "SKULL_SCALE"}, 1.2), 123 | texture = "guis/textures/pd2/risklevel_blackscreen", 124 | texture_rect = {0, 0, 64, 64}, 125 | blend_mode = "normal", 126 | on_minimap = false 127 | }, 128 | label = { 129 | type = "label", 130 | show = true, 131 | text = self:build_popup_text(damage, headshot, true) 132 | }, 133 | duration = { 134 | type = "duration", 135 | show = false, 136 | initial_value = waypoint_duration, 137 | fade_duration = { 138 | start = 0, 139 | stop = 1, 140 | position = Vector3(0, 0, 30), 141 | }, 142 | }, 143 | component_order = { VHUDPlus:getSetting({"DamagePopupNew", "SKULL_ALIGN"}, 1) == 1 and { "icon", "label" } or { "label", "icon" } , { "duration" } } 144 | } 145 | managers.waypoints:add_waypoint(id, "CustomWaypoint", params) 146 | end 147 | end 148 | end 149 | 150 | function CopDamage:build_popup_text(damage, headshot, is_new) 151 | self._dmg_value = (not is_new and self._dmg_value or 0) + (damage * 10) 152 | return math.floor(self._dmg_value) .. ((CopDamage.DMG_POPUP_SETTING == 3 and headshot) and "!" or "") 153 | end 154 | 155 | elseif RequiredScript == "lib/units/civilians/civiliandamage" then 156 | local _on_damage_received_original = CivilianDamage._on_damage_received 157 | function CivilianDamage:_on_damage_received(data, ...) 158 | CivilianDamage.super._process_popup_damage(self, data) 159 | return _on_damage_received_original(self, data, ...) 160 | end 161 | end -------------------------------------------------------------------------------- /devlua/DownCounter.lua: -------------------------------------------------------------------------------- 1 | if _G.IS_VR then 2 | return 3 | end 4 | if VHUDPlus:getSetting({"CustomHUD", "HUDTYPE"}, 2) == 2 or VHUDPlus:getSetting({"CustomHUD", "HUDTYPE"}, 2) == 3 then 5 | 6 | if string.lower(RequiredScript) == "lib/units/beings/player/huskplayermovement" then 7 | 8 | -- local _perform_movement_action_enter_bleedout_original = HuskPlayerMovement._perform_movement_action_enter_bleedout 9 | 10 | -- function HuskPlayerMovement:_perform_movement_action_enter_bleedout(...) 11 | -- if not self._bleedout then 12 | -- local crim_data = managers.criminals:character_data_by_unit(self._unit) 13 | -- if crim_data and crim_data.panel_id then 14 | -- managers.hud:increment_teammate_downs(crim_data.panel_id) 15 | -- end 16 | -- end 17 | 18 | -- return _perform_movement_action_enter_bleedout_original(self, ...) 19 | -- end 20 | elseif string.lower(RequiredScript) == "lib/managers/group_ai_states/groupaistatebase" then 21 | 22 | -- local set_whisper_mode_original = GroupAIStateBase.set_whisper_mode 23 | -- function GroupAIStateBase:set_whisper_mode(enabled, ...) 24 | -- set_whisper_mode_original(self, enabled, ...) 25 | -- if (enabled) then 26 | -- managers.hud:set_hud_mode("stealth") 27 | -- else 28 | -- managers.hud:set_hud_mode("loud") 29 | -- end 30 | -- self:_call_listeners("whisper_mode", enabled) 31 | -- end 32 | elseif string.lower(RequiredScript) == "lib/managers/hudmanagerpd2" then 33 | 34 | HUDManager.DOWNS_COUNTER_PLUGIN = true 35 | HUDManager.DETECT_COUNTER_PLUGIN = true 36 | 37 | -- local set_player_health_original = HUDManager.set_player_health 38 | -- local set_mugshot_custody_original = HUDManager.set_mugshot_custody 39 | 40 | -- function HUDManager:set_player_health(data, ...) 41 | -- if data.revives then 42 | -- self:set_player_revives(HUDManager.PLAYER_PANEL, data.revives - 1) 43 | -- end 44 | -- return set_player_health_original(self, data, ...) 45 | -- end 46 | 47 | -- function HUDManager:set_mugshot_custody(id, ...) 48 | -- local data = self:_get_mugshot_data(id) 49 | -- if data then 50 | -- local i = managers.criminals:character_data_by_name(data.character_name_id).panel_id 51 | -- managers.hud:reset_teammate_downs(i) 52 | -- end 53 | 54 | -- return set_mugshot_custody_original(self, id, ...) 55 | -- end 56 | 57 | function HUDManager:set_hud_mode(mode) 58 | for _, panel in pairs(self._teammate_panels or {}) do 59 | panel:set_hud_mode(mode) 60 | end 61 | end 62 | 63 | HUDManager.set_player_revives = HUDManager.set_player_revives or function(self, i, revive_amount) 64 | self._teammate_panels[i]:set_revives_amount(revive_amount) 65 | end 66 | 67 | -- HUDManager.increment_teammate_downs = HUDManager.increment_teammate_downs or function(self, i) 68 | -- self._teammate_panels[i]:increment_downs() 69 | -- end 70 | 71 | -- HUDManager.reset_teammate_downs = HUDManager.reset_teammate_downs or function(self, i) 72 | -- self._teammate_panels[i]:reset_downs() 73 | -- end 74 | 75 | elseif string.lower(RequiredScript) == "lib/managers/hud/hudteammate" and not HUDManager.CUSTOM_TEAMMATE_PANELS then 76 | 77 | Hooks:PostHook( HUDTeammate, "init", "WolfHUD_DownCounter_HUDTeammate_init", function(self, ...) 78 | self._health_panel = self._health_panel or self._player_panel:child("radial_health_panel") 79 | self._condition_icon = self._condition_icon or self._panel:child("condition_icon") 80 | self._setting_prefix = self._main_player and "PLAYER" or "TEAMMATE" 81 | self._down_counter = HUDManager.DOWNS_COUNTER_PLUGIN and VHUDPlus:getSetting({"CustomHUD", self._setting_prefix, "DOWNCOUNTER"}, true) 82 | self._detection_risk = HUDManager.DETECT_COUNTER_PLUGIN and VHUDPlus:getSetting({"CustomHUD", self._setting_prefix, "DETECTIONCOUNTER"}, true) 83 | self.vis_down = self._condition_icon and self._condition_icon:visible() or not (HUDManager.DOWNS_COUNTER_PLUGIN and VHUDPlus:getSetting({"CustomHUD", self._setting_prefix, "DOWNCOUNTER"}, true)) or self._ai 84 | self.vis_detect = self._condition_icon and self._condition_icon:visible() or not (HUDManager.DETECT_COUNTER_PLUGIN and VHUDPlus:getSetting({"CustomHUD", self._setting_prefix, "DETECTIONCOUNTER"}, true)) or self._ai 85 | 86 | self._health_panel:bitmap({ 87 | name = "risk_indicator_bg", 88 | texture = "guis/textures/pd2/hot_cold_glow", 89 | texture_rect = { 0, 0, 64, 64 }, 90 | blend_mode = "normal", 91 | color = Color.black, 92 | alpha = 0.6, 93 | w = self._health_panel:w(), 94 | h = self._health_panel:h(), 95 | layer = 1 96 | }) 97 | 98 | self._downs_counter = self._health_panel:text({ 99 | name = "downs", 100 | color = Color.white, 101 | align = "center", 102 | vertical = "center", 103 | w = self._health_panel:w(), 104 | h = self._health_panel:h(), 105 | font_size = self._main_player and 16 or 13, 106 | font = tweak_data.menu.pd2_medium_font, 107 | layer = 2, 108 | visible = HUDManager.DOWNS_COUNTER_PLUGIN and VHUDPlus:getSetting({"CustomHUD", self._setting_prefix, "DOWNCOUNTER"}, true) and not self._ai or false 109 | }) 110 | 111 | self._detection_counter = self._health_panel:text({ 112 | name = "detection", 113 | color = Color.red, 114 | align = "center", 115 | vertical = "center", 116 | w = self._health_panel:w(), 117 | h = self._health_panel:h(), 118 | font_size = self._main_player and 16 or 13, 119 | font = tweak_data.menu.pd2_medium_font, 120 | layer = 2, 121 | visible = HUDManager.DETECT_COUNTER_PLUGIN and VHUDPlus:getSetting({"CustomHUD", self._setting_prefix, "DETECTIONCOUNTER"}, true) and not self._ai or false 122 | }) 123 | 124 | self:set_detection() 125 | 126 | if managers.gameinfo then 127 | managers.gameinfo:register_listener("HealthRadial_whisper_mode_listener" .. tostring(self._id), "whisper_mode", "change", callback(self, self, "_whisper_mode_change"), nil, true) 128 | end 129 | 130 | if self._panel:child("player"):child("revive_panel") then 131 | self._panel:child("player"):child("revive_panel"):set_visible(VHUDPlus:getSetting({"CustomHUD", self._setting_prefix, "NEWDOWNCOUNTER"}, false)) 132 | end 133 | end) 134 | 135 | Hooks:PostHook( HUDTeammate, "remove_panel", "WolfHUD_DownCounter_HUDTeammate_remove_panel", function(self, ...) 136 | managers.gameinfo:unregister_listener("HealthRadial_whisper_mode_listener" .. tostring(self._id), "whisper_mode", "change") 137 | end) 138 | 139 | Hooks:PostHook( HUDTeammate, "set_peer_id", "WolfHUD_DownCounter_HUDTeammate_set_peer_id", function(self, ...) 140 | self:set_detection() 141 | end) 142 | 143 | Hooks:PostHook( HUDTeammate, "set_callsign", "WolfHUD_DownCounter_HUDTeammate_set_callsign", function(self, ...) 144 | if self._main_player then 145 | self:set_detection() 146 | end 147 | end) 148 | 149 | local set_revives_amount_ori = HUDTeammate.set_revives_amount 150 | function HUDTeammate:set_revives_amount(revive_amount) 151 | set_revives_amount_ori(self, revive_amount) 152 | self._health_panel = self._health_panel or self._player_panel:child("radial_health_panel") 153 | self._downs_counter = self._health_panel:child("downs") 154 | 155 | if self._downs_counter then 156 | self._downs_counter:set_text(tostring(math.max(revive_amount - 1, 0))) 157 | end 158 | end 159 | 160 | function HUDTeammate:_whisper_mode_change(status) 161 | self._downs_counter:set_visible(not self.vis_down and not status) 162 | self._detection_counter:set_visible(not self.vis_detect and managers.groupai:state():whisper_mode()) 163 | end 164 | 165 | HUDTeammate.set_downs = HUDTeammate.set_downs or function(self, amount) 166 | self._downs_counter:set_visible(not self.vis_down and not managers.groupai:state():whisper_mode()) 167 | self._detection_counter:set_visible(not self.vis_detect and managers.groupai:state():whisper_mode()) 168 | end 169 | 170 | HUDTeammate.set_detection = HUDTeammate.set_detection or function(self, risk) 171 | if not risk then 172 | if self._main_player then 173 | risk = tonumber(string.format("%.0f", managers.blackmarket:get_suspicion_offset_of_local(tweak_data.player.SUSPICION_OFFSET_LERP or 0.75) * 100)) 174 | elseif self:peer_id() then 175 | risk = tonumber(string.format("%.0f", managers.blackmarket:get_suspicion_offset_of_peer(managers.network:session():peer(self:peer_id()), tweak_data.player.SUSPICION_OFFSET_LERP or 0.75) * 100)) 176 | end 177 | end 178 | if not self._risk or risk and risk ~= self._risk then 179 | self._risk = risk 180 | if self._risk then 181 | local color = self._risk < 50 and Color(1, 0, 0.8, 1) or Color(1, 1, 0.2, 0) 182 | self._detection_counter:set_text(tostring(self._risk)) 183 | self._detection_counter:set_color(color) 184 | end 185 | 186 | if self._downs_counter then 187 | self._downs_counter:set_visible(not self.vis_down and not managers.groupai:state():whisper_mode()) 188 | end 189 | if self._detection_counter then 190 | self._detection_counter:set_visible(not self.vis_detect and managers.groupai:state():whisper_mode()) 191 | end 192 | end 193 | end 194 | end 195 | end 196 | -------------------------------------------------------------------------------- /devlua/EnemyHealthbarAlt.lua: -------------------------------------------------------------------------------- 1 | if string.lower(RequiredScript) == "lib/managers/hudmanager" and not HopLib then 2 | 3 | Hooks:PostHook( HUDManager , "_player_hud_layout" , "WolfHUDPostHUDManagerPlayerInfoHUDLayout" , function( self ) 4 | self._health_text_rect = { 2 , 18 , 232 , 11 } --Green Bar 5 | self._shield_text_rect = { 2 , 34 , 232 , 11 } --Blue Bar 6 | self._bar_text_rect = self._health_text_rect 7 | self._shield = false 8 | 9 | local unit_health_main = managers.hud:script(PlayerBase.PLAYER_INFO_HUD_PD2).panel:panel({ 10 | name = "unit_health_main", 11 | halign = "grow", 12 | valign = "grow" 13 | }) 14 | 15 | self._unit_health_panel = unit_health_main:panel({ 16 | name = "unit_health_panel", 17 | visible = false 18 | }) 19 | 20 | self._unit_bar = self._unit_health_panel:bitmap({ 21 | name = "unit_health", 22 | texture = "guis/textures/pd2/healthshield", 23 | texture_rect = self._bar_text_rect, 24 | blend_mode = "normal" 25 | }) 26 | 27 | self._unit_bar_bg = self._unit_health_panel:bitmap({ 28 | name = "unit_shield", 29 | texture = "guis/textures/pd2/healthshield", 30 | texture_rect = { 1, 1, 234, 13 }, 31 | blend_mode = "normal" 32 | }) 33 | 34 | self._unit_health_text = self._unit_health_panel:text({ 35 | name = "unit_health_text", 36 | text = "250000/250000", 37 | blend_mode = "normal", 38 | alpha = 1, 39 | halign = "right", 40 | font = tweak_data.hud.medium_font, 41 | font_size = 20, 42 | color = Color.white, 43 | align = "center", 44 | layer = 1 45 | }) 46 | 47 | self._unit_health_enemy_text = self._unit_health_panel:text({ 48 | name = "unit_health_enemy_text", 49 | text = "SWAT VAN TURRET", 50 | blend_mode = "normal", 51 | alpha = 1, 52 | halign = "left", 53 | font = tweak_data.hud.medium_font, 54 | font_size = 22, 55 | color = Color.white, 56 | align = "center", 57 | layer = 1 58 | }) 59 | 60 | self._unit_health_enemy_location = self._unit_health_panel:text({ 61 | name = "unit_health_enemy_location", 62 | text = "^", 63 | blend_mode = "normal", 64 | visible = VHUDPlus:getSetting({"EnemyHealthbar", "SHOW_POINTER"}, false), 65 | alpha = 0.75, 66 | halign = "center", 67 | font = tweak_data.hud.medium_font, 68 | font_size = 20, 69 | color = Color.white, 70 | align = "center", 71 | layer = 1 72 | }) 73 | 74 | local _ ,_ ,hw ,hh = self._unit_health_text:text_rect() 75 | local _ ,_ ,ew ,eh = self._unit_health_enemy_text:text_rect() 76 | local _ ,_ ,lw ,lh = self._unit_health_enemy_location:text_rect() 77 | 78 | self._unit_health_text:set_size( hw , hh ) 79 | self._unit_health_enemy_text:set_size( ew , eh ) 80 | self._unit_health_enemy_location:set_size( lw , lh ) 81 | 82 | self._unit_bar:set_w( self._unit_bar:w() - 2 ) 83 | 84 | self._unit_bar:set_center( self._unit_health_panel:center_x() , self._unit_health_panel:center_y() - 190 ) 85 | self._unit_bar_bg:set_center( self._unit_health_panel:center_x() , self._unit_health_panel:center_y() - 190 ) 86 | 87 | self._unit_health_text:set_right( self._unit_bar_bg:right() ) 88 | self._unit_health_text:set_bottom( self._unit_bar_bg:top() ) 89 | 90 | self._unit_health_enemy_text:set_left( self._unit_bar_bg:left() ) 91 | self._unit_health_enemy_text:set_bottom( self._unit_bar_bg:top() ) 92 | 93 | self._unit_health_enemy_location:set_center_x( self._unit_bar_bg:center_x() ) 94 | self._unit_health_enemy_location:set_top( self._unit_bar_bg:bottom() ) 95 | 96 | end ) 97 | 98 | function HUDManager:set_unit_health_visible( visible, shield ) 99 | if visible and self._shield ~= shield then 100 | self._shield = shield or false 101 | self._bar_text_rect = self._shield and self._shield_text_rect or self._health_text_rect 102 | end 103 | 104 | if visible == true and not self._unit_health_visible and VHUDPlus:getSetting({"EnemyHealthbar", "ENABLED_ALT"}, true) then 105 | 106 | self._unit_health_visible = true 107 | self._unit_health_enemy_location:set_visible(VHUDPlus:getSetting({"EnemyHealthbar", "SHOW_POINTER"}, false)) 108 | self._unit_health_panel:stop() 109 | self._unit_health_panel:animate( function( p ) 110 | self._unit_health_panel:set_visible( true ) 111 | 112 | over( 0.25 , function( o ) 113 | self._unit_health_panel:set_alpha( math.lerp( self._unit_health_panel:alpha() , 1 , o ) ) 114 | end ) 115 | end ) 116 | 117 | elseif visible == false and self._unit_health_visible then 118 | 119 | self._unit_health_visible = nil 120 | self._unit_health_panel:stop() 121 | 122 | self._unit_health_panel:animate( function( p ) 123 | if self._unit_health_panel:alpha() >= 0.9 then 124 | over( 0.5 , function( o ) end ) 125 | end 126 | 127 | over( 1.5 , function( o ) 128 | self._unit_health_panel:set_alpha( math.lerp( self._unit_health_panel:alpha() , 0 , o ) ) 129 | end ) 130 | 131 | self._unit_health_panel:set_visible( false ) 132 | end ) 133 | end 134 | 135 | if VHUDPlus:getSetting({"EnemyHealthbar", "ENABLED_ALT"}, true) then 136 | managers.hud:set_enemy_health_visible(false) 137 | end 138 | end 139 | 140 | function HUDManager:set_unit_health( current , total , tweak_table ) 141 | 142 | if not current or not total then return end 143 | 144 | local enemy = VHUDPlus:getCharacterName(tweak_table, true) 145 | 146 | total = math.min(total, 999999999) 147 | current = math.clamp(current, 0, total) 148 | local _r = current / total 149 | 150 | local r = self._unit_bar:width() 151 | local rn = ( self._unit_bar_bg:w() - 4 ) * _r 152 | 153 | self._unit_health_enemy_text:set_text( enemy ) 154 | if total > 0 then 155 | self._unit_health_text:set_text( string.format( "%s/%s" , managers.money:add_decimal_marks_to_string(tostring(current)) , managers.money:add_decimal_marks_to_string(tostring(total)) ) ) 156 | else 157 | self._unit_health_text:set_text( string.format( "%s" , managers.money:add_decimal_marks_to_string(tostring(current)) ) ) 158 | end 159 | 160 | local _ ,_ ,hw ,hh = self._unit_health_text:text_rect() 161 | local _ ,_ ,ew ,eh = self._unit_health_enemy_text:text_rect() 162 | 163 | self._unit_health_text:set_size( hw , hh ) 164 | self._unit_health_enemy_text:set_size( ew , eh ) 165 | 166 | self._unit_health_text:set_right( self._unit_bar_bg:right() ) 167 | self._unit_health_text:set_bottom( self._unit_bar_bg:top() ) 168 | self._unit_health_enemy_text:set_left( self._unit_bar_bg:left() ) 169 | self._unit_health_enemy_text:set_bottom( self._unit_bar_bg:top() ) 170 | 171 | self._unit_health_text:set_color( _r <= 0.1 and Color.red or _r <= 0.25 and Color.yellow or Color.white ) 172 | 173 | self._unit_bar:stop() 174 | 175 | self._bar_text_rect = self._shield and self._shield_text_rect or self._health_text_rect 176 | 177 | self._unit_bar:animate( function( p ) 178 | if rn < r then 179 | over( 0.2 , function( o ) 180 | self._unit_bar:set_w( math.lerp( r , rn , o ) ) 181 | self._unit_bar:set_texture_rect( self._bar_text_rect[1] , self._bar_text_rect[2] , math.lerp( r , rn , o ) , self._bar_text_rect[4] ) 182 | end ) 183 | end 184 | 185 | self._unit_bar:set_w( _r * ( self._bar_text_rect[3] - 2 ) ) 186 | self._unit_bar:set_texture_rect( self._bar_text_rect[1] , self._bar_text_rect[2] , self._bar_text_rect[3] * _r , self._bar_text_rect[4] ) 187 | end ) 188 | end 189 | 190 | function HUDManager:set_unit_health_rotation( angle ) 191 | 192 | self._unit_health_enemy_location:set_rotation( angle ) 193 | 194 | end 195 | elseif string.lower(RequiredScript) == "lib/managers/hudmanager" and HopLib then 196 | Hooks:PostHook( HUDManager , "_player_hud_layout" , "WolfHUDPostHUDManagerPlayerInfoHUDLayout" , function( self ) 197 | self._health_text_rect = { 2 , 18 , 232 , 11 } --Green Bar 198 | self._shield_text_rect = { 2 , 34 , 232 , 11 } --Blue Bar 199 | self._bar_text_rect = self._health_text_rect 200 | self._shield = false 201 | 202 | local unit_health_main = managers.hud:script(PlayerBase.PLAYER_INFO_HUD_PD2).panel:panel({ 203 | name = "unit_health_main", 204 | halign = "grow", 205 | valign = "grow" 206 | }) 207 | 208 | self._unit_health_panel = unit_health_main:panel({ 209 | name = "unit_health_panel", 210 | visible = false 211 | }) 212 | 213 | self._unit_bar = self._unit_health_panel:bitmap({ 214 | name = "unit_health", 215 | texture = "guis/textures/pd2/healthshield", 216 | texture_rect = self._bar_text_rect, 217 | blend_mode = "normal" 218 | }) 219 | 220 | self._unit_bar_bg = self._unit_health_panel:bitmap({ 221 | name = "unit_shield", 222 | texture = "guis/textures/pd2/healthshield", 223 | texture_rect = { 1, 1, 234, 13 }, 224 | blend_mode = "normal" 225 | }) 226 | 227 | self._unit_health_text = self._unit_health_panel:text({ 228 | name = "unit_health_text", 229 | text = "250000/250000", 230 | blend_mode = "normal", 231 | alpha = 1, 232 | halign = "right", 233 | font = tweak_data.hud.medium_font, 234 | font_size = 20, 235 | color = Color.white, 236 | align = "center", 237 | layer = 1 238 | }) 239 | 240 | self._unit_health_enemy_text = self._unit_health_panel:text({ 241 | name = "unit_health_enemy_text", 242 | text = "SWAT VAN TURRET", 243 | blend_mode = "normal", 244 | alpha = 1, 245 | halign = "left", 246 | font = tweak_data.hud.medium_font, 247 | font_size = 22, 248 | color = Color.white, 249 | align = "center", 250 | layer = 1 251 | }) 252 | 253 | self._unit_health_enemy_location = self._unit_health_panel:text({ 254 | name = "unit_health_enemy_location", 255 | text = "^", 256 | blend_mode = "normal", 257 | visible = VHUDPlus:getSetting({"EnemyHealthbar", "SHOW_POINTER"}, false), 258 | alpha = 0.75, 259 | halign = "center", 260 | font = tweak_data.hud.medium_font, 261 | font_size = 20, 262 | color = Color.white, 263 | align = "center", 264 | layer = 1 265 | }) 266 | 267 | local _ ,_ ,hw ,hh = self._unit_health_text:text_rect() 268 | local _ ,_ ,ew ,eh = self._unit_health_enemy_text:text_rect() 269 | local _ ,_ ,lw ,lh = self._unit_health_enemy_location:text_rect() 270 | 271 | self._unit_health_text:set_size( hw , hh ) 272 | self._unit_health_enemy_text:set_size( ew , eh ) 273 | self._unit_health_enemy_location:set_size( lw , lh ) 274 | 275 | self._unit_bar:set_w( self._unit_bar:w() - 2 ) 276 | 277 | self._unit_bar:set_center( self._unit_health_panel:center_x() , self._unit_health_panel:center_y() - 190 ) 278 | self._unit_bar_bg:set_center( self._unit_health_panel:center_x() , self._unit_health_panel:center_y() - 190 ) 279 | 280 | self._unit_health_text:set_right( self._unit_bar_bg:right() ) 281 | self._unit_health_text:set_bottom( self._unit_bar_bg:top() ) 282 | 283 | self._unit_health_enemy_text:set_left( self._unit_bar_bg:left() ) 284 | self._unit_health_enemy_text:set_bottom( self._unit_bar_bg:top() ) 285 | 286 | self._unit_health_enemy_location:set_center_x( self._unit_bar_bg:center_x() ) 287 | self._unit_health_enemy_location:set_top( self._unit_bar_bg:bottom() ) 288 | 289 | end ) 290 | 291 | function HUDManager:set_unit_health_visible( visible, shield ) 292 | if visible and self._shield ~= shield then 293 | self._shield = shield or false 294 | self._bar_text_rect = self._shield and self._shield_text_rect or self._health_text_rect 295 | end 296 | 297 | if visible == true and not self._unit_health_visible and VHUDPlus:getSetting({"EnemyHealthbar", "ENABLED_ALT"}, true) then 298 | 299 | self._unit_health_visible = true 300 | self._unit_health_enemy_location:set_visible(VHUDPlus:getSetting({"EnemyHealthbar", "SHOW_POINTER"}, false)) 301 | self._unit_health_panel:stop() 302 | self._unit_health_panel:animate( function( p ) 303 | self._unit_health_panel:set_visible( true ) 304 | 305 | over( 0.25 , function( o ) 306 | self._unit_health_panel:set_alpha( math.lerp( self._unit_health_panel:alpha() , 1 , o ) ) 307 | end ) 308 | end ) 309 | 310 | elseif visible == false and self._unit_health_visible then 311 | 312 | self._unit_health_visible = nil 313 | self._unit_health_panel:stop() 314 | 315 | self._unit_health_panel:animate( function( p ) 316 | if self._unit_health_panel:alpha() >= 0.9 then 317 | over( 0.5 , function( o ) end ) 318 | end 319 | 320 | over( 1.5 , function( o ) 321 | self._unit_health_panel:set_alpha( math.lerp( self._unit_health_panel:alpha() , 0 , o ) ) 322 | end ) 323 | 324 | self._unit_health_panel:set_visible( false ) 325 | end ) 326 | end 327 | 328 | if VHUDPlus:getSetting({"EnemyHealthbar", "ENABLED_ALT"}, true) then 329 | managers.hud:set_enemy_health_visible(false) 330 | end 331 | end 332 | 333 | function HUDManager:set_unit_health( current , total , unit ) 334 | 335 | if not current or not total then return end 336 | 337 | local info = HopLib and HopLib:unit_info_manager():get_info(unit) 338 | 339 | local enemy = info and info:name() or "Unknown" 340 | 341 | local _r = current / total 342 | 343 | local r = self._unit_bar:width() 344 | local rn = ( self._unit_bar_bg:w() - 4 ) * _r 345 | 346 | self._unit_health_enemy_text:set_text( enemy ) 347 | self._unit_health_text:set_text( string.format( "%d/%d" , current * 10 , total * 10 ) ) 348 | 349 | local _ ,_ ,hw ,hh = self._unit_health_text:text_rect() 350 | local _ ,_ ,ew ,eh = self._unit_health_enemy_text:text_rect() 351 | 352 | self._unit_health_text:set_size( hw , hh ) 353 | self._unit_health_enemy_text:set_size( ew , eh ) 354 | 355 | self._unit_health_text:set_right( self._unit_bar_bg:right() ) 356 | self._unit_health_text:set_bottom( self._unit_bar_bg:top() ) 357 | self._unit_health_enemy_text:set_left( self._unit_bar_bg:left() ) 358 | self._unit_health_enemy_text:set_bottom( self._unit_bar_bg:top() ) 359 | 360 | self._unit_health_text:set_color( _r <= 0.1 and Color.red or _r <= 0.25 and Color.yellow or Color.white ) 361 | 362 | self._unit_bar:stop() 363 | 364 | self._bar_text_rect = self._shield and self._shield_text_rect or self._health_text_rect 365 | 366 | self._unit_bar:animate( function( p ) 367 | if rn < r then 368 | over( 0.2 , function( o ) 369 | self._unit_bar:set_w( math.lerp( r , rn , o ) ) 370 | self._unit_bar:set_texture_rect( self._bar_text_rect[1] , self._bar_text_rect[2] , math.lerp( r , rn , o ) , self._bar_text_rect[4] ) 371 | end ) 372 | end 373 | 374 | self._unit_bar:set_w( _r * ( self._bar_text_rect[3] - 2 ) ) 375 | self._unit_bar:set_texture_rect( self._bar_text_rect[1] , self._bar_text_rect[2] , self._bar_text_rect[3] * _r , self._bar_text_rect[4] ) 376 | end ) 377 | end 378 | 379 | function HUDManager:set_unit_health_rotation( angle ) 380 | 381 | self._unit_health_enemy_location:set_rotation( angle ) 382 | 383 | end 384 | elseif string.lower(RequiredScript) == "lib/units/beings/player/states/playerstandard" and not HopLib then 385 | Hooks:PostHook( PlayerStandard , "_update_fwd_ray" , "WolfHUDPostPlayerStandardUpdate" , function( self , t , dt ) 386 | if self._fwd_ray and self._fwd_ray.unit and type(self._fwd_ray.unit) == "userdata" then 387 | local unit = self._fwd_ray.unit 388 | if unit:in_slot( 8 ) and alive(unit:parent()) then -- Fix when aiming at shields shield. 389 | unit = unit:parent() 390 | end 391 | 392 | if VHUDPlus:getSetting({"EnemyHealthbar", "IGNORE_CIVILIAN_HEALTH"}, true) and managers.enemy:is_civilian(unit) then 393 | return 394 | end 395 | if VHUDPlus:getSetting({"EnemyHealthbar", "IGNORE_TEAM_AI_HEALTH"}, true) and unit:in_slot(16) then 396 | return 397 | end 398 | 399 | local visible, name, name_id, health, max_health, shield, repair_check 400 | if alive( unit ) then 401 | if alive( unit ) and unit:in_slot( 25 ) and unit:character_damage() and not unit:character_damage():dead() then 402 | self._last_unit = nil 403 | visible = true 404 | name_id = unit:base():get_name_id() or "TURRET" 405 | repair_check = unit:character_damage():needs_repair() 406 | if not repair_check then 407 | shield = true 408 | health = unit:character_damage()._shield_health * 10 or 0 409 | max_health = unit:character_damage()._SHIELD_HEALTH_INIT * 10 or 0 410 | else 411 | health = unit:character_damage()._health * 10 or 0 412 | max_health = unit:character_damage()._HEALTH_INIT * 10 or 0 413 | end 414 | elseif alive( unit ) and ( unit:in_slot( 12 ) or ( unit:in_slot( 21 ) or unit:in_slot( 22 ) ) or unit:in_slot( 16 )) and not unit:character_damage():dead() then 415 | self._last_unit = unit 416 | visible = true 417 | health = unit:character_damage()._health * 10 or 0 418 | max_health = unit:character_damage()._HEALTH_INIT * 10 or 0 419 | name_id = unit:base()._tweak_table or "ENEMY" 420 | 421 | if name_id == "robbers_safehouse" and unit:interaction() then 422 | name_id = CriminalsManager.convert_new_to_old_character_workname(unit:interaction().character or name_id) 423 | end 424 | elseif alive( unit ) and unit:in_slot( 39 ) and VHUDPlus:getSetting({"EnemyHealthbar", "SHOW_VEHICLE"}, true) and unit:vehicle_driving() and not self._seat then 425 | self._last_unit = nil 426 | visible = true 427 | health = unit:character_damage()._health or 0 428 | max_health = unit:character_damage()._current_max_health or 0 429 | name = unit:vehicle_driving()._tweak_data.name or "VEHICLE" 430 | else 431 | visible = false 432 | end 433 | end 434 | 435 | if not visible and self._last_unit and alive( self._last_unit ) and self._last_unit:character_damage() then 436 | health = self._last_unit:character_damage()._health * 10 or 0 437 | max_health = self._last_unit:character_damage()._HEALTH_INIT * 10 or 0 438 | name_id = self._last_unit:base() and self._last_unit:base()._tweak_table or "ENEMY" 439 | 440 | if name_id == "robbers_safehouse" and self._last_unit:interaction() then 441 | name_id = CriminalsManager.convert_new_to_old_character_workname(self._last_unit:interaction().character or name_id) 442 | end 443 | 444 | local angle = (self:getUnitRotation(self._last_unit) + 360) % 360 445 | if self._last_unit:character_damage():dead() or (angle < 350 and angle > 10) then 446 | visible = false 447 | self._last_unit = nil 448 | else 449 | visible = true 450 | end 451 | 452 | managers.hud:set_unit_health_rotation( 360 - angle ) 453 | else 454 | managers.hud:set_unit_health_rotation(0) 455 | end 456 | 457 | managers.hud:set_unit_health_visible( visible, shield ) 458 | if health and (name or name_id) then 459 | managers.hud:set_unit_health( math.floor(health or 0) , math.floor(max_health or 0) , name_id or string.upper(name or "UNKNOWN")) 460 | end 461 | else 462 | managers.hud:set_unit_health_visible( false ) 463 | end 464 | 465 | end ) 466 | 467 | function PlayerStandard:getUnitRotation( unit ) 468 | 469 | if not unit or not alive( unit ) then return 360 end 470 | 471 | local unit_position = unit:position() 472 | local vector = unit_position - self._camera_unit:position() 473 | local forward = self._camera_unit:rotation():y() 474 | local rotation = math.floor( vector:to_polar_with_reference( forward , math.UP ).spin ) 475 | 476 | return rotation 477 | 478 | end 479 | elseif string.lower(RequiredScript) == "lib/units/beings/player/states/playerstandard" and HopLib then 480 | Hooks:PostHook( PlayerStandard , "_update_fwd_ray" , "uHUDPostPlayerStandardUpdateFwdRay" , function( self ) 481 | 482 | if self._last_unit then 483 | 484 | local iAngle = 360 485 | local cAngle = 360 486 | 487 | iAngle = self:getUnitRotation( self._last_unit ) 488 | 489 | if iAngle then 490 | 491 | cAngle = cAngle + ( iAngle - cAngle ) 492 | 493 | if cAngle == 0 then cAngle = 360 end 494 | 495 | managers.hud:set_unit_health_rotation( cAngle ) 496 | 497 | end 498 | 499 | end 500 | 501 | if self._fwd_ray and self._fwd_ray.unit then 502 | 503 | local unit = self._fwd_ray.unit 504 | 505 | if unit:in_slot( 8 ) and alive( unit:parent() ) then 506 | unit = unit:parent() 507 | end 508 | 509 | if VHUDPlus:getSetting({"EnemyHealthbar", "IGNORE_CIVILIAN_HEALTH"}, true) and managers.enemy:is_civilian(unit) then 510 | return 511 | end 512 | if VHUDPlus:getSetting({"EnemyHealthbar", "IGNORE_TEAM_AI_HEALTH"}, true) and unit:in_slot(16) then 513 | return 514 | end 515 | 516 | if alive( unit ) and unit:character_damage() and not unit:character_damage()._dead and unit:base() and (unit:base()._tweak_table or unit:base()._tweak_table_id) then 517 | 518 | if unit:in_slot( 25 ) then 519 | local repair_check 520 | repair_check = unit:character_damage():needs_repair() 521 | if not repair_check then 522 | shield = true 523 | managers.hud:set_unit_health_visible( true, true) 524 | managers.hud:set_unit_health( unit:character_damage()._shield_health or 0 , unit:character_damage()._SHIELD_HEALTH_INIT or 0 , unit ) 525 | end 526 | else 527 | self._last_unit = unit 528 | managers.hud:set_unit_health_visible( true, false ) 529 | managers.hud:set_unit_health( unit:character_damage()._health or 0 , unit:character_damage()._HEALTH_INIT or 0 , unit ) 530 | end 531 | 532 | elseif self._last_unit and alive( self._last_unit ) then 533 | managers.hud:set_unit_health( self._last_unit:character_damage()._health or 0 , self._last_unit:character_damage()._HEALTH_INIT or 0 , self._last_unit ) 534 | managers.hud:set_unit_health_visible( false, false ) 535 | end 536 | end 537 | 538 | end ) 539 | 540 | function PlayerStandard:getUnitRotation( unit ) 541 | 542 | if not unit or not alive( unit ) then return 360 end 543 | 544 | local unit_position = unit:position() 545 | local vector = self._camera_unit:position() - unit_position 546 | local forward = self._camera_unit:rotation():y() 547 | local rotation = math.floor( vector:to_polar_with_reference( forward , math.UP ).spin ) 548 | 549 | return -( rotation + 180 ) 550 | 551 | end 552 | elseif string.lower(RequiredScript) == "lib/states/ingamearrested" then 553 | Hooks:PostHook( IngameArrestedState , "at_enter" , "WolfHUDPostIngameArrestedAtEnter" , function( self ) 554 | if managers.hud then 555 | managers.hud:set_unit_health_visible( false, false ) 556 | end 557 | end ) 558 | end 559 | -------------------------------------------------------------------------------- /devlua/EnhancedObjective.lua: -------------------------------------------------------------------------------- 1 | if string.lower(RequiredScript) == "lib/managers/hud/hudobjectives" then 2 | 3 | HUDObjectives._TEXT_MARGIN = 8 4 | HUDObjectives._MAX_WIDTH = 300 5 | HUDObjectives._FONT_SIZE = tweak_data.hud.active_objective_title_font_size 6 | HUDObjectives._BOUNCE = 12 7 | 8 | local init_original = HUDObjectives.init 9 | local activate_objective_original = HUDObjectives.activate_objective 10 | local update_amount_objective_original = HUDObjectives.update_amount_objective 11 | local remind_objective_original = HUDObjectives.remind_objective 12 | local complete_objective_original = HUDObjectives.complete_objective 13 | 14 | function HUDObjectives:init(hud) 15 | if VHUDPlus:getSetting({"CustomHUD", "ENABLED_ENHANCED_OBJECTIVE"}, false) then 16 | 17 | if alive(self._hud_panel) then 18 | hud.panel:remove(self._hud_panel) 19 | end 20 | 21 | self._hud_panel = hud.panel:panel({ 22 | visible = false, 23 | name = "objectives_panel", 24 | h = 130, 25 | w = 400, 26 | x = 80, 27 | valign = "top" 28 | }) 29 | 30 | self._bg_box = HUDBGBox_create(self._hud_panel, { 31 | w = 400, 32 | h = 38, 33 | }) 34 | 35 | self._objective_text = self._bg_box:text({ 36 | name = "objective_text", 37 | visible = false, 38 | layer = 2, 39 | color = Color.white, 40 | text = "", 41 | font_size = HUDObjectives._FONT_SIZE, 42 | font = tweak_data.hud.medium_font_noshadow, 43 | align = "left", 44 | vertical = "center", 45 | w = self._bg_box:w(), 46 | x = HUDObjectives._TEXT_MARGIN, 47 | y = HUDObjectives._TEXT_MARGIN, 48 | wrap = false, 49 | word_wrap = false 50 | }) 51 | 52 | self._amount_text = self._bg_box:text({ 53 | name = "amount_text", 54 | visible = false, 55 | layer = 2, 56 | color = Color.white, 57 | text = "", 58 | font_size = HUDObjectives._FONT_SIZE, 59 | font = tweak_data.hud.medium_font_noshadow, 60 | align = "left", 61 | vertical = "center", 62 | w = self._bg_box:w(), 63 | h = HUDObjectives._FONT_SIZE, 64 | x = HUDObjectives._TEXT_MARGIN, 65 | y = HUDObjectives._TEXT_MARGIN 66 | }) 67 | else 68 | return init_original(self, hud) 69 | end 70 | end 71 | 72 | function HUDObjectives:activate_objective(data) 73 | if VHUDPlus:getSetting({"CustomHUD", "ENABLED_ENHANCED_OBJECTIVE"}, false) then 74 | 75 | self._active_objective_id = data.id 76 | self._hud_panel:set_visible(true) 77 | self._objective_text:set_visible(true) 78 | self._amount_text:set_visible(false) 79 | 80 | local width, height, wrapped_text = self:_get_wrapped_text_dimensions(utf8.to_upper(data.text)) 81 | 82 | self._objective_text:set_text(wrapped_text) 83 | self._objective_text:set_w(width) 84 | self._objective_text:set_h(height) 85 | self._bg_box:set_h(HUDObjectives._TEXT_MARGIN * 2 + height) 86 | 87 | if data.amount then 88 | self:update_amount_objective(data, true) 89 | else 90 | self._amount_text:set_text("") 91 | self._bg_box:set_w(HUDObjectives._TEXT_MARGIN * 2 + width) 92 | end 93 | if not self._active_move then 94 | self._bg_box:stop() 95 | self._bg_box:animate(callback(self, self, "_animate_update_objective")) 96 | end 97 | else 98 | return activate_objective_original(self, data) 99 | end 100 | end 101 | 102 | function HUDObjectives:update_amount_objective(data, hide_animation) 103 | 104 | if VHUDPlus:getSetting({"CustomHUD", "ENABLED_ENHANCED_OBJECTIVE"}, false) then 105 | 106 | if data.id ~= self._active_objective_id then 107 | return 108 | end 109 | local amount = (data.current_amount or 0) 110 | self._amount_text:set_text(amount .. "/" .. data.amount) 111 | self._amount_text:set_left(self._objective_text:right() + HUDObjectives._TEXT_MARGIN) 112 | self._amount_text:set_bottom(self._objective_text:h() + HUDObjectives._TEXT_MARGIN) 113 | self._bg_box:set_w(HUDObjectives._TEXT_MARGIN * 3 + self._objective_text:w() + self:_get_text_dimensions(self._amount_text:text()).w) 114 | self._amount_text:set_visible(true) 115 | self._amount_text:stop() 116 | if not hide_animation and amount > 0 then 117 | self._amount_text:animate(callback(self, self, "_animate_new_amount")) 118 | else 119 | self._amount_text:set_color(Color(1, 1, 1, 1)) 120 | end 121 | else 122 | return update_amount_objective_original(self, data, hide_animation) 123 | end 124 | end 125 | 126 | function HUDObjectives:remind_objective(id) 127 | 128 | if VHUDPlus:getSetting({"CustomHUD", "ENABLED_ENHANCED_OBJECTIVE"}, false) then 129 | 130 | if id ~= self._active_objective_id then 131 | return 132 | end 133 | if not self._active_move then 134 | self._bg_box:stop() 135 | self._bg_box:animate(callback(self, self, "_animate_update_objective")) 136 | end 137 | else 138 | return remind_objective_original(self, id) 139 | end 140 | end 141 | 142 | function HUDObjectives:complete_objective(data) 143 | 144 | if VHUDPlus:getSetting({"CustomHUD", "ENABLED_ENHANCED_OBJECTIVE"}, false) then 145 | 146 | if data.id ~= self._active_objective_id then 147 | return 148 | end 149 | 150 | self._active_objective_id = "" 151 | 152 | else 153 | return complete_objective_original(self, data) 154 | end 155 | end 156 | 157 | if VHUDPlus:getSetting({"CustomHUD", "ENABLED_ENHANCED_OBJECTIVE"}, false) then 158 | 159 | function HUDObjectives:_animate_new_amount(object) 160 | local TOTAL_T = 2 161 | local t = TOTAL_T 162 | object:set_color(Color(1, 1, 1, 1)) 163 | while t > 0 do 164 | local dt = coroutine.yield() 165 | t = t - dt 166 | object:set_color(Color(1, 1 , 1, 1 - (0.5 * math.sin(t * 360 * 2) + 0.5))) 167 | end 168 | object:set_color(Color(1, 1, 1, 1)) 169 | end 170 | 171 | function HUDObjectives:_animate_update_objective(object) 172 | local TOTAL_T = 2 173 | local t = TOTAL_T 174 | object:set_y(self._offset_y or 0) 175 | while t > 0 do 176 | local dt = coroutine.yield() 177 | t = t - dt 178 | object:set_y((self._offset_y or 0) + math.round((1 + math.sin((TOTAL_T - t) * 450 * 2)) * (HUDObjectives._BOUNCE * (t / TOTAL_T)))) 179 | end 180 | object:set_y(self._offset_y or 0) 181 | end 182 | 183 | function HUDObjectives:_get_text_dimensions(text_string) 184 | local string_width_measure_text_field = self._hud_panel:child("string_dimensions") or self._hud_panel:text({ 185 | name = "string_dimensions", 186 | visible = false, 187 | font_size = HUDObjectives._FONT_SIZE, 188 | font = tweak_data.hud.medium_font_noshadow, 189 | align = "left", 190 | vertical = "center", 191 | wrap = false 192 | }) 193 | string_width_measure_text_field:set_text(text_string) 194 | local x, y, w, h = string_width_measure_text_field:text_rect() 195 | return {x = x, y = y, w = w, h = h} 196 | end 197 | 198 | function HUDObjectives:_get_wrapped_text_dimensions(text_string) 199 | local layout_text_field = self._hud_panel:child("layout") or self._hud_panel:text({ 200 | name = "layout", 201 | width = self._MAX_WIDTH, 202 | visible = false, 203 | font_size = HUDObjectives._FONT_SIZE, 204 | font = tweak_data.hud.medium_font_noshadow, 205 | align = "left", 206 | vertical = "center", 207 | wrap = true, 208 | word_wrap = true 209 | }) 210 | layout_text_field:set_text(text_string) 211 | local line_breaks = table.collect(layout_text_field:line_breaks(), function(index) 212 | return index + 1 213 | end) 214 | local wrapped_lines = {} 215 | for line = 1, #line_breaks do 216 | local range_start = line_breaks[line] 217 | local range_end = line_breaks[line + 1] 218 | local string_range = utf8.sub(text_string, range_start, (range_end or 0) - 1) 219 | table.insert(wrapped_lines, string.trim(string_range)) 220 | end 221 | local wrapped_text = "" 222 | local w, h = 0, layout_text_field:font_size() * math.max(#wrapped_lines, 1) 223 | for _, line in ipairs(wrapped_lines) do 224 | w = math.max(w, self:_get_text_dimensions(line).w) 225 | wrapped_text = string.format("%s%s\n", wrapped_text, line) 226 | end 227 | return math.ceil(w), math.ceil(h), wrapped_text 228 | end 229 | 230 | function HUDObjectives:apply_offset(offset) 231 | return 232 | end 233 | 234 | function HUDObjectives:_animate_move(panel, x, y, instant) 235 | self._active_move = true 236 | if not instant then 237 | local move_speed = 150 238 | local init_x = panel:x() 239 | local init_y = panel:y() 240 | local x_change = x > init_x and 1 or x < init_x and -1 241 | local y_change = y > init_y and 1 or y < init_y and -1 242 | local T = math.max(math.abs(x - init_x) / move_speed, math.abs(y - init_y) / move_speed) 243 | local t = 0 244 | 245 | while alive(panel) and t < T do 246 | if x_change then 247 | panel:set_x(init_x + t * x_change * move_speed) 248 | end 249 | if y_change then 250 | panel:set_y(init_y + t * y_change * move_speed) 251 | end 252 | t = t + coroutine.yield() 253 | end 254 | end 255 | 256 | if alive(panel) then 257 | panel:set_x(x) 258 | panel:set_y(y) 259 | end 260 | self._active_move = nil 261 | end 262 | end 263 | 264 | elseif string.lower(RequiredScript) == "lib/managers/hud/hudheisttimer" then 265 | local init_original_time = HUDHeistTimer.init 266 | function HUDHeistTimer:init(hud, tweak_hud) 267 | init_original_time(self, hud, tweak_hud) 268 | if VHUDPlus:getSetting({"CustomHUD", "ENABLED_ENHANCED_OBJECTIVE"}, false) then 269 | self._hud_panel = hud.panel 270 | self._enabled = not (tweak_hud and tweak_hud.no_timer) 271 | if self._hud_panel:child("heist_timer_panel") then 272 | self._hud_panel:remove(self._hud_panel:child("heist_timer_panel")) 273 | end 274 | 275 | self._heist_timer_panel = self._hud_panel:panel({ 276 | visible = self._enabled, 277 | name = "heist_timer_panel", 278 | h = 40, 279 | w = 80, 280 | valign = "top", 281 | layer = 0 282 | }) 283 | self._timer_text = self._heist_timer_panel:text({ 284 | name = "timer_text", 285 | text = "00:00:00", 286 | font_size = tweak_data.hud.medium_deafult_font_size, 287 | font = tweak_data.hud.medium_font_noshadow, 288 | color = Color.white, 289 | align = "center", 290 | vertical = "center", 291 | layer = 1, 292 | wrap = false, 293 | word_wrap = false 294 | }) 295 | 296 | self._last_time = 0 297 | end 298 | end 299 | 300 | elseif string.lower(RequiredScript) == "core/lib/managers/subtitle/coresubtitlepresenter" then 301 | core:module("CoreSubtitlePresenter") 302 | function OverlayPresenter:show_text(text, duration) 303 | self.__font_name = "fonts/font_medium_mf" 304 | self._text_scale = _G.VHUDPlus:getSetting({"MISCHUD", "SCALE"}, 1) 305 | local text_shadow = _G.VHUDPlus:getSetting({"MISCHUD", "SUB"}, true) 306 | local label = self.__subtitle_panel:child("label") or self.__subtitle_panel:text({ 307 | name = "label", 308 | font = self.__font_name, 309 | font_size = self.__font_size * self._text_scale, 310 | color = Color.white, 311 | align = "center", 312 | vertical = "bottom", 313 | layer = 1, 314 | wrap = true, 315 | word_wrap = true 316 | }) 317 | local shadow = self.__subtitle_panel:child("shadow") or self.__subtitle_panel:text({ 318 | name = "shadow", 319 | x = 1, 320 | y = 1, 321 | font = self.__font_name, 322 | font_size = self.__font_size * self._text_scale, 323 | color = Color.black:with_alpha(1), 324 | align = "center", 325 | vertical = "bottom", 326 | layer = 0, 327 | wrap = true, 328 | word_wrap = true 329 | }) 330 | label:set_text(text) 331 | shadow:set_text(text) 332 | label:set_font_size(self.__font_size * self._text_scale) 333 | shadow:set_font_size(self.__font_size * self._text_scale) 334 | shadow:set_visible(text_shadow) 335 | end 336 | 337 | local _on_resolution_changed_original = OverlayPresenter._on_resolution_changed 338 | function OverlayPresenter:_on_resolution_changed(...) 339 | _on_resolution_changed_original(self, ...) 340 | self:apply_bottom_offset() 341 | end 342 | 343 | function OverlayPresenter:set_bottom(offset) 344 | if self._bottom_off ~= offset then 345 | self._bottom_off = offset 346 | self:apply_bottom_offset() 347 | end 348 | end 349 | 350 | function OverlayPresenter:apply_bottom_offset() 351 | if self.__subtitle_panel then 352 | self.__subtitle_panel:set_height(_G.VHUDPlus:getSetting({"MISCHUD", "SUB_HEIGHT"}, 600)) 353 | local label = self.__subtitle_panel:child("label") 354 | if label then 355 | label:set_h(self.__subtitle_panel:h()) 356 | label:set_w(self.__subtitle_panel:w()) 357 | end 358 | local shadow = self.__subtitle_panel:child("shadow") 359 | if shadow then 360 | shadow:set_h(self.__subtitle_panel:h()) 361 | shadow:set_w(self.__subtitle_panel:w()) 362 | end 363 | end 364 | end 365 | end 366 | -------------------------------------------------------------------------------- /devlua/EquipmentTweaks.lua: -------------------------------------------------------------------------------- 1 | if string.lower(RequiredScript) == "lib/units/weapons/sentrygunweapon" then 2 | local old_setup = SentryGunWeapon.init 3 | local old_destroy = SentryGunWeapon.destroy 4 | 5 | function SentryGunWeapon:init(...) 6 | old_setup(self, ...) 7 | if tweak_data.blackmarket.deployables[self._unit:base():get_type()] then 8 | managers.enemy:add_delayed_clbk("Sentry_post_init_" .. tostring(self._unit:key()), callback(self, self, "post_init"), Application:time() + 0.1) 9 | end 10 | end 11 | 12 | function SentryGunWeapon:post_init() 13 | local enable_ap = false 14 | local laser_theme = "team_sentry" 15 | if self._unit:base():is_owner() then 16 | laser_theme = "player_sentry" 17 | enable_ap = managers.player:has_category_upgrade("sentry_gun", "ap_bullets") 18 | end 19 | self._laser_align = self._unit:get_object(Idstring("fire")) 20 | self:set_laser_enabled(laser_theme) 21 | 22 | if VHUDPlus:getSetting({"EQUIPMENT", "SENTRY_AUTO_AP"}, true) and enable_ap then 23 | if alive(self._fire_mode_unit) and alive(self._unit) then 24 | local firemode_interaction = self._fire_mode_unit:interaction() 25 | if firemode_interaction and firemode_interaction:can_interact(managers.player:player_unit()) then 26 | self:_set_fire_mode(true) 27 | self._unit:network():send("sentrygun_sync_armor_piercing", self._use_armor_piercing) 28 | self._unit:event_listener():call("on_switch_fire_mode", self._use_armor_piercing) 29 | end 30 | end 31 | end 32 | end 33 | 34 | function SentryGunWeapon:destroy(...) 35 | managers.enemy:remove_delayed_clbk("Sentry_post_init_" .. tostring(self._unit:key())) 36 | old_destroy(self, ...) 37 | end 38 | elseif string.lower(RequiredScript) == "lib/units/equipment/ecm_jammer/ecmjammerbase" then 39 | local setup_original = ECMJammerBase.setup 40 | local contour_interaction_original = ECMJammerBase.contour_interaction 41 | local destroy_original = ECMJammerBase.destroy 42 | function ECMJammerBase:setup(...) 43 | setup_original(self, ...) 44 | if VHUDPlus:getSetting({"EQUIPMENT", "ECM_FEEDBACK_STEALTH_DISABLED"}, true) and managers.groupai:state():whisper_mode() then 45 | local owner_unit = self:owner() 46 | local player_unit = managers.player:player_unit() 47 | if alive(owner_unit) and alive(player_unit) and owner_unit:key() == player_unit:key() then 48 | managers.gameinfo:register_listener("ECMContour_whisper_mode_listener" .. tostring(self._unit:key()), "whisper_mode", "change", callback(self, self, "_whisper_mode_change")) 49 | end 50 | end 51 | end 52 | 53 | function ECMJammerBase:contour_interaction(...) 54 | if not (managers.groupai:state():whisper_mode() and VHUDPlus:getSetting({"EQUIPMENT", "ECM_FEEDBACK_STEALTH_DISABLED"}, true)) then 55 | contour_interaction_original(self, ...) 56 | end 57 | end 58 | 59 | function ECMJammerBase:destroy(...) 60 | managers.gameinfo:unregister_listener("ECMContour_whisper_mode_listener" .. tostring(self._unit:key()), "whisper_mode", "change") 61 | destroy_original(self, ...) 62 | end 63 | 64 | function ECMJammerBase:_whisper_mode_change(event, key, status) 65 | if not status then 66 | contour_interaction_original(self) 67 | end 68 | end 69 | elseif string.lower(RequiredScript) == "lib/units/interactions/interactionext" then 70 | BaseInteractionExt.SHAPED_CHARGE_TIMEOUT = VHUDPlus:getTweakEntry("STEALTH_SHAPED_CHARGE_TIMEOUT", "number", 0.25) --Timeout for 2 InteractKey pushes, to prevent accidents in stealth 71 | BaseInteractionExt.KEYCARD_DOORS_TIMEOUT = VHUDPlus:getTweakEntry("KEYCARD_DOORS_TIMEOUT", "number", 0.25) --Timeout for 2 InteractKey pushes, to prevent accidents in hoxton breakout day 2 72 | 73 | local BaseInteraction_interact_start_original = BaseInteractionExt.interact_start 74 | local ECMJammerInteaction_can_interact_original = ECMJammerInteractionExt.can_interact 75 | local ECMJammerInteraction_can_select_original = ECMJammerInteractionExt.can_select 76 | 77 | function BaseInteractionExt:interact_start(player, data, ...) 78 | local t = Application:time() 79 | if VHUDPlus:getSetting({"EQUIPMENT", "SHAPED_CHARGE_STEALTH_DISABLED"}, true) and managers.groupai:state():whisper_mode() 80 | and self._tweak_data.required_deployable and self._tweak_data.required_deployable == "trip_mine" 81 | and (t - (self._last_shaped_charge_t or 0) >= BaseInteractionExt.SHAPED_CHARGE_TIMEOUT) then 82 | self._last_shaped_charge_t = t 83 | return false 84 | end 85 | if VHUDPlus:getSetting({"EQUIPMENT", "KEYCARD_DOORS_DISABLED"}, true) 86 | and self.tweak_data and self.tweak_data == "hold_close_keycard" 87 | and (t - (self._last_hold_close_keycard_t or 0) >= BaseInteractionExt.KEYCARD_DOORS_TIMEOUT) then 88 | self._last_hold_close_keycard_t = t 89 | return false 90 | end 91 | return BaseInteraction_interact_start_original(self, player, data, ...) 92 | end 93 | 94 | function ECMJammerInteractionExt:can_interact(...) 95 | if VHUDPlus:getSetting({"EQUIPMENT", "ECM_FEEDBACK_STEALTH_DISABLED"}, true) and managers.groupai:state():whisper_mode() then 96 | return false 97 | end 98 | return ECMJammerInteaction_can_interact_original(self, ...) 99 | end 100 | 101 | function ECMJammerInteractionExt:can_select(...) 102 | if VHUDPlus:getSetting({"EQUIPMENT", "ECM_FEEDBACK_STEALTH_DISABLED"}, true) and managers.groupai:state():whisper_mode() then 103 | return false 104 | end 105 | return ECMJammerInteraction_can_select_original(self, ...) 106 | end 107 | end -------------------------------------------------------------------------------- /devlua/ForceReady.lua: -------------------------------------------------------------------------------- 1 | -- if string.lower(RequiredScript) == "lib/managers/hudmanagerpd2" then 2 | 3 | -- -- Host-controlled force start 4 | -- -- Need to click the "Ready" button in lobby multiple times for a menu to appear 5 | -- local FORCE_READY_CLICKS = 3 6 | -- local FORCE_READY_TIME = 2 7 | -- local FORCE_READY_ACTIVE_T = 90 8 | 9 | -- local force_ready_start_t = 0 10 | -- local force_ready_clicked = 0 11 | 12 | -- local set_slot_ready_orig = HUDManager.set_slot_ready 13 | -- function HUDManager:set_slot_ready(peer, peer_id, ...) 14 | -- set_slot_ready_orig(self, peer, peer_id, ...) 15 | 16 | -- if Network:is_server() and not Global.game_settings.single_player then 17 | -- local session = managers.network and managers.network:session() 18 | -- local local_peer = session and session:local_peer() 19 | -- local time_elapsed = managers.game_play_central and managers.game_play_central:get_heist_timer() or 0 20 | -- if local_peer and local_peer:id() == peer_id then 21 | -- local t = Application:time() 22 | -- if (force_ready_start_t + FORCE_READY_TIME) > t then 23 | -- force_ready_clicked = force_ready_clicked + 1 24 | -- if force_ready_clicked >= FORCE_READY_CLICKS then 25 | -- local enough_wait_time = (time_elapsed > FORCE_READY_ACTIVE_T) 26 | -- local friends_list = not enough_wait_time and Steam:logged_on() and Steam:friends() or {} 27 | -- local abort = false 28 | -- for _, peer in ipairs(session:peers()) do 29 | -- local is_friend = false 30 | -- for _, friend in ipairs(friends_list) do 31 | -- if friend:id() == peer:user_id() then 32 | -- is_friend = true 33 | -- break 34 | -- end 35 | -- end 36 | -- if not (enough_wait_time or is_friend) or not (peer:synced() or peer:id() == local_peer:id()) then 37 | -- abort = true 38 | -- break 39 | -- end 40 | -- end 41 | 42 | -- if game_state_machine and not abort then 43 | -- local menu_options = { 44 | -- [1] = { 45 | -- text = managers.localization:text("dialog_yes"), 46 | -- callback = function(self, item) 47 | -- local gsm = game_state_machine 48 | -- local gsm_state = gsm and gsm:current_state() 49 | -- -- Fix crash where Force Start menu remains open 50 | -- -- into the loading screen (between lobby and in-game state) 51 | -- -- @TODO: Automatically close the menu when the game starts? 52 | -- if gsm_state and gsm_state.start_game_intro then 53 | -- managers.chat:send_message(ChatManager.GAME, local_peer, 54 | -- managers.localization:text("wolfhud_dialog_force_start_msg")) 55 | 56 | -- gsm_state:start_game_intro() 57 | -- else 58 | -- -- 'ingame_mask_off' state is the black loading screen 59 | -- log(string.format("VHUDPlus: Cannot force start in current game state '%s' (%s)", 60 | -- gsm.current_state_name and gsm:current_state_name() or "", 61 | -- tostring(gsm_state) 62 | -- )) 63 | -- end 64 | -- end, 65 | -- }, 66 | -- [2] = { 67 | -- text = managers.localization:text("dialog_no"), 68 | -- is_cancel_button = true, 69 | -- } 70 | -- } 71 | -- QuickMenu:new( managers.localization:text("wolfhud_dialog_force_start_title"), managers.localization:text("wolfhud_dialog_force_start_desc"), menu_options, true ) 72 | -- end 73 | -- end 74 | -- else 75 | -- force_ready_clicked = 1 76 | -- force_ready_start_t = t 77 | -- end 78 | -- end 79 | -- end 80 | -- end 81 | 82 | -- end 83 | -------------------------------------------------------------------------------- /devlua/KillCounter.lua: -------------------------------------------------------------------------------- 1 | if _G.IS_VR then 2 | return 3 | end 4 | if VHUDPlus:getSetting({"CustomHUD", "HUDTYPE"}, 2) == 2 or VHUDPlus:getSetting({"CustomHUD", "HUDTYPE"}, 2) == 3 or VHUDPlus:getSetting({"CustomHUD", "HUDTYPE"}, 2) == 4 then 5 | 6 | if RequiredScript == "lib/units/enemies/cop/copdamage" and not VHUDPlus.kill_fix then 7 | VHUDPlus.kill_fix = true 8 | 9 | local _update_debug_ws_original = CopDamage._update_debug_ws 10 | --Workaround for Teammate Headshots, since col_ray doesn't get forwarded... (self._sync_ibody_killcount) 11 | local sync_damage_bullet_original = CopDamage.sync_damage_bullet 12 | local sync_damage_melee_original = CopDamage.sync_damage_melee 13 | 14 | function CopDamage:_update_debug_ws(data, ...) 15 | _update_debug_ws_original(self, data, ...) 16 | if self._dead then 17 | self:_process_kill(data) 18 | end 19 | 20 | self._sync_ibody_killcount = nil 21 | end 22 | 23 | function CopDamage:_process_kill(data) 24 | local killer 25 | 26 | local attacker = data and alive(data.attacker_unit) and data.attacker_unit 27 | 28 | if attacker then 29 | if attacker:in_slot(3) or attacker:in_slot(5) then 30 | --Human team mate 31 | killer = attacker 32 | elseif attacker:in_slot(2) then 33 | --Player 34 | killer = attacker 35 | elseif attacker:in_slot(16) then 36 | --Bot/joker 37 | killer = attacker 38 | elseif attacker:in_slot(12) then 39 | --Enemy 40 | elseif attacker:in_slot(25) then 41 | --Turret 42 | local owner = attacker:base():get_owner_id() 43 | if owner then 44 | killer = managers.criminals:character_unit_by_peer_id(owner) 45 | end 46 | elseif attacker:base().thrower_unit then 47 | killer = attacker:base():thrower_unit() 48 | end 49 | 50 | if alive(killer) and alive(self._unit) then 51 | local tweak_id = self._unit:base()._tweak_table 52 | local special_unit_ids = managers.statistics and managers.statistics.special_unit_ids or {} 53 | local is_special = managers.groupai:state():is_enemy_special(self._unit) or table.contains(special_unit_ids, tweak_id) 54 | local body = data.col_ray and data.col_ray.body or self._sync_ibody_killcount and self._unit:body(self._sync_ibody_killcount) 55 | local headshot = body and self.is_head and self:is_head(body) or false 56 | 57 | if killer:in_slot(2) then 58 | managers.hud:increment_teammate_kill_count(HUDManager.PLAYER_PANEL, is_special, headshot) 59 | 60 | local current_player_state = managers.player and managers.player:get_current_state() 61 | local weapon_base = current_player_state and current_player_state._equipped_unit:base() 62 | local projectile_name = "bullet" 63 | if weapon_base._projectile_type_index then 64 | projectile_name = tweak_data and tweak_data:get_raw_value("blackmarket", "projectiles", "_projectiles_index", weapon_base._projectile_type_index) 65 | end 66 | if projectile_name == (data.variant or "") then 67 | local weapon_id = weapon_base:get_name_id() 68 | local weapon_tweak = weapon_base and weapon_base:weapon_tweak_data() 69 | local weapon_type = weapon_tweak.category 70 | local slot = weapon_tweak and weapon_tweak.use_data and weapon_tweak.use_data.selection_index 71 | managers.hud:increment_teammate_kill_count_detailed(HUDManager.PLAYER_PANEL, self._unit, weapon_id, weapon_type, slot) 72 | end 73 | else 74 | local crim_data = managers.criminals:character_data_by_unit(killer) 75 | if crim_data and crim_data.panel_id then 76 | managers.hud:increment_teammate_kill_count(crim_data.panel_id, is_special, headshot) 77 | end 78 | end 79 | end 80 | end 81 | end 82 | 83 | function CopDamage:sync_damage_bullet(attacker_unit, damage_percent, i_body, ...) 84 | if i_body then 85 | self._sync_ibody_killcount = i_body 86 | end 87 | 88 | return sync_damage_bullet_original(self, attacker_unit, damage_percent, i_body, ...) 89 | end 90 | 91 | function CopDamage:sync_damage_melee(attacker_unit, damage_percent, damage_effect_percent, i_body, ...) 92 | if i_body then 93 | self._sync_ibody_killcount = i_body 94 | end 95 | 96 | return sync_damage_melee_original(self, attacker_unit, damage_percent, damage_effect_percent, i_body, ...) 97 | 98 | end 99 | 100 | --TODO: Add sync damage checks for non-local bots and players 101 | 102 | elseif RequiredScript == "lib/units/equipment/sentry_gun/sentrygunbase" then 103 | 104 | local sync_setup_original = SentryGunBase.sync_setup 105 | 106 | function SentryGunBase:sync_setup(upgrade_lvl, peer_id, ...) 107 | sync_setup_original(self, upgrade_lvl, peer_id, ...) 108 | self._owner_id = self._owner_id or peer_id 109 | end 110 | 111 | elseif RequiredScript == "lib/managers/statisticsmanager" then 112 | 113 | local shot_fired_original = StatisticsManager.shot_fired 114 | 115 | function StatisticsManager:shot_fired(data, ...) 116 | shot_fired_original(self, data, ...) 117 | 118 | --[[ 119 | This does not work well for HE rounds. It would be almost correct if you halved number of shots, 120 | but would not take into account shots that goes into the void or compensate for direct hits 121 | ]] 122 | 123 | local name_id = data.name_id or data.weapon_unit:base():get_name_id() 124 | local weapon_tweak = tweak_data.weapon[name_id] 125 | local slot = weapon_tweak and weapon_tweak.use_data and weapon_tweak.use_data.selection_index 126 | if slot then --Exclude throwables like exploding cards mod... 127 | local weapon_data = name_id and self._global.session.shots_by_weapon[name_id] 128 | local weapon_accuracy = 0 129 | if weapon_data and weapon_data.total > 0 then 130 | weapon_accuracy = math.floor(100 * weapon_data.hits / weapon_data.total) 131 | end 132 | managers.hud:set_teammate_weapon_accuracy(HUDManager.PLAYER_PANEL, slot, weapon_accuracy) 133 | end 134 | 135 | managers.hud:set_teammate_accuracy(HUDManager.PLAYER_PANEL, self:session_hit_accuracy()) 136 | end 137 | 138 | elseif RequiredScript == "lib/managers/hudmanagerpd2" then 139 | 140 | HUDManager.KILL_COUNTER_PLUGIN = true 141 | HUDManager.ACCURACY_PLUGIN = true 142 | 143 | HUDManager.increment_teammate_kill_count = HUDManager.increment_teammate_kill_count or function (self, i, is_special, headshot) 144 | self._teammate_panels[i]:increment_kill_count(is_special, headshot) 145 | end 146 | 147 | HUDManager.reset_teammate_kill_count = HUDManager.reset_teammate_kill_count or function(self, i) 148 | self._teammate_panels[i]:reset_kill_count() 149 | end 150 | 151 | HUDManager.increment_teammate_kill_count_detailed = HUDManager.increment_teammate_kill_count_detailed or function(self, i, unit, weapon_id, weapon_type, weapon_slot) 152 | --TODO: Add call for default HUD | No need for that, really... 153 | end 154 | 155 | HUDManager.set_teammate_accuracy = HUDManager.set_teammate_accuracy or function(self, i, value) 156 | self._teammate_panels[i]:set_accuracy(value) 157 | end 158 | 159 | HUDManager.set_teammate_weapon_accuracy = HUDManager.set_teammate_weapon_accuracy or function(self, i, slot, value) 160 | --TODO 161 | end 162 | 163 | function HUDManager:teampanels_height() 164 | return (VHUDPlus:getSetting({"CustomHUD", "PLAYER", "SHOW_ACCURACY"}, true) and not VHUDPlus:getSetting({"CustomHUD", "PLAYER", "KILLCOUNTER", "HIDE"}, false)) and 140 or 120 165 | end 166 | 167 | elseif string.lower(RequiredScript) == "lib/managers/hud/hudteammate" then 168 | 169 | if not HUDManager.CUSTOM_TEAMMATE_PANELS then --Custom HUD compatibility 170 | local init_original = HUDTeammate.init 171 | local set_name_original = HUDTeammate.set_name 172 | local set_state_original = HUDTeammate.set_state 173 | 174 | function HUDTeammate:init(...) 175 | init_original(self, ...) 176 | self._setting_prefix = self._main_player and "PLAYER" or "TEAMMATE" 177 | self:_init_killcount() 178 | self:init_accuracy() 179 | end 180 | 181 | function HUDTeammate:_init_killcount() 182 | self._kills_panel = self._panel:panel({ 183 | name = "kills_panel", 184 | visible = not VHUDPlus:getSetting({"CustomHUD", self._setting_prefix, "KILLCOUNTER", "HIDE"}, false), 185 | w = 150, 186 | h = 20, 187 | x = 0, 188 | halign = "right" 189 | }) 190 | 191 | local player_panel = self._panel:child("player") 192 | local name_label = self._panel:child("name") 193 | self._kills_panel:set_rightbottom(player_panel:right(), (self._main_player or VHUDPlus:getSetting({"CustomHUD", "TEAMMATE", "INTERACTION", "TEXT"}, true)) and name_label:bottom() or name_label:top()) 194 | local killcount_color = VHUDPlus:getColorSetting({"CustomHUD", self._setting_prefix, "KILLCOUNTER", "COLOR"}, "yellow") 195 | 196 | self._kill_icon = self._kills_panel:bitmap({ 197 | texture = "guis/textures/pd2/cn_miniskull", 198 | w = self._kills_panel:h() * 0.75, 199 | h = self._kills_panel:h(), 200 | texture_rect = { 0, 0, 12, 16 }, 201 | alpha = 1, 202 | blend_mode = "normal", 203 | layer = 0, 204 | color = killcount_color 205 | }) 206 | 207 | self._kills_text = self._kills_panel:text({ 208 | name = "kills_text", 209 | text = "-", 210 | layer = 1, 211 | color = killcount_color, 212 | w = self._kills_panel:w() - self._kill_icon:w(), 213 | h = self._kills_panel:h(), 214 | vertical = "center", 215 | align = "right", 216 | font_size = self._kills_panel:h(), 217 | font = tweak_data.hud_players.name_font 218 | }) 219 | self._kills_text:set_right(self._kills_panel:w()) 220 | 221 | self:reset_kill_count() 222 | end 223 | 224 | function HUDTeammate:init_accuracy() 225 | if not self._main_player then return end 226 | self._accuracy_panel = self._panel:panel({ 227 | name = "accuracy_panel", 228 | visible = VHUDPlus:getSetting({"CustomHUD", "PLAYER", "SHOW_ACCURACY"}, true), 229 | w = 100, 230 | h = 20, 231 | x = 0, 232 | halign = "right" 233 | }) 234 | 235 | local player_panel = self._panel:child("player") 236 | local name_label = self._panel:child("name") 237 | self._accuracy_panel:set_rightbottom(player_panel:right(), self._kills_panel and self._kills_panel:visible() and self._kills_panel:top() or name_label:bottom()) 238 | 239 | self._accuracy_icon = self._accuracy_panel:bitmap({ 240 | texture = "guis/textures/pd2/pd2_waypoints", 241 | w = self._accuracy_panel:h() * 0.75, 242 | h = self._accuracy_panel:h(), 243 | texture_rect = { 96, 0, 32, 32 }, 244 | alpha = 1, 245 | blend_mode = "normal", 246 | layer = 0, 247 | color = Color.white 248 | }) 249 | 250 | self._accuracy_text = self._accuracy_panel:text({ 251 | name = "accuracy_text", 252 | text = "0%", 253 | layer = 1, 254 | color = Color.white, 255 | w = self._accuracy_panel:w(), 256 | h = self._accuracy_panel:h(), 257 | vertical = "center", 258 | align = "right", 259 | font_size = self._accuracy_panel:h(), 260 | font = tweak_data.hud_players.name_font 261 | }) 262 | self:set_accuracy(0) 263 | end 264 | 265 | function HUDTeammate:increment_kill_count(is_special, headshot) 266 | self._kill_count = self._kill_count + 1 267 | self._kill_count_special = self._kill_count_special + (is_special and 1 or 0) 268 | self._headshot_kills = self._headshot_kills + (headshot and 1 or 0) 269 | self:_update_kill_count_text() 270 | end 271 | 272 | function HUDTeammate:_update_kill_count_text() 273 | local kill_string = tostring(self._kill_count) 274 | if VHUDPlus:getSetting({"CustomHUD", self._setting_prefix, "KILLCOUNTER", "SHOW_SPECIAL_KILLS"}, true) then 275 | kill_string = kill_string .. "/" .. tostring(self._kill_count_special) 276 | end 277 | if VHUDPlus:getSetting({"CustomHUD", self._setting_prefix, "KILLCOUNTER", "SHOW_HEADSHOT_KILLS"}, true) then 278 | kill_string = kill_string .. " (" .. tostring(self._headshot_kills) .. ")" 279 | end 280 | self._kills_text:set_text(kill_string) 281 | local _, _, w, _ = self._kills_text:text_rect() 282 | self._kill_icon:set_right(self._kills_panel:w() - w - self._kill_icon:w() * 0.15) 283 | 284 | if (self._main_player or VHUDPlus:getSetting({"CustomHUD", "TEAMMATE", "INTERACTION", "TEXT"}, true)) and not VHUDPlus:getSetting({"CustomHUD", self._setting_prefix, "KILLCOUNTER", "HIDE"}, false) then 285 | self._max_name_panel_width = (self._kills_panel:x() + self._kill_icon:x() - 4) 286 | self:_truncate_name() 287 | end 288 | 289 | local color = VHUDPlus:getColorSetting({"CustomHUD", self._setting_prefix, "KILLCOUNTER", "COLOR"}, "yellow") 290 | self._kill_icon:set_color(color) 291 | self._kills_text:set_color(color) 292 | end 293 | 294 | function HUDTeammate:reset_kill_count() 295 | self._kill_count = 0 296 | self._kill_count_special = 0 297 | self._headshot_kills = 0 298 | self:_update_kill_count_text() 299 | end 300 | 301 | function HUDTeammate:set_name(teammate_name, ...) 302 | if teammate_name ~= self._name then 303 | self._name = teammate_name 304 | self:reset_kill_count() 305 | end 306 | 307 | return set_name_original(self, teammate_name, ...) 308 | end 309 | 310 | function HUDTeammate:set_state(...) 311 | set_state_original(self, ...) 312 | 313 | local visible = not VHUDPlus:getSetting({"CustomHUD", self._setting_prefix, "KILLCOUNTER", "HIDE"}, false) and (not self._ai or VHUDPlus:getSetting({"CustomHUD", "TEAMMATE", "KILLCOUNTER", "SHOW_BOT_KILLS"}, true)) 314 | self._kills_panel:set_visible(visible) 315 | 316 | if self._ai then 317 | self._kills_panel:set_bottom(self._panel:child("player"):bottom()) 318 | else 319 | local name_label = self._panel:child("name") 320 | self._kills_panel:set_bottom((self._main_player or VHUDPlus:getSetting({"CustomHUD", "TEAMMATE", "INTERACTION", "TEXT"}, true)) and name_label:bottom() or name_label:top()) 321 | end 322 | end 323 | 324 | function HUDTeammate:set_accuracy(value) 325 | if self._accuracy_text then 326 | self._accuracy_text:set_text(tostring(value) .. "%") 327 | local _, _, w, _ = self._accuracy_text:text_rect() 328 | self._accuracy_icon:set_right(self._accuracy_panel:w() - w - self._accuracy_icon:w() * 0.15) 329 | if VHUDPlus:getSetting({"CustomHUD", "PLAYER", "KILLCOUNTER", "HIDE"}, false) and VHUDPlus:getSetting({"CustomHUD", "PLAYER", "SHOW_ACCURACY"}, true) then 330 | self._max_name_panel_width = (self._accuracy_panel:x() + self._accuracy_icon:x() - 4) 331 | self:_truncate_name() 332 | end 333 | end 334 | end 335 | 336 | HUDTeammate._truncate_name = HUDTeammate._truncate_name or function() end 337 | end 338 | end 339 | end 340 | 341 | -------------------------------------------------------------------------------- /devlua/NetworkHandler.lua: -------------------------------------------------------------------------------- 1 | local sync_contour_state_original = UnitNetworkHandler.sync_contour_state 2 | 3 | function UnitNetworkHandler:sync_contour_state(unit, u_id, type, state, multiplier, sender, ...) 4 | if not self._verify_gamestate(self._gamestate_filter.any_ingame) or not self._verify_sender(sender) then 5 | return 6 | end 7 | if (type == 7 or type == 11) and alive(unit) and unit:id() ~= -1 and (state and unit:slot() == 12 or unit:slot() == 16) and (managers.job:current_level_id() ~= "spa" or Network:is_server()) then 8 | return 9 | else 10 | return sync_contour_state_original(self, unit, u_id, type, state, multiplier, sender, ...) 11 | end 12 | end 13 | 14 | function UnitNetworkHandler:set_weapon_gadget_color(unit, red, green, blue, sender) 15 | if not self._verify_character_and_sender(unit, sender) then 16 | return 17 | end 18 | 19 | if red and green and blue then 20 | local threshold = 0.66 21 | if red * threshold > green + blue then 22 | red = 1 23 | green = 51 24 | blue = 1 25 | end 26 | end 27 | unit:inventory():sync_weapon_gadget_color(Color(red / 255, green / 255, blue / 255)) 28 | end 29 | 30 | --[[ 31 | do return end -- Disabled cause: WiP 32 | VHUDPlus.Sync = VHUDPlus.Sync or {} 33 | VHUDPlus.Sync.peers = VHUDPlus.Sync.peers or {false, false, false, false} 34 | VHUDPlus.Sync.cache = VHUDPlus.Sync.cache or {} 35 | 36 | local Net = _G.LuaNetworking 37 | 38 | function VHUDPlus.Sync.table_to_string(tbl) 39 | return Net:TableToString(tbl) or "" 40 | end 41 | 42 | function VHUDPlus.Sync.string_to_table(str) 43 | return Net:StringToTable(str) or "" 44 | end 45 | 46 | -- Functions to send stuff 47 | function VHUDPlus.Sync.send(id, data) 48 | if VHUDPlus.Sync.peers and data then 49 | managers.chat:feed_system_message(ChatManager.GAME, string.format("[%s] Syncing event %s.", id, data.event or "N/A")) --TEST 50 | local exclusion = {} 51 | local send_data = VHUDPlus.Sync.table_to_string(data) 52 | for peer_id, enabled in pairs(VHUDPlus.Sync.peers) do 53 | if not enabled then 54 | table.insert(exclusion, peer_id) 55 | end 56 | end 57 | Net:SendToPeersExcept(exclusion, id, send_data) 58 | end 59 | if id == "WolfHUD_Sync_Cache" then 60 | VHUDPlus.Sync.receive_cache_event(data) 61 | end 62 | end 63 | 64 | function VHUDPlus.Sync.gameinfo_ecm_feedback_event_sender(event, key, data) 65 | if VHUDPlus.Sync then 66 | local send_data = { 67 | source = "ecm", 68 | event = event, 69 | key = key, 70 | feedback_duration = data.feedback_duration, 71 | feedback_expire_t = data.feedback_expire_t 72 | } 73 | VHUDPlus.Sync.send("WolfHUD_Sync_GameInfo_ecm_feedback", send_data) 74 | end 75 | end 76 | 77 | --receive and apply data 78 | function VHUDPlus.Sync.receive_gameinfo_ecm_feedback_event(event_data) 79 | local source = data.source 80 | local event = event_data.event 81 | local key = event_data.key 82 | local data = { feedback_duration = event_data.feedback_duration, feedback_expire_t = data.feedback_expire_t } 83 | managers.chat:feed_system_message(ChatManager.GAME, string.format("[WolfHUD_GameInfo] Received data, source: %s, event: %s.", source or "N/A", event or "N/A")) --TEST 84 | if managers.gameinfo and source and key and data then 85 | managers.gameinfo:event(source, event, key, data) 86 | end 87 | end 88 | 89 | function VHUDPlus.Sync.receive_cache_event(event_data) 90 | local event = event_data.event 91 | local data = event_data.data 92 | managers.chat:feed_system_message(ChatManager.GAME, string.format("[WolfHUD_Cache] Received data, event: %s.", event or "N/A")) --TEST 93 | if VHUDPlus.Sync.cache and event and data then 94 | VHUDPlus.Sync.cache[event] = data 95 | end 96 | end 97 | 98 | function VHUDPlus.Sync.receive(event_data) 99 | local event = event_data.event 100 | local data = event_data.data 101 | managers.chat:feed_system_message(ChatManager.GAME, string.format("[VHUDPlus] Received data, event: %s.", event or "N/A")) --TEST 102 | if event == "assault_lock_state" then 103 | if managers.hud and managers.hud._locked_assault and event and data then 104 | managers.hud:_locked_assault(data) 105 | end 106 | end 107 | end 108 | 109 | function VHUDPlus.Sync:getCache(id) 110 | if self.cache[id] then 111 | return self.cache[id] 112 | else 113 | return self.cache 114 | end 115 | end 116 | 117 | -- Manage Networking and list of peers to sync to... 118 | Hooks:Add("NetworkReceivedData", "NetworkReceivedData_WolfHUD", function(sender, messageType, data) 119 | if VHUDPlus.Sync then 120 | if peer then 121 | if messageType == "Using_WolfHUD?" then 122 | Net:SendToPeer(sender, "Using_WolfHUD!", "") 123 | VHUDPlus.Sync.peers[sender] = true --Sync to peer, IDs of other peers using VHUDPlus? 124 | managers.chat:feed_system_message(ChatManager.GAME, "Host is using VHUDPlus ;)") --TEST 125 | elseif messageType == "Using_WolfHUD!" then 126 | VHUDPlus.Sync.peers[sender] = true --Sync other peers, that new peer is using VHUDPlus? 127 | managers.chat:feed_system_message(ChatManager.GAME, "A Client is using VHUDPlus ;)") --TEST 128 | else 129 | local receive_data = WoldHUD.Sync.string_to_table(data) 130 | if messageType == "WolfHUD_Sync_GameInfo_ecm_feedback" then -- receive and call gameinfo event 131 | managers.chat:feed_system_message(ChatManager.GAME, "Sync GameInfo event received!") --TEST 132 | log("GameInfo event received!") 133 | VHUDPlus.Sync.receive_gameinfo_ecm_feedback_event(receive_data) 134 | elseif messageType == "WolfHUD_Sync_Cache" then -- Add data to cache 135 | managers.chat:feed_system_message(ChatManager.GAME, "Sync Cache event received!") --TEST 136 | log("Sync Cache event received!") 137 | VHUDPlus.Sync.receive_cache_event(receive_data) 138 | elseif messageType == "WolfHUD_Sync" then -- Receive data that needs to be handled by data.event 139 | managers.chat:feed_system_message(ChatManager.GAME, "Sync event received!") --TEST 140 | log("Sync event received!") 141 | VHUDPlus.Sync.receive(receive_data) 142 | end 143 | end 144 | end 145 | end 146 | end) 147 | 148 | Hooks:Add("BaseNetworkSessionOnPeerRemoved", "BaseNetworkSessionOnPeerRemoved_WolfHUD", function(self, peer, peer_id, reason) 149 | if VHUDPlus.Sync and VHUDPlus.Sync.peers[peer_id] then 150 | VHUDPlus.Sync.peers[peer_id] = false 151 | end 152 | end) 153 | 154 | Hooks:Add("BaseNetworkSessionOnLoadComplete", "BaseNetworkSessionOnLoadComplete_WolfHUD", function(local_peer, id) 155 | if VHUDPlus.Sync and Net:IsMultiplayer() then 156 | if Network:is_client() then 157 | Net:SendToPeer(managers.network:session():server_peer():id(), "Using_WolfHUD?", "") 158 | else 159 | if managers.gameinfo then 160 | managers.gameinfo:register_listener("ecm_feedback_duration_listener", "ecm", "set_feedback_duration", callback(nil, VHUDPlus.Sync, "gameinfo_ecm_feedback_event_sender")) 161 | end 162 | end 163 | end 164 | end) 165 | ]] 166 | -------------------------------------------------------------------------------- /devlua/NumbericSuspicion.lua: -------------------------------------------------------------------------------- 1 | if not VHUDPlus:getSetting({"HUDSuspicion", "ENABLED"}, true) then return end 2 | 3 | local hudsuspicion_init_original = HUDSuspicion.init 4 | local hudsuspicions_animate_eye_original = HUDSuspicion.animate_eye 5 | local hudsuspicion_hide_original = HUDSuspicion.hide 6 | 7 | function HUDSuspicion:init(...) 8 | hudsuspicion_init_original(self, ...) 9 | self._scale = 1 10 | self._suspicion_text_panel = self._suspicion_panel:panel({ 11 | name = "suspicion_text_panel", 12 | visible = true, 13 | x = 0, 14 | y = 0, 15 | h = self._suspicion_panel:h(), 16 | w = self._suspicion_panel:w(), 17 | layer = 1 18 | }) 19 | 20 | self._suspicion_text = OutlinedText:new(self._suspicion_text_panel, { 21 | name = "suspicion_text", 22 | visible = true, 23 | text = "", 24 | valign = "center", 25 | align = "center", 26 | layer = 2, 27 | color = Color.white, 28 | font = tweak_data.menu.pd2_large_font, 29 | font_size = 28, 30 | h = 64 31 | }) 32 | self._suspicion_text:set_y((math.round(self._suspicion_text_panel:h() / 4))) 33 | end 34 | 35 | function HUDSuspicion:_is_detected() 36 | local detected_text = self._suspicion_panel and self._suspicion_panel:child("suspicion_detected") 37 | return self._discovered or self._suspicion_value and self._suspicion_value >= 1 or detected_text and detected_text:visible() and detected_text:alpha() > 0 38 | end 39 | 40 | function HUDSuspicion:set_detection(text_item, detection) 41 | detection = math.clamp(detection, 0, 1) 42 | local color = math.lerp(Color(0, 0.71, 1), Color(0.99, 0.08, 0), detection) 43 | text_item:set_color(color) 44 | text_item:set_text(string.format("%d%%", detection*100)) 45 | end 46 | 47 | function HUDSuspicion:_animate_text(suspicion_panel, suspicion_text) 48 | while true do 49 | local detection = self:_is_detected() and 1 or self._suspicion_value or 0 50 | self:set_detection(suspicion_text, detection) 51 | coroutine.yield() 52 | end 53 | end 54 | 55 | function HUDSuspicion:animate_eye(...) 56 | local was_animating = self._eye_animation and true or false 57 | hudsuspicions_animate_eye_original(self, ...) 58 | 59 | if not was_animating and self._eye_animation then 60 | self:rescale() 61 | 62 | local visible = VHUDPlus:getSetting({"HUDSuspicion", "SHOW_BARS"}, true) 63 | self._suspicion_panel:child("suspicion_left"):set_visible(visible) 64 | self._suspicion_panel:child("suspicion_right"):set_visible(visible) 65 | self._misc_panel:child("hud_stealthmeter_bg"):set_visible(visible) 66 | self._misc_panel:child("hud_stealth_eye"):set_visible(visible) 67 | self._misc_panel:child("hud_stealth_exclam"):set_visible(visible) 68 | 69 | if VHUDPlus:getSetting({"HUDSuspicion", "SHOW_PERCENTAGE"}, true) and not self._text_animation then 70 | self._suspicion_text:set_outlines_visible(VHUDPlus:getSetting({"HUDSuspicion", "SHOW_PERCENTAGE_OUTLINE"}, true)) 71 | self._text_animation = self._suspicion_text_panel:animate(callback(self, self, "_animate_text"), self._suspicion_text) 72 | end 73 | end 74 | end 75 | 76 | function HUDSuspicion:hide(...) 77 | if self._text_animation then 78 | self._suspicion_text_panel:stop() 79 | self._text_animation = nil 80 | end 81 | 82 | if self._suspicion_panel then 83 | self._suspicion_panel:set_visible(false) 84 | end 85 | 86 | return hudsuspicion_hide_original(self, ...) 87 | end 88 | 89 | function HUDSuspicion:rescale() 90 | local scale = VHUDPlus:getSetting({"HUDSuspicion", "SCALE"}, 0.8) 91 | if self._scale ~= scale then 92 | local suspicion_left = self._suspicion_panel:child("suspicion_left") 93 | local suspicion_right = self._suspicion_panel:child("suspicion_right") 94 | local hud_stealthmeter_bg = self._misc_panel:child("hud_stealthmeter_bg") 95 | local suspicion_detected = self._suspicion_panel:child("suspicion_detected") 96 | local hud_stealth_eye = self._misc_panel:child("hud_stealth_eye") 97 | local hud_stealth_exclam = self._misc_panel:child("hud_stealth_exclam") 98 | suspicion_left:set_size((suspicion_left:w() / self._scale) * scale, (suspicion_left:h() / self._scale) * scale) 99 | suspicion_right:set_size((suspicion_right:w() / self._scale) * scale, (suspicion_right:h() / self._scale) * scale) 100 | hud_stealthmeter_bg:set_size((hud_stealthmeter_bg:w() / self._scale) * scale, (hud_stealthmeter_bg:h() / self._scale) * scale) 101 | suspicion_detected:set_font_size((suspicion_detected:font_size() / self._scale) * scale) 102 | local fontSize = (self._suspicion_text:font_size() / self._scale) * scale 103 | self._suspicion_text:set_font_size(fontSize) 104 | hud_stealth_eye:set_size((hud_stealth_eye:w() / self._scale) * scale, (hud_stealth_eye:h() / self._scale) * scale) 105 | hud_stealth_exclam:set_size((hud_stealth_exclam:w() / self._scale) * scale, (hud_stealth_exclam:h() / self._scale) * scale) 106 | suspicion_left:set_center_x(self._suspicion_panel:w() / 2) 107 | suspicion_left:set_center_y(self._suspicion_panel:h() / 2) 108 | suspicion_right:set_center(suspicion_left:center()) 109 | hud_stealthmeter_bg:set_center(suspicion_left:center()) 110 | hud_stealth_eye:set_center(suspicion_left:center_x(), suspicion_left:bottom() - 4) 111 | hud_stealth_exclam:set_center(suspicion_left:center_x(), suspicion_left:top() - 4) 112 | self._suspicion_text:set_y(suspicion_left:top() + (suspicion_left:center_y() - suspicion_left:top()) / 2 - self._suspicion_text:font_size() / 2) 113 | self._scale = scale 114 | end 115 | end 116 | -------------------------------------------------------------------------------- /devlua/PacifiedCivs.lua: -------------------------------------------------------------------------------- 1 | 2 | -- local _upd_criminal_suspicion_progress_original = GroupAIStateBase._upd_criminal_suspicion_progress 3 | -- function GroupAIStateBase:_upd_criminal_suspicion_progress(...) 4 | -- if self._ai_enabled then 5 | -- for obs_key, obs_susp_data in pairs(self._suspicion_hud_data or {}) do 6 | -- local unit = obs_susp_data.u_observer 7 | -- if managers.enemy:is_civilian(unit) then 8 | -- local waypoint_id = "susp1" .. tostring(obs_key) 9 | -- local waypoint = managers.hud and managers.hud._hud.waypoints[waypoint_id] 10 | -- if waypoint then 11 | -- local color, arrow_color 12 | -- if unit:anim_data().drop and VHUDPlus:getSetting({"HUDSuspicion", "SHOW_PACIFIED_CIVILIANS"}, true) then 13 | -- if not obs_susp_data._subdued_civ then 14 | -- obs_susp_data._alerted_civ = nil 15 | -- obs_susp_data._subdued_civ = true 16 | -- if VHUDPlus:getSetting({"HUDSuspicion", "SHOW_PACIFIED_CIVILIANS_ALT_ICON"}, true) then 17 | -- waypoint.bitmap:set_color(Color(0.0, 1.0, 0.0)) 18 | -- waypoint.arrow:set_color(Color(0.75, 0, 0.3, 0)) 19 | -- else 20 | -- color = Color(0, 0.71, 1) 21 | -- arrow_color = Color(0, 0.35, 0.5) 22 | -- waypoint.bitmap:set_image("guis/textures/menu_singletick") 23 | -- end 24 | -- end 25 | -- elseif obs_susp_data.alerted then 26 | -- if not obs_susp_data._alerted_civ then 27 | -- obs_susp_data._subdued_civ = nil 28 | -- obs_susp_data._alerted_civ = true 29 | -- color = Color.white 30 | -- arrow_color = tweak_data.hud.detected_color 31 | -- waypoint.bitmap:set_image("guis/textures/hud_icons") 32 | -- waypoint.bitmap:set_texture_rect(479, 433, 32, 32) 33 | -- end 34 | -- end 35 | -- if color and arrow_color then 36 | -- waypoint.bitmap:set_color(color) 37 | -- waypoint.arrow:set_color(arrow_color:with_alpha(0.75)) 38 | -- end 39 | -- end 40 | -- end 41 | -- end 42 | -- end 43 | -- return _upd_criminal_suspicion_progress_original(self, ...) 44 | -- end 45 | -- CONFIG ********************************************************************** 46 | local config = {} 47 | 48 | config.icons = {} 49 | 50 | config.icons.civilian_alerted = "assets/guis/textures/civilian_alerted" 51 | config.icons.civilian_curious = "assets/guis/textures/civilian_curious" 52 | 53 | if VHUDPlus:getSetting({"HUDSuspicion", "SHOW_PACIFIED_CIVILIANS_WOLFDEFAULT"}, true) then 54 | config.icons.civilian_subdued = "guis/textures/menu_singletick" 55 | else 56 | config.icons.civilian_subdued = "assets/guis/textures/civilian_subdued" 57 | end 58 | 59 | config.icons.guard_alerted = "assets/guis/textures/guard_alerted" 60 | config.icons.guard_curious = "assets/guis/textures/guard_curious" 61 | 62 | config.icons.camera_alerted = "assets/guis/textures/camera_alerted" 63 | config.icons.camera_curious = "assets/guis/textures/camera_curious" 64 | 65 | config.colors = {} 66 | 67 | config.colors.called = Color(1,0,0) 68 | config.colors.calling = Color(1,0,0) 69 | 70 | if VHUDPlus:getSetting({"HUDSuspicion", "SHOW_PACIFIED_CIVILIANS_WOLFDEFAULT"}, true) then 71 | config.colors.subdued = Color(0,0.65,1) 72 | else 73 | config.colors.subdued = Color('008000') 74 | end 75 | 76 | config.colors.alerted = Color(1,0.2,0) 77 | config.colors.curious = Color(0,0.65,1) 78 | 79 | -- OVERRIDES ******************************************************************* 80 | local _upd_criminal_suspicion_progress_orig = GroupAIStateBase._upd_criminal_suspicion_progress 81 | function GroupAIStateBase:_upd_criminal_suspicion_progress(...) 82 | if self._ai_enabled and not VHUDPlus:getSetting({"HUDSuspicion", "SHOW_PACIFIED_CIVILIANS_ALT_ICON"}, true) then 83 | for obs_key, obs_susp_data in pairs(self._suspicion_hud_data or {}) do 84 | local unit = obs_susp_data.u_observer 85 | if managers.enemy:is_civilian(unit) then 86 | local waypoint_id = "susp1" .. tostring(obs_key) 87 | local waypoint = managers.hud and managers.hud._hud.waypoints[waypoint_id] 88 | if waypoint then 89 | local color, arrow_color 90 | if unit:anim_data().drop and VHUDPlus:getSetting({"HUDSuspicion", "SHOW_PACIFIED_CIVILIANS"}, true) then 91 | if not obs_susp_data._subdued_civ then 92 | obs_susp_data._alerted_civ = nil 93 | obs_susp_data._subdued_civ = true 94 | 95 | if VHUDPlus:getSetting({"HUDSuspicion", "SHOW_PACIFIED_CIVILIANS_WOLFDEFAULT"}, true) then 96 | color = Color(0, 0.71, 1) 97 | arrow_color = Color(0, 0.35, 0.5) 98 | waypoint.bitmap:set_image("guis/textures/menu_singletick") 99 | else 100 | waypoint.bitmap:set_color(Color(0.0, 1.0, 0.0)) 101 | waypoint.arrow:set_color(Color(0.75, 0, 0.3, 0)) 102 | end 103 | end 104 | elseif obs_susp_data.alerted then 105 | if not obs_susp_data._alerted_civ then 106 | obs_susp_data._subdued_civ = nil 107 | obs_susp_data._alerted_civ = true 108 | color = Color.white 109 | arrow_color = tweak_data.hud.detected_color 110 | waypoint.bitmap:set_image("guis/textures/hud_icons") 111 | waypoint.bitmap:set_texture_rect(479, 433, 32, 32) 112 | end 113 | end 114 | 115 | if color and arrow_color then 116 | waypoint.bitmap:set_color(color) 117 | waypoint.arrow:set_color(arrow_color:with_alpha(0.75)) 118 | end 119 | end 120 | end 121 | end 122 | elseif self._ai_enabled and VHUDPlus:getSetting({"HUDSuspicion", "SHOW_PACIFIED_CIVILIANS_ALT_ICON"}, true) and VHUDPlus:getSetting({"HUDSuspicion", "SHOW_PACIFIED_CIVILIANS"}, true) then 123 | for obs_key, obs_susp_data in pairs(self._suspicion_hud_data or {}) do 124 | local waypoint = managers.hud._hud.waypoints["susp1" .. tostring(obs_key)] 125 | 126 | if waypoint then 127 | local waypoint_data = buildWaypointData(obs_susp_data) 128 | setWaypointIcon(waypoint, decideWaypointIcon(waypoint_data)) 129 | setWaypointColor(waypoint, decideWaypointColor(waypoint_data)) 130 | end 131 | end 132 | end 133 | 134 | return _upd_criminal_suspicion_progress_orig(self, ...) 135 | end 136 | 137 | -- FUNCTION LIB **************************************************************** 138 | function buildWaypointData(obs_susp_data) 139 | local unit = obs_susp_data.u_observer 140 | local data = {} 141 | 142 | --type 143 | if managers.enemy:is_civilian(unit) then 144 | data.type = "civilian" 145 | elseif unit:character_damage() then 146 | data.type = "guard" 147 | else 148 | data.type = "camera" 149 | end 150 | 151 | --state 152 | if (type(obs_susp_data.status) == 'string' and obs_susp_data.status == 'called') then 153 | data.state = "called" 154 | elseif (type(obs_susp_data.status) == 'string' and obs_susp_data.status == 'calling') then 155 | data.state = "calling" 156 | elseif (unit:anim_data() and unit:anim_data().drop) then 157 | data.state = "subdued" 158 | elseif (obs_susp_data.alerted) then 159 | data.state = "alerted" 160 | else 161 | data.state = "curious" 162 | end 163 | 164 | return data 165 | end 166 | 167 | function decideWaypointIcon(waypoint_data) 168 | local icon 169 | 170 | if waypoint_data.type == "camera" then 171 | if waypoint_data.state == "alerted" then 172 | icon = config.icons.camera_alerted 173 | else 174 | icon = config.icons.camera_curious 175 | end 176 | elseif waypoint_data.type == "civilian" then 177 | if waypoint_data.state == "subdued" then 178 | icon = config.icons.civilian_subdued 179 | elseif waypoint_data.state == "alerted" then 180 | icon = config.icons.civilian_alerted 181 | else 182 | icon = config.icons.civilian_curious 183 | end 184 | elseif waypoint_data.type == "guard" then 185 | if waypoint_data.state == "alerted" then 186 | icon = config.icons.guard_alerted 187 | else 188 | icon = config.icons.guard_curious 189 | end 190 | end 191 | 192 | --disable icon change for calling/called status (use built-in icons) 193 | if waypoint_data.state == "calling" or waypoint_data.state == "called" then 194 | icon = false 195 | end 196 | 197 | return icon 198 | end 199 | 200 | function decideWaypointColor(waypoint_data) 201 | local color 202 | 203 | if waypoint_data.state == "called" then 204 | color = config.colors.called 205 | elseif waypoint_data.state == "calling" then 206 | color = config.colors.calling 207 | elseif waypoint_data.state == "subdued" then 208 | color = config.colors.subdued 209 | elseif waypoint_data.state == "alerted" then 210 | color = config.colors.alerted 211 | elseif waypoint_data.state == "curious" then 212 | color = config.colors.curious 213 | end 214 | 215 | return color 216 | end 217 | 218 | function setWaypointIcon(waypoint, icon) 219 | if icon then 220 | waypoint.bitmap:set_image(icon) 221 | end 222 | end 223 | 224 | function setWaypointColor(waypoint, color) 225 | if color then 226 | waypoint.bitmap:set_color(color) 227 | waypoint.arrow:set_color(color:with_alpha(0.75)) 228 | end 229 | end 230 | -------------------------------------------------------------------------------- /devlua/ProfileMenu.lua: -------------------------------------------------------------------------------- 1 | local PROFILE_MENU_ID = "wolfhud_profile_switch_node_menu" 2 | 3 | if RequiredScript == "lib/managers/menumanager" then 4 | local function create_profile_menu_node(nodes, menu_id) 5 | local arugements = { 6 | gui_class = "MenuNodeProfileSwitchGui", 7 | help_id = "menu_skill_switch_help", 8 | menu_components = nodes.kit and "mission_briefing" or managers.menu:is_pc_controller() and "inventory" or "", 9 | modifier = "ProfileSwitchInitiator", 10 | name = PROFILE_MENU_ID, 11 | no_item_parent = false, 12 | no_menu_wrapper = true, 13 | refresh = "ProfileSwitchInitiator", 14 | scene_state = "inventory", --"standard", 15 | sync_state = "inventory", 16 | topic_id = "menu_inventory", 17 | --back_callback = "profile_menu_back", 18 | { 19 | ["_meta"] = "legend", 20 | ["name"] = "menu_legend_select" 21 | }, 22 | { 23 | ["_meta"] = "legend", 24 | ["name"] = "menu_legend_back" 25 | }, 26 | } 27 | 28 | local node_class = CoreSerialize.string_to_classtable("MenuNodeTable") 29 | if node_class then 30 | nodes[menu_id] = node_class:new(arugements) 31 | 32 | local callback_handler = CoreSerialize.string_to_classtable("MenuCallbackHandler") 33 | if callback_handler then 34 | nodes[menu_id]:set_callback_handler(callback_handler:new()) 35 | end 36 | end 37 | end 38 | 39 | Hooks:Add("MenuManagerBuildCustomMenus", "WolfHUD_MenuManager_BuildProfileMenu", function( menu_manager, nodes ) 40 | if nodes.main and not nodes[PROFILE_MENU_ID]then 41 | create_profile_menu_node(nodes, PROFILE_MENU_ID) 42 | end 43 | end) 44 | 45 | local LobbyOptionInitiator_modify_node_orig = LobbyOptionInitiator.modify_node 46 | function LobbyOptionInitiator:modify_node(node, ...) 47 | local active_menu = managers.menu:active_menu() 48 | local briefing_nodes = active_menu and active_menu.logic and active_menu.logic._data._nodes 49 | if briefing_nodes and briefing_nodes.kit and not briefing_nodes[PROFILE_MENU_ID] then 50 | create_profile_menu_node(briefing_nodes, PROFILE_MENU_ID, true) 51 | end 52 | return LobbyOptionInitiator_modify_node_orig(self, node, ...) 53 | end 54 | 55 | ProfileSwitchInitiator = ProfileSwitchInitiator or class(SkillSwitchInitiator) 56 | function ProfileSwitchInitiator:modify_node(node, data) 57 | node:clean_items() 58 | self:create_divider(node, "title", "wolfhud_profile_switch_title_profiles", nil, tweak_data.screen_colors.text) 59 | local mpm = managers.multi_profile 60 | for i = 1, mpm:profile_count() do 61 | local profile = mpm:profile(i) 62 | if profile then 63 | local hightlight_color, row_item_color, callback 64 | if (i == mpm:current_profile_id()) then 65 | hightlight_color = tweak_data.screen_colors.text 66 | row_item_color = tweak_data.screen_colors.text 67 | callback = "menu_back" 68 | else 69 | hightlight_color = tweak_data.screen_colors.button_stage_2 70 | row_item_color = tweak_data.screen_colors.button_stage_3 71 | callback = "profile_menu_switch" 72 | end 73 | 74 | self:create_item(node, { 75 | name = i, 76 | text_id = profile.name or string.format("Profile %d", i), 77 | enabled = true, 78 | localize = false, 79 | callback = callback, 80 | hightlight_color = hightlight_color, 81 | row_item_color = row_item_color, 82 | disabled_color = row_item_color, 83 | }) 84 | end 85 | end 86 | self:create_divider(node, "back_div") 87 | self:add_back_button(node) 88 | node:set_default_item_name(1) 89 | return node 90 | end 91 | 92 | function MenuCallbackHandler:profile_menu_switch(item) 93 | local mpm = managers.multi_profile 94 | local profile_id = item:parameters().name 95 | if mpm and mpm:is_valid_id(profile_id) then 96 | mpm:set_current_profile(profile_id) 97 | end 98 | 99 | self:refresh_node() 100 | end 101 | elseif RequiredScript == "lib/managers/menu/renderers/menunodeskillswitchgui" then 102 | MenuNodeProfileSwitchGui = MenuNodeProfileSwitchGui or class(MenuNodeSkillSwitchGui) 103 | MenuNodeProfileSwitchGui.SKILL_POINTS_X = 0.24 104 | MenuNodeProfileSwitchGui.STATUS_X = 0.52 105 | MenuNodeProfileSwitchGui.PROFILE_PREVIEW_W = 195 106 | 107 | function MenuNodeProfileSwitchGui:_setup_item_panel(...) 108 | MenuNodeProfileSwitchGui.super._setup_item_panel(self, ...) 109 | 110 | if alive(self.title_text) then 111 | self.title_text:set_text(managers.localization:to_upper_text("wolfhud_profile_switch_title")) 112 | end 113 | 114 | local ws_panel = self.item_panel:parent() 115 | if alive(ws_panel) then 116 | ws_panel:bitmap({ 117 | texture = "guis/textures/test_blur_df", 118 | w = ws_panel:w(), 119 | h = ws_panel:h(), 120 | render_template = "VertexColorTexturedBlur3D", 121 | halign = "scale", 122 | valign = "scale", 123 | layer = 50, 124 | alpha = 1 125 | }) 126 | end 127 | 128 | if alive(self.item_panel) and LoadoutPanel then 129 | local offset_h = managers.menu:is_pc_controller() and 25 or 0 130 | local height = math.min(math.floor(self.item_panel:h()), ws_panel:height()) 131 | self.profile_preview = LoadoutPanel:new(self.item_panel:parent(), self, 0, self.PROFILE_PREVIEW_W, height - offset_h, { 132 | component_layout = { 133 | { "skills" }, 134 | { "perk" }, 135 | { "primary", "secondary" }, 136 | { "grenade", "armor" }, 137 | { "deployable", "secondary_deployable" } 138 | }, 139 | default = { alpha = 0.9 }, 140 | margin = 5, 141 | borders = { 1, 1, 1, 1 }, 142 | layer = 53, 143 | }) 144 | local outfit = managers.multi_profile:get_profile_outfit(managers.multi_profile:current_profile_id()) 145 | self.profile_preview:set_outfit(outfit) 146 | if managers.multi_profile:profile_count() > 30 then 147 | self.profile_preview:set_top(0) 148 | end 149 | end 150 | end 151 | 152 | function MenuNodeProfileSwitchGui:_create_menu_item(row_item, ...) 153 | MenuNodeProfileSwitchGui.super._create_menu_item(self, row_item, ...) 154 | if row_item.type ~= "divider" and row_item.name ~= "back" then 155 | local mpm = managers.multi_profile 156 | local profile_id = row_item.name 157 | local profile = mpm:profile(profile_id) 158 | local skill_name, perk_name = "", "" 159 | 160 | skill_name = profile.skillset and managers.skilltree:get_skill_switch_name(profile.skillset, false) or managers.localization:to_upper_text("menu_st_locked_skill_switch") 161 | if profile.perk_deck then 162 | local data = tweak_data.skilltree.specializations[tonumber(profile.perk_deck)] 163 | local name_id = data and data.name_id 164 | perk_name = managers.localization:to_upper_text(name_id) 165 | end 166 | 167 | if alive(row_item.skill_points_gui) then 168 | row_item.skill_points_gui:set_text(utf8.to_upper(skill_name)) 169 | row_item.skill_points_gui:set_alpha(1) 170 | end 171 | if alive(row_item.status_gui) then 172 | row_item.status_gui:set_text(perk_name) 173 | end 174 | row_item.distribution_after_text = false 175 | elseif row_item.type == "divider" and row_item.name == "divider_title" then 176 | 177 | if alive(row_item.skill_points_gui) then 178 | row_item.skill_points_gui:set_text(string.format("%s-%s", managers.localization:to_upper_text("menu_st_skilltree", {}), managers.localization:to_upper_text("menu_st_skill_switch_title_name", {}))) 179 | row_item.skill_points_gui:show() 180 | end 181 | if alive(row_item.status_gui) then 182 | row_item.status_gui:set_text(managers.localization:to_upper_text("menu_specialization", {}) .. ":") 183 | end 184 | end 185 | end 186 | 187 | function MenuNodeProfileSwitchGui:arrange_loadout_panels() 188 | if self.profile_preview then 189 | self.profile_preview:set_top(self.item_panel:top()) 190 | self.profile_preview:set_right(self.item_panel:right()) 191 | end 192 | end 193 | 194 | function MenuNodeProfileSwitchGui:_highlight_row_item(row_item, mouse_over, ...) 195 | MenuNodeProfileSwitchGui.super._highlight_row_item(self, row_item, mouse_over, ...) 196 | 197 | local mpm = managers.multi_profile 198 | local profile_id = row_item.name and mpm:is_valid_id(row_item.name) and row_item.name or mpm:current_profile_id() 199 | self:change_outfit_preview(profile_id) 200 | end 201 | 202 | function MenuNodeProfileSwitchGui:_align_marker(row_item, ...) 203 | MenuNodeProfileSwitchGui.super._align_marker(self, row_item, ...) 204 | 205 | if self.profile_preview then 206 | if row_item.name ~= "back" then 207 | self._marker_data.marker:set_w(self.item_panel:w() - self.profile_preview:w() - 10) 208 | else 209 | self._marker_data.marker:set_w(self.profile_preview:w()) 210 | self._marker_data.marker:set_right(self.item_panel:w()) 211 | end 212 | end 213 | end 214 | 215 | function MenuNodeProfileSwitchGui:_clear_gui(...) 216 | if self.profile_preview then 217 | self.profile_preview:destroy() 218 | end 219 | 220 | MenuNodeProfileSwitchGui.super._clear_gui(self, ...) 221 | end 222 | 223 | function MenuNodeProfileSwitchGui:mouse_moved(o, x, y, ...) 224 | local used, icon = MenuNodeProfileSwitchGui.super.mouse_moved(self, o, x, y, ...) 225 | return true, icon 226 | end 227 | 228 | function MenuNodeProfileSwitchGui:change_outfit_preview(profile_id) 229 | local mpm = managers.multi_profile 230 | if self.profile_preview and mpm:is_valid_id(profile_id) and (self._previewing_outfit or 0) ~= profile_id then 231 | local outfit = mpm and mpm:get_profile_outfit(profile_id) 232 | self.profile_preview:set_outfit(outfit) 233 | self._previewing_outfit = profile_id 234 | end 235 | end 236 | elseif RequiredScript == "lib/managers/multiprofilemanager" then 237 | local open_quick_select_original = MultiProfileManager.open_quick_select 238 | function MultiProfileManager:open_quick_select(...) 239 | if VHUDPlus:getSetting({"CrewLoadout", "REPLACE_PROFILE_MENU"}, true) then 240 | managers.menu:open_node(PROFILE_MENU_ID, {}) 241 | else 242 | open_quick_select_original(self, ...) 243 | end 244 | end 245 | 246 | 247 | function MultiProfileManager:current_profile_id() 248 | return self._global._current_profile or 1 249 | end 250 | 251 | function MultiProfileManager:is_valid_id(profile_id) 252 | return profile_id and type(profile_id) == "number" and profile_id > 0 and profile_id <= self:profile_count() and true or false 253 | end 254 | 255 | function MultiProfileManager:get_profile_outfit(profile_id) 256 | if profile_id ~= self:current_profile_id() then 257 | local profile = self:profile(profile_id) 258 | local gd = Global.skilltree_manager.skill_switches[profile.skillset] 259 | local skills = {} 260 | if gd and gd.trees then 261 | local pts = 0 262 | for i=1, #gd.trees do 263 | pts=Application:digest_value(gd.trees[i].points_spent, false) 264 | table.insert(skills, pts) 265 | end 266 | end 267 | local outfit = { 268 | skills = { 269 | skills = skills, 270 | specializations = { profile.perk_deck, 9 }, 271 | }, 272 | primary = self:get_item_data("primaries", profile.primary), 273 | secondary = self:get_item_data("secondaries", profile.secondary), 274 | melee_weapon = profile.melee, 275 | grenade = profile.throwable, 276 | armor = profile.armor, 277 | mask = self:get_item_data("mask", profile.mask), 278 | deployable = profile.deployable, 279 | secondary_deployable = profile.deployable_secondary, 280 | deployable_amount = self:get_deployable_amount(profile.deployable, gd and gd.skills), 281 | secondary_deployable_amount = self:get_deployable_amount(profile.deployable_secondary, gd and gd.skills), 282 | } 283 | return outfit 284 | else 285 | local outfit = managers.blackmarket:unpack_outfit_from_string(managers.blackmarket:outfit_string()) 286 | return outfit 287 | end 288 | end 289 | 290 | function MultiProfileManager:get_item_data(category, slot) 291 | if not Global.blackmarket_manager.crafted_items[category] then 292 | return nil 293 | end 294 | if not Global.blackmarket_manager.crafted_items[category][slot] then 295 | slot = 1 296 | end 297 | local item_data = Global.blackmarket_manager.crafted_items[category][slot] 298 | return item_data or {} 299 | end 300 | 301 | function MultiProfileManager:get_deployable_amount(deployable, skills) 302 | local amount = 0 303 | if deployable then 304 | if deployable == "sentry_gun_silent" then 305 | deployable = "sentry_gun" 306 | end 307 | amount = tweak_data.equipments[deployable] and tweak_data.equipments[deployable].quantity[1] or 0 308 | local upgrade_def, upgrade_values, skill_tweak = tweak_data.upgrades.definitions, tweak_data.upgrades.values, tweak_data.skilltree.skills 309 | if skills and upgrade_values[deployable] and upgrade_values[deployable]["quantity"] then 310 | local value_index = 0 311 | for skill, data in pairs(skills) do 312 | local skill_data = skill_tweak[skill] 313 | for i = 1, data.unlocked do 314 | local upgrade_ids = skill_data and skill_data[i].upgrades 315 | for _, upgrade_id in ipairs(upgrade_ids) do 316 | local u_data = upgrade_def[upgrade_id] and upgrade_def[upgrade_id].upgrade 317 | if u_data and u_data.category == deployable and u_data.upgrade == "quantity" then 318 | if upgrade_def[upgrade_id].incremental then 319 | value_index = value_index + (u_data.value or 0) 320 | else 321 | value_index = u_data.value 322 | end 323 | end 324 | end 325 | end 326 | end 327 | if value_index > 0 then 328 | amount = amount + (upgrade_values[deployable]["quantity"][math.floor(value_index)] or 0) 329 | end 330 | end 331 | end 332 | return amount 333 | end 334 | elseif RequiredScript == "lib/managers/menu/multiprofileitemgui" then 335 | local init_orig = MultiProfileItemGui.init 336 | 337 | function MultiProfileItemGui:init(...) 338 | init_orig(self, ...) 339 | 340 | self._max_length = VHUDPlus:getTweakEntry("MAX_PROFILE_NAME_LENGTH", "number", 20) 341 | end 342 | elseif RequiredScript == "lib/managers/menu/missionbriefinggui" then 343 | local special_btn_pressed_orig = MissionBriefingGui.special_btn_pressed 344 | local input_focus_orig = MissionBriefingGui.input_focus 345 | local reload_loadout_orig = MissionBriefingGui.reload_loadout 346 | function MissionBriefingGui:special_btn_pressed(button, ...) 347 | if self._enabled and button == Idstring("menu_change_profile_right") and managers.menu:get_controller():get_input_bool("menu_change_profile_left") then 348 | managers.menu:open_node(PROFILE_MENU_ID, {}) 349 | return 350 | end 351 | 352 | return special_btn_pressed_orig(self, button, ...) 353 | end 354 | 355 | function MissionBriefingGui:input_focus(...) 356 | local focus = input_focus_orig(self, ...) 357 | if focus then 358 | local active_menu = managers.menu:active_menu() 359 | local selected_node = active_menu and active_menu.logic:selected_node() 360 | if selected_node and selected_node:parameters().name == PROFILE_MENU_ID then 361 | focus = false 362 | end 363 | end 364 | return focus 365 | end 366 | 367 | JukeboxItemNew = JukeboxItemNew or class(JukeboxItem) 368 | function JukeboxItemNew:select(...) 369 | local active_menu = managers.menu:active_menu() 370 | local selected_node = active_menu and active_menu.logic:selected_node() 371 | if not selected_node or selected_node:parameters().name == "kit" then 372 | JukeboxItemNew.super.select(self, ...) 373 | else 374 | self.displayed = true 375 | JukeboxItemNew.super.super.select(self, ...) 376 | end 377 | end 378 | function JukeboxItemNew:deselect(...) 379 | local active_menu = managers.menu:active_menu() 380 | local selected_node = active_menu and active_menu.logic:selected_node() 381 | if not selected_node or selected_node:parameters().name == "jukebox" then 382 | JukeboxItemNew.super.deselect(self, ...) 383 | else 384 | self.closing = true 385 | self.displayed = nil 386 | JukeboxItemNew.super.super.deselect(self, ...) 387 | end 388 | end 389 | 390 | if CoreClass then 391 | CoreClass.override_class(JukeboxItem, JukeboxItemNew) 392 | end 393 | elseif RequiredScript == "lib/managers/menu/playerinventorygui" then 394 | local special_btn_pressed_orig = PlayerInventoryGui.special_btn_pressed 395 | function PlayerInventoryGui:special_btn_pressed(button, ...) 396 | if button == Idstring("menu_change_profile_right") and managers.menu:get_controller():get_input_bool("menu_change_profile_left") then 397 | managers.menu:open_node(PROFILE_MENU_ID, {}) 398 | return 399 | end 400 | 401 | return special_btn_pressed_orig(self, button, ...) 402 | end 403 | end 404 | -------------------------------------------------------------------------------- /devlua/README.md: -------------------------------------------------------------------------------- 1 | # VPlusHUD Localizations 2 | -------------------------------------------------------------------------------- /devlua/RichPresence.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steam-test1/VPlusHUD/c56193720729ca712c23bbd87af665e1447eff2a/devlua/RichPresence.lua -------------------------------------------------------------------------------- /devlua/Utils/InputDialog.lua: -------------------------------------------------------------------------------- 1 | --Dialog working fine, GUI not present...? 2 | 3 | local requiresScript = RequiredScript:lower() 4 | if requiresScript == "lib/managers/systemmenumanager" then 5 | 6 | core:module("SystemMenuManager") 7 | require("lib/managers/dialogs/SpecializationDialog") 8 | 9 | GenericSystemMenuManager.GENERIC_INPUT_DIALOG_CLASS = TextInputDialog 10 | GenericSystemMenuManager.INPUT_DIALOG_CLASS = TextInputDialog 11 | 12 | function GenericSystemMenuManager:show_input( data ) 13 | local success = self:_show_class(data, self.GENERIC_INPUT_DIALOG_CLASS, self.INPUT_DIALOG_CLASS, data.force) 14 | self:_show_result(success, data) 15 | end 16 | elseif requiresScript == "lib/managers/dialogs/specializationdialog" then 17 | 18 | core:module("SystemMenuManager") 19 | require("lib/managers/dialogs/GenericDialog") 20 | 21 | TextInputDialog = TextInputDialog or class(GenericDialog) 22 | TextInputDialog.KEY_INIT_DELAY = 0.6 23 | TextInputDialog.KEY_DELAY = 0.03 24 | 25 | function TextInputDialog:init(manager, data, ...) 26 | Dialog.init(self, manager, data) 27 | 28 | if not self._data.focus_button then 29 | if #self._button_text_list > 0 then 30 | self._data.focus_button = #self._button_text_list 31 | else 32 | self._data.focus_button = 1 33 | end 34 | end 35 | self._ws = self._data.ws or manager:_get_ws() 36 | local text_config = { 37 | title_font = data.title_font, 38 | title_font_size = data.title_font_size, 39 | font = data.font or _G.tweak_data.menu.pd2_medium_font, 40 | font_size = data.font_size or _G.tweak_data.menu.pd2_medium_font_size, 41 | w = data.w or 500, 42 | h = data.h or 400, 43 | no_close_legend = true, 44 | no_scroll_legend = true, 45 | use_indicator = data.indicator or data.no_buttons or false, 46 | is_title_outside = is_title_outside or false, 47 | use_text_formating = data.use_text_formating, 48 | text_formating_color = data.text_formating_color, 49 | text_formating_color_table = data.text_formating_color_table, 50 | text_blend_mode = data.text_blend_mode or "add" 51 | } 52 | self._panel_script = _G.TextInputBoxGui:new(self._ws, self._data.title or "", self._data.text or "", self._data.user_text or "", self._data, text_config) 53 | self._panel_script:add_background() 54 | self._panel_script:set_layer(_G.tweak_data.gui.DIALOG_LAYER) 55 | self._panel_script:set_centered() 56 | self._panel_script:set_fade(0) 57 | self._controller = self._data.controller or manager:_get_controller() 58 | self._confirm_func = callback(self, self, "button_pressed_callback") 59 | self._cancel_func = callback(self, self, "dialog_cancel_callback") 60 | self._resolution_changed_callback = callback(self, self, "resolution_changed_callback") 61 | managers.viewport:add_resolution_changed_func(self._resolution_changed_callback) 62 | if data.counter then 63 | self._counter = data.counter 64 | self._counter_time = self._counter[1] 65 | end 66 | self._sound_event = data.sound_event 67 | 68 | self._last_key_pressed = nil 69 | self._next_key_send_t = 0 70 | end 71 | 72 | function TextInputDialog:set_input_enabled(enabled) 73 | TextInputDialog.super.set_input_enabled(self, enabled) 74 | 75 | if managers.controller:get_default_wrapper_type() == "pc" or managers.controller:get_default_wrapper_type() == "steam" then 76 | self._controller:remove_trigger("confirm", self._confirm_func) 77 | self._controller:remove_trigger("toggle_menu", self._cancel_func) 78 | self._controller:remove_trigger("cancel", self._cancel_func) 79 | end 80 | 81 | if enabled then 82 | local dialog_panel = self._panel_script and self._panel_script._panel 83 | if not self._kb_connected and self._ws and dialog_panel then 84 | local kb = Input:keyboard() 85 | self._ws:connect_keyboard(kb) 86 | 87 | dialog_panel:enter_text(function(that, char) self:on_enter_text(char) end) 88 | dialog_panel:key_press(function(that, key) self:on_key_press(key) end) 89 | dialog_panel:key_release(function(that, key) self:on_key_release(key) end) 90 | 91 | self._kb_connected = true 92 | end 93 | else 94 | local dialog_panel = self._panel_script and self._panel_script._panel 95 | if self._kb_connected and self._ws and dialog_panel then 96 | self._ws:disconnect_keyboard() 97 | dialog_panel:enter_text(nil) 98 | dialog_panel:key_press(nil) 99 | dialog_panel:key_release(nil) 100 | self._kb_connected = nil 101 | end 102 | end 103 | end 104 | 105 | function TextInputDialog:mouse_moved(o, x, y) 106 | if self._panel_script and alive(self._panel_script._text_input_panel) then 107 | local x, y = managers.mouse_pointer:convert_1280_mouse_pos(x, y) 108 | local status = self._panel_script._text_input_panel:inside(x, y) 109 | self._panel_script:set_textinput_highlight(status) 110 | self._data.text_input_highlight = status 111 | if status then 112 | return true, "link" 113 | end 114 | end 115 | return TextInputDialog.super.mouse_moved(self, o, x, y) 116 | end 117 | 118 | function TextInputDialog:mouse_pressed(o, button, x, y) 119 | if button == Idstring("0") then 120 | if self._panel_script and alive(self._panel_script._text_input_panel) then 121 | local x, y = managers.mouse_pointer:convert_1280_mouse_pos(x, y) 122 | local status = self._panel_script._text_input_panel:inside(x, y) 123 | self._panel_script:set_textinput_selected(status) 124 | self._data.text_input_focus = status 125 | if status then 126 | self:chk_mouse_pointer_status() 127 | return true, "link" 128 | end 129 | end 130 | end 131 | return TextInputDialog.super.mouse_pressed(self, o, button, x, y) 132 | end 133 | 134 | function TextInputDialog:on_enter_text(char) 135 | if self._data.text_input_focus then 136 | local text = self._data.user_text 137 | local n = utf8.len(text) 138 | local m = self._data.max_len or n + 1 139 | if n < m then 140 | local key = self._data.to_upper and utf8.to_upper(char) or char 141 | text = string.format("%s%s", text, key) 142 | self._panel_script:update_user_text(text) 143 | self._data.user_text = text 144 | end 145 | end 146 | end 147 | 148 | function TextInputDialog:on_key_press(key) 149 | local text = self._data.user_text 150 | local n = utf8.len(text) 151 | if key == Idstring("backspace") then 152 | if self._data.text_input_focus then 153 | text = utf8.sub(text, 0, math.max(n - 1, 0)) 154 | self._panel_script:update_user_text(text) 155 | self._last_key_pressed = key 156 | self._next_key_send_t = Application:time() + TextInputDialog.KEY_INIT_DELAY 157 | end 158 | elseif key == Idstring("enter") then 159 | if self._data.text_input_focus then 160 | self._panel_script:set_textinput_selected(false) 161 | self._data.text_input_focus = false 162 | self._data.text_input_highlight = false 163 | self:chk_mouse_pointer_status() 164 | elseif self._data.text_input_highlight then 165 | self._panel_script:set_textinput_selected(true) 166 | self._data.text_input_focus = true 167 | self:chk_mouse_pointer_status() 168 | else 169 | self:button_pressed_callback() 170 | end 171 | elseif key == Idstring("esc") then 172 | if self._data.text_input_focus then 173 | self._panel_script:set_textinput_selected(false) 174 | self._data.text_input_focus = false 175 | self:chk_mouse_pointer_status() 176 | else 177 | self:dialog_cancel_callback() 178 | end 179 | end 180 | self._data.user_text = text 181 | end 182 | 183 | function TextInputDialog:on_key_release(key) 184 | self._last_key_pressed = nil 185 | end 186 | 187 | function TextInputDialog:update_input(t, dt) 188 | if self._data.text_input_focus then 189 | if self._last_key_pressed and self._next_key_send_t < t then 190 | local text = self._data.user_text 191 | local n = utf8.len(text) 192 | 193 | if self._last_key_pressed == Idstring("backspace") then 194 | text = utf8.sub(text, 0, math.max(n - 1, 0)) 195 | else 196 | text = string.format("%s%s", text, self._last_key_pressed) 197 | end 198 | self._panel_script:update_user_text(text) 199 | self._next_key_send_t = self._next_key_send_t + TextInputDialog.KEY_DELAY 200 | 201 | self._data.user_text = text 202 | end 203 | 204 | local scroll = self._controller:get_input_axis("menu_scroll") 205 | if scroll.y > self.MOVE_AXIS_LIMIT or scroll.y < -self.MOVE_AXIS_LIMIT then 206 | self._panel_script:set_textinput_selected(false) 207 | self._data.text_input_focus = false 208 | end 209 | end 210 | return TextInputDialog.super.update_input(self, t, dt) 211 | end 212 | 213 | function TextInputDialog:chk_mouse_pointer_status() 214 | if self._text_box_focus then 215 | managers.mouse_pointer:disable() 216 | elseif managers.controller:get_default_wrapper_type() == "pc" or managers.controller:get_default_wrapper_type() == "steam" then 217 | managers.mouse_pointer:enable() 218 | end 219 | end 220 | 221 | function TextInputDialog:button_pressed(button_index) 222 | local button_list = self._data.button_list 223 | self:fade_out_close() 224 | if button_list then 225 | local button = button_list[button_index] 226 | if button and button.callback_func then 227 | button.callback_func(button_index, button, self._data.user_text) 228 | end 229 | end 230 | local callback_func = self._data.callback_func 231 | if callback_func then 232 | callback_func(button_index, self._data) 233 | end 234 | end 235 | elseif requiresScript == "lib/managers/menu/specializationboxgui" then 236 | TextInputBoxGui = TextInputBoxGui or class(TextBoxGui) 237 | TextInputBoxGui.TEXT = "" 238 | 239 | function TextInputBoxGui:init(...) 240 | 241 | TextInputBoxGui.super.init(self, ...) 242 | 243 | self._text_box_highlight = false 244 | self._text_box_focus = false 245 | self._cursor_animation = false 246 | end 247 | 248 | function TextInputBoxGui:_create_text_box(ws, title, text, user_text, content_data, config, ...) 249 | text = text .. "\n\n." 250 | 251 | local panel = TextInputBoxGui.super._create_text_box(self, ws, title, text, content_data, config, ...) 252 | 253 | local text_input_panel = self._scroll_panel:panel({ 254 | name = "text_input_panel", 255 | x = 10, 256 | h = tweak_data.menu.pd2_medium_font_size * 1.1, 257 | w = panel:w() - 20, 258 | layer = self._scroll_panel:layer() + 1, 259 | }) 260 | 261 | local scroll_text = self._scroll_panel:child("text") 262 | if alive(scroll_text) then 263 | scroll_text:set_h(scroll_text:h() - 10) 264 | text_input_panel:set_bottom(scroll_text:bottom() - 5) 265 | end 266 | 267 | local input_text = text_input_panel:text({ 268 | x = 5, 269 | y = 0, 270 | w = text_input_panel:w(), 271 | h = text_input_panel:h(), 272 | name = "input_text", 273 | text = user_text or "", 274 | color = tweak_data.screen_colors.button_stage_3, 275 | font = config.font or tweak_data.menu.pd2_medium_font, 276 | font_size = config.font_size or tweak_data.menu.pd2_medium_font_size, 277 | align = "left", 278 | vertical = "center", 279 | blend_mode = config.text_blend_mode or "add", 280 | layer = 2, 281 | }) 282 | local _, _, w, _ = input_text:text_rect() 283 | input_text:set_w(w) 284 | 285 | local input_text_bg = text_input_panel:rect({ 286 | name = "text_input_bg", 287 | h = text_input_panel:h(), 288 | w = text_input_panel:w(), 289 | color = tweak_data.screen_colors.button_stage_1, 290 | alpha = 0.4, 291 | layer = 1 292 | }) 293 | 294 | local cursor = text_input_panel:rect({ 295 | name = "cursor", 296 | x = input_text:right(), 297 | w = 4, 298 | h = text_input_panel:h(), 299 | color = Color.white, 300 | alpha = 0.8, 301 | layer = 2, 302 | blend_mode = config.text_blend_mode or "add", 303 | visible = false, 304 | }) 305 | 306 | self._text_input_panel = text_input_panel 307 | end 308 | 309 | function TextInputBoxGui:scroll_up(y) 310 | 311 | TextInputBoxGui.super.scroll_up(self, y) 312 | 313 | local scroll_text = self._scroll_panel:child("text") 314 | if alive(self._text_input_panel) and alive(scroll_text) then 315 | self._text_input_panel:set_bottom(scroll_text:bottom() - 5) 316 | end 317 | end 318 | 319 | function TextInputBoxGui:scroll_down(y) 320 | 321 | TextInputBoxGui.super.scroll_down(self, y) 322 | 323 | local scroll_text = self._scroll_panel:child("text") 324 | if alive(self._text_input_panel) and alive(scroll_text) then 325 | self._text_input_panel:set_bottom(scroll_text:bottom() - 5) 326 | end 327 | end 328 | 329 | function TextInputBoxGui:update_user_text(text) 330 | local text_box = self._text_input_panel:child("input_text") 331 | if text_box then 332 | text_box:set_text(text) 333 | local _, _, w, _ = text_box:text_rect() 334 | text_box:set_w(w) 335 | 336 | local cursor = self._text_input_panel:child("cursor") 337 | if cursor then 338 | cursor:set_x(text_box:right()) 339 | end 340 | end 341 | end 342 | 343 | function TextInputBoxGui:set_textinput_highlight(status) 344 | if status ~= self._text_box_highlight and alive(self._text_input_panel) then 345 | self._text_box_highlight = status 346 | 347 | local text_input_bg = self._text_input_panel:child("text_input_bg") 348 | local text_input = self._text_input_panel:child("input_text") 349 | if not self._text_box_focus then 350 | local color, color_bg 351 | if status then 352 | color = tweak_data.screen_colors.button_stage_2 353 | color_bg = tweak_data.screen_colors.button_stage_3 354 | else 355 | color = tweak_data.screen_colors.button_stage_3 356 | color_bg = tweak_data.screen_colors.button_stage_1 357 | self._cursor_animation = false 358 | end 359 | if alive(text_input) then 360 | text_input:set_color(color) 361 | end 362 | if alive(text_input_bg) then 363 | text_input_bg:set_color(color_bg) 364 | end 365 | managers.menu_component:post_event("highlight") 366 | end 367 | end 368 | end 369 | 370 | function TextInputBoxGui:set_textinput_selected(status) 371 | if status ~= self._text_box_focus and alive(self._text_input_panel) then 372 | self._text_box_focus = status 373 | 374 | local text_input_bg = self._text_input_panel:child("text_input_bg") 375 | local text_input = self._text_input_panel:child("input_text") 376 | if alive(text_input_bg) and alive(text_input) then 377 | local color, color_bg 378 | if status then 379 | color = tweak_data.screen_colors.button_stage_2 380 | color_bg = tweak_data.screen_colors.button_stage_2 381 | else 382 | if self._text_box_highlight then 383 | color = tweak_data.screen_colors.button_stage_2 384 | color_bg = tweak_data.screen_colors.button_stage_3 385 | else 386 | color = tweak_data.screen_colors.button_stage_3 387 | color_bg = tweak_data.screen_colors.button_stage_1 388 | end 389 | end 390 | text_input:set_color(color) 391 | text_input_bg:set_color(color_bg) 392 | end 393 | 394 | local cursor = self._text_input_panel:child("cursor") 395 | if alive(cursor) and self._cursor_animation ~= status then 396 | self._cursor_animation = status 397 | if status then 398 | cursor:animate(callback(self, self, "_animate_cursor")) 399 | end 400 | end 401 | end 402 | end 403 | 404 | function TextInputBoxGui:_animate_cursor(o) 405 | local t = Application:time() 406 | o:set_visible(true) 407 | while self._cursor_animation do 408 | t = t + coroutine.yield() 409 | o:set_alpha(math.sin(t * 540) * 0.5 + 0.5) 410 | end 411 | o:set_visible(false) 412 | end 413 | end -------------------------------------------------------------------------------- /devlua/Utils/OutlinedText.lua: -------------------------------------------------------------------------------- 1 | OutlinedText = OutlinedText or class() 2 | 3 | function OutlinedText:init(panel, params) 4 | self._name = params.name 5 | self._parent = panel 6 | self._outlines_disabled = false 7 | 8 | self._text = panel:text(params) 9 | self._bgs = {} 10 | 11 | local bg_params = deep_clone(params) 12 | bg_params.name = nil 13 | bg_params.color = Color.black:with_alpha(0.5) 14 | bg_params.layer = self._text:layer() - 1 15 | for i = 1, 4 do 16 | bg_params.name = string.format("bg_%d", i) 17 | self._bgs[i] = panel:text(bg_params) 18 | end 19 | 20 | self:_update_positions() 21 | end 22 | 23 | function OutlinedText:set_outlines_visible(status) 24 | if self._outlines_disabled ~= not status then 25 | self._outlines_disabled = not status 26 | self:_update_visibility() 27 | end 28 | end 29 | 30 | function OutlinedText:set_outlines_color(color) 31 | if color then 32 | self:_call_func_bgs("set_color", color:with_alpha(0.5)) 33 | end 34 | end 35 | 36 | function OutlinedText:remove() 37 | self._parent:remove(self._text) 38 | for _, bg in pairs(self._bgs) do 39 | self._parent:remove(bg) 40 | end 41 | end 42 | 43 | function OutlinedText:x() return self._text:x() end 44 | function OutlinedText:y() return self._text:y() end 45 | function OutlinedText:w() return self._text:w() end 46 | function OutlinedText:h() return self._text:h() end 47 | function OutlinedText:center() return self._text:center() end 48 | function OutlinedText:center_x() return self._text:center_x() end 49 | function OutlinedText:center_y() return self._text:center_y() end 50 | function OutlinedText:text() return self._text:text() end 51 | function OutlinedText:font() return self._text:font() end 52 | function OutlinedText:font_size() return self._text:font_size() end 53 | function OutlinedText:visible() return self._text:visible() end 54 | function OutlinedText:color() return self._text:color() end 55 | function OutlinedText:alpha() return self._text:alpha() end 56 | 57 | function OutlinedText:set_x(...) return self:_call_func_text("set_x", ...) end 58 | function OutlinedText:set_y(...) return self:_call_func_text("set_y", ...) end 59 | function OutlinedText:set_w(...) return self:_call_func_text("set_w", ...) end 60 | function OutlinedText:set_h(...) return self:_call_func_text("set_h", ...) end 61 | function OutlinedText:set_center(...) return self:_call_func_text("set_center", ...) end 62 | function OutlinedText:set_center_x(...) return self:_call_func_text("set_center_x", ...) end 63 | function OutlinedText:set_center_y(...) return self:_call_func_text("set_center_y", ...) end 64 | function OutlinedText:set_text(...) return self:_call_func_all("set_text", ...) end 65 | function OutlinedText:set_font(...) return self:_call_func_all("set_font", ...) end 66 | function OutlinedText:set_font_size(...) return self:_call_func_all("set_font_size", ...) end 67 | function OutlinedText:set_visible(...) return self:_call_func_text("set_visible", ...) end 68 | function OutlinedText:show(...) return self:_call_func_text("show", ...) end 69 | function OutlinedText:hide(...) return self:_call_func_text("hide", ...) end 70 | function OutlinedText:set_color(...) return self:_call_func_text("set_color", ...) end 71 | function OutlinedText:set_alpha(...) return self:_call_func_all("set_alpha", ...) end 72 | function OutlinedText:animate(...) return self:_call_func_text("animate", ...) end 73 | function OutlinedText:stop(...) return self:_call_func_text("stop", ...) end 74 | 75 | function OutlinedText:_call_func_all(func, ...) 76 | local results 77 | if self._text[func] then 78 | results = { self._text[func](self._text, ...) } 79 | end 80 | 81 | self:_call_func_bgs(func, ...) 82 | 83 | return unpack(results or {}) 84 | end 85 | 86 | function OutlinedText:_call_func_text(func, ...) 87 | local results 88 | if self._text[func] then 89 | results = { self._text[func](self._text, ...) } 90 | end 91 | 92 | self:_update_visibility() 93 | self:_update_positions() 94 | 95 | return unpack(results or {}) 96 | end 97 | 98 | function OutlinedText:_call_func_bgs(func, ...) 99 | for _, bg in ipairs(self._bgs) do 100 | if bg[func] then 101 | bg[func](bg, ...) 102 | end 103 | end 104 | 105 | self:_update_visibility() 106 | self:_update_positions() 107 | end 108 | 109 | function OutlinedText:_update_positions() 110 | local x, y = self._text:x(), self._text:y() 111 | self._bgs[1]:set_x(x - 1) 112 | self._bgs[1]:set_y(y - 1) 113 | self._bgs[2]:set_x(x + 1) 114 | self._bgs[2]:set_y(y - 1) 115 | self._bgs[3]:set_x(x - 1) 116 | self._bgs[3]:set_y(y + 1) 117 | self._bgs[4]:set_x(x + 1) 118 | self._bgs[4]:set_y(y + 1) 119 | end 120 | 121 | function OutlinedText:_update_visibility() 122 | for _, bg in pairs(self._bgs) do 123 | bg:set_visible(not self._outlines_disabled and self._text:visible()) 124 | end 125 | end 126 | -------------------------------------------------------------------------------- /devlua/Utils/QuickInputMenu.lua: -------------------------------------------------------------------------------- 1 | QuickInputMenu = QuickInputMenu or class() 2 | QuickInputMenu._menu_id_key = "quick_input_menu_id_" 3 | QuickInputMenu._menu_id_index = 0 4 | 5 | function QuickInputMenu:new( ... ) 6 | return self:init( ... ) 7 | end 8 | 9 | function QuickInputMenu:init( title, text, user_text, options, show_immediately, config ) 10 | 11 | QuickInputMenu._menu_id_index = QuickInputMenu._menu_id_index + 1 12 | self.dialog_data = { 13 | id = QuickInputMenu._menu_id_key .. tostring( QuickInputMenu._menu_id_index ), 14 | title = title, 15 | text = text, 16 | user_text = user_text or "", 17 | button_list = {}, 18 | } 19 | 20 | if config then 21 | for k, v in pairs(config) do 22 | self.dialog_data[k] = self.dialog_data[k] or v 23 | end 24 | end 25 | 26 | self.visible = false 27 | 28 | local add_default = false 29 | if (not options) or (options ~= nil and type(options) ~= "table") or (options ~= nil and type(options) == "table" and #options == 0) then 30 | add_default = true 31 | end 32 | if add_default then 33 | local tbl = { 34 | text = "OK", 35 | is_cancel_button = true, 36 | } 37 | table.insert( options, tbl ) 38 | end 39 | 40 | for _, option in ipairs( options ) do 41 | 42 | option.data = option.data 43 | option.callback = option.callback 44 | 45 | local button = {} 46 | local callback_data = { 47 | data = option.data, 48 | callback = option.callback 49 | } 50 | button.text = option.text 51 | button.callback_func = callback( self, self, "_callback", callback_data ) 52 | button.cancel_button = option.is_cancel_button or false 53 | 54 | if option.is_focused_button then 55 | self.dialog_data.focus_button = #self.dialog_data.button_list + 1 56 | end 57 | 58 | table.insert( self.dialog_data.button_list, button ) 59 | 60 | end 61 | 62 | if show_immediately then 63 | self:show() 64 | end 65 | 66 | return self 67 | 68 | end 69 | 70 | function QuickInputMenu:_callback( callback_data, ... ) 71 | 72 | if callback_data.callback then 73 | callback_data.callback( callback_data.data, ... ) 74 | end 75 | 76 | self.visible = false 77 | 78 | end 79 | 80 | function QuickInputMenu:Show() 81 | 82 | if not self.visible then 83 | self.visible = true 84 | managers.system_menu:show_input( self.dialog_data ) 85 | end 86 | 87 | end 88 | 89 | function QuickInputMenu:show() 90 | self:Show() 91 | end 92 | 93 | function QuickInputMenu:Hide() 94 | 95 | if self.visible then 96 | managers.system_menu:close( self.dialog_data.id ) 97 | self.visible = false 98 | end 99 | 100 | end 101 | 102 | function QuickInputMenu:hide() 103 | self:Hide() 104 | end 105 | -------------------------------------------------------------------------------- /loc/RealWeaponNames.json: -------------------------------------------------------------------------------- 1 | { 2 | "bm_w_akm_gold" : "Golden AKMS", 3 | "bm_w_amcar" : "Colt M733", 4 | "bm_w_ak74" : "Izhmash AKS-74", 5 | "bm_w_m4" : "Colt M4A1", 6 | "bm_w_aug" : "Steyr AUG A2", 7 | "bm_w_akm" : "Izhmash AKMS", 8 | "bm_w_g36" : "H&K G36KV", 9 | "bm_w_m14" : "Springfield Armory M1A SOCOM 16", 10 | "bm_w_ak5" : "Bofors Ak 5", 11 | "bm_w_m16" : "Colt M16A4", 12 | "bm_w_s552" : "Swiss Arms SG 552-2", 13 | "bm_w_scar" : "FN SCAR-H STD", 14 | "bm_w_fal" : "FN FAL", 15 | "bm_w_famas" : "FAMAS F1", 16 | "bm_w_galil" : "IMI Galil ARM", 17 | "bm_w_g3" : "H&K G3A3", 18 | "bm_w_l85a2" : "Enfield L85A2", 19 | "bm_w_vhs" : "VHS-D2", 20 | "bm_w_asval" : "AS VAL", 21 | "bm_w_sub2000" : "Kel-tec SUB-2000", 22 | "bm_w_tecci" : "H&K 416C", 23 | "bm_w_contraband" : "H&K 417 w/M203 GL", 24 | "bm_w_ak12" : "Izhmash AK-12", 25 | "bm_w_spas12" : "Franchi SPAS-12", 26 | "bm_w_b682" : "CZ Redhead Deluxe", 27 | "bm_w_r870" : "Remington M870", 28 | "bm_w_saiga" : "Izhmash Saiga-12K", 29 | "bm_w_huntsman" : "Stoeger/IGA Coach", 30 | "bm_w_benelli" : "Benelli M4 Super 90", 31 | "bm_w_ksg" : "Kel-tec KSG", 32 | "bm_w_aa12" : "MPS AA-12 CQB", 33 | "bm_w_boot" : "Winchester Model 1887", 34 | "bm_w_rota" : "Crye Precision SIX12", 35 | "bm_w_ching" : "Springfield Armory M1 Garand", 36 | "bm_w_corgi" : "FN F2000", 37 | "bm_w_komodo" : "IWI X95", 38 | "bm_w_groza" : "OTs-14 Groza", 39 | "bm_w_shak12" : "Izhmash ShAK-12", 40 | 41 | "bm_w_jowi" : "Akimbo Glock 26", 42 | "bm_w_x_1911" : "Akimbo M1911 Lightweight Operator", 43 | "bm_w_x_b92fs" : "Akimbo Beretta 92FS Centurion", 44 | "bm_w_x_deagle" : "Akimbo IMI Desert Eagle Mark XIX", 45 | "bm_w_x_g17" : "Akimbo Glock 17", 46 | "bm_w_x_g22c" : "Akimbo Glock 22C", 47 | "bm_w_x_usp" : "Akimbo USP Tactical .45", 48 | "bm_w_x_packrat" : "Akimbo H&K P30L", 49 | "bm_w_x_chinchilla" : "Akimbo S&W Model 29", 50 | "bm_w_x_basset" : "Akimbo CBRPS Saiga Spike X1S", 51 | "bm_w_x_shrew" : "Akimbo Colt Defender", 52 | "bm_w_x_baka" : "Akimbo IMI Micro Uzi", 53 | "bm_w_x_2006m" : "Akimbo Mateba 2006M", 54 | 55 | "bm_w_gre_m79" : "SA M79 Grenade Launcher", 56 | "bm_w_saw" : "OVE9000", 57 | "bm_w_m134" : "M134 Minigun", 58 | "bm_w_m32" : "MGL Mk 1S", 59 | "bm_w_flamethrower_mk2" : "Flamethrower", 60 | "bm_w_plainsrider" : "Plainsrider Bow", 61 | "bm_w_elastic" : "Compound Bow", 62 | 63 | "bm_w_msr" : "Remington MSR", 64 | "bm_w_r93" : "Blaser R93 LRS2", 65 | "bm_w_m95" : "Barrett M95", 66 | "bm_w_mosin" : "Mosin-Nagant M1907", 67 | "bm_w_winchester1874" : "Winchester Model 1873", 68 | "bm_w_wa2000" : "Walther WA 2000", 69 | "bm_w_model70" : "Winchester Model 70", 70 | "bm_w_desertfox" : "Desert Tech SRSA1", 71 | "bm_w_tti" : "KAC SR-25", 72 | "bm_w_siltstone" : "SVD Dragunov", 73 | "bm_w_sbl" : "Marlin Model 1895", 74 | "bm_w_r700" : "Remington Model 700P", 75 | "bm_w_qbu88" : "Norinco QBU-88", 76 | 77 | "bm_w_rpk" : "Izhmash RPK", 78 | "bm_w_m249" : "FN M249 Para", 79 | "bm_w_hk21" : "H&K 21E", 80 | "bm_w_mg42" : "MG-42", 81 | "bm_w_par" : "FN M240B", 82 | 83 | "bm_w_usp" : "H&K USP Tactical .45", 84 | "bm_w_g22c" : "Glock 22C", 85 | "bm_wp_pis_g26" : "Glock 26", 86 | "bm_w_glock_17" : "Glock 17", 87 | "bm_w_colt_1911" : "M1911 Lightweight Operator", 88 | "bm_w_b92fs" : "Beretta 92FS Centurion", 89 | "bm_w_raging_bull" : "Taurus Raging Bull .44 Magnum", 90 | "bm_w_glock_18c" : "Glock 18C", 91 | "bm_w_deagle" : "IMI Desert Eagle Mark XIX", 92 | "bm_w_ppk" : "Walther PPK", 93 | "bm_w_p226" : "SIG-Sauer P226", 94 | "bm_w_c96" : "Mauser C96", 95 | "bm_w_hs2000" : "Springfield Armory XDM", 96 | "bm_w_peacemaker" : "Single Action Army Cavalry", 97 | "bm_w_mateba" : "Mateba 2006M", 98 | "bm_w_sparrow" : "Jericho 941 RPL", 99 | "bm_w_pl14" : "PL-14 Lebedev", 100 | "bm_w_packrat" : "H&K P30L", 101 | "bm_w_lemming" : "FN Five-Seven", 102 | "bm_w_chinchilla" : "S&W Model 29", 103 | "bm_w_breech" : "Luger P08", 104 | "bm_w_shrew" : "Colt Defender", 105 | "bm_w_legacy" : "H&K P7M13", 106 | "bm_w_beer" : "Beretta 93R", 107 | "bm_w_czech" : "CZ AccuShadow 2", 108 | "bm_w_stech" : "Stechkin Automatic Pistol", 109 | "bm_w_holt" : "Hudson H9", 110 | "bm_w_model3" : "S&W No. 3 Russian Model", 111 | "bm_w_m1911" : "Colt M1911", 112 | "bm_w_type54" : "Tokarev TT-33", 113 | "bm_w_rsh12" : "KBP RSh-12", 114 | 115 | 116 | "bm_w_m1928" : "Thompson M1928A1", 117 | "bm_w_mac10" : "Ingram MAC-10", 118 | "bm_w_mp5" : "H&K MP5A4", 119 | "bm_w_x_mp5" : "Akimbo H&K MP5A4", 120 | "bm_w_mp9" : "B&T MP9", 121 | "bm_w_olympic" : "Olympic Arms K23B Tactical", 122 | "bm_w_akmsu" : "Izhmash AKMSU", 123 | "bm_w_p90" : "FN P90 TR", 124 | "bm_w_m45" : "Carl Gustav M/45", 125 | "bm_w_mp7" : "H&K MP7A2", 126 | "bm_w_tec9" : "Intratec TEC-9", 127 | "bm_w_uzi" : "IMI Uzi", 128 | "bm_w_sterling" : "Sterling L2A1", 129 | "bm_w_cobray" : "Cobray M11/9", 130 | "bm_w_polymer" : "KRISS Vector", 131 | "bm_w_baka" : "IMI Micro Uzi", 132 | "bm_w_x_sr2" : "Akimbo SR-2M Veresk", 133 | "bm_w_sr2" : "SR-2M Veresk", 134 | "bm_w_hajk" : "CZ 805 BREN A1", 135 | "bm_w_schakal" : "H&K UMP-45", 136 | "bm_w_coal" : "PP-19 Bizon", 137 | "bm_w_erma" : "MP40", 138 | "bm_w_shepheard" : "SIG-Sauer MPX", 139 | "bm_w_vityaz" : "PP-19 Vityaz-SN", 140 | "bm_w_pm9" : "Minebea PM-9", 141 | 142 | "bm_w_judge" : "Taurus Judge 4510PLYFS", 143 | "bm_w_serbu" : "Remington M870 Short-Barreled", 144 | "bm_w_striker" : "Sentinel Armsel Striker", 145 | "bm_w_m37" : "Ithaca 37", 146 | "bm_w_basset" : "CBRPS Saiga Spike X1S", 147 | "bm_w_coach" : "Remington Exposed Hammer SxS", 148 | "bm_w_m1897" : "Winchester Model 1897", 149 | "bm_w_m590" : "Mossberg 590 Compact Cruiser", 150 | 151 | "bm_w_rpg7" : "RPG-7", 152 | "bm_w_hunter" : "Avalanche Pistol Crossbow", 153 | "bm_w_china" : "China Lake Grenade Launcher", 154 | "bm_w_arbiter" : "H&K XM-25", 155 | "bm_w_ray" : "M202 FLASH", 156 | "bm_w_slap" : "H&K M320", 157 | 158 | "bm_w_x_coal" : "Akimbo PP-19 Bizon", 159 | "bm_w_x_uzi" : "Akimbo IMI Uzi", 160 | "bm_w_x_sterling" : "Akimbo Sterling L2A1", 161 | "bm_w_x_mp7" : "Akimbo H&K MP7A2", 162 | "bm_w_x_schakal" : "Akimbo H&K UMP-45", 163 | "bm_w_x_m45" : "Akimbo Carl Gustav M/45", 164 | "bm_w_x_judge" : "Akimbo Taurus Judge", 165 | "bm_w_x_tec9" : "Akimbo Intratec TEC-9", 166 | "bm_w_x_rota" : "Akimbo Crye Precision SIX12", 167 | "bm_w_x_mp9" : "Akimbo B&T MP9", 168 | "bm_w_x_m1928" : "Akimbo Thompson M1928A1", 169 | "bm_w_x_cobray" : "Akimbo Cobray M11/9", 170 | "bm_w_x_olympic" : "Akimbo K23B Tactical", 171 | "bm_w_x_scorpion" : "Akimbo Scorpion vz.61", 172 | "bm_w_scorpion" : "Scorpion vz.61", 173 | "bm_w_x_mac10" : "Akimbo Ingram MAC-10", 174 | "bm_w_x_polymer" : "Akimbo KRISS Vector", 175 | "bm_w_x_akmsu" : "Akimbo Izhmash AKMSU", 176 | "bm_w_x_p90" : "Akimbo FN P90 TR", 177 | "bm_w_x_hajk" : "Akimbo CZ 805 BREN A1", 178 | "bm_w_x_g18c" : "Akimbo Glock 18C", 179 | "bm_w_x_breech" : "Akimbo Luger P08", 180 | "bm_w_x_ppk" : "Akimbo Walther PPK", 181 | "bm_w_x_p226" : "Akimbo Sig-Sauer P226", 182 | "bm_w_x_c96" : "Akimbo Mauser C96", 183 | "bm_w_x_hs2000" : "Akimbo SA XDM", 184 | "bm_w_x_rage" : "Akimbo Taurus Raging Bull.44", 185 | "bm_w_x_sparrow" : "Akimbo Jericho 941 RPL", 186 | "bm_w_x_erma" : "Akimbo MP40", 187 | "bm_w_x_shepheard" : "Akimbo SIG-Sauer MPX", 188 | "bm_w_x_pl14" : "Akimbo PL-14 Lebedev", 189 | "bm_w_x_beer" : "Akimbo Beretta 93R", 190 | "bm_w_x_czech" : "Akimbo CZ AccuShadow 2", 191 | "bm_w_x_stech" : "Akimbo Stechkin Automatic Pistol", 192 | "bm_w_x_model3" : "Akimbo S&W No. 3 Russian Model", 193 | "bm_w_x_m1911" : "Akimbo Colt M1911", 194 | "bm_w_x_vityaz" : "Akimbo PP-19 Vityaz-SN", 195 | "bm_w_x_pm9" : "Akimbo Minebea PM-9", 196 | "bm_w_x_type54" : "Akimbo Tokarev TT-33", 197 | 198 | "bm_w_x_maxim9" : "Akimbo Maxim 9", 199 | "bm_w_maxim9" : "Maxim 9", 200 | "bm_w_ultima" : "Kalashnikov MP-155 Ultima", 201 | "bm_w_fmg9" : "Magpul FMG-9", 202 | 203 | "bm_w_hk51b" : "Vollmer HK51B", 204 | "bm_w_scout" : "Steyr Scout", 205 | "bm_w_ms3gl" : "Metal Storm 3GL", 206 | 207 | "bm_w_x_korth" : "Akimbo Korth NXA/NXS", 208 | "bm_w_x_sko12" : "Akimbo SKO-12", 209 | "bm_w_korth" : "Korth NXA/NXS", 210 | "bm_w_sko12" : "SKO-12", 211 | "bm_w_hailstorm" : "Metal Storm Based Fictional Gun", 212 | 213 | "bm_w_victor" : "Springfield SAINT Victor AR-15", 214 | 215 | "bm_w_tkb" : "TKB-059", 216 | "bm_w_hcar" : "Ohio Ordnance HCAR", 217 | "bm_w_contender" : "Thompson/Center G2 Contender", 218 | 219 | "bm_w_kacchainsaw" : "KAC ChainSAW", 220 | "bm_w_supernova" : "Benelli Supernova", 221 | "bm_w_awp" : "AT308" 222 | } -------------------------------------------------------------------------------- /mod.txt: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "VanillaHUDPlus", 3 | "description" : "This is a Mod Collection of HUD altering scripts, as well as quality of life changes to the game and its menus", 4 | "author" : "Test1, LT71 (Bunnie( 2)), Kamikaze94, BangL", 5 | "version" : "3.3.7.43", 6 | "priority" : 1, 7 | "blt_version" : 2, 8 | "updates": [ 9 | { 10 | "identifier": "vanhudplus", 11 | "host": { 12 | "meta": "https://gitlab.com/steam-test1/alternative-updates/-/raw/main/updates_metas/meta_vanhudplus.json" 13 | } 14 | } 15 | ], 16 | "hooks" : [ 17 | { "hook_id" : "lib/setups/setup", "script_path" : "Core.lua" }, 18 | { "hook_id" : "lib/managers/menumanager", "script_path" : "Core.lua" }, 19 | { "hook_id" : "lib/managers/menumanagerdialogs", "script_path" : "Core.lua" }, 20 | { "hook_id" : "lib/managers/chatmanager", "script_path" : "Core.lua" }, 21 | { "hook_id" : "lib/managers/crimenetmanager", "script_path" : "Core.lua" }, 22 | { "hook_id" : "lib/managers/localizationmanager", "script_path" : "Core.lua" }, 23 | { "hook_id" : "lib/managers/experiencemanager", "script_path" : "Core.lua" }, 24 | { "hook_id" : "lib/managers/moneymanager", "script_path" : "Core.lua" }, 25 | { "hook_id" : "lib/managers/multiprofilemanager", "script_path" : "Core.lua" }, 26 | { "hook_id" : "lib/managers/crimespreemanager", "script_path" : "Core.lua" }, 27 | { "hook_id" : "lib/managers/hudmanager", "script_path" : "Core.lua" }, 28 | { "hook_id" : "lib/managers/hudmanagerpd2", "script_path" : "Core.lua" }, 29 | { "hook_id" : "lib/managers/statisticsmanager", "script_path" : "Core.lua" }, 30 | { "hook_id" : "lib/managers/objectinteractionmanager", "script_path" : "Core.lua" }, 31 | { "hook_id" : "lib/managers/missionassetsmanager", "script_path" : "Core.lua" }, 32 | { "hook_id" : "lib/managers/playermanager", "script_path" : "Core.lua" }, 33 | { "hook_id" : "lib/managers/preplanningmanager", "script_path" : "Core.lua" }, 34 | { "hook_id" : "lib/managers/enemymanager", "script_path" : "Core.lua" }, 35 | { "hook_id" : "lib/managers/hud/huddriving", "script_path" : "Core.lua" }, 36 | { "hook_id" : "lib/managers/hud/hudteammate", "script_path" : "Core.lua" }, 37 | { "hook_id" : "lib/managers/hud/hudtemp", "script_path" : "Core.lua" }, 38 | { "hook_id" : "lib/managers/hud/hudassaultcorner", "script_path" : "Core.lua" }, 39 | { "hook_id" : "lib/managers/hud/hudobjectives", "script_path" : "Core.lua" }, 40 | { "hook_id" : "lib/managers/hud/hudheisttimer", "script_path" : "Core.lua" }, 41 | { "hook_id" : "lib/managers/hud/hudchat", "script_path" : "Core.lua" }, 42 | { "hook_id" : "lib/managers/hud/newhudstatsscreen", "script_path" : "Core.lua" }, 43 | { "hook_id" : "lib/managers/hud/hudinteraction", "script_path" : "Core.lua" }, 44 | { "hook_id" : "lib/managers/hud/hudsuspicion", "script_path" : "Core.lua" }, 45 | { "hook_id" : "lib/managers/hud/hudhitdirection", "script_path" : "Core.lua" }, 46 | { "hook_id" : "lib/managers/hud/hudwaitinglegend", "script_path" : "Core.lua" }, 47 | { "hook_id" : "lib/managers/group_ai_states/groupaistatebase", "script_path" : "Core.lua" }, 48 | { "hook_id" : "lib/managers/menu/blackmarketgui", "script_path" : "Core.lua" }, 49 | { "hook_id" : "lib/managers/menu/contractboxgui", "script_path" : "Core.lua" }, 50 | { "hook_id" : "lib/managers/menu/crimespreecontractboxgui", "script_path" : "Core.lua" }, 51 | { "hook_id" : "lib/managers/menu/crimespreedetailsmenucomponent", "script_path" : "Core.lua" }, 52 | { "hook_id" : "lib/managers/menu/missionbriefinggui", "script_path" : "Core.lua" }, 53 | { "hook_id" : "lib/managers/menu/multiprofileitemgui", "script_path" : "Core.lua" }, 54 | { "hook_id" : "lib/managers/menu/stageendscreengui", "script_path" : "Core.lua" }, 55 | { "hook_id" : "lib/managers/menu/lootdropscreengui", "script_path" : "Core.lua" }, 56 | { "hook_id" : "lib/managers/menu/skilltreeguinew", "script_path" : "Core.lua" }, 57 | { "hook_id" : "lib/managers/menu/playerinventorygui", "script_path" : "Core.lua" }, 58 | { "hook_id" : "lib/managers/menu/renderers/menunodeskillswitchgui", "script_path" : "Core.lua" }, 59 | { "hook_id" : "lib/managers/player/smokescreeneffect", "script_path" : "Core.lua" }, 60 | { "hook_id" : "lib/modifiers/boosts/gagemodifiermeleeinvincibility", "script_path" : "Core.lua" }, 61 | { "hook_id" : "lib/modifiers/boosts/gagemodifierlifesteal", "script_path" : "Core.lua" }, 62 | { "hook_id" : "lib/network/handlers/unitnetworkhandler", "script_path" : "Core.lua" }, 63 | { "hook_id" : "lib/units/props/timergui", "script_path" : "Core.lua" }, 64 | { "hook_id" : "lib/units/props/digitalgui", "script_path" : "Core.lua" }, 65 | { "hook_id" : "lib/units/props/drill", "script_path" : "Core.lua" }, 66 | { "hook_id" : "lib/units/props/securitylockgui", "script_path" : "Core.lua" }, 67 | { "hook_id" : "lib/units/props/securitycamera", "script_path" : "Core.lua" }, 68 | { "hook_id" : "lib/units/civilians/civiliandamage", "script_path" : "Core.lua" }, 69 | { "hook_id" : "lib/units/enemies/cop/copdamage", "script_path" : "Core.lua" }, 70 | { "hook_id" : "lib/units/cameras/fpcameraplayerbase", "script_path" : "Core.lua" }, 71 | { "hook_id" : "lib/units/equipment/ammo_bag/ammobagbase", "script_path" : "Core.lua" }, 72 | { "hook_id" : "lib/units/equipment/bodybags_bag/bodybagsbagbase", "script_path" : "Core.lua" }, 73 | { "hook_id" : "lib/units/equipment/doctor_bag/doctorbagbase", "script_path" : "Core.lua" }, 74 | { "hook_id" : "lib/units/equipment/first_aid_kit/firstaidkitbase", "script_path" : "Core.lua" }, 75 | { "hook_id" : "lib/units/equipment/ecm_jammer/ecmjammerbase", "script_path" : "Core.lua" }, 76 | { "hook_id" : "lib/units/equipment/grenade_crate/grenadecratebase", "script_path" : "Core.lua" }, 77 | { "hook_id" : "lib/units/equipment/sentry_gun/sentrygunbase", "script_path" : "Core.lua" }, 78 | { "hook_id" : "lib/units/equipment/sentry_gun/sentrygundamage", "script_path" : "Core.lua" }, 79 | { "hook_id" : "lib/units/interactions/interactionext", "script_path" : "Core.lua" }, 80 | { "hook_id" : "lib/units/weapons/akimboweaponbase", "script_path" : "Core.lua" }, 81 | { "hook_id" : "lib/units/weapons/akimboshotgunbase", "script_path" : "Core.lua" }, 82 | { "hook_id" : "lib/units/weapons/sentrygunweapon", "script_path" : "Core.lua" }, 83 | { "hook_id" : "lib/units/weapons/weapongadgetbase", "script_path" : "Core.lua" }, 84 | { "hook_id" : "lib/units/weapons/weaponlaser", "script_path" : "Core.lua" }, 85 | { "hook_id" : "lib/units/weapons/weaponflashlight", "script_path" : "Core.lua" }, 86 | { "hook_id" : "lib/units/weapons/raycastweaponbase", "script_path" : "Core.lua" }, 87 | { "hook_id" : "lib/units/weapons/newraycastweaponbase", "script_path" : "Core.lua" }, 88 | { "hook_id" : "lib/units/weapons/npcraycastweaponbase", "script_path" : "Core.lua" }, 89 | { "hook_id" : "lib/units/weapons/newnpcraycastweaponbase", "script_path" : "Core.lua" }, 90 | { "hook_id" : "lib/units/beings/player/playerdamage", "script_path" : "Core.lua" }, 91 | { "hook_id" : "lib/units/beings/player/playermovement", "script_path" : "Core.lua" }, 92 | { "hook_id" : "lib/units/beings/player/playerinventory", "script_path" : "Core.lua" }, 93 | { "hook_id" : "lib/units/beings/player/huskplayermovement", "script_path" : "Core.lua" }, 94 | { "hook_id" : "lib/units/beings/player/states/playercivilian", "script_path" : "Core.lua" }, 95 | { "hook_id" : "lib/units/beings/player/states/playerdriving", "script_path" : "Core.lua" }, 96 | { "hook_id" : "lib/units/beings/player/states/playerstandard", "script_path" : "Core.lua" }, 97 | { "hook_id" : "lib/units/beings/player/states/playermaskoff", "script_path" : "Core.lua" }, 98 | { "hook_id" : "lib/units/beings/player/states/playerbleedout", "script_path" : "Core.lua" }, 99 | { "hook_id" : "lib/units/vehicles/vehicledamage", "script_path" : "Core.lua" }, 100 | { "hook_id" : "lib/units/vehicles/vehicledrivingext", "script_path" : "Core.lua" }, 101 | { "hook_id" : "lib/utils/temporarypropertymanager", "script_path" : "Core.lua" }, 102 | { "hook_id" : "lib/player_actions/skills/playeractionbloodthirstbase", "script_path" : "Core.lua" }, 103 | { "hook_id" : "lib/player_actions/skills/playeractionexperthandling", "script_path" : "Core.lua" }, 104 | { "hook_id" : "lib/player_actions/skills/playeractionshockandawe", "script_path" : "Core.lua" }, 105 | { "hook_id" : "lib/player_actions/skills/playeractiondireneed", "script_path" : "Core.lua" }, 106 | { "hook_id" : "lib/player_actions/skills/playeractionunseenstrike", "script_path" : "Core.lua" }, 107 | { "hook_id" : "lib/player_actions/skills/playeractiontriggerhappy", "script_path" : "Core.lua" }, 108 | { "hook_id" : "lib/player_actions/skills/playeractiontagteam", "script_path" : "Core.lua" }, 109 | { "hook_id" : "lib/states/ingamedriving", "script_path" : "Core.lua" }, 110 | { "hook_id" : "lib/states/ingamearrested", "script_path" : "Core.lua" }, 111 | { "hook_id" : "lib/states/ingamewaitingforplayers", "script_path" : "Core.lua" }, 112 | { "hook_id" : "lib/tweak_data/tweakdata", "script_path" : "Core.lua" }, 113 | { "hook_id" : "lib/tweak_data/guitweakdata", "script_path" : "Core.lua" }, 114 | { "hook_id" : "lib/tweak_data/timespeedeffecttweakdata", "script_path" : "Core.lua" }, 115 | { "hook_id" : "core/lib/managers/menu/items/coremenuitemslider", "script_path" : "Core.lua" }, 116 | { "hook_id" : "core/lib/managers/subtitle/coresubtitlepresenter", "script_path" : "Core.lua" }, 117 | { "hook_id" : "lib/managers/platformmanager", "script_path" : "Core.lua" }, 118 | { "hook_id" : "lib/managers/skirmishmanager", "script_path" : "Core.lua" }, 119 | { "hook_id" : "core/lib/managers/coreenvironmentcontrollermanager", "script_path" : "Core.lua" }, 120 | { "hook_id" : "lib/managers/menu/preplanningmapgui", "script_path" : "Core.lua" }, 121 | { "hook_id" : "lib/managers/hud/hudhitconfirm", "script_path" : "Core.lua" }, 122 | { "hook_id" : "lib/units/contourext", "script_path" : "Core.lua" }, 123 | { "hook_id" : "lib/managers/menu/items/contractbrokerheistitem", "script_path" : "Core.lua" }, 124 | { "hook_id" : "lib/network/base/hostnetworksession", "script_path" : "Core.lua" }, 125 | { "hook_id" : "lib/managers/hud/hudplayercustody", "script_path" : "Core.lua" }, 126 | { "hook_id" : "lib/units/weapons/shotgun/shotgunbase", "script_path" : "Core.lua" }, 127 | { "hook_id" : "lib/tweak_data/weapontweakdata", "script_path" : "Core.lua" }, 128 | { "hook_id" : "lib/tweak_data/levelstweakdata", "script_path" : "Core.lua" }, 129 | { "hook_id" : "lib/network/matchmaking/networkmatchmakingsteam", "script_path" : "Core.lua" }, 130 | { "hook_id" : "lib/managers/menu/nodes/menunodeserverlist", "script_path" : "Core.lua" }, 131 | { "hook_id" : "lib/managers/menu/renderers/menunodetablegui", "script_path" : "Core.lua" }, 132 | { "hook_id" : "lib/managers/hud/hudpresenter", "script_path" : "Core.lua" }, 133 | { "hook_id" : "core/lib/managers/menu/reference_input/coremenuinput", "script_path" : "Core.lua" }, 134 | { "hook_id" : "lib/managers/menu/menucomponentmanager", "script_path" : "Core.lua" }, 135 | { "hook_id" : "lib/network/matchmaking/networkmatchmakingepic", "script_path" : "Core.lua" }, 136 | 137 | { "hook_id" : "lib/entry", "script_path" : "Core.lua" }, 138 | { "hook_id" : "lib/managers/systemmenumanager", "script_path" : "Core.lua" }, 139 | { "hook_id" : "lib/managers/dialogs/specializationdialog", "script_path" : "Core.lua" }, 140 | { "hook_id" : "lib/managers/menu/specializationboxgui", "script_path" : "Core.lua" } 141 | ] 142 | } 143 | --------------------------------------------------------------------------------