diff --git a/backgrounds/1.jpg b/backgrounds/1.jpg new file mode 100644 index 00000000..18cc42b1 Binary files /dev/null and b/backgrounds/1.jpg differ diff --git a/content/materials/lambda/blocked.png b/content/materials/lambda/blocked.png new file mode 100644 index 00000000..a8a67a05 Binary files /dev/null and b/content/materials/lambda/blocked.png differ diff --git a/content/materials/lambda/death_point.png b/content/materials/lambda/death_point.png new file mode 100644 index 00000000..a79549b0 Binary files /dev/null and b/content/materials/lambda/death_point.png differ diff --git a/content/materials/lambda/ring1.png b/content/materials/lambda/ring1.png new file mode 100644 index 00000000..fbf8375d Binary files /dev/null and b/content/materials/lambda/ring1.png differ diff --git a/content/materials/lambda/ring2.png b/content/materials/lambda/ring2.png new file mode 100644 index 00000000..5bf31eea Binary files /dev/null and b/content/materials/lambda/ring2.png differ diff --git a/content/materials/lambda/ring3.png b/content/materials/lambda/ring3.png new file mode 100644 index 00000000..b3798a73 Binary files /dev/null and b/content/materials/lambda/ring3.png differ diff --git a/content/materials/lambda/run_point.png b/content/materials/lambda/run_point.png new file mode 100644 index 00000000..a944aeee Binary files /dev/null and b/content/materials/lambda/run_point.png differ diff --git a/content/materials/lambda/trigger.png b/content/materials/lambda/trigger.png new file mode 100644 index 00000000..8e017d74 Binary files /dev/null and b/content/materials/lambda/trigger.png differ diff --git a/content/materials/lambda/vehicle.png b/content/materials/lambda/vehicle.png new file mode 100644 index 00000000..5ec77580 Binary files /dev/null and b/content/materials/lambda/vehicle.png differ diff --git a/content/scripts/sentences-hl1.txt b/content/scripts/sentences-hl1.txt new file mode 100644 index 00000000..4ecda86d --- /dev/null +++ b/content/scripts/sentences-hl1.txt @@ -0,0 +1 @@ +// keep clean \ No newline at end of file diff --git a/content/sound/lambda/death.mp3 b/content/sound/lambda/death.mp3 new file mode 100644 index 00000000..8dda1440 Binary files /dev/null and b/content/sound/lambda/death.mp3 differ diff --git a/entities/effects/lambda_blood_explosion.lua b/entities/effects/lambda_blood_explosion.lua new file mode 100644 index 00000000..24fabda3 --- /dev/null +++ b/entities/effects/lambda_blood_explosion.lua @@ -0,0 +1,65 @@ +function EFFECT:Init( data ) + + local size = 64 + local ply = data:GetEntity() + + self:SetCollisionBounds( Vector( -size,-size,-size ), Vector( size,size,size ) ) + self:SetAngles( data:GetNormal():Angle() + Angle( 0.01, 0.01, 0.01 ) ) + + self.Pos = data:GetOrigin() + self.Normal = data:GetNormal() + self.Magnitude = data:GetMagnitude() + self.Alpha = 1 + self.Player = ply + --self.Force = data:GetVelocity() + self:SetPos( data:GetOrigin() ) + + local emitter = ParticleEmitter(ply:GetPos()) + self.Emitter = emitter + self:AddEffects(EF_NODRAW) + +end + +function EFFECT:Think( ) + + local emitter = self.Emitter + local ply = self.Player + + for i = 0, 3 do + local particle = emitter:Add("particle/smokesprites_000"..math.random(1,9), self.Pos) + particle:SetVelocity( self.Normal * self.Magnitude ) + particle:SetDieTime(0.2) + particle:SetStartAlpha( 255 ) + particle:SetEndAlpha( 0 ) + particle:SetStartSize( 10 ) + particle:SetEndSize( 50 ) + --particle:SetRoll( math.Rand(150, 360) ) + --particle:SetRollDelta( math.Rand(-1, 1) ) + particle:SetAirResistance( 0 ) + --particle:SetGravity( Vector( math.Rand( -200 , 200 ), math.Rand( -200 , 200 ), math.Rand( 10 , 100 ) ) ) + particle:SetColor( 64, 0, 0 ) + end + + local particle = emitter:Add("particle/smokesprites_000"..math.random(1,9), self.Pos) + particle:SetVelocity( self.Normal * self.Magnitude ) + particle:SetDieTime(1.2) + particle:SetStartAlpha( 255 ) + particle:SetEndAlpha( 0 ) + particle:SetStartSize( 10 ) + particle:SetEndSize( 150 ) + --particle:SetRoll( math.Rand(150, 360) ) + --particle:SetRollDelta( math.Rand(-1, 1) ) + particle:SetAirResistance( 0 ) + --particle:SetGravity( Vector( math.Rand( -200 , 200 ), math.Rand( -200 , 200 ), math.Rand( 10 , 100 ) ) ) + particle:SetColor( 64, 0, 0 ) + + self:Remove() + +end + +function EFFECT:OnRemove() + --self.Emitter:Finish() +end + +function EFFECT:Draw() +end diff --git a/entities/effects/lambda_death.lua b/entities/effects/lambda_death.lua new file mode 100644 index 00000000..b022266a --- /dev/null +++ b/entities/effects/lambda_death.lua @@ -0,0 +1,71 @@ +EFFECT.Mat1 = Material( "lambda/death_point.png" ) + +function EFFECT:Init( data ) + + local size = 64 + local ply = data:GetEntity() + + self:SetCollisionBounds( Vector( -size,-size,-size ), Vector( size,size,size ) ) + self:SetAngles( data:GetNormal():Angle() + Angle( 0.01, 0.01, 0.01 ) ) + + self.Pos = data:GetOrigin() + self.Normal = data:GetNormal() + self.Alpha = 1 + self.Player = ply + + self.Direction = data:GetScale() + self.Size = data:GetRadius() + self.Axis = data:GetOrigin() + self.Dist = 0 + + self:SetPos( data:GetOrigin() ) + self.PlayerName = ply:Nick() + +end + +function EFFECT:Think( ) + + local speed = FrameTime() + + if not IsValid(self.Player) then + return false + end + + if self.Player:Alive() then + return false + end + + self.Alpha = self.Alpha - speed * 0.08 + self.Dist = math.sin(CurTime() * 5) * 5 + + if (self.Alpha < 0 ) then return false end + + return true + +end + +function EFFECT:Render( ) + + if (self.Alpha < 0 ) then return end + + local Normal = self.Normal + local dir = Normal:Angle() + local ply = LocalPlayer() + local ang = ply:GetPos() - self:GetPos() + local dist = ply:GetPos():Distance(self:GetPos()) + + local signsize = math.Clamp(dist / 20, self.Size / 2, self.Size * 5) + local offset_z = math.Clamp(dist / 20, 50, 200) + + cam.IgnoreZ(true) + + render.SetMaterial( self.Mat1 ) + render.DrawQuadEasy( self:GetPos() + (dir:Forward() * (offset_z + self.Dist)) , + ang, + signsize, signsize, + Color( 255, 255, 255, (self.Alpha ^ 1.1) * 255 ), + 180) + + cam.IgnoreZ(false) + +end diff --git a/entities/effects/lambda_pointer.lua b/entities/effects/lambda_pointer.lua new file mode 100644 index 00000000..8bb95917 --- /dev/null +++ b/entities/effects/lambda_pointer.lua @@ -0,0 +1,86 @@ +EFFECT.Mat1 = Material( "lambda/ring1.png" ) +EFFECT.Mat2 = Material( "lambda/ring2.png" ) +EFFECT.Mat3 = Material( "lambda/ring3.png" ) +EFFECT.Mat4 = Material( "lambda/run_point.png" ) + +function EFFECT:Init( data ) + + local size = 64 + local ply = data:GetEntity() + + if ply.LastPointer and IsValid(ply.LastPointer) then + ply.LastPointer:Remove() + end + ply.LastPointer = self + + self:SetCollisionBounds( Vector( -size,-size,-size ), Vector( size,size,size ) ) + self:SetAngles( data:GetNormal():Angle() + Angle( 0.01, 0.01, 0.01 ) ) + + self.Pos = data:GetOrigin() + self.Normal = data:GetNormal() + self.Alpha = 1 + + self.Direction = data:GetScale() + self.Size = data:GetRadius() + self.Axis = data:GetOrigin() + self.Dist = 0 + + self:SetPos( data:GetOrigin() ) + +end + +function EFFECT:Think( ) + + local speed = FrameTime() + + self.Alpha = self.Alpha - speed * 0.16 + self.Dist = math.sin(CurTime() * 5) * 5 + + if (self.Alpha < 0 ) then return false end + + return true + +end + +function EFFECT:Render( ) + + if (self.Alpha < 0 ) then return end + + local Normal = self.Normal + local dir = Normal:Angle() + local ply = LocalPlayer() + local ang = ply:GetPos() - self:GetPos() + local dist = ply:GetPos():Distance(self:GetPos()) + + render.SetMaterial( self.Mat1 ) + render.DrawQuadEasy( self:GetPos() + Normal, + Normal:GetNormalized() * self.Direction, + self.Size, self.Size, + Color( 255, 255, 255, (self.Alpha ^ 1.1) * 255 ), + -(self.Alpha * 400) ) + + render.SetMaterial( self.Mat2 ) + render.DrawQuadEasy( self:GetPos() + Normal, + Normal:GetNormalized() * self.Direction, + self.Size, self.Size, + Color( 255, 255, 255, (self.Alpha ^ 1.1) * 255 ), + (self.Alpha * 500) ) + + render.SetMaterial( self.Mat3 ) + render.DrawQuadEasy( self:GetPos() + Normal, + Normal:GetNormalized() * self.Direction, + self.Size, self.Size, + Color( 255, 255, 255, (self.Alpha ^ 1.1) * 255 ), + -(self.Alpha * 800) ) + + local signsize = math.Clamp(dist / 20, self.Size / 2, self.Size * 5) + local offset_z = math.Clamp(dist / 20, 50, 200) + + render.SetMaterial( self.Mat4 ) + render.DrawQuadEasy( self:GetPos() + (dir:Forward() * (offset_z + self.Dist)) , + ang, + signsize, signsize, + Color( 255, 255, 255, (self.Alpha ^ 1.1) * 255 ), + 180) + +end diff --git a/entities/entities/env_hudhint_.lua b/entities/entities/env_hudhint_.lua new file mode 100644 index 00000000..9a7d067f --- /dev/null +++ b/entities/entities/env_hudhint_.lua @@ -0,0 +1,60 @@ +if SERVER then + + util.AddNetworkString("LambdaHintText") + + SF_HUDHINT_ALLPLAYERS = 1 + + ENT.Base = "lambda_entity" + ENT.Type = "point" + + DEFINE_BASECLASS( "lambda_entity" ) + + function ENT:PreInitialize() + + BaseClass.PreInitialize(self) + + self:SetInputFunction("ShowHudHint", self.InputShowHudHint) + self:SetInputFunction("HideHudHint", self.InputHideHudHint) + self.Message = "" + + end + + function ENT:Initialize() + + BaseClass.Initialize(self) + + self:AddSpawnFlags(SF_HUDHINT_ALLPLAYERS) + + end + + function ENT:KeyValue(key, val) + + BaseClass.KeyValue(self, key, val) + + if key == "message" then + self.Message = val + end + + end + + function ENT:InputShowHudHint(data, activator, caller) + + return self:Command(data, activator, caller) + + end + + function ENT:InputHideHudHint(data, activator, caller) + + return self:Command(data, activator, caller) + + end + + function ENT:Command(data, activator, caller) + -- Stub + end + +else -- CLIENT + + + +end diff --git a/entities/entities/env_message_.lua b/entities/entities/env_message_.lua new file mode 100644 index 00000000..1cd173d8 --- /dev/null +++ b/entities/entities/env_message_.lua @@ -0,0 +1,27 @@ +if SERVER then + +ENT.Base = "lambda_entity" +ENT.Type = "point" + +DEFINE_BASECLASS( "lambda_entity" ) + +function ENT:PreInitialize() + + BaseClass.PreInitialize(self) + --self:SetInputFunction("ShowMessage", self.InputCommand) + +end + +function ENT:Initialize() + + BaseClass.Initialize(self) + +end + +function ENT:KeyValue(key, val) + + BaseClass.KeyValue(self, key, val) + +end + +end diff --git a/entities/entities/info_npc_spawn_destination.lua b/entities/entities/info_npc_spawn_destination.lua new file mode 100644 index 00000000..15913d3f --- /dev/null +++ b/entities/entities/info_npc_spawn_destination.lua @@ -0,0 +1,59 @@ +local DbgPrint = GetLogging("NPC") + +if SERVER then + +ENT.Base = "base_point" +ENT.ReuseDelay = 0 +ENT.RenameNPC = nil +ENT.TimeNextAvailable = 0 + +DEFINE_BASECLASS( "base_point" ) + +function ENT:PreInitialize() + + self:SetupOutput("OnSpawnNPC") + +end + +function ENT:KeyValue(key, val) + + if key:iequals("ReuseDelay") then + self.ReuseDelay = tonumber(val) + elseif key:iequals("RenameNPC") then + self.RenameNPC = val + end + + return BaseClass.KeyValue(self, key, val) + +end + +function ENT:Initialize() + + self.TimeNextAvailable = CurTime() + + BaseClass.Initialize(self) + +end + +function ENT:IsAvailable() + + if self.TimeNextAvailable > CurTime() then + return false + end + + return true + +end + +function ENT:OnSpawnedNPC(ent) + + if self.RenameNPC ~= nil and self.RenameNPC ~= "" then + ent:SetName(self.RenameNPC) + end + + self:FireOutputs("OnSpawnNPC", ent, self) + self.TimeNextAvailable = CurTime() + self.ReuseDelay + +end + +end diff --git a/entities/entities/lambda_checkpoint.lua b/entities/entities/lambda_checkpoint.lua new file mode 100644 index 00000000..92415cad --- /dev/null +++ b/entities/entities/lambda_checkpoint.lua @@ -0,0 +1,5 @@ +ENT.Base = "base_point" +ENT.Type = "point" + +function ENT:Initialize() +end diff --git a/entities/entities/lambda_clientcommand.lua b/entities/entities/lambda_clientcommand.lua new file mode 100644 index 00000000..1116b0c9 --- /dev/null +++ b/entities/entities/lambda_clientcommand.lua @@ -0,0 +1,38 @@ +if SERVER then + +ENT.Base = "lambda_entity" +ENT.Type = "point" + +DEFINE_BASECLASS( "lambda_entity" ) + +function ENT:PreInitialize() + + BaseClass.PreInitialize(self) + self:SetInputFunction("Command", self.InputCommand) + +end + +function ENT:Initialize() + + BaseClass.Initialize(self) + +end + +function ENT:KeyValue(key, val) + + BaseClass.KeyValue(self, key, val) + +end + +function ENT:InputCommand(data, activator, caller) + + DbgPrint("Command: " .. data .. ", " .. tostring(activator) .. ", " .. tostring(caller)) + return self:Command(data, activator, caller) + +end + +function ENT:Command(data, activator, caller) + -- Stub +end + +end diff --git a/entities/entities/lambda_entity.lua b/entities/entities/lambda_entity.lua new file mode 100644 index 00000000..5e470a13 --- /dev/null +++ b/entities/entities/lambda_entity.lua @@ -0,0 +1,413 @@ +local DbgPrint = GetLogging("LambdaEnt") + +ENT.Base = "base_entity" +ENT.Type = "point" + +AddCSLuaFile() + +DEFINE_BASECLASS("base_entity") + +local NW2_VARS = true + +local DTVAR_TO_TYPE = +{ + ["string"] = function(val) return val end, + ["bool"] = function(val) return tobool(val) end, + ["float"] = function(val) return util.StringToType(val, "float") end, + ["int"] = function(val) return util.StringToType(val, "int") end, + ["angle"] = function(val) return util.StringToType(val, "angle") end, + ["entity"] = function(val) error("Can not use entity as key value") end, +} + +local DTVAR_TO_STRING = +{ + ["string"] = function(val) return val end, + ["bool"] = function(val) return val and "1" or "0" end, + ["float"] = function(val) return util.TypeToString(val) end, + ["int"] = function(val) return util.TypeToString(val) end, + ["angle"] = function(val) return util.TypeToString(val) end, + ["entity"] = function(val) error("Can not use entity as key value") end, +} + +local DTVAR_SET +if NW2_VARS == true then + DTVAR_SET = + { + ["string"] = function(ent, key, index, val) ent:SetNW2String(key, val) end, + ["bool"] = function(ent, key, index, val) ent:SetNW2Bool(key, val) end, + ["float"] = function(ent, key, index, val) ent:SetNW2Float(key, val) end, + ["int"] = function(ent, key, index, val) ent:SetNW2Int(key, val) end, + ["angle"] = function(ent, key, index, val) ent:SetNW2Angle(key, val) end, + ["entity"] = function(ent, key, index, val) ent:SetNW2Entity(key, val) end, + } +else + DTVAR_SET = + { + ["string"] = function(ent, key, index, val) ent:SetDTString(index, val) end, + ["bool"] = function(ent, key, index, val) ent:SetDTBool(index, val) end, + ["float"] = function(ent, key, index, val) ent:SetDTFloat(index, val) end, + ["int"] = function(ent, key, index, val) ent:SetDTInt(index, val) end, + ["angle"] = function(ent, key, index, val) ent:SetDTAngle(index, val) end, + ["entity"] = function(ent, key, index, val) ent:SetDTEntity(index, val) end, + } +end + +local DTVAR_GET +if NW2_VARS == true then + DTVAR_GET = + { + ["string"] = function(ent, key, index, fallback) return ent:GetNW2String(key, fallback) end, + ["bool"] = function(ent, key,index, fallback) return ent:GetNW2Bool(key, fallback) end, + ["float"] = function(ent, key, index, fallback) return ent:GetNW2Float(key, fallback) end, + ["int"] = function(ent, key, index, fallback) return ent:GetNW2Int(key, fallback) end, + ["angle"] = function(ent, key, index, fallback) return ent:GetNW2Angle(key, fallback) end, + ["entity"] = function(ent, key, index, fallback) return ent:GetNW2Entity(key, fallback) end, + } +else + DTVAR_GET = + { + ["string"] = function(ent, key, index, fallback) return ent:GetDTString(index) or fallback end, + ["bool"] = function(ent, key, index, fallback) return ent:GetDTBool(index) or fallback end, + ["float"] = function(ent, key, index, fallback) return ent:GetDTFloat(index) or fallback end, + ["int"] = function(ent, key, index, fallback) return ent:GetDTInt(index) or fallback end, + ["angle"] = function(ent, key, index, fallback) return ent:GetDTAngle(index) or fallback end, + ["entity"] = function(ent, key, index, fallback) return ent:GetDTEntity(index) or fallback end, + } +end + +function ENT:PreInitialize() + + DbgPrint(self, "PreInitialize") + + self.OutputTable = self.OutputTable or {} + self.InputsTable = self.InputsTable or {} + self.KeyValueTable = self.KeyValueTable or {} + self.IsPreInitialized = true + self.DTVarIndex = self.DTVarIndex or + { + ["string"] = { Index = 0, Max = 4 }, + ["bool"] = { Index = 0, Max = 32 }, + ["float"] = { Index = 0, Max = 32 }, + ["int"] = { Index = 0, Max = 32 }, + ["angle"] = { Index = 0, Max = 32 }, + ["entity"] = { Index = 0, Max = 32 }, + } + self.DTVarTable = self.DTVarTable or {} + self.DTListener = self.DTListener or {} + self.KeyValueMapping = self.KeyValueMapping or {} + + if NW2_VARS == false then + self:InstallDataTable() + end + +end + +function ENT:DTVarNotify(dtVar, val, default) + + if val == nil and default ~= nil then + error("Investigate", default) + end + + if dtVar.LastVal == val then + return + end + + DbgPrint(self, "DTVar Changed: " .. tostring(dtVar.Key) .. " New: " .. tostring(val) .. ", Old: " .. tostring(dtVar.LastVal)) + + if dtVar.OnChange ~= nil then + dtVar.OnChange(self, dtVar.Key, dtVar.LastVal, val) + end + + -- Keep keyvalues up to date. + if dtVar.KeyValue ~= nil then + self.KeyValueTable[dtVar.KeyValue] = val + end + + dtVar.LastVal = val + +end + +function ENT:NotifyDTChange() + + for _, dtVar in pairs(self.DTListener) do + + local curVal = dtVar.Get(self, dtVar.Key, dtVar.Index, dtVar.LastVal or dtVar.Default) + self:DTVarNotify(dtVar, curVal, dtVar.Default) + + end + +end + +--[[ +function ENT:SetupDataTables() + + if self.IsPreInitialized ~= true then + self:PreInitialize() + end + + DbgPrint(self, "SetupDataTables") + + self.DataTableSetup = true + + for k,v in pairs(self.DTVarTable or {}) do + self:SetNWVar(k, v.LastVal) + end + + -- Lets stay away from the Think functions form the entities based on this one. + hook.Add("Think", self, self.NotifyDTChange) + +end +]] + +function ENT:Initialize() + if self.IsPreInitialized ~= true then + self:PreInitialize() + end + BaseClass.Initialize(self) +end + +function ENT:SetupNWVar(key, dtType, data) + + dtType = dtType:lower() + + local dtVarIndex = self.DTVarIndex[dtType] + if dtVarIndex == nil then + DbgError("Invalid DTVar type") + return + end + + if NW2_VARS == false then + if dtVarIndex.Index >= dtVarIndex.Max then + DbgError("Reached maximum DTVar type index") + return + end + end + + local dtVar = self.DTVarTable[key] or {} + dtVar.Key = key + if dtVar.Index == nil then + dtVar.Index = dtVarIndex.Index + dtVarIndex.Index = dtVarIndex.Index + 1 + end + + dtVar.Type = dtType + dtVar.ToType = DTVAR_TO_TYPE[dtType] + dtVar.Get = DTVAR_GET[dtType] + dtVar.Set = DTVAR_SET[dtType] + dtVar.LastVal = nil + + self.DTVarTable[key] = dtVar + + --DbgPrint(self, "Setup new DTVar: " .. key .. ", index: " .. tostring(dtvar.Index)) + + if data.KeyValue ~= nil then + self.KeyValueMapping[data.KeyValue:lower()] = dtVar + end + + if data.OnChange ~= nil then + dtVar.OnChange = data.OnChange + self.DTListener[key] = dtVar + end + + if data.Default ~= nil then + self:SetNWVar(key, data.Default) + end + +end + +function ENT:GetNWVar(key, fallback) + local dtVar = self.DTVarTable[key] + if dtVar == nil and fallback == nil then + DbgError("DTVar not setup, no fallback specified") + return + end + --[[ + if self.DataTableSetup ~= true then + return dtVar.LastVal or dtVar.Default + end + ]] + return dtVar.Get(self, dtVar.Key, dtVar.Index, nil) +end + +function ENT:SetNWVar(key, val) + local dtVar = self.DTVarTable[key] + if dtVar == nil then + DbgError("DTVar not setup: " .. key) + return + end + --[[ + if self.DataTableSetup == true then + dtVar.Set(self, dtVar.Key, dtVar.Index, val) + end + ]] + dtVar.Set(self, dtVar.Key, dtVar.Index, val) -- Refactored, remove this comment if working + self:DTVarNotify(dtVar, val) +end + +function ENT:GetNWVars() + + local vars = {} + for k,v in pairs(self.DTVarTable) do + vars[k] = self:GetNWVar(k) + end + return vars + +end + +function ENT:SetNWVars(vars) + for k,v in pairs(vars) do + self:SetNWVar(k, v) + end +end + +if SERVER then + + function ENT:AddSpawnFlags(flags) + local flags = bit.bor(self:GetSpawnFlags(), flags) + self:SetKeyValue("spawnflags", tostring(flags)) + end + + function ENT:SetupOutput(name) + self.OutputTable = self.OutputTable or {} + self.OutputTable[name] = self.OutputTable[name] or {} + --DbgPrint(self, "Setup output: " .. name) + end + + function ENT:SetInputFunction(input, fnc) + self.InputsTable = self.InputsTable or {} + self.InputsTable[input] = fnc + end + + function ENT:KeyValue(name, val) + + if self.IsPreInitialized ~= true and self.PreInitialize ~= nil then + self.IsPreInitialized = true + self:PreInitialize() + end + + if self.OutputTable[name] ~= nil then + self.OutputTable[name] = self.OutputTable[name] or {} + table.insert(self.OutputTable[name], { val, 0 }) + else + self.KeyValueTable = self.KeyValueTable or {} + self.KeyValueTable[name] = val + end + + local mapping = self.KeyValueMapping[name:lower()] + if mapping ~= nil then + local data = mapping.ToType(val) + if data == nil then + DbgError("Unable to convert value data on key: " .. name .. " -> " .. tostring(val)) + end + --DbgPrint(self, "KeyValue to DTVar: " .. name .. " -> " .. val) + --PrintTable(mapping) + --mapping.Set(self, mapping.Key, mapping.Index, data) + self:SetNWVar(mapping.Key, data) + end + + return BaseClass.KeyValue(self, name, val) + + end + + function ENT:GetLambdaKeyValueTable() + return table.Copy(self.KeyValueTable) + end + + function ENT:CloneOutputs(ent) + if ent.OutputTable ~= nil then + self.OutputTable = table.Copy(ent.OutputTable) + end + end + + function ENT:GetOutputsTable() + return self.OutputTable + end + + function ENT:SetOutputsTable(outputs) + self.OutputTable = outputs + end + + function ENT:FireOutputs(name, param, activator, caller) + local caller = caller or self + local activator = activator or self + local outputs = self.OutputTable[name] or {} + util.RunNextFrame(function() + util.TriggerOutputs(outputs, activator, caller, param, self) + end) + end + + function ENT:AddOutput(output, target, input, param, delay, times) + + param = param or "" + delay = delay or "0" + times = times or "-1" + + param = string.Trim(param) + delay = string.Trim(delay) + times = string.Trim(times) + + local outputData = target .. "," .. input .. "," .. param .. "," .. delay .. "," .. times + + if self.OutputTable[output] ~= nil then + self.OutputTable[output] = self.OutputTable[output] or {} + table.insert(self.OutputTable[output], { outputData, 0 }) + end + + DbgPrint("Registered output") + + end + + function ENT:ClearOutputs() + self.OutputTable = {} + end + + function ENT:AcceptInput(name, activator, caller, data) + + if GAMEMODE ~= nil and GAMEMODE.AcceptInput ~= nil and GAMEMODE:AcceptInput(self, name, activator, caller, data) == true then + DbgPrint(self, "Suppressed Input via GAMEMODE:AcceptInput") + return true + end + + DbgPrint(self, "Name: " .. tostring(name)) + + if name:iequals("Kill") then + self:Remove() + return + elseif name:iequals("AddOutput") then + + local outputname + local params + + outputname, params = string.match(data, "(%w+)(.+)") + params = string.Explode(",", string.Trim(params), false) + --PrintTable(params) + + local target = params[1] + local input = params[2] + local param = params[3] + local delay = params[4] + local times = params[5] + + return self:AddOutput(outputname, target, input, param, delay, times) + end + + if self.InputsTable ~= nil then + local fn = self.InputsTable[name] + if fn then + DbgPrint(self, "Handling Input (" .. name .. ")") + local res = fn(self, data, activator, caller) + if res ~= nil then + return res + end + else + DbgPrint(self, "Unhandled input: " .. name) + end + else + DbgPrint("No InputsTable") + end + + return BaseClass.AcceptInput(name, activator, caller, data) + + end + +end diff --git a/entities/entities/lambda_gib_part.lua b/entities/entities/lambda_gib_part.lua new file mode 100644 index 00000000..66fa2484 --- /dev/null +++ b/entities/entities/lambda_gib_part.lua @@ -0,0 +1,197 @@ +AddCSLuaFile() + +ENT.Base = "lambda_entity" +ENT.Type = "anim" + +DEFINE_BASECLASS("lambda_entity") + +function ENT:PreInitialize() + BaseClass.PreInitialize(self) +end + +function ENT:Initialize() + + BaseClass.Initialize(self) + + if CLIENT then + CreateParticleSystem(self, "blood_impact_red_01", PATTACH_ABSORIGIN_FOLLOW) + self.Emitter = ParticleEmitter(self:GetPos(), false) + else + self:PhysicsInit(SOLID_VPHYSICS) + self:SetMoveType(MOVETYPE_VPHYSICS) + self:SetCollisionGroup(COLLISION_GROUP_DISSOLVING) + local phys = self:GetPhysicsObject() + if IsValid(phys) then + phys:EnableMotion(true) + end + self:PhysWake() + end + + self.LastDecalTime = CurTime() + self.LastThinkTime = CurTime() + self.BloodAmount = 100 + self.Sticky = false + self.EmitBlood = false + +end + +function ENT:SetSticky(sticky) + self.Sticky = sticky +end + +function ENT:SetEmitBlood(emit) + self.EmitBlood = emit +end + +function ENT:OnRemove() + if CLIENT then + --self.Emitter:Finish() + end +end + +function ENT:Think() + + if CLIENT then + + local emitter = self.Emitter + if self.EmitBlood ~= true then + return + end + + local curTime = CurTime() + local elapsed = curTime - self.LastThinkTime + + self.BloodAmount = self.BloodAmount - (elapsed * 10) + if self.BloodAmount < 0 then + return + end + + self.LastThinkTime = curTime + + local pos = self:GetPos() + local nearbyGibs = false + for k,v in pairs(ents.FindInBox(pos - Vector(15, 15, 10), pos + Vector(15, 15, 10))) do + if v:GetClass() == "lambda_gib_part" then + nearbyGibs = true + break + end + end + + local count = math.Round(self.BloodAmount / 30) + local mins = self:OBBMins() + local maxs = self:OBBMaxs() + local size = maxs - mins + local sizeLen = size:Length() / 100 + local decalRand = 20 + + if nearbyGibs == true then + sizeLen = sizeLen / 2 + decalRand = 100 + end + + for i = 0, count do + local particle = emitter:Add("effects/blood_core", pos + VectorRand() * 5) + particle:SetVelocity( VectorRand() * 30 ) + particle:SetGravity(Vector(0, 0, -600)) + particle:SetDieTime( math.Rand( 0.2, 0.4 ) ) + particle:SetStartAlpha( 200 ) + particle:SetStartSize( math.Rand( 10, 20 ) * sizeLen ) + particle:SetEndSize( math.Rand( 20, 30 ) * sizeLen ) + particle:SetCollide(true) + particle:SetRoll( math.Rand( 0, 180 ) ) + particle:SetRollDelta( math.Rand( -0.2, 0.2 ) ) + particle:SetColor( 100, 0, 0 ) + particle:SetCollideCallback(function(part, hitPos, hitNormal) + part:SetDieTime(0.2) + part:SetLifeTime(0) + if math.random(1, decalRand) == 1 then + util.Decal("Blood", hitPos + hitNormal, hitPos - hitNormal) + end + end) + + particle = emitter:Add("effects/blood", self:GetPos()) + particle:SetVelocity( VectorRand() * 30 ) + particle:SetGravity(Vector(0, 0, -600)) + particle:SetDieTime( 10 ) + particle:SetStartAlpha( 150 ) + particle:SetStartSize( math.Rand( 3, 6 ) ) + particle:SetEndSize( math.Rand( 6, 10 ) ) + particle:SetCollide(true) + particle:SetRoll( math.Rand( 0, 360 ) ) + particle:SetColor( 128, 0, 0 ) + particle:SetCollideCallback(function(part, hitPos, hitNormal) + part:SetDieTime(0.2) + part:SetLifeTime(0) + if math.random(1, decalRand) == 1 then + util.Decal("Blood", hitPos + hitNormal, hitPos - hitNormal) + end + end) + + end + + self:SetNextClientThink(CurTime() + 0.1) + return true + end + +end + +function ENT:PhysicsCollide(data, collider) + + local curTime = CurTime() + + if curTime - (self.LastImpactTime or 0) < 0.05 then + return + end + + self.LastImpactTime = curTime + + if data.Speed >= 50 then + local effectdata = EffectData() + effectdata:SetNormal(data.HitNormal) + effectdata:SetOrigin(data.HitPos) + effectdata:SetMagnitude(3) + effectdata:SetScale(10) + effectdata:SetFlags(3) + effectdata:SetColor(0) + util.Effect("bloodspray", effectdata, true, true) + + local effectdata = EffectData() + effectdata:SetNormal(data.HitNormal) + effectdata:SetOrigin(data.HitPos) + effectdata:SetMagnitude(data.Speed / 100) + effectdata:SetScale(10) + effectdata:SetFlags(3) + effectdata:SetColor(0) + util.Effect("BloodImpact", effectdata, true, true) + + end + + local emitBlood = false + local emitSound = false + + local phys = self:GetPhysicsObject() + if IsValid(phys) then + phys:SetVelocity(phys:GetVelocity() * 0.8) + + local ent = data.HitEntity + if self.Sticky == true and not self:OnGround() and ent:IsWorld() == true and data.Speed > 100 then + --phys:EnableMotion(false) + emitBlood = true + end + end + + if emitBlood == true or (data.Speed > 10 and math.random(0, 5) == 1) then + util.Decal("Blood", data.HitPos + data.HitNormal, data.HitPos - data.HitNormal) + end + + if emitSound == true or (data.Speed > 25) then + self:EmitSound( "physics/flesh/flesh_squishy_impact_hard3.wav", math.Clamp(data.Speed, 0, 75), math.Rand( 70, 100 ) ) + end + +end + +if CLIENT then + function ENT:Draw() + self:DrawModel() + end +end diff --git a/entities/entities/lambda_npcmaker.lua b/entities/entities/lambda_npcmaker.lua new file mode 100644 index 00000000..f2843f79 --- /dev/null +++ b/entities/entities/lambda_npcmaker.lua @@ -0,0 +1,498 @@ +local DbgPrint = GetLogging("NPC") + +if SERVER then + +AddCSLuaFile() + +DEFINE_BASECLASS("lambda_entity") + +ENT.Base = "lambda_entity" +ENT.Type = "point" + +--ENT.Outputs = table.Merge(BaseClass.Outputs, { "OnAllSpawned", "OnAllSpawnedDead", "OnAllLiveChildrenDead", "OnSpawnNPC" }) + +SF_NPCMAKER_START_ON = 1 -- start active ( if has targetname ) +SF_NPCMAKER_NPCCLIP = 8 -- Children are blocked by NPCclip +SF_NPCMAKER_FADE = 16 -- Children's corpses fade +SF_NPCMAKER_INF_CHILD = 32 -- Infinite number of children +SF_NPCMAKER_NO_DROP = 64 -- Do not adjust for the ground's position when checking for spawn +SF_NPCMAKER_HIDEFROMPLAYER = 128 -- Don't spawn if the player's looking at me +SF_NPCMAKER_ALWAYSUSERADIUS = 256 -- Use radius spawn whenever spawning +SF_NPCMAKER_NOPRELOADMODELS = 512 -- Suppress preloading into the cache of all referenced .mdl files + +local HULL_HUMAN_MINS = Vector(-13, -13, 0) +local HULL_HUMAN_MAXS = Vector(13, 13, 72) + +local function InPlayerViewCone(ply, pos) + + local los = pos - ply:EyePos() + los.z = 0 + los:Normalize() + + local eyeDir = ply:GetAimVector() + + -- 2D eye direction. + eyeDir.z = 0 + + local len = eyeDir:Length2D() + if len ~= 0 then + eyeDir = eyeDir / len + else + eyeDir.x = 0 + eyeDir.y = 0 + end + + local dot = los:Dot(eyeDir) + if dot > ply:GetFOV() then + return true + end + + return false + +end + +function ENT:PreInitialize() + + DbgPrint(self, "ENT:PreInitialize") + + BaseClass.PreInitialize(self) + + self:SetupOutput("OnAllSpawned") + self:SetupOutput("OnAllSpawnedDead") + self:SetupOutput("OnAllLiveChildrenDead") + self:SetupOutput("OnSpawnNPC") + + self:SetInputFunction("Enable", self.Enable) + self:SetInputFunction("Disable", self.Disable) + self:SetInputFunction("Toggle", self.Toggle) + self:SetInputFunction("Spawn", self.InputSpawnNPC) + + self:SetInputFunction("SetMaxChildren", self.SetMaxChildren) + self:SetInputFunction("AddMaxChildren", self.AddMaxChildren) + self:SetInputFunction("SetMaxLiveChildren", self.SetMaxLiveChildren) + self:SetInputFunction("SetSpawnFrequency", self.SetSpawnFrequency) + + self:SetupNWVar("Disabled", "bool", { Default = false, KeyValue = "StartDisabled" }) + self:SetupNWVar("MaxNPCCount", "int", { Default = 0, KeyValue = "MaxNPCCount" }) + self:SetupNWVar("MaxLiveChildren", "int", { Default = 0, KeyValue = "MaxLiveChildren" }) + self:SetupNWVar("SpawnFrequency", "float", { Default = 0, KeyValue = "SpawnFrequency" }) + self:SetupNWVar("DisableScaling", "bool", { Default = 0, KeyValue = "DisableScaling" }) + self:SetupNWVar("LiveChildren", "int", { Default = 0 }) + self:SetupNWVar("CreatedCount", "int", { Default = 0 }) + self:SetupNWVar("ScaleLiveChildren", "bool", { Default = true, KeyValue = "ScaleLiveChildren" }) + + --self.MaxNPCCount = 0 + --self.MaxLiveChildren = 0 + --self.SpawnFrequency = 0 + --self.Disabled = false + --self.LiveChildren = 0 + --self.CreatedCount = 0 + --self.DisableScaling = false + +end + +function ENT:KeyValue(key, val) + + --DbgPrint(self, "Key: " .. key .. ", Val: " .. val) + + --[[ + if key:iequals("StartDisabled") then + self.Disabled = tobool(val) + elseif key:iequals("SpawnFrequency") then + self.SpawnFrequency = tonumber(val) + elseif key:iequals("MaxLiveChildren") then + self.MaxLiveChildren = tonumber(val) + elseif key:iequals("MaxNPCCount") then + self.MaxNPCCount = tonumber(val) + elseif key:iequals("DisableScaling") then + self.DisableScaling = tobool(val) + end + ]] + + return BaseClass.KeyValue(self, key, val) + +end + +function ENT:Initialize() + + DbgPrint(self, "ENT:Initialize") + + BaseClass.Initialize(self) + + self:SetSolid(SOLID_NONE) + + if self:GetNWVar("Disabled") == false then + self:NextThink( CurTime() + 0.1 ) + self.Think = self.MakerThink + else + self.Think = self.StubThink + end + +end + +function ENT:SetMaxChildren(data) + self:SetNWVar("MaxNPCCount", tonumber(data or 0)) +end + +function ENT:AddMaxChildren(data) + self:SetNWVar("MaxNPCCount", self:GetNWVar("MaxNPCCount", 0) + tonumber(data or 0)) +end + +function ENT:SetMaxLiveChildren(data) + self:SetNWVar("MaxLiveChildren", tonumber(data or 0)) +end + +function ENT:SetDisableScaling(scaling) + self:SetNWVar("DisableScaling", tobool(scaling)) +end + +function ENT:SetSpawnFrequency(data) + self:SetNWVar("SpawnFrequency", tonumber(data)) +end + +function ENT:InputSpawnNPC() + DbgPrint(self, "ENT:InputSpawnNPC") + + if not self:IsDepleted() then + self:MakeNPC() + end +end + +function ENT:HumanHullFits(pos) + + -- ai_hull_t Human_Hull (bits_HUMAN_HULL, "HUMAN_HULL", Vector(-13,-13, 0), Vector(13, 13, 72), Vector(-8,-8, 0), Vector( 8, 8, 72) ); + local tr = util.TraceHull( + { + start = pos, + endpos = pos + Vector(0, 0, 1), + mins = HULL_HUMAN_MINS, + maxs = HULL_HUMAN_MAXS, + mask = MASK_NPCSOLID, + }) + + return tr.Fraction == 1.0 + +end + +function ENT:AcceptInput(name, activator, caller, data) + + return BaseClass.AcceptInput(self, name, activator, caller, data) + +end + +function ENT:GetScaledMaxLiveChildren() + + local maxLiveChildren = self:GetNWVar("MaxLiveChildren") + + if self:GetNWVar("DisableScaling") == true or + self:GetNWVar("ScaleLiveChildren") ~= true or + (GAMEMODE.MapScript and GAMEMODE.MapScript.DisableNPCScaling == true) then + DbgPrint("Using original MaxLiveChildren: " .. maxLiveChildren) + return maxLiveChildren + end + + if self.PrecacheData ~= nil then + local class = self.PrecacheData["classname"] + + if IsFriendEntityName(class) then + return maxLiveChildren + end + end + + local playerCount = #player.GetAll() + local extraCount = math.floor(playerCount / 4) + local res = maxLiveChildren + extraCount + + return res + +end + +function ENT:GetScaledMaxNPCs() + + local maxNPCCount = self:GetNWVar("MaxNPCCount") + + if self:GetNWVar("DisableScaling") == true or + (GAMEMODE.MapScript and GAMEMODE.MapScript.DisableNPCScaling == true) then + return maxNPCCount + end + + local playerCount = #player.GetAll() + local extraCount = math.floor(playerCount / 2) + local res = maxNPCCount + extraCount + + if self.PrecacheData ~= nil then + local class = self.PrecacheData["classname"] + if IsFriendEntityName(class) then + return maxNPCCount + end + end + + return res + +end + +function ENT:IsDepleted() + if self:HasSpawnFlags(SF_NPCMAKER_INF_CHILD) or self:GetNWVar("CreatedCount") < self:GetScaledMaxNPCs() then + return false + end + return true +end + +function ENT:Toggle() + if self:GetNWVar("Disabled") == true then + self:Enable() + else + self:Disable() + end +end + +function ENT:Enable() + + if self:IsDepleted() then + --DbgPrint("Can not enable because entity is depleted!") + --return + end + + self:SetNWVar("Disabled", false) + + --self.Disabled = false + self.Think = self.MakerThink + self:NextThink( CurTime() ) +end + +function ENT:Disable() + --self.Disabled = true + self:SetNWVar("Disabled", true) + self.Think = self.StubThink +end + +function ENT:CanMakeNPC(ignoreSolidEnts) + + ignoreSolidEnts = ignoreSolidEnts or false + + if self:IsDepleted() then + DbgPrint(self, "Depleted") + return false + end + + local maxLiveChildren = self:GetNWVar("MaxLiveChildren") + local liveChildren = self:GetNWVar("LiveChildren") + local scaledMaxLiveChildren = self:GetScaledMaxLiveChildren() + + if maxLiveChildren > 0 and liveChildren >= scaledMaxLiveChildren then + DbgPrint(self, "Too many live children") + return false + end + + local pos = self:GetPos() + local mins = pos - Vector(34, 34, 0) + local maxs = pos + Vector(34, 34, pos.z) + + if ignoreSolidEnts == false then + + for _,ent in pairs(ents.FindInBox(mins, maxs)) do + + if not ent:IsPlayer() and not ent:IsNPC() then + continue + end + + if bit.band(ent:GetSolidFlags(), FSOLID_NOT_SOLID) == 0 then + + -- This is used for striders because of the big bounding box, + -- NOTE: This is all based on monstermaker.cpp from the Source SDK + + local tr = util.TraceHull({ + start = self:GetPos() + Vector(0, 0, 2), + endpos = self:GetPos() - Vector(0, 0, 8192), + mins = HULL_HUMAN_MINS, + maxs = HULL_HUMAN_MAXS, + mask = MASK_NPCSOLID, + }) + + if not self:HumanHullFits(tr.HitPos + Vector(0, 0, 1)) then + return false + end + + end + + end + + end + + local ForcedNPCS = + { + ["npc_rollermine"] = true, + ["npc_breen"] = true, + } + + if self:HasSpawnFlags( SF_NPCMAKER_HIDEFROMPLAYER ) then + + local class = self:GetNPCClass() + + -- Make sure we spawn friendlies and enforced npcs. + if ForcedNPCS[class] == nil and IsFriendEntityName(class) == false then + --DbgPrint("Checking player Distance") + for _, ply in pairs(player.GetAll()) do + + --if InPlayerViewCone(ply, pos) and ply:VisibleVec(pos) then + --[[ + if InPlayerViewCone(ply, pos) then + if bit.band(ply:GetFlags(), FL_NOTARGET) == 0 then + DbgPrint("Visible to player") + return false + end + end + + local dist = self:GetPos():Distance(ply:GetPos()) + if dist <= 256 then -- This is somewhat bogus. + DbgPrint("Player too close for: " .. class) + return false + end + ]] + + if ply:Visible(self) then + return false + end + + -- Also add a minimum distance, its not cool if they just spawn behind a wall. + local dist = ply:GetPos():Distance(self:GetPos()) + if dist < 500 then + return false + end + + end + end + else + --DbgPrint("No player visibility check") + end + + return true + +end + +function ENT:StubThink() + + --DbgPrint(self, "ENT:StubThink", ent) + +end + +function ENT:MakerThink() + + --DbgPrint(self, "ENT:MakerThink", ent) + + self:NextThink( CurTime() + self:GetNWVar("SpawnFrequency") ) + self:MakeNPC() + + return true + +end + +function ENT:DeathNotice(ent) + + if self:GetNWVar("LiveChildren", 0) <= 0 then + DbgError(self, "No live children but death notice! Investigate me") + end + + self:SetNWVar("LiveChildren", self:GetNWVar("LiveChildren") - 1) + + if self:GetNWVar("LiveChildren") <= 0 then + + self:FireOutputs("OnAllLiveChildrenDead", nil, self) + + if self:HasSpawnFlags(SF_NPCMAKER_INF_CHILD) == false and self:IsDepleted() == true then + + DbgPrint("All spawned NPCs are dead.") + + self:FireOutputs("OnAllSpawnedDead", nil, self) + + if self.OnAllSpawnedDead ~= nil then + self:OnAllSpawnedDead() + end + + end + + end + +end + +function ENT:DispatchSpawn(ent) + + DbgPrint(self, "ENT:DispatchSpawn", ent) + + if not IsValid(ent) then + return + end + + ent:Spawn() + + -- Check again, spawn can remove the ent. + if not IsValid(ent) then + return + end + +end + +function ENT:DispatchActivate(ent) + + DbgPrint(self, "ENT:DispatchActivate", ent) + + if not IsValid(ent) then + return + end + + ent:Activate() + +end + +function ENT:ChildPreSpawn(ent) + +end + +function ENT:ChildPostSpawn(ent) + + -- TODO: Check if ent is stuck and remove it. + + local maker = self + + -- Usually the entities would do that based on npc_template_maker but we are not C++ the object where it could call it. + ent:CallOnRemove(self, function(npc) + if IsValid(maker) then + DbgPrint("NPC (" .. tostring(npc) .. ") dead, notifying npc_maker: " .. tostring(maker)) + self:DeathNotice(npc) + end + end) + + DbgPrint(self, "Created new NPC: " .. tostring(ent)) + +end + +function ENT:UpdateScaling() + + DbgPrint(self, "ENT:UpdateScaling", ent) + + local maxCount = self:GetNWVar("MaxNPCCount") + if self:HasSpawnFlags(SF_NPCMAKER_INF_CHILD) == false and maxCount == 1 and self:GetNWVar("CreatedCount") == maxCount then + -- From this point on only spawn when not visible. + DbgPrint("Adjusted flags, hiding from player, CreatedCount == 1 and MaxNPCCount == 1") + self:AddSpawnFlags(SF_NPCMAKER_HIDEFROMPLAYER) + end + +end + +function ENT:MakeNPC() + -- Override me. + DbgPrint(self, "ENT:MakeNPC", ent) +end + +function ENT:GetNPCClass() + DbgPrint(self, "ENT:GetNPCClass", ent) + return "" +end + +function ENT:UpdateTransmitState() + + return TRANSMIT_NEVER + +end + +end diff --git a/entities/entities/lambda_player_tracker.lua b/entities/entities/lambda_player_tracker.lua new file mode 100644 index 00000000..9b7edc95 --- /dev/null +++ b/entities/entities/lambda_player_tracker.lua @@ -0,0 +1,177 @@ +AddCSLuaFile() + +ENT.Base = "base_anim" +ENT.Type = "anim" +ENT.RenderGroup = RENDERGROUP_OPAQUE + +function ENT:Initialize() + if CLIENT then + -- I know this seems insane but otherwise it would clip the purpose. + self:SetRenderBounds(Vector(-10000, -10000, -10000), Vector(10000, 10000, 10000)) + + hook.Add("PostDrawTranslucentRenderables", self, function(ent, bDrawingDepth, bDrawingSkybox) + if bDrawingDepth == true or bDrawingSkybox == true then + return + end + ent:RenderPlayer() + end) + end + self:DrawShadow(false) +end + +function ENT:AttachToPlayer(ply) + self:SetModel(ply:GetModel()) + self:SetPos(ply:GetPos()) + self:SetAngles(ply:GetAngles()) + self:SetParent(ply) + self:AddEffects(EF_BONEMERGE) + self:DrawShadow(false) + self.Player = ply +end + +function ENT:UpdateTransmitState() + return TRANSMIT_ALWAYS +end + +if CLIENT then + + local pixVis = util.GetPixelVisibleHandle() + local font = "DermaLarge" + local pad = 2 + local health_w = 100 + local health_h = 5 + local aux_w = 100 + local aux_h = 5 + + local function IsPlayerVisible(ply) + + local localPly = LocalPlayer() + if localPly:IsLineOfSightClear(ply:EyePos()) then + return true + end + + local visibility = util.PixelVisible(ply:EyePos(), 0, pixVis) + return visibility > 0 + + end + + local function IsPlayerBehind(ply) + + local dir = (ply:EyePos() - EyePos()):GetNormal() + local dot = dir:Dot(EyeAngles():Forward()) + if dot < 0 then + return true + end + return false + + end + + function ENT:RenderPlayer() + + local ply = self:GetParent() + if not IsValid(ply) or not ply:IsPlayer() then + return + end + + local localPly = LocalPlayer() + if ply == localPly then + return + end + + if IsPlayerBehind(ply) == true or ply:Alive() == false then + return + end + + local lastFrame = self.LastFrameNumber + if lastFrame == nil or lastFrame == FrameNumber() then + --return + end + self.LastFrameNumber = FrameNumber() + + if IsPlayerVisible(ply) == false then + cam.IgnoreZ(true) + ply:DrawModel() + cam.IgnoreZ(false) + end + + local text = ply:Nick() + local pos = ply:EyePos() + Vector(0, 0, 12) + + local boneIdx = ply:LookupBone("ValveBiped.Bip01_Head1") + if boneIdx ~= nil then + pos = ply:GetBonePosition(boneIdx) + Vector(0, 0, 14) + end + + local ang = (pos - EyePos()):GetNormal():Angle() + ang:RotateAroundAxis(ang:Forward(), 90); + ang:RotateAroundAxis(ang:Right(), 90); + ang:RotateAroundAxis(ang:Up(), 0); + + local dist = EyePos():Distance(ply:EyePos()) + local scale = 0.12 * (dist * 0.005) + if scale < 0.12 then + scale = 0.12 + end + if dist < 200 then + dist = 200 + elseif dist > 6000 then + dist = 6000 + end + local zOffset = 1 * (scale * 45) + + cam.IgnoreZ(true) + + cam.Start3D2D(pos + Vector(0, 0, zOffset), ang, scale) + + surface.SetFont(font) + + local w, h = surface.GetTextSize( text ) + local x = -(w / 2) + local y = 0 + + draw.SimpleText( text, font, x + 1, y + 1, Color( 0, 0, 0, 120 ) ) + draw.SimpleText( text, font, x + 2, y + 2, Color( 0, 0, 0, 50 ) ) + draw.SimpleText( text, font, x, y, GAMEMODE:GetTeamColor( ply ) ) + + y = y + h + pad + + do + local p = ply:Health() / ply:GetMaxHealth() + local redPower = (1.0 - p) * 10 + local v = CurTime() * redPower + local flash = (1 + math.sin(v) * math.cos(v)) * 55 + + surface.SetDrawColor(0, 0, 0, 100) + surface.DrawOutlinedRect(-1 - (health_w / 2), y, health_w + 2, health_h + 2) + + surface.SetDrawColor(200 - (p * 200) + flash, (p * 255) - (flash / 2), 0, 100) + surface.DrawRect(-(health_w / 2), y + 1, p * health_w, health_h) + + y = y + health_h + pad + + end + + do + local aux = ply:GetSuitPower() + local p = aux / 100 + + surface.SetDrawColor(0, 0, 0, 100) + surface.DrawOutlinedRect(-1 - (aux_w / 2), y, aux_w + 2, aux_h + 2) + + surface.SetDrawColor(255 - p * 255, p * 200, p * 150, 100) + surface.DrawRect(-(aux_w / 2), y + 1, p * aux_w, aux_h) + + end + cam.End3D2D() + + cam.IgnoreZ(false) + + end + + function ENT:Draw() + end + + function ENT:DrawTranslucent() + end + +end diff --git a/entities/entities/lambda_trigger.lua b/entities/entities/lambda_trigger.lua new file mode 100644 index 00000000..52d9b9ac --- /dev/null +++ b/entities/entities/lambda_trigger.lua @@ -0,0 +1,1054 @@ +--local DbgPrint = function() end + +local showtriggers = GetConVar("showtriggers") +local DbgPrint = GetLogging("Trigger") + +local TRIGGER_MSG_PLAYER_COUNT = 0 +local TRIGGER_MSG_SHOWWAIT = 1 +local TRIGGER_MSG_SETBLOCKED = 2 +local TRIGGER_MSG_REMOVED = 3 + +if SERVER then + + AddCSLuaFile() + + util.AddNetworkString("LambdaTriggerUpdate") + + ENT.Base = "lambda_entity" + ENT.Type = "brush" + + DEFINE_BASECLASS("lambda_entity") + + SF_TRIGGER_ALLOW_CLIENTS = 0x01 -- Players can fire this trigger + SF_TRIGGER_ALLOW_NPCS = 0x02 -- NPCS can fire this trigger + SF_TRIGGER_ALLOW_PUSHABLES = 0x04 -- Pushables can fire this trigger + SF_TRIGGER_ALLOW_PHYSICS = 0x08 -- Physics objects can fire this trigger + SF_TRIGGER_ONLY_PLAYER_ALLY_NPCS = 0x10 -- *if* NPCs can fire this trigger, this flag means only player allies do so + SF_TRIGGER_ONLY_CLIENTS_IN_VEHICLES = 0x20 -- *if* Players can fire this trigger, this flag means only players inside vehicles can + SF_TRIGGER_ALLOW_ALL = 0x40 -- Everything can fire this trigger EXCEPT DEBRIS! + SF_TRIGGER_ONLY_CLIENTS_OUT_OF_VEHICLES = 0x200 -- *if* Players can fire this trigger, this flag means only players outside vehicles can + SF_TRIG_PUSH_ONCE = 0x80 -- trigger_push removes itself after firing once + SF_TRIG_PUSH_AFFECT_PLAYER_ON_LADDER = 0x100 -- if pushed object is player on a ladder, then this disengages them from the ladder (HL2only) + SF_TRIG_TOUCH_DEBRIS = 0x400 -- Will touch physics debris objects + SF_TRIGGER_ONLY_NPCS_IN_VEHICLES = 0x800 -- *if* NPCs can fire this trigger, only NPCs in vehicles do so (respects player ally flag too) + SF_TRIGGER_DISALLOW_BOTS = 0x1000 -- Bots are not allowed to fire this trigger + + function ENT:PreInitialize() + + DbgPrint(self, "PreInitialize") + + BaseClass.PreInitialize(self) + + self:SetupOutput("OnTrigger") + self:SetupOutput("OnStartTouch") + self:SetupOutput("OnStartTouchAll") + self:SetupOutput("OnEndTouch") + self:SetupOutput("OnEndTouchAll") + + self:SetInputFunction("Enable", self.Enable) + self:SetInputFunction("Disable", self.Disable) + self:SetInputFunction("Toggle", self.Toggle) + + self:SetupNWVar("Disabled", "bool", { Default = false, KeyValue = "StartDisabled", OnChange = self.HandleDisableChange }) + self:SetupNWVar("WaitTime", "float", { Default = 0.2, KeyValue = "wait"} ) + self:SetupNWVar("FilterName", "string", { Default = "", KeyValue = "filtername"} ) + self:SetupNWVar("WaitForTeam", "bool", { Default = false, KeyValue = "teamwait"} ) + self:SetupNWVar("LockPlayers", "bool", { Default = false, KeyValue = "lockplayers"} ) + self:SetupNWVar("Blocked", "bool", { Default = false, KeyValue = "blocked", OnChange = self.HandleBlockingUpdate } ) + self:SetupNWVar("Timeout", "float", { Default = 0, KeyValue = "timeout" } ) + self:SetupNWVar("DisableEndTouch", "bool", { Default = false, KeyValue = "disableendtouch" }) + self:SetupNWVar("ShowWait", "bool", { Default = true, KeyValue = "showwait" }) + + -- Internal variables + self.TeamInside = false + self.IsWaiting = false + self.NextTimeout = 0 + self.DisabledTouchingObjects = {} + self.TouchingObjects = {} + self.LastTouch = CurTime() + + self:AddDebugOverlays(bit.bor(OVERLAY_PIVOT_BIT, OVERLAY_BBOX_BIT, OVERLAY_NAME_BIT)) + + end + + function ENT:Initialize() + + BaseClass.Initialize(self) + + DbgPrint(self, "Initialize") + + self:SetNotSolid(true) + self:SetTrigger(true) + + if IsValid(self:GetParent()) then + self:SetSolid(SOLID_VPHYSICS) + else + self:SetSolid(SOLID_BSP) + end + + self:AddSolidFlags( FSOLID_NOT_SOLID ) + self:AddSolidFlags( FSOLID_TRIGGER ) + + self:SetMoveType( MOVETYPE_NONE ) + + if self:HasSpawnFlags(SF_TRIG_TOUCH_DEBRIS) then + self:AddSolidFlags( FSOLID_TRIGGER_TOUCH_DEBRIS ) + end + + if self:HasSpawnFlags( SF_TRIGGER_ONLY_PLAYER_ALLY_NPCS ) or + self:HasSpawnFlags( SF_TRIGGER_ONLY_NPCS_IN_VEHICLES ) then + self:AddSpawnFlags( SF_TRIGGER_ALLOW_NPCS ); + end + + if self:HasSpawnFlags( SF_TRIGGER_ONLY_CLIENTS_IN_VEHICLES ) then + self:AddSpawnFlags( SF_TRIGGER_ALLOW_CLIENTS ); + end + + if self:HasSpawnFlags( SF_TRIGGER_ONLY_CLIENTS_OUT_OF_VEHICLES ) then + self:AddSpawnFlags( SF_TRIGGER_ALLOW_CLIENTS ); + end + + --DbgPrint(self, "OnTriggerEvents: " .. #self.OnTriggerEvents) + --DbgPrint(self, "OnStartTouchEvents: " .. #self.OnStartTouchEvents) + + if showtriggers:GetBool() == false then + self:AddEffects(EF_NODRAW) + else + self:RemoveEffects(EF_NODRAW) + end + + if self:GetNWVar("Blocked") == true then + self:HandleBlockingUpdate(nil, false, true) + end + + hook.Add("PlayerInitialSpawn", self, function(gm, ply) + gm:FullPlayerUpdate(ply) + end) + + end + + function ENT:KeyValue(key, val) + + BaseClass.KeyValue(self, key, val) + + end + + function ENT:HandleDisableChange(key, wasDisabled, isDisabled) + + if wasDisabled == false and isDisabled == true then + + if self.IsWaiting == true then + DbgPrint("Reset state because it got disabled") + self:CmdShowTeamWaiting(nil, false, 0) + end + + end + + end + + function ENT:HandleBlockingUpdate(key, wasBlocked, wantsBlocking) + + DbgPrint(self, "HandleBlockingUpdate", wasBlocked, wantsBlocking) + + if wasBlocked == true and wantsBlocking == false then + self:SetCustomCollisionCheck(false) + if IsValid(self:GetPhysicsObject()) then + self:PhysicsDestroy() + end + if self.PrevModel ~= nil then + self:SetModel(self.PrevModel) + end + self:SetTrigger(true) + --self:UseTriggerBounds(true) + elseif wasBlocked == false and wantsBlocking == true then + self:PhysicsInit(SOLID_BSP) + self:SetSolid(SOLID_BSP) + self:SetMoveType(MOVETYPE_NONE) + local phys = self:GetPhysicsObject() + if IsValid(phys) then + phys:EnableMotion(false) + end + self:SetCustomCollisionCheck(true) + self.PrevModel = self:GetModel() + end + + self:CmdSetBlocked(nil) + + end + + function ENT:SetupTrigger(pos, ang, mins, maxs, spawn) + + --DbgPrint("Creating Trigger at " .. tostring(pos) .. "\n\tMins: "..tostring(mins) .. "\n\tMaxs: " .. tostring(maxs)) + self:SetPos(pos) + self:SetAngles(ang) + self:SetKeyValue("spawnflags", SF_TRIGGER_ALLOW_CLIENTS) + self:SetTrigger(true) + self:SetMoveType(0) + self:SetNoDraw(true) + + if spawn == nil or spawn == true then + self:Spawn() + end + + self:SetTrigger(true) + self:SetCollisionBounds(mins, maxs) + self:UseTriggerBounds(true) + + end + + function ENT:ResizeTriggerBox(mins, maxs) + + self:SetTrigger(true) + self:SetCollisionBounds(mins, maxs) + self:UseTriggerBounds(true) + + end + + function ENT:Enable() + DbgPrint(self, "ENT:Enable") + + -- This is a lame workaround but sadly theres no binding to invalidate touch links. + -- To explain this scenario: + -- NPC walks in into a trigger, its currently Disabled. + -- The npc will stop calling Touch once it stops moving unlike players. + -- NPC now presses a button that enables the trigger but it wont fire StartTouch/Touch as the NPC is not moving after. + -- So we have to do this: + -- 8/6/2016: FIX -- Delay by a frame it can cause recursion, happens if two triggers disable/enable each other constantly. + -- apparanetly its also done in Source SDK. + util.RunNextFrame(function() + if not IsValid(self) then + return + end + + self:SetNWVar("Disabled", false) + + if not self:IsEFlagSet(EFL_CHECK_UNTOUCH) then + self:AddEFlags(EFL_CHECK_UNTOUCH) + end + + for k,v in pairs(self.DisabledTouchingObjects) do + if IsValid(Entity(k)) then + self:StartTouch(Entity(k)) + self:Touch(Entity(k)) + end + end + + self.DisabledTouchingObjects = {} + end) + end + + function ENT:Disable() + DbgPrint(self, "ENT:Disable") + --self:RemoveSolidFlags(FSOLID_TRIGGER) + self:SetNWVar("Disabled", true) + self:RemoveEFlags(EFL_CHECK_UNTOUCH) + + self.DisabledTouchingObjects = self.TouchingObjects or {} + end + + function ENT:Toggle() + DbgPrint(self, "ENT:Toggle") + if self:GetNWVar("Disabled") == false then + self:Disable() + else + self:Enable() + end + end + + function ENT:OnRemove() + -- Only send the info if really needed. + self.TeamInside = false + self.IsWaiting = false + self.NextTimeout = 0 + self.DisabledTouchingObjects = {} + self.TouchingObjects = {} + + self:FullPlayerUpdate() + end + + function ENT:SetWaitTime(waitTime) + --self.WaitTime = tonumber(waitTime or -1) + self:KeyValue("wait", tostring(waitTime)) + end + + function ENT:SetBlocked(blocked) + if blocked == true then + self:SetKeyValue("blocked", "1") + else + self:SetKeyValue("blocked", "0") + end + end + + function ENT:IsBlocked() + + return self:GetNWVar("Blocked", false) + + end + + function ENT:Think() + + local playersInside = 0 + + self.DisabledTouchingObjects = self.DisabledTouchingObjects or {} + for id,v in pairs(self.DisabledTouchingObjects) do + local ent = Entity(id) + if not IsValid(ent) then + self.DisabledTouchingObjects[id] = nil + end + end + + self.TouchingObjects = self.TouchingObjects or {} + for id,v in pairs(self.TouchingObjects) do + + local ent = Entity(id) + if not IsValid(ent) then + self.TouchingObjects[id] = nil + continue + end + + if ent:IsPlayer() then + if ent:Alive() == true then + playersInside = playersInside + 1 + else + self.TouchingObjects[id] = nil + continue + end + end + end + + if self:GetNWVar("WaitForTeam") == true then + + local playersAlive = 0 + for _,v in pairs(player.GetAll()) do + if v:Alive() then + playersAlive = playersAlive + 1 + end + end + + if playersInside >= playersAlive then + self.TeamInside = true + elseif playersInside < playersAlive then + self.TeamInside = false + end + + if playersInside > 0 then + if self:GetNWVar("Disabled") == false then + + -- HACKHACK: Sometimes the player slips thru the trigger so it stops calling Touch. + if CurTime() - self.LastTouch >= 0.2 then + DbgPrint("Enforcing Touch") + self:Touch(nil) + end + + if self.IsWaiting == false and playersInside > 0 then + if self:GetNWVar("Timeout", 0) > 0 then + DbgPrint("Setting next timeout") + self.NextTimeout = GetSyncedTimestamp() + self:GetNWVar("Timeout", 0) + else + DbgPrint("No timeout set") + end + self.IsWaiting = true + self:CmdShowTeamWaiting(nil, true, self.NextTimeout) + self:CmdPlayerCount(nil) + elseif self.IsWaiting == true and playersInside == 0 then + self.IsWaiting = false + self:CmdShowTeamWaiting(nil, false, 0) + self.NextTimeout = 0 + end + else + --DbgPrint(self, "Logic disabled!") + end + else + if self.IsWaiting == true then + self.IsWaiting = false + self:CmdShowTeamWaiting(nil, false, 0) + self.NextTimeout = 0 + end + end + end + + end + + -- This is basically OnTriggerEvents + function ENT:Touch(ent) + + --DbgPrint(self, "Touch") + self.LastTouch = CurTime() + + local waitTime = self:GetNWVar("WaitTime") + + DbgPrint(self, "Touch(" .. tostring(ent) .. ") -> flags: " .. tostring(self:GetSpawnFlags()) .. ", wait: " .. waitTime) + + if self:GetNWVar("Disabled") == true or self:GetNWVar("Blocked") == true then + --DbgPrint("Disabled") + return + end + + if self.NextWait ~= nil and self.NextWait ~= 0 then + if CurTime() < self.NextWait then + return + end + self.NextWait = nil + end + + if ent and self.PassesTriggerFilters and self:PassesTriggerFilters(ent) == false then + --DbgPrint(self, "Object " .. tostring(ent) .. " did not pass trigger filter") + return + end + + --DbgPrint(self, "Touch(" .. tostring(ent) .. ") -> flags: " .. tostring(self:GetSpawnFlags()) .. ", wait: " .. tostring(self.WaitTime)) + --DbgPrint(self, "OnTriggerEvents: " .. #self.OnTriggerEvents) + if self:GetNWVar("WaitForTeam") == true then + --DbgPrint("Waiting") + if self.TeamInside == false then + local timeout = self:GetNWVar("Timeout", 0) + if timeout == 0 then + --DbgPrint("timeout is 0!") + return + elseif timeout > 0 and self.NextTimeout == 0 then + return + elseif self.NextTimeout > 0 and GetSyncedTimestamp() < self.NextTimeout then + return + end + else + self.IsWaiting = false + end + end + + local n = table.Count(self.OutputTable["OnTrigger"] or {}) + self:FireOutputs("OnTrigger", nil, ent) + + if self.OnTrigger ~= nil then + self.OnTrigger(self, ent) + end + + if waitTime < 0 then + self:Disable() + self:Remove() + else + self.NextWait = CurTime() + waitTime + end + + end + + function ENT:StartTouch(ent) + + --DbgPrint(self, "StartTouch(" .. tostring(ent) .. ")") + + local entIndex = ent:EntIndex() + + if self:GetNWVar("Disabled") == true then + if self.DisabledTouchingObjects[entIndex] == nil then + self.DisabledTouchingObjects[entIndex] = true + end + return + end + + if self:PassesTriggerFilters(ent) == false then + --DbgPrint("Object " .. tostring(ent) .. " did not pass trigger filter") + return + end + + if self:GetNWVar("Blocked") == true and ent:IsPlayer() then + + local dir = self:OBBCenter() - ent:GetPos() + local ang = dir:Angle() + local force = 1400 + if ent:IsOnGround() == false then + force = 200 + end + local vel = -ang:Forward() * force + vel.z = 0 + ent:SetVelocity(vel) + + return + end + + if self.OnStartTouch ~= nil and isfunction(self.OnStartTouch) then + self:OnStartTouch(ent) + end + + self.TouchingObjects = self.TouchingObjects or {} -- This is called before Initialize? + if self.TouchingObjects[entIndex] == nil then + + self.TouchingObjects[entIndex] = true + + if ent:IsPlayer() and self:GetNWVar("LockPlayers") == true --[[ self.LockPlayers ]] then + DbgPrint(self, "StartTouch: Locking player " .. tostring(ent)) + ent:LockPosition(true) + end + + local waitForTeam = self:GetNWVar("WaitForTeam") + --local disabled = self:GetNWVar("Disabled") + --DbgPrint("WaitForTeam: " .. tostring(waitForTeam), "Disabled: " .. tostring(disabled)) + + if waitForTeam == false or (waitForTeam == true and self.TeamInside == true) then + DbgPrint(self, CurTime() .. ", OnStartTouch") + self:FireOutputs("OnStartTouch", nil, ent) + end + + if table.Count(self.TouchingObjects) == 1 then + DbgPrint(self, CurTime() .. ", OnStartTouchAll") + self:FireOutputs("OnStartTouchAll", nil, ent) + end + + end + + if self.IsWaiting == true then + self:CmdPlayerCount(nil) + end + + end + + function ENT:EndTouch(ent) + + local entIndex = ent:EntIndex() + + if self.DisabledTouchingObjects[entIndex] ~= nil then + self.DisabledTouchingObjects[entIndex] = nil + end + + if self:GetNWVar("DisableEndTouch") ~= true then + + self.TouchingObjects = self.TouchingObjects or {} -- Seems this is called before Initialize in some cases. + if self.TouchingObjects[entIndex] ~= nil then + + self.TouchingObjects[entIndex] = nil + + local waitForTeam = self:GetNWVar("WaitForTeam") + if waitForTeam == false or (waitForTeam and self.TeamInside == true) then + self:FireOutputs("OnEndTouch", nil, ent) + if self.OnEndTouch ~= nil then + self:OnEndTouch(ent) + end + end + + if table.Count(self.TouchingObjects) == 0 then + if self.OnEndTouchAll then + self:OnEndTouchAll() + end + + self:FireOutputs("OnEndTouchAll", nil, ent) + end + end + + if self.IsWaiting == true then + self:CmdPlayerCount(nil) + end + end + + end + + function ENT:IsPlayerTouching(ply) + + local plyId = ply:EntIndex() + return self.TouchingObjects[plyId] ~= nil + + end + + function ENT:GetTouchingObjects() + + -- Instead of our internal data we return it a list of entities. + local touching = {} + + for entId,_ in pairs(self.TouchingObjects) do + local ent = Entity(entId) + if IsValid(ent) then + table.insert(touching, ent) + else + -- Lets clean it up + self.TouchingObjects[entId] = nil + end + end + + return touching + + end + + function ENT:PassesTriggerFilters(ent) + + if self:HasSpawnFlags(SF_TRIGGER_ALLOW_ALL) or + (self:HasSpawnFlags(SF_TRIGGER_ALLOW_CLIENTS) and ent:IsPlayer()) or + (self:HasSpawnFlags(SF_TRIGGER_ALLOW_NPCS) and ent:IsNPC()) or + (self:HasSpawnFlags(SF_TRIGGER_ALLOW_PUSHABLES) and ent:GetClass() == "func_pushable") or + (self:HasSpawnFlags(SF_TRIGGER_ALLOW_PHYSICS) and ent:GetMoveType() == MOVETYPE_VPHYSICS) + then + + if ent:IsNPC() then + + if self:HasSpawnFlags(SF_TRIGGER_ONLY_PLAYER_ALLY_NPCS) and IsFriendEntityName(ent:GetClass()) == false then + return false + end + + if self:HasSpawnFlags(SF_TRIGGER_ONLY_NPCS_IN_VEHICLES) then + + -- TODO: There is no way to tell if a NPC is inside a vehicle, figure out if we can obtain it via savetable. + + end + + end + + if self:HasSpawnFlags(SF_TRIGGER_ONLY_CLIENTS_IN_VEHICLES) and ent:IsPlayer() then + + if ent:InVehicle() == false then + --DbgPrint("Client must be in vehicle") + return false + end + + end + + if self:HasSpawnFlags(SF_TRIGGER_ONLY_CLIENTS_OUT_OF_VEHICLES) and ent:IsPlayer() then + + if ent:InVehicle() == true then + --DbgPrint("Client must be not in vehicle") + return false + end + + end + + local filterName = self:GetNWVar("FilterName") + if filterName ~= nil and filterName ~= "" then + + local filter = ents.FindFirstByName(filterName) + if IsValid(filter) and filter.PassesFilter then + --DbgPrint("Using filter: " .. self.Filter .. " ( " .. tostring(filter) .. ") -> " .. tostring(ent)) + local res = filter:PassesFilter(self, ent) + --DbgPrint("Result: " .. tostring(res)) + return res + end + + end + + return true + + end + + return false + + end + + function ENT:CmdPlayerCount(ply) + + if self:GetNWVar("ShowWait") == false then + return + end + + ply = ply or player.GetHumans() + + local playerCount = 0 + local players = {} + + for entId, _ in pairs(self.TouchingObjects) do + local ent = Entity(entId) + if IsValid(ent) and ent:IsPlayer() then + playerCount = playerCount + 1 + table.insert(players, entId) + end + end + + net.Start("LambdaTriggerUpdate") + net.WriteUInt(self:EntIndex(), 13) + net.WriteUInt(TRIGGER_MSG_PLAYER_COUNT, 4) + net.WriteUInt(playerCount, 8) + for _,v in pairs(players) do + if v >= 255 then + ErrorNoHalt("CRITICAL ERROR: Player entIndex > 255") + end + net.WriteUInt(v, 8) + end + + net.Send(ply) + + end + + function ENT:CmdShowTeamWaiting(ply, state, timeout) + + DbgPrint(self, "Sending trigger update: ", state, timeout) + + ply = ply or player.GetAll() + + net.Start("LambdaTriggerUpdate") + net.WriteUInt(self:EntIndex(), 13) + net.WriteUInt(TRIGGER_MSG_SHOWWAIT, 4) + net.WriteBool(state) + if state == true then + net.WriteFloat(timeout) + net.WriteVector(self:GetPos()) + net.WriteVector(self:OBBCenter()) + net.WriteVector(self:OBBMins()) + net.WriteVector(self:OBBMaxs()) + end + net.Send(ply) + + end + + function ENT:CmdSetBlocked(ply) + + local blocked = self:GetNWVar("Blocked") + + DbgPrint(self, "Sending trigger blocked: ", blocked) + + ply = ply or player.GetHumans() + + net.Start("LambdaTriggerUpdate") + net.WriteUInt(self:EntIndex(), 13) + net.WriteUInt(TRIGGER_MSG_SETBLOCKED, 4) + net.WriteBool(blocked) + + if blocked == true then + local phys = self:GetPhysicsObject() + if IsValid(phys) then + local mesh = phys:GetMesh() + net.WriteTable(mesh) + else + DbgError(self, "No valid phys object while blocking!") + net.WriteTable({}) + end + net.WriteVector(self:GetPos()) + net.WriteVector(self:OBBCenter()) + end + + net.Send(ply) + + end + + function ENT:CmdTriggerRemoved() + + -- Wipe it from the table on the client, he doesnt need to do anything anymore. + net.Start("LambdaTriggerUpdate") + net.WriteUInt(self:EntIndex(), 13) + net.WriteUInt(TRIGGER_MSG_REMOVED, 4) + net.Broadcast() + + end + + function ENT:FullPlayerUpdate(ply) + + DbgPrint("Sending full update for trigger") + + self:CmdShowTeamWaiting(ply, self.IsWaiting, self.NextTimeout) + self:CmdPlayerCount(ply) + self:CmdSetBlocked(ply) + + end + + +else -- CLIENT + + LAMBDA_TRIGGERS = LAMBDA_TRIGGERS or {} + + local function CmdShowTeamWaiting(entIndex) + + LAMBDA_TRIGGERS[entIndex] = LAMBDA_TRIGGERS[entIndex] or {} + + local state = net.ReadBool() + if state == true then + + local timeout = net.ReadFloat() + local pos = net.ReadVector() + local center = net.ReadVector() + local obbMins = net.ReadVector() + local obbMaxs = net.ReadVector() + + DbgPrint(self, "Trigger(" .. entIndex .. ") waiting for team, timeout: " .. timeout) + + LAMBDA_TRIGGERS[entIndex].Timeout = timeout + LAMBDA_TRIGGERS[entIndex].Pos = pos + LAMBDA_TRIGGERS[entIndex].Center = center + LAMBDA_TRIGGERS[entIndex].Mins = obbMins + LAMBDA_TRIGGERS[entIndex].Maxs = obbMaxs + LAMBDA_TRIGGERS[entIndex].PlayerCount = 0 + LAMBDA_TRIGGERS[entIndex].ActivePlayers = {} + LAMBDA_TRIGGERS[entIndex].Waiting = true + + else + + --DbgPrint("Trigger(" .. entIndex .. ") no longer waiting for team") + LAMBDA_TRIGGERS[entIndex].Waiting = false + + end + + end + + local function CmdPlayerCount(entIndex) + + local count = net.ReadUInt(8) + + DbgPrint("Trigger(" .. entIndex .. ") new player count: " .. count) + + if LAMBDA_TRIGGERS[entIndex] == nil then + DbgError("Unknown trigger, we can not update information: " .. entIndex) + return + end + + LAMBDA_TRIGGERS[entIndex].PlayerCount = count + LAMBDA_TRIGGERS[entIndex].ActivePlayers = {} + + for i = 1, count do + local plyIndex = net.ReadUInt(8) + table.insert(LAMBDA_TRIGGERS[entIndex].ActivePlayers, plyIndex) + end + + end + + local function CmdSetBlocked(entIndex) + + DbgPrint("Received trigger block update") + + LAMBDA_TRIGGERS[entIndex] = LAMBDA_TRIGGERS[entIndex] or {} + + local state = net.ReadBool() + if state == true then + local mesh = net.ReadTable() + local pos = net.ReadVector() + local center = net.ReadVector() + LAMBDA_TRIGGERS[entIndex].MeshData = mesh + LAMBDA_TRIGGERS[entIndex].Pos = pos + LAMBDA_TRIGGERS[entIndex].Center = center + DbgPrint("Trigger(" .. entIndex .. ") now blocked") + else + -- What shall we do about this? + DbgPrint("Trigger(" .. entIndex .. ") now unblocked") + end + + LAMBDA_TRIGGERS[entIndex].Blocked = state + + end + + net.Receive("LambdaTriggerUpdate", function(len) + + local entIndex = net.ReadUInt(13) + local msg = net.ReadUInt(4) + + if msg == TRIGGER_MSG_SHOWWAIT then + CmdShowTeamWaiting(entIndex) + elseif msg == TRIGGER_MSG_PLAYER_COUNT then + CmdPlayerCount(entIndex) + elseif msg == TRIGGER_MSG_SETBLOCKED then + CmdSetBlocked(entIndex) + elseif msg == TRIGGER_MSG_REMOVED then + LAMBDA_TRIGGERS[entIndex] = nil + end + + end) + + local MAT_POINTER = Material( "lambda/trigger.png" ) + + surface.CreateFont( "LAMBDA_1", + { + font = "Arial", + size = 33, + weight = 600, + blursize = 10, + scanlines = 0, + antialias = true, + underline = false, + italic = false, + strikeout = false, + symbol = false, + rotary = false, + shadow = true, + additive = false, + outline = true, + } ) + + surface.CreateFont( "LAMBDA_2", + { + font = "Arial", + size = 33, + weight = 600, + blursize = 0, + scanlines = 0, + antialias = true, + underline = false, + italic = false, + strikeout = false, + symbol = false, + rotary = false, + shadow = false, + additive = false, + outline = false, + } ) + + local function DrawTriggerWaiting(activePlayers, scheduledTime, pos, ang, obbMins, obbMaxs, realPos) + + local playerCount = 0 + local activePlayerCount = #activePlayers + + --print(scheduledTime) + + for _,v in pairs(player.GetAll()) do + if v:Alive() then + playerCount = playerCount + 1 + end + end + + local ply = LocalPlayer() + -- TODO: Expirement with clamping the position within the trigger box. + --pos = ply:GetEyeTrace().HitPos + local eyePos = ply:EyePos() + local eyeAngles = EyeAngles() --ply:EyeAngles() + + local distance = eyePos:Distance(pos) + local localView = false + local allowLocalView = true -- TODO: Make this a setting. + + local showRunner = true + if distance < 50 then + localView = true + end + + local distanceScale = distance * 0.0008 + + if allowLocalView and table.HasValue(activePlayers, ply:EntIndex()) then + --pos = eyePos + (eyeAngles:Forward() * 90) + --distanceScale = 0.1 + local plyPos = ply:GetPos() + if plyPos:WithinAABox(realPos + (obbMins * 5), realPos + (obbMaxs * 5)) == true then + localView = true + end + end + + if localView == true then + local tr = ply:GetEyeTrace() + local hitDistance = eyePos:Distance(tr.HitPos) + local fwdDistance = 50 + if hitDistance < fwdDistance then + fwdDistance = hitDistance + end + if ply:InVehicle() then + if fwdDistance < 200 then + fwdDistance = 200 + end + else + if fwdDistance < 30 then + fwdDistance = 30 + end + end + pos = eyePos + (eyeAngles:Forward() * fwdDistance) + showRunner = false + end + + distanceScale = math.Clamp(distanceScale, 0.05, 5.5) + + local w,h = 0,0 + local text = "" + local remaining = scheduledTime - GetSyncedTimestamp() + if remaining < 0 then + remaining = 0 + end + + local bounce = math.sin(CurTime() * 5) + math.cos(CurTime() * 5) + pos = pos + (Vector(0, 0, 1) * bounce) + + local diff = pos - eyePos + ang = diff:Angle() + + ang:RotateAroundAxis(ang:Up(), 90) + ang:RotateAroundAxis(ang:Forward(), 90) + + --DbgPrint(distanceScale) + + local mat1 = Matrix() + mat1:SetTranslation( pos ) + mat1:Scale( Vector(1, 1, 1) * distanceScale ) + mat1:SetTranslation( pos ) + mat1:SetAngles(ang) + mat1:Rotate(Angle(0, 180, 0)) + mat1:SetTranslation( pos ) + + diff = pos - eyePos + ang = diff:Angle() + + ang:RotateAroundAxis(ang:Up(), 45) + ang:RotateAroundAxis(ang:Forward(), 180) + + cam.IgnoreZ(true) + cam.Start3D2D(pos, Angle(0,0,0), 0.1) + cam.PushModelMatrix(mat1) + + pcall(function() + surface.SetFont("LAMBDA_2") + + local textY = 0 + local spacing = 10 + + text = "Waiting for players: " .. tostring(activePlayerCount) .. " / " .. tostring(playerCount) + draw.DrawText( text, "LAMBDA_1", 0, textY, Color( 10, 10, 10 ), TEXT_ALIGN_CENTER ) + draw.DrawText( text, "LAMBDA_2", 0, textY, Color( 200, 200, 200 ), TEXT_ALIGN_CENTER ) + w,h = surface.GetTextSize( text ) + textY = textY + h + spacing + + text = "Game will continue once all players are here" + draw.DrawText( text, "LAMBDA_1", 0, textY, Color( 10, 10, 10 ), TEXT_ALIGN_CENTER ) + draw.DrawText( text, "LAMBDA_2", 0, textY, Color( 200, 200, 200 ), TEXT_ALIGN_CENTER ) + textY = textY + h + spacing + + if scheduledTime > 0 then + + text = "Timeout in " .. string.format("%.02f", remaining) .. " seconds" + + draw.DrawText( text, "LAMBDA_1", 0, textY, Color( 10, 10, 10 ), TEXT_ALIGN_CENTER ) + draw.DrawText( text, "LAMBDA_2", 0, textY, Color( 200, 200, 200 ), TEXT_ALIGN_CENTER ) + textY = textY + h + spacing + + end + + if showRunner == true then + surface.SetDrawColor( 255, 255, 255, 200 ) + surface.SetMaterial( MAT_POINTER ) + surface.DrawTexturedRect( -30, textY + 30 + (-bounce * 10), 60, 60 ) + end + end) + + cam.PopModelMatrix() + + cam.End3D2D() + cam.IgnoreZ(false) + + end + + local MAT_BLOCKED = Material("lambda/blocked.png") + + local function DrawTriggerBlockade(data) + + --DbgPrint("Drawing mesh") + local mesh = data.Mesh + + if mesh == nil then + DbgPrint("Creating new mesh") + mesh = Mesh(MAT_BLOCKED) + + local meshData = table.Copy(data.MeshData) + for k,v in pairs(meshData) do + meshData[k].v = v.pos.z * 0.005 + meshData[k].u = v.pos.y * 0.005 + end + + mesh:BuildFromTriangles(meshData) + data.Mesh = mesh + end + + --render.SuppressEngineLighting(true) + render.SetMaterial(MAT_BLOCKED) + + mesh:Draw() + --render.SuppressEngineLighting(false) + + end + + hook.Add("PostDrawTranslucentRenderables", "LambdaTrigger", function() + + for k, data in pairs(LAMBDA_TRIGGERS) do + + if data.Blocked == true then + DrawTriggerBlockade(data) + elseif data.Waiting == true then + DrawTriggerWaiting(data.ActivePlayers, data.Timeout, data.Pos + data.Center, Angle(0, 0, 0), data.Pos, data.Mins, data.Maxs) + end + + end + + end) + +end diff --git a/entities/entities/lambda_vehicle_tracker.lua b/entities/entities/lambda_vehicle_tracker.lua new file mode 100644 index 00000000..0b359af5 --- /dev/null +++ b/entities/entities/lambda_vehicle_tracker.lua @@ -0,0 +1,197 @@ +local DbgPrint = GetLogging("Vehicle") + +AddCSLuaFile() + +ENT.Base = "base_anim" +ENT.Type = "anim" +ENT.RenderGroup = RENDERGROUP_OPAQUE + +function ENT:Initialize() + if CLIENT then + -- I know this seems insane but otherwise it would clip the purpose. + self:SetRenderBounds(Vector(-10000, -10000, -10000), Vector(10000, 10000, 10000)) + + hook.Add("PostDrawTranslucentRenderables", self, function(ent, bDrawingDepth, bDrawingSkybox) + if bDrawingDepth == true or bDrawingSkybox == true then + return + end + ent:RenderVehicleStatus() + end) + end + self:DrawShadow(false) + self:AddEffects(EF_NODRAW) +end + +function ENT:AttachToVehicle(vehicle) + self:SetModel(vehicle:GetModel()) + self:SetPos(vehicle:GetPos()) + self:SetAngles(vehicle:GetAngles()) + self:SetParent(vehicle) + self:AddEffects(EF_NODRAW) + self:DrawShadow(false) + + self.Vehicle = vehicle + self.Player = vehicle.LambdaPlayer + self:SetNW2Entity("LambdaVehicleOwner", self.Player) + self:SetNW2Bool("LambdaVehicleTaken", IsValid(self.Player)) + +end + +function ENT:UpdateTransmitState() + return TRANSMIT_ALWAYS +end + +if SERVER then + + function ENT:Think() + + local vehicle = self:GetParent() + if not IsValid(vehicle) then + self:Remove() + return + end + + if self.Player ~= vehicle.LambdaPlayer then + self.Player = vehicle.LambdaPlayer + self:SetNW2Entity("LambdaVehicleOwner", self.Player) + self:SetNW2Bool("LambdaVehicleTaken", IsValid(self.Player)) + DbgPrint("Owner changed") + end + + self:NextThink(CurTime() + 0.1) + return true + end + +elseif CLIENT then + + local pixVis = util.GetPixelVisibleHandle() + local font = "DermaLarge" + local pad = 2 + local health_w = 100 + local health_h = 5 + local aux_w = 100 + local aux_h = 5 + + local function IsVehicleVisible(vehicle) + + local localPly = LocalPlayer() + if localPly:IsLineOfSightClear(vehicle:EyePos()) then + return true + end + + local visibility = util.PixelVisible(vehicle:GetPos(), 0, pixVis) + return visibility > 0 + + end + + local function IsVehicleBehind(vehicle) + + local dir = (vehicle:GetPos() - EyePos()):GetNormal() + local dot = dir:Dot(EyeAngles():Forward()) + if dot < 0 then + return true + end + return false + + end + + local VEHICLE_MAT = Material("lambda/vehicle.png") + + function ENT:RenderVehicleStatus() + + local vehicle = self:GetParent() + if not IsValid(vehicle) then + return + end + + -- We could do this but its rather ugly. + --[[ + if IsVehicleVisible(vehicle) == false then + cam.IgnoreZ(true) + vehicle:DrawModel() + cam.IgnoreZ(false) + end + ]] + + local pos = self:GetPos() + self:OBBCenter() + Vector(0, 0, 50) + local localPly = LocalPlayer() + + if IsVehicleBehind(vehicle) then + -- Dont bother + return + end + + local ownedVehicle = localPly:GetNW2Entity("LambdaOwnedVehicle") + --DbgPrint("Owned: " .. tostring(ownedVehicle)) + local isTaken = self:GetNW2Bool("LambdaVehicleTaken") + local vehiclePly = self:GetNW2Entity("LambdaVehicleOwner") + local displayIcon = false + + + if isTaken == false then + displayIcon = true + else + if localPly:GetVehicle() ~= vehicle and vehiclePly == localPly then + displayIcon = true + end + end + + if (ownedVehicle ~= nil and ownedVehicle ~= NULL) and ownedVehicle ~= vehicle then + displayIcon = false + end + + if displayIcon == true then + + local eyePos = EyePos() + local distance = eyePos:Distance(pos) + local distanceScale = distance * 0.0008 + distanceScale = math.Clamp(distanceScale, 0.25, 5.5) + + local bounce = math.sin(CurTime() * 5) + math.cos(CurTime() * 5) + pos = pos + (Vector(0, 0, 1) * bounce) + + local diff = pos - eyePos + ang = diff:Angle() + + ang:RotateAroundAxis(ang:Up(), 90) + ang:RotateAroundAxis(ang:Forward(), 90) + + pos = pos + (Vector(0, 0, 60) * distanceScale) + + local mat1 = Matrix() + mat1:SetTranslation( pos ) + mat1:Scale( Vector(1, 1, 1) * distanceScale ) + mat1:SetTranslation( pos ) + mat1:SetAngles(ang) + mat1:Rotate(Angle(0, 180, 0)) + mat1:SetTranslation( pos ) + + diff = pos - eyePos + ang = diff:Angle() + + ang:RotateAroundAxis(ang:Up(), 45) + ang:RotateAroundAxis(ang:Forward(), 180) + + cam.IgnoreZ(true) + cam.Start3D2D(pos, Angle(0,0,0), 0.1) + + cam.PushModelMatrix(mat1) + surface.SetDrawColor( 255, 255, 255, 200 ) + surface.SetMaterial( VEHICLE_MAT ) + surface.DrawTexturedRect( -32, 0 + (-bounce * 10), 60, 60 ) + cam.PopModelMatrix() + + cam.End3D2D() + cam.IgnoreZ(false) + + end + + end + + function ENT:Draw() + end + + function ENT:DrawTranslucent() + end + +end diff --git a/entities/entities/npc_maker.lua b/entities/entities/npc_maker.lua new file mode 100644 index 00000000..237c572c --- /dev/null +++ b/entities/entities/npc_maker.lua @@ -0,0 +1,132 @@ +local DbgPrint = GetLogging("NPC") + +if SERVER then + + ENT.Base = "lambda_npcmaker" + ENT.Type = "point" + + DEFINE_BASECLASS( "lambda_npcmaker" ) + + function ENT:PreInitialize() + + DbgPrint(self, "ENT:PreInitialize") + + BaseClass.PreInitialize(self) + + self.NPCType = "" + self.NPCTargetname = "" + self.NPCSquadName = "" + self.AdditionalEquipment = "" + self.NPCHintGroup = "" + self.Relationship = "" + + end + + function ENT:Initialize() + + DbgPrint(self, "ENT:Initialize") + + BaseClass.Initialize(self) + + end + + function ENT:KeyValue(key, value) + + BaseClass.KeyValue(self, key, value) + + if key:iequals("NPCType") then + self.NPCType = value + elseif key:iequals("NPCTargetname") then + self.NPCTargetname = value + elseif key:iequals("NPCSquadName") then + self.NPCSquadName = value + elseif key:iequals("additionalequipment") then + self.AdditionalEquipment = value + elseif key:iequals("NPCHintGroup") then + self.NPCHintGroup = value + elseif key:iequals("Relationship") then + self.Relationship = value + end + end + + function ENT:MakeNPC() + + --DbgPrint(self, "ENT:MakeNPC") + + if self:CanMakeNPC() == false then + return + end + + DbgPrint("Creating NPC: " .. self.NPCType) + + local ent = ents.Create(self.NPCType) + if not IsValid(ent) then + --DbgPrint(self, "Unable to create NPC!") + return + end + + ent:SetKeyValue("Relationship", self.Relationship) + + local self = self + local ent = ent + + ent:SetPos(self:GetPos()) + + local ang = self:GetAngles() + ang.x = 0 + ang.z = 0 + + ent:SetAngles(ang) + + if self:HasSpawnFlags(SF_NPCMAKER_FADE) then + ent:AddSpawnFlags( SF_NPC_FADE_CORPSE ) + end + + ent:SetKeyValue("additionalequipment", self.AdditionalEquipment) + ent:SetKeyValue("squadname", self.NPCSquadName) + ent:SetKeyValue("hintgroup", self.NPCHintGroup) + + if self:HasSpawnFlags(SF_NPCMAKER_NO_DROP) == false then + ent:RemoveSpawnFlags(SF_NPC_FALL_TO_GROUND) + end + + self:ChildPreSpawn(ent) + + self:DispatchSpawn(ent) + ent:SetOwner(self) + self:DispatchActivate(ent) + + DbgPrint("Created NPC: " .. tostring(ent)) + + self:ChildPostSpawn(ent) + + ent:SetName(self.NPCTargetname) + + self:FireOutputs("OnSpawnNPC", ent, ent, self) + + self:SetNWVar("LiveChildren", self:GetNWVar("LiveChildren") + 1) + + if self:HasSpawnFlags(SF_NPCMAKER_INF_CHILD) == false then + + --self.MaxNPCCount = self.MaxNPCCount - 1 + --self.CreatedCount = self.CreatedCount + 1 + self:SetNWVar("CreatedCount", self:GetNWVar("CreatedCount") + 1) + + DbgPrint("Spawned npc, count: " .. self:GetNWVar("CreatedCount") .. " / " .. self:GetScaledMaxNPCs()) + + if self:IsDepleted() then + self:FireOutputs("OnAllSpawned", nil, self) + --self.Think = self.StubThink + end + + else + + DbgPrint("Infinite NPCs!") + + end + + self:UpdateScaling() + + end + +end diff --git a/entities/entities/npc_template_maker.lua b/entities/entities/npc_template_maker.lua new file mode 100644 index 00000000..7a16fd6a --- /dev/null +++ b/entities/entities/npc_template_maker.lua @@ -0,0 +1,583 @@ +local DbgPrint = GetLogging("NPC") + +if SERVER then + +AddCSLuaFile() + +DEFINE_BASECLASS( "lambda_npcmaker" ) + +ENT.Base = "lambda_npcmaker" +ENT.Type = "point" + +local TS_YN_YES = 0 +local TS_YN_NO = 1 +local TS_YN_DONT_CARE = 2 +local TS_DIST_NEAREST = 0 +local TS_DIST_FARTHEST = 1 +local TS_DIST_DONT_CARE = 2 + +function ENT:PreInitialize() + + DbgPrint(self, "ENT:PreInitialize") + + BaseClass.PreInitialize(self) + + self.TemplateName = "" + self.Radius = 256 + self.DestinationGroup = nil + self.CriterionVisibility = 0 + self.CriterionDistance = 0 + self.MinSpawnDistance = 0 + self.PrecacheData = nil + + self:SetupOutput("OnAllSpawned") + self:SetupOutput("OnAllSpawnedDead") + self:SetupOutput("OnAllLiveChildrenDead") + self:SetupOutput("OnSpawnNPC") + + self:SetInputFunction("SpawnNPCInRadius", self.MakeNPCInRadius ) + self:SetInputFunction("SpawnNPCInLine", self.MakeNPCInLine ) + self:SetInputFunction("SpawnMultiple", self.MakeMultipleNPCS ) + self:SetInputFunction("ChangeDestinationGroup", self.ChangeDestinationGroup ) + +end + +function ENT:KeyValue(key, val) + + BaseClass.KeyValue(self, key, val) + + if key:iequals("TemplateName") then + self.TemplateName = val + elseif key:iequals("Radius") then + self.Radius = tonumber(val) + elseif key:iequals("DestinationGroup") then + self.DestinationGroup = val + elseif key:iequals("CriterionVisibility") then + self.CriterionVisibility = tonumber(val) + elseif key:iequals("CriterionDistance") then + self.CriterionDistance = tonumber(val) + elseif key:iequals("MinSpawnDistance") then + self.MinSpawnDistance = tonumber(val) + end + +end + +function ENT:Precache() + + if self.PrecacheData ~= nil then + return + end + + if self.PrecacheData == nil then + self.PrecacheData = table.Copy(game.FindEntityInMapData(self.TemplateName)) + --[[ + local mapdata = game.GetMapData() + for _,ent in pairs(mapdata.Entities) do + if ent["targetname"] and tostring(ent["targetname"]):iequals(self.TemplateName) then + self.PrecacheData = ent + break + end + end + ]] + end + + if self.PrecacheData == nil then + --ErrorNoHalt("Unable to find npc template in map data, can not precache!") + return + end + + if self.PrecacheData["model"] then + util.PrecacheModel(self.PrecacheData["model"]) + end + +end + +function ENT:RemoveTemplateData(name) + + for k,_ in pairs(self.PrecacheData or {}) do + if k:iequals(name) then + self.PrecacheData[k] = nil + end + end + +end + +function ENT:AddTemplateData(key, val) + + self.PrecacheData[key] = val + +end + +function ENT:GetNPCClass() + + if self.PrecacheData then + return self.PrecacheData["classname"] + end + + return "" + +end + +function ENT:Initialize() + + DbgPrint(self, "ENT:Initialize") + + BaseClass.Initialize(self) + + self:Precache() + + -- NOTE: Should we add the flag only under specific circumstances? + --self:AddSpawnFlags(SF_NPCMAKER_HIDEFROMPLAYER) + + -- NOTE: Lets figure out a way that tells us if we could apply infinite childreen. + -- one way would be going per NPC type? + +end + +function ENT:FindSpawnDestination() + + local spawnDestinations = ents.FindByName(self.DestinationGroup) + local possible = {} + + if _DEBUG then + if table.Count(spawnDestinations) == 0 then + ErrorNoHalt("npc_template_maker has no spawn destinations") + return nil + end + end + + local vecPlayerCenter = Vector(0,0,0) + local centerDiv = 0 + for k,v in pairs(player.GetAll()) do + vecPlayerCenter = vecPlayerCenter + v:GetPos() + centerDiv = centerDiv + 1 + end + vecPlayerCenter = vecPlayerCenter / centerDiv + + for _, dest in pairs(spawnDestinations) do + + if dest.IsAvailable and dest:IsAvailable() then + + local valid = true + local destPos = dest:GetPos() + + if self.CriterionVisibility ~= TS_YN_DONT_CARE then + + local visible = false + for _, ply in pairs(player.GetAll()) do + if ply:VisibleVec(destPos) then + visible = true + break + end + end + + if self.CriterionVisibility == TS_YN_YES then + if not visible then + valid = false + end + else + if visible then + valid = false + end + end + end + + if valid then + table.insert(possible, dest) + end + + end + + end + + if table.Count(possible) < 1 then + return nil + end + + if self.CriterionDistance == TS_DIST_DONT_CARE then + + for i = 0, 5 do + local dest = table.Random(possible) + if self:HumanHullFits(dest:GetPos()) then + return dest + end + end + -- Porbably all positions are blocked. + return nil + + elseif self.CriterionDistance == TS_DIST_NEAREST then + + local nearestDist = 0 + local nearestDest = nil + + for _,dest in pairs(possible) do + + local destPos = dest:GetPos() + local dist = destPos:Distance(vecPlayerCenter) + + if nearestDist == 0 or dist < nearestDist then + if self:HumanHullFits(destPos) then + nearestDist = dist + nearestDest = dest + end + end + + end + + return nearestDest + + elseif self.CriterionDistance == TS_DIST_FARTHEST then + + local farthestDist = 0 + local farthestDest = nil + + for _,dest in pairs(possible) do + + local destPos = dest:GetPos() + local dist = destPos:Distance(vecPlayerCenter) + + if dist > farthestDist then + if self:HumanHullFits(destPos) then + farthestDist = dist + farthestDest = dest + end + end + + end + + return farthestDest + + end + + return nil + +end + +function ENT:MakeNPC() + + --DbgPrint(self, "ENT:MakeNPC") + + if self.Radius > 0 and self:HasSpawnFlags(SF_NPCMAKER_ALWAYSUSERADIUS) then + return self:MakeNPCInRadius() + end + + if self:CanMakeNPC( self.DestinationGroup ~= nil ) == false then + return + end + + local dest = nil + + if self.DestinationGroup ~= nil then + + dest = self:FindSpawnDestination() + if dest == nil then + DbgPrint(self, "Failed to find valid spawnpoint in destination group: " .. self.DestinationGroup) + return + end + + end + + self:Precache() + + local ent = ents.CreateFromData(self.PrecacheData) + if not IsValid(ent) then + --DbgPrint(self, "Unable to create NPC!") + return + end + + local destObj = nil + + if dest == nil then + dest = self + else + destObj = dest + end + + ent:SetPos(dest:GetPos()) + + local ang = dest:GetAngles() + ang.x = 0 + ang.z = 0 + + ent:SetAngles(ang) + + if IsValid(destObj) and destObj.OnSpawnNPC then + --DbgPrint("Firing OnSpawnNPC in info_npc_spawn_destination") + destObj:OnSpawnNPC() + end + + if self:HasSpawnFlags(SF_NPCMAKER_FADE) then + ent:AddSpawnFlags( SF_NPC_FADE_CORPSE ) + end + + ent:RemoveSpawnFlags( SF_NPC_TEMPLATE ) + + if self:HasSpawnFlags(SF_NPCMAKER_NO_DROP) == false then + ent:RemoveSpawnFlags(SF_NPC_FALL_TO_GROUND) + end + + self:ChildPreSpawn(ent) + self:DispatchSpawn(ent) + ent:SetOwner(self) + self:DispatchActivate(ent) + self:ChildPostSpawn(ent) + + self:FireOutputs("OnSpawnNPC", ent, ent, self) + + --self.LiveChildren = self.LiveChildren + 1 + self:SetNWVar("LiveChildren", self:GetNWVar("LiveChildren") + 1) + + if self:HasSpawnFlags(SF_NPCMAKER_INF_CHILD) == false then + + --self.MaxNPCCount = self.MaxNPCCount - 1 + --self.CreatedCount = self.CreatedCount + 1 + self:SetNWVar("CreatedCount", self:GetNWVar("CreatedCount") + 1) + + DbgPrint("Spawned npc, count: " .. self:GetNWVar("CreatedCount") .. " / " .. self:GetScaledMaxNPCs()) + + if self:IsDepleted() then + self:FireOutputs("OnAllSpawned", nil, self) + self.Think = self.StubThink + end + + end + + self:UpdateScaling() + +end + +function ENT:PlaceNPCInRadius(npc, checkVisible) + + DbgPrint(self, "ENT:PlaceNPCInRadius") + + local pos = self:GetPos() + local radius = self.Radius + + local ang = Angle(0, 0, 0) + + local step = 360 / self:GetScaledMaxNPCs() + + local hullMins = npc:GetHullMins() + local hullMaxs = npc:GetHullMaxs() + + --DbgPrint("NPC Hull: " .. tostring(hullMins) .. ", " .. tostring(hullMaxs)) + --DbgPrint("NPC Hulltype: " .. tostring(npc:GetHullType())) + + for y = 0, 360, step do + + ang.y = y + + local dir = ang:Forward() + local testPos = pos + (dir * radius) + + if checkVisible == true and util.IsPosVisibleToPlayers(testPos) == true then + continue + end + + -- Check if they would fall. + local tr = util.TraceLine( + { + start = testPos, + endpos = testPos - Vector(0, 0, 8192), + filter = npc, + mask = MASK_SHOT, + }) + + if tr.Fraction == 1 then + continue + end + + -- See if they fit. + local hull = util.TraceHull( + { + start = tr.HitPos, + endpos = tr.HitPos + Vector(0, 0, 10), + mins = hullMins, + maxs = hullMaxs, + mask = MASK_NPCSOLID, + filter = npc, + }) + + --debugoverlay.Box(tr.HitPos, hullMins, hullMaxs, 999, Color(255, 255, 255)) + + if hull.Fraction == 1.0 then + + -- The SDK also checks the MoveProbe for stand position, we have no access. + npc:SetPos(hull.HitPos) + return true + + end + + end + + return false + +end + +function ENT:MakeNPCInRadius() + + DbgPrint(self, "ENT:MakeNPCInRadius") + + if not self:CanMakeNPC(true) then + return + end + + local ent = ents.CreateFromData(self.PrecacheData) + if not IsValid(ent) then + ErrorNoHalt("Unable to create npc!") + return + end + + if self:PlaceNPCInRadius(ent) == false then + DbgPrint("Failed to create NPC in radius: " .. tostring(ent)) + ent:Remove() + return + else + DbgPrint("Created NPC in radius: " .. tostring(ent)) + end + + ent:AddSpawnFlags(SF_NPC_FALL_TO_GROUND) + ent:RemoveSpawnFlags(SF_NPC_TEMPLATE) + + self:ChildPreSpawn(ent) + self:DispatchSpawn(ent) + ent:SetOwner(self) + self:DispatchActivate(ent) + self:ChildPostSpawn(ent) + + self:FireOutputs("OnSpawnNPC", ent, ent, self) + + self:SetNWVar("LiveChildren", self:GetNWVar("LiveChildren") + 1) + + if self:HasSpawnFlags(SF_NPCMAKER_INF_CHILD) == false then + + --self.MaxNPCCount = self.MaxNPCCount - 1 + --self.CreatedCount = self.CreatedCount + 1 + self:SetNWVar("CreatedCount", self:GetNWVar("CreatedCount") + 1) + + DbgPrint("Spawned npc, count: " .. self:GetNWVar("CreatedCount") .. " / " .. self:GetScaledMaxNPCs()) + + if self:IsDepleted() then + self:FireOutputs("OnAllSpawned", nil, self) + self.Think = self.StubThink + end + + end + + self:UpdateScaling() + +end + +function ENT:PlaceNPCInLine(npc) + + local fwd = self:GetForward() + fwd = fwd * -1 -- invert + + local tr = util.TraceLine({ + startpos = self:GetPos(), + endpos = self:GetPos() - Vector(0, 0, 8192), + mask = MASK_SHOT, + filter = npc, + }) + + local mins = npc:GetHullMins() + local maxs = npc:GetHullMaxs() + local hullWidth = maxs.y - mins.y + + local dest = tr.HitPos + for i = 0, 10 do + + local tr = util.TraceHull({ + start = dest, + endpos = dest + Vector(0, 0, 10), + mins = mins, + maxs = maxs, + filter = npc, + mask = MASK_SHOT, + }) + + if tr.Fraction == 1.0 then + npc:SetPos(tr.HitPos) + return true + end + + dest = dest + (fwd * hullWidth) + end + + return false + +end + +function ENT:MakeNPCInLine() + + DbgPrint(self, "ENT:MakeNPCInRadius") + + if not self:CanMakeNPC(true) then + return + end + + local ent = ents.CreateFromData(self.PrecacheData) + if not IsValid(ent) then + ErrorNoHalt("Unable to create npc!") + return + end + + if self:PlaceNPCInLine(ent) == false then + DbgPrint("Failed to create npc in line: " .. tostring(ent)) + ent:Remove() + return + else + DbgPrint("Created NPC in line: " .. tostring(ent)) + end + + ent:AddSpawnFlags(SF_NPC_FALL_TO_GROUND) + ent:RemoveSpawnFlags(SF_NPC_TEMPLATE) + + self:ChildPreSpawn(ent) + self:DispatchSpawn(ent) + ent:SetOwner(self) + self:DispatchActivate(ent) + self:ChildPostSpawn(ent) + + self:FireOutputs("OnSpawnNPC", ent, ent, self) + + self:SetNWVar("LiveChildren", self:GetNWVar("LiveChildren") + 1) + + if self:HasSpawnFlags(SF_NPCMAKER_INF_CHILD) == false then + + --self.MaxNPCCount = self.MaxNPCCount - 1 + --self.CreatedCount = self.CreatedCount + 1 + self:SetNWVar("CreatedCount", self:GetNWVar("CreatedCount") + 1) + + DbgPrint("Spawned npc, count: " .. self:GetNWVar("CreatedCount") .. " / " .. self:GetScaledMaxNPCs()) + + if self:IsDepleted() then + self:FireOutputs("OnAllSpawned", nil, self) + self.Think = self.StubThink + end + + end + + self:UpdateScaling() + +end + +function ENT:MakeMultipleNPCS() + + Error("MakeMultipleNPCS not implemented") + +end + +function ENT:ChangeDestinationGroup(data) + + --Error("ChangeDestinationGroup not implemented") + self.DestinationGroup = data -- ?? +end + +function ENT:SetMinimumSpawnDistance(data) + + Error("SetMinimumSpawnDistance not implemented") + +end + +end diff --git a/entities/entities/player_loadsaved.lua b/entities/entities/player_loadsaved.lua new file mode 100644 index 00000000..a859d443 --- /dev/null +++ b/entities/entities/player_loadsaved.lua @@ -0,0 +1,41 @@ +if SERVER then + +ENT.Base = "lambda_entity" +ENT.Type = "point" + +DEFINE_BASECLASS( "lambda_entity" ) + +function ENT:PreInitialize() + + BaseClass.PreInitialize(self) + self:SetInputFunction("Reload", self.InputReload) + +end + +function ENT:Initialize() + + BaseClass.Initialize(self) + +end + +function ENT:KeyValue(key, val) + + BaseClass.KeyValue(self, key, val) + +end + +function ENT:InputReload(data, activator, caller) + + GAMEMODE:RestartRound(nil, true) + + return true + +end + +function ENT:UpdateTransmitState() + + return TRANSMIT_NEVER + +end + +end diff --git a/entities/entities/player_speedmod.lua b/entities/entities/player_speedmod.lua new file mode 100644 index 00000000..a59faab7 --- /dev/null +++ b/entities/entities/player_speedmod.lua @@ -0,0 +1,27 @@ +--https://developer.valvesoftware.com/wiki/Player_speedmod +local DbgPrint = GetLogging("Trigger") + +ENT.Base = "base_point" +ENT.Type = "point" + +function ENT:Initialize() + DbgPrint("player_speedmod:Initialize") +end + +function ENT:AcceptInput(inputName, activator, called, data) + + DbgPrint("player_speedmod:AcceptInput(" .. tostring(inputName) .. ", " .. tostring(activator) .. ", " .. tostring(called) .. ", " .. tostring(data) .. ")") + + if inputName == "ModifySpeed" then + local speed = tonumber(data) + for _,v in pairs(player.GetAll()) do + v:Flashlight(false) + v:SetLaggedMovementValue(speed) + end + return true + else + DbgPrint("Unhandled input: " .. tostring(inputName)) + end + + return false +end diff --git a/entities/entities/point_teleport.lua b/entities/entities/point_teleport.lua new file mode 100644 index 00000000..4695ee66 --- /dev/null +++ b/entities/entities/point_teleport.lua @@ -0,0 +1,76 @@ +--local DbgPrint = print +-- REFACTOR ME: lambad_entity as base +local DbgPrint = GetLogging("Trigger") + +ENT.Base = "base_point" +ENT.Type = "point" + +function ENT:Initialize() + DbgPrint("point_teleport:Initialize") + self.Target = self.Target or "" + self.StackMode = self.StackMode or false + self.StackDir = self.StackDir or self:GetAngles():Forward() + self.StackLength = self.StackLength or 100 +end + +function ENT:AcceptInput(inputName, activator, called, data) + + DbgPrint("point_teleport:AcceptInput(" .. tostring(inputName) .. ", " .. tostring(activator) .. ", " .. tostring(called) .. ", " .. tostring(data) .. ")") + + if inputName == "Teleport" then + + -- We gonna teleport all players, kinda nasty work-around to replicate this entity type. + if self.Target == "!player" or self.Target == "!players" then + DbgPrint("[" .. self:GetName() .. "] Teleporting players") + for _,v in pairs(player.GetAll()) do + v:SetPos(self:GetPos()) + v:SetAngles(self:GetAngles()) + end + return true + else + -- We have to find them. + local entryPos = self:GetPos() + local teleportPos = entryPos + + for _,v in pairs(ents.FindByName(self.Target)) do + + DbgPrint("Teleporting target: " .. self.Target .. " to: " .. tostring(teleportPos)) + + v:SetPos(teleportPos) + v:SetAngles(self:GetAngles()) + + if self.StackMode == true then + DbgPrint("Using stack mode teleportation") + teleportPos = teleportPos + (self.StackDir * self.StackLength) + end + end + + return true + end + else + DbgPrint("Unhandled input: " .. tostring(inputName)) + end + + --return false +end + +function ENT:KeyValue( key, value ) + DbgPrint("point_teleport:KeyValue(" .. key .. ", " .. value .. ")") + + if key == "target" then + self.Target = value + elseif key == "stackmode" then + self.StackMode = tobool(value) + elseif key == "stackdir" then + self.StackDir = util.StringToType(value, "Vector") + elseif key == "stacklength" then + self.StackLength = tonumber(value) + end + +end + +function ENT:Think() +end + +function ENT:OnRemove() +end diff --git a/entities/entities/trigger_changelevel.lua b/entities/entities/trigger_changelevel.lua new file mode 100644 index 00000000..4b62eb6f --- /dev/null +++ b/entities/entities/trigger_changelevel.lua @@ -0,0 +1,87 @@ +local DbgPrint = GetLogging("Trigger") + +if SERVER then + +ENT.Base = "lambda_trigger" +ENT.Type = "brush" + +DEFINE_BASECLASS( "lambda_trigger" ) + +SF_CHANGELEVEL_NOTOUCH = 0x0002 +SF_CHANGELEVEL_CHAPTER = 0x0004 + +function ENT:PreInitialize() + + BaseClass.PreInitialize(self) + + self:SetInputFunction("ChangeLevel", self.OnTrigger) + + self.TargetMap = "" + self.Landmark = "" + self.DisableTouch = false + +end + +function ENT:Initialize() + + self:SetKeyValue("teamwait", "1") + self:SetKeyValue("timeout", lambda_map_change_timeout:GetInt()) + self:SetKeyValue("lockplayers", "1") + self:SetNWVar("DisableEndTouch", true) + + self:AddSpawnFlags(SF_TRIGGER_ALLOW_CLIENTS) + + BaseClass.Initialize(self) + BaseClass.SetWaitTime(self, -1) -- Remove once triggered. + + --[[ + if self:HasSpawnFlags(SF_CHANGELEVEL_NOTOUCH) == true then + DbgPrint(self, "Disabling because of SF_CHANGELEVEL_NOTOUCH") + self:Disable() + self.DisableTouch = true + end + ]] + +end + +function ENT:KeyValue( key, val ) + + BaseClass.KeyValue(self, key, val) + + if key:iequals("landmark") then + self.Landmark = val + elseif key:iequals("map") then + self.TargetMap = val + end + +end + +function ENT:EndTouch(ent) + if self:HasSpawnFlags(SF_CHANGELEVEL_NOTOUCH) == true then + return + end + return BaseClass.EndTouch(self, ent) +end + +function ENT:Touch(ent) + if self:HasSpawnFlags(SF_CHANGELEVEL_NOTOUCH) == true then + return + end + return BaseClass.Touch(self, ent) +end + +function ENT:StartTouch(ent) + if self:HasSpawnFlags(SF_CHANGELEVEL_NOTOUCH) == true then + return + end + return BaseClass.StartTouch(self, ent) +end + +function ENT:OnTrigger() + + DbgPrint("CHANGELEVEL") + GAMEMODE:ChangeLevel(string.lower(self.TargetMap), self.Landmark, self:GetTouchingObjects()) + +end + +end diff --git a/entities/entities/trigger_hurt.lua b/entities/entities/trigger_hurt.lua new file mode 100644 index 00000000..b6abe647 --- /dev/null +++ b/entities/entities/trigger_hurt.lua @@ -0,0 +1,356 @@ +local DbgPrint = GetLogging("Trigger") + +ENT.Base = "lambda_trigger" +ENT.Type = "brush" + +DEFINE_BASECLASS("lambda_trigger") + +DAMAGEMODEL_NORMAL = 0 +DAMAGEMODEL_DOUBLE_FORGIVENESS = 1 +TRIGGER_HURT_FORGIVE_TIME = 3.0 + +function ENT:HasDamageType(dmgtype) + return bit.band(self.DamageType, DMG_RADIATION) ~= 0 +end + +local THINKTYPE_NONE = 0 +local THINKTYPE_HURT = 1 +local THINKTYPE_RADIATION = 2 + +function ENT:PreInitialize() + + BaseClass.PreInitialize(self) + + self:SetupOutput("OnHurtPlayer") + self:SetupOutput("OnHurt") + + self.DamageType = 0 + self.Damage = 0 + self.DamageCap = 0 + self.DamageModel = 0 + self.NoDamageForce = false + self.DamageResetTime = 0 + self.WaitTime = 0.2 + self.ThinkType = THINKTYPE_NONE + +end + +function ENT:Initialize() + + BaseClass.Initialize(self) + + self.OriginalDamage = self.Damage + self.LastDamageTime = 0 + + self.ThinkType = THINKTYPE_NONE + + if self:HasDamageType(DMG_RADIATION) then + + self.ThinkType = THINKTYPE_RADIATION + + end + +end + +function ENT:KeyValue( key, val ) + + BaseClass.KeyValue(self, key, val) + + if key:iequals("damage") then + self.Damage = tonumber(val) + elseif key:iequals("damagecap") then + self.DamageCap = tonumber(val) + elseif key:iequals("damagetype") then + self.DamageType = tonumber(val) + elseif key:iequals("damagemodel") then + self.DamageModel = tonumber(val) + elseif key:iequals("nodmgforce") then + self.NoDamageForce = tobool(val) + end + +end + +function ENT:Think() + + BaseClass.Think(self) + + if self.ThinkType == THINKTYPE_HURT then + return self:HurtThink() + elseif self.ThinkType == THINKTYPE_RADIATION then + return self:RadiationThink() + end + +end + +function ENT:Touch(ent) + + if self.ThinkType == THINKTYPE_NONE then + self.ThinkType = THINKTYPE_HURT + end + + return BaseClass.Touch(self, ent) + +end + +function ENT:EndTouch(ent) + + if self:PassesTriggerFilters(ent) then + + self.HurtEntities = self.HurtEntities or {} + + if self.HurtEntities[ent] == nil then + self:HurtEntity(ent, self.Damage * 0.5 ) + end + + end + + return BaseClass.EndTouch(self, ent) + +end + +function ENT:HurtThink() + + if self:HurtTouchingObjects(0.5) <= 0 then + self.ThinkType = THINKTYPE_NONE + end + + self:NextThink(CurTime() + 0.5) + return true + +end + +function ENT:CalcDistanceFromPoint(vec) + + local nearestPoint = self:NearestPoint(vec) + return nearestPoint:Distance(vec) + +end + +function ENT:RadiationThink() + + for _,v in pairs(player.GetAll()) do + + local pos2 = v:GetPos() + + local nearestPoint = self:NearestPoint(pos2) + local range = nearestPoint:Distance(pos2) + + v:SetNearestRadiationRange(range * 3) + + end + + local curTime = CurTime() + + local dt = curTime - self.LastDamageTime + if dt >= 0.5 then + self.LastDamageTime = curTime + self:HurtTouchingObjects( dt ) + end + + self:NextThink(curTime + 0.25) + + return true + +end + +function ENT:HurtTouchingObjects(dt) + + self.HurtEntities = {} + + if self:GetNWVar("Disabled") == true then + return 0 + end + + local dmgAmount = self.Damage * dt + local hurtCount = 0 + + local touching = self:GetTouchingObjects() + for _, ent in pairs(touching) do + + if IsValid(ent) then + if self:HurtEntity(ent, dmgAmount) == true then + hurtCount = hurtCount + 1 + end + end + + end + + local curTime = CurTime() + + if self.DamageModel == DAMAGEMODEL_DOUBLE_FORGIVENESS then + + if hurtCount == 0 then + + if curTime > self.DamageResetTime then + self.Damage = self.OriginalDamage + end + + else + + self.Damage = self.Damage * 2 + + if self.Damage > self.DamageCap then + self.Damage = self.DamageCap + end + + self.DamageResetTime = curTime + TRIGGER_HURT_FORGIVE_TIME + + end + + end + + return hurtCount + +end + +local POUNDS_PER_KG = 2.2 +local KG_PER_POUND = 1.0 / POUNDS_PER_KG +local BULLET_IMPULSE_EXAGGERATION = 3.5 + +local function lbs2kg(x) + return x * KG_PER_POUND +end + +local function BULLET_MASS_GRAINS_TO_LB(grains) + return 0.002285 * grains / 16.0 +end + +local function BULLET_MASS_GRAINS_TO_KG(grains) + return lbs2kg(BULLET_MASS_GRAINS_TO_LB(grains)) +end + +local function BULLET_IMPULSE(grains, ftpersec) + + return ftpersec * 12 * BULLET_MASS_GRAINS_TO_KG(grains) * BULLET_IMPULSE_EXAGGERATION + +end + +local SMG1_FORCE = BULLET_IMPULSE( 200, 1225 ) +local phys_pushscale = GetConVar("phys_pushscale") + +function ENT:CalculateBulletForce(d, forceDir, forcePos, scale) + + d:SetDamagePosition( forcePos ); + + local vecForce = forceDir; + vecForce:Normalize() + + vecForce = vecForce * SMG1_FORCE -- Hardcoded in Source SDK as SMG1. + vecForce = vecForce * phys_pushscale:GetFloat(); + vecForce = vecForce * scale; + + d:SetDamageForce( vecForce ); + +end + +function ENT:CalculateExplosiveDamageForce(d, forceDir, forcePos, scale) + + d:SetDamagePosition(forcePos) + + -- ImpulseScale(targetMass, desiredSpeed) = (targetMass * desiredSpeed) + + local clampForce = 30000 -- ImpulseScale( 75, 400 ) + local forceScale = d:GetBaseDamage() * 300 -- ImpulseScale( 75, 4 ) + + if forceScale > clampForce then + forceScale = clampForce + end + + local rnd = math.random() + forceScale = forceScale * (0.85 + ((rnd * 1.15) - 0.85)) + + local vecForce = forceDir + vecForce:Normalize() + + vecForce = vecForce * forceScale + vecForce = vecForce * phys_pushscale:GetFloat() + vecForce = vecForce * scale + + d:SetDamageForce(vecForce) + +end + +function ENT:CalculateMeleeDamageForce(d, forceDir, forcePos, scale) + + d:SetDamagePosition(forcePos) + + -- ImpulseScale(targetMass, desiredSpeed) = (targetMass * desiredSpeed) + + -- impulse large enough to push a 75kg man 4 in/sec per point of damage + local forceScale = d:GetBaseDamage() * 300 -- ImpulseScale( 75, 4 ) + + local vecForce = forceDir + vecForce:Normalize() + vecForce = vecForce * forceScale + vecForce = vecForce * phys_pushscale:GetFloat() + vecForce = vecForce * scale + + d:SetDamageForce(vecForce) + +end + +function ENT:GuessDamageForce(d, forceDir, forcePos, scale) + + scale = scale or 1 + + if self:HasDamageType(DMG_BULLET) then + self:CalculateBulletForce(d, forceDir, forcePos, scale) + elseif self:HasDamageType(DMG_BLAST) then + self:CalculateExplosiveDamageForce(d, forceDir, forcePos, scale) + else + self:CalculateMeleeDamageForce(d, forceDir, forcePos, scale) + end + +end + +function ENT:HurtEntity(ent, dmg) + + if self:GetNWVar("Disabled") == true then + return false + end + + if not IsValid(ent) then + return false + end + + if self:PassesTriggerFilters(ent) == false then + return false + end + + if self.Damage < 0 then + + ent:SetHealth(ent:GetHealth() - (-self.Damage)) + + else + + local pos = self:WorldSpaceCenter() + local damagePos = ent:NearestPoint(pos) + + local d = DamageInfo() + d:SetDamage( self.Damage ) + d:SetDamageType( dmg ) + d:SetInflictor(self) + d:SetAttacker(self) + if self.NoDamageForce then + d:SetDamageForce( Vector(0, 0, 0) ) + else + self:GuessDamageForce(d, damagePos - pos, damagePos) + end + + ent:TakeDamageInfo(d) + end + + --DbgPrint(self, "Causing damage to " .. tostring(ent)) + + if ent:IsPlayer() then + self:FireOutputs("OnHurtPlayer", ent, self) + else + self:FireOutputs("OnHurt", ent, self) + end + + self.HurtEntities = self.HurtEntities or {} + self.HurtEntities[ent] = true + + return true + +end diff --git a/entities/entities/trigger_multiple.lua b/entities/entities/trigger_multiple.lua new file mode 100644 index 00000000..530e838d --- /dev/null +++ b/entities/entities/trigger_multiple.lua @@ -0,0 +1,17 @@ +if SERVER then + +ENT.Base = "lambda_trigger" +ENT.Type = "brush" + +DEFINE_BASECLASS( "lambda_trigger" ) + +function ENT:Initialize() + + --DbgPrint(self, "trigger_multiple:Initialize") + + BaseClass.Initialize(self) + BaseClass.SetWaitTime(self, 0.2) -- Remove once triggered. + +end + +end diff --git a/entities/entities/trigger_once.lua b/entities/entities/trigger_once.lua new file mode 100644 index 00000000..91c1545d --- /dev/null +++ b/entities/entities/trigger_once.lua @@ -0,0 +1,17 @@ +if SERVER then + +ENT.Base = "lambda_trigger" +ENT.Type = "brush" + +DEFINE_BASECLASS( "lambda_trigger" ) + +function ENT:Initialize() + + --DbgPrint(self, "trigger_once:Initialize") + + BaseClass.Initialize(self) + BaseClass.SetWaitTime(self, -1) -- Remove once triggered. + +end + +end diff --git a/entities/entities/trigger_transition.lua b/entities/entities/trigger_transition.lua new file mode 100644 index 00000000..1e2fa135 --- /dev/null +++ b/entities/entities/trigger_transition.lua @@ -0,0 +1,40 @@ +if SERVER then + +ENT.Base = "lambda_trigger" +ENT.Type = "brush" + +DEFINE_BASECLASS( "lambda_trigger" ) + +function ENT:Initialize() + + --DbgPrint(self, "trigger_once:Initialize") + + BaseClass.Initialize(self) + BaseClass.SetWaitTime(self, 0) -- Never remove. + + self:AddSolidFlags(FSOLID_TRIGGER_TOUCH_DEBRIS) + +end + +function ENT:PassesTriggerFilters(ent) + + return true -- Anything goes in here. + +end + +function ENT:StartTouch(ent) + + --DbgPrint(self, "StartTouch(" .. tostring(ent) .. ")") + return BaseClass.StartTouch(self, ent) + +end + +function ENT:Touch(ent) + + --DbgPrint(self, "Touch(" .. tostring(ent) .. ")") + return BaseClass.Touch(self, ent) + +end + + +end diff --git a/entities/weapons/weapon_physcannon2.lua b/entities/weapons/weapon_physcannon2.lua new file mode 100644 index 00000000..5220389a --- /dev/null +++ b/entities/weapons/weapon_physcannon2.lua @@ -0,0 +1,777 @@ +-- WIP! Don't touch me + +AddCSLuaFile() + +SWEP.PrintName = "#HL2_GravityGun" +SWEP.Author = "Zeh Matt" +SWEP.Instructions = "" + +SWEP.Spawnable = true +SWEP.AdminOnly = true + +SWEP.Primary.ClipSize = -1 +SWEP.Primary.DefaultClip = -1 +SWEP.Primary.Automatic = true +SWEP.Primary.Ammo = "none" + +SWEP.Secondary.ClipSize = -1 +SWEP.Secondary.DefaultClip = -1 +SWEP.Secondary.Automatic = true +SWEP.Secondary.Ammo = "none" + +SWEP.HoldType = "physgun" +SWEP.Weight = 5 +SWEP.AutoSwitchTo = false +SWEP.AutoSwitchFrom = false + +SWEP.ViewModel = "models/weapons/v_physcannon.mdl" +SWEP.WorldModel = "models/weapons/w_Physics.mdl" + +if CLIENT then + SWEP.Slot = 0 + SWEP.SlotPos = 2 + SWEP.DrawAmmo = false + SWEP.DrawCrosshair = true + SWEP.DrawWeaponInfoBox = false + SWEP.BounceWeaponIcon = false + SWEP.WepSelectIcon = surface.GetTextureID( "weapons/swep" ) + SWEP.RenderGroup = RENDERGROUP_OPAQUE +end + +-- +-- ConVars +local physcannon_tracelength = GetConVar("physcannon_tracelength") +local physcannon_maxforce = GetConVar("physcannon_maxforce") +local physcannon_cone = GetConVar("physcannon_cone") +local physcannon_pullforce = GetConVar("physcannon_pullforce") + +-- +-- States +local ELEMENT_STATE_NONE = -1 +local ELEMENT_STATE_OPEN = 0 +local ELEMENT_STATE_CLOSED = 1 + +-- +-- Effect State +local EFFECT_NONE = 0 +local EFFECT_CLOSED = 1 +local EFFECT_READY = 2 +local EFFECT_HOLDING = 3 +local EFFECT_LAUNCH = 4 + +-- +-- Object Find Result +local OBJECT_FOUND = 0 +local OBJECT_NOT_FOUND = 1 +local OBJECT_BEING_DETACHED = 2 + + +-- +-- Code +function SWEP:Initialize() + DbgPrint(self, "Initialize") + + self.CalcViewModelView = nil + self.GetViewModelPosition = nil + + self.LastPuntedObject = nil + self.NextPuntTime = CurTime() + self.EffectState = EFFECT_NONE + self.OldEffectState = EFFECT_NONE + self.ChangeState = ELEMENT_STATE_NONE + self.ElementDebounce = CurTime() + self.CheckSuppressTime = CurTime() + self.ObjectShadowParams = {} + self.DebounceSecondary = false + self:SetWeaponHoldType(self.HoldType) + + if SERVER then + local motionController = ents.Create("base_entity") + motionController:SetPos(self:GetPos()) + motionController:Spawn() + --motionController:SetParent(self) + motionController.PhysicsSimulate = function(mc, phys, dt) + return self:PhysicsSimulate(phys, dt) + end + self:SetNW2Entity("MotionController", motionController) + end + + self:SetNW2Vector("TargetPos", Vector(0, 0, 0)) + self:SetNW2Angle("TargetAng", Angle(0, 0, 0)) + self:SetNW2Bool("Holding", false) + self:SetNW2Entity("AttachedEnt", nil) + + if CLIENT then + hook.Add("EntityNetworkedVarChanged", self, function(self, ent, name, oldval, newval) + if ent == self then + --DbgPrint("NetworkVar Changed: ", name, oldval, newval) + end + end) + end +end + +function SWEP:GetMotionController() + return self:GetNW2Entity("MotionController") +end + +function SWEP:LaunchObject(ent, fwd, force) + + if self.LastPuntedObject == ent and CurTime() < self.NextPuntTime then + return + end + + self:DetachObject() + + self.LastPuntedObject = ent + self.NextPuntTime = CurTime() + 0.5 + + self:ApplyVelocityBasedForce(ent, fwd) + + self:SetNextPrimaryFire(CurTime() + 0.5) + self:SetNextSecondaryFire(CurTime() + 0.5) + + self:DoEffect(EFFECT_LAUNCH, ent:WorldSpaceCenter()) + +end + +function SWEP:PrimaryAttack() + --DbgPrint(self, "PrimaryAttack") + + local owner = self.Owner + if not IsValid(owner) then + return + end + + self:SetNextPrimaryFire(CurTime() + 0.5) + + if self:GetNW2Bool("Holding") == true then + + local ent = self:GetNW2Entity("AttachedEnt") + if not IsValid(ent) then + return + end + + -- Make sure its in range. + local dist = (ent:WorldSpaceCenter() - owner:WorldSpaceCenter()):Length() + if dist > physcannon_tracelength:GetFloat() then + return self:DryFire() + end + + self:LaunchObject(ent, owner:GetAimVector(), physcannon_maxforce:GetFloat()) + self:PrimaryFireEffect() + self:SendWeaponAnim(ACT_VM_SECONDARYATTACK) + + return + end + + -- Punt object. + local eyeAng = owner:EyeAngles() + local fwd = owner:GetAimVector() + local start = owner:GetShootPos() + local puntDist = physcannon_tracelength:GetFloat() + local endPos = start + (fwd * puntDist) + local trMask = bit.bor(MASK_SHOT, CONTENTS_GRATE) + + local tr = util.TraceHull({ + start = start, + endpos = endPos, + filter = owner, + mins = Vector(-8, -8, -8), + maxs = Vector(8, 8, 8), + mask = trMask + }) + + local valid = true + local ent = tr.Entity + + if tr.Fraction == 1 or not IsValid(ent) or ent:IsEFlagSet(EFL_NO_PHYSCANNON_INTERACTION) then + valid = false + elseif ent:GetMoveType() ~= MOVETYPE_VPHYSICS then + -- FIXME: GetInternalVariable does return nothing for m_takedamage + local savetable = ent:GetSaveTable() + if savetable.m_takedamage ~= nil and savetable.m_takedamage == 0 --[[DAMAGE_NO]] then + valid = false + end + end + + if valid == false then + tr = util.TraceLine({ + start = start, + endpos = endPos, + mask = trMask, + filter = owner, + }) + ent = tr.Entity + if tr.Fraction == 1 or not IsValid(ent) or ent:IsEFlagSet(EFL_NO_PHYSCANNON_INTERACTION) then + return self:DryFire() + end + end + + if ent:GetMoveType() ~= MOVETYPE_VPHYSICS then + -- FIXME: GetInternalVariable does return nothing for m_takedamage + local savetable = ent:GetSaveTable() + if savetable.m_takedamage ~= nil and savetable.m_takedamage == 0 --[[DAMAGE_NO]] then + return self:DryFire() + end + + -- SDK: // Don't let the player zap any NPC's except regular antlions and headcrabs. + if owner:IsPlayer() and ent:IsPlayer() then + return self:DryFire() + end + + return self:PuntNonVPhysics(ent, fwd, tr) + end + + if ent:IsVPhysicsFlesh() then + return self:DryFire() + end + + return self:PuntVPhysics(ent, fwd, tr) + +end + +function SWEP:CanSecondaryAttack() + + local owner = self.Owner + if not IsValid(owner) then + DbgPrint("Invalid owner") + return false + end + + return true + +end + +function SWEP:SecondaryAttack() + + DbgPrint(self, "SecondaryAttack") + + if self:CanSecondaryAttack() == false then + return + end + + if self:GetNW2Bool("Holding") == true then + + self:SetNextPrimaryFire(CurTime() + 0.5) + self:SetNextSecondaryFire(CurTime() + 0.5) + self.Secondary.Automatic = true + + self:DetachObject() + self:DoEffect(EFFECT_READY) + self:SendWeaponAnim(ACT_VM_PRIMARYATTACK) + + else + + local res = self:FindObject() + + if res == OBJECT_FOUND then + self.Secondary.Automatic = false -- No longer automatic, debounce. + self:SetNextSecondaryFire(CurTime() + 0.5) + elseif res == OBJECT_NOT_FOUND then + self:SetNextSecondaryFire(CurTime() + 0.1) + self.Secondary.Automatic = true + elseif res == OBJECT_BEING_DETACHED then + self:SetNextSecondaryFire(CurTime() + 0.01) + self.Secondary.Automatic = true + end + + self:DoEffect(EFFECT_HOLDING) + + end + +end + +function SWEP:FindObjectInCone(start, fwd, coneSize) + local nearestDist = physcannon_tracelength:GetFloat() + 1.0 + local mins = start - Vector(nearestDist, nearestDist, nearestDist) + local maxs = start + Vector(nearestDist, nearestDist, nearestDist) + local nearest + + for _,v in pairs(ents.FindInBox(mins, maxs)) do + if not IsValid(v:GetPhysicsObject()) then + continue + end + local los = v:WorldSpaceCenter() - start + local dist = los:Length() + los:Normalize() + if dist >= nearestDist or los:DotProduct(fwd) < coneSize then + continue + end + + local tr = util.TraceLine({ + start = start, + endpos = v:WorldSpaceCenter(), + mask = bit.bor(MASK_SHOT, CONTENTS_GRATE), + filter = self.Owner + }) + + if tr.Entity == v then + nearestDist = dist + nearest = v + end + end + + return nearest +end + +function SWEP:FindObject() + + local owner = self.Owner + if not IsValid(owner) then + return + end + + local fwd = owner:GetAimVector() + local start = owner:GetShootPos() + local testLength = physcannon_tracelength:GetFloat() * 4.0 + local endPos = start + (fwd * testLength) + local trMask = bit.bor(MASK_SHOT, CONTENTS_GRATE) + + local tr = util.TraceLine({ + start = start, + endpos = endPos, + mask = trMask, + filter = owner + }) + + if tr.Fraction == 1 or not IsValid(tr.Entity) or tr.HitWorld == true then + tr = util.TraceHull({ + start = start, + endpos = endPos, + mask = trMask, + filter = owner, + mins = Vector(-4, -4, -4), + maxs = Vector(4, 4, 4) + }) + end + + local ent + if IsValid(tr.Entity) then + ent = tr.Entity:GetRootMoveParent() + end + + local attach = false + local pull = false + + if tr.Fraction ~= 1.0 and IsValid(tr.Entity) and tr.HitWorld == false then + if tr.Fraction <= 0.25 then + attach = true + elseif tr.Fraction > 0.25 then + pull = true + end + end + + local coneEnt + if attach == false and pull == false then + coneEnt = self:FindObjectInCone(start, fwd, physcannon_cone:GetFloat()) + end + + if IsValid(coneEnt) then + ent = coneEnt + + if ent:WorldSpaceCenter():DistToSqr(start) <= (testLength * testLength) then + attach = true + else + pull = true + end + end + + if false --[[CanPickupObject(ent) == false]] then + return OBJECT_NOT_FOUND + end + + if attach == true then + if self:AttachObject(ent, tr) == true then + return OBJECT_FOUND + end + return OBJECT_NOT_FOUND + end + + if pull == false then + return OBJECT_NOT_FOUND + end + + local phys = ent:GetPhysicsObject() + if not IsValid(phys) then + return OBJECT_NOT_FOUND + end + + local pullDir = start - ent:WorldSpaceCenter() + pullDir = pullDir:GetNormal() * physcannon_pullforce:GetFloat() + + local mass = ent:GetPhysMass() + if mass < 50 then + pullDir = pullDir * ((mass + 0.5) * (1 / 50.0)) + end + + phys:ApplyForceCenter(pullDir) + return OBJECT_NOT_FOUND + +end + +function SWEP:PhysicsSimulate( phys, dt ) + + --DbgPrint(self, "PhysicsSimulate", phys, dt) + + self.ObjectShadowParams.deltatime = dt + + --phys:Wake() + phys:ComputeShadowControl(self.ObjectShadowParams) + + return SIM_LOCAL_ACCELERATION + +end + +function SWEP:UpdateObject() + + local owner = self.Owner + if not IsValid(owner) then + return + end + + local lastUpdate = self.LastSimUpdate or CurTime() + local dt = CurTime() - lastUpdate + self.lastUpdate = CurTime() + local attachedObject = self:GetNW2Entity("AttachedEnt") + + if not IsValid(attachedObject) then + return self:DetachObject() + end + + local fwd = owner:GetAimVector() + local start = owner:GetShootPos() + local minDist = 24 + local playerLen = owner:OBBMaxs():Length2D() + local objLen = attachedObject:OBBMaxs():Length2D() + local distance = minDist + playerLen + objLen + + local targetAng = self:GetNW2Angle("TargetAng") + local targetAttachment = self:GetNW2Vector("AttachmentPoint") + + local ang = owner:LocalToWorldAngles(targetAng) + local endPos = start + (fwd * distance) + + local attachmentPoint = Vector(targetAttachment) + attachmentPoint:Rotate(ang) + + self.ObjectShadowParams.secondstoarrive = (1 / 33) * 0.5 + self.ObjectShadowParams.pos = endPos - attachmentPoint + self.ObjectShadowParams.angle = ang + + self.ObjectShadowParams.maxangular = 2000 + self.ObjectShadowParams.maxangulardamp = 150 + self.ObjectShadowParams.maxspeed = 1000000 + self.ObjectShadowParams.maxspeeddamp = 2000 + self.ObjectShadowParams.dampfactor = 0.7 + self.ObjectShadowParams.teleportdistance = 200 + + attachedObject:PhysWake() + + if CLIENT then + local phys = attachedObject:GetPhysicsObject() + if IsValid(phys) then + self:PhysicsSimulate(phys, dt) + --attachedObject:SetPos(phys:GetPos()) + --attachedObject:SetAngles(phys:GetAngles()) + else + DbgPrint("Invalid phys!", phys) + end + end + +end + +function SWEP:Think() + + if self:GetNW2Bool("Holding") == true then + self:UpdateObject() + end + +end + +function SWEP:AttachObject(ent, tr) + + DbgPrint(self, "AttachObject", ent) + + local owner = self.Owner + if not IsValid(owner) then + return + end + + local phys + if SERVER then + phys = ent:GetPhysicsObject() + else + ent:PhysicsInit(SOLID_VPHYSICS) + ent:SetMoveType(MOVETYPE_VPHYSICS) + ent:SetSolid(SOLID_VPHYSICS) + phys = ent:GetPhysicsObject() + phys:Wake() + phys:EnableMotion(true) + end + + if not IsValid(phys) then + DbgPrint("Physics invalid!") + return + end + + phys:AddGameFlag(FVPHYSICS_PLAYER_HELD) + + local motionController = self:GetMotionController() + + motionController:StartMotionController() + motionController:AddToMotionController(phys) + + --if SERVER then + if not IsValid(ent:GetOwner()) then + ent:SetOwner(owner) + self.ResetOwner = true + end + + self.SavedMass = {} + self.SavedRotDamping = {} + for i = 0, ent:GetPhysicsObjectCount() - 1 do + local phys2 = ent:GetPhysicsObjectNum(i) + if not IsValid(phys2) then + continue + end + self.SavedMass[i] = phys2:GetMass() + phys2:SetMass(1) -- Carry mass + + local linear, angular = phys2:GetDamping() + self.SavedRotDamping[i] = angular + phys2:SetDamping(linear, 10) + end + + phys:SetMass(1.0) + phys:EnableDrag(false) + --end + + local attachmentPoint = ent:WorldToLocal(ent:WorldSpaceCenter()) + local targetAng = owner:WorldToLocalAngles(ent:GetAngles()) + + self:SetNW2Angle("TargetAng", targetAng) + self:SetNW2Vector("AttachmentPoint", attachmentPoint) + self:SetNW2Entity("AttachedEnt", ent) + self:SetNW2Bool("Holding", true) + + -- We call it once so it resets the positions. + self:UpdateObject() + + return true + +end + +function SWEP:DetachObject() + + local ent = self:GetNW2Entity("AttachedEnt") + + DbgPrint(self, "DetachObject", ent) + + if self:GetNW2Bool("Holding") == false then + return + end + + if IsValid(ent) then + --if SERVER then + if self.ResetOwner == true then + ent:SetOwner(nil) + end + + for i = 0, ent:GetPhysicsObjectCount() - 1 do + local phys = ent:GetPhysicsObjectNum(i) + if not IsValid(phys) then + continue + end + + if self.SavedMass[i] ~= nil then + phys:SetMass(self.SavedMass[i]) + end + if self.SavedRotDamping[i] ~= nil then + local linear,_ = phys:GetDamping() + phys:SetDamping(linear, self.SavedRotDamping[i]) + end + + phys:EnableDrag(true) + phys:SetVelocity(Vector(0, 0, 0)) + phys:ClearGameFlag(FVPHYSICS_PLAYER_HELD) + + end + --else + + if CLIENT then + ent:PhysicsDestroy() + end + + local motionController = self:GetMotionController() + motionController:RemoveFromMotionController(ent:GetPhysicsObject()) + else + DbgPrint("Invalid entity") + end + + self.SavedMass = {} + self.SavedRotDamping = {} + + self:SetNW2Bool("Holding", false) + self:SetNW2Entity("AttachedEnt", nil) + +end + +function SWEP:DryFire() + self:SendWeaponAnim( ACT_VM_PRIMARYATTACK ) + self:EmitSound("Weapon_PhysCannon.DryFire") +end + +function SWEP:PrimaryFireEffect() + + local owner = self.Owner + if not IsValid(owner) then + return + end + + owner:ViewPunch( Angle(-6, util.SharedRandom("physcannonfire", -2, 2), 0) ) + + if SERVER then + --TODO: Screen fadein + end + + self:EmitSound("Weapon_PhysCannon.Launch") + +end + +function SWEP:PuntNonVPhysics(ent, fwd, tr) + +end + +function SWEP:ApplyVelocityBasedForce(ent, fwd) + if not SERVER then + return + end + + local phys = ent:GetPhysicsObject() + + local maxForce = physcannon_maxforce:GetFloat() + local force = maxForce + + local mass = phys:GetMass() + if mass > 100 then + + end + + local vVel = fwd * force + --local aVel = tr.HitPos + + phys:AddVelocity(vVel) + --phys:AddAngleVelocity(aVel * 1) +end + +function SWEP:PuntVPhysics(ent, fwd, tr) + + local curTime = CurTime() + + if self.LastPuntedObject == ent and curTime < self.NextPuntTime then + return + end + + self.LastPuntedObject = ent + self.NextPuntTime = curTime + 0.5 + + if SERVER then + + local dmgInfo = DamageInfo() + dmgInfo:SetAttacker(self.Owner) + dmgInfo:SetInflictor(self) + dmgInfo:SetDamage(0) + dmgInfo:SetDamageType(DMG_PHYSGUN) + ent:DispatchTraceAttack(dmgInfo, tr, fwd) + + if fwd.z < 0 then + fwd.z = fwd.z * -0.65 + end + + -- Physgun_OnPhysGunPickup( pEntity, pOwner, PUNTED_BY_CANNON ); + local phys = ent:GetPhysicsObjectNum(0) + if phys:HasGameFlag(FVPHYSICS_CONSTRAINT_STATIC) and ent:IsVehicle() then + fwd.x = 0 + fwd.y = 0 + fwd.z = 0 + end + + if false then -- if ( !Pickup_ShouldPuntUseLaunchForces( pEntity, PHYSGUN_FORCE_PUNTED ) ) + + for i = 0, ent:GetPhysicsObjectCount() - 1 do + phys = ent:GetPhysicsObjectNum(i) + + -- Physgun_OnPhysGunPickup( pEntity, pOwner, PUNTED_BY_CANNON ); + + + end + + else + self:ApplyVelocityBasedForce(ent, fwd, tr) + end + end + + self:PrimaryFireEffect() + self:SendWeaponAnim(ACT_VM_SECONDARYATTACK) + + self.ChangeState = ELEMENT_STATE_CLOSED + self.ElementDebounce = CurTime() + 0.5 + self.CheckSuppressTime = CurTime() + 0.25 + + self:SetNextPrimaryFire(CurTime() + 0.5) + self:SetNextSecondaryFire(CurTime() + 0.5) + +end + +function SWEP:DoEffectNone(pos) + +end + +function SWEP:DoEffectClosed(pos) + +end + +function SWEP:DoEffectReady(pos) + +end + +function SWEP:DoEffectHolding(pos) + +end + +function SWEP:DoEffectLaunch(pos) + +end + +local EFFECT_TABLE = +{ + [EFFECT_NONE] = SWEP.DoEffectNone, + [EFFECT_CLOSED] = SWEP.DoEffectClosed, + [EFFECT_READY] = SWEP.DoEffectReady, + [EFFECT_HOLDING] = SWEP.DoEffectHolding, + [EFFECT_LAUNCH] = SWEP.DoEffectLaunch, +} + +function SWEP:DoEffect(effect, pos) + + self.EffectState = effect + + if CLIENT then + self.OldEffectState = self.EffectState + end + + EFFECT_TABLE[effect](self, pos) + +end + +function SWEP:DrawWorldModel() + + self.Weapon:DrawModel() + +end + +function SWEP:DrawWorldModelTranslucent() + + self.Weapon:DrawModel() + +end diff --git a/gamemode/cl_hud.lua b/gamemode/cl_hud.lua new file mode 100644 index 00000000..8ababf82 --- /dev/null +++ b/gamemode/cl_hud.lua @@ -0,0 +1,283 @@ +include("huds/hud_numeric.lua") +include("huds/hud_suit.lua") +include("huds/hud_pickup.lua") +include("huds/hud_respawn.lua") + +local DbgPrint = GetLogging("HUD") + +DEFINE_BASECLASS( "gamemode_base" ) + +local function AskWeapon(ply, hud, wep) + if IsValid( wep ) and wep.HUDShouldDraw ~= nil then + return wep.HUDShouldDraw( wep, name ) + end +end + +function GM:HUDTick() + + local drawHud = true + local ply = LocalPlayer() + if not IsValid(ply) then + return + end + + local wep = ply:GetActiveWeapon() + local CHudHealth = drawHud and (not wep:IsValid() or AskWeapon(ply, "CHudHealth", wep) ~= false) and hook.Call("HUDShouldDraw", nil, "CHudHealth") ~= false + local CHudAmmo = drawHud and (not wep:IsValid() or AskWeapon(ply, "CHudAmmo", wep) ~= false) and hook.Call("HUDShouldDraw", nil, "CHudAmmo") ~= false + local CHudBattery = drawHud and (not wep:IsValid() or AskWeapon(ply, "CHudBattery", wep) ~= false) and hook.Call("HUDShouldDraw", nil, "CHudBattery") ~= false + local CHudSecondaryAmmo = drawHud and wep:IsValid() and AskWeapon(ply, "CHudSecondaryAmmo", wep) ~= false and hook.Call("HUDShouldDraw", nil, "CHudSecondaryAmmo") ~= false + + --DbgPrint(CHudHealth, CHudAmmo, CHudBattery, CHudSecondaryAmmo) + + if IsValid(self.HUDSuit) then + local suit = self.HUDSuit + suit.HUDHealth:SetVisible(CHudHealth) + suit.HUDArmor:SetVisible(CHudBattery) + suit.HUDAux:SetVisible(CHudBattery) + suit.HUDAmmo:SetVisible(CHudSecondaryAmmo) + end + +end + +function GM:HUDShouldDraw( name ) + + local ply = LocalPlayer() + local res = true + + if name == "CHudCrosshair" then + local wep = ply:GetActiveWeapon() + if not IsValid(wep) then + return false + end + if lambda_dynamic_crosshair:GetBool() == true and wep.DoDrawCrosshair == nil then + return false + end + elseif name == "CHudGeiger" then + if not ply:IsSuitEquipped() then + return false + end + elseif name == "CHudBattery" then + return false + elseif name == "CHudHealth" or + name == "CHudAmmo" or + name == "CHudSecondaryAmmo" then + return false + elseif name == "CHudDamageIndicator" then + -- We include the lifetime because theres some weird thing going with the damage indicator. + if ply:Alive() == false or ply:GetLifeTime() < 1.0 then + return false + end + elseif name == "CHudHistoryResource" then + return false + end + + return true + +end + +local CROSSHAIR_W = 32 +local CROSSHAIR_H = 32 +local CROSSHAIR_SPACE = 4 +local RT_NAME = "LambdaCrosshair" .. CurTime() +local CROSSHAIR_RT +local CROSSHAIR_MAT +local CROSSHAIR_RT_SETUP = false + +local AMMO_BAR_H = 2 +local AMMO_BAR_W = 32 +local AMMO_BAR_SPACING = 2 +local AMMO_BAR1_Y = (CROSSHAIR_H / 2) + AMMO_BAR_SPACING +local AMMO_BAR2_Y = AMMO_BAR1_Y + AMMO_BAR_H + AMMO_BAR_SPACING +local AMMO_BAR1_COLOR = Color(255, 255, 255, 50) +local AMMO_BAR2_COLOR = Color(255, 255, 255, 50) + +local function UpdateCrosshair(centerX, centerY) + + local screenCenterX = ScrH() / 2 + local screenCenterY = ScrW() / 2 + local localCenterX = CROSSHAIR_W / 2 + local localCenterY = CROSSHAIR_H / 2 + local r,g,b + + --local data = render.Capture({format = "png", h = CROSSHAIR_H, w = CROSSHAIR_W, x = screenCenterX, y = screenCenterY, quality = 50}) + --DbgPrint(data) + render.CapturePixels() + + if CROSSHAIR_RT_SETUP == false then + + CROSSHAIR_RT = GetRenderTarget(RT_NAME, CROSSHAIR_W, CROSSHAIR_H, false) + CROSSHAIR_MAT = CreateMaterial("LambdaCrosshair" .. CurTime(), "UnlitGeneric", + { + ["$basetexture"] = RT_NAME, + ["$translucent"] = 1, + }) + + CROSSHAIR_MAT:SetTexture("$basetexture", CROSSHAIR_RT) + + render.ClearRenderTarget(CROSSHAIR_RT, Color(0, 0, 0, 0)) + --render.ClearDepth() + --render.Clear( 0, 0, 0, 0 ) + + CROSSHAIR_RT_SETUP = true + + end + + render.PushRenderTarget(CROSSHAIR_RT) + render.OverrideAlphaWriteEnable( true, true ) + + r,g,b = render.ReadPixel(centerX, centerY + AMMO_BAR1_Y) + AMMO_BAR1_COLOR.r = 255 - r + AMMO_BAR1_COLOR.g = 255 - g + AMMO_BAR1_COLOR.b = 255 - b + AMMO_BAR1_COLOR.a = 128 + + r,g,b = render.ReadPixel(centerX, centerY + AMMO_BAR2_Y) + AMMO_BAR2_COLOR.r = 255 - r + AMMO_BAR2_COLOR.g = 255 - g + AMMO_BAR2_COLOR.b = 255 - b + AMMO_BAR2_COLOR.a = 128 + + cam.Start2D() + + local pad = 1 + local alpha = 128 + + -- Up + for y = 0, (CROSSHAIR_H / 2) - CROSSHAIR_SPACE, pad do + r,g,b = render.ReadPixel(centerX, centerY - y - CROSSHAIR_SPACE) + surface.SetDrawColor(255 - r, 255 - g, 255 - b, alpha) + surface.DrawLine(localCenterX, localCenterY - y - CROSSHAIR_SPACE, localCenterX, localCenterY - y - CROSSHAIR_SPACE - 1) + --surface.DrawRect(localCenterX, localCenterY - y - CROSSHAIR_SPACE, 2, 2) + end + + -- Down + for y = 0, (CROSSHAIR_H / 2) - CROSSHAIR_SPACE, pad do + r,g,b = render.ReadPixel(centerX, centerY + y + CROSSHAIR_SPACE) + surface.SetDrawColor(255 - r, 255 - g, 255 - b, alpha) + surface.DrawLine(localCenterX, localCenterY + y + CROSSHAIR_SPACE, localCenterX, localCenterY + y + CROSSHAIR_SPACE + 1) + --surface.DrawRect(localCenterX, localCenterY + y + CROSSHAIR_SPACE, 2, 2) + end + + -- Left + for x = 0, (CROSSHAIR_W / 2) - CROSSHAIR_SPACE, pad do + r,g,b = render.ReadPixel(centerX - x - CROSSHAIR_SPACE, centerY) + surface.SetDrawColor(255 - r, 255 - g, 255 - b, alpha) + surface.DrawLine(localCenterX - x - CROSSHAIR_SPACE, localCenterY, localCenterX - x - CROSSHAIR_SPACE - 1, localCenterY) + --surface.DrawRect(localCenterX - x - CROSSHAIR_SPACE, localCenterY, 2, 2) + end + + -- Right + for x = 0, (CROSSHAIR_W / 2) - CROSSHAIR_SPACE, pad do + r,g,b = render.ReadPixel(centerX + x + CROSSHAIR_SPACE, centerY) + surface.SetDrawColor(255 - r, 255 - g, 255 - b, alpha) + surface.DrawLine(localCenterX + x + CROSSHAIR_SPACE, localCenterY, localCenterX + x + CROSSHAIR_SPACE + 1, localCenterY) + --surface.DrawRect(localCenterX + x + CROSSHAIR_SPACE, localCenterY, 2, 2) + end + + -- Dot + r,g,b = render.ReadPixel(centerX, centerY) + surface.SetDrawColor(255 - (r / 4), math.Clamp(255 - (g * 4), 0, 255), math.Clamp(255 - (b * 4), 0, 255), 255) + surface.DrawLine(localCenterX - 4, localCenterY - 4, localCenterX + 4, localCenterY + 4) + surface.DrawLine(localCenterX + 4, localCenterY - 4, localCenterX - 4, localCenterY + 4) + + cam.End2D() + + render.OverrideAlphaWriteEnable( false ) + render.PopRenderTarget() + +end + +function GM:DrawDynamicCrosshair() + + local ply = LocalPlayer() + if ply:Alive() == true then + if ply:InVehicle() == true then + local veh = ply:GetVehicle() + if veh:GetClass() == "prop_vehicle_jeep" or veh:GetClass() == "prop_vehicle_airboat" then + return + end + end + end + + local wep = ply:GetActiveWeapon() + if wep == nil or not IsValid(wep) then + return + end + if wep:GetClass() == "weapon_crowbar" then + return + end + + if wep.DoDrawCrosshair ~= nil then + return + end + + local scrW, scrH = ScrW(), ScrH() + local centerX = scrW / 2 + local centerY = scrH / 2 + + if FrameNumber() % 60 == 0 or CROSSHAIR_RT_SETUP == false then + UpdateCrosshair(centerX, centerY) + end + + surface.SetDrawColor( 255, 255, 255, 255 ) + surface.SetMaterial(CROSSHAIR_MAT) + surface.DrawTexturedRect(centerX - (CROSSHAIR_W / 2), centerY - (CROSSHAIR_H / 2), CROSSHAIR_W, CROSSHAIR_H) + + local clip1 = wep:Clip1() + if clip1 ~= -1 then + local p = clip1 / wep:GetMaxClip1() + local w = math.Round(p * 32) + surface.SetDrawColor( AMMO_BAR1_COLOR.r, AMMO_BAR1_COLOR.g, AMMO_BAR1_COLOR.b, AMMO_BAR1_COLOR.a ) + surface.DrawRect(centerX - (AMMO_BAR_W / 2), centerY + AMMO_BAR1_Y, w, AMMO_BAR_H) + end + + local ammoType = wep:GetPrimaryAmmoType() + local ammoCount = ply:GetAmmoCount(ammoType) + if ammoCount > 0 then + local ammoName = game.GetAmmoName(ammoType) + local maxVar = self.MAX_AMMO_DEF[ammoName] + if maxVar ~= nil then + local p = ammoCount / maxVar:GetInt() + local w = math.Round(p * 32) + surface.SetDrawColor( AMMO_BAR2_COLOR.r, AMMO_BAR2_COLOR.g, AMMO_BAR2_COLOR.b, AMMO_BAR2_COLOR.a ) + surface.DrawRect(centerX - (AMMO_BAR_W / 2), centerY + AMMO_BAR2_Y, w, AMMO_BAR_H) + end + end + +end + +function GM:HUDPaint() + + hook.Run( "HUDDrawPickupHistory" ) + hook.Run( "DrawDeathNotice", 0.85, 0.04 ) + if lambda_dynamic_crosshair:GetBool() == true then + hook.Run( "DrawDynamicCrosshair" ) + end + +end + +function GM:HUDInit() + + if IsValid(self.HUDSuit) then + self.HUDSuit:Remove() + end + + if IsValid(self.HUDRespawn) then + self.HUDRespawn:Remove() + end + + self.HUDRespawn = vgui.Create("HudRespawn") + self.HUDSuit = vgui.Create("HudSuit") + + CROSSHAIR_RT_SETUP = false + +end + +function GM:EnableRespawnHUD(enabled, startTime, timeout) + if not IsValid(self.HUDRespawn) then + -- What? + return + end + self.HUDRespawn:SetVisible(enabled) + self.HUDRespawn:SetTimeout(startTime, timeout) +end diff --git a/gamemode/cl_init.lua b/gamemode/cl_init.lua new file mode 100644 index 00000000..7ba0367a --- /dev/null +++ b/gamemode/cl_init.lua @@ -0,0 +1,318 @@ +include("shared.lua") +include("cl_postprocess.lua") +include("cl_ragdoll_ext.lua") +include("cl_taunts.lua") +include("cl_hud.lua") +include("cl_scoreboard.lua") + +DEFINE_BASECLASS( "gamemode_base" ) + +local DbgPrint = GetLogging("Client") + +-- This is nasty +function GM:OnSpawnMenuOpen() + RunConsoleCommand("lastinv") +end + +function GM:NetworkEntityCreated( ent ) + + if ent.PVSInitialize then + ent:PVSInitialize() + end + + local class = ent:GetClass() + if class == "class C_HL2MPRagdoll" then + self:HandleRagdollCreation(ent) + end + +end + +function GM:OnResolutionChanged(oldW, oldH, newW, newH) + self:HUDInit() +end + +function GM:Think() + + local scrW = ScrW() + local scrH = ScrH() + + self.CurResW = self.CurResW or scrW + self.CurResH = self.CurResH or scrH + + local resChanged = false + + if self.CurResW ~= scrW or self.CurResH ~= scrH then + resChanged = true + end + + if resChanged then + + local self = self + local curW = self.CurResW + local curH = self.CurResH + + -- We can not just load fonts at this point, it actually freezes gmod. + timer.Simple(1, function() + hook.Call("OnResolutionChanged", self, curW, curH, scrW, scrH) + end) + + self.CurResH = resH + self.CurResW = resW + + DbgPrint("Resolution changed") + end + + self:BulletsThink() + + for _,v in pairs(player.GetAll()) do + self:PlayerThink(v) + end + +end + +local BOBTIME = 0 +local LAST_BOBTIME = CurTime() +local HL2_BOB_CYCLE_MAX = 0.40 +local HL2_BOB_UP = 0.5 +local MAX_SPEED = 320 +local PI = math.pi +local PLAYER_SPEED = 0 + +local host_timescale = GetConVar("host_timescale") +local function GetTimeScale() + if host_timescale:GetFloat() ~= 1 then + return host_timescale:GetFloat() + end + return game.GetTimeScale() +end + +function GM:CalcViewModelBob( wep, vm, oldPos, oldAng, pos, ang ) + + local ply = LocalPlayer() + + local speed = Lerp(RealFrameTime() * 3, PLAYER_SPEED, ply:GetVelocity():Length2D()) + PLAYER_SPEED = speed + + speed = math.Clamp(speed, -MAX_SPEED, MAX_SPEED) + + -- NOTE: Using 0.0 instead of 0.1 causes weird behavior, hl2 uses 0.0 but lets not make it uglier than required. + local bob_offset = math.Remap(speed, 0, MAX_SPEED, 0.0, 1.0) + + BOBTIME = BOBTIME + (RealFrameTime() * 0.8 * GetTimeScale()) * bob_offset + LAST_BOBTIME = BOBTIME + + local cycle = BOBTIME - math.Round(BOBTIME / HL2_BOB_CYCLE_MAX, 0) * HL2_BOB_CYCLE_MAX + cycle = cycle / HL2_BOB_CYCLE_MAX + + if cycle < HL2_BOB_UP then + cycle = PI * (cycle / HL2_BOB_UP) + else + cycle = PI + PI * ((cycle - HL2_BOB_UP) / (1.0 - HL2_BOB_UP)) + end + + local vertBob = speed * 0.005 + vertBob = vertBob * 0.3 + vertBob * 0.7 * math.sin(cycle) + vertBob = math.Clamp(vertBob, -7.0, 4.0) + + cycle = BOBTIME - math.Round(BOBTIME / HL2_BOB_CYCLE_MAX * 2, 0) * HL2_BOB_CYCLE_MAX * 2 + cycle = cycle / (HL2_BOB_CYCLE_MAX * 2) + + if cycle < HL2_BOB_UP then + cycle = PI * (cycle / HL2_BOB_UP) + else + cycle = PI + PI * (cycle - HL2_BOB_UP) / (1.0 - HL2_BOB_UP) + end + + local lateralBob = speed * 0.005 + lateralBob = lateralBob * 0.3 + lateralBob * 0.7 * math.sin(cycle) + lateralBob = math.Clamp(lateralBob, -7.0, 4.0) + + local fwd = oldAng:Forward() + local right = oldAng:Right() + + local newPos = oldPos + (fwd * (vertBob * 0.1)) + newPos.z = newPos.z + (vertBob * 0.1) + + local newAng = oldAng + newAng.roll = newAng.roll + (vertBob * 0.5) + newAng.pitch = newAng.pitch - (vertBob * 0.4) + newAng.yaw = newAng.yaw - (lateralBob * 0.3) + + newPos = newPos + (right * (lateralBob * 0.8)) + + return newPos, newAng + +end + +local LastFacing = Vector(0, 0, 0) +local MaxViewModelLag = 0.4 + +function GM:CalcViewModelLag( wep, vm, oldPos, oldAng, pos, ang ) + + local fwd = oldAng:Forward() + + local newPos = oldPos + local newAng = oldAng + + local frameTime = math.Clamp(RealFrameTime() * GetTimeScale(), 0, 1 / 30) + if frameTime ~= 0.0 then + + local diff = fwd - LastFacing + local speed = 0.8 + + local len = diff:Length() + if len > MaxViewModelLag and MaxViewModelLag > 0.0 then + local scale = len / MaxViewModelLag + speed = speed * scale + end + + LastFacing = LastFacing + (diff * (speed * frameTime)) + + LastFacing:Normalize() + + newPos = oldPos + (diff * -1.0 * speed) + + end + + local up = oldAng:Up() + local right = oldAng:Right() + + local pitch = oldAng.pitch + if pitch > 180 then + pitch = pitch - 360 + elseif pitch < -180 then + pitch = pitch + 360 + end + + newPos = newPos + (fwd * (-pitch * 0.035)) + newPos = newPos + (right * (-pitch * 0.03)) + newPos = newPos + (up * (-pitch * 0.03)) + + return newPos, newAng + +end + +local HEAD_POS +local HEAD_POS_DELTA = Vector(0, 0, 0) + +function GM:CalcViewModelView( wep, vm, oldPos, oldAng, pos, ang ) + + if not IsValid( wep ) then + return + end + + local vm_origin, vm_angles = pos, ang + local modified = false + + -- Controls the position of all viewmodels + local func = wep.GetViewModelPosition + if ( func ) then + local pos, ang = func(wep, pos * 1, ang * 1) + vm_origin = pos or vm_origin + vm_angles = ang or vm_angles + modified = true + end + + -- Controls the position of individual viewmodels + func = wep.CalcViewModelView + if ( func ) then + local pos, ang = func(wep, ViewModel, oldPos * 1, oldAng * 1, pos * 1, ang * 1) + vm_origin = pos or vm_origin + vm_angles = ang or vm_angles + modified = true + end + + -- Lets not mess with custom stuff + if modified then + return vm_origin, vm_angles + end + + local newPos = oldPos + newPos = newPos + HEAD_POS_DELTA + local newAng = oldAng + + newPos, newAng = self:CalcViewModelBob(wep, vm, newPos, newAng, pos, ang) + newPos, newAng = self:CalcViewModelLag(wep, vm, newPos, newAng, pos, ang) + + return newPos, newAng + +end + +function GM:CalcView(ply, pos, ang, fov, nearZ, farZ) + + local view = {} + view.origin = pos + view.ang = ang + view.fov = fov + view.angles = ang + + local headBone = ply:LookupBone("ValveBiped.Bip01_Head1") + local headPos + if headBone ~= nil then + headPos = ply:GetBonePosition(headBone) + else + headPos = ply:EyePos() + end + + local t = RealFrameTime() * 5 + + HEAD_POS = LerpVector(t, HEAD_POS or headPos, headPos) + + local deltaX = (HEAD_POS.x - view.origin.x) * 0.05 + local deltaY = (HEAD_POS.y - view.origin.y) * 0.05 + local deltaZ = (HEAD_POS.z - view.origin.z) * 0.16 + + if ply:IsSpectator() == false then + HEAD_POS_DELTA = Vector(deltaX, deltaY, deltaZ) + else + HEAD_POS_DELTA = Vector(0, 0, 0) + end + + view.origin = view.origin + HEAD_POS_DELTA + + local viewlock = ply:GetViewLock() + + if viewlock == VIEWLOCK_ANGLE then + + view.angles = ply:GetNWAngle("LockedViewAngles") + view.fov = fov + view.origin = pos + return view + + elseif viewlock == VIEWLOCK_NPC or viewlock == VIEWLOCK_PLAYER then + + local npc = ply:GetNWEntity("LockedViewEntity") + if IsValid(npc) then + view.angles = (npc:EyePos() - ply:EyePos()):Angle() + view.fov = fov + view.origin = pos + return view + end + + else + + local Vehicle = ply:GetVehicle() + if IsValid( Vehicle ) then + return hook.Run( "CalcVehicleView", Vehicle, ply, view ) + end + + end + + return view + +end + +function GM:ShouldDrawLocalPlayer(ply) + + local vehicle = ply:GetVehicle() + if vehicle ~= nil and IsValid(vehicle) then + local class = vehicle:GetClass() + if class == "prop_vehicle_jeep" or class == "prop_vehicle_airboat" then + ply.VehicleSteeringView = true + return true + end + else + ply.VehicleSteeringView = false + end + +end diff --git a/gamemode/cl_postprocess.lua b/gamemode/cl_postprocess.lua new file mode 100644 index 00000000..0da3ace5 --- /dev/null +++ b/gamemode/cl_postprocess.lua @@ -0,0 +1,132 @@ +local DbgPrint = GetLogging("PostProcess") + +local GRAIN_RT = GetRenderTarget("LambdaFilmGrain", ScrW(), ScrH(), true) +local GRAIN_MAT = CreateMaterial("LambdaFilmGrain" .. CurTime(), "UnlitGeneric", +{ + ["$alpha"] = 1, + ["$translucent"] = 1, + ["$basetexture"] = "models/debug/debugwhite", + Proxies = + { + TextureScroll = + { + texturescrollvar = "$basetexturetransform", + texturescrollrate = 10, + texturescrollangle = 40, + }, + } +}) +local GRAIN_SETUP = false + +-- FIXME: Use a static texture instead. +local function GenerateFilmGrain() + + if GRAIN_SETUP == true then + return + end + GRAIN_SETUP = true + + render.PushRenderTarget(GRAIN_RT) + render.Clear(0, 0, 0, 1, true, true) + + surface.SetDrawColor(0, 50, 0, 100) + + cam.Start2D() + for y = 0, ScrH() do + for x = 0, ScrW() do + local a = math.random(0, 5) + if a == 0 then + surface.DrawLine(x, y, x + 2, y + 2) + end + end + end + cam.End2D() + + render.BlurRenderTarget(GRAIN_RT, 0.01, 0.01, 1) + render.PopRenderTarget() + + GRAIN_MAT:SetTexture("$basetexture", GRAIN_RT) + +end + +local LAST_GEIGER_RANGE = 1000 +local RADIATION_COLOR_MOD = { + ["$pp_colour_addr"] = 0, + ["$pp_colour_addg"] = 0, + ["$pp_colour_addb"] = 0, + ["$pp_colour_brightness"] = 0, + ["$pp_colour_contrast"] = 1, + ["$pp_colour_colour"] = 1.0, + ["$pp_colour_mulr"] = 0, + ["$pp_colour_mulg"] = 0, + ["$pp_colour_mulb"] = 0 +} + +function GM:RenderRadiationEffects(ply) + + GenerateFilmGrain() + + local curGeigerRange = math.Clamp(ply:GetGeigerRange() * 4, 0, 1000) + local geigerRange = Lerp(FrameTime(), LAST_GEIGER_RANGE, curGeigerRange) + LAST_GEIGER_RANGE = geigerRange + + local rv = (LAST_GEIGER_RANGE / 1000) + local iv = 1 - rv + + GRAIN_MAT:SetFloat("$alpha", iv) + + render.SetMaterial(GRAIN_MAT) + render.DrawScreenQuad() + + RADIATION_COLOR_MOD["$pp_colour_mulg"] = iv * 3 + DrawColorModify( RADIATION_COLOR_MOD ) + +end + +function GM:RenderSprintEffect(ply) + + self.TargetMotionBlur = self.TargetMotionBlur or 0.0 + + local vel = Vector(0, 0, 0) + if ply:InVehicle() then + local veh = ply:GetVehicle() + if IsValid(veh) then + vel = veh:GetVelocity() + end + else + vel = ply:GetVelocity() + end + + local len = vel:Length2DSqr() + local amount = 0 + if len > 1 then + amount = math.log(len * len) + end + + self.TargetMotionBlur = math.Approach(self.TargetMotionBlur, 5 + amount, RealFrameTime() * 15) + + DrawToyTown( 1, self.TargetMotionBlur * 5 ) + +end + +function GM:RenderScreenspaceEffects() + + local ply = LocalPlayer() + if not IsValid(ply) then + return + end + + if lambda_postprocess:GetBool() == false then + return + end + + self:RenderRadiationEffects(ply) + self:RenderSprintEffect(ply) + +end + +function GM:PreDrawSkyBox() +end + +function GM:PostDrawSkyBox() +end diff --git a/gamemode/cl_ragdoll_ext.lua b/gamemode/cl_ragdoll_ext.lua new file mode 100644 index 00000000..ce30b56b --- /dev/null +++ b/gamemode/cl_ragdoll_ext.lua @@ -0,0 +1,92 @@ +local DbgPrint = GetLogging("Ragdoll") + +local ImpactSounds = +{ + Soft = + { + "physics/body/body_medium_impact_soft1.wav", + "physics/body/body_medium_impact_soft2.wav", + "physics/body/body_medium_impact_soft3.wav", + "physics/body/body_medium_impact_soft4.wav", + "physics/body/body_medium_impact_soft5.wav", + "physics/body/body_medium_impact_soft6.wav", + "physics/body/body_medium_impact_soft7.wav", + }, + Hard = + { + "physics/body/body_medium_impact_hard1.wav", + "physics/body/body_medium_impact_hard2.wav", + "physics/body/body_medium_impact_hard3.wav", + "physics/body/body_medium_impact_hard4.wav", + "physics/body/body_medium_impact_hard5.wav", + "physics/body/body_medium_impact_hard6.wav", + }, + Break = + { + "physics/body/body_medium_break2.wav", + "physics/body/body_medium_break3.wav", + "physics/body/body_medium_break4.wav", + }, +} + +local bloodEmitter = nil + +local function HandleRagdollImpact(ent, data) + + ent.LastRagdollImpact = ent.LastRagdollImpact or 0 + + if bloodEmitter == nil then + bloodEmitter = ParticleEmitter(Vector(0, 0, 0), false) + end + + if CurTime() - ent.LastRagdollImpact > 0.05 then + + ent.LastRagdollImpact = CurTime() + + --PrintTable(data) + + local sndTable = nil + if data.Speed >= 600 then + sndTable = ImpactSounds.Break + elseif data.Speed >= 300 then + sndTable = ImpactSounds.Hard + elseif data.Speed >= 100 then + sndTable = ImpactSounds.Soft + end + + if sndTable then + local snd = table.Random(sndTable) + ent:EmitSound(snd) + end + + if data.Speed >= 130 then + local effectdata = EffectData() + effectdata:SetNormal(data.HitNormal) + effectdata:SetOrigin(data.HitPos) + effectdata:SetMagnitude(3) + effectdata:SetScale(10) + effectdata:SetFlags(3) + effectdata:SetColor(0) + util.Effect("bloodspray", effectdata, true, true) + + local effectdata = EffectData() + effectdata:SetNormal(data.HitNormal) + effectdata:SetOrigin(data.HitPos) + effectdata:SetMagnitude(data.Speed / 100) + effectdata:SetScale(10) + effectdata:SetFlags(3) + effectdata:SetColor(0) + util.Effect("BloodImpact", effectdata, true, true) + + util.Decal("Blood", data.HitPos + data.HitNormal, data.HitPos - data.HitNormal) + end + + end + +end + +function GM:HandleRagdollCreation(ragdoll) + + ragdoll:AddCallback("PhysicsCollide", HandleRagdollImpact) + +end diff --git a/gamemode/cl_scoreboard.lua b/gamemode/cl_scoreboard.lua new file mode 100644 index 00000000..9cde606d --- /dev/null +++ b/gamemode/cl_scoreboard.lua @@ -0,0 +1,289 @@ +-- Used base scoreboard for... base +local DbgPrint = GetLogging("Scoreboard") + +local function DrawPingMeter(x, y, ping) + surface.SetDrawColor(Color(90,90,92,200)) + surface.DrawRect(x,y+15,3,4) + surface.DrawRect(x+4,y+12,3,7) + surface.DrawRect(x+8,y+8,3,11) + surface.DrawRect(x+12,y+4,3,15) + + if ping <= 50 then + surface.SetDrawColor(Color(0,255,0,200)) + surface.DrawRect(x,y+15,3,4) + surface.DrawRect(x+4,y+12,3,7) + surface.DrawRect(x+8,y+8,3,11) + surface.DrawRect(x+12,y+4,3,15) + elseif ping <= 100 and ping > 50 then + surface.SetDrawColor(Color(255,227,0,200)) + surface.DrawRect(x,y+15,3,4) + surface.DrawRect(x+4,y+12,3,7) + surface.DrawRect(x+8,y+8,3,11) + elseif ping <= 150 and ping > 100 then + surface.SetDrawColor(Color(255,80,0,200)) + surface.DrawRect(x,y+15,3,4) + surface.DrawRect(x+4,y+12,3,7) + elseif ping > 150 then + surface.SetDrawColor(Color(255,0,0,200)) + surface.DrawRect(x,y+15,3,4) + end + surface.SetFont("ScoreboardDefaultSmall") + surface.SetTextColor(255,255,255,255) + surface.SetTextPos(x+20,y+4) + surface.DrawText(ping) +end + +surface.CreateFont( "ScoreboardDefault", { + font = "Roboto", + size = 22, + weight = 500, + antialias = true, +}) + +surface.CreateFont( "ScoreboardDefaultSmall", { + font = "Roboto", + size = 15, + weight = 400, + antialias = true, + shadow = true, +}) + +surface.CreateFont( "ScoreboardTitle", { + font = "HalfLife2", + size = 32, + weight = 700 +}) + +local PLAYER_PANEL = { + Init = function( self ) + + self.AvatarButton = self:Add( "DButton" ) + self.AvatarButton:Dock( LEFT ) + self.AvatarButton:DockMargin(6, 0, 0, 0) + self.AvatarButton:SetSize( 32, 32 ) + self.AvatarButton.DoClick = function() + usrm = DermaMenu() + usrp = usrm:AddOption("Steam profile", function() self.Player:ShowProfile() end) + usrp:SetIcon("icon16/vcard.png") + usrm:AddSpacer() + usrm:Open() + if LocalPlayer() ~= self.Player then + if self.Player:IsMuted() then + usrvm = usrm:AddOption("Unmute", function() self.Player:SetMuted(false) end) + usrvm:SetIcon("icon16/sound.png") + else + usrv = usrm:AddOption("Mute", function() self.Player:SetMuted(true) end) + usrv:SetIcon("icon16/sound_mute.png") + end + else return + end + end + + self.Avatar = vgui.Create( "AvatarImage", self.AvatarButton ) + self.Avatar:SetSize( 32, 32 ) + self.Avatar:DockMargin(6, 0, 0, 0) + self.Avatar:SetMouseInputEnabled( false ) + + self.Name = self:Add( "DLabel" ) + self.Name:Dock( FILL ) + self.Name:SetFont( "ScoreboardDefault" ) + self.Name:SetTextColor( Color( 250, 250, 250 ) ) + self.Name:DockMargin( 8, 0, 0, 0 ) + + self.Ping = self:Add( "DLabel" ) + self.Ping:Dock( RIGHT ) + self.Ping:DockMargin( 8, 0, 0, 0 ) + self.Ping:SetWidth( 50 ) + self.Ping:SetFont( "ScoreboardDefaultSmall" ) + self.Ping:SetTextColor( Color( 250, 250, 250 ) ) + self.Ping:DockPadding( 20, 0, 0, 0 ) + + self.Deaths = self:Add( "DLabel" ) + self.Deaths:Dock( RIGHT ) + self.Deaths:SetWidth( 50 ) + self.Deaths:SetFont( "ScoreboardDefault" ) + self.Deaths:SetTextColor( Color( 250, 250, 250 ) ) + self.Deaths:SetContentAlignment( 5 ) + + self.Kills = self:Add( "DLabel" ) + self.Kills:Dock( RIGHT ) + self.Kills:SetWidth( 50 ) + self.Kills:SetFont( "ScoreboardDefault" ) + self.Kills:SetTextColor( Color( 250, 250, 250 ) ) + self.Kills:SetContentAlignment( 5 ) + + self:Dock( TOP ) + self:DockPadding( 3, 3, 3, 3 ) + self:SetHeight( 32 + 3 * 2 ) + self:DockMargin( 2, 0, 2, 2 ) + + end, + + Setup = function( self, pl ) + + self.Player = pl + + self.Avatar:SetPlayer( pl ) + + self:Think( self ) + + end, + + Think = function( self ) + + if ( !IsValid( self.Player ) ) then + self:SetZPos( 9999 ) -- Causes a rebuild + self:Remove() + return + end + + if ( self.PName == nil or self.PName ~= self.Player:Nick() ) then + self.PName = self.Player:Nick() + self.Name:SetText( self.PName ) + end + + if ( self.NumKills == nil or self.NumKills ~= self.Player:Frags() ) then + self.NumKills = self.Player:Frags() + self.Kills:SetText( self.NumKills ) + end + + if ( self.NumDeaths == nil or self.NumDeaths ~= self.Player:Deaths() ) then + self.NumDeaths = self.Player:Deaths() + self.Deaths:SetText( self.NumDeaths ) + end + + if ( self.NumPing == nil or self.NumPing ~= self.Player:Ping() ) then + self.NumPing = self.Player:Ping() + self.Ping:SetText( "" ) + end + + if ( self.Player:Team() == TEAM_CONNECTING ) then + self:SetZPos( 2000 + self.Player:EntIndex() ) + return + end + + self:SetZPos( ( self.NumKills * -50 ) + self.NumDeaths + self.Player:EntIndex() ) + + end, + + Paint = function( self, w, h ) + + if ( !IsValid( self.Player ) ) then + return + end + + -- KNOXED: If player is alive it will have a yellow bar on the left, if connecting or dead the bar will be gray + if ( self.Player:Team() == TEAM_CONNECTING ) then + draw.RoundedBox(0,0,0,4,h, Color(93,93,93,200 )) + draw.RoundedBox(0, 4, 0, w, h, Color(0, 0, 0, 150)) + return + end + + if ( !self.Player:Alive() ) then + draw.RoundedBox(0,0,0,4,h, Color(93,93,93,200 )) + draw.RoundedBox(0, 4, 0, w, h, Color(0, 0, 0, 150)) + DrawPingMeter(650, 6,self.Player:Ping()) + return + end + + draw.RoundedBox(0,0,0,4,h, Color(255,227,0,200 )) + draw.RoundedBox(0, 4, 0, w, h, Color(0, 0, 0, 150)) + DrawPingMeter(650, 6,self.Player:Ping()) + + end +} + +PLAYERLINE = vgui.RegisterTable( PLAYER_PANEL, "DPanel" ) + +local SCOREBOARD_PANEL = { + Init = function( self ) + + self.Header = self:Add( "Panel" ) + self.Header:Dock( TOP ) + self.Header:SetHeight( 100 ) + + self.Name = self.Header:Add( "DLabel" ) + self.Name:SetFont( "ScoreboardTitle" ) + self.Name:SetTextColor( Color( 255, 255, 255, 255 ) ) + self.Name:Dock( TOP ) + self.Name:SetHeight( 40 ) + self.Name:SetContentAlignment( 5 ) + self.Name:SetExpensiveShadow( 2, Color( 0, 0, 0, 200 ) ) + + + self.Scores = self:Add( "DScrollPanel" ) + self.Scores:Dock( FILL ) + + end, + + PerformLayout = function( self ) + + self:SetSize( 700, ScrH() - 200 ) + self:SetPos( ScrW() / 2 - 350, 100 ) + + end, + + Paint = function( self, w, h ) + + draw.RoundedBox( 0, 1, 94, w-3, 1, Color(0, 0, 0, 150)) + surface.SetFont("ScoreboardDefaultSmall") + surface.SetTextColor( 255, 255, 255, 255 ) + surface.SetTextPos(1,80) + surface.DrawText( #player.GetAll() .. "/" .. game.MaxPlayers() .. " PLAYERS ON " .. string.upper(game.GetMap()) ) + surface.SetTextPos(545, 80) + surface.DrawText("KILLS") + surface.SetTextPos(590,80) + surface.DrawText("DEATHS") + surface.SetTextPos(650,80) + surface.DrawText("PING") + + end, + + Think = function( self, w, h ) + + self.Name:SetText( "HALF-LIFE'" ) + + local plyrs = player.GetAll() + for id, pl in pairs( plyrs ) do + + if ( IsValid( pl.ScoreEntry ) ) then continue end + + pl.ScoreEntry = vgui.CreateFromTable( PLAYERLINE, pl.ScoreEntry ) + pl.ScoreEntry:Setup( pl ) + + self.Scores:AddItem( pl.ScoreEntry ) + + end + + end +} + +SCOREBOARD = vgui.RegisterTable( SCOREBOARD_PANEL, "EditablePanel" ) + +function GM:ScoreboardShow() + + if ( !IsValid( g_Scoreboard ) ) then + g_Scoreboard = vgui.CreateFromTable( SCOREBOARD ) + end + + if ( IsValid( g_Scoreboard ) ) then + g_Scoreboard:Show() + g_Scoreboard:MakePopup() + end + return false + +end + + +function GM:ScoreboardHide() + + if ( IsValid(usrm)) then + usrm:Hide() + end + + if ( IsValid( g_Scoreboard ) ) then + g_Scoreboard:Hide() + end + return false + +end diff --git a/gamemode/cl_taunts.lua b/gamemode/cl_taunts.lua new file mode 100644 index 00000000..812627dd --- /dev/null +++ b/gamemode/cl_taunts.lua @@ -0,0 +1,243 @@ +include("sh_taunts.lua") + +local DbgPrint = GetLogging("Taunts") + +local TauntIndex = 1 +local TauntMaxDisplay = 3 -- Each direction +local TauntSelection = false + +surface.CreateFont("TauntFont", +{ + font = "Arial", + size = 30, + weight = 500, + blursize = 1, + scanlines = 0, + antialias = true, + underline = false, + italic = false, + strikeout = false, + symbol = false, + rotary = false, + shadow = false, + additive = false, + outline = true +}) + +surface.CreateFont("TauntFont2", +{ + font = "Arial", + size = 30, + weight = 100, + blursize = 0, + scanlines = 0, + antialias = true, + underline = false, + italic = false, + strikeout = false, + symbol = false, + rotary = false, + shadow = false, + additive = false, + outline = false +}) + +function DrawTauntElement(text, xpos, size, alpha, offset) + + local w, h = ScrW(), ScrH() + local x = 100 + local y = (h / 2) + xpos + offset = offset or 0 + --mat:Translate( Vector( w/2, h/2 ) ) + --mat:Rotate( Angle( 0,0,0 ) ) + + local mat1 = Matrix() + mat1:Scale( Vector(1, 1, 1) * size ) + mat1:SetTranslation( Vector( x, y, 0 ) ) + --mat:Translate( -Vector( w/2, h/2 ) ) + + render.PushFilterMag( TEXFILTER.ANISOTROPIC ) + render.PushFilterMin( TEXFILTER.ANISOTROPIC ) + + cam.PushModelMatrix(mat1) + surface.SetTextPos(offset, 0) + surface.SetFont("TauntFont") + surface.SetTextColor(0, 0, 0, alpha * 0.5) + surface.DrawText(text) + cam.PopModelMatrix() + + local mat2 = Matrix() + mat2:Scale( Vector(1, 1, 1) * size ) + mat2:SetTranslation( Vector( x, y, 0 ) ) + + cam.PushModelMatrix(mat2) + surface.SetTextPos(offset, 0) + surface.SetFont("TauntFont2") + surface.SetTextColor(255, 255, 255, alpha) + surface.DrawText(text) + cam.PopModelMatrix() + + render.PopFilterMag() + render.PopFilterMin() + + return w, h + +end + +function DrawTauntsMenu() + + local ply = LocalPlayer() + local gender = ply:GetGender() + local taunts = Taunts[gender] + local count = 0 + if taunts ~= nil then + count = #taunts + end + + if TauntIndex > count then + TauntIndex = count + end + if TauntIndex < 1 then + TauntIndex = 1 + end + + local back_count = math.Clamp(TauntIndex - 1, 0, TauntMaxDisplay) + local front_count = math.Clamp(count - (TauntIndex + 1), 0, TauntMaxDisplay) + local zpos = 0 + local xpos = 0 + local x = 1 + + local scrh = ScrH() + local scrw = ScrW() + local startx = scrh / 4 + local endx = scrh / 8 + + local size = 10.0 + local xpos = (3 * 20) + math.pow(3, 1.5) + + -- Back + local back_max = TauntIndex - TauntMaxDisplay + if back_max < 1 then + back_max = 1 + end + + local x = 1 + for i = (TauntIndex - 1), back_max, -1 do + local taunt = Taunts[gender][i] + if not taunt then + break + end + local alpha = (1 - (x / 4)) * 50 + DrawTauntElement(taunt.Name, xpos, 1.2 - (x / 3), alpha) + x = x + 1 + xpos = xpos - 35 - math.pow(x + 1, 1.1) + end + + local xpos = (3 * 20) + math.pow(3, 1.2) + 40 + + -- Current + local taunt = Taunts[gender][TauntIndex] + if not taunt then + return + end + + --text, xpos, size, alpha + local scaleTime = CurTime() * 4 + local offset = 10 + (math.sin(scaleTime) * math.cos(scaleTime)) * 10 + DrawTauntElement(taunt.Name, xpos, 1.3, 255, offset) + xpos = xpos + 50 + + -- Front + local front_max = TauntIndex + TauntMaxDisplay + if front_max > count then + front_max = count + end + + local x = 1 + for i = (TauntIndex + 1), front_max do + local taunt = Taunts[gender][i] + if not taunt then + break + end + local alpha = (1 - (x / 4)) * 50 + DrawTauntElement(taunt.Name, xpos, 1.2 - (x / 3), alpha) + x = x + 1 + xpos = xpos + 35 + math.pow(x + 1, 1.1) + end + +end + +function SendSelectedTaunt() + + local ply = LocalPlayer() + ply.LastTaunt = ply.LastTaunt or (RealTime() - 5) + + if RealTime() - ply.LastTaunt < 2 then + return false + end + + ply.LastTaunt = RealTime() + + local gender = ply:GetGender() + local taunts = Taunts[gender] + local count = #taunts + + if TauntIndex < 1 or TauntIndex > count then + return false + end + + local taunt = Taunts[gender][TauntIndex] + if not taunt then + return false + end + + local snd = table.Random(taunt.Sounds) + + net.Start("PlayerStartTaunt") + net.WriteFloat(TauntIndex) + net.SendToServer() +end + +hook.Add( "OnContextMenuOpen", "Lambda_Taunts", function() + + local ply = LocalPlayer() + if IsValid(ply) and ply:Alive() == false then + return + end + + TauntSelection = true + hook.Add("HUDPaint", "LambdaTaunts", DrawTauntsMenu) +end) + +hook.Add( "OnContextMenuClose", "Lambda_Taunts", function() + TauntSelection = false + SendSelectedTaunt() + hook.Remove("HUDPaint", "LambdaTaunts") +end) + +--[[ +concommand.Add("+showtaunts", function() + TauntSelection = true + hook.Add("HUDPaint", "LambdaTaunts", DrawTauntsMenu) +end) + +concommand.Add("-showtaunts", function() + TauntSelection = false + SendSelectedTaunt() + hook.Remove("HUDPaint", "LambdaTaunts") +end) +]] + +hook.Add("PlayerBindPress", "LambdaTaunts", function(ply, bind, pressed) + + if TauntSelection then + if bind == "invnext" and pressed then + TauntIndex = TauntIndex + 1 + return true + elseif bind == "invprev" and pressed then + TauntIndex = TauntIndex - 1 + return true + end + end + +end) diff --git a/gamemode/gametypes/hl2.lua b/gamemode/gametypes/hl2.lua new file mode 100644 index 00000000..58847e51 --- /dev/null +++ b/gamemode/gametypes/hl2.lua @@ -0,0 +1,296 @@ +if SERVER then + AddCSLuaFile() +end + +local GAMETYPE = {} + +// Include Mapscript. +GAMETYPE.MapScript = include("hl2/mapscripts/" .. game.GetMap():lower() .. ".lua") + +GAMETYPE.MapList = +{ + "d1_trainstation_01", + "d1_trainstation_02", + "d1_trainstation_03", + "d1_trainstation_04", + "d1_trainstation_05", + "d1_trainstation_06", + "d1_canals_01", + "d1_canals_01a", + "d1_canals_02", + "d1_canals_03", + "d1_canals_05", + "d1_canals_06", + "d1_canals_07", + "d1_canals_08", + "d1_canals_09", + "d1_canals_10", + "d1_canals_11", + "d1_canals_12", + "d1_canals_13", + "d1_eli_01", + "d1_eli_02", + "d1_town_01", + "d1_town_01a", + "d1_town_02", + "d1_town_03", + "d1_town_02", + "d1_town_02a", + "d1_town_04", + "d1_town_05", + "d2_coast_01", + "d2_coast_03", + "d2_coast_04", + "d2_coast_05", + "d2_coast_07", + "d2_coast_08", + "d2_coast_07", + "d2_coast_09", + "d2_coast_10", + "d2_coast_11", + "d2_coast_12", + "d2_prison_01", + "d2_prison_02", + "d2_prison_03", + "d2_prison_04", + "d2_prison_05", + "d2_prison_06", + "d2_prison_07", + "d2_prison_08", + "d3_c17_01", + "d3_c17_02", + "d3_c17_03", + "d3_c17_04", + "d3_c17_05", + "d3_c17_06a", + "d3_c17_06b", + "d3_c17_07", + "d3_c17_08", + "d3_c17_09", + "d3_c17_10a", + "d3_c17_10b", + "d3_c17_11", + "d3_c17_12", + "d3_c17_12b", + "d3_c17_13", + "d3_citadel_01", + "d3_citadel_02", + "d3_citadel_03", + "d3_citadel_04", + "d3_citadel_05", + "d3_breen_01" +} + +GAMETYPE.ClassesEnemyNPC = +{ + ["npc_metropolice"] = true, + ["npc_combine"] = true, + ["npc_combine_s"] = true, + ["npc_zombie"] = true, + ["npc_headcrab"] = true, +} + +GAMETYPE.ImportantPlayerNPCNames = +{ + ["arrest_cit_female"] = true, -- Come on, give her some slack. + ["boxcar_human"] = true, + ["boxcar_vort"] = true, + ["citizen_greeter"] = true, + ["mary"] = true, + ["Al"] = true, + ["Arlene"] = true, + ["citizen_b_regular_original"] = true, + ["gatekeeper"] = true, + ["Chester"] = true, + ["lamarr_jumper"] = true, + ["stanley"] = true, + ["warehouse_citizen_jacobs"] = true, + ["warehouse_citizen"] = true, + ["warehouse_citizen_leon"] = true, + ["winston"] = true, + ["vort_Lab"] = true, + ["vort_lab"] = true, + ["rocketman"] = true, -- Mission critical + ["citizen_a_medic_original"] = true, + ["citizen_a_ammo_original"] = true, + ["vort"] = true, + ["citizen_3"] = true, + ["vortigaunt_bugbait"] = true, -- Well guess why + ["stanley"] = true, -- He will loose his friend! +} + +GAMETYPE.ImportantPlayerNPCClasses = +{ + ["npc_alyx"] = true, + ["npc_barney"] = true, + ["npc_odessa"] = true, + ["npc_kleiner"] = true, + ["npc_dog"] = true, + ["npc_mossman"] = true, +} + +function GAMETYPE:ShouldRestartRound() + + local playerCount = 0 + local aliveCount = 0 + + -- Collect how many players exist and how many are alive, in case they are all dead + -- we have to restart the round. + for _,ply in pairs(player.GetAll()) do + if ply:Alive() then + aliveCount = aliveCount + 1 + end + playerCount = playerCount + 1 + end + + if playerCount > 0 and aliveCount == 0 then + DbgPrint("All players are dead, restart required") + return true + end + + return false + +end + +hook.Add("LambdaLoadGameTypes", "HL2GameType", function(gametypes) + gametypes:Add("hl2", GAMETYPE) +end) + +if CLIENT then + language.Add("HL2_Chapter1_Title", "POINT INSERTION") + language.Add("HL2_Chapter2_Title", "\"A RED LETTER DAY\"") + language.Add("HL2_Chapter3_Title", "ROUTE KANAL") + language.Add("HL2_Chapter4_Title", "WATER HAZARD") + language.Add("HL2_Chapter5_Title", "BLACK MESA EAST") + language.Add("HL2_Chapter6_Title", "\"WE DON'T GO TO RAVENHOLM...\"") + language.Add("HL2_Chapter7_Title", "HIGHWAY 17") + language.Add("HL2_Chapter8_Title", "SANDTRAPS") + language.Add("HL2_Chapter9_Title", "NOVA PROSPEKT") + language.Add("HL2_Chapter9a_Title", "ENTANGLEMENT") + language.Add("HL2_Chapter10_Title", "ANTICITIZEN ONE") + language.Add("HL2_Chapter11_Title", "\"FOLLOW FREEMAN!\"") + language.Add("HL2_Chapter12_Title", "OUR BENEFACTORS") + language.Add("HL2_Chapter13_Title", "DARK ENERGY") + language.Add("HL2_Chapter14_Title", "CREDITS") + + language.Add("hl2_AmmoFull", "FULL") + + language.Add("HL2_GameOver_Object", "ASSIGNMENT: TERMINATED\nSUBJECT: FREEMAN\nREASON: FAILURE TO PRESERVE MISSION-CRITICAL RESOURCES") + language.Add("HL2_GameOver_Ally", "ASSIGNMENT: TERMINATED\nSUBJECT: FREEMAN\nREASON: FAILURE TO PRESERVE MISSION-CRITICAL PERSONNEL") + language.Add("HL2_GameOver_Timer", "ASSIGNMENT: TERMINATED\nSUBJECT: FREEMAN\nREASON: FAILURE TO PREVENT TIME-CRITICAL SEQUENCE") + language.Add("HL2_GameOver_Stuck", "ASSIGNMENT: TERMINATED\nSUBJECT: FREEMAN\nREASON: DEMONSTRATION OF EXCEEDINGLY POOR JUDGMENT") + + language.Add("HL2_357Handgun", ".357 MAGNUM") + language.Add("HL2_Pulse_Rifle", "PULSE-RIFLE") + language.Add("HL2_Bugbait", "BUGBAIT") + language.Add("HL2_Crossbow", "CROSSBOW") + language.Add("HL2_Crowbar", "CROWBAR") + language.Add("HL2_Grenade", "GRENADE") + language.Add("HL2_GravityGun", "GRAVITY GUN") + language.Add("HL2_Pistol", "9MM PISTOL") + language.Add("HL2_RPG", "RPG") + language.Add("HL2_Shotgun", "SHOTGUN") + language.Add("HL2_SMG1", "SMG") + + language.Add("HL2_Saved", "Saved...") + + language.Add("HL2_Credits_VoicesTitle", "Voices:") + language.Add("HL2_Credits_Eli", "Robert Guillaume - Dr. Eli Vance") + language.Add("HL2_Credits_Breen", "Robert Culp - Dr. Wallace Breen") + language.Add("HL2_Credits_Vortigaunt", "Lou Gossett, Jr. - Vortigaunt") + language.Add("HL2_Credits_Mossman", "Michelle Forbes - Dr. Judith Mossman") + language.Add("HL2_Credits_Alyx", "Merle Dandridge - Alyx Vance") + language.Add("HL2_Credits_Barney", "Mike Shapiro - Barney Calhoun") + language.Add("HL2_Credits_Gman", "Mike Shapiro - Gman") + language.Add("HL2_Credits_Kleiner", "Harry S. Robins - Dr. Isaac Kleiner") + language.Add("HL2_Credits_Grigori", "Jim French - Father Grigori") + language.Add("HL2_Credits_Misc1", "John Patrick Lowrie - Citizens\\Misc. characters") + language.Add("HL2_Credits_Misc2", "Mary Kae Irvin - Citizens\\Misc. characters") + language.Add("HL2_Credits_Overwatch", "Ellen McLain - Overwatch") + + language.Add("HL2_Credits_VoiceCastingTitle", "Voice Casting:") + language.Add("HL2_Credits_VoiceCastingText", "Shana Landsburg\\Teri Fiddleman") + + language.Add("HL2_Credits_VoiceRecordingTitle", "Voice Recording:") + language.Add("HL2_Credits_VoiceRecordingText1", "Pure Audio, Seattle, WA") + language.Add("HL2_Credits_VoiceRecordingText2", "LA Studios, LA, CA") + + language.Add("HL2_Credits_VoiceSchedulingTitle", "Voice recording scheduling and logistics:") + language.Add("HL2_Credits_VoiceSchedulingText", "Pat Cockburn, Pure Audio") + + language.Add("HL2_Credits_LegalTeam", "Crack Legal Team:") + language.Add("HL2_Credits_FacesThanks", "Thanks to the following for the use of their faces:") + language.Add("HL2_Credits_SpecialThanks", "Special thanks to everyone at:") + + language.Add("HL2_HIT_CANCOP_WITHCAN_NAME", "Defiant") + language.Add("HL2_HIT_CANCOP_WITHCAN_DESC", "Hit the trashcan cop with the can.") + language.Add("HL2_PUT_CANINTRASH_NAME", "Submissive") + language.Add("HL2_PUT_CANINTRASH_DESC", "Put the can in the trash.") + language.Add("HL2_ESCAPE_APARTMENTRAID_NAME", "Malcontent") + language.Add("HL2_ESCAPE_APARTMENTRAID_DESC", "Escape the apartment block raid.") + language.Add("HL2_BREAK_MINITELEPORTER_NAME", "What cat?") + language.Add("HL2_BREAK_MINITELEPORTER_DESC", "Break the mini-teleporter in Kleiner's lab.") + language.Add("HL2_GET_CROWBAR_NAME", "Trusty Hardware") + language.Add("HL2_GET_CROWBAR_DESC", "Get the crowbar.") + language.Add("HL2_KILL_BARNACLESWITHBARREL_NAME", "Barnacle Bowling") + language.Add("HL2_KILL_BARNACLESWITHBARREL_DESC", "Kill five barnacles with one barrel.") + language.Add("HL2_GET_AIRBOAT_NAME", "Anchor's Aweigh!") + language.Add("HL2_GET_AIRBOAT_DESC", "Get the airboat.") + language.Add("HL2_FLOAT_WITHAIRBOAT_NAME", "Catching Air") + language.Add("HL2_FLOAT_WITHAIRBOAT_DESC", "Float five seconds in the air with the airboat.") + language.Add("HL2_GET_AIRBOATGUN_NAME", "Heavy Weapons") + language.Add("HL2_GET_AIRBOATGUN_DESC", "Get the airboat's mounted gun.") + language.Add("HL2_FIND_VORTIGAUNTCAVE_NAME", "Vorticough") + language.Add("HL2_FIND_VORTIGAUNTCAVE_DESC", "Discover the hidden singing vortigaunt cave in chapter Water Hazard.") + language.Add("HL2_KILL_CHOPPER_NAME", "Revenge!") + language.Add("HL2_KILL_CHOPPER_DESC", "Destroy the hunter-chopper in Half-Life 2.") + language.Add("HL2_FIND_HEVFACEPLATE_NAME", "Blast from the Past") + language.Add("HL2_FIND_HEVFACEPLATE_DESC", "Find the HEV Suit Charger faceplate in Eli's scrapyard.") + language.Add("HL2_GET_GRAVITYGUN_NAME", "Zero-Point Energy") + language.Add("HL2_GET_GRAVITYGUN_DESC", "Get the Gravity Gun in Black Mesa East.") + language.Add("HL2_MAKEABASKET_NAME", "Two Points") + language.Add("HL2_MAKEABASKET_DESC", "Use DOG's ball to make a basket in Eli's scrapyard.") + language.Add("HL2_BEAT_RAVENHOLM_NOWEAPONS_NAME", "Zombie Chopper") + language.Add("HL2_BEAT_RAVENHOLM_NOWEAPONS_DESC", "Play through Ravenholm using only the Gravity Gun.") + language.Add("HL2_BEAT_CEMETERY_NAME", "Hallowed Ground") + language.Add("HL2_BEAT_CEMETERY_DESC", "Escort Grigori safely through the church cemetery.") + language.Add("HL2_KILL_ENEMIES_WITHCRANE_NAME", "OSHA Violation") + language.Add("HL2_KILL_ENEMIES_WITHCRANE_DESC", "Kill 3 enemies using the crane.") + language.Add("HL2_PIN_SOLDIER_TOBILLBOARD_NAME", "Targetted Advertising") + language.Add("HL2_PIN_SOLDIER_TOBILLBOARD_DESC", "Pin a soldier to the billboard in chapter Highway 17.") + language.Add("HL2_KILL_ODESSAGUNSHIP_NAME", "Where Cubbage Fears to Tread") + language.Add("HL2_KILL_ODESSAGUNSHIP_DESC", "Defend Little Odessa from the gunship attack.") + language.Add("HL2_KILL_THREEGUNSHIPS_NAME", "One Man Army") + language.Add("HL2_KILL_THREEGUNSHIPS_DESC", "Destroy six gunships in Half-Life 2.") + language.Add("HL2_BEAT_DONTTOUCHSAND_NAME", "Keep Off the Sand!") + language.Add("HL2_BEAT_DONTTOUCHSAND_DESC", "Cross the antlion beach in chapter Sandtraps without touching the sand.") + language.Add("HL2_KILL_BOTHPRISONGUNSHIPS_NAME", "Uninvited Guest") + language.Add("HL2_KILL_BOTHPRISONGUNSHIPS_DESC", "Kill both gunships in the Nova Prospekt courtyard.") + language.Add("HL2_KILL_ENEMIES_WITHANTLIONS_NAME", "Bug Hunt") + language.Add("HL2_KILL_ENEMIES_WITHANTLIONS_DESC", "Use the antlions to kill 50 enemies.") + language.Add("HL2_KILL_ENEMY_WITHTOILET_NAME", "Flushed") + language.Add("HL2_KILL_ENEMY_WITHTOILET_DESC", "Kill an enemy with a toilet.") + language.Add("HL2_BEAT_TURRETSTANDOFF2_NAME", "Warden Freeman") + language.Add("HL2_BEAT_TURRETSTANDOFF2_DESC", "Survive the second turret standoff in Nova Prospekt.") + language.Add("HL2_FOLLOWFREEMAN_NAME", "Follow Freeman") + language.Add("HL2_FOLLOWFREEMAN_DESC", "Gain command of a squad of rebels in the uprising.") + language.Add("HL2_BEAT_TOXICTUNNEL_NAME", "Radiation Levels Detected") + language.Add("HL2_BEAT_TOXICTUNNEL_DESC", "Get through the toxic tunnel under City 17 in Half-Life 2.") + language.Add("HL2_BEAT_PLAZASTANDOFF_NAME", "Plaza Defender") + language.Add("HL2_BEAT_PLAZASTANDOFF_DESC", "Survive the generator plaza standoff in chapter Anticitizen One.") + language.Add("HL2_KILL_ALLC1709SNIPERS_NAME", "Counter-Sniper") + language.Add("HL2_KILL_ALLC1709SNIPERS_DESC", "Kill all of the snipers in City 17.") + language.Add("HL2_BEAT_SUPRESSIONDEVICE_NAME", "Fight the Power") + language.Add("HL2_BEAT_SUPRESSIONDEVICE_DESC", "Shut down the supression device by disabling its generators.") + language.Add("HL2_BEAT_C1713STRIDERSTANDOFF_NAME", "Giant Killer") + language.Add("HL2_BEAT_C1713STRIDERSTANDOFF_DESC", "Survive the rooftop strider battle in the ruins of City 17.") + language.Add("HL2_DISINTEGRATE_SOLDIERSINFIELD_NAME", "Atomizer") + language.Add("HL2_DISINTEGRATE_SOLDIERSINFIELD_DESC", "Disintegrate 15 soldiers by throwing them into a Combine ball field.") + language.Add("HL2_BEAT_GAME_NAME", "Singularity Collapse") + language.Add("HL2_BEAT_GAME_DESC", "Destroy the Citadel's reactor core.") + language.Add("HL2_FIND_ALLLAMBDAS_NAME", "Lambda Locator") + language.Add("HL2_FIND_ALLLAMBDAS_DESC", "Find all lambda caches in Half-Life 2.") + + language.Add("World", "Cruel World") + language.Add("base_ai", "Creature") +end diff --git a/gamemode/gametypes/hl2/mapscripts/d1_canals_01.lua b/gamemode/gametypes/hl2/mapscripts/d1_canals_01.lua new file mode 100644 index 00000000..38e64879 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_canals_01.lua @@ -0,0 +1,104 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + }, + Ammo = {}, + Armor = 0, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ + ["boxcar_closedoor"] = { "BeginSequence" }, + ["brush_boxcar_door_PClip"] = { "Enable" }, +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["start_item_template"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(650.433105, -6424.663086, 540.031250) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(614.625732, -6519.078613, 540.031250), + Angle(0,0,0), + Vector(-100, -100, 0), + Vector(100, 100, 180) + ) + checkpointTrigger1.OnTrigger = function() + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(877.780457, 2621.807617, -55.060749), Ang = Angle(0, 180, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(855.660400, 2638.366943, -51.748753), + Angle(0,0,0), + Vector(-100, -100, 0), + Vector(100, 100, 180) + ) + checkpointTrigger2.OnTrigger = function() + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + -- 447.302185 -2656.709961 576.031250 + local checkpoint3 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(447.302185, -2656.709961, 576.031250), Ang = Angle(0, 180, 0) }) + local checkpointTrigger3 = ents.Create("trigger_once") + checkpointTrigger3:SetupTrigger( + Vector(447.302185, -2656.709961, 576.031250), + Angle(0,0,0), + Vector(-50, -50, 0), + Vector(50, 50, 180) + ) + checkpointTrigger3.OnTrigger = function() + GAMEMODE:SetPlayerCheckpoint(checkpoint3) + end + + -- 544.810791 -3423.548584 322.719330 + local checkpoint4 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(473.498352, -3530.257324, 256.031250), Ang = Angle(0, 90, 0) }) + local checkpointTrigger4 = ents.Create("trigger_once") + checkpointTrigger4:SetupTrigger( + Vector(544.810791, -3423.548584, 322.719330), + Angle(0,0,0), + Vector(-70, -70, -50), + Vector(70, 70, 100) + ) + checkpointTrigger4.OnTrigger = function() + GAMEMODE:SetPlayerCheckpoint(checkpoint4) + end + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d1_canals_01a.lua b/gamemode/gametypes/hl2/mapscripts/d1_canals_01a.lua new file mode 100644 index 00000000..9cd8c510 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_canals_01a.lua @@ -0,0 +1,228 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + }, + Ammo = + { + ["Pistol"] = 10, + }, + Armor = 0, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["spawnitems_template"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-1183.380615, 6344.419922, -59.326172), Ang = Angle(0, -180, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(-1183.380615, 6344.419922, 6.326172), + Angle(0,0,0), + Vector(-100, -100, 0), + Vector(100, 100, 180) + ) + checkpointTrigger1.OnTrigger = function() + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + --- 1215.137695 6346.565430 -59.008865 + + + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-3002.406494, 7870.711426, 12.031250), Ang = Angle(0, 90, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(-3002.406494, 7870.711426, 48.031250), + Angle(0,0,0), + Vector(-100, -100, 0), + Vector(100, 100, 180) + ) + checkpointTrigger2.OnTrigger = function() + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + -- 2104.908447 5759.881348 -95.968750 + local checkpoint3 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(2104.908447, 5759.881348, -95.968750), Ang = Angle(0, 45, 0) }) + local checkpointTrigger3 = ents.Create("trigger_once") + checkpointTrigger3:SetupTrigger( + Vector(2104.908447, 5759.881348, -95.968750), + Angle(0,0,0), + Vector(-100, -100, 0), + Vector(100, 100, 180) + ) + checkpointTrigger3.OnTrigger = function() + GAMEMODE:SetPlayerCheckpoint(checkpoint3) + end + + local npcMaker1 = ents.Create("npc_maker") + npcMaker1:SetPos(Vector(-2174.593262, 9086.971680, 288.031250)) + npcMaker1:SetAngles(Angle(0, 180, 0)) + npcMaker1:SetKeyValue("NPCType", "npc_metropolice") + npcMaker1:SetKeyValue("additionalequipment", "weapon_pistol") + npcMaker1:SetKeyValue("MaxNPCCount", "4") + npcMaker1:SetKeyValue("MaxLiveChildren", "4") + npcMaker1:SetKeyValue("StartDisabled", "1") + npcMaker1:SetKeyValue("NPCSquadName", "Overwatch") + npcMaker1:Spawn() + + local npcMaker2 = ents.Create("npc_maker") + npcMaker2:SetPos(Vector(-3895.005615, 9614.399414, 288.031250)) + npcMaker2:SetAngles(Angle(0, 180, 0)) + npcMaker2:SetKeyValue("spawnflags", SF_NPCMAKER_HIDEFROMPLAYER + SF_NPCMAKER_ALWAYSUSERADIUS) + npcMaker2:SetKeyValue("NPCType", "npc_metropolice") + npcMaker2:SetKeyValue("additionalequipment", "weapon_pistol") + npcMaker2:SetKeyValue("MaxNPCCount", "2") + npcMaker2:SetKeyValue("MaxLiveChildren", "2") + npcMaker2:SetKeyValue("StartDisabled", "1") + npcMaker2:SetKeyValue("NPCSquadName", "Overwatch") + npcMaker2:SetKeyValue("Radius", "200") + npcMaker2:SetName("lambda_npc_maker2") + npcMaker2:Spawn() + + -- gallery_destgroup_1 + ents.WaitForEntityByName("gallery_destgroup_1", function(ent) + ent:SetPos(Vector(-47.880901, 6160.045898, -58.842937)) + end, true) + + -- room3_cop + -- Lets not wait for the explosion, thats boring. + ents.WaitForEntityByName("room3_cop", function(ent) + ent:Fire("AddOutput", "OnDeath gallerycop_maker2,Enable") + ent:Fire("AddOutput", "OnDeath gallerycop_maker3,Enable") + end) + + --1251.081177 5989.771484 -95.968750 + --[[ + local trigger1 = ents.Create("trigger_once") + trigger1:SetupTrigger( + Vector(1251.081177, 5989.771484, -95.968750), + Angle(0,0,0), + Vector(-150, -150, 0), + Vector(150, 150, 180) + ) + trigger1.OnTrigger = function() + TriggerOutputs({ + {"gallery_start_relay", "Trigger", 0.0, ""}, + --{"escape_foil_brush", "Kill", 0.2, ""}, + {"gallerycop_maker1", "Enable", 0.0, ""}, + }) + end + ]] + ents.WaitForEntityByName("massacre_initiate_trigger", function(ent) + ent:Fire("AddOutput", "OnTrigger gallery_start_relay,Trigger,,0.0") + ent:Fire("AddOutput", "OnTrigger gallerycop_maker1,Enable,,0.0") + ent:Fire("AddOutput", "OnTrigger lambda_npc_maker2,Enable,,0.0") + end) + + -- -2849.247314 8805.366211 47.039879 + local trigger2 = ents.Create("trigger_once") + trigger2:SetupTrigger( + Vector(-2849.247314, 8805.366211, 47.039879), + Angle(0,0,0), + Vector(-150, -150, 0), + Vector(150, 150, 180) + ) + trigger2.OnTrigger = function() + npcMaker1:Fire("Enable") + npcMaker2:Fire("Enable") + end + + local npcMaker3 = ents.Create("npc_maker") + npcMaker3:SetPos(Vector(-3001.867676, 6401.143066, -88.595261)) + npcMaker3:SetAngles(Angle(0, 180, 0)) + npcMaker3:SetKeyValue("spawnflags", SF_NPCMAKER_HIDEFROMPLAYER + SF_NPCMAKER_ALWAYSUSERADIUS) + npcMaker3:SetKeyValue("NPCType", "npc_metropolice") + npcMaker3:SetKeyValue("additionalequipment", "weapon_pistol") + npcMaker3:SetKeyValue("MaxNPCCount", "2") + npcMaker3:SetKeyValue("MaxLiveChildren", "2") + npcMaker3:SetKeyValue("StartDisabled", "1") + npcMaker3:SetKeyValue("NPCSquadName", "mudcopsquad") + npcMaker3:SetKeyValue("Radius", "200") + npcMaker3:SetName("lambda_npc_maker3") + npcMaker3:Spawn() + + -- -2956.739746 6570.918945 -95.968781 + local npcMaker4 = ents.Create("npc_maker") + npcMaker4:SetPos(Vector(-2264.835693, 6979.781250, 128.031250)) + npcMaker4:SetAngles(Angle(0, 180, 0)) + npcMaker4:SetKeyValue("spawnflags", SF_NPCMAKER_HIDEFROMPLAYER + SF_NPCMAKER_ALWAYSUSERADIUS) + npcMaker4:SetKeyValue("NPCType", "npc_metropolice") + npcMaker4:SetKeyValue("additionalequipment", "weapon_pistol") + npcMaker4:SetKeyValue("MaxNPCCount", "8") + npcMaker4:SetKeyValue("MaxLiveChildren", "2") + npcMaker4:SetKeyValue("StartDisabled", "1") + npcMaker4:SetKeyValue("NPCSquadName", "mudcopsquad") + --npcMaker4:SetKeyValue("Radius", "300") + npcMaker4:SetName("lambda_npc_maker4") + npcMaker4:Spawn() + + -- -3456.227539 6972.550293 128.031250 + local npcMaker5 = ents.Create("npc_maker") + npcMaker5:SetPos(Vector(-3552.302979, 6977.757324, 128.031250)) + npcMaker5:SetAngles(Angle(0, 180, 0)) + npcMaker5:SetKeyValue("spawnflags", SF_NPCMAKER_HIDEFROMPLAYER) + npcMaker5:SetKeyValue("NPCType", "npc_metropolice") + npcMaker5:SetKeyValue("additionalequipment", "weapon_pistol") + npcMaker5:SetKeyValue("MaxNPCCount", "3") + npcMaker5:SetKeyValue("MaxLiveChildren", "1") + npcMaker5:SetKeyValue("StartDisabled", "1") + npcMaker5:SetKeyValue("NPCSquadName", "mudcopsquad") + --npcMaker5:SetKeyValue("Radius", "300") + npcMaker5:SetName("lambda_npc_maker4") + npcMaker5:Spawn() + + + -- -2620.882813 5306.772949 -45.723671 + local trigger3 = ents.Create("trigger_once") + trigger3:SetupTrigger( + Vector(-2620.882813, 5306.772949, -45.723671), + Angle(0,0,0), + Vector(-150, -150, 0), + Vector(150, 150, 180) + ) + trigger3.OnTrigger = function() + npcMaker3:Fire("Enable") + npcMaker4:Fire("Enable") + npcMaker5:Fire("Enable") + end + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d1_canals_02.lua b/gamemode/gametypes/hl2/mapscripts/d1_canals_02.lua new file mode 100644 index 00000000..7ff28905 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_canals_02.lua @@ -0,0 +1,82 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + }, + Ammo = + { + ["Pistol"] = 10, + }, + Armor = 0, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["global_newgame_spawner_suit"] = true, + ["global_newgame_spawner_crowbar"] = true, + ["global_newgame_spawner_pistol"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- The map has two spawns both with the priority flag, so we gonna wipe them. + for _,v in pairs(ents.FindByClass("info_player_start")) do + DbgPrint("Removing start: " .. tostring(v)) + v:Remove() + end + -- And create a default one. + local spawn = ents.CreateSimple("info_player_start", { Pos = Vector(2896, -2272, -604), Ang = Angle(0, 90, 0) }) + spawn.MasterSpawn = true + + ents.RemoveByClass("prop_physics", Vector(367, 70, -846.01397705078)) -- wooden plate shortcut + + -- -114.632774 -1179.170288 -847.968750 + + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-114.632774, -1179.170288, -847.968750), Ang = Angle(0, 90, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(-114.632774, -1179.170288, -847.968750), + Angle(0,0,0), + Vector(-100, -100, 0), + Vector(100, 100, 180) + ) + checkpointTrigger1.OnTrigger = function() + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d1_canals_03.lua b/gamemode/gametypes/hl2/mapscripts/d1_canals_03.lua new file mode 100644 index 00000000..fbc3c030 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_canals_03.lua @@ -0,0 +1,159 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + }, + Ammo = + { + ["Pistol"] = 40, + }, + Armor = 0, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["global_newgame_template"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-722.162354, 1341.204834, -831.968750), Ang = Angle(0, 135, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(-722.162354, 1341.204834, -831.968750), + Angle(0, 0, 0), + Vector(-100, -100, 0), + Vector(100, 100, 180) + ) + checkpointTrigger1.OnTrigger = function() + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-1368.427856, -69.149689, -1023.968750), Ang = Angle(0, 0, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(-1058.438110, -66.407013, -959.968750), + Angle(0, 0, 0), + Vector(-100, -100, 0), + Vector(100, 100, 180) + ) + checkpointTrigger2.OnTrigger = function() + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + local matt + ents.WaitForEntityByName("matt", function(ent) + matt = ent + matt.FilterDamage = true + end) + + GAMEMODE:WaitForInput("lcs_matt_survived", "Start", function() + if IsValid(matt) then + matt.FilterDamage = false -- Feel free to die now. + end + end) + + -- Rename it, we fire it via a different output + ents.WaitForEntityByName("math_manhack_death_coutner", function(ent) + ent:SetName("stub_math_manhack_death_coutner") + end) + + ents.WaitForEntityByName("underground_script_matt_spawn_mh1", function(ent) + ent:Fire("AddOutput", "OnAllSpawnedDead logic_matt_survival,Trigger") + end) + + local checkpoint3 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-1833.402344, -775.765564, -895.968750), Ang = Angle(0, -110, 0) }) + local checkpointTrigger3 = ents.Create("trigger_once") + checkpointTrigger3:SetupTrigger( + Vector(-1808.799927, -958.450073, -895.968750), + Angle(0, 0, 0), + Vector(-100, -100, 0), + Vector(100, 100, 180) + ) + checkpointTrigger3.OnTrigger = function() + GAMEMODE:SetPlayerCheckpoint(checkpoint3) + end + + -- -446.415466 -526.288147 -1017.968750 + local checkpoint4 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-347.239502, -525.000366, -1017.968750), Ang = Angle(0, -180, 0) }) + local checkpointTrigger4 = ents.Create("trigger_once") + checkpointTrigger4:SetupTrigger( + Vector(-446.415466, -526.288147, -1017.968750), + Angle(0, 0, 0), + Vector(-60, -60, 0), + Vector(60, 60, 60) + ) + checkpointTrigger4.OnTrigger = function() + GAMEMODE:SetPlayerCheckpoint(checkpoint4) + end + + -- -74.684479 -1155.334595 -915.968750 + local checkpoint5 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-361.833801, -1075.059692, -959.968750), Ang = Angle(0, 130, 0) }) + local checkpointTrigger5 = ents.Create("trigger_once") + checkpointTrigger5:SetupTrigger( + Vector(-74.684479, -1155.334595, -915.968750), + Angle(0, 0, 0), + Vector(-60, -60, 0), + Vector(60, 60, 60) + ) + checkpointTrigger5.OnTrigger = function() + GAMEMODE:SetPlayerCheckpoint(checkpoint5) + end + + local a = ents.CreateSimple("prop_physics_override", { + Pos = Vector(-2153.951416, -852.403381, -1028.920410), + Ang = Angle(0.107, -1.445, 8.021), + Model = "models/props_wasteland/dockplank01a.mdl", + SpawnFlags = bit.bor(2, 8), + KeyValues = { ["health"] = 0, }, + UnFreezable = true, + }) + a:Activate() + + local b = ents.CreateSimple("prop_physics_override", { + Pos = Vector(-2133.457275, -851.055847, -1028.304565), + Ang = Angle(-0.798, 175.696, -7.717), + Model = "models/props_wasteland/dockplank01b.mdl", + SpawnFlags = bit.bor(2, 8), + KeyValues = { ["health"] = 0, }, + UnFreezable = true, + }) + b:Activate() + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d1_canals_05.lua b/gamemode/gametypes/hl2/mapscripts/d1_canals_05.lua new file mode 100644 index 00000000..e5f4d94b --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_canals_05.lua @@ -0,0 +1,83 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + }, + Ammo = + { + ["Pistol"] = 60, + ["SMG1"] = 60, + }, + Armor = 0, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["global_newgame_entmaker"] = true, + ["relay_rockfall_start"] = true, -- Don't do that, its trivial. +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(4149.820313, 3446.334229, -466.530853), Ang = Angle(0, -66, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(4236.846191, 3261.946289, -474.814972), + Angle(0, 0, 0), + Vector(-100, -100, 0), + Vector(100, 100, 180) + ) + checkpointTrigger1.OnTrigger = function() + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(7352.527344, 1597.768555, -447.968750), Ang = Angle(0, -90, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(6770.862793, 1569.191040, -447.968750), + Angle(0, 0, 0), + Vector(-100, -100, 0), + Vector(100, 100, 180) + ) + checkpointTrigger2.OnTrigger = function() + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d1_canals_06.lua b/gamemode/gametypes/hl2/mapscripts/d1_canals_06.lua new file mode 100644 index 00000000..8eedd1da --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_canals_06.lua @@ -0,0 +1,58 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + }, + Ammo = + { + ["Pistol"] = 60, + ["SMG1"] = 60, + }, + Armor = 0, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["global_newgame_entmaker"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d1_canals_07.lua b/gamemode/gametypes/hl2/mapscripts/d1_canals_07.lua new file mode 100644 index 00000000..d4d9030e --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_canals_07.lua @@ -0,0 +1,127 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + }, + Ammo = + { + ["Pistol"] = 60, + ["SMG1"] = 60, + }, + Armor = 0, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["global_newgame_entmaker"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(11292.084961, 2207.724365, -255.968750), Ang = Angle(0, -90, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(11296.274414, 2074.708008, -255.968750), + Angle(0, 0, 0), + Vector(-100, -100, 0), + Vector(100, 100, 180) + ) + checkpointTrigger1.OnTrigger = function() + GAMEMODE:SetVehicleCheckpoint(Vector(10367.498047, 1265.902466, -487.621826), Angle(0, 90, 0)) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + -- Subtile rush blocking. + ents.CreateSimple("prop_physics", { + Model = "models/props_wasteland/laundry_washer003.mdl", + Pos = Vector(7780.393555, 1381.725220, -228.653198), + Ang = Angle(0, -90, 0), + MoveType = MOVETYPE_NONE, + SpawnFlags = SF_PHYSPROP_MOTIONDISABLED, + Flags = FL_STATICPROP, + }) + + -- Remove the default explose barrels, too easy to shoot from the gate. + local searchPos = Vector(6975.288574, 1361.227783, -255.968735) + for _,v in pairs(ents.FindInBox(searchPos - Vector(250, 250, 0), searchPos + Vector(255, 255, 100))) do + if v:GetClass() == "prop_physics" and v:GetModel() == "models/props_c17/oildrum001_explosive.mdl" then + v:Remove() + end + end + + -- Create better positioned ones. + + -- 6899.897461 1423.682495 -255.634171, 0.003 -171.758 0.005 + ents.CreateSimple("prop_physics", { + Model = "models/props_c17/oildrum001_explosive.mdl", + Pos = Vector(6991.625488, 1304.797119, -255.640411), + }) + + -- 6871.656250 1421.762695 -255.474014, -0.403 136.494 0.118 + ents.CreateSimple("prop_physics", { + Model = "models/props_c17/oildrum001_explosive.mdl", + Pos = Vector(7020.829102, 1305.285522, -255.544678), + }) + + -- Block the view to the barrels + ents.CreateSimple("prop_physics", { + Model = "models/props_debris/metal_panel01a.mdl", + Pos = Vector(7050.838379, 1287.056885, -231.276840), + Ang = Angle(6.208, -89.358, 90.071), + }) + + ents.CreateSimple("prop_physics", { + Model = "models/props_c17/oildrum001.mdl", + Pos = Vector(7131.379883, 1305.574463, -255.968750), + }) + + ents.CreateSimple("prop_physics", { + Model = "models/props_c17/oildrum001.mdl", + Pos = Vector(7089.489258, 1304.665649, -255.525589), + }) + + -- Additional fancy + ents.CreateSimple("prop_dynamic", { + Model = "models/props_buildings/row_res_1_fullscale.mdl", + Pos = Vector(9748.061523, -1349.575928, -6.638969), + MoveType = MOVETYPE_NONE, + }) + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d1_canals_08.lua b/gamemode/gametypes/hl2/mapscripts/d1_canals_08.lua new file mode 100644 index 00000000..f47b333a --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_canals_08.lua @@ -0,0 +1,104 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + }, + Ammo = + { + ["Pistol"] = 60, + ["SMG1"] = 60, + }, + Armor = 0, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["global_newgame_entmaker"] = true, + ["relay_locks_closegates"] = true, -- Dont close the doors if we pass thru the gate +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + for _,v in pairs(ents.FindByClass("info_player_start")) do + v:Remove() + end + + local playerStart = ents.Create("info_player_start") + playerStart:SetPos(Vector(7504, -11398, -412)) + playerStart:Spawn() + playerStart.MasterSpawn = true + + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-486.748169, -329.674469, -591.968750), Ang = Angle(0, 90, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(-480.402649, -58.779499, -575.968750), + Angle(0, 0, 0), + Vector(-100, -100, 0), + Vector(100, 100, 180) + ) + checkpointTrigger1.OnTrigger = function() + GAMEMODE:SetVehicleCheckpoint(Vector(53.214970, -102.730621, -615.638123), Angle(0, -180, 0)) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + -- -841.505310 -1408.689331 -382.968750 + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-841.505310, -1408.689331, -382.968750), Ang = Angle(0, 90, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(-841.505310, -1408.689331, -382.968750), + Angle(0, 0, 0), + Vector(-100, -100, 0), + Vector(100, 100, 180) + ) + checkpointTrigger2.OnTrigger = function() + --GAMEMODE:SetVehicleCheckpoint(Vector(53.214970, -102.730621, -615.638123), Angle(0, -180, 0)) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + -- It looks odd when they spawn right infront of one. + ents.WaitForEntityByName("bunker_copmaker1", function(ent) + ent:AddSpawnFlags(SF_NPCMAKER_HIDEFROMPLAYER) + end) + + ents.WaitForEntityByName("bunker_copmaker2", function(ent) + ent:AddSpawnFlags(SF_NPCMAKER_HIDEFROMPLAYER) + end) + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d1_canals_09.lua b/gamemode/gametypes/hl2/mapscripts/d1_canals_09.lua new file mode 100644 index 00000000..2a35b6e7 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_canals_09.lua @@ -0,0 +1,59 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + }, + Ammo = + { + ["Pistol"] = 60, + ["SMG1"] = 60, + }, + Armor = 0, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["global_newgame_entmaker"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d1_canals_10.lua b/gamemode/gametypes/hl2/mapscripts/d1_canals_10.lua new file mode 100644 index 00000000..19aa0ab1 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_canals_10.lua @@ -0,0 +1,83 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + }, + Ammo = + { + ["Pistol"] = 60, + ["SMG1"] = 60, + ["357"] = 3, + }, + Armor = 0, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["global_newgame_entmaker"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + for k,v in pairs(ents.FindByClass("info_player_start")) do + v:Remove() + end + + local playerStart = ents.Create("info_player_start") + playerStart:SetPos(Vector(11876.291016, -12289.263672, -526.052246)) + playerStart:SetAngles(Angle(0, 100, 0)) + playerStart:Spawn() + playerStart.MasterSpawn = true + + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(4757.852051, 9866.387695, -111.968750), Ang = Angle(0, 180, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(5046.067871, 9267.515625, -127.968750), + Angle(0, 0, 0), + Vector(-100, -100, 0), + Vector(100, 100, 180) + ) + checkpointTrigger1.OnTrigger = function() + GAMEMODE:SetVehicleCheckpoint(Vector(4270.903320, 9841.201172, -124.578499), Angle(0, 180, 0)) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d1_canals_11.lua b/gamemode/gametypes/hl2/mapscripts/d1_canals_11.lua new file mode 100644 index 00000000..cd2f75b7 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_canals_11.lua @@ -0,0 +1,93 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + }, + Ammo = + { + ["Pistol"] = 60, + ["SMG1"] = 60, + ["357"] = 3, + }, + Armor = 0, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ + ["gate1"] = { "EnableMotion" } +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["global_newgame_template"] = true, + ["relay_guncave_gate_exit_close"] = true, +} + +MAPSCRIPT.VehicleGuns = false + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + local self = self + if SERVER then + + self.VehicleGuns = false + + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(6457.725586, 4986.333984, -953.968750), Ang = Angle(0, 180, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(6338.301270, 5018.617188, -953.968750), + Angle(0, 0, 0), + Vector(-100, -100, 0), + Vector(100, 100, 180) + ) + checkpointTrigger1.OnTrigger = function() + GAMEMODE:SetVehicleCheckpoint(Vector(6363.024902, 4874.115234, -967.214539), Angle(0, 90, 0)) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + GAMEMODE:WaitForInput("global_newgame_spawner_airboat", "Unlock", function(ent) + self.VehicleGuns = true + end) + + ents.WaitForEntityByName("teleport_guncave_airboat", function(ent) + -- This should fix the issue where airboats gone missing, also it properly lines em up + -- given by our specific stack mode within point_teleport + ent:SetKeyValue("stackmode", "1") + ent:SetKeyValue("stackdir", util.TypeToString(ent:GetAngles():Right())) + ent:SetKeyValue("stacklength", "200") + ent:SetPos(Vector(5992.192383, 4864.584473, -926.774841)) + end) + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d1_canals_12.lua b/gamemode/gametypes/hl2/mapscripts/d1_canals_12.lua new file mode 100644 index 00000000..09b32ab1 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_canals_12.lua @@ -0,0 +1,80 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + }, + Ammo = + { + ["Pistol"] = 60, + ["SMG1"] = 60, + ["357"] = 3, + }, + Armor = 0, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["global_newgame_entmaker"] = true, + ["spawnitems_template"] = true, +} + +MAPSCRIPT.VehicleGuns = true + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + + if SERVER then + + end + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-961.568787, -1598.274902, 192.031250), Ang = Angle(0, 0, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(-520.426453, -2655.423828, 83.702911), + Angle(0, 0, 0), + Vector(-400, -200, 0), + Vector(400, 200, 280) + ) + checkpointTrigger1.OnTrigger = function() + GAMEMODE:SetVehicleCheckpoint(Vector(-845.746704, -1628.464966, 120.773956), Angle(0, -180, 0)) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d1_canals_13.lua b/gamemode/gametypes/hl2/mapscripts/d1_canals_13.lua new file mode 100644 index 00000000..7f193a0d --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_canals_13.lua @@ -0,0 +1,100 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + }, + Ammo = + { + ["Pistol"] = 60, + ["SMG1"] = 60, + ["357"] = 3, + }, + Armor = 0, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["global_newgame_entmaker"] = true, + ["canals_trigger_elitrans"] = true, -- Do not changelevel based on the output. +} + +MAPSCRIPT.VehicleGuns = true + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- TODO: Duplicate canals_npc_reservoircopter01 (player / 2) times + -- TODO: Trigger helicopter OnDeath outputs only if all of them are dead. + + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(3435.695557, 1247.184448, -385.343903), Ang = Angle(0, 90, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(3425.643555, 2139.872314, -476.733490), + Angle(0, 0, 0), + Vector(-200, -400, 0), + Vector(200, 400, 280) + ) + --checkpointTrigger1:RemoveEffects(EF_NODRAW) + checkpointTrigger1.OnTrigger = function() + GAMEMODE:SetVehicleCheckpoint(Vector(3437.813477, 1579.182251, -455.238220), Angle(0, -90, 0)) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + -- We gotta place a giant changelevel trigger here, the other one is dangling in the air and uses Input instead of touch. + -- -1024.000000 -6656.000000 -1262.920044 + -- *16 + local changelevelTrigger = ents.CreateSimple("trigger_changelevel", { + Pos = Vector(-1024.000000, -6656.000000, -1262.920044), + Ang = Angle(0, 0, 0), + Model = "*16", + KeyValues = + { + ["map"] = "d1_eli_01", + ["landmark"] = "canals_trans_13_eli", + } + }) + changelevelTrigger:Spawn() + + ents.WaitForEntityByName("lambda_canals_portal_elitrans", function(ent) + DbgPrint("Fixing visibility") + ent:Fire("Open") + end) + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d1_eli_01.lua b/gamemode/gametypes/hl2/mapscripts/d1_eli_01.lua new file mode 100644 index 00000000..f9b5f8db --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_eli_01.lua @@ -0,0 +1,121 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 3, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ + ["inner_door"] = { "Close" }, + ["lab_exit_door_raven"] = { "Close" }, + ["lab_exit_door_raven2"] = { "Close" }, +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["global_newgame_template_base_items"] = true, + ["global_newgame_template_local_items"] = true, + ["global_newgame_template_ammo"] = true, + ["trigger_startScene"] = true, + ["pclip_exit_door_raven2"] = true, + ["brush_exit_door_raven_PClip"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- Perhaps skip this entire scene, its somewhat useless. + local entryTrigger = ents.Create("trigger_once") + entryTrigger:SetupTrigger(Vector(-64.453362, 2733.531006, -1279.9687500), Angle(0,0,0), Vector(-80, -105, 0), Vector(80, 105, 90)) + entryTrigger:SetKeyValue("teamwait", "1") + --entryTrigger:SetKeyValue("lockplayers", "1") -- Do we really want this? + entryTrigger.OnTrigger = function(self) + --DbgPrint("All players inside trigger, closing door, swapping spawnpoint.") + -- Everyone is inside, we can close the door. + ents.WaitForEntityByName("logic_startScene", function(ent) ent:Fire("Trigger") end) + + -- Make sure players dont spawn outside the base + local checkpoint = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-66.911217, 2753.892822, -1279.968750), Ang = Angle(0, 0, 0) }) + GAMEMODE:SetPlayerCheckpoint(checkpoint) + end + + -- 454.184753 1670.932373 -1281.335693 + ents.WaitForEntityByName("elevator_trigger_go_up_1", function(ent) + DbgPrint("Setting up elevator team wait") + ent:SetKeyValue("teamwait", "1") + ent.OnTrigger = function(self) + + DbgPrint("All players in elevator") + + local elevator_lab = ents.FindFirstByName("elevator_lab") + local checkpoint = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(454.184753, 1670.932373, -1281.335693), Ang = Angle(0, 90, 0) }) + checkpoint:SetParent(elevator_lab) + + GAMEMODE:SetPlayerCheckpoint(checkpoint) + + end + end) + + -- What is it with NPCs being busy? + ents.WaitForEntityByName("lcs_alyxtour01", function(ent) + ent:SetKeyValue("busyactor", "0") + end) + + ents.WaitForEntityByName("lcs_alyxtour03", function(ent) + ent:SetKeyValue("busyactor", "0") + end) + + ents.WaitForEntityByName("lcs_alyxtour04", function(ent) + ent:SetKeyValue("busyactor", "0") + end) + + ents.WaitForEntityByName("lcs_Labtalk04", function(ent) + ent:SetKeyValue("busyactor", "0") + end) + + ents.WaitForEntityByName("trigger_alyxtour04b", function(ent) + ent:SetKeyValue("teamwait", "1") + end) + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d1_eli_02.lua b/gamemode/gametypes/hl2/mapscripts/d1_eli_02.lua new file mode 100644 index 00000000..494a4f56 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_eli_02.lua @@ -0,0 +1,178 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 3, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ + ["inner_door"] = { "Close" }, + ["lab_exit_door_raven"] = { "Close" }, + ["lab_exit_door_raven2"] = { "Close" }, + ["gravgun_prop"] = { "Kill" }, -- We need it for spawn position. +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["global_newgame_template_base_items"] = true, + ["global_newgame_template_local_items"] = true, + ["global_newgame_template_ammo"] = true, + ["global_newgame_spawner_ammo"] = true, -- They piled up 20 of em. + + ["trigger_startScene"] = true, + ["pclip_exit_door_raven2"] = true, + ["brush_exit_door_raven_PClip"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + local gravgun_prop + ents.WaitForEntityByName("gravgun_prop", function(ent) gravgun_prop = ent end) + + local createPhyscannon = ents.Create("lambda_clientcommand") + createPhyscannon:Spawn() + createPhyscannon.Command = function(self, data, activator, caller) + + DbgPrint("Creating gravity gun") + + local pos = Vector(-469.619568, 797.148071, -2688.000000) + local ang = Angle(0, 0, 0) + if IsValid(gravgun_prop) then -- Yes I've seen it break because alyx vanished. + pos = gravgun_prop:GetPos() + ang = gravgun_prop:GetAngles() + end + + local wep = ents.CreateSimple("weapon_physcannon", { + Pos = pos, + Ang = ang, + }) + local phys = wep:GetPhysicsObject() + if IsValid(phys) then + phys:SetMass(1000) -- Somewhat prevents players trying to hide the gun or moving it too far as its rather important. + end + + gravgun_prop:Remove() + + return true + + end + + -- Replace it with ours. + ents.WaitForEntityByName("command_physcannon", function(ent) + createPhyscannon:SetName("command_physcannon") + ent:Remove() + end) + + ents.WaitForEntityByName("airlock_south_door_exitb", function(ent) + ent:SetKeyValue("speed", 60) + end) + + ents.WaitForEntityByName("airlock_south_door_exit", function(ent) + ent:SetKeyValue("speed", 60) + end) + + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-604.471130, 840.267578, -2688.000000), Ang = Angle(0, -90, 0) }) + + -- Players must gather nearby alyx. + ents.WaitForEntityByName("trigger_scrapyard_start", function(ent) + -- Too small, causes players to freak out. + --ent:SetKeyValue("teamwait", "1") + + local trigger = ents.Create("trigger_once") + trigger:SetKeyValue("teamwait", "1") + trigger:SetupTrigger( + Vector(-608.376709, 525.137512, -2688.000000), + Angle(0, 0, 0), + Vector(-300, -300, 0), + Vector(300, 300, 200) + ) + trigger:Disable() + trigger:CloneOutputs(ent) + trigger:SetName("trigger_scrapyard_start") + trigger.OnTrigger = function(self) + DbgPrint("Starting scrapeyard scene") + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + ent:Remove() + end) + + + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-600.126587, 1066.952637, -2687.968750), Ang = Angle(0, 90, 0) }) + + -- Players must be inside before doors close again. + ents.WaitForEntityByName("trigger_attack02", function(ent) + -- Too small, causes players to freak out. + --ent:SetKeyValue("teamwait", "1") + + local trigger = ents.Create("trigger_once") + trigger:SetKeyValue("teamwait", "1") + trigger:SetupTrigger( + Vector(-590.0, 1027.204346, -2687.968750), + Angle(0, 0, 0), + Vector(-100, -90, 0), + Vector(100, 130, 100) + ) + trigger:Disable() + trigger:CloneOutputs(ent) + trigger:SetName("trigger_attack02") + trigger.OnTrigger = function(self) + DbgPrint("Starting attack") + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + ent:Remove() + end) + + -- Fix the door pushing players. + GAMEMODE:WaitForInput("trigger_RavenDoor_Drop", "Enable", function() + DbgPrint("Fixing the Ravenholm door") + ents.WaitForEntityByName("ravenDoor", function(ent) + ent:Fire("DisablePlayerCollision") + end) + return true -- Suppress, do not close that door + end) + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d1_town_01.lua b/gamemode/gametypes/hl2/mapscripts/d1_town_01.lua new file mode 100644 index 00000000..fd503d3b --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_town_01.lua @@ -0,0 +1,89 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 3, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + --["test_name"] = true, + ["player_spawn_template"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- 2849.690674 -1397.864624 -3839.968750 + + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(2643.776611, -1465.673584, -3839.968750), Ang = Angle(0, 90, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(3007.881836, -1393.500732, -3783.968750), + Angle(0, 0, 0), + Vector(-50, -50, 0), + Vector(50, 50, 70) + ) + checkpointTrigger1.OnTrigger = function() + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(2018.717896, -1513.990112, -3839.968750), Ang = Angle(0, 90, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(1936.609863, -1431.232666, -3775.968750), + Angle(0, 0, 0), + Vector(-50, -50, 0), + Vector(50, 50, 70) + ) + checkpointTrigger2.OnTrigger = function() + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d1_town_01a.lua b/gamemode/gametypes/hl2/mapscripts/d1_town_01a.lua new file mode 100644 index 00000000..8a8fd35b --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_town_01a.lua @@ -0,0 +1,67 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 3, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["player_spawn_template"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + ents.WaitForEntityByName("portalwindow_03_portal", function(ent) ent:Fire("Open") end) + ents.WaitForEntityByName("attic_door_1", function(ent) + -- TODO: Investigate why this door is basically invisible + no collision but it exists + -- when going from d1_town_01 to d1_town_01a + end) + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d1_town_02.lua b/gamemode/gametypes/hl2/mapscripts/d1_town_02.lua new file mode 100644 index 00000000..238ab4c7 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_town_02.lua @@ -0,0 +1,159 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 3, + ["Grenade"] = 1, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ + ["buildingD_roofhatch"] = { "Close" }, -- Never close it, it might close while players climb up and get stuck. +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["startobjects_template"] = true, + --["test_name"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- If we come from 03 + if GAMEMODE:GetPreviousMap() == "d1_town_03" then + -- -3764.476807 -332.874481 -3327.968750 + local checkpointTransfer = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-3764.476807, -332.874481, -3327.968750), Ang = Angle(0, 90, 0) }) + GAMEMODE:SetPlayerCheckpoint(checkpointTransfer) + end + + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-1808.973267, 721.884277, -3071.968750), Ang = Angle(0, -180, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(-1789.687012, 684.973572, -3071.968750), + Angle(0, 0, 0), + Vector(-50, -50, 0), + Vector(50, 50, 70) + ) + checkpointTrigger1.OnTrigger = function() + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + -- -2942.757324 895.897278 -3135.814697 + -- w = 128 (x) + -- l = 95 (y) + -- freightlift_lift + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-2948.138428, 887.582458, -3135.968750), Ang = Angle(0, -180, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(-2942.757324, 895.897278, -3135.814697), + Angle(0, 0, 0), + Vector(-64, -45, 0), + Vector(64, 45, 90) + ) + checkpointTrigger2:SetKeyValue("teamwait", "1") + checkpointTrigger2:Disable() -- Initially disabled, started by button. + checkpointTrigger2.OnTrigger = function() + TriggerOutputs({ + {"elevator_nodelink", "TurnOff", 10.0, ""}, + {"freight_lift_down_relay", "Trigger", 0, ""}, + {"freight_lift_button_2", "Lock", 0, ""}, + }) + ents.WaitForEntityByName("freightlift_lift", function(ent) + checkpoint2:SetParent(ent) + end) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + -- Replace the logic of that button. + GAMEMODE:WaitForInput("freight_lift_button_2", "Use", function() + if IsValid(checkpointTrigger2) then + checkpointTrigger2:Enable() + end + return true -- Suppress. + end) + + -- We spawn the monk in the second part sooner, players should not see him being spawned. + -- -3396.734619 417.609131 -3327.968750 + local monkTrigger = ents.Create("trigger_once") + monkTrigger:SetupTrigger( + Vector(-3396.734619, 417.609131, -3327.968750), + Angle(0, 0, 0), + Vector(-64, -45, 0), + Vector(64, 45, 90) + ) + monkTrigger.OnTrigger = function() + TriggerOutputs({ + {"church_monk_maker", "Spawn", 0.0, ""}, + {"church_monk_maker", "Disable", 0.0, ""}, + }) + end + + -- Checkpoints for part 2 + -- -4323.520996 1618.552734 -3135.968750 + local checkpoint3 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-4323.520996, 1618.552734, -3135.968750), Ang = Angle(0, -90, 0) }) + local checkpointTrigger3 = ents.Create("trigger_once") + checkpointTrigger3:SetupTrigger( + Vector(-4345.541504, 1502.828979, -3135.968750), + Angle(0, 0, 0), + Vector(-50, -50, 0), + Vector(50, 50, 70) + ) + checkpointTrigger3.OnTrigger = function() + GAMEMODE:SetPlayerCheckpoint(checkpoint3) + end + + local checkpoint4 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-4836.597168, 545.560608, -3263.968750), Ang = Angle(0, 90, 0) }) + local checkpointTrigger4 = ents.Create("trigger_once") + checkpointTrigger4:SetupTrigger( + Vector(-4522.980469, 838.613159, -3065.248779), + Angle(0, 0, 0), + Vector(-50, -50, 0), + Vector(50, 50, 170) + ) + checkpointTrigger4.OnTrigger = function() + GAMEMODE:SetPlayerCheckpoint(checkpoint4) + end + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d1_town_02a.lua b/gamemode/gametypes/hl2/mapscripts/d1_town_02a.lua new file mode 100644 index 00000000..69b12ec8 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_town_02a.lua @@ -0,0 +1,69 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 3, + ["Grenade"] = 1, + ["Buckshot"] = 12, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["startobjects"] = true, + --["test_name"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- Figure out a better way to finish this scene. + ents.RemoveByClass("trigger_once", Vector(-7504, -304, -3344)) + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d1_town_03.lua b/gamemode/gametypes/hl2/mapscripts/d1_town_03.lua new file mode 100644 index 00000000..176a8ecf --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_town_03.lua @@ -0,0 +1,77 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 3, + ["Grenade"] = 1, + ["Buckshot"] = 12, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + --["test_name"] = true, + ["startobjects_template"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- The player gets stuck here, so we just put something there so it wont happen. + -- + ents.CreateSimple("prop_physics", { + Model = "models/props_debris/concrete_chunk02b.mdl", + Pos = Vector(-3128.362549, -1026.139160, -3604.878906), + Ang = Angle(2.362, -13.966, 9.108), + MoveType = MOVETYPE_NONE, + SpawnFlags = SF_PHYSPROP_MOTIONDISABLED, + Flags = FL_STATICPROP, + }) + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d1_town_04.lua b/gamemode/gametypes/hl2/mapscripts/d1_town_04.lua new file mode 100644 index 00000000..55f25e30 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_town_04.lua @@ -0,0 +1,80 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 3, + ["Grenade"] = 1, + ["Buckshot"] = 12, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["player_spawn_template"] = true, + --["test_name"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- 1915.561768 -19.246124 -5120.762695 + + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(1893.508423, 365.617035, -5120.287109), Ang = Angle(0, -90 , 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(1915.561768, -19.246124, -5120.762695), + Angle(0, 0, 0), + Vector(-150, -50, 0), + Vector(150, 50, 70) + ) + checkpointTrigger1.OnTrigger = function() + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d1_town_05.lua b/gamemode/gametypes/hl2/mapscripts/d1_town_05.lua new file mode 100644 index 00000000..da055c26 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_town_05.lua @@ -0,0 +1,217 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 3, + ["Grenade"] = 1, + ["Buckshot"] = 12, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ + ["warehouse_citizen"] = { "Kill" }, + ["warehouse_citizen_jacobs"] = { "Kill" }, + ["winston"] = { "Kill" }, + ["citizen_warehouse_door_1"] = { "Close", "Lock" }, +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["player_spawn_items"] = true, + ["trigger_changelevel"] = true, -- We use a better one. +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + ents.WaitForEntityByName("warehouse_soldier", function(ent) + DbgPrint("Solider: " .. tostring(ent)) + end) + + -- Fix scaling affect math_counter by renaming it and fire on OnAllSpawnedDead instead, since they are set to 2 + ents.WaitForEntityByName("end_reinforcements_counter", function(ent) + ent:SetName("lambda_end_reinforcements_counter") + end) + + ents.WaitForEntityByName("warehouse_deadcombine_counter", function(ent) + ent:SetName("lambda_warehouse_deadcombine_counter") + end) + + -- -6381.103027 8103.064453 896.031250 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-6533.443848, 8131.516602, 896.031250), Ang = Angle(0, 0, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(-6381.103027, 8103.064453, 896.031250), + Angle(0, 0, 0), + Vector(-100, -300, 0), + Vector(100, 300, 170) + ) + checkpointTrigger1.OnTrigger = function() + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + -- Make sure to substract on our renamed math_counter. + ents.WaitForEntityByName("end_reinforcements_trigger", function(ent) + ent:Fire("AddOutput", "OnTrigger lambda_warehouse_deadcombine_counter,Subtractw,2") + end) + + -- Because those npcs are created via point_template, this is a good hooking spot to correct the output. + GAMEMODE:WaitForInput("lcs_winston", "Start", function(ent) + for _,v in pairs(ents.FindByName("warehouse_soldier")) do + v:Fire("AddOutput", "OnDeath lambda_warehouse_deadcombine_counter,Add,1") + end + end) + + ents.WaitForEntityByName("end_soldier_1_maker", function(ent) + ent:AddSpawnFlags(SF_NPCMAKER_ALWAYSUSERADIUS) + --ent:AddSpawnFlags(SF_NPCMAKER_HIDEFROMPLAYER) + ent:SetName("lambda_end_soldier_1_maker") + ent:SetKeyValue("MaxNPCCount", "2") + ent:SetKeyValue("SpawnFrequency", "0") + ent:SetKeyValue("Radius", 428) + ent:SetPos(Vector(-1946.261353, 8187.082031, 955.381775)) + ent:Fire("AddOutput", "OnAllSpawnedDead lambda_end_reinforcements_counter,Add,1") + end_soldier_1_maker = ent + end) + + ents.WaitForEntityByName("end_soldier_2_maker", function(ent) + ent:AddSpawnFlags(SF_NPCMAKER_ALWAYSUSERADIUS) + --ent:AddSpawnFlags(SF_NPCMAKER_HIDEFROMPLAYER) + ent:SetName("lambda_end_soldier_2_maker") + ent:SetKeyValue("MaxNPCCount", "2") + ent:SetKeyValue("SpawnFrequency", "0") + ent:SetKeyValue("Radius", 128) + ent:SetPos(Vector(-1497.389404, 8514.711914, 896.0312507)) -- Lets give them a beter position. + ent:Fire("AddOutput", "OnAllSpawnedDead lambda_end_reinforcements_counter,Add,1") + end) + + ents.WaitForEntityByName("end_soldier_3_maker", function(ent) + ent:AddSpawnFlags(SF_NPCMAKER_ALWAYSUSERADIUS) + --ent:AddSpawnFlags(SF_NPCMAKER_HIDEFROMPLAYER) + ent:SetName("lambda_end_soldier_3_maker") + ent:SetKeyValue("MaxNPCCount", "2") + ent:SetKeyValue("SpawnFrequency", "0") + ent:SetKeyValue("Radius", 328) + --ent:Fire("AddOutput", "OnAllSpawnedDead lambda_warehouse_deadcombine_counter,Add,1") + end) + + -- -3500.986816 7756.634766 896.031250 + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-4065.605957, 7748.239258, 896.032776), Ang = Angle(3.366, 19.338, 0.000) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(-3500.986816, 7756.634766, 896.031250), + Angle(0, 0, 0), + Vector(-25, -100, 0), + Vector(25, 100, 170) + ) + checkpointTrigger2.OnTrigger = function() + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + TriggerOutputs({ + {"lambda_end_soldier_1_maker", "Enable", 0, ""}, + {"lambda_end_soldier_2_maker", "Enable", 0, ""}, + {"lambda_end_soldier_3_maker", "Enable", 0, ""}, + }) + end + + ents.WaitForEntityByName("end_soldier_4_maker", function(ent) + --ent:KeyValue("DisableScaling", "1") + ent:AddSpawnFlags(SF_NPCMAKER_ALWAYSUSERADIUS) + --ent:AddSpawnFlags(SF_NPCMAKER_HIDEFROMPLAYER) + ent:SetKeyValue("MaxNPCCount", "2") + ent:SetKeyValue("SpawnFrequency", "0.3") + ent:SetKeyValue("Radius", 60) + ent:Fire("AddOutput", "OnAllSpawnedDead lambda_warehouse_deadcombine_counter,Add,1") + end) + GAMEMODE:WaitForInput("end_soldier_4_maker", "Spawn", function(ent) + ent:Fire("Enable") + end) + + ents.WaitForEntityByName("end_soldier_5_maker", function(ent) + --ent:KeyValue("DisableScaling", "1") + ent:AddSpawnFlags(SF_NPCMAKER_ALWAYSUSERADIUS) + --ent:AddSpawnFlags(SF_NPCMAKER_HIDEFROMPLAYER) + ent:SetKeyValue("MaxNPCCount", "2") + ent:SetKeyValue("SpawnFrequency", "0.3") + ent:SetKeyValue("Radius", 128) + ent:Fire("AddOutput", "OnAllSpawnedDead lambda_warehouse_deadcombine_counter,Add,1") + end) + GAMEMODE:WaitForInput("end_soldier_5_maker", "Spawn", function(ent) + ent:Fire("Enable") + end) + + ents.WaitForEntityByName("warehouse_leonleads_lcs", function(ent) + ent:Fire("AddOutput", "OnTrigger2 !self,Resume,,2") -- Whoever gets picked as freeman, stop giving a fuck. + end) + + -- Checkpoint + -- -1123.785400 10358.985352 896.031250 + local checkpoint3 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-1098.884766, 10457.261719, 896.031250), Ang = Angle(0, -180, 0.000) }) + local checkpointTrigger3 = ents.Create("trigger_once") + checkpointTrigger3:SetupTrigger( + Vector(-1123.785400, 10358.985352, 896.031250), + Angle(0, 0, 0), + Vector(-100, -25, 0), + Vector(100, 25, 170) + ) + checkpointTrigger3.OnTrigger = function() + GAMEMODE:SetPlayerCheckpoint(checkpoint3) + end + + + -- Better changelevel trigger. + local changelevelTrigger = ents.CreateSimple("trigger_changelevel", { + Pos = Vector(-1680, 10970, 952), + Ang = Angle(0, 0, 0), + Model = "*40", + KeyValues = + { + ["map"] = "d2_coast_01", + ["landmark"] = "d1_town-coast", + } + }) + changelevelTrigger:Spawn() + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d1_trainstation_01.lua b/gamemode/gametypes/hl2/mapscripts/d1_trainstation_01.lua new file mode 100644 index 00000000..08cc5cf8 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_trainstation_01.lua @@ -0,0 +1,199 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = true +MAPSCRIPT.DefaultLoadout = +{ + Weapons = {}, + Ammo = {}, + Armor = 30, + HEV = false, +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["point_teleport"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + --["teleport_to_start"] = true, + --["teleport_to_train"] = true, + --["teleport_to_trainstation"] = true, + --["teleport_to_citadel"] = true, + --["teleport_to_test_chamber"] = true, +} + +MAPSCRIPT.InputFilters = +{ + ["train_door_2_counter"] = {"Add"}, + ["razortrain_gate_cop_2"] = {"SetPoliceGoal"}, + ["cage_playerclip"] = {"Enable"}, + ["cage_door_counter"] = {"Add"}, + ["logic_kill_citizens"] = {"Trigger"}, + ["storage_room_door"] = {"Close", "Lock"}, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: d1_trainstation_01 --") + +end + +function MAPSCRIPT:ResetPlayerPos(ply) + + if self.PlayersLocked == true then + local gman = ents.FindFirstByName("gman") + ply:SetPos(Vector(-14576, -13924, -1290)) + ply:LockPosition(true, VIEWLOCK_NPC, gman) + end + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + local self = self + + self.PlayersLocked = true + + -- Remove all default spawnpoints. + ents.RemoveByClass("info_player_start") + + -- Annoying stuff. + ents.RemoveByName("cage_playerclip") + --ents.RemoveByName("barney_room_blocker") + ents.RemoveByName("barney_room_blocker_2") + ents.RemoveByName("barney_hallway_clip") + ents.RemoveByName("logic_kill_citizens") + + -- Fix spawn position + ents.WaitForEntityByName("teleport_to_start", function(ent) + ent:SetPos(Vector(-14576, -13924, -1290)) + end) + + -- Spawn infront of G-Man + local spawn1 = ents.Create("info_player_start") + spawn1:SetPos(Vector(-14576, -13924, -1274)) + spawn1:SetAngles(Angle(0, 90, 0)) + spawn1:Spawn() + spawn1.MasterSpawn = true + + -- Spawn after the intro. + local spawn2 = ents.Create("info_player_start") + spawn2:SetPos(Vector(-5182, -2106, -31)) + spawn2:SetAngles(Angle(0, 0, 0)) + spawn2:Spawn() + spawn2.MasterSpawn = false + + -- Spawn after barney + local spawn3 = ents.Create("info_player_start") + spawn3:SetPos(Vector(-3549, -347, -31)) + spawn3:SetAngles(Angle(0, 0, 0)) + spawn3:Spawn() + spawn3.MasterSpawn = false + + -- Fix point_viewcontrol, setup All Players flag. + for k,v in pairs(ents.FindByClass("point_viewcontrol")) do + v:SetKeyValue("spawnflags", "128") + end + + -- Make the cop go outside the hallway so other players can still pass by. + local mark_cop_security_room_leave = ents.FindFirstByName("mark_cop_security_room_leave"); + mark_cop_security_room_leave:SetPos(Vector(-4304, -464, -16)) + + GAMEMODE:WaitForInput("logic_start_train", "Trigger", function() + + DbgPrint("Assigning new spawnpoint") + + spawn1.MasterSpawn = false + spawn2.MasterSpawn = true + + -- Unlock players. + self.PlayersLocked = false + + for k,v in pairs(player.GetAll()) do + v:LockPosition(false, false) + v:SetNoDraw(false) + end + + end) + + -- Block players from escaping control gate. + local cage_playerclip = ents.Create("func_brush") + cage_playerclip:SetPos(Vector(-4226.9350585938, -417.03271484375,-31.96875)) + cage_playerclip:SetModel("*68") + cage_playerclip:SetKeyValue("spawnflags", "2") + cage_playerclip:Spawn() + + -- Setup the door to not close anymore once we entered the trigger. + GAMEMODE:WaitForInput("razor_train_gate_2", "Close", function() + DbgPrint("Preventing barney_door_1 to close") + GAMEMODE:FilterEntityInput("barney_door_1", "Close") + end) + + -- Create a trigger once all players are inside we setup a new spawnpoint and close the door. + ents.RemoveByClass("trigger_once", Vector(-3442, -316, 8)) -- We will take over. + + local barney_room_trigger = ents.Create("trigger_once") + barney_room_trigger:SetupTrigger(Vector(-3450, -255, 20), Angle(0,0,0), Vector(-150, -150, -50), Vector(150, 150, 50)) + barney_room_trigger:SetKeyValue("teamwait", 1) + barney_room_trigger.OnTrigger = function(self) + spawn2.MasterSpawn = false + spawn3.MasterSpawn = true + --ents.WaitForEntityByName("barney_door_2", function(ent) ent:Fire("Close") end) + --ents.WaitForEntityByName("barney_door_2", function(ent) ent:Fire("Lock") end) + ents.WaitForEntityByName("security_intro_02", function(ent) ent:Fire("Start") end) + ents.WaitForEntityByName("barney_room_blocker", function(ent) ent:Fire("Enable") end) + end + + ents.WaitForEntityByName("barney_door_2", function(ent) + ent:SetKeyValue("opendir", "2") + end) + + --[[ + GAMEMODE:WaitForInput("barney_door_2", "Close", function() + GAMEMODE:RemoveInputCallback("barney_door_2", "Close") + GAMEMODE:RemoveInputCallback("barney_door_2", "Lock") + barney_room_trigger:Fire("Enable") + return true -- Supress + end) + ]] + + -- Use a better spot for barney + local mark_barneyroom_comblock_4 = ents.FindFirstByName("mark_barneyroom_comblock_4") + mark_barneyroom_comblock_4:SetPos(Vector(-3588, 3, -31)) + end + + -- Override env_global so combines dont flip shit on everyone + local gordon_invulnerable = ents.Create("env_global") + gordon_invulnerable:SetKeyValue("globalstate", "gordon_invulnerable") + gordon_invulnerable:SetKeyValue("initialstate", "0") + gordon_invulnerable:Spawn() + gordon_invulnerable:Fire("TurnOn") + + local gordon_precriminal = ents.Create("env_global") + gordon_precriminal:SetKeyValue("globalstate", "gordon_precriminal") + gordon_precriminal:SetKeyValue("initialstate", "0") + gordon_precriminal:Spawn() + gordon_precriminal:Fire("TurnOn") + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + DbgPrint("PostPlayerSpawn") + + if self.PlayersLocked then + self:ResetPlayerPos(ply) + ply:SetNoDraw(true) + else + ply:SetNoDraw(false) + end + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d1_trainstation_02.lua b/gamemode/gametypes/hl2/mapscripts/d1_trainstation_02.lua new file mode 100644 index 00000000..82d9f085 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_trainstation_02.lua @@ -0,0 +1,210 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = {}, + Ammo = {}, + Armor = 30, + HEV = false, +} + +MAPSCRIPT.InputFilters = +{ +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: d1_trainstation_02 --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + local cupcop_can = nil + local cupcop = nil + local cupcopSpeech = + { + "npc/combine_soldier/vo/sectorisnotsecure.wav", + "npc/combine_soldier/vo/reaper.wav", + "npc/combine_soldier/vo/stayalert.wav", + "npc/combine_soldier/vo/ghost.wav", + "npc/combine_soldier/vo/target.wav", + "npc/combine_soldier/vo/visualonexogens.wav", + } + + ents.WaitForEntityByName("cupcop_can", function(ent) + cupcop_can = ent + end) + + ents.WaitForEntityByName("cupcop", function(ent) + cupcop = ent + end) + + -- swing_seat_1 + -- -4674.464844 -3538.560059 25.073853 + -- models/nova/airboat_seat.mdl + -- prop_vehicle_prisoner_pod + local swing_seat_1 = ents.FindFirstByName("swing_seat_1") + local seat_1 = ents.Create("prop_vehicle_prisoner_pod") + seat_1:SetPos(Vector(-4674.464844, -3540, 25)) + seat_1:SetModel("models/nova/airboat_seat.mdl") + seat_1:SetAngles(Angle(0, 180, 0)) + seat_1:SetCollisionGroup(COLLISION_GROUP_NONE) + seat_1:SetParent(swing_seat_1) + seat_1:SetNoDraw(true) + seat_1:Spawn() + + local phys_seat_1 = seat_1:GetPhysicsObject() + if IsValid(phys_seat_1) then + phys_seat_1:SetMass(1) + end + + -- swing_seat_2 + -- -4633.555664 -3542.251465 24.702568 + -- models/nova/airboat_seat.mdl + -- prop_vehicle_prisoner_pod + local swing_seat_2 = ents.FindFirstByName("swing_seat_2") + local seat_2 = ents.Create("prop_vehicle_prisoner_pod") + seat_2:SetPos(Vector(-4633.555664, -3540, 25)) + seat_2:SetModel("models/nova/airboat_seat.mdl") + seat_2:SetCollisionGroup(COLLISION_GROUP_NONE) + seat_2:SetAngles(Angle(0, 180, 0)) + seat_2:SetParent(swing_seat_2) + seat_2:SetNoDraw(true) + seat_2:Spawn() + + local phys_seat_2 = seat_2:GetPhysicsObject() + if IsValid(phys_seat_2) then + phys_seat_2:SetMass(1) + end + + -- Why not.. + hook.Add("VehicleMove", "Lambda_SwingSeat", function(ply, vehicle, cmd) + + if vehicle ~= seat_1 and vehicle ~= seat_2 then + return + end + + local parent = vehicle:GetParent() + local phys = parent:GetPhysicsObject() + if IsValid(phys) then + + if cmd:KeyDown(IN_FORWARD) then + local fwd = vehicle:GetForward() + phys:ApplyForceCenter(fwd * 30) + elseif cmd:KeyDown(IN_BACK) then + local fwd = vehicle:GetForward() + phys:ApplyForceCenter(-fwd * 30) + end + + end + + end) + + GAMEMODE:WaitForInput("cupcop_nag_timer", "Enable", function() + do + return + end + DbgPrint("Starting to nag the cop") + + timer.Simple(4, function() + + cupcop_can:SetModel("models/gibs/hgibs.mdl") + cupcop_can:Ignite(999999) + + hook.Add("Think", "CupCopRevenge", function() + + if not IsValid(cupcop) or not IsValid(cupcop_can) then + DbgPrint("Not valid, removing hook") + hook.Remove("Think", "CupCopRevenge") + return + end + + local phys = cupcop_can:GetPhysicsObject() + if not IsValid(phys) then + DbgPrint("Not valid, removing hook") + hook.Remove("Think", "CupCopRevenge") + return + end + + local cupcopFwd = cupcop:EyeAngles():Forward() + local cupcopBck = -cupcopFwd + local cupcopPos = cupcop:EyePos() + (cupcopFwd * 50) + + local dist = cupcop:EyePos():Distance(cupcop_can:GetPos()) + local accumulator = dist / 100 + local power = dist * 0.8 + + local vecDir = cupcopPos - cupcop_can:GetPos() + local vecLookDir = cupcop:GetPos() - cupcop_can:GetPos() + local ang = vecDir:Angle() + local angLook = vecLookDir:Angle() + local angFwd = ang:Forward() + local vel = angFwd * (Vector(1, 1, 1) * power) + local minDistance = 150 + local runAhead = 160 + local curTime = CurTime() + + --DbgPrint("Power: " .. tostring(power)) + cupcop.LastAction = cupcop.LastAction or 0 + if dist < minDistance and CurTime() - cupcop.LastAction >= 5 then + + cupcop.LastAction = CurTime() + + if cupcop:IsCurrentSchedule(SCHED_COWER) == false then + + local cops = {} + for _,v in pairs(ents.FindByClass("npc_metropolice")) do + if v ~= cupcop then + table.insert(cops, v) + end + end + + local cupcopRunPos = table.Random(cops):GetPos() + + cupcop:SetLastPosition(cupcopRunPos) + cupcop:SetSchedule(SCHED_FORCED_GO_RUN) + + cupcop.LastTalk = cupcop.LastTalk or CurTime() - 2.1 + if CurTime() - cupcop.LastTalk >= 2 then + local speech = table.Random(cupcopSpeech) + DbgPrint("EmitSound: " .. tostring(speech)) + cupcop:EmitSound(speech) + cupcop.LastTalk = CurTime() + end + end + + end + + phys:SetVelocity(vel) + phys:SetAngles(angLook) + + end) + end) + + end) + + end + + -- Override env_global so combines dont flip shit on everyone + local gordon_invulnerable = ents.Create("env_global") + gordon_invulnerable:SetKeyValue("globalstate", "gordon_invulnerable") + gordon_invulnerable:SetKeyValue("initialstate", "0") + gordon_invulnerable:Spawn() + gordon_invulnerable:Fire("TurnOn") + + local gordon_precriminal = ents.Create("env_global") + gordon_precriminal:SetKeyValue("globalstate", "gordon_precriminal") + gordon_precriminal:SetKeyValue("initialstate", "0") + gordon_precriminal:Spawn() + gordon_precriminal:Fire("TurnOn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d1_trainstation_03.lua b/gamemode/gametypes/hl2/mapscripts/d1_trainstation_03.lua new file mode 100644 index 00000000..dca74ae3 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_trainstation_03.lua @@ -0,0 +1,151 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = {}, + Ammo = {}, + Armor = 30, + HEV = false, +} + +MAPSCRIPT.InputFilters = +{ + ["relay_rush_downstairscops"] = { "Trigger" }, +} + +MAPSCRIPT.EntityFilterByClass = +{ +} + +MAPSCRIPT.EntityFilterByName = +{ + ["logic_flr1tv_turnoffallscreens"] = true, + ["ai_breakin_cop3goal4_blockplayer"] = true, + ["ai_breakin_cop3goal4_blockplayer"] = true, + --["attic_door_push"] = true, + --["attic_door_push_trigger"] = true, + --["brush_prevent_cops_getting_to_bracer"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- FIX: This is not automatically reset because of the global stored state. + ents.WaitForEntityByName("gordon_criminal_global", function(ent) ent:Fire("TurnOn") end) + ents.WaitForEntityByName("gordon_invulnerable", function(ent) DbgPrint("Test2") ent:Fire("TurnOn") end) + + -- FIX: The cop would stand there annoying players that have not yet passed through. + GAMEMODE:WaitForInput("brush_breakin_blockplayer1", "Kill", function() + ents.WaitForEntityByName("npc_breakincop3", function(ent) ent:SetName("lambda_npc_breakincop3") DbgPrint("Changed name") end) + ents.WaitForEntityByName("ai_breakin_cop3goal3_blockplayer2", function(ent) ent:SetName("lambda_ai_breakin_cop3goal3_blockplayer2") end) + ents.WaitForEntityByName("ai_breakin_cop3goal3_blockplayer", function(ent) ent:SetName("lambda_ai_breakin_cop3goal3_blockplayer") end) + end) + + -- Move the target a little further away from the the player path + ents.WaitForEntityByName("mark_RaidEscape02", function(ent) ent:SetPos(Vector(-5017, -4637, 384)) end) + + local lcs_cit_RaidAnticipation + ents.WaitForEntityByName("lcs_cit_RaidAnticipation", function(ent) + ent:Fire("AddOutput", "OnCompletion !self,Start") + ent:SetKeyValue("busyactor", "0") + lcs_cit_RaidAnticipation = ent + end) + + GAMEMODE:WaitForInput("trigger_rush_start", "Enable", function() + DbgPrint("Preventing police rush") + lcs_cit_RaidAnticipation:Fire("Start") + return true + end) + + ents.WaitForEntityByName("attic_door_close_relay", function(ent) + ent:SetName("lambda_attic_door_close_relay") + end) + + ents.WaitForEntityByName("attic_door_push", function(ent) + ent:SetName("lambda_attic_door_push") + end) + + ents.WaitForEntityByName("attic_door_push_trigger", function(ent) + ent:SetName("lambda_attic_door_push_trigger") + end) + + ents.WaitForEntityByName("brush_prevent_cops_getting_to_bracer", function(ent) + ent:SetName("lambda_brush_prevent_cops_getting_to_bracer") + end) + + local door_bracer_trigger = ents.Create("trigger_once") + door_bracer_trigger:SetupTrigger(Vector(-4995, -4848, 512), Angle(0,0,0), Vector(-110, -80, 0), Vector(110, 110, 90)) + door_bracer_trigger:SetKeyValue("teamwait", "1") + door_bracer_trigger.OnTrigger = function(self) + DbgPrint("All players inside trigger, closing door, swapping spawnpoint.") + -- Everyone is inside, we can close the door. + ents.WaitForEntityByName("lambda_attic_door_push", function(ent) ent:Fire("Kill") end) + ents.WaitForEntityByName("lambda_attic_door_close_relay", function(ent) ent:Fire("Trigger") end) + ents.WaitForEntityByName("lambda_attic_door_push_trigger", function(ent) ent:Fire("Kill") end) + ents.WaitForEntityByName("lambda_brush_prevent_cops_getting_to_bracer", function(ent) ent:Fire("Enable") end) + + ents.WaitForEntityByName("gordon_criminal_global", function(ent) ent:Fire("TurnOff") end) + end + + -- FIX: For some reason the door pushed us away. + ents.WaitForEntityByName("door_bracerProp", function(ent) ent:Fire("DisablePlayerCollision") end) + + -- More subtle path blocking + ents.CreateSimple("prop_physics", + { + Model = "models/props_interiors/furniture_couch01a.mdl", + SpawnFlags = 11, + Pos = Vector(-3948.116211, -4605.383301, 405.858459), + Ang = Angle(0, -28, 0) + }) + ents.CreateSimple("prop_physics", + { + Model = "models/props_interiors/furniture_shelf01a.mdl", + SpawnFlags = 11, + Pos = Vector(-3978.584961, -4591.714355, 428.674622), + Ang = Angle(2.685, -43.640, -1.595) + }) + ents.CreateSimple("prop_physics", + { + Model = "models/props_interiors/furniture_couch02a.mdl", + SpawnFlags = 11, + Pos = Vector(-3991.768799 -4628.245117, 413.455383), + Ang = Angle(48.364, 2.325, -54.165) + }) + ents.CreateSimple("prop_physics", + { + Model = "models/props_interiors/furniture_cabinetdrawer01a.mdl", + SpawnFlags = 11, + Pos = Vector(-4001.259521, -4626.048828, 451.491089), + Ang = Angle(32.242, 48.029, -59.341) + }) + ents.CreateSimple("prop_physics", + { + Model = "models/props_interiors/furniture_couch01a.mdl", + SpawnFlags = 11, + Pos = Vector(-4033.726074, -4614.500000, 405.713776), + Ang = Angle(0.035, 151.586, 0.003) + }) + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d1_trainstation_04.lua b/gamemode/gametypes/hl2/mapscripts/d1_trainstation_04.lua new file mode 100644 index 00000000..edd4fc38 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_trainstation_04.lua @@ -0,0 +1,187 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = {}, + Ammo = {}, + Armor = 30, + HEV = false, +} + +MAPSCRIPT.InputFilters = +{ + ["logic_fade_view"] = {"Trigger"}, + ["door_inside_secret"] = {"Close", "Lock"} +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["window_player_clip"] = true, + ["trigger_knockout_teleport"] = true, + ["ss_alyx_intro_bendover"] = true, + ["lcs_knockout_kickdoor_2"] = true, + ["lcs_knockout_kickdoor"] = true, + --["npc_knockout_cop_upstairs"] = true, -- If players are still up they would see them spawn. +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + ents.WaitForEntityByName("global_gordon_invulnerable", function(ent) ent:Fire("TurnOff") end) + + -- If the changelevel fires before he closed it, the position would be off. + ents.WaitForEntityByName("citizen_DoorBracer", function(ent) + ent:SetPos(Vector(-3082.781738, -3532.943115, 384.031250)) + end) + + local supressKickdownEvent = true + + GAMEMODE:WaitForInput("kickdown_relay", "Trigger", function() + if supressKickdownEvent == true then + DbgPrint("Supressing event") + return true + end + end) + + GAMEMODE:WaitForInput("ss_DoorBracer_Struggle", "Kill", function() + if supressKickdownEvent == true then + DbgPrint("Supressing event") + return true + end + end) + + -- -3183.032227 -3624.933350 384.031250 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-3789.004150, -3686.312256, 564.031250), Ang = Angle(0, -180, 0) }) + local checkpointTrigger1 = ents.Create("trigger_multiple") + checkpointTrigger1:SetupTrigger( + Vector(-3183.032227, -3624.933350, 384.031250), + Angle(0,0,0), + Vector(-500, -200, 0), + Vector(200, 300, 280) + ) + checkpointTrigger1.OnEndTouchAll = function(trigger) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + supressKickdownEvent = false + TriggerOutputs({ + {"kickdown_relay", "Trigger", 0, ""}, + {"ss_DoorBracer_Struggle", "Kill", 2, ""}, + }) + trigger:Remove() + DbgPrint("All players left") + end + + -- -6975.404297 -4207.044922 520.031250 + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-6974.692383, -4174.132813, 520.031250), Ang = Angle(0, 90, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(-6974.692383, -4254.132813, 520.031250), + Angle(0,0,0), + Vector(-130, -20, 0), + Vector(130, 20, 180) + ) + checkpointTrigger2.OnEndTouchAll = function(trigger) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + -- We skip the knockout scene because its not shown anyway. + ents.WaitForEntityByName("door_knockout_1", function(ent) + --ent:Fire("Lock") + ent:SetKeyValue("speed", "100") + ent:SetKeyValue("opendir", "1") + end) + + local tracktrain_elevator + ents.WaitForEntityByName("tracktrain_elevator", function(ent) + tracktrain_elevator = ent + end) + + ents.WaitForEntityByName("trigger_elevator_go_down", function(ent) + ent:ResizeTriggerBox(Vector(-70, -70, -60), Vector(70, 70, 60)) + ent:SetKeyValue("teamwait", "1") + ent.OnTrigger = function(ent) + local checkpoint = ents.Create("lambda_checkpoint") + checkpoint:SetPos(Vector(-7740.829590, -3959.260010, 388.031250)) + checkpoint:Spawn() + checkpoint:SetParent(tracktrain_elevator) + GAMEMODE:SetPlayerCheckpoint(checkpoint) + + -- No idea why this wouldnt be triggered already. + TriggerOutputs({ + {"speaker_alyxfollow1", "TurnOff", 0, ""}, + {"speaker_alyxfollow1", "Kill", 0.1, ""}, + }) + end + end) + + ents.WaitForEntityByName("mark_knockout_alyxmark1", function(ent) + ent:SetPos(Vector(-7464, -4008, 393)) + end) + + ents.WaitForEntityByName("alyx", function(ent) + ent:SetPos(Vector(-7464, -4008, 393)) + end) + -- -7740.829590 -3959.260010 388.031250 + + GAMEMODE:WaitForInput("relay_knockout_start", "Trigger", function(ent) + DbgPrint("Starting alyx action") + + TriggerOutputs({ + {"breakable_alyxwindow", "Break", 0.5, ""}, + {"template_alyx", "ForceSpawn", 0.2, ""}, + {"lcs_alyxgreet00", "Start", 0.4, ""}, + {"logic_kill_cops", "Trigger", 0.2, ""}, + {"relay_knockout_alyxrescue", "Trigger", 0.5, ""}, + {"door_knockout_1", "Unlock", 8.5, ""}, + {"door_knockout_1", "Open", 8.5, ""}, + {"alyx_pos_fix", "Trigger", 8.5, ""}, + {"door_knockout_2", "Lock", 1.0, ""}, + {"door_knockout_2", "Close", 1.1, ""}, + {"global_gordon_invulnerable", "TurnOff", 0.3, ""}, + {"relationship_cops_hate_player", "RevertRelationship", 0, ""}, + {"sound_knockout_copspeech_done", "PlaySound", 2.0, ""}, + --{"logic_fade_view", "Trigger", 0.1, ""}, + {"npc_knockout_cop_upstairs", "Kill", 3.0, ""}, + {"mic_alyx", "Enable", 0, ""}, + }) + end) + + -- -7176.394043 -3890.482178 384.031250 + local checkpoint3 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-7204.497070, -3997.591064, 384.031250), Ang = Angle(0, -180, 0) }) + local checkpointTrigger3 = ents.Create("trigger_once") + checkpointTrigger3:SetupTrigger( + Vector(-7176.394043, -3890.482178, 384.031250), + Angle(0,0,0), + Vector(-130, -130, 0), + Vector(130, 130, 180) + ) + checkpointTrigger3.OnTrigger = function(trigger) + GAMEMODE:SetPlayerCheckpoint(checkpoint3) + end + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d1_trainstation_05.lua b/gamemode/gametypes/hl2/mapscripts/d1_trainstation_05.lua new file mode 100644 index 00000000..d1157539 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_trainstation_05.lua @@ -0,0 +1,106 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = {}, + Ammo = {}, + Armor = 30, + HEV = false, +} + +MAPSCRIPT.InputFilters = +{ + ["soda_machine_entry_door_1"] = { "Toggle" }, + ["soda_door_areaportal_1"] = { "Close" }, + ["lab_door"] = { "Close" }, + ["lab_door_clip"] = { "Close" }, +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["brush_soda_clip_player_2"] = true, + --["Barney_lab_entry_closedoor_1"] = true, + ["brush_soda_clip_player"] = true, -- Why not +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + self.DefaultLoadout.HEV = false + + ents.WaitForEntityByName("player_in_teleport", function(ent) + ent:SetKeyValue("teamwait", "1") + end) + + ents.WaitForEntityByName("start_first_teleport_01", function(ent) + ent:SetKeyValue("teamwait", "1") + end) + + ents.WaitForEntityByName("kleiner_console_lift_1", function(ent) + ent:SetKeyValue("spawnflags", "256") + ent:SetKeyValue("dmg", "0") -- Don`t hurt the player + end) + + local mapscript = self + + -- We gotta give all players the suit, some might be not so willing to take it and thats bad. + GAMEMODE:WaitForInput("suiton", "Enable", function(ent) + for _,v in pairs(player.GetAll()) do + -- Equip suit. + v:EquipSuit() + + -- Update model. + GAMEMODE:PlayerSetModel(v) + + mapscript.DefaultLoadout.HEV = true + end + end) + + for _,v in pairs(ents.FindByClass("item_suit")) do + v:EnableRespawn(true) + end + + -- -6569.488281 -1150.120850 0.031250 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-6569.488281, -1150.120850, 0.031250), Ang = Angle(0, 0, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(-6482.711914, -1095.658813, 0.031250), + Angle(0, 0, 0), + Vector(-50, -50, 0), + Vector(50, 50, 180) + ) + checkpointTrigger1.OnTrigger = function() + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + ents.WaitForEntityByName("gman_fixtie_1", function(ent) + ent:SetKeyValue("m_iszPlay", "citizen4_valve") + end) + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d1_trainstation_06.lua b/gamemode/gametypes/hl2/mapscripts/d1_trainstation_06.lua new file mode 100644 index 00000000..92ff90f8 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d1_trainstation_06.lua @@ -0,0 +1,137 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = {}, + Ammo = {}, + Armor = 30, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ + ["station_cop_2"] = { "Kill" }, + ["station_cop_1"] = { "Kill" }, + ["station_cop_4"] = { "Kill" }, + ["rappeller_cop_2_maker"] = { "Spawn" }, + ["rappeller_cop_2_maker_2"] = { "Spawn" }, +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + --["test_name"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- Make sure the door is there and lock it. + local transition_door = ents.FindFirstByName("transition_door") + if not IsValid(transition_door) then + transition_door = ents.Create("prop_door_rotating") + transition_door:SetPos(Vector(-9943.000000, -3970.000000, 374.000000)) + transition_door:SetAngles(Angle(0, -90, 0)) + transition_door:SetModel("models/props_c17/door01_left.mdl") + transition_door:SetSkin(5) + transition_door:Spawn() + transition_door:Activate() + end + transition_door:Fire("close") + transition_door:Fire("lock") + + -- Fix barney beeing strict about standing infront of him + local scriptCond_seeBarney = ents.FindFirstByName("scriptCond_seeBarney") + scriptCond_seeBarney:SetKeyValue("PlayerActorFOV", "-1") + scriptCond_seeBarney:SetKeyValue("PlayerTargetLOS", "3") + + -- Lets lift up the spawn a little, theres some invisible object that gets players stuck inside. + local spawns = ents.FindByClass("info_player_start") + for k,v in pairs(spawns) do + local pos = v:GetPos() + v:SetPos(pos + Vector(0,0,5)) + end + + -- Lets automatically scale some enemies. + -- -7871.712891 -1510.040405 -63.968754 + local maker1 = ents.Create("npc_maker") + maker1:SetPos(Vector(-8490.908203, -2256.173096, -63.968750)) + maker1:SetKeyValue("spawnflags", SF_NPCMAKER_HIDEFROMPLAYER + SF_NPCMAKER_ALWAYSUSERADIUS) + maker1:SetKeyValue("StartDisabled", "1") + maker1:SetKeyValue("NPCType", "npc_metropolice") + maker1:SetKeyValue("NPCSquadName", "baton_cop_squad") + maker1:SetKeyValue("additionalequipment", "weapon_pistol") + maker1:SetKeyValue("MaxNPCCount", "2") + maker1:SetKeyValue("MaxLiveChildren", "2") + maker1:SetKeyValue("SpawnFrequency", "0.2") + maker1:SetKeyValue("Radius", "1000") + maker1:Spawn() + + -- -8038.701660 -2541.850098 -63.968746 + local maker2 = ents.Create("npc_maker") + maker2:SetPos(Vector(-8038.701660, -2541.850098, -63.968746)) + maker2:SetKeyValue("spawnflags", SF_NPCMAKER_HIDEFROMPLAYER + SF_NPCMAKER_ALWAYSUSERADIUS) + maker2:SetKeyValue("StartDisabled", "1") + maker2:SetKeyValue("NPCType", "npc_metropolice") + maker2:SetKeyValue("NPCSquadName", "baton_cop_squad") + maker2:SetKeyValue("additionalequipment", "weapon_pistol") + maker2:SetKeyValue("MaxNPCCount", "2") + maker2:SetKeyValue("MaxLiveChildren", "2") + maker2:SetKeyValue("SpawnFrequency", "0.2") + maker2:SetKeyValue("Radius", "1000") + maker2:Spawn() + + local maker3 = ents.Create("npc_maker") + maker3:SetPos(Vector(-6699.455078, -1714.247314, -63.968750)) + maker3:SetKeyValue("spawnflags", SF_NPCMAKER_HIDEFROMPLAYER + SF_NPCMAKER_ALWAYSUSERADIUS) + maker3:SetKeyValue("StartDisabled", "1") + maker3:SetKeyValue("NPCType", "npc_metropolice") + maker3:SetKeyValue("NPCSquadName", "baton_cop_squad") + maker3:SetKeyValue("additionalequipment", "weapon_pistol") + maker3:SetKeyValue("MaxNPCCount", "2") + maker3:SetKeyValue("MaxLiveChildren", "2") + maker3:SetKeyValue("SpawnFrequency", "0.2") + maker3:SetKeyValue("Radius", "1000") + maker3:Spawn() + + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-8169.935059, -3181.270508, 192.031250), Ang = Angle(0, 0, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(-8169.935059, -3181.270508, 192.031250), + Angle(0, 0, 0), + Vector(-50, -50, 0), + Vector(50, 50, 70) + ) + checkpointTrigger1.OnTrigger = function() + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + maker1:Fire("Enable") + maker2:Fire("Enable") + maker3:Fire("Enable") + end + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d2_coast_01.lua b/gamemode/gametypes/hl2/mapscripts/d2_coast_01.lua new file mode 100644 index 00000000..d2fa8402 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d2_coast_01.lua @@ -0,0 +1,77 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + --"weapon_frag", + "weapon_shotgun", + "weapon_ar2", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + --["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ + ["push_car_superjump_01"] = { "Disable" }, +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["logic_jeepflipped"] = true, -- Annoying +} + +MAPSCRIPT.VehicleGuns = true + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + ents.WaitForEntityByName("push_car_superjump_01", function(ent) + ent:Fire("Enable") + ent:SetName("Lambda_" .. ent:GetName()) -- Prevent anyone disabling it. + end) + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d2_coast_03.lua b/gamemode/gametypes/hl2/mapscripts/d2_coast_03.lua new file mode 100644 index 00000000..b6351fc6 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d2_coast_03.lua @@ -0,0 +1,149 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["SMG1_Grenade"] = 3, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + --["test_name"] = true, +} + +MAPSCRIPT.VehicleGuns = true + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- Adds an overlay to the player view and never gets removed. + ents.WaitForEntityByName("telescope_button", function(ent) + ent:SetName("Lambda_" .. ent:GetName()) + end) + + ents.WaitForEntityByName("killed_critical_npc", function(ent) + ent:SetName("killed_critical_npc_2") + end) + + ents.WaitForEntityByName("rocketman", function(ent) + ent:Fire("AddOutput", "OnDeath killed_critical_npc_2,ShowMessage,0") -- Use one with no delay. + end) + + GAMEMODE:WaitForInput("spawner_rpg", "ForceSpawn", function(ent) + + local entityData = game.FindEntityInMapData("rpg_weapon") + local pos = util.StringToType(entityData["origin"], "Vector") + local ang = util.StringToType(entityData["angles"], "Angle") + + local newRPG = ents.Create("weapon_rpg") + newRPG:SetPos(pos) + newRPG:SetAngles(ang) + newRPG:Spawn() + + TriggerOutputs({ + {"first_train_rl", "Trigger", 0.0, ""}, + {"train_horn", "PlaySound", 0.0, ""}, + {"template_rpg", "Kill", 0.0, ""}, + {"spawner_rpg", "Kill", 0.1, ""}, + }) + + return true -- Suppress + + end) + + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-5971.663574, 3534.091064, 269.338867), Ang = Angle(4.653, 55.612, 0.000) }) + if not IsValid(checkpoint1) then + DbgError("Unable to create checkpoint") + end + + GAMEMODE:WaitForInput("spypost_template", "ForceSpawn", function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + GAMEMODE:SetVehicleCheckpoint(Vector(-5811.580566, 3605.574463, 257.262878), Angle(0, 0, 0)) + end) + + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(6494.825195, 4199.202637, 260.031250), Ang = Angle(0, 0, 0) }) + if not IsValid(checkpoint2) then + DbgError("Unable to create checkpoint") + end + GAMEMODE:WaitForInput("aisc_pre_ingreeterrange", "Enable", function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + GAMEMODE:SetVehicleCheckpoint(Vector(6610.592285, 4405.477539, 264.207794), Angle(0.091, -121.466, 0.363)) + end) + + GAMEMODE:WaitForInput("gunship_spawner_2", "Spawn", function(ent) + ent:RemoveTemplateData("OnDeath") + ent:AddTemplateData("squadname", "lambda_gunships") + ent:SetKeyValue("SpawnFrequency", "10") + ent:Enable() + ent.OnAllSpawnedDead = function(ent) + TriggerOutputs({ + {"ag_siren", "StopSound", 0.0, ""}, + {"lr_radioloop", "Disable", 0.0, ""}, + {"citizen_standoff", "Kill", 0.0, ""}, + {"aigf_combat", "Kill", 0.0, ""}, + {"aisc_odessapostgunship", "Enable", 0.0, ""}, + {"lr_squad_follow_*", "Kill", 0.0, ""}, + {"post_gunship_jeep_relay*", "Enable", 0.0, ""}, + {"aigf_odessapostgunship*", "Activate", 0.10, ""}, + {"ss_post**", "BeginSequence", 2.00, ""}, + {"gunshipdown_music*", "PlaySound", 3.00, ""}, + }) + end + return true + end) + + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d2_coast_04.lua b/gamemode/gametypes/hl2/mapscripts/d2_coast_04.lua new file mode 100644 index 00000000..c835f03c --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d2_coast_04.lua @@ -0,0 +1,234 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "night" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + --["test_name"] = true, + ["global_newgame_template_base_items"] = true, + ["global_newgame_template_local_items"] = true, + ["global_newgame_template_ammo"] = true, + ["fall_trigger"] = true, -- We replaced it by a more friendly variant + ["crane_soldier_kill"] = true, -- Why? +} + +MAPSCRIPT.VehicleGuns = true + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + --PrintTable(dock_soldiers) + -- 2219.829834 -2778.555176 256.031250 + local dock_soldiers = game.FindEntityInMapData("dock_soldiers_ontherun") + local crane_soldier = game.FindEntityInMapData("crane_soldier1") + + -- This is a far better spot to create all the npcs, it sucks if the player sees them spawning. + -- -4059.708252 54.849800 -10.067627 + local trigger1 = ents.Create("trigger_once") + trigger1:SetupTrigger( + Vector(-4059.708252, 54.849800, -10.067627), + Angle(0, 0, 0), + Vector(-100, -800, 0), + Vector(100, 800, 280) + ) + trigger1.OnTrigger = function() + TriggerOutputs({ + {"dock_soldier_template", "ForceSpawn", 0.0, ""}, + {"dock_soldier_template", "Kill", 0.1, ""}, + {"dock_antlion_spawner", "Spawn", 0.2, ""}, + {"dock_spawn", "ForceSpawn", 0.0, ""}, + {"ontherun_begin_assault", "Activate", 0.5, ""}, + }) + + -- Few extra npcs + local npc + + npc = ents.CreateFromData(dock_soldiers) + npc:SetPos(Vector(4175.628906, -2315.031738, 384.031250)) + npc:Spawn() + + npc = ents.CreateFromData(dock_soldiers) + npc:SetPos(Vector(4163.271973, -2513.076660, 384.031250)) + npc:Spawn() + + npc = ents.CreateFromData(dock_soldiers) + npc:SetPos(Vector(3997.812012, -2928.038086, 384.031250)) + npc:Spawn() + + npc = ents.CreateFromData(dock_soldiers) + npc:SetPos(Vector(4213.705078, -1796.927490, 672.031250)) + npc:Spawn() + + npc = ents.CreateFromData(dock_soldiers) + npc:SetPos(Vector(1731.862427, -2624.286377, 512.031250)) + npc:Spawn() + + npc = ents.CreateFromData(dock_soldiers) + npc:SetPos(Vector(1157.538452, -2616.800537, 512.031250)) + npc:Spawn() + + end + + -- The thumper should be enabled, the combine did take over the place so why is it shut off? + ents.WaitForEntityByName("thumper_1", function(ent) + util.RunNextFrame(function() + ent:Fire("Enable") + end) + end) + + -- rush checkpoint + -- 2835.472412 -1599.243896 142.031235, 1864.473999 -3026.903076 256.031250 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(1864.473999, -3026.903076, 256.031250), Ang = Angle(0, 90, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(2835.472412, -1599.243896, 142.031235), + Angle(0, 0, 0), + Vector(-100, -100, 0), + Vector(100, 100, 180) + ) + checkpointTrigger1.OnTrigger = function() + GAMEMODE:SetVehicleCheckpoint(Vector(3377.796875, -1352.083008, 9.863693), Angle(0, 0, 0)) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + -- bridge checkpoint + -- 5068.378418 -2688.673828 384.031250 + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(5189.114258, -2913.917236, 384.031250), Ang = Angle(0, 90, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(5068.378418, -2688.673828, 384.031250), + Angle(0, 0, 0), + Vector(-100, -100, 0), + Vector(100, 100, 180) + ) + checkpointTrigger2.OnTrigger = function() + GAMEMODE:SetVehicleCheckpoint(Vector(5128.125488, -2679.885986, 384.031250), Angle(0, -90, 0)) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + -- More enemies inside the warehouse + local npc + npc = ents.CreateFromData(crane_soldier) + npc:SetPos(Vector(5337.789551, -4445.919922, 416.031250)) + npc:Spawn() + + npc = ents.CreateFromData(crane_soldier) + npc:SetPos(Vector(5846.189453, -4383.688965, 416.031250)) + npc:Spawn() + + npc = ents.CreateFromData(crane_soldier) + npc:SetPos(Vector(5758.164063, -4566.489746, 416.031250)) + npc:Spawn() + + npc = ents.CreateFromData(crane_soldier) + npc:SetPos(Vector(5775.033203, -4182.553711, 384.031250)) + npc:Spawn() + + ents.WaitForEntityByName("push_car_superjump_01", function(ent) + ent:Fire("Enable") + ent:SetName("lambda_push_car_superjump_01") -- Prevent disabling it. + end) + + -- Setup a trigger that hurts the falling players, + -- it would take a immense effort to get back up there with the crane and all. + local bridgeKillTrigger = ents.Create("trigger_multiple") + bridgeKillTrigger:SetupTrigger( + Vector(-1835.606934, 1068.328979, 669.459900), + Angle(0, 0, 0), + Vector(-400, -350, 0), + Vector(400, 350, 100) + ) + bridgeKillTrigger.OnTrigger = function(self, ent) + if ent:IsVehicle() then + local driver = ent:GetDriver() + if IsValid(driver) and driver:Alive() then + driver:Kill() + end + local passengerSeat = ent.PassengerSeat + if IsValid(passengerSeat) then + local passenger = passengerSeat:GetDriver() + if IsValid(passenger) and passenger:Alive() then + passenger:Kill() + end + end + elseif ent:IsPlayer() and ent:Alive() then + ent:Kill() + end + end + + -- fall checkpoint + -- 1826.217529 2.297394 928.031250 + local checkpoint3 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-1328.088135, -1649.725464, 958.014343), Ang = Angle(0, 90, 0) }) + local checkpointTrigger3 = ents.Create("trigger_once") + checkpointTrigger3:SetupTrigger( + Vector(-1823.722290, -1220.703369, 928.031250), + Angle(0, 0, 0), + Vector(-200, -100, 0), + Vector(200, 100, 180) + ) + checkpointTrigger3.OnTrigger = function() + GAMEMODE:SetVehicleCheckpoint(Vector(-1352.137207, -1540.197876, 951.312805), Angle(0, 90, 0)) + GAMEMODE:SetPlayerCheckpoint(checkpoint3) + end + + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d2_coast_05.lua b/gamemode/gametypes/hl2/mapscripts/d2_coast_05.lua new file mode 100644 index 00000000..a6b39057 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d2_coast_05.lua @@ -0,0 +1,149 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["player_spawn_items"] = true, +} + +MAPSCRIPT.VehicleGuns = true + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-4118.057617, -12352.347656, 704.031250), Ang = Angle(0, 180, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(-4097.192871, -12543.278320, 704.031250), + Angle(0, 0, 0), + Vector(-100, -250, 0), + Vector(100, 250, 280) + ) + checkpointTrigger1.OnTrigger = function() + GAMEMODE:SetVehicleCheckpoint(Vector(-4308.972656, -12341.547852, 706.201477), Angle(0, 90, 0)) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + + TriggerOutputs({ + {"house_secondwave", "ForceSpawn", 0.0, ""}, + {"secondwave_assault", "Activate", 1.0, ""}, + {"secondwave_assault", "BeginAssault", 3.0, ""}, + {"house_secondwave", "Kill", 4.0, ""}, -- Don't trigger again + }) + end + + -- The game isnt over if someone falls down, we clear the outputs and just kill the player. + for _,v in pairs(ents.FindByName("fall_trigger")) do + v:ClearOutputs() + v.OnTrigger = function(self, ent) + if ent:IsVehicle() then + local driver = ent:GetDriver() + if IsValid(driver) and driver:Alive() then + driver:Kill() + end + local passengerSeat = ent.PassengerSeat + if IsValid(passengerSeat) then + local passenger = passengerSeat:GetDriver() + if IsValid(passenger) and passenger:Alive() then + passenger:Kill() + end + end + -- If someone shoves the vehicle down it would be lost forever. + ent:Remove() + elseif ent:IsPlayer() and ent:Alive() then + ent:Kill() + end + end + end + + -- More npcs + local maker1 = ents.Create("npc_maker") + maker1:SetPos(Vector(-3408.264160, -203.868591, 1084.031250)) + maker1:SetKeyValue("spawnflags", SF_NPCMAKER_HIDEFROMPLAYER) + maker1:SetKeyValue("StartDisabled", "1") + maker1:SetKeyValue("NPCType", "npc_combine_s") + maker1:SetKeyValue("NPCSquadName", "gas_station_squad") + --maker1:SetKeyValue("NPCHintGroup", "gas_station") + maker1:SetKeyValue("additionalequipment", "weapon_shotgun") + maker1:SetKeyValue("MaxNPCCount", "4") + maker1:SetKeyValue("MaxLiveChildren", "2") + maker1:SetKeyValue("SpawnFrequency", "2") + maker1:Spawn() + + -- -4863.671875 -3216.657471 1088.031250 + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-5365.758789, -3840.734619, 1082.535034), Ang = Angle(0, 0, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(-4863.671875, -3216.657471, 1088.031250), + Angle(0, 0, 0), + Vector(-300, -50, 0), + Vector(300, 50, 280) + ) + checkpointTrigger2.OnTrigger = function() + GAMEMODE:SetVehicleCheckpoint(Vector(-5233.240723, -3937.720459, 1105.934570), Angle(0, 55, 0)) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + + maker1:Fire("Enable") + end + + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d2_coast_07.lua b/gamemode/gametypes/hl2/mapscripts/d2_coast_07.lua new file mode 100644 index 00000000..1039294f --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d2_coast_07.lua @@ -0,0 +1,150 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["player_spawn_items"] = true, +} + +MAPSCRIPT.VehicleGuns = true + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + if GAMEMODE:GetPreviousMap() == "d2_coast_08" then + --- 3304.103271 5262.621094 1536.031250 + local checkpointTransfer = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(3304.103271, 5262.621094, 1536.031250), Ang = Angle(0, 90, 0) }) + GAMEMODE:SetPlayerCheckpoint(checkpointTransfer) + end + -- -1074.218628 9386.666016 1664.031250 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-1469.086060, 9136.386719, 1666.920044), Ang = Angle(0, 0, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(-1074.218628, 9386.666016, 1664.031250), + Angle(0, 0, 0), + Vector(-150, -305, 0), + Vector(150, 305, 200) + ) + checkpointTrigger1.OnTrigger = function() + GAMEMODE:SetVehicleCheckpoint(Vector(-1375.794800, 9251.247070, 1665.878174), Angle(0, -90, 0)) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(3302.857178, 5274.505859, 1536.031250), Ang = Angle(0, 180, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(3302.857178, 5274.505859, 1536.031250), + Angle(0, 0, 0), + Vector(-150, -80, 0), + Vector(150, 80, 100) + ) + checkpointTrigger2.OnTrigger = function() + GAMEMODE:SetVehicleCheckpoint(Vector(1950.889160, 6521.036621, 1538.650757), Angle(0.372, 3.839, 1.433)) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + -- The game isnt over if someone falls down, we clear the outputs and just kill the player. + for _,v in pairs(ents.FindByName("fall_trigger")) do + v:ClearOutputs() + v.OnTrigger = function(self, ent) + if ent:IsVehicle() then + local driver = ent:GetDriver() + if IsValid(driver) and driver:Alive() then + driver:Kill() + end + local passengerSeat = ent.PassengerSeat + if IsValid(passengerSeat) then + local passenger = passengerSeat:GetDriver() + if IsValid(passenger) and passenger:Alive() then + passenger:Kill() + end + end + -- If someone shoves the vehicle down it would be lost forever. + ent:Remove() + elseif ent:IsPlayer() and ent:Alive() then + ent:Kill() + end + end + end + + -- Lets make sure its closed. + ents.WaitForEntityByName("bridge_door_1", function(ent) + ent:Fire("Close") + end) + + -- Workaround: Make sure we let the dropship fly off, atm theres lua way to tell the contents of a specific model shape. + -- 3031.886963 5218.268066 1532.155762 + local hackTrigger1 = ents.Create("trigger_once") + hackTrigger1:SetupTrigger( + Vector(3031.886963, 5218.268066, 1532.155762), + Angle(0, 0, 0), + Vector(-150, -80, 0), + Vector(150, 80, 100) + ) + hackTrigger1.OnTrigger = function() + TriggerOutputs({ + {"dropship", "Activate", 0.0, ""}, + }) + end + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d2_coast_08.lua b/gamemode/gametypes/hl2/mapscripts/d2_coast_08.lua new file mode 100644 index 00000000..1f255dec --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d2_coast_08.lua @@ -0,0 +1,160 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["player_spawn_items"] = true, +} + +MAPSCRIPT.VehicleGuns = true + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- 3233.962402 -5601.413086 1564.521851 + + -- 3330.477539 1352.385864 1536.031250 + local checkpoint0 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(3332.003174, 1683.768311, 1536.031250), Ang = Angle(0, -90, 0) }) + GAMEMODE:SetPlayerCheckpoint(checkpoint0) + + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(3237.011963, -1235.819336, 1792.031250), Ang = Angle(0, -90, 0) }) + local checkpoint1rev = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(3237.011963, -1235.819336, 1792.031250), Ang = Angle(0, 90, 0) }) + local checkpointTrigger1 = ents.Create("trigger_multiple") + checkpointTrigger1:SetupTrigger( + Vector(3313.845215, -1269.754028, 1792.031250), + Angle(0, 0, 0), + Vector(-250, -105, 0), + Vector(250, 105, 200) + ) + checkpointTrigger1.OnTrigger = function(trigger) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + checkpoint1 = checkpoint1rev + trigger:Disable() + end + + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(3336.251709, -2644.284424, 1480.031250), Ang = Angle(0, -90, 0) }) + local checkpoint2rev = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(3336.251709, -2644.284424, 1480.031250), Ang = Angle(0, 90, 0) }) + local checkpointTrigger2 = ents.Create("trigger_multiple") + checkpointTrigger2:SetupTrigger( + Vector(3336.251709, -2644.284424, 1480.031250), + Angle(0, 0, 0), + Vector(-250, -105, 0), + Vector(250, 105, 200) + ) + checkpointTrigger2.OnTrigger = function(trigger) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + if checkpoint2 == checkpoint2rev then + checkpointTrigger1:Enable() + else + checkpoint2 = checkpoint2rev + end + trigger:Disable() + end + + -- 3338.592041 -4066.411621 1792.031250 + local checkpoint3 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(3415.853760, -4052.803955, 1792.031250), Ang = Angle(0, -90, 0) }) + local checkpoint3rev = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(3415.853760, -4052.803955, 1792.031250), Ang = Angle(0, 90, 0) }) + local checkpointTrigger3 = ents.Create("trigger_multiple") + checkpointTrigger3:SetupTrigger( + Vector(3338.592041, -4066.411621, 1792.031250), + Angle(0, 0, 0), + Vector(-250, -105, 0), + Vector(250, 105, 200) + ) + checkpointTrigger3.OnTrigger = function(trigger) + GAMEMODE:SetPlayerCheckpoint(checkpoint3) + if checkpoint3 == checkpoint3rev then + checkpointTrigger2:Enable() + else + checkpoint3 = checkpoint3rev + end + trigger:Disable() + end + + + -- 3302.523193 -5592.021484 1536.031250 + local checkpoint4 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(3325.756836, -5639.022461, 1536.031250), Ang = Angle(0, 0, 0) }) + local checkpoint4rev = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(3187.962402, -5593.404297, 1551.531250), Ang = Angle(0, 0, 0) }) + local checkpointTrigger4 = ents.Create("trigger_multiple") + checkpointTrigger4:SetupTrigger( + Vector(3302.523193, -5592.021484, 1536.031250), + Angle(0, 0, 0), + Vector(-250, -105, 0), + Vector(250, 105, 200) + ) + checkpointTrigger4.OnTrigger = function(trigger) + GAMEMODE:SetPlayerCheckpoint(checkpoint4) + if checkpoint4 == checkpoint4rev then + checkpointTrigger3:Enable() + else + checkpoint4 = checkpoint4rev + end + trigger:Disable() + end + + GAMEMODE:WaitForInput("button_trigger", "Use", function() + checkpointTrigger4:Enable() + GAMEMODE:EnablePreviousMap() + end) + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d2_coast_09.lua b/gamemode/gametypes/hl2/mapscripts/d2_coast_09.lua new file mode 100644 index 00000000..b8df71f7 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d2_coast_09.lua @@ -0,0 +1,168 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["global_newgame_spawner_ammo"] = true, + ["global_newgame_template_local_items"] = true, + ["global_newgame_template_base_items"] = true, +} + +MAPSCRIPT.VehicleGuns = true + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + -- -6397.890625 4632.765625 512.031250 + if SERVER then + + ents.WaitForEntityByName("reload", function(ent) ent:Remove() end) + ents.WaitForEntityByName("jeep_lost_in_water", function(ent) ent:Remove() end) + + ents.WaitForEntityByName("garage_door_1", function(ent) ent:SetKeyValue("spawnflags", "2097152") end) + ents.WaitForEntityByName("garage_door_2", function(ent) ent:SetKeyValue("spawnflags", "2097152") end) + ents.WaitForEntityByName("garage_door_3", function(ent) ent:SetKeyValue("spawnflags", "2097152") end) + + -- In case people throw batteries away. + local function ProtectBattery(ent) + + ent:SetKeyValue("spawnflags", "128") + + local data = game.FindEntityInMapData(ent:GetName()) + local originalPos = util.StringToType(data["origin"], "Vector") + local originalAng = util.StringToType(data["angles"], "Angle") + local centerPos = Vector(10211.183594, 8695.581055, -191.968750) + + hook.Add("Tick", ent, function(ent) + local pos = ent:GetPos() + local reset = false + -- Check general bounding distance. + if pos:Distance(centerPos) >= 1300 then + reset = true + end + -- Check positions that are unreachable + local vel = ent:GetVelocity() + if vel:Length() <= 0.01 then + local zDistance = pos.z - centerPos.z + if zDistance >= 120 then + reset = true + end + end + if reset == true and pos:Distance(originalPos) > 20 then + ent:SetVelocity(Vector(0, 0, 0)) + ent:SetPos(originalPos) + ent:SetAngles(originalAng) + end + end) + + end + + ents.WaitForEntityByName("battery", ProtectBattery) + ents.WaitForEntityByName("battery1", ProtectBattery) + ents.WaitForEntityByName("battery2", ProtectBattery) + ents.WaitForEntityByName("battery3", ProtectBattery) + ents.WaitForEntityByName("battery4", ProtectBattery) + + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-6203.434570, 4812.755859, 512.031250), Ang = Angle(0, -90, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(-6397.890625, 4632.765625, 512.031250), + Angle(0, 0, 0), + Vector(-300, -20, 0), + Vector(300, 20, 200) + ) + checkpointTrigger1.OnTrigger = function() + GAMEMODE:SetVehicleCheckpoint(Vector(-6321.518555, 4750.143066, 532.837036), Angle(0, 180, 0)) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + -- -1972.218506 -6339.304199 -831.352173 + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-2678.945068, -4921.056641, -739.129150), Ang = Angle(0, 0, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(-2628.320557, -7534.162109, -746.717529), + Angle(0, 0, 0), + Vector(-300, -2500, -1000), + Vector(300, 2800, 1000) + ) + checkpointTrigger2.OnTrigger = function() + GAMEMODE:SetVehicleCheckpoint(Vector(-2580.499023, -4993.037598, -759.513550), Angle(8, -90, -5)) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + + -- 8663.506836 11871.029297 -191.968750 + local checkpoint3 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(8648.458008, 11745.508789, -196.678345), Ang = Angle(0, -50, 0) }) + local checkpointTrigger3 = ents.Create("trigger_once") + checkpointTrigger3:SetupTrigger( + Vector(8663.506836, 11871.029297, -191.968750), + Angle(0, 0, 0), + Vector(-50, -600, 0), + Vector(50, 450, 200) + ) + checkpointTrigger3.OnTrigger = function() + GAMEMODE:SetVehicleCheckpoint(Vector(8699.614258, 11645.158203, -192.527618), Angle(0, -90, 0)) + GAMEMODE:SetPlayerCheckpoint(checkpoint3) + end + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d2_coast_10.lua b/gamemode/gametypes/hl2/mapscripts/d2_coast_10.lua new file mode 100644 index 00000000..de76cbf6 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d2_coast_10.lua @@ -0,0 +1,149 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["player_spawn_items_maker"] = true, +} + +MAPSCRIPT.VehicleGuns = true + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + -- -6397.890625 4632.765625 512.031250 + if SERVER then + + -- In case of map reset. + GAMEMODE:SetSpawnPlayerVehicles(true) + + -- This is ugly but it solves a strange issue where the whole script falls apart. + local timer1 = ents.Create("logic_timer") + timer1:SetKeyValue("RefireTime", "1") + timer1:Fire("AddOutput", "OnTimer dropship_container,SetDamageFilter,lambda_null_filter,0,-1") + timer1:Spawn() + + local nullFilter = ents.Create("filter_activator_class") + nullFilter:SetName("lambda_null_filter") + nullFilter:SetKeyValue("filterclass", "null") + nullFilter:Spawn() + + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(4805.765625, -401.630463, 916.031250), Ang = Angle(0, 0, 0) }) + + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(4891.401855, -227.542877, 916.031250), + Angle(0, 0, 0), + Vector(-100, -100, 0), + Vector(100, 100, 200) + ) + checkpointTrigger1:SetKeyValue("teamwait", "1") + checkpointTrigger1:SetKeyValue("disableendtouch", "1") + checkpointTrigger1.OnStartTouch = function(self, ent) + if ent:IsPlayer() then + local car = ent:GetVehicle() + if IsValid(car) then + car:Remove() + end + end + end + checkpointTrigger1.OnTrigger = function(self) + GAMEMODE:SetSpawnPlayerVehicles(false) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + TriggerOutputs({ + {"garage_exit_trigger", "Enable", 0, ""}, + {"greeter_conditions", "Disable", 0, ""}, + {"greeter_car_nag_timer", "Kill", 0, ""}, + {"garage_door", "Close", 0, ""}, + {"greeter_briefing_conditions", "Enable", 0, ""}, + {"greeter_wave_timer", "Disable", 0, ""}, + {"look_at_player", "Resume", 0, ""}, + }) + end + + -- 8222.646484 1799.084961 960.000000 + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(8222.646484, 1799.084961, 960.000000), Ang = Angle(0, 90, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(8220.174805, 1837.689819, 960.000000), + Angle(0, 0, 0), + Vector(-100, -100, 0), + Vector(100, 100, 200) + ) + checkpointTrigger2.OnTrigger = function(self) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + local triggerCar = ents.FindByPos(Vector(4773, -228, 976), "trigger_once") + for _,v in pairs(triggerCar) do + v:Remove() + end + + local triggerRaid = ents.FindByPos(Vector(8088, 1920, 896), "trigger_once") + for _,v in pairs(triggerRaid) do + v:SetKeyValue("teamwait", "1") + v:SetKeyValue("showwait", "0") -- Don't let the players know, this is subtile. + v:SetKeyValue("disableendtouch", "1") + end + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d2_coast_11.lua b/gamemode/gametypes/hl2/mapscripts/d2_coast_11.lua new file mode 100644 index 00000000..1677f667 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d2_coast_11.lua @@ -0,0 +1,218 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["global_newgame_template_base_items"] = true, + ["global_newgame_template_local_items"] = true, + ["global_newgame_template_ammo"] = true, + ["fall_trigger"] = true, + ["mc_both_in"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + -- -6397.890625 4632.765625 512.031250 + if SERVER then + + -- 8222.646484 1799.084961 960.000000 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(1391.161987, -4552.412598, 1201.034180), Ang = Angle(0, 45, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(1639.652832, -4384.989746, 1124.123779), + Angle(0, 45, 0), + Vector(-100, -250, 0), + Vector(100, 250, 200) + ) + checkpointTrigger1.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + -- 4805.734863 -293.060852 544.752808 + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(4805.734863, -293.060852, 544.752808), Ang = Angle(0, 106, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(4805.734863, -293.060852, 544.752808), + Angle(0, 0, 0), + Vector(-150, -150, 0), + Vector(150, 150, 200) + ) + checkpointTrigger2.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + -- 4194.318848 3518.950195 371.710144 + local checkpoint3 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(3319.693848, 3064.873535, 567.830078), Ang = Angle(0, 90, 0) }) + local checkpointTrigger3 = ents.Create("trigger_once") + checkpointTrigger3:SetupTrigger( + Vector(4151.009277, 2739.715820, 377.123840), + Angle(0, 0, 0), + Vector(-1700, -150, -300), + Vector(2400, 150, 600) + ) + checkpointTrigger3.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint3) + end + + ents.WaitForEntityByName("generator_button", function(ent) + ent:SetKeyValue("spawnflags", "1025") + ent:SetKeyValue("wait", "-1") + end) + + -- 4646.223145 6915.463867 447.677368 + local checkpoint4 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(4646.223145, 6915.463867, 447.677368), Ang = Angle(0, 90, 0) }) + local checkpointTrigger4 = ents.Create("trigger_once") + checkpointTrigger4:SetupTrigger( + Vector(4646.223145, 6915.463867, 447.677368), + Angle(0, 0, 0), + Vector(-420, -220, -200), + Vector(220, 420, 100) + ) + checkpointTrigger4.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint4) + end + + local allowGuard = false + GAMEMODE:WaitForInput("citizen_ambush_guard", "Unburrow", function(ent) + if allowGuard == false then + DbgPrint("Filtering antlion guard") + return true + end + end) + GAMEMODE:WaitForInput("music_antlionguard_2", "PlaySound", function(ent) + if allowGuard == false then + DbgPrint("Filtering antlion guard") + return true + end + end) + + -- Create a better trigger for all players. + local guardTrigger = ents.Create("trigger_once") + guardTrigger:SetupTrigger( + Vector(5680.671875, 8944.449219, 107.807495), + Angle(0, 0, 0), + Vector(-1500, -2000, -100), + Vector(1600, 1900, 180) + ) + guardTrigger:SetKeyValue("teamwait", "1") + guardTrigger.OnTrigger = function(ent) + allowGuard = true + TriggerOutputs({ + {"citizen_ambush_guard", "Unburrow", 0, ""}, + {"music_antlionguard_2", "PlaySound", 0, ""}, + }) + end + + ents.WaitForEntityByName("vortigaunt_bugbait", function(ent) + ent:SetKeyValue("spawnflags", "1030") -- Remove SF_NPC_WAIT_FOR_SCRIPT + end) + + -- Some players might refuse this, let this continue anyway. + ents.WaitForEntityByName("leadgoal_vortigaunt", function(ent) + ent:SetKeyValue("RetrieveDistance", "3000") + ent:SetKeyValue("LeadDistance", "3000") + ent:SetKeyValue("LeadDistance", "3000") + ent:SetKeyValue("WaitDistance", "3000") + end) + + -- Some players might refuse this, let this continue anyway. + ents.WaitForEntityByName("aigl_vort", function(ent) + ent:SetKeyValue("RetrieveDistance", "3000") + ent:SetKeyValue("LeadDistance", "3000") + ent:SetKeyValue("LeadDistance", "3000") + ent:SetKeyValue("WaitDistance", "3000") + end) + + GAMEMODE:WaitForInput("antlion_cage_door", "Close", function(ent) + return true -- dont close. + end) + + -- 5166.699219 9918.750977 162.514114 + local checkpoint5 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(5166.699219, 9918.750977, 162.514114), Ang = Angle(0, 180, 0) }) + local checkpointTrigger5 = ents.Create("trigger_once") + checkpointTrigger5:SetupTrigger( + Vector(5166.699219, 9918.750977, 162.514114), + Angle(0, 0, 0), + Vector(-50, -50, 0), + Vector(50, 50, 100) + ) + checkpointTrigger5.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint5) + end + + -- Checkpoint + -- 799.167236 11539.323242 499.299133 + local checkpoint6 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(799.167236, 11539.323242, 499.299133), Ang = Angle(0, 180, 0) }) + local checkpointTrigger6 = ents.Create("trigger_once") + checkpointTrigger6:SetupTrigger( + Vector(799.167236, 11539.323242, 499.299133), + Angle(0, 0, 0), + Vector(-50, -50, 0), + Vector(50, 50, 100) + ) + checkpointTrigger6.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint6) + end + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d2_coast_12.lua b/gamemode/gametypes/hl2/mapscripts/d2_coast_12.lua new file mode 100644 index 00000000..a6b773d9 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d2_coast_12.lua @@ -0,0 +1,166 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + "weapon_bugbait", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + --3957.129150 -5952.989258 450.031250 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(3957.129150, -5952.989258, 450.031250), Ang = Angle(0, 45, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(3652.347900, -5942.446777, 450.478577), + Angle(0, 0, 0), + Vector(-100, -250, 0), + Vector(100, 250, 200) + ) + checkpointTrigger1.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + -- 3544.566162 -5148.934570 494.436218 + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(3544.566162, -5148.934570, 494.436218), Ang = Angle(0, 45, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(5272.279785, -3704.953613, 244.444000), + Angle(0, 0, 0), + Vector(-100, -250, 0), + Vector(100, 250, 200) + ) + checkpointTrigger2.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + -- 2141.143555 -346.152466 672.031250 + local checkpoint3 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(2141.143555, -346.152466, 672.031250), Ang = Angle(0, 45, 0) }) + local checkpointTrigger3 = ents.Create("trigger_once") + checkpointTrigger3:SetupTrigger( + Vector(2141.143555, -346.152466, 672.031250), + Angle(0, 0, 0), + Vector(-100, -250, 0), + Vector(100, 250, 200) + ) + checkpointTrigger3.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint3) + end + + -- 2200.594727, 2562.878418, 644.802246 + local checkpoint4 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(2200.594727, 2562.878418, 644.802246), Ang = Angle(0, 45, 0) }) + local checkpointTrigger4 = ents.Create("trigger_once") + checkpointTrigger4:SetupTrigger( + Vector(2200.594727, 2562.878418, 644.802246), + Angle(0, 0, 0), + Vector(-100, -250, 0), + Vector(100, 250, 200) + ) + checkpointTrigger4.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint4) + end + + -- 4624.031250 4047.968750 848.031250 + local checkpoint5 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(4624.031250, 4047.968750, 848.031250), Ang = Angle(0, 45, 0) }) + local checkpointTrigger5 = ents.Create("trigger_once") + checkpointTrigger5:SetupTrigger( + Vector(4702.513184, 4080.001953, 848.031250), + Angle(0, 0, 0), + Vector(-100, -250, 0), + Vector(100, 250, 200) + ) + checkpointTrigger5.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint5) + end + + --7709.140625 6282.970703 686.273071 + local checkpoint6 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(7709.140625, 6282.970703, 686.273071), Ang = Angle(0, 45, 0) }) + local checkpointTrigger6 = ents.Create("trigger_once") + checkpointTrigger6:SetupTrigger( + Vector(7709.140625, 6282.970703, 686.273071), + Angle(0, 0, 0), + Vector(-100, -250, 0), + Vector(100, 250, 200) + ) + checkpointTrigger6.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint6) + end + + --9101.698242 7700.960938 1742.293091 + local checkpoint7 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(9101.698242, 7700.960938, 1742.293091), Ang = Angle(0, 45, 0) }) + local checkpointTrigger7 = ents.Create("trigger_once") + checkpointTrigger6:SetupTrigger( + Vector(9101.698242, 7700.960938, 1742.293091), + Angle(0, 0, 0), + Vector(-100, -250, 0), + Vector(100, 250, 200) + ) + checkpointTrigger7.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint7) + end + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d2_prison_01.lua b/gamemode/gametypes/hl2/mapscripts/d2_prison_01.lua new file mode 100644 index 00000000..711d5a5b --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d2_prison_01.lua @@ -0,0 +1,129 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + "weapon_bugbait", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- Enable the changelevel trigger like it would normally. + ents.WaitForEntityByName("changelevel_01-02", function(ent) + ent:SetKeyValue("spawnflags", "1") -- Remove no-touch + ent:Fire("Enable") + end) + + --1726.193115 -3289.614502 1344.031250 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(1726.193115, -3289.614502, 1280.03125), Ang = Angle(0, 0, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(1726.193115, -3289.614502, 1280.03125), + Angle(0, 0, 0), + Vector(-100, -250, 0), + Vector(100, 250, 200) + ) + checkpointTrigger1.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + --2918.824219 -3629.748779 1344.031250 + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(2918.824219, -3629.748779, 1280.03125), Ang = Angle(0, 0, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(3940.151855, -3635.220215, 1312.03125), + Angle(0, 0, 0), + Vector(-100, -250, 0), + Vector(100, 250, 200) + ) + checkpointTrigger2.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + --1645.749756 -2053.893066 1664.687744 + local checkpoint3 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(1645.749756, -2053.893066, 1600.687744), Ang = Angle(0, 0, 0) }) + local checkpointTrigger3 = ents.Create("trigger_once") + checkpointTrigger3:SetupTrigger( + Vector(1645.749756, -2053.893066, 1600.687744), + Angle(0, 0, 0), + Vector(-100, -250, 0), + Vector(100, 250, 200) + ) + checkpointTrigger3.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint3) + end + + -- Rock falling at the end + GAMEMODE:WaitForInput("relay_start_rockfall", "Trigger", function(ent) + TriggerOutputs({ + {"ambient_rockfall_creak", "PlaySound", 0, ""}, + {"door_2", "Unlock", 0, ""}, + }) + return true + end) + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d2_prison_02.lua b/gamemode/gametypes/hl2/mapscripts/d2_prison_02.lua new file mode 100644 index 00000000..f2c11b2d --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d2_prison_02.lua @@ -0,0 +1,106 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + "weapon_bugbait", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + ents.WaitForEntityByName("door_2", function(ent) + ent:Fire("Unlock") + end) + + if SERVER then + + --setpos -1384.557129 2894.679688 448.031250;setang -1.010203 -63.622845 0.000000 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-1384.557129, 2894.679688, 384.031250), Ang = Angle(0, 45, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(-1384.557129, 2894.679688, 384.031250), + Angle(0, 0, 0), + Vector(-100, -250, 0), + Vector(100, 250, 200) + ) + checkpointTrigger1.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + -- cp 2 setpos -1951.139526 2554.889893 576.031250;setang 6.475924 -93.248947 0.000000 + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-1951.139526, 2554.889893, 576.031250), Ang = Angle(0, 45, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(-1951.139526, 2554.889893, 576.031250), + Angle(0, 0, 0), + Vector(-100, -250, 0), + Vector(100, 250, 200) + ) + checkpointTrigger2.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d2_prison_03.lua b/gamemode/gametypes/hl2/mapscripts/d2_prison_03.lua new file mode 100644 index 00000000..772965ab --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d2_prison_03.lua @@ -0,0 +1,89 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + "weapon_bugbait", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["playerclip_shower_dropdown"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- -3566.677979 4935.034668 64.031250 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-3584.677979, 4911.034668, 0.031250), Ang = Angle(0, 45, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(-3584.677979, 4911.034668, 0.031250), + Angle(0, 0, 0), + Vector(-100, -250, 0), + Vector(100, 250, 200) + ) + checkpointTrigger1.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d2_prison_04.lua b/gamemode/gametypes/hl2/mapscripts/d2_prison_04.lua new file mode 100644 index 00000000..ca35bebb --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d2_prison_04.lua @@ -0,0 +1,101 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + "weapon_bugbait", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- -171.849915 1534.266602 320.031250 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-193.849915, 1534.266602, 256.031250), Ang = Angle(0, 45, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(-171.849915, 1534.266602, 320.031250), + Angle(0, 0, 0), + Vector(-100, -250, 0), + Vector(100, 250, 200) + ) + checkpointTrigger1.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + -- -563.311829 1569.210205 448.031250 + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-563.311829, 1569.210205, 384.163727), Ang = Angle(0, 45, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(-563.311829, 1569.210205, 384.163727), + Angle(0, 0, 0), + Vector(-100, -250, 0), + Vector(100, 250, 200) + ) + checkpointTrigger2.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d2_prison_05.lua b/gamemode/gametypes/hl2/mapscripts/d2_prison_05.lua new file mode 100644 index 00000000..3b6e3d81 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d2_prison_05.lua @@ -0,0 +1,128 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + "weapon_bugbait", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- setpos -497.127838 29.422707 576.030090;setang 1.708000 -178.566528 0.000000 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-497.127838, 29.422707, 512.03009), Ang = Angle(0, 0, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(-497.127838, 29.422707, 576.030090), + Angle(0, 0, 0), + Vector(-100, -250, 0), + Vector(100, 250, 200) + ) + checkpointTrigger1.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + --setpos -1863.151978 -198.581955 576.031250;setang 4.380192 174.982666 0.000000 + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-1863.151978, -198.581955, 512.03125), Ang = Angle(0, 0, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(-1863.151978, -198.581955, 576.031250), + Angle(0, 0, 0), + Vector(-100, -250, 0), + Vector(100, 250, 200) + ) + checkpointTrigger2.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + -- setpos -2622.549316 191.525955 704.031250;setang 4.698761 -175.380798 0.000000 + local checkpoint3 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-2622.549316, 191.525955, 640.03125), Ang = Angle(0, 0, 0) }) + local checkpointTrigger3 = ents.Create("trigger_once") + checkpointTrigger3:SetupTrigger( + Vector(-2622.549316, 191.525955, 704.031250), + Angle(0, 0, 0), + Vector(-100, -250, 0), + Vector(100, 250, 200) + ) + checkpointTrigger3.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint3) + end + + -- setpos -4656.063477 -734.348145 704.031250;setang 3.504144 -4.528329 0.000000 + local checkpoint4 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-4656.063477, -734.348145, 640.03125), Ang = Angle(0, 0, 0) }) + local checkpointTrigger4 = ents.Create("trigger_once") + checkpointTrigger4:SetupTrigger( + Vector(-4656.063477, -734.348145, 704.031250), + Angle(0, 0, 0), + Vector(-100, -250, 0), + Vector(100, 250, 200) + ) + checkpointTrigger4.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint4) + end + + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d2_prison_06.lua b/gamemode/gametypes/hl2/mapscripts/d2_prison_06.lua new file mode 100644 index 00000000..483d2d9e --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d2_prison_06.lua @@ -0,0 +1,145 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + "weapon_bugbait", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ + ["door_controlroom_1"] = { "Close", "Lock" }, + ["door_room1_gate"] = { "Close" }, +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- setpos 1389.400879 666.277100 -127.968750;setang 0.437201 177.274811 0.000000 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(1389.400879, 666.277100, -191.836243), Ang = Angle(0, 0, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(1389.400879, 666.277100, -191.836243), + Angle(0, 0, 0), + Vector(-100, -250, 0), + Vector(100, 250, 200) + ) + checkpointTrigger1.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + -- 1577.605347 651.466064 -642.468750 + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(1577.605347, 651.466064, -672.468750), Ang = Angle(0, 180, 0) }) + ents.WaitForEntityByName("introom_elevator_1", function(ent) + checkpoint2:SetParent(ent) + end) + ents.WaitForEntityByName("elevator_trigger_go_up_1", function(ent) + ent:SetKeyValue("teamwait", "1") + ent.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + end) + + local resume_hack = ents.Create("logic_timer") + resume_hack:SetKeyValue("startdisabled", "1") + resume_hack:SetKeyValue("refiretime", "1") + resume_hack:SetName("lambda_resume_hack") + resume_hack:Spawn() + resume_hack:Fire("AddOutput", "OnTimer lcs_np_cell02,Resume,,0.0") + + local checkpoint5 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(509.210663, 65.186150, 0.031250), Ang = Angle(0, 180, 0) }) + + ents.WaitForEntityByName("int_door_close_inside_1", function(ent) + ent:SetKeyValue("teamwait", "1") + ent.OnTrigger = function(ent) + DbgPrint("Firing resume hack") + resume_hack:Fire("Enable") + GAMEMODE:SetPlayerCheckpoint(checkpoint5) + end + end) + + -- setpos 508.389771 -932.631348 64.031250;setang 0.842813 -0.293497 0.000000 + local checkpoint3 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(508.389771, -932.631348, 0.031250), Ang = Angle(0, 45, 0) }) + local checkpointTrigger3 = ents.Create("trigger_once") + checkpointTrigger3:SetupTrigger( + Vector(481.376953, -937.476746, 0.031250), + Angle(0, 0, 0), + Vector(0, -100, 0), + Vector(10, 100, 100) + ) + checkpointTrigger3.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint3) + end + + -- 981.835876 -3084.621826 -239.968750 + local checkpoint4 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(980.400391, -3211.114746, -239.968750), Ang = Angle(0, 90, 0) }) + local checkpointTrigger4 = ents.Create("trigger_once") + checkpointTrigger4:SetupTrigger( + Vector(981.835876, -3084.621826, -239.968750), + Angle(0, 0, 0), + Vector(-50, -10, 0), + Vector(50, 10, 100) + ) + checkpointTrigger4.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint4) + end + + end +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d2_prison_07.lua b/gamemode/gametypes/hl2/mapscripts/d2_prison_07.lua new file mode 100644 index 00000000..de3d8da5 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d2_prison_07.lua @@ -0,0 +1,213 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + "weapon_bugbait", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ + ["door_controlroom_1"] = { "Close", "Lock" }, + ["door_room1_gate"] = { "Close" }, +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["relationship_turret_vs_combine_hate"] = true, + ["relationship_turret_vs_alyx_like"] = true, + ["relationship_turret_vs_manhack_hate"] = true, + ["relationship_combine_vs_turret_hate"] = true, + ["relationship_alyx_vs_turret_like"] = true, + ["relationship_turret_vs_player_like"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + local allowClose = false + GAMEMODE:WaitForInput("door_croom2_gate", "Close", function(ent) + if allowClose == false then + return true + end + end) + + ents.WaitForEntityByName("turret_buddy", function(ent) + ent:SetKeyValue("spawnflags", "576") + end, true) + + -- First defense clip, causes glitches if bypassed. + local pclip1 = ents.Create("func_brush") + pclip1:SetModel("*17") + pclip1:SetPos(Vector(-423.9, -3681, 17.21)) + pclip1:SetName("lambda_pclip1") + pclip1:Spawn() + pclip1:AddDebugOverlays(bit.bor(OVERLAY_PIVOT_BIT, OVERLAY_BBOX_BIT, OVERLAY_NAME_BIT)) + + local pclip2 = ents.Create("func_brush") + pclip2:SetModel("*17") + pclip2:SetPos(Vector(-423.9, -3681, 185.21)) + pclip2:SetName("lambda_pclip2") + pclip2:Spawn() + pclip2:AddDebugOverlays(bit.bor(OVERLAY_PIVOT_BIT, OVERLAY_BBOX_BIT, OVERLAY_NAME_BIT)) + + -- -122.634003 -2595.938477 -239.968750 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-440.542938, -2845.282227, -239.968750), Ang = Angle(0, -90, 0) }) + local checkpointTrigger1 = ents.Create("trigger_multiple") + checkpointTrigger1:SetupTrigger( + Vector(-122.634003, -2595.938477, -239.968750), + Angle(0,0,0), + Vector(-500, -300, 0), + Vector(500, 200, 200) + ) + checkpointTrigger1.OnEndTouchAll = function(trigger) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + allowClose = true + TriggerOutputs({ + {"door_croom2_gate", "Close", 0, ""}, + }) + trigger:Remove() + DbgPrint("All players left") + end + + -- 1142.276611 -3385.270264 -295.968750 + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(1142.276611, -3385.270264, -295.968750), Ang = Angle(0, 90, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(1142.276611, -3385.270264, -295.968750), + Angle(0, 0, 0), + Vector(-100, -100, 0), + Vector(100, 100, 100) + ) + checkpointTrigger2.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + -- 1680.254639 -3440.008301 -679.968750 + local checkpoint3 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(1680.254639, -3440.008301, -679.968750), Ang = Angle(0, -90, 0) }) + local checkpointTrigger3 = ents.Create("trigger_once") + checkpointTrigger3:SetupTrigger( + Vector(1680.254639, -3440.008301, -679.968750), + Angle(0, 0, 0), + Vector(-50, -50, 0), + Vector(50, 50, 100) + ) + checkpointTrigger3.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint3) + end + + -- 4689.422852 -3630.892090 -479.968750 + local checkpoint4 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(4689.422852, -3630.892090, -479.968750), Ang = Angle(0, 180, 0) }) + local checkpointTrigger4 = ents.Create("trigger_once") + checkpointTrigger4:SetupTrigger( + Vector(4689.422852, -3630.892090, -479.968750), + Angle(0, 0, 0), + Vector(-40, -150, 0), + Vector(40, 150, 100) + ) + checkpointTrigger4.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint4) + end + + -- 4161.470215 -3967.863525 -543.968750 + local checkpoint5 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(4779.625488, -4233.572266, -543.968750), Ang = Angle(0, 180, 0) }) + local checkpointTrigger5 = ents.Create("trigger_once") + checkpointTrigger5:SetupTrigger( + Vector(4161.470215, -3967.863525, -543.968750), + Angle(0, 0, 0), + Vector(-180, -100, 0), + Vector(180, 100, 100) + ) + checkpointTrigger5.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint5) + end + + -- Second defense, we manipulate the math_counter for the turrets and add an extra input value that fires once all players are there. + ents.WaitForEntityByName("math_room5_count_turrets", function(ent) + ent:SetKeyValue("max", "4") + end) + + local checkpointTrigger6 = ents.Create("trigger_once") + checkpointTrigger6:SetupTrigger( + Vector(4143.243164, -4192.229980, -531.423218), + Angle(0, 0, 0), + Vector(-500, -700, -30), + Vector(700, 420, 100) + ) + checkpointTrigger6:SetKeyValue("teamwait", "1") + checkpointTrigger6.OnTrigger = function(ent) + TriggerOutputs({ + {"math_room5_count_turrets", "Add", 0, "1"}, + }) + end + + -- Make sure that alyx will get there. + ents.WaitForEntityByName("lcs_message_room5_done", function(ent) + ent:Fire("AddOutput", "OnCompletion logic_room5_assault_finished,Trigger,,10,-1") + ent:Fire("AddOutput", "OnCompletion logic_room5_assault_finished,Kill,,10.1,-1") + end) + + end +end + +function MAPSCRIPT:PreChangelevel(map, landmark) + + -- Make sure alyx is within the volume . + local alyx = ents.FindFirstByName("alyx") + if IsValid(alyx) then + alyx:SetPos(Vector(4459.584961, -4338.886230, -695.906250)) + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d2_prison_08.lua b/gamemode/gametypes/hl2/mapscripts/d2_prison_08.lua new file mode 100644 index 00000000..fd860397 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d2_prison_08.lua @@ -0,0 +1,173 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + "weapon_bugbait", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["NClip_sec_tp_door_1"] = true, + ["PClip_sec_tp_door_1"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- setpos -497.127838 29.422707 576.030090;setang 1.708000 -178.566528 0.000000 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-497.127838, 29.422707, 512.03009), Ang = Angle(0, 0, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(-497.127838, 29.422707, 576.030090), + Angle(0, 0, 0), + Vector(-100, -250, 0), + Vector(100, 250, 200) + ) + checkpointTrigger1.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + -- -709.431885 820.863708 960.031250 + local triggerPoint1 = false + GAMEMODE:WaitForInput("brush_bigdoor_ALYXClip_1", "Enable", function(ent) + if triggerPoint1 == false then + return true + end + end) + GAMEMODE:WaitForInput("trigger_teleport01", "Enable", function(ent) + if triggerPoint1 == false then + return true + end + end) + + -- -956.561707 820.578613 960.031250 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-956.561707, 820.578613, 960.031250), Ang = Angle(0, 0, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(-709.431885, 820.863708, 960.031250), + Angle(0, 0, 0), + Vector(-400, -300, -10), + Vector(500, 180, 250) + ) + checkpointTrigger1:SetKeyValue("teamwait", "1") + checkpointTrigger1.OnTrigger = function(ent) + triggerPoint1 = true + TriggerOutputs({ + {"brush_bigdoor_ALYXClip_1", "Enable", 0, ""}, + {"trigger_teleport01", "Enable", 0, ""}, + }) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + ents.WaitForEntityByName("trigger_teleport01", function(ent) + ent:ResizeTriggerBox(Vector(-330, -300, -100), Vector(500, 50, 200)) + --ent:SetKeyValue("teamwait", "1") + end) + + -- Inverse + -- -579.983948 563.455078 928.031250 + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-579.983948, 563.455078, 928.031250), Ang = Angle(0, 0, 0) }) + local checkpointTrigger2 = ents.Create("trigger_multiple") + checkpointTrigger2:SetupTrigger( + Vector(-709.431885, 820.863708, 960.031250), + Angle(0, 0, 0), + Vector(-400, -240, -10), + Vector(500, 180, 250) + ) + checkpointTrigger2:SetKeyValue("StartDisabled", "1") + checkpointTrigger2.OnEndTouchAll = function(ent) + TriggerOutputs({ + {"combine_door_1", "SetAnimation", 0, "Close"}, + {"logic_apply_relationships_1", "Trigger", 0, ""}, + {"sec_room_door_1", "Close", 0, ""}, + {"prop_camerasx", "Kill", 0, ""}, + {"combine_door_1", "SetAnimation", 0, "idle_closed"}, + }) + ent:Remove() + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + -- Replace trigger with inverse one. + ents.WaitForEntityByName("trigger_close_console_door_1", function(ent) + checkpointTrigger2:SetName("trigger_close_console_door_1") + ent:Remove() + end) + + -- Skip alyx closing the door + ents.WaitForEntityByName("trigger_tp_scene_start", function(ent) + ent:Fire("AddOutput", "OnTrigger relayAnim_PodExtractor_extract,Trigger,,5,-1") + end) + + ents.WaitForEntityByName("lcs_np_teleport04", function(ent) + ent:Remove() + ents.WaitForEntityByName("lcs_np_teleport05", function(ent) + ent:SetName("lcs_np_teleport04") + ent:Fire("AddOutput", "OnTrigger1") + end) + end) + + ents.WaitForEntityByName("trigger_teleport_player_enter_1", function(ent) + ent:ResizeTriggerBox(Vector(-30, -30, 0), Vector(30, 30, 100)) + ent:SetKeyValue("teamwait", "1") + end) + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d3_c17_01.lua b/gamemode/gametypes/hl2/mapscripts/d3_c17_01.lua new file mode 100644 index 00000000..577fc73c --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d3_c17_01.lua @@ -0,0 +1,94 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + "weapon_bugbait", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ + ["doors_elevator_2"] = { "Close" }, + ["doors_elevator_1"] = { "Close" }, + ["timer_nag_leave_1"] = { "Kill" }, + ["logic_nag_leave_1"] = { "Kill" }, +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["trigger_closeTPDoor"] = true, + ["teleport_screenoverlay_Kleiner_1"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- setpos -497.127838 29.422707 576.030090;setang 1.708000 -178.566528 0.000000 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-497.127838, 29.422707, 512.03009), Ang = Angle(0, 0, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(-497.127838, 29.422707, 576.030090), + Angle(0, 0, 0), + Vector(-100, -250, 0), + Vector(100, 250, 200) + ) + checkpointTrigger1.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d3_c17_02.lua b/gamemode/gametypes/hl2/mapscripts/d3_c17_02.lua new file mode 100644 index 00000000..789be6f2 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d3_c17_02.lua @@ -0,0 +1,102 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + "weapon_bugbait", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + --["pclip_gate1"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + ents.RemoveByClass("trigger_once", Vector(-5504, -5636, 30)) + + -- setpos -497.127838 29.422707 576.030090;setang 1.708000 -178.566528 0.000000 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-5478.429688, -5604.233887, -3.968750), Ang = Angle(0, 90, 0) }) + local checkpointTrigger1 = ents.Create("trigger_multiple") + checkpointTrigger1:SetupTrigger( + Vector(-7763.793945, -6373.333496, 10.588013), + Angle(0, 0, 0), + Vector(-3400, -1050, -100), + Vector(2200, 1050, 300) + ) + checkpointTrigger1.OnEndTouchAll = function(ent) + TriggerOutputs({ + {"relationship_soldiers_vs_dog_like", "RevertRelationship", 0, ""}, + {"pclip_gate1", "Enable", 0, ""}, + {"lcs_dog_nag_door_loop1", "Cancel", 0, ""}, + {"lcs_dog_nag_door_loop1", "Kill", 0.10, ""}, + {"relationship_soldiers_vs_dog_hate", "ApplyRelationship", 0.20, ""}, + {"logic_dropshipStart", "Trigger", 1.00, ""}, + {"ss_dog_ThruGate", "BeginSequence", 2.50, ""}, + {"sound_dog_surprised_1", "PlaySound", 4.00, ""}, + {"sound_dog_roar_1", "PlaySound", 6.00, ""}, + }) + ent:Remove() + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d3_c17_03.lua b/gamemode/gametypes/hl2/mapscripts/d3_c17_03.lua new file mode 100644 index 00000000..d4ce1d76 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d3_c17_03.lua @@ -0,0 +1,75 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + "weapon_bugbait", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["pclip_gate1"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d3_c17_04.lua b/gamemode/gametypes/hl2/mapscripts/d3_c17_04.lua new file mode 100644 index 00000000..fc1bf0df --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d3_c17_04.lua @@ -0,0 +1,88 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + "weapon_bugbait", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["pclip_gate1"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- -1468.447632 -4747.628418 320.031250 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-1468.447632, -4747.628418, 320.031250), Ang = Angle(0, -90, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(-1468.447632, -4747.628418, 320.031250), + Angle(0, 0, 0), + Vector(-50, -50, 0), + Vector(50, 50, 130) + ) + checkpointTrigger1.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d3_c17_05.lua b/gamemode/gametypes/hl2/mapscripts/d3_c17_05.lua new file mode 100644 index 00000000..032d42f2 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d3_c17_05.lua @@ -0,0 +1,127 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + "weapon_bugbait", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["pclip_gate1"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- 1921.614014 -5632.266602 320.031250 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(1921.614014, -5632.266602, 320.031250), Ang = Angle(0, 180, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(1921.614014, -5632.266602, 320.031250), + Angle(0, 0, 0), + Vector(-110, -110, 0), + Vector(110, 110, 100) + ) + checkpointTrigger1.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + -- 896.339966 -4236.764160 384.031250 + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(830.641296, -4235.453125, 128.031250), Ang = Angle(0, 90, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(831.859619, -4104.012695, 128.031250), + Angle(0, 0, 0), + Vector(-20, -20, 0), + Vector(20, 20, 100) + ) + checkpointTrigger2.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + -- 1793.683350 -3479.405762 320.031250 + local checkpoint3 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(1793.683350, -3479.405762, 320.031250), Ang = Angle(0, 0, 0) }) + local checkpointTrigger3 = ents.Create("trigger_once") + checkpointTrigger3:SetupTrigger( + Vector(1793.683350, -3479.405762, 320.031250), + Angle(0, 0, 0), + Vector(-100, -80, 0), + Vector(100, 80, 100) + ) + checkpointTrigger3.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint3) + end + + -- 1600.604126 -3304.045898 -63.968750 + local checkpoint4 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(1597.989380, -3329.118408, -63.968750), Ang = Angle(0, 0, 0) }) + local checkpointTrigger4 = ents.Create("trigger_once") + checkpointTrigger4:SetupTrigger( + Vector(1597.989380, -3329.118408, -63.968750), + Angle(0, 0, 0), + Vector(-60, -60, 0), + Vector(60, 60, 100) + ) + checkpointTrigger4.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint4) + end + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d3_c17_06a.lua b/gamemode/gametypes/hl2/mapscripts/d3_c17_06a.lua new file mode 100644 index 00000000..2dd99fb7 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d3_c17_06a.lua @@ -0,0 +1,102 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + "weapon_bugbait", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["pclip_gate1"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- 3081.572754 -1725.475098 -287.968750 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(3081.572754, -1725.475098, -287.968750), Ang = Angle(0, 90, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(3081.572754, -1725.475098, -287.968750), + Angle(0, 0, 0), + Vector(-50, -50, 0), + Vector(50, 50, 100) + ) + checkpointTrigger1.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + -- 2937.786865 2507.701416 -319.968750 6.483 89.871 0.000 + + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(2667.206787, 3911.651367, -323.968750), Ang = Angle(0, 90, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(2945.403076, 2563.369629, -319.968750), + Angle(0, 0, 0), + Vector(-30, -30, 0), + Vector(30, 30, 100) + ) + checkpointTrigger2.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d3_c17_06b.lua b/gamemode/gametypes/hl2/mapscripts/d3_c17_06b.lua new file mode 100644 index 00000000..21a4ff98 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d3_c17_06b.lua @@ -0,0 +1,149 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + "weapon_bugbait", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["pclip_gate1"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- 2894.431396 1052.031250 64.031250 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(2843.645508, 1058.373169, 64.031250), Ang = Angle(0, 0, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(2894.431396, 1052.031250, 64.031250), + Angle(0, 0, 0), + Vector(-20, -20, 0), + Vector(20, 20, 100) + ) + checkpointTrigger1.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + -- 3477.289062 1116.633179 0.031250 -0.188 -90.478 0.000 + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(3477.289062, 1116.633179, 0.031250), Ang = Angle(0, -90, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(3477.289062, 1116.633179, 0.031250), + Angle(0, 0, 0), + Vector(-60, -60, 0), + Vector(60, 60, 100) + ) + checkpointTrigger2.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + -- 3575.494873 1570.045532 256.031250 26.014 90.459 0.000 + local checkpoint3 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(3648.722412, 1569.612793, 256.031250), Ang = Angle(0, 90, 0) }) + local checkpointTrigger3 = ents.Create("trigger_once") + checkpointTrigger3:SetupTrigger( + Vector(3575.494873, 1570.045532, 256.031250), + Angle(0, 0, 0), + Vector(-60, -60, 0), + Vector(60, 60, 100) + ) + checkpointTrigger3.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint3) + end + + ents.WaitForEntityByName("wench_1_lever_1", function(ent) + ent:SetKeyValue("spawnflags", "122") + end) + + -- 3314.308350 1882.039551 0.031250 10.966 -88.900 0.000 + local checkpoint4 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(3648.722412, 1569.612793, 256.031250), Ang = Angle(0, -90, 0) }) + local checkpointTrigger4 = ents.Create("trigger_once") + checkpointTrigger4:SetupTrigger( + Vector(3314.308350, 1882.039551, 0.031250), + Angle(0, 0, 0), + Vector(-30, -30, 0), + Vector(30, 30, 100) + ) + checkpointTrigger4.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint4) + end + + ents.WaitForEntityByName("wench_2_lever_1", function(ent) + ent:Fire("AddOutput", "OnOpen !self,Lock") + end) + + -- 4022.167480 1330.496826 387.531250 3.706 -140.541 0.000 + local checkpoint5 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(3940.753906, 1200.170898, 384.031250), Ang = Angle(0, 180, 0) }) + local checkpointTrigger5 = ents.Create("trigger_once") + checkpointTrigger5:SetupTrigger( + Vector(4022.167480, 1330.496826, 387.531250), + Angle(0, 0, 0), + Vector(-40, -40, 0), + Vector(40, 40, 100) + ) + checkpointTrigger5.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint5) + end + + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d3_c17_07.lua b/gamemode/gametypes/hl2/mapscripts/d3_c17_07.lua new file mode 100644 index 00000000..aa0c6a69 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d3_c17_07.lua @@ -0,0 +1,120 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + "weapon_bugbait", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ + ["alyx_briefingroom_exitdoor"] = { "Close", "Lock" }, +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["pclip_gate1"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- 5487.663574 1408.772949 0.031250 10.626 -1.579 0.000 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(5329.144043, 1568.602905, 0.031250), Ang = Angle(0, 0, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(5487.663574, 1408.772949, 0.031250), + Angle(0, 0, 0), + Vector(-30, -30, 0), + Vector(30, 30, 100) + ) + checkpointTrigger1.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + -- 4817.152344 1203.166138 0.031250 + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(4817.152344, 1203.166138, 0.031250), Ang = Angle(0, -90, 0) }) + ents.WaitForEntityByName("lcs_pregate01_trigger", function(ent) + ent:ResizeTriggerBox(Vector(-180, -100, -40), Vector(180, 400, 60)) + ent:SetKeyValue("teamwait", "1") + ent.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + end) + + ents.WaitForEntityByName("gate_close_trigger", function(ent) + ent:Remove() + end) + + + local checkpoint3 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(7399.153809, 1336.154907, 0.031250), Ang = Angle(0, 0, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(8031.499512, 1544.012939, -3.968811), + Angle(0, 0, 0), + Vector(-800, -1000, -600), + Vector(2600, 1600, 200) + ) + checkpointTrigger2:SetKeyValue("teamwait", "1") + checkpointTrigger2.OnTrigger = function(ent) + TriggerOutputs({ + {"gate_close_counter", "Add", 0, "1"}, + }) + GAMEMODE:SetPlayerCheckpoint(checkpoint3) + end + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d3_c17_08.lua b/gamemode/gametypes/hl2/mapscripts/d3_c17_08.lua new file mode 100644 index 00000000..16b7c028 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d3_c17_08.lua @@ -0,0 +1,142 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + "weapon_bugbait", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["pclip_gate1"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- -1478.292725 -1717.604614 104.600342 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-1478.292725, -1717.604614, 104.600342), Ang = Angle(0, 90, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(-1478.292725, -1717.604614, 104.600342), + Angle(0, 0, 0), + Vector(-130, -130, 0), + Vector(130, 130, 100) + ) + checkpointTrigger1.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + -- 1119.968750 -840.288269 -559.968750 + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(299.584564, -1424.746704, -287.968750), Ang = Angle(0, 0, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(227.741821, -1265.945923, -287.968750), + Angle(0, 0, 0), + Vector(-130, -130, 0), + Vector(130, 130, 100) + ) + checkpointTrigger2.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + -- 1537.006226 -813.546021 80.031250 + local checkpoint3 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(1488.074829, -900.734985, 80.031250), Ang = Angle(0, 90, 0) }) + local checkpointTrigger3 = ents.Create("trigger_once") + checkpointTrigger3:SetupTrigger( + Vector(1537.006226, -813.546021, 80.031250), + Angle(0, 0, 0), + Vector(-130, -130, 0), + Vector(130, 130, 100) + ) + checkpointTrigger3.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint3) + end + + + -- 1392.383179 -76.121971 372.128113 + local checkpoint4 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(1286.711914, 610.125366, 400.031250), Ang = Angle(0, -90, 0) }) + local checkpointTrigger4 = ents.Create("trigger_once") + checkpointTrigger4:SetupTrigger( + Vector(1392.383179, -76.121971, 372.128113), + Angle(0, 0, 0), + Vector(-500, -500, 0), + Vector(500, 500, 250) + ) + checkpointTrigger4.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint4) + end + + -- 1650.219482 -89.667931 624.031250 + local checkpoint5 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(1650.219482, -89.667931, 624.031250), Ang = Angle(0, 0, 0) }) + local checkpointTrigger5 = ents.Create("trigger_once") + checkpointTrigger5:SetupTrigger( + Vector(1650.219482, -89.667931, 624.031250), + Angle(0, 0, 0), + Vector(-100, -100, 0), + Vector(100, 100, 100) + ) + checkpointTrigger5.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint5) + end + + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d3_c17_09.lua b/gamemode/gametypes/hl2/mapscripts/d3_c17_09.lua new file mode 100644 index 00000000..b80e3879 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d3_c17_09.lua @@ -0,0 +1,125 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + "weapon_bugbait", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ + ["sniper1"] = { "Kill" }, + ["sniper2"] = { "Kill" }, +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["pclip_gate1"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- 7099.762695 6237.561523 0.031250 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(7405.353516, 6305.318848, 0.031250), Ang = Angle(0, 180, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(7099.762695, 6237.561523, 0.031250), + Angle(0, 0, 0), + Vector(-130, -130, 0), + Vector(130, 130, 100) + ) + checkpointTrigger1.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + -- 6000.681641 6446.313477 96.031250 + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(6000.681641, 6446.313477, 96.031250), Ang = Angle(0, 0, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(6000.681641, 6446.313477, 96.031250), + Angle(0, 0, 0), + Vector(-130, -130, 0), + Vector(130, 130, 100) + ) + checkpointTrigger2.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + --[[ + ents.WaitForEntityByName("sniper1", function(ent) + ent:SetName("lambda_sniper1") + end) + + ents.WaitForEntityByName("sniper2", function(ent) + ent:SetName("lambda_sniper2") + end) + + ents.WaitForEntityByName("sniper3", function(ent) + ent:SetName("lambda_sniper3") + end) + + ents.WaitForEntityByName("sniper4", function(ent) + ent:SetName("lambda_sniper4") + end) + + ents.WaitForEntityByName("sniper5", function(ent) + ent:SetName("lambda_sniper5") + end) + ]] + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d3_c17_10a.lua b/gamemode/gametypes/hl2/mapscripts/d3_c17_10a.lua new file mode 100644 index 00000000..3e415b2f --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d3_c17_10a.lua @@ -0,0 +1,127 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + "weapon_bugbait", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["player_spawn_items"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- -2672.437500 6479.918945 512.031250 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-2672.437500, 6479.918945, 512.031250), Ang = Angle(0, 0, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(-2672.437500, 6479.918945, 512.031250), + Angle(0, 0, 0), + Vector(-60, -60, 0), + Vector(60, 60, 100) + ) + checkpointTrigger1.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + -- -1407.534912 4417.064453 128.031250 + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-1416.659668, 4142.781738, 128.031250), Ang = Angle(0, 90, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(-1407.534912, 4417.064453, 128.031250), + Angle(0, 0, 0), + Vector(-60, -60, 0), + Vector(60, 60, 100) + ) + checkpointTrigger2.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + -- -1404.743896 8211.465820 128.031250 + local checkpoint3 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-1404.743896, 8211.465820, 128.031250), Ang = Angle(0, 0, 0) }) + local checkpointTrigger3 = ents.Create("trigger_once") + checkpointTrigger3:SetupTrigger( + Vector(-1404.743896, 8161.465820, 128.031250), + Angle(0, 0, 0), + Vector(-60, -60, 0), + Vector(60, 60, 100) + ) + checkpointTrigger3.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint3) + end + + end + +end + +function MAPSCRIPT:OnNewGame() + + DbgPrint("OnNewGame") + + -- TODO: Validate me. + if not IsValid(ents.FindFirstByName("barney")) then + ents.WaitForEntityByName("player_spawn_items_maker", function(ent) + ent:Fire("ForceSpawn") + end) + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d3_c17_10b.lua b/gamemode/gametypes/hl2/mapscripts/d3_c17_10b.lua new file mode 100644 index 00000000..c51a06c4 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d3_c17_10b.lua @@ -0,0 +1,130 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + "weapon_bugbait", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ + ["s_room_panelswitch"] = { "Lock" }, -- Prevent it from locking the button. +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["player_spawn_items"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- 3887.857910 -514.078979 512.031250 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(4184.389160, -740.649597, 512.031250), Ang = Angle(0, 180, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(3887.857910, -514.078979, 512.031250), + Angle(0, 0, 0), + Vector(-160, -160, 0), + Vector(160, 160, 100) + ) + checkpointTrigger1.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + -- Add another logic relay that disables all turrets once the button is pressed. + local turretsOffRelay = ents.Create("logic_relay") + turretsOffRelay:SetKeyValue("targetname", "s_room_off_relay") + turretsOffRelay:SetKeyValue("StartDisabled", "0") + turretsOffRelay:SetKeyValue("OnTrigger", "s_room_turret_1,Disable,,0,-1") + turretsOffRelay:SetKeyValue("OnTrigger", "s_room_turret_2,Disable,,0,-1") + turretsOffRelay:SetKeyValue("OnTrigger", "s_room_turret_3,Disable,,0,-1") + turretsOffRelay:SetKeyValue("OnTrigger", "s_room_turret_4,Disable,,0,-1") + turretsOffRelay:SetKeyValue("OnTrigger", "s_room_turret_5,Disable,,0,-1") + turretsOffRelay:SetKeyValue("OnTrigger", "s_room_turret_6,Disable,,0,-1") + turretsOffRelay:SetKeyValue("OnTrigger", "s_room_turret_7,Disable,,0,-1") + turretsOffRelay:SetKeyValue("OnTrigger", "s_room_turret_8,Disable,,0,-1") + turretsOffRelay:SetKeyValue("OnTrigger", "s_room_doors,Open,,0,-1") + turretsOffRelay:Spawn() + + -- 2657.141357 1033.785645 256.031250 + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(2657.141357, 1033.785645, 256.031250), Ang = Angle(0, 0, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(2657.141357, 1033.785645, 256.031250), + Angle(0, 0, 0), + Vector(-60, -60, 0), + Vector(60, 60, 100) + ) + checkpointTrigger2.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + end + +end + +function MAPSCRIPT:OnNewGame() + + DbgPrint("OnNewGame") + + -- TODO: Validate me. + if not IsValid(ents.FindFirstByName("barney")) then + ents.WaitForEntityByName("player_spawn_items_maker", function(ent) + ent:Fire("ForceSpawn") + end) + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d3_c17_11.lua b/gamemode/gametypes/hl2/mapscripts/d3_c17_11.lua new file mode 100644 index 00000000..8eef773d --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d3_c17_11.lua @@ -0,0 +1,102 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + "weapon_bugbait", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["pclip_gate1"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- 1141.241089 6502.354492 896.031250 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(843.202148, 8012.508301, 960.031250), Ang = Angle(0, -90, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(910.880127, 7848.197266, 960.031250), + Angle(0, 0, 0), + Vector(-20, -20, 0), + Vector(20, 20, 100) + ) + checkpointTrigger1.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + -- 1448.796265 4695.322266 960.031250 + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(917.399902, 4806.428223, 960.031250), Ang = Angle(0, 0, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(1448.796265, 4695.322266, 960.031250), + Angle(0, 0, 0), + Vector(-160, -40, 0), + Vector(60, 40, 100) + ) + checkpointTrigger2.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d3_c17_12.lua b/gamemode/gametypes/hl2/mapscripts/d3_c17_12.lua new file mode 100644 index 00000000..e812e4fd --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d3_c17_12.lua @@ -0,0 +1,101 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + "weapon_bugbait", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["pclip_gate1"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- -1550.889771 7297.707520 128.031250 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-1505.414917, 7372.614258, -59.968750), Ang = Angle(0, 180, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(-1550.889771, 7297.707520, 128.031250), + Angle(0, 0, 0), + Vector(-250, -250, 0), + Vector(250, 250, 100) + ) + checkpointTrigger1.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + -- -1370.895020 6269.638184 66.207535 + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-1505.414917, 7372.614258, -59.968750), Ang = Angle(0, -90, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(-1370.895020, 6269.638184, 66.207535), + Angle(0, 0, 0), + Vector(-80, -80, 0), + Vector(80, 80, 100) + ) + checkpointTrigger2.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d3_c17_12b.lua b/gamemode/gametypes/hl2/mapscripts/d3_c17_12b.lua new file mode 100644 index 00000000..661490e4 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d3_c17_12b.lua @@ -0,0 +1,100 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + "weapon_bugbait", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["pclip_gate1"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-4438.691406, 274.473907, -319.968750), Ang = Angle(0, 0, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(-4493.349121, 297.115906, -319.968750), + Angle(0, 0, 0), + Vector(-20, -20, 0), + Vector(20, 20, 100) + ) + checkpointTrigger1.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + -- -4295.874023 430.960907 96.031250 + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(-4295.874023, 430.960907, 96.031250), Ang = Angle(0, 90, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(-4295.874023, 430.960907, 96.031250), + Angle(0, 0, 0), + Vector(-20, -20, 0), + Vector(20, 20, 100) + ) + checkpointTrigger2.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/d3_c17_13.lua b/gamemode/gametypes/hl2/mapscripts/d3_c17_13.lua new file mode 100644 index 00000000..d38554b0 --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/d3_c17_13.lua @@ -0,0 +1,119 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + "weapon_bugbait", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ + ["strider2"] = { "Kill" }, + ["relay_wallDrop"] = { "Trigger" }, +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + ["escape_attempt_killtrigger"] = true, + ["ss_dog_drop"] = true, +} + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + -- 5629.913086 -1056.541016 -127.968750 + local checkpoint1 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(5895.568359, -1049.733887, -127.968750), Ang = Angle(0, -180, 0) }) + local checkpointTrigger1 = ents.Create("trigger_once") + checkpointTrigger1:SetupTrigger( + Vector(5629.913086, -1056.541016, -127.968750), + Angle(0, 0, 0), + Vector(-20, -300, 0), + Vector(20, 150, 100) + ) + checkpointTrigger1.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint1) + end + + -- 5949.389648 125.043320 0.031250 + local checkpoint2 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(5961.045898, 43.669514, 0.031250), Ang = Angle(0, -180, 0) }) + local checkpointTrigger2 = ents.Create("trigger_once") + checkpointTrigger2:SetupTrigger( + Vector(5949.389648, 125.043320, 0.031250), + Angle(0, 0, 0), + Vector(-20, -120, 0), + Vector(20, 120, 100) + ) + checkpointTrigger2.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint2) + end + + + -- 5077.874512 405.469330 -3.968750 + local checkpoint3 = ents.CreateSimple("lambda_checkpoint", { Pos = Vector(5366.176758, 302.146027, 0.031250), Ang = Angle(0, 90, 0) }) + local checkpointTrigger3 = ents.Create("trigger_once") + checkpointTrigger3:SetupTrigger( + Vector(5077.874512, 405.469330, -3.968750), + Angle(0, 0, 0), + Vector(-250, -120, 0), + Vector(400, 320, 200) + ) + checkpointTrigger3.OnTrigger = function(ent) + GAMEMODE:SetPlayerCheckpoint(checkpoint3) + end + + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/gametypes/hl2/mapscripts/template.lua b/gamemode/gametypes/hl2/mapscripts/template.lua new file mode 100644 index 00000000..bd758e4d --- /dev/null +++ b/gamemode/gametypes/hl2/mapscripts/template.lua @@ -0,0 +1,59 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("MapScript") +local MAPSCRIPT = {} + +MAPSCRIPT.DayTime = "morning" + +MAPSCRIPT.PlayersLocked = false +MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + + }, + Ammo = + { + + }, + Armor = 0, + HEV = true, +} + +MAPSCRIPT.InputFilters = +{ +} + +MAPSCRIPT.EntityFilterByClass = +{ + --["env_global"] = true, +} + +MAPSCRIPT.EntityFilterByName = +{ + --["spawnitems_template"] = true, +} + +MAPSCRIPT.VehicleGuns = true + +function MAPSCRIPT:Init() + + DbgPrint("-- Mapscript: Template loaded --") + +end + +function MAPSCRIPT:PostInit() + + if SERVER then + + end + +end + +function MAPSCRIPT:PostPlayerSpawn(ply) + + --DbgPrint("PostPlayerSpawn") + +end + +return MAPSCRIPT diff --git a/gamemode/huds/hud_ammo.lua b/gamemode/huds/hud_ammo.lua new file mode 100644 index 00000000..f113b4c5 --- /dev/null +++ b/gamemode/huds/hud_ammo.lua @@ -0,0 +1,184 @@ +include("hud_primary_ammo.lua") +include("hud_secondary_ammo.lua") + +local PANEL = {} + +function PANEL:Init() + + self:SetSize(util.ScreenScaleH(143), util.ScreenScaleH(37)) + + self.AnimateValueChanged = Derma_Anim("AmmoIncreased", self, self.AnimValueChanged) + self.AnimateShowAlt = Derma_Anim("AmmoShowAlt", self, self.AnimShowAlt) + + self.Animations = + { + self.AnimateValueChanged, + self.AnimateShowAlt, + } + + self.HUDPrimary = vgui.Create("HudPrimaryAmmo", self) + self.HUDSecondary = vgui.Create("HudSecondaryAmmo", self) + self.LastAltCount = 0 + self.LastClipVal = 0 + self.InitialThink = true + self.LastWeapon = nil + self.LastPrimaryAmmo = -1 + +end + +function PANEL:AnimValueChanged(anim, delta, data) + self.Blur = (1 - delta) * 3 + self:SetBackgroundColor(0, 0, 0, 128) + self:SetTextColor(255, 208, 64, 255) +end + +function PANEL:AnimShowAlt(anim, delta, data) + + local w,_ = self:GetSize() + local targetW = Lerp(delta, w, data.targetW) + local targetX, _ = self:GetPos() + targetX = Lerp(delta, targetX, data.targetX) + + self:SetSize(targetW, util.ScreenScaleH(37)) + self:SetPos(targetX, data.targetY) + +end + +function PANEL:StopAnimations() + for _,v in pairs(self.Animations) do + v:Stop() + end +end + +function PANEL:Think() + + local ply = LocalPlayer() + if not IsValid(ply) then + return + end + + for _,v in pairs(self.Animations) do + if v:Active() then + v:Run() + end + end + + local animateSize = false + local animType = -1 + local primaryAmmoType = -1 + local secondaryAmmoType = -1 + local w, h = 0, 0 + local altAmmo = 0 + local clip1 = -1 + local totalW = 0 + + local vehicle = ply:GetVehicle() + if vehicle ~= nil and IsValid(vehicle) then + + if self.LastWeapon ~= vehicle then + animateSize = true + end + self.LastWeapon = vehicle + + if vehicle.GetAmmo ~= nil then + primaryAmmoType, clip, num = vehicle:GetAmmo() + else + primaryAmmoType = -1 + end + + secondaryAmmoType = -1 + altAmmo = 0 + clip1 = -1 + + else + + local wep = ply:GetActiveWeapon() + if not IsValid(wep) then + return + end + + if self.LastWeapon ~= wep then + animateSize = true + end + self.LastWeapon = wep + + primaryAmmoType = wep:GetPrimaryAmmoType() + secondaryAmmoType = wep:GetSecondaryAmmoType() + altAmmo = ply:GetAmmoCount(wep:GetSecondaryAmmoType()) + clip1 = wep:Clip1() + + end + + if clip1 ~= -1 then + self.HUDPrimary:ShowAmmoCount(true) + else + self.HUDPrimary:ShowAmmoCount(false) + end + + if self.LastClipVal ~= clip1 then + animateSize = true + end + + self.LastClipVal = clip1 + + local firstOffset = 0 + if primaryAmmoType ~= -1 then + + w, h = self.HUDPrimary:GetSize() + totalW = w + util.ScreenScaleH(10) + + self.HUDPrimary:SetVisible(true) + firstOffset = util.ScreenScaleH(10) + else + self.HUDPrimary:SetVisible(false) + end + + if self.LastPrimaryAmmo ~= primaryAmmoType then + animateSize = true + end + + self.LastPrimaryAmmo = primaryAmmoType + + if secondaryAmmoType ~= -1 and altAmmo > 0 then + + if self.LastAltCount <= 0 then + animateSize = true + animType = 0 + end + + self.HUDSecondary:SetVisible(true) + self.HUDSecondary:SetPos(w + firstOffset, 0) + + w, h = self.HUDSecondary:GetSize() + totalW = totalW + w + util.ScreenScaleH(10) + + else + + if self.LastAltCount > 0 then + animateSize = true + animType = 1 + end + + self.HUDSecondary:SetVisible(false) + + end + + self.LastAltCount = altAmmo + self.HUDPrimary:SetPos(0, 0) + + if animateSize == true then + local targetX = ScrW() - totalW - 15 + local targetY = ScrH() - h - util.ScreenScaleH(10) + local targetW = totalW + if animType == 0 then + self.HUDSecondary:Reset() + self.HUDSecondary:FadeIn(0.5) + elseif animType == 1 then + self.HUDSecondary:FadeOut(0.5) + end + self.AnimateShowAlt:Start(1, { targetX = targetX, targetY = targetY, targetW = targetW }) + end + +end + +vgui.Register( "HudAmmo", PANEL, "Panel" ) diff --git a/gamemode/huds/hud_armor.lua b/gamemode/huds/hud_armor.lua new file mode 100644 index 00000000..451217be --- /dev/null +++ b/gamemode/huds/hud_armor.lua @@ -0,0 +1,61 @@ +include("hud_numeric.lua") + +local PANEL = {} + +function PANEL:Init() + + self:SetSize(util.ScreenScaleH(103), util.ScreenScaleH(37)) + + self:SetLabelText(Localize("#Valve_Hud_SUIT")) + self.LastArmor = 0 + + self.AnimateValueChanged = Derma_Anim("HealthIncreased", self, self.AnimValueChanged) + + self.Animations = + { + self.AnimateValueChanged, + } + +end + +function PANEL:AnimValueChanged(anim, delta, data) + self.Blur = (1 - delta) * 3 + self:SetBackgroundColor(0, 0, 0, 128) + self:SetTextColor(255, 208, 64, 255) +end + +function PANEL:StopAnimations() + for _,v in pairs(self.Animations) do + v:Stop() + end +end + +function PANEL:Think() + + local ply = LocalPlayer() + if not IsValid(ply) then + return + end + + for _,v in pairs(self.Animations) do + if v:Active() then + v:Run() + end + end + + local armor = ply:Armor() + + if armor == self.LastArmor then + return + end + self.LastArmor = armor + + if armor >= 20 then + self.AnimateValueChanged:Start(2) + end + + self:SetDisplayValue(armor) + +end + +vgui.Register( "HudArmor", PANEL, "HudNumeric" ) diff --git a/gamemode/huds/hud_aux.lua b/gamemode/huds/hud_aux.lua new file mode 100644 index 00000000..dc177f93 --- /dev/null +++ b/gamemode/huds/hud_aux.lua @@ -0,0 +1,241 @@ +local FONT_TEXT = "HudDefault" +local PANEL = {} + +-- TODO: Make those shared. +local SUIT_DEVICE_BREATHER = 1 +local SUIT_DEVICE_SPRINT = 2 +local SUIT_DEVICE_FLASHLIGHT = 3 + +function PANEL:Init() + + self.ShouldDrawBackground = true + + self:SetSize(util.ScreenScaleH(103), util.ScreenScaleH(28)) + + self.AnimateSizeChange = Derma_Anim("SizeChange", self, self.AnimSizeChange) + self.AnimateFadeIn = Derma_Anim("FadeIn", self, self.AnimFadeIn) + self.AnimateFadeOut = Derma_Anim("FadeIn", self, self.AnimFadeOut) + self.Animations = + { + self.AnimateSizeChange, + self.AnimateFadeIn, + self.AnimateFadeOut, + } + + self.TextX = 8 + self.TextY = 15 + self.Text2X = 8 + self.Text2Y = 25 + self.Text2Gap = 1 + + self.BarInsetX = 8 + self.BarInsetY = 8 + self.BarWidth = 80 + self.BarHeight = 4 + self.BarChunkWidth = 4 + self.BarChunkGap = 2 + self.SprintActive = false + self.OxygenActive = false + self.LastPower = 0 + + self.Alpha = 1 + self.LabelText = Localize("#Valve_Hud_AUX_POWER", "AUX") + self.LabelOxygen = Localize("#Valve_Hud_OXYGEN", "OXYGEN") + self.LabelSprint = Localize("#Valve_Hud_SPRINT", "SPRINT") + + self:SetTextColor(255, 208, 64, 255) + self:SetBackgroundColor(0, 0, 0, 76) + +end + +function PANEL:GetBackgroundColor() + return self.BackgroundColor +end + +function PANEL:SetBackgroundColor(r, g, b, a) + self.BackgroundColor = Color(r, g, b, a) +end + +function PANEL:SetTextColor(r, g, b, a) + self.TextColor = Color(r, g, b, a) +end + +function PANEL:AnimSizeChange(anim, delta, data) + + local w,h = self:GetSize() + local targetW = Lerp(delta, w, data.targetW) + local targetH = Lerp(delta, h, data.targetH) + local targetX, targetY = self:GetPos() + targetX = Lerp(delta, targetX, data.targetX) + targetY = Lerp(delta, targetY, data.targetY) + + self:SetSize(targetW, targetH) + self:SetPos(targetX, targetY) + +end + +function PANEL:AnimFadeIn(anim, delta, data) + self.Alpha = Lerp(delta, data.Alpha, 1) +end + +function PANEL:AnimFadeOut(anim, delta, data) + self.Alpha = Lerp(delta, data.Alpha, 0) + --DbgPrint(self.Alpha) +end + +function PANEL:FadeIn(secs) + self.AnimateFadeOut:Stop() + self.AnimateFadeIn:Start(secs, { Alpha = self.Alpha }) +end + +function PANEL:FadeOut(secs) + self.AnimateFadeIn:Stop() + self.AnimateFadeOut:Start(secs, { Alpha = self.Alpha }) +end + +function PANEL:StopAnimations() + for _,v in pairs(self.Animations) do + v:Stop() + end +end + +function PANEL:Think() + +end + +function PANEL:PaintLabel() + + surface.SetFont(FONT_TEXT) + surface.SetTextColor(self.TextColor.r, self.TextColor.g, self.TextColor.b, self.TextColor.a * self.Alpha) + surface.SetTextPos(util.ScreenScaleH(self.TextX), util.ScreenScaleH(self.TextY)) + surface.DrawText(self.LabelText) + +end + +function PANEL:Paint(width, height) + + local ply = LocalPlayer() + if not IsValid(ply) then + return + end + + for _,v in pairs(self.Animations) do + if v:Active() then + v:Run() + end + end + + if self.ShouldDrawBackground == true then + local col = table.Copy(self:GetBackgroundColor()) + col.a = col.a * self.Alpha + draw.RoundedBox( 8, 0, 0, width, height, col ) + end + + local suitPower = ply:GetSuitPower() + if suitPower ~= self.LastPower and suitPower == 100.0 then + --DbgPrint("Fade out") + self:FadeOut(5) + elseif suitPower ~= self.LastPower and suitPower < 100.0 then + --DbgPrint("Fade in") + self:FadeIn(0.2) + end + self.LastPower = suitPower + + local chunkCount = util.ScreenScaleH(self.BarWidth) / (util.ScreenScaleH(self.BarChunkWidth) + util.ScreenScaleH(self.BarChunkGap)) + local enabledChunks = math.ceil(chunkCount * (suitPower * 1.0 / 100.0) ) + local lowPower = false + + local red = ((enabledChunks / chunkCount) * 1.2) * 208 + if red <= 100 then + self:SetTextColor(255, red, 0, 255 * self.Alpha) + else + self:SetTextColor(255, 208, 0, 255 * self.Alpha) + end + + local xpos = util.ScreenScaleH(self.BarInsetX) + local ypos = util.ScreenScaleH(self.BarInsetY) + + local enabledColor = Color(255, red, 64, 255 * self.Alpha) + local emptyColor = Color(255, red, 64, 20 * self.Alpha) + + if lowPower == true then + enabledColor = Color(255, 0, 0, 255 * self.Alpha) + emptyColor = Color(255, 0, 0, 20 * self.Alpha) + end + + local chunkWidth = util.ScreenScaleH(self.BarChunkWidth) + local barHeight = util.ScreenScaleH(self.BarHeight) + + surface.SetDrawColor(enabledColor.r, enabledColor.g, enabledColor.b, enabledColor.a) + for i = 1, enabledChunks + 1, 1 do + surface.DrawRect(xpos, ypos, chunkWidth, barHeight) + xpos = xpos + (chunkWidth + util.ScreenScaleH(self.BarChunkGap)) + end + + surface.SetDrawColor(emptyColor.r, emptyColor.g, emptyColor.b, emptyColor.a) + for i = enabledChunks, chunkCount, 1 do + surface.DrawRect(xpos, ypos, chunkWidth, barHeight) + xpos = xpos + (chunkWidth + util.ScreenScaleH(self.BarChunkGap)) + end + + self:PaintLabel() + + local sizeChange = false + + xpos = util.ScreenScaleH(self.Text2X) + ypos = util.ScreenScaleH(self.Text2Y) + local newH = 0 + local gap = util.ScreenScaleH(self.Text2Gap) + + if ply:UsingSuitDevice(SUIT_DEVICE_BREATHER) then + surface.SetTextPos(xpos, ypos) + surface.DrawText(self.LabelOxygen) + ypos = ypos + gap + newH = newH + gap + if self.OxygenActive == false then + sizeChange = true + end + self.OxygenActive = true + else + if self.OxygenActive == true then + sizeChange = true + end + self.OxygenActive = false + end + + if ply:UsingSuitDevice(SUIT_DEVICE_SPRINT) then + surface.SetTextPos(xpos, ypos) + surface.DrawText(self.LabelSprint) + ypos = ypos + gap + newH = newH + gap + if self.SprintActive == false then + sizeChange = true + end + self.SprintActive = true + else + if self.SprintActive == true then + sizeChange = true + end + self.SprintActive = false + end + + if sizeChange == true then + + --DbgPrint("Changign Size: ") + + local targetH = util.ScreenScaleH(30) + newH + local targetW = util.ScreenScaleH(103) + local targetY = ScrH() - util.ScreenScaleH(30) - util.ScreenScaleH(10) - util.ScreenScaleH(30) - util.ScreenScaleH(10) + if newH > 0 then + targetH = targetH + util.ScreenScaleH(10) + targetY = targetY - newH - util.ScreenScaleH(10) + end + local targetX = 35 + + self.AnimateSizeChange:Start(1, { targetH = targetH, targetW = targetW, targetY = targetY, targetX = targetX }) + + end + +end + +vgui.Register( "HudAux", PANEL, "Panel" ) diff --git a/gamemode/huds/hud_health.lua b/gamemode/huds/hud_health.lua new file mode 100644 index 00000000..c429f716 --- /dev/null +++ b/gamemode/huds/hud_health.lua @@ -0,0 +1,99 @@ +include("hud_numeric.lua") + +local PANEL = {} + +function PANEL:Init() + + self:SetSize(util.ScreenScaleH(103), util.ScreenScaleH(37)) + + self:SetLabelText(Localize("#Valve_Hud_HEALTH")) + self.LastHealth = 0 + self.LastArmor = 0 + + self.AnimateHealthIncreased = Derma_Anim("HealthIncreased", self, self.AnimHealthIncreased) + self.AnimateHealthDecreasedBelow20 = Derma_Anim("HealthDecreasedBelow20", self, self.AnimHealthDecreasedBelow20) + self.AnimateHealthLow = Derma_Anim("HealthLow", self, self.AnimHealthLow) + + self.Animations = + { + self.AnimateHealthIncreased, + self.AnimateHealthDecreasedBelow20, + self.AnimateHealthLow, + } + +end + +function PANEL:AnimHealthIncreased(anim, delta, data) + self.Blur = (1 - delta) * 3 + self:SetBackgroundColor(0, 0, 0, 128) + self:SetTextColor(255, 208, 64, 255) +end + +function PANEL:AnimHealthDecreasedBelow20(anim, delta, data) + self.Blur = delta * 1 + self:SetBackgroundColor(delta * 70, 0, 0, 128) +end + +function PANEL:AnimHealthLow(anim, delta, data) + + if delta == 1 then + return self.AnimateHealthLow:Start(0.8) + end + + local r + if delta <= 0.3 then + r = (delta / 0.3) * 100 + else + delta = delta - 0.3 + r = (1 - (delta / 0.7)) * 100 + end + --DbgPrint(r) + + self:SetTextColor(255, 0, 0, 128) + self:SetBackgroundColor(r, 0, 0, 128) + +end + +function PANEL:StopAnimations() + for _,v in pairs(self.Animations) do + v:Stop() + end +end + +function PANEL:Think() + + local ply = LocalPlayer() + if not IsValid(ply) then + return + end + + for _,v in pairs(self.Animations) do + if v:Active() then + v:Run() + end + end + + local health = math.Clamp(ply:Health(), 0, ply:GetMaxHealth()) + + if health == self.LastHealth then + return + end + self.LastHealth = health + + if health >= 20 then + self.AnimateHealthLow:Stop() + self.AnimateHealthDecreasedBelow20:Stop() + + self.AnimateHealthIncreased:Start(3) + else + self.AnimateHealthIncreased:Stop() + + self.AnimateHealthDecreasedBelow20:Start(0.5) + self.AnimateHealthLow:Start(1) + end + + self:SetDisplayValue(health) + +end + +vgui.Register( "HudHealth", PANEL, "HudNumeric" ) diff --git a/gamemode/huds/hud_numeric.lua b/gamemode/huds/hud_numeric.lua new file mode 100644 index 00000000..dde65ced --- /dev/null +++ b/gamemode/huds/hud_numeric.lua @@ -0,0 +1,235 @@ +local FONT_NUMBER = "LambdaHudNumbers" +local FONT_NUMBER_GLOW = "LambdaHudNumbersGlow" +local FONT_NUMBER_SMALL = "LambdaHudNumbersSmall" +local FONT_TEXT = "HudDefault" + +local function InitFonts() + surface.CreateFont(FONT_NUMBER, + { + font = "HalfLife2", + size = util.ScreenScaleH(32), + weight = 0, + blursize = 0, + scanlines = 0, + antialias = true, + additive = true, + }) + + surface.CreateFont(FONT_NUMBER_GLOW, + { + font = "HalfLife2", + size = util.ScreenScaleH(32), + weight = 0, + blursize = util.ScreenScaleH(4), + scanlines = 2, + antialias = true, + additive = true, + }) + + surface.CreateFont(FONT_NUMBER_SMALL, + { + font = "HalfLife2", + size = util.ScreenScaleH(16), + weight = 1000, + blursize = 0, + scanlines = 0, + antialias = true, + additive = true, + }) +end + +local PANEL = {} + +function PANEL:Init() + + -- On resolution changes we simply recreate this panel. + InitFonts() + + self.ShouldDrawBackground = true + self.DisplayValue = true + self.DisplaySecondaryValue = false + self.Indent = false + self.IsTime = false + self.Blur = 0.0 + self.PrimaryVal = 0 + self.SecondaryVal = 0 + self.CurPrimaryVal = 0 + self.CurSecondaryVal = 0 + self.LabelText = "" + self.LerpValues = true + self.LerpFraction = 0.08 + self.AnimateFadeIn = Derma_Anim("FadeIn", self, self.AnimFadeIn) + self.AnimateFadeOut = Derma_Anim("FadeIn", self, self.AnimFadeOut) + + self.TextX = 8 + self.TextY = 20 + self.DigitX = 50 + self.DigitY = 2 + self.Digit2X = 98 + self.Digit2Y = 16 + self.Alpha = 1 + + self:SetTextColor(255, 220, 0, 100) + self:SetBackgroundColor(0, 0, 0, 76) + +end + +function PANEL:GetBackgroundColor() + return self.BackgroundColor +end + +function PANEL:SetBackgroundColor(r, g, b, a) + self.BackgroundColor = Color(r, g, b, a) +end + +function PANEL:SetTextColor(r, g, b, a) + self.TextColor = Color(r, g, b, a) +end + +function PANEL:Reset() + self.Blur = 0.0 +end + +function PANEL:SetDisplayValue(val) + self.PrimaryVal = val +end + +function PANEL:SetSecondaryValue(val) + self.SecondaryVal = val +end + +function PANEL:SetShouldDisplayValue(state) + self.DisplayValue = state +end + +function PANEL:SetShouldDisplaySecondaryValue(state) + self.DisplaySecondaryValue = state +end + +function PANEL:SetLabelText(text) + self.LabelText = text +end + +function PANEL:SetIndent(state) + self.Indent = state +end + +function PANEL:SetIsTime(state) + self.IsTime = state +end + +function PANEL:SetDrawBackground(state) + self.ShouldDrawBackground = state +end + +function PANEL:PaintNumbers(font, x, y, val) + + surface.SetFont(font) + + local text + if self.IsTime then + local mins = val / 60 + local secs = val - mins * 60 + -- Whatever. + else + text = tostring(val) + end + + local w = surface.GetTextSize("0") + if val < 100 and self.Indent then + x = x + w + end + if val < 10 and self.Indent then + x = x + w + end + + surface.SetTextPos(x, y) + surface.DrawText(text) + +end + +function PANEL:PaintLabel() + + surface.SetFont(FONT_TEXT) + surface.SetTextColor(self.TextColor.r, self.TextColor.g, self.TextColor.b, self.TextColor.a * self.Alpha) + surface.SetTextPos(util.ScreenScaleH(self.TextX), util.ScreenScaleH(self.TextY)) + surface.DrawText(self.LabelText) + +end + +function PANEL:AnimFadeIn(anim, delta, data) + self.Alpha = delta +end + +function PANEL:AnimFadeOut(anim, delta, data) + self.Alpha = 1 - delta +end + +function PANEL:FadeIn(secs) + self.AnimateFadeOut:Stop() + self.AnimateFadeIn:Start(secs) +end + +function PANEL:FadeOut(secs) + self.AnimateFadeIn:Stop() + self.AnimateFadeOut:Start(secs) +end + +function PANEL:Paint(width, height) + + if self.AnimateFadeIn:Active() then + self.AnimateFadeIn:Run() + end + if self.AnimateFadeOut:Active() then + self.AnimateFadeOut:Run() + end + + if self.ShouldDrawBackground == true then + local col = table.Copy(self:GetBackgroundColor()) + col.a = col.a * self.Alpha + draw.RoundedBox( 8, 0, 0, width, height, col ) + end + + if self.DisplayValue then + + surface.SetTextColor(self.TextColor.r, self.TextColor.g, self.TextColor.b, self.TextColor.a * self.Alpha) + + if self.LerpValues == true then + self.CurPrimaryVal = Lerp(self.LerpFraction, self.CurPrimaryVal, self.PrimaryVal) + else + self.CurPrimaryVal = self.PrimaryVal + end + + self:PaintNumbers(FONT_NUMBER, util.ScreenScaleH(self.DigitX), util.ScreenScaleH(self.DigitY), math.Round(self.CurPrimaryVal)) + + for i = self.Blur, 0, -1.0 do + + if i > 1.0 then + self:PaintNumbers(FONT_NUMBER_GLOW, util.ScreenScaleH(self.DigitX), util.ScreenScaleH(self.DigitY), math.Round(self.CurPrimaryVal)) + else + surface.SetTextColor(self.TextColor.r, self.TextColor.g, self.TextColor.b, (self.TextColor.a * i) * self.Alpha) + self:PaintNumbers(FONT_NUMBER_GLOW, util.ScreenScaleH(self.DigitX), util.ScreenScaleH(self.DigitY), math.Round(self.CurPrimaryVal)) + end + + end + + end + + if self.DisplaySecondaryValue then + + if self.LerpValues == true then + self.CurSecondaryVal = Lerp(self.LerpFraction, self.CurSecondaryVal, self.SecondaryVal) + else + self.CurSecondaryVal = self.SecondaryVal + end + + surface.SetTextColor(self.TextColor.r, self.TextColor.g, self.TextColor.b, self.TextColor.a * self.Alpha) + self:PaintNumbers(FONT_NUMBER_SMALL, util.ScreenScaleH(self.Digit2X), util.ScreenScaleH(self.Digit2Y), math.Round(self.CurSecondaryVal)) + + end + + self:PaintLabel() + +end + +vgui.Register( "HudNumeric", PANEL, "Panel" ) diff --git a/gamemode/huds/hud_pickup.lua b/gamemode/huds/hud_pickup.lua new file mode 100644 index 00000000..4e32379f --- /dev/null +++ b/gamemode/huds/hud_pickup.lua @@ -0,0 +1,313 @@ +GM.PickupHistory = {} +GM.PickupHistoryLast = 0 +GM.PickupHistoryTop = ScrH() / 2 +GM.PickupHistoryWide = 300 +GM.PickupHistoryCorner = surface.GetTextureID( "gui/corner8" ) + +GM.SymbolLookupTable = +{ + ["Pistol"] = "p", + ["SMG1"] = "\x72", + ["SMG1_Grenade"] = "\x5F", + ["357"] = "\x71", + ["AR2"] = "u", + ["AR2AltFire"] = "z", + ["Buckshot"] = "s", + ["XBowBolt"] = "w", + ["Grenade"] = "v", + ["RPG_Round"] = "x", + + ["weapon_smg1"] = "&", + ["weapon_shotgun"] = "(", + ["weapon_pistol"] = "%", + ["weapon_357"] = "$", + ["weapon_crossbow"] = ")", + ["weapon_ar2"] = ":", + ["weapon_frag"] = "_", + ["weapon_rpg"] = ";", + ["weapon_crowbar"] = "^", + ["weapon_physcannon"] = "!", + ["weapon_physgun"] = "!", + ["weapon_bugbait"] = "~", +} + +surface.CreateFont( "LAMBDA_AMMO", +{ + font = 'halflife2', + size = 46 +} ) + +--[[--------------------------------------------------------- + Name: gamemode:HUDWeaponPickedUp( wep ) + Desc: The game wants you to draw on the HUD that a weapon has been picked up +-----------------------------------------------------------]] +function GM:HUDWeaponPickedUp( wep ) + + if ( !IsValid( LocalPlayer() ) || !LocalPlayer():Alive() ) then return end + if ( !IsValid( wep ) ) then return end + if ( !isfunction( wep.GetPrintName ) ) then return end + + local pickup = {} + pickup.time = CurTime() + pickup.symbol = self.SymbolLookupTable[wep:GetClass()] + pickup.name = wep:GetPrintName() + pickup.holdtime = 10 + pickup.fadein = 0.04 + pickup.fadeout = 0.3 + pickup.font = "DermaDefaultBold" + pickup.color = Color( 255, 220, 0, 100 ) + + surface.SetFont( pickup.font ) + local w, h = surface.GetTextSize( pickup.name ) + pickup.height = h + 10 + pickup.width = w + + if pickup.symbol then + surface.SetFont("LAMBDA_AMMO") + local w,_ = surface.GetTextSize(pickup.symbol) + pickup.width = pickup.width + w + 16 + pickup.swidth = w + end + + if ( self.PickupHistoryLast >= pickup.time ) then + pickup.time = self.PickupHistoryLast + 0.05 + end + + table.insert( self.PickupHistory, pickup ) + self.PickupHistoryLast = pickup.time + +end + +--[[--------------------------------------------------------- + Name: gamemode:HUDItemPickedUp( itemname ) + Desc: An item has been picked up.. +-----------------------------------------------------------]] +function GM:HUDItemPickedUp( itemname ) + + if ( !IsValid( LocalPlayer() ) || !LocalPlayer():Alive() ) then return end + + -- Try to tack it onto an exisiting ammo pickup + if ( self.PickupHistory ) then + + for k, v in pairs( self.PickupHistory ) do + + if ( v.name == "#" .. itemname ) then + + v.amount = v.amount + 1 + + local fadeDelay = 1 - v.fadein + local fadeOut = 1 - v.fadeout + local elapsed = CurTime() - v.time + if elapsed > (v.holdtime - fadeDelay - fadeOut) then + v.time = CurTime() - v.fadein + else + v.time = CurTime() - fadeDelay + end + + return + + end + + end + + end + + local pickup = {} + pickup.time = CurTime() + pickup.name = "#"..itemname + pickup.holdtime = 10 + pickup.fadein = 0.04 + pickup.fadeout = 0.3 + pickup.font = "DermaDefaultBold" + pickup.color = Color( 180, 255, 180, 255 ) + pickup.amount = 1 + + surface.SetFont( pickup.font ) + local w, h = surface.GetTextSize( pickup.name ) + pickup.height = h + 10 + pickup.width = w + + if ( self.PickupHistoryLast >= pickup.time ) then + pickup.time = self.PickupHistoryLast + 0.05 + end + + table.insert( self.PickupHistory, pickup ) + self.PickupHistoryLast = pickup.time + +end + +--[[--------------------------------------------------------- + Name: gamemode:HUDAmmoPickedUp( itemname, amount ) + Desc: Ammo has been picked up.. +-----------------------------------------------------------]] +function GM:HUDAmmoPickedUp( itemname, amount ) + + if ( !IsValid( LocalPlayer() ) || !LocalPlayer():Alive() ) then return end + + -- Try to tack it onto an exisiting ammo pickup + if ( self.PickupHistory ) then + + for k, v in pairs( self.PickupHistory ) do + + if ( v.name == "#" .. itemname .. "_ammo" ) then + + v.amount = tostring( tonumber( v.amount ) + amount ) + + local fadeDelay = 1 - v.fadein + local fadeOut = 1 - v.fadeout + local elapsed = CurTime() - v.time + if elapsed > (v.holdtime - fadeDelay - fadeOut) then + v.time = CurTime() - v.fadein + else + v.time = CurTime() - fadeDelay + end + + return + + end + + end + + end + + --DbgPrint(itemname) + + local pickup = {} + pickup.time = CurTime() + pickup.symbol = self.SymbolLookupTable[itemname] + pickup.name = "#" .. itemname .. "_ammo" + pickup.holdtime = 10 + pickup.fadein = 0.04 + pickup.fadeout = 0.3 + pickup.font = "DermaDefaultBold" + pickup.color = Color( 180, 200, 255, 255 ) + pickup.amount = tostring( amount ) + + surface.SetFont( pickup.font ) + local w, h = surface.GetTextSize( pickup.name ) + pickup.height = h + 10 + pickup.width = w + + local w, h = surface.GetTextSize( pickup.amount ) + pickup.xwidth = w + pickup.width = pickup.width + w + 16 + + if pickup.symbol then + surface.SetFont("LAMBDA_AMMO") + local w,h = surface.GetTextSize(pickup.symbol) + pickup.width = pickup.width + w + 16 + pickup.swidth = w + end + + if ( self.PickupHistoryLast >= pickup.time ) then + pickup.time = self.PickupHistoryLast + 0.05 + end + + table.insert( self.PickupHistory, pickup ) + self.PickupHistoryLast = pickup.time + +end + +local blur = Material("pp/blurscreen") + +local function DrawBlurRect(x, y, w, h) + local X, Y = 0,0 + + surface.SetDrawColor(255, 255, 255) + --surface.SetMaterial(blur) + --[[ + for i = 1, 5 do + blur:SetFloat("$blur", (i / 3) * (5)) + blur:Recompute() + + render.UpdateScreenEffectTexture() + + render.SetScissorRect(x, y, x+w, y+h, true) + surface.DrawTexturedRect(X * -1, Y * -1, ScrW(), ScrH()) + render.SetScissorRect(0, 0, 0, 0, false) + end + ]] + + draw.RoundedBox(3, x, y, w, h, Color(0, 0, 0, 30)) + + surface.SetDrawColor(0, 0, 0) + --surface.DrawOutlinedRect(x, y, w, h) + +end + +function GM:HUDDrawPickupHistory() + + if ( self.PickupHistory == nil ) then return end + + local x, y = ScrW() - self.PickupHistoryWide - 20, self.PickupHistoryTop + local tall = 0 + local wide = 0 + + for k, v in pairs( self.PickupHistory ) do + + if ( !istable( v ) ) then + + Msg( tostring( v ) .."\n" ) + PrintTable( self.PickupHistory ) + self.PickupHistory[ k ] = nil + return + + end + + if ( v.time < CurTime() ) then + + if ( v.y == nil ) then v.y = y end + + v.y = ( v.y * 5 + y ) / 6 + + local delta = ( v.time + v.holdtime ) - CurTime() + delta = delta / v.holdtime + + local alpha = 255 + local colordelta = math.Clamp( delta, 0.6, 0.7 ) + + -- Fade in/out + if ( delta > 1 - v.fadein ) then + alpha = math.Clamp( ( 1.0 - delta ) * ( 255 / v.fadein ), 0, 255 ) + elseif ( delta < v.fadeout ) then + alpha = math.Clamp( delta * ( 255 / v.fadeout ), 0, 255 ) + end + + v.x = x + self.PickupHistoryWide - (self.PickupHistoryWide * ( alpha / 255 ) ) + + local rx, ry, rw, rh = math.Round( v.x - 8 ), math.Round( v.y - ( v.height / 2 ) - 4 ), math.Round( self.PickupHistoryWide + 19 ), math.Round( v.height + 10 ) + local bordersize = 8 + + DrawBlurRect( rx, ry, rw, rh ) + + local offsetX = 0 + + if v.symbol ~= nil then + draw.SimpleText( v.symbol, "LAMBDA_AMMO", v.x + 55 , v.y - v.height, Color( 255, 220, 0, alpha ), TEXT_ALIGN_RIGHT ) + offsetX = 40 + end + + --draw.SimpleText( v.name, v.font, v.x + v.height + 4, v.y - ( v.height / 2 ) + 4, Color( 0, 0, 0, alpha * 0.5 ) ) + draw.SimpleText( v.name, v.font, offsetX + v.x + v.height + 4, v.y - ( v.height / 2 ) + 4, Color( 255, 220, 0, alpha ) ) + + if ( v.amount ) then + + --draw.SimpleText( v.amount, v.font, v.x + self.PickupHistoryWide + 1, v.y - ( v.height / 2 ) + 4, Color( 0, 0, 0, alpha * 0.5 ), TEXT_ALIGN_RIGHT ) + draw.SimpleText( v.amount, v.font, v.x + self.PickupHistoryWide, v.y - ( v.height / 2 ) + 4, Color( 255, 220, 0, alpha ), TEXT_ALIGN_RIGHT ) + + end + + y = y + ( v.height + 20 ) + tall = tall + v.height + 18 + wide = math.Max( wide, v.width + v.height + 24 ) + + if ( alpha == 0 ) then self.PickupHistory[ k ] = nil end + + end + + end + + self.PickupHistoryTop = ( self.PickupHistoryTop * 5 + ( ScrH() * 0.75 - tall ) / 2 ) / 6 + self.PickupHistoryWide = ( self.PickupHistoryWide * 5 + wide ) / 6 + +end diff --git a/gamemode/huds/hud_primary_ammo.lua b/gamemode/huds/hud_primary_ammo.lua new file mode 100644 index 00000000..a4058bee --- /dev/null +++ b/gamemode/huds/hud_primary_ammo.lua @@ -0,0 +1,112 @@ +include("hud_numeric.lua") + +local PANEL = {} + +function PANEL:Init() + + self:SetShouldDisplaySecondaryValue(true) + self:SetSize(util.ScreenScaleH(103), util.ScreenScaleH(37)) + + self:SetLabelText(Localize("#Valve_Hud_AMMO") ) + self.LastClip1 = 0 + self.LastClip2 = 0 + self.LerpValues = false + + self.AnimateValueChanged = Derma_Anim("AmmoChanged", self, self.AnimValueChanged) + + self.Animations = + { + self.AnimateValueChanged, + } + +end + +function PANEL:Reset() + + self.LastClip1 = -1 + self.LastClip2 = 0 + +end + +function PANEL:ShowAmmoCount(state) + self:SetShouldDisplaySecondaryValue(state) + if state == false then + self:SetSize(util.ScreenScaleH(103), util.ScreenScaleH(37)) + else + self:SetSize(util.ScreenScaleH(130), util.ScreenScaleH(37)) + end +end + +function PANEL:AnimValueChanged(anim, delta, data) + self.Blur = (1 - delta) * 3 + self:SetBackgroundColor(0, 0, 0, 128) + self:SetTextColor(255, 208, 64, 255) +end + +function PANEL:StopAnimations() + for _,v in pairs(self.Animations) do + v:Stop() + end +end + +function PANEL:Think() + + local ply = LocalPlayer() + if not IsValid(ply) then + return + end + + for _,v in pairs(self.Animations) do + if v:Active() then + v:Run() + end + end + + local vehicle = ply:GetVehicle() + local clip1 + local ammo = 0 + local ammotype = -1 + + if vehicle ~= nil and IsValid(vehicle) then + + if vehicle.GetAmmo ~= nil then + ammotype, clip1, num = vehicle:GetAmmo() + end + + if clip1 ~= self.LastClip1 then + self.AnimateValueChanged:Start(2) + self.LastClip1 = clip1 + end + + self:SetDisplayValue(num) + self:SetShouldDisplaySecondaryValue(false) + self:SetSecondaryValue(0) + + else + + local wep = ply:GetActiveWeapon() + if wep ~= nil and not IsValid(wep) then + return + end + + ammotype = wep:GetPrimaryAmmoType() + ammo = ply:GetAmmoCount(ammotype) + + clip1 = wep:Clip1() + if clip1 == -1 then + clip1 = ply:GetAmmoCount(ammotype) + end + + if clip1 ~= self.LastClip1 then + self.AnimateValueChanged:Start(2) + self.LastClip1 = clip1 + end + + self:SetDisplayValue(clip1) + self:SetSecondaryValue(ammo) + + end + +end + +vgui.Register( "HudPrimaryAmmo", PANEL, "HudNumeric" ) diff --git a/gamemode/huds/hud_respawn.lua b/gamemode/huds/hud_respawn.lua new file mode 100644 index 00000000..0d369a6f --- /dev/null +++ b/gamemode/huds/hud_respawn.lua @@ -0,0 +1,71 @@ +include("hud_numeric.lua") + +local FONT_TEXT = "HudDefault" +local PANEL = {} + +function PANEL:Init() + local h = util.ScreenScaleH(40) + + self:SetSize(ScrW(), h) + self:SetTimeout(GetSyncedTimestamp(), 10) + self.TextColor = Color(255, 220, 0, 100) + self.Alpha = 100 + + -- Dont popup initially. + self:SetVisible(false) + +end + +function PANEL:PaintText(font, val, x, y, w, h) + + surface.SetTextColor(self.TextColor.r, self.TextColor.g, self.TextColor.b, self.TextColor.a * self.Alpha) + + surface.SetFont(font) + local text = tostring(val) + + local textW, textH = surface.GetTextSize(text) + x = x + (w / 2) - (textW / 2) + y = y + (textH / 2) + + surface.SetTextPos(x, y) + surface.DrawText(text) + + return textW, textH + +end + +function PANEL:Paint() + + local w,h = self:GetSize() + surface.SetDrawColor(0, 0, 0, 64) + surface.DrawRect(0, 0, ScrW(), h) + + local timeEnd = self.StartTime + self.Timeout + local remain = timeEnd - GetSyncedTimestamp() + + local text + local x,y + if remain > 0 then + text = string.upper("Time remaining until respawn") + x, y = self:PaintText(FONT_TEXT, text, 0, h / 6, w, h) + text = string.format("%0.2f", remain) + self:PaintText(FONT_TEXT, text, 0, h / 4 + y, w, h) + self:PaintText(FONT_TEXT, text, 0, h / 4 + y, w, h) + else + local keyName = input.LookupBinding("+jump", true) + text = string.format("Press <%s> to respawn", keyName) + x, y = self:PaintText(FONT_TEXT, text, 0, h / 4, w, h) + end + + +end + +function PANEL:Think() +end + +function PANEL:SetTimeout(startTime, timeout) + self.StartTime = startTime + self.Timeout = timeout +end + +vgui.Register( "HudRespawn", PANEL ) diff --git a/gamemode/huds/hud_secondary_ammo.lua b/gamemode/huds/hud_secondary_ammo.lua new file mode 100644 index 00000000..1711df26 --- /dev/null +++ b/gamemode/huds/hud_secondary_ammo.lua @@ -0,0 +1,72 @@ +include("hud_numeric.lua") + +local PANEL = {} + +function PANEL:Init() + + self:SetShouldDisplaySecondaryValue(false) + self:SetSize(util.ScreenScaleH(80), util.ScreenScaleH(37)) + + self:SetLabelText(Localize("#Valve_Hud_AMMO_ALT") ) + self.LastClip1 = 0 + self.LastClip2 = 0 + self.LerpValues = false + + self.AnimateValueChanged = Derma_Anim("AmmoChanged", self, self.AnimValueChanged) + + self.Animations = + { + self.AnimateValueChanged, + } + +end + +function PANEL:Reset() + + self.LastClip1 = 0 + self.LastClip2 = 0 + +end + +function PANEL:AnimValueChanged(anim, delta, data) + self.Blur = (1 - delta) * 3 + self:SetBackgroundColor(0, 0, 0, 128) + self:SetTextColor(255, 208, 64, 255) +end + +function PANEL:StopAnimations() + for _,v in pairs(self.Animations) do + v:Stop() + end +end + +function PANEL:Think() + + local ply = LocalPlayer() + if not IsValid(ply) then + return + end + + local wep = ply:GetActiveWeapon() + if not IsValid(wep) then + return + end + + for _,v in pairs(self.Animations) do + if v:Active() then + v:Run() + end + end + + local altAmmo = ply:GetAmmoCount(wep:GetSecondaryAmmoType()) + + if altAmmo ~= self.LastClip1 then + self.AnimateValueChanged:Start(2) + self.LastClip1 = altAmmo + end + + self:SetDisplayValue(altAmmo) + +end + +vgui.Register( "HudSecondaryAmmo", PANEL, "HudNumeric" ) diff --git a/gamemode/huds/hud_suit.lua b/gamemode/huds/hud_suit.lua new file mode 100644 index 00000000..4d400d55 --- /dev/null +++ b/gamemode/huds/hud_suit.lua @@ -0,0 +1,53 @@ +include("hud_health.lua") +include("hud_armor.lua") +include("hud_ammo.lua") +include("hud_aux.lua") + +local PANEL = {} + +function PANEL:Init() + + self:ParentToHUD() + self:SetSize(ScrW(), ScrH()) + + local posX = 35 + local w,h + + self.HUDHealth = vgui.Create("HudHealth", self) + w, h = self.HUDHealth:GetSize() + self.HUDHealth:SetPos(posX, ScrH() - h - util.ScreenScaleH(10)) + + self.HUDAux = vgui.Create("HudAux", self) + local w2, h2 = self.HUDAux:GetSize() + self.HUDAux:SetPos(posX, ScrH() - h - util.ScreenScaleH(10) - h2 - util.ScreenScaleH(5)) + + posX = posX + w + util.ScreenScaleW(10) + + self.HUDArmor = vgui.Create("HudArmor", self) + self.HUDArmor:SetPos(posX, ScrH() - h - util.ScreenScaleH(10)) + + self.HUDAmmo = vgui.Create("HudAmmo", self) + w, h = self.HUDAmmo:GetSize() + self.HUDAmmo:SetPos(ScrW() - w - util.ScreenScaleH(35), ScrH() - h - util.ScreenScaleH(10)) + +end + +function PANEL:Think() + + local ply = LocalPlayer() + if not IsValid(ply) then + return + end + + local drawHud = ply:IsSuitEquipped() and ply:Alive() + + self.HUDHealth:SetVisible(drawHud) + self.HUDArmor:SetVisible(drawHud) + self.HUDAux:SetVisible(drawHud) + + local wep = ply:GetActiveWeapon() + local vehicle = ply:GetVehicle() + self.HUDAmmo:SetVisible(drawHud and IsValid(wep) or IsValid(vehicle)) +end + +vgui.Register( "HudSuit", PANEL, "Panel" ) diff --git a/gamemode/init.lua b/gamemode/init.lua new file mode 100644 index 00000000..e053f923 --- /dev/null +++ b/gamemode/init.lua @@ -0,0 +1,171 @@ +AddCSLuaFile("cl_init.lua") +AddCSLuaFile("cl_hud.lua") +AddCSLuaFile("cl_postprocess.lua") +AddCSLuaFile("cl_ragdoll_ext.lua") +AddCSLuaFile("cl_scoreboard.lua") + +AddCSLuaFile("huds/hud_numeric.lua") +AddCSLuaFile("huds/hud_suit.lua") +AddCSLuaFile("huds/hud_health.lua") +AddCSLuaFile("huds/hud_armor.lua") +AddCSLuaFile("huds/hud_primary_ammo.lua") +AddCSLuaFile("huds/hud_secondary_ammo.lua") +AddCSLuaFile("huds/hud_ammo.lua") +AddCSLuaFile("huds/hud_aux.lua") +AddCSLuaFile("huds/hud_pickup.lua") +AddCSLuaFile("huds/hud_respawn.lua") + +DEFINE_BASECLASS( "gamemode_base" ) + +include("shared.lua") +include("sv_inputoutput.lua") +include("sv_changelevel.lua") +include("sv_transition.lua") +include("sv_generic_fixes.lua") +include("sv_difficulty.lua") +include("sv_resource.lua") +include("sv_taunts.lua") +include("sv_commands.lua") + +local DbgPrint = GetLogging("Server") + +function GM:OnEntityCreated(ent) + + local self = self + local ent = ent + local class = ent:GetClass() + + -- Run this next frame so we can safely remove entities and have their actual names assigned. + util.RunNextFrame(function() + + if not IsValid(ent) then + return + end + + if self.MapScript then + -- Monitor scripts that we have filtered by class name. + if self.MapScript.EntityFilterByClass and self.MapScript.EntityFilterByClass[ent:GetClass()] == true then + DbgPrint("Removing filtered entity by class: " .. tostring(ent)) + ent:Remove() + end + + -- Monitor scripts that have filtered by name. + if self.MapScript.EntityFilterByName and self.MapScript.EntityFilterByName[ent:GetName()] == true then + DbgPrint("Removing filtered entity by name: " .. tostring(ent) .. " (" .. ent:GetName() .. ")") + ent:Remove() + end + + if class == "env_hudhint" then + DbgPrint("Enabling env_hudhint for all players") + ent:AddSpawnFlags(1) -- SF_HUDHINT_ALLPLAYERS + elseif class == "env_message" then + ent:AddSpawnFlags(2) -- SF_MESSAGE_ALL + elseif class == "func_areaportal" then + -- TODO: This is not ideal at all on larger maps, however can can not get a position for them. + ent:SetKeyValue("StartOpen", "1") + ent:Fire("Open") + ent:SetName("Lambda_" .. ent:GetName()) + elseif class == "func_areaportalwindow" then + -- I know this is ugly, but its better than white windows everywhere, this is not 2004 anymore. + local saveTable = ent:GetSaveTable() + local fadeStartDist = tonumber(saveTable["FadeStartDist"] or "0") * 3 + local fadeDist = tonumber(saveTable["FadeDist"] or "0") * 3 + ent:SetKeyValue("FadeDist", fadeDist) + ent:SetKeyValue("FadeStartDist", fadeStartDist) + end + + end + + if ent:IsNPC() then + self:RegisterNPC(ent) + end + end) + + -- Deal with vehicles at the same frame, sometimes it wouldn't show the gun. + if ent:IsVehicle() then + self:HandleVehicleCreation(ent) + end + +end + +function GM:EntityTakeDamage(target, dmginfo) + + local attacker = dmginfo:GetAttacker() + local inflictor = dmginfo:GetInflictor() + local class = target:GetClass() + + DbgPrint("EntityTakeDamage -> Target: " .. tostring(target) .. ", Attacker: " .. tostring(attacker) .. ", Inflictor: " .. tostring(inflictor)) + + local gameType = self:GetGameType() + + if target:IsNPC() then + + local isFriendly = gameType.ImportantPlayerNPCNames[target:GetName()] or gameType.ImportantPlayerNPCClasses[target:GetClass()] + + -- Check if player is attacking friendlies. + if (IsValid(attacker) and attacker:IsPlayer()) or (IsValid(inflictor) and inflictor:IsPlayer()) then + if isFriendly == true then + DbgPrint("Filtering damage on friendly") + dmginfo:ScaleDamage(0) + return true + end + end + + if IsValid(attacker) and attacker:IsPlayer() and dmginfo:IsDamageType(DMG_BLAST) == false then + dmginfo:ScaleDamage(self:GetDifficultyNPCDamageScale(target)) + + self:RegisterNPCDamage(target, attacker, dmginfo) + end + + elseif target:IsPlayer() then + + if target:IsPositionLocked() or target:IsInactive() == true then + return true + end + + if (IsValid(attacker) and attacker:IsPlayer()) or (IsValid(inflictor) and inflictor:IsPlayer()) then + if not dmginfo:IsExplosionDamage() then + return true + end + end + + local dmg = dmginfo:GetDamage() + if dmg > 0 then + local hitGroup = HITGROUP_GENERIC + if dmginfo:IsDamageType(DMG_FALL) then + if dmg > 40 and math.random(1, 2) == 1 then + hitGroup = HITGROUP_LEFTLEG + end + end + self:EmitPlayerHurt(dmginfo:GetDamage(), target, hitGroup) + end + + if IsValid(attacker) and attacker:IsNPC() and dmginfo:IsDamageType(DMG_BLAST) == false then + --dmginfo:ScaleDamage(self:GetDifficultyPlayerDamageScale(attacker)) + + self:RegisterPlayerDamage(target, attacker, dmginfo) + end + + if target:InVehicle() then + dmginfo:ScaleDamage(0.6) + end + + -- NOTE: Blocking too early would not register any damage. + if lambda_player_god:GetBool() == true then + return true + end + + + elseif target:IsVehicle() then + + + end + + if target.FilterDamage == true then + DbgPrint("Filtering Damage!") + dmginfo:ScaleDamage(0) + return true + end + + +end diff --git a/gamemode/sh_animations.lua b/gamemode/sh_animations.lua new file mode 100644 index 00000000..b475288f --- /dev/null +++ b/gamemode/sh_animations.lua @@ -0,0 +1,359 @@ +if SERVER then + AddCSLuaFile() +end + +local DbgPrint = GetLogging("Animation") + +function GM:HandlePlayerJumping(ply, velocity) + if (ply:GetMoveType() == MOVETYPE_NOCLIP) then + ply.m_bJumping = false + + return + end + + -- airwalk more like hl2mp, we airwalk until we have 0 velocity, then it's the jump animation + -- underwater we're alright we airwalking + if (not ply.m_bJumping and not ply:OnGround() and ply:WaterLevel() <= 0) then + if (not ply.m_fGroundTime) then + ply.m_fGroundTime = CurTime() + elseif (CurTime() - ply.m_fGroundTime) > 0 and velocity:Length2DSqr() < 1 then + ply.m_bJumping = true + ply.m_bFirstJumpFrame = false + ply.m_flJumpStartTime = 0 + end + end + + if ply.m_bJumping then + if ply.m_bFirstJumpFrame then + ply.m_bFirstJumpFrame = false + ply:AnimRestartMainSequence() + end + + if (ply:WaterLevel() >= 2) or ((CurTime() - ply.m_flJumpStartTime) > 0.2 and ply:OnGround()) then + ply.m_bJumping = false + ply.HandledCrouching = false + ply.m_fGroundTime = nil + ply:AnimRestartMainSequence() + end + + if ply.m_bJumping then + ply.CalcIdeal = ACT_MP_JUMP + + return true + end + end + + return false +end + +function GM:HandlePlayerDucking(ply, velocity) + + if ply:InVehicle() == true or (ply:KeyDown(IN_DUCK) == false and ply:GetNW2Bool("InDuck", false) == false) then + return false + end + + if (velocity:Length2DSqr() > 0.25) then + ply.CalcIdeal = ACT_MP_CROUCHWALK + else + ply.CalcIdeal = ACT_MP_CROUCH_IDLE + end + + return true + +end + +function GM:HandlePlayerNoClipping(ply, velocity) + if (ply:GetMoveType() ~= MOVETYPE_NOCLIP or ply:InVehicle()) then + if (ply.m_bWasNoclipping) then + ply.m_bWasNoclipping = nil + ply:AnimResetGestureSlot(GESTURE_SLOT_CUSTOM) + + if (CLIENT) then + ply:SetIK(true) + end + end + + return + end + + if (not ply.m_bWasNoclipping) then + ply:AnimRestartGesture(GESTURE_SLOT_CUSTOM, ACT_GMOD_NOCLIP_LAYER, false) + + if (CLIENT) then + ply:SetIK(false) + end + end + + return true +end + +function GM:HandlePlayerVaulting(ply, velocity) + if (velocity:Length() < 1000) then return end + if (ply:IsOnGround()) then return end + ply.CalcIdeal = ACT_MP_SWIM + + return true +end + +function GM:HandlePlayerSwimming(ply, velocity) + if (ply:WaterLevel() < 2 or ply:IsOnGround()) then + ply.m_bInSwim = false + + return false + end + + ply.CalcIdeal = ACT_MP_SWIM + ply.m_bInSwim = true + + return true +end + +function GM:HandlePlayerLanding(ply, velocity, WasOnGround) + if (ply:GetMoveType() == MOVETYPE_NOCLIP) then return end + + if (ply:IsOnGround() and not WasOnGround) then + ply:AnimRestartGesture(GESTURE_SLOT_JUMP, ACT_LAND, true) + end +end + +function GM:HandlePlayerDriving(ply) + if (not ply:InVehicle()) then return false end + local pVehicle = ply:GetVehicle() + + if (not pVehicle.HandleAnimation and pVehicle.GetVehicleClass) then + local c = pVehicle:GetVehicleClass() + local t = list.Get("Vehicles")[c] + + if (t and t.Members and t.Members.HandleAnimation) then + pVehicle.HandleAnimation = t.Members.HandleAnimation + -- Prevent this if block from trying to assign HandleAnimation again. + else + pVehicle.HandleAnimation = true + end + end + + local class = pVehicle:GetClass() + + if (isfunction(pVehicle.HandleAnimation)) then + local seq = pVehicle:HandleAnimation(ply) + + if (seq ~= nil) then + ply.CalcSeqOverride = seq + end + end + + if (ply.CalcSeqOverride == -1) then + if (class == "prop_vehicle_jeep") then + ply.CalcSeqOverride = ply:LookupSequence("drive_jeep") + -- HACK!! + elseif (class == "prop_vehicle_airboat") then + ply.CalcSeqOverride = ply:LookupSequence("drive_airboat") + elseif (class == "prop_vehicle_prisoner_pod" and pVehicle:GetModel() == "models/vehicles/prisoner_pod_inner.mdl") then + ply.CalcSeqOverride = ply:LookupSequence("drive_pd") + else + ply.CalcSeqOverride = ply:LookupSequence("sit_rollercoaster") + end + end -- pVehicle.HandleAnimation did not give us an animation + + local use_anims = ply.CalcSeqOverride == ply:LookupSequence("sit_rollercoaster") or ply.CalcSeqOverride == ply:LookupSequence("sit") + + if (use_anims and ply:GetAllowWeaponsInVehicle() and IsValid(ply:GetActiveWeapon())) then + local holdtype = ply:GetActiveWeapon():GetHoldType() + + if (holdtype == "smg") then + holdtype = "smg1" + end + + local seqid = ply:LookupSequence("sit_" .. holdtype) + + if (seqid ~= -1) then + ply.CalcSeqOverride = seqid + end + end + + return true +end + +--[[--------------------------------------------------------- +Name: gamemode:UpdateAnimation() +Desc: Animation updates (pose params etc) should be done here +-----------------------------------------------------------]] +function GM:UpdateAnimation(ply, velocity, maxseqgroundspeed) + local len = velocity:Length() + local movement = 1.0 + + if (len > 0.2) then + movement = len / maxseqgroundspeed + end + + local rate = math.min(movement, 2) + + -- if we're under water we want to constantly be swimming.. + if (ply:WaterLevel() >= 2) then + rate = math.max(rate, 0.5) + elseif (not ply:IsOnGround() and len >= 1000) then + rate = 0.1 + end + + ply:SetPlaybackRate(rate) + + if (ply:InVehicle()) then + local Vehicle = ply:GetVehicle() + + -- We only need to do this clientside.. + if (CLIENT) then + -- + -- This is used for the 'rollercoaster' arms + -- + local Velocity = Vehicle:GetVelocity() + local fwd = Vehicle:GetUp() + local dp = fwd:Dot(Vector(0, 0, 1)) + local dp2 = fwd:Dot(Velocity) + ply:SetPoseParameter("vertical_velocity", (dp < 0 and dp or 0) + dp2 * 0.005) + -- Pass the vehicles steer param down to the player + local steer = Vehicle:GetPoseParameter("vehicle_steer") + steer = steer * 2 - 1 -- convert from 0..1 to -1..1 + + if (Vehicle:GetClass() == "prop_vehicle_prisoner_pod") then + steer = 0 + ply:SetPoseParameter("aim_yaw", math.NormalizeAngle(ply:GetAimVector():Angle().y - Vehicle:GetAngles().y - 90)) + end + + ply:SetPoseParameter("vehicle_steer", steer) + end + end + + if (CLIENT) then + GAMEMODE:GrabEarAnimation(ply) + GAMEMODE:MouthMoveAnimation(ply) + end +end + +-- +-- If you don't want the player to grab his ear in your gamemode then +-- just override this. +-- +function GM:GrabEarAnimation(ply) + ply.ChatGestureWeight = ply.ChatGestureWeight or 0 + -- Don't show this when we're playing a taunt! + if (ply:IsPlayingTaunt()) then return end + + if (ply:IsTyping()) then + ply.ChatGestureWeight = math.Approach(ply.ChatGestureWeight, 1, FrameTime() * 5.0) + else + ply.ChatGestureWeight = math.Approach(ply.ChatGestureWeight, 0, FrameTime() * 5.0) + end + + if (ply.ChatGestureWeight > 0) then + ply:AnimRestartGesture(GESTURE_SLOT_VCD, ACT_GMOD_IN_CHAT, true) + ply:AnimSetGestureWeight(GESTURE_SLOT_VCD, ply.ChatGestureWeight) + end +end + +-- +-- Moves the mouth when talking on voicecom +-- +local MOVING_MOUTH_PARTS = +{ + "jaw_drop", + "right_part", + "left_part", + "right_mouth_drop", + "left_mouth_drop" +} + +function GM:MouthMoveAnimation(ply) + local isSpeaking = ply:IsSpeaking() + local moveMouth = isSpeaking or ply.m_bSpeaking + ply.m_bSpeaking = isSpeaking + if moveMouth ~= true then + return + end + local vol = math.Clamp(ply:VoiceVolume() * 2, 0, 2) + for _,v in ipairs(MOVING_MOUTH_PARTS) do + local index = ply:GetFlexIndexByName(v) + if index ~= nil then + ply:SetFlexWeight(index, vol) + end + end +end + +function GM:CalcMainActivity(ply, velocity) + ply.CalcIdeal = ACT_MP_STAND_IDLE + ply.CalcSeqOverride = -1 + self:HandlePlayerLanding(ply, velocity, ply.m_bWasOnGround) + + if (self:HandlePlayerNoClipping(ply, velocity) or self:HandlePlayerDriving(ply) or self:HandlePlayerVaulting(ply, velocity) or self:HandlePlayerJumping(ply, velocity) or self:HandlePlayerSwimming(ply, velocity) or self:HandlePlayerDucking(ply, velocity)) then + else + local len2d = velocity:Length2DSqr() + + if (len2d > 300) then + ply.CalcIdeal = ACT_MP_RUN + elseif (len2d > 1) then + ply.CalcIdeal = ACT_MP_WALK + end + end + + ply.m_bWasOnGround = ply:IsOnGround() + ply.m_bWasNoclipping = ply:GetMoveType() == MOVETYPE_NOCLIP and not ply:InVehicle() + + return ply.CalcIdeal, ply.CalcSeqOverride +end + +local IdleActivity = ACT_HL2MP_IDLE +local IdleActivityTranslate = {} +IdleActivityTranslate[ACT_MP_STAND_IDLE] = IdleActivity +IdleActivityTranslate[ACT_MP_WALK] = IdleActivity + 1 +IdleActivityTranslate[ACT_MP_RUN] = IdleActivity + 2 +IdleActivityTranslate[ACT_MP_CROUCH_IDLE] = IdleActivity + 3 +IdleActivityTranslate[ACT_MP_CROUCHWALK] = IdleActivity + 4 +IdleActivityTranslate[ACT_MP_ATTACK_STAND_PRIMARYFIRE] = IdleActivity + 5 +IdleActivityTranslate[ACT_MP_ATTACK_CROUCH_PRIMARYFIRE] = IdleActivity + 5 +IdleActivityTranslate[ACT_MP_RELOAD_STAND] = IdleActivity + 6 +IdleActivityTranslate[ACT_MP_RELOAD_CROUCH] = IdleActivity + 6 +IdleActivityTranslate[ACT_MP_JUMP] = ACT_HL2MP_JUMP_SLAM +IdleActivityTranslate[ACT_MP_SWIM] = IdleActivity + 9 +IdleActivityTranslate[ACT_LAND] = ACT_LAND + +-- it is preferred you return ACT_MP_* in CalcMainActivity, and if you have a specific need to not tranlsate through the weapon do it here +function GM:TranslateActivity(ply, act) + local newact = ply:TranslateWeaponActivity(act) + -- select idle anims if the weapon didn't decide + if (act == newact) then return IdleActivityTranslate[act] end + + return newact +end + +function GM:DoAnimationEvent(ply, event, data) + if (event == PLAYERANIMEVENT_ATTACK_PRIMARY) then + if ply:Crouching() then + ply:AnimRestartGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_ATTACK_CROUCH_PRIMARYFIRE, true) + else + ply:AnimRestartGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_ATTACK_STAND_PRIMARYFIRE, true) + end + -- there is no gesture, so just fire off the VM event + + return ACT_VM_PRIMARYATTACK + elseif (event == PLAYERANIMEVENT_ATTACK_SECONDARY) then + return ACT_VM_SECONDARYATTACK + elseif (event == PLAYERANIMEVENT_RELOAD) then + if ply:Crouching() then + ply:AnimRestartGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_RELOAD_CROUCH, true) + else + ply:AnimRestartGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_RELOAD_STAND, true) + end + + return ACT_INVALID + elseif (event == PLAYERANIMEVENT_JUMP) then + ply.m_bJumping = true + ply.m_bFirstJumpFrame = true + ply.m_flJumpStartTime = CurTime() + ply:AnimRestartMainSequence() + + return PLAYERANIMEVENT_JUMP + elseif (event == PLAYERANIMEVENT_CANCEL_RELOAD) then + ply:AnimResetGestureSlot(GESTURE_SLOT_ATTACK_AND_RELOAD) + + return ACT_INVALID + end +end diff --git a/gamemode/sh_bullets.lua b/gamemode/sh_bullets.lua new file mode 100644 index 00000000..600ab891 --- /dev/null +++ b/gamemode/sh_bullets.lua @@ -0,0 +1,349 @@ +if SERVER then + AddCSLuaFile() + util.AddNetworkString("LambdaWaterBullet") +end + +local DbgPrint = GetLogging("Bullets") + +if CLIENT then + + local BULLET_STEP_SIZE = 2500 + local BULLET_STEP_DISTANCE = 15 + local BUBBLES_PER_UNIT = 1.5 + + function GM:CreateWaterBulletParticles(bullet, newPos, distance) + + local ply = LocalPlayer() + if IsValid(ply) == false or ply:WaterLevel() ~= 3 then + return + end + + local curPos = bullet.CurPos + --debugoverlay.Box(curPos, Vector(-2, -2, -2), Vector(2, 2, 2), 1, Color(0, 255, 0)) + + local newAmount = math.Round(distance) + if newAmount < 1 then + newAmount = 1 + end + + local dir = bullet.Dir + + local offset + for i = 0, newAmount, BULLET_STEP_DISTANCE do + + offset = curPos + (dir * (distance / newAmount) * i) + (VectorRand() * 2.5) + + if offset:Distance(bullet.StartPos) >= bullet.Dist then + continue + end + + local inWater = bit.band(util.PointContents(offset), CONTENTS_WATER) ~= 0 + if inWater == false then + continue + end + + local p1 = bullet.Emitter:Add("effects/bubble", offset) + if p1 ~= nil then + p1:SetLifeTime(0.0) + p1:SetDieTime(util.RandomFloat(0.75, 1.25)) + p1:SetRoll(0) + p1:SetRollDelta(0) + local col = util.RandomInt(128, 255) + p1:SetColor(col, col, col) + p1:SetStartAlpha(128) + p1:SetEndAlpha(0) + local size = util.RandomInt(1, 2) + p1:SetStartSize(1) + p1:SetEndSize(0) + p1:SetVelocity( (dir * 64.0) + Vector(0, 0, 32) ) + p1:SetAirResistance(0.1) + p1:SetNextThink(CurTime() + 0.01) + p1.CurPos = p1:GetPos() + p1:SetThinkFunction(function(bubble) + -- Because the bubble effect does not affect the position + -- this is based on the best result, its not precise but its close + -- enough to not really notice + local curPos = bubble.CurPos + curPos = curPos + (bubble:GetVelocity() * FrameTime() * 40) + bubble.CurPos = curPos + local inWater = bit.band(util.PointContents(curPos), CONTENTS_WATER) ~= 0 + if inWater == false then + bubble:SetDieTime(0) + bubble:SetLifeTime(0) + end + end) + end + + local p2 = bullet.Emitter:Add("effects/splash2", offset) + if p2 ~= nil then + p2:SetLifeTime(0.0) + p2:SetDieTime(0.2) + p2:SetRoll(util.RandomInt(0, 360)) + p2:SetRollDelta(util.RandomInt(-4, 4)) + + local col = util.RandomInt(200, 255) + + p2:SetColor(col, col, col) + p2:SetStartAlpha(80) + p2:SetEndAlpha(0) + local size = 1 + p2:SetStartSize(size) + p2:SetEndSize(size * 4) + p2:SetVelocity( (dir * 64.0) ) + end + + --DbgPrint("Created particle: " .. tostring(p)) + + end + + end + + function GM:BulletsThink() + + if self.SimulatingBullets == nil then + return + end + + local curTime = CurTime() + + for k,v in pairs(self.SimulatingBullets) do + + local timeDelta = FrameTime() --((1 / 33) * game.GetTimeScale()) * v.Decay + local newPos = v.CurPos + ((v.Dir * BULLET_STEP_SIZE) * timeDelta) + + if newPos:Distance(v.StartPos) >= v.Dist then + self.SimulatingBullets[k] = nil + continue + end + + local dist = newPos:Distance(v.CurPos) + + self:CreateWaterBulletParticles(v, newPos, dist) + + v.CurPos = newPos + v.LastTime = curTime + v.Decay = 1 + + --debugoverlay.Box(newPos, Vector(-1, -1, -1), Vector(1, 1, 1), 1, Color(255, 255, 0)) + + self.SimulatingBullets[k] = v + + end + + end + + function GM:AddWaterBullet(timestamp, startPos, endPos, ang, force) + + self.SimulatingBullets = self.SimulatingBullets or {} + + local curTime = CurTime() + local dir = ang:Forward() + local timeDelta = curTime - timestamp + local pos = startPos + ((dir * BULLET_STEP_SIZE) * timeDelta) + local dist = startPos:Distance(endPos) + + local bullet = + { + StartPos = startPos, + EndPos = endPos, + Dist = dist, + Dir = dir, + CurPos = startPos, + Force = force, + LastTime = curTime, + Decay = 1, + Emitter = ParticleEmitter(startPos, false), + } + + --debugoverlay.Box(startPos, Vector(-2, -2, -2), Vector(2, 2, 2), 1, Color(0, 255, 0)) + + table.insert(self.SimulatingBullets, bullet) + + end + + net.Receive("LambdaWaterBullet", function(len) + + local timestamp = net.ReadFloat() + local startPos = net.ReadVector() + local endPos = net.ReadVector() + local ang = net.ReadAngle() + local force = net.ReadFloat() + + GAMEMODE:AddWaterBullet(timestamp, startPos, endPos, ang, force) + + end) + +end + +function GM:HandleShotImpactingWater(ent, attacker, tr, dmginfo, data) + + DbgPrint("HandleShotImpactingWater") + + local waterTr = util.TraceLine({ + start = tr.StartPos, + endpos = tr.HitPos, + filter = { ent, attacker, dmginfo:GetInflictor() }, + mask = bit.bor(MASK_SHOT, CONTENTS_WATER, CONTENTS_SLIME) + }) + + local ang = (tr.HitPos - tr.StartPos):Angle() + local fwd = ang:Forward() + local startPos = waterTr.HitPos + local endPos = tr.HitPos + (fwd * 400) + + local startedInWater = bit.band(util.PointContents(data.Src), CONTENTS_WATER) ~= 0 + if startedInWater == true then + startPos = data.Src + end + + --debugoverlay.Box(startPos, Vector(-2, -2, -2), Vector(2, 2, 2), 1, Color(0, 255, 0)) + --debugoverlay.Box(endPos, Vector(-2, -2, -2), Vector(2, 2, 2), 1, Color(255, 0, 0)) + + local timestamp = CurTime() + + --print(dmginfo:GetDamageForce()) + ent.NextBulletCheck = ent.NextBulletCheck or timestamp + if timestamp > ent.NextBulletCheck then + --return + end + ent.NextBulletCheck = timestamp + 0.1 + + if ent:IsPlayer() then + if CLIENT then + self:AddWaterBullet(timestamp, startPos, endPos, ang, 0) + else + local plys = {} + for _,v in pairs(player.GetAll()) do + -- TODO: Should we really just show it the person who is in water?, I couldn`t see them from above + if v ~= ent and v:WaterLevel() == 3 then + table.insert(plys, v) + end + end + -- Everything else does not work. + net.Start("LambdaWaterBullet") + net.WriteFloat(timestamp) + net.WriteVector(startPos) + net.WriteVector(endPos) + net.WriteAngle(ang) + net.WriteFloat(dmginfo:GetDamageForce():Length()) + net.Send(plys) + end + else + -- Everything else does not work. + net.Start("LambdaWaterBullet") + net.WriteFloat(timestamp) + net.WriteVector(startPos) + net.WriteVector(endPos) + net.WriteAngle(ang) + net.WriteFloat(dmginfo:GetDamageForce():Length()) + net.SendPVS(ent:GetPos()) + end + +end + +function GM:GetPlayerBulletSpread(ply) + + local wep = ply:GetActiveWeapon() + if wep == nil then + return Vector(0, 0, 0) + end + + vel = ply:GetAbsVelocity() + local velLen = vel:Length2D() + + return Vector(0.005, 0.005, 0.005) * ((velLen * 0.5) + 1) + +end + +function GM:EntityFireBullets(ent, data) + + local class + local scale = false + local wep + + if ent:IsPlayer() or ent:IsNPC() then + + if SERVER then + self:RegisterBulletFired(ent, data.Num) + end + + -- We have to assume its fired by the weapon. + wep = ent:GetActiveWeapon() + if IsValid(wep) then + + class = wep:GetClass() + class = self.AITranslatedGameWeapons[class] or class + + local ammo = game.GetAmmoName(wep:GetPrimaryAmmoType()) + + if self.GameWeapons[class] == true and data.AmmoType == ammo then + scale = true + --DbgPrint("Scaling recoil") + end + + local vel = Vector(0, 0, 0) + if ent:IsPlayer() then + + local primaryAmmo = ent:GetAmmoCount(wep:GetPrimaryAmmoType()) + local secondaryAmmo = ent:GetAmmoCount(wep:GetSecondaryAmmoType()) + local clip1 = wep:Clip1() + local clip2 = wep:Clip2() + + -- Treat as empty. + if clip2 == -1 then clip2 = 0 end + + if primaryAmmo == 0 and secondaryAmmo == 0 and clip1 == 0 and clip2 == 0 and IsFirstTimePredicted() then + self:OnPlayerAmmoDepleted(ent, wep) + end + + vel = ent:GetAbsVelocity() + elseif ent:IsNPC() then + + local phys = ent:GetPhysicsObject() + if IsValid(phys) then + vel = phys:GetVelocity() + end + + end + + local velLen = vel:Length2D() + velLen = math.Clamp(velLen, 0, 380) + + local spread = data.Spread + if velLen > 50 then + spread = spread * (velLen * 0.0035) + else + spread = spread * 0.3 + end + data.Spread = spread + + end + + end + + -- We will add a callback to handle water bullets. + local prevCallback = data.Callback + local self = self + local ent = ent + local newData = { Dir = data.Dir, Src = data.Src } + + data.Callback = function(attacker, tr, dmginfo) + + local pointContents = util.PointContents(tr.HitPos) + + if bit.band(pointContents, bit.bor(CONTENTS_WATER, CONTENTS_SLIME)) ~= 0 or bit.band(util.PointContents(newData.Src), CONTENTS_WATER) ~= 0 then + if IsFirstTimePredicted() then + -- Only call this once clientside, causes weird effects otherwise + hook.Call("HandleShotImpactingWater", self, ent, attacker, tr, dmginfo, newData) + end + end + + if prevCallback ~= nil then + prevCallback(attacker, tr, dmginfo) + end + + end + + return true + +end diff --git a/gamemode/sh_collisions.lua b/gamemode/sh_collisions.lua new file mode 100644 index 00000000..5b97fca5 --- /dev/null +++ b/gamemode/sh_collisions.lua @@ -0,0 +1,37 @@ +if SERVER then + AddCSLuaFile() +end + +local COLLISION_ID_PAIRS = {} +local DbgPrint = GetLogging("Collision") + +local function GetPairId(ent1, ent2) + local id1 = ent1:GetCreationID() + local id2 = ent2:GetCreationID() + + if (id2 < id1) then + id1, id2 = id2, id1 + end + + local id = bit.lshift(id2, 16) + id = bit.bor(id, id1) + + return id +end + +hook.Add("ShouldCollide", "LambdaShouldCollide", function(ent1, ent2) + local id = GetPairId(ent1, ent2) + + return COLLISION_ID_PAIRS[id] or true +end) + +local ENTITY_META = FindMetaTable("Entity") + +function ENTITY_META:SetCollideWith(ent2, state) + local id = GetPairId(self, ent2) + self:EnableCustomCollisions(state) + ent2:EnableCustomCollisions(state) + COLLISION_ID_PAIRS[id] = state + self:CollisionRulesChanged() + ent2:CollisionRulesChanged() +end diff --git a/gamemode/sh_convars.lua b/gamemode/sh_convars.lua new file mode 100644 index 00000000..b2871357 --- /dev/null +++ b/gamemode/sh_convars.lua @@ -0,0 +1,44 @@ +AddCSLuaFile() + +include("sh_debug.lua") + +GM.ConVars = {} + +function GM:RegisterConVar(name, value, flags, helptext) + local prefix = "lambda_" + local actualName = prefix .. name + local actualValue = "" + + if isbool(value) then + actualValue = tostring(tonumber(value)) + elseif isstring(value) then + actualValue = value + else + actualValue = tostring(value) + end + + local convar = CreateConVar(actualName, actualValue, flags, helptext) + self.ConVars[name] = convar + + return convar +end + +if SERVER then + -- Server -- + lambda_max_respawn_timeout = GM:RegisterConVar("max_respawn_timeout", 20, bit.bor(0, FCVAR_ARCHIVE, FCVAR_NOTIFY), "Time before player can respawn") + lambda_map_restart_timeout = GM:RegisterConVar("map_restart_timeout", 20, bit.bor(0, FCVAR_ARCHIVE, FCVAR_NOTIFY), "Time before a new round starts when all players are dead") + lambda_instance_id = GM:RegisterConVar("instance_id", 1, bit.bor(0, FCVAR_ARCHIVE, FCVAR_NOTIFY), "Allows to assign a unique instance id to support multiple srcds instances at once from the same directory.") + lambda_map_change_timeout = GM:RegisterConVar("map_change_timeout", 60, bit.bor(0, FCVAR_ARCHIVE, FCVAR_NOTIFY), "Time before changing level as soon first player gets to it") + lambda_player_god = GM:RegisterConVar("player_god", 0, bit.bor(0, FCVAR_ARCHIVE, FCVAR_NOTIFY), "No player damage") + lambda_pickup_delay = GM:RegisterConVar("pickup_delay", 0.5, bit.bor(0, FCVAR_ARCHIVE, FCVAR_NOTIFY), "The time to wait before player can pickup again") + -- Client side -- +else + lambda_sound_override = GM:RegisterConVar("sound_override", 0, bit.bor(0, FCVAR_ARCHIVE), "Expiremental sound override system") + lambda_dynamic_crosshair = GM:RegisterConVar("dynamic_crosshair", 1, bit.bor(0, FCVAR_ARCHIVE), "Dynamic crosshair") + lambda_postprocess = GM:RegisterConVar("postprocess", 1, bit.bor(0, FCVAR_ARCHIVE), "Postprocessing") +end + +lambda_gametype = GM:RegisterConVar("gametype", "hl2", bit.bor(0, FCVAR_ARCHIVE, FCVAR_NOTIFY), "Current gametype") +lambda_walkspeed = GM:RegisterConVar("walkspeed", 150, bit.bor(0, FCVAR_ARCHIVE, FCVAR_NOTIFY), "Walk speed") +lambda_normspeed = GM:RegisterConVar("normspeed", 190, bit.bor(0, FCVAR_ARCHIVE, FCVAR_NOTIFY), "Walk speed") +lambda_sprintspeed = GM:RegisterConVar("sprintspeed", 320, bit.bor(0, FCVAR_ARCHIVE, FCVAR_NOTIFY), "Sprint speed") diff --git a/gamemode/sh_debug.lua b/gamemode/sh_debug.lua new file mode 100644 index 00000000..02772890 --- /dev/null +++ b/gamemode/sh_debug.lua @@ -0,0 +1,180 @@ +AddCSLuaFile() + +_DEBUG = true + +--function print() error() end +USED_LOG_GROUPS = USED_LOG_GROUPS or {} + +function GetLogging(group, color) + + USED_LOG_GROUPS[group] = true + + if _DEBUG == false then + return function(...) end + end + + local group = group + local color = color or Color(255, 255, 255) + + return function(...) + LogGroup(group, color, ...) + end + +end + +if _DEBUG then + + local LOG_GROUPS = {} + local LOG_GROUPS_STR = "" + local lambda_log = GetConVar("lambda_log") or CreateConVar("lambda_log", "none", FCVAR_REPLICATED + FCVAR_ARCHIVE + FCVAR_NOTIFY, "Enable logging groups seperated by comma") + + local function ProcessLogGroups() + + local val = lambda_log:GetString() + if val == LOG_GROUPS_STR then + return + end + + --print("Log group changed: " .. val) + LOG_GROUPS = {} + LOG_GROUPS_STR = val + local groupList = string.Explode(",", val) + for _,v in pairs(groupList) do + local groupVal = string.Trim(v) + groupVal = string.lower(groupVal) + --print("Group: " .. groupVal) + if groupVal == "" then + continue + elseif groupVal:lower() == "all" then + print("Using all groups") + LOG_GROUPS = {} + for k,_ in pairs(USED_LOG_GROUPS) do + LOG_GROUPS[k:lower()] = true + end + --PrintTable(LOG_GROUPS) + return true + end + + LOG_GROUPS[groupVal] = true + end + --PrintTable(LOG_GROUPS) + + end + + local function IsGroupLogActive(group) + + --print("IsGroupLogActive: " .. group) + ProcessLogGroups() + + group = string.lower(group) + + return LOG_GROUPS[group] == true + + end + + -- Fallback to old method. + function DbgPrint(...) + LogGeneric(Color(255, 255, 255), ...) + end + + function LogGroup(group, color, ...) + + if IsGroupLogActive(group) == false then + return + end + + local printResult = "" + for i,v in ipairs( {...} ) do + printResult = printResult .. tostring(v) .. "\t" + end + printResult = printResult + + if SERVER then + print("[SV:" .. group .. "] " .. printResult) + else + if epoe and epoe.Print then + epoe.Print("[CL:" .. group .. "] " .. printResult) + else + print("[CL:" .. group .. "] " .. printResult) + end + end + + end + + function LogGeneric(color, ...) + + local printResult = "" + for i,v in ipairs( {...} ) do + printResult = printResult .. tostring(v) .. "\t" + end + printResult = printResult + + if SERVER then + --MsgC(Color(0, 179, 255), "[SV] " .. printResult .. "\n") + print("[SV] " .. printResult) + else + --MsgC(Color(188, 188, 0), "[CL] " .. printResult .. "\n") + if epoe and epoe.Print then + epoe.Print("[CL] " .. printResult) + else + print("[CL] " .. printResult) + end + end + + end + + function DbgError(...) + + local printResult = "" + for i,v in ipairs( {...} ) do + printResult = printResult .. tostring(v) .. "\t" + end + + if SERVER then + MsgC(Color(0, 179, 255), "[SV] " .. printResult .. "\n") + else + if epoe and epoe.Print then + epoe.Print(printResult) + else + print(printResult) + end + end + + error(printResult) + + end + + local lastDebugOutput = "" + + function DbgUniquePrint(...) + + -- I know I know this isnt exactly efficient but who gives a fuck, debugging purpose! + local t = {...} + local output = table.ToString(t) + + if output ~= lastDebugOutput then + lastDebugOutput = output + DbgPrint(unpack(t)) + end + + end + + concommand.Add( "lambda_log_groups", function( ply, cmd, args ) + ProcessLogGroups() + local activeGroups = {} + for k,_ in pairs(LOG_GROUPS) do + table.insert(activeGroups, k) + end + print("current = " .. table.concat(activeGroups,",")) + print("All") + for k,_ in pairs(USED_LOG_GROUPS) do + print(k) + end + end ) + +else + + function DbgPrint(...) end + function DbgUniquePrint(...) end + +end diff --git a/gamemode/sh_entity_extend.lua b/gamemode/sh_entity_extend.lua new file mode 100644 index 00000000..abfcc865 --- /dev/null +++ b/gamemode/sh_entity_extend.lua @@ -0,0 +1,227 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("EntityExt") +local ENTITY_META = FindMetaTable("Entity") + +function ENTITY_META:AddSpawnFlags(flags) + + local newFlags = bit.bor(self:GetSpawnFlags(), flags) + self:SetKeyValue("spawnflags", newFlags) + +end + +function ENTITY_META:RemoveSpawnFlags(flags) + + local newFlags = bit.band(self:GetSpawnFlags(), bit.bnot(flags)) + self:SetKeyValue("spawnflags", newFlags) + +end + +function ENTITY_META:IsDoor() + local class = self:GetClass() + return class == "prop_door_rotating" or class == "func_door" or class == "func_door_rotating" +end + +DOOR_STATE_CLOSED = 0 +DOOR_STATE_OPENING = 1 +DOOR_STATE_OPEN = 2 +DOOR_STATE_CLOSING = 3 +DOOR_STATE_AJAR = 4 + +function ENTITY_META:GetDoorState() + return self:GetSaveTable().m_eDoorState +end + +function ENTITY_META:IsDoorClosing() + return self:GetDoorState() == DOOR_STATE_CLOSING +end + +function ENTITY_META:IsDoorClosed() + return self:GetDoorState() == DOOR_STATE_CLOSED +end + +function ENTITY_META:IsDoorOpening() + return self:GetDoorState() == DOOR_STATE_OPENING +end + +function ENTITY_META:IsDoorOpen() + return self:GetDoorState() == DOOR_STATE_OPEN +end + +function ENTITY_META:GetDoorBlocker() + return self:GetSaveTable().m_hBlocker +end + +function ENTITY_META:IsDoorLocked() + return self:GetSaveTable().m_bLocked +end + +function ENTITY_META:GetDoorOpenDir() + +end + +OVERLAY_TEXT_BIT = 0x00000001 -- show text debug overlay for this entity +OVERLAY_NAME_BIT = 0x00000002 -- show name debug overlay for this entity +OVERLAY_BBOX_BIT = 0x00000004 -- show bounding box overlay for this entity +OVERLAY_PIVOT_BIT = 0x00000008 -- show pivot for this entity +OVERLAY_MESSAGE_BIT = 0x00000010 -- show messages for this entity +OVERLAY_ABSBOX_BIT = 0x00000020 -- show abs bounding box overlay +OVERLAY_RBOX_BIT = 0x00000040 -- show the rbox overlay +OVERLAY_SHOW_BLOCKSLOS = 0x00000080 -- show entities that block NPC LOS +OVERLAY_ATTACHMENTS_BIT = 0x00000100 -- show attachment points +OVERLAY_AUTOAIM_BIT = 0x00000200 -- Display autoaim radius +OVERLAY_NPC_SELECTED_BIT = 0x00001000 -- the npc is current selected +OVERLAY_NPC_NEAREST_BIT = 0x00002000 -- show the nearest node of this npc +OVERLAY_NPC_ROUTE_BIT = 0x00004000 -- draw the route for this npc +OVERLAY_NPC_TRIANGULATE_BIT = 0x00008000 -- draw the triangulation for this npc +OVERLAY_NPC_ZAP_BIT = 0x00010000 -- destroy the NPC +OVERLAY_NPC_ENEMIES_BIT = 0x00020000 -- show npc's enemies +OVERLAY_NPC_CONDITIONS_BIT = 0x00040000 -- show NPC's current conditions +OVERLAY_NPC_SQUAD_BIT = 0x00080000 -- show npc squads +OVERLAY_NPC_TASK_BIT = 0x00100000 -- show npc task details +OVERLAY_NPC_FOCUS_BIT = 0x00200000 -- show line to npc's enemy and target +OVERLAY_NPC_VIEWCONE_BIT = 0x00400000 -- show npc's viewcone +OVERLAY_NPC_KILL_BIT = 0x00800000 -- kill the NPC running all appropriate AI. +OVERLAY_WC_CHANGE_ENTITY = 0x01000000 -- object changed during WC edit +OVERLAY_BUDDHA_MODE = 0x02000000 -- take damage but don't die +OVERLAY_NPC_STEERING_REGULATIONS = 0x04000000 -- Show the steering regulations associated with the NPC +OVERLAY_TASK_TEXT_BIT = 0x08000000 -- show task and schedule names when they start +OVERLAY_PROP_DEBUG = 0x10000000 +OVERLAY_NPC_RELATION_BIT = 0x20000000 -- show relationships between target and all children +OVERLAY_VIEWOFFSET = 0x40000000 -- show view offset + +function ENTITY_META:AddDebugOverlays(f) + local flags = self:GetDebugOverlays() + flags = bit.bor(flags, tonumber(f or 0)) + self:SetSaveValue("m_debugOverlays", flags) +end + +function ENTITY_META:RemoveDebugOverlays(f) + local flags = self:GetDebugOverlays() + flags = bit.band(flags, bit.bnot(f)) + self:SetSaveValue("m_debugOverlays", flags) +end + +function ENTITY_META:GetDebugOverlays() + local tbl = self:GetSaveTable() + return tonumber(tbl["m_debugOverlays"] or 0) +end + +-- Vehicles +function ENTITY_META:IsGunEnabled() + return self:GetSaveTable().EnableGun == true +end + +-- caps +FCAP_MUST_SPAWN = 0x00000001 -- Spawn after restore +FCAP_ACROSS_TRANSITION = 0x00000002 -- should transfer between transitions +-- UNDONE: This will ignore transition volumes (trigger_transition), but not the PVS!!! +FCAP_FORCE_TRANSITION = 0x00000004 -- ALWAYS goes across transitions +FCAP_NOTIFY_ON_TRANSITION = 0x00000008 -- Entity will receive Inside/Outside transition inputs when a transition occurs + +FCAP_IMPULSE_USE = 0x00000010 -- can be used by the player +FCAP_CONTINUOUS_USE = 0x00000020 -- can be used by the player +FCAP_ONOFF_USE = 0x00000040 -- can be used by the player +FCAP_DIRECTIONAL_USE = 0x00000080 -- Player sends +/- 1 when using (currently only tracktrains) + +-- NOTE: Normally +USE only works in direct line of sight. Add these caps for additional searches +FCAP_USE_ONGROUND = 0x00000100 +FCAP_USE_IN_RADIUS = 0x00000200 +FCAP_SAVE_NON_NETWORKABLE = 0x00000400 + +FCAP_MASTER = 0x10000000 -- Can be used to "master" other entities (like multisource) +FCAP_WCEDIT_POSITION = 0x40000000 -- Can change position and update Hammer in edit mode +FCAP_DONT_SAVE = 0x80000000 -- Don't save this + +function ENTITY_META:HasObjectCaps(caps) + return bit.band(self:ObjectCaps(), caps) ~= 0 +end + +function ENTITY_META:GetObjectCaps() + return self:ObjectCaps() +end + +function ENTITY_META:EnableRespawn(state, time) + -- On shutdown this actually errors thats why this check exists. + if not IsValid(self) then + return + end + + if state == true then + time = time or 1 + + self:CallOnRemove("LambdaRespawn", function(self) + local class = self:GetClass() + local pos = self:GetPos() + local ang = self:GetAngles() + local mdl = self:GetModel() + + timer.Simple(time, function() + local new = ents.Create(class) + new:SetPos(pos) + new:SetAngles(ang) + new:SetModel(mdl) + new:Spawn() + new:EnableRespawn(true) + end) + + end) + + else + self:RemoveCallOnRemove("LambdaRespawn") + end + +end + +function ENTITY_META:GetKeyValueTable() + return table.Copy(self.LambdaKeyValues or {}) +end + +-- FIXME: I'm not sure if we can use the material path alone, no way to get surface data atm. +function ENTITY_META:IsVPhysicsFlesh() + + --[[ + IPhysicsObject *pList[VPHYSICS_MAX_OBJECT_LIST_COUNT]; + int count = VPhysicsGetObjectList( pList, ARRAYSIZE(pList) ); + for ( int i = 0; i < count; i++ ) + { + int material = pList[i]->GetMaterialIndex(); + const surfacedata_t *pSurfaceData = physprops->GetSurfaceData( material ); + // Is flesh ?, don't allow pickup + if ( pSurfaceData->game.material == CHAR_TEX_ANTLION || pSurfaceData->game.material == CHAR_TEX_FLESH || pSurfaceData->game.material == CHAR_TEX_BLOODYFLESH || pSurfaceData->game.material == CHAR_TEX_ALIENFLESH ) + return true; + } + return false; + ]] + + for i = 0, self:GetPhysicsObjectCount() - 1 do + + local phys = self:GetPhysicsObjectNum( i ) + local mat = phys:GetMaterial() + DbgPrint("IsVPhysicsFlesh: " .. mat) + end + + return false + +end + +function ENTITY_META:GetRootMoveParent() + local ent = self + local parent = ent:GetMoveParent() + while IsValid(parent) do + ent = parent + parent = ent:GetMoveParent() + end + return ent +end + +function ENTITY_META:GetPhysMass() + local mass = 0.0 + for i = 0, self:GetPhysicsObjectCount() - 1 do + local phys = self:GetPhysicsObjectNum(i) + if IsValid(phys) then + mass = mass + phys:GetMass() + end + end + return mass +end diff --git a/gamemode/sh_ents_extend.lua b/gamemode/sh_ents_extend.lua new file mode 100644 index 00000000..4386c312 --- /dev/null +++ b/gamemode/sh_ents_extend.lua @@ -0,0 +1,230 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("EntsExt") + +if SERVER then + + local persistantremovals = {} + local delayedcallbacks = {} + local delayedcallbacksIndex = {} + + hook.Add("OnEntityCreated", "LambdaEntityCreation", function(ent) + + local ent = ent + + -- Do this the next frame. + util.RunNextFrame(function() + + if not IsValid(ent) then + --DbgPrint("Entity " .. tostring(ent) .. " no longer valid") + return + end + + local name = ent:GetName() + if persistantremovals[name] then + + DbgPrint("Persistant removal of entity " .. tostring(ent)) + SafeRemoveEntityDelayed(ent, 0.1) + + end + + local cbs = delayedcallbacks[name] + if cbs ~= nil then + for k,v in pairs(cbs) do + v.cb(ent) + if v.multiple == false then + delayedcallbacks[name][k] = nil + end + end + end + end) + + end) + + function ents.WaitForEntityByName(name, cb, multiple) + + local multiple = multiple or false + local found = ents.FindByName(name) + + for _,v in pairs(found) do + cb(v) + end + + local data = {} + if found == nil or #found == 0 then + DbgPrint("Entity " .. tostring(name) .. " not found yet, waiting for creation") + delayedcallbacks[name] = delayedcallbacks[name] or {} + data.cb = cb + data.multiple = multiple + table.insert(delayedcallbacks[name], data) + end + + end + + function ents.WaitForEntityByIndex(index, cb) + local ent = Entity(index) + if IsValid(ent) then + cb(ent) + return + end + delayedcallbacksIndex[index] = delayedcallbacksIndex[index] or {} + table.insert(delayedcallbacksIndex[index], cb) + end + + function ents.RemoveByClass(class, pos) + + local found = ents.FindByClass(class) + for _,v in pairs(found) do + if pos ~= nil then + if v:GetPos() == pos then + v:Remove() + end + else + v:Remove() + end + end + + end + + function ents.RemoveByName(name, persistant) + + local found = ents.FindByName(name) + for _,v in pairs(found) do + v:Remove() + end + + if persistant then + + persistantremovals[name] = true + + end + + end + + function ents.FindByGlobalName(globalname) + for _,v in pairs(ents.GetAll()) do + if v:GetInternalVariable("globalname") == globalname or v:GetNWString("GlobalName") == globalname then + return v + end + end + + return nil + end + + function ents.CreateSimple(class, data) + + local ent = ents.Create(class) + ent:SetPos(data.Pos or Vector(0, 0, 0)) + if data.SpawnFlags then + ent:SetKeyValue("spawnflags", tostring(data.SpawnFlags)) + end + if data.KeyValues ~= nil then + for k,v in pairs(data.KeyValues) do + ent:SetKeyValue(k, v) + end + end + ent:SetAngles(data.Ang or Angle(0, 0, 0)) + if data.Model ~= nil then + ent:SetModel(data.Model) + end + if data.MoveType ~= nil then + ent:SetMoveType(data.MoveType) + end + if data.UnFreezable ~= nil then + ent:SetUnFreezable(data.UnFreezable) + end + if data.Flags ~= nil then + ent:AddFlags(data.Flags) + end + + ent:Spawn() + + if data.Freeze == true then + local phys = ent:GetPhysicsObject() + if IsValid(phys) then + phys:EnableMotion(false) + end + end + + return ent + end + + function ents.CreateFromData(entData) + if entData == nil then + return nil + end + + local classname = entData["classname"] + if classname == nil or classname == "" then + Error("Data has no classname") + end + + local ent = ents.Create(classname) + + for k,v in pairs(entData) do + if istable(v) then + for _, v2 in pairs(v) do + ent:SetKeyValue(k, v2) + -- We process outputs and keyvalues in here, its not calling when calling SetKeyValue + GAMEMODE:EntityKeyValue(ent, k, v2) + end + else + ent:SetKeyValue(k, v) + -- We process outputs and keyvalues in here, its not calling when calling SetKeyValue + GAMEMODE:EntityKeyValue(ent, k, v) + end + end + + return ent + end + +end + +function ents.FindFirstByName(name) + + local f = ents.FindByName(name) + if f == nil then + return nil + end + + return f[1] + +end + +function ents.FindByPos(pos, class, name) + + local tolerance = Vector(1, 1, 1) + local found = ents.FindInBox(pos - tolerance, pos + tolerance) + local res = {} + + for _,v in pairs(found) do + + if class ~= nil and name ~= nil then + + if v:GetClass() == class and v:GetName() == name then + table.insert(res, v) + end + + elseif class ~= nil and name == nil then + + if v:GetClass() == class then + table.insert(res, v) + end + + elseif class == nil and name ~= nil then + + if v:GetName() == name then + table.insert(res, v) + end + + else + + table.insert(res, v) + + end + + end + + return res + +end diff --git a/gamemode/sh_gametypes.lua b/gamemode/sh_gametypes.lua new file mode 100644 index 00000000..f5330f51 --- /dev/null +++ b/gamemode/sh_gametypes.lua @@ -0,0 +1,81 @@ +AddCSLuaFile() + +include("gametypes/hl2.lua") + +local DEFAULT_MAPSCRIPT = {} +DEFAULT_MAPSCRIPT.InputFilters = {} +DEFAULT_MAPSCRIPT.DefaultLoadout = +{ + Weapons = + { + "weapon_crowbar", + "weapon_pistol", + "weapon_smg1", + "weapon_357", + "weapon_physcannon", + "weapon_frag", + "weapon_shotgun", + "weapon_ar2", + "weapon_rpg", + "weapon_crossbow", + "weapon_bugbait", + }, + Ammo = + { + ["Pistol"] = 20, + ["SMG1"] = 45, + ["357"] = 6, + ["Grenade"] = 3, + ["Buckshot"] = 12, + ["AR2"] = 50, + ["RPG_Round"] = 8, + ["SMG1_Grenade"] = 3, + ["XBowBolt"] = 4, + }, + Armor = 60, + HEV = true, +} +DEFAULT_MAPSCRIPT.EntityCleanupFilter = +{ +} + +-- Default functions. +DEFAULT_MAPSCRIPT.Init = function(self) end +DEFAULT_MAPSCRIPT.PostInit = function(self) end +DEFAULT_MAPSCRIPT.PrePlayerSpawn = function(self, ply) end +DEFAULT_MAPSCRIPT.PostPlayerSpawn = function(self, ply) end +DEFAULT_MAPSCRIPT.OnNewGame = function(self) end + +GameTypes = GameTypes or {} +GameTypes.Registered = {} + +function GameTypes:Add(name, tbl) + local mappedName = name:lower() + if self.Registered[mappedName] ~= nil then + error("GameType name is already taken: " .. name) + end + self.Registered[mappedName] = tbl +end + +function GameTypes:Get(name) + local mappedName = name:lower() + return self.Registered[mappedName] +end + +function GM:LoadGameTypes() + hook.Run("LambdaLoadGameTypes", GameTypes) +end + +function GM:SetGameType(gametype) + local gametype = GameTypes:Get(gametype) + if gametype == nil then + error("Unable to find gametype: " .. gametype) + return + end + self.GameType = gametype + self.MapScript = gametype.MapScript or table.Copy(DEFAULT_MAPSCRIPT) +end + +function GM:GetGameType() + return self.GameType +end diff --git a/gamemode/sh_hudhint.lua b/gamemode/sh_hudhint.lua new file mode 100644 index 00000000..4f9a40f1 --- /dev/null +++ b/gamemode/sh_hudhint.lua @@ -0,0 +1,33 @@ +if SERVER then + + AddCSLuaFile() + + util.AddNetworkString("LambdaHudHint") + + function GM:AddHintText(data) + + local tab + if isstring(data) then + tab = { data } + elseif istable(data) then + tab = data + else + Error("AddHintText: Invalid argument passed, can be string or table of strings") + end + + local count = table.Count(tab) + + net.Start("LambdaHudHint") + net.WriteUInt(count, 8) + for _,v in pairs(tab) do + net.WriteString(v) + end + net.Broadcast() + + end + +else -- CLIENT + + -- TODO: Implement rendering those things. + +end diff --git a/gamemode/sh_lambda.lua b/gamemode/sh_lambda.lua new file mode 100644 index 00000000..b95f69a6 --- /dev/null +++ b/gamemode/sh_lambda.lua @@ -0,0 +1,229 @@ +AddCSLuaFile() + +LAMBDA_TEAM_CONNECTING = 1200 +LAMBDA_TEAM_DEAD = 1 +LAMBDA_TEAM_ALIVE = 5 +LAMBDA_TEAM_SPECTATOR = 3 + +GM.HurtSounds = {} + +-- Male +GM.HurtSounds["male"] = {} +GM.HurtSounds["male"][HITGROUP_LEFTARM] = { + "vo/npc/male01/myarm01.wav", + "vo/npc/male01/myarm02.wav" +} +GM.HurtSounds["male"][HITGROUP_RIGHTARM] = { + "vo/npc/male01/myarm01.wav", + "vo/npc/male01/myarm02.wav" +} +GM.HurtSounds["male"][HITGROUP_LEFTLEG] = { + "vo/npc/male01/myleg01.wav", + "vo/npc/male01/myleg02.wav" +} +GM.HurtSounds["male"][HITGROUP_RIGHTLEG] = { + "vo/npc/male01/myleg01.wav", + "vo/npc/male01/myleg02.wav" +} +GM.HurtSounds["male"][HITGROUP_STOMACH] = { + "vo/npc/male01/hitingut01.wav", + "vo/npc/male01/hitingut02.wav", + "vo/npc/male01/mygut02.wav" +} +GM.HurtSounds["male"][HITGROUP_GENERIC] = { + "vo/npc/male01/pain01.wav", + "vo/npc/male01/pain02.wav", + "vo/npc/male01/pain03.wav", + "vo/npc/male01/pain04.wav", + "vo/npc/male01/pain04.wav", + "vo/npc/male01/pain05.wav", + "vo/npc/male01/pain06.wav", + "vo/npc/male01/pain07.wav", + "vo/npc/male01/pain08.wav", + "vo/npc/male01/pain09.wav" +} +GM.HurtSounds["male"][HITGROUP_CHEST] = { + "vo/npc/male01/pain01.wav", + "vo/npc/male01/pain02.wav", + "vo/npc/male01/pain03.wav", + "vo/npc/male01/pain04.wav", + "vo/npc/male01/pain04.wav", + "vo/npc/male01/pain05.wav", + "vo/npc/male01/pain06.wav", + "vo/npc/male01/pain07.wav", + "vo/npc/male01/pain08.wav", + "vo/npc/male01/pain09.wav" +} +GM.HurtSounds["male"][HITGROUP_GEAR] = { + "vo/npc/male01/pain01.wav", + "vo/npc/male01/pain02.wav", + "vo/npc/male01/pain03.wav", + "vo/npc/male01/pain04.wav", + "vo/npc/male01/pain04.wav", + "vo/npc/male01/pain05.wav", + "vo/npc/male01/pain06.wav", + "vo/npc/male01/pain07.wav", + "vo/npc/male01/pain08.wav", + "vo/npc/male01/pain09.wav" +} + +-- Female +GM.HurtSounds["female"] = {} +GM.HurtSounds["female"][HITGROUP_LEFTARM] = { + "vo/npc/female01/myarm01.wav", + "vo/npc/female01/myarm02.wav" +} +GM.HurtSounds["female"][HITGROUP_RIGHTARM] = { + "vo/npc/female01/myarm01.wav", + "vo/npc/female01/myarm02.wav" +} +GM.HurtSounds["female"][HITGROUP_LEFTLEG] = { + "vo/npc/female01/myleg01.wav", + "vo/npc/female01/myleg02.wav" +} +GM.HurtSounds["female"][HITGROUP_RIGHTLEG] = { + "vo/npc/female01/myleg01.wav", + "vo/npc/female01/myleg02.wav" +} +GM.HurtSounds["female"][HITGROUP_STOMACH] = { + "vo/npc/female01/hitingut01.wav", + "vo/npc/female01/hitingut02.wav", + "vo/npc/female01/mygut02.wav" +} +GM.HurtSounds["female"][HITGROUP_GENERIC] = { + "vo/npc/female01/pain01.wav", + "vo/npc/female01/pain02.wav", + "vo/npc/female01/pain03.wav", + "vo/npc/female01/pain04.wav", + "vo/npc/female01/pain04.wav", + "vo/npc/female01/pain05.wav", + "vo/npc/female01/pain06.wav", + "vo/npc/female01/pain07.wav", + "vo/npc/female01/pain08.wav", + "vo/npc/female01/pain09.wav" +} +GM.HurtSounds["female"][HITGROUP_CHEST] = { + "vo/npc/female01/pain01.wav", + "vo/npc/female01/pain02.wav", + "vo/npc/female01/pain03.wav", + "vo/npc/female01/pain04.wav", + "vo/npc/female01/pain04.wav", + "vo/npc/female01/pain05.wav", + "vo/npc/female01/pain06.wav", + "vo/npc/female01/pain07.wav", + "vo/npc/female01/pain08.wav", + "vo/npc/female01/pain09.wav" +} +GM.HurtSounds["female"][HITGROUP_GEAR] = { + "vo/npc/female01/pain01.wav", + "vo/npc/female01/pain02.wav", + "vo/npc/female01/pain03.wav", + "vo/npc/female01/pain04.wav", + "vo/npc/female01/pain04.wav", + "vo/npc/female01/pain05.wav", + "vo/npc/female01/pain06.wav", + "vo/npc/female01/pain07.wav", + "vo/npc/female01/pain08.wav", + "vo/npc/female01/pain09.wav" +} + +sk_max_pistol = GetConVar("sk_max_pistol") +sk_max_smg1 = GetConVar("sk_max_smg1") +sk_max_smg1_grenade = GetConVar("sk_max_smg1_grenade") +sk_max_357 = GetConVar("sk_max_357") +sk_max_ar2 = GetConVar("sk_max_ar2") +sk_max_ar2_altfire = GetConVar("sk_max_ar2_altfire") +sk_max_buckshot = GetConVar("sk_max_buckshot") +sk_max_crossbow = GetConVar("sk_max_crossbow") +sk_max_grenade = GetConVar("sk_max_grenade") +sk_max_rpg_round = GetConVar("sk_max_rpg_round") + +GM.MAX_AMMO_DEF = +{ + ["Pistol"] = sk_max_pistol, + ["SMG1"] = sk_max_smg1, + ["SMG1_Grenade"] = sk_max_smg1_grenade, + ["357"] = sk_max_357, + ["AR2"] = sk_max_ar2, + ["Buckshot"] = sk_max_buckshot, + ["AR2AltFire"] = sk_max_ar2_altfire, + ["XBowBolt"] = sk_max_crossbow, + ["Grenade"] = sk_max_grenade, + ["RPG_Round"] = sk_max_rpg_round, +} + +GM.ITEM_DEF = +{ + ["item_ammo_pistol"] = { ["Type"] = "Pistol", ["Max"] = sk_max_pistol, ["1"] = 24, ["2"] = 20, ["3"] = 12 }, + ["item_ammo_pistol_large"] = { ["Type"] = "Pistol", ["Max"] = sk_max_pistol, ["1"] = 120, ["2"] = 100, ["3"] = 60 }, + ["item_ammo_smg1"] = { ["Type"] = "SMG1", ["Max"] = sk_max_smg1, ["1"] = 54, ["2"] = 45, ["3"] = 27 }, + ["item_ammo_smg1_large"] = { ["Type"] = "SMG1", ["Max"] = sk_max_smg1, ["1"] = 225, ["2"] = 225, ["3"] = 135 }, + ["item_ammo_smg1_grenade"] = { ["Type"] = "SMG1_Grenade", ["Max"] = sk_max_smg1_grenade, ["1"] = 1, ["2"] = 1, ["3"] = 1 }, + ["item_ammo_357"] = { ["Type"] = "357", ["Max"] = sk_max_357, ["1"] = 7, ["2"] = 6, ["3"] = 3 }, + ["item_ammo_357_large"] = { ["Type"] = "357", ["Max"] = sk_max_357, ["1"] = 12, ["2"] = 12, ["3"] = 12 }, + ["item_ammo_ar2"] = { ["Type"] = "AR2", ["Max"] = sk_max_ar2, ["1"] = 24, ["2"] = 20, ["3"] = 12 }, + ["item_ammo_ar2_large"] = { ["Type"] = "AR2", ["Max"] = sk_max_ar2, ["1"] = 60, ["2"] = 60, ["3"] = 60 }, + ["item_ammo_ar2_altfire"] = { ["Type"] = "AR2AltFire", ["Max"] = sk_max_ar2_altfire, ["1"] = 1, ["2"] = 1, ["3"] = 1 }, + ["item_box_buckshot"] = { ["Type"] = "Buckshot", ["Max"] = sk_max_buckshot, ["1"] = 24, ["2"] = 20, ["3"] = 12 }, + ["item_ammo_crossbow"] = { ["Type"] = "XBowBolt", ["Max"] = sk_max_crossbow, ["1"] = 7, ["2"] = 6, ["3"] = 3 }, + ["item_ammo_crossbow"] = { ["Type"] = "XBowBolt", ["Max"] = sk_max_crossbow, ["1"] = 7, ["2"] = 6, ["3"] = 3 }, + ["item_rpg_round"] = { ["Type"] = "RPG_Round", ["Max"] = sk_max_rpg_round, ["1"] = 1, ["2"] = 1, ["3"] = 1 }, + ["weapon_frag"] = { ["Type"] = "Grenade", ["Max"] = sk_max_grenade, ["1"] = 1, ["2"] = 1, ["3"] = 1 }, +} + +GM.PLAYER_WEAPON_DAMAGE = +{ + ["weapon_crowbar"] = GetConVar("sk_plr_dmg_crowbar"), + ["weapon_stunstick"] = GetConVar("sk_plr_dmg_stunstick"), + ["weapon_ar2"] = GetConVar("sk_plr_dmg_ar2"), + ["weapon_357"] = GetConVar("sk_plr_dmg_357"), + ["weapon_smg1"] = GetConVar("sk_plr_dmg_smg1"), + ["weapon_crossbow"] = GetConVar("sk_plr_dmg_crowssbow"), + ["weapon_shotgun"] = GetConVar("sk_plr_dmg_buckshot"), + ["weapon_pistol"] = GetConVar("sk_plr_dmg_pistol"), +} + +GM.NPC_WEAPON_DAMAGE = +{ + ["weapon_crowbar"] = GetConVar("sk_npc_dmg_crowbar"), + ["weapon_stunstick"] = GetConVar("sk_npc_dmg_stunstick"), + ["weapon_ar2"] = GetConVar("sk_npc_dmg_ar2"), + ["weapon_357"] = GetConVar("sk_npc_dmg_357"), +} + +GM.GameWeapons = +{ + ["weapon_357"] = true, + ["weapon_alyxgun"] = true, + ["weapon_annabelle"] = true, + ["weapon_ar2"] = true, + ["weapon_brickbat"] = true, + ["weapon_bugbait"] = true, + ["weapon_crossbow"] = true, + ["weapon_crowbar"] = true, + ["weapon_frag"] = true, + ["weapon_physcannon"] = true, + ["weapon_pistol"] = true, + ["weapon_rpg"] = true, + ["weapon_shotgun"] = true, + ["weapon_smg1"] = true, + ["weapon_striderbuster"] = true, + ["weapon_stunstick"] = true, +} + +GM.AITranslatedGameWeapons = +{ + ["ai_weapon_357"] = "weapon_357", + ["ai_weapon_ar2"] = "weapon_ar2", + ["ai_weapon_smg1"] = "weapon_smg1", + ["ai_weapon_shotgun"] = "weapon_shotgun", +} + +function GM:CreateTeams() + + team.SetUp(LAMBDA_TEAM_ALIVE, "Alive", Color(0, 0, 255), true) + team.SetUp(LAMBDA_TEAM_DEAD, "Dead", Color(255, 0, 0), true) + team.SetUp(LAMBDA_TEAM_SPECTATOR, "Spectating", Color(100, 100, 100), true) + team.SetUp(LAMBDA_TEAM_CONNECTING, "Connecting", Color(100, 100, 100), true) + +end diff --git a/gamemode/sh_lambda_npc.lua b/gamemode/sh_lambda_npc.lua new file mode 100644 index 00000000..4fe5b9f3 --- /dev/null +++ b/gamemode/sh_lambda_npc.lua @@ -0,0 +1,258 @@ +DEFINE_BASECLASS( "gamemode_base" ) + +local DbgPrint = GetLogging("NPC") + +if SERVER then + + AddCSLuaFile() + +end + + local sk_npc_head = GetConVar("sk_npc_head") + local sk_npc_chest = GetConVar("sk_npc_chest") + local sk_npc_stomach = GetConVar("sk_npc_stomach") + local sk_npc_arm = GetConVar("sk_npc_arm") + local sk_npc_leg = GetConVar("sk_npc_leg") + + local HITGROUP_SCALE = + { + [HITGROUP_GENERIC] = function() return 1.0 end, + [HITGROUP_HEAD] = function() return sk_npc_head:GetFloat() end, + [HITGROUP_CHEST] = function() return sk_npc_chest:GetFloat() end, + [HITGROUP_STOMACH] = function() return sk_npc_stomach:GetFloat() end, + [HITGROUP_LEFTARM] = function() return sk_npc_arm:GetFloat() end, + [HITGROUP_RIGHTARM] = function() return sk_npc_arm:GetFloat() end, + [HITGROUP_LEFTLEG] = function() return sk_npc_leg:GetFloat() end, + [HITGROUP_RIGHTLEG] = function() return sk_npc_leg:GetFloat() end, + } + + local SOLIDER_GEAR_SOUNDS = + { + "npc/combine_soldier/gear1.wav", + "npc/combine_soldier/gear2.wav", + "npc/combine_soldier/gear3.wav", + "npc/combine_soldier/gear4.wav", + "npc/combine_soldier/gear5.wav", + "npc/combine_soldier/gear6.wav" + } + + function GM:NPCFootstep(npc, data) + + local class = npc:GetClass() + if class == "npc_combine" or class == "npc_combine_s" then + --npc:EmitSound(table.Random(SOLIDER_GEAR_SOUNDS)) + local vel = npc:GetVelocity() + local len = vel:Length() + if vel:Length() >= 40 then + EmitSound(table.Random(SOLIDER_GEAR_SOUNDS), npc:GetPos(), npc:EntIndex(), CHAN_BODY) + end + end + + end + +if SERVER then + + function GM:ScaleNPCDamage(npc, hitgroup, dmginfo) + + local attacker = dmginfo:GetAttacker() + local inflictor = dmginfo:GetInflictor() + + --DbgPrint("ScaleNPCDamage -> Attacker: " .. tostring(attacker) .. ", Inflictor: " .. tostring(inflictor)) + + -- For the lazy matt to test things more quickly. + if attacker:IsPlayer() then + --dmginfo:ScaleDamage(100) + if not IsValid(npc:GetEnemy()) then + DbgPrint("Making the attacker the NPC enemy") + npc:SetEnemy(attacker) + end + end + + self:ApplyCorrectedDamage(dmginfo) + + local hitgroupScale = HITGROUP_SCALE[hitgroup] or function() return 1.0 end + + if dmginfo:IsDamageType(DMG_BLAST) then + + else + + if hitgroup == HITGROUP_GEAR then + dmginfo:SetDamage(0.1) + return + else + local scale = hitgroupScale() + --DbgPrint("Scaling damage with: " .. scale) + dmginfo:ScaleDamage( scale ) + end + + local difficulty = game.GetSkillLevel() + if difficulty == 3 then + dmginfo:ScaleDamage( 0.7 ) + end + + end + + --DbgPrint("ScaleNPCDamage -> Applying " .. dmginfo:GetDamage() .. " damage to: " .. tostring(npc)) + + end + + function GM:RegisterNPC(npc) + + -- Enable lag compensation on NPCs + npc:SetLagCompensated(true) + + self.EnemyNPCs = self.EnemyNPCs or {} + + local gametype = self:GetGameType() + + if gametype and gametype.ClassesEnemyNPC and gametype.ClassesEnemyNPC[npc:GetClass()] == true then + table.insert(self.EnemyNPCs, npc) + end + + self:AdjustNPCDifficulty(npc) + + if npc:GetClass() == "npc_combine_s" then + + -- HACKHACK: I'm guessing garry removed loading skins based on their weapons at some point. + if npc:GetInternalVariable("additionalequipment") == "ai_weapon_shotgun" then + npc:SetSkin(1) + end + + end + + npc:SetCustomCollisionCheck(true) + + end + + function GM:OnNPCKilled(npc, attacker, inflictor) + local ply = nil + if IsValid(attacker) and attacker:IsPlayer() then + ply = attacker + elseif IsValid(inflictor) and inflictor:IsPlayer() then + ply = inflictor + end + if IsValid(ply) then + if IsFriendEntityName(npc:GetClass()) then + ply:AddFrags(-1) + else + ply:AddFrags(1) + end + end + + self:RegisterNPCDeath(npc, attacker, inflictor) + + BaseClass.OnNPCKilled(self, npc, attacker, inflictor) + end + + local function GetClosestPlayer(pos, minRange) + -- Hunt closest player. + local minDist = minRange + local ply + for _,v in pairs(player.GetAll()) do + if bit.band(v:GetFlags(), FL_NOTARGET) ~= 0 then + continue + end + local dist = v:GetPos():Distance(pos) + if dist < minDist then + minDist = dist + ply = v + end + end + return ply + end + + local IDLE_SCHEDULES = + { + SCHED_COMBAT_PATROL, + SCHED_PATROL_RUN, + SCHED_COMBAT_STAND, + SCHED_COMBAT_SWEEP, + SCHED_COMBAT_WALK, + } + + function GM:NPCThink() + + local curTime = CurTime() + + self.NextNPCThink = self.NextNPCThink or curTime + + if curTime < self.NextNPCThink then + return + end + + self.NextNPCThink = curTime + 0.1 + + local precriminal = false + for _,v in pairs(ents.FindByClass("env_global")) do + local state = v:GetInternalVariable("globalstate") + if isstring(state) and state == "gordon_precriminal" then + --DbgPrint("Gordon precriminal") + precriminal = true + end + end + + -- Don't chase players if they are not criminals. + if precriminal == true then + return + end + + self.IdleEnemyNPCs = {} + + for k,v in pairs(self.EnemyNPCs or {}) do + + if not IsValid(v) or not v:IsNPC() then + --self.EnemyNPCs[k] = nil + continue + end + + --[[ + local enemy = v:GetEnemy() + if IsValid(enemy) then + if v:VisibleVec(enemy:GetPos()) == false then + --DbgPrint("Enemy is not visible") + --v:SetEnemy(nil) + --v:SetTarget(v) + --v:ClearSchedule() + --v:SetSchedule(SCHED_IDLE_STAND) + end + end + ]] + + local idleNPC = v:IsCurrentSchedule(SCHED_ALERT_STAND) or + v:IsCurrentSchedule(SCHED_IDLE_STAND) or + v:IsCurrentSchedule(SCHED_FAIL) or + v:IsCurrentSchedule(SCHED_COMBAT_STAND) + + if idleNPC == false then + continue + end + + --DbgPrint("Found idle NPC: " .. tostring(v)) + + local npc = v + table.insert(self.IdleEnemyNPCs, npc) + npc:SetSchedule(SCHED_COMBAT_PATROL) + + end + + end + +end + +function GM:NotifyNPCFootsteps( ply, pos, foot, sound, volume) + + for _,npc in pairs(self.IdleEnemyNPCs or {}) do + + if not IsValid(npc) then + continue + end + + local dist = npc:GetPos():Distance(pos) + if dist < 1000 then + npc:SetLastPosition(pos) + npc:SetSchedule(SCHED_FORCED_GO) + end + + end + +end diff --git a/gamemode/sh_lambda_player.lua b/gamemode/sh_lambda_player.lua new file mode 100644 index 00000000..8cdf5e2d --- /dev/null +++ b/gamemode/sh_lambda_player.lua @@ -0,0 +1,1492 @@ +if SERVER then + AddCSLuaFile() + util.AddNetworkString("LambdaPlayerEnableRespawn") +end + +local DbgPrint = GetLogging("Player") + +DEFINE_BASECLASS( "gamemode_base" ) + +local SUIT_DEVICE_BREATHER = 1 +local SUIT_DEVICE_SPRINT = 2 +local SUIT_DEVICE_FLASHLIGHT = 3 + +local sv_infinite_aux_power = GetConVar("sv_infinite_aux_power") + +if SERVER then + + function GM:CanPlayerSuicide(ply) + + if ply:Alive() == false then + return false + end + + if ply:IsPositionLocked() then + return false + end + + return true + + end + + function GM:PlayerDisconnected(ply) + + if ply.LambdaPlayerData then + --PLAYER_ROLES_TAKEN[ply.LambdaPlayerData.Id] = nil + else + DbgPrint("Disconnected without LambdaPlayerData assigned, bug?") + end + + if IsValid(ply.TrackerEntity) then + ply.TrackerEntity:Remove() + end + + return BaseClass.PlayerDisconnected(self, ply) + + end + + function GM:SetPlayerCheckpoint(checkpoint) + DbgPrint("Assigned new checkpoint to: " .. tostring(checkpoint)) + self.CurrentCheckpoint = checkpoint + end + + function GM:SetupPlayerVisibility(ply, viewEnt) + + end + + function GM:PlayerInitialSpawn(ply) + + DbgPrint("GM:PlayerInitialSpawn") + + self:HandlePlayerConnect(ply:SteamID(), ply:Nick(), ply:EntIndex(), ply:IsBot(), ply:UserID()) + self:IncludePlayerInRound(ply) + + local model = "models/player/riot.mdl" + local name = "!player" -- Some stuff will fail if this is not set, not everything is ported. + local gender = "male" + + local hash = tonumber(util.CRC(ply:SteamID64() or "LOCALPLAYER")) + math.randomseed(hash * 4) -- * 4 because im special! :v + + -- We pick something random. + local genders = { "male", "female" } + gender = genders[math.random(1, #genders)] + + local index = "0" .. tostring(math.random(1, 5)) + + model = gender .. "_" .. index .. ".mdl" + name = "!player" + + ply.LambdaPlayerData = + { + Gender = gender, + Name = name, + Model = model, + } + + local transitionData = self:GetPlayerTransitionData(ply) + if transitionData ~= nil then + ply:SetFrags(transitionData.Frags) + ply:SetDeaths(transitionData.Deaths) + end + + DbgPrint("Gender: " .. gender) + DbgPrint("Model: " .. model) + DbgPrint("Unique: " .. tostring(unique)) + + ply:SetNWString("Gender", gender) + ply:SetName(name) -- Some thing are triggered between PlayerInitialSpawn and PlayerSpawn + ply:SetInactive(true) + + BaseClass.PlayerInitialSpawn( self, ply ) + + end + + function GM:PlayerSelectSpawn(ply) + + DbgPrint("PlayerSelectSpawn") + + -- Check if players reached a checkpoint. + if self.CurrentCheckpoint ~= nil and IsValid(self.CurrentCheckpoint) then + return self.CurrentCheckpoint + end + + local spawnpoints = ents.FindByClass("info_player_start") + local spawnpoint = nil + + for _,v in pairs(spawnpoints) do + + -- Initial spawnpoint if none set. + spawnpoint = spawnpoint or v + + -- If set by us then this is the absolute. + if v.MasterSpawn == true then + DbgPrint("Spawn using MasterSpawn variable: " .. tostring(v)) + spawnpoint = v + break + end + + -- If master flag is set it has priority. + if v:HasSpawnFlags(1) then + spawnpoint = v + end + + end + + DbgPrint("Select spawnpoint for player: " .. tostring(ply) .. ", spawn: " .. tostring(spawnpoint)) + + return spawnpoint + + end + + function GM:PlayerSetModel(ply) + + DbgPrint("GM:PlayerSetModel") + + local mdl = "models/player" + if ply:IsSuitEquipped() then + mdl = mdl .. "/group03/" .. ply.LambdaPlayerData.Model + else + mdl = mdl .. "/group01/" .. ply.LambdaPlayerData.Model + end + + ply:SetModel(mdl) + + end + + function GM:PlayerLoadout(ply) + + DbgPrint("PlayerLoadout: " .. tostring(ply)) + + ply.LambdaDisablePickupDuplication = true + + local transitionData = ply.TransitionData + if transitionData ~= nil and transitionData.Include == true then + + for _,v in pairs(ply.TransitionData.Weapons) do + ply:Give(v.Class) + ply:SetAmmo(v.Ammo1.Count, v.Ammo1.Id) + ply:SetAmmo(v.Ammo2.Count, v.Ammo2.Id) + if v.Active then + ply.ScheduledActiveWeapon = v.Class + end + end + + ply:SetHealth(ply.TransitionData.Health) + ply:SetArmor(ply.TransitionData.Armor) + + if ply.TransitionData.Suit then + ply:EquipSuit() + else + ply:RemoveSuit() + end + + else + -- Weapons + for k,v in pairs(self.MapScript.DefaultLoadout.Weapons) do + ply:Give(v) + end + + -- Ammo + for k,v in pairs(self.MapScript.DefaultLoadout.Ammo) do + ply:GiveAmmo(v, k, true) + end + + -- Armor + ply:SetArmor(self.MapScript.DefaultLoadout.Armor) + + -- HEV + if self.MapScript.DefaultLoadout.HEV then + ply:EquipSuit() + else + ply:RemoveSuit() + end + + end + + ply.LambdaDisablePickupDuplication = false + + end + + function GM:PlayerSpawn(ply) + + DbgPrint("GM:PlayerSpawn") + + if self.WaitingForRoundStart == true or self:IsRoundRestarting() == true then + ply:KillSilent() + return + end + + ply:EndSpectator() + + net.Start("LambdaPlayerEnableRespawn") + net.WriteUInt(ply:EntIndex(), 8) + net.WriteBool(false) + net.Send(ply) + + -- Ensure we keep it. + local ply = ply + + if not IsValid(ply.TrackerEntity) then + ply.TrackerEntity = ents.Create("lambda_player_tracker") + end + + -- Lets remove whatever the player left on vehicles behind before he got killed. + self:RemovePlayerVehicles(ply) + + -- We call this first in order to call PlayerLoadout, once we enter a vehicle we can not + -- get any weapons. + BaseClass.PlayerSpawn(self, ply) + + if self.MapScript.PrePlayerSpawn ~= nil then + self.MapScript:PrePlayerSpawn(ply) + end + + ply.LambdaSpawnTime = CurTime() + + -- Should we really do this? + ply:SetName(ply.LambdaPlayerData.Name) + ply:SetupHands() + ply:SetTeam(LAMBDA_TEAM_ALIVE) + ply:SetShouldServerRagdoll(false) + ply:SetCustomCollisionCheck(true) + + ply:SetSuitPower(100) + ply:SetSuitEnergy(100) + ply:SetGeigerRange(1000) + ply:SetStateSprinting(false) + ply:SetSprinting(false) + ply:SetDuckSpeed(0.4) + ply:SetUnDuckSpeed(0.2) + ply:SetInactive(true) + + ply:SetRunSpeed(lambda_sprintspeed:GetInt()) -- TODO: Put this in a convar. + ply:SetWalkSpeed(lambda_normspeed:GetInt()) + + local transitionData = ply.TransitionData + + if transitionData ~= nil then + + -- We keep those. + ply:SetFrags(transitionData.Frags) + ply:SetDeaths(transitionData.Deaths) + + if transitionData.Include == true then + DbgPrint("Player " .. tostring(ply) .. " uses transition data!") + ply:SetPos(transitionData.Pos) + ply:SetAngles(transitionData.Ang) + ply:SetEyeAngles(transitionData.EyeAng) + end + + if transitionData.Vehicle ~= nil and transitionData.Include == true then + + local vehicle = self:FindEntityByTransitionReference(transitionData.Vehicle) + if IsValid(vehicle) then + DbgPrint("Putting player " .. tostring(ply) .. " back in vehicle: " .. tostring(vehicle)) + + -- Sometimes does crazy things to the view angles, this only helps to a certain amount. + vehicle:SetVehicleEntryAnim(false) + vehicle.ResetVehicleEntryAnim = true + + local eyeAng = vehicle:WorldToLocalAngles(transitionData.EyeAng) + + -- NOTE: Workaround as they seem to not get any weapons if we enter the vehicle this frame. + util.RunNextFrame(function() + if IsValid(ply) and IsValid(vehicle) then + ply:SetPos(vehicle:GetPos()) + ply:EnterVehicle(vehicle) + ply:SetEyeAngles(eyeAng) -- We call it again because the vehicle sets it to how you entered. + end + end) + + else + DbgPrint("Unable to find player " .. tostring(ply) .. " vehicle: " .. tostring(transitionData.Vehicle)) + end + end + + end + + if SERVER then + if ply.ScheduledActiveWeapon ~= nil then + ply:SelectWeapon(ply.ScheduledActiveWeapon) + ply.ScheduledActiveWeapon = nil + else + self:SelectBestWeapon(ply) + end + end + + util.RunNextFrame(function() + if SERVER then + self:CheckPlayerNotStuck(ply) + end + if self.MapScript.PostPlayerSpawn ~= nil then + self.MapScript:PostPlayerSpawn(ply) + end + end) + + ply.TransitionData = nil -- Make sure we erase it because this only happens on a new round. + + -- Adjust difficulty, we want later some dynamic system that adjusts depending on the players. + self:AdjustDifficulty() + + ply.TrackerEntity:AttachToPlayer(ply) + + end + + function GM:CheckPlayerNotStuck(ply) + + -- Thats all there is to it, hopefully. + if ply:InVehicle() then + return + end + + util.PlayerUnstuck(ply) + + end + + function GM:DoPlayerDeath(ply, attacker, dmg) + + if ply.LastWeaponsDropped ~= nil then + for _,v in pairs(ply.LastWeaponsDropped) do + if IsValid(v) and v:GetOwner() ~= ply then + v:Remove() + end + end + end + + local weps = ply:GetWeapons() + local activeWep = ply:GetActiveWeapon() + if IsValid(activeWep) then + table.insert(weps, activeWep) + end + + ply.LastWeaponsDropped = {} + for _,v in pairs(weps) do + + local ammoType1 = v:GetPrimaryAmmoType() + local ammoType2 = v:GetSecondaryAmmoType() + + -- Only drop relevant stuff, except the crowbar. + if ply:GetAmmoCount(ammoType1) == 0 and ply:GetAmmoCount(ammoType2) == 0 and v:GetClass() ~= "weapon_crowbar" then + continue + end + + ply:DropWeapon(v) + + v.PreventDuplication = true + + if v:GetClass() == "weapon_crowbar" then + -- Damage players if it gets thrown their way + v:SetSolidFlags(FSOLID_CUSTOMBOXTEST) + v:SetCollisionGroup(COLLISION_GROUP_PLAYER) + end + + table.insert(ply.LastWeaponsDropped, v) + end + + local createRagdoll = true + + -- Because the weapons are attached to the player at the time the explosion happened they did + -- not receive the force, we gonna apply it so things go flying. + if dmg:IsExplosionDamage() then + + local dmgPos = dmg:GetDamagePosition() + + local force = dmg:GetDamageForce() * 0.05 + + for _,v in ipairs(ply.LastWeaponsDropped) do + local phys = v:GetPhysicsObject() + if IsValid(phys) then + phys:AddVelocity(force * Vector(math.random(-10, 10), math.random(-10, 10), 1)) + end + end + + --[[ + -- Removed for now, actually working on getting the gibs models. + if ply:GetPos():Distance(dmgPos) < 128 and dmg:GetDamageForce():Length() > 256 then + createRagdoll = false + self:CreatePlayerGibs(ply, force) + end + ]] + + end + + if createRagdoll == true then + ply:CreateRagdoll() + end + + ply:AddDeaths( 1 ) + + if attacker:IsValid() and attacker:IsPlayer() then + + if attacker == ply then + attacker:AddFrags( -1 ) + else + attacker:AddFrags( 1 ) + end + + end + + end + + function GM:PlayerDeath(victim, attacker, inflictor) + + local effectdata = EffectData() + effectdata:SetOrigin( victim:GetPos() ) + effectdata:SetNormal( Vector(0,0,1) ) + effectdata:SetRadius(50) + effectdata:SetEntity(victim) + util.Effect( "lambda_death", effectdata, true ) + + self:RegisterPlayerDeath(victim, attacker, inflictor) + + BaseClass.PlayerDeath(self, victim, attacker, inflictor) + + end + + function GM:PostPlayerDeath(ply) + + DbgPrint("GM:PostPlayerDeath") + + ply.DeathTime = GetSyncedTimestamp() + ply:SetTeam(LAMBDA_TEAM_DEAD) + ply:LockPosition(false, false) + + local timeout = math.Clamp(lambda_max_respawn_timeout:GetInt(), 1, 255) + local alive = #team.GetPlayers(LAMBDA_TEAM_ALIVE) + local total = #player.GetAll() + local timeoutAmount = math.Round(alive / total * timeout) + + ply.RespawnTime = ply.DeathTime + timeoutAmount + + if self:IsRoundRestarting() == false and alive > 0 then + net.Start("LambdaPlayerEnableRespawn") + net.WriteUInt(ply:EntIndex(), 8) + net.WriteBool(true) + net.WriteFloat(ply.DeathTime) + net.WriteUInt(timeoutAmount, 8) + net.Send(ply) + end + + end + + function GM:PlayerDeathThink(ply) + + --DbgPrint("GM:PlayerDeathThink") + + if self:IsRoundRestarting() then + --DbgPrint("Round is restarting") + return false + end + + if self.WaitingForRoundStart == true or self:IsRoundRestarting() == true then + --DbgPrint("Can not spawn before players available") + return false + end + + local elapsed = GetSyncedTimestamp() - ply.DeathTime + + if elapsed >= 5 and ply:IsSpectator() == false then + ply:SetSpectator() + end + + if GetSyncedTimestamp() < ply.RespawnTime then + return false + end + + if ply:KeyReleased(IN_JUMP) then + ply:Spawn() + end + + return true + + end + + function GM:PlayerSwitchFlashlight(ply, enabled) + + if not ply:IsSuitEquipped() then + return false + end + + return true + + end + + function GM:Move(ply, mv) + + -- Whoever stumbles upon this code might ask what this is all about. + -- + -- Its best shown by going to d1_town_01 to the part where you have to lift up the + -- vehicles, you have to walk on them and them and jump off which is close to impossible + -- without the code below, feel free to comment it in order to see the difference. + local groundEnt = ply:GetGroundEntity() + + if mv:KeyDown(IN_JUMP) and groundEnt ~= NULL and IsValid(groundEnt) then + local class = groundEnt:GetClass() + if class == "prop_physics" or class == "func_physbox" then + local phys = groundEnt:GetPhysicsObject() + if IsValid(phys) and phys:IsMotionEnabled() == true then + local currentVel = phys:GetVelocity() + phys:EnableMotion(false) + -- Enable it back next frame + util.RunNextFrame(function() + if IsValid(groundEnt) then + local phys = groundEnt:GetPhysicsObject() + if IsValid(phys) then + phys:EnableMotion(true) + phys:SetVelocity(currentVel) + end + end + end) + end + end + end + + end + + function GM:LimitPlayerAmmo(ply) + + local curTime = CurTime() + + ply.LastAmmoCheck = ply.LastAmmoCheck or curTime + + if curTime - ply.LastAmmoCheck < 0.100 then + return + end + + ply.LastAmmoCheck = curTime + + for k,v in pairs(self.MAX_AMMO_DEF) do + local count = ply:GetAmmoCount(k) + local maxCount = v:GetInt() + if count > maxCount then + ply:SetAmmo(maxCount, k) + end + end + + end + + function GM:AllowPlayerPickup( ply, ent ) + + ply.LastPickupTime = ply.LastPickupTime or 0 + + local pickupDelay = lambda_pickup_delay:GetFloat() + local curTime = CurTime() + if curTime - ply.LastPickupTime < pickupDelay then + return false + end + + ply.LastPickupTime = curTime + + return true + + end + + function GM:PlayerCanPickupItem(ply, item) + + if ply.LambdaDisablePickupDuplication == true then + return true + end + + -- Maps have the annoying template spawner for all weapons so give it a slight chance to pick it up + -- those items arent usually cleaned up so let the player have it, for now.. + if CurTime() - ply.LambdaSpawnTime <= 1 then + return true + end + + local class = item:GetClass() + local res = true + + -- Dont pickup stuff if we dont need it. + if class == "item_health" or class == "item_healthvial" or class == "item_healthkit" then + if ply:Health() >= ply:GetMaxHealth() then + return false + end + elseif class == "item_battery" then + if ply:Armor() >= 100 then + return false + end + elseif class == "item_suit" then + if ply:IsSuitEquipped() == true then + return false + else + return true + end + end + + -- Limit the ammo to pickup based on the sk convars. + local skill = tostring(game.GetSkillLevel()) + + local ammo = self.ITEM_DEF[class] + if ammo then + local cur = ply:GetAmmoCount(ammo.Type) + local amount = ammo[skill] + local max = ammo.Max:GetInt() + if cur + amount > max then + --DbgPrint("Limited ammo pickup: " .. tostring(item)) + res = false + end + end + + return res + + end + + function GM:WeaponEquip(wep) + + local wep = wep + + util.RunNextFrame(function() + if not IsValid(wep) then + return + end + + local ply = wep:GetOwner() + if IsValid(ply) then + + if wep.CreatedForPlayer == ply then + ply.WeaponDuplication[wep.OriginalWeapon] = nil + end + if ply.LastDuplicatedWeapon == wep then + ply:SelectWeapon(wep:GetClass()) + end + + for k,v in pairs(wep.EntityOutputs or {}) do + util.SimpleTriggerOutputs(v, ply, ply, wep ) + end + + ply:EmitSound("Player.PickupWeapon") + end + end) + + end + + function GM:PlayerCanPickupWeapon(ply, wep) + + --DbgPrint("PlayerCanPickupWeapon", ply, wep) + + if ply.LambdaDisablePickupDuplication == true then + return true + end + + local class = wep:GetClass() + + if class == "weapon_frag" then + if ply:GetAmmoCount("grenade") < sk_max_grenade:GetInt() then + return true + end + elseif class == "weapon_annabelle" then + return false -- Not supposed to have this. + end + + -- Maps have the annoying template spawner for all weapons so give it a slight chance to pick it up + -- those items arent usually cleaned up so let the player have it, for now.. + if CurTime() - ply.LambdaSpawnTime <= 2 then + return true + end + + if ply:HasWeapon(wep:GetClass()) then + + local clip1 = wep:Clip1() + if clip1 > 5 then + local rest = clip1 - 5 + ply:GiveAmmo(rest, wep:GetPrimaryAmmoType(), false) + wep:SetClip1(5) + end + + return false + + end + + if wep.PreventDuplication == true then + return true + end + + ply.WeaponDuplication = ply.WeaponDuplication or {} + + if ply.WeaponDuplication[wep] == true then + --DbgPrint("Already duplicating this weapon") + return false + end + + if wep.CreatedForPlayer ~= nil then + if wep.CreatedForPlayer == ply then + -- This was specifically created for the player, allow it. + --DbgPrint("Allowing to pickup") + return true + else + -- Lets not duplicate a duplicate + return false + end + end + + DbgPrint("Duplicating new player weapon") + + ply.WeaponDuplication[wep] = true + + local copy = ents.Create(class) + copy:SetPos(wep:GetPos()) + copy:SetAngles(wep:GetAngles()) + copy:SetClip1(wep:Clip1()) + copy:SetClip2(wep:Clip2()) + copy:SetName(wep:GetName()) + copy.CreatedForPlayer = ply + copy.OriginalWeapon = wep + -- Copy the outputs, some of the maps use them to trigger events. + copy.EntityOutputs = table.Copy(wep.EntityOutputs or {}) + copy:Spawn() + + -- Only ever select the last duplicated weapon. + ply.LastDuplicatedWeapon = copy + + return false + + end + + local sk_player_head = GetConVar("sk_player_head") + local sk_player_chest = GetConVar("sk_player_chest") + local sk_player_stomach = GetConVar("sk_player_stomach") + local sk_player_arm = GetConVar("sk_player_arm") + local sk_player_leg = GetConVar("sk_player_leg") + + local HITGROUP_SCALE = + { + [HITGROUP_GENERIC] = function() return 1.0 end, + [HITGROUP_HEAD] = function() return sk_player_head:GetFloat() end, + [HITGROUP_CHEST] = function() return sk_player_chest:GetFloat() end, + [HITGROUP_STOMACH] = function() return sk_player_stomach:GetFloat() end, + [HITGROUP_LEFTARM] = function() return sk_player_arm:GetFloat() end, + [HITGROUP_RIGHTARM] = function() return sk_player_arm:GetFloat() end, + [HITGROUP_LEFTLEG] = function() return sk_player_leg:GetFloat() end, + [HITGROUP_RIGHTLEG] = function() return sk_player_leg:GetFloat() end, + } + + function GM:ScalePlayerDamage(ply, hitgroup, dmginfo) + + DbgPrint("ScalePlayerDamage", ply, hitgroup) + + self:ApplyCorrectedDamage(dmginfo) + + local hitgroupScale = HITGROUP_SCALE[hitgroup] or function() return 1.0 end + + if hitgroup == HITGROUP_GEAR then + dmginfo:SetDamage(0.1) + return + else + local scale = hitgroupScale() + --DbgPrint("Scaling damage with: " .. scale) + dmginfo:ScaleDamage( scale ) + end + + if dmginfo:IsDamageType(DMG_BLAST) then + dmginfo:ScaleDamage( 2 ) + end + + if dmginfo:GetDamage() > 0 then + --DbgPrint("ScalePlayerDamage: " .. tostring(ply)) + self:EmitPlayerHurt(dmginfo:GetDamage(), ply, hitgroup) + end + + -- Reset water damage + if ply.IsDrowning ~= true then + ply.WaterDamage = 0 + end + + if ply:IsPositionLocked() == true then + dmginfo:ScaleDamage(0) + end + + end + + function GM:GetFallDamage( ply, speed ) + speed = speed - 480 + return speed * (100 / (1024-480)) + end + + function GM:EmitPlayerHurt(amount, ply, hitgroup) + + if ply:WaterLevel() == 3 then + return + end + + if ply:Health() - amount <= 0 then + -- Dead people dont say stuff + return + end + + if hitgroup == nil or hitgroup == HITGROUP_HEAD or hitgroup == HITGROUP_GEAR then + hitgroup = HITGROUP_GENERIC + end + + local gender = ply.LambdaPlayerData.Gender + local hurtsounds = self.HurtSounds[gender][hitgroup] + + ply.NextHurtSound = ply.NextHurtSound or 0 + + local curTime = CurTime() + if curTime - ply.NextHurtSound >= 2 then + local snd = table.Random(hurtsounds) + ply:EmitSound(snd) + ply.NextHurtSound = curTime + 2 + end + + end + + +else -- CLIENT + + function GM:CalcView( ply, pos, angles, fov ) + + local view = {} + + view.origin = pos + view.angles = angles + view.fov = fov + view.drawviewer = false + + return view + + end + + function GM:NotifyPlayerRespawn(state, entIndex, deathTime, timeout) + + local localPly = LocalPlayer() + if Entity(entIndex) == localPly then + GAMEMODE:EnableRespawnHUD(state, deathTime, timeout) + end + + end + + net.Receive("LambdaPlayerEnableRespawn", function(len) + + local entIndex = net.ReadUInt(8) + local state = net.ReadBool() + local deathTime = 0 + local timeout = 0 + + if state == true then + deathTime = net.ReadFloat() + timeout = net.ReadUInt(8) + end + + GAMEMODE:NotifyPlayerRespawn(state, entIndex, deathTime, timeout) + + end) + +end + +local GEIGER_DELAY = 0.25 +local GEIGER_SOUND_DELAY = 0.06 + +function GM:UpdateGeigerCounter(ply) + + local curTime = CurTime() + + if SERVER then + + ply.GeigerDelay = ply.GeigerDelay or curTime + + if curTime < ply.GeigerDelay then + return + end + + ply.GeigerDelay = curTime + GEIGER_DELAY + + local range = math.Clamp(math.floor(ply:GetNearestRadiationRange() / 4), 0, 255) + + if ply:InVehicle() then + range = math.Clamp(range * 4, 0, 1000) + end + + if math.random(0, 5) == 0 then + ply:SetGeigerRange(1000) + ply:SetNearestRadiationRange(1000, true) + else + ply:SetGeigerRange(range) + end + + else + + if ply:Alive() == false or ply ~= LocalPlayer() then + return + end + + ply.GeigerSoundDelay = ply.GeigerSoundDelay or curTime + + if curTime < ply.GeigerSoundDelay then + return + end + + ply.GeigerSoundDelay = curTime + GEIGER_SOUND_DELAY + + local range = ply:GetGeigerRange() * 4 + --DbgPrint(range) + if range == 0 or range >= 1000 then + return + end + + local pct = 0 + local vol = 0 + local highSnd = false + + if range > 800 then + pct = 0 + elseif range > 600 then + pct = 2 + vol = 0.2 + elseif range > 500 then + pct = 4 + vol = 0.25 + elseif range > 400 then + pct = 8 + vol = 0.3 + highSnd = true + elseif range > 300 then + pct = 8 + vol = 0.35 + highSnd = true + elseif range > 200 then + pct = 28 + vol = 0.39 + highSnd = true + elseif range > 150 then + pct = 40 + vol = 0.40 + highSnd = true + elseif range > 100 then + pct = 60 + vol = 0.45 + highSnd = true + elseif range > 75 then + pct = 80 + vol = 0.45 + highSnd = true + elseif range > 50 then + pct = 90 + vol = 0.475 + else + pct = 95 + vol = 0.5 + end + + vol = (vol * (math.random(0, 127) / 255)) + 0.25 + + if math.random(0, 127) < pct then + local snd + if highSnd then + snd = "Geiger.BeepHigh" + else + snd = "Geiger.BeepLow" + end + --DbgPrint("EMITSOUND") + ply:EmitSound(snd, 75, 100, vol, CHAN_BODY) + + end + + end + +end + +local SUIT_SPRINT_DRAIN = 20.0 +local SUIT_FLASHLIGHT_DRAIN = 2.222 +local SUIT_BREATH_DRAIN = 6.7 +local SUIT_CHARGE_RATE = 12.5 +local SUIT_CHARGE_DELAY = 1.5 +local SUIT_ENERGY_CHARGE_RATE = 12.5 + +function GM:PlayerAllowSprinting(ply, inSprint) + + inSprint = inSprint or false + + if ply:IsSuitEquipped() == false then + return false + end + + if ply:WaterLevel() > 1 then + return false + end + + if ply:InVehicle() == true then + return false + end + + if ply:KeyDown(IN_DUCK) then + return false + end + + if ply:GetSuitPower() <= 0 then + return false + end + + return true + +end + +function GM:PlayerStartSprinting(ply, mv) + + --DbgPrint("PlayerStartSprinting: " .. tostring(ply)) + + ply:AddSuitDevice(SUIT_DEVICE_SPRINT) + + if CLIENT and IsFirstTimePredicted() then + local suitPower = ply:GetSuitPower() + if suitPower <= 0 then + ply:EmitSound("HL2Player.SprintNoPower") + return false + else + ply:EmitSound("HL2Player.SprintStart") + end + end + + ply:SetRunSpeed(lambda_sprintspeed:GetInt()) -- TODO: Put this in a convar. + ply:SetWalkSpeed(lambda_normspeed:GetInt()) + ply:SetSprinting(true) + + --DbgPrint("Sprint State: " .. tostring(ply:GetSprinting())) + +end + +function GM:PlayerEndSprinting(ply, mv) + + --DbgPrint("PlayerEndSprinting: " .. tostring(ply) ) + + ply:RemoveSuitDevice(SUIT_DEVICE_SPRINT) + ply:SetRunSpeed(lambda_normspeed:GetInt()) -- TODO: Put this in a convar. + ply:SetWalkSpeed(lambda_normspeed:GetInt()) + ply:SetSprinting(false) + +end + +function GM:StartCommand(ply, cmd) + + --DbgPrint("StartCommand", ply) + + if ply:IsPositionLocked() == true then + local vel = ply:GetVelocity() + vel.x = 0 + vel.y = 0 + vel.z = math.Clamp(vel.z, -2, 0) + ply:SetVelocity(vel) + cmd:ClearButtons() + cmd:ClearMovement() + return + end + + if cmd:KeyDown(IN_SPEED) == true and (ply:IsSuitEquipped() ~= true or ply:WaterLevel() >= 1) and ply:InVehicle() == false then + cmd:SetButtons(bit.band(cmd:GetButtons(), bit.bnot(IN_SPEED))) + end + + if cmd:KeyDown(IN_DUCK) then + ply:SetNW2Bool("InDuck", true) + else + ply:SetNW2Bool("InDuck", false) + end + +end + +function GM:SetupMove(ply, mv, cmd) + + --if not IsFirstTimePredicted() then return end + if ply:Alive() == false then + return + end + + local isSprinting = false + if ply.GetSprinting ~= nil then + isSprinting = ply:GetSprinting() + end + + if mv:KeyDown(IN_DUCK) and ply:IsOnGround() and isSprinting == true then + + self:PlayerEndSprinting(ply, mv) + ply:SetStateSprinting(false) + + end + + if mv:KeyDown(IN_SPEED) == true then + + --DbgPrint("Is Sprinting: " .. tostring(isSprinting)) + + if self:PlayerAllowSprinting(ply) == true and + isSprinting == false and + ply:GetStateSprinting() == false and + self:PlayerStartSprinting(ply, mv) ~= false + then + ply:SetStateSprinting(true) + end + + else + + if isSprinting == true then + --DbgPrint("IN_SPEED missing, stopped sprinting " .. tostring(isSprinting)) + self:PlayerEndSprinting(ply, mv, cmd) + end + + ply:SetStateSprinting(false) + + end + +end + +function GM:FinishMove(ply, mv) + + if (mv:GetButtons() ~= 0 or ply:IsBot()) and ply:GetLifeTime() > 0.1 and ply:IsInactive() == true then + DbgPrint(ply, "Player now active") + ply:SetInactive(false) + end + +end + +function GM:DrainSuit(ply, amount) + + local current = ply:GetSuitPower() + local res = true + + if ply:GetMoveType() == MOVETYPE_NOCLIP then + -- Dont do anything in this case + return true + end + + if sv_infinite_aux_power:GetBool() == true then + amount = 0 + end + + current = current - amount + + if current < 0 then + current = 0 + res = false + end + + ply:SetSuitPower(current) + + return res + +end + +function GM:ChargeSuitPower(ply, amount) + + local current = ply:GetSuitPower() + + current = current + amount + if current > 100.0 then + current = 100.0 + end + + ply:SetSuitPower(current) + ply:RemoveSuitDevice(SUIT_DEVICE_BREATHER) + ply:RemoveSuitDevice(SUIT_DEVICE_SPRINT) + +end + +function GM:ShouldChargeSuitPower(ply) + + --local flashlight = ply:FlashlightIsOn() -- Its just annoying. + local sprinting = ply:GetSprinting() + local inWater = ply:WaterLevel() >= 3 + local powerDrain = sprinting or inWater + + if powerDrain == true then + return false -- Something is draning power. + end + + local power = ply:GetSuitPower() + if power >= 100.0 then + return false -- Full + end + + local curTime = CurTime() + ply.NextSuitCharge = ply.NextSuitCharge or curTime + + if curTime < ply.NextSuitCharge then + return false + end + + --DbgPrint("Should Charge") + return true + +end + +function GM:UpdateSuit(ply, mv) + + if ply:IsSuitEquipped() == false then + return + end + + local frameTime = FrameTime() + local currentEnergy = ply:GetSuitEnergy() + + if ply:FlashlightIsOn() then + --powerLoad = powerLoad + SUIT_FLASHLIGHT_DRAIN + ply:AddSuitDevice(SUIT_DEVICE_FLASHLIGHT) + currentEnergy = currentEnergy - (SUIT_FLASHLIGHT_DRAIN * frameTime) + if currentEnergy <= 0 then + if SERVER then + ply:Flashlight(false) + end + ply:RemoveSuitDevice(SUIT_DEVICE_FLASHLIGHT) + end + else + currentEnergy = currentEnergy + (SUIT_ENERGY_CHARGE_RATE * frameTime) + ply:RemoveSuitDevice(SUIT_DEVICE_FLASHLIGHT) + end + + ply:SetSuitEnergy(currentEnergy) + + -- Check if we should recharge. + if self:ShouldChargeSuitPower(ply) == true then + + local amount = SUIT_CHARGE_RATE * frameTime + self:ChargeSuitPower(ply, amount) + + else + + local powerLoad = 0 + + if ply:GetSprinting() then + local pos = ply:GetAbsVelocity() + if math.abs(pos.x) > 0 or math.abs(pos.y) > 0 then + powerLoad = powerLoad + SUIT_SPRINT_DRAIN + end + end + + if ply:WaterLevel() >= 3 then + powerLoad = powerLoad + SUIT_BREATH_DRAIN + ply:AddSuitDevice(SUIT_DEVICE_BREATHER) + else + ply:RemoveSuitDevice(SUIT_DEVICE_BREATHER) + end + + if powerLoad > 0 and self:DrainSuit(ply, powerLoad * frameTime) == false then + ply.NextSuitCharge = CurTime() + SUIT_CHARGE_DELAY + if ply:GetSprinting() == true then + self:PlayerEndSprinting(ply, mv) + end + end + + end + +end + +local CHOKE_TIME = 1 +local WATER_HEALTH_RECHARGE_TIME = 3 + +function GM:PlayerCheckDrowning(ply) + + if not ply:Alive() or not ply:IsSuitEquipped() then + return + end + + ply.WaterDamage = ply.WaterDamage or 0 + + local curTime = CurTime() + + if ply:WaterLevel() ~= 3 then + + if ply.IsDrowning == true then + ply.IsDrowning = false + end + + if ply.WaterDamage > 0 then + + ply.NextWaterHealthTime = ply.NextWaterHealthTime or curTime + WATER_HEALTH_RECHARGE_TIME + + if ply:Health() >= 100 then + ply.WaterDamage = 0 + else + if ply.NextWaterHealthTime < curTime then + + ply.WaterDamage = ply.WaterDamage - 10 + if ply:Health() + 10 > 100 then + ply:SetHealth(100) + else + ply:SetHealth(ply:Health() + 10) + end + + ply.NextWaterHealthTime = curTime + WATER_HEALTH_RECHARGE_TIME + end + + end + + end + + else + + ply.NextChokeTime = ply.NextChokeTime or curTime + CHOKE_TIME + + if ply:GetSuitPower() == 0 and curTime > ply.NextChokeTime then + + if ply.IsDrowning ~= true then + ply.IsDrowning = true + ply.DrowningStartTime = CurTime() + ply.WaterDamage = 0 + end + + local dmgInfo = DamageInfo() + dmgInfo:SetDamage( 10 ) + dmgInfo:SetDamageType( DMG_DROWN ) + dmgInfo:SetInflictor( game.GetWorld() ) + dmgInfo:SetAttacker( game.GetWorld() ) + + ply:TakeDamageInfo( dmgInfo ) + + ply.WaterDamage = ply.WaterDamage + 10 + ply.NextChokeTime = curTime + CHOKE_TIME + + end + + end + +end + +function GM:PlayerTick(ply, mv) + + -- Predicted, must be called here. + self:UpdateSuit(ply, mv) + + if SERVER then + self:LimitPlayerAmmo(ply) + self:PlayerCheckDrowning(ply) + end + +end + +function GM:PlayerThink(ply) + + if SERVER then + -- I don't really like this, however there is no way to tell if we just equipped the suit + local prevSuitEquipped = ply.LambdaSuitEquipped or false + local suitEquipped = ply:IsSuitEquipped() + if suitEquipped == true and prevSuitEquipped == false then + self:PlayerSetModel(ply) + end + ply.LambdaSuitEquipped = suitEquipped + end + + --DbgPrint(CurTime()) + self:UpdateGeigerCounter(ply) + +end + +function GM:GravGunPickupAllowed(ply, ent) + + if ent:IsWeapon() and ent:GetClass() ~= "weapon_crowbar" then + return false + end + + do + return true + end + + --return BaseClass.GravGunPickupAllowed(ply, ent) +end + +function GM:GravGunPunt(ply, ent) + + if ent:IsWeapon() and ent:GetClass() ~= "weapon_crowbar" then + return false + end + + local playerVehicle = ply:GetVehicle() + if playerVehicle and IsValid(playerVehicle) then + if ent:IsVehicle() then + if ent.PassengerSeat == playerVehicle then + return false + end + end + end + + if ent:IsVehicle() then + util.RunNextFrame(function() + if not IsValid(ent) then + return + end + local phys = ent:GetPhysicsObject() + if not IsValid(phys) then + return + end + local force = phys:GetVelocity() + force = force * 0.000001 + phys:SetVelocity(force) + end) + end + + if ent:IsNPC() and IsFriendEntityName(ent:GetClass()) then + return false + end + + return BaseClass.GravGunPickupAllowed(ply, ent) + +end + +function GM:PlayerFootstep( ply, pos, foot, sound, volume, filter ) + + if ply:KeyDown(IN_WALK) then + return true + end + + if SERVER then + self:NotifyNPCFootsteps(ply, pos, foot, sound, volume ) + end + +end + +if SERVER then + + function GM:SelectBestWeapon(ply) + + -- Switch to a better weapon. + local weps = ply:GetWeapons() + local highestDmg = 0 + local bestWep = nil + + for k,v in pairs(weps) do + local ammo = ply:GetAmmoCount(v:GetPrimaryAmmoType()) + if bestWep == nil then + bestWep = v + end + if ammo ~= 0 then + local dmgCVar = self.PLAYER_WEAPON_DAMAGE[v:GetClass()] + if dmgCVar ~= nil then + local dmg = dmgCVar:GetFloat() + if dmg > highestDmg then + bestWep = v + highestDmg = dmg + end + end + end + end + + if bestWep ~= nil then + DbgPrint(bestWep) + ply:SelectWeapon(bestWep:GetClass()) + end + + end + +end + +function GM:OnPlayerAmmoDepleted(ply, wep) + + DbgPrint("Ammo Depleted: " .. tostring(ply) .. " - " .. tostring(wep) ) + + if SERVER then + self:SelectBestWeapon(ply) + end + + if CLIENT then + ply:EmitSound("hl1/fvox/ammo_depleted.wav", 75, 100, 0.5) + end + +end + +function GM:PlayerNoClip(ply, desiredState) + + local sv_cheats = GetConVar("sv_cheats") + if desiredState == false then + return true + elseif sv_cheats:GetBool() == true then + return true + end + +end diff --git a/gamemode/sh_mapdata.lua b/gamemode/sh_mapdata.lua new file mode 100644 index 00000000..1eaa9339 --- /dev/null +++ b/gamemode/sh_mapdata.lua @@ -0,0 +1,170 @@ +AddCSLuaFile() + +local function ReadLump(f) + + local data = {} + data.pos = f:ReadLong() + data.len = f:ReadLong() + data.ver = f:ReadLong() + data.reserved = f:Read(4) + + return data + +end + +local function ReadHeader(f) + + local header = {} + header.sig = f:Read(4) + if header.sig ~= "VBSP" then + ErrorNoHalt("Signature mismatch expected 'VBSP' got '" .. header.signature .. "'") + return nil + end + + header.ver = f:ReadLong() + header.lumps = {} + for i = 0, 63 do + header.lumps[i] = ReadLump(f) + end + + return header + +end + +local function ReadEntities(header, f) + + local pos = header.lumps[0].pos + local len = header.lumps[0].len + + f:Seek(pos) + + local data = f:Read(len) + local entities = {} + + for s in string.gmatch(data, "%{.-%}") do + -- We can not use util.KeyValuesToTable because of multiple keys with same name. + local entData = util.KeyValuesToTablePreserveOrder('"xd"\r\n' .. s) + + -- Lets create a more efficient table. + local newData = {} + for _,v in pairs(entData) do + local entry = newData[v.Key] + if entry ~= nil then + if istable(entry) then + table.insert(entry, v.Value) + else + entry = { entry, v.Value } + end + else + entry = v.Value + end + newData[v.Key] = entry + end + + table.insert(entities, newData) + end + + return entities + +end + +local function ReadBSPFormat(f) + + local header = ReadHeader(f) + if header == nil then + return nil + end + + local entities = ReadEntities(header, f) + if entities == nil then + return nil + end + + return { Header = header, Entities = entities } + +end + +local function LoadMapData() + + local map = game.GetMap() + + local f = file.Open("maps/" .. map .. ".bsp", "rb", "GAME") + + if f == nil then + return nil + end + + local res = ReadBSPFormat(f) + + f:Close() + + return res + +end + +local mapdata = nil + +function game.GetMapData() + + if mapdata == nil then + mapdata = LoadMapData() + end + + return mapdata + +end + +function game.FindEntityInMapData(name) + + local mapdata = game.GetMapData() + if mapdata == nil then + return nil + end + + for _,v in pairs(mapdata.Entities) do + local targetname = v["targetname"] + if targetname and isstring(targetname) and targetname:iequals(name) then + return v + end + end + + return nil + +end + + +function game.FindEntityByGlobalNameInMapData(name) + + local mapdata = game.GetMapData() + if mapdata == nil then + return nil + end + + for _,v in pairs(mapdata.Entities) do + local targetname = v["globalname"] + if targetname and isstring(targetname) and targetname:iequals(name) then + return v + end + end + + return nil + +end + +function game.FindEntityByClassInMapData(class) + + local mapdata = game.GetMapData() + if mapdata == nil then + return nil + end + + for _,v in pairs(mapdata.Entities) do + local classname = v["classname"] + if classname and isstring(classname) and classname:iequals(class) then + return v + end + end + + return nil + +end diff --git a/gamemode/sh_npc_extend.lua b/gamemode/sh_npc_extend.lua new file mode 100644 index 00000000..a2a3862b --- /dev/null +++ b/gamemode/sh_npc_extend.lua @@ -0,0 +1,67 @@ +if SERVER then + AddCSLuaFile() +end + +local DbgPrint = GetLogging("NPCExt") +local META_NPC = FindMetaTable("NPC") + +if SERVER then + + -- Sadly theres only GetHull on the Player metatable, so this is a neccesary evil. + local HULLS = + { + [HULL_HUMAN] = { Vector(-13,-13, 0), Vector(13, 13, 72), Vector(-8,-8, 0), Vector( 8, 8, 72) }, + [HULL_SMALL_CENTERED] = { Vector(-20,-20, -20), Vector(20, 20, 20), Vector(-12,-12,-12), Vector(12, 12, 12) }, + [HULL_WIDE_HUMAN] = { Vector(-15,-15, 0), Vector(15, 15, 72), Vector(-10,-10, 0), Vector(10, 10, 72) }, + [HULL_TINY] = { Vector(-12,-12, 0), Vector(12, 12, 24), Vector(-12,-12, 0), Vector(12, 12, 24) }, + [HULL_WIDE_SHORT] = { Vector(-35,-35, 0), Vector(35, 35, 32), Vector(-20,-20, 0), Vector(20, 20, 32) }, + [HULL_MEDIUM] = { Vector(-16,-16, 0), Vector(16, 16, 64), Vector(-8,-8, 0), Vector(8, 8, 64) }, + [HULL_TINY_CENTERED] = { Vector(-8, -8, -4), Vector(8, 8, 4), Vector(-8,-8, -4), Vector( 8, 8, 4) }, + [HULL_LARGE] = { Vector(-40,-40, 0), Vector(40, 40, 100), Vector(-40,-40, 0), Vector(40, 40, 100) }, + [HULL_LARGE_CENTERED] = { Vector(-38,-38, -38), Vector(38, 38, 38), Vector(-30,-30,-30), Vector(30, 30, 30) }, + [HULL_MEDIUM_TALL] = { Vector(-18,-18, 0), Vector(18, 18, 100), Vector(-12,-12, 0), Vector(12, 12, 100) }, + } + + function META_NPC:GetHullMins() + + local hullType = self:GetHullType() + if hullType == nil then + return Vector(0, 0, 0) + end + + local hull = HULLS[hullType] + if hull == nil then + return Vector(0, 0, 0) + end + + return hull[1] + + end + + function META_NPC:GetHullMaxs() + + local hullType = self:GetHullType() + if hullType == nil then + return Vector(0, 0, 0) + end + + local hull = HULLS[hullType] + if hull == nil then + return Vector(0, 0, 0) + end + + return hull[2] + + end + + function META_NPC:GetCurrentSchedule( ) + + for s = 0, LAST_SHARED_SCHEDULE-1 do + if ( self:IsCurrentSchedule( s ) ) then return s end + end + + return 0 + + end + +end diff --git a/gamemode/sh_player_extend.lua b/gamemode/sh_player_extend.lua new file mode 100644 index 00000000..d0561e9c --- /dev/null +++ b/gamemode/sh_player_extend.lua @@ -0,0 +1,194 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("PlayerExt") +local PLAYER_META = FindMetaTable("Player") + +VIEWLOCK_NONE = 0 +VIEWLOCK_ANGLE = 1 +VIEWLOCK_NPC = 2 +VIEWLOCK_PLAYER = 3 + +if SERVER then + + function PLAYER_META:LockPosition(poslock, viewlock, viewdata) + + poslock = poslock or false + viewlock = viewlock or false + + self.PositionLocked = self.PositionLocked or false + self.ViewLocked = self.ViewLocked or false + + if poslock == true then + DbgPrint("Locking player position: " .. tostring(self)) + else + DbgPrint("Unlocking player position: " .. tostring(self)) + end + + local prevPositionLock = self.PositionLocked + local prevViewLocked = self.ViewLocked + + self.PositionLocked = poslock + self.ViewLock = viewlock + self.LockedViewAngles = viewang + self:SetNoTarget(poslock) + self:SetNWBool("PositionLocked", poslock) + self:SetNWInt("ViewLock", viewlock) + + if viewlock == VIEWLOCK_ANGLE then + self:SetNWAngle("LockedViewAngles", viewdata) + elseif viewlock == VIEWLOCK_NPC then + self:SetNWEntity("LockedViewEntity", viewdata) + end + + if self.PositionLocked ~= prevPositionLock or self.ViewLock ~= prevViewLocked then + hook.Call("Lambda_PlayerLockChanged", GAMEMODE, poslock, viewlock, viewdata) + end + + end + +end -- SERVER + +function PLAYER_META:IsPositionLocked() + + if SERVER then + self.PositionLocked = self.PositionLocked or false + return self.PositionLocked + end + + return self:GetNWBool("PositionLocked", false) + +end + +function PLAYER_META:GetGender() + return self:GetNWString("Gender", "male") +end + +function PLAYER_META:GetViewLock() + + if SERVER then + self.ViewLock = self.ViewLock or false + return self.ViewLock + end + + return self:GetNWInt("ViewLock", VIEWLOCK_NONE) + +end + +function PLAYER_META:GetNearestRadiationRange() + return self:GetNWInt("LambdaRadiationRange", 1000) +end + +function PLAYER_META:SetNearestRadiationRange(range, override) + + local current = self:GetNearestRadiationRange() + + if override == true then + current = range + else + if current >= range then + current = range + end + end + + self:SetNWInt("LambdaRadiationRange", current) + +end + +function PLAYER_META:SetGeigerRange(range) + self:SetNWInt("LambdaGeigerRange", range) +end + +function PLAYER_META:GetGeigerRange() + return self:GetNWInt("LambdaGeigerRange", 1000) +end + +function PLAYER_META:AddSuitDevice(device) + self.SuitDevices = self.SuitDevices or {} + self.SuitDevices[device] = true +end + +function PLAYER_META:RemoveSuitDevice(device) + self.SuitDevices = self.SuitDevices or {} + self.SuitDevices[device] = nil +end + +function PLAYER_META:GetSuitDevices() + self.SuitDevices = self.SuitDevices or {} + return table.Copy(self.SuitDevices) +end + +function PLAYER_META:UsingSuitDevice(device) + self.SuitDevices = self.SuitDevices or {} + return self.SuitDevices[device] or false +end + +function PLAYER_META:GetFlexIndexByName(name) + + self.LastModelName = self.LastModelName or "" + self.FlexIndexCache = self.FlexIndexCache or {} + local mdl = self:GetModel() + + if mdl ~= self.LastModelName then + self.LastModelName = mdl + self.FlexIndexCache = {} + local count = self:GetFlexNum() - 1 + if count <= 0 then return end + + for i = 0, count do + local flexName = self:GetFlexName(i) + self.FlexIndexCache[flexName] = i + end + end + + return self.FlexIndexCache[name] + +end + +function PLAYER_META:GetSpawnTime() + return self.LambdaSpawnTime or CurTime() +end + +function PLAYER_META:GetLifeTime() + return CurTime() - self:GetSpawnTime() +end + +function PLAYER_META:IsInactive() + return self:GetNW2Bool("Inactive", true) +end + +function PLAYER_META:SetInactive(state) + self:SetNW2Bool("Inactive", state) +end + +-- ply:NetworkVar("Float", 0, "SuitPower") +function PLAYER_META:SetSuitPower(val) + self:SetNW2Float("SuitPower", val) +end +function PLAYER_META:GetSuitPower() + return self:GetNW2Float("SuitPower", 0.0) +end + +-- ply:NetworkVar("Float", 1, "SuitEnergy") +function PLAYER_META:SetSuitEnergy(val) + self:SetNW2Float("SuitEnergy", val) +end +function PLAYER_META:GetSuitEnergy() + return self:GetNW2Float("SuitEnergy", 0.0) +end + +-- ply:NetworkVar("Bool", 0, "Sprinting") +function PLAYER_META:SetSprinting(val) + self:SetNW2Bool("Sprinting", val) +end +function PLAYER_META:GetSprinting() + return self:GetNW2Bool("Sprinting", false) +end + +-- ply:NetworkVar("Bool", 1, "StateSprinting") +function PLAYER_META:SetStateSprinting(val) + self:SetNW2Bool("StateSprinting", val) +end + +function PLAYER_META:GetStateSprinting() + return self:GetNW2Bool("StateSprinting", false) +end diff --git a/gamemode/sh_player_list.lua b/gamemode/sh_player_list.lua new file mode 100644 index 00000000..6eec7b48 --- /dev/null +++ b/gamemode/sh_player_list.lua @@ -0,0 +1,175 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("PlayerList") + +function GM:InitializePlayerList() + DbgPrint("InitializePlayerList") + self.Players = {} + self.Connecting = {} + self.Connected = {} +end + +if SERVER then + + function GM:TransferPlayers() + + DbgPrint("TransferPlayers") + + if self.TransitionData ~= nil and self.TransitionData.Players ~= nil then + + -- Changelevel does not signal a new connect, so we take players from the transition data instead. + for _,data in pairs(self.TransitionData.Players) do + + local userId = data["UserID"] + local playerData = self.Players[userId] or {} + + playerData.ConnectTime = GetSyncedTimestamp() + playerData.Nick = data["Nick"] + playerData.SteamID = data["SteamID"] + playerData.UserID = userId + playerData.Connecting = true + playerData.Bot = false -- Cant be done. + + self.Players[userId] = playerData + self.Connecting[userId] = playerData + + end + + PrintTable(self.Connecting) + + for k,_ in pairs(self.Connecting) do + hook.Call("NotifyPlayerListChanged", GAMEMODE, k) + end + + end + + end + + function GM:HandlePlayerConnect(steamid, nick, entIndex, bot, userid) + + DbgPrint("HandlePlayerConnect", steamid, nick, entIndex, userid) + + local playerData = self.Players[userid] + if playerData ~= nil then + playerData.Connecting = bot == false + playerData.Bot = bot + else + playerData = {} + playerData.ConnectTime = GetSyncedTimestamp() + playerData.Nick = nick + playerData.SteamID = steamid + playerData.UserID = userid + playerData.Bot = bot + playerData.Connecting = bot == false + end + + self.Players[userid] = playerData + if playerData.Connecting == true then + self.Connecting[userid] = playerData + end + + end + + function GM:HandlePlayerDisconnect(steamid, nick, reason, bot, userid) + + DbgPrint("HandlePlayerDisconnect", steamid, nick, reason, bot, userid) + + local playerData = self.Players[userid] + if playerData == nil then + DbgError("ERROR: User never signaled a connect") + return + end + + playerData.Connecting = false -- Just in case of references. + + self.Connecting[userid] = nil + self.Players[userid] = nil + + end + + function GM:HandlePlayerReadyState(ply) + + DbgPrint("[NET] Player fully connected: " .. tostring(ply)) + + local userId = ply:UserID() + local playerData = self.Connecting[userId] + if playerData == nil then + DbgError("Bogus: User never signaled connection") + end + + playerData.Connecting = false + + self.Connecting[userId] = nil + self.Connected[userId] = playerData + + hook.Call("NotifyPlayerListChanged", GAMEMODE, userId) + + end + + function GM:CheckPlayerTimeouts() + + local timestamp = GetSyncedTimestamp() + for k,v in pairs(self.Connecting) do + if timestamp - v.ConnectTime >= 120 then + DbgPrint("Player " .. v.Nick .. " timed out") + v.Connecting = false + self.Connecting[k] = nil + continue + end + end + + end + + function GM:GetPlayerCount() + return table.Count(self.Players) + end + + function GM:GetFullyConnectedCount() + return table.Count(self.Connected) + end + + gameevent.Listen("player_connect") + hook.Add("player_connect", "LambdaPlayerConnect", function(data) + GAMEMODE:HandlePlayerConnect(data.networkid, data.name, data.index, data.bot == 1, data.userid) + end) + + gameevent.Listen("player_disconnect") + hook.Add("player_disconnect", "LambdaPlayerConnect", function(data) + GAMEMODE:HandlePlayerDisconnect(data.networkid, data.name, data.reason, data.bot == 1, data.userid) + end) + + util.AddNetworkString("LambdaPlayerReady") + + net.Receive("LambdaPlayerReady",function(len, ply) + GAMEMODE:HandlePlayerReadyState(ply) + end) + +else -- CLIENT + + hook.Add("StartCommand", "LambdaPlayerReady", function(ply, cmd) + + -- NOTE: Just making sure its us. + if ply ~= LocalPlayer() then + return + end + + -- Auto-reload + if ply.SignaledConnection ~= true then + net.Start("LambdaPlayerReady") + net.SendToServer() + ply.SignaledConnection = true + end + + hook.Remove("StartCommand", "LambdaPlayerReady") + + end) + +end + +function player.GetCount() + return #player.GetAll() +end + +function GM:GetConnectingCount() + return table.Count(self.Connecting) + 0 +end diff --git a/gamemode/sh_roundsystem.lua b/gamemode/sh_roundsystem.lua new file mode 100644 index 00000000..edf533fc --- /dev/null +++ b/gamemode/sh_roundsystem.lua @@ -0,0 +1,622 @@ +if SERVER then + AddCSLuaFile() + util.AddNetworkString("LambdaRestartRound") + util.AddNetworkString("LambdaWaitingForPlayers") +end + +local DbgPrint = GetLogging("RoundLogic") + +local STATE_BOOTING = -2 +local STATE_IDLE = -1 +local STATE_RESTART_REQUESTED = 0 +local STATE_RESTARTING = 1 +local STATE_RUNNING = 2 + +function GM:InitializeRoundSystem() + + DbgPrint("GM:InitializeRoundSystem") + + self.RoundState = STATE_IDLE + self.RoundStartTime = GetSyncedTimestamp() + self.WaitingForRoundStart = true + self.RoundStartTimeout = GetSyncedTimestamp() + 120 + + if SERVER then + self.OnNewGameEvents = {} + self.OnMapTransitionEvents = {} + self.OnMapSpawnEvents = {} + end + +end + +if SERVER then + + function GM:NotifyPlayerListChanged() + + DbgPrint("GM:NotifyPlayerListChanged") + + self.RoundStartTimeout = self.RoundStartTimeout or GetSyncedTimestamp() + 120 + net.Start("LambdaWaitingForPlayers") + net.WriteBool(self.WaitingForRoundStart) + net.WriteFloat(self.RoundStartTimeout) + net.WriteUInt(self:GetFullyConnectedCount(), 8) + net.WriteUInt(self:GetConnectingCount() + self:GetFullyConnectedCount(), 8) + net.Broadcast() + + end + + function GM:SetRoundBootingComplete() + + DbgPrint("GM:SetRoundBootingComplete") + + if self.RoundState == STATE_BOOTING then + self.RoundState = STATE_IDLE -- Wait for players. + end + + end + + function GM:IncludePlayerInRound(ply) + + DbgPrint("GM:IncludePlayerInRound(" .. tostring(ply) .. ")") + self:NotifyPlayerListChanged() + + end + + function GM:RestartRound(restartTime, showInfo) + + DbgPrint("Requested restart") + + restartTime = restartTime or lambda_map_restart_timeout:GetInt() + + if self.RoundState ~= STATE_RUNNING then + DbgPrint("Attempted to restart while restart is pending") + return + end + + self.RoundState = STATE_RESTART_REQUESTED + self.ScheduledRestartTime = GetSyncedTimestamp() + restartTime + self.RealTimeScale = game.GetTimeScale() + + if IsValid(self.LambdaFailureMessage) then + self.LambdaFailureMessage:Fire("ShowMessage") + end + + if showInfo == nil then + showInfo = true + end + + net.Start("LambdaRestartRound") + net.WriteFloat(restartTime) + net.WriteBool(showInfo) + net.Broadcast() + + end + + function GM:CleanUpMap() + + DbgPrint("GM:CleanUpMap") + + -- Make sure nothing is going to create new things now + self.RoundState = STATE_RESTARTING + + -- Remove vehicles + self:CleanUpVehicles() + + -- Check what we have to cleanup + local filter = {} + hook.Call("LambdaCleanupFilter", GAMEMODE, filter) + + game.CleanUpMap(false, filter) + + end + + function GM:RoundThink() + + local gameType = self:GetGameType() + + if self.RoundState == STATE_BOOTING then + + DbgUniquePrint("Waiting for boot") + + elseif self.RoundState == STATE_IDLE then + + if self.WaitingForRoundStart == true and (self:GetConnectingCount() > 0 or #player.GetAll() == 0) then + -- Waiting for players + --DbgUniquePrint("Waiting for players") + if self.RoundStartTimeout ~= nil and GetSyncedTimestamp() >= self.RoundStartTimeout then + DbgPrint("Timeout, round will start now") + self:StartRound() + end + + elseif self.WaitingForRoundStart == true and #player.GetAll() > 0 and self:GetConnectingCount() == 0 then + DbgPrint("All players available") + self:StartRound() + elseif self.WaitingForRoundStart == false then + self:StartRound() + end + + elseif self.RoundState == STATE_RESTART_REQUESTED then + + local curTime = GetSyncedTimestamp() + if curTime > self.ScheduledRestartTime then + DbgPrint("Restarting round...") + self.RoundState = STATE_RESTARTING + self:CleanUpMap() + else + local remaining = self.ScheduledRestartTime - curTime + local timescale = 0.7 - ((curTime / self.ScheduledRestartTime) * 0.5) + game.SetTimeScale(timescale) + + local remainingTime = string.format("%0.0f",remaining) + DbgUniquePrint(remainingTime .. "s remaining until restart") + end + + elseif self.RoundState == STATE_RESTARTING then + + -- PostCleanupMap takes care of this. + -- Handle restarting state. + --DbgUniquePrint("Restarting") + --DbgPrint("Setting restart") + --self.WaitingForRoundStart = false + --self:OnNewGame() + + elseif self.RoundState == STATE_RUNNING then + + --DbgUniquePrint("Round Logic") + if gameType.ShouldRestartRound ~= nil and gameType:ShouldRestartRound() == true then + DbgPrint("All players are dead, restart required") + self:RestartRound() + self:RegisterRoundLost() + end + + else + Error("Unknown round state") + end + + end + +else + + net.Receive("LambdaRestartRound", function(length) + + local scheduledRestartTime = net.ReadFloat() + local showMessage = net.ReadBool() + GAMEMODE:SetRoundRestarting(GetSyncedTimestamp(), scheduledRestartTime, showMessage) + + end) + + net.Receive("LambdaWaitingForPlayers", function(length) + + local waitingForPlayers = net.ReadBool() + local timeout = net.ReadFloat() + local connected = net.ReadUInt(8) + local totalPlayers = net.ReadUInt(8) + + GAMEMODE:SetWaitingForPlayers(waitingForPlayers, timeout, connected, totalPlayers) + + end) + + function GM:SetRoundRestarting(currentTime, scheduledRestartTime, showMessage) + + self.ScheduledRestartTime = currentTime + scheduledRestartTime + self.RestartTimeout = scheduledRestartTime + self.RoundState = STATE_RESTART_REQUESTED + + self:BeginRoundRestart() + self:EnableRespawnHUD(false, 0, 0) + + local showMessage = showMessage + + hook.Add("RenderScreenspaceEffects", "LambdaRoundRestart", function() + GAMEMODE:DrawRoundRestart(showMessage) + end) + + end + + function GM:BeginRoundRestart() + + local self = self + local ply = LocalPlayer() + + RunConsoleCommand("stopsound") + util.RunNextFrame(function() + if IsValid(ply) then + surface.PlaySound("lambda/death.mp3") + end + self:SetSoundSuppressed(true) + end) + + end + + function GM:SetWaitingForPlayers(waitingForPlayers, timeout, connected, totalPlayers) + + local timeout = timeout + local connected = connected + local totalPlayers = totalPlayers + + if waitingForPlayers == true then + DbgPrint("Set waiting for players") + hook.Add("HUDPaint", "LambdaRoundWaitingForPlayers", function() + GAMEMODE:DrawWaitingForPlayers(timeout, connected, totalPlayers) + end) + else + DbgPrint("Unset waiting for players") + hook.Remove("HUDPaint", "LambdaRoundWaitingForPlayers") + end + + end + + function GM:DrawRoundRestart(showMessage) + + local curTime = GetSyncedTimestamp() + if curTime > self.ScheduledRestartTime then + return + end + + local remaining = self.ScheduledRestartTime - curTime + if remaining < 0 then + return + end + + local reverse = self.RestartTimeout - remaining + local perc = 1 - (remaining / self.RestartTimeout) + local brightness = 0 + if reverse <= 0.5 then + brightness = (0.5 - reverse) * 1.3 + else + brightness = 0 + end + + local noiseX = 0 + local noiseY = 0 + local alpha = 255 + + if math.random(0, 15) == 0 then + noiseX = math.random(-10, 5) + noiseY = math.random(-5, 10) + end + + if math.random(0, 5) == 0 then + alpha = math.random(50, 150) + end + + if showMessage == true then + + local text = "RESTARTING ROUND IN " .. string.format("%.1f", remaining) .. " SECONDS" + local x = (ScrW() * 0.5) + local y = (ScrH() * 0.5) + 80 + + draw.SimpleText(text, "DermaLarge", x, y, Color(255, 255, 255, 50), TEXT_ALIGN_CENTER) + + end + + local mul = perc * 3 + + local tab = + { + ["$pp_colour_addr"] = 0, + ["$pp_colour_addg"] = 0, + ["$pp_colour_addb"] = 0, + ["$pp_colour_brightness"] = brightness, + ["$pp_colour_contrast"] = (1 - perc * 0.2), + ["$pp_colour_colour"] = 0.8 - (perc * 0.5), + ["$pp_colour_mulr"] = mul, + ["$pp_colour_mulg"] = 0, + ["$pp_colour_mulb"] = 0, + } + + DrawColorModify( tab ) + + end + + function GM:DrawWaitingForPlayers(timeout, connected, totalPlayers) + + local noiseX = math.random(-2, 2) + local noiseY = math.random(-2, 2) + local progress = string.rep(".", 1 + (CurTime() * 0.5 % 3)) + local remaining = timeout - GetSyncedTimestamp() + if remaining < 0 then + remaining = 0 + end + + surface.SetFont("DermaLarge") + + local text = "Waiting for other players" .. progress + local _,h = surface.GetTextSize(text) + local y = 0 + + draw.SimpleText("Waiting for other players " .. string.format("%d/%d ", connected, totalPlayers) .. progress, "DermaLarge", ScrW() * 0.5, ScrH() * 0.5 + y, Color(255, 255, 255, 50), TEXT_ALIGN_CENTER) + y = y + h + draw.SimpleText("Forcing start in " .. string.format("%.02f seconds", remaining), "DermaLarge", ScrW() * 0.5, ScrH() * 0.5 + y, Color(255, 255, 255, 50), TEXT_ALIGN_CENTER) + + end + +end + +function GM:PreCleanupMap() + DbgPrint("GM:PreCleanupMap") + + for _,v in pairs(player.GetAll()) do + v:KillSilent() + end + + -- Prevent recursions. + for _,v in pairs(ents.GetAll()) do + v:EnableRespawn(false) + end + + -- Cleanup the input/output system. + self.RoundState = STATE_RESTARTING + self:CleanUpGameEvents() + self:ResetInputOutput() + self:ResetVehicleCheckpoint() +end + +function GM:PostCleanupMap() + + DbgPrint("GM:PostCleanupMap") + if SERVER then + --self:PostInitializeSkybox() + end + + if self.RoundState ~= STATE_RESTARTING then + return + end + + local self = self + util.RunNextFrame(function() + self:StartRound(true) + end) + +end + +function GM:IsRoundRestarting() + + if self.RoundState == STATE_RESTART_REQUESTED or + self.RoundState == STATE_RESTARTING + then + return true + end + + return false + +end + +function GM:CleanUpGameEvents() + DbgPrint("Cleaning up Game events") + self.OnNewGameEvents = {} + self.OnMapTransitionEvents = {} + self.OnMapSpawnEvents = {} +end + +function GM:RegisterNewGameEvent(v) + table.insert(self.OnNewGameEvents, { v, 0 }) +end + +function GM:RegisterMapTransitionEvent(v) + table.insert(self.OnMapTransitionEvents, { v, 0 }) +end + +function GM:RegisterMapSpawnEvent(v) + table.insert(self.OnMapSpawnEvents, { v, 0 }) +end + +function GM:RoundSystemEntityKeyValue(ent, key, val) + + if key:iequals("OnNewGame") then + DbgPrint(tostring(ent) .. ": Overriding OnNewGame event") + self:RegisterNewGameEvent(val) + return "" + elseif key:iequals("OnMapSpawn") then + DbgPrint(tostring(ent) .. ": Overriding OnMapSpawn event") + self:RegisterMapSpawnEvent(val) + return "" + elseif key:iequals("OnMapTransition") then + DbgPrint(tostring(ent) .. ": Overriding OnMapTransition event") + self:RegisterMapTransitionEvent(val) + return "" + end + +end + +-- Called as soon players are ready to play or a new round has begun. +function GM:OnNewGame() + + DbgPrint("GM:OnNewGame") + + if self.WaitingForRoundStart == true then + Error("Critical flaw: Called OnNewGame before NewRound == false") + end + + -- This should be the right spot. + self.RoundState = STATE_RUNNING + self.RoundStartTime = GetSyncedTimestamp() + + if SERVER then + + -- FIXME: Don't ignore the delay time. + self:CreateTransitionObjects() + + DbgPrint("Spawning players") + for _,v in pairs(player.GetAll()) do + v.TransitionData = self:GetPlayerTransitionData(v) + v:Spawn() + end + + -- Notify clients. + net.Start("LambdaWaitingForPlayers") + net.WriteBool(false) + net.Broadcast() + + local failureMessage = ents.Create("env_message") + failureMessage:SetKeyValue("spawnflags", "2") + failureMessage:SetKeyValue("message", "GAMEOVER_ALLY") + failureMessage:Spawn() + + self.LambdaFailureMessage = failureMessage + + -- Create/Replace things for the map. + if self.MapScript.PostInit ~= nil then + self.MapScript:PostInit() + end + + util.RunNextFrame(function() + GAMEMODE:PostRoundSetup() + end) + + end + +end + +function GM:PostRoundSetup() + + DbgPrint("PostRoundSetup") + DbgPrint("Game Events: " .. tostring(#self.OnNewGameEvents)) + + -- Reset some env_global things. + local friendly_encounter = ents.Create("env_global") + friendly_encounter:SetKeyValue("globalstate", "friendly_encounter") + friendly_encounter:SetKeyValue("initialstate", "0") + friendly_encounter:Spawn() + friendly_encounter:Fire("TurnOff") + + -- we always fire OnMapSpawn + util.TriggerOutputs(self.OnMapSpawnEvents) + --[[ + for _,outputs in pairs(self.OnMapSpawnEvents) do + local params = string.Split(outputs, ",") + for _, ent in pairs(ents.FindByName(params[1])) do + if IsValid(ent) then + DbgPrint("Firing OnMapSpawn -> " .. tostring(ent) .. " : " .. params[2] .. ", " .. params[3] .. ", " .. params[4]) + ent:Fire(params[2], params[3], tonumber(params[4])) + end + end + end + ]] + + -- Fire this only when we used map. + if self.IsChangeLevel == false then + DbgPrint("Firing OnNewGame events") + --[[ + for _,outputs in pairs(self.OnNewGameEvents) do + local params = string.Split(outputs, ",") + --local ent = ents.FindFirstByName(params[1]) + for _, ent in pairs(ents.FindByName(params[1])) do + if IsValid(ent) then + ent:Fire(params[2], params[3], tonumber(params[4])) + end + end + end + ]] + util.TriggerOutputs(self.OnNewGameEvents) + else + DbgPrint("Firing OnMapTransition events") + --[[ + for _,outputs in pairs(self.OnMapTransitionEvents) do + local params = string.Split(outputs, ",") + for _, ent in pairs(ents.FindByName(params[1])) do + if IsValid(ent) then + ent:Fire(params[2], params[3], tonumber(params[4])) + end + end + end + ]] + util.TriggerOutputs(self.OnMapTransitionEvents) + end + + if self.MapScript.OnNewGame then + local self = self + util.RunNextFrame(function() + self.MapScript:OnNewGame() + end) + end + +end + +function GM:StartRound(cleaned) + + -- Initialize map script. + DbgPrint("GM:StartRound") + + if CLIENT then + hook.Remove("HUDPaint", "LambdaRoundRestart") + hook.Remove("Think", "LambdaRoundRestart") + + self:SetSoundSuppressed(false) + end + + if SERVER then + + game.SetTimeScale(1) + + if self.InitPostEntityDone ~= true then + DbgError("Unfinished booting") + end + + if cleaned ~= true then + -- GAMEMODE:CleanUpMap() + -- DbgPrint("Forcing map refresh.") + else + -- Make sure map created vehicles are gone, we take over. + self:CleanUpVehicles() + end + + end + + self.WaitingForRoundStart = false + + if self:GetConnectingCount() > 0 and self.RoundState ~= STATE_RESTARTING then + self.WaitingForRoundStart = true + elseif #player.GetAll() == 0 then + self.WaitingForRoundStart = true + end + + self.RoundState = STATE_RESTARTING + + if self.MapScript.Init ~= nil then + self.MapScript:Init() + end + + if SERVER then + local count = 0 + for k,t in pairs(self.MapScript.InputFilters) do + for _,v in pairs(t) do + self:FilterEntityInput(k, v) + count = count + 1 + end + end + DbgPrint("Loaded " .. tostring(count) .. " input filter for current map") + end + + if SERVER then + self:DisablePreviousMap() + end + + if self.WaitingForRoundStart == false then + local self = self + util.RunNextFrame(function() + self:OnNewGame() + end) + + else + if SERVER then + self.RoundStartTimeout = GetSyncedTimestamp() + 120 + self:NotifyPlayerListChanged() + end + end + +end + +function GM:IsRoundRunning() + return self.RoundState == STATE_RUNNING +end + +function GM:RoundElapsedTime() + + if self.RoundState == STATE_RUNNING then + return GetSyncedTimestamp() - self.RoundStartTime + end + + return 0 + +end diff --git a/gamemode/sh_sound_env.lua b/gamemode/sh_sound_env.lua new file mode 100644 index 00000000..5db94fdd --- /dev/null +++ b/gamemode/sh_sound_env.lua @@ -0,0 +1,34 @@ +if SERVER then + AddCSLuaFile() +end + +function GM:SetSoundSuppressed(suppress) + self.SuppressSound = suppress +end + +local host_timescale = GetConVar("host_timescale") + +function GM:EntityEmitSound(data) + + local p = data.Pitch + + if game.GetTimeScale() ~= 1 then + p = p * (game.GetTimeScale() * 1.5) + elseif host_timescale:GetFloat() ~= 1 then + p = p * (host_timescale:GetFloat() * 1.5) + end + + p = math.Clamp(p, 0, 255) + data.Pitch = p + + local ent = data.Entity + + if IsValid(ent) and ent:IsNPC() and string.sub(data.SoundName, 1, 16):iequals("player/footsteps") then + if self:NPCFootstep(ent, data) == false then + return false + end + end + + return true + +end diff --git a/gamemode/sh_spectate.lua b/gamemode/sh_spectate.lua new file mode 100644 index 00000000..4eaa2a16 --- /dev/null +++ b/gamemode/sh_spectate.lua @@ -0,0 +1,137 @@ +AddCSLuaFile() + +local PLAYER_META = FindMetaTable("Player") + +if SERVER then + + function GM:GetSpectatorTargets() + return team.GetPlayers( LAMBDA_TEAM_ALIVE ) + end + + function PLAYER_META:SetSpectator() + + local ent = table.Random( GAMEMODE:GetSpectatorTargets() ) + + self:SetNW2Bool("Spectator", true) + self:SetNW2Entity("SpectateEntity", ent) + + self:StripWeapons() + if self:Alive() then + self:KillSilent() + end + self:Spectate( 5 ) + if IsValid(ent) then + self:SpectateEntity(ent) + end + + end + + function PLAYER_META:EndSpectator() + + self:SetNW2Bool("Spectator", false) + self:UnSpectate() + + end + + function PLAYER_META:GetSpectateMode() + return self:GetObserverMode() + end + + function PLAYER_META:GetSpectateTarget() + return self:GetObserverTarget() + end + + function PLAYER_META:ChangeSpectateMode() + + local target = self:GetObserverTarget() + + if self:GetSpectateMode() == 5 then + self:SetObserverMode( 4 ) + self:SetupHands( target ) + elseif self:GetSpectateMode() == 4 then + self:SetObserverMode( 5 ) + self:SetupHands( nil ) + end + end + + hook.Add( "KeyPress", "ChangeObserverMode", function( ply, key ) + + if !ply:IsSpectator() then return end + + if key == IN_JUMP then + ply:ChangeSpectateMode() + end + + if key == IN_ATTACK then + ply:NextSpectateTarget() + end + + if key == IN_ATTACK2 then + ply:PrevSpectateTarget() + end + + end) + + function GM:GetNextSpectateTarget( ply, ent ) + + local targets = GAMEMODE:GetSpectatorTargets() + return table.FindNext( targets, ent) + + end + + function GM:GetPrevSpectateTarget( ply, ent ) + + local targets = GAMEMODE:GetSpectatorTargets() + return table.FindPrev( targets, ent ) + + end + + local function IsValidTarget( ply, ent ) + + if !IsValid( ent ) then return false end + if ent == ply then return false end + if !ent:Alive() then return false end + + return true + + end + + function PLAYER_META:NextSpectateTarget() + + local target = self:GetObserverTarget() + + target = GAMEMODE:GetNextSpectateTarget( self, target ) + + if IsValidTarget( self, target ) then + self:SpectateEntity( target ) + if self:GetSpectateMode() == 4 then + self:SetupHands( target ) + end + else + return + end + + end + + function PLAYER_META:PrevSpectateTarget() + + local target = self:GetObserverTarget() + + target = GAMEMODE:GetPrevSpectateTarget( self, target ) + + if IsValidTarget( self, target ) then + self:SpectateEntity( target ) + if self:GetSpectateMode() == 4 then + self:SetupHands( target ) + end + else + return + end + + end + +end -- SERVER + +function PLAYER_META:IsSpectator() + return self:GetNW2Bool("Spectator", false) +end diff --git a/gamemode/sh_string_extend.lua b/gamemode/sh_string_extend.lua new file mode 100644 index 00000000..cd0aefa5 --- /dev/null +++ b/gamemode/sh_string_extend.lua @@ -0,0 +1,8 @@ +AddCSLuaFile() + +function string.iequals(a, b) + if string.len(a) ~= string.len(b) then + return false + end + return string.lower(a) == string.lower(b) +end diff --git a/gamemode/sh_taunts.lua b/gamemode/sh_taunts.lua new file mode 100644 index 00000000..bb1e6971 --- /dev/null +++ b/gamemode/sh_taunts.lua @@ -0,0 +1,92 @@ +AddCSLuaFile() + +Taunts = {} + +local function InsertTaunt(gender, name, files) + Taunts[gender] = Taunts[gender] or {} + local data = { + Name = name, + Sounds = files, + } + table.insert(Taunts[gender], data) +end + +InsertTaunt("male", "Hi", {"vo/npc/male01/hi01.wav", "vo/npc/male01/hi02.wav"}) +InsertTaunt("male", "Yeah", {"vo/npc/male01/yeah02.wav"}) +InsertTaunt("male", "Okay", {"vo/npc/male01/ok01.wav", "vo/npc/male01/ok02.wav"}) +InsertTaunt("male", "No", {"vo/npc/male01/no01.wav"}) +InsertTaunt("male", "Nice", {"vo/npc/male01/nice.wav"}) +InsertTaunt("male", "Help", {"vo/npc/male01/help01.wav"}) +InsertTaunt("male", "Sorry", {"vo/npc/male01/sorry01.wav", "vo/npc/male01/sorry02.wav", "vo/npc/male01/sorry03.wav"}) +InsertTaunt("male", "Over there", {"vo/npc/male01/overthere01.wav", "vo/npc/male01/overthere02.wav"}) +InsertTaunt("male", "Over here", {"vo/npc/male01/overhere01.wav"}) +InsertTaunt("male", "Leave it alone", {"vo/npc/male01/answer38.wav"}) +InsertTaunt("male", "I'm Ready", {"vo/npc/male01/okimready01.wav", "vo/npc/male01/okimready02.wav", "vo/npc/male01/okimready03.wav"}) +InsertTaunt("male", "I'm with you", {"vo/npc/male01/answer13.wav"}) +InsertTaunt("male", "Ready when you are", {"vo/npc/male01/readywhenyouare01.wav", "vo/npc/male01/readywhenyouare02.wav"}) +InsertTaunt("male", "Whatever you say", {"vo/npc/male01/squad_affirm03.wav"}) +InsertTaunt("male", "Let's go", {"vo/npc/male01/letsgo01.wav", "vo/npc/male01/letsgo02.wav"}) +InsertTaunt("male", "Excuse me", {"vo/npc/male01/excuseme01.wav", "vo/npc/male01/excuseme02.wav"}) +InsertTaunt("male", "Get down", {"vo/npc/male01/getdown02.wav"}) +InsertTaunt("male", "Heads up", {"vo/npc/male01/headsup01.wav", "vo/npc/male01/headsup02.wav"}) +InsertTaunt("male", "Fantastic", {"vo/npc/male01/fantastic01.wav", "vo/npc/male01/fantastic02.wav"}) +InsertTaunt("male", "Finally", {"vo/npc/male01/finally.wav"}) +InsertTaunt("male", "Good God", {"vo/npc/male01/goodgod.wav"}) +InsertTaunt("male", "Run for your life", {"vo/npc/male01/runforyourlife01.wav", "vo/npc/male01/runforyourlife02.wav", "vo/npc/male01/runforyourlife03.wav"}) +InsertTaunt("male", "Scanners", {"vo/npc/male01/scanners01.wav", "vo/npc/male01/scanners02.wav"}) +InsertTaunt("male", "Strider", {"vo/npc/male01/strider.wav"}) +InsertTaunt("male", "Combine", {"vo/npc/male01/combine01.wav", "vo/npc/male01/combine02.wav"}) +InsertTaunt("male", "Gunship", {"vo/npc/male01/gunship02.wav"}) +InsertTaunt("male", "Headcrabs", {"vo/npc/male01/headcrabs01.wav", "vo/npc/male01/headcrabs02.wav"}) +InsertTaunt("male", "Zombies", {"vo/npc/male01/zombies01.wav", "vo/npc/male01/zombies02.wav"}) +InsertTaunt("male", "Run", {"vo/npc/male01/strider_run.wav"}) +InsertTaunt("male", "Behind you", {"vo/npc/male01/behindyou01.wav", "vo/npc/male01/behindyou02.wav"}) +InsertTaunt("male", "Take cover", {"vo/npc/male01/takecover02.wav"}) +InsertTaunt("male", "You got it", {"vo/npc/male01/yougotit02.wav"}) +InsertTaunt("male", "Whoops", {"vo/npc/male01/whoops01.wav"}) +InsertTaunt("male", "Watch out", {"vo/npc/male01/watchout.wav"}) +InsertTaunt("male", "Waiting for somebody?", {"vo/npc/male01/waitingsomebody.wav"}) +InsertTaunt("male", "Like that", {"vo/npc/male01/likethat.wav"}) +InsertTaunt("male", "We trusted you", {"vo/npc/male01/wetrustedyou01.wav", "vo/npc/male01/wetrustedyou02.wav"}) +InsertTaunt("male", "How about that", {"vo/npc/male01/answer25.wav"}) +InsertTaunt("male", "Wanna bet", {"vo/npc/male01/answer27.wav"}) + +InsertTaunt("female", "Hi", {"vo/npc/female01/hi01.wav", "vo/npc/female01/hi02.wav"}) +InsertTaunt("female", "Yeah", {"vo/npc/female01/yeah02.wav"}) +InsertTaunt("female", "Okay", {"vo/npc/female01/ok01.wav", "vo/npc/female01/ok02.wav"}) +InsertTaunt("female", "No", {"vo/npc/female01/no01.wav"}) +InsertTaunt("female", "Nice", {"vo/npc/female01/nice.wav"}) +InsertTaunt("female", "Help", {"vo/npc/female01/help01.wav"}) +InsertTaunt("female", "Sorry", {"vo/npc/female01/sorry01.wav", "vo/npc/female01/sorry02.wav", "vo/npc/female01/sorry03.wav"}) +InsertTaunt("female", "Over there", {"vo/npc/female01/overthere01.wav", "vo/npc/female01/overthere02.wav"}) +InsertTaunt("female", "Over here", {"vo/npc/female01/overhere01.wav"}) +InsertTaunt("female", "Leave it alone", {"vo/npc/female01/answer38.wav"}) +InsertTaunt("female", "I'm Ready", {"vo/npc/female01/okimready01.wav", "vo/npc/female01/okimready02.wav", "vo/npc/female01/okimready03.wav"}) +InsertTaunt("female", "I'm with you", {"vo/npc/female01/answer13.wav"}) +InsertTaunt("female", "Ready when you are", {"vo/npc/female01/readywhenyouare01.wav", "vo/npc/female01/readywhenyouare02.wav"}) +InsertTaunt("female", "Whatever you say", {"vo/npc/female01/squad_affirm03.wav"}) +InsertTaunt("female", "Let's go", {"vo/npc/female01/letsgo01.wav", "vo/npc/female01/letsgo02.wav"}) +InsertTaunt("female", "Excuse me", {"vo/npc/female01/excuseme01.wav", "vo/npc/female01/excuseme02.wav"}) +InsertTaunt("female", "Get down", {"vo/npc/female01/getdown02.wav"}) +InsertTaunt("female", "Heads up", {"vo/npc/female01/headsup01.wav", "vo/npc/female01/headsup02.wav"}) +InsertTaunt("female", "Fantastic", {"vo/npc/female01/fantastic01.wav", "vo/npc/female01/fantastic02.wav"}) +InsertTaunt("female", "Finally", {"vo/npc/female01/finally.wav"}) +InsertTaunt("female", "Good God", {"vo/npc/female01/goodgod.wav"}) +InsertTaunt("female", "Run for your life", {"vo/npc/female01/runforyourlife01.wav", "vo/npc/female01/runforyourlife02.wav", "vo/npc/female01/runforyourlife03.wav"}) +InsertTaunt("female", "Scanners", {"vo/npc/female01/scanners01.wav", "vo/npc/female01/scanners02.wav"}) +InsertTaunt("female", "Strider", {"vo/npc/female01/strider.wav"}) +InsertTaunt("female", "Combine", {"vo/npc/female01/combine01.wav", "vo/npc/female01/combine02.wav"}) +InsertTaunt("female", "Gunship", {"vo/npc/female01/gunship02.wav"}) +InsertTaunt("female", "Headcrabs", {"vo/npc/female01/headgrabs01.wav", "vo/npc/female01/headgrabs02.wav"}) +InsertTaunt("female", "Zombies", {"vo/npc/female01/zombies01.wav", "vo/npc/female01/zombies02.wav"}) +InsertTaunt("female", "Run", {"vo/npc/female01/strider_run.wav"}) +InsertTaunt("female", "Behind you", {"vo/npc/female01/behindyou01.wav", "vo/npc/female01/behindyou02.wav"}) +InsertTaunt("female", "Take cover", {"vo/npc/female01/takecover02.wav"}) +InsertTaunt("female", "You got it", {"vo/npc/female01/yougotit02.wav"}) +InsertTaunt("female", "Whoops", {"vo/npc/female01/whoops01.wav"}) +InsertTaunt("female", "Watch out", {"vo/npc/female01/watchout.wav"}) +InsertTaunt("female", "Waiting for somebody?", {"vo/npc/female01/waitingsomebody.wav"}) +InsertTaunt("female", "Like that", {"vo/npc/female01/likethat.wav"}) +InsertTaunt("female", "We trusted you", {"vo/npc/female01/wetrustedyou01.wav", "vo/npc/female01/wetrustedyou02.wav"}) +InsertTaunt("female", "How about that", {"vo/npc/female01/answer25.wav"}) +InsertTaunt("female", "Wanna bet", {"vo/npc/female01/answer27.wav"}) diff --git a/gamemode/sh_temp.lua b/gamemode/sh_temp.lua new file mode 100644 index 00000000..42a74634 --- /dev/null +++ b/gamemode/sh_temp.lua @@ -0,0 +1,45 @@ +-- Before this issue is not resolved, we have to do this. +-- https://github.com/Facepunch/garrysmod-issues/issues/2657 + +if SERVER then + AddCSLuaFile() +end + +local ENTITY = FindMetaTable("Entity") + +local PVS_DIST = 9000 +local PVS_MINS = Vector(-PVS_DIST, -PVS_DIST, -PVS_DIST) +local PVS_MAXS = Vector(PVS_DIST, PVS_DIST, PVS_DIST) + +if ENTITY.TestPVS == nil then + + function ENTITY:TestPVS(test) + + if IsEntity(test) then + test = test:GetPos() + end + + local pos = self:GetPos() + if pos:Distance(test) > PVS_DIST then + return false + end + + return true + + end + +end + +--if ents.FindInPVS == nil then + + function ents.FindInPVS(what) + + if IsEntity(what) then + what = what:GetPos() + end + + return ents.FindInBox(what + PVS_MINS, what + PVS_MAXS) + + end + +--end diff --git a/gamemode/sh_timestamp.lua b/gamemode/sh_timestamp.lua new file mode 100644 index 00000000..ef735397 --- /dev/null +++ b/gamemode/sh_timestamp.lua @@ -0,0 +1,122 @@ +-- If you are wondering what this is about, this is just producing a synced timestamp not affected by any scale such +-- as host_timescale or game.GetTimeScale +if SERVER then + AddCSLuaFile() +end + +CURRENT_TIMESTAMP = CURRENT_TIMESTAMP or 0 + +local UpdateTimestamp + +if SERVER then + + util.AddNetworkString("LambdaTimeSync") + util.AddNetworkString("LambdaTimeClientSync") + + local lastUpdate = SysTime() + + hook.Add("Tick", "LambdaTimeSync", function() + UpdateTimestamp() + end) + + UpdateTimestamp = function() + + CURRENT_TIMESTAMP = SysTime() + + if CURRENT_TIMESTAMP - lastUpdate >= 1 then + + net.Start("LambdaTimeSync") + net.WriteDouble(CURRENT_TIMESTAMP) + net.Broadcast() + + lastUpdate = CURRENT_TIMESTAMP + end + + local world = game.GetWorld() + if IsValid(world) then + world:SetNWFloat("LambdaTimeSync", CURRENT_TIMESTAMP) + end + end + +else + + TIMESTAMP_UPDATE_TIME = TIMESTAMP_UPDATE_TIME or 0 + + net.Receive("LambdaTimeSync", function(len) + + local ply = LocalPlayer() + TIMESTAMP_UPDATE_TIME = SysTime() + CURRENT_TIMESTAMP = net.ReadDouble() + if IsValid(ply) then + CURRENT_TIMESTAMP = CURRENT_TIMESTAMP + ((ply:Ping() / 2) / 1000) + end + --DbgPrint("Update") + + end) + +end + +function GetSyncedTimestamp() + if CURRENT_TIMESTAMP == 0 then + if SERVER then + UpdateTimestamp() + else + local world = game.GetWorld() + if IsValid(world) then + CURRENT_TIMESTAMP = world:GetNWFloat("LambdaTimeSync", 0) + else + CURRENT_TIMESTAMP = 0 + end + end + end + + local res = CURRENT_TIMESTAMP + + if CLIENT then + local delta = (SysTime() - TIMESTAMP_UPDATE_TIME) + res = res + delta + end + + return res +end + +--[[ +if SERVER then + + util.AddNetworkString("SyncTest") + + timer.Create("test", 1, 10, function() + net.Start("SyncTest") + net.WriteDouble(os.clock()) + net.WriteDouble(SysTime()) + net.WriteDouble(CurTime()) + net.WriteDouble(GetSyncedTimestamp()) + net.Broadcast() + end) + +else + + DbgPrint(" ", "os.clock", "SysTime", "CurTime", "SyncedTimestamp") + net.Receive("SyncTest",function(len) + + local network1 = net.ReadDouble() + local network2 = net.ReadDouble() + local network3 = net.ReadDouble() + local network4 = net.ReadDouble() + local cl1 = os.clock() + local cl2 = SysTime() + local cl3 = CurTime() + local cl4 = GetSyncedTimestamp() + local diff1 = cl1 - network1 + local diff2 = cl2 - network2 + local diff3 = cl3 - network3 + local diff4 = cl4 - network4 + + DbgPrint("SV", network1, network2, network3, network4) + DbgPrint("CL", cl1, cl2, cl3, cl4) + DbgPrint("Diff", diff1, diff2, diff3, diff4) + + end) + +end +]] diff --git a/gamemode/sh_utils.lua b/gamemode/sh_utils.lua new file mode 100644 index 00000000..699f8291 --- /dev/null +++ b/gamemode/sh_utils.lua @@ -0,0 +1,482 @@ +AddCSLuaFile() + +local DbgPrint = GetLogging("Util") + +-- Any utility function should go in here. +if SERVER then + + function TriggerOutputs(outputs) + + DbgPrint("Firing outputs") + + for _, out in pairs(outputs) do + local entname = out[1] or "" + local cmd = out[2] or "" + local delay = out[3] or 0 + local param = out[4] or "" + local targetents = ents.FindByName(entname) or {} + for k,v in pairs(targetents) do + v:Fire(cmd, param, delay) + end + end + + end + + function util.TriggerOutputs(outputs, activator, caller, param, self) + + --DbgPrint("Firing " .. tostring(table.Count(outputs)) .. " outputs") + local removedOutput = false + + for k, data in pairs(outputs) do + + out = string.Split(data[1], ",") + + local entname = out[1] or "" + local cmd = out[2] or "" + local param = param + if out[3] and out[3] ~= "" then + param = out[3] + end + if IsEntity(param) and IsValid(param) then + param = param:GetName() + end + param = param or "" + + local delay = tonumber(out[4] or 0) + local times = tonumber(out[5] or "-1") + local called = data[2] + 1 + + outputs[k][2] = called + + local callerName = "" + if IsValid(caller) then + callerName = caller:GetName() + end + DbgPrint("Output: (Caller: " .. tostring(caller) .. ", " .. callerName .. ") -> (Target: " .. entname .. ", Cmd: " .. cmd .. ", Delay:" .. tostring(delay) .. ", Param:" .. param .. ", Times: " .. tostring(times) .. ")") + + local triggerOutput = function() + local targetents + + if entname == "!activator" then + targetents = { activator } + elseif entname == "!caller" then + targetents = { caller } + elseif entname == "!self" then + targetents = { self } + elseif entname == "!player" or entname == "player" then + targetents = player.GetAll() + elseif entname == "!pvsplayer" then + ErrorNoHalt("Unhandled output targetname: " .. entname) + targetents = {} + else + targetents = ents.FindByName(entname) + end + + for _,ent in pairs(targetents) do + if IsValid(ent) then + DbgPrint("Firing " .. tostring(ent) .. "(" .. entname .. ") -> Cmd: " .. cmd .. ", Delay: " .. tostring(delay) .. ", Param: " .. param .. ", Times: " .. tostring(times) .. ")") + ent:Input(cmd, activator, caller, param) + else + DbgPrint("Firing Output: Ent (" .. tostring(entname) .. ") is invalid, can not trigger output!") + end + end + end + + -- With 0 it must be called this frame, timer.Simple delays everything. + if delay == 0 then + triggerOutput() + else + timer.Simple(delay, triggerOutput) + end + + if times > 0 and called >= times then + --DbgPrint("Removing output") + outputs[k] = nil + removedOutput = true + end + + end + + return outputs, removedOutput + + end + + function util.SimpleTriggerOutputs(outputs, activator, caller, param, self) + + --DbgPrint("Firing " .. tostring(table.Count(outputs)) .. " outputs") + + for k, data in pairs(outputs) do + + out = string.Split(data, ",") + + local entname = out[1] or "" + local cmd = out[2] or "" + local param = param + if out[3] and out[3] ~= "" then + param = out[3] + end + if IsEntity(param) and IsValid(param) then + param = param:GetName() + end + param = param or "" + + local delay = tonumber(out[4] or 0) + local times = tonumber(out[5] or "-1") + local called = 1 + + --[k].Times = outputs[k].Times or times + --times = outputs[k].Times + DbgPrint("Output: (Caller: " .. tostring(caller) .. ", " .. caller:GetName() .. ") -> (Target: " .. entname .. ", Cmd: " .. cmd .. ", Delay:" .. tostring(delay) .. ", Param:" .. param .. ", Times: " .. tostring(times) .. ")") + + timer.Simple(delay, function() + + local targetents + + if entname == "!activator" then + targetents = { activator } + elseif entname == "!caller" then + targetents = { caller } + elseif entname == "!self" then + targetents = { self } + elseif entname == "!player" or entname == "player" then + targetents = player.GetAll() + elseif entname == "!pvsplayer" then + ErrorNoHalt("Unhandled output targetname: " .. entname) + targetents = {} + else + targetents = ents.FindByName(entname) + end + + for _,ent in pairs(targetents) do + if IsValid(ent) then + + DbgPrint("Firing " .. tostring(ent) .. "(" .. entname .. ") -> Cmd: " .. cmd .. ", Delay: " .. tostring(delay) .. ", Param: " .. param .. ", Times: " .. tostring(times) .. ")") + ent:Input(cmd, activator, caller, param) + + else + --DbgPrint("Firing Output: Ent (" .. tostring(entname) .. ") is invalid, can not trigger output!") + end + end + + end) + + if times > 0 and called >= times then + --DbgPrint("Removing output") + outputs[k] = nil + end + + end + + return outputs + + end + + local ENTITY_OUTPUTS = + { + ["OnAnimationBegun"] = true, + ["OnAnimationDone"] = true, + ["OnIgnite"] = true, + ["OnBreak"] = true, + ["OnTakeDamage"] = true, + ["OnHealthChanged"] = true, + ["OnPhysCannonDetach"] = true, + ["OnPhysCannonAnimatePreStarted"] = true, + ["OnPhysCannonAnimatePullStarted"] = true, + ["OnPhysCannonAnimatePostStarted"] = true, + ["OnPhysCannonPullAnimFinished"] = true, + ["OnUser1"] = true, + ["OnUser2"] = true, + ["OnUser3"] = true, + ["OnUser4"] = true, + ["OnKilled"] = true, + ["OnMotionEnabled"] = true, + ["OnAwakened"] = true, + ["OnPhysGunOnlyPickup"] = true, + ["OnPlayerPickup"] = true, + ["OnPhysGunDrop"] = true, + ["OnPlayerUse"] = true, + ["OnHitByTank"] = true, + ["OnFinishInteractWithObject"] = true, + ["OnDamaged"] = true, + ["OnDeath"] = true, + ["OnHalfHealth"] = true, + ["OnHearWorld"] = true, + ["OnCacheInteraction"] = true, + ["OnNPCPickup"] = true, + ["OnHearPlayer"] = true, + ["OnHearCombat"] = true, + ["OnFoundEnemy"] = true, + ["OnLostEnemyLOS"] = true, + ["OnLostEnemy"] = true, + ["OnFoundPlayer"] = true, + ["OnLostPlayerLOS"] = true, + ["OnLostPlayer"] = true, + ["OnDamagedByPlayer"] = true, + ["OnDamagedByPlayerSquad"] = true, + ["OnDenyCommanderUse"] = true, + ["OnWake"] = true, + ["OnSpawnNPC"] = true, + ["OnAllSpawned"] = true, + ["OnAllLiveChildrenDead"] = true, + ["ImpactForce"] = true, + ["OnStartTouch"] = true, + ["OnTrigger"] = true, + ["OnTrigger1"] = true, + ["OnTrigger2"] = true, + ["OnTrigger3"] = true, + ["OnTrigger4"] = true, + ["OnTrigger5"] = true, + ["OnTrigger6"] = true, + ["OnTrigger7"] = true, + ["OnTrigger8"] = true, + ["OnTrigger9"] = true, + ["OnTrigger10"] = true, + ["OnTrigger11"] = true, + ["OnTrigger12"] = true, + ["OnTrigger13"] = true, + ["OnTrigger14"] = true, + ["OnTrigger15"] = true, + ["OnTrigger16"] = true, + ["OnStartTouchAll"] = true, + ["OnEndTouch"] = true, + ["OnEndTouchAll"] = true, + } + + function util.IsOutputValue(key) + for k, v in pairs(ENTITY_OUTPUTS) do + if k:iequals(key) then + return true + end + end + return false + end + + function util.TracePlayerHull(ply, origin) + + local mins, maxs = ply:OBBMins(), ply:OBBMaxs() + local height = maxs.z - mins.z + + local pos = origin or ply:GetPos() + + --DbgPrint(mins, maxs) + + local tr = util.TraceHull( + { + start = pos, + endpos = pos + Vector(0, 0, 1), + filter = function(ent) return not ent:IsPlayer() end, + mins = mins, + maxs = maxs, + mask = MASK_PLAYERSOLID, + }) + + debugoverlay.Cross(pos, 10, 7, Color(255, 255, 255), true) + + debugoverlay.Box(tr.HitPos, Vector(0, 0, 0), Vector(1, 1, 1), 7, Color(255, 0, 0)) + debugoverlay.Box(tr.StartPos, Vector(0, 0, 0), Vector(2, 2, 2), 7, Color(0, 255, 0)) + + --debugoverlay.Box(tr.HitPos, mins, maxs, 5 ) + + return tr + + end + + -- NOTE: If we still get stuck we should perhaps decrease this. + local STEP_SIZE = 1 + local STEP_ITERATIONS = 100 + + local function GetPlayerLineTrace(ply, dir, space, useCenter, swap) + + local pos = ply:GetPos() + + if useCenter == true or useCenter == nil then + pos = pos + ply:OBBCenter() + end + + local startPos = pos + (dir * space) + local endPos = pos + + if swap == true then + --DbgPrint("Swapped") + local tmp = startPos + startPos = endPos + endPos = tmp + end + + local tr = util.TraceLine({ + start = startPos, + endpos = endPos, + filter = function(ent) return ent:IsPlayer() end, + mask = MASK_DEADSOLID, + }) + + tr.TotalFraction = tr.Fraction + if tr.FractionLeftSolid > 0 then + tr.TotalFraction = tr.TotalFraction + (1 - tr.FractionLeftSolid) + end + + debugoverlay.Line(startPos, endPos, 5, Color(255, 0, 0), true ) + + return tr + + end + + function util.PlayerUnstuck(ply) + + local mins, maxs = ply:OBBMins(), ply:OBBMaxs() + + local vecUp = Vector(0, 0, 1) --ply:GetUp() + local vecRight = Vector(0, 1, 0) --ply:GetRight() + local vecFwd = Vector(1, 0, 0) --ply:GetForward() + + local height = (maxs.z - mins.z) * 3 + local width = (maxs.y - mins.y) * 2 + + local plyPos = ply:GetPos() + local offset = Vector(0, 0, 0) + + --local i = 1 + local iterations = 0 + + for i = 0, STEP_ITERATIONS do + + local tr = util.TracePlayerHull(ply) + if tr.Fraction == 1 then + break + end + + local traces = + { + Up = GetPlayerLineTrace(ply, vecUp, height, true, true), -- z + Down = GetPlayerLineTrace(ply, vecUp, -height, true, true), -- z + Forward = GetPlayerLineTrace(ply, -vecFwd, width, true, true), -- x + Back = GetPlayerLineTrace(ply, vecFwd, width, true, true), -- x + Right = GetPlayerLineTrace(ply, vecRight, width, true, true), -- y + Left = GetPlayerLineTrace(ply, -vecRight, width, true, true), -- y + } + + if fractions == 6 then + --DbgPrint("No more solving required") + break + end + + --DbgPrint("Left: " .. traces.Left.Fraction) + --DbgPrint("Right: " .. traces.Right.Fraction) + + if traces.Left.TotalFraction > traces.Right.TotalFraction then + offset.y = offset.y - (STEP_SIZE + traces.Left.TotalFraction) + --DbgPrint("Moving to left") + end + + if traces.Right.TotalFraction > traces.Left.TotalFraction then + offset.y = offset.y + (STEP_SIZE + traces.Right.TotalFraction) + --DbgPrint("Moving to right") + end + + if traces.Forward.TotalFraction > traces.Back.TotalFraction then + offset.x = offset.x - (STEP_SIZE + traces.Forward.TotalFraction) + --DbgPrint("Moving forward") + end + + if traces.Back.TotalFraction > traces.Forward.TotalFraction then + offset.x = offset.x + (STEP_SIZE + traces.Back.TotalFraction) + --DbgPrint("Moving back") + end + + if traces.Up.TotalFraction > traces.Down.TotalFraction then + offset.z = offset.z + (STEP_SIZE + traces.Up.TotalFraction) + --DbgPrint("Moving Up") + end + + if traces.Down.TotalFraction > traces.Up.TotalFraction then + offset.z = offset.z - (STEP_SIZE + traces.Down.TotalFraction ) + --DbgPrint("Moving down") + end + + ply:SetPos(plyPos + offset) + + iterations = iterations + 1 + + end + + DbgPrint("Solved within " .. iterations .. " iterations") + + end + + function util.IsEntVisibleToPlayers(ent) + + for _,v in pairs(player.GetAll()) do + if v:Visible(ent) == true then + return true + end + end + + return false + + end + + function util.IsPosVisibleToPlayers(pos) + + for _,v in pairs(player.GetAll()) do + if v:VisibleVec(pos) == true then + return true + end + end + + return false + + end + +else -- CLIENT + + function util.ScreenScaleH(n) + return n * (ScrH() / 480) + end + + function util.ScreenScaleW(n) + return ScreenScale(n) + end + +end + +local thinkCount = 0 +local funcQueue = {} + +hook.Add("Think", "LambdaRunNextFrame", function() + + for k,v in ipairs(funcQueue) do + if v.thinkId == thinkCount then + -- In case it was added before Think was called. + continue + end + v.func() + table.remove(funcQueue, k) + end + + thinkCount = thinkCount + 1 + +end) + +function util.RunNextFrame(func) + + local data = + { + func = func, + thinkId = thinkCount, + } + table.insert(funcQueue, data) + +end + +function util.RandomFloat(min, max) + + return min + (math.random() * (max - min)) + +end + +function util.RandomInt(min, max) + + -- This sucks, who cares tho. + return math.Clamp(math.Round(math.random(min, max)), min, max) + +end diff --git a/gamemode/sh_vehicles.lua b/gamemode/sh_vehicles.lua new file mode 100644 index 00000000..65bf9162 --- /dev/null +++ b/gamemode/sh_vehicles.lua @@ -0,0 +1,537 @@ +-- Those are the returned collision bounds for the airboat, big enough to work on the jeep. +local DbgPrint = GetLogging("Vehicle") + +local VEHICLE_MINS = Vector(-150.0000, -150.0000, -40.0000) +local VEHICLE_MAXS = Vector(150.0000, 150.0000, 150.0000) +local VEHICLE_THINK = 1 + +local VEHICLE_SPAWN_MINS = Vector(-85, -132, -40) +local VEHICLE_SPAWN_MAXS = Vector(85, 104, 110) + +local VEHICLE_JEEP = 0 +local VEHICLE_AIRBOAT = 1 +local VEHICLE_JALOPY = 2 + +if SERVER then + + AddCSLuaFile() + + function GM:InitializeMapVehicles() + + DbgPrint("InitializeMapVehicles") + + -- Because autoreload.. + self.ActiveVehicles = {} + self.MapVehicles = {} + self.SpawnPlayerVehicles = true + + local mapdata = game.GetMapData() + for _,v in pairs(mapdata.Entities) do + if v["classname"] == "prop_vehicle_airboat" then + table.insert(self.MapVehicles, v) + elseif v["classname"] == "prop_vehicle_jeep" and v["model"] == "models/buggy.mdl" then + table.insert(self.MapVehicles, v) + elseif v["classname"] == "prop_vehicle_jalopy" then + table.insert(self.MapVehicles, v) + end + end + + + end + + function GM:CleanUpVehicles() + + DbgPrint("Cleaning up vehicles..") + for k,_ in pairs(self.ActiveVehicles) do + if IsValid(k) then + DbgPrint("Removing vehicle: " .. tostring(k)) + k:Remove() + + local ply = k.LambdaPlayer + if IsValid(ply) and ply.OwnedVehicle == k then + ply.OwnedVehicle = nil + end + + else + DbgPrint("Vehicle " .. tostring(k) .. " invalid") + end + end + + end + + function GM:SetVehicleCheckpoint(pos, ang) + + self.VehicleCheckpoint = { Pos = pos, Ang = ang } + + end + + function GM:ResetVehicleCheckpoint() + + self.VehicleCheckpoint = nil + + end + + local function SpawnAirboatSeat(airboat, localPos, localAng) + + local pos = airboat:LocalToWorld(localPos) + local ang = airboat:LocalToWorldAngles(localAng) + + local seat = ents.Create("prop_vehicle_prisoner_pod") + seat:SetModel("models/nova/airboat_seat.mdl") + seat:SetPos(pos) + seat:SetAngles(ang) + seat:SetParent(airboat) + seat:Spawn() + + end + + function GM:HandleVehicleCreation(vehicle) + + DbgPrint("HandleVehicleCreation") + + local class = vehicle:GetClass() + local vehicleType = nil + + if class ~= "prop_vehicle_airboat" and class ~= "prop_vehicle_jeep" then + return + end + + -- This has to be set this frame. + if self.MapScript.VehicleGuns == true then + DbgPrint("Enabling Gun") + vehicle:SetKeyValue("EnableGun", "1") + else + DbgPrint("No guns enabled") + end + + -- We only get a model next frame, delay it. + local self = self + local vehicle = vehicle + + util.RunNextFrame(function() + + if not IsValid(vehicle) then + return + end + + local mdl = vehicle:GetModel() + if class == "prop_vehicle_airboat" and mdl == "models/airboat.mdl" then + vehicleType = VEHICLE_AIRBOAT + elseif class == "prop_vehicle_jeep" and mdl == "models/buggy.mdl" then + vehicleType = VEHICLE_JEEP + else + return + end + + self.ActiveVehicles[vehicle] = true + + vehicle:SetCustomCollisionCheck(true) + vehicle:CallOnRemove("LambdaVehicleCleanup", function(ent) + self.ActiveVehicles[ent] = nil + local ply = ent.LambdaPlayer + if IsValid(ply) and ply.OwnedVehicle == ent then + ply.OwnedVehicle = nil + end + end) + + local tracker = ents.Create("lambda_vehicle_tracker") + tracker:AttachToVehicle(vehicle) + tracker:Spawn() + + if vehicleType == VEHICLE_JEEP then + self:HandleJeepCreation(vehicle) + elseif vehicleType == VEHICLE_AIRBOAT then + self:HandleAirboatCreation(vehicle) + end + + end) + + end + + function GM:HandleJeepCreation(jeep) + + if IsValid(jeep.PassengerSeat) then + return + end + + local seat = ents.Create("prop_vehicle_prisoner_pod") + seat:SetPos(jeep:LocalToWorld(Vector(19.369112, -37.018456, 18.896046))) + seat:SetAngles(jeep:LocalToWorldAngles(Angle(-0.497, -3.368, 0.259))) + seat:SetModel("models/nova/jeep_seat.mdl") + seat:SetParent(jeep) + seat:Spawn() + seat.IsPassengerSeat = true + + jeep.PassengerSeat = seat + + end + + function GM:HandleAirboatCreation(airboat) + + end + + function GM:PlayerEnteredVehicle(ply, vehicle, role) + + if vehicle:GetClass() == "prop_vehicle_jeep" or + vehicle:GetClass() == "prop_vehicle_airboat" or + vehicle:GetClass() == "prop_vehicle_jalopy" + then + + if vehicle.LambdaPlayer ~= nil and vehicle.LambdaPlayer ~= ply then + DbgError("Bogus vehicle logic: Player entering vehicle that does not belong to him") + elseif vehicle.LambdaPlayer == nil then + -- Now belongs to the specific player. + DbgPrint("Player " .. tostring(ply) .. " gets ownership of vehicle: " .. tostring(vehicle)) + + vehicle.LambdaPlayer = ply + ply.OwnedVehicle = vehicle + + ply:SetNW2Entity("LambdaOwnedVehicle", vehicle) + + end + + end + + end + + function GM:PlayerLeaveVehicle(ply, vehicle) + + -- Reset, we disabled it for transition probably + DbgPrint("Player leave: " .. tostring(ply)) + + if vehicle.ResetVehicleEntryAnim == true then + vehicle:SetVehicleEntryAnim(true) + end + + if ply:Alive() == false then + DbgPrint("Player who left is now dead, we shall remove this") + + -- We give the driver a chance to pick up this vehicle. + if IsValid(vehicle.PassengerSeat) then + local passenger = vehicle.PassengerSeat:GetDriver() + if IsValid(passenger) and passenger:IsPlayer() then + DbgPrint("Giving passenger temporary ownership of vehicle") + vehicle.LambdaPlayer = nil + vehicle.LambdaAllowEnter = passenger + + ply.OwnedVehicle = nil + ply:SetNW2Entity("LambdaOwnedVehicle", nil) + + end + end + + end + + if ply:Alive() and vehicle.IsPassengerSeat == true then + + local ang = vehicle:GetAngles() + local pos = vehicle:GetPos() + local exitpos = pos + (ang:Forward() * 50) + + -- Look towards the seat. + local exitang = (pos - exitpos):Angle() + + ply:SetPos(exitpos) + ply:SetEyeAngles(exitang) + ply:SetAllowWeaponsInVehicle(false) + + vehicle:GetParent().Passenger = nil + + end + + end + + function GM:CanPlayerEnterVehicle(ply, vehicle, role) + + if ply.OwnedVehicle ~= nil and IsValid(ply.OwnedVehicle) == false then + -- Just to make sure, its possible it might error somewhere and did not unassign it. + ply.OwnedVehicle = nil + end + + if vehicle:GetClass() == "prop_vehicle_jeep" or + vehicle:GetClass() == "prop_vehicle_airboat" or + vehicle:GetClass() == "prop_vehicle_jalopy" then + + if vehicle.LambdaPlayer == nil and ply.OwnedVehicle == nil then + -- Not yet owned. + return true + elseif vehicle.LambdaPlayer == nil and ply.OwnedVehicle ~= nil then + if vehicle.LambdaAllowEnter == ply then + -- Important to set this, RemovePlayerVehicles cleans up those where we are allowed to enter. + vehicle.LambdaAllowEnter = nil + -- Remove his old vehicle. + self:RemovePlayerVehicles(ply) + return true + end + -- TODO: Add notification of whats happening. + return false + elseif vehicle.LambdaPlayer ~= nil then + -- Check if we own the vehicle. + if vehicle.LambdaPlayer == ply then + DbgPrint("Player can enter") + return true + else + DbgPrint("Player not allowed to enter") + return false + end + end + + end + + if vehicle.IsPassengerSeat == true then + vehicle:SetKeyValue("limitview", "0") + ply:SetAllowWeaponsInVehicle(true) + else + ply:SetAllowWeaponsInVehicle(false) + end + + return true + + end + + function GM:RemovePlayerVehicles(ply) + + DbgPrint("GM:RemovePlayerVehicles", ply) + + for vehicle,_ in pairs(self.ActiveVehicles) do + if vehicle.LambdaPlayer == ply then + DbgPrint("Removing player vehicle: " .. tostring(vehicle)) + vehicle:Remove() + elseif vehicle.LambdaAllowEnter == ply and vehicle.LambdaPlayer == nil then + DbgPrint("Passenger took no ownership of the vehicle, no owner, removing.") + vehicle:Remove() + end + end + + ply.OwnedVehicle = nil + ply:SetNW2Entity("LambdaOwnedVehicle", nil) + + end + + function GM:SetSpawnPlayerVehicles(state) + self.SpawnPlayerVehicles = state + if self.SpawnPlayerVehicles == nil then + self.SpawnPlayerVehicles = true + end + end + + function GM:CanSpawnVehicle() + + local alivePlayers = 0 + local playerCount = 0 + + for _,v in pairs(player.GetAll()) do + if v:Alive() then + alivePlayers = alivePlayers + 1 + end + playerCount = playerCount + 1 + end + + if alivePlayers == 0 then + return false + end + + if self.SpawnPlayerVehicles ~= true then + return false + end + + if table.Count(self.ActiveVehicles) < playerCount then + return true + end + + return false + + end + + function GM:SpawnVehicleAtSpot(vehicle) + + local pos = util.StringToType(vehicle["origin"], "Vector") + if self.VehicleCheckpoint ~= nil then + pos = self.VehicleCheckpoint.Pos + end + + -- Check if there is already one. + local nearbyEnts = ents.FindInBox(pos + VEHICLE_SPAWN_MINS, pos + VEHICLE_SPAWN_MAXS) + for _,v in pairs(nearbyEnts) do + if v:GetClass() == vehicle["classname"] then + -- We normally dont want this, but its possible to spawn two of them at the same spot. + -- TODO: Create a convar and let the server owner decide. + return false + elseif v:IsPlayer() then + -- The box is somewhat big, we should deal with players standing directly in the way. + end + end + + local newVehicle = ents.CreateFromData(vehicle) + if self.VehicleCheckpoint ~= nil then + newVehicle:SetPos(self.VehicleCheckpoint.Pos) + newVehicle:SetAngles(self.VehicleCheckpoint.Ang) + end + if self.EnableVehicleGuns then + newVehicle:SetKeyValue("EnableGun", "1") + end + newVehicle:Spawn() + newVehicle:Activate() + + DbgPrint("Created new vehicle: " .. tostring(newVehicle)) + + end + + function GM:VehiclesThink() + + if self:IsRoundRunning() == false and self:RoundElapsedTime() >= 1 then + return + end + + local curTime = CurTime() + self.NextVehicleThink = self.NextVehicleThink or (curTime + VEHICLE_THINK) + + if curTime < self.NextVehicleThink then + return + end + self.NextVehicleThink = curTime + VEHICLE_THINK + + if self:CanSpawnVehicle() then + + for _,v in pairs(self.MapVehicles) do + self:SpawnVehicleAtSpot(v) + end + + end + + -- Make sure we clean up vehicles from disconnected players. + for vehicle,_ in pairs(self.ActiveVehicles) do + + if vehicle.LambdaPlayer ~= nil then + local ply = vehicle.LambdaPlayer + if not IsValid(ply) then + DbgPrint("Removing player vehicle") + vehicle:Remove() + end + end + + end + + end + +else -- CLIENT + + local VEHICLE_LIST = {} + + function GM:RenderVehicleStatus() + + local ply = LocalPlayer() + if not IsValid(ply) then + return + end + + local vehicle = ply:GetNW2Entity("LambdaOwnedVehicle") + if IsValid(vehicle) then + -- Show vehicle of player if not inside. + if ply:InVehicle() and ply:GetVehicle() == vehicle then + return + end + + + else + -- Show all available vehicles. + + end + + end + + function GM:CalcVehicleView(Vehicle, ply, view) + local viewPos = view.origin + local headBone = ply:LookupBone("ValveBiped.Bip01_Head1") + + if headBone ~= nil then + viewPos, _ = ply:GetBonePosition(headBone) + end + + if ply.VehicleSteeringView == true then + view.origin = viewPos + (view.angles:Forward() * 3) + end + + return view + end + +end + +function GM:VehicleShouldCollide(veh1, veh2) + + -- FIXME: When vehicles initially intersect they shouldn't collide as long they do. + do + return + end + +end + +local function HandleVehiclePositionLock(ply, vehicle, cmd) + + if ply:IsPositionLocked() == true then + cmd:SetButtons(0) + local phys = vehicle:GetPhysicsObject() + if IsValid(phys) then + local vel = phys:GetVelocity() + local len = vel:Length() + + if vel:Length() >= 1 then + vel = vel - (vel * 0.02) + phys:SetVelocity(vel) + end + + if len < 50 then + vehicle:Fire("HandBrakeOn") + end + end + end + +end + +function GM:VehicleMove(ply, vehicle, mv) + + -- We have to call it here because PlayerTick wont be called if we are inside a vehicle. + self:UpdateSuit(ply, mv) + + -- + -- On duck toggle third person view + -- + if mv:KeyPressed( IN_DUCK ) and vehicle.SetThirdPersonMode then + vehicle:SetThirdPersonMode( not vehicle:GetThirdPersonMode() ) + end + + -- + -- Adjust the camera distance with the mouse wheel + -- + local iWheel = ply:GetCurrentCommand():GetMouseWheel() + if iWheel ~= 0 and vehicle.SetCameraDistance then + -- The distance is a multiplier + -- Actual camera distance = ( renderradius + renderradius * dist ) + -- so -1 will be zero.. clamp it there. + local newdist = math.Clamp( vehicle:GetCameraDistance() - iWheel * 0.03 * ( 1.1 + vehicle:GetCameraDistance() ), -1, 10 ) + vehicle:SetCameraDistance( newdist ) + end + + if ply:IsPositionLocked() ~= true then + return + end + + mv:SetButtons(0) + local phys = vehicle:GetPhysicsObject() + if IsValid(phys) then + local vel = phys:GetVelocity() + local len = vel:Length() + + if vel:Length() >= 1 then + vel = vel - (vel * 0.015) + phys:SetVelocity(vel) + end + + if len < 50 then + if vehicle:GetClass() == "prop_vehicle_jeep" or vehicle:GetClass() == "prop_vehicle_jalopy" then + vehicle:Fire("HandBrakeOn") + end + end + end + +end diff --git a/gamemode/shared.lua b/gamemode/shared.lua new file mode 100644 index 00000000..ef4cbbed --- /dev/null +++ b/gamemode/shared.lua @@ -0,0 +1,201 @@ +AddCSLuaFile() + +GM.Name = "Lambda" +GM.Author = "N/A" +GM.Email = "N/A" +GM.Website = "N/A" + +DEFINE_BASECLASS( "gamemode_base" ) + +include("sh_debug.lua") +include("sh_string_extend.lua") + +include("sh_player_list.lua") +include("sh_mapdata.lua") +include("sh_utils.lua") +include("sh_convars.lua") +include("sh_ents_extend.lua") +include("sh_npc_extend.lua") +include("sh_player_extend.lua") +include("sh_entity_extend.lua") +include("sh_roundsystem.lua") +include("sh_sound_env.lua") +include("sh_vehicles.lua") +include("sh_sound_env.lua") +include("sh_temp.lua") +include("sh_bullets.lua") +include("sh_timestamp.lua") + +include("sh_lambda.lua") +include("sh_lambda_npc.lua") +include("sh_lambda_player.lua") +include("sh_animations.lua") +include("sh_spectate.lua") + +--Disabled for now +--include("sh_gibs.lua") + +include("sh_gametypes.lua") + +local DbgPrint = GetLogging("Shared") + +function GM:Tick() + + if CLIENT then + self:HUDTick() + end + +end + +function GM:Think() + + if SERVER then + self:CheckPlayerTimeouts() + self:RoundThink() + self:VehiclesThink() + self:NPCThink() + + for _,v in pairs(player.GetAll()) do + self:PlayerThink(v) + end + end + +end + +function GM:OnReloaded() + + if CLIENT then + self:HUDInit() + end + +end + +function GM:Initialize() + + self:LoadGameTypes() + self:SetGameType(lambda_gametype:GetString()) + + self:InitializePlayerList() + self:InitializeRoundSystem() + + if SERVER then + self:InitializeDifficulty() + if self.InitializeSkybox then + self:InitializeSkybox() + end + self:InitializeCurrentLevel() + self:TransferPlayers() + end + +end + +function GM:ClearGlobalState() + + local gordon_invulnerable = ents.Create("env_global") + gordon_invulnerable:SetKeyValue("globalstate", "gordon_invulnerable") + gordon_invulnerable:SetKeyValue("initialstate", "0") + gordon_invulnerable:Spawn() + gordon_invulnerable:Fire("TurnOff") + + local gordon_precriminal = ents.Create("env_global") + gordon_precriminal:SetKeyValue("globalstate", "gordon_precriminal") + gordon_precriminal:SetKeyValue("initialstate", "0") + gordon_precriminal:Spawn() + gordon_precriminal:Fire("TurnOff") + +end + +function GM:InitPostEntity() + + DbgPrint("GM:InitPostEntity") + + if SERVER then + self:ClearGlobalState() + self:PostLoadTransitionData() + self:InitializeMapVehicles() + if self.PostInitializeSkybox then + self:PostInitializeSkybox() + end + self:SetRoundBootingComplete() + self.InitPostEntityDone = true + else + self:HUDInit() + end + +end + +function GM:ShouldCollide(ent1, ent2) + + if ent1:IsPlayer() and ent2:IsPlayer() then + return false + elseif (ent1:IsNPC() and ent2:GetClass() == "trigger_changelevel") or + (ent2:IsNPC() and ent1:GetClass() == "trigger_changelevel") + then + return false + end + + return true + +end + +function GM:EntityKeyValue(ent, key, val) + + ent.LambdaKeyValues = ent.LambdaKeyValues or {} + + if util.IsOutputValue(key) then + ent.EntityOutputs = ent.EntityOutputs or {} + ent.EntityOutputs[key] = ent.EntityOutputs[key] or {} + table.insert(ent.EntityOutputs[key], val) + else + ent.LambdaKeyValues[key] = val + end + + if SERVER then + local res + res = self:RoundSystemEntityKeyValue(ent, key, val) + if res ~= nil then + return res + end + end + + if self.MapScript.EntityKeyValue then + res = self.MapScript:EntityKeyValue(ent, key, val) + if res ~= nil then + return res + end + end + +end + +function GM:ApplyCorrectedDamage(dmginfo) + + local attacker = dmginfo:GetAttacker() + + if IsValid(attacker) and dmginfo:IsDamageType(DMG_BULLET) then + + local weaponTable = nil + local wep = nil + + if attacker:IsPlayer() then + weaponTable = self.PLAYER_WEAPON_DAMAGE + wep = attacker:GetActiveWeapon() + elseif attacker:IsNPC() then + weaponTable = self.NPC_WEAPON_DAMAGE + wep = attacker:GetActiveWeapon() + end + + if weaponTable ~= nil and IsValid(wep) then + local class = wep:GetClass() + local dmgCVar = weaponTable[class] + if dmgCVar ~= nil then + local dmgAmount = dmgCVar:GetInt() + --DbgPrint("Setting modified weapon damage " .. tostring(dmgAmount) .. " on " .. class) + dmginfo:SetDamage(dmgAmount) + end + end + + end + + return dmginfo + +end diff --git a/gamemode/sv_changelevel.lua b/gamemode/sv_changelevel.lua new file mode 100644 index 00000000..0216fe09 --- /dev/null +++ b/gamemode/sv_changelevel.lua @@ -0,0 +1,228 @@ +local DbgPrint = GetLogging("Level") +local g_debug_transitions = GetConVar("g_debug_transitions") + +function GM:InitializeCurrentLevel() + + DbgPrint("GM:InitializeCurrentLevel") + + local changelevel = tobool(util.GetPData("Lambda", "Changelevel", "0")) + local prevMap = util.GetPData("Lambda", "PrevMap", nil) + local targetMap = util.GetPData("Lambda", "NextMap", nil) + local landmark = util.GetPData("Lambda", "Landmark", nil) + + self.PreviousMap = prevMap + if targetMap == self:GetCurrentMap() then + self.EntryLandmark = landmark + else + self.EntryLandmark = nil + end + + if changelevel == true and targetMap == self:GetCurrentMap() then + -- Reset + self.IsChangeLevel = true + else + self.IsChangeLevel = false + end + + util.RemovePData("Lambda", "Changelevel") + util.RemovePData("Lambda", "Landmark") + util.RemovePData("Lambda", "PrevMap") + + DbgPrint("Used Changelevel: " .. tostring(self.IsChangeLevel)) + + self:InitializeTransitionData() + +end + +function GM:DisablePreviousMap() + + DbgPrint("GM:DisablePreviousMap") + + local landmark = self:GetEntryLandmark() + local prevMap = self:GetPreviousMap() + + for _,v in pairs(ents.FindByClass("trigger_changelevel")) do + + if v.TargetMap == nil then + continue + end + + if v:HasSpawnFlags(SF_CHANGELEVEL_NOTOUCH) then + continue + end + + if landmark ~= nil then + if v.Landmark ~= nil and v.Landmark ~= "" then + if v.Landmark == landmark then + DbgPrint("Disabling previous changelevel: " .. v.Landmark) + v:SetBlocked(true) + end + else + if v.TargetMap == prevMap then + DbgPrint("Disabling previous changelevel: " .. v.Landmark) + v:SetBlocked(true) + end + end + else + if v.TargetMap == prevMap then + DbgPrint("Blocking previous map (assumed): " .. prevMap) + v:SetBlocked(true) + end + end + + end + +end + +function GM:EnablePreviousMap() + + DbgPrint("GM:EnablePreviousMap") + + local landmark = self:GetEntryLandmark() + local prevMap = self:GetPreviousMap() + + for _,v in pairs(ents.FindByClass("trigger_changelevel")) do + + if v.TargetMap == nil then + continue + end + + if v.DisableTouch == true then + continue + end + + if landmark ~= nil then + if v.Landmark == landmark then + DbgPrint("Enabling previous changelevel: " .. v.Landmark) + v:SetBlocked(false) + v:Enable() + end + else + if v.TargetMap == prevMap then + DbgPrint("Enabling previous map (assumed): " .. prevMap) + v:SetBlocked(false) + v:Enable() + end + end + + end + +end + +function GM:PreChangelevel(map, landmark, playersInTrigger) + + util.SetPData("Lambda", "PrevMap", self:GetCurrentMap()) + util.SetPData("Lambda", "NextMap", map) + util.SetPData("Lambda", "Landmark", landmark) + util.SetPData("Lambda", "Changelevel", "1") + + -- Serialize user infos. + if self.MapScript ~= nil and self.MapScript.PreChangelevel then + self.MapScript:PreChangelevel(map, landmark) + end + + hook.Call("LambdaPreChangelevel", GAMEMODE, map, landmark) + + self:TransitionToLevel(map, landmark, playersInTrigger) + +end + +function GM:GetNextMap() + + local gameType = self:GetGameType() + local mapList = gameType.MapList + + local current = self:GetCurrentMapIndex() + if current + 1 > #mapList then + return nil + end + return mapList[current + 1] + +end + +function GM:GetPreviousMap() + + local gameType = self:GetGameType() + local mapList = gameType.MapList + + local current = self:GetCurrentMapIndex() + if current - 1 < 0 then + return nil + end + return mapList[current - 1] + +end + +function GM:GetCurrentMap() + local curMap = string.lower(game.GetMap()) + return curMap +end + +function GM:GetEntryLandmark() + return self.EntryLandmark or nil +end + +function GM:GetMapIndex(prevMap, currentMap) + + local gameType = self:GetGameType() + local mapList = gameType.MapList + + DbgPrint("Getting Map Index, Prev: " .. tostring(prevMap) .. ", Cur: " .. currentMap) + local foundPrev = false + local lastIndex = 0 + + for k, v in pairs(mapList) do + if foundPrev then + if v == currentMap then + return k + end + foundPrev = false + end + + if v == currentMap then + lastIndex = k -- In case there was a huge jump due a manual changelevel by user. + end + + if v == prevMap then + foundPrev = true + elseif prevMap == nil and v == currentMap then + return k + end + end + + return lastIndex + +end + +function GM:GetCurrentMapIndex() + local curMap = self:GetCurrentMap() + local index = self:GetMapIndex( self.PreviousMap, curMap ) + DbgPrint("GetCurrentMapIndex: " .. tostring(index)) + return index +end + +if SERVER then + + function GM:ChangeLevel(map, landmark, playersInTrigger) + + if self.ChangingLevel == true then + DbgError("Called ChangeLevel twice!") + return + end + + self.ChangingLevel = true + + DbgPrint("Changing to level: " .. map) + + self:PreChangelevel(map, landmark, playersInTrigger) + + local map = map + if g_debug_transitions:GetBool() ~= true then + --timer.Simple(0.1, function() + game.ConsoleCommand("changelevel " .. map .. "\n") + --end) + end + + end + +end diff --git a/gamemode/sv_commands.lua b/gamemode/sv_commands.lua new file mode 100644 index 00000000..07f23fb7 --- /dev/null +++ b/gamemode/sv_commands.lua @@ -0,0 +1,41 @@ +local function PlayerNoTarget(ply, cmd, args, argStr) + local flags = ply:GetFlags() + if bit.band(flags, FL_NOTARGET) ~= 0 then + DbgPrint("Player: " .. tostring(ply) .. " target") + ply:SetNoTarget(false) + else + DbgPrint("Player: " .. tostring(ply) .. " notarget") + ply:SetNoTarget(true) + end +end +concommand.Add("lambda_notarget", PlayerNoTarget, nil, nil, bit.bor(FCVAR_CHEAT, FCVAR_CLIENTCMD_CAN_EXECUTE)) + +local function RestartLevel(ply, cmd, args) + if !ply:IsAdmin() then return end + local curmap = game.GetMap() + game.ConsoleCommand("changelevel " .. curmap .. "\n") +end +concommand.Add("lambda_restart", RestartLevel, nil, nil, bit.bor(FCVAR_CLIENTCMD_CAN_EXECUTE)) + +local function PreviousLevel(ply, cmd, args) + if !ply:IsAdmin() then return end + local curmap = game.GetMap() + local prevmap = table.FindPrev(GAMEMODE.MapList,curmap) + game.ConsoleCommand("changelevel " .. prevmap .. "\n") +end +concommand.Add("lambda_prevmap", PreviousLevel, nil, nil, bit.bor(FCVAR_CLIENTCMD_CAN_EXECUTE)) + +local function NextLevel(ply, cmd, args) + if !ply:IsAdmin() then return end + local curmap = game.GetMap() + local nextmap = table.FindNext(GAMEMODE.MapList,curmap) + game.ConsoleCommand("changelevel " .. nextmap .. "\n") +end +concommand.Add("lambda_nextmap", NextLevel, nil, nil, bit.bor(FCVAR_CLIENTCMD_CAN_EXECUTE)) + +local function ResetLevel(ply, cmd, args) + if !ply:IsAdmin() then return end + GAMEMODE:CleanUpMap() + DbgPrint("Lambda_RESET: Map cleanup and reset") +end +concommand.Add("lambda_reset", ResetLevel, nil, nil, bit.bor(FCVAR_CLIENTCMD_CAN_EXECUTE)) diff --git a/gamemode/sv_difficulty.lua b/gamemode/sv_difficulty.lua new file mode 100644 index 00000000..f7767948 --- /dev/null +++ b/gamemode/sv_difficulty.lua @@ -0,0 +1,157 @@ +local DbgPrint = GetLogging("Difficulty") + +function GM:InitializeDifficulty() + + DbgPrint("GM:InitializeDifficulty") + + self.RoundNumber = 0 + + self.PlayerDeaths = 1 + self.PlayerKills = 1 + self.PlayerBulletsFired = 0 + self.PlayerFitness = 1 + self.PlayerFitnessScale = 0.2 + + self.NPCDeaths = 1 + self.NPCKills = 1 + self.NPCFitness = 1 + self.NPCBulletsFired = 0 + self.NPCAwareness = 0 + self.NPCDamage = 1 + self.PlayerDamage = 1 + self.RoundsLost = 1 + self.RoundsWon = 1 + + --self:CalculateDifficulty() + +end + +function GM:SaveTransitionDifficulty(data) + data.RoundNumber = self.RoundNumber + data.PlayerDeaths = self.PlayerDeaths + data.PlayerKills = self.PlayerKills + data.PlayerBulletsFired = self.PlayerBulletsFired + data.PlayerFitness = self.PlayerFitness + data.PlayerFitnessScale = self.PlayerFitnessScale + data.NPCDeaths = self.NPCDeaths + data.NPCKills = self.NPCKills + data.NPCFitness = self.NPCFitness + data.NPCBulletsFired = self.NPCBulletsFired + data.NPCAwareness = self.NPCAwareness + data.PlayerDamage = self.PlayerDamage + data.NPCDamage = self.NPCDamage + data.RoundsLost = self.RoundsLost + data.RoundsWon = self.RoundsWon +end + +function GM:LoadTransitionDifficulty(data) + self.RoundNumber = data.RoundNumber + self.PlayerDeaths = data.PlayerDeaths + self.PlayerKills = data.PlayerKills + self.PlayerBulletsFired = data.PlayerBulletsFired + self.PlayerFitness = data.PlayerFitness + self.PlayerFitnessScale = data.PlayerFitnessScale + self.NPCDeaths = data.NPCDeaths + self.NPCKills = data.NPCKills + self.NPCFitness = data.NPCFitness + self.NPCBulletsFired = data.NPCBulletsFired + self.NPCAwareness = data.NPCAwareness + self.PlayerDamage = data.PlayerDamage + self.NPCDamage = data.NPCDamage + self.RoundsLost = data.RoundsLost + self.RoundsWon = data.RoundsWon + + --self:CalculateDifficulty() +end + +function GM:RegisterBulletFired(attacker, bullets) + +end + +function GM:RegisterNPCDamage(npc, attacker, dmginfo) + +end + +function GM:RegisterPlayerDamage(ply, attacker, dmginfo) +end + +function GM:RegisterRoundLost() + self.RoundsLost = self.RoundsLost + 1 +end + +function GM:RegisterRoundWon() + self.RoundsWon = self.RoundsWon + 1 +end + +function GM:GetPVN() + -- FIXME: Add some scaling that doesnt suck. + return 1 +end + +function GM:GetNVP() + -- FIXME: Add some scaling that doesnt suck. + return 1 +end + +function GM:RegisterPlayerDeath(ply, attacker, inflictor) +end + +function GM:RegisterNPCDeath(npc, attacker, inflictor) +end + +function GM:GetDifficultyPlayerDamageScale(attacker) + + local scale = self:GetNVP() + return scale + +end + +function GM:GetDifficultyNPCDamageScale() + + local scale = self:GetPVN() + return scale + +end + +function GM:GetDifficulty() + + return 3 + +end + +function GM:AdjustDifficulty() + + if player.GetCount() == 0 then + -- calling game.SetSkilLLevel can crash if gamesrules is nullptr, so we just use it once players are around. + return + end + + local difficulty = self:GetDifficulty() + + DbgPrint("Difficulty: " .. difficulty) + + game.SetSkillLevel(difficulty) + + for k,v in pairs(self.EnemyNPCs or {}) do + if IsValid(v) then + self:AdjustNPCDifficulty(v, difficulty) + end + end + +end + +local WEAPON_PROFICIENCY = +{ + WEAPON_PROFICIENCY_AVERAGE, + WEAPON_PROFICIENCY_GOOD, + WEAPON_PROFICIENCY_PERFECT, +} + +function GM:AdjustNPCDifficulty(npc, difficulty) + + difficulty = difficulty or self:GetDifficulty() + local proficiency = WEAPON_PROFICIENCY[difficulty] + + npc:SetCurrentWeaponProficiency(proficiency) + +end diff --git a/gamemode/sv_generic_fixes.lua b/gamemode/sv_generic_fixes.lua new file mode 100644 index 00000000..28c247c8 --- /dev/null +++ b/gamemode/sv_generic_fixes.lua @@ -0,0 +1,44 @@ +local Dbgprint = GetLogging("Generic") + +local function ReplaceFuncTankVolume(ent, volname) + + --DbgPrint("Replacing control volume: " .. volname) + + local ent = ent + local newName = "coop" .. volname + + ents.WaitForEntityByName(volname, function(vol) + + DbgPrint("Replacing control volume for: " .. tostring(ent)) + + local newVol = ents.Create("trigger") -- Yes this actually exists and it has what func_tank needs. + newVol:SetKeyValue("StartDisabled", "0") + newVol:SetKeyValue("spawnflags", vol:GetSpawnFlags()) + newVol:SetModel(vol:GetModel()) + newVol:SetMoveType(vol:GetMoveType()) + newVol:SetPos(vol:GetPos()) + newVol:SetAngles(vol:GetAngles()) + newVol:SetName(newName) + newVol:Spawn() + newVol:Activate() + newVol:AddSolidFlags(FSOLID_TRIGGER) + newVol:SetNotSolid(true) + newVol:AddEffects(EF_NODRAW) + + -- The previous volume is no longer needed. + vol:Remove() + + end) + + return newName + +end + +--- func_tank not controllable because of custom trigger entities +hook.Add("EntityKeyValue", "Lambda_FuncTank", function(ent, key, val) + if ent:GetClass() == "func_tank" or ent:GetClass() == "func_tankairboatgun" then + if key == "control_volume" then + return ReplaceFuncTankVolume(ent, val) + end + end +end) diff --git a/gamemode/sv_inputoutput.lua b/gamemode/sv_inputoutput.lua new file mode 100644 index 00000000..46f03498 --- /dev/null +++ b/gamemode/sv_inputoutput.lua @@ -0,0 +1,94 @@ +local DbgPrint = GetLogging("IO") + +GM.InputFilters = {} +GM.OutputCallbacks = {} +GM.InputCallbacks = {} + +function GM:ResetInputOutput() + self.InputFilters = {} + self.OutputCallbacks = {} + self.InputCallbacks = {} +end + +function GM:FilterEntityInput(name, input) + + self.InputFilters[name] = self.InputFilters[name] or {} + table.insert(self.InputFilters[name], input) + +end + +function GM:AddOutputCallback(name, outputname, inputname, delay, cb) + + ents.WaitForEntityByName(name, function(ent) + + local infotarget = ents.Create("info_target") + infotarget:SetName(inputname) + infotarget:Spawn() + + DbgPrint("Added new output on " .. tostring(ent) .. " -> " .. outputname .. " " .. inputname) + + ent:Fire("AddOutput", outputname .. " " .. inputname .. ",OutputCallback", delay) + + self.OutputCallbacks[inputname] = cb + + end) + +end + +function GM:WaitForInput(name, input, cb) + + ents.WaitForEntityByName(name, function(ent) + + DbgPrint("Added new input listener on " .. tostring(ent) .. " -> " .. input) + + self.InputCallbacks[ent] = self.InputCallbacks[ent] or {} + self.InputCallbacks[ent][input] = cb + + end) + +end + +function GM:RemoveInputCallback(name, input) + ents.WaitForEntityByName(name, function(ent) + + DbgPrint("Removing input listener on " .. tostring(ent) .. " -> " .. input) + + self.InputCallbacks[ent] = self.InputCallbacks[ent] or {} + self.InputCallbacks[ent][input] = nil + + end) +end + +function GM:AcceptInput(ent, input, activator, caller, value) + + local name = ent:GetName() + local filters = self.InputFilters[name] + if filters ~= nil then + for _,v in pairs(filters) do + if v == input then + DbgPrint(ent, "Filtered input: " .. name .. " -> " .. input) + return true + end + end + end + + local inputcb = self.InputCallbacks[ent] + if inputcb ~= nil then + local cb = inputcb[input] + if cb ~= nil then + local res = cb(ent, input, activator, caller, value) + if res == true then + DbgPrint(ent, "Filtered input: " .. name .. " -> " .. input) + return true + end + else + end + end + + local output = self.OutputCallbacks[name] + if output ~= nil then + DbgPrint("Input Target: " .. name) + output(name) + end + +end diff --git a/gamemode/sv_loadsave.lua b/gamemode/sv_loadsave.lua new file mode 100644 index 00000000..a2c80bb8 --- /dev/null +++ b/gamemode/sv_loadsave.lua @@ -0,0 +1,368 @@ +-- NOTE: This is currently not working properly to reset map states at a specific time. + +function GM:ShouldSaveEntity(ent) + + local caps = ent:ObjectCaps() + if bit.band(caps, FCAP_DONT_SAVE) ~= 0 then + --return false + end + + return true + +end + +function GM:GetEntitySaveData(ent, queue) + + local data = {} + local class = ent:GetKeyValues()["classname"] or ent:GetClass() + + data.RefId = ent:EntIndex() + data.Class = class + data.SaveTable = ent:GetSaveTable() + data.Outputs = ent.EntityOutputs or {} + data.KeyValues = ent.KeyValueTable or ent:GetKeyValues() + data.Pos = ent:GetPos() + data.Ang = ent:GetAngles() + data.Model = ent:GetModel() + data.Effects = ent:GetEffects() + data.Name = ent:GetName() + data.Skin = ent:GetSkin() + data.Mat = ent:GetMaterial() + data.CollisionGroup = ent:GetCollisionGroup() + data.SolidFlags = ent:GetSolidFlags() + data.Table = table.Copy(ent:GetTable()) + data.MoveType = ent:GetMoveType() + data.MoveCollide = ent:GetMoveCollide() + data.Flags = ent:GetFlags() + data.EFlags = ent:GetEFlags() + data.IsPlayer = ent:IsPlayer() + data.IsNPC = ent:IsNPC() + data.IsWeapon = ent:IsWeapon() + data.IsWorld = ent:IsWorld() + + --data.LuaData + if ent.GetCoopKeyValueTable then + table.Merge(data.KeyValues, ent:GetCoopKeyValueTable()) + end + + for k,v in pairs(data.SaveTable) do + + if isentity(v) and IsValid(v) and not v:IsWorld() and self:ShouldSaveEntity(v) then + data.SaveTable[k] = "CoopRef_" .. v:EntIndex() + table.insert(queue, v) + end + + end + + for k,v in pairs(data.KeyValues) do + if k == "angle" then + local y = tonumber(v) + if y >= 0 then + local localAng = ent:GetLocalAngles() + local ang = string.format("%f %f %f", localAng.x, y, localAng.z) + data.KeyValues["angles"] = ang + elseif y == -1 then + data.KeyValues["angles"] = "-90 0 0" + else + data.KeyValues["angles"] = "90 0 0" + end + + data.KeyValues[k] = nil + elseif k == "hammerid" then + data.KeyValues[k] = nil + end + end + + return data + +end + +function GM:GetPlayerSaveData(ply) + +end + +SAVEDATA = SAVEDATA or { Ents = {}, Players = {} } + +function GM:SaveGameState() + + do + + SAVEDATA = gmsave.SaveMap(game.SinglePlayer() and Entity( 1 ) or player.GetAll()[1]) + + return true + + end + + SAVEDATA = { Ents = {}, Players = {} } + + local queue = table.Copy(ents.GetAll()) + local processed = {} + + local uniqueIdStart = CurTime() + SysTime() + local i = 0 + + while table.Count(queue) > 0 do + + local v = queue[1] + table.remove(queue, 1) + + if processed[v] == true then + continue + end + + processed[v] = true + + if self:ShouldSaveEntity(v) == false then + continue + end + + v.UniqueSaveId = uniqueIdStart + i + i = i + 1 + + local data = self:GetEntitySaveData(v, queue) + table.insert(SAVEDATA.Ents, data) + + data.UniqueSaveId = v.UniqueSaveId + + end + + DbgPrint("Saved " .. #SAVEDATA.Ents .. " objects") + --PrintTable(SAVEDATA) + +end + +local SAVETABLE_BLACKLIST = +{ + --["m_iActiveSound"] = true, + --["m_iFreeSound"] = true, + --[[ + ["m_vecCommandGoal"] = true, + ["basevelocity"] = true, + ["m_vecLean"] = true, + ["avelocity"] = true, + ["velocity"] = true, + ["m_vecOrigin"] = true, + ["m_angRotation"] = true, + ["m_angAbsRotation"] = true, + ["m_vecAbsOrigin"] = true, + ["m_vSavePosition"] = true, + ["m_hMoveEntity"] = true, + ["model"] = true, + ["modelindex"] = true, + ["m_iszModelName"] = true, + ["effects"] = true, + ["spawnflags"] = true, + ["m_MoveType"] = true, + ["hammerid"] = true, + ["globalname"] = true, + ["m_pnext"] = true, + ["m_pprevious"] = true, + ]] +} + +function GM:CreateSavedEntities() + + -- Create everything. + local createdEnts = {} + local entData = {} + local referencedEnts = {} + local spawned = {} + local dispatchSpawn = {} + --PrintTable(SAVEDATA) + + for k,data in pairs(SAVEDATA.Ents) do + + DbgPrint("Creating: " .. data.Class .. " RefId: " .. data.RefId) + + local ent = Entity(data.RefId) + if IsValid(ent) then + if ent.UniqueSaveId ~= data.UniqueSaveId then + DbgPrint("Overriding entity: " .. tostring(ent) .. ", non-matching save id") + ent = nil + end + end + + if not IsValid(ent) and data.IsPlayer == false and data.IsWorld == false then + ent = ents.Create(data.Class) + dispatchSpawn[ent] = true + else + dispatchSpawn[ent] = false + end + + if not IsValid(ent) then + DbgPrint("Failed to create entity: " .. data.Class) + continue + end + + for k,v in pairs(data.KeyValues) do + DbgPrint("KeyValue: " .. k .. " -> " .. v) + --ent:SetKeyValue(k, v) + GAMEMODE:EntityKeyValue(ent, k, v) + end + + ent:SetTable(data.Table) + + createdEnts[data.RefId] = ent + data.RefId = ent:EntIndex() + + entData[ent] = data + SAVEDATA.Ents[k] = data + + end + + -- Fix references, save values + for _, ent in pairs(createdEnts) do + + local data = entData[ent] + + ent:SetTable(data.Table) + + for k,v in pairs(data.SaveTable) do + if SAVETABLE_BLACKLIST[k] == true then + continue + end + + if isstring(v) and v:sub(1, 8) == "CoopRef_" then + local refId = tonumber(v:sub(9)) + local refEnt = createdEnts[refId] + if refEnt ~= nil and IsValid(refEnt) then + if refEnt == ent then + DbgPrint(ent, "Cyclic reference!", refEnt) + else + DbgPrint(tostring(ent), "SaveValue: " .. k .. " -> " .. tostring(refEnt)) + ent:SetSaveValue(k, refEnt) + table.insert(referencedEnts, refEnt) + DbgPrint(tostring(ent), "Resolved reference (" .. k .. "): " .. tostring(refEnt)) + end + else + DbgPrint("Unable to solve reference (" .. k .. "): " .. tostring(refId)) + end + else + --DbgPrint("SaveValue: " .. k .. " -> " .. tostring(v)) + if v ~= NULL then + ent:SetSaveValue(k, v) + end + end + end + + for output, tab in pairs(data.Outputs or {}) do + for _,v in pairs(tab) do + ent:SetKeyValue(output, v) + GAMEMODE:EntityKeyValue(ent, output, v) + end + end + + ent:SetPos(data.Pos) + ent:SetAngles(data.Ang) + if data.Model ~= nil then + ent:SetModel(data.Model) + end + ent:SetName(data.Name) + ent:AddEffects(data.Effects) + ent:SetSkin(data.Skin) + ent:SetMaterial(data.Mat) + ent:SetCollisionGroup(data.CollisionGroup) + ent:SetSolidFlags(data.SolidFlags) + ent:SetMoveType(data.MoveType) + ent:SetMoveCollide(data.MoveCollide) + ent:AddFlags(data.Flags) + ent:AddEFlags(data.EFlags) + end + + -- Spawn + for _, ent in pairs(referencedEnts) do + + if spawned[ent] == true then + continue + end + spawned[ent] = true + + local data = entData[ent] + + local caps = ent:ObjectCaps() + if bit.band(caps, FCAP_MUST_SPAWN) and dispatchSpawn[ent] == true then + --DbgPrint("Spawn: " .. tostring(ent)) + ent:Spawn() + end + + local class = ent:GetClass() + if ent:IsNPC() or ent:IsVehicle() and dispatchSpawn[ent] == true then + ent:Activate() + end + + if IsValid(ent) then + DbgPrint("Created: " .. tostring(ent)) + else + DbgPrint("Unable to create entity: " .. data.Class) + end + + end + + -- Spawn + for _, ent in pairs(createdEnts) do + + if spawned[ent] == true then + continue + end + spawned[ent] = true + + local data = entData[ent] + + local caps = ent:ObjectCaps() + if bit.band(caps, FCAP_MUST_SPAWN) and dispatchSpawn[ent] == true then + --DbgPrint("Spawn: " .. tostring(ent)) + ent:Spawn() + end + + local class = ent:GetClass() + if ent:IsNPC() or ent:IsVehicle() and dispatchSpawn[ent] == true then + ent:Activate() + end + + ent.UniqueSaveId = data.UniqueSaveId + + if IsValid(ent) then + DbgPrint("Created: " .. tostring(ent)) + else + DbgPrint("Unable to create entity: " .. data.Class) + end + + end + +end + +function GM:LoadGameState() + + do + + if SAVEDATA ~= nil then + + gmsave.LoadMap(SAVEDATA, game.SinglePlayer() and Entity( 1 ) or player.GetAll()[1]) + return true + + end + + end + --game.CleanUpMap() + + if SAVEDATA == nil or table.Count(SAVEDATA.Ents) == 0 then + DbgPrint("Empty SaveData!") + return + end + + -- Remove everything. + for k,data in pairs(SAVEDATA.Ents) do + local ent = Entity(data.RefId) + if IsValid(ent) and ent:GetKeyValues()["classname"] == data.Class then + --ent:Remove() + else + --DbgPrint("Invalid reference: " .. data.RefId) + end + end + + local self = self + timer.Simple(1, function() + self:CreateSavedEntities() + end) + +end diff --git a/gamemode/sv_resource.lua b/gamemode/sv_resource.lua new file mode 100644 index 00000000..0f2a1d7f --- /dev/null +++ b/gamemode/sv_resource.lua @@ -0,0 +1,35 @@ +local RESOURCE_FOLDER = +{ + "materials/lambda", + "materials/models", + "materials/models/gibs", + "models/gibs", + "models", + "scripts", + "models", + "sound", +} + +local BASE_PATH = GM.Folder .. "/content" +local FOLDERS = {} + +for _,v in ipairs(RESOURCE_FOLDER) do + table.insert(FOLDERS, BASE_PATH .. "/" .. v) +end + +while #FOLDERS > 0 do + + local folder = FOLDERS[1] + table.remove(FOLDERS, 1) + + local res = file.Find(folder .. "/*", "GAME") + for _, filename in ipairs(res) do + local filepath = folder .. "/" .. filename + if file.IsDir(filepath, "GAME") then + table.insert(FOLDERS, filepath) + else + resource.AddSingleFile(filepath) + end + end + +end diff --git a/gamemode/sv_taunts.lua b/gamemode/sv_taunts.lua new file mode 100644 index 00000000..4e5dfe4e --- /dev/null +++ b/gamemode/sv_taunts.lua @@ -0,0 +1,72 @@ +AddCSLuaFile("cl_taunts.lua") + +include("sh_taunts.lua") + +util.AddNetworkString("PlayerStartTaunt") + +function PlaceRunPointer(ply) + + local traceang = ply:EyeAngles() + local tracepos = ply:EyePos() + local tracelen = traceang:Forward() * 10000 + local filter = {ply} + if ply:InVehicle() then + table.insert(filter, ply:GetVehicle()) + end + local trace = util.QuickTrace(tracepos, tracelen, filter) + + if trace.HitWorld or (IsValid(trace.Entity) and not trace.Entity:IsNPC()) then + local effectdata = EffectData() + effectdata:SetOrigin( trace.HitPos ) + effectdata:SetNormal( trace.HitNormal ) + effectdata:SetRadius(50) + util.Effect( "lambda_pointer", effectdata, true ) + + local effectdata = EffectData() + effectdata:SetOrigin( trace.HitPos ) + effectdata:SetStart( ply:GetShootPos() - Vector(0,0,5) ) + effectdata:SetAttachment( 1 ) + effectdata:SetEntity( ply ) + util.Effect( "ToolTracer", effectdata ) + end +end + +function PlaceRunPointerLocal(ply) + + local effectdata = EffectData() + effectdata:SetOrigin( ply:GetPos() ) + effectdata:SetNormal( Vector(0,0,1) ) + effectdata:SetRadius(50) + util.Effect( "lambda_pointer", effectdata, true ) + +end + +net.Receive("PlayerStartTaunt", function(len, ply) + + if ply:Alive() == false then + return + end + + local TauntIndex = net.ReadFloat() + local gender = ply:GetGender() + + local taunt = Taunts[gender][TauntIndex] + local snd = table.Random(taunt.Sounds) + + if taunt.Name == "Over here" then + ply:SendLua[[RunConsoleCommand("act", "wave")]] + PlaceRunPointerLocal(ply) + elseif taunt.Name == "Over there" then + ply:SendLua[[RunConsoleCommand("act", "forward")]] + PlaceRunPointer(ply) + elseif taunt.Name == "Scanners" then + ply:SendLua[[RunConsoleCommand("act", "forward")]] + elseif taunt.Name == "Nice" then + ply:SendLua[[RunConsoleCommand("act", "agree")]] + elseif taunt.Name == "Take cover" then + ply:SendLua[[RunConsoleCommand("act", "halt")]] + end + + ply:EmitSound(snd) + +end) diff --git a/gamemode/sv_transition.lua b/gamemode/sv_transition.lua new file mode 100644 index 00000000..127728fc --- /dev/null +++ b/gamemode/sv_transition.lua @@ -0,0 +1,1137 @@ +local DbgPrint = GetLogging("Transition") + +local ENT_TYPE_NPC = 0 +local ENT_TYPE_VEHICLE = 1 +local ENT_TYPE_DOOR = 2 +local ENT_TYPE_GENERIC = 3 + +local SERIALIZE_VECTOR = function(ent, val) return ent:WorldToLocal(val) end +local SERIALIZE_ANGLES = function(ent, val) return ent:WorldToLocalAngles(val) end + +local FIELD_SERIALIZE = +{ + ["Pos"] = SERIALIZE_VECTOR, + ["Vec"] = SERIALIZE_VECTOR, + ["Ang"] = SERIALIZE_ANGLES, + ["EyeAng"] = SERIALIZE_ANGLES, +} + +local DESERIALIZE_VECTOR = function(ent, val) return ent:LocalToWorld(val) end +local DESERIALIZE_ANGLES = function(ent, val) return ent:LocalToWorldAngles(val) end + +local FIELD_DESERIALIZE = +{ + ["Pos"] = DESERIALIZE_VECTOR, + ["Vec"] = DESERIALIZE_VECTOR, + ["Ang"] = DESERIALIZE_ANGLES, + ["EyeAng"] = DESERIALIZE_ANGLES, +} + +local DEFAULT_TRANSITION_DATA = util.TableToJSON({ Objects = {}, Players = {} }) + +function GM:InitializeTransitionData() + + -- I know this is not ideal but lets be honest, I have so much more important work left :3 + + if self.IsChangeLevel == true then + local transitionData = util.GetPData("Lambda", "TransitionData", DEFAULT_TRANSITION_DATA) + self.TransitionData = util.JSONToTable(transitionData) + + else + self.TransitionData = util.JSONToTable(DEFAULT_TRANSITION_DATA) + end + + DbgPrint("TransitionData containts " .. tostring(table.Count(self.TransitionData)) .. " objects") + + --PrintTable(self.TransitionData) + util.RemovePData("Lambda", "TransitionData") + +end + +function GM:TransitionToLevel(map, landmark, playersInTrigger) + + -- 1. Lets collect all entities with the landmark name we have to seperate them by landmark and trigger + local transitionTriggers = {} + local landmarkEnt = nil + + for _,v in pairs(ents.FindByName(landmark)) do + + if v:GetClass() == "info_landmark" then + if landmarkEnt ~= nil then + DbgPrint("Something is wrong, we already have found the landmark") + end + landmarkEnt = v + DbgPrint("Found landmark entity: " .. tostring(landmarkEnt)) + elseif v:GetClass() == "trigger_transition" then + table.insert(transitionTriggers, v) + DbgPrint("Found transition trigger: " .. tostring(v)) + end + + end + + if not IsValid(landmarkEnt) then + DbgPrint("Unable to find landmark! - " .. tostring(landmark)) + end + + -- 2. We now create a list of objects to transfer. + local objectTable = {} + local playerTable = {} + + --[[ + if table.Count(transitionTriggers) > 0 then + self:TransitionObjectsByVolumes(landmarkEnt, transitionTriggers, objectTable, playerTable) + else + self:TransitionObjectsByLandmark(landmarkEnt, objectTable, playerTable) + end + ]] + + self:TransitionNearbyObjects(landmarkEnt, transitionTriggers, objectTable, playerTable, playersInTrigger) + + -- In case players didnt make it, we erase their position from the data. + for k,v in pairs(playerTable) do + + local ply = Entity(v.RefId) + if not IsValid(ply) then + DbgError("Invalid player detected, this should not happen") + end + + if table.HasValue(playersInTrigger, ply) == false then + DbgPrint("Removing player: " .. tostring(ply) .. " from transitioning, not in changelevel trigger") + --playerTable[k] = nil + playerTable[k].Include = false -- NOTE: Changed this to carry stats and other information. + end + + end + + DbgPrint("Transitioning #" .. tostring(table.Count(objectTable)) .. " objects") + --PrintTable(objectTable) + + DbgPrint("Transitioning #" .. tostring(table.Count(playerTable)) .. " players") + --PrintTable(playerTable) + + local transitionData = { + Objects = objectTable, + Players = playerTable, + Data = {}, + } + + -- We have to mimic the input on transition. + local transitionMap = {} + for _,v in pairs(objectTable) do + transitionMap[Entity(v.RefId)] = true + end + + for _,v in pairs(ents.GetAll()) do + local caps = v:ObjectCaps() + + if bit.band(caps, FCAP_NOTIFY_ON_TRANSITION) ~= 0 then + if transitionMap[v] == true then + v:Fire("OutsideTransition") + else + v:Fire("InsideTransition") + end + end + end + + hook.Run("SaveTransitionData", transitionData.Data) + + util.SetPData("Lambda", "TransitionData", util.TableToJSON(transitionData)) + +end + +function GM:SaveTransitionData(data) + + self:SaveTransitionDifficulty(data) + +end + +local TRANSITION_BLACKLIST = +{ + --["env_sprite"] = true, -- Crashes in combination with TestPVS + --["trigger_once"] = true, + --["trigger_multiple"] = true, + --["info_landmark"] = true, + ["keyframe_rope"] = true, + ["info_landmark"] = true, + ["env_sprite"] = true, + ["env_lightglow"] = true, + ["env_soundscape"] = true, + ["lambda_checkpoint"] = true, + --["path_track"] = true, + --["point_camera"] = true, + ["move_rope"] = true, + ["trigger_transition"] = true, + ["game_ragdoll_manager"] = true, + --["aiscripted_schedule"] = true, + ["env_fog_controller"] = true, +} + +local TRANSITION_ENFORCED_NPC = +{ + ["npc_zombie"] = true, + ["npc_headcrab"] = true, + ["npc_fastzombie"] = true, +} + +function GM:ShouldTransitionObject(obj, playersInTrigger) + + if obj:IsWorld() then + return false + end + + local transition = false + local caps = obj:ObjectCaps() + + local class = obj:GetClass() + if TRANSITION_BLACKLIST[class] == true then + return false + end + + if bit.band(caps, FCAP_DONT_SAVE) ~= 0 then + --if g_debug_transitions:GetBool() == true then + DbgPrint("Ignoring object for transition (FCAP_DONT_SAVE): " .. tostring(obj)) + --end + if obj:IsVehicle() == false then + return false + end + end + + if bit.band(caps, FCAP_ACROSS_TRANSITION) ~= 0 then + transition = true + end + + if bit.band(caps, FCAP_FORCE_TRANSITION) ~= 0 then + transition = true + obj.ForceTransition = true + end + + local globalName = obj:GetNWString("GlobalName", obj:GetInternalVariable("globalname") or "") + if globalName ~= "" and obj:IsDormant() == false then + transition = true + obj.ForceTransition = true + end + + if obj:IsNPC() and TRANSITION_ENFORCED_NPC[obj:GetClass()] == true then + transition = true + obj.ForceTransition = true + end + + if obj:IsVehicle() and transition == false then + + local driver = obj:GetDriver() + + if IsValid(driver) and driver:IsPlayer() then + if table.HasValue(playersInTrigger, driver) == true then + DbgPrint("Enforcing vehicle to transition because player is driving: " .. tostring(obj)) + transition = true + else + -- TODO: Create a estimate distance and give it a tolerance of lets say 1024 units? + DbgPrint("Player is not in changelevel trigger") + transition = false + end + else + --if obj.CoopPlayer ~= nil then + --transition = false -- Player is not inside so give him a new one. + --end + end + + end + + if transition == false then + DbgPrint("Object " .. tostring(obj) .. " failed transition pass, caps: " .. tostring(caps)) + end + + local parent = obj:GetParent() + if IsValid(parent) and (parent:IsPlayer() or parent:IsNPC() or parent:IsWeapon()) then + transition = false + end + + local owner = obj:GetOwner() + if IsValid(owner) and (owner:IsPlayer() or owner:IsNPC()) then + transition = false + end + + if obj:IsWeapon() and IsValid(owner) and owner:IsNPC() then + -- We deal with that specifically. + transition = false + end + + -- Overpass owner/parent test, it might be not strictly attached. + if obj:IsPlayerHolding() then + transition = true + obj.ForceTransition = true + end + + return transition + +end + +function GM:SerializePlayerData(landmarkEnt, ply, playersInTrigger) + + -- Construct a weapon table that contains also info about the ammo. + local weapons = {} + + for _, weapon in pairs(ply:GetWeapons()) do + local isActive = ply:GetActiveWeapon() == weapon + local weaponData = + { + Class = weapon:GetClass(), + Ammo1 = + { + Id = weapon:GetPrimaryAmmoType(), + Count = ply:GetAmmoCount(weapon:GetPrimaryAmmoType()), + }, + Ammo2 = + { + Id = weapon:GetSecondaryAmmoType(), + Count = ply:GetAmmoCount(weapon:GetSecondaryAmmoType()), + }, + Active = isActive, + } + table.insert(weapons, weaponData) + end + + local data = + { + RefId = ply:EntIndex(), + SteamID64 = ply:SteamID64(), -- Important for later. + SteamID = ply:SteamID(), + UserID = ply:UserID(), -- For those who wonder, as long you dont disconnect it stays the same: https://developer.valvesoftware.com/wiki/Userid + Nick = ply:Nick(), + Pos = ply:GetPos(), + Ang = ply:GetAngles(), + EyeAng = ply:EyeAngles(), + Vel = ply:GetVelocity(), + Mdl = ply:GetModel(), + Health = ply:Health(), + Frags = ply:Frags(), + Deaths = ply:Deaths(), + Armor = ply:Armor(), + Suit = ply:IsSuitEquipped(), + Weapons = weapons, + } + + if table.HasValue(playersInTrigger, ply) == true and ply:Alive() == true then + if ply:InVehicle() then + data.Vehicle = ply:GetVehicle():EntIndex() + end + data.Include = true + else + data.Include = false + data.Weapons = {} -- Ditch the table, no need. + end + + -- Serialize vectors, angles to local ones by landmark. + for k, v in pairs(data) do + + local serializeFn = FIELD_SERIALIZE[k] + if serializeFn then + data[k] = serializeFn(landmarkEnt, v) + end + + end + + return data + +end + +local SAVETABLE_BLACKLIST = +{ + ["m_vecCommandGoal"] = true, + ["basevelocity"] = true, + ["m_vecLean"] = true, + ["avelocity"] = true, + ["velocity"] = true, + ["m_vecOrigin"] = true, + ["m_angRotation"] = true, + ["m_angAbsRotation"] = true, + ["m_vecAbsOrigin"] = true, + ["m_vSavePosition"] = true, + ["m_hMoveEntity"] = true, + ["model"] = true, + ["modelindex"] = true, + ["m_iszModelName"] = true, + ["effects"] = true, + ["spawnflags"] = true, + ["m_MoveType"] = true, + ["hammerid"] = true, + ["m_hMovePeer"] = true, + ["m_hMoveChild"] = true, -- dead locks. + ["m_hMoveParent"] = true, -- dead locks. + ["m_pParent"] = true, -- dead locks. + ["globalname"] = true, + ["additionalequipment"] = true, + ["m_bConditionsGathered"] = true, + ["m_flReadinessLockedUntil"] = true, +} + +function GM:SerializeEntityData(landmarkEnt, ent, playersInTrigger) + + DbgPrint("GM:SerializeEntityData(" .. tostring(landmarkEnt) .. ", " .. tostring(ent) .. ")") + + local currentMap = self:GetCurrentMap() + + local data = + { + Class = ent:GetClass(), + RefId = ent:EntIndex(), + InitialRefId = ent.InitialRefId or ent:EntIndex(), + Pos = ent:GetPos(), + Ang = ent:GetAngles(), + Vel = ent:GetVelocity(), + EyeAng = ent:EyeAngles(), + Mdl = ent:GetModel(), + Skin = ent:GetSkin(), + Name = ent:GetName(), + Mat = ent:GetMaterial(), + Health = ent:Health(), + Flags = ent:GetFlags(), + EFlags = ent:GetEFlags(), + Effects = ent:GetEffects(), + SolidFlags = ent:GetSolidFlags(), + Solid = ent:GetSolid(), + SpawnFlags = ent:GetSpawnFlags(), + CollisionGroup = ent:GetCollisionGroup(), + Sequence = ent:GetSequence(), + MoveCollide = ent:GetMoveCollide(), + MoveType = ent:GetMoveType(), + KeyValues = ent.KeyValueTable or ent:GetKeyValues(), + SaveTable = ent:GetSaveTable(), + Table = ent:GetTable(), + SourceMap = ent.SourceMap or currentMap, + GlobalName = ent:GetNWString("GlobalName", ent:GetInternalVariable("globalname")), + } + + if ent.CoopKeyValues ~= nil then + table.Merge(data.KeyValues, ent.CoopKeyValues) + end + + if ent.GetNWVars ~= nil then + data.NWVars = ent:GetNWVars() + end + + if ent.GetOutputsTable ~= nil then + data.Outputs = ent:GetOutputsTable() + end + + if ent.EntityOutputs ~= nil then + data.EntityOutputs = table.Copy(ent.EntityOutputs) + end + + if ent:IsNPC() then + data.Type = ENT_TYPE_NPC + data.MovementActivity = ent:GetMovementActivity() + --data.MovementSequence = ent:GetMovementSequence() + data.Expression = ent:GetExpression() + data.Activity = ent:GetActivity() + data.NPCState = ent:GetNPCState() + local activeWeapon = ent:GetActiveWeapon() + if IsValid(activeWeapon) then + data.ActiveWeapon = activeWeapon:GetClass() + end + elseif ent:IsVehicle() then + data.Type = ENT_TYPE_VEHICLE + if ent:IsGunEnabled() then + data.EnableGun = true + else + data.EnableGun = false + end + data.VehicleScript = ent:GetSaveTable()["VehicleScript"] + if ent.IsPassengerSeat == true then + data.IsPassengerSeat = true + end + + elseif ent:IsDoor() then + data.Type = ENT_TYPE_DOOR + if ent:IsDoorOpen() or ent:IsDoorOpening() then + data.SpawnFlags = bit.bor(data.SpawnFlags, 1) -- Starts Open + end + if ent:IsDoorLocked() then + data.SpawnFlags = bit.bor(data.SpawnFlags, 2048) -- Starts Locked + end + else + data.Type = ENT_TYPE_GENERIC + end + + for k,v in pairs(data.SaveTable) do + + if SAVETABLE_BLACKLIST[k] == true then + data.SaveTable[k] = nil + continue + end + + if IsEntity(v) and IsValid(v) then + data.SaveTable[k] = "CoopRef_" .. tostring(v:EntIndex()) + elseif isvector(v) then + --data.SaveTable[k] = ent:WorldToLocal(v) + elseif isangle(v) then + --data.SaveTable[k] = ent:WorldToLocalAngles(v) + end + + end + + local parent = ent:GetParent() + if IsValid(parent) and not parent:IsPlayer() then + data.Parent = parent:EntIndex() + end + + local owner = ent:GetOwner() + if IsValid(owner) and not owner:IsPlayer() then + data.Owner = parent:EntIndex() + end + + -- Serialize vectors, angles to local ones by landmark. + for k, v in pairs(data) do + + local serializeFn = FIELD_SERIALIZE[k] + if serializeFn then + data[k] = serializeFn(landmarkEnt, v) + end + + end + + if ent:GetClass() == "func_brush" then + --PrintTable(data) + end + + return data + +end + +function GM:TransitionObjects(landmarkEnt, objects, objectTable, playerTable, playersInTrigger) + + DbgPrint("GM:TransitionObjects") + + local processed = {} + local transitionTable = {} + local debugTransition = true + local processedPlayers = {} + + for _, touchingEnt in pairs(objects) do + + if not IsValid(touchingEnt) then + continue + end + + -- Prevent duplicates + if processed[touchingEnt] == true then + continue + end + + processed[touchingEnt] = true + + if touchingEnt:IsPlayer() and not touchingEnt:IsBot() then + + local ply = touchingEnt + + local data = self:SerializePlayerData(landmarkEnt, ply, playersInTrigger) + table.insert(playerTable, data) + + processedPlayers[ply] = true + + if debugTransition == true then + table.insert(transitionTable, ply) + end + + else + + local ent = touchingEnt + + local data = self:SerializeEntityData(landmarkEnt, ent, playersInTrigger) + table.insert(objectTable, data) + + if debugTransition == true then + table.insert(transitionTable, ent) + ent:AddDebugOverlays(bit.bor(OVERLAY_PIVOT_BIT, OVERLAY_BBOX_BIT, OVERLAY_NAME_BIT)) + end + end + + end + + -- Matt: Special case, we include them all because of some refactored code that relys on this. + for _,ply in pairs(player.GetAll()) do + if processedPlayers[ply] == nil and ply:IsBot() == false then + local data = self:SerializePlayerData(landmarkEnt, ply, playersInTrigger) + data.Include = false + table.insert(playerTable, data) + end + end + + if debugTransition == true then + PrintTable(transitionTable) + end + +end + +function GM:InTransitionVolume(volumes, obj) + + local caps = obj:ObjectCaps() + + if bit.band(caps, FCAP_FORCE_TRANSITION) ~= 0 or obj.ForceTransition == true then + return true + end + + for _,volume in pairs(volumes) do + + local pos = obj:GetPos() + local volPos = volume:GetPos() + local volMins = volPos + volume:OBBMins() + local volMaxs = volPos + volume:OBBMaxs() + + -- FIXME: This is currently inaccurate, but theres no way to do it properly. + if pos:WithinAABox(volMins, volMaxs) == false then + return false + else + -- We have no collision test that would apply to the model. + end + + end + + return true + +end + +function GM:TransitionNearbyObjects(landmarkEnt, transitionTriggers, objectTable, playerTable, playersInTrigger) + + DbgPrint("GM:TransitionNearbyObjects") + + local objects = {} + + DbgPrint("Collecting players") + + for _,v in pairs(player.GetAll()) do + if v:Alive() == false then + continue + end + table.insert(objects, v) + if v:InVehicle() and table.HasValue(playersInTrigger, v) == true then + table.insert(objects, v:GetVehicle()) + end + end + + local checkVolumes = table.Count(transitionTriggers) > 0 + + --local inPVS = ents.FindInPVS(landmarkEnt) -- Currently crashing, we use landmark:TestPVS instead. + local allEnts = ents.GetAll() + for _,v in pairs(allEnts) do + + if self:ShouldTransitionObject(v, playersInTrigger) == false then + continue + end + + if v.ForceTransition ~= true then + DbgPrint("Testing PVS on: " .. tostring(v)) + if landmarkEnt:TestPVS(v) == false then + continue + end + else + DbgPrint("Enforcing transition: " .. tostring(v)) + end + + if checkVolumes == true and v.ForceTransition ~= true and self:InTransitionVolume(transitionTriggers, v) == false then + --if g_debug_transitions:GetBool() == true then + DbgPrint("Object " .. tostring(v) .. " not in transition volumes") + --end + continue + end + + table.insert(objects, v) + end + + self:TransitionObjects(landmarkEnt, objects, objectTable, playerTable, playersInTrigger) + +end + +function GM:TransitionObjectsByVolumes(landmarkEnt, transitionTriggers, objectTable, playerTable) + + for _,trigger in pairs(transitionTriggers) do + + if trigger.GetTouchingObjects == nil then + DbgPrint("Flawed trigger, does not have a member called GetTouchingObjects") + continue + end + + local objects = trigger:GetTouchingObjects() + + -- Ensure we have always all players in the table. + for _,v in pairs(player.GetAll()) do + table.insert(objects, v) + if v:InVehicle() then + table.insert(objects, v:GetVehicle()) + end + end + + self:TransitionObjects(landmarkEnt, objects, objectTable, playerTable) + + end + +end + +function GM:TransitionObjectsByLandmark(landmarkEnt, objectTable, playerTable) + + DbgPrint("GM:TransitionObjectsByLandmark") + + local objects = {} + + for _,v in pairs(player.GetAll()) do + table.insert(objects, v) + if v:InVehicle() then + table.insert(objects, v:GetVehicle()) + end + end + + local inPVS = ents.FindInPVS(landmarkEnt) -- Thanks again Willox :3 + for _,v in pairs(inPVS) do + table.insert(objects, v) + end + + self:TransitionObjects(landmarkEnt, objects, objectTable, playerTable) + +end + +function GM:FindEntityByTransitionReference(id) + + self.CreatedTransitionObjects = self.CreatedTransitionObjects or {} + return self.CreatedTransitionObjects[id] + +end + +function GM:PostLoadTransitionData() + + DbgPrint("GM:PostLoadTransitionData") + + -- In case there is a entry landmark we are going to resolve the relative positioning, + -- this avoids us doing it over and over again at places where its used. + local entryLandmark = self:GetEntryLandmark() + if entryLandmark == nil then + return + end + + local landmarkEnt = nil + + for _,v in pairs(ents.FindByName(entryLandmark)) do + if v:GetClass() == "info_landmark" then + if landmarkEnt ~= nil then + DbgPrint("Something is wrong, we already have found the landmark") + end + landmarkEnt = v + DbgPrint("Found entry landmark entity: " .. tostring(landmarkEnt) .. "( " .. entryLandmark .. ")") + break + end + end + + if IsValid(landmarkEnt) == false then + DbgError("No landmark found to resolve transition data") + return + end + + DbgPrint("Resolving absolute position on transition players.") + + for objId, obj in pairs(self.TransitionData.Players) do + for k,v in pairs(obj) do + local deserializeFn = FIELD_DESERIALIZE[k] + if deserializeFn then + self.TransitionData.Players[objId][k] = deserializeFn(landmarkEnt, v) + end + end + end + + DbgPrint("Resolving absolute position on transition Objects.") + + for objId, data in pairs(self.TransitionData.Objects) do + for k,v in pairs(data) do + if objId == nil then + continue + end + local deserializeFn = FIELD_DESERIALIZE[k] + if deserializeFn then + self.TransitionData.Objects[objId][k] = deserializeFn(landmarkEnt, v) + end + --[[ + if k == "Mdl" and v:sub(1, 1) == "*" and data.GlobalName ~= "" and data.SourceMap ~= self:GetCurrentMap() then + local mapEnt = game.FindEntityByGlobalNameInMapData(data.GlobalName) + + if mapEnt ~= nil and mapEnt["model"] ~= nil then + DbgPrint("Translated old model " .. v .. " to new: " .. mapEnt["model"]) + self.TransitionData.Objects[objId][k] = mapEnt["model"] + elseif mapEnt == nil then + -- Discard this one, we cant find the new model. + DbgPrint("Unable to translate model: " .. tostring(v) .. ", removing: " .. data.Class .. ", map: " .. data.SourceMap .. ", name: " .. data.Name .. ", globalname" .. data.GlobalName) + self.TransitionData.Objects[objId] = nil + objId = nil + end + end + ]] + end + end + + hook.Run("LoadTransitionData", self.TransitionData.Data) + +end + +function GM:LoadTransitionData(data) + + self:LoadTransitionDifficulty(data) + +end + +local sv_lan = GetConVar("sv_lan") + +function GM:GetPlayerTransitionData(ply) + + if self.TransitionData == nil then + Error("No transition data table, something is flawed") + end + + -- Lan support, because duplicates of STEAM_0:0:0 + local key = "SteamID64" + local val = ply:SteamID64() + if sv_lan:GetBool() == true then + key = "UserID" + val = ply:UserID() + end + + for _,v in pairs(self.TransitionData.Players) do + if v[key] == val then + DbgPrint("Found transition data!") + return v + end + end + + return nil + +end + +GM.CreatedTransitionObjects = GM.CreatedTransitionObjects or {} + +-- Ive noticed strange issues when just applying every KeyValue that is in the table +-- therefor we go by a whitelist. +local DOOR_KEYVALUES = +{ + "opendir", + "ajarangles", + "forceclosed", + "spawnpos", + "dmg", + "hardware", + "speed", + "health", + "returndelay", +} + +local VEHICLE_KEYVALUES = +{ +} + +local KEYVALUE_BLACKLIST = +{ + ["hammerid"] = true, + ["globalname"] = true, + ["model"] = true, + ["modelindex"] = true, + ["origin"] = true, + ["spawnflags"] = true, + ["additionalequipment"] = true, +} + +function GM:CreateTransitionObjects() + + self.CreatedTransitionObjects = {} + + self.TransitionData = self.TransitionData or {} + + -- First iteration: We create the things. + local objects = self.TransitionData.Objects or {} + local objCount = table.Count(objects) + + -- We shall first remove everything that already exists. + DbgPrint("Removing duplicate global entities") + + local objectsToRemove = {} + + for _,data in pairs(objects) do + if data.GlobalName ~= nil and isstring(data.GlobalName) then + local e = ents.FindByGlobalName(data.GlobalName) + if IsValid(e) then + --if data.SourceMap == self:GetCurrentMap() then + local oldMdl = data.Mdl + data.Mdl = e:GetModel() or oldMdl + DbgPrint("Old Model: " .. oldMdl .. ", new: " .. data.Mdl) + --end + --e:SetSaveValue("globalname", "nope") + --DbgPrint("Deleting duplicate: " .. tostring(data.GlobalName), e:GetModel()) + table.insert(objectsToRemove, e) + else + local mapData = game.FindEntityByGlobalNameInMapData(data.GlobalName) + --PrintTable(mapData) + if mapData ~= nil and mapData["model"] ~= nil then + PrintTable(mapData) + local oldMdl = data.Mdl + data.Mdl = mapData["model"] + DbgPrint("Old Model: " .. oldMdl .. ", new: " .. data.Mdl) + end + end + end + + --if data.SourceMap == curMap and data.Name ~= "" then + for _,v in pairs(ents.FindByName(data.Name)) do + table.insert(objectsToRemove, v) + end + --end + end + + -- Wipe the transition area clean if it has a volume. + local entryLandmark = self:GetEntryLandmark() + if entryLandmark ~= nil then + DbgPrint("Entry Landmark: " .. entryLandmark) + for _,v in pairs(ents.FindByName(entryLandmark)) do + + if v:GetClass() ~= "trigger_transition" then + continue + end + + --local objects = ents.FindInBox(v:GetPos() + v:OBBMins(), v:GetPos() + v:OBBMaxs()) + local touchingObjects = v:GetTouchingObjects() + local remove = false + + for _, obj in pairs(touchingObjects) do + if v:IsWorld() then + continue + end + + if self:ShouldTransitionObject(obj) or obj.ForceTransition == true then + remove = true + end + + if remove == true then + --DbgPrint("Removing old object: " .. tostring(obj)) + --table.insert(objectsToRemove, obj) + end + end + end + end + + for _,v in pairs(objectsToRemove) do + if TRANSITION_BLACKLIST[v:GetClass()] ~= true then + DbgPrint("Removing old object: " .. tostring(v)) + v:Remove() + end + end + + DbgPrint("Creating " .. tostring(objCount) .. " transition Objects...") + + local curMap = self:GetCurrentMap() + local entityTransitionData = {} + + ignoreKeyIndex = -1 -- ignoreKeyIndex + 1 + + DbgPrint("IgnoreKeyIndex: " .. ignoreKeyIndex) + + for _,data in pairs(objects) do + + -- NOTE/FIXME: Observed different results on linux + if util.IsInWorld(data.Pos) == false then + DbgPrint("Ignoring creation of " .. data.Class .. ", position out of world: " .. tostring(data.Pos)) + continue + end + + if (data.Name == nil or data.Name == "") and (data.GlobalName == nil or data.GlobalName == "") and data.SourceMap == curMap then + DbgPrint("Ignoring creation of " .. data.Class .. ", originated from this map: " .. tostring(data.SourceMap)) + continue + end + + DbgPrint("Creating: " .. data.Class) + + local ent = ents.Create(data.Class) + local dispatchSpawn = true + + if not IsValid(ent) then + DbgPrint("Attempted to create bogus entity: " .. data.Class) + continue + end + + ent.SourceMap = data.SourceMap + ent.DispatchSpawn = dispatchSpawn + + -- Do key values first because we might override a few things with setters. + local keyIndex = 0 + for k, v in pairs(data.KeyValues) do + if KEYVALUE_BLACKLIST[k] == true then + continue + end + -- Deal with specifics. + if data.Type == ENT_TYPE_DOOR and table.HasValue(DOOR_KEYVALUES, k) then + ent:SetKeyValue(k, v) + GAMEMODE:EntityKeyValue(ent, k, v) + elseif data.Type == ENT_TYPE_VEHICLE and table.HasValue(VEHICLE_KEYVALUES, k) then + ent:SetKeyValue(k, v) + GAMEMODE:EntityKeyValue(ent, k, v) + else + if keyIndex == ignoreKeyIndex then + DbgPrint("IGNORED KEY: " .. k) + else + ent:SetKeyValue(k, v) + GAMEMODE:EntityKeyValue(ent, k, v) + end + end + keyIndex = keyIndex + 1 + end + + for k,v in pairs(data.EntityOutputs or {}) do + if istable(v) then + for _,output in pairs(v) do + ent:SetKeyValue(k, output) + GAMEMODE:EntityKeyValue(ent, k, output) + end + else + ent:SetKeyValue(k, v) + GAMEMODE:EntityKeyValue(ent, k, v) + end + end + + ent:SetPos(data.Pos) + ent:SetAngles(data.Ang) + ent:SetVelocity(data.Vel) + if data.Mdl ~= nil then + ent:SetModel(data.Mdl) + end + ent:SetName(data.Name) + ent:SetSkin(data.Skin) + ent:SetMaterial(data.Mat) + ent:SetHealth(data.Health) + ent:AddFlags(data.Flags) + ent:AddEFlags(data.EFlags) + ent:AddEffects(data.Effects) + ent:SetSolidFlags(data.SolidFlags) + ent:SetSolid(data.Solid) + ent:AddSpawnFlags(data.SpawnFlags) + ent:SetCollisionGroup(data.CollisionGroup) + ent:SetMoveCollide(data.MoveCollide) + ent:SetMoveType(data.MoveType) + ent:SetSequence(data.Sequence) + + if data.IsPassengerSeat == true then + ent.IsPassengerSeat = true + end + + if data.Type == ENT_TYPE_NPC then + ent:SetMovementActivity(data.MovementActivity) + --ent:SetMovementSequence(data.MovementSequence) + ent:SetExpression(data.Expression) + ent:SetNPCState(data.NPCState) + if data.ActiveWeapon ~= nil then + ent:SetKeyValue("additionalequipment", data.ActiveWeapon) + GAMEMODE:EntityKeyValue(ent, "additionalequipment", data.ActiveWeapon) + end + if data.KeyValues ~= nil and data.KeyValues["spawnflags"] ~= nil then + --ent:SetKeyValue("spawnflags", data.KeyValues["spawnflags"]) + --GAMEMODE:EntityKeyValue(ent, "spawnflags", data.KeyValues["spawnflags"]) + end + elseif data.Type == ENT_TYPE_VEHICLE then + if data.EnableGun == true then + ent:SetKeyValue("EnableGun", "1") + else + ent:SetKeyValue("EnableGun", "0") + end + if data.VehicleScript ~= nil then + ent:SetKeyValue("VehicleScript", data.VehicleScript) + end + end + + if data.Outputs ~= nil then + ent:SetOutputsTable(table.Copy(data.Outputs)) -- Dont mess with the references on cleanups. + end + + if ent.SetNWVars ~= nil and data.NWVars ~= nil then + ent:SetNWVars(data.NWVars) + end + + --ent.TransitionData = data + entityTransitionData[ent] = data + + self.CreatedTransitionObjects[data.RefId] = ent + + DbgPrint("Created " .. tostring(ent)) + + end + + -- Second iteration: We resolve dependencies. + DbgPrint("Fixing object referencs...") + for _,ent in pairs(self.CreatedTransitionObjects) do + + local data = entityTransitionData[ent] + if data == nil then + continue + end + + if data.Parent then + local parent = self.CreatedTransitionObjects[data.Parent] + if IsValid(parent) then + ent:SetParent(parent) + -- FIX: Make sure we assign the seat to the vehicle. + if ent.IsPassengerSeat == true then + parent.PassengerSeat = ent + end + end + end + + if data.Owner then + local owner = self.CreatedTransitionObjects[data.Owner] + if IsValid(owner) then + ent:SetOwner(owner) + end + end + + for k,v in pairs(data.SaveTable) do + + if SAVETABLE_BLACKLIST[k] == true then + continue + end + + if isstring(v) and v:sub(1, 8) == "CoopRef_" then + local refId = tonumber(v:sub(9)) + local refEnt = self.CreatedTransitionObjects[refId] + if IsValid(refEnt) and refEnt ~= ent and ent:IsNPC() == false then + DbgPrint("Resolved reference: " .. k .. " -> " .. tostring(refEnt)) + ent:SetSaveValue(k, refEnt) + end + elseif isvector(v) then + --local newVec = ent:LocalToWorld(v) + --ent:SetSaveValue(k, newVec) + elseif isangle(v) then + --local newAng = ent:LocalToWorldAngles(v) + --ent:SetSaveValue(k, newAng) + else + ent:SetSaveValue(k,v) + end + end + + ent.TransitionData = nil + + end + + -- Third iteration: We spawn and activate. + DbgPrint("Spawning objects...") + for _,ent in pairs(self.CreatedTransitionObjects) do + DbgPrint("Spawning: " .. tostring(ent)) + if ent.DispatchSpawn ~= true then + continue + end + ent:Spawn() + if ent:IsNPC() or ent:IsVehicle() then + ent:Activate() + end + local data = entityTransitionData[ent] + if data == nil then + continue + end + if data.GlobalName ~= nil and data.GlobalName ~= "" then + --ent:SetKeyValue("globalname", data.GlobalName) + end + end + + if ignoreKeyIndex ~= -1 then + ignoreKeyIndex = ignoreKeyIndex + 1 + end + +end diff --git a/icon24.png b/icon24.png new file mode 100644 index 00000000..13a3dcde Binary files /dev/null and b/icon24.png differ diff --git a/lambda.txt b/lambda.txt new file mode 100644 index 00000000..149a0389 --- /dev/null +++ b/lambda.txt @@ -0,0 +1,12 @@ +"lambda" +{ + "base" "base" + "title" "Lambda" + "maps" "d1_trainstation_01|d1_trainstation_02|d1_trainstation_03|d1_trainstation_04|d1_trainstation_05|d1_trainstation_06|d1_canals_01|d1_canals_01a|d1_canals_02|d1_canals_03|d1_canals_05|d1_canals_06|d1_canals_07|d1_canals_08|d1_canals_09|d1_canals_10|d1_canals_11|d1_canals_12|d1_canals_13|d1_eli_01|d1_eli_02|d1_town_01|d1_town_01a|d1_town_02|d1_town_02a|d1_town_03|d1_town_04|d1_town_05|d2_coast_01|d2_coast_03|d2_coast_04|d2_coast_05|d2_coast_07|d2_coast_08|d2_coast_09|d2_coast_10|d2_coast_11|d2_coast_12|d2_prison_01|d2_prison_02|d2_prison_03|d2_prison_04|d2_prison_05|d2_prison_06|d2_prison_07|d2_prison_08|d3_c17_01|d3_c17_02|d3_c17_03|d3_c17_04|d3_c17_05|d3_c17_06a|d3_c17_06b|d3_c17_07|d3_c17_08|d3_c17_09|d3_c17_10a|d3_c17_10b|d3_c17_11|d3_c17_12|d3_c17_12b|d3_c17_13|d3_citadel_01|d3_citadel_02|d3_citadel_03|d3_citadel_04|d3_citadel_05|d3_breen_01" + "menusystem" "1" + + "settings" + { + + } +} diff --git a/logo.png b/logo.png new file mode 100644 index 00000000..309b57b0 Binary files /dev/null and b/logo.png differ