├── Core.lua
├── OptionMenus.lua
├── WolfHUDTweakData.lua
├── assets
├── assets.xml
├── drivinghud
│ ├── bike.texture
│ ├── blackhawk.texture
│ ├── boat.texture
│ ├── falcogini.texture
│ ├── forklift.texture
│ ├── golfcart.texture
│ ├── legend.texture
│ ├── longfellow.texture
│ └── truck.texture
└── hudlist
│ ├── mask_up.texture
│ └── weapon_charge.texture
├── docs
├── ISSUE_TEMPLATE.md
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── PULL_REQUEST_TEMPLATE.md
└── README.md
├── loc
├── RealWeaponNames.json
├── chinese.json
├── dutch.json
├── english.json
├── french.json
├── german.json
├── italian.json
├── korean.json
├── portuguese.json
├── russian.json
└── spanish.json
├── lua
├── AdvAssault.lua
├── BurstFire.lua
├── BuyAllAsset.lua
├── ContractHeat.lua
├── CustomHUD.lua
├── CustomWaypoints.lua
├── DamageIndicator.lua
├── DamagePopup.lua
├── DownCounter.lua
├── DrivingHUD.lua
├── EnemyHealthbar.lua
├── EnhancedCrewLoadout.lua
├── EnhancedObjective.lua
├── EquipmentTweaks.lua
├── GameInfoManager.lua
├── HUDChat.lua
├── HUDList.lua
├── Interaction.lua
├── KillCounter.lua
├── MenuTweaks.lua
├── NetworkHandler.lua
├── NumbericSuspicion.lua
├── PacifiedCivs.lua
├── PrePlanManager.lua
├── ProfileMenu.lua
├── RichPresence.lua
├── Scripts.lua
├── TabStats.lua
├── Utils
│ ├── InputDialog.lua
│ ├── LoadoutPanel.lua
│ ├── OutlinedText.lua
│ └── QuickInputMenu.lua
├── VanillaHUD.lua
├── WaypointsManager.lua
└── WeaponGadgets.lua
├── mod.txt
├── supermod.xml
└── wolfhud.png
/assets/assets.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/assets/drivinghud/bike.texture:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kamikaze94/WolfHUD/1b2736f9290062fe73ef3f2f10b913255def4905/assets/drivinghud/bike.texture
--------------------------------------------------------------------------------
/assets/drivinghud/blackhawk.texture:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kamikaze94/WolfHUD/1b2736f9290062fe73ef3f2f10b913255def4905/assets/drivinghud/blackhawk.texture
--------------------------------------------------------------------------------
/assets/drivinghud/boat.texture:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kamikaze94/WolfHUD/1b2736f9290062fe73ef3f2f10b913255def4905/assets/drivinghud/boat.texture
--------------------------------------------------------------------------------
/assets/drivinghud/falcogini.texture:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kamikaze94/WolfHUD/1b2736f9290062fe73ef3f2f10b913255def4905/assets/drivinghud/falcogini.texture
--------------------------------------------------------------------------------
/assets/drivinghud/forklift.texture:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kamikaze94/WolfHUD/1b2736f9290062fe73ef3f2f10b913255def4905/assets/drivinghud/forklift.texture
--------------------------------------------------------------------------------
/assets/drivinghud/golfcart.texture:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kamikaze94/WolfHUD/1b2736f9290062fe73ef3f2f10b913255def4905/assets/drivinghud/golfcart.texture
--------------------------------------------------------------------------------
/assets/drivinghud/legend.texture:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kamikaze94/WolfHUD/1b2736f9290062fe73ef3f2f10b913255def4905/assets/drivinghud/legend.texture
--------------------------------------------------------------------------------
/assets/drivinghud/longfellow.texture:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kamikaze94/WolfHUD/1b2736f9290062fe73ef3f2f10b913255def4905/assets/drivinghud/longfellow.texture
--------------------------------------------------------------------------------
/assets/drivinghud/truck.texture:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kamikaze94/WolfHUD/1b2736f9290062fe73ef3f2f10b913255def4905/assets/drivinghud/truck.texture
--------------------------------------------------------------------------------
/assets/hudlist/mask_up.texture:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kamikaze94/WolfHUD/1b2736f9290062fe73ef3f2f10b913255def4905/assets/hudlist/mask_up.texture
--------------------------------------------------------------------------------
/assets/hudlist/weapon_charge.texture:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kamikaze94/WolfHUD/1b2736f9290062fe73ef3f2f10b913255def4905/assets/hudlist/weapon_charge.texture
--------------------------------------------------------------------------------
/docs/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 |
3 | Please answer the following questions for yourself before submitting an issue.
4 | **YOU MAY DELETE THE PREREQUISITES SECTION.**
5 |
6 | - [ ] I am running the latest version
7 | - [ ] I made sure this issue doesn't persist without this mod
8 | - [ ] I checked to make sure that this issue has not already been filed
9 |
10 | # Expected Behavior
11 |
12 | Please describe the behavior you are expecting
13 |
14 | # Current Behavior
15 |
16 | What is the current behavior?
17 |
18 | # Failure Information (for bugs)
19 | #### Please help provide information about the failure if this is a bug. If it is not a bug, please remove the rest of this template.
20 |
21 | ## Steps to Reproduce
22 |
23 | Please provide detailed steps for reproducing the issue.
24 |
25 | 1. step 1
26 | 2. step 2
27 | 3. you get it...
28 |
29 | ## Context
30 |
31 | Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions.
32 |
33 | * Operating System:
34 | * BLT version:
35 | * Other mods installed:
36 | * ...
37 |
38 | ## BLT log
39 |
40 | Please include the contents of your BLT log around the time the bug appeared.
41 | You can find the BLT log inside your games "/mods/logs/" folder.
42 |
43 |
44 | BLT Log
45 |
46 | [Please paste your BLT log here.]
47 |
48 |
49 |
50 | ## Crash log(s)
51 |
52 | If the bug is causing a crash, please provide the contents of your crashlog.
53 | You can find your crashlog in "%localappdata%/Payday 2/crash.txt"
54 |
55 |
56 | Crash.txt
57 |
58 | [Please paste your crash log here.]
59 |
60 |
61 |
--------------------------------------------------------------------------------
/docs/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 |
5 | ---
6 |
7 | # Prerequisites
8 |
9 | Please answer the following questions for yourself before submitting an issue.
10 | **YOU MAY DELETE THE PREREQUISITES SECTION.**
11 |
12 | - [ ] I am running the latest version
13 | - [ ] I made sure this issue doesn't persist without this mod
14 | - [ ] I checked to make sure that this issue has not already been filed
15 |
16 | # Expected Behavior
17 |
18 | Please describe the behavior you are expecting
19 |
20 | # Current Behavior
21 |
22 | What is the current behavior?
23 |
24 | # Failure Information
25 |
26 | ## Steps to Reproduce
27 |
28 | Please provide detailed steps for reproducing the issue.
29 |
30 | 1. step 1
31 | 2. step 2
32 | 3. you get it...
33 |
34 | ## Context
35 |
36 | Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions.
37 |
38 | * Operating System:
39 | * BLT version:
40 | * Other mods installed:
41 | * ...
42 |
43 | ## BLT log
44 |
45 | Please include the contents of your BLT log around the time the bug appeared.
46 | You can find the BLT log inside your games "/mods/logs/" folder.
47 |
48 |
49 | BLT Log
50 |
51 | [Please paste your BLT log here.]
52 |
53 |
54 |
55 | ## Crash log(s)
56 |
57 | If the bug is causing a crash, please provide the contents of your crashlog.
58 | You can find your crashlog in "%localappdata%/Payday 2/crash.txt"
59 |
60 |
61 | Crash.txt
62 |
63 | [Please paste your crash log here.]
64 |
65 |
66 |
--------------------------------------------------------------------------------
/docs/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 |
5 | ---
6 |
7 | # Prerequisites
8 |
9 | Please answer the following questions for yourself before submitting an issue.
10 | **YOU MAY DELETE THE PREREQUISITES SECTION.**
11 |
12 | - [ ] I am running the latest version
13 | - [ ] I made sure this issue doesn't persist without this mod
14 | - [ ] I checked to make sure that this issue has not already been filed
15 |
16 |
17 | # Current Behavior
18 |
19 | What is the current behavior?
20 |
21 | # Expected Behavior
22 |
23 | Please describe the behavior you are expecting
24 |
--------------------------------------------------------------------------------
/docs/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | # Description
2 |
3 | [Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.]
4 |
5 | Fixes # [issue]
6 |
7 | ## Type of change
8 |
9 | Please delete options that are not relevant.
10 |
11 | - [ ] Bug fix (non-breaking change which fixes an issue)
12 | - [ ] New feature (non-breaking change which adds functionality)
13 | - [ ] This change requires a documentation update
14 |
15 | # How Has This Been Tested?
16 |
17 | Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration
18 |
19 | - [ ] Test A
20 | - [ ] Test B
21 |
22 |
23 | # Checklist:
24 |
25 | - [ ] My changes generate no new warnings
26 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # WolfHUD
2 |
3 | ## Description
4 |
5 | This is a Mod collection of several useful HUD altering mods.
6 | I've modified them and added features which I felt that were either needed or useful, or both.
7 | It was originally a recreated and updated version of GageHUD, since it was really painful to maintain with all the mixed up files.
8 | Over time I added more and more useful scripts and currently it becomes kind of an All-in-One solution...
9 | Not sure if I want it to become that, but at least I added ingame Options to turn off functions you don't like. ;)
10 |
11 | I got the permission from **Seven, ViciousWalrus, Undeadsewer, FishTaco, friendIyfire and Terminator01** for the use of their scripts and from N**ervatel Hanging Closet Monster** for using his icons.
12 |
13 | **Huge thanks to [Kampfhörnchen](http://modworkshop.net/member.php?action=profile&uid=19364) for creating a better logo and a banner.**
14 |
15 | ## Preview
16 |
17 |
18 |
19 | 
20 | (Click to view bigger version)
21 |
22 |
23 | ## Requirements
24 |
25 | To make this mod work you will need to install __[SuperBLT](https://superblt.znix.xyz)__.
26 |
27 | *Note: Regular BLT is, with Version 3.00 forward, no longer supported.*
28 |
29 | ## Installation (Direct Download)
30 |
31 | 1. [Download WolfHUD from here](https://github.com/Kamikaze94/WolfHUD/archive/master.zip) or clone the master branch.
32 | 2. Open the downloaded archive, using WinRAR or 7Zip
33 | 3. Extract the **WolfHUD-master** folder into your 'PAYDAY 2/mods' folder
34 | 4. Start the game once. It will prompt you to update Federal Inventory.
35 |
36 | ## AutoUpdates
37 |
38 | This mod uses SuperBLTs custom update URL support.
39 | When an update is available, you'll be notified about it in the game.
40 | The update can be downloaded and installed through SuperBLTs download manager.
41 | *(The installation-folder needs to be named **WolfHUD-master** for autoupdates to work!)*
42 |
43 | ## If you don't want/like Inventory Icons
44 |
45 | To remove "Federal Inventory" go to your **PAYDAY 2/assets/mod_overrides/Federal Inventory** folder and delete it.
46 | Don't download the "update" for it, obviously.
47 |
48 | ## Bug reports
49 |
50 | If you encounter any bugs, feel free to post about it on the issues tab!
51 | Please try to provide information from your crashlog and the actions you and your teammates were doing, when you crashed. ;)
52 | The Crashlog can be found at **%localappdata%/PAYDAY 2/crashlog.txt**.
53 | The BLT log can be found at **PAYDAY 2/mods/logs/**.
54 |
55 | ## Included Mods
56 |
57 | * [CustomHUD](https://bitbucket.org/pjal3urb/customhud/src) made by **Seven** modified by **me**
58 | * [HudPanelList](https://bitbucket.org/pjal3urb/hudlist/src/) made by **Seven**, modified by **me**
59 | * [KillCounter](https://bitbucket.org/pjal3urb/customhud/src) made by **Seven**, modified by **me**
60 | * [Accuracy Plugin](https://bitbucket.org/pjal3urb/customhud/src) made by **Seven**, modified by **me**
61 | * [ToggleInteract](https://bitbucket.org/pjal3urb/toggleinteract/src) made by **Seven**, modified by **Iron Predator** and **me**
62 | * [DoubleTap Granades](https://bitbucket.org/pjal3urb/doubletapgrenades/src) made by **Seven**
63 | * [AutoPickup](https://bitbucket.org/pjal3urb/autopickup/src) made by **Seven**
64 | * [WeaponGadgets](https://bitbucket.org/pjal3urb/gadgets) made by **Seven**
65 | * [Remember Gadget State](https://bitbucket.org/pjal3urb/persistentgadgets/src) made by **Seven**
66 | * [TabStats](https://steamcommunity.com/app/218620/discussions/15/618463738399320805/) made by **friendIyfire**
67 | * [Numeric Suspicion](https://github.com/cjur3/GageHud) made by **friendIyfire**, updated by **me**
68 | * Angeled Sight Visualisation, made by **me** (based on HoxHUD P4.1)
69 | * [EnemyHealthbar](https://modworkshop.net/mydownloads.php?action=view_down&did=15157) made by **Undeadsewer**, modified by **me**
70 | * AdvAssault made by **me** (based on HoxHUD P4.1)
71 | * Dynamic Damage Indicator made by **me**
72 | * DamagePopups made by **me** (Uses [WaypointsManager](https://bitbucket.org/pjal3urb/waypoints) made by **Seven**)
73 | * [BurstFire](https://bitbucket.org/pjal3urb/burstfire/src) made by **Seven**
74 | * [Real Ammo](https://modworkshop.net/mydownloads.php?action=view_down&did=15108) made by **FishTaco**, modified by **me**
75 | * [No Spam](http://steamcommunity.com/app/218620/discussions/15/618457398976607330/) made by **Ahab**, **Seven**, **AmEyeBlind** & **money123451**, updated by **me**
76 | * [DrivingHUD](https://modworkshop.net/mydownloads.php?action=view_down&did=12982) made by **ViciousWalrus** and **Great Big Bushy Beard**, rewritten by **me**
77 | * [Real Weapon Names](http://modworkshop.net/mydownloads.php?action=view_down&did=15433) made by **(AD) Jaqueto**, updated by **Terminator01**
78 | * [Buy all Assets](http://steamcommunity.com/app/218620/discussions/15/618458030689719683/) made by **=TBM= BangL**, rewritten by **me**
79 | * PrePlanManager made by **me**
80 | * ProfileMenu made by **me**
81 | * Equipment Tweaks made by **me**
82 | * Smaller Menu Tweaks
83 | * [Always show Mod Icons](http://modworkshop.net/mydownloads.php?action=view_down&did=13975) made by **Slippai**, updated by **me**
84 | * [Slider Values](http://modworkshop.net/mydownloads.php?action=view_down&did=14800) made by **Snh20**, modified by **me**
85 | * Show Weapon Names made by **me**
86 | * Show Skill Names made by **me**
87 | * [Skillset Info](http://modworkshop.net/mydownloads.php?action=view_down&did=15294) made by **Fooksie**
88 | * Increased the maximum chars of custom Weapon/Mask/Skillset names
89 | * Federal Inventory (Mod Override), made by **Nervatel Hanging Closet Monster** and **Luffy**, updated by **me**
90 | * [Weapon Icons](https://modworkshop.net/mydownloads.php?action=view_down&did=14240), [Melee Icons](http://modworkshop.net/mydownloads.php?action=view_down&did=13910) and [Mask Icons](http://modworkshop.net/mydownloads.php?action=view_down&did=13911) made by **Nervatel Hanging Closet Monster**
91 | * [Throwables, Equipment, Armor and Heister Portraits](http://modworkshop.net/mydownloads.php?action=view_down&did=13916) made by **Luffy**
92 |
93 | ## Localizations
94 |
95 | * English made by **me**
96 | * German made by **me**
97 | * Russian made by **chrom[K]a**, **Magic3000** & **MEXAHOTABOP**
98 | * Korean made by **Я!zu**
99 | * Spanish made by **papydeath95** & **ElReyZero1201**
100 | * Chinese made by **zhongfly** & **CoolLKK**
101 | * French made by **Elise MRX (La Mule)**
102 | * Portuguese made by **Kazenin (Aldo Raine)**
103 | * Italian made by **LeecanIt**
104 | * Dutch made by **Azoraqua**
105 |
106 | Big credit goes to all of you!
107 | Without your awesome mods, I would have quitted this game a long time ago!
108 | **If I forgot to mention you, I'm really sorry.
109 | Please feel free to contact me, so I can credit you, for the awesome stuff you have made :)**
110 |
--------------------------------------------------------------------------------
/loc/RealWeaponNames.json:
--------------------------------------------------------------------------------
1 | {
2 | "bm_w_akm_gold" : "Golden AKMS",
3 | "bm_w_amcar" : "Colt Model 733",
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 | "bm_w_scout" : "Steyr Scout",
77 |
78 | "bm_w_rpk" : "Izhmash RPK",
79 | "bm_w_m249" : "FN M249 Para",
80 | "bm_w_hk21" : "H&K 21E",
81 | "bm_w_mg42" : "MG-42",
82 | "bm_w_par" : "FN M240B",
83 | "bm_w_hk51b" : "H&K 51 Bravo",
84 |
85 | "bm_w_usp" : "H&K USP Tactical .45",
86 | "bm_w_g22c" : "Glock 22C",
87 | "bm_wp_pis_g26" : "Glock 26",
88 | "bm_w_glock_17" : "Glock 17",
89 | "bm_w_colt_1911" : "M1911 Lightweight Operator",
90 | "bm_w_b92fs" : "Beretta 92FS Centurion",
91 | "bm_w_raging_bull" : "Taurus Raging Bull .44 Magnum",
92 | "bm_w_glock_18c" : "Glock 18C",
93 | "bm_w_deagle" : "IMI Desert Eagle Mark XIX",
94 | "bm_w_ppk" : "Walther PPK",
95 | "bm_w_p226" : "SIG-Sauer P226",
96 | "bm_w_c96" : "Mauser C96",
97 | "bm_w_hs2000" : "Springfield Armory XDM",
98 | "bm_w_peacemaker" : "Single Action Army Cavalry",
99 | "bm_w_mateba" : "Mateba 2006M",
100 | "bm_w_sparrow" : "Jericho 941 RPL",
101 | "bm_w_pl14" : "PL-14 Lebedev",
102 | "bm_w_packrat" : "H&K P30L",
103 | "bm_w_lemming" : "FN Five-Seven",
104 | "bm_w_chinchilla" : "S&W Model 29",
105 | "bm_w_breech" : "Luger P08",
106 | "bm_w_shrew" : "Colt Defender",
107 | "bm_w_legacy" : "H&K P7M13",
108 | "bm_w_beer" : "Beretta 93R",
109 | "bm_w_czech" : "CZ AccuShadow 2",
110 | "bm_w_stech" : "Stechkin Automatic Pistol",
111 | "bm_w_holt" : "Hudson H9",
112 | "bm_w_model3" : "S&W No. 3 Russian Model",
113 | "bm_w_m1911" : "Colt M1911",
114 | "bm_w_type54" : "Tokarev TT-33",
115 | "bm_w_rsh12" : "KBP RSh-12",
116 | "bm_w_maxim9" : "Maxim 9",
117 |
118 |
119 | "bm_w_m1928" : "Thompson M1928A1",
120 | "bm_w_mac10" : "Ingram MAC-10",
121 | "bm_w_mp5" : "H&K MP5A4",
122 | "bm_w_x_mp5" : "Akimbo H&K MP5A4",
123 | "bm_w_mp9" : "B&T MP9",
124 | "bm_w_olympic" : "Olympic Arms K23B Tactical",
125 | "bm_w_akmsu" : "Izhmash AKMSU",
126 | "bm_w_p90" : "FN P90 TR",
127 | "bm_w_m45" : "Carl Gustav M/45",
128 | "bm_w_mp7" : "H&K MP7A2",
129 | "bm_w_tec9" : "Intratec TEC-9",
130 | "bm_w_scorpion" : "Scorpion vz.61",
131 | "bm_w_uzi" : "IMI Uzi",
132 | "bm_w_sterling" : "Sterling L2A1",
133 | "bm_w_cobray" : "Cobray M11/9",
134 | "bm_w_polymer" : "KRISS Vector",
135 | "bm_w_baka" : "IMI Micro Uzi",
136 | "bm_w_x_sr2" : "Akimbo SR-2M Veresk",
137 | "bm_w_sr2" : "SR-2M Veresk",
138 | "bm_w_hajk" : "CZ 805 BREN A1",
139 | "bm_w_schakal" : "H&K UMP-45",
140 | "bm_w_coal" : "PP-19 Bizon",
141 | "bm_w_erma" : "MP40",
142 | "bm_w_shepheard" : "SIG-Sauer MPX",
143 | "bm_w_vityaz" : "PP-19 Vityaz-SN",
144 | "bm_w_pm9" : "Minebea PM-9",
145 | "bm_w_fmg9" : "Magpul FMG-9",
146 |
147 | "bm_w_judge" : "Taurus Judge 4510PLYFS",
148 | "bm_w_serbu" : "Remington M870 Short-Barreled",
149 | "bm_w_striker" : "Sentinel Armsel Striker",
150 | "bm_w_m37" : "Ithaca 37",
151 | "bm_w_basset" : "CBRPS Saiga Spike X1S",
152 | "bm_w_coach" : "Remington Exposed Hammer SxS",
153 | "bm_w_m1897" : "Winchester Model 1897",
154 | "bm_w_m590" : "Mossberg 590 Compact Cruiser",
155 | "bm_w_ultima" : "Kalashnikov MP-155 Ultima",
156 |
157 | "bm_w_rpg7" : "RPG-7",
158 | "bm_w_hunter" : "Avalanche Pistol Crossbow",
159 | "bm_w_china" : "China Lake Grenade Launcher",
160 | "bm_w_arbiter" : "H&K XM-25",
161 | "bm_w_ray" : "M202 FLASH",
162 | "bm_w_slap" : "H&K M320",
163 | "bm_w_ms3gl" : "Metal Storm 3GL",
164 |
165 | "bm_w_x_coal" : "Akimbo PP-19 Bizon",
166 | "bm_w_x_uzi" : "Akimbo IMI Uzi",
167 | "bm_w_x_sterling" : "Akimbo Sterling L2A1",
168 | "bm_w_x_mp7" : "Akimbo H&K MP7A2",
169 | "bm_w_x_schakal" : "Akimbo H&K UMP-45",
170 | "bm_w_x_m45" : "Akimbo Carl Gustav M/45",
171 | "bm_w_x_judge" : "Akimbo Taurus Judge",
172 | "bm_w_x_tec9" : "Akimbo Intratec TEC-9",
173 | "bm_w_x_rota" : "Akimbo Crye Precision SIX12",
174 | "bm_w_x_mp9" : "Akimbo B&T MP9",
175 | "bm_w_x_m1928" : "Akimbo Thompson M1928A1",
176 | "bm_w_x_cobray" : "Akimbo Cobray M11/9",
177 | "bm_w_x_olympic" : "Akimbo K23B Tactical",
178 | "bm_w_x_scorpion" : "Akimbo Scorpion vz.61",
179 | "bm_w_x_mac10" : "Akimbo Ingram MAC-10",
180 | "bm_w_x_polymer" : "Akimbo KRISS Vector",
181 | "bm_w_x_akmsu" : "Akimbo Izhmash AKMSU",
182 | "bm_w_x_p90" : "Akimbo FN P90 TR",
183 | "bm_w_x_hajk" : "Akimbo CZ 805 BREN A1",
184 | "bm_w_x_g18c" : "Akimbo Glock 18C",
185 | "bm_w_x_breech" : "Akimbo Luger P08",
186 | "bm_w_x_ppk" : "Akimbo Walther PPK",
187 | "bm_w_x_p226" : "Akimbo Sig-Sauer P226",
188 | "bm_w_x_c96" : "Akimbo Mauser C96",
189 | "bm_w_x_hs2000" : "Akimbo SA XDM",
190 | "bm_w_x_rage" : "Akimbo Taurus Raging Bull.44",
191 | "bm_w_x_sparrow" : "Akimbo Jericho 941 RPL",
192 | "bm_w_x_erma" : "Akimbo MP40",
193 | "bm_w_x_shepheard" : "Akimbo SIG-Sauer MPX",
194 | "bm_w_x_pl14" : "Akimbo PL-14 Lebedev",
195 | "bm_w_x_beer" : "Akimbo Beretta 93R",
196 | "bm_w_x_czech" : "Akimbo CZ AccuShadow 2",
197 | "bm_w_x_stech" : "Akimbo Stechkin Automatic Pistol",
198 | "bm_w_x_model3" : "Akimbo S&W No. 3 Russian Model",
199 | "bm_w_x_m1911" : "Akimbo Colt M1911",
200 | "bm_w_x_vityaz" : "Akimbo PP-19 Vityaz-SN",
201 | "bm_w_x_pm9" : "Akimbo Minebea PM-9",
202 | "bm_w_x_type54" : "Akimbo Tokarev TT-33",
203 | "bm_w_x_maxim9" : "Akimbo Maxim 9"
204 | }
--------------------------------------------------------------------------------
/lua/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 | function HUDAssaultCorner:init(...)
15 | init_original(self, ...)
16 |
17 | -- Waves completed are visible in Objective and overlapping with HUDList.
18 | if self:should_display_waves() then
19 | local wave_panel = self._hud_panel:child("wave_panel")
20 | if alive(wave_panel) then
21 | wave_panel:set_alpha(0)
22 | end
23 | local assault_panel = self._hud_panel:child("assault_panel")
24 | if alive(assault_panel) then
25 | self._wave_text = assault_panel:text({
26 | name = "num_waves",
27 | text = self:get_completed_waves_string(),
28 | valign = "center",
29 | vertical = "center",
30 | align = "center",
31 | halign = "right",
32 | w = self._bg_box and self._bg_box:w() or 100,
33 | h = tweak_data.hud.active_objective_title_font_size,
34 | layer = 1,
35 | x = 0,
36 | y = 0,
37 | color = Color.white,
38 | alpha = 0.8,
39 | font = "fonts/font_medium_shadow_mf",
40 | font_size = tweak_data.hud.active_objective_title_font_size * 0.9,
41 | })
42 | self._wave_text:set_top(self._bg_box and self._bg_box:bottom() or 40)
43 | self._wave_text:set_right(self._bg_box and self._bg_box:right() or 575)
44 | end
45 | end
46 |
47 | self:update_banner_pos()
48 | end
49 |
50 | function HUDAssaultCorner:update_banner_pos()
51 | if not alive(self._hud_panel) then return end
52 | local hud_w = self._hud_panel:w()
53 | local banner_pos = math.clamp(WolfHUD:getSetting({"AssaultBanner", "POSITION"}, 2), 1, 3)
54 | local assault_panel = self._hud_panel:child("assault_panel")
55 | local buffs_panel = self._hud_panel:child("buffs_panel")
56 | local point_of_no_return_panel = self._hud_panel:child("point_of_no_return_panel")
57 | local casing_panel = self._hud_panel:child("casing_panel")
58 | if alive(assault_panel) and alive(buffs_panel) and alive(point_of_no_return_panel) and alive(casing_panel) then
59 | if banner_pos < 2 then --Quite messy, but all the panels in this class are far wider than they would need to be, giving "false information" on their w() function...
60 | buffs_panel:set_right(self._vip_bg_box:w())
61 | assault_panel:set_right((buffs_panel:visible() and buffs_panel:right() or 80) + self._bg_box:w() + 6 + assault_panel:child("icon_assaultbox"):w())
62 | point_of_no_return_panel:set_right(80 + self._bg_box:w() + 3 + point_of_no_return_panel:child("icon_noreturnbox"):w())
63 | casing_panel:set_right(80 + self._bg_box:w() + 3 + casing_panel:child("icon_casingbox"):w())
64 | elseif banner_pos == 2 then
65 | assault_panel:set_right(hud_w / 2 + self._bg_box:w() / 2 + assault_panel:child("icon_assaultbox"):w() + 3)
66 | buffs_panel:set_x(assault_panel:left() + self._bg_box:left() - 3 - buffs_panel:w())
67 | point_of_no_return_panel:set_right(hud_w / 2 + (self._bg_box:w() + point_of_no_return_panel:child("icon_noreturnbox"):w()) / 2)
68 | casing_panel:set_right(hud_w / 2 + (self._bg_box:w() + casing_panel:child("icon_casingbox"):w()) / 2)
69 | else
70 | assault_panel:set_right(hud_w)
71 | buffs_panel:set_x(assault_panel:left() + self._bg_box:left() - 3 - buffs_panel:w())
72 | point_of_no_return_panel:set_right(hud_w)
73 | casing_panel:set_right(hud_w)
74 | end
75 | end
76 |
77 | self:update_hudlist_offset()
78 | end
79 |
80 | function HUDAssaultCorner:set_buff_enabled(...)
81 | self:update_banner_pos()
82 | return set_buff_enabled_original(self, ...)
83 | end
84 |
85 | function HUDAssaultCorner:update_hudlist_offset(banner_visible)
86 | banner_visible = banner_visible or banner_visible == nil and (self._assault or self._point_of_no_return or self._casing)
87 | local banner_pos = math.clamp(WolfHUD:getSetting({"AssaultBanner", "POSITION"}, 2), 1, 3)
88 | if managers.hud and banner_pos ~= 2 then
89 | local offset = banner_visible and ((self._bg_box and self._bg_box:bottom() or 0) + (self:should_display_waves() and self._wave_text:h() or 0)+ 12) or 0
90 | if banner_pos > 2 and HUDListManager then
91 | managers.hud:change_list_setting("right_list_height_offset", offset)
92 | elseif banner_pos < 2 then
93 | if managers.hud._hud_objectives and managers.hud._hud_objectives.apply_offset then
94 | managers.hud._hud_objectives:apply_offset(offset)
95 | end
96 | end
97 | end
98 | end
99 |
100 | function HUDAssaultCorner:_set_hostage_offseted(is_offseted, ...)
101 | _set_hostage_offseted_original(self, is_offseted, ...)
102 | self:update_hudlist_offset(is_offseted)
103 | end
104 |
105 | function HUDAssaultCorner:show_point_of_no_return_timer(...)
106 | show_point_of_no_return_timer_original(self, ...)
107 | self:update_hudlist_offset(true)
108 | end
109 |
110 | function HUDAssaultCorner:hide_point_of_no_return_timer(...)
111 | hide_point_of_no_return_timer_original(self, ...)
112 | self:update_hudlist_offset(false)
113 | end
114 |
115 | function HUDAssaultCorner:show_casing(...)
116 | --show_casing_original(self, ...)
117 | --self:update_hudlist_offset(true)
118 | end
119 | function HUDAssaultCorner:hide_casing(...)
120 | --hide_casing_original(self, ...)
121 | --self:update_hudlist_offset(false)
122 | end
123 |
124 | function HUDAssaultCorner:_start_assault(text_list, ...)
125 | for i, string_id in ipairs(text_list) do
126 | if string_id == "hud_assault_assault" then
127 | text_list[i] = "hud_adv_assault"
128 | end
129 | end
130 | return _start_assault_original(self, text_list, ...)
131 | end
132 |
133 | function HUDAssaultCorner:_animate_wave_started(...)
134 | self._wave_text:set_text(self:get_completed_waves_string())
135 |
136 | return _animate_wave_started_original(self, ...)
137 | end
138 | function HUDAssaultCorner:_animate_wave_completed(...)
139 | self._wave_text:set_text(self:get_completed_waves_string())
140 |
141 | return _animate_wave_completed_original(self, ...)
142 | end
143 |
144 | function HUDAssaultCorner:set_assault_wave_number(...)
145 | if alive(self._wave_text) then
146 | self._wave_text:set_text(self:get_completed_waves_string())
147 | self._wave_text:animate(callback(self, self, "_animate_wave_text"))
148 | end
149 |
150 | return set_assault_wave_number_original(self, ...)
151 | end
152 |
153 | function HUDAssaultCorner:_animate_wave_text(object)
154 | local TOTAL_T = 2
155 | local t = TOTAL_T
156 | object:set_alpha(0.8)
157 | while t > 0 do
158 | local dt = coroutine.yield()
159 | t = t - dt
160 | object:set_alpha(0.5 + 0.5 * (0.5 * math.sin(t * 360 * 2) + 0.5))
161 | end
162 | object:set_alpha(0.8)
163 | end
164 |
165 | function HUDAssaultCorner:locked_assault(status)
166 | local assault_panel = self._hud_panel:child("assault_panel")
167 | local icon_assaultbox = assault_panel and assault_panel:child("icon_assaultbox")
168 | local image
169 | if status then
170 | image = "guis/textures/pd2/hud_icon_padlockbox"
171 | else
172 | image = "guis/textures/pd2/hud_icon_assaultbox"
173 | end
174 | if icon_assaultbox and image then
175 | icon_assaultbox:set_image(image)
176 | end
177 | end
178 | elseif string.lower(RequiredScript) == "lib/managers/hudmanagerpd2" then
179 | local sync_start_assault_original = HUDManager.sync_start_assault
180 | local sync_end_assault_original = HUDManager.sync_end_assault
181 | local _create_downed_hud_original = HUDManager._create_downed_hud
182 | local _create_custody_hud_original = HUDManager._create_custody_hud
183 |
184 | function HUDManager:_locked_assault(status)
185 | if Network:is_server() then
186 | status = managers.groupai:state():get_hunt_mode() or false
187 | end
188 | if self._assault_locked ~= status then
189 | if self._hud_assault_corner then
190 | self._hud_assault_corner:locked_assault(status)
191 | end
192 | self._assault_locked = status
193 | if Network:is_server() and WolfHUD.Sync then
194 | WolfHUD.Sync:endless_assault_status(self._assault_locked)
195 | end
196 | end
197 | end
198 |
199 | function HUDManager:is_assault_locked()
200 | return self._assault_locked or false
201 | end
202 |
203 | function HUDManager:change_assaultbanner_setting(setting, value)
204 | if self._hud_assault_corner then
205 | if setting == "POSITION" then
206 | self._hud_assault_corner:update_banner_pos()
207 | end
208 | end
209 | end
210 |
211 | function HUDManager:sync_start_assault(...)
212 | sync_start_assault_original(self, ...)
213 |
214 | if Network:is_server() then
215 | self:_locked_assault()
216 | end
217 | end
218 |
219 | function HUDManager:sync_end_assault(...)
220 | sync_end_assault_original(self, ...)
221 |
222 | if Network:is_server() then
223 | self:_locked_assault()
224 | end
225 | end
226 |
227 | function HUDManager:_create_downed_hud(...)
228 | _create_downed_hud_original(self, ...)
229 | local banner_pos = math.clamp(WolfHUD:getSetting({"AssaultBanner", "POSITION"}, 2), 1, 3)
230 | if banner_pos == 2 and self._hud_player_downed then
231 | local downed_panel = self._hud_player_downed._hud_panel
232 | local downed_hud = self._hud_player_downed._hud
233 | local timer_msg = downed_panel and downed_panel:child("downed_panel"):child("timer_msg")
234 | local timer = downed_hud and downed_hud.timer
235 | if timer_msg and timer then
236 | timer_msg:set_y(65)
237 | timer:set_y(math.round(timer_msg:bottom() - 6))
238 | end
239 | end
240 | end
241 |
242 | function HUDManager:_create_custody_hud(...)
243 | _create_custody_hud_original(self, ...)
244 | local banner_pos = math.clamp(WolfHUD:getSetting({"AssaultBanner", "POSITION"}, 2), 1, 3)
245 | if banner_pos == 2 and self._hud_player_custody then
246 | local custody_panel = self._hud_player_custody._hud_panel
247 | local timer_msg = custody_panel and custody_panel:child("custody_panel") and custody_panel:child("custody_panel"):child("timer_msg")
248 | local timer = self._hud_player_custody._timer
249 | if timer_msg and timer then
250 | timer_msg:set_y(65)
251 | timer:set_y(math.round(timer_msg:bottom() - 6))
252 | end
253 | end
254 | end
255 | elseif string.lower(RequiredScript) == "lib/managers/localizationmanager" then
256 | local text_original = LocalizationManager.text
257 |
258 | function LocalizationManager:text(string_id, ...)
259 | if string_id == "hud_adv_assault" then
260 | return self:hud_adv_assault()
261 | end
262 | return text_original(self, string_id, ...)
263 | end
264 |
265 | function LocalizationManager:hud_adv_assault()
266 | if WolfHUD:getSetting({"AssaultBanner", "USE_ADV_ASSAULT"}, true) then
267 | if managers.hud and managers.hud:is_assault_locked() then
268 | return self:text("wolfhud_locked_assault")
269 | else
270 | local tweak = tweak_data.group_ai.besiege.assault
271 | local gai_state = managers.groupai:state()
272 | local assault_data = Network:is_server() and gai_state and gai_state._task_data.assault
273 | if tweak and gai_state and assault_data and assault_data.active then
274 | local get_value = gai_state._get_difficulty_dependent_value or function() return 0 end
275 | local get_mult = gai_state._get_balancing_multiplier or function() return 0 end
276 | local phase = self:text("wolfhud_advassault_phase_title") .. " " .. self:text("wolfhud_advassault_phase_" .. assault_data.phase)
277 |
278 | local spawns = get_value(gai_state, tweak.force_pool) * get_mult(gai_state, tweak.force_pool_balance_mul)
279 | local spawns_left = self:text("wolfhud_advassault_spawns_title") .. " " .. math.round(math.max(spawns - assault_data.force_spawned, 0))
280 |
281 | local time_left = assault_data.phase_end_t - gai_state._t + 350
282 | if assault_data.phase == "build" then
283 | 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)
284 | time_left = time_left + sustain_duration + tweak.fade_duration
285 | elseif assault_data.phase == "sustain" then
286 | time_left = time_left + tweak.fade_duration
287 | end
288 | --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).
289 | -- time_left = time_left + 350
290 | --end
291 | if time_left < 0 then
292 | time_left = self:text("wolfhud_advassault_time_overdue")
293 | else
294 | time_left = self:text("wolfhud_advassault_time_title") .. " " .. string.format("%.2f", time_left)
295 | end
296 |
297 | local spacer = string.rep(" ", 10)
298 | local sep = string.format("%s%s%s", spacer, self:text("hud_assault_end_line"), spacer)
299 | return string.format("%s%s%s%s%s", phase, sep, spawns_left, sep, time_left)
300 | end
301 | end
302 | end
303 | return self:text("hud_assault_assault")
304 | end
305 | end
306 |
--------------------------------------------------------------------------------
/lua/BurstFire.lua:
--------------------------------------------------------------------------------
1 | --[[
2 | Weapon tweak data attributes:
3 | BURST_FIRE:
4 | - Force enable burst fire using the specified number as the burst size (if weapon does not have a fire mode mod installed)
5 | 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)
6 | false - Force disable burst fire even if weapon can toggle fire mode
7 |
8 | ADAPTIVE_BURST_SIZE:
9 | nil/true - Allow abortion of ongoing burst if trigger is released
10 | false - Force entire burst to be fired before resetting
11 |
12 | BURST_FIRE_RATE_MULTIPLIER:
13 | - Apply specified multiplier to fire rate when firing in burst mode
14 |
15 | DELAYED_BURST_RECOIL:
16 | true/false - Build up and delay recoil until last shot in burst is fired
17 | ]]
18 | if not WolfHUD:getSetting({"EQUIPMENT", "ENABLE_BURSTMODE"}, true) then
19 | return
20 | end
21 |
22 | if string.lower(RequiredScript) == "lib/units/weapons/newraycastweaponbase" then
23 |
24 | local _update_stats_values_original = NewRaycastWeaponBase._update_stats_values
25 | local fire_rate_multiplier_original = NewRaycastWeaponBase.fire_rate_multiplier
26 | local recoil_multiplier_original = NewRaycastWeaponBase.recoil_multiplier
27 | local on_enabled_original = NewRaycastWeaponBase.on_enabled
28 | local on_disabled_original = NewRaycastWeaponBase.on_disabled
29 | local start_reload_original = NewRaycastWeaponBase.start_reload
30 | local fire_original = NewRaycastWeaponBase.fire
31 | local toggle_firemode_original = NewRaycastWeaponBase.toggle_firemode
32 |
33 | NewRaycastWeaponBase.DEFAULT_BURST_SIZE = 3
34 | NewRaycastWeaponBase.IDSTRING_SINGLE = Idstring("single")
35 | NewRaycastWeaponBase.IDSTRING_AUTO = Idstring("auto")
36 |
37 | function NewRaycastWeaponBase:_update_stats_values(...)
38 | _update_stats_values_original(self, ...)
39 |
40 | if not self:is_npc() then
41 | self._burst_rounds_remaining = 0
42 | self._has_auto = not self._locked_fire_mode and (self:can_toggle_firemode() or self:weapon_tweak_data().FIRE_MODE == "auto")
43 | self._has_burst_fire = (self:can_toggle_firemode() or self:weapon_tweak_data().BURST_FIRE) and self:weapon_tweak_data().BURST_FIRE ~= false
44 | --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
45 | --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")
46 | self._burst_size = self:weapon_tweak_data().BURST_FIRE or NewRaycastWeaponBase.DEFAULT_BURST_SIZE
47 | self._adaptive_burst_size = self:weapon_tweak_data().ADAPTIVE_BURST_SIZE ~= false
48 | self._burst_fire_rate_multiplier = self:weapon_tweak_data().BURST_FIRE_RATE_MULTIPLIER or 1
49 | self._delayed_burst_recoil = self:weapon_tweak_data().DELAYED_BURST_RECOIL
50 |
51 | self._burst_rounds_fired = 0
52 | end
53 | end
54 |
55 | function NewRaycastWeaponBase:fire_rate_multiplier(...)
56 | local mult = 1
57 | if self:in_burst_mode() then
58 | mult = mult * (self._burst_fire_rate_multiplier or 1)
59 | end
60 |
61 | return fire_rate_multiplier_original(self, ...) * mult
62 | end
63 |
64 | function NewRaycastWeaponBase:recoil_multiplier(...)
65 | local mult = 1
66 | if self._delayed_burst_recoil and self:in_burst_mode() and self:burst_rounds_remaining() then
67 | mult = 0
68 | end
69 |
70 | return recoil_multiplier_original(self, ...) * mult
71 | end
72 |
73 | function NewRaycastWeaponBase:on_enabled(...)
74 | self:cancel_burst()
75 | return on_enabled_original(self, ...)
76 | end
77 |
78 | function NewRaycastWeaponBase:on_disabled(...)
79 | self:cancel_burst()
80 | return on_disabled_original(self, ...)
81 | end
82 |
83 | function NewRaycastWeaponBase:start_reload(...)
84 | self:cancel_burst()
85 | return start_reload_original(self, ...)
86 | end
87 |
88 | function NewRaycastWeaponBase:fire(...)
89 | local result = fire_original(self, ...)
90 |
91 | if result and not self.AKIMBO and self:in_burst_mode() then
92 | if self:clip_empty() then
93 | self:cancel_burst()
94 | else
95 | self._burst_rounds_fired = self._burst_rounds_fired + 1
96 | self._burst_rounds_remaining = (self._burst_rounds_remaining <= 0 and self._burst_size or self._burst_rounds_remaining) - 1
97 | if self._burst_rounds_remaining <= 0 then
98 | self:cancel_burst()
99 | end
100 | end
101 | end
102 |
103 | return result
104 | end
105 |
106 | --Semi-override
107 | function NewRaycastWeaponBase:toggle_firemode(...)
108 | 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, ...)
109 | end
110 |
111 | function NewRaycastWeaponBase:_check_toggle_burst()
112 | if self:in_burst_mode() then
113 | self:_set_burst_mode(false, self.AKIMBO and not self._has_auto)
114 | return true
115 | elseif (self._fire_mode == Idstring("single")) or (self._fire_mode == Idstring("auto") and not self:can_toggle_firemode()) then
116 | self:_set_burst_mode(true, self.AKIMBO)
117 | return true
118 | end
119 | end
120 |
121 | function NewRaycastWeaponBase:_set_burst_mode(status, skip_sound)
122 | self._in_burst_mode = status
123 | self._fire_mode = NewRaycastWeaponBase["IDSTRING_" .. (status and "SINGLE" or self._has_auto and "AUTO" or "SINGLE")]
124 |
125 | if not skip_sound then
126 | self._sound_fire:post_event((status or self._has_auto) and "wp_auto_switch_on" or "wp_auto_switch_off")
127 | end
128 |
129 | self:cancel_burst()
130 | end
131 |
132 | function NewRaycastWeaponBase:can_use_burst_mode()
133 | return self._has_burst_fire
134 | end
135 |
136 | function NewRaycastWeaponBase:in_burst_mode()
137 | return self._fire_mode == NewRaycastWeaponBase.IDSTRING_SINGLE and self._in_burst_mode and not self:gadget_overrides_weapon_functions()
138 | end
139 |
140 | function NewRaycastWeaponBase:burst_rounds_remaining()
141 | return self._burst_rounds_remaining > 0 and self._burst_rounds_remaining or false
142 | end
143 |
144 | function NewRaycastWeaponBase:cancel_burst(soft_cancel)
145 | if self._adaptive_burst_size or not soft_cancel then
146 | self._burst_rounds_remaining = 0
147 |
148 | if self._delayed_burst_recoil and self._burst_rounds_fired > 0 then
149 | self._setup.user_unit:movement():current_state():force_recoil_kick(self, self._burst_rounds_fired)
150 | end
151 | self._burst_rounds_fired = 0
152 | end
153 | end
154 |
155 | elseif string.lower(RequiredScript) == "lib/units/weapons/akimboweaponbase" then
156 |
157 | local _update_stats_values_original = AkimboWeaponBase._update_stats_values
158 | local fire_original = AkimboWeaponBase.fire
159 | local fire_rate_multiplier_original = AkimboWeaponBase.fire_rate_multiplier
160 | local toggle_firemode_original = AkimboWeaponBase.toggle_firemode
161 |
162 | function AkimboWeaponBase:_update_stats_values(...)
163 | _update_stats_values_original(self, ...)
164 |
165 | if not self:is_npc() then
166 | self._has_burst_fire = self._has_burst_fire or ((self:weapon_tweak_data().BURST_FIRE ~= false) and (self._fire_mode == NewRaycastWeaponBase.IDSTRING_SINGLE))
167 |
168 | if self:can_use_burst_mode() then
169 | self:_set_burst_mode(not self._manual_fire_second_gun, true)
170 | end
171 | end
172 | end
173 |
174 | function AkimboWeaponBase:fire(...)
175 | local results = fire_original(self, ...)
176 |
177 | if not self:_in_burst_or_auto_mode() then
178 | self._fire_callbacks = {}
179 | end
180 |
181 | return results
182 | end
183 |
184 | function AkimboWeaponBase:fire_rate_multiplier(...)
185 | return fire_rate_multiplier_original(self, ...) * (self:_in_burst_or_auto_mode() and 2 or 1)
186 | end
187 |
188 | --Override
189 | function AkimboWeaponBase:toggle_firemode(...)
190 | return self:can_use_burst_mode() and self:_check_toggle_burst() or toggle_firemode_original(self, ...)
191 | end
192 |
193 | function AkimboWeaponBase:_set_burst_mode(status, skip_sound)
194 | if alive(self._second_gun) then
195 | self._second_gun:base():_set_burst_mode(status, skip_sound)
196 | end
197 |
198 | return AkimboWeaponBase.super._set_burst_mode(self, status, skip_sound)
199 | end
200 |
201 | function AkimboWeaponBase:_in_burst_or_auto_mode()
202 | return self._fire_mode == NewRaycastWeaponBase.IDSTRING_AUTO or self:in_burst_mode()
203 | end
204 |
205 | elseif string.lower(RequiredScript) == "lib/units/weapons/akimboshotgunbase" then
206 |
207 | local _update_stats_values_original = AkimboShotgunBase._update_stats_values
208 |
209 | function AkimboShotgunBase:_update_stats_values(...)
210 | _update_stats_values_original(self, ...)
211 |
212 | if not self:is_npc() then
213 | self._has_burst_fire = self._has_burst_fire or ((self:weapon_tweak_data().BURST_FIRE ~= false) and (self._fire_mode == NewRaycastWeaponBase.IDSTRING_SINGLE))
214 |
215 | if self._has_burst_fire then
216 | self:_set_burst_mode(not self._manual_fire_second_gun, true)
217 | end
218 | end
219 | end
220 |
221 | elseif string.lower(RequiredScript) == "lib/units/beings/player/states/playerstandard" then
222 |
223 | local update_original = PlayerStandard.update
224 | local _check_action_primary_attack_original = PlayerStandard._check_action_primary_attack
225 | local _check_action_deploy_underbarrel_original = PlayerStandard._check_action_deploy_underbarrel
226 |
227 | function PlayerStandard:update(t, ...)
228 | update_original(self, t, ...)
229 | self:_update_burst_fire(t)
230 | end
231 |
232 | function PlayerStandard:_check_action_primary_attack(t, input, ...)
233 | if self._trigger_down and not input.btn_primary_attack_state then
234 | self._equipped_unit:base():cancel_burst(true)
235 | end
236 | self._trigger_down = input.btn_primary_attack_state
237 |
238 | return _check_action_primary_attack_original(self, t, input, ...)
239 | end
240 |
241 | function PlayerStandard:_check_action_deploy_underbarrel(...)
242 | local new_action = _check_action_deploy_underbarrel_original(self, ...)
243 |
244 | if new_action and alive(self._equipped_unit) and self._equipped_unit:base() and self._equipped_unit:base():in_burst_mode() then
245 | managers.hud:set_teammate_weapon_firemode_burst(self._equipped_unit:base():selection_index())
246 | end
247 |
248 | return new_action
249 | end
250 |
251 | --Override
252 | function PlayerStandard:_check_action_weapon_firemode(t, input)
253 | local wbase = self._equipped_unit:base()
254 | if input.btn_weapon_firemode_press and wbase.toggle_firemode then
255 | self:_check_stop_shooting()
256 | if wbase:toggle_firemode() then
257 | if wbase:in_burst_mode() then
258 | managers.hud:set_teammate_weapon_firemode_burst(self._unit:inventory():equipped_selection())
259 | else
260 | managers.hud:set_teammate_weapon_firemode(HUDManager.PLAYER_PANEL, self._unit:inventory():equipped_selection(), wbase:fire_mode())
261 | end
262 | end
263 | end
264 | end
265 |
266 | function PlayerStandard:_update_burst_fire(t)
267 | if alive(self._equipped_unit) and self._equipped_unit:base():burst_rounds_remaining() then
268 | self:_check_action_primary_attack(t, { btn_primary_attack_state = true, btn_primary_attack_press = true })
269 | end
270 | end
271 |
272 | function PlayerStandard:force_recoil_kick(weap_base, manual_multiplier)
273 | local recoil_multiplier = (weap_base:recoil() + weap_base:recoil_addend()) * weap_base:recoil_multiplier() * (manual_multiplier or 1)
274 | 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"])
275 | self._camera_unit:base():recoil_kick(up * recoil_multiplier, down * recoil_multiplier, left * recoil_multiplier, right * recoil_multiplier)
276 | end
277 |
278 | elseif string.lower(RequiredScript) == "lib/managers/playermanager" then
279 |
280 | local spawned_player_original = PlayerManager.spawned_player
281 |
282 | function PlayerManager:spawned_player(id, unit, ...)
283 | spawned_player_original(self, id, unit, ...)
284 |
285 | if unit:key() == self:player_unit():key() then
286 | for i = 1, 2, 1 do
287 | local wbase = unit:inventory():unit_by_selection(i):base()
288 | if wbase:in_burst_mode() then
289 | managers.hud:set_teammate_weapon_firemode_burst(i)
290 | end
291 | end
292 | end
293 | end
294 |
295 | elseif string.lower(RequiredScript) == "lib/managers/hudmanagerpd2" then
296 |
297 | HUDManager._USE_BURST_MODE = true --Custom HUD compatibility
298 |
299 | HUDManager.set_teammate_weapon_firemode_burst = HUDManager.set_teammate_weapon_firemode_burst or function(self, id)
300 | self._teammate_panels[HUDManager.PLAYER_PANEL]:set_weapon_firemode_burst(id)
301 | end
302 |
303 | elseif string.lower(RequiredScript) == "lib/managers/hud/hudteammate" then
304 |
305 | --Default function for vanilla HUD. If using a custom HUD that alters fire mode HUD components, make sure to implement this function in it
306 | HUDTeammate.set_weapon_firemode_burst = HUDTeammate.set_weapon_firemode_burst or function(self, id)
307 | local is_secondary = id == 1
308 | local secondary_weapon_panel = self._player_panel:child("weapons_panel"):child("secondary_weapon_panel")
309 | local primary_weapon_panel = self._player_panel:child("weapons_panel"):child("primary_weapon_panel")
310 | local weapon_selection = is_secondary and secondary_weapon_panel:child("weapon_selection") or primary_weapon_panel:child("weapon_selection")
311 | if alive(weapon_selection) then
312 | local firemode_single = weapon_selection:child("firemode_single")
313 | local firemode_auto = weapon_selection:child("firemode_auto")
314 | if alive(firemode_single) and alive(firemode_auto) then
315 | firemode_single:show()
316 | firemode_auto:show()
317 | end
318 | end
319 | end
320 |
321 | end
322 |
--------------------------------------------------------------------------------
/lua/BuyAllAsset.lua:
--------------------------------------------------------------------------------
1 | --do return end
2 |
3 | if string.lower(RequiredScript) == "lib/managers/missionassetsmanager" then
4 | function MissionAssetsManager:unlock_all_buyable_assets()
5 | for _, asset in ipairs(self._global.assets) do
6 | if self:asset_is_buyable(asset) then
7 | self:unlock_asset(asset.id)
8 | end
9 | end
10 | end
11 |
12 | function MissionAssetsManager:asset_is_buyable(asset)
13 | return self:asset_is_locked(asset) and (Network:is_server() and asset.can_unlock or Network:is_client() and self:get_asset_can_unlock_by_id(asset.id))
14 | end
15 |
16 | function MissionAssetsManager:asset_is_locked(asset)
17 | return asset.show and not asset.unlocked
18 | end
19 |
20 | function MissionAssetsManager:has_locked_assets()
21 | local level_id = managers.job:current_level_id()
22 | if not tweak_data.preplanning or not tweak_data.preplanning.locations or not tweak_data.preplanning.locations[level_id] then
23 | for _, asset in ipairs(self._global.assets) do
24 | if self:asset_is_locked(asset) then
25 | return true
26 | end
27 | end
28 | end
29 | return false
30 | end
31 |
32 | function MissionAssetsManager:has_buyable_assets()
33 | local level_id = managers.job:current_level_id()
34 | if self:is_unlock_asset_allowed() and not tweak_data.preplanning or not tweak_data.preplanning.locations or not tweak_data.preplanning.locations[level_id] then
35 | local asset_costs = self:get_total_assets_costs()
36 | if asset_costs > 0 then
37 | return true
38 | end
39 | end
40 | return false
41 | end
42 |
43 | function MissionAssetsManager:get_total_assets_costs()
44 | local total_costs = 0
45 | for _, asset in ipairs(self._global.assets) do
46 | if self:asset_is_buyable(asset) then
47 | total_costs = total_costs + (asset.id and managers.money:get_mission_asset_cost_by_id(asset.id) or 0)
48 | end
49 | end
50 | return total_costs
51 | end
52 | elseif string.lower(RequiredScript) == "lib/managers/menu/missionbriefinggui" then
53 | local create_assets_original = AssetsItem.create_assets
54 | local unlock_asset_by_id_original = AssetsItem.unlock_asset_by_id
55 | local move_up_original = AssetsItem.move_up
56 | local move_down_original = AssetsItem.move_down
57 | local move_left_original = AssetsItem.move_left
58 | local move_right_original = AssetsItem.move_right
59 | local confirm_pressed_original = AssetsItem.confirm_pressed
60 | local mouse_moved_original = AssetsItem.mouse_moved
61 | local mouse_pressed_original = AssetsItem.mouse_pressed
62 |
63 | function AssetsItem:create_assets(...)
64 | create_assets_original(self, ...)
65 |
66 | if self.buy_all_button then
67 | self.buy_all_button:hide()
68 | self._is_buy_all_dialog_open = true
69 | end
70 |
71 | self._buy_all_btn = self._panel:text({
72 | name = "buy_all_btn",
73 | text = "",
74 | h = tweak_data.menu.pd2_medium_font_size * 0.95,
75 | font_size = tweak_data.menu.pd2_medium_font_size * 0.9,
76 | font = tweak_data.menu.pd2_medium_font,
77 | color = tweak_data.screen_colors.button_stage_3,
78 | align = "right",
79 | blend_mode = "add",
80 | visible = managers.assets:has_locked_assets(),
81 | })
82 |
83 | self:update_buy_all_btn()
84 | end
85 |
86 | function AssetsItem:unlock_asset_by_id(...)
87 | unlock_asset_by_id_original(self, ...)
88 |
89 | self:update_buy_all_btn()
90 | end
91 |
92 | function AssetsItem:move_up(...)
93 | if self._asset_selected and (self._asset_selected % 2 > 0) and managers.assets:has_buyable_assets() and self:can_afford_all_assets() then
94 | self._buy_all_highlighted = true
95 | self._last_selected_asset = self._asset_selected
96 | self:check_deselect_item()
97 | self:update_buy_all_btn(true)
98 | managers.menu_component:post_event("highlight")
99 | else
100 | move_up_original(self, ...)
101 | end
102 | end
103 |
104 | function AssetsItem:move_down(...)
105 | if self._buy_all_highlighted then
106 | self._buy_all_highlighted = nil
107 | self:select_asset(self._last_selected_asset)
108 | self:update_buy_all_btn(true)
109 | self._last_selected_asset = nil
110 | else
111 | move_down_original(self, ...)
112 | end
113 | end
114 |
115 | function AssetsItem:move_left(...)
116 | if not self._buy_all_highlighted then
117 | move_left_original(self, ...)
118 | end
119 | end
120 |
121 | function AssetsItem:move_right(...)
122 | if not self._buy_all_highlighted then
123 | move_right_original(self, ...)
124 | end
125 | end
126 |
127 | function AssetsItem:confirm_pressed(...)
128 | if self._buy_all_highlighted then
129 | if self:can_afford_all_assets() then
130 | managers.assets:unlock_all_buyable_assets()
131 | self:update_buy_all_btn()
132 | self:move_down()
133 | end
134 | else
135 | return confirm_pressed_original(self, ...)
136 | end
137 | end
138 |
139 | function AssetsItem:mouse_moved(x, y, ...)
140 | if alive(self._buy_all_btn) and managers.assets:has_buyable_assets() then
141 | if self._buy_all_btn:inside(x, y) then
142 | if not self._buy_all_highlighted then
143 | self._buy_all_highlighted = true
144 | self:update_buy_all_btn(true)
145 | self:check_deselect_item()
146 | if self:can_afford_all_assets() then
147 | managers.menu_component:post_event("highlight")
148 | end
149 | end
150 | return true, "link"
151 | elseif self._buy_all_highlighted then
152 | self._buy_all_highlighted = nil
153 | self:update_buy_all_btn(true)
154 | end
155 | end
156 |
157 | return mouse_moved_original(self, x, y, ...)
158 | end
159 |
160 | function AssetsItem:mouse_pressed(button, x, y, ...)
161 | if alive(self._buy_all_btn) and self:can_afford_all_assets() and button == Idstring("0") and self._buy_all_btn:inside(x, y) then
162 | managers.assets:unlock_all_buyable_assets()
163 | self:update_buy_all_btn()
164 | end
165 |
166 | return mouse_pressed_original(self, button, x, y, ...)
167 | end
168 |
169 | function AssetsItem:update_buy_all_btn(colors_only)
170 | if alive(self._buy_all_btn) then
171 | local asset_costs = managers.assets:get_total_assets_costs()
172 | if managers.assets:has_buyable_assets() then
173 | if self:can_afford_all_assets() then
174 | self._buy_all_btn:set_color(self._buy_all_highlighted and tweak_data.screen_colors.button_stage_2 or tweak_data.screen_colors.button_stage_3)
175 | else
176 | self._buy_all_btn:set_color(tweak_data.screen_colors.pro_color)
177 | end
178 | else
179 | self._buy_all_btn:set_color(tweak_data.screen_color_grey)
180 | end
181 | if not colors_only then
182 | local text = string.format("%s (%s)", managers.localization:to_upper_text("wolfhud_buy_all_assets"), managers.experience:cash_string(asset_costs))
183 | self._buy_all_btn:set_text(text)
184 | local _, _, w, _ = self._buy_all_btn:text_rect()
185 | self._buy_all_btn:set_w(math.ceil(w))
186 | self._buy_all_btn:set_top(15)
187 | if managers.menu:is_pc_controller() then
188 | self._buy_all_btn:set_right(self._panel:w() - 5)
189 | else
190 | self._buy_all_btn:set_left(5)
191 | end
192 | end
193 | end
194 | end
195 |
196 | function AssetsItem:can_afford_all_assets()
197 | return (managers.assets:get_total_assets_costs() <= managers.money:total())
198 | end
199 | end
--------------------------------------------------------------------------------
/lua/ContractHeat.lua:
--------------------------------------------------------------------------------
1 | -- CONFIG **********************************************************************
2 |
3 | -- OVERRIDES *******************************************************************
4 | local init_original = ContractBrokerHeistItem.init
5 | function ContractBrokerHeistItem:init(...) -- parent_panel, job_data, idx
6 |
7 | init_original(self, ...)
8 |
9 | local job_tweak = tweak_data.narrative:job_data(self._job_data.job_id)
10 |
11 | if WolfHUD:getSetting({"INVENTORY", "SHOW_CONTRACTOR_JOB_HEAT"}, true) and job_tweak and job_tweak.contact ~= "skirmish" then
12 | local heat_text, heat_color = self:get_job_heat_text(self._job_data.job_id)
13 |
14 | local heat = self._panel:text({
15 | alpha = 1,
16 | vertical = "top",
17 | layer = 1,
18 | align = "right",
19 | halign = "right",
20 | valign = "top",
21 | text = heat_text,
22 | font = tweak_data.menu.pd2_large_font,
23 | font_size = tweak_data.menu.pd2_medium_font_size * 0.8,
24 | color = heat_color
25 | })
26 | self:make_fine_text(heat)
27 | heat:set_right(self._panel:right() - 10)
28 | heat:set_top(13)
29 | end
30 | end
31 |
32 | -- FUNCTION LIB ****************************************************************
33 | function ContractBrokerHeistItem:make_fine_text(text)
34 | local x, y, w, h = text:text_rect()
35 |
36 | text:set_size(w, h)
37 | text:set_position(math.round(text:x()), math.round(text:y()))
38 | end
39 |
40 | function ContractBrokerHeistItem:get_job_heat_text(job_id)
41 | local heat_text = ""
42 | local heat_color = Color(1,0,1)
43 | local exp_multiplier = managers.job:heat_to_experience_multiplier(managers.job:get_job_heat(job_id))
44 | local exp_percent = ((1 - exp_multiplier)*-1)*100
45 |
46 | if exp_percent ~= 0 then
47 | local prefix = exp_percent > 0 and "+" or ""
48 | heat_text = "("..prefix..exp_percent.."%)"
49 | heat_color = exp_percent > 0 and tweak_data.screen_colors.heat_warm_color or tweak_data.screen_colors.heat_cold_color
50 | end
51 |
52 | return heat_text, heat_color
53 | end
--------------------------------------------------------------------------------
/lua/DamageIndicator.lua:
--------------------------------------------------------------------------------
1 | if not WolfHUD:getSetting({"DamageIndicator", "ENABLED"}, true) then return end
2 |
3 | if string.lower(RequiredScript) == "lib/managers/hud/hudhitdirection" then
4 | HUDHitDirection.indicator_count = 0
5 | HUDHitDirection.DAMAGE_TYPES = {}
6 | HUDHitDirection.DAMAGE_TYPES.HEALTH = 1
7 | HUDHitDirection.DAMAGE_TYPES.ARMOUR = 2
8 | HUDHitDirection.DAMAGE_TYPES.VEHICLE = 3
9 | HUDHitDirection.DAMAGE_TYPES.CRIT = 4
10 | HUDHitDirection.DAMAGE_TYPES.FRIENDLY_FIRE = 5
11 |
12 | local init_original = HUDHitDirection.init
13 | local _add_hit_indicator_original = HUDHitDirection._add_hit_indicator
14 | local _remove_original = HUDHitDirection._remove
15 |
16 | function HUDHitDirection:init(...)
17 | init_original(self, ...)
18 | if alive(self._hud_panel) and alive(self._hit_direction_panel) then
19 | self._hit_direction_panel:set_w(self._hud_panel:w())
20 | self._hit_direction_panel:set_h(self._hud_panel:h())
21 | self._hit_direction_panel:set_center(self._hit_direction_panel:parent():w() * 0.5, self._hit_direction_panel:parent():h() * 0.5)
22 | end
23 | end
24 |
25 | function HUDHitDirection:_add_hit_indicator(...)
26 | HUDHitDirection.PANEL_SIZE = WolfHUD:getSetting({"DamageIndicator", "SIZE"}, 150)
27 | if self.indicator_count < WolfHUD:getSetting({"DamageIndicator", "MAX_AMOUNT"}, 10) then
28 | self.indicator_count = self.indicator_count + 1
29 | _add_hit_indicator_original(self, ...)
30 | end
31 | end
32 |
33 | function HUDHitDirection:_animate(indicator, data, remove_func)
34 | data.duration = WolfHUD:getSetting({"DamageIndicator", "DURATION"}, 2)
35 | data.t = 0
36 | while data.t < data.duration do
37 | data.t = data.t + coroutine.yield()
38 | if alive(indicator) then
39 | local o = data.t / data.duration
40 | indicator:set_color(self:_get_indicator_color(data.damage_type, o))
41 | indicator:set_alpha( math.clamp(math.sin(o * 180), 0, 1) )
42 | if managers.player:player_unit() then
43 | local ply_camera = managers.player:player_unit():camera()
44 | if ply_camera then
45 | local target_vec = ply_camera:position() - data.origin
46 | local angle = target_vec:to_polar_with_reference(ply_camera:forward(), math.UP).spin
47 | local r = HUDHitDirection.PANEL_SIZE + (1-math.pow(o,0.5)) * (100)
48 | if data.fixed_angle ~= nil then
49 | angle = data.fixed_angle
50 | end
51 | indicator:set_rotation(90 - angle)
52 | 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)
53 | end
54 | end
55 | end
56 | end
57 | remove_func(indicator, data)
58 | end
59 |
60 | function HUDHitDirection:_remove(...)
61 | _remove_original(self, ...)
62 | self.indicator_count = self.indicator_count - 1
63 | end
64 |
65 | function HUDHitDirection:_get_indicator_color(damage_type, t)
66 | if damage_type == HUDHitDirection.DAMAGE_TYPES.HEALTH then
67 | return WolfHUD:getColorSetting({"DamageIndicator", "HEALTH_COLOR"}, "red")
68 | elseif damage_type == HUDHitDirection.DAMAGE_TYPES.ARMOUR then
69 | return WolfHUD:getColorSetting({"DamageIndicator", "SHIELD_COLOR"}, "white")
70 | elseif damage_type == HUDHitDirection.DAMAGE_TYPES.VEHICLE then
71 | return WolfHUD:getColorSetting({"DamageIndicator", "VEHICLE_COLOR"}, "yellow")
72 | elseif damage_type == HUDHitDirection.DAMAGE_TYPES.CRIT then
73 | return WolfHUD:getColorSetting({"DamageIndicator", "CRIT_COLOR"}, "purple")
74 | elseif damage_type == HUDHitDirection.DAMAGE_TYPES.FRIENDLY_FIRE then
75 | return WolfHUD:getColorSetting({"DamageIndicator", "FRIENDLY_FIRE_COLOR"}, "orange")
76 | else
77 | return Color(1, t, t)
78 | end
79 | end
80 | elseif string.lower(RequiredScript) == "lib/units/beings/player/playerdamage" then
81 | local PlayerDamage_damage_explosion = PlayerDamage.damage_explosion
82 | local PlayerDamage_damage_fire = PlayerDamage.damage_fire
83 |
84 | function PlayerDamage:damage_explosion(attack_data, ...)
85 | local value = PlayerDamage_damage_explosion(self, attack_data, ...)
86 | if alive(self._unit) and (attack_data.position or attack_data.col_ray.position) then
87 | local distance = mvector3.distance(attack_data.position or attack_data.col_ray.position, self._unit:position())
88 | 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
89 | self:_hit_direction(attack_data.position, HUDHitDirection.DAMAGE_TYPES.FRIENDLY_FIRE)
90 | end
91 | end
92 | return value
93 | end
94 |
95 | function PlayerDamage:damage_fire(attack_data, ...)
96 | local value = PlayerDamage_damage_fire(self, attack_data, ...)
97 | if alive(self._unit) and (attack_data.position or attack_data.col_ray.position) then
98 | local distance = mvector3.distance(attack_data.position or attack_data.col_ray.position, self._unit:position())
99 | if self:_chk_can_take_dmg() and (attack_data.range == nil or 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
100 | self:_hit_direction(attack_data.position, HUDHitDirection.DAMAGE_TYPES.FRIENDLY_FIRE)
101 | end
102 | end
103 | return value
104 | end
105 |
106 | function PlayerDamage:_hit_direction(position_vector, damage_type)
107 | if position_vector then
108 | local armor_left, low_health = (self:get_real_armor() > 0), ((self:get_real_health() / self:_max_health()) <= 0.20)
109 | 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
110 | managers.hud:on_hit_direction(position_vector, dmg_type)
111 | end
112 | end
113 | elseif string.lower(RequiredScript) == "lib/units/vehicles/vehicledamage" then
114 | --[[ -- Causes Access violation: Something with the angle calculation of the animation...
115 | function VehicleDamage:_hit_direction(position_vector, damage_type)
116 | if position_vector then
117 | local dmg_type = damage_type or HUDHitDirection.DAMAGE_TYPES.VEHICLE
118 | managers.hud:on_hit_direction(position_vector, dmg_type)
119 | end
120 | end
121 | --]]
122 | end
--------------------------------------------------------------------------------
/lua/DamagePopup.lua:
--------------------------------------------------------------------------------
1 | if RequiredScript == "lib/units/enemies/cop/copdamage" and not CopDamage._damage_popup_loaded then
2 | CopDamage._damage_popup_loaded = true
3 | local _on_damage_received_original = CopDamage._on_damage_received
4 | --Workaround for Teammate Headshots, since col_ray doesn't get forwarded... (self._sync_ibody_popup)
5 | local sync_damage_bullet_original = CopDamage.sync_damage_bullet
6 | local sync_damage_melee_original = CopDamage.sync_damage_melee
7 |
8 | function CopDamage:_on_damage_received(data, ...)
9 | self:_process_popup_damage(data)
10 | self._sync_ibody_popup = nil
11 | return _on_damage_received_original(self, data, ...)
12 | end
13 |
14 | function CopDamage:sync_damage_bullet(attacker_unit, damage_percent, i_body, ...)
15 | if i_body then
16 | self._sync_ibody_popup = i_body
17 | end
18 |
19 | return sync_damage_bullet_original(self, attacker_unit, damage_percent, i_body, ...)
20 | end
21 |
22 | function CopDamage:sync_damage_melee(attacker_unit, damage_percent, damage_effect_percent, i_body, ...)
23 | if i_body then
24 | self._sync_ibody_popup = i_body
25 | end
26 |
27 | return sync_damage_melee_original(self, attacker_unit, damage_percent, damage_effect_percent, i_body, ...)
28 |
29 | end
30 |
31 | function CopDamage:_process_popup_damage(data)
32 | CopDamage.DMG_POPUP_SETTING = WolfHUD:getSetting({"DamagePopup", "DISPLAY_MODE"}, 2)
33 |
34 | local attacker = alive(data.attacker_unit) and data.attacker_unit
35 | local damage = tonumber(data.damage) or 0
36 |
37 | if attacker and damage >= 0.1 and CopDamage.DMG_POPUP_SETTING > 1 then
38 | local killer
39 |
40 | if attacker:in_slot(3) or attacker:in_slot(5) then
41 | --Human team mate
42 | killer = attacker
43 | elseif attacker:in_slot(2) then
44 | --Player
45 | killer = attacker
46 | elseif attacker:in_slot(16) then
47 | --Bot/joker
48 | local key = tostring(attacker:key())
49 | local minion_data = managers.gameinfo and managers.gameinfo:get_minions(key)
50 | if minion_data then
51 | -- Joker
52 | killer = minion_data.owner and managers.criminals:character_unit_by_peer_id(minion_data.owner)
53 | else
54 | -- Bot
55 | killer = attacker
56 | end
57 | elseif attacker:in_slot(12) then
58 | --Enemy
59 | elseif attacker:in_slot(25) then
60 | --Turret
61 | local owner = attacker:base():get_owner_id()
62 | if owner then
63 | killer = managers.criminals:character_unit_by_peer_id(owner)
64 | end
65 | elseif attacker:base().thrower_unit then
66 | killer = attacker:base():thrower_unit()
67 | end
68 |
69 | if alive(killer) and alive(self._unit) then
70 | local body = data.col_ray and data.col_ray.body or self._sync_ibody_popup and self._unit:body(self._sync_ibody_popup)
71 | local headshot = body and self.is_head and self:is_head(body) or false
72 | if CopDamage.DMG_POPUP_SETTING == 2 then
73 | if killer:in_slot(2) then
74 | self:show_popup(damage, self._dead, headshot, data.critical_hit)
75 | end
76 | else
77 | local color_id = managers.criminals:character_color_id_by_unit(killer)
78 | if color_id then
79 | self:show_popup(damage, self._dead, headshot, false, color_id)
80 | end
81 | end
82 | end
83 | end
84 | end
85 |
86 | function CopDamage:show_popup(damage, dead, headshot, critical, color_id)
87 | if managers.waypoints then
88 | local id = "damage_wp_" .. tostring(self._unit:key())
89 | local waypoint = managers.waypoints:get_waypoint(id)
90 | local waypoint_color = color_id and ((color_id == 5 and WolfHUD:getSetting({"CustomHUD", "TEAMMATE", "AI_COLOR", "USE"}, false)) and WolfHUD:getColorSetting({"CustomHUD", "TEAMMATE", "AI_COLOR", "COLOR"}, Color.white) or tweak_data.chat_colors[color_id]) or WolfHUD:getColorSetting({"DamagePopup", critical and "CRITICAL_COLOR" or headshot and "HEADSHOT_COLOR" or "COLOR"}, "yellow")
91 | waypoint_color = waypoint_color:with_alpha(WolfHUD:getSetting({"DamagePopup", "ALPHA"}, 1))
92 | local waypoint_duration = WolfHUD:getSetting({"DamagePopup", "DURATION"}, 3)
93 | if waypoint and not waypoint:is_deleted() then
94 | managers.waypoints:set_waypoint_duration(id, "duration", waypoint_duration)
95 | managers.waypoints:set_waypoint_label(id, "label", self:build_popup_text(damage, headshot))
96 | managers.waypoints:set_waypoint_setting(id, "color", waypoint_color)
97 | managers.waypoints:set_waypoint_component_setting(id, "icon", "show", dead)
98 | else
99 | local params = {
100 | unit = self._unit,
101 | offset = Vector3(10, 10, WolfHUD:getSetting({"DamagePopup", "HEIGHT"}, 20)),
102 | scale = 2 * WolfHUD:getSetting({"DamagePopup", "SCALE"}, 1),
103 | color = waypoint_color,
104 | visible_distance = {
105 | min = 30,
106 | max = 10000
107 | },
108 | rescale_distance = {
109 | start_distance = 500,
110 | end_distance = 3000,
111 | final_scale = 0.5
112 | },
113 | fade_duration = {
114 | start = 0.5,
115 | stop = 1,
116 | alpha = true,
117 | },
118 | icon = {
119 | type = "icon",
120 | show = dead,
121 | scale = WolfHUD:getSetting({"DamagePopup", "SKULL_SCALE"}, 1.2),
122 | texture = "guis/textures/pd2/risklevel_blackscreen",
123 | texture_rect = {0, 0, 64, 64},
124 | blend_mode = "normal",
125 | on_minimap = false
126 | },
127 | label = {
128 | type = "label",
129 | show = true,
130 | text = self:build_popup_text(damage, headshot, true)
131 | },
132 | duration = {
133 | type = "duration",
134 | show = false,
135 | initial_value = waypoint_duration,
136 | fade_duration = {
137 | start = 0,
138 | stop = 1,
139 | position = Vector3(0, 0, 30),
140 | },
141 | },
142 | component_order = { WolfHUD:getSetting({"DamagePopup", "SKULL_ALIGN"}, 1) == 1 and { "icon", "label" } or { "label", "icon" } , { "duration" } }
143 | }
144 | managers.waypoints:add_waypoint(id, "CustomWaypoint", params)
145 | end
146 | end
147 | end
148 |
149 | function CopDamage:build_popup_text(damage, headshot, is_new)
150 | self._dmg_value = (not is_new and self._dmg_value or 0) + (damage * 10)
151 | return math.floor(self._dmg_value) .. ((CopDamage.DMG_POPUP_SETTING == 3 and headshot) and "!" or "")
152 | end
153 |
154 | elseif RequiredScript == "lib/units/civilians/civiliandamage" then
155 | local _on_damage_received_original = CivilianDamage._on_damage_received
156 | function CivilianDamage:_on_damage_received(data, ...)
157 | CivilianDamage.super._process_popup_damage(self, data)
158 | return _on_damage_received_original(self, data, ...)
159 | end
160 | end
161 |
--------------------------------------------------------------------------------
/lua/DownCounter.lua:
--------------------------------------------------------------------------------
1 | --TODO: Add bots? Add player support for standalone version?
2 |
3 | if string.lower(RequiredScript) == "lib/units/beings/player/huskplayermovement" then
4 |
5 | local _perform_movement_action_enter_bleedout_original = HuskPlayerMovement._perform_movement_action_enter_bleedout
6 |
7 | function HuskPlayerMovement:_perform_movement_action_enter_bleedout(...)
8 | if not self._bleedout then
9 | local crim_data = managers.criminals:character_data_by_unit(self._unit)
10 | if crim_data and crim_data.panel_id then
11 | managers.hud:increment_teammate_downs(crim_data.panel_id)
12 | end
13 | end
14 |
15 | return _perform_movement_action_enter_bleedout_original(self, ...)
16 | end
17 | elseif string.lower(RequiredScript) == "lib/network/handlers/unitnetworkhandler" then
18 |
19 | local sync_doctor_bag_taken_original = UnitNetworkHandler.sync_doctor_bag_taken
20 |
21 | function UnitNetworkHandler:sync_doctor_bag_taken(unit, amount, sender, ...)
22 | local peer = self._verify_sender(sender)
23 | if peer then
24 | local crim_data = managers.criminals:character_data_by_peer_id(peer:id())
25 | if crim_data and crim_data.panel_id then
26 | managers.hud:reset_teammate_downs(crim_data.panel_id)
27 | end
28 | end
29 |
30 | return sync_doctor_bag_taken_original(self, unit, amount, sender, ...)
31 | end
32 | elseif string.lower(RequiredScript) == "lib/managers/hudmanagerpd2" then
33 |
34 | HUDManager.DOWNS_COUNTER_PLUGIN = true
35 |
36 | local set_player_health_original = HUDManager.set_player_health
37 | local set_mugshot_custody_original = HUDManager.set_mugshot_custody
38 |
39 | function HUDManager:set_player_health(data, ...)
40 | if data.revives then
41 | self:set_player_revives(HUDManager.PLAYER_PANEL, data.revives - 1)
42 | end
43 | return set_player_health_original(self, data, ...)
44 | end
45 |
46 | function HUDManager:set_mugshot_custody(id, ...)
47 | local data = self:_get_mugshot_data(id)
48 | if data then
49 | local i = managers.criminals:character_data_by_name(data.character_name_id).panel_id
50 | managers.hud:reset_teammate_downs(i)
51 | end
52 |
53 | return set_mugshot_custody_original(self, id, ...)
54 | end
55 |
56 | HUDManager.set_player_revives = HUDManager.set_player_revives or function(self, i, value)
57 | self._teammate_panels[i]:set_revives(value)
58 | end
59 |
60 | HUDManager.increment_teammate_downs = HUDManager.increment_teammate_downs or function(self, i)
61 | self._teammate_panels[i]:increment_downs()
62 | end
63 |
64 | HUDManager.reset_teammate_downs = HUDManager.reset_teammate_downs or function(self, i)
65 | self._teammate_panels[i]:reset_downs()
66 | end
67 |
68 | elseif string.lower(RequiredScript) == "lib/managers/hud/hudteammate" and not HUDManager.CUSTOM_TEAMMATE_PANELS then
69 |
70 | Hooks:PostHook( HUDTeammate, "init", "WolfHUD_DownCounter_HUDTeammate_init", function(self, ...)
71 | self._health_panel = self._health_panel or self._player_panel:child("radial_health_panel")
72 | self._condition_icon = self._condition_icon or self._panel:child("condition_icon")
73 |
74 | self._max_downs = (Global.game_settings.one_down and 2 or tweak_data.player.damage.LIVES_INIT) - 1
75 | if managers.modifiers and managers.modifiers.modify_value then
76 | self._max_downs = managers.modifiers:modify_value("PlayerDamage:GetMaximumLives", self._max_downs)
77 | end
78 | self._max_downs = self._max_downs + (self._main_player and managers.player:upgrade_value("player", "additional_lives", 0) or 0)
79 | self._downs = self._main_player and self._max_downs or 0
80 |
81 | self._setting_prefix = self._main_player and "PLAYER" or "TEAMMATE"
82 |
83 | self._health_panel:bitmap({
84 | name = "risk_indicator_bg",
85 | texture = "guis/textures/pd2/crimenet_marker_glow",
86 | texture_rect = { 0, 0, 64, 64 },
87 | blend_mode = "normal",
88 | color = Color.black,
89 | alpha = 0.6,
90 | w = self._health_panel:w(),
91 | h = self._health_panel:h(),
92 | layer = 1,
93 | })
94 |
95 | self._downs_counter = self._health_panel:text({
96 | name = "downs",
97 | text = tostring(self._downs),
98 | color = Color.white,
99 | align = "center",
100 | vertical = "center",
101 | w = self._health_panel:w(),
102 | h = self._health_panel:h(),
103 | font_size = self._main_player and 15 or 12,
104 | font = tweak_data.menu.pd2_medium_font,
105 | layer = 2,
106 | visible = HUDManager.DOWNS_COUNTER_PLUGIN and WolfHUD:getSetting({"CustomHUD", self._setting_prefix, "DOWNCOUNTER"}, true) and not self._ai or false,
107 | })
108 |
109 | self._detection_counter = self._health_panel:text({
110 | name = "detection",
111 | text = utf8.char(57363),
112 | color = Color.red,
113 | align = "center",
114 | vertical = "center",
115 | w = self._health_panel:w(),
116 | h = self._health_panel:h(),
117 | font_size = self._main_player and 15 or 12,
118 | font = tweak_data.menu.pd2_medium_font,
119 | layer = 2,
120 | visible = HUDManager.DOWNS_COUNTER_PLUGIN and WolfHUD:getSetting({"CustomHUD", self._setting_prefix, "DOWNCOUNTER"}, true) and not self._ai or false,
121 | })
122 |
123 | self:set_detection()
124 |
125 | if managers.gameinfo then
126 | managers.gameinfo:register_listener("HealthRadial_whisper_mode_listener" .. tostring(self._id), "whisper_mode", "change", callback(self, self, "_whisper_mode_change"), nil, true)
127 | end
128 | end)
129 |
130 | Hooks:PostHook( HUDTeammate, "remove_panel", "WolfHUD_DownCounter_HUDTeammate_remove_panel", function(self, ...)
131 | managers.gameinfo:unregister_listener("HealthRadial_whisper_mode_listener" .. tostring(self._id), "whisper_mode", "change")
132 | end)
133 |
134 | Hooks:PostHook( HUDTeammate, "set_peer_id", "WolfHUD_DownCounter_HUDTeammate_set_peer_id", function(self, ...)
135 | self:set_detection()
136 | end)
137 |
138 | Hooks:PostHook( HUDTeammate, "set_callsign", "WolfHUD_DownCounter_HUDTeammate_set_callsign", function(self, ...)
139 | if self._main_player then
140 | self:set_detection()
141 | end
142 | end)
143 |
144 | Hooks:PreHook( HUDTeammate, "set_name", "WolfHUD_DownCounter_HUDTeammate_set_name", function(self, teammate_name, ...)
145 | if teammate_name ~= self._name then
146 | self._name = teammate_name
147 | self:reset_downs()
148 | end
149 | end)
150 |
151 | function HUDTeammate:_whisper_mode_change(status)
152 | local disabled = self._condition_icon and self._condition_icon:visible() or not (HUDManager.DOWNS_COUNTER_PLUGIN and WolfHUD:getSetting({"CustomHUD", self._setting_prefix, "DOWNCOUNTER"}, true)) or self._ai
153 | self._downs_counter:set_visible(not disabled and (not status or self:down_amount() > 0))
154 | self._detection_counter:set_visible(not disabled and not self._downs_counter:visible())
155 | end
156 |
157 | HUDTeammate.set_downs = HUDTeammate.set_downs or function(self, amount)
158 | if amount and self._downs ~= amount then
159 | self._downs = amount
160 | self._downs_counter:set_text(tostring(self._downs))
161 | local progress = math.clamp(self:down_amount() / self._max_downs, 0, 1)
162 | self._downs_counter:set_color(math.lerp(Color.white, Color(1, 1, 0.2, 0), progress))
163 | local disabled = self._condition_icon and self._condition_icon:visible() or not (HUDManager.DOWNS_COUNTER_PLUGIN and WolfHUD:getSetting({"CustomHUD", self._setting_prefix, "DOWNCOUNTER"}, true)) or self._ai
164 | self._downs_counter:set_visible(not disabled and (not managers.groupai:state():whisper_mode() or self:down_amount() > 0))
165 | self._detection_counter:set_visible(not disabled and not self._downs_counter:visible())
166 | end
167 | end
168 |
169 | HUDTeammate.set_revives = HUDTeammate.set_revives or function(self, value)
170 | self:set_downs(value)
171 | end
172 |
173 | HUDTeammate.increment_downs = HUDTeammate.increment_downs or function(self)
174 | self:set_downs(self._downs + 1)
175 | end
176 |
177 | HUDTeammate.reset_downs = HUDTeammate.reset_downs or function(self)
178 | self:set_downs((self._main_player and self._max_downs) or 0)
179 | end
180 |
181 | HUDTeammate.down_amount = HUDTeammate.down_amount or function(self)
182 | return self._main_player and self._max_downs - self._downs or self._downs
183 | end
184 |
185 | HUDTeammate.set_detection = HUDTeammate.set_detection or function(self, risk)
186 | if not risk then
187 | if self._main_player then
188 | risk = tonumber(string.format("%.0f", managers.blackmarket:get_suspicion_offset_of_local(tweak_data.player.SUSPICION_OFFSET_LERP or 0.75) * 100))
189 | elseif self:peer_id() then
190 | 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))
191 | end
192 | end
193 | if not self._risk or risk and risk ~= self._risk then
194 | self._risk = risk
195 | if self._risk then
196 | local color = self._risk < 50 and Color(1, 0, 0.8, 1) or Color(1, 1, 0.2, 0)
197 | self._detection_counter:set_text(utf8.char(57363) .. tostring(self._risk))
198 | self._detection_counter:set_color(color)
199 | end
200 | local disabled = self._condition_icon and self._condition_icon:visible() or not (HUDManager.DOWNS_COUNTER_PLUGIN and WolfHUD:getSetting({"CustomHUD", self._setting_prefix, "DOWNCOUNTER"}, true)) or self._ai
201 | self._downs_counter:set_visible(not disabled and (not managers.groupai:state():whisper_mode() or self:down_amount() > 0))
202 | self._detection_counter:set_visible(not disabled and not self._downs_counter:visible())
203 | end
204 | end
205 | end
206 |
--------------------------------------------------------------------------------
/lua/EnemyHealthbar.lua:
--------------------------------------------------------------------------------
1 | if string.lower(RequiredScript) == "lib/managers/hudmanager" 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 = "fonts/font_medium_shadow_mf",
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 = "fonts/font_medium_mf",
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 = WolfHUD:getSetting({"EnemyHealthbar", "SHOW_POINTER"}, false),
65 | alpha = 0.75,
66 | halign = "center",
67 | font = "fonts/font_medium_shadow_mf",
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 WolfHUD:getSetting({"EnemyHealthbar", "ENABLED"}, true) then
105 |
106 | self._unit_health_visible = true
107 | self._unit_health_enemy_location:set_visible(WolfHUD: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 | end
135 |
136 | function HUDManager:set_unit_health( current , total , tweak_table )
137 |
138 | if not current or not total then return end
139 |
140 | local enemy = WolfHUD:getCharacterName(tweak_table, true)
141 | if enemy == tweak_table and managers.localization:exists(tweak_table) then
142 | enemy = managers.localization:to_upper_text(tweak_table)
143 | end
144 |
145 | total = math.min(total, 999999999)
146 | current = math.clamp(current, 0, total)
147 | local _r = current / total
148 |
149 | local r = self._unit_bar:width()
150 | local rn = ( self._unit_bar_bg:w() - 4 ) * _r
151 |
152 | self._unit_health_enemy_text:set_text( enemy )
153 | if total > 0 then
154 | 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)) ) )
155 | else
156 | self._unit_health_text:set_text( string.format( "%s" , managers.money:add_decimal_marks_to_string(tostring(current)) ) )
157 | end
158 |
159 | local _ ,_ ,hw ,hh = self._unit_health_text:text_rect()
160 | local _ ,_ ,ew ,eh = self._unit_health_enemy_text:text_rect()
161 |
162 | self._unit_health_text:set_size( hw , hh )
163 | self._unit_health_enemy_text:set_size( ew , eh )
164 |
165 | self._unit_health_text:set_right( self._unit_bar_bg:right() )
166 | self._unit_health_text:set_bottom( self._unit_bar_bg:top() )
167 | self._unit_health_enemy_text:set_left( self._unit_bar_bg:left() )
168 | self._unit_health_enemy_text:set_bottom( self._unit_bar_bg:top() )
169 |
170 | self._unit_health_text:set_color( _r <= 0.1 and Color.red or _r <= 0.25 and Color.yellow or Color.white )
171 |
172 | self._unit_bar:stop()
173 |
174 | self._bar_text_rect = self._shield and self._shield_text_rect or self._health_text_rect
175 |
176 | self._unit_bar:animate( function( p )
177 | if rn < r then
178 | over( 0.2 , function( o )
179 | self._unit_bar:set_w( math.lerp( r , rn , o ) )
180 | 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] )
181 | end )
182 | end
183 |
184 | self._unit_bar:set_w( _r * ( self._bar_text_rect[3] - 2 ) )
185 | 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] )
186 | end )
187 | end
188 |
189 | function HUDManager:set_unit_health_rotation( angle )
190 | self._unit_health_enemy_location:set_rotation( angle )
191 | end
192 |
193 | elseif string.lower(RequiredScript) == "lib/units/beings/player/states/playerstandard" then
194 | Hooks:PostHook( PlayerStandard , "_update_fwd_ray" , "WolfHUDPostPlayerStandardUpdate" , function( self , t , dt )
195 | if self._fwd_ray and self._fwd_ray.unit and type(self._fwd_ray.unit) == "userdata" then
196 | local unit = self._fwd_ray.unit
197 | if unit:in_slot( 8 ) and alive(unit:parent()) then -- Fix when aiming at shields shield.
198 | unit = unit:parent()
199 | end
200 |
201 | local visible, name, name_id, health, max_health, shield
202 | if alive( unit ) and unit:character_damage() then
203 | if unit:in_slot( 25 ) and not unit:character_damage():dead() and (table.contains(managers.groupai:state():turrets() or {}, unit) or WolfHUD:getSetting({"EnemyHealthbar", "SHOW_CIVILIAN"}, true) and Network:is_server()) then
204 | self._last_unit = nil
205 | visible = true
206 | name_id = unit:base() and unit:base():get_name_id() or "TURRET"
207 | if not unit:character_damage():needs_repair() then
208 | shield = true
209 | health = unit:character_damage()._shield_health * 10 or 0
210 | max_health = unit:character_damage()._SHIELD_HEALTH_INIT * 10 or 0
211 | else
212 | health = unit:character_damage()._health * 10 or 0
213 | max_health = unit:character_damage()._HEALTH_INIT * 10 or 0
214 | end
215 | elseif alive( unit ) and ( unit:in_slot( 12 ) or WolfHUD:getSetting({"EnemyHealthbar", "SHOW_CIVILIAN"}, false) and ( unit:in_slot( 21 ) or unit:in_slot( 22 ) ) or unit:in_slot( 16 ) and Network:is_server()) and not unit:character_damage():dead() then
216 | self._last_unit = unit
217 | visible = true
218 | health = unit:character_damage()._health * 10 or 0
219 | max_health = unit:character_damage()._HEALTH_INIT * 10 or 0
220 | name_id = unit:base() and unit:base()._tweak_table or "ENEMY"
221 |
222 | if name_id == "robbers_safehouse" and unit:interaction() then
223 | name_id = CriminalsManager.convert_new_to_old_character_workname(unit:interaction().character or name_id)
224 | end
225 | elseif alive( unit ) and unit:in_slot( 39 ) and WolfHUD:getSetting({"EnemyHealthbar", "SHOW_VEHICLE"}, true) and unit:vehicle_driving() and not self._seat then
226 | self._last_unit = nil
227 | visible = true
228 | health = unit:character_damage()._health or 0
229 | max_health = unit:character_damage()._current_max_health or 0
230 | name = unit:vehicle_driving()._tweak_data.name_id and managers.localization:text(unit:vehicle_driving()._tweak_data.name_id) or "VEHICLE"
231 | else
232 | visible = false
233 | end
234 | end
235 |
236 | if not visible and self._last_unit and alive( self._last_unit ) then
237 | health = self._last_unit:character_damage()._health * 10 or 0
238 | max_health = self._last_unit:character_damage()._HEALTH_INIT * 10 or 0
239 | name_id = self._last_unit:base() and self._last_unit:base()._tweak_table or "ENEMY"
240 |
241 | if name_id == "robbers_safehouse" and self._last_unit:interaction() then
242 | name_id = CriminalsManager.convert_new_to_old_character_workname(self._last_unit:interaction().character or name_id)
243 | end
244 |
245 | local angle = (self:getUnitRotation(self._last_unit) + 360) % 360
246 | if self._last_unit:character_damage():dead() or (angle < 350 and angle > 10) then
247 | visible = false
248 | self._last_unit = nil
249 | else
250 | visible = true
251 | end
252 |
253 | managers.hud:set_unit_health_rotation( 360 - angle )
254 | else
255 | managers.hud:set_unit_health_rotation(0)
256 | end
257 |
258 | managers.hud:set_unit_health_visible( visible, shield )
259 | if health and name_id then
260 | managers.hud:set_unit_health( math.floor(health or 0) , math.floor(max_health or 0) , name_id or string.upper(name or "UNKNOWN"))
261 | end
262 | else
263 | managers.hud:set_unit_health_visible( false )
264 | end
265 |
266 | end )
267 |
268 | function PlayerStandard:getUnitRotation( unit )
269 |
270 | if not unit or not alive( unit ) then return 360 end
271 |
272 | local unit_position = unit:position()
273 | local vector = unit_position - self._camera_unit:position()
274 | local forward = self._camera_unit:rotation():y()
275 | local rotation = math.floor( vector:to_polar_with_reference( forward , math.UP ).spin )
276 |
277 | return rotation
278 |
279 | end
280 | elseif string.lower(RequiredScript) == "lib/states/ingamearrested" then
281 | Hooks:PostHook( IngameArrestedState , "at_enter" , "WolfHUDPostIngameArrestedAtEnter" , function( self )
282 | if managers.hud then
283 | managers.hud:set_unit_health_visible( false, false )
284 | end
285 | end )
286 | end
287 |
--------------------------------------------------------------------------------
/lua/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 | function HUDObjectives:init(hud)
9 | if alive(self._panel) then
10 | hud.panel:remove(self._panel)
11 | end
12 |
13 | self._panel = hud.panel:panel({
14 | visible = false,
15 | name = "objectives_panel",
16 | h = 130,
17 | w = 400,
18 | x = (WolfHUD:getSetting({"TabStats", "CLOCK_MODE"}, 3) == 4) and 0 or 80,
19 | valign = "top"
20 | })
21 |
22 | self._bg_box = HUDBGBox_create(self._panel, {
23 | w = 400,
24 | h = 38,
25 | })
26 |
27 | self._objective_text = self._bg_box:text({
28 | name = "objective_text",
29 | visible = false,
30 | layer = 2,
31 | color = Color.white,
32 | text = "",
33 | font_size = HUDObjectives._FONT_SIZE,
34 | font = tweak_data.hud.medium_font_noshadow,
35 | align = "left",
36 | vertical = "center",
37 | w = self._bg_box:w(),
38 | x = HUDObjectives._TEXT_MARGIN,
39 | y = HUDObjectives._TEXT_MARGIN,
40 | wrap = false,
41 | word_wrap = false
42 | })
43 |
44 | self._amount_text = self._bg_box:text({
45 | name = "amount_text",
46 | visible = false,
47 | layer = 2,
48 | color = Color.white,
49 | text = "",
50 | font_size = HUDObjectives._FONT_SIZE,
51 | font = tweak_data.hud.medium_font_noshadow,
52 | align = "left",
53 | vertical = "center",
54 | w = self._bg_box:w(),
55 | h = HUDObjectives._FONT_SIZE,
56 | x = HUDObjectives._TEXT_MARGIN,
57 | y = HUDObjectives._TEXT_MARGIN
58 | })
59 |
60 | self:apply_offset(0)
61 | end
62 |
63 | function HUDObjectives:activate_objective(data)
64 | self._active_objective_id = data.id
65 | self._panel:set_visible(true)
66 | self._objective_text:set_visible(true)
67 | self._amount_text:set_visible(false)
68 |
69 | local width, height, wrapped_text = self:_get_wrapped_text_dimensions(utf8.to_upper(data.text))
70 |
71 | self._objective_text:set_text(wrapped_text)
72 | self._objective_text:set_w(width)
73 | self._objective_text:set_h(height)
74 | self._bg_box:set_h(HUDObjectives._TEXT_MARGIN * 2 + height)
75 |
76 | if data.amount then
77 | self:update_amount_objective(data, true)
78 | else
79 | self._amount_text:set_text("")
80 | self._bg_box:set_w(HUDObjectives._TEXT_MARGIN * 2 + width)
81 | end
82 | if not self._active_move then
83 | self._bg_box:stop()
84 | self._bg_box:animate(callback(self, self, "_animate_update_objective"))
85 | end
86 |
87 | self:apply_offset(self._offset_y)
88 | end
89 |
90 | function HUDObjectives:update_amount_objective(data, hide_animation)
91 | if data.id ~= self._active_objective_id then
92 | return
93 | end
94 | local amount = (data.current_amount or 0)
95 | self._amount_text:set_text(amount .. "/" .. data.amount)
96 | self._amount_text:set_left(self._objective_text:right() + HUDObjectives._TEXT_MARGIN)
97 | self._amount_text:set_bottom(self._objective_text:h() + HUDObjectives._TEXT_MARGIN)
98 | self._bg_box:set_w(HUDObjectives._TEXT_MARGIN * 3 + self._objective_text:w() + self:_get_text_dimensions(self._amount_text:text()).w)
99 | self._amount_text:set_visible(true)
100 | self._amount_text:stop()
101 | if not hide_animation and amount > 0 then
102 | self._amount_text:animate(callback(self, self, "_animate_new_amount"))
103 | else
104 | self._amount_text:set_color(Color(1, 1, 1, 1))
105 | end
106 | end
107 |
108 | function HUDObjectives:remind_objective(id)
109 | if id ~= self._active_objective_id then
110 | return
111 | end
112 | if not self._active_move then
113 | self._bg_box:stop()
114 | self._bg_box:animate(callback(self, self, "_animate_update_objective"))
115 | end
116 | end
117 |
118 | function HUDObjectives:complete_objective(data)
119 | if data.id ~= self._active_objective_id then
120 | return
121 | end
122 |
123 | self._active_objective_id = ""
124 | self._amount_text:set_visible(false)
125 | self._objective_text:set_visible(false)
126 | self._panel:set_visible(false)
127 | self._bg_box:set_w(0)
128 |
129 | self:apply_offset(self._offset_y)
130 | end
131 |
132 | function HUDObjectives:_animate_new_amount(object)
133 | local TOTAL_T = 2
134 | local t = TOTAL_T
135 | object:set_color(Color(1, 1, 1, 1))
136 | while t > 0 do
137 | local dt = coroutine.yield()
138 | t = t - dt
139 | object:set_color(Color(1, 1 , 1, 1 - (0.5 * math.sin(t * 360 * 2) + 0.5)))
140 | end
141 | object:set_color(Color(1, 1, 1, 1))
142 | end
143 |
144 | function HUDObjectives:_animate_update_objective(object)
145 | local TOTAL_T = 2
146 | local t = TOTAL_T
147 | object:set_y(self._offset_y or 0)
148 | while t > 0 do
149 | local dt = coroutine.yield()
150 | t = t - dt
151 | object:set_y((self._offset_y or 0) + math.round((1 + math.sin((TOTAL_T - t) * 450 * 2)) * (HUDObjectives._BOUNCE * (t / TOTAL_T))))
152 | end
153 | object:set_y(self._offset_y or 0)
154 | end
155 |
156 | function HUDObjectives:_get_text_dimensions(text_string)
157 | local string_width_measure_text_field = self._panel:child("string_dimensions") or self._panel:text({
158 | name = "string_dimensions",
159 | visible = false,
160 | font_size = HUDObjectives._FONT_SIZE,
161 | font = tweak_data.hud.medium_font_noshadow,
162 | align = "left",
163 | vertical = "center",
164 | wrap = false
165 | })
166 | string_width_measure_text_field:set_text(text_string)
167 | local x, y, w, h = string_width_measure_text_field:text_rect()
168 | return {x = x, y = y, w = w, h = h}
169 | end
170 |
171 | function HUDObjectives:_get_wrapped_text_dimensions(text_string)
172 | local layout_text_field = self._panel:child("layout") or self._panel:text({
173 | name = "layout",
174 | width = self._MAX_WIDTH,
175 | visible = false,
176 | font_size = HUDObjectives._FONT_SIZE,
177 | font = tweak_data.hud.medium_font_noshadow,
178 | align = "left",
179 | vertical = "center",
180 | wrap = true,
181 | word_wrap = true
182 | })
183 | layout_text_field:set_text(text_string)
184 | local line_breaks = table.collect(layout_text_field:line_breaks(), function(index)
185 | return index + 1
186 | end)
187 | local wrapped_lines = {}
188 | for line = 1, #line_breaks do
189 | local range_start = line_breaks[line]
190 | local range_end = line_breaks[line + 1]
191 | local string_range = utf8.sub(text_string, range_start, (range_end or 0) - 1)
192 | table.insert(wrapped_lines, string.trim(string_range))
193 | end
194 | local wrapped_text = ""
195 | local w, h = 0, layout_text_field:font_size() * math.max(#wrapped_lines, 1)
196 | for _, line in ipairs(wrapped_lines) do
197 | w = math.max(w, self:_get_text_dimensions(line).w)
198 | wrapped_text = string.format("%s%s\n", wrapped_text, line)
199 | end
200 | return math.ceil(w), math.ceil(h), wrapped_text
201 | end
202 |
203 | function HUDObjectives:apply_offset(offset)
204 | if offset and offset ~= self._offset_y then
205 | self._offset_y = offset
206 | if alive(self._bg_box) then
207 | self._bg_box:stop()
208 | self._bg_box:animate(callback(self, self, "_animate_move"), self._bg_box:x(), self._offset_y, true)
209 | self._panel:animate(callback(self, self, "_animate_move"), (self._offset_y > 40 or WolfHUD:getSetting({"TabStats", "CLOCK_MODE"}, 3) == 4) and 0 or 80, self._panel:y(), true)
210 | end
211 | end
212 | if managers.hud and managers.hud.change_list_setting then
213 | managers.hud:change_list_setting("left_list_height_offset", self._offset_y + (self._bg_box:w() > 0 and (self._bg_box:h() + HUDObjectives._BOUNCE) or 40) + HUDObjectives._TEXT_MARGIN)
214 | end
215 | end
216 |
217 | function HUDObjectives:_animate_move(panel, x, y, instant)
218 | self._active_move = true
219 | if not instant then
220 | local move_speed = 150
221 | local init_x = panel:x()
222 | local init_y = panel:y()
223 | local x_change = x > init_x and 1 or x < init_x and -1
224 | local y_change = y > init_y and 1 or y < init_y and -1
225 | local T = math.max(math.abs(x - init_x) / move_speed, math.abs(y - init_y) / move_speed)
226 | local t = 0
227 |
228 | while alive(panel) and t < T do
229 | if x_change then
230 | panel:set_x(init_x + t * x_change * move_speed)
231 | end
232 | if y_change then
233 | panel:set_y(init_y + t * y_change * move_speed)
234 | end
235 | t = t + coroutine.yield()
236 | end
237 | end
238 |
239 | if alive(panel) then
240 | panel:set_x(x)
241 | panel:set_y(y)
242 | end
243 | self._active_move = nil
244 | end
245 |
246 | elseif string.lower(RequiredScript) == "lib/managers/hud/hudheisttimer" then
247 |
248 | function HUDHeistTimer:init(hud, tweak_hud)
249 | self._hud_panel = hud.panel
250 | self._enabled = (WolfHUD:getSetting({"TabStats", "CLOCK_MODE"}, 3) ~= 4) and not (tweak_hud and tweak_hud.no_timer)
251 | if self._hud_panel:child("heist_timer_panel") then
252 | self._hud_panel:remove(self._hud_panel:child("heist_timer_panel"))
253 | end
254 |
255 | self._heist_timer_panel = self._hud_panel:panel({
256 | visible = self._enabled,
257 | name = "heist_timer_panel",
258 | h = 40,
259 | w = 80,
260 | valign = "top",
261 | layer = 0
262 | })
263 | self._timer_text = self._heist_timer_panel:text({
264 | name = "timer_text",
265 | text = "00:00:00",
266 | font_size = tweak_data.hud.medium_deafult_font_size,
267 | font = tweak_data.hud.medium_font_noshadow,
268 | color = Color.white,
269 | align = "center",
270 | vertical = "center",
271 | layer = 1,
272 | wrap = false,
273 | word_wrap = false
274 | })
275 |
276 | self._last_time = 0
277 | end
278 | elseif string.lower(RequiredScript) == "core/lib/managers/subtitle/coresubtitlepresenter" then
279 | core:module("CoreSubtitlePresenter")
280 | local _on_resolution_changed_original = OverlayPresenter._on_resolution_changed
281 | function OverlayPresenter:_on_resolution_changed(...)
282 | _on_resolution_changed_original(self, ...)
283 | self:apply_bottom_offset()
284 | end
285 |
286 | function OverlayPresenter:set_bottom(offset)
287 | if self._bottom_off ~= offset then
288 | self._bottom_off = offset
289 | self:apply_bottom_offset()
290 | end
291 | end
292 |
293 | function OverlayPresenter:apply_bottom_offset()
294 | if self.__subtitle_panel and self._bottom_off then
295 | self.__subtitle_panel:set_height(self._bottom_off or self.__subtitle_panel:h())
296 | local label = self.__subtitle_panel:child("label")
297 | if label then
298 | label:set_h(self.__subtitle_panel:h())
299 | label:set_w(self.__subtitle_panel:w())
300 | end
301 | local shadow = self.__subtitle_panel:child("shadow")
302 | if shadow then
303 | shadow:set_h(self.__subtitle_panel:h())
304 | shadow:set_w(self.__subtitle_panel:w())
305 | end
306 | end
307 | end
308 | end
309 |
--------------------------------------------------------------------------------
/lua/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 WolfHUD: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 WolfHUD: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 WolfHUD: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 = WolfHUD:getTweakEntry("STEALTH_SHAPED_CHARGE_TIMEOUT", "number", 0.25) --Timeout for 2 InteractKey pushes, to prevent accidents in stealth
71 | BaseInteractionExt.KEYCARD_DOORS_TIMEOUT = WolfHUD: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 WolfHUD: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 WolfHUD: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 WolfHUD: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 WolfHUD: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
--------------------------------------------------------------------------------
/lua/KillCounter.lua:
--------------------------------------------------------------------------------
1 | if RequiredScript == "lib/units/enemies/cop/copdamage" and not CopDamage._kill_counter_loaded then
2 | CopDamage._kill_counter_loaded = true
3 |
4 | --This needs fixing for DoT kills (then again, so does the games own kill counter) as client somehow and a lot of testing
5 |
6 | --[[
7 | local chk_killshot_original = CopDamage.chk_killshot
8 |
9 | function CopDamage:chk_killshot(attacker_unit, variant)
10 | --printf("chk_killshot: %s\n", tostring(attacker_unit and attacker_unit:slot()))
11 |
12 | if alive(attacker_unit) then
13 | local source = "direct/unknown"
14 | local killer = attacker_unit
15 |
16 | if attacker_unit:in_slot(14) then
17 | if attacker_unit:base().thrower_unit then
18 | source = "throwable"
19 | killer = attacker_unit:base():thrower_unit()
20 | end
21 | elseif attacker_unit:in_slot(25) then
22 | if attacker_unit:base().sentry_gun then
23 | local owner = attacker_unit:base()._owner_id
24 | if owner then
25 | source = "sentry"
26 | killer = managers.criminals:character_unit_by_peer_id(owner)
27 | end
28 | end
29 | end
30 |
31 | if killer then
32 | if killer:in_slot(3) then
33 | --printf("Teammate kill (%s)\n", source)
34 | local crim_data = managers.criminals:character_data_by_unit(killer)
35 | if crim_data and crim_data.panel_id then
36 | managers.hud:increment_teammate_kill_count(crim_data.panel_id, managers.groupai:state():is_enemy_special(self._unit))
37 | end
38 | elseif killer:in_slot(2) then
39 | --printf("Player kill (%s)\n", source)
40 | managers.hud:increment_teammate_kill_count(HUDManager.PLAYER_PANEL, managers.groupai:state():is_enemy_special(self._unit))
41 | elseif killer:in_slot(16) then
42 | printf("Bot/joker kill (%s)\n", source)
43 | local crim_data = managers.criminals:character_data_by_unit(killer)
44 | if crim_data and crim_data.panel_id then
45 | managers.hud:increment_teammate_kill_count(crim_data.panel_id, managers.groupai:state():is_enemy_special(self._unit))
46 | end
47 | elseif killer:in_slot(12) then
48 | --printf("Enemy kill (%s)\n", source)
49 | else
50 | printf("UNKNOWN KILL (%d / %s)\n", killer:slot(), source)
51 | end
52 | else
53 | printf("UNKNOWN KILL (no killer, attacker unit: %d)\n", attacker_unit:slot())
54 | end
55 | end
56 |
57 | return chk_killshot_original(self, attacker_unit, variant)
58 | end
59 | ]]
60 |
61 | local _on_damage_received_original = CopDamage._on_damage_received
62 | --Workaround for Teammate Headshots, since col_ray doesn't get forwarded... (self._sync_ibody_killcount)
63 | local sync_damage_bullet_original = CopDamage.sync_damage_bullet
64 | local sync_damage_melee_original = CopDamage.sync_damage_melee
65 |
66 | function CopDamage:_process_kill(data)
67 | local killer
68 |
69 | local attacker = alive(data.attacker_unit) and data.attacker_unit
70 |
71 | if attacker then
72 | if attacker:in_slot(3) or attacker:in_slot(5) then
73 | --Human team mate
74 | killer = attacker
75 | elseif attacker:in_slot(2) then
76 | --Player
77 | killer = attacker
78 | elseif attacker:in_slot(16) then
79 | --Bot/joker
80 | killer = attacker
81 | elseif attacker:in_slot(12) then
82 | --Enemy
83 | elseif attacker:in_slot(25) then
84 | --Turret
85 | local owner = attacker:base():get_owner_id()
86 | if owner then
87 | killer = managers.criminals:character_unit_by_peer_id(owner)
88 | end
89 | elseif attacker:base().thrower_unit then
90 | killer = attacker:base():thrower_unit()
91 | end
92 |
93 | if alive(killer) and alive(self._unit) then
94 | local tweak_id = self._unit:base()._tweak_table
95 | local special_unit_ids = managers.statistics and managers.statistics.special_unit_ids or {}
96 | local is_special = managers.groupai:state():is_enemy_special(self._unit) or table.contains(special_unit_ids, tweak_id)
97 | local body = data.col_ray and data.col_ray.body or self._sync_ibody_killcount and self._unit:body(self._sync_ibody_killcount)
98 | local headshot = body and self.is_head and self:is_head(body) or false
99 |
100 | if killer:in_slot(2) then
101 | managers.hud:increment_teammate_kill_count(HUDManager.PLAYER_PANEL, is_special, headshot)
102 |
103 | local current_player_state = managers.player and managers.player:get_current_state()
104 | local weapon_base = current_player_state and current_player_state._equipped_unit:base()
105 | local projectile_name = "bullet"
106 | if weapon_base._projectile_type_index then
107 | projectile_name = tweak_data and tweak_data:get_raw_value("blackmarket", "projectiles", "_projectiles_index", weapon_base._projectile_type_index)
108 | end
109 | if projectile_name == (data.variant or "") then
110 | local weapon_id = weapon_base:get_name_id()
111 | local weapon_tweak = weapon_base and weapon_base:weapon_tweak_data()
112 | local weapon_type = weapon_tweak.category
113 | local slot = weapon_tweak and weapon_tweak.use_data and weapon_tweak.use_data.selection_index
114 | managers.hud:increment_teammate_kill_count_detailed(HUDManager.PLAYER_PANEL, self._unit, weapon_id, weapon_type, slot)
115 | end
116 | else
117 | local crim_data = managers.criminals:character_data_by_unit(killer)
118 | if crim_data and crim_data.panel_id then
119 | managers.hud:increment_teammate_kill_count(crim_data.panel_id, is_special, headshot)
120 | end
121 | end
122 | end
123 | end
124 | end
125 |
126 | function CopDamage:_on_damage_received(data, ...)
127 | if self._dead then
128 | self:_process_kill(data)
129 | end
130 | self._sync_ibody_killcount = nil
131 | return _on_damage_received_original(self, data, ...)
132 | end
133 |
134 | function CopDamage:sync_damage_bullet(attacker_unit, damage_percent, i_body, ...)
135 | if i_body then
136 | self._sync_ibody_killcount = i_body
137 | end
138 |
139 | return sync_damage_bullet_original(self, attacker_unit, damage_percent, i_body, ...)
140 | end
141 |
142 | function CopDamage:sync_damage_melee(attacker_unit, damage_percent, damage_effect_percent, i_body, ...)
143 | if i_body then
144 | self._sync_ibody_killcount = i_body
145 | end
146 |
147 | return sync_damage_melee_original(self, attacker_unit, damage_percent, damage_effect_percent, i_body, ...)
148 |
149 | end
150 |
151 | --TODO: Add sync damage checks for non-local bots and players
152 |
153 | elseif RequiredScript == "lib/units/equipment/sentry_gun/sentrygunbase" then
154 |
155 | local sync_setup_original = SentryGunBase.sync_setup
156 |
157 | function SentryGunBase:sync_setup(upgrade_lvl, peer_id, ...)
158 | sync_setup_original(self, upgrade_lvl, peer_id, ...)
159 | self._owner_id = self._owner_id or peer_id
160 | end
161 |
162 | elseif RequiredScript == "lib/managers/statisticsmanager" then
163 |
164 | local shot_fired_original = StatisticsManager.shot_fired
165 |
166 | function StatisticsManager:shot_fired(data, ...)
167 | shot_fired_original(self, data, ...)
168 |
169 | --[[
170 | This does not work well for HE rounds. It would be almost correct if you halved number of shots,
171 | but would not take into account shots that goes into the void or compensate for direct hits
172 | ]]
173 |
174 | local name_id = data.name_id or data.weapon_unit:base():get_name_id()
175 | local weapon_tweak = tweak_data.weapon[name_id]
176 | local slot = weapon_tweak and weapon_tweak.use_data and weapon_tweak.use_data.selection_index
177 | if slot then --Exclude throwables like exploding cards mod...
178 | local weapon_data = name_id and self._global.session.shots_by_weapon[name_id]
179 | local weapon_accuracy = 0
180 | if weapon_data and weapon_data.total > 0 then
181 | weapon_accuracy = math.floor(100 * weapon_data.hits / weapon_data.total)
182 | end
183 | managers.hud:set_teammate_weapon_accuracy(HUDManager.PLAYER_PANEL, slot, weapon_accuracy)
184 | end
185 |
186 | managers.hud:set_teammate_accuracy(HUDManager.PLAYER_PANEL, self:session_hit_accuracy())
187 | end
188 |
189 | elseif RequiredScript == "lib/managers/hudmanagerpd2" then
190 |
191 | HUDManager.KILL_COUNTER_PLUGIN = true
192 | HUDManager.ACCURACY_PLUGIN = true
193 |
194 | HUDManager.increment_teammate_kill_count = HUDManager.increment_teammate_kill_count or function (self, i, is_special, headshot)
195 | self._teammate_panels[i]:increment_kill_count(is_special, headshot)
196 | end
197 |
198 | HUDManager.reset_teammate_kill_count = HUDManager.reset_teammate_kill_count or function(self, i)
199 | self._teammate_panels[i]:reset_kill_count()
200 | end
201 |
202 | HUDManager.increment_teammate_kill_count_detailed = HUDManager.increment_teammate_kill_count_detailed or function(self, i, unit, weapon_id, weapon_type, weapon_slot)
203 | --TODO: Add call for default HUD | No need for that, really...
204 | end
205 |
206 | HUDManager.set_teammate_accuracy = HUDManager.set_teammate_accuracy or function(self, i, value)
207 | self._teammate_panels[i]:set_accuracy(value)
208 | end
209 |
210 | HUDManager.set_teammate_weapon_accuracy = HUDManager.set_teammate_weapon_accuracy or function(self, i, slot, value)
211 | --TODO
212 | end
213 |
214 | function HUDManager:teampanels_height()
215 | return (WolfHUD:getSetting({"CustomHUD", "PLAYER", "SHOW_ACCURACY"}, true) and not WolfHUD:getSetting({"CustomHUD", "PLAYER", "KILLCOUNTER", "HIDE"}, false)) and 140 or 120
216 | end
217 |
218 | elseif string.lower(RequiredScript) == "lib/managers/hud/hudteammate" then
219 |
220 | if not HUDManager.CUSTOM_TEAMMATE_PANELS then --Custom HUD compatibility
221 | local init_original = HUDTeammate.init
222 | local set_name_original = HUDTeammate.set_name
223 | local set_state_original = HUDTeammate.set_state
224 |
225 | function HUDTeammate:init(...)
226 | init_original(self, ...)
227 | self._setting_prefix = self._main_player and "PLAYER" or "TEAMMATE"
228 | self:_init_killcount()
229 | self:init_accuracy()
230 | end
231 |
232 | function HUDTeammate:_init_killcount()
233 | self._kills_panel = self._panel:panel({
234 | name = "kills_panel",
235 | visible = not WolfHUD:getSetting({"CustomHUD", self._setting_prefix, "KILLCOUNTER", "HIDE"}, false),
236 | w = 150,
237 | h = 20,
238 | x = 0,
239 | halign = "right"
240 | })
241 |
242 | local player_panel = self._panel:child("player")
243 | local name_label = self._panel:child("name")
244 | self._kills_panel:set_rightbottom(player_panel:right(), (self._main_player or WolfHUD:getSetting({"CustomHUD", "TEAMMATE", "INTERACTION", "TEXT"}, true)) and name_label:bottom() or name_label:top())
245 | local killcount_color = WolfHUD:getColorSetting({"CustomHUD", self._setting_prefix, "KILLCOUNTER", "COLOR"}, "yellow")
246 |
247 | self._kill_icon = self._kills_panel:bitmap({
248 | texture = "guis/textures/pd2/cn_miniskull",
249 | w = self._kills_panel:h() * 0.75,
250 | h = self._kills_panel:h(),
251 | texture_rect = { 0, 0, 12, 16 },
252 | alpha = 1,
253 | blend_mode = "normal",
254 | layer = 0,
255 | color = killcount_color
256 | })
257 |
258 | self._kills_text = self._kills_panel:text({
259 | name = "kills_text",
260 | text = "-",
261 | layer = 1,
262 | color = killcount_color,
263 | w = self._kills_panel:w() - self._kill_icon:w(),
264 | h = self._kills_panel:h(),
265 | vertical = "center",
266 | align = "right",
267 | font_size = self._kills_panel:h(),
268 | font = tweak_data.hud_players.name_font
269 | })
270 | self._kills_text:set_right(self._kills_panel:w())
271 |
272 | self:reset_kill_count()
273 | end
274 |
275 | function HUDTeammate:init_accuracy()
276 | if not self._main_player then return end
277 | self._accuracy_panel = self._panel:panel({
278 | name = "accuracy_panel",
279 | visible = WolfHUD:getSetting({"CustomHUD", "PLAYER", "SHOW_ACCURACY"}, true),
280 | w = 100,
281 | h = 20,
282 | x = 0,
283 | halign = "right"
284 | })
285 |
286 | local player_panel = self._panel:child("player")
287 | local name_label = self._panel:child("name")
288 | 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())
289 |
290 | self._accuracy_icon = self._accuracy_panel:bitmap({
291 | texture = "guis/textures/pd2/pd2_waypoints",
292 | w = self._accuracy_panel:h() * 0.75,
293 | h = self._accuracy_panel:h(),
294 | texture_rect = { 96, 0, 32, 32 },
295 | alpha = 1,
296 | blend_mode = "normal",
297 | layer = 0,
298 | color = Color.white
299 | })
300 |
301 | self._accuracy_text = self._accuracy_panel:text({
302 | name = "accuracy_text",
303 | text = "0%",
304 | layer = 1,
305 | color = Color.white,
306 | w = self._accuracy_panel:w(),
307 | h = self._accuracy_panel:h(),
308 | vertical = "center",
309 | align = "right",
310 | font_size = self._accuracy_panel:h(),
311 | font = tweak_data.hud_players.name_font
312 | })
313 | self:set_accuracy(0)
314 | end
315 |
316 | function HUDTeammate:increment_kill_count(is_special, headshot)
317 | self._kill_count = self._kill_count + 1
318 | self._kill_count_special = self._kill_count_special + (is_special and 1 or 0)
319 | self._headshot_kills = self._headshot_kills + (headshot and 1 or 0)
320 | self:_update_kill_count_text()
321 | end
322 |
323 | function HUDTeammate:_update_kill_count_text()
324 | local kill_string = tostring(self._kill_count)
325 | if WolfHUD:getSetting({"CustomHUD", self._setting_prefix, "KILLCOUNTER", "SHOW_SPECIAL_KILLS"}, true) then
326 | kill_string = kill_string .. "/" .. tostring(self._kill_count_special)
327 | end
328 | if WolfHUD:getSetting({"CustomHUD", self._setting_prefix, "KILLCOUNTER", "SHOW_HEADSHOT_KILLS"}, true) then
329 | kill_string = kill_string .. " (" .. tostring(self._headshot_kills) .. ")"
330 | end
331 | self._kills_text:set_text(kill_string)
332 | local _, _, w, _ = self._kills_text:text_rect()
333 | self._kill_icon:set_right(self._kills_panel:w() - w - self._kill_icon:w() * 0.15)
334 |
335 | if (self._main_player or WolfHUD:getSetting({"CustomHUD", "TEAMMATE", "INTERACTION", "TEXT"}, true)) and not WolfHUD:getSetting({"CustomHUD", self._setting_prefix, "KILLCOUNTER", "HIDE"}, false) then
336 | self._max_name_panel_width = (self._kills_panel:x() + self._kill_icon:x() - 4)
337 | self:_truncate_name()
338 | end
339 |
340 | local color = WolfHUD:getColorSetting({"CustomHUD", self._setting_prefix, "KILLCOUNTER", "COLOR"}, "yellow")
341 | self._kill_icon:set_color(color)
342 | self._kills_text:set_color(color)
343 | end
344 |
345 | function HUDTeammate:reset_kill_count()
346 | self._kill_count = 0
347 | self._kill_count_special = 0
348 | self._headshot_kills = 0
349 | self:_update_kill_count_text()
350 | end
351 |
352 | function HUDTeammate:set_name(teammate_name, ...)
353 | if teammate_name ~= self._name then
354 | self._name = teammate_name
355 | self:reset_kill_count()
356 | end
357 |
358 | return set_name_original(self, teammate_name, ...)
359 | end
360 |
361 | function HUDTeammate:set_state(...)
362 | set_state_original(self, ...)
363 |
364 | local visible = not WolfHUD:getSetting({"CustomHUD", self._setting_prefix, "KILLCOUNTER", "HIDE"}, false) and (not self._ai or WolfHUD:getSetting({"CustomHUD", "TEAMMATE", "KILLCOUNTER", "SHOW_BOT_KILLS"}, true))
365 | self._kills_panel:set_visible(visible)
366 |
367 | if self._ai then
368 | self._kills_panel:set_bottom(self._panel:child("player"):bottom())
369 | else
370 | local name_label = self._panel:child("name")
371 | self._kills_panel:set_bottom((self._main_player or WolfHUD:getSetting({"CustomHUD", "TEAMMATE", "INTERACTION", "TEXT"}, true)) and name_label:bottom() or name_label:top())
372 | end
373 | end
374 |
375 | function HUDTeammate:set_accuracy(value)
376 | self._accuracy_text:set_text(tostring(value) .. "%")
377 | local _, _, w, _ = self._accuracy_text:text_rect()
378 | self._accuracy_icon:set_right(self._accuracy_panel:w() - w - self._accuracy_icon:w() * 0.15)
379 | if WolfHUD:getSetting({"CustomHUD", "PLAYER", "KILLCOUNTER", "HIDE"}, false) and WolfHUD:getSetting({"CustomHUD", "PLAYER", "SHOW_ACCURACY"}, true) then
380 | self._max_name_panel_width = (self._accuracy_panel:x() + self._accuracy_icon:x() - 4)
381 | self:_truncate_name()
382 | end
383 | end
384 |
385 | HUDTeammate._truncate_name = HUDTeammate._truncate_name or function() end
386 | end
387 | end
388 |
--------------------------------------------------------------------------------
/lua/NetworkHandler.lua:
--------------------------------------------------------------------------------
1 | --do return end -- Disabled cause: WiP
2 | if WolfHUD and not WolfHUD.Sync then
3 | WolfHUD.Sync = {
4 | msg_id = "WolfHUD_Sync",
5 | peers = { false, false, false, false },
6 | events = {
7 | discover_wolfhud = "Using_WolfHUD?",
8 | confirm_wolfhud = "Using_WolfHUD!",
9 | peer_disconnect = "Leaving_Game",
10 | locked_assault_status = "locked_assault_status",
11 | },
12 | }
13 |
14 | local Net = _G.LuaNetworking
15 |
16 | function WolfHUD.Sync.table_to_string(tbl)
17 | return Net:TableToString(tbl) or ""
18 | end
19 |
20 | function WolfHUD.Sync.string_to_table(str)
21 | local tbl = Net:StringToTable(str) or ""
22 |
23 | for k, v in pairs(tbl) do
24 | tbl[k] = self.to_original_type(v)
25 | end
26 |
27 | return tbl
28 | end
29 |
30 | function WolfHUD.Sync.to_original_type(s)
31 | local v = s
32 | if type(s) == "string" then
33 | if s == "nil" then
34 | v = nil
35 | elseif s == "true" or s == "false" then
36 | v = (s == "true")
37 | else
38 | v = tonumber(s) or s
39 | end
40 | end
41 | return v
42 | end
43 |
44 | function WolfHUD.Sync:send_to_peer(peer_id, messageType, data)
45 | if peer_id and peer_id ~= Net:LocalPeerID() and messageType then
46 | local tags = {
47 | id = self.msg_id,
48 | event = messageType
49 | }
50 |
51 | if type(data) == "table" then
52 | data = self.table_to_string(data)
53 | tags["table"] = true
54 | end
55 |
56 | Net:SendToPeer(peer_id, self.table_to_string(tags), data or "")
57 | end
58 | end
59 |
60 | function WolfHUD.Sync:send_to_host(messageType, data)
61 | self:send_to_peer(managers.network:session():server_peer():id(), messageType, data)
62 | end
63 |
64 | function WolfHUD.Sync:send_to_all_peers( messageType, data)
65 | for peer_id, enabled in ipairs(self.peers) do
66 | self:send_to_peer(peer_id, messageType, data)
67 | end
68 | end
69 |
70 | function WolfHUD.Sync:send_to_all_discovered_peers( messageType, data)
71 | for peer_id, enabled in ipairs(self.peers) do
72 | if enabled then
73 | self:send_to_peer(peer_id, messageType, data)
74 | end
75 | end
76 | end
77 |
78 | function WolfHUD.Sync:send_to_all_undiscovered_peers( messageType, data)
79 | for peer_id, enabled in ipairs(self.peers) do
80 | if not enabled then
81 | self:send_to_peer(peer_id, messageType, data)
82 | end
83 | end
84 | end
85 |
86 | function WolfHUD.Sync:receive_message(peer_id, event, data)
87 | if peer_id and event then
88 | local events = WolfHUD.Sync.events
89 |
90 | if event == events.discover_wolfhud then
91 | WolfHUD.Sync:send_to_peer(peer_id, events.confirm_wolfhud)
92 | WolfHUD.Sync.peers[peer_id] = true
93 | managers.chat:feed_system_message(ChatManager.GAME, "Client " .. tostring(peer_id) .. " is using WolfHUD ;)") --TEST
94 | elseif event == events.confirm_wolfhud then
95 | WolfHUD.Sync.peers[peer_id] = true
96 | managers.chat:feed_system_message(ChatManager.GAME, "The Host is using WolfHUD ;)") --TEST
97 | elseif event == events.peer_disconnect then
98 | WolfHUD.Sync.peers[peer_id] = false
99 | elseif event == events.locked_assault_status then
100 | managers.hud:_locked_assault(data)
101 | end
102 | end
103 | end
104 |
105 | -- Manage Networking and list of peers to sync to...
106 | Hooks:Add("NetworkReceivedData", "NetworkReceivedData_WolfHUDSync", function(sender, messageType, data)
107 | sender = tonumber(sender)
108 | if sender then
109 | local tags = WolfHUD.Sync.string_to_table(messageType)
110 | if WolfHUD.Sync and tags.id and tags.id == WolfHUD.Sync.msg_id and not string.is_nil_or_empty(tags.event) then
111 | if tags.table then
112 | data = WolfHUD.Sync.string_to_table(data)
113 | else
114 | data = WolfHUD.Sync.to_original_type(data)
115 | end
116 |
117 | WolfHUD.Sync:receive_message(sender, tags.event, data)
118 | end
119 | end
120 | end)
121 |
122 | Hooks:Add("BaseNetworkSessionOnPeerRemoved", "BaseNetworkSessionOnPeerRemoved_WolfHUDSync", function(self, peer, peer_id, reason)
123 | WolfHUD.Sync:receive_message(peer_id, WolfHUD.Sync.events.peer_disconnect, "")
124 | end)
125 |
126 | Hooks:Add("BaseNetworkSessionOnLoadComplete", "BaseNetworkSessionOnLoadComplete_WolfHUDSync", function(local_peer, id)
127 | if WolfHUD.Sync and Net:IsMultiplayer() and Network:is_client() then
128 | WolfHUD.Sync:send_to_host(WolfHUD.Sync.events.discover_wolfhud)
129 | end
130 | end)
131 |
132 |
133 | -- Data Sync functions:
134 |
135 | function WolfHUD.Sync:endless_assault_status(status)
136 | if Network:is_server() then
137 | self:send_to_all_discovered_peers(WolfHUD.Sync.events.locked_assault_status, tostring(status))
138 | end
139 | end
140 | end
--------------------------------------------------------------------------------
/lua/NumbericSuspicion.lua:
--------------------------------------------------------------------------------
1 | local hudsuspicion_init_original = HUDSuspicion.init
2 | local hudsuspicions_animate_eye_original = HUDSuspicion.animate_eye
3 | local hudsuspicion_hide_original = HUDSuspicion.hide
4 |
5 | function HUDSuspicion:init(...)
6 | hudsuspicion_init_original(self, ...)
7 | self._scale = 1
8 | self._suspicion_text_panel = self._suspicion_panel:panel({
9 | name = "suspicion_text_panel",
10 | visible = true,
11 | x = 0,
12 | y = 0,
13 | h = self._suspicion_panel:h(),
14 | w = self._suspicion_panel:w(),
15 | layer = 1
16 | })
17 |
18 | self._suspicion_text = OutlinedText:new(self._suspicion_text_panel, {
19 | name = "suspicion_text",
20 | visible = true,
21 | text = "",
22 | valign = "center",
23 | align = "center",
24 | layer = 2,
25 | color = Color.white,
26 | font = tweak_data.menu.pd2_large_font,
27 | font_size = 28,
28 | h = 64
29 | })
30 | self._suspicion_text:set_y((math.round(self._suspicion_text_panel:h() / 4)))
31 | end
32 |
33 | function HUDSuspicion:_is_detected()
34 | local detected_text = self._suspicion_panel and self._suspicion_panel:child("suspicion_detected")
35 | return self._discovered or self._suspicion_value and self._suspicion_value >= 1 or detected_text and detected_text:visible() and detected_text:alpha() > 0
36 | end
37 |
38 | function HUDSuspicion:set_detection(text_item, detection)
39 | detection = math.clamp(detection, 0, 1)
40 | local color = math.lerp(Color(0, 0.71, 1), Color(0.99, 0.08, 0), detection)
41 | text_item:set_color(color)
42 | text_item:set_text(string.format("%d%%", detection*100))
43 | end
44 |
45 | function HUDSuspicion:_animate_text(suspicion_panel, suspicion_text)
46 | while true do
47 | local detection = self:_is_detected() and 1 or self._suspicion_value or 0
48 | self:set_detection(suspicion_text, detection)
49 | coroutine.yield()
50 | end
51 | end
52 |
53 | function HUDSuspicion:animate_eye(...)
54 | local was_animating = self._eye_animation and true or false
55 | hudsuspicions_animate_eye_original(self, ...)
56 |
57 | if not was_animating and self._eye_animation then
58 | self:rescale()
59 |
60 | local visible = WolfHUD:getSetting({"HUDSuspicion", "SHOW_BARS"}, true)
61 | self._suspicion_panel:child("suspicion_left"):set_visible(visible)
62 | self._suspicion_panel:child("suspicion_right"):set_visible(visible)
63 | self._misc_panel:child("hud_stealthmeter_bg"):set_visible(visible)
64 | self._misc_panel:child("hud_stealth_eye"):set_visible(visible)
65 | self._misc_panel:child("hud_stealth_exclam"):set_visible(visible)
66 |
67 | if WolfHUD:getSetting({"HUDSuspicion", "SHOW_PERCENTAGE"}, true) and not self._text_animation then
68 | self._suspicion_text:set_outlines_visible(WolfHUD:getSetting({"HUDSuspicion", "SHOW_PERCENTAGE_OUTLINE"}, true))
69 | self._text_animation = self._suspicion_text_panel:animate(callback(self, self, "_animate_text"), self._suspicion_text)
70 | end
71 | end
72 | end
73 |
74 | function HUDSuspicion:hide(...)
75 | if self._text_animation then
76 | self._suspicion_text_panel:stop()
77 | self._text_animation = nil
78 | end
79 |
80 | if self._suspicion_panel then
81 | self._suspicion_panel:set_visible(false)
82 | end
83 |
84 | return hudsuspicion_hide_original(self, ...)
85 | end
86 |
87 | function HUDSuspicion:rescale()
88 | local scale = WolfHUD:getSetting({"HUDSuspicion", "SCALE"}, 0.8)
89 | if self._scale ~= scale then
90 | local suspicion_left = self._suspicion_panel:child("suspicion_left")
91 | local suspicion_right = self._suspicion_panel:child("suspicion_right")
92 | local hud_stealthmeter_bg = self._misc_panel:child("hud_stealthmeter_bg")
93 | local suspicion_detected = self._suspicion_panel:child("suspicion_detected")
94 | local hud_stealth_eye = self._misc_panel:child("hud_stealth_eye")
95 | local hud_stealth_exclam = self._misc_panel:child("hud_stealth_exclam")
96 | suspicion_left:set_size((suspicion_left:w() / self._scale) * scale, (suspicion_left:h() / self._scale) * scale)
97 | suspicion_right:set_size((suspicion_right:w() / self._scale) * scale, (suspicion_right:h() / self._scale) * scale)
98 | hud_stealthmeter_bg:set_size((hud_stealthmeter_bg:w() / self._scale) * scale, (hud_stealthmeter_bg:h() / self._scale) * scale)
99 | suspicion_detected:set_font_size((suspicion_detected:font_size() / self._scale) * scale)
100 | local fontSize = (self._suspicion_text:font_size() / self._scale) * scale
101 | self._suspicion_text:set_font_size(fontSize)
102 | hud_stealth_eye:set_size((hud_stealth_eye:w() / self._scale) * scale, (hud_stealth_eye:h() / self._scale) * scale)
103 | hud_stealth_exclam:set_size((hud_stealth_exclam:w() / self._scale) * scale, (hud_stealth_exclam:h() / self._scale) * scale)
104 | suspicion_left:set_center_x(self._suspicion_panel:w() / 2)
105 | suspicion_left:set_center_y(self._suspicion_panel:h() / 2)
106 | suspicion_right:set_center(suspicion_left:center())
107 | hud_stealthmeter_bg:set_center(suspicion_left:center())
108 | hud_stealth_eye:set_center(suspicion_left:center_x(), suspicion_left:bottom() - 4)
109 | hud_stealth_exclam:set_center(suspicion_left:center_x(), suspicion_left:top() - 4)
110 | self._suspicion_text:set_y(suspicion_left:top() + (suspicion_left:center_y() - suspicion_left:top()) / 2 - self._suspicion_text:font_size() / 2)
111 | self._scale = scale
112 | end
113 | end
114 |
--------------------------------------------------------------------------------
/lua/PacifiedCivs.lua:
--------------------------------------------------------------------------------
1 | local _upd_criminal_suspicion_progress_original = GroupAIStateBase._upd_criminal_suspicion_progress
2 | function GroupAIStateBase:_upd_criminal_suspicion_progress(...)
3 | if self._ai_enabled then
4 | for obs_key, obs_susp_data in pairs(self._suspicion_hud_data or {}) do
5 | local unit = obs_susp_data.u_observer
6 | if managers.enemy:is_civilian(unit) then
7 | local waypoint_id = "susp1" .. tostring(obs_key)
8 | local waypoint = managers.hud and managers.hud._hud.waypoints[waypoint_id]
9 | if waypoint then
10 | local color, arrow_color
11 | if unit:anim_data().drop and WolfHUD:getSetting({"HUDSuspicion", "SHOW_PACIFIED_CIVILIANS"}, true) then
12 | if not obs_susp_data._subdued_civ then
13 | obs_susp_data._alerted_civ = nil
14 | obs_susp_data._subdued_civ = true
15 | color = Color(0, 0.71, 1)
16 | arrow_color = Color(0, 0.35, 0.5)
17 | waypoint.bitmap:set_image("guis/textures/menu_singletick")
18 | end
19 | elseif obs_susp_data.alerted then
20 | if not obs_susp_data._alerted_civ then
21 | obs_susp_data._subdued_civ = nil
22 | obs_susp_data._alerted_civ = true
23 | color = Color.white
24 | arrow_color = tweak_data.hud.detected_color
25 | waypoint.bitmap:set_image("guis/textures/hud_icons")
26 | waypoint.bitmap:set_texture_rect(479, 433, 32, 32)
27 | end
28 | end
29 | if color and arrow_color then
30 | waypoint.bitmap:set_color(color)
31 | waypoint.arrow:set_color(arrow_color:with_alpha(0.75))
32 | end
33 | end
34 | end
35 | end
36 | end
37 | return _upd_criminal_suspicion_progress_original(self, ...)
38 | end
--------------------------------------------------------------------------------
/lua/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 | self.profile_preview = LoadoutPanel:new(self.item_panel:parent(), self, 0, self.PROFILE_PREVIEW_W, math.floor(self.item_panel:h()) - offset_h, {
131 | component_layout = {
132 | { "skills" },
133 | { "perk" },
134 | { "primary", "secondary" },
135 | { "grenade", "armor" },
136 | { "deployable", "secondary_deployable" }
137 | },
138 | default = { alpha = 0.9 },
139 | margin = 5,
140 | borders = { 1, 1, 1, 1 },
141 | layer = 53,
142 | })
143 | local outfit = managers.multi_profile:get_profile_outfit(managers.multi_profile:current_profile_id())
144 | self.profile_preview:set_outfit(outfit)
145 | end
146 | end
147 |
148 | function MenuNodeProfileSwitchGui:_create_menu_item(row_item, ...)
149 | MenuNodeProfileSwitchGui.super._create_menu_item(self, row_item, ...)
150 | if row_item.type ~= "divider" and row_item.name ~= "back" then
151 | local mpm = managers.multi_profile
152 | local profile_id = row_item.name
153 | local profile = mpm:profile(profile_id)
154 | local skill_name, perk_name = "", ""
155 |
156 | 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")
157 | if profile.perk_deck then
158 | local data = tweak_data.skilltree.specializations[tonumber(profile.perk_deck)]
159 | local name_id = data and data.name_id
160 | perk_name = managers.localization:to_upper_text(name_id)
161 | end
162 |
163 | if alive(row_item.skill_points_gui) then
164 | row_item.skill_points_gui:set_text(utf8.to_upper(skill_name))
165 | row_item.skill_points_gui:set_alpha(1)
166 | end
167 | if alive(row_item.status_gui) then
168 | row_item.status_gui:set_text(perk_name)
169 | end
170 | row_item.distribution_after_text = false
171 | elseif row_item.type == "divider" and row_item.name == "divider_title" then
172 |
173 | if alive(row_item.skill_points_gui) then
174 | 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", {})))
175 | row_item.skill_points_gui:show()
176 | end
177 | if alive(row_item.status_gui) then
178 | row_item.status_gui:set_text(managers.localization:to_upper_text("menu_specialization", {}) .. ":")
179 | end
180 | end
181 | end
182 |
183 | function MenuNodeProfileSwitchGui:arrange_loadout_panels()
184 | if self.profile_preview then
185 | self.profile_preview:set_top(self.item_panel:top())
186 | self.profile_preview:set_right(self.item_panel:right())
187 | end
188 | end
189 |
190 | function MenuNodeProfileSwitchGui:_highlight_row_item(row_item, mouse_over, ...)
191 | MenuNodeProfileSwitchGui.super._highlight_row_item(self, row_item, mouse_over, ...)
192 |
193 | local mpm = managers.multi_profile
194 | local profile_id = row_item.name and mpm:is_valid_id(row_item.name) and row_item.name or mpm:current_profile_id()
195 | self:change_outfit_preview(profile_id)
196 | end
197 |
198 | function MenuNodeProfileSwitchGui:_align_marker(row_item, ...)
199 | MenuNodeProfileSwitchGui.super._align_marker(self, row_item, ...)
200 |
201 | if self.profile_preview then
202 | if row_item.name ~= "back" then
203 | self._marker_data.marker:set_w(self.item_panel:w() - self.profile_preview:w() - 10)
204 | else
205 | self._marker_data.marker:set_w(self.profile_preview:w())
206 | self._marker_data.marker:set_right(self.item_panel:w())
207 | end
208 | end
209 | end
210 |
211 | function MenuNodeProfileSwitchGui:_clear_gui(...)
212 | if self.profile_preview then
213 | self.profile_preview:destroy()
214 | end
215 |
216 | MenuNodeProfileSwitchGui.super._clear_gui(self, ...)
217 | end
218 |
219 | function MenuNodeProfileSwitchGui:mouse_moved(o, x, y, ...)
220 | local used, icon = MenuNodeProfileSwitchGui.super.mouse_moved(self, o, x, y, ...)
221 | return true, icon
222 | end
223 |
224 | function MenuNodeProfileSwitchGui:change_outfit_preview(profile_id)
225 | local mpm = managers.multi_profile
226 | if self.profile_preview and mpm:is_valid_id(profile_id) and (self._previewing_outfit or 0) ~= profile_id then
227 | local outfit = mpm:get_profile_outfit(profile_id)
228 | self.profile_preview:set_outfit(outfit)
229 | self._previewing_outfit = profile_id
230 | end
231 | end
232 | elseif RequiredScript == "lib/managers/multiprofilemanager" then
233 | local open_quick_select_original = MultiProfileManager.open_quick_select
234 | function MultiProfileManager:open_quick_select(...)
235 | if WolfHUD:getSetting({"CrewLoadout", "REPLACE_PROFILE_MENU"}, true) then
236 | managers.menu:open_node(PROFILE_MENU_ID, {})
237 | else
238 | open_quick_select_original(self, ...)
239 | end
240 | end
241 |
242 |
243 | function MultiProfileManager:current_profile_id()
244 | return self._global._current_profile or 1
245 | end
246 |
247 | function MultiProfileManager:is_valid_id(profile_id)
248 | return profile_id and type(profile_id) == "number" and profile_id > 0 and profile_id <= self:profile_count() and true or false
249 | end
250 |
251 | function MultiProfileManager:get_profile_outfit(profile_id)
252 | if profile_id ~= self:current_profile_id() then
253 | local profile = self:profile(profile_id)
254 | local gd = Global.skilltree_manager.skill_switches[profile.skillset]
255 | local skills = {}
256 | if gd.trees then
257 | local pts = 0
258 | for i=1, #gd.trees do
259 | pts=Application:digest_value(gd.trees[i].points_spent, false)
260 | table.insert(skills, pts)
261 | end
262 | end
263 | local outfit = {
264 | skills = {
265 | skills = skills,
266 | specializations = { profile.perk_deck, 9 },
267 | },
268 | primary = self:get_item_data("primaries", profile.primary),
269 | secondary = self:get_item_data("secondaries", profile.secondary),
270 | melee_weapon = profile.melee,
271 | grenade = profile.throwable,
272 | armor = profile.armor,
273 | armor_skin = profile.armor_skin,
274 | mask = self:get_item_data("mask", profile.mask),
275 | player_style = profile.player_style or managers.blackmarket:get_default_player_style(),
276 | suit_variations = (profile.suit_variations or {}),
277 | deployable = profile.deployable,
278 | secondary_deployable = profile.deployable_secondary,
279 | deployable_amount = self:get_deployable_amount(profile.deployable, gd.skills),
280 | secondary_deployable_amount = self:get_deployable_amount(profile.deployable_secondary, gd.skills),
281 | }
282 | return outfit
283 | else
284 | local outfit = managers.blackmarket:unpack_outfit_from_string(managers.blackmarket:outfit_string())
285 | return outfit
286 | end
287 | end
288 |
289 | function MultiProfileManager:get_item_data(category, slot)
290 | if not Global.blackmarket_manager.crafted_items[category] then
291 | return nil
292 | end
293 | if not Global.blackmarket_manager.crafted_items[category][slot] then
294 | slot = 1
295 | end
296 | local item_data = Global.blackmarket_manager.crafted_items[category][slot]
297 | return item_data or {}
298 | end
299 |
300 | function MultiProfileManager:get_deployable_amount(deployable, skills)
301 | local amount = 0
302 | if deployable then
303 | if deployable == "sentry_gun_silent" then
304 | deployable = "sentry_gun"
305 | end
306 | amount = tweak_data.equipments[deployable] and tweak_data.equipments[deployable].quantity[1] or 0
307 | local upgrade_def, upgrade_values, skill_tweak = tweak_data.upgrades.definitions, tweak_data.upgrades.values, tweak_data.skilltree.skills
308 | if skills and upgrade_values[deployable] and upgrade_values[deployable]["quantity"] then
309 | local value_index = 0
310 | for skill, data in pairs(skills) do
311 | local skill_data = skill_tweak[skill]
312 | for i = 1, data.unlocked do
313 | local upgrade_ids = skill_data and skill_data[i].upgrades
314 | for _, upgrade_id in ipairs(upgrade_ids) do
315 | local u_data = upgrade_def[upgrade_id] and upgrade_def[upgrade_id].upgrade
316 | if u_data and u_data.category == deployable and u_data.upgrade == "quantity" then
317 | if upgrade_def[upgrade_id].incremental then
318 | value_index = value_index + (u_data.value or 0)
319 | else
320 | value_index = u_data.value
321 | end
322 | end
323 | end
324 | end
325 | end
326 | if value_index > 0 then
327 | amount = amount + (upgrade_values[deployable]["quantity"][math.floor(value_index)] or 0)
328 | end
329 | end
330 | end
331 | return amount
332 | end
333 | elseif RequiredScript == "lib/managers/menu/multiprofileitemgui" then
334 | local init_orig = MultiProfileItemGui.init
335 |
336 | function MultiProfileItemGui:init(...)
337 | init_orig(self, ...)
338 |
339 | self._max_length = WolfHUD:getTweakEntry("MAX_PROFILE_NAME_LENGTH", "number", 20)
340 | end
341 | elseif RequiredScript == "lib/managers/menu/missionbriefinggui" then
342 | local special_btn_pressed_orig = MissionBriefingGui.special_btn_pressed
343 | local input_focus_orig = MissionBriefingGui.input_focus
344 | local reload_loadout_orig = MissionBriefingGui.reload_loadout
345 | function MissionBriefingGui:special_btn_pressed(button, ...)
346 | if self._enabled and button == Idstring("menu_change_profile_right") and managers.menu:get_controller():get_input_bool("menu_change_profile_left") then
347 | managers.menu:open_node(PROFILE_MENU_ID, {})
348 | return
349 | end
350 |
351 | return special_btn_pressed_orig(self, button, ...)
352 | end
353 |
354 | function MissionBriefingGui:input_focus(...)
355 | local focus = input_focus_orig(self, ...)
356 | if focus then
357 | local active_menu = managers.menu:active_menu()
358 | local selected_node = active_menu and active_menu.logic:selected_node()
359 | if selected_node and selected_node:parameters().name == PROFILE_MENU_ID then
360 | focus = false
361 | end
362 | end
363 | return focus
364 | end
365 |
366 | JukeboxItemNew = JukeboxItemNew or class(JukeboxItem)
367 | function JukeboxItemNew:select(...)
368 | local active_menu = managers.menu:active_menu()
369 | local selected_node = active_menu and active_menu.logic:selected_node()
370 | if not selected_node or selected_node:parameters().name == "kit" then
371 | JukeboxItemNew.super.select(self, ...)
372 | else
373 | self.displayed = true
374 | JukeboxItemNew.super.super.select(self, ...)
375 | end
376 | end
377 | function JukeboxItemNew:deselect(...)
378 | local active_menu = managers.menu:active_menu()
379 | local selected_node = active_menu and active_menu.logic:selected_node()
380 | if not selected_node or selected_node:parameters().name == "jukebox" then
381 | JukeboxItemNew.super.deselect(self, ...)
382 | else
383 | self.closing = true
384 | self.displayed = nil
385 | JukeboxItemNew.super.super.deselect(self, ...)
386 | end
387 | end
388 |
389 | if CoreClass then
390 | CoreClass.override_class(JukeboxItem, JukeboxItemNew)
391 | end
392 | elseif RequiredScript == "lib/managers/menu/playerinventorygui" then
393 | local special_btn_pressed_orig = PlayerInventoryGui.special_btn_pressed
394 | function PlayerInventoryGui:special_btn_pressed(button, ...)
395 | if button == Idstring("menu_change_profile_right") and managers.menu:get_controller():get_input_bool("menu_change_profile_left") then
396 | managers.menu:open_node(PROFILE_MENU_ID, {})
397 | return
398 | end
399 |
400 | return special_btn_pressed_orig(self, button, ...)
401 | end
402 | end
403 |
--------------------------------------------------------------------------------
/lua/Scripts.lua:
--------------------------------------------------------------------------------
1 | if string.lower(RequiredScript) == "lib/managers/hudmanagerpd2" then
2 | local set_teammate_ammo_amount_orig = HUDManager.set_teammate_ammo_amount
3 | local set_slot_ready_orig = HUDManager.set_slot_ready
4 |
5 | function HUDManager:set_teammate_ammo_amount(id, selection_index, max_clip, current_clip, current_left, max, ...)
6 | if WolfHUD:getSetting({"CustomHUD", "USE_REAL_AMMO"}, true) then
7 | local total_left = current_left - current_clip
8 | if total_left >= 0 then
9 | current_left = total_left
10 | max = max - current_clip
11 | end
12 | end
13 | return set_teammate_ammo_amount_orig(self, id, selection_index, max_clip, current_clip, current_left, max, ...)
14 | end
15 |
16 | local FORCE_READY_CLICKS = 3
17 | local FORCE_READY_TIME = 2
18 | local FORCE_READY_ACTIVE_T = 90
19 |
20 | local force_ready_start_t = 0
21 | local force_ready_clicked = 0
22 |
23 | function HUDManager:set_slot_ready(peer, peer_id, ...)
24 | set_slot_ready_orig(self, peer, peer_id, ...)
25 |
26 | if Network:is_server() and not Global.game_settings.single_player then
27 | local session = managers.network and managers.network:session()
28 | local local_peer = session and session:local_peer()
29 | local time_elapsed = managers.game_play_central and managers.game_play_central:get_heist_timer() or 0
30 | if local_peer and local_peer:id() == peer_id then
31 | local t = Application:time()
32 | if (force_ready_start_t + FORCE_READY_TIME) > t then
33 | force_ready_clicked = force_ready_clicked + 1
34 | if force_ready_clicked >= FORCE_READY_CLICKS then
35 | local enough_wait_time = (time_elapsed > FORCE_READY_ACTIVE_T)
36 | local friends_list = not enough_wait_time and Steam:logged_on() and Steam:friends() or {}
37 | local abort = false
38 | for _, peer in ipairs(session:peers()) do
39 | local is_friend = false
40 | for _, friend in ipairs(friends_list) do
41 | if friend:id() == peer:user_id() then
42 | is_friend = true
43 | break
44 | end
45 | end
46 | if not (enough_wait_time or is_friend) or not (peer:synced() or peer:id() == local_peer:id()) then
47 | abort = true
48 | break
49 | end
50 | end
51 | if game_state_machine and not abort then
52 | local menu_options = {
53 | [1] = {
54 | text = managers.localization:text("dialog_yes"),
55 | callback = function(self, item)
56 | managers.chat:send_message(ChatManager.GAME, local_peer, "The Game was forced to start.")
57 | game_state_machine:current_state():start_game_intro()
58 | end,
59 | },
60 | [2] = {
61 | text = managers.localization:text("dialog_no"),
62 | is_cancel_button = true,
63 | }
64 | }
65 | QuickMenu:new( managers.localization:text("wolfhud_dialog_force_start_title"), managers.localization:text("wolfhud_dialog_force_start_desc"), menu_options, true )
66 | end
67 | end
68 | else
69 | force_ready_clicked = 1
70 | force_ready_start_t = t
71 | end
72 | end
73 | end
74 | end
75 | elseif string.lower(RequiredScript) == "lib/tweak_data/timespeedeffecttweakdata" then
76 | local init_original = TimeSpeedEffectTweakData.init
77 | local FORCE_ENABLE = {
78 | mission_effects = true,
79 | }
80 | function TimeSpeedEffectTweakData:init(...)
81 | init_original(self, ...)
82 | if WolfHUD:getSetting({"SkipIt", "NO_SLOWMOTION"}, true) then
83 | local function disable_effect(table)
84 | for name, data in pairs(table) do
85 | if not FORCE_ENABLE[name] then
86 | if data.speed and data.sustain then
87 | data.speed = 1
88 | data.fade_in_delay = 0
89 | data.fade_in = 0
90 | data.sustain = 0
91 | data.fade_out = 0
92 | elseif type(data) == "table" then
93 | disable_effect(data)
94 | end
95 | end
96 | end
97 | end
98 |
99 | disable_effect(self)
100 | end
101 | end
102 | elseif string.lower(RequiredScript) == "lib/tweak_data/economytweakdata" then
103 | if EconomyTweakData then
104 | -- Fix community market links for Real Weapon Names
105 | Hooks:PostHook(EconomyTweakData, "create_weapon_skin_market_search_url" ,"WolfHUD_EconomyTweakDataPostCreateWeaponSkinMarketSearchUrl", function(self, weapon_id, cosmetic_id)
106 | local cosmetic_name = tweak_data.blackmarket.weapon_skins[cosmetic_id] and managers.localization:text(tweak_data.blackmarket.weapon_skins[cosmetic_id].name_id)
107 | local weapon_name = managers.localization.orig.text(managers.localization, tweak_data.weapon[weapon_id].name_id) -- bypass custom localizations
108 | if cosmetic_name and weapon_name then
109 | cosmetic_name = string.gsub(cosmetic_name, " ", "+")
110 | weapon_name = string.gsub(weapon_name, " ", "+")
111 | return string.gsub("http://steamcommunity.com/market/search?appid=218620&q=" .. cosmetic_name .. "+" .. weapon_name, "++", "+")
112 | end
113 | return nil
114 | end)
115 | end
116 | elseif string.lower(RequiredScript) == "lib/managers/menu/items/menuitemmultichoice" then
117 | if MenuItemMultiChoice then
118 | Hooks:PostHook( MenuItemMultiChoice , "setup_gui" , "MenuItemMultiChoicePostSetupGui_WolfHUD" , function( self, node, row_item )
119 | if self:selected_option() and self:selected_option():parameters().color and row_item.choice_text then
120 | row_item.choice_text:set_blend_mode("normal")
121 | end
122 | end)
123 | end
124 | elseif string.lower(RequiredScript) == "lib/managers/menu/menunodegui" then
125 | if MenuNodeMainGui then
126 | Hooks:PostHook( MenuNodeMainGui , "_add_version_string" , "MenuNodeMainGuiPostAddVersionString_WolfHUD" , function( self )
127 | if alive(self._version_string) then
128 | self._version_string:set_text("Payday 2 v" .. Application:version() .. " | WolfHUD v" .. WolfHUD:getVersion())
129 | end
130 | end)
131 | end
132 | elseif string.lower(RequiredScript) == "lib/managers/experiencemanager" then
133 | local cash_string_original = ExperienceManager.cash_string
134 |
135 | function ExperienceManager:cash_string(...)
136 | local val = cash_string_original(self, ...)
137 | if self._cash_sign ~= "$" and val:find(self._cash_sign) then
138 | val = val:gsub(self._cash_sign, "") .. self._cash_sign
139 | end
140 | return val
141 | end
142 | elseif string.lower(RequiredScript) == "lib/managers/moneymanager" then
143 | function MoneyManager:total_string()
144 | local total = math.round(self:total())
145 | return managers.experience:cash_string(total)
146 | end
147 | function MoneyManager:total_collected_string()
148 | local total = math.round(self:total_collected())
149 | return managers.experience:cash_string(total)
150 | end
151 | end
152 |
--------------------------------------------------------------------------------
/lua/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
--------------------------------------------------------------------------------
/lua/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 |
--------------------------------------------------------------------------------
/lua/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 |
--------------------------------------------------------------------------------
/lua/VanillaHUD.lua:
--------------------------------------------------------------------------------
1 |
2 | if WolfHUD:getSetting({"CustomHUD", "ENABLED"}, true) then
3 | return
4 | end
5 |
6 | if RequiredScript == "lib/managers/hudmanagerpd2" then
7 |
8 | local set_stamina_value_original = HUDManager.set_stamina_value
9 | local set_max_stamina_original = HUDManager.set_max_stamina
10 | local teammate_progress_original = HUDManager.teammate_progress
11 |
12 | function HUDManager:set_stamina_value(value, ...)
13 | self._teammate_panels[HUDManager.PLAYER_PANEL]:set_current_stamina(value)
14 | return set_stamina_value_original(self, value, ...)
15 | end
16 |
17 | function HUDManager:set_max_stamina(value, ...)
18 | self._teammate_panels[HUDManager.PLAYER_PANEL]:set_max_stamina(value)
19 | return set_max_stamina_original(self, value, ...)
20 | end
21 |
22 | function HUDManager:teammate_progress(peer_id, type_index, enabled, tweak_data_id, timer, success, ...)
23 | teammate_progress_original(self, peer_id, type_index, enabled, tweak_data_id, timer, success, ...)
24 | local character_data = managers.criminals:character_data_by_peer_id(peer_id)
25 | if character_data then
26 | local teammate_panel = self._teammate_panels[character_data.panel_id]
27 | local name_label = self:_name_label_by_peer_id(peer_id)
28 | if name_label then
29 | teammate_panel:set_interact_text(name_label.panel:child("action"):text())
30 | end
31 | teammate_panel:set_interact_visibility(enabled and timer and WolfHUD:getSetting({"CustomHUD", "TEAMMATE", "INTERACTION", "MIN_DURATION"}, 1) <= timer and not WolfHUD:getSetting({"CustomHUD", "TEAMMATE", "INTERACTION", "HIDE"}, false) and WolfHUD:getSetting({"CustomHUD", "TEAMMATE", "INTERACTION", "TEXT"}, true))
32 | end
33 | end
34 |
35 | elseif RequiredScript == "lib/managers/hud/hudteammate" then
36 |
37 | local init_original = HUDTeammate.init
38 | local set_name_original = HUDTeammate.set_name
39 | local set_condition_original = HUDTeammate.set_condition
40 | local teammate_progress_original = HUDTeammate.teammate_progress
41 | local update_original = HUDManager.update
42 |
43 | function HUDTeammate:init(...)
44 | init_original(self, ...)
45 |
46 | self._setting_prefix = self._main_player and "PLAYER" or "TEAMMATE"
47 | self._max_name_panel_width = self._panel:w()
48 |
49 | self._condition_icon = self._panel:child("condition_icon")
50 | self._condition_icon:set_color(WolfHUD:getColorSetting({"CustomHUD", self._setting_prefix, "CONDITION_ICON_COLOR"}, "white"))
51 |
52 | self._next_latency_update_t = 0
53 |
54 | if self._main_player and not HUDManager.CUSTOM_TEAMMATE_PANELS then
55 | self:_create_stamina_circle()
56 | else
57 | self:_init_interact_info()
58 | end
59 |
60 | if WolfHUD:getSetting({"CustomHUD","TEAMMATE","LATENCY"}, true) then
61 | self:_create_ping_info()
62 | end
63 | end
64 |
65 | function HUDTeammate:set_name(name, ...)
66 | if not self._ai then
67 | if WolfHUD:getSetting({"CustomHUD", self._setting_prefix, "TRUNCATE_TAGS"}, true) then
68 | name = WolfHUD:truncateNameTag(name)
69 | end
70 | if WolfHUD:getSetting({"CustomHUD", self._setting_prefix, "RANK"}, true) then
71 | local peer = self:peer_id() and managers.network:session():peer(self:peer_id())
72 | local infamy, level = peer and peer:rank() or managers.experience:current_rank(), peer and peer:level() or managers.experience:current_level()
73 | local level_str = string.format("%s%s ",
74 | (infamy or 0) > 0 and string.format("%s-", managers.experience:rank_string(infamy)) or "",
75 | tostring(level)
76 | )
77 | name = level_str .. name
78 | self._color_pos = level_str:len()
79 | end
80 | end
81 | set_name_original(self, name,...)
82 | self:_truncate_name()
83 | end
84 |
85 | function HUDTeammate:_truncate_name()
86 | local name_panel = self._panel:child("name")
87 | local name_bg_panel = self._panel:child("name_bg")
88 | local teammate_name = name_panel:text()
89 | name_panel:set_vertical("center")
90 | name_panel:set_font_size(tweak_data.hud_players.name_size)
91 | name_panel:set_w(self._panel:w() - name_panel:x())
92 | local _,_,w,h = name_panel:text_rect()
93 | while (name_panel:x() + w) > self._max_name_panel_width do
94 | if name_panel:font_size() > 15.1 then
95 | name_panel:set_font_size(name_panel:font_size() - 0.1)
96 | else
97 | name_panel:set_text(teammate_name:sub(1, teammate_name:len() - 1))
98 | end
99 | teammate_name = name_panel:text()
100 | _,_,w,h = name_panel:text_rect()
101 | end
102 | if not self._ai then
103 | name_panel:set_range_color((self._color_pos or 0) + 1, name_panel:text():len() + 1, self._panel:child("callsign"):color():with_alpha(1))
104 | else
105 | name_panel:set_color(WolfHUD:getSetting({"CustomHUD", "TEAMMATE", "AI_COLOR", "USE"}, false) and WolfHUD:getColorSetting({"CustomHUD", "TEAMMATE", "AI_COLOR", "COLOR"}, "white") or tweak_data.chat_colors[5])
106 | end
107 | name_bg_panel:set_w(w + 4)
108 | name_bg_panel:set_h(h + 2)
109 | name_bg_panel:set_y(name_panel:y() + name_panel:h() / 2 - h / 2 - 1)
110 | end
111 |
112 | function HUDTeammate:update(t,dt)
113 | self:update_latency(t,dt)
114 | end
115 |
116 | function HUDTeammate:update_latency(t,dt)
117 | local ping_panel = self._panel:child("latency")
118 | if ping_panel and self:peer_id() and t > self._next_latency_update_t then
119 | local net_session = managers.network:session()
120 | local peer = net_session and net_session:peer(self:peer_id())
121 | local latency = peer and Network:qos(peer:rpc()).ping or "n/a"
122 |
123 | if type(latency) == "number" then
124 | ping_panel:set_text(string.format("%.0fms", latency))
125 | ping_panel:set_color(latency < 75 and Color('C2FC97') or latency < 150 and Color('CEA168') or Color('E24E4E'))
126 | else
127 | ping_panel:set_text(latency)
128 | ping_panel:set_color(Color('E24E4E'))
129 | end
130 |
131 | self._next_latency_update_t = t + 1
132 | elseif not self:peer_id() and ping_panel then
133 | ping_panel:set_text("")
134 | end
135 | end
136 |
137 | function HUDManager:update(...)
138 | for i, panel in ipairs(self._teammate_panels) do
139 | panel:update(...)
140 | end
141 |
142 | return update_original(self, ...)
143 | end
144 |
145 | function HUDTeammate:_create_ping_info()
146 | local name_panel = self._panel:child("name")
147 | local ping_info = self._panel:text({
148 | name = "latency",
149 | vertical = "right",
150 | font_size = tweak_data.hud.small_font_size,
151 | align = "right",
152 | halign = "right",
153 | text = "",
154 | font = "fonts/font_small_mf",
155 | layer = 1,
156 | visible = true,
157 | color = Color.white,
158 | x = -12,
159 | y = name_panel:y() - tweak_data.hud.small_font_size,
160 | h = 50
161 | })
162 | end
163 |
164 | function HUDTeammate:_create_stamina_circle()
165 | local radial_health_panel = self._panel:child("player"):child("radial_health_panel")
166 | self._stamina_bar = radial_health_panel:bitmap({
167 | name = "radial_stamina",
168 | texture = "guis/textures/pd2/hud_radial_rim",
169 | render_template = "VertexColorTexturedRadial",
170 | blend_mode = "add",
171 | alpha = 1,
172 | w = radial_health_panel:w() * 0.37,--53,
173 | h = radial_health_panel:h() * 0.37,--53,
174 | layer = 2,
175 | visible = WolfHUD:getSetting({"CustomHUD", "PLAYER", "STAMINA"}, true)
176 | })
177 | self._stamina_bar:set_color(Color(1, 1, 0, 0))
178 | self._stamina_bar:set_center(radial_health_panel:child("radial_health"):center())
179 |
180 | self._stamina_line = radial_health_panel:rect({
181 | color = Color.red:with_alpha(0.4),
182 | w = radial_health_panel:w() * 0.05,
183 | h = 2,
184 | layer = 10,
185 | visible = WolfHUD:getSetting({"CustomHUD", "PLAYER", "STAMINA"}, true)
186 | })
187 | self._stamina_line:set_center(radial_health_panel:child("radial_health"):center())
188 | end
189 |
190 | function HUDTeammate:set_max_stamina(value)
191 | if not self._max_stamina or self._max_stamina ~= value then
192 | self._max_stamina = value
193 | local w = self._stamina_bar:w()
194 | local threshold = tweak_data.player.movement_state.stamina.MIN_STAMINA_THRESHOLD
195 | local angle = 360 * (threshold/self._max_stamina) - 90
196 | local x = 0.48 * w * math.cos(angle) + w * 0.5 + self._stamina_bar:x()
197 | local y = 0.48 * w * math.sin(angle) + w * 0.5 + self._stamina_bar:y()
198 | self._stamina_line:set_x(x)
199 | self._stamina_line:set_y(y)
200 | self._stamina_line:set_rotation(angle)
201 | end
202 | end
203 |
204 | function HUDTeammate:set_current_stamina(value)
205 | self._stamina_bar:set_color(Color(1, value/self._max_stamina, 0, 0))
206 | self:set_stamina_meter_visibility(WolfHUD:getSetting({"CustomHUD", "PLAYER", "STAMINA"}, true) and not self._condition_icon:visible())
207 | end
208 |
209 | function HUDTeammate:set_stamina_meter_visibility(value)
210 | if self._stamina_bar and self._stamina_bar:visible() ~= value then
211 | self._stamina_bar:set_visible(value)
212 | self._stamina_line:set_visible(value)
213 | end
214 | end
215 |
216 | function HUDTeammate:_init_interact_info()
217 | self._interact_info_panel = self._panel:panel({
218 | name = "interact_info_panel",
219 | x = 0,
220 | y = 0,
221 | visible = false
222 | })
223 | self._interact_info = self._interact_info_panel:text({
224 | name = "interact_info",
225 | text = "|",
226 | layer = 3,
227 | color = Color.white,
228 | x = 0,
229 | y = 1,
230 | align = "right",
231 | vertical = "top",
232 | font_size = tweak_data.hud_players.name_size,
233 | font = tweak_data.hud_players.name_font
234 | })
235 | local _, _, text_w, text_h = self._interact_info:text_rect()
236 | self._interact_info:set_right(self._interact_info_panel:w() - 4)
237 | self._interact_info_bg = self._interact_info_panel:bitmap({
238 | name = "interact_info_bg",
239 | texture = "guis/textures/pd2/hud_tabs",
240 | texture_rect = {
241 | 84,
242 | 0,
243 | 44,
244 | 32
245 | },
246 | layer = 2,
247 | color = Color.white / 3,
248 | x = 0,
249 | y = 0,
250 | align = "left",
251 | vertical = "bottom",
252 | w = text_w + 4,
253 | h = text_h
254 | })
255 | end
256 |
257 | function HUDTeammate:set_interact_text(text)
258 | if alive(self._interact_info) then
259 | self._interact_info:set_text(text)
260 | local _, _, w, _ = self._interact_info:text_rect()
261 | self._interact_info_bg:set_w(w + 8)
262 | self._interact_info_bg:set_right(self._interact_info:right() + 4)
263 | end
264 | end
265 |
266 | function HUDTeammate:set_interact_visibility(visible)
267 | if self._interact_info_panel then
268 | self._interact_info_panel:set_visible(visible)
269 | end
270 | end
271 |
272 | function HUDTeammate:teammate_progress(enabled, tweak_data_id, timer, success, ...)
273 | local show = timer and WolfHUD:getSetting({"CustomHUD", "TEAMMATE", "INTERACTION", "MIN_DURATION"}, 1) <= timer and not WolfHUD:getSetting({"CustomHUD", "TEAMMATE", "INTERACTION", "HIDE"}, false)
274 | teammate_progress_original(self, enabled and show, tweak_data_id, timer, success and show, ...)
275 | if enabled and show and WolfHUD:getSetting({"CustomHUD", "TEAMMATE", "INTERACTION", "NUMBER"}, true) then
276 | self:_start_interact_timer(timer)
277 | else
278 | self:_stop_interact_timer()
279 | end
280 | end
281 |
282 | function HUDTeammate:_start_interact_timer(interaction_time)
283 | local condition_timer = self._panel:child("condition_timer")
284 | condition_timer:stop()
285 | condition_timer:animate(callback(self, self, "_animate_interact_timer"), interaction_time)
286 | end
287 |
288 | function HUDTeammate:_animate_interact_timer(condition_timer, total_time)
289 | condition_timer:set_font_size(tweak_data.hud_players.timer_size)
290 | condition_timer:set_color(Color.white)
291 | condition_timer:set_visible(true)
292 |
293 | local t = total_time
294 | while t >= 0 do
295 | t = t - coroutine.yield()
296 | condition_timer:set_text(string.format("%.1fs", t))
297 | condition_timer:set_color(math.lerp(Color('00FF00'), Color.white, t / total_time))
298 | end
299 | condition_timer:set_text(string.format("%.1fs", 0))
300 | condition_timer:set_color(Color('00FF00'))
301 | end
302 |
303 | function HUDTeammate:_stop_interact_timer()
304 | if alive(self._panel) then
305 | local condition_timer = self._panel:child("condition_timer")
306 | condition_timer:stop()
307 | condition_timer:set_visible(false)
308 | end
309 | end
310 |
311 | function HUDTeammate:set_condition(icon_data, ...)
312 | local visible = icon_data ~= "mugshot_normal"
313 | self:set_stamina_meter_visibility(not visible and WolfHUD:getSetting({"CustomHUD", "PLAYER", "STAMINA"}, true))
314 | if HUDManager.DOWNS_COUNTER_PLUGIN and self._downs_counter and self._detection_counter then
315 | local disabled = visible or not WolfHUD:getSetting({"CustomHUD", self._setting_prefix, "DOWNCOUNTER"}, true) or self._ai
316 | self._downs_counter:set_visible(not disabled and (not managers.groupai:state():whisper_mode() or self:down_amount() > 0))
317 | self._detection_counter:set_visible(not disabled and not self._downs_counter:visible())
318 | end
319 | set_condition_original(self, icon_data, ...)
320 | end
321 |
322 | end
323 |
--------------------------------------------------------------------------------
/mod.txt:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "WolfHUD",
3 | "description" : "This is a Mod Collection of HUD altering scripts, as well as quality of life changes to the game and its menus. \n\nSome of the included scripts are: \n- CustomHUD, HUDList, KillCounter, Press2Hold & WeaponGadgets,\n made by Seven\n- TabStats + NumericSuspicion, by friendlyfire\n- Enemy Healthbar, by Undeadsewer\n- DrivingHUD, by ViciousWalrus + Great Big Bushy Beard, rewritten by me\n- PrePlanManager, ProfileMenu & Equipment Tweaks, made by me\n- many many more...\n\nFor a full list of included mods, go to the GitHUB repository, linked as contact.\n\nLocalizations: \n- English made by me\n- German made by me\n- Russian made by chrom[K]a, Magic3000 & MEXAHOTABOP\n- Korean made by Я!zu\n- Spanish made by papydeath95\n- Chinese made by zhongfly\n- French made by EliseMRX (La Mule).",
4 | "author" : "Kamikaze94",
5 | "contact" : "https://github.com/Kamikaze94/WolfHUD",
6 | "version" : "3.4.0",
7 | "priority" : 1,
8 | "blt_version" : 2,
9 | "supermod_definition" : "supermod.xml",
10 | "image" : "wolfhud.png",
11 | "color" : "0 255 128",
12 | "pre_hooks" : [
13 | { "hook_id" : "lib/entry", "script_path" : "Core.lua" }
14 | ],
15 | "updates" : [
16 | {
17 | "identifier" : "wolfhud",
18 | "host" : {
19 | "meta" : "https://github.com/Kamikaze94/WolfHUD/raw/autoupdate/meta.json"
20 | }
21 | },
22 | {
23 | "identifier" : "fed_inv",
24 | "host" : {
25 | "meta" : "https://github.com/Kamikaze94/WolfHUD/raw/autoupdate/meta.json"
26 | },
27 | "install_dir" : "assets/mod_overrides/",
28 | "install_folder" : "Federal Inventory",
29 | "display_name" : "Federal Inventory"
30 | }
31 | ]
32 | }
--------------------------------------------------------------------------------
/supermod.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 | <:include src="assets/assets.xml"/>
309 |
310 |
--------------------------------------------------------------------------------
/wolfhud.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kamikaze94/WolfHUD/1b2736f9290062fe73ef3f2f10b913255def4905/wolfhud.png
--------------------------------------------------------------------------------