├── README.md ├── charactercreation_simplified ├── cl_plugin.lua ├── derma │ └── cl_charcreate.lua └── sh_plugin.lua ├── deequip_on_death └── sh_plugin.lua ├── scavenging ├── cl_plugin.lua ├── derma │ └── cl_scavengingsetup.lua ├── entities │ └── entities │ │ └── ix_scavengingpile │ │ ├── cl_init.lua │ │ ├── init.lua │ │ └── shared.lua ├── items │ └── sh_scavengingkit.lua ├── sh_plugin.lua ├── sv_configuration.lua └── sv_plugin.lua └── spawnmenu_itemtab.lua /README.md: -------------------------------------------------------------------------------- 1 | # "Help! I'm getting errors!" 2 | ### "I changed a configuration and getting errors that I didn't have before!" 3 | Check for typos. 4 | ### "I tried everything above and it still doesn't work!" 5 | Try the plugin in a brand new helix gamemode. If you're no longer getting errors, then something in your old schema was breaking something. 6 | If you're still getting errors after this, then contact me. 7 | -------------------------------------------------------------------------------- /charactercreation_simplified/cl_plugin.lua: -------------------------------------------------------------------------------- 1 | 2 | ix = ix or {}; 3 | ix.CCSimplified = ix.CCSimplified or {}; 4 | ix.CCSimplified.List = ix.CCSimplified.List or {}; -- This holds all the information by UniqueID. 5 | ix.CCSimplified.Order = ix.CCSimplified.Order or {}; -- This holds all the information by Order after handling ix.CCSimplified.List. 6 | ix.CCSimplified.Compile = function() 7 | ix.CCSimplified.Order = {}; 8 | for UniqueID, v in SortedPairsByMemberValue( ix.CCSimplified.List, "Order", false ) do 9 | local PredictedNextValue = table.Count( ix.CCSimplified.Order ) + 1; 10 | ix.CCSimplified.Order[PredictedNextValue] = v["Hooks"]; 11 | end 12 | end 13 | ix.CCSimplified.Add = function( order, uniqueid, hooktable ) 14 | ix.CCSimplified.List[uniqueid] = { 15 | ["Order"] = order, 16 | ["Hooks"] = hooktable 17 | }; 18 | ix.CCSimplified.Compile(); 19 | end 20 | 21 | ix.CCSimplified.Add( 1, "Resetting Populate Panels", { 22 | ["Populate"] = function( self ) 23 | for i = 1, #self.RepopulatePanels do 24 | self.RepopulatePanels[i]:Remove(); 25 | end 26 | 27 | self.RepopulatePanels = {}; 28 | end 29 | } ); 30 | ix.CCSimplified.Add( 2, "Creating Progress Bar", { 31 | ["Initalize"] = function( self ) 32 | self.Progress = self:Add( "ixSegmentedProgress" ); 33 | self.Progress:SetBarColor( ix.config.Get( "color" ) ); 34 | self.Progress:SetSize( self:GetParent():GetWide(), 0 ); 35 | self.Progress:SizeToContents(); 36 | self.Progress:SetPos( 0, self:GetParent():GetTall() - self.Progress:GetTall() ); 37 | end 38 | } ); 39 | ix.CCSimplified.Add( 3, "Factions & Whitelisting: 'faction'", { 40 | ["Initalize"] = function( self ) 41 | -- Definitions: 42 | local Padding = ScreenScale( 32 ); 43 | local Parent = self:GetParent(); 44 | local HalfWidth = Parent:GetWide() * 0.5 - ( Padding * 2 ); 45 | local HalfHeight = Parent:GetTall() * 0.5 - ( Padding * 2 ); 46 | local ModelFOV = ( ScrW() > ScrH() * 1.8 ) and 100 or 78; 47 | self.Factions = {}; 48 | -- This is the buttons to pick what faction you want to be in. This is for populate later on! 49 | self.Factions.Buttons = {}; 50 | self.Factions.Panel = self:AddSubpanel( "faction", true ); 51 | self.Factions.Panel:SetTitle( "chooseFaction" ); 52 | self.Factions.Panel.OnSetActive = function() 53 | -- Two options is two options, but one option is no option. Move on if there is no other option. 54 | if( #self.Factions.Buttons == 1 ) then 55 | self:SetActiveSubpanel( "description", 0 ); 56 | end 57 | end 58 | 59 | self.Factions.PanelRight = self.Factions.Panel:Add( "Panel" ); 60 | self.Factions.PanelRight:Dock( RIGHT ); 61 | self.Factions.PanelRight:SetSize( HalfWidth + Padding * 2, HalfHeight ); 62 | 63 | self.Factions.Proceed = self.Factions.PanelRight:Add( "ixMenuButton" ); 64 | self.Factions.Proceed:SetText( "proceed" ); 65 | self.Factions.Proceed:SetContentAlignment( 6 ); 66 | self.Factions.Proceed:Dock( BOTTOM ); 67 | self.Factions.Proceed:SizeToContents(); 68 | self.Factions.Proceed.DoClick = function() 69 | self.Progress:IncrementProgress(); 70 | self:Populate(); 71 | self:SetActiveSubpanel( "description" ); 72 | end 73 | 74 | self.Factions.Model = self.Factions.PanelRight:Add( "ixModelPanel" ); 75 | self.Factions.Model:Dock( FILL ); 76 | self.Factions.Model:SetModel( "models/error.mdl" ); 77 | self.Factions.Model:SetFOV( ModelFOV ); 78 | self.Factions.Model.PaintModel = self.Factions.Model.Paint; 79 | 80 | self.Factions.PanelLeft = self.Factions.Panel:Add( "ixCharMenuButtonList" ); 81 | self.Factions.PanelLeft:SetWide( HalfWidth ); 82 | self.Factions.PanelLeft:Dock( FILL ); 83 | 84 | self.Factions.Back = self.Factions.Panel:Add( "ixMenuButton" ); 85 | self.Factions.Back:SetText( "return" ); 86 | self.Factions.Back:SizeToContents(); 87 | self.Factions.Back:Dock( BOTTOM ); 88 | self.Factions.Back.DoClick = function() 89 | self.Progress:DecrementProgress(); 90 | self:SetActiveSubpanel( "faction", 0 ); 91 | self:SlideDown(); 92 | self:GetParent().mainPanel:Undim(); 93 | end 94 | end, 95 | ["Populate"] = function( self ) 96 | if( !self.Payload.Faction ) then 97 | for _, v in pairs( self.Factions.Buttons ) do 98 | if( v:GetSelected() ) then 99 | v:SetSelected( true ); 100 | break; 101 | end 102 | end 103 | end 104 | 105 | self.Factions.PanelLeft:SizeToContents(); 106 | 107 | if( self.bInitialPopulate ) then return end; 108 | local lastSelected; 109 | 110 | for _, v in pairs( self.Factions.Buttons ) do 111 | if( v:GetSelected() ) then 112 | lastSelected = v.Faction; 113 | end 114 | if( IsValid( v ) ) then 115 | v:Remove(); 116 | end 117 | end 118 | 119 | self.Factions.Buttons = {}; 120 | 121 | for _, v in SortedPairs( ix.faction.teams ) do 122 | if( ix.faction.HasWhitelist( v.index ) ) then 123 | local button = self.Factions.PanelLeft:Add( "ixMenuSelectionButton" ); 124 | button:SetBackgroundColor( v.color or color_white ); 125 | button:SetText( L( v.name ):utf8upper() ); 126 | button:SizeToContents(); 127 | button:SetButtonList( self.Factions.Buttons ); 128 | button.Faction = v.index; 129 | button.OnSelected = function( panel ) 130 | local faction = ix.faction.indices[panel.Faction]; 131 | local models = faction:GetModels( LocalPlayer() ); 132 | 133 | self.Payload:Set( "faction", panel.Faction ); 134 | self.Payload:Set( "model", math.random( 1, #models ) ); 135 | end 136 | if( ( lastSelected and lastSelected == v.index ) or ( !lastSelected and v.isDefault ) ) then 137 | button:SetSelected( true ); 138 | lastSelected = v.index; 139 | end 140 | end 141 | end 142 | 143 | if( #self.Factions.Buttons > 1 ) then 144 | self.Progress:AddSegment( "@faction" ); 145 | end 146 | 147 | end, 148 | ["GetContainerPanel"] = function( self, name ) 149 | if( name == "faction" ) then 150 | return self.Factions.PanelLeft; 151 | end 152 | end, 153 | ["OnModelPayload"] = function( self, value ) 154 | print( self ) 155 | print( value ) 156 | local faction = ix.faction.indices[self.Payload.faction]; 157 | if( faction ) then 158 | local model = faction:GetModels( LocalPlayer() )[value]; 159 | if( istable( model ) ) then 160 | self.Factions.Model:SetModel( model[1], model[2] or 0, model[3] ); 161 | else 162 | self.Factions.Model:SetModel( model ); 163 | end 164 | end 165 | end 166 | } ); 167 | ix.CCSimplified.Add( 4, "Description: 'description'", { 168 | ["Initalize"] = function( self ) 169 | -- Definitions: 170 | local Padding = ScreenScale( 32 ); 171 | local Parent = self:GetParent(); 172 | local HalfWidth = Parent:GetWide() * 0.5 - ( Padding * 2 ); 173 | local HalfHeight = Parent:GetTall() * 0.5 - ( Padding * 2 ); 174 | local ModelFOV = ( ScrW() > ScrH() * 1.8 ) and 100 or 78; 175 | 176 | self.Description = self:AddSubpanel( "description" ); 177 | self.Description:SetTitle( "chooseDescription" ); 178 | 179 | self.Description.PanelLeft = self.Description:Add( "Panel" ); 180 | self.Description.PanelLeft:Dock( LEFT ); 181 | self.Description.PanelLeft:SetSize( HalfWidth, HalfHeight ); 182 | 183 | self.Description.Back = self.Description.PanelLeft:Add( "ixMenuButton" ); 184 | self.Description.Back:SetText( "return" ); 185 | self.Description.Back:SetContentAlignment( 4 ); 186 | self.Description.Back:SizeToContents(); 187 | self.Description.Back:Dock( BOTTOM ); 188 | self.Description.Back.DoClick = function() 189 | self.Progress:DecrementProgress(); 190 | if( #self.Factions.Buttons == 1 ) then 191 | self.Factions.Back:DoClick(); 192 | else 193 | self:SetActiveSubpanel( "faction" ); 194 | end 195 | end 196 | 197 | self.Description.Model = self.Description.PanelLeft:Add( "ixModelPanel" ); 198 | self.Description.Model:Dock( FILL ); 199 | self.Description.Model:SetModel( self.Factions.Model:GetModel() ); 200 | self.Description.Model:SetFOV( ModelFOV - 13 ); 201 | self.Description.Model.PaintModel = self.Description.Model.Paint; 202 | 203 | self.Description.PanelRight = self.Description:Add( "Panel" ); 204 | self.Description.PanelRight:SetWide( HalfWidth + Padding * 2 ); 205 | self.Description.PanelRight:Dock( RIGHT ); 206 | 207 | self.Description.Proceed = self.Description.PanelRight:Add( "ixMenuButton" ); 208 | self.Description.Proceed:SetText( "proceed" ); 209 | self.Description.Proceed:SetContentAlignment( 6 ); 210 | self.Description.Proceed:SizeToContents(); 211 | self.Description.Proceed:Dock( BOTTOM ); 212 | self.Description.Proceed.DoClick = function() 213 | if( self:VerifyProgression( "description" ) ) then 214 | if ( #self.Attributes.PanelRight:GetChildren() < 2) then 215 | self:SendPayload(); 216 | return 217 | end 218 | self.Progress:IncrementProgress(); 219 | self:SetActiveSubpanel( "attributes" ); 220 | end 221 | end 222 | end, 223 | ["PostPopulate"] = function( self ) 224 | if( self.bInitialPopulate ) then return end; 225 | 226 | self.Progress:AddSegment( "@description" ); 227 | end, 228 | ["GetContainerPanel"] = function( self, name ) 229 | if( name == "description" ) then 230 | return self.Description.PanelRight; 231 | end 232 | end, 233 | ["OnModelPayload"] = function( self, value ) 234 | local faction = ix.faction.indices[self.Payload.faction]; 235 | if( faction ) then 236 | local model = faction:GetModels( LocalPlayer() )[value]; 237 | if( istable( model ) ) then 238 | self.Description.Model:SetModel( model[1], model[2] or 0, model[3] ); 239 | else 240 | self.Description.Model:SetModel( model ); 241 | end 242 | end 243 | end 244 | } ); 245 | ix.CCSimplified.Add( 5, "Attributes: 'attributes'", { 246 | ["Initalize"] = function( self ) 247 | -- Definitions: 248 | local Padding = ScreenScale( 32 ); 249 | local Parent = self:GetParent(); 250 | local HalfWidth = Parent:GetWide() * 0.5 - ( Padding * 2 ); 251 | local HalfHeight = Parent:GetTall() * 0.5 - ( Padding * 2 ); 252 | local ModelFOV = ( ScrW() > ScrH() * 1.8 ) and 100 or 78; 253 | 254 | self.Attributes = self:AddSubpanel( "attributes" ); 255 | self.Attributes:SetTitle( "chooseSkills" ); 256 | 257 | self.Attributes.PanelLeft = self.Attributes:Add( "Panel" ); 258 | self.Attributes.PanelLeft:Dock( LEFT ); 259 | self.Attributes.PanelLeft:SetSize( HalfWidth, HalfHeight ); 260 | 261 | self.Attributes.Back = self.Attributes.PanelLeft:Add( "ixMenuButton" ); 262 | self.Attributes.Back:SetText( "return" ); 263 | self.Attributes.Back:SetContentAlignment( 4 ); 264 | self.Attributes.Back:SizeToContents(); 265 | self.Attributes.Back:Dock( BOTTOM ); 266 | self.Attributes.Back.DoClick = function() 267 | self.Progress:DecrementProgress(); 268 | self:SetActiveSubpanel( "description" ); 269 | end 270 | 271 | self.Attributes.Model = self.Attributes.PanelLeft:Add( "ixModelPanel" ); 272 | self.Attributes.Model:Dock( FILL ); 273 | self.Attributes.Model:SetModel( self.Factions.Model:GetModel() ); 274 | self.Attributes.Model:SetFOV( ModelFOV - 13 ); 275 | self.Attributes.Model.PaintModel = self.Attributes.Model.Paint; 276 | 277 | self.Attributes.PanelRight = self.Attributes:Add( "Panel" ); 278 | self.Attributes.PanelRight:SetWide( HalfWidth + Padding * 2); 279 | self.Attributes.PanelRight:Dock( RIGHT ); 280 | 281 | self.Attributes.Proceed = self.Attributes.PanelRight:Add( "ixMenuButton" ); 282 | self.Attributes.Proceed:SetText( "finish" ); 283 | self.Attributes.Proceed:SetContentAlignment( 6 ); 284 | self.Attributes.Proceed:SizeToContents(); 285 | self.Attributes.Proceed:Dock( BOTTOM ); 286 | self.Attributes.Proceed.DoClick = function() 287 | self:SendPayload(); 288 | end 289 | end, 290 | ["PostPopulate"] = function( self ) 291 | if( self.bInitialPopulate ) then return end; 292 | if( #self.Attributes.PanelRight:GetChildren() > 1 ) then 293 | self.Progress:AddSegment( "@skills" ); 294 | end 295 | end, 296 | ["GetContainerPanel"] = function( self, name ) 297 | if( name == "attributes" ) then 298 | return self.Attributes.PanelRight; 299 | end 300 | end, 301 | ["OnModelPayload"] = function( self, value ) 302 | local faction = ix.faction.indices[self.Payload.faction]; 303 | if( faction ) then 304 | local model = faction:GetModels( LocalPlayer() )[value]; 305 | if( istable( model ) ) then 306 | self.Attributes.Model:SetModel( model[1], model[2] or 0, model[3] ); 307 | else 308 | self.Attributes.Model:SetModel( model ); 309 | end 310 | end 311 | end 312 | } ); 313 | ix.CCSimplified.Add( 998, "Hiding Progress Bar", { 314 | ["PostPopulate"] = function( self ) 315 | if( self.bInitialPopulate ) then return end; 316 | 317 | -- No need for the progress bar to be shown if it's only one segment. 318 | if( #self.Progress:GetSegments() == 1 ) then 319 | self.Progress:SetVisible( false ); 320 | end 321 | end 322 | } ); 323 | ix.CCSimplified.Add( 999, "Character Variables Population", { 324 | ["Populate"] = function( self ) 325 | local zPos = 1; 326 | -- set up character vars 327 | for k, v in SortedPairsByMemberValue( ix.char.vars, "index" ) do 328 | if( !v.bNoDisplay and k != "__SortedIndex" ) then 329 | local container = self:GetContainerPanel( v.category or "description" ); 330 | local panel; 331 | if( v.ShouldDisplay and v:ShouldDisplay( container, self.Payload ) == false ) then continue end; 332 | -- if the var has a custom way of displaying, we'll use that instead 333 | if( v.OnDisplay ) then 334 | panel = v:OnDisplay( container, self.Payload ); 335 | elseif( isstring( v.default ) ) then 336 | panel = container:Add( "ixTextEntry" ); 337 | panel:Dock( TOP ); 338 | panel:SetFont( "ixMenuButtonHugeFont" ); 339 | panel:SetUpdateOnType( true ); 340 | panel.OnValueChange = function( this, text ) 341 | self.Payload:Set( k, text ); 342 | end 343 | end 344 | 345 | if( IsValid( panel ) ) then 346 | -- add label for entry 347 | local label = container:Add( "DLabel" ); 348 | label:SetFont( "ixMenuButtonLabelFont" ); 349 | label:SetText( L( k ):utf8upper() ); 350 | label:SizeToContents(); 351 | label:DockMargin( 0, 16, 0, 2 ); 352 | label:Dock( TOP ); 353 | 354 | -- we need to set the docking order so the label is above the panel 355 | label:SetZPos( zPos - 1 ); 356 | panel:SetZPos( zPos ); 357 | 358 | self:AttachCleanup( label ); 359 | self:AttachCleanup( panel ); 360 | 361 | if( v.OnPostSetup ) then 362 | v:OnPostSetup( panel, self.Payload ); 363 | end 364 | 365 | zPos = zPos + 2; 366 | end 367 | end 368 | end 369 | end 370 | } ); 371 | 372 | hook.Add( "CharMenuInitalize", "CharMenuRedoneInitalize", function( self ) 373 | self.RepopulatePanels = {}; 374 | for _, context in ipairs( ix.CCSimplified.Order ) do 375 | for hookname, func in pairs( context ) do 376 | if( hookname != "Initalize" ) then continue end; 377 | func( self ); 378 | end 379 | end 380 | end ); 381 | 382 | hook.Add( "CharMenuPostInitalize", "CharMenuRedonePostInitalize", function( self ) 383 | for _, context in pairs( ix.CCSimplified.Order ) do 384 | for hookname, func in pairs( context ) do 385 | if( hookname != "PostInitalize" ) then continue end; 386 | func( self ); 387 | end 388 | end 389 | 390 | self:AddPayloadHook( "model", function( value ) 391 | for _, context in pairs( ix.CCSimplified.Order ) do 392 | for hookname, func in pairs( context ) do 393 | if( hookname != "OnModelPayload" ) then continue end; 394 | func( self, value ); 395 | end 396 | end 397 | end ); 398 | 399 | net.Receive("ixCharacterAuthed", function() 400 | timer.Remove( "ixCharacterCreateTimeout" ); 401 | self.AwaitingResponse = false; 402 | 403 | local id = net.ReadUInt( 32 ); 404 | local indices = net.ReadUInt( 6 ); 405 | local charList = {}; 406 | 407 | for _ = 1, indices do 408 | charList[#charList + 1] = net.ReadUInt( 32 ); 409 | end 410 | 411 | ix.characters = charList; 412 | 413 | self:SlideDown(); 414 | 415 | if( !IsValid( self ) or !IsValid( self:GetParent() ) ) then return end; 416 | 417 | if( LocalPlayer():GetCharacter() ) then 418 | self:GetParent().mainPanel:Undim(); 419 | self:GetParent():ShowNotice( 2, L( "charCreated" ) ); 420 | elseif( id ) then 421 | self.bMenuShouldClose = true; 422 | 423 | net.Start( "ixCharacterChoose" ); 424 | net.WriteUInt( id, 32 ); 425 | net.SendToServer(); 426 | else 427 | self:SlideDown(); 428 | end 429 | end) 430 | 431 | net.Receive("ixCharacterAuthFailed", function() 432 | timer.Remove( "ixCharacterCreateTimeout" ); 433 | self.AwaitingResponse = false; 434 | 435 | local fault = net.ReadString(); 436 | local args = net.ReadTable(); 437 | 438 | self:SlideDown(); 439 | 440 | self:GetParent().mainPanel:Undim(); 441 | self:GetParent():ShowNotice( 3, L( fault, unpack( args ) ) ); 442 | end) 443 | 444 | end ); 445 | 446 | hook.Add( "CharMenuPopulate", "CharMenuRedonePopulate", function( self ) 447 | for _, context in ipairs( ix.CCSimplified.Order ) do 448 | for hookname, func in pairs( context ) do 449 | if( hookname != "Populate" ) then continue end; 450 | func( self ); 451 | end 452 | end 453 | end ); 454 | 455 | hook.Add( "CharMenuPostPopulate", "CharMenuRedonePopulate", function( self ) 456 | for _, context in ipairs( ix.CCSimplified.Order ) do 457 | for hookname, func in pairs( context ) do 458 | if( hookname != "PostPopulate" ) then continue end; 459 | func( self ); 460 | end 461 | end 462 | end ); 463 | 464 | hook.Add( "CharMenuGetContainerPanel", "CharMenuRedoneGetContainerPanel", function( self, name ) 465 | for _, context in ipairs( ix.CCSimplified.Order ) do 466 | for hookname, func in pairs( context ) do 467 | if( hookname != "GetContainerPanel" ) then continue end; 468 | if( func( self, name ) != nil ) then 469 | return func( self, name ); 470 | end 471 | end 472 | end 473 | end ); -------------------------------------------------------------------------------- /charactercreation_simplified/derma/cl_charcreate.lua: -------------------------------------------------------------------------------- 1 | local Padding = ScreenScale( 32 ); 2 | 3 | DEFINE_BASECLASS( "ixCharMenuPanel" ); 4 | local PANEL = {}; 5 | 6 | function PANEL:Init() 7 | -- Definitions (even if they don't do anything here): 8 | local Parent = self:GetParent(); 9 | local HalfWidth = Parent:GetWide() * 0.5 - ( Padding * 2 ); 10 | local HalfHeight = Parent:GetTall() * 0.5 - ( Padding * 2 ); 11 | local ModelFOV = ( ScrW() > ScrH() * 1.8 ) and 100 or 78; 12 | -- Reset: 13 | self:ResetPayload( true ); 14 | -- CharMenuInitalize Hook: 15 | hook.Run( "CharMenuInitalize", self ); 16 | -- CharMenuPostInitalize Hook: 17 | hook.Run( "CharMenuPostInitalize", self ); 18 | end 19 | 20 | function PANEL:SendPayload() 21 | if( self.AwaitingResponse or !self:VerifyProgression() ) then return end; 22 | self.AwaitingResponse = true; 23 | 24 | timer.Create( "ixCharacterCreateTimeout", 10, 1, function() 25 | if( IsValid( self ) and self.AwaitingResponse ) then 26 | self.AwaitingResponse = false; 27 | self:SlideDown(); 28 | self:GetParent().MainPanel:Undim() 29 | self:GetParent():ShowNotice( 3, L( "unknownError" ) ); 30 | end 31 | end) 32 | 33 | self.Payload:Prepare(); 34 | 35 | net.Start( "ixCharacterCreate" ); 36 | net.WriteTable( self.Payload ); 37 | net.SendToServer(); 38 | end 39 | 40 | function PANEL:OnSlideUp() 41 | self:ResetPayload(); 42 | self:Populate(); 43 | self.Progress:SetProgress( 1 ); 44 | self:SetActiveSubpanel( "faction", 0 ); 45 | end 46 | 47 | function PANEL:OnSlideDown() 48 | end 49 | 50 | function PANEL:ResetPayload( bWithHooks ) 51 | if( bWithHooks ) then 52 | self.Hooks = {}; 53 | end 54 | 55 | self.Payload = {}; 56 | 57 | function self.Payload.Set( payload, key, value ) 58 | self:SetPayload( key, value ); 59 | end 60 | 61 | function self.Payload.AddHook( payload, key, callback ) 62 | self:AddPayloadHook( key, callback ); 63 | end 64 | 65 | function self.Payload.Prepare( payload ) 66 | self.Payload.Set = nil; 67 | self.Payload.AddHook = nil; 68 | self.Payload.Prepare = nil; 69 | end 70 | end 71 | 72 | function PANEL:SetPayload( key, value ) 73 | self.Payload[key] = value; 74 | self:RunPayloadHook( key, value ); 75 | end 76 | 77 | function PANEL:AddPayloadHook( key, callback ) 78 | if( !self.Hooks[key] ) then 79 | self.Hooks[key] = {}; 80 | end 81 | 82 | self.Hooks[key][#self.Hooks[key] + 1] = callback; 83 | end 84 | 85 | function PANEL:RunPayloadHook( key, value ) 86 | local hooks = self.Hooks[key] or {}; 87 | for _, v in ipairs( hooks ) do 88 | v( value ); 89 | end 90 | end 91 | 92 | function PANEL:GetContainerPanel( name ) 93 | return hook.Run( "CharMenuGetContainerPanel", self, name ); 94 | end 95 | 96 | function PANEL:AttachCleanup( panel ) 97 | self.RepopulatePanels[#self.RepopulatePanels + 1] = panel; 98 | end 99 | 100 | function PANEL:Populate() 101 | -- CharMenuPopulate Hook: 102 | hook.Run( "CharMenuPopulate", self ); 103 | -- CharMenuPostPopulate Hook: 104 | hook.Run( "CharMenuPostPopulate", self ); 105 | self.bInitialPopulate = true; 106 | end 107 | 108 | function PANEL:VerifyProgression( name ) 109 | for k, v in SortedPairsByMemberValue( ix.char.vars, "index" ) do 110 | if( name != nil and ( v.category or "description" ) != name ) then continue end; 111 | local value = self.Payload[k]; 112 | 113 | if( !v.bNoDisplay or v.OnValidate ) then 114 | if( v.OnValidate ) then 115 | local result = { v:OnValidate( value, self.Payload, LocalPlayer() ) }; 116 | if( result[1] == false ) then 117 | self:GetParent():ShowNotice( 3, L( unpack( result, 2 ) ) ); 118 | return false; 119 | end 120 | end 121 | self.Payload[k] = value; 122 | end 123 | end 124 | return true; 125 | end 126 | 127 | function PANEL:Paint( width, height ) 128 | derma.SkinFunc( "PaintCharacterCreateBackground", self, width, height ); 129 | BaseClass.Paint( self, width, height ); 130 | end 131 | 132 | vgui.Register("ixCharMenuNew", PANEL, "ixCharMenuPanel") 133 | -------------------------------------------------------------------------------- /charactercreation_simplified/sh_plugin.lua: -------------------------------------------------------------------------------- 1 | PLUGIN.name = "Character Creation: Simplified"; 2 | PLUGIN.author = "Rune Knight"; 3 | PLUGIN.description = "Simplifies the character creation derma by breaking it down into hooks and a readable table."; 4 | PLUGIN.license = [[Copyright 2021 Rune Knight 5 | 6 | This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.]]; 7 | 8 | --[[ 9 | STEAM: https://steamcommunity.com/profiles/76561198028996329/ 10 | DISCORD: Rune Knight#5972 11 | ]] 12 | 13 | --[[ 14 | This plugin was ultimately created to simplify how the character creation is handled and to move it away from the schema. 15 | ]] 16 | 17 | ix.util.Include( "cl_plugin.lua" ); -------------------------------------------------------------------------------- /deequip_on_death/sh_plugin.lua: -------------------------------------------------------------------------------- 1 | PLUGIN.name = "Unequip on Death"; -- Technically misleading name; should be 'Unequip after Death, but before Respawning'. 2 | PLUGIN.author = "Rune Knight"; 3 | PLUGIN.description = "Automatically de-equips items during a period after death and before (fully) respawning."; 4 | PLUGIN.license = [[Copyright 2021 Rune Knight 5 | 6 | This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.]]; 7 | 8 | --[[ 9 | STEAM: https://steamcommunity.com/profiles/76561198028996329/ 10 | DISCORD: Rune Knight#5972 11 | ]] 12 | 13 | -- PlayerDeath doesn't work because ix.item.PerformInventoryAction requires the player to alive. 14 | -- PlayerSpawn and PlayerLoadout is fine, so either works. 15 | -- PostPlayerLoadout is too late because the character's health stop beings nil. 16 | function PLUGIN:PlayerSpawn( client ) 17 | local character = client:GetCharacter(); 18 | if( !character or !character:GetInventory() ) then return end; 19 | if( character:GetData( "health" ) ) then return end; -- On death, the character's health becomes nil. This is our way to differentiate "dying then respawning" and "swapping characters then respawning". 20 | for _, v in pairs( character:GetInventory():GetItems() ) do 21 | if( v:GetData( "equip" ) == true ) then 22 | local ret = ix.item.PerformInventoryAction( client, "EquipUn", v:GetID(), v.invID, {} ); 23 | continue; 24 | end 25 | end 26 | end -------------------------------------------------------------------------------- /scavenging/cl_plugin.lua: -------------------------------------------------------------------------------- 1 | local PLUGIN = PLUGIN; 2 | 3 | -- Context Menu: 4 | net.Receive( "ixScavengingSetup", function() 5 | PLUGIN.Panel = vgui.Create( "ixScavengingSetup" ); 6 | PLUGIN.Panel:Setup( net.ReadEntity(), net.ReadTable() ); 7 | end) 8 | -------------------------------------------------------------------------------- /scavenging/derma/cl_scavengingsetup.lua: -------------------------------------------------------------------------------- 1 | local PLUGIN = PLUGIN; 2 | local PANEL = {}; 3 | 4 | function PANEL:Init() 5 | if( IsValid( PLUGIN.Panel ) ) then 6 | PLUGIN.Panel:Remove(); 7 | end 8 | 9 | self:SetSize( 180, 90 ); 10 | self:Center(); 11 | self:SetBackgroundBlur( true ); 12 | self:SetDeleteOnClose( true ); 13 | self:SetTitle( "Scavenging: Setup" ); 14 | 15 | self.Save = self:Add( "DButton" ); 16 | self.Save:Dock( BOTTOM ); 17 | self.Save:DockMargin( 0, 4, 0, 0 ) 18 | self.Save:SetText( "Finalize" ); 19 | self.Save.DoClick = function() 20 | local name, data = self.ComboBox:GetSelected(); 21 | if( name ) then 22 | net.Start( "ixScavengingSetupFinalize" ); 23 | net.WriteEntity( self.Entity ); 24 | net.WriteString( name ); 25 | net.SendToServer(); 26 | end 27 | self:Close(); 28 | end 29 | 30 | self.ComboBox = self:Add( "DComboBox" ); 31 | self.ComboBox:SetDisabled( false ); 32 | self.ComboBox:Dock( FILL ); 33 | 34 | self:MakePopup(); 35 | PLUGIN.Panel = self; 36 | end 37 | 38 | function PANEL:Setup( entity, tabl ) 39 | if( !entity or !tabl ) then 40 | self:Close(); 41 | end 42 | self.Entity = entity; 43 | self.List = tabl; 44 | for name, _ in pairs( self.List ) do 45 | self.ComboBox:AddChoice( name, nil, false, nil ); 46 | end 47 | end 48 | 49 | function PANEL:OnRemove() 50 | PLUGIN.Panel = nil; 51 | end 52 | 53 | vgui.Register( "ixScavengingSetup", PANEL, "DFrame" ); 54 | -------------------------------------------------------------------------------- /scavenging/entities/entities/ix_scavengingpile/cl_init.lua: -------------------------------------------------------------------------------- 1 | include( "shared.lua" ); 2 | 3 | ENT.PopulateEntityInfo = true; 4 | 5 | function ENT:OnPopulateEntityInfo( tooltip ) 6 | -- If you're seriously putting this as your entity displays, then what did you expect? 7 | if( self:GetDisplayName() == "Default Display Name" and self:GetDisplayDescription() == "Default Display Description" ) then return end; 8 | 9 | local title = tooltip:AddRow( "name" ); 10 | title:SetImportant(); 11 | title:SetText( self:GetDisplayName() ); 12 | title:SetBackgroundColor( ix.config.Get( "color" ) ); 13 | title:SizeToContents(); 14 | 15 | local description = tooltip:AddRow( "description" ); 16 | description:SetText( self:GetDisplayDescription() ); 17 | description:SizeToContents(); 18 | end -------------------------------------------------------------------------------- /scavenging/entities/entities/ix_scavengingpile/init.lua: -------------------------------------------------------------------------------- 1 | AddCSLuaFile( "cl_init.lua" ); 2 | AddCSLuaFile( "shared.lua" ); 3 | 4 | include( "shared.lua" ); 5 | 6 | local PLUGIN = PLUGIN; 7 | 8 | function ENT:Initialize() 9 | -- Initialize: 10 | self:SetModel( "models/hunter/blocks/cube025x025x025.mdl" ); 11 | self:PhysicsInit( SOLID_VPHYSICS ); 12 | self:SetSolid( SOLID_VPHYSICS ); 13 | self:SetUseType( SIMPLE_USE ); 14 | -- Physics: 15 | local physics = self:GetPhysicsObject(); 16 | physics:EnableMotion( false ); 17 | physics:Sleep(); 18 | -- Variables: 19 | self.Vars = {}; 20 | self.Vars.Configured = false; 21 | self.Vars.RemainingCooldown = 0; 22 | self.Vars.TableName = nil; -- 23 | self.Vars.Money = 0; 24 | self.Vars.InventoryID = 0; 25 | self:SetDisplayName( "Default Display Name" ); 26 | self:SetDisplayDescription( "Default Display Description" ); 27 | end 28 | 29 | -- Information: 30 | function ENT:GetVars() 31 | return self.Vars; 32 | end 33 | 34 | function ENT:SetVars( tabl ) 35 | self.Vars = tabl; 36 | end 37 | 38 | function ENT:GetConfigured() 39 | return self.Vars.Configured; 40 | end 41 | 42 | function ENT:SetConfigured( bool ) 43 | self.Vars.Configured = bool; 44 | end 45 | 46 | function ENT:GetRemainingCooldown() 47 | return self.Vars.RemainingCooldown; 48 | end 49 | 50 | function ENT:SetRemainingCooldown( num ) 51 | self.Vars.RemainingCooldown = num; 52 | end 53 | 54 | function ENT:GetTableName() 55 | return self.Vars.TableName; 56 | end 57 | 58 | function ENT:SetTableName( str ) 59 | self.Vars.TableName = str; 60 | end 61 | 62 | function ENT:GetMoney() 63 | return self.Vars.Money; 64 | end 65 | 66 | function ENT:SetMoney( num ) 67 | self.Vars.Money = num; 68 | end 69 | 70 | function ENT:GetInventoryID() 71 | return self.Vars.InventoryID; 72 | end 73 | 74 | function ENT:SetInventoryID( num ) 75 | self.Vars.InventoryID = num; 76 | end 77 | 78 | -- Inventory: 79 | function ENT:GetInventory() 80 | return ix.item.inventories[self:GetInventoryID()]; 81 | end 82 | 83 | function ENT:CreateInventory() 84 | ix.inventory.New( 0, "ix_scavengingpile_" .. self.Vars.TableName, function( inventory ) 85 | inventory.vars.isBag = true; 86 | inventory.vars.isContainer = true; 87 | self:SetInventoryID( inventory:GetID() ); -- Can we even use "self"? 88 | end); 89 | end 90 | 91 | function ENT:RemoveInventory() 92 | ix.item.inventories[self:GetInventoryID()] = nil; 93 | local query = mysql:Delete( "ix_items" ); 94 | query:Where( "inventory_id", self:GetInventoryID() ); 95 | query:Execute(); 96 | query = mysql:Delete( "ix_inventories" ); 97 | query:Where( "inventory_id", self:GetInventoryID() ); 98 | query:Execute(); 99 | self:SetInventoryID( 0 ); 100 | end 101 | 102 | function ENT:OpenInventory( client ) 103 | ix.log.Add( client, "scavengingOpen", self:GetInventoryID(), self:GetDisplayName() ); 104 | ix.storage.Open( client, self:GetInventory(), { 105 | name = self:GetDisplayName(), 106 | entity = self, 107 | data = { 108 | money = self:GetMoney() 109 | }, 110 | OnPlayerClose = function() 111 | ix.log.Add( client, "scavengingClose", self:GetInventoryID(), self:GetDisplayName() ); 112 | end, 113 | searchTime = 0, 114 | }); 115 | end 116 | 117 | -- Spawning/Removal: 118 | function ENT:SpawnFunction( client, trace ) 119 | local ent = ents.Create( "ix_scavengingpile" ); 120 | ent:SetPos( trace.HitPos + Vector( 0, 0, 0 ) ); 121 | ent:SetAngles( Angle( 0, ( ent:GetPos() - client:GetPos() ):Angle().y, 0 ) ); 122 | ent:Spawn(); 123 | ent:Activate(); 124 | return ent; 125 | end 126 | 127 | function ENT:OnRemove() 128 | --[[ 129 | The entity is only properly removed if done by any method that isn't shutting down the server. 130 | ]] 131 | -- Checks: 132 | if( ix.shuttingDown ) then return end; 133 | -- Main: 134 | self:RemoveInventory(); 135 | -- Saving: 136 | PLUGIN:SaveData(); 137 | end 138 | 139 | -- Setup: 140 | function ENT:Setup( client ) 141 | --[[ 142 | nil return; 143 | false return; 144 | string return & client:Notify(); 145 | true return true; 146 | ]] 147 | -- Checks: 148 | if( !self:GetVars() ) then 149 | return "This entity does not have any variables."; 150 | end 151 | if( !self:GetConfigured() ) then 152 | if( !CAMI.PlayerHasAccess( client, "Scavenging: Setup", nil ) ) then 153 | return "You don't have permission to perform setup."; 154 | end 155 | -- Getting Names: 156 | local tabl = {}; 157 | for name, _ in pairs( ix.Scavenging.InformationTables ) do 158 | tabl[name] = true; 159 | end 160 | -- Sending to Client: 161 | net.Start( "ixScavengingSetup" ); 162 | net.WriteEntity( self ); 163 | net.WriteTable( tabl ); 164 | net.Send( client ); 165 | return false; 166 | end 167 | return true; 168 | end 169 | 170 | -- CanUse/CanScavenge: 171 | function ENT:CanUse( client, character ) 172 | return true; 173 | end 174 | 175 | function ENT:CanScavenge( client, character ) 176 | if( !PLUGIN:GetScavengingEnabled() ) then 177 | return "Scavenging is currently disabled."; 178 | end 179 | if( table.Count( player.GetAll() ) < PLUGIN:GetScavengingPlayerMinimum() ) then 180 | return "There is not enough players on."; 181 | end 182 | if( self:GetRemainingCooldown() != 0 ) then 183 | return "Try again in " .. tostring( self:GetRemainingCooldown() ) .. " seconds."; 184 | end 185 | if( !character:GetInventory():HasItem( "scavengingkit" ) ) then 186 | return "You don't have a scavenging kit."; 187 | end 188 | return true; 189 | end 190 | 191 | -- Main: 192 | function ENT:Use( client ) 193 | -- Checks: 194 | local character = client:GetCharacter(); 195 | if( !character ) then return end; 196 | local stabl = ix.Scavenging.InformationTables; 197 | if( !stabl ) then 198 | client:Notify( "Unable to find main Information Table." ); 199 | end 200 | -- Setup: 201 | local ret = self:Setup( client ); 202 | if( !ret ) then 203 | return; 204 | elseif( ix.util.GetTypeFromValue( ret ) == ix.type.string ) then 205 | client:Notify( ret ); 206 | return; 207 | end 208 | -- Checks 2: 209 | local tabl = stabl[self:GetTableName()]; 210 | if( !tabl ) then 211 | client:Notify( "Unable to find specific Information Table: '" .. self:GetTableName() .. "'." ); 212 | end 213 | -- CanUse: 214 | if( !tabl["CanUse"] or tabl["CanUse"]( client, character, self ) == nil ) then 215 | local ret = self:CanUse( client, character ); 216 | if( !ret ) then return; 217 | elseif( ix.util.GetTypeFromValue( ret ) == ix.type.string ) then 218 | client:Notify( ret ); 219 | return; 220 | end 221 | else 222 | local ret = tabl["CanUse"]( client, character, self ); 223 | if( !ret ) then return; 224 | elseif( ix.util.GetTypeFromValue( ret ) == ix.type.string ) then 225 | client:Notify( ret ); 226 | return; 227 | end 228 | end 229 | -- CanScavenge: 230 | local ShouldScavenge = true; 231 | if( !tabl["CanScavenge"] or tabl["CanScavenge"]( client, character, self ) == nil ) then 232 | ShouldScavenge = self:CanScavenge( client, character ); 233 | else 234 | ShouldScavenge = tabl["CanScavenge"]( client, character, self ); 235 | end 236 | -- Allowing/Disallowing Viewing: 237 | if( ( !ShouldScavenge or ShouldScavenge != true ) ) then 238 | if( table.Count( self:GetInventory():GetItems() ) == 0 and self:GetMoney() == 0 ) then 239 | if( ix.util.GetTypeFromValue( ShouldScavenge ) == ix.type.string ) then 240 | client:Notify( ShouldScavenge ); 241 | end 242 | return; 243 | end 244 | ShouldScavenge = false; 245 | end 246 | -- Vars: 247 | local UsageMessage = tabl["Usage Message"]( client, character, self, ShouldScavenge ); 248 | local SItems = tabl["Amount of Spawned Items"]( client, character, self ); 249 | local SCredits = tabl["Amount of Spawned Credits"]( character, character, self ); 250 | local PItems = tabl["Possible Items"]( character, character, self ); 251 | -- Main: 252 | client:SetAction( UsageMessage, PLUGIN:GetScavengingDelay() ); 253 | client:DoStaredAction( self, function() 254 | if( ShouldScavenge ) then 255 | if( tabl["PerformScavenge"] ) then 256 | tabl["PerformScavenge"]( client, character, self, ShouldScavenge ); 257 | else 258 | local ItemsToSpawn = {}; 259 | local PossibleItems = {}; 260 | -- Compiling: 261 | for _, info in pairs( PItems ) do 262 | local ItemID = info["ItemID"]; 263 | local Data = info["Data"] or {}; 264 | local Chance = info["Chance"] or 1; 265 | for i = 1, Chance do 266 | local Next = table.Count( PossibleItems ) + 1; 267 | PossibleItems[Next] = { 268 | ["ItemID"] = ItemID, 269 | ["Data"] = Data, 270 | }; 271 | end 272 | end 273 | -- Randomly Selecting: 274 | for i = 1, SItems do 275 | local Next = table.Count( ItemsToSpawn ) + 1; 276 | local Selected = table.Random( PossibleItems ); 277 | ItemsToSpawn[Next] = Selected; 278 | end 279 | -- Spawning: 280 | for _, info in pairs( ItemsToSpawn ) do 281 | if( !self:GetInventory():Add( info["ItemID"], 1, info["Data"] ) ) then 282 | local item = ix.item.Spawn( info["ItemID"], self:GetPos(), nil, nil, info["Data"] ); 283 | end 284 | end 285 | if( SCredits and ix.util.GetTypeFromValue( SCredits ) == ix.type.number and math.max( 0, self:GetMoney() + SCredits ) != 0 ) then 286 | self:SetMoney( self:GetMoney() + SCredits ); 287 | end 288 | self:SetRemainingCooldown( PLUGIN:GetScavengingCooldown() ); 289 | end 290 | -- Logging: 291 | ix.log.Add( client, "scavengingScavenging", self:GetInventoryID(), self:GetDisplayName() ); 292 | end 293 | self:OpenInventory( client ); 294 | end, PLUGIN:GetScavengingDelay(), function() 295 | client:SetAction(); 296 | end, 96 ); 297 | end 298 | 299 | function ENT:Think() 300 | self:SetRemainingCooldown( math.max( 0, self:GetRemainingCooldown() - 1 ) ); 301 | self:NextThink( CurTime() + 1 ); 302 | return true; 303 | end -------------------------------------------------------------------------------- /scavenging/entities/entities/ix_scavengingpile/shared.lua: -------------------------------------------------------------------------------- 1 | ENT.Type = "anim"; 2 | ENT.PrintName = "Scavenging Object"; 3 | ENT.Category = "HL2 RP"; 4 | ENT.Spawnable = true; 5 | ENT.AdminOnly = true; 6 | ENT.PhysgunDisable = false; 7 | ENT.bNoPersist = true; 8 | 9 | function ENT:SetupDataTables() 10 | self:NetworkVar( "String", 0, "DisplayName" ); 11 | self:NetworkVar( "String", 1, "DisplayDescription" ); 12 | end -------------------------------------------------------------------------------- /scavenging/items/sh_scavengingkit.lua: -------------------------------------------------------------------------------- 1 | local PLUGIN = PLUGIN; 2 | 3 | ITEM.name = "Scavenging Kit"; 4 | ITEM.model = Model( "models/props_junk/cardboard_box004a.mdl" ); 5 | ITEM.width = 2; 6 | ITEM.height = 2; 7 | ITEM.description = "A kit containing multiple tools and alike to aid in scavenging."; 8 | 9 | function ITEM:GetName() 10 | return self.name; 11 | end 12 | 13 | function ITEM:GetDescription() 14 | return self.description; 15 | end -------------------------------------------------------------------------------- /scavenging/sh_plugin.lua: -------------------------------------------------------------------------------- 1 | PLUGIN.name = "Scavenging"; 2 | PLUGIN.author = "Rune Knight"; 3 | PLUGIN.description = "Adds an usable and configurable entity which players can use for purposes such as gathering items and credits."; 4 | PLUGIN.license = [[Copyright 2021 Rune Knight 5 | 6 | This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.]]; 7 | 8 | --[[ 9 | STEAM: https://steamcommunity.com/profiles/76561198028996329/ 10 | DISCORD: Rune Knight#5972 11 | ]] 12 | 13 | -- Configuration: 14 | -- If false, this means that no more item spawning. This does not mean prevention of looking into the entity's inventory. 15 | ix.config.Add( "scavengingEnabled", true, "Should players be allowed to scavenge at all?", nil, { 16 | category = "Scavenging" 17 | }); 18 | 19 | -- This is compares table.Count( player.GetAll() ) to this number. If it's under that number, then scavenging is disabled as if like above. 20 | ix.config.Add( "scavengingPlayerMinimum", 5, "If there is not this many players (has to be equal or greater), then scavenging will be prevented.", nil, { 21 | data = { min = 1, max = 60 }, 22 | category = "Scavenging" 23 | }); 24 | 25 | -- When you scavenge, this is how long (in seconds) you'll have to wait to complete scavenging. 26 | ix.config.Add( "scavengingDelay", 5, "If a character begins to scavenge, how long will they have to wait until they finish?", nil, { 27 | data = { min = 1, max = 60 }, 28 | category = "Scavenging" 29 | }); 30 | 31 | -- After finishing scavenging, you can do it again after this amount of seconds. 32 | ix.config.Add( "scavengingCooldown", 1800, "Once something is scavenged, how long until it can be scavenged again?", nil, { 33 | data = { min = 30, max = 7200 }, 34 | category = "Scavenging"; 35 | }); 36 | 37 | function PLUGIN:GetScavengingEnabled() 38 | return ix.config.Get( "scavengingEnabled", true ); 39 | end 40 | 41 | function PLUGIN:GetScavengingPlayerMinimum() 42 | return ix.config.Get( "scavengingPlayerMinimum", 5 ); 43 | end 44 | 45 | function PLUGIN:GetScavengingDelay() 46 | return ix.config.Get( "scavengingDelay", 5 ); 47 | end 48 | 49 | function PLUGIN:GetScavengingCooldown() 50 | return ix.config.Get( "scavengingCooldown", 1800 ); 51 | end 52 | 53 | -- Privileges: 54 | CAMI.RegisterPrivilege({ 55 | Name = "Scavenging: Setup", 56 | MinAccess = "superadmin" 57 | }); 58 | 59 | CAMI.RegisterPrivilege({ 60 | Name = "Scavenging: Change Display Name", 61 | MinAccess = "superadmin" 62 | }); 63 | 64 | CAMI.RegisterPrivilege({ 65 | Name = "Scavenging: Change Display Description", 66 | MinAccess = "superadmin" 67 | }); 68 | 69 | CAMI.RegisterPrivilege({ 70 | Name = "Scavenging: Change Model", 71 | MinAccess = "superadmin" 72 | }); 73 | 74 | -- Files: 75 | ix.util.Include( "cl_plugin.lua" ); 76 | ix.util.Include( "sv_configuration.lua" ); 77 | ix.util.Include( "sv_plugin.lua" ); 78 | 79 | -- Context Menu: 80 | properties.Add( "scavenging_changedisplayname", { 81 | MenuLabel = "Change Display Name", 82 | Order = 401, 83 | MenuIcon = "icon16/pencil.png", 84 | Filter = function( self, entity, client ) 85 | if( entity:GetClass() != "ix_scavengingpile" ) then return end; 86 | if( !gamemode.Call( "CanProperty", client, "scavenging_changedisplayname", entity ) ) then return end; 87 | if( !CAMI.PlayerHasAccess( client, "Scavenging: Change Display Name", nil ) ) then return end; 88 | return true; 89 | end, 90 | Action = function( self, entity ) 91 | Derma_StringRequest( "Change Display Name", "", "", function( text ) 92 | self:MsgStart(); 93 | net.WriteEntity( entity ); 94 | net.WriteString( text ); 95 | self:MsgEnd(); 96 | end ) 97 | end, 98 | Receive = function( self, length, client ) 99 | local entity = net.ReadEntity(); 100 | local string = net.ReadString(); 101 | if( !IsValid( entity ) ) then return end; 102 | if( !self:Filter( entity, client ) ) then return end; 103 | if( !entity.Vars.Configured ) then return end; 104 | -- Logging: 105 | ix.log.Add( client, "scavengingChangeVariable", "display name", entity:GetInventoryID(), entity:GetDisplayName(), string ); 106 | -- Main: 107 | entity:SetDisplayName( string ); 108 | end 109 | }); 110 | 111 | properties.Add( "scavenging_changedisplaydescription", { 112 | MenuLabel = "Change Display Description", 113 | Order = 401, 114 | MenuIcon = "icon16/pencil.png", 115 | Filter = function( self, entity, client ) 116 | if( entity:GetClass() != "ix_scavengingpile" ) then return end; 117 | if( !gamemode.Call( "CanProperty", client, "scavenging_changedisplaydescription", entity ) ) then return end; 118 | if( !CAMI.PlayerHasAccess( client, "Scavenging: Change Display Description", nil ) ) then return end; 119 | return true; 120 | end, 121 | Action = function( self, entity ) 122 | Derma_StringRequest( "Change Display Description", "", "", function( text ) 123 | self:MsgStart(); 124 | net.WriteEntity( entity ); 125 | net.WriteString( text ); 126 | self:MsgEnd(); 127 | end ) 128 | end, 129 | Receive = function( self, length, client ) 130 | local entity = net.ReadEntity(); 131 | local string = net.ReadString(); 132 | if( !IsValid( entity ) ) then return end; 133 | if( !self:Filter( entity, client ) ) then return end; 134 | if( !entity.Vars.Configured ) then return end; 135 | -- Logging: 136 | ix.log.Add( client, "scavengingChangeVariable", "display description", entity:GetInventoryID(), entity:GetDisplayName(), string ); 137 | -- Main: 138 | entity:SetDisplayDescription( string ); 139 | end 140 | }); 141 | 142 | properties.Add( "scavenging_changemodel", { 143 | MenuLabel = "Change Model", 144 | Order = 401, 145 | MenuIcon = "icon16/pencil.png", 146 | Filter = function( self, entity, client ) 147 | if( entity:GetClass() != "ix_scavengingpile" ) then return end; 148 | if( !gamemode.Call( "CanProperty", client, "scavenging_changemodel", entity ) ) then return end; 149 | if( !CAMI.PlayerHasAccess( client, "Scavenging: Change Model", nil ) ) then return end; 150 | return true; 151 | end, 152 | Action = function( self, entity ) 153 | Derma_StringRequest( "Change Model", "", "", function( text ) 154 | self:MsgStart(); 155 | net.WriteEntity( entity ); 156 | net.WriteString( text ); 157 | self:MsgEnd(); 158 | end ) 159 | end, 160 | Receive = function( self, length, client ) 161 | local entity = net.ReadEntity(); 162 | local string = net.ReadString(); 163 | if( !IsValid( entity ) ) then return end; 164 | if( !self:Filter( entity, client ) ) then return end; 165 | if( !util.IsValidModel( string ) ) then return end; 166 | if( !entity.Vars.Configured ) then return end; 167 | -- Logging: 168 | ix.log.Add( client, "scavengingChangeVariable", "model", entity:GetInventoryID(), entity:GetDisplayName(), string ); 169 | -- Main: 170 | entity:SetModel( string ); 171 | entity:SetSolid( SOLID_VPHYSICS ); 172 | entity:PhysicsInit( SOLID_VPHYSICS ); 173 | -- Physics: 174 | local physics = entity:GetPhysicsObject(); 175 | physics:EnableMotion( false ); 176 | physics:Sleep(); 177 | end 178 | }); -------------------------------------------------------------------------------- /scavenging/sv_configuration.lua: -------------------------------------------------------------------------------- 1 | local PLUGIN = PLUGIN; 2 | -- I think this is okay. 3 | ix = ix or {}; 4 | ix.Scavenging = ix.Scavenging or {}; 5 | ix.Scavenging.InformationTables = ix.Scavenging.InformationTables or {}; 6 | 7 | --[[ 8 | Most functions are generally done in top-down order: 9 | CanUse -> CanScavenge -> PerformScavenge 10 | 11 | Templates have been added to give a summary of what functions do. 12 | ]] 13 | 14 | --[[ 15 | If you don't know how Chance works, it adds up all the Chance as a total number. 16 | That total number is used to divide a specific item's Chance to determine it's odds. 17 | 18 | For example, Item 1 with Chance 4 and Item 2 with Chance 1 would equal to a total of Chance 5. 19 | Item 1 would have a 80% chance or "4/5" chance. 20 | Item 2 would have a 20% chance or "1/5" chance. 21 | ]] 22 | 23 | ix.Scavenging.InformationTables["Blank Template"] = { -- Example #1: Blank Template. 24 | ["Display Name"] = "Blank Template", 25 | ["Display Description"] = "A template with the barest bones of functions and returns.", 26 | ["StartingModel"] = "models/hunter/blocks/cube025x025x025.mdl", 27 | ["Inventory Width"] = 2, 28 | ["Inventory Height"] = 2, 29 | ["CanUse"] = function( client, character, entity ) 30 | --[[ 31 | nil return entity:CanUse(); 32 | false return; 33 | string return & client:Notify(); 34 | true return true; 35 | ]] 36 | return nil; 37 | end, 38 | ["CanScavenge"] = function( client, character, entity ) 39 | --[[ 40 | nil ShouldScavenge = entity:CanScavenge(); 41 | false ShouldScavenge = false; 42 | string ShouldScavenge = false & client:Notify(); 43 | true ShouldScavenge = true; 44 | ]] 45 | return nil; 46 | end, 47 | ["PerformScavenge"] = function( client, character, entity, ShouldScavenge ) 48 | --[[ 49 | This is only called when ShouldScavenge = true. 50 | This is called before ix.storage.Open(). 51 | 52 | WARNING: This will replace the spawning of items if included in the table. 53 | ]] 54 | return; 55 | end, 56 | ["Usage Message"] = function( client, character, entity, ShouldScavenge ) 57 | --[[ 58 | string Name for ix.storage.Open(). 59 | ]] 60 | if( ShouldScavenge ) then 61 | return "PerformScavenge & Opening Inventory..."; 62 | end 63 | return "Opening Inventory..."; 64 | end, 65 | ["Amount of Spawned Items"] = function( client, character, entity ) 66 | --[[ 67 | number Spawns this many items. 68 | ]] 69 | return 1; 70 | end, 71 | ["Amount of Spawned Credits"] = function( client, character, entity ) 72 | --[[ 73 | number Adds this amount of credits. 74 | ]] 75 | return 0; 76 | end, 77 | ["Possible Items"] = function( client, character, entity ) 78 | --[[ 79 | table Information about Possible Items. 80 | ]] 81 | local Items = { 82 | [1] = { 83 | ["ItemID"] = "water", 84 | ["Data"] = {}, 85 | ["Chance"] = 3 86 | }, 87 | [2] = { 88 | ["ItemID"] = "request_device", 89 | ["Data"] = {}, 90 | ["Chance"] = 1 91 | } 92 | }; 93 | return Items; 94 | end 95 | }; 96 | 97 | ix.Scavenging.InformationTables["Default Template"] = { -- Example #2: Default Template. 98 | ["Display Name"] = "Template With Default/Expected Results", 99 | ["Display Description"] = "A template that returns results that would typically occur by default.", 100 | ["StartingModel"] = "models/hunter/blocks/cube025x025x025.mdl", 101 | ["Inventory Width"] = 2, 102 | ["Inventory Height"] = 2, 103 | ["CanUse"] = function( client, character, entity ) 104 | return true; 105 | end, 106 | ["CanScavenge"] = function( client, character, entity ) 107 | if( !PLUGIN:GetScavengingEnabled() ) then 108 | return "Scavenging is currently disabled."; 109 | end 110 | if( table.Count( player.GetAll() ) < PLUGIN:GetScavengingPlayerMinimum() ) then 111 | return "There is not enough players on."; 112 | end 113 | if( entity:GetRemainingCooldown() != 0 ) then 114 | return "Try again in " .. tostring( entity:GetRemainingCooldown() ) .. " seconds."; 115 | end 116 | if( !character:GetInventory():HasItem( "scavengingkit" ) ) then 117 | return "You don't have a scavenging kit."; 118 | end 119 | return true; 120 | end, 121 | ["PerformScavenge"] = function( client, character, entity, ShouldScavenge ) 122 | -- Variables: 123 | local tabl = ix.Scavenging.InformationTables[entity:GetTableName()]; 124 | local SItems = tabl["Amount of Spawned Items"]( client, character, entity ); 125 | local SCredits = tabl["Amount of Spawned Credits"]( character, character, entity ); 126 | local PItems = tabl["Possible Items"]( character, character, entity ); 127 | local ItemsToSpawn = {}; 128 | local PossibleItems = {}; 129 | -- Compiling: 130 | for _, info in pairs( PItems ) do 131 | local ItemID = info["ItemID"]; 132 | local Data = info["Data"] or {}; 133 | local Chance = info["Chance"] or 1; 134 | for i = 1, Chance do 135 | local Next = table.Count( PossibleItems ) + 1; 136 | PossibleItems[Next] = { 137 | ["ItemID"] = ItemID, 138 | ["Data"] = Data, 139 | }; 140 | end 141 | end 142 | -- Randomly Selecting: 143 | for i = 1, SItems do 144 | local Next = table.Count( ItemsToSpawn ) + 1; 145 | local Selected = table.Random( PossibleItems ); 146 | ItemsToSpawn[Next] = Selected; 147 | end 148 | -- Spawning: 149 | for _, info in pairs( ItemsToSpawn ) do 150 | if( !entity:GetInventory():Add( info["ItemID"], 1, info["Data"] ) ) then 151 | local item = ix.item.Spawn( info["ItemID"], entity:GetPos(), nil, nil, info["Data"] ); 152 | end 153 | end 154 | if( SCredits and ix.util.GetTypeFromValue( SCredits ) == ix.type.number and math.max( 0, entity:GetMoney() + SCredits ) != 0 ) then 155 | entity:SetMoney( entity:GetMoney() + SCredits ); 156 | end 157 | entity:SetRemainingCooldown( PLUGIN:GetScavengingCooldown() ); 158 | return; 159 | end, 160 | ["Usage Message"] = function( client, character, entity, ShouldScavenge ) 161 | if( ShouldScavenge ) then 162 | return "Scavenging..."; 163 | end 164 | return "Checking..."; 165 | end, 166 | ["Amount of Spawned Items"] = function( client, character, entity ) 167 | return 1; 168 | end, 169 | ["Amount of Spawned Credits"] = function( client, character, entity ) 170 | return 0; 171 | end, 172 | ["Possible Items"] = function( client, character, entity ) 173 | local Items = { 174 | [1] = { 175 | ["ItemID"] = "water", 176 | ["Data"] = {}, 177 | ["Chance"] = 1 178 | }, 179 | [2] = { 180 | ["ItemID"] = "request_device", 181 | ["Data"] = {}, 182 | ["Chance"] = 1 183 | } 184 | }; 185 | return Items; 186 | end 187 | }; 188 | 189 | ix.Scavenging.InformationTables["Blank Template"] = nil; 190 | ix.Scavenging.InformationTables["Default Template"] = nil; 191 | 192 | --[[ 193 | Examples have been added to give a general understanding of what can be done. 194 | Though, they may be a little lackluster due to the low variety of items in the default helix/hl2rp schema. 195 | ]] 196 | 197 | ix.Scavenging.InformationTables["Trash Pile"] = { 198 | ["Display Name"] = "Trash Pile", 199 | ["Display Description"] = "A pile of rubbish and garbage.", 200 | ["StartingModel"] = "models/props_junk/garbage128_composite001a.mdl", 201 | ["Inventory Width"] = 4, 202 | ["Inventory Height"] = 2, 203 | ["Usage Message"] = function( client, character, entity, ShouldScavenge ) 204 | if( ShouldScavenge ) then 205 | return "Scavenging..."; 206 | end 207 | return "Checking..."; 208 | end, 209 | ["Amount of Spawned Items"] = function( client, character, entity ) 210 | return 2; 211 | end, 212 | ["Amount of Spawned Credits"] = function( client, character, entity ) 213 | return 0; 214 | end, 215 | ["Possible Items"] = function( client, character, entity ) 216 | local Items = { 217 | [1] = { 218 | ["ItemID"] = "water", 219 | ["Data"] = {}, 220 | ["Chance"] = 2 221 | }, 222 | [2] = { 223 | ["ItemID"] = "request_device", 224 | ["Data"] = {}, 225 | ["Chance"] = 2 226 | } 227 | }; 228 | return Items; 229 | end 230 | }; 231 | 232 | ix.Scavenging.InformationTables["Broken Vending Machine"] = { 233 | ["Display Name"] = "Broken Vending Machine", 234 | ["Display Description"] = "A machine that once distributed cans of water. It doesn't seem to vend anymore.", 235 | ["StartingModel"] = "models/props_interiors/vendingmachinesoda01a.mdl", 236 | ["Inventory Width"] = 4, 237 | ["Inventory Height"] = 2, 238 | ["Usage Message"] = function( client, character, entity, ShouldScavenge ) 239 | if( ShouldScavenge ) then 240 | return "Scavenging..."; 241 | end 242 | return "Checking..."; 243 | end, 244 | ["Amount of Spawned Items"] = function( client, character, entity ) 245 | return 1; 246 | end, 247 | ["Amount of Spawned Credits"] = function( client, character, entity ) 248 | return math.random( 5, 8 ); 249 | end, 250 | ["Possible Items"] = function( client, character, entity ) 251 | local Items = { 252 | [1] = { 253 | ["ItemID"] = "water", 254 | ["Data"] = {}, 255 | ["Chance"] = 16 256 | }, 257 | [2] = { 258 | ["ItemID"] = "water_sparkling", 259 | ["Data"] = {}, 260 | ["Chance"] = 3 261 | }, 262 | [3] = { 263 | ["ItemID"] = "water_special", 264 | ["Data"] = {}, 265 | ["Chance"] = 1 266 | } 267 | }; 268 | return Items; 269 | end 270 | }; 271 | 272 | ix.Scavenging.InformationTables["Abandoned Crate"] = { 273 | ["Display Name"] = "Abandoned Crate", 274 | ["Display Description"] = "A mysterious crate. It's content is entirely unknown until seen with one's eyes.", 275 | ["StartingModel"] = "models/props_junk/wood_crate001a.mdl", 276 | ["Inventory Width"] = 4, 277 | ["Inventory Height"] = 2, 278 | ["Usage Message"] = function( client, character, entity, ShouldScavenge ) 279 | if( ShouldScavenge ) then 280 | return "Scavenging..."; 281 | end 282 | return "Checking..."; 283 | end, 284 | ["Amount of Spawned Items"] = function( client, character, entity ) 285 | return 1; 286 | end, 287 | ["Amount of Spawned Credits"] = function( client, character, entity ) 288 | return 0; 289 | end, 290 | ["Possible Items"] = function( client, character, entity ) 291 | local Items = { 292 | [1] = { 293 | ["ItemID"] = "bandage", 294 | ["Data"] = {}, 295 | ["Chance"] = 1 296 | }, 297 | [2] = { 298 | ["ItemID"] = "chinese_takeout", 299 | ["Data"] = {}, 300 | ["Chance"] = 1 301 | }, 302 | [3] = { 303 | ["ItemID"] = "combinelock", 304 | ["Data"] = {}, 305 | ["Chance"] = 1 306 | }, 307 | [4] = { 308 | ["ItemID"] = "handheld_radio", 309 | ["Data"] = { 310 | ["enabled"] = false 311 | }, 312 | ["Chance"] = 1 313 | }, 314 | [5] = { 315 | ["ItemID"] = "health_kit", 316 | ["Data"] = {}, 317 | ["Chance"] = 1 318 | }, 319 | [6] = { 320 | ["ItemID"] = "health_vial", 321 | ["Data"] = {}, 322 | ["Chance"] = 1 323 | }, 324 | [7] = { 325 | ["ItemID"] = "melon", 326 | ["Data"] = {}, 327 | ["Chance"] = 1 328 | }, 329 | [8] = { 330 | ["ItemID"] = "metropolice_supplements", 331 | ["Data"] = {}, 332 | ["Chance"] = 1 333 | }, 334 | [9] = { 335 | ["ItemID"] = "milk_carton", 336 | ["Data"] = {}, 337 | ["Chance"] = 1 338 | }, 339 | [10] = { 340 | ["ItemID"] = "ration", 341 | ["Data"] = {}, 342 | ["Chance"] = 1 343 | }, 344 | [11] = { 345 | ["ItemID"] = "request_device", 346 | ["Data"] = {}, 347 | ["Chance"] = 1 348 | }, 349 | [12] = { 350 | ["ItemID"] = "supplements", 351 | ["Data"] = {}, 352 | ["Chance"] = 1 353 | }, 354 | [13] = { 355 | ["ItemID"] = "water", 356 | ["Data"] = {}, 357 | ["Chance"] = 1 358 | }, 359 | [14] = { 360 | ["ItemID"] = "water_sparkling", 361 | ["Data"] = {}, 362 | ["Chance"] = 1 363 | }, 364 | [15] = { 365 | ["ItemID"] = "water_special", 366 | ["Data"] = {}, 367 | ["Chance"] = 1 368 | }, 369 | [16] = { 370 | ["ItemID"] = "zip_tie", 371 | ["Data"] = {}, 372 | ["Chance"] = 1 373 | }, 374 | }; 375 | return Items; 376 | end 377 | }; -------------------------------------------------------------------------------- /scavenging/sv_plugin.lua: -------------------------------------------------------------------------------- 1 | local PLUGIN = PLUGIN; 2 | ix = ix or {}; 3 | ix.Scavenging = ix.Scavenging or {}; 4 | ix.Scavenging.InformationTables = ix.Scavenging.InformationTables or {}; 5 | 6 | -- Network: 7 | util.AddNetworkString( "ixScavengingSetup" ); 8 | util.AddNetworkString( "ixScavengingSetupFinalize" ); 9 | 10 | net.Receive( "ixScavengingSetupFinalize", function( len, client ) 11 | -- Variables: 12 | local entity = net.ReadEntity(); 13 | local name = net.ReadString(); 14 | -- Checks: 15 | if( !IsValid( entity ) ) then return end; 16 | if( entity:GetClass() != "ix_scavengingpile" ) then return end; 17 | if( !ix.Scavenging.InformationTables[name] ) then return end; 18 | if( !entity:GetVars() ) then return end; 19 | if( !CAMI.PlayerHasAccess( client, "Scavenging: Setup", nil ) ) then return end; 20 | if( entity:GetConfigured() ) then return end; 21 | 22 | -- Variables: 23 | local model = ix.Scavenging.InformationTables[name]["StartingModel"]; 24 | -- Main: 25 | entity:SetModel( model ); 26 | entity:SetSolid( SOLID_VPHYSICS ); 27 | entity:PhysicsInit( SOLID_VPHYSICS ); 28 | -- Physics: 29 | local physics = entity:GetPhysicsObject(); 30 | physics:EnableMotion( false ); 31 | physics:Sleep(); 32 | -- Main: 33 | entity:SetConfigured( true ); 34 | entity:SetTableName( name ); 35 | local tabl = entity:CreateInventory( name ); 36 | entity:SetDisplayName( ix.Scavenging.InformationTables[name]["Display Name"] ); 37 | entity:SetDisplayDescription( ix.Scavenging.InformationTables[name]["Display Description"] ); 38 | -- Logging: 39 | ix.log.Add( client, "scavengingSetup", entity:GetInventoryID(), entity:GetDisplayName() ); 40 | -- Saving: 41 | PLUGIN:SaveData(); 42 | end) 43 | 44 | -- Data: 45 | function PLUGIN:SaveData() 46 | local data = {}; 47 | for _, v in pairs( ents.FindByClass( "ix_scavengingpile" ) ) do 48 | data[#data + 1] = { 49 | Model = v:GetModel(), 50 | Position = v:GetPos(), 51 | Angles = v:GetAngles(), 52 | DisplayName = v:GetDisplayName(), 53 | DisplayDescription = v:GetDisplayDescription(), 54 | Vars = v.Vars 55 | }; 56 | end 57 | self:SetData( data ); 58 | end 59 | 60 | function PLUGIN:LoadData() 61 | local data = self:GetData(); 62 | for _, v in pairs( data ) do 63 | if( !v.Vars.Configured ) then continue end; 64 | local ent = ents.Create( "ix_scavengingpile" ); 65 | ent:SetPos( v["Position"] ); 66 | ent:SetAngles( v["Angles"] ); 67 | ent:Spawn(); -- Runs the entity's Initialize(). 68 | ent:SetModel( v["Model"] ); 69 | ent:PhysicsInit( SOLID_VPHYSICS ); 70 | ent:SetSolid( SOLID_VPHYSICS ); 71 | -- Physics: 72 | local physics = ent:GetPhysicsObject(); 73 | physics:EnableMotion( false ); 74 | physics:Sleep(); 75 | -- Variables: 76 | ent:SetDisplayName( v["DisplayName"] ); 77 | ent:SetDisplayDescription( v["DisplayDescription"] ); 78 | ent.Vars = v.Vars; 79 | -- Inventories: 80 | ix.inventory.Restore( ent:GetInventoryID(), ix.Scavenging.InformationTables[ent:GetTableName()]["Inventory Width"], ix.Scavenging.InformationTables[ent:GetTableName()]["Inventory Height"], 81 | function( inventory ) 82 | inventory.vars.isBag = true; 83 | inventory.vars.isContainer = true; 84 | end) 85 | end 86 | PLUGIN:SaveData(); 87 | end 88 | 89 | -- Logging: 90 | ix.log.AddType( "scavengingOpen", function( client, ... ) 91 | local arg = { ... }; 92 | return string.format( "%s opened scavenging container #%d, '%s'.", client:Name(), arg[1], arg[2] ); 93 | end) 94 | 95 | ix.log.AddType( "scavengingClose", function( client, ... ) 96 | local arg = { ... }; 97 | return string.format( "%s closed scavenging container #%d, '%s'.", client:Name(), arg[1], arg[2] ); 98 | end) 99 | 100 | ix.log.AddType( "scavengingSetup", function( client, ... ) 101 | local arg = { ... }; 102 | return string.format( "%s completed setup for scavenging container #%d, now '%s'.", client:Name(), arg[1], arg[2] ); 103 | end) 104 | 105 | ix.log.AddType( "scavengingScavenging", function( client, ... ) 106 | local arg = { ... }; 107 | return string.format( "%s completed scavenging for scavenging container #%d, '%s'.", client:Name(), arg[1], arg[2] ); 108 | end) 109 | 110 | ix.log.AddType( "scavengingChangeVariable", function( client, ... ) 111 | local arg = { ... }; 112 | return string.format( "%s changed the %s of scavenging container #%d, '%s' to '%s'.", client:Name(), arg[1], arg[2], arg[3], arg[4] ); 113 | end) 114 | 115 | --[[ 116 | This is for compatibility with other plugins. 117 | ]] 118 | function PLUGIN:SetInventoryTable( name, content ) 119 | ix.Scavenging.InformationTables[name] = content; 120 | end 121 | ix.Scavenging.SetInventoryTable = PLUGIN.SetInventoryTable; 122 | 123 | 124 | PLUGIN.AddInformationTable = PLUGIN.SetInventoryTable; 125 | ix.Scavenging.AddInformationTable = PLUGIN.AddInformationTable; 126 | 127 | --[[ 128 | commit 9efc4b6 added an inventory library which seperates and renames some functions. 129 | This happened on 1/1/21. This is only for older helix bases. 130 | ]] 131 | ix.inventory = ix.inventory or {}; 132 | if( !ix.inventory.Register ) then 133 | ix.inventory.Register = ix.item.RegisterInv; 134 | end 135 | 136 | -- Registering Inventories: 137 | do 138 | for name, info in pairs( ix.Scavenging.InformationTables ) do 139 | ix.inventory.Register( "ix_scavengingpile_" .. name, info["Inventory Width"], info["Inventory Height"], true ); 140 | end 141 | end 142 | -------------------------------------------------------------------------------- /spawnmenu_itemtab.lua: -------------------------------------------------------------------------------- 1 | PLUGIN.name = "Spawn Menu: Items"; 2 | PLUGIN.author = "Rune Knight"; 3 | PLUGIN.description = "Adds a tab to the spawn menu which players can use to spawn items."; 4 | PLUGIN.license = [[Copyright 2021 Rune Knight 5 | 6 | This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.]]; 7 | 8 | --[[ 9 | STEAM: https://steamcommunity.com/profiles/76561198028996329/ 10 | DISCORD: Rune Knight#5972 11 | ]] 12 | 13 | 14 | CAMI.RegisterPrivilege({ 15 | Name = "Spawn Menu: Items - Spawning", 16 | MinAccess = "superadmin" 17 | }) 18 | 19 | function PLUGIN:GetExpectedIcon( s ) 20 | local i = { 21 | ["Ammunition"] = "icon16/tab.png", -- :shrug: 22 | ["Clothing"] = "icon16/user_suit.png", 23 | ["Consumables"] = "icon16/pill.png", 24 | ["Medical"] = "icon16/heart.png", 25 | ["misc"] = "icon16/error.png", 26 | ["Permits"] = "icon16/note.png", 27 | ["Storage"] = "icon16/package.png", 28 | ["Weapons"] = "icon16/gun.png", 29 | 30 | }; 31 | return hook.Run( "GetIconsForSpawnMenuItems", s ) or i[s] or "icon16/folder.png"; 32 | end 33 | 34 | if( SERVER ) then 35 | util.AddNetworkString( "spawnmenuspawnitem" ); 36 | 37 | ix.log.AddType( "spawnmenuspawnitem", function( client, name ) 38 | return string.format( "%s has spawned \"%s\".", client:GetCharacter():GetName(), tostring( name ) ) 39 | end ); 40 | 41 | net.Receive("spawnmenuspawnitem", function( len, client ) 42 | local u = net.ReadString(); 43 | if( !CAMI.PlayerHasAccess( client, "Spawn Menu: Items - Spawning", nil ) ) then return end; 44 | for _, t in pairs( ix.item.list ) do 45 | if( t.uniqueID == u ) then 46 | ix.item.Spawn( t.uniqueID, client:GetShootPos() + client:GetAimVector() * 84 + Vector( 0, 0, 16 ) ); 47 | ix.log.Add( client, "spawnmenuspawnitem", t.name ) 48 | break; 49 | end 50 | end 51 | end ); 52 | else 53 | 54 | function PLUGIN:InitializedPlugins() 55 | if( SERVER ) then return end; 56 | RunConsoleCommand( "spawnmenu_reload" ); -- If someone legit knows how to insert stuff into the spawn menu without breaking it or doing it before the spawn menu is created, please tell me. Otherwise, this is the best I got. 57 | end 58 | 59 | local PLUGIN = PLUGIN; 60 | 61 | spawnmenu.AddCreationTab( "Items", function() 62 | 63 | local p = vgui.Create( "SpawnmenuContentPanel" ); 64 | local t, n = p.ContentNavBar.Tree, p.OldSpawnlists; 65 | 66 | local l = {}; 67 | for uid, i in pairs( ix.item.list ) do 68 | local c = i.category; 69 | l[c] = l[c] or {}; 70 | table.insert( l[c], i ); 71 | end 72 | 73 | for c, i in SortedPairs( l ) do 74 | 75 | local icon16 = PLUGIN:GetExpectedIcon( c ); 76 | local node = t:AddNode( L(c), icon16 ) 77 | node.DoClick = function( self ) 78 | 79 | if( self.PropPanel and IsValid( self.PropPanel ) ) then 80 | self.PropPanel:Remove() 81 | self.PropPanel = nil; 82 | end; 83 | 84 | self.PropPanel = vgui.Create( "ContentContainer", p ); 85 | self.PropPanel:SetVisible( false ); 86 | self.PropPanel:SetTriggerSpawnlistChange( false ); 87 | 88 | for _, t in SortedPairsByMemberValue( i, "name" ) do 89 | 90 | spawnmenu.CreateContentIcon( "item", self.PropPanel, { 91 | nicename = ( t.GetName and t:GetName() ) or t.name, 92 | spawnname = t.uniqueID, 93 | } ) 94 | 95 | end 96 | 97 | p:SwitchPanel( self.PropPanel ); 98 | 99 | end 100 | 101 | end 102 | 103 | local FirstNode = t:Root():GetChildNode( 0 ); 104 | if ( IsValid( FirstNode ) ) then 105 | FirstNode:InternalDoClick(); 106 | end 107 | 108 | return p; 109 | 110 | end, "icon16/cog_add.png", 201 ); 111 | 112 | spawnmenu.AddContentType( "item", function( p, data ) 113 | 114 | local n = data.nicename; 115 | local u = data.spawnname; 116 | 117 | local icon = vgui.Create( "SpawnIcon", p ); 118 | icon:SetWide( 64 ); 119 | icon:SetTall( 64 ); 120 | icon:InvalidateLayout( true ); 121 | 122 | local t = ix.item.list; 123 | local i = t[u]; 124 | 125 | icon:SetModel( ( i.GetModel and i:GetModel() ) or i.model ); 126 | icon:SetTooltip( n ); 127 | 128 | icon.DoClick = function( s ) 129 | surface.PlaySound( "ui/buttonclickrelease.wav" ); 130 | if( !CAMI.PlayerHasAccess( LocalPlayer(), "Spawn Menu: Items - Spawning", nil ) ) then 131 | return; 132 | end 133 | 134 | net.Start( "spawnmenuspawnitem" ); 135 | net.WriteString( u ); 136 | net.SendToServer(); 137 | end 138 | 139 | icon:InvalidateLayout( true ); 140 | 141 | if ( IsValid( p ) ) then 142 | p:Add( icon ) 143 | end 144 | 145 | return icon; 146 | 147 | end ); 148 | 149 | end 150 | --------------------------------------------------------------------------------