|
1 | | -comms = { |
2 | | - Init: (data) => |
3 | | - @Base.Init @, data |
4 | | - |
5 | | - if SERVER |
6 | | - @SetMajor true |
7 | | - @SetPersistent true |
8 | | - |
9 | | - OnStart: => |
10 | | - @Base.OnStart @ |
11 | | - if SERVER |
12 | | - GAMEMODE\SetCommunicationsDisabled true |
13 | | - |
14 | | - local btn |
15 | | - for ent in *ents.GetAll! |
16 | | - if ent.GetSabotageName and ent\GetSabotageName! == @GetHandler! |
17 | | - btn = ent |
18 | | - break |
19 | | - |
20 | | - if btn |
21 | | - @SetActivationButtons btn |
22 | | - |
23 | | - OnButtonUse: (playerTable, button) => |
24 | | - if SERVER |
25 | | - GAMEMODE\Sabotage_OpenVGUI playerTable, @, button |
26 | | - |
27 | | - OnSubmit: => |
28 | | - @End! |
29 | | - |
30 | | - OnEnd: => |
31 | | - @Base.OnEnd @ |
32 | | - if SERVER |
33 | | - GAMEMODE\SetCommunicationsDisabled false |
34 | | - @SetActivationButtons! |
35 | | -} |
36 | | - |
37 | | -if CLIENT |
38 | | - with comms |
39 | | - .CreateVGUI = => |
40 | | - base = vgui.Create "AmongUsSabotageBase" |
41 | | - |
42 | | - with base |
43 | | - \SetSabotage @ |
44 | | - \Setup with vgui.Create "DPanel" |
45 | | - max_size = ScrH! * 0.7 |
46 | | - |
47 | | - \SetSize max_size, max_size * 0.55 |
48 | | - |
49 | | - \SetBackgroundColor Color 64, 64, 64 |
50 | | - with \Add "DButton" |
51 | | - margin = ScrH! * 0.01 |
52 | | - \DockMargin margin * 4, 0, margin * 4, margin * 4 |
53 | | - \SetTall ScrH! * 0.05 |
54 | | - \SetFont "NMW AU PlaceholderText" |
55 | | - \Dock BOTTOM |
56 | | - \SetText "Submit" |
57 | | - .DoClick = -> |
58 | | - base\Submit! |
59 | | - \Popup! |
60 | | - |
61 | | - return base |
62 | | - |
63 | | -return comms |
| 1 | +comms = { |
| 2 | + Init: (data) => |
| 3 | + @Base.Init @, data |
| 4 | + |
| 5 | + if SERVER |
| 6 | + @SetMajor true |
| 7 | + @SetPersistent true |
| 8 | + @SetNetworkable "Position" |
| 9 | + |
| 10 | + OnStart: => |
| 11 | + @Base.OnStart @ |
| 12 | + if SERVER |
| 13 | + @SetPosition math.random -110, 110 |
| 14 | + GAMEMODE\SetCommunicationsDisabled true |
| 15 | + |
| 16 | + local btn |
| 17 | + for ent in *ents.GetAll! |
| 18 | + if ent.GetSabotageName and ent\GetSabotageName! == @GetHandler! |
| 19 | + btn = ent |
| 20 | + break |
| 21 | + |
| 22 | + if btn |
| 23 | + @SetActivationButtons btn |
| 24 | + |
| 25 | + OnButtonUse: (playerTable, button) => |
| 26 | + if SERVER |
| 27 | + GAMEMODE\Sabotage_OpenVGUI playerTable, @, button |
| 28 | + |
| 29 | + OnSubmit: => |
| 30 | + @End! |
| 31 | + |
| 32 | + OnEnd: => |
| 33 | + @Base.OnEnd @ |
| 34 | + if SERVER |
| 35 | + GAMEMODE\SetCommunicationsDisabled false |
| 36 | + @SetActivationButtons! |
| 37 | + |
| 38 | + SetPosition: (value) => |
| 39 | + @__position = value |
| 40 | + if SERVER |
| 41 | + @SetDirty! |
| 42 | + |
| 43 | + GetPosition: => @__position or 0 |
| 44 | +} |
| 45 | + |
| 46 | +if CLIENT |
| 47 | + ROTATION_MATRIX = Matrix! |
| 48 | + |
| 49 | + COLOR_ACTIVE = Color 0, 255, 0 |
| 50 | + COLOR_INACTIVE = Color 255, 0, 0 |
| 51 | + |
| 52 | + COMMONS = {asset, Material("au/gui/sabotages/common/#{asset}.png", "smooth") for asset in *{ |
| 53 | + "light" |
| 54 | + "lightshine" |
| 55 | + }} |
| 56 | + |
| 57 | + ASSETS = {asset, Material("au/gui/sabotages/comms/#{asset}.png", "smooth") for asset in *{ |
| 58 | + "radio" |
| 59 | + "headphones" |
| 60 | + "dial" |
| 61 | + }} |
| 62 | + |
| 63 | + -- Swiggity swooty. |
| 64 | + comms.SetPosition = (value) => |
| 65 | + @__position = value |
| 66 | + @__theta = nil |
| 67 | + |
| 68 | + OSCIL_COUNT = 200 |
| 69 | + comms.CreateVGUI = (data) => |
| 70 | + base = vgui.Create "AmongUsSabotageBase" |
| 71 | + |
| 72 | + -- Create sounds and attach them to the button (radio). |
| 73 | + sounds = |
| 74 | + radio: CreateSound data.button, "au/panel_comms_radio.wav" |
| 75 | + static: CreateSound data.button, "au/panel_comms_static.wav" |
| 76 | + |
| 77 | + sounds.radio\PlayEx 0, 100 |
| 78 | + |
| 79 | + sounds.static\PlayEx 0.25, 100 |
| 80 | + |
| 81 | + -- Set up a hook to catch and clean sounds up. |
| 82 | + hook.Add "Think", "GMAU Comms Thinker", -> |
| 83 | + for _, sound in pairs sounds |
| 84 | + continue if not sound |
| 85 | + if sound\IsPlaying! and not IsValid base |
| 86 | + sound\Stop! |
| 87 | + |
| 88 | + if not IsValid base |
| 89 | + hook.Remove "Think", "GMAU Comms Thinker" |
| 90 | + |
| 91 | + with base |
| 92 | + \SetSabotage @ |
| 93 | + \Setup with vgui.Create "DImage" |
| 94 | + if not @__theta |
| 95 | + validPositions = {} |
| 96 | + -- You know what? This is the definition of jank. |
| 97 | + -- I didn't want to implement proper weighted random. |
| 98 | + for i = -110, 110, 10 |
| 99 | + if 10 < math.abs @GetPosition! - i |
| 100 | + table.insert validPositions, i |
| 101 | + |
| 102 | + @__theta = table.Random validPositions |
| 103 | + |
| 104 | + correct = false |
| 105 | + accumulator = 0 |
| 106 | + submitted = false |
| 107 | + |
| 108 | + .Think = -> |
| 109 | + -- Determine whether we should increment/decrement the accumulator. |
| 110 | + changed = if correct and accumulator < 1.25 |
| 111 | + accumulator = math.min 1.25, accumulator + FrameTime! * 0.5 |
| 112 | + true |
| 113 | + |
| 114 | + elseif not correct and accumulator > 0 |
| 115 | + accumulator = math.max 0, accumulator - FrameTime! * 0.5 |
| 116 | + true |
| 117 | + |
| 118 | + -- If the accumulator value was changed earlier... |
| 119 | + if changed |
| 120 | + clamped = math.Clamp accumulator, 0, 1 |
| 121 | + |
| 122 | + -- Modulate sounds. |
| 123 | + sounds.static\ChangeVolume 0.25 * (1 - clamped) |
| 124 | + sounds.radio\ChangeVolume 0.25 * clamped |
| 125 | + |
| 126 | + -- Submit. |
| 127 | + if accumulator == 1.25 and not submitted |
| 128 | + submitted = true |
| 129 | + base\Submit! |
| 130 | + |
| 131 | + max_size = ScrH! * 0.75 |
| 132 | + \SetSize max_size, (max_size / 505) * 349 |
| 133 | + \SetMaterial ASSETS.radio |
| 134 | + |
| 135 | + oscilWidth = (max_size / 505) * 196 |
| 136 | + oscilHeight = (max_size / 505) * 121 |
| 137 | + |
| 138 | + leftOscilX = (max_size / 505) * 37 |
| 139 | + rightOscilX = (max_size / 505) * 276 |
| 140 | + oscilY = (max_size / 505) * 37 |
| 141 | + |
| 142 | + headphonesWidth = (max_size / 505) * 577 |
| 143 | + headphonesHeight = (max_size / 505) * 486 |
| 144 | + |
| 145 | + headphonesOffsetX = (max_size / 505) * -72 |
| 146 | + headphonesOffsetY = (max_size / 505) * -136 |
| 147 | + |
| 148 | + -- Override Paint and draw headphones behind the panel. |
| 149 | + -- Hacky but gets the job done. |
| 150 | + oldPaint = .Paint |
| 151 | + .Paint = (w, h) => |
| 152 | + old = DisableClipping true |
| 153 | + |
| 154 | + surface.SetDrawColor 255, 255, 255 |
| 155 | + surface.SetMaterial ASSETS.headphones |
| 156 | + surface.DrawTexturedRect headphonesOffsetX, headphonesOffsetY, |
| 157 | + headphonesWidth, headphonesHeight |
| 158 | + |
| 159 | + DisableClipping old |
| 160 | + |
| 161 | + oldPaint @, w, h |
| 162 | + |
| 163 | + -- Left oscillator. |
| 164 | + -- Fast sin. |
| 165 | + with \Add "Panel" |
| 166 | + \SetPos leftOscilX, oscilY |
| 167 | + \SetSize oscilWidth, oscilHeight |
| 168 | + .Paint = (_, w, h) -> |
| 169 | + surface.SetDrawColor 0, 255, 0 |
| 170 | + |
| 171 | + local prev |
| 172 | + for i = 1, OSCIL_COUNT |
| 173 | + value = 0.5 + (math.sin CurTime! * 15 + i * 0.1) * 0.2 |
| 174 | + if prev |
| 175 | + -- Multiply and flip the values. |
| 176 | + cy = h - h * value |
| 177 | + py = h - h * prev |
| 178 | + |
| 179 | + -- Flip the values again. |
| 180 | + cx = w - w * ((i - 1) / (OSCIL_COUNT - 1)) |
| 181 | + px = w - w * ((i - 2) / (OSCIL_COUNT - 1)) |
| 182 | + |
| 183 | + -- This will probably look horrible for 4K players. |
| 184 | + -- But oh well! |
| 185 | + surface.DrawLine cx, cy, px, py |
| 186 | + |
| 187 | + prev = value |
| 188 | + |
| 189 | + -- Right oscillator. |
| 190 | + -- Fast sin with noise. |
| 191 | + with \Add "Panel" |
| 192 | + \SetPos rightOscilX, oscilY |
| 193 | + \SetSize oscilWidth, oscilHeight |
| 194 | + .Paint = (_, w, h) -> |
| 195 | + surface.SetDrawColor 0, 255, 0 |
| 196 | + |
| 197 | + local prev |
| 198 | + for i = 1, OSCIL_COUNT |
| 199 | + distortion = math.abs(@GetPosition! - @__theta) / 110 |
| 200 | + |
| 201 | + value = 0.5 + (math.sin CurTime! * 15 + i * 0.1) * 0.2 + |
| 202 | + ((math.random! * 2) - 1) * 0.1 * distortion + |
| 203 | + ((math.random! * 2) - 1) * 0.01 |
| 204 | + |
| 205 | + if prev |
| 206 | + -- Multiply and flip the values. |
| 207 | + cy = h - h * value |
| 208 | + py = h - h * prev |
| 209 | + |
| 210 | + cx = w * ((i - 1) / (OSCIL_COUNT - 1)) |
| 211 | + px = w * ((i - 2) / (OSCIL_COUNT - 1)) |
| 212 | + |
| 213 | + -- This will probably look horrible for 4K players. |
| 214 | + -- But oh well! |
| 215 | + surface.DrawLine cx, cy, px, py |
| 216 | + |
| 217 | + prev = value |
| 218 | + |
| 219 | + dialX = (max_size / 505) * 381 |
| 220 | + dialY = (max_size / 505) * 252 |
| 221 | + dialWidth = (max_size / 505) * 122 |
| 222 | + dialHeight = (max_size / 505) * 137 |
| 223 | + dialMax = math.max dialWidth, dialHeight |
| 224 | + |
| 225 | + dialOriginX = (max_size / 505) * 122 / 2 |
| 226 | + dialOriginY = (max_size / 505) * 79 |
| 227 | + |
| 228 | + -- Dial. |
| 229 | + with \Add "Button" |
| 230 | + \SetPos dialX - dialMax/2, dialY - dialMax/2 |
| 231 | + \SetSize dialMax, dialMax |
| 232 | + \SetText "" |
| 233 | + .Paint = (_, w, h) -> |
| 234 | + -- If the player is holding the dial, |
| 235 | + -- point it towards the cursor. |
| 236 | + if \IsDown! |
| 237 | + cursorX, cursorY = \LocalCursorPos! |
| 238 | + |
| 239 | + @__theta = math.Clamp (math.NormalizeAngle -90 + math.deg( |
| 240 | + math.atan2 dialOriginY - cursorY, dialOriginX - cursorX |
| 241 | + )), -110, 110 |
| 242 | + |
| 243 | + correct = 8 > math.abs @GetPosition! - @__theta |
| 244 | + |
| 245 | + -- Prepare the rotation matrix. |
| 246 | + ltsx, ltsy = _\LocalToScreen 0, 0 |
| 247 | + v = Vector ltsx + dialOriginX, ltsy + dialOriginY |
| 248 | + |
| 249 | + with ROTATION_MATRIX |
| 250 | + \Identity! |
| 251 | + \Translate v |
| 252 | + \Rotate Angle 0, @__theta, 0 |
| 253 | + \Translate -v |
| 254 | + |
| 255 | + surface.DisableClipping true |
| 256 | + cam.PushModelMatrix ROTATION_MATRIX, true |
| 257 | + |
| 258 | + surface.SetDrawColor 255, 255, 255 |
| 259 | + |
| 260 | + -- Draw the dial. |
| 261 | + surface.SetMaterial ASSETS.dial |
| 262 | + surface.DrawTexturedRect 0, 0, |
| 263 | + dialWidth, dialHeight |
| 264 | + |
| 265 | + cam.PopModelMatrix! |
| 266 | + surface.DisableClipping false |
| 267 | + |
| 268 | + lightWidth = (max_size / 505) * 24 |
| 269 | + lightHeight = (max_size / 505) * 24 |
| 270 | + lightOffsetX = (max_size / 505) * 476 |
| 271 | + lightOffsetY = (max_size / 505) * 166 |
| 272 | + |
| 273 | + -- Right LED. |
| 274 | + -- Becomes greener the longer the dial is held at the correct position. |
| 275 | + with \Add "Panel" |
| 276 | + \SetSize lightWidth, lightHeight |
| 277 | + \SetPos lightOffsetX - lightWidth, lightOffsetY |
| 278 | + |
| 279 | + .Paint = (_, w, h) -> |
| 280 | + surface.SetDrawColor 0, 255 * math.min(accumulator, 1), 0 |
| 281 | + surface.SetMaterial COMMONS.light |
| 282 | + surface.DrawTexturedRect 0, 0, w, h |
| 283 | + |
| 284 | + with \Add "DImage" |
| 285 | + \Dock FILL |
| 286 | + \SetMaterial COMMONS.lightshine |
| 287 | + |
| 288 | + -- LED. |
| 289 | + -- |
| 290 | + with \Add "Panel" |
| 291 | + \SetSize lightWidth, lightHeight |
| 292 | + \SetPos lightOffsetX - lightWidth * 2 - lightWidth / 4, lightOffsetY |
| 293 | + |
| 294 | + .Paint = (_, w, h) -> |
| 295 | + surface.SetDrawColor (accumulator > 1) and COLOR_ACTIVE or COLOR_INACTIVE |
| 296 | + surface.SetMaterial COMMONS.light |
| 297 | + surface.DrawTexturedRect 0, 0, w, h |
| 298 | + |
| 299 | + with \Add "DImage" |
| 300 | + \Dock FILL |
| 301 | + \SetMaterial COMMONS.lightshine |
| 302 | + |
| 303 | + \Popup! |
| 304 | + |
| 305 | +return comms |
0 commit comments