diff --git a/Changelog.txt b/Changelog.txt new file mode 100644 index 0000000..a415094 --- /dev/null +++ b/Changelog.txt @@ -0,0 +1,12 @@ +Changelist +- Made Seeker Weapons & Ammo configurable from console & cfg file. +- Updated Gamemode info so that new configuration options are visible on the client. + +ToDo: +- Replace all createconvar with getconvar? +- Seeker model not existing after unblind? +- End round triggers +- Other game modes +- UI stuff +- Scoreboard +- Custom Collisions for Hiders? Allows to copy the prop geometry/align with rotation \ No newline at end of file diff --git a/Gamemode/gamemodes/xaymars_prop_hunt/entities/entities/ph_prop/init.lua b/Gamemode/gamemodes/xaymars_prop_hunt/entities/entities/ph_prop/init.lua deleted file mode 100644 index 70cc2d1..0000000 --- a/Gamemode/gamemodes/xaymars_prop_hunt/entities/entities/ph_prop/init.lua +++ /dev/null @@ -1,50 +0,0 @@ ---Thanks to Blasteh for gmod update the fix and nifnat for spectate fix! - --- Send required files to client -AddCSLuaFile("cl_init.lua") -AddCSLuaFile("shared.lua") - - --- Include needed files -include("shared.lua") - --- Called when we take damge -function ENT:OnTakeDamage(dmg) - local pl = self.Owner - local attacker = dmg:GetAttacker() - local inflictor = dmg:GetInflictor() - - -- Health - if pl && pl:IsValid() && pl:Alive() && pl:IsPlayer() && attacker:IsPlayer() && dmg:GetDamage() > 0 then - pl:SetHealth(pl:Health() - dmg:GetDamage()) - - if pl:Health() <= 0 then - -- Figure out real attacker. - if inflictor && inflictor == attacker && inflictor:IsPlayer() then - inflictor = inflictor:GetActiveWeapon() - if !inflictor || inflictor == NULL then inflictor = attacker end - end - - -- Kill player and remove the prop - pl:KillSilent() - pl:RemoveProp() -- Needs to be executed before net.Broadcast - - -- Send kill message. - net.Start( "PlayerKilledByPlayer" ) - net.WriteEntity( pl ) - net.WriteString( inflictor:GetClass() ) - net.WriteEntity( attacker ) - net.Broadcast() - - -- Broadcast same message to all players in console. - MsgAll(attacker:Name() .. " found and killed " .. pl:Name() .. "\n") - - -- Increment frags and deaths. - attacker:AddFrags(1) - pl:AddDeaths(1) - - -- Update attacker health - attacker:SetHealth(math.Clamp(attacker:Health() + GetConVar("HUNTER_KILL_BONUS"):GetInt(), 1, 100)) - end - end -end diff --git a/Gamemode/gamemodes/xaymars_prop_hunt/entities/entities/ph_prop/shared.lua b/Gamemode/gamemodes/xaymars_prop_hunt/entities/entities/ph_prop/shared.lua deleted file mode 100644 index 37734d3..0000000 --- a/Gamemode/gamemodes/xaymars_prop_hunt/entities/entities/ph_prop/shared.lua +++ /dev/null @@ -1,46 +0,0 @@ --- Entity information -ENT.Type = "anim" -ENT.Base = "base_anim" - --- Initialize -function ENT:Initialize() - self:SetModel("models/player/Kleiner.mdl") - self:DrawShadow(true); - - -- Physical properties - self:SetSolid(SOLID_OBB) - - -- Initialize Networked Variables - self:SetApplyNewAngles(false) - self:SetHealth(100) - if SERVER then self:SetMaxHealth(100) end - if CLIENT then self.Owner.ph_prop = self.Entity end -end - --- Set up shared Data. -function ENT:SetupDataTables() - self:NetworkVar( "Bool", 0, "ApplyNewAngles" ) -end - --- Update position -function ENT:Think() - -- Calculate hull size. - local hullOBBMin = self:OBBMins() - local hullOBBMax = self:OBBMaxs() - local hullOBB = hullOBBMax - hullOBBMin - - -- Shared update - local pos = -Vector(0, 0, hullOBBMin.z) - self:SetPos(self.Owner:GetPos() + pos) - self:SetVelocity(self:GetOwner():GetVelocity()) - - -- Server only updates - if SERVER then - -- Prevent confusion by updating angles only on the server. - if self:GetApplyNewAngles() then - self:SetAngles(Angle(0, self:GetOwner():GetAngles().yaw, 0)) - end - - self:NextThink( CurTime() ) - end -end diff --git a/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/cl_init.lua b/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/cl_init.lua deleted file mode 100644 index c16c637..0000000 --- a/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/cl_init.lua +++ /dev/null @@ -1,178 +0,0 @@ --- Include the needed files -include("sh_init.lua") ---include("cl_hints.lua") - --- Draw round timeleft and hunter release timeleft -function HUDPaint() - if GetGlobalBool("InRound", false) then - local blindlock_time_left = (GetConVar("HUNTER_BLINDLOCK_TIME"):GetInt() - (CurTime() - GetGlobalFloat("RoundStartTime", 0))) + 1 - - if blindlock_time_left < 1 && blindlock_time_left > -6 then - blindlock_time_left_msg = "Hunters have been released!" - elseif blindlock_time_left > 0 then - blindlock_time_left_msg = "Hunters will be unblinded and released in "..string.ToMinutesSeconds(blindlock_time_left) - else - blindlock_time_left_msg = nil - end - - if LocalPlayer():Team() == TEAM_HUNTERS && blindlock_time_left > 1 then - draw.RoundedBox(0, 0, 0, surface.ScreenWidth(), surface.ScreenHeight(), Color(20, 20, 20, 255)) - end - - if blindlock_time_left_msg then - surface.SetFont("MyFont") - local tw, th = surface.GetTextSize(blindlock_time_left_msg) - - draw.RoundedBox(8, 20, 20, tw + 20, 26, Color(0, 0, 0, 75)) - draw.DrawText(blindlock_time_left_msg, "MyFont", 31, 26, Color(255, 255, 0, 255), TEXT_ALIGN_LEFT) - end - end -end -hook.Add("HUDPaint", "PH_HUDPaint", HUDPaint) - --- Called immediately after starting the gamemode -function Initialize() - hullz = 80 - --surface.CreateFont("Arial", 14, 1200, true, false, "ph_arial") - surface.CreateFont( "MyFont", - { - font = "Arial", - size = 14, - weight = 1200, - antialias = true, - underline = false - }) -end -hook.Add("Initialize", "PH_Initialize", Initialize) - - --- Resets the player hull -function ResetHull(um) - if LocalPlayer() && LocalPlayer():IsValid() then - LocalPlayer():ResetHull() - LocalPlayer():SetViewOffset(Vector(0, 0, 64)) - LocalPlayer():SetViewOffsetDucked(Vector(0, 0, 28)) - hullz = 80 - end -end -usermessage.Hook("ResetHull", ResetHull) - - --- Sets the local blind variable to be used in CalcView -function SetBlind(um) - blind = um:ReadBool() -end -usermessage.Hook("SetBlind", SetBlind) - - -function GM:ShouldDrawLocalPlayer() - return false -end - -function GM:CalcView( ply, pos, ang, fov ) - local view = { - origin = pos, - angles = ang, - fov = fov - } - - if ply:Team() == TEAM_PROPS && ply:Alive() then - -- Fix lua errors by doing this instead. - if LocalPlayer().ThirdPersonDistance == nil then - LocalPlayer().ThirdPersonDistance = 100 - end - - -- Slowly return ThirdPersonDistance to 100 - local traceDist = math.Clamp(LocalPlayer().ThirdPersonDistance * 0.98 + 100 * 0.02, 0, 100) - - -- Trace a line to find the correct position for the camera. - local tracePos = pos - local trace = { - -- Start somewhat outside the prop. - start = tracePos - (ang:Forward() * 5), - endpos = tracePos - (ang:Forward() * (traceDist + 10)), - filter = function(ent) - if (ent == LocalPlayer() || ent == LocalPlayer().ph_prop || ent == LocalPlayer().ThirdPersonFilter || ent == ThirdPersonFilter) then - return false - elseif (ent:GetClass() == "ph_prop" || ent:GetClass() == "worldspawn") then - return false - end - return true - end - } - local traceResult = util.TraceLine(trace); - - -- Readjust trace hit distance to force camera outside of the hit position. - if traceResult.Hit then - traceDist = math.max(traceResult.HitPos:Distance(tracePos) - 10, 0) - end - LocalPlayer().ThirdPersonDistance = traceDist - - -- Correct view position - view.origin = tracePos - (ang:Forward() * traceDist) ---[[ else - local wep = ply:GetActiveWeapon() - if wep && wep != NULL then - local func = wep.GetViewModelPosition - if func then - view.vm_origin, view.vm_angles = func(wep, origin*1, angles*1) -- Note: *1 to copy the object so the child function can't edit it. - end - - local func = wep.CalcView - if func then - view.origin, view.angles, view.fov = func(wep, pl, origin*1, angles*1, fov) -- Note: *1 to copy the object so the child function can't edit it. - end - end--]] - end - - return view; -end - --- Render halos and player names. -function DrawPlayerNames(bDrawingDepth, bDrawingSkybox) - for i,v in ipairs(player.GetAll()) do - if v:Alive() && v != LocalPlayer() then - local pos = v:GetPos() + v:GetViewOffset() + Vector(0, 0, 5) - local ang = Angle(0, LocalPlayer():EyeAngles().y - 90, 90 - LocalPlayer():EyeAngles().x) - local healthPrc = v:Health() / v:GetMaxHealth() - local healthCol = HSVToColor(120 * healthPrc, 1.0, 1.0) - - if v:Team() == TEAM_HUNTERS || LocalPlayer():Team() == TEAM_PROPS then - cam.Start3D2D(pos, ang, 0.15) - draw.DrawText(v:GetName(), "Trebuchet24", 0, -draw.GetFontHeight("Trebuchet24"), healthCol, TEXT_ALIGN_CENTER) - cam.End3D2D() - end - end - end -end -hook.Add("PostDrawTranslucentRenderables", "PH_DrawPlayerNames", DrawPlayerNames) - -function DrawPlayerHalos(bDrawingDepth, bDrawingSkybox) - for i,v in ipairs(player.GetAll()) do - if v:Alive() then - local pos = v:GetPos() + Vector(0, 0, 1) * (v:OBBMaxs().z - v:OBBMins().z + 5) - local ang = Angle(0, LocalPlayer():EyeAngles().y - 90, 90 - LocalPlayer():EyeAngles().x) - local healthPrc = v:Health() / v:GetMaxHealth() - local healthCol = HSVToColor(120 * healthPrc, 1.0, 1.0) - - if v:Team() == TEAM_HUNTERS || LocalPlayer():Team() == TEAM_PROPS then - local ent = v - if v.ph_prop && v.ph_prop:IsValid() then ent = v.ph_prop end - - halo.Add({ent}, healthCol, 2, 2, 1) - end - end - end -end ---hook.Add("PostDrawEffects", "PH_DrawPlayerHalos", DrawPlayerHalos) - --- UMSG: Update player Hull and health. -function UMSGSetHull(um) - local hullOBBMin = um:ReadVector() - local hullOBBMax = um:ReadVector() - local new_health = um:ReadShort() - - LocalPlayer():NewHull(hullOBBMin, hullOBBMax) - LocalPlayer():SetHealth(new_health) -end -usermessage.Hook("SetHull", UMSGSetHull) diff --git a/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/cl_worldtips.lua b/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/cl_worldtips.lua deleted file mode 100644 index c4ed6e0..0000000 --- a/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/cl_worldtips.lua +++ /dev/null @@ -1,93 +0,0 @@ - - -surface.CreateFont( "GModWorldtip", -{ - font = "Helvetica", - size = 20, - weight = 700 -}) - -local cl_drawworldtooltips = CreateConVar( "cl_drawworldtooltips", "1", { FCVAR_ARCHIVE } ) -local WorldTip = nil - -local TipColor = Color( 250, 250, 200, 255 ) - --- --- Adds a hint to the queue --- -function AddWorldTip( unused1, text, unused2, pos, ent ) - - WorldTip = {} - - WorldTip.dietime = SysTime() + 0.05 - WorldTip.text = text - WorldTip.pos = pos - WorldTip.ent = ent - -end - - -local function DrawWorldTip( tip ) - - if ( IsValid( tip.ent ) ) then - tip.pos = tip.ent:GetPos() - end - - local pos = tip.pos:ToScreen() - - local black = Color( 0, 0, 0, 255 ) - local tipcol = Color( TipColor.r, TipColor.g, TipColor.b, 255 ) - - local x = 0 - local y = 0 - local padding = 10 - local offset = 50 - - surface.SetFont( "GModWorldtip" ) - local w, h = surface.GetTextSize( tip.text ) - - x = pos.x - w - y = pos.y - h - - x = x - offset - y = y - offset - - draw.RoundedBox( 8, x-padding-2, y-padding-2, w+padding*2+4, h+padding*2+4, black ) - - - local verts = {} - verts[1] = { x=x+w/1.5-2, y=y+h+2 } - verts[2] = { x=x+w+2, y=y+h/2-1 } - verts[3] = { x=pos.x-offset/2+2, y=pos.y-offset/2+2 } - - draw.NoTexture() - surface.SetDrawColor( 0, 0, 0, tipcol.a ) - surface.DrawPoly( verts ) - - - draw.RoundedBox( 8, x-padding, y-padding, w+padding*2, h+padding*2, tipcol ) - - local verts = {} - verts[1] = { x=x+w/1.5, y=y+h } - verts[2] = { x=x+w, y=y+h/2 } - verts[3] = { x=pos.x-offset/2, y=pos.y-offset/2 } - - draw.NoTexture() - surface.SetDrawColor( tipcol.r, tipcol.g, tipcol.b, tipcol.a ) - surface.DrawPoly( verts ) - - - draw.DrawText( tip.text, "GModWorldtip", x + w/2, y, black, TEXT_ALIGN_CENTER ) - -end - - -function GM:PaintWorldTips() - - if ( !cl_drawworldtooltips:GetBool() ) then return end - - if ( WorldTip && WorldTip.dietime > SysTime() ) then - DrawWorldTip( WorldTip ) - end - -end diff --git a/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/init.lua b/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/init.lua deleted file mode 100644 index ab3621a..0000000 --- a/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/init.lua +++ /dev/null @@ -1,401 +0,0 @@ ---[[ - The MIT License (MIT) - - Copyright (c) 2015 Project Kube - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. ---]] - ---! Client Files -AddCSLuaFile("cl_init.lua") -AddCSLuaFile("sh_init.lua") - ---! Include shared lua. -include "sh_init.lua" - ---! Include server lua. -include "server/config.lua" -include "server/console/variables.lua" -include "compat/compat_tauntpackloader.lua" - --- ------------------------------------------------------------------------- -- ---! Gamemode --- ------------------------------------------------------------------------- -- - --- GameStates -GM_STATES_SETUP = 0 -GM_STATES_HIDE = 1 -GM_STATES_SEEK = 2 -GM_STATES_SHAMING = 3 -- Do your best, hiders! - ---! Initialize -function GM:Initialize() - self.State = GM_STATES_SETUP - self.StatePrev = self.State - - --! Run any hooked functions that addons have registered for Prop Hunt. - hook.Run("OnPropHuntInitialized") -end - ---! Check Victory and Loss conditions -function GM:Think() - if (self.State == GM_STATES_SETUP) then - --! GameState: Setup - -- Here we do all the stuff that would be ridiculous to do while playing. - if (self.StatePrev != self.State) then - game.CleanUpMap() - - -- Assign correct teams depending on Sub-Gamemode. - if (self.Config.Modes.SwapTeams == 1) then - for i,pl in ipairs(player.GetAll()) do - if (pl:Team() == TEAM_HIDERS) then - pl:SetTeam(TEAM_SEEKERS) - elseif (pl:Team() == TEAM_SEEKERS) then - pl:SetTeam(TEAM_HIDERS) - end - end - elseif (self.Config.Modes.RandomizeTeams == 1) then - local plys = player.GetAll() - --local plyCount = - - elseif (self.Config.Modes.TheDeadHunt == 1) then - - end - - -- Respawn players - for i,pl in ipairs(player.GetAll()) do - pl:Respawn() - end - end - - -- Advanced to next GameState if we have enough players - self.StatePrev = self.State - self.State = GM_STATES_HIDE - elseif (self.State == GM_STATES_HIDE) then - - elseif (self.State == GM_STATES_SEEK) then - - elseif (self.State == GM_STATES_SHAMING) then - - else - -- Invalid State, we have to reset - self.StatePrev = self.State - self.State = GM_STATES_SETUP - end -end - --- ------------------------------------------------------------------------- -- ---! LEGACY CODE - TO BE REPLACED SOON --- ------------------------------------------------------------------------- -- -function GM:AllowPlayerPickup(player, entity) - return true -end - -function AnnounceVictory(players, force) - for i,pl in ipairs(players) do - if pl:Alive() || force || pl:Team() == TEAM_SPECTATOR then - announcer = table.Random(VICTORY_SOUNDS); - print("Prop Hunt: '"..pl:GetName().."' announcing victory with '"..announcer.."'.") - pl:EmitSound(announcer, 200, 100, 0.5, CHAN_VOICE2) - end - end -end - -function AnnounceLoss(players, force) - for i,pl in ipairs(players) do - if pl:Alive() || force || pl:Team() == TEAM_SPECTATOR then - announcer = table.Random(LOSS_SOUNDS); - print("Prop Hunt: '"..pl:GetName().."' announcing loss with '"..announcer.."'.") - pl:EmitSound(announcer, 100, 100, 0.5, CHAN_VOICE2) - end - end -end - --- If there is a mapfile send it to the client (sometimes servers want to change settings for certain maps) -if file.Exists("maps/"..game.GetMap()..".lua", "LUA") then - AddCSLuaFile("maps/"..game.GetMap()..".lua") -end - - --- Server only constants -EXPLOITABLE_DOORS = { - "func_door", - "prop_door_rotating", - "func_door_rotating" -} -USABLE_PROP_ENTITIES = { - "prop_physics", - "prop_physics_multiplayer" -} - --- Send the required resources to the client -for _, announcer in pairs(LOSS_SOUNDS) do resource.AddFile("sound/"..announcer) end -for _, announcer in pairs(VICTORY_SOUNDS) do resource.AddFile("source/"..announcer) end -for _, taunt in pairs(HUNTER_TAUNTS) do resource.AddFile("sound/"..taunt) end -for _, taunt in pairs(PROP_TAUNTS) do resource.AddFile("sound/"..taunt) end - --- Called alot -function GM:CheckPlayerDeathRoundEnd() - if !GAMEMODE.RoundBased || !GAMEMODE:InRound() then - return - end - - local Teams = GAMEMODE:GetTeamAliveCounts() - - if table.Count(Teams) == 0 then - GAMEMODE:RoundEndWithResult(1001, "Draw, everyone loses!") - AnnounceLoss(player.GetAll(), true) - return - end - - if table.Count(Teams) == 1 then - -- Play victory and loss sounds. - if Teams[0] == TEAM_HUNTERS then - AnnounceVictory(team.GetPlayers(TEAM_HUNTERS)) - AnnounceLoss(team.GetPlayers(TEAM_PROPS)) - elseif Teams[0] == TEAM_PROPS then - AnnounceLoss(team.GetPlayers(TEAM_HUNTERS)) - AnnounceVictory(team.GetPlayers(TEAM_PROPS)) - end - - local TeamID = table.GetFirstKey(Teams) - GAMEMODE:RoundEndWithResult(TeamID, team.GetName(TeamID).." win!") - return - end -end - - --- Called when an entity takes damage -function EntityTakeDamage(ent, dmginfo) - local att = dmginfo:GetAttacker() - if GAMEMODE:InRound() && ent && ent:GetClass() != "ph_prop" && !ent:IsPlayer() && att && att:IsPlayer() && att:Team() == TEAM_HUNTERS && att:Alive() then - att:SetHealth(att:Health() - GetConVar("HUNTER_FIRE_PENALTY"):GetInt()) - if att:Health() <= 0 then - MsgAll(att:Name() .. " felt guilty for hurting so many innocent props and committed suicide\n") - att:Kill() - end - end -end -hook.Add("EntityTakeDamage", "PH_EntityTakeDamage", EntityTakeDamage) - - --- Called when player tries to pickup a weapon -function GM:PlayerCanPickupWeapon(pl, ent) - if pl:Team() != TEAM_HUNTERS then - return false - end - - return true -end - - --- Called when player needs a model -function GM:PlayerSetModel(pl) - local player_model = pl:GetModel() - - if pl:Team() == TEAM_HUNTERS then - player_model = "models/player/combine_super_soldier.mdl" - elseif pl:Team() == TEAM_PROPS then - player_model = "models/Gibs/Antlion_gib_small_3.mdl" - end - - util.PrecacheModel(player_model) - pl:SetModel(player_model) -end - - --- Called when a player tries to use an object -function GM:PlayerUse(pl, ent) - if !pl:Alive() || pl:Team() == TEAM_SPECTATOR then return false end - --- if pl:Team() == TEAM_PROPS && pl:IsOnGround() && !pl:Crouching() && table.HasValue(USABLE_PROP_ENTITIES, ent:GetClass()) && ent:GetModel() then - if pl:Team() == TEAM_PROPS && table.HasValue(USABLE_PROP_ENTITIES, ent:GetClass()) && ent:GetModel() then - if table.HasValue(BANNED_PROP_MODELS, ent:GetModel()) then - pl:ChatPrint("That prop has been banned by the server.") - elseif ent:GetPhysicsObject():IsValid() then -- && pl.ph_prop:GetModel() != ent:GetModel() then - local ent_health = math.Clamp(ent:GetPhysicsObject():GetVolume() / 250, 1, 200) - - -- Prevent props from gaining health by changing. - local per = math.min(pl:Health() / pl:GetMaxHealth(), pl.tempHealthPc || 1.0) - if (pl.tempHealthPc == nil) || (per <= pl.tempHealthPc) then pl.tempHealthPc = per end - local new_health = math.Clamp(per * ent_health, 1, 200) - - pl:SetJumpPower(math.Clamp(ent:GetPhysicsObject():GetVolume() / 333, 200, 600)); - - -- Set Prop Data - pl.ph_prop:SetHealth(new_health) - pl.ph_prop:SetMaxHealth(ent_health) - pl.ph_prop:SetModel(ent:GetModel()) - pl.ph_prop:SetSkin(ent:GetSkin()) - - -- Update Hull and Health - pl:NewHull(ent:OBBMins(), ent:OBBMaxs()) - pl:SetHealth(new_health) - pl:SetMaxHealth(ent_health) - umsg.Start("SetHull", pl) - umsg.Vector(ent:OBBMins()) - umsg.Vector(ent:OBBMaxs()) - umsg.Short(new_health) - umsg.End() - end - end - - -- Prevent the door exploit - if table.HasValue(EXPLOITABLE_DOORS, ent:GetClass()) && pl.last_door_time && pl.last_door_time + 1 > CurTime() then - return false - end - - pl.last_door_time = CurTime() - return true -end - - --- Called when player presses [F3]. Plays a taunt for their team -function GM:ShowSpare1(pl) - if GAMEMODE:InRound() && pl:Alive() && (pl:Team() == TEAM_HUNTERS || pl:Team() == TEAM_PROPS) && pl.last_taunt_time + TAUNT_DELAY <= CurTime() && #PROP_TAUNTS > 1 && #HUNTER_TAUNTS > 1 then --- repeat - if pl:Team() == TEAM_HUNTERS then - rand_taunt = table.Random(HUNTER_TAUNTS) - else - rand_taunt = table.Random(PROP_TAUNTS) - end --- until rand_taunt != pl.last_taunt - - pl.last_taunt_time = CurTime() - pl.last_taunt = rand_taunt - - print("Prop Hunt: '"..pl:GetName().."' taunting with '"..rand_taunt.."'.") - local vol = 1.0 - if pl:Team() == TEAM_HUNTERS then vol = vol * 0.5 end - pl:EmitSound(rand_taunt, 100, 100, vol, CHAN_VOICE2) - end -end - --- Allow player to rotate the prop. (Either F4 or ducking) -function GM:ShowSpare2(pl) - if pl:Alive() && (pl:Team() == TEAM_PROPS) then - pl.ph_prop:SetApplyNewAngles(!pl.ph_prop:GetApplyNewAngles()) --- pl.ph_prop:SetNewAngles(pl:GetAngles()) - end -end - --- Called when the gamemode is initialized -function Initialize() - game.ConsoleCommand("mp_flashlight 0\n") -end -hook.Add("Initialize", "PH_Initialize", Initialize) - - --- Called when a player leaves -function PlayerDisconnected(pl) - pl:RemoveProp() -end -hook.Add("PlayerDisconnected", "PH_PlayerDisconnected", PlayerDisconnected) - - --- Called when the players spawns -function PlayerSpawn(pl) - pl:Blind(false) - pl:RemoveProp() - pl:SetColor( Color(255, 255, 255, 255)) - pl:SetRenderMode( RENDERMODE_TRANSALPHA ) - pl:UnLock() - pl:ResetHull() - pl:SetViewOffset(Vector(0, 0, 64)) - pl:SetViewOffsetDucked(Vector(0, 0, 28)) - pl.last_taunt_time = 0 - pl:SetupHands() - - umsg.Start("ResetHull", pl) - umsg.End() --- umsg.Start("ThirdPerson", pl) --- umsg.Bool(pl:Team() == TEAM_PROPS) --- umsg.Entity(nil) --- umsg.End() - - pl:SetCollisionGroup(COLLISION_GROUP_PASSABLE_DOOR) -end -hook.Add("PlayerSpawn", "PH_PlayerSpawn", PlayerSpawn) - -function GM:PlayerSetHandsModel( ply, ent ) - local simplemodel = player_manager.TranslateToPlayerModelName( ply:GetModel() ) - local info = player_manager.TranslatePlayerHands( simplemodel ) - if ( info ) then - ent:SetModel( info.model ) - ent:SetSkin( info.skin ) - ent:SetBodyGroups( info.body ) - end -end - - --- Removes all weapons on a map -function RemoveWeaponsAndItems() - for _, wep in pairs(ents.FindByClass("weapon_*")) do - wep:Remove() - end - - for _, item in pairs(ents.FindByClass("item_*")) do - item:Remove() - end -end -hook.Add("InitPostEntity", "PH_RemoveWeaponsAndItems", RemoveWeaponsAndItems) - - --- Called when round ends -function RoundEnd() - for _, pl in pairs(team.GetPlayers(TEAM_HUNTERS)) do - pl:Blind(false) - pl:UnLock() - end -end -hook.Add("RoundEnd", "PH_RoundEnd", RoundEnd) - - --- This is called when the round time ends (props win) -function GM:RoundTimerEnd() - if !GAMEMODE:InRound() then - return - end - - GAMEMODE:RoundEndWithResult(TEAM_PROPS, "Props win!") -end - - --- Called before start of round -function GM:OnPreRoundStart(num) - game.CleanUpMap() - - if GetGlobalInt("RoundNumber") != 1 && (SWAP_TEAMS_EVERY_ROUND == 1 || ((team.GetScore(TEAM_PROPS) + team.GetScore(TEAM_HUNTERS)) > 0 || SWAP_TEAMS_POINTS_ZERO==1)) then - for _, pl in pairs(player.GetAll()) do - if pl:Team() == TEAM_PROPS || pl:Team() == TEAM_HUNTERS then - if pl:Team() == TEAM_PROPS then - pl:SetTeam(TEAM_HUNTERS) - else - pl:SetTeam(TEAM_PROPS) - end - - pl:ChatPrint("Teams have been swapped!") - end - end - end - - UTIL_StripAllPlayers() - UTIL_SpawnAllPlayers() - UTIL_FreezeAllPlayers() -end diff --git a/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/player_class/class_hider.lua b/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/player_class/class_hider.lua deleted file mode 100644 index b1f1996..0000000 --- a/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/player_class/class_hider.lua +++ /dev/null @@ -1,52 +0,0 @@ --- Create new class -DEFINE_BASECLASS( "player_default" ) -local CLASS = {} - --- Some settings for the class -CLASS.DisplayName = "Hider" -CLASS.WalkSpeed = 250 -CLASS.CrouchedWalkSpeed = 0.2 -CLASS.RunSpeed = 250 -CLASS.DuckSpeed = 0.2 -CLASS.DrawTeamRing = false - --- Called by spawn and sets loadout -function CLASS:Loadout(pl) - -- Props don't get anything -end - --- Called when player spawns with this class -function CLASS:OnSpawn(pl) - pl:SetColor( Color(255, 255, 255, 0)) - - pl.ph_prop = ents.Create("ph_prop") - pl.ph_prop:SetPos(pl:GetPos()) - pl.ph_prop:SetAngles(pl:GetAngles()) - pl.ph_prop:Spawn() - pl.ph_prop:SetOwner(pl) - - pl:SetJumpPower(200); - - -- Update Hull and Health - pl:SetHealth(100) - pl:SetMaxHealth(100) - pl.ph_prop:SetHealth(100) - pl.ph_prop:SetMaxHealth(100) - - local hullMin = Vector(-20, -20, -10) - local hullMax = Vector( 20, 20, 60) - pl:NewHull(hullMin, hullMax) - umsg.Start("SetHull", pl) - umsg.Vector(hullMin) - umsg.Vector(hullMax) - umsg.Short(100) - umsg.End() -end - --- Called when a player dies with this class -function CLASS:OnDeath(pl, attacker, dmginfo) - pl:RemoveProp() -end - --- Register -player_manager.RegisterClass("Hider", CLASS) diff --git a/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/player_class/class_seeker.lua b/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/player_class/class_seeker.lua deleted file mode 100644 index 14decc6..0000000 --- a/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/player_class/class_seeker.lua +++ /dev/null @@ -1,120 +0,0 @@ ---[[ - The MIT License (MIT) - - Copyright (c) 2015 Project Kube - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. ---]] - ---! This file defines the Seeker player class. --- A seeker is someone who is looking for the hiders, using weapons or other --- means of detecting idiots. Also someone who looks like a diaper baby. --- Weapons and Ammo are granted upon spawn and have to be used sparingly or --- they'll be stuck with the crowbar. Bad seeker, bad. --- Gain health upon killing a hider, lose health when attacking non-hiders. --- Death upon health reaching 0. - -DEFINE_BASECLASS( "player_default" ) -local SEEKER = {} -SEEKER.DisplayName = "Seeker" -SEEKER.WalkSpeed = 230 -- How fast to move when not running -SEEKER.RunSpeed = 460 -- How fast to move when running -SEEKER.CrouchedWalkSpeed = 0.2 -- Multiply move speed by this when crouching -SEEKER.DuckSpeed = 0.2 -- How fast to go from not ducking, to ducking -SEEKER.UnDuckSpeed = 0.2 -- How fast to go from ducking, to not ducking -SEEKER.JumpPower = 200 -- How powerful our jump should be -SEEKER.CanUseFlashlight = true -- Can we use the flashlight -SEEKER.MaxHealth = 100 -- Max health we can have -SEEKER.StartHealth = 100 -- How much health we start with -SEEKER.StartArmor = 0 -- How much armour we start with -SEEKER.DropWeaponOnDie = false -- Do we drop our weapon when we die -SEEKER.TeammateNoCollide = true -- Do we collide with teammates or run straight through them -SEEKER.AvoidPlayers = true -- Automatically swerves around other players -SEEKER.UseVMHands = true -- Uses viewmodel hands - --- Called by spawn and sets loadout -function SEEKER:Loadout(pl) - -- Give the weapons the admin told us to. - local weapons = string.Split(GM.Config.Seeker.Weapons, ",") - for i,weapon in ipairs(weapons) do - pl:Give(weapon) - end - - -- Give the ammo the admin told us to. - local ammos = string.Split(GM.Config.Seeker.Ammo, ",") - for i,ammo in ipairs(ammos) do - local typeCount = string.Split(ammo, ":") - pl:GiveAmmo(typeCount[1], typeCount[0], true) - end - - -- Default weapon stuff - local cl_defaultweapon = pl:GetInfo("cl_defaultweapon") - if pl:HasWeapon(cl_defaultweapon) then - pl:SelectWeapon(cl_defaultweapon) - end -end - --- Called when player spawns with this class -function SEEKER:OnSpawn(pl) - local unlock_time = math.Clamp(GetConVar("ph_rounds_blindtime"):GetInt() - (CurTime() - GetGlobalFloat("RoundStartTime", 0)), 0, GetConVar("ph_rounds_blindtime"):GetInt()) - 1 - -- !TODO! ph_rounds_blindtime - - --function MyLockFunc() - --function MyUnlockFunc() - - local unblindfunc = function() - if pl:IsValid() == false then return end - --MyUnblindFunc(pl.Blind(false)) - pl:Blind(false) - end - local lockfunc = function() - if pl:IsValid() == false then return end - --MyLockFunc(pl.Lock()) - pl.Lock(pl) - end - local unlockfunc = function() - if pl:IsValid() == false then return end - --MyUnlockFunc(pl.UnLock()) - pl.UnLock(pl) - end - - if unlock_time > 2 then - pl:Blind(true) - - timer.Simple(unlock_time, unblindfunc) - - timer.Simple(1, lockfunc) - timer.Simple(unlock_time, unlockfunc) - end - - pl:SetupHands() -end - -function SEEKER:GetHandsModel() - return { model = "models/weapons/c_arms_combine.mdl", skin = 1, body = "0100000" } -end - --- Called when a player dies with this SEEKER -function SEEKER:OnDeath(pl, attacker, dmginfo) - pl:CreateRagdoll() - pl:UnLock() -end - --- Register -player_manager.RegisterClass("Seeker", SEEKER) diff --git a/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/server/config.lua b/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/server/config.lua deleted file mode 100644 index 73dded6..0000000 --- a/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/server/config.lua +++ /dev/null @@ -1,433 +0,0 @@ ---[[ - The MIT License (MIT) - - Copyright (c) 2015 Project Kube - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. ---]] - ---! Initialize configuration table. -GM.Config = { } - ---! Basic Settings --- Timelimit in minutes -GM.Config.TimeLimit = math.max(GetConVarNumber("mp_timelimit"),0) --- You have to wait x seconds to taunt again. -GM.Config.TauntWaitTime = 5 --- Is sprinting enabled? -GM.Config.Sprinting = 0 --false - ---! Round Settings -GM.Config.Rounds = {} --- How many rounds should we attempt to have? -GM.Config.Rounds.Amount = 10 --- Rounds last x seconds. -GM.Config.Rounds.Time = 300 --- Time for HIders to hide. -GM.Config.Rounds.BlindTime = 30 - ---! Game Modes -GM.Config.Modes = {} --- Sub-mode: Simple Team Swap -GM.Config.Modes.SwapTeams = 1--true --- Sub-mode: Randomize Teams -GM.Config.Modes.RandomizeTeams = 0--false --- Sub-mode: The Dead Hunt (Dead Prop becomes Hunter) -GM.Config.Modes.TheDeadHunt = 0--false - ---! Seeker Settings -GM.Config.Seeker = {} -GM.Config.Seeker.HealthStart = 100 -GM.Config.Seeker.HealthMax = 100 -GM.Config.Seeker.HealthBonus = 10 -GM.Config.Seeker.HealthPenalty = 1 -GM.Config.Seeker.Weapons = "weapon_crowbar,weapon_pistol,weapon_ph_smg,weapon_shotgun" -GM.Config.Seeker.Ammo = "Pistol:100,SMG1:300,SMG1_Grenade:1,Buckshot:64" - ---! Hider Settings -GM.Config.Hider = {} -GM.Config.Hider.HealthStart = 100 -GM.Config.Hider.HealthMax = 100 -GM.Config.Hider.HealthScaling = 1--true -GM.Config.Hider.HealthScalingMax = 200 - ---! Taunts -GM.Config.Taunts = { - Seeker = { }, - Hider = { }, -} - --- Taunts.Clear() ---@desc: Clears the current taunt list. -GM.Config.Taunts.Clear = function() - this.Seeker = {} - this.Hider = {} -end - --- Taunts.Load(sTauntListFile) ---@desc: Loads the taunt list from disk. ---@param: --- sTauntListFile - A string containing the path to the taunt list to load. ---@return: true or false depending on success. -GM.Config.Taunts.Load = function(sTauntListFile) - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Load: Loading taunt list from file '"..sTauntListFile.."'...") end - - -- Safeguard against idiots. - if type(sTauntListFile) != "string" then - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Load: is not a string.") end - return false - end - - -- Given file must exist for us to continue. - if ! file.Exists(sTauntListFile, "GAME") then - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Load: File not found.") end - return false - end - - -- Read the file and check if it's empty. - sTauntListData = file.Read(sTauntListFile, "GAME") - if sTauntListData == "" then - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Load: File is empty.") end - return false - end - - -- Convert JSON to a table for us to use. - sTauntList = util.JSONToTable(sTauntListData) - - -- Is it nil? Then it's not valid JSON - if sTauntList == nil then - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Load: File contains invalid JSON.") end - return false - end - - -- Finally, append the taunt lists. - if sTauntList.Seeker != nil then - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Load: Adding Seeker taunts...") end - for k,v in pairs(sTauntList.Seeker) do - GAMEMODE.Taunts.Seeker[k] = v - end - end - if sTauntList.Hider != nil then - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Load: Adding Hider taunts...") end - for k,v in pairs(sTauntList.Hider) do - GAMEMODE.Taunts.Hider[k] = v - end - end - - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Load: Complete.") end - return true -end - --- Taunts.Save(sTauntListFile) ---@desc: Saves the current taunt list to disk. ---@param: --- sTauntListFile - A string containing the path to the file to save to. ---@return: true or false depending on success. -GM.Config.Taunts.Save = function(sTauntListFile) - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Save: Saving taunt list to file '"..sTauntListFile.."'...") end - - -- Safeguard against idiots. - if type(sTauntListFile) != "string" then - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Save: is not a string.") end - return false - end - - -- File must not be nil, otherwise we can't write to it. - if sTauntListFile == nil then - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Save: No file given.") end - return false - end - - -- Convert our taunt table to JSON. - sTauntListData = util.TableToJSON(GAMEMODE.Taunts); - if sTauntListData == nil then - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Save: Corrupted GAMEMODE table.") end - return false - end - - -- Write out JSON out to file - if ! file.Write(sTauntListFile, sTauntListData) then - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Save: Failed to write to file.") end - return false - end - - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Save: Complete.") end - return true -end - --- Taunts.Add(sTauntName, sSoundFile, iTeamID, mPropFilter) ---@desc: Registers a new taunt with the given name, file, team and filter. ---@param: --- sTauntName - The unique name of the taunt. --- sSoundFile - A sound file to play when this taunt is selected. --- iTeamID - The team that should receive the taunt or nil for all teams. --- mPropFilter - A string or a table containing strings for props that should be able to use this taunt. ---@return: true or false depending on success. -GM.Config.Taunts.Add = function(sTauntName, sSoundFile, iTeamID, mPropFilter) - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Add: Adding new taunt '"..sTauntName.."'...") end - - -- Safeguard against idiots. - if type(sTauntName) != "string" then - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Add: is not a string.") end - return false - end - if type(sSoundFile) != "string" then - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Add: is not a string.") end - return false - end - if (type(iTeamID) != "number" && iTeamID != nil) then - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Add: is not a number or nil.") end - return false - end - if (type(mPropFilter) != "string" && type(mPropFilter) != "table" && mPropFilter != nil) then - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Add: is not a string, table or nil.") end - return false - end - - -- Check if the sound file actually exists - if !file.Exists("sound/"..sSoundFile, "GAME") then - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Add: File '"..sSoundFile.."' does not exist.") end - return false - end - - -- Make sure that our prop filter is a table listing the props it's supposed to work for. - if (mPropFilter == nil) then - mPropFilter = { } - elseif type(mPropFilter) == "string" then - mPropFilter = { mPropFilter } - end - - -- Prepare Taunt table - Taunt = { - File = sSoundFile, - Filter = mPropFilter - } - - -- If iTeamID is nil, both teams will receive the taunt. - if iTeamID == nil then - GAMEMODE.Taunts.Seeker[sTauntName] = Taunt - GAMEMODE.Taunts.Hider[sTauntName] = Taunt - else - -- Make sure that the team is valid. - if ! team.Valid(iTeamID) then - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Add: Team "..iTeamID.."' does not exist.") end - return false - end - - if (iTeamID == TEAM_SEEKERS) then - GAMEMODE.Taunts.Seeker[sTauntName] = Taunt - elseif (iTeamID == TEAM_HIDERS) then - GAMEMODE.Taunts.Hider[sTauntName] = Taunt - else - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Add: Team "..iTeamID.."' can't have taunts.") end - return false - end - end - - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Add: Complete.") end - return true -end - --- Taunts.Remove(sTauntName, iTeamID) ---@desc: Removes a registered taunt with the given name and team. ---@param: --- sTauntName - The unique name of the taunt. --- iTeamID - The team that the taunt should be removed from or nil for all teams. ---@return: true or false depending on success. -GM.Config.Taunts.Remove = function(sTauntName, iTeamID) - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Remove: Removing taunt '"..sTauntName.."'...") end - - -- Safeguard against idiots. - if type(sTauntName) != "string" then - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Remove: is not a string.") end - return false - end - if (type(iTeamID) != "number" && iTeamID != nil) then - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Remove: is not a number or nil.") end - return false - end - - -- if iTeamID is nil, both teams will have the taunt removed. - if (iTeamID == nil) then - GAMEMODE.Taunts.Seeker[sTauntName] = nil - GAMEMODE.Taunts.Hider[sTauntName] = nil - else - -- Make sure we have a valid Team. - if ! team.Valid(iTeamID) then - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Remove: Team "..iTeamID.."' does not exist.") end - return false - end - - if iTeamID == TEAM_SEEKERS then - GAMEMODE.Taunts.Seeker[sTauntName] = nil - elseif iTeamID == TEAM_HIDERS then - GAMEMODE.Taunts.Hider[sTauntName] = nil - else - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Remove: Team "..iTeamID.."' can't have taunts.") end - return false - end - end - - if GAMEMODE.Debug then print("Prop Hunt.Taunts.Remove: Complete.") end - return true -end - --- ToDo: Taunts.Get(iTeamID, sPropName) - ---! Announcers (Round Start, Unblind, Win, Loss) -GM.Config.Announcers = { - Start = { }, - Unblind = { }, - Win = { }, - Loss = { } -} - --- Announcers.Clear() ---@desc: Clears the current announcer list. -GM.Config.Announcers.Clear = function() - Announcers.Start = { } - Announcers.Unblind = { } - Announcers.Win = { } - Announcers.Loss = { } -end - --- Announcers.Load(sAnnouncerListFile) ---@desc: Tries to load the given announcer list. ---@param: --- sAnnouncerListFile - A string containing the path to the announcer list to load. ---@return: true or false depending on success. -GM.Config.Announcers.Load = function(sAnnouncerListFile) - if GAMEMODE.Debug then print("Prop Hunt.Announcers.Load: Loading announcer list from file '"..sAnnouncerListFile.."'...") end - - -- Safeguard against idiots. - if type(sAnnouncerListFile) != "string" then - if GAMEMODE.Debug then print("Prop Hunt.Announcers.Load: is not a string.") end - return false - end - - -- Given file must exist for us to continue. - if ! file.Exists(sAnnouncerListFile, "GAME") then - if GAMEMODE.Debug then print("Prop Hunt.Announcers.Load: File not found.") end - return false - end - - -- Read the file and check if it's empty. - sAnnouncerListData = file.Read(sAnnouncerListFile, "GAME") - if sAnnouncerListData == "" then - if GAMEMODE.Debug then print("Prop Hunt.Announcers.Load: File is empty.") end - return false - end - - -- Convert JSON to a table for us to use. - sAnnouncerList = util.JSONToTable(sAnnouncerListData) - - -- Is it nil? Then it's not valid JSON - if sAnnouncerList == nil then - if GAMEMODE.Debug then print("Prop Hunt.Announcers.Load: File contains invalid JSON.") end - return false - end - - -- Finally, insert the announcer lists. - if sAnnouncerList.Start != nil then - if GAMEMODE.Debug then print("Prop Hunt.Announcers.Load: Adding Start announcers...") end - for k,v in pairs(sAnnouncerList.Start) do - GAMEMODE.Announcers.Start[k] = v - end - end - if sAnnouncerList.Unblind != nil then - if GAMEMODE.Debug then print("Prop Hunt.Announcers.Load: Adding Unblind announcers...") end - for k,v in pairs(sAnnouncerList.Unblind) do - GAMEMODE.Announcers.Unblind[k] = v - end - end - if sAnnouncerList.Win != nil then - if GAMEMODE.Debug then print("Prop Hunt.Announcers.Load: Adding Win announcers...") end - for k,v in pairs(sAnnouncerList.Win) do - GAMEMODE.Announcers.Win[k] = v - end - end - if sAnnouncerList.Loss != nil then - if GAMEMODE.Debug then print("Prop Hunt.Announcers.Load: Adding Loss announcers...") end - for k,v in pairs(sAnnouncerList.Loss) do - GAMEMODE.Announcers.Loss[k] = v - end - end - - if GAMEMODE.Debug then print("Prop Hunt.Announcers.Load: Complete.") end - return true -end - --- Announcers.Save(sAnnouncerListFile) ---@desc: Saves the current taunt list to disk. ---@param: --- sAnnouncerListFile - A string containing the path to the file to save to. ---@return: true or false depending on success. -GM.Config.Announcers.Save = function(sAnnouncerListFile) - if GAMEMODE.Debug then print("Prop Hunt.Announcers.Save: Saving announcer list to file '"..sAnnouncerListFile.."'...") end - - -- Safeguard against idiots. - if type(sAnnouncerListFile) != "string" then - if GAMEMODE.Debug then print("Prop Hunt.Announcers.Save: is not a string.") end - return false - end - - -- File must not be nil, otherwise we can't write to it. - if sAnnouncerListFile == nil then - if GAMEMODE.Debug then print("Prop Hunt.Announcers.Save: No file given.") end - return false - end - - -- Convert our taunt table to JSON. - sAnnouncerListData = util.TableToJSON(GAMEMODE.Announcers); - if sAnnouncerListData == nil then - if GAMEMODE.Debug then print("Prop Hunt.Announcers.Save: Corrupted GAMEMODE table.") end - return false - end - - -- Write out JSON out to file - if ! file.Write(sAnnouncerListFile, sAnnouncerListData) then - if GAMEMODE.Debug then print("Prop Hunt.Announcers.Save: Failed to write to file.") end - return false - end - - - if GAMEMODE.Debug then print("Prop Hunt.Announcers.Save: Complete.") end - return true -end - --- ToDo: Announcers.Add --- ToDo: Announcers.Remove --- ToDo: Announcers.Get(iType) - ---! Whitelists and Blacklists --- Hiders: Entity Whitelist (exact match) -GM.Config.EntityWhitelist = { - "prop_physics", - "prop_physics_multiplayer" -} - --- Hiders: Prop Blacklist (exact match) -GM.Config.PropBlacklist = {} - --- Both: Entity Use-abuse Blacklist (exact match) -GM.Config.EntityAbuseBlacklist = { - "func_door", - "func_door_rotating", - "prop_door_rotating" -} diff --git a/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/server/console/variables.lua b/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/server/console/variables.lua deleted file mode 100644 index 1db30c9..0000000 --- a/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/server/console/variables.lua +++ /dev/null @@ -1,45 +0,0 @@ ---[[ - The MIT License (MIT) - - Copyright (c) 2015 Project Kube - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. ---]] - -CreateConVar("ph_tauntwaittime", GM.Config.TauntWaitTime) -CreateConVar("ph_sprinting", GM.Config.Sprinting) -CreateConVar("ph_rounds", GM.Config.Rounds.Amount) -CreateConVar("ph_rounds_time", GM.Config.Rounds.Time) -CreateConVar("ph_rounds_blindtime", GM.Config.Rounds.BlindTime) - -CreateConVar("ph_modes_swap", GM.Config.Modes.SwapTeams) -CreateConVar("ph_modes_randomize", GM.Config.Modes.RandomizeTeams) -CreateConVar("ph_modes_thedeadhunt", GM.Config.Modes.TheDeadHunt) - -CreateConVar("ph_seeker_health", GM.Config.Seeker.HealthStart) -CreateConVar("ph_seeker_health_max", GM.Config.Seeker.HealthMax) -CreateConVar("ph_seeker_health_killbonus", GM.Config.Seeker.HealthBonus) -CreateConVar("ph_seeker_health_penalty", GM.Config.Seeker.HealthPenalty) -CreateConVar("ph_seeker_weapons", GM.Config.Seeker.Weapons) -CreateConVar("ph_seeker_ammo", GM.Config.Seeker.Ammo) - -CreateConVar("ph_hider_health", GM.Config.Hider.HealthStart) -CreateConVar("ph_hider_health_max", GM.Config.Hider.HealthMax) -CreateConVar("ph_hider_health_scale", GM.Config.Hider.HealthScaling) -CreateConVar("ph_hider_health_scaled_max", GM.Config.Hider.HealthScalingMax) \ No newline at end of file diff --git a/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/sh_init.lua b/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/sh_init.lua deleted file mode 100644 index 62864a9..0000000 --- a/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/sh_init.lua +++ /dev/null @@ -1,93 +0,0 @@ --- Gamemode Information -GM.Name = "Prop Hunt" -GM.Author = "Michael 'Xaymar' Dirks (Based on Kow@lskis Version, Original by AMT)" -GM.Email = "michael.fabian.dirks@gmail.com" -GM.Website = "http://xaymar.com/" -GM.Debug = (cvars.Number("developer") != 0) - --- ToDo: Remove fretta as a base gamemode (it's outdated and doesn't help us much). -DeriveGamemode("fretta13") - --- Shared Lua Files -if SERVER then - AddCSLuaFile("sh_config.lua") - AddCSLuaFile("sh_player.lua") -end - --- Player Classes -if SERVER then - AddCSLuaFile("player_class/class_seeker.lua") - AddCSLuaFile("player_class/class_hider.lua") -end -include "player_class/class_seeker.lua" -include "player_class/class_hider.lua" - --- Set up Teams -TEAM_SPECTATOR = 0 -TEAM_SEEKERS = 1 -TEAM_HIDERS = 2 -TEAM_HUNTERS = TEAM_SEEKERS -- Deprecated -TEAM_PROPS = TEAM_HIDERS -- Deprecated - -function GM:CreateTeams() - -- Seekers: "Hunters" - team.SetUp(TEAM_SEEKERS, "Seekers", Color(153, 204, 255, 255)) - team.SetSpawnPoint(TEAM_SEEKERS, { - "info_player_deathmatch", - "info_player_axis", - "info_player_combine", - "info_player_counterterrorist" - }) - team.SetClass(TEAM_SEEKERS, { "Seeker" }) - - -- Hiders: "Props" - team.SetUp(TEAM_HIDERS, "Hiders", Color(255, 204, 153, 255)) - team.SetSpawnPoint(TEAM_HIDERS, { - "info_player_deathmatch", - "info_player_allies", - "info_player_terrorist" - }) - team.SetClass(TEAM_HIDERS, { "Hider" }) -end - - - - - --- Gamemode Player Code & Data -include("sh_player.lua") - --- Gamemode Configuration Code & Data -include("sh_config.lua") - --- Include the configuration for this map -if file.Exists("maps/"..game.GetMap()..".lua", "LUA") || file.Exists("maps/"..game.GetMap()..".lua", "LUA") then - include("maps/"..game.GetMap()..".lua") -end - --- Help info -GM.Help = [[Prop Hunt is a twist on the classic backyard game Hide and Seek. - -As a Prop you have ]]..GetConVar("HUNTER_BLINDLOCK_TIME"):GetInt()..[[ seconds to replicate an existing prop on the map and then find a good hiding spot. Press [E] to replicate the prop you are looking at. Your health is scaled based on the size of the prop you replicate. - -As a Hunter you will be blindfolded for the first ]]..GetConVar("HUNTER_BLINDLOCK_TIME"):GetInt()..[[ seconds of the round while the Props hide. When your blindfold is taken off, you will need to find props controlled by players and kill them. Damaging non-player props will lower your health significantly. However, killing a Prop will increase your health by ]]..GetConVar("HUNTER_KILL_BONUS"):GetInt()..[[ points. - -Both teams can press [F3] to play a taunt sound. Props can press F4 to enable rotation.]] - - --- Fretta configuration -GM.AddFragsToTeamScore = true -GM.CanOnlySpectateOwnTeam = true -GM.Data = {} -GM.EnableFreezeCam = true -GM.GameLength = GAME_TIME -GM.NoAutomaticSpawning = true -GM.NoNonPlayerPlayerDamage = true -GM.NoPlayerPlayerDamage = true -GM.RoundBased = true -GM.RoundLimit = ROUNDS_PER_MAP -GM.RoundLength = ROUND_TIME -GM.RoundPreStartTime = 0 -GM.SelectModel = false -GM.SuicideString = "couldn't take the pressure and committed suicide." -GM.TeamBased = true diff --git a/Gamemode/gamemodes/xaymars_prop_hunt/prophunt.npprj b/Gamemode/gamemodes/xaymars_prop_hunt/prophunt.npprj deleted file mode 100644 index 6e4e41e..0000000 --- a/Gamemode/gamemodes/xaymars_prop_hunt/prophunt.npprj +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Gamemode/addon.json b/Source/addon.json similarity index 57% rename from Gamemode/addon.json rename to Source/addon.json index 229a1a2..74f6fee 100644 --- a/Gamemode/addon.json +++ b/Source/addon.json @@ -1,5 +1,5 @@ { - "title" : "Xaymar's Custom Prop Hunt ", + "title" : "Prop Hunt Extended", "type" : "gamemode", "tags" : [ "fun" ], "ignore" : [ diff --git a/Gamemode/gamemodes/xaymars_prop_hunt/data/prop_hunt/banned_props.txt b/Source/gamemodes/prophuntextended/data/prop_hunt/banned_props.txt similarity index 100% rename from Gamemode/gamemodes/xaymars_prop_hunt/data/prop_hunt/banned_props.txt rename to Source/gamemodes/prophuntextended/data/prop_hunt/banned_props.txt diff --git a/Gamemode/gamemodes/xaymars_prop_hunt/data/prop_hunt/config.txt b/Source/gamemodes/prophuntextended/data/prop_hunt/config.txt similarity index 100% rename from Gamemode/gamemodes/xaymars_prop_hunt/data/prop_hunt/config.txt rename to Source/gamemodes/prophuntextended/data/prop_hunt/config.txt diff --git a/Gamemode/gamemodes/xaymars_prop_hunt/data/prop_hunt/sounds_loss.txt b/Source/gamemodes/prophuntextended/data/prop_hunt/sounds_loss.txt similarity index 100% rename from Gamemode/gamemodes/xaymars_prop_hunt/data/prop_hunt/sounds_loss.txt rename to Source/gamemodes/prophuntextended/data/prop_hunt/sounds_loss.txt diff --git a/Gamemode/gamemodes/xaymars_prop_hunt/data/prop_hunt/sounds_taunt_hunter.txt b/Source/gamemodes/prophuntextended/data/prop_hunt/sounds_taunt_hunter.txt similarity index 100% rename from Gamemode/gamemodes/xaymars_prop_hunt/data/prop_hunt/sounds_taunt_hunter.txt rename to Source/gamemodes/prophuntextended/data/prop_hunt/sounds_taunt_hunter.txt diff --git a/Gamemode/gamemodes/xaymars_prop_hunt/data/prop_hunt/sounds_taunt_prop.txt b/Source/gamemodes/prophuntextended/data/prop_hunt/sounds_taunt_prop.txt similarity index 100% rename from Gamemode/gamemodes/xaymars_prop_hunt/data/prop_hunt/sounds_taunt_prop.txt rename to Source/gamemodes/prophuntextended/data/prop_hunt/sounds_taunt_prop.txt diff --git a/Gamemode/gamemodes/xaymars_prop_hunt/data/prop_hunt/sounds_victory.txt b/Source/gamemodes/prophuntextended/data/prop_hunt/sounds_victory.txt similarity index 100% rename from Gamemode/gamemodes/xaymars_prop_hunt/data/prop_hunt/sounds_victory.txt rename to Source/gamemodes/prophuntextended/data/prop_hunt/sounds_victory.txt diff --git a/Gamemode/gamemodes/xaymars_prop_hunt/entities/entities/ph_prop/cl_init.lua b/Source/gamemodes/prophuntextended/entities/entities/ph_prop/cl_init.lua similarity index 100% rename from Gamemode/gamemodes/xaymars_prop_hunt/entities/entities/ph_prop/cl_init.lua rename to Source/gamemodes/prophuntextended/entities/entities/ph_prop/cl_init.lua diff --git a/Source/gamemodes/prophuntextended/entities/entities/ph_prop/init.lua b/Source/gamemodes/prophuntextended/entities/entities/ph_prop/init.lua new file mode 100644 index 0000000..d468194 --- /dev/null +++ b/Source/gamemodes/prophuntextended/entities/entities/ph_prop/init.lua @@ -0,0 +1,8 @@ +--Thanks to Blasteh for gmod update the fix and nifnat for spectate fix! + +-- Send required files to client +AddCSLuaFile("cl_init.lua") +AddCSLuaFile("shared.lua") + +-- Include needed files +include("shared.lua") diff --git a/Source/gamemodes/prophuntextended/entities/entities/ph_prop/shared.lua b/Source/gamemodes/prophuntextended/entities/entities/ph_prop/shared.lua new file mode 100644 index 0000000..8669d18 --- /dev/null +++ b/Source/gamemodes/prophuntextended/entities/entities/ph_prop/shared.lua @@ -0,0 +1,24 @@ +-- Entity information +ENT.Type = "anim" +ENT.Base = "base_anim" + +-- Initialize +function ENT:Initialize() + self:SetModel("models/Kleiner.mdl") + self:SetCollisionGroup(COLLISION_GROUP_PLAYER) + self:SetSolid(SOLID_OBB) + self:SetRenderMode(RENDERMODE_TRANSALPHA) + self:SetColor(Color(255,255,255,255)) +end + +-- Update position +function ENT:Think() + local hullOBBMin = self:OBBMins() + local hullOBBMax = self:OBBMaxs() + local hullOBB = hullOBBMax - hullOBBMin + local pos = -Vector(0, 0, hullOBBMin.z) + + self:SetPos(self.Owner:GetPos() + pos) + self:SetVelocity(self:GetOwner():GetVelocity()) +end +--]] diff --git a/Gamemode/gamemodes/xaymars_prop_hunt/entities/weapons/weapon_ph_smg.lua b/Source/gamemodes/prophuntextended/entities/weapons/weapon_ph_smg.lua similarity index 92% rename from Gamemode/gamemodes/xaymars_prop_hunt/entities/weapons/weapon_ph_smg.lua rename to Source/gamemodes/prophuntextended/entities/weapons/weapon_ph_smg.lua index 5ff146b..93e8fce 100644 --- a/Gamemode/gamemodes/xaymars_prop_hunt/entities/weapons/weapon_ph_smg.lua +++ b/Source/gamemodes/prophuntextended/entities/weapons/weapon_ph_smg.lua @@ -193,7 +193,15 @@ end -- Reload: Combination of reloading and switching fire type. function SWEP:Reload() - if self:DefaultReload(ACT_VM_RELOAD) then self:EmitSound(self.Sound.Reload) end + if self:DefaultReload(ACT_VM_RELOAD) then + self:EmitSound(self.Sound.Reload) + else + if (self.LastReload) && ((CurTime() - self.LastReload) > 1) then + self:GetOwner():ChatPrint("BurstToggle") + self.BurstFire = !self.BurstFire + end + end + self.LastReload = CurTime() return end diff --git a/Source/gamemodes/prophuntextended/gamemode/cl_init.lua b/Source/gamemodes/prophuntextended/gamemode/cl_init.lua new file mode 100644 index 0000000..490d0fc --- /dev/null +++ b/Source/gamemodes/prophuntextended/gamemode/cl_init.lua @@ -0,0 +1,290 @@ +--[[ + The MIT License (MIT) + + Copyright (c) 2015 Xaymar + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +--]] + +-- ------------------------------------------------------------------------- -- +--! Includes +-- ------------------------------------------------------------------------- -- +include("sh_init.lua") + +include("client/cl_ui_teamselection.lua") + +-- ------------------------------------------------------------------------- -- +--! Code +-- ------------------------------------------------------------------------- -- +function GM:Initialize() + print("-------------------------------------------------------------------------") + print("Prop Hunt CL: Initializing...") + + print("Prop Hunt CL: Initializing Gamemode Data...") + self.Data = {} + + print("Prop Hunt CL: Creating Huge Ass Font...") + surface.CreateFont("PHHugeAssFont", {font="Roboto Bold Condensed", extended=true, size=160, weight=800, antialias=true}) + + print("Prop Hunt CL: Complete.") + print("-------------------------------------------------------------------------") + +end + +function GM:Think() end + +function GM:InitialPlayerSpawn() + print("Prop Hunt CL: InitialPlayerSpawn") + + -- Delay execution until LocalPlayer() is valid. + if (!LocalPlayer()) || (!IsValid(LocalPlayer())) then + timer.Simple(.1, function() GAMEMODE:InitialPlayerSpawn() end) + return + end + + print("Prop Hunt CL: InitialPlayerSpawn Valid") + + player_manager.RunClass(LocalPlayer(), "InitialClientSpawn") +end + +function GM:PlayerSpawn() + print("Prop Hunt CL: PlayerSpawn") + + -- Delay execution until LocalPlayer() is valid. + if (!LocalPlayer()) || (!IsValid(LocalPlayer())) then + timer.Simple(.1, function() GAMEMODE:PlayerSpawn() end) + return + end + + print("Prop Hunt CL: PlayerSpawn Valid") + + if !(LocalPlayer().Data) then + LocalPlayer().Data = {} + LocalPlayer().Data.ThirdPerson = true + end + + player_manager.RunClass(LocalPlayer(), "ClientSpawn") +end + +function GM:HUDPaint() + local State = GetGlobalInt("RoundState", GAMEMODE.States.PreMatch) + + -- Show Status at the top center + local statusX, statusY, statusW, statusH + statusW = 192 + statusH = 64 + statusX = ScrW() / 2 - statusW / 2 + statusY = 16 + + --! States + -- Pre Match + if (State == GAMEMODE.States.PreMatch) then + -- Show Status at the top center + draw.RoundedBox(16, statusX, statusY, statusW, statusH, Color(0, 0, 0, 204)) + surface.SetFont( "Trebuchet24" ) + surface.SetTextColor( 255, 255, 255, 255 ) + local w,h = surface.GetTextSize("Waiting...") + surface.SetTextPos( statusX + statusW/2 - w / 2, statusY + statusH/2 - h / 2) + surface.DrawText( "Waiting..." ) + + -- Pre Round + elseif (State == GAMEMODE.States.PreRound) then + -- Show Status at the top center + draw.RoundedBox(16, statusX, statusY, statusW, statusH, Color(0, 0, 0, 204)) + surface.SetFont( "Trebuchet24" ) + surface.SetTextColor( 255, 255, 255, 255 ) + local w,h = surface.GetTextSize("Preparing...") + surface.SetTextPos( statusX + statusW/2 - w / 2, statusY + statusH/2 - h / 2) + surface.DrawText( "Preparing..." ) + + -- Hide! + elseif (State == GAMEMODE.States.Hide) then + local strTime = tostring(math.ceil(GetGlobalInt("RoundTime"))) + + -- Show Status at the top center + draw.RoundedBox(16, statusX, statusY, statusW, statusH, Color(0, 0, 0, 204)) + surface.SetTextColor(255,255,255,255) + surface.SetFont("Trebuchet18") + local w,h = surface.GetTextSize("Seekers unblinded in:") + surface.SetTextPos(statusX + statusW/2 - w / 2, statusY + statusH/4 - h / 2) + surface.DrawText("Seekers unblinded in:") + + surface.SetFont( "Trebuchet24" ) + local w,h = surface.GetTextSize(strTime.." Seconds!") + surface.SetTextPos( statusX + statusW/2 - w / 2, statusY + statusH/1.5 - h / 2) + surface.DrawText(strTime.." Seconds!") + elseif (State == GAMEMODE.States.Seek) then + local intTime = math.ceil(GetGlobalInt("RoundTime")) + local strTime = string.format("%d:%02d", math.floor(intTime / 60), math.ceil(intTime % 60)) + + -- Show Status at the top center + draw.RoundedBox(16, statusX, statusY, statusW, statusH, Color(0, 0, 0, 204)) + surface.SetTextColor(255,255,255,255) + surface.SetFont("Trebuchet18") + local w,h = surface.GetTextSize("Hunting Time!") + surface.SetTextPos(statusX + statusW/2 - w / 2, statusY + statusH/4 - h / 2) + surface.DrawText("Hunting Time!") + + surface.SetFont( "Trebuchet24" ) + local w,h = surface.GetTextSize(strTime) + surface.SetTextPos( statusX + statusW/2 - w / 2, statusY + statusH/1.5 - h / 2) + surface.DrawText(strTime) + + elseif (State == GAMEMODE.States.PostRound) then + + elseif (State == GAMEMODE.States.PostMatch) then + + end + + player_manager.RunClass(LocalPlayer(), "HUDPaint") +end + +function GM:ShowTeamSelection() + TeamSelectionUI:Show() +end +concommand.Add("ph_select_team", function() GAMEMODE:ShowTeamSelection() end) + +function GM:GetHandsModel() + return player_manager.RunClass(LocalPlayer(), "GetHandsModel") +end + +function GM:PostDrawViewModel( vm, ply, weapon ) + if ( weapon.UseHands || !weapon:IsScripted() ) then + local hands = LocalPlayer():GetHands() + if ( IsValid( hands ) ) then hands:DrawModel() end + end +end + +-- ------------------------------------------------------------------------- -- +--! Player Manager Binding +-- ------------------------------------------------------------------------- -- +function GM:CalcView(ply, pos, ang, fov, nearZ, farZ) + return player_manager.RunClass(LocalPlayer(), "CalcView", {origin = pos, angles = ang, fov = fov, znear = nearZ, zfar = farZ}) +end + +-- ------------------------------------------------------------------------- -- +--! Gamemode Functionality +-- ------------------------------------------------------------------------- -- +function GM:PlayerSetViewOffset(vo, voduck) + -- Delay execution until LocalPlayer() is valid. + if (!LocalPlayer()) || (!IsValid(LocalPlayer())) then + if !(GAMEMODE.TempData) then GAMEMODE.TempData = {} end + GAMEMODE.TempData.ViewOffset = vo + GAMEMODE.TempData.ViewOffsetDuck = voduck + + timer.Simple(.1, function() GAMEMODE:PlayerSetViewOffset(GAMEMODE.TempData.ViewOffset, GAMEMODE.TempData.ViewOffsetDuck) end) + return + end + + LocalPlayer():SetViewOffset(vo) + LocalPlayer():SetViewOffsetDucked(voduck) + if LocalPlayer():Crouching() then + LocalPlayer():SetCurrentViewOffset(voduck) + else + LocalPlayer():SetCurrentViewOffset(vo) + end +end + +function GM:PlayerSetHull(hullMin, hullMax) + -- Delay execution until LocalPlayer() is valid. + if (!LocalPlayer()) || (!IsValid(LocalPlayer())) then + if !(GAMEMODE.TempData) then GAMEMODE.TempData = {} end + GAMEMODE.TempData.HullMin = hullMin + GAMEMODE.TempData.HullMax = hullMax + + timer.Simple(.1, function() GAMEMODE:PlayerSetHull(GAMEMODE.TempData.HullMin, GAMEMODE.TempData.HullMax) end) + return + end + + if (hullMin == hullMax) && (hullMin == nil) then + LocalPlayer():ResetHull() + else + LocalPlayer():SetHull(hullMin, hullMax) + LocalPlayer():SetHullDuck(hullMin, hullMax) + end +end + +-- ------------------------------------------------------------------------- -- +--! Commands +-- ------------------------------------------------------------------------- -- +function GM:OnContextMenuOpen() +end + +function GM:OnContextMenuClose() + print("Prop Hunt CL: Toggled View Mode") + LocalPlayer().Data.ThirdPerson = !LocalPlayer().Data.ThirdPerson +end + +-- ------------------------------------------------------------------------- -- +--! Network Messages +-- ------------------------------------------------------------------------- -- +net.Receive("PlayerManagerInitialClientSpawn", function(len, pl) GAMEMODE:InitialPlayerSpawn() end) +net.Receive("PlayerManagerClientSpawn", function(len, pl) GAMEMODE:PlayerSpawn() end) +net.Receive( "PlayerSetHull", function(len, pl) + local hullMin, hullMax = net.ReadVector(), net.ReadVector(); + GAMEMODE:PlayerSetHull(hullMin, hullMax) +end) +net.Receive( "PlayerResetHull", function(len, pl) GAMEMODE:PlayerSetHull(nil, nil) end) +net.Receive( "PlayerViewOffset", function(len, pl) + local vo, voduck = net.ReadVector(), net.ReadVector() + GAMEMODE:PlayerSetViewOffset(vo, voduck) +end) + +-- ------------------------------------------------------------------------- -- +--! Old Code +-- ------------------------------------------------------------------------- -- +--[[ +-- Render halos and player names. +function DrawPlayerNames(bDrawingDepth, bDrawingSkybox) + for i,v in ipairs(player.GetAll()) do + if v:Alive() && v != LocalPlayer() then + local pos = v:GetPos() + v:GetViewOffset() + Vector(0, 0, 5) + local ang = Angle(0, LocalPlayer():EyeAngles().y - 90, 90 - LocalPlayer():EyeAngles().x) + local healthPrc = v:Health() / v:GetMaxHealth() + local healthCol = HSVToColor(120 * healthPrc, 1.0, 1.0) + + if v:Team() == TEAM_HUNTERS || LocalPlayer():Team() == TEAM_PROPS then + cam.Start3D2D(pos, ang, 0.15) + draw.DrawText(v:GetName(), "Trebuchet24", 0, -draw.GetFontHeight("Trebuchet24"), healthCol, TEXT_ALIGN_CENTER) + cam.End3D2D() + end + end + end +end +hook.Add("PostDrawTranslucentRenderables", "PH_DrawPlayerNames", DrawPlayerNames) + +function DrawPlayerHalos(bDrawingDepth, bDrawingSkybox) + for i,v in ipairs(player.GetAll()) do + if v:Alive() then + local pos = v:GetPos() + Vector(0, 0, 1) * (v:OBBMaxs().z - v:OBBMins().z + 5) + local ang = Angle(0, LocalPlayer():EyeAngles().y - 90, 90 - LocalPlayer():EyeAngles().x) + local healthPrc = v:Health() / v:GetMaxHealth() + local healthCol = HSVToColor(120 * healthPrc, 1.0, 1.0) + + if v:Team() == TEAM_HUNTERS || LocalPlayer():Team() == TEAM_PROPS then + local ent = v + if v.ph_prop && v.ph_prop:IsValid() then ent = v.ph_prop end + + halo.Add({ent}, healthCol, 2, 2, 1) + end + end + end +end +--hook.Add("PostDrawEffects", "PH_DrawPlayerHalos", DrawPlayerHalos) +]] \ No newline at end of file diff --git a/Source/gamemodes/prophuntextended/gamemode/client/cl_ui_teamselection.lua b/Source/gamemodes/prophuntextended/gamemode/client/cl_ui_teamselection.lua new file mode 100644 index 0000000..e3956a6 --- /dev/null +++ b/Source/gamemodes/prophuntextended/gamemode/client/cl_ui_teamselection.lua @@ -0,0 +1,75 @@ +--[[ + The MIT License (MIT) + + Copyright (c) 2015 Xaymar + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +--]] + +TeamSelectionUI = {} +TeamSelectionUI.Frame = vgui.Create("DFrame") +TeamSelectionUI.Frame:SetPos(0, 0) +TeamSelectionUI.Frame:SetSize(400, 320) +TeamSelectionUI.Frame:Center() +TeamSelectionUI.Frame:SetTitle("Select a Team") +TeamSelectionUI.Frame:SetVisible(false) +TeamSelectionUI.Frame:SetDraggable(true) +TeamSelectionUI.Frame:SetSizable(false) +TeamSelectionUI.Frame:ShowCloseButton(true) +TeamSelectionUI.Frame:SetDeleteOnClose(false) +function TeamSelectionUI.Frame:Paint(w, h) + draw.RoundedBox(0, 0, 0, w, h, Color(0, 0, 0, 225)) +end + +function TeamSelectionUI:Show() + self.Frame:MakePopup() + TeamSelectionUI.Frame:SetVisible(true) +end + +function TeamSelectionUI:Hide() + TeamSelectionUI.Frame:Close() + TeamSelectionUI.Frame:SetVisible(false) +end + +TeamSelectionUI.SelectSeeker = vgui.Create("DButton", TeamSelectionUI.Frame) +TeamSelectionUI.SelectSeeker:SetPos(0, 20) +TeamSelectionUI.SelectSeeker:SetSize(200, 200) +TeamSelectionUI.SelectSeeker:SetText("Seeker") +TeamSelectionUI.SelectSeeker.DoClick = function() + TeamSelectionUI:Hide() + LocalPlayer():ConCommand("changeteam " .. tostring(GAMEMODE.Teams.Seekers)) +end + +TeamSelectionUI.SelectHider = vgui.Create("DButton", TeamSelectionUI.Frame) +TeamSelectionUI.SelectHider:SetPos(200, 20) +TeamSelectionUI.SelectHider:SetSize(200, 200) +TeamSelectionUI.SelectHider:SetText("Hiders") +TeamSelectionUI.SelectHider.DoClick = function() + TeamSelectionUI:Hide() + LocalPlayer():ConCommand("changeteam " .. tostring(GAMEMODE.Teams.Hiders)) +end + +TeamSelectionUI.Spectate = vgui.Create("DButton", TeamSelectionUI.Frame) +TeamSelectionUI.Spectate:SetPos(0, 220) +TeamSelectionUI.Spectate:SetSize(400, 100) +TeamSelectionUI.Spectate:SetText("Spectate") +TeamSelectionUI.Spectate.DoClick = function() + TeamSelectionUI:Hide() + LocalPlayer():ConCommand("changeteam " .. tostring(GAMEMODE.Teams.Spectators)) +end \ No newline at end of file diff --git a/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/compat/compat_tauntpackloader.lua b/Source/gamemodes/prophuntextended/gamemode/compat/compat_tauntpackloader.lua similarity index 96% rename from Gamemode/gamemodes/xaymars_prop_hunt/gamemode/compat/compat_tauntpackloader.lua rename to Source/gamemodes/prophuntextended/gamemode/compat/compat_tauntpackloader.lua index 1049ace..4af0561 100644 --- a/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/compat/compat_tauntpackloader.lua +++ b/Source/gamemodes/prophuntextended/gamemode/compat/compat_tauntpackloader.lua @@ -1,7 +1,7 @@ --[[ The MIT License (MIT) - Copyright (c) 2015 Project Kube + Copyright (c) 2015 Xaymar Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Source/gamemodes/prophuntextended/gamemode/init.lua b/Source/gamemodes/prophuntextended/gamemode/init.lua new file mode 100644 index 0000000..8b098a5 --- /dev/null +++ b/Source/gamemodes/prophuntextended/gamemode/init.lua @@ -0,0 +1,414 @@ +--[[ + The MIT License (MIT) + + Copyright (c) 2015 Xaymar + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +--]] + +-- ------------------------------------------------------------------------- -- +--! Downloadable Lua +-- ------------------------------------------------------------------------- -- +-- Shared +AddCSLuaFile("sh_init.lua") +AddCSLuaFile("sh_config.lua") +AddCSLuaFile("sh_player.lua") +AddCSLuaFile("player_class/class_default.lua") +AddCSLuaFile("player_class/class_spectator.lua") +AddCSLuaFile("player_class/class_seeker.lua") +AddCSLuaFile("player_class/class_hider.lua") + +-- Client-Only +AddCSLuaFile("cl_init.lua") +AddCSLuaFile("client/cl_ui_teamselection.lua") + +-- ------------------------------------------------------------------------- -- +--! Code +-- ------------------------------------------------------------------------- -- +-- Shared +include "sh_init.lua" + +-- Server Only +include "server/config.lua" +include "compat/compat_tauntpackloader.lua" +include "server/roundmanager.lua" +include "server/states/state_prematch.lua" +include "server/states/state_preround.lua" +include "server/states/state_hide.lua" +include "server/states/state_seek.lua" +include "server/states/state_postround.lua" + +function GM:Initialize() + print("-------------------------------------------------------------------------") + print("Prop Hunt: Initializing...") + + print("Prop Hunt: Registering Networked Messages...") + util.AddNetworkString("PlayerManagerInitialClientSpawn") + util.AddNetworkString("PlayerManagerClientSpawn") + + util.AddNetworkString("PlayerSetHull") + util.AddNetworkString("PlayerResetHull") + util.AddNetworkString("PlayerViewOffset") + util.AddNetworkString("PlayerRegisterPropEntity") + + print("Prop Hunt: Initializing Gamemode Data...") + self.Data = {} + + print("Prop Hunt: Setting initial RoundManager State...") + self.RoundManager:SetState(StatePreMatch) + + print("Prop Hunt: Complete.") + print("-------------------------------------------------------------------------") +end + +function GM:Think() + self.RoundManager:Tick() +end + +-- Player Connected +function GM:PlayerConnect(name, ip) + print("Prop Hunt: Player '"..name.."' connecting from IP '"..ip.."'.") +end + +-- Player Authenticated +function GM:PlayerAuthed(ply, steamid, uniqueid) + print("Prop Hunt: Player '"..ply:GetName().."' (SteamID: "..ply:SteamID()..") authenticated.") +end + +-- Player Disconnected +function GM:PlayerDisconnected(ply) + print("Prop Hunt: Player '"..ply:GetName().."' (SteamID: "..ply:SteamID()..") disconnected.") +end + +-- Player Spawn (Initial) +function GM:PlayerInitialSpawn(ply) + print("Prop Hunt: Player '"..ply:GetName().."' (SteamID: "..ply:SteamID()..") spawned for the first time, applying defaults...") + + if (!ply.Data) then + -- Initialize Data Structure + ply.Data = {} + ply.Data.Alive = false + ply.Data.AliveTime = 0 + end + + -- Kill Silently + ply:KillSilent() + + -- Show Team Selection Menu + ply:SetTeam(GAMEMODE.Teams.Spectators) + self:ShowTeam(ply) + + -- Bot: Auto Assign to Team + if (ply:IsBot()) then + if team.NumPlayers(self.Teams.Hiders) > team.NumPlayers(self.Teams.Seekers) then + print("Prop Hunt: Bot '"..ply:GetName().."' assigned to Seekers.") + ply:SetTeam(self.Teams.Seekers) + else + print("Prop Hunt: Bot '"..ply:GetName().."' assigned to Hiders.") + ply:SetTeam(self.Teams.Hiders) + end + end + + -- Notify Player Manager + player_manager.RunClass(ply, "InitialSpawn") + + -- Signal Client + net.Start("PlayerManagerInitialClientSpawn");net.Send(ply) +end + +-- Player Spawn +function GM:PlayerSpawn(ply) + print("Prop Hunt: Player '"..ply:GetName().."' (SteamID: "..ply:SteamID()..") spawned in.") + + -- Player Manager: Assign Player Class + local class = team.GetClass(ply:Team()) + if (class) then + if (ply.Data.Alive) then -- Alive Class + player_manager.SetPlayerClass(ply, class[1]) + else -- Dead Class (Spectator) + player_manager.SetPlayerClass(ply, class[2]) + end + else + player_manager.SetPlayerClass(ply, "Spectator") + end + + -- Notify Player Manager + player_manager.OnPlayerSpawn(ply) + player_manager.RunClass(ply, "Spawn") + + -- Some hooks are not called + hook.Call("PlayerSetModel", self, ply) + hook.Call("PlayerLoadout", self, ply) + + -- Signal Client + net.Start("PlayerManagerClientSpawn");net.Send(ply) +end + +-- Player requests Team Change +function GM:PlayerRequestTeam(ply, teamId) + if self:PlayerCanJoinTeam(ply, teamId) then + print("Prop Hunt: Player '"..ply:GetName().."' (SteamID: "..ply:SteamID()..") requested to join Team "..team.GetName(teamId)..".") + + if (ply:Team() != teamId) then + ply:KillSilent() + ply:SetTeam(teamId) + + if (GetGlobalInt("RoundState", GAMEMODE.States.PreMatch) <= GAMEMODE.States.PreRound) then + ply.Alive = true + ply.AliveTime = CurTime() + end + else + print("Prop Hunt: Player '"..ply:GetName().."' (SteamID: "..ply:SteamID()..") attempted to rejoin the Team it is already in.") + end + end +end + +-- ------------------------------------------------------------------------- -- +--! Player Manager Binding +-- ------------------------------------------------------------------------- -- +function GM:PlayerLoadout(ply) player_manager.RunClass(ply, "Loadout") end +function GM:PlayerDeath(ply, inflictor, attacker) player_manager.RunClass(ply, "Death", inflictor, attacker) end +function GM:PlayerSilentDeath(ply) player_manager.RunClass(ply, "SilentDeath") end +function GM:PostPlayerDeath(ply) + player_manager.RunClass(ply, "PostDeath") + + -- Debug Mode: Respawn after Death + if (GAMEMODE.Config:Debug()) then + ply.Data.Alive = true + print("Prop Hunt: Debug Mode active, Player "..ply:GetName().." was respawned.") + end +end +--function GM:DoPlayerDeath(ply, attacker, dmg) player_manager.RunClass(ply, "DoDeath", attacker, dmg) end +function GM:PlayerDeathThink(ply) return player_manager.RunClass(ply, "DeathThink") end +function GM:CanPlayerSuicide(ply) return player_manager.RunClass(ply, "CanSuicide") end +function GM:PlayerCanPickupWeapon(ply, weapon) return player_manager.RunClass(ply, "CanPickupWeapon", weapon) end +function GM:PlayerCanPickupItem(ply, item) return player_manager.RunClass(ply, "CanPickupItem", item) end +function GM:PlayerUse(ply, ent) return player_manager.RunClass(ply, "Use", ent) end +function GM:AllowPlayerPickup(ply, ent) return player_manager.RunClass(ply, "AllowPickup", ent) end +function GM:PlayerSetModel(ply) return player_manager.RunClass(ply, "SetModel") end + +-- Called when an entity takes damage +function GM:EntityTakeDamage(ent, dmg) + local att = dmg:GetAttacker() + + if (att) && (att:IsValid()) && (att:IsPlayer()) then + player_manager.RunClass(att, "DamageEntity", ent, att, dmg) + end +end + +-- ------------------------------------------------------------------------- -- +--! Gamemode Functionality +-- ------------------------------------------------------------------------- -- +function GM:SetRoundState(State) + SetGlobalInt("RoundState", State) +end + +function GM:PlayerHullFromEntity(ply, ent) + if (ent) && (ent:IsValid()) then + local hmin, hmax = ent:OBBMins(), ent:OBBMaxs() + local hull = Vector(hmax.x - hmin.x, hmax.y - hmin.y, hmax.z - hmin.z) + if hull.x <= hull.y then + hull.y = hull.x + else + hull.x = hull.y + end + hull:Mul(0.5) + + local hullmin = Vector(-hull.x, -hull.y, 0) + local hullmax = Vector(hull.x, hull.y, hull.z * 2) + + ply:SetHull(hullmin, hullmax) + ply:SetHullDuck(hullmin, hullmax) + net.Start("PlayerSetHull") + net.WriteVector(hullmin) + net.WriteVector(hullmax) + net.Send(ply) + return {hullmin, hullmax} + else + ply:ResetHull() + net.Start("PlayerResetHull") + net.Send(ply) + return nil + end +end + +function GM:PlayerSetViewOffset(ply, vo, voduck) + ply:SetViewOffset(vo) + ply:SetViewOffsetDucked(voduck) + if ply:Crouching() then + ply:SetCurrentViewOffset(voduck) + else + ply:SetCurrentViewOffset(vo) + end + + -- Signal Client + net.Start("PlayerViewOffset") + net.WriteVector(vo) + net.WriteVector(voduck) + net.Send(ply) +end + +-- ------------------------------------------------------------------------- -- +--! Commands +-- ------------------------------------------------------------------------- -- +-- F1/ShowHelp +function GM:ShowHelp(ply) end + +-- F2/ShowTeam - Select Team +function GM:ShowTeam(ply) + ply:ConCommand("ph_select_team") +end + +-- F3/ShowSpare1 +function GM:ShowSpare1(ply) end + +-- F4/ShowSpare2 +function GM:ShowSpare2(ply) end + +-- Debug Command: Print All Players +concommand.Add("ph_debug_printplayers", function(ply, cmd, args, argStr) + print ("All Players:") + for i,ply in ipairs(player.GetAll()) do + print(" "..ply:GetName().." (SteamID: "..ply:SteamID()..") - Team "..team.GetName(ply:Team()).. " - Alive "..tostring(ply.Data.Alive)) + end + + print ("Spectators:") + for i,ply in ipairs(team.GetPlayers(GAMEMODE.Teams.Spectators)) do + print(" "..ply:GetName().." (SteamID: "..ply:SteamID()..")") + end + + print ("Seekers:") + for i,ply in ipairs(team.GetPlayers(GAMEMODE.Teams.Seekers)) do + print(" "..ply:GetName().." (SteamID: "..ply:SteamID()..")") + end + + print ("Hiders:") + for i,ply in ipairs(team.GetPlayers(GAMEMODE.Teams.Hiders)) do + print(" "..ply:GetName().." (SteamID: "..ply:SteamID()..")") + end + +end, nil, nil, FCVAR_CLIENTCMD_CAN_EXECUTE + FCVAR_CHEAT) + +-- ------------------------------------------------------------------------- -- +--! LEGACY CODE - TO BE REPLACED SOON +-- ------------------------------------------------------------------------- -- +--[[ +function AnnounceVictory(players, force) + for i,pl in ipairs(players) do + if pl:Alive() || force || pl:Team() == TEAM_SPECTATOR then + announcer = table.Random(VICTORY_SOUNDS); + print("Prop Hunt: '"..pl:GetName().."' announcing victory with '"..announcer.."'.") + pl:EmitSound(announcer, 200, 100, 0.5, CHAN_VOICE2) + end + end +end + +function AnnounceLoss(players, force) + for i,pl in ipairs(players) do + if pl:Alive() || force || pl:Team() == TEAM_SPECTATOR then + announcer = table.Random(LOSS_SOUNDS); + print("Prop Hunt: '"..pl:GetName().."' announcing loss with '"..announcer.."'.") + pl:EmitSound(announcer, 100, 100, 0.5, CHAN_VOICE2) + end + end +end + +-- If there is a mapfile send it to the client (sometimes servers want to change settings for certain maps) +if file.Exists("maps/"..game.GetMap()..".lua", "LUA") then + AddCSLuaFile("maps/"..game.GetMap()..".lua") +end + +-- Send the required resources to the client +for _, announcer in pairs(LOSS_SOUNDS) do resource.AddFile("sound/"..announcer) end +for _, announcer in pairs(VICTORY_SOUNDS) do resource.AddFile("source/"..announcer) end +for _, taunt in pairs(HUNTER_TAUNTS) do resource.AddFile("sound/"..taunt) end +for _, taunt in pairs(PROP_TAUNTS) do resource.AddFile("sound/"..taunt) end + +-- Called alot +function GM:CheckPlayerDeathRoundEnd() + if !GAMEMODE.RoundBased || !GAMEMODE:InRound() then + return + end + + local Teams = GAMEMODE:GetTeamAliveCounts() + + if table.Count(Teams) == 0 then + GAMEMODE:RoundEndWithResult(1001, "Draw, everyone loses!") + AnnounceLoss(player.GetAll(), true) + return + end + + if table.Count(Teams) == 1 then + -- Play victory and loss sounds. + if Teams[0] == TEAM_HUNTERS then + AnnounceVictory(team.GetPlayers(TEAM_HUNTERS)) + AnnounceLoss(team.GetPlayers(TEAM_PROPS)) + elseif Teams[0] == TEAM_PROPS then + AnnounceLoss(team.GetPlayers(TEAM_HUNTERS)) + AnnounceVictory(team.GetPlayers(TEAM_PROPS)) + end + + local TeamID = table.GetFirstKey(Teams) + GAMEMODE:RoundEndWithResult(TeamID, team.GetName(TeamID).." win!") + return + end +end + +-- Called when player presses [F3]. Plays a taunt for their team +function GM:ShowSpare1(pl) + if GAMEMODE:InRound() && pl:Alive() && (pl:Team() == TEAM_HUNTERS || pl:Team() == TEAM_PROPS) && pl.last_taunt_time + TAUNT_DELAY <= CurTime() && #PROP_TAUNTS > 1 && #HUNTER_TAUNTS > 1 then +-- repeat + if pl:Team() == TEAM_HUNTERS then + rand_taunt = table.Random(HUNTER_TAUNTS) + else + rand_taunt = table.Random(PROP_TAUNTS) + end +-- until rand_taunt != pl.last_taunt + + pl.last_taunt_time = CurTime() + pl.last_taunt = rand_taunt + + print("Prop Hunt: '"..pl:GetName().."' taunting with '"..rand_taunt.."'.") + local vol = 1.0 + if pl:Team() == TEAM_HUNTERS then vol = vol * 0.5 end + pl:EmitSound(rand_taunt, 100, 100, vol, CHAN_VOICE2) + end +end + +-- Allow player to rotate the prop. (Either F4 or ducking) +function GM:ShowSpare2(pl) + if pl:Alive() && (pl:Team() == TEAM_PROPS) then + pl.ph_prop:SetApplyNewAngles(!pl.ph_prop:GetApplyNewAngles()) +-- pl.ph_prop:SetNewAngles(pl:GetAngles()) + end +end + +-- Removes all weapons on a map +function RemoveWeaponsAndItems() + for _, wep in pairs(ents.FindByClass("weapon_*")) do + wep:Remove() + end + + for _, item in pairs(ents.FindByClass("item_*")) do + item:Remove() + end +end +hook.Add("InitPostEntity", "PH_RemoveWeaponsAndItems", RemoveWeaponsAndItems) + +]] \ No newline at end of file diff --git a/Source/gamemodes/prophuntextended/gamemode/player_class/class_default.lua b/Source/gamemodes/prophuntextended/gamemode/player_class/class_default.lua new file mode 100644 index 0000000..99ee5ae --- /dev/null +++ b/Source/gamemodes/prophuntextended/gamemode/player_class/class_default.lua @@ -0,0 +1,137 @@ +--[[ + The MIT License (MIT) + + Copyright (c) 2015 Xaymar + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +--]] + +DEFINE_BASECLASS("player_default") +local CLASS = {} +CLASS.DisplayName = "Default" +CLASS.WalkSpeed = 250 -- How fast to move when not running +CLASS.RunSpeed = 500 -- How fast to move when running +CLASS.CrouchedWalkSpeed = 0.5 -- Multiply move speed by this when crouching +CLASS.DuckSpeed = 0.2 -- How fast to go from not ducking, to ducking +CLASS.UnDuckSpeed = 0.2 -- How fast to go from ducking, to not ducking +CLASS.JumpPower = 200 -- How powerful our jump should be +CLASS.CanUseFlashlight = false -- Can we use the flashlight +CLASS.MaxHealth = 100 -- Max health we can have +CLASS.StartHealth = 100 -- How much health we start with +CLASS.StartArmor = 0 -- How much armour we start with +CLASS.DropWeaponOnDie = false -- Do we drop our weapon when we die +CLASS.TeammateNoCollide = true -- Do we collide with teammates or run straight through them +CLASS.AvoidPlayers = true -- Automatically swerves around other players +CLASS.UseVMHands = true -- Uses viewmodel hands + +-- ------------------------------------------------------------------------- -- +--! Server-Side +-- ------------------------------------------------------------------------- -- +-- Spawn +function CLASS:InitialSpawn() end +function CLASS:Spawn() end +function CLASS:Loadout() end + +-- Damage +function CLASS:Hurt(victim, attacker, healthRemaining, damageTaken) end -- Damage Taken +function CLASS:Damage(victim, attacker, healthRemaining, damageDealt) end -- Damage Dealt +function CLASS:DamageEntity(ent, attacker, dmginfo) end -- Damage Dealt To Entity + +-- Death +function CLASS:Death(inflictor, attacker) + self.Player.Data.Alive = false + self.Player.Data.AliveTime = CurTime() +end +function CLASS:SilentDeath() + self.Player.Data.Alive = false + self.Player.Data.AliveTime = CurTime() +end +function CLASS:PostDeath() end + +function CLASS:DoDeath() end + +function CLASS:DeathThink() + if (CurTime() - self.Player.Data.AliveTime) > 2 then + self.Player:Spawn() + return true + end + return false +end + +function CLASS:CanSuicide() return true end + +-- Visible Stuff +function CLASS:SetModel() BaseClass.SetModel( self ) end + +-- Interaction +function CLASS:Use(ent) + -- Entity must be valid and not a player. + if (!ent) || (!ent:IsValid()) || (ent:IsPlayer()) then + return false + end + + -- Cool Down + if (self.Player.Data.UseTime) then + local timeSinceUse = (CurTime() - self.Player.Data.UseTime) + if (0.2 > timeSinceUse) then + return false + end + + -- Abuse Blacklist (Buttons, Doors, etc) + if (5 > timeSinceUse) then + local abuseBlacklist = GAMEMODE.Config.Lists:AbuseBlacklist() + if (table.HasValue(abuseBlacklist, ent:GetClass())) then + return false + end + end + end + self.Player.Data.UseTime = CurTime() + + return true +end +function CLASS:AllowPickup(ent) return false end +function CLASS:CanPickupWeapon(ent) return false end +function CLASS:CanPickupItem(ent) return false end + +-- ------------------------------------------------------------------------- -- +--! Shared +-- ------------------------------------------------------------------------- -- +function CLASS:PostThink() end +function CLASS:Tick(mv) end + +-- ------------------------------------------------------------------------- -- +--! Client-Side +-- ------------------------------------------------------------------------- -- +-- Spawn +function CLASS:InitialClientSpawn() + self.Player.Data = {} + self.Player.Data.ThirdPerson = false -- Default to FirstPerson View +end +function CLASS:ClientSpawn() end + +-- View & HUD +function CLASS:GetHandsModel() return BaseClass.GetHandsModel(self) end +function CLASS:ShouldDrawLocal() return false end +function CLASS:HUDPaint() end +function CLASS:CalcView(camdata) return camdata end + +-- ------------------------------------------------------------------------- -- +--! Register +-- ------------------------------------------------------------------------- -- +player_manager.RegisterClass( "Default", CLASS, "player_default") \ No newline at end of file diff --git a/Source/gamemodes/prophuntextended/gamemode/player_class/class_hider.lua b/Source/gamemodes/prophuntextended/gamemode/player_class/class_hider.lua new file mode 100644 index 0000000..4b0fbc6 --- /dev/null +++ b/Source/gamemodes/prophuntextended/gamemode/player_class/class_hider.lua @@ -0,0 +1,234 @@ +--[[ + The MIT License (MIT) + + Copyright (c) 2015 Xaymar + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +--]] + +DEFINE_BASECLASS( "Default" ) +local CLASS = {} +CLASS.DisplayName = "Hider" +CLASS.DuckSpeed = 0.0 -- How fast to go from not ducking, to ducking +CLASS.UnDuckSpeed = 0.0 -- How fast to go from ducking, to not ducking +CLASS.CanUseFlashlight = false -- Can we use the flashlight +CLASS.UseVMHands = false -- Uses viewmodel hands + +-- ------------------------------------------------------------------------- -- +--! Server-Side +-- ------------------------------------------------------------------------- -- +-- Spawn +function CLASS:Spawn() + print("Prop Hunt: Hider '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") spawned.") + BaseClass.Spawn(self, self.Player) + + -- Sprinting + if (!GAMEMODE.Config:Sprinting()) then + self.Player:SetRunSpeed(self.WalkSpeed) + end + + -- Settings + self.Player:SetMaxHealth(GAMEMODE.Config.Hider:HealthMax()) + self.Player:SetHealth(GAMEMODE.Config.Hider:Health()) + self.Player:SetRenderMode(RENDERMODE_TRANSALPHA) + self.Player:SetColor(Color(0,0,0,0)) + + -- Hull & View Offset + GAMEMODE:PlayerHullFromEntity(self.Player, nil) + GAMEMODE:PlayerSetViewOffset(self.Player, Vector(0,0,72), Vector(0,0,72)) + + -- Collision Group + self.Player:SetCollisionGroup(COLLISION_GROUP_PLAYER) + + -- Prop Stuff + self.Player.Data.Prop = ents.Create("ph_prop") + self.Player.Data.Prop:SetOwner(self.Player) + self.Player.Data.Prop:Spawn() + self.Player:DeleteOnRemove(self.Player.Data.Prop) + + -- Assign Hands (Auto Networked Sync!) + local oldhands = self.Player:GetHands() + if (IsValid(oldhands)) then oldhands:Remove() end + self.Player:SetHands(self.Player.Data.Prop) +end + +-- Death +function CLASS:PostDeath(attacker, dmginfo) + print("Prop Hunt: Hider '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") died.") + BaseClass.PostDeath(self, inflictor, attacker) + + -- Delete Hands Model + self.Player:GetHands():Remove() + + -- Collision Group + self.Player:SetCollisionGroup(COLLISION_GROUP_PLAYER) + + -- Hull + GAMEMODE:PlayerHullFromEntity(self.Player, nil) + + -- Rendering + self.Player:SetRenderMode(RENDERMODE_NORMAL) + self.Player:SetColor(Color(255,255,255,255)) +end + +function CLASS:CanSuicide() + return true +end + +function CLASS:DeathThink() + if 1 > (CurTime() - self.Player.Data.AliveTime) then + return false + end + + self.Player:Spawn() + return true +end + +-- Visible Stuff +function CLASS:SetModel() self.Player:SetModel("models/Gibs/Antlion_gib_small_3.mdl") end -- does "" even work? + +-- Interaction +function CLASS:Use(ent) + if (!(BaseClass.Use(self, ent))) then + return false + end + + -- Allow interacting while crouched instead of turning into the prop. + if (self.Player:Crouching()) then + return true + end + + -- Check Lists and other Parameters + if (!table.HasValue(GAMEMODE.Config.Lists:ClassWhitelist(), ent:GetClass()))-- Class is not Whitelisted + || (GAMEMODE.Config.Lists.ModelBlacklist[ent:GetModel()]) -- Model is Blacklisted + || !((ent:GetPhysicsObject()) && (ent:GetPhysicsObject():IsValid())) -- Entity doesn't have Physics + then + print("Prop Hunt: Hider '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") attempted to turn into "..ent:GetClass().." ("..ent:GetModel()..").") + return true -- Use instead of erroring. + end + + -- Turn into the prop + local eProp = self.Player:GetHands() + util.PrecacheModel(ent:GetModel()) + eProp:SetModel(ent:GetModel()) + eProp:SetSkin(ent:GetSkin()) + eProp:SetHealth(100) + eProp:SetMaxHealth(100) + eProp:SetRenderMode(RENDERMODE_TRANSALPHA) + + -- Hull (Optimize into single function? Code is repeated often) + local hull = GAMEMODE:PlayerHullFromEntity(self.Player, ent) + + -- View Offset + local vo = Vector(0, 0, hull[2].z) + GAMEMODE:PlayerSetViewOffset(self.Player, vo, vo) + + -- Health Scaling + if (GAMEMODE.Config.Hider:HealthScaling()) then + local prc = math.Clamp(self.Player:Health() / self.Player:GetMaxHealth(), 0, 1) + local maxhealth = math.Clamp(ent:GetPhysicsObject():GetVolume() / 250, 1, GAMEMODE.Config.Hider:HealthScalingMax()) + local health = math.Clamp(maxhealth * prc, 1, maxhealth) + + -- Set Health + self.Player:SetHealth(health) + self.Player:SetMaxHealth(maxhealth) + end + + print("Prop Hunt: Hider '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") turned into "..ent:GetClass().." ("..ent:GetModel()..").") +end + +function CLASS:AllowPickup(ent) return true end + +-- ------------------------------------------------------------------------- -- +--! Shared +-- ------------------------------------------------------------------------- -- + +-- ------------------------------------------------------------------------- -- +--! Client-Side +-- ------------------------------------------------------------------------- -- +function CLASS:ClientSpawn() + print("Prop Hunt CL: Hider '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") spawned.") + BaseClass.ClientSpawn(self, self.Player) + + self.Player:SetRenderMode(RENDERMODE_TRANSALPHA) +end + +function CLASS:ShouldDrawLocal() + return false +end + +function CLASS:CalcView(camdata) + -- ThirdPerson Settings (ToDo: client config maybe?) + local maxViewDist = 100 + local viewDist = self.Player.Data.ViewDistance or 0 + + -- First/Third + if (self.Player.Data.ThirdPerson) then + if (IsValid(self.Player:GetHands())) then + self.Player:GetHands():SetRenderMode(RENDERMODE_TRANSALPHA) + self.Player:GetHands():SetColor(Color(255, 255, 255, 127)) + end + + -- Incremental Distance instead of instant. + viewDist = math.Clamp(viewDist * 0.9 + maxViewDist * 0.1, 0, maxViewDist) -- Zoom Out + else + if (IsValid(self.Player:GetHands())) then + self.Player:GetHands():SetRenderMode(RENDERMODE_TRANSALPHA) + self.Player:GetHands():SetColor(Color(255, 255, 255, 0)) + end + + viewDist = math.Clamp(viewDist * 0.9, 0, maxViewDist) -- Zoom In + end + + -- Trace from Player to would-be camera position + local trace = { + start = camdata.origin, + endpos = camdata.origin - (camdata.angles:Forward() * viewDist), + --filter = { "worldspawn", "ph_prop" }, + filter = function(ent) + local filter = { "worldspawn", "ph_prop" } + + if (ent:IsPlayer()) + || (table.HasValue(filter, ent:GetClass())) + || (ent == LocalPlayer()) || (ent == LocalPlayer():GetHands()) then + return false + end + return true + end + } + local result = util.TraceLine(trace) + + -- The Camera has a Sphere radius of 10. + if (result.Hit) then -- Configurable? + viewDist = math.Clamp(result.HitPos:Distance(camdata.origin), 0, maxViewDist) + end + + -- Store ViewDistance + self.Player.Data.ViewDistance = viewDist + + -- Adjust CamData + camdata.origin = camdata.origin - (camdata.angles:Forward() * math.Clamp(viewDist - 10, 0, maxViewDist)) + camdata.drawviewer = false + + -- Return + return camdata +end + +-- Register +player_manager.RegisterClass("Hider", CLASS, "Default") diff --git a/Source/gamemodes/prophuntextended/gamemode/player_class/class_seeker.lua b/Source/gamemodes/prophuntextended/gamemode/player_class/class_seeker.lua new file mode 100644 index 0000000..faae551 --- /dev/null +++ b/Source/gamemodes/prophuntextended/gamemode/player_class/class_seeker.lua @@ -0,0 +1,235 @@ +--[[ + The MIT License (MIT) + + Copyright (c) 2015 Xaymar + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +--]] + +--! This file defines the Seeker player class. +-- A seeker is someone who is looking for the hiders, using weapons or other +-- means of detecting idiots. Also someone who looks like a diaper baby. +-- Weapons and Ammo are granted upon spawn and have to be used sparingly or +-- they'll be stuck with the crowbar. Bad seeker, bad. +-- Gain health upon killing a hider, lose health when attacking non-hiders. +-- Death upon health reaching 0. + +DEFINE_BASECLASS( "Default" ) +local CLASS = {} +CLASS.DisplayName = "Seeker" +CLASS.CanUseFlashlight = true -- Can we use the flashlight +CLASS.MaxHealth = 100 +CLASS.StartHealth = 100 +CLASS.StartArmor = 0 +CLASS.DropWeaponOnDie = true + +-- ------------------------------------------------------------------------- -- +--! Server-Side +-- ------------------------------------------------------------------------- -- +-- Spawn +function CLASS:Spawn() + print("Prop Hunt: Seeker '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") spawned.") + BaseClass.Spawn(self) + + -- Sprinting + if (GAMEMODE.Config:Sprinting()) then + self.Player:SetRunSpeed(self.WalkSpeed) + end + + -- Settings + self.Player:SetMaxHealth(GAMEMODE.Config.Seeker:HealthMax()) + self.Player:SetHealth(GAMEMODE.Config.Seeker:Health()) + self.Player:SetRenderMode(RENDERMODE_NORMAL) + self.Player:SetColor(Color(255,255,255,255)) + + -- Hull & View Offset + GAMEMODE:PlayerHullFromEntity(self.Player, nil) + GAMEMODE:PlayerSetViewOffset(self.Player, Vector(0,0,64), Vector(0,0,32)) +end + +function CLASS:Loadout() + -- Give the weapons the admin told us to. + local weapons = GAMEMODE.Config.Seeker:Weapons() + for i,weapon in ipairs(weapons) do + self.Player:Give(weapon) + end + + -- Give the ammo the admin told us to. + local ammos = GAMEMODE.Config.Seeker:Ammo() + for i,ammo in ipairs(ammos) do + local typeCount = string.Split(ammo, ":") + self.Player:GiveAmmo(tonumber(typeCount[2]), typeCount[1], true) + end + + -- Default weapon stuff + local cl_defaultweapon = self.Player:GetInfo("cl_defaultweapon") + if self.Player:HasWeapon(cl_defaultweapon) then + self.Player:SelectWeapon(cl_defaultweapon) + end +end + +-- Damage +function CLASS:Damage(victim, attacker, healthRemaining, damageDealt) end +function CLASS:DamageEntity(ent, att, dmg) + print("Prop Hunt: Seeker '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") damaged entity "..ent:GetClass()..".") + + -- Only take damage during this phase. + if (GAMEMODE:GetRoundState() == GAMEMODE.States.Seek) then + if IsValid(ent) && (!(ent:IsPlayer())) then + if (ent:GetClass() == "ph_prop") then + ent:GetOwner():TakeDamageInfo(dmg) + elseif (ent:GetClass() == "func_breakable") then -- ToDo: Make Configurable which entities don't hurt + else + att:TakeDamage(GAMEMODE.Config.Seeker:HealthPenalty(), ent, ent) + end + end + end +end + +-- Death +function CLASS:Death(inflictor, attacker) + BaseClass.Death(self, inflictor, attacker) + + self.Player:CreateRagdoll() +end + +function CLASS:PostDeath() + print("Prop Hunt: Seeker '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") died.") + BaseClass.PostDeath(self, inflictor, attacker) + + self.Player:UnLock() +end + +function CLASS:CanSuicide() + return true +end + +function CLASS:DeathThink() + if (CurTime() - self.Player.Data.AliveTime) > 1 then + self.Player:Spawn() + return true + end + + return false +end + +-- Visible Stuff +function CLASS:SetModel() + local cl_playermodel = self.Player:GetInfo( "cl_playermodel" ) + local modelname = player_manager.TranslatePlayerModel( cl_playermodel ) + if !(util.IsValidModel(modelname)) then + modelname = "models/player/combine_super_soldier.mdl" + end + util.PrecacheModel(modelname) + self.Player:SetModel(modelname) + + -- Hands + self.Player:SetupHands() +end + +-- Interaction +function CLASS:AllowPickup(ent) return true end +function CLASS:CanPickupItem(ent) return true end +function CLASS:CanPickupWeapon(ent) return true end + +-- ------------------------------------------------------------------------- -- +--! Client-Side +-- ------------------------------------------------------------------------- -- +function CLASS:ClientSpawn() + print("Prop Hunt CL: Seeker '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") spawned.") + BaseClass.ClientSpawn(self) +end + +function CLASS:HUDPaint() + local State = GetGlobalInt("RoundState", GAMEMODE.States.PreMatch) + if (State == GAMEMODE.States.Hide) then + local intTime = math.ceil(GetGlobalInt("RoundTime")) + local strTime = tostring(intTime) + + -- Seekers are blinded in this Phase. + draw.RoundedBox(0, 0, 0, surface.ScreenWidth(), surface.ScreenHeight(), Color(0, 0, 0, 255)) + + -- Show Status at the center + surface.SetTextColor( 255, 255, 255, 255 ) + if (intTime >= 1) then + surface.SetFont("CloseCaption_Bold") + local w,h = surface.GetTextSize("Unblinded in "..strTime.." seconds...") + surface.SetTextPos( ScrW()/2 - w / 2, ScrH()/2 - h / 2) + surface.DrawText("Unblinded in "..strTime.." seconds...") + else + surface.SetFont("PHHugeAssFont") + local w,h = surface.GetTextSize("NOW") + surface.SetTextPos( ScrW()/2 - w / 2, ScrH()/2 - h / 2) + surface.DrawText("NOW") + end + end +end + +function CLASS:ShouldDrawLocal() + return self.Player.Data.ThirdPerson +end + +function CLASS:CalcView(camdata) + -- ThirdPerson Settings (ToDo: client config maybe?) + local maxViewDist = 100 + local viewDist = self.Player.Data.ViewDistance or 0 + + -- First/Third + if (self.Player.Data.ThirdPerson) then + viewDist = math.Clamp(viewDist * 0.9 + maxViewDist * 0.1, 0, maxViewDist) -- Zoom Out + else + viewDist = math.Clamp(viewDist * 0.9, 0, maxViewDist) -- Zoom In + end + + -- Trace from Player to would-be camera position + local trace = { + start = camdata.origin, + endpos = camdata.origin - (camdata.angles:Forward() * viewDist), + --filter = { "worldspawn", "ph_prop" }, + filter = function(ent) + local filter = { "worldspawn", "ph_prop" } + + if (ent:IsPlayer()) + || (table.HasValue(filter, ent:GetClass())) + || (ent == LocalPlayer()) || (ent == LocalPlayer():GetHands()) then + return false + end + return true + end + } + local result = util.TraceLine(trace) + + -- The Camera has a Sphere radius of 10. + if (result.Hit) then -- Configurable? + viewDist = math.Clamp(result.HitPos:Distance(camdata.origin), 0, maxViewDist) + end + + -- Store ViewDistance + self.Player.Data.ViewDistance = viewDist + + -- Adjust CamData + camdata.origin = camdata.origin - (camdata.angles:Forward() * math.Clamp(viewDist - 10, 0, maxViewDist)) + --camdata.drawviewer = false + + -- Return + return camdata +end + +-- Register +player_manager.RegisterClass("Seeker", CLASS, "Default") diff --git a/Source/gamemodes/prophuntextended/gamemode/player_class/class_spectator.lua b/Source/gamemodes/prophuntextended/gamemode/player_class/class_spectator.lua new file mode 100644 index 0000000..d7dd2a2 --- /dev/null +++ b/Source/gamemodes/prophuntextended/gamemode/player_class/class_spectator.lua @@ -0,0 +1,85 @@ +--[[ + The MIT License (MIT) + + Copyright (c) 2015 Xaymar + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +--]] + +DEFINE_BASECLASS("Default") +local CLASS = {} +CLASS.DisplayName = "Spectator" +CLASS.DuckSpeed = 0.0 -- How fast to go from not ducking, to ducking +CLASS.UnDuckSpeed = 0.0 -- How fast to go from ducking, to not ducking +CLASS.CanUseFlashlight = false -- Can we use the flashlight +CLASS.UseVMHands = false -- Uses viewmodel hands + +-- ------------------------------------------------------------------------- -- +--! Server-Side +-- ------------------------------------------------------------------------- -- +-- Spawn +function CLASS:Spawn() + print("Prop Hunt: Spectator '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") spawned.") + BaseClass.Spawn(self) + + self.Player:Spectate(OBS_MODE_ROAMING) + self.Player:SetRenderMode(RENDERMODE_NONE) + + -- View Offset & Hull + GAMEMODE:PlayerSetViewOffset(self.Player, Vector(0,0,0), Vector(0,0,0)) + GAMEMODE:PlayerHullFromEntity(self.Player, nil) +end + +-- Death +function CLASS:PostDeath(inflictor, attacker) + print("Prop Hunt: Spectator '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") died.") + BaseClass.PostDeath(self, inflictor, attacker) + + self.Player:Spectate(OBS_MODE_NONE) + self.Player:UnSpectate() + + -- Hull + GAMEMODE:PlayerHullFromEntity(self.Player, nil) + + self.Player:SetRenderMode(RENDERMODE_NORMAL) +end + +-- Visible Stuff +function CLASS:SetModel() + self.Player:SetModel("") + + -- Hands + self.Player:SetupHands() +end + +-- Interaction +function CLASS:Use(ent) return false end +function CLASS:AllowPickup(ent) return false end +function CLASS:CanPickupWeapon(ent) return false end +function CLASS:CanPickupItem(ent) return false end +-- ------------------------------------------------------------------------- -- +--! Client-Side +-- ------------------------------------------------------------------------- -- +function CLASS:ClientSpawn() + print("Prop Hunt CL: Spectator '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") spawned.") +end + +function CLASS:ShouldDrawLocal() return false end + +player_manager.RegisterClass( "Spectator", CLASS, "Default") \ No newline at end of file diff --git a/Source/gamemodes/prophuntextended/gamemode/server/config.lua b/Source/gamemodes/prophuntextended/gamemode/server/config.lua new file mode 100644 index 0000000..4295053 --- /dev/null +++ b/Source/gamemodes/prophuntextended/gamemode/server/config.lua @@ -0,0 +1,549 @@ +--[[ + The MIT License (MIT) + + Copyright (c) 2015 Xaymar + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +--]] + +--! Initialize configuration table. +GM.Config = { } +GM.Config.ConVars = {} + +-- ------------------------------------------------------------------------- -- +--! Basic Settings +-- ------------------------------------------------------------------------- -- +-- Debug Mode +GM.Config.ConVars.Debug = CreateConVar("ph_debug", 0, FCVAR_CHEAT + FCVAR_REPLICATED) +function GM.Config:Debug() + return self.ConVars.Debug:GetBool() +end + +-- Game Mode (See sh_init.lua) +GM.Config.ConVars.GameMode = CreateConVar("ph_gamemode", GM.Modes.Original, FCVAR_REPLICATED) +function GM.Config:GameMode() + return self.ConVars.GameMode:GetInt() +end + +-- Timelimit in minutes +GM.Config.ConVars.TimeLimit = GetConVar("mp_timelimit") +function GM.Config:TimeLimit() + return self.ConVars.TimeLimit:GetFloat() +end + +-- Enable Sprinting? +GM.Config.ConVars.Sprinting = CreateConVar("ph_sprinting", 0, FCVAR_REPLICATED) +function GM.Config:Sprinting() + return self.ConVars.Sprinting:GetBool() +end + +-- Taunt Cooldown (Seconds) +GM.Config.ConVars.TauntCoolDown = CreateConVar("ph_tauntcooldown", 5, FCVAR_REPLICATED) +function GM.Config:TauntCoolDown() + return self.ConVars.TauntCoolDown:GetFloat() +end + +-- ------------------------------------------------------------------------- -- +--! Round Settings +-- ------------------------------------------------------------------------- -- +GM.Config.Round = {} +GM.Config.Round.ConVars = {} + +-- How many rounds should the gamemode attempt to fit into the map timelimit, if there is any? +GM.Config.Round.ConVars.Amount = CreateConVar("ph_round_limit", 10, FCVAR_REPLICATED) +function GM.Config.Round:Amount() + return self.ConVars.Amount:GetInt() +end + +-- Round Time Limit (Seconds, Default 3 minutes) +GM.Config.Round.ConVars.Time = CreateConVar("ph_round_timelimit", 180, FCVAR_REPLICATED) +function GM.Config.Round:Time() + return self.ConVars.Time:GetInt() - GAMEMODE.Config.Round:BlindTime() +end + +-- For how many seconds are the Seekers blinded? (Seconds) +GM.Config.Round.ConVars.BlindTime = CreateConVar("ph_round_blindtime", 30, FCVAR_REPLICATED, "How long are hunters blinded? (positive values will be inside the round time limit, negative will add to the round time limit)") +function GM.Config.Round:BlindTime() + return self.ConVars.BlindTime:GetInt() +end + +-- ------------------------------------------------------------------------- -- +--! Seeker Settings +-- ------------------------------------------------------------------------- -- +GM.Config.Seeker = {} +GM.Config.Seeker.ConVars = {} + +GM.Config.Seeker.ConVars.Health = CreateConVar("ph_seeker_health", 100, FCVAR_REPLICATED) +function GM.Config.Seeker:Health() + return self.ConVars.Health:GetInt() +end + +GM.Config.Seeker.ConVars.HealthMax = CreateConVar("ph_seeker_health_max", 100, FCVAR_REPLICATED) +function GM.Config.Seeker:HealthMax() + return self.ConVars.HealthMax:GetInt() +end + +GM.Config.Seeker.ConVars.HealthBonus = CreateConVar("ph_seeker_health_bonus", 20, FCVAR_REPLICATED) +function GM.Config.Seeker:HealthBonus() + return self.ConVars.HealthBonus:GetInt() +end + +GM.Config.Seeker.ConVars.HealthPenalty = CreateConVar("ph_seeker_health_penalty", 5, FCVAR_REPLICATED) +function GM.Config.Seeker:HealthPenalty() + return self.ConVars.HealthPenalty:GetInt() +end + +GM.Config.Seeker.ConVars.Weapons = CreateConVar("ph_seeker_weapons", "weapon_crowbar,weapon_pistol,weapon_ph_smg,weapon_shotgun", FCVAR_REPLICATED) +function GM.Config.Seeker:Weapons() + return string.Split(self.ConVars.Weapons:GetString(), ",") +end + +GM.Config.Seeker.ConVars.Ammo = CreateConVar("ph_seeker_ammo", "Pistol:100,SMG1:300,SMG1_Grenade:1,Buckshot:64", FCVAR_REPLICATED) +function GM.Config.Seeker:Ammo() + return string.Split(self.ConVars.Ammo:GetString(), ",") +end + +-- ------------------------------------------------------------------------- -- +--! Hider Settings +-- ------------------------------------------------------------------------- -- +GM.Config.Hider = {} +GM.Config.Hider.ConVars = {} + +GM.Config.Hider.ConVars.Health = CreateConVar("ph_hider_health", 100, FCVAR_REPLICATED) +function GM.Config.Hider:Health() + return self.ConVars.Health:GetInt() +end + +GM.Config.Hider.ConVars.HealthMax = CreateConVar("ph_hider_health_max", 100, FCVAR_REPLICATED) +function GM.Config.Hider:HealthMax() + return self.ConVars.HealthMax:GetInt() +end + +GM.Config.Hider.ConVars.HealthScaling = CreateConVar("ph_hider_health_scaling", 100, FCVAR_REPLICATED) +function GM.Config.Hider:HealthScaling() + return self.ConVars.HealthScaling:GetBool() +end + +GM.Config.Hider.ConVars.HealthScalingMax = CreateConVar("ph_hider_health_scaling_max", 200, FCVAR_REPLICATED) +function GM.Config.Hider:HealthScalingMax() + return self.ConVars.HealthScalingMax:GetInt() +end + +-- ------------------------------------------------------------------------- -- +--! Whitelist & Blacklist +-- ------------------------------------------------------------------------- -- +GM.Config.Lists = {} +GM.Config.Lists.ConVars = {} +GM.Config.Lists.ConCmds = {} + +GM.Config.Lists.ConVars.ClassWhitelist = CreateConVar("ph_list_class_whitelist", "prop_physics,prop_physics_multiplayer,prop_physics_respawnable", FCVAR_REPLICATED) +function GM.Config.Lists:ClassWhitelist() + return string.Split(self.ConVars.ClassWhitelist:GetString(), ",") +end + +-- Use Abuse Blacklist +GM.Config.Lists.ConVars.AbuseBlacklist = CreateConVar("ph_list_abuse_blacklist", "func_button,func_door,func_door_rotation,prop_door_rotation,func_tracktrain,func_tanktrain,func_breakable", FCVAR_REPLICATED) +function GM.Config.Lists:AbuseBlacklist() + return string.Split(self.ConVars.AbuseBlacklist:GetString(), ",") +end + +-- Model Blacklist +GM.Config.Lists.ModelBlacklist = {} +GM.Config.Lists.ModelBlacklist["models/props/cs_assault/dollar.mdl"] = true +GM.Config.Lists.ModelBlacklist["models/props/cs_assault/money.mdl"] = true +GM.Config.Lists.ModelBlacklist["models/props/cs_office/snowman_arm.mdl"] = true +GM.Config.Lists.ModelBlacklist["models/props_junk/garbage_plasticbottle001a.mdl"] = true +GM.Config.Lists.ModelBlacklist["models/props/cs_office/projector_remote.mdl"] = true + +GM.Config.Lists.ConCmds.ModelBlacklistList = concommand.Add("ph_list_model_blacklist_list", function(ply, cmd, args, argStr) + print("Model Blacklist:") + for k,v in pairs(GAMEMODE.Config.Lists.ModelBlacklist) do + print(" "..k) + end +end, "List all blacklisted models.") + +GM.Config.Lists.ConCmds.ModelBlacklistClear = concommand.Add("ph_list_model_blacklist_list", function(ply, cmd, args, argStr) + GM.Config.Lists.ModelBlacklist = {} +end, "Clear blacklisted models.") + +GM.Config.Lists.ConCmds.ModelBlacklistAdd = concommand.Add("ph_list_model_blacklist_add", function(ply, cmd, args, argStr) + if (table.count(args) > 0) then + GAMEMODE.Config.Lists.ModelBlacklist[args[1]] = true + else + print("Missing model name") + end +end, "Add a new blacklisted model.") + +GM.Config.Lists.ConCmds.ModelBlacklistRemove = concommand.Add("ph_list_model_blacklist_remove", function(ply, cmd, args, argStr) + if (table.count(args) > 0) then + GAMEMODE.Config.Lists.ModelBlacklist[args[1]] = nil + else + print("Missing model name") + end +end, "Removes a blacklisted model.") + +-- ------------------------------------------------------------------------- -- +--! Taunts +-- ------------------------------------------------------------------------- -- +-- GM.Config.Taunts = { + -- Seeker = { }, + -- Hider = { }, +-- } + +-- -- Taunts.Clear() +-- --@desc: Clears the current taunt list. +-- GM.Config.Taunts.Clear = function() + -- this.Seeker = {} + -- this.Hider = {} +-- end + +-- -- Taunts.Load(sTauntListFile) +-- --@desc: Loads the taunt list from disk. +-- --@param: +-- -- sTauntListFile - A string containing the path to the taunt list to load. +-- --@return: true or false depending on success. +-- GM.Config.Taunts.Load = function(sTauntListFile) + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Load: Loading taunt list from file '"..sTauntListFile.."'...") end + + -- -- Safeguard against idiots. + -- if type(sTauntListFile) != "string" then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Load: is not a string.") end + -- return false + -- end + + -- -- Given file must exist for us to continue. + -- if ! file.Exists(sTauntListFile, "GAME") then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Load: File not found.") end + -- return false + -- end + + -- -- Read the file and check if it's empty. + -- sTauntListData = file.Read(sTauntListFile, "GAME") + -- if sTauntListData == "" then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Load: File is empty.") end + -- return false + -- end + + -- -- Convert JSON to a table for us to use. + -- sTauntList = util.JSONToTable(sTauntListData) + + -- -- Is it nil? Then it's not valid JSON + -- if sTauntList == nil then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Load: File contains invalid JSON.") end + -- return false + -- end + + -- -- Finally, append the taunt lists. + -- if sTauntList.Seeker != nil then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Load: Adding Seeker taunts...") end + -- for k,v in pairs(sTauntList.Seeker) do + -- GAMEMODE.Taunts.Seeker[k] = v + -- end + -- end + -- if sTauntList.Hider != nil then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Load: Adding Hider taunts...") end + -- for k,v in pairs(sTauntList.Hider) do + -- GAMEMODE.Taunts.Hider[k] = v + -- end + -- end + + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Load: Complete.") end + -- return true +-- end + +-- -- Taunts.Save(sTauntListFile) +-- --@desc: Saves the current taunt list to disk. +-- --@param: +-- -- sTauntListFile - A string containing the path to the file to save to. +-- --@return: true or false depending on success. +-- GM.Config.Taunts.Save = function(sTauntListFile) + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Save: Saving taunt list to file '"..sTauntListFile.."'...") end + + -- -- Safeguard against idiots. + -- if type(sTauntListFile) != "string" then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Save: is not a string.") end + -- return false + -- end + + -- -- File must not be nil, otherwise we can't write to it. + -- if sTauntListFile == nil then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Save: No file given.") end + -- return false + -- end + + -- -- Convert our taunt table to JSON. + -- sTauntListData = util.TableToJSON(GAMEMODE.Taunts); + -- if sTauntListData == nil then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Save: Corrupted GAMEMODE table.") end + -- return false + -- end + + -- -- Write out JSON out to file + -- if ! file.Write(sTauntListFile, sTauntListData) then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Save: Failed to write to file.") end + -- return false + -- end + + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Save: Complete.") end + -- return true +-- end + +-- -- Taunts.Add(sTauntName, sSoundFile, iTeamID, mPropFilter) +-- --@desc: Registers a new taunt with the given name, file, team and filter. +-- --@param: +-- -- sTauntName - The unique name of the taunt. +-- -- sSoundFile - A sound file to play when this taunt is selected. +-- -- iTeamID - The team that should receive the taunt or nil for all teams. +-- -- mPropFilter - A string or a table containing strings for props that should be able to use this taunt. +-- --@return: true or false depending on success. +-- GM.Config.Taunts.Add = function(sTauntName, sSoundFile, iTeamID, mPropFilter) + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Add: Adding new taunt '"..sTauntName.."'...") end + + -- -- Safeguard against idiots. + -- if type(sTauntName) != "string" then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Add: is not a string.") end + -- return false + -- end + -- if type(sSoundFile) != "string" then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Add: is not a string.") end + -- return false + -- end + -- if (type(iTeamID) != "number" && iTeamID != nil) then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Add: is not a number or nil.") end + -- return false + -- end + -- if (type(mPropFilter) != "string" && type(mPropFilter) != "table" && mPropFilter != nil) then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Add: is not a string, table or nil.") end + -- return false + -- end + + -- -- Check if the sound file actually exists + -- if !file.Exists("sound/"..sSoundFile, "GAME") then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Add: File '"..sSoundFile.."' does not exist.") end + -- return false + -- end + + -- -- Make sure that our prop filter is a table listing the props it's supposed to work for. + -- if (mPropFilter == nil) then + -- mPropFilter = { } + -- elseif type(mPropFilter) == "string" then + -- mPropFilter = { mPropFilter } + -- end + + -- -- Prepare Taunt table + -- Taunt = { + -- File = sSoundFile, + -- Filter = mPropFilter + -- } + + -- -- If iTeamID is nil, both teams will receive the taunt. + -- if iTeamID == nil then + -- GAMEMODE.Taunts.Seeker[sTauntName] = Taunt + -- GAMEMODE.Taunts.Hider[sTauntName] = Taunt + -- else + -- -- Make sure that the team is valid. + -- if ! team.Valid(iTeamID) then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Add: Team "..iTeamID.."' does not exist.") end + -- return false + -- end + + -- if (iTeamID == TEAM_SEEKERS) then + -- GAMEMODE.Taunts.Seeker[sTauntName] = Taunt + -- elseif (iTeamID == TEAM_HIDERS) then + -- GAMEMODE.Taunts.Hider[sTauntName] = Taunt + -- else + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Add: Team "..iTeamID.."' can't have taunts.") end + -- return false + -- end + -- end + + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Add: Complete.") end + -- return true +-- end + +-- -- Taunts.Remove(sTauntName, iTeamID) +-- --@desc: Removes a registered taunt with the given name and team. +-- --@param: +-- -- sTauntName - The unique name of the taunt. +-- -- iTeamID - The team that the taunt should be removed from or nil for all teams. +-- --@return: true or false depending on success. +-- GM.Config.Taunts.Remove = function(sTauntName, iTeamID) + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Remove: Removing taunt '"..sTauntName.."'...") end + + -- -- Safeguard against idiots. + -- if type(sTauntName) != "string" then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Remove: is not a string.") end + -- return false + -- end + -- if (type(iTeamID) != "number" && iTeamID != nil) then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Remove: is not a number or nil.") end + -- return false + -- end + + -- -- if iTeamID is nil, both teams will have the taunt removed. + -- if (iTeamID == nil) then + -- GAMEMODE.Taunts.Seeker[sTauntName] = nil + -- GAMEMODE.Taunts.Hider[sTauntName] = nil + -- else + -- -- Make sure we have a valid Team. + -- if ! team.Valid(iTeamID) then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Remove: Team "..iTeamID.."' does not exist.") end + -- return false + -- end + + -- if iTeamID == TEAM_SEEKERS then + -- GAMEMODE.Taunts.Seeker[sTauntName] = nil + -- elseif iTeamID == TEAM_HIDERS then + -- GAMEMODE.Taunts.Hider[sTauntName] = nil + -- else + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Remove: Team "..iTeamID.."' can't have taunts.") end + -- return false + -- end + -- end + + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Remove: Complete.") end + -- return true +-- end + +-- -- ToDo: Taunts.Get(iTeamID, sPropName) + +-- --! Announcers (Round Start, Unblind, Win, Loss) +-- GM.Config.Announcers = { + -- Start = { }, + -- Unblind = { }, + -- Win = { }, + -- Loss = { } +-- } + +-- -- Announcers.Clear() +-- --@desc: Clears the current announcer list. +-- GM.Config.Announcers.Clear = function() + -- Announcers.Start = { } + -- Announcers.Unblind = { } + -- Announcers.Win = { } + -- Announcers.Loss = { } +-- end + +-- -- Announcers.Load(sAnnouncerListFile) +-- --@desc: Tries to load the given announcer list. +-- --@param: +-- -- sAnnouncerListFile - A string containing the path to the announcer list to load. +-- --@return: true or false depending on success. +-- GM.Config.Announcers.Load = function(sAnnouncerListFile) + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: Loading announcer list from file '"..sAnnouncerListFile.."'...") end + + -- -- Safeguard against idiots. + -- if type(sAnnouncerListFile) != "string" then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: is not a string.") end + -- return false + -- end + + -- -- Given file must exist for us to continue. + -- if ! file.Exists(sAnnouncerListFile, "GAME") then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: File not found.") end + -- return false + -- end + + -- -- Read the file and check if it's empty. + -- sAnnouncerListData = file.Read(sAnnouncerListFile, "GAME") + -- if sAnnouncerListData == "" then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: File is empty.") end + -- return false + -- end + + -- -- Convert JSON to a table for us to use. + -- sAnnouncerList = util.JSONToTable(sAnnouncerListData) + + -- -- Is it nil? Then it's not valid JSON + -- if sAnnouncerList == nil then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: File contains invalid JSON.") end + -- return false + -- end + + -- -- Finally, insert the announcer lists. + -- if sAnnouncerList.Start != nil then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: Adding Start announcers...") end + -- for k,v in pairs(sAnnouncerList.Start) do + -- GAMEMODE.Announcers.Start[k] = v + -- end + -- end + -- if sAnnouncerList.Unblind != nil then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: Adding Unblind announcers...") end + -- for k,v in pairs(sAnnouncerList.Unblind) do + -- GAMEMODE.Announcers.Unblind[k] = v + -- end + -- end + -- if sAnnouncerList.Win != nil then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: Adding Win announcers...") end + -- for k,v in pairs(sAnnouncerList.Win) do + -- GAMEMODE.Announcers.Win[k] = v + -- end + -- end + -- if sAnnouncerList.Loss != nil then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: Adding Loss announcers...") end + -- for k,v in pairs(sAnnouncerList.Loss) do + -- GAMEMODE.Announcers.Loss[k] = v + -- end + -- end + + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: Complete.") end + -- return true +-- end + +-- -- Announcers.Save(sAnnouncerListFile) +-- --@desc: Saves the current taunt list to disk. +-- --@param: +-- -- sAnnouncerListFile - A string containing the path to the file to save to. +-- --@return: true or false depending on success. +-- GM.Config.Announcers.Save = function(sAnnouncerListFile) + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Save: Saving announcer list to file '"..sAnnouncerListFile.."'...") end + + -- -- Safeguard against idiots. + -- if type(sAnnouncerListFile) != "string" then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Save: is not a string.") end + -- return false + -- end + + -- -- File must not be nil, otherwise we can't write to it. + -- if sAnnouncerListFile == nil then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Save: No file given.") end + -- return false + -- end + + -- -- Convert our taunt table to JSON. + -- sAnnouncerListData = util.TableToJSON(GAMEMODE.Announcers); + -- if sAnnouncerListData == nil then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Save: Corrupted GAMEMODE table.") end + -- return false + -- end + + -- -- Write out JSON out to file + -- if ! file.Write(sAnnouncerListFile, sAnnouncerListData) then + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Save: Failed to write to file.") end + -- return false + -- end + + + -- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Save: Complete.") end + -- return true +-- end + +-- -- ToDo: Announcers.Add +-- -- ToDo: Announcers.Remove +-- -- ToDo: Announcers.Get(iType) diff --git a/Source/gamemodes/prophuntextended/gamemode/server/roundmanager.lua b/Source/gamemodes/prophuntextended/gamemode/server/roundmanager.lua new file mode 100644 index 0000000..381a5ff --- /dev/null +++ b/Source/gamemodes/prophuntextended/gamemode/server/roundmanager.lua @@ -0,0 +1,63 @@ +--[[ + The MIT License (MIT) + + Copyright (c) 2015 Xaymar + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +--]] + +GM.RoundManager = {} +GM.RoundManager.State = nil; +GM.RoundManager.NextState = nil; + +function GM.RoundManager:Tick(...) + if (self.State != nil) then + if (self.State.Tick != nil) then + self.State:Tick(...) + end + end + + -- Advance States + if (self.NextState != self.State) then + -- Call OnLeave(NewState) + if (self.State != nil) then + if (self.State.OnLeave != nil) then + self.State:OnLeave(self.NextState) + end + end + + -- Call OnEnter(OldState) + if (self.NextState != nil) then + if (self.NextState.OnEnter != nil) then + self.NextState:OnEnter(self.State) + end + end + + -- Set State + self.State = self.NextState + end +end + +function GM.RoundManager:GetState() + return self.State +end + +function GM.RoundManager:SetState(State) + self.NextState = State +end diff --git a/Source/gamemodes/prophuntextended/gamemode/server/states/state_hide.lua b/Source/gamemodes/prophuntextended/gamemode/server/states/state_hide.lua new file mode 100644 index 0000000..2f10849 --- /dev/null +++ b/Source/gamemodes/prophuntextended/gamemode/server/states/state_hide.lua @@ -0,0 +1,61 @@ +--[[ + The MIT License (MIT) + + Copyright (c) 2015 Xaymar + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +--]] + +StateHide = {} + +function StateHide:OnEnter(OldState) + if GAMEMODE.Config:Debug() then print("StateHide: OnEnter") end + GAMEMODE:SetRoundState(GAMEMODE.States.Hide) + + -- Round Data + GAMEMODE.Data.RoundTime = math.abs(GAMEMODE.Config.Round:BlindTime()) + GAMEMODE.Data.RoundStartTime = CurTime() + + SetGlobalInt("RoundTime", GAMEMODE.Data.RoundTime) + + -- Freeze Seekers + for i, ply in ipairs(team.GetPlayers(GAMEMODE.Teams.Seekers)) do + ply:Freeze(true) + ply:Lock() + end +end + +function StateHide:Tick() + -- Update Game Time + GAMEMODE.Data.RoundTime = math.abs(GAMEMODE.Config.Round:BlindTime()) - (CurTime() - GAMEMODE.Data.RoundStartTime) + SetGlobalInt("RoundTime", math.ceil(GAMEMODE.Data.RoundTime)) + + -- Advance to Seeking State + if (GAMEMODE.Data.RoundTime <= 0) then + if GAMEMODE.Config:Debug() then print("StateHide: Advancing to Seek stage.") end + + GAMEMODE.RoundManager:SetState(StateSeek) + end + + -- ToDo: Logic for more game modes here? +end + +function StateHide:OnLeave(NewState) + if GAMEMODE.Config:Debug() then print("StateHide: OnLeave") end +end \ No newline at end of file diff --git a/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/sh_roundmanager.lua b/Source/gamemodes/prophuntextended/gamemode/server/states/state_postmatch.lua similarity index 70% rename from Gamemode/gamemodes/xaymars_prop_hunt/gamemode/sh_roundmanager.lua rename to Source/gamemodes/prophuntextended/gamemode/server/states/state_postmatch.lua index cca9642..14c23c8 100644 --- a/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/sh_roundmanager.lua +++ b/Source/gamemodes/prophuntextended/gamemode/server/states/state_postmatch.lua @@ -1,39 +1,39 @@ ---[[ - The MIT License (MIT) - - Copyright (c) 2015 Project Kube - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. ---]] - ---! Our custom RoundManager --- We need to keep track of three states in a round: Hide, Seek and PostRound. - ---! Round States -ROUNDSTATE_HIDE = 1 -ROUNDSTATE_SEEK = 2 -ROUNDSTATE_POSTROUND = 3 - -function RoundManagerInit() - -end - -function RoundManagerAdvance() - +--[[ + The MIT License (MIT) + + Copyright (c) 2015 Xaymar + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +--]] + +StatePostMatch = {} + +function StatePostMatch:OnEnter(OldState) + if GAMEMODE.Config:Debug() then print("StatePostMatch: OnEnter") end + GAMEMODE:SetRoundState(GAMEMODE.States.PostMatch) +end + +function StatePostMatch:Tick() + -- Advance State + GAMEMODE.RoundManager:SetState(StatePreMatch) +end + +function StatePostMatch:OnLeave(NewState) + if GAMEMODE.Config:Debug() then print("StatePostMatch: OnLeave") end end \ No newline at end of file diff --git a/Source/gamemodes/prophuntextended/gamemode/server/states/state_postround.lua b/Source/gamemodes/prophuntextended/gamemode/server/states/state_postround.lua new file mode 100644 index 0000000..34472b7 --- /dev/null +++ b/Source/gamemodes/prophuntextended/gamemode/server/states/state_postround.lua @@ -0,0 +1,55 @@ +--[[ + The MIT License (MIT) + + Copyright (c) 2015 Xaymar + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +--]] + +StatePostRound = {} + +function StatePostRound:OnEnter(OldState) + if GAMEMODE.Config:Debug() then print("StatePostRound: OnEnter") end + GAMEMODE:SetRoundState(GAMEMODE.States.PostRound) +end + +function StatePostRound:Tick() + -- Advance State + GAMEMODE.RoundManager:SetState(StatePreRound) -- Test: Reset to Hide +end + +function StatePostRound:OnLeave(NewState) + if GAMEMODE.Config:Debug() then print("StatePostRound: OnLeave") end + + -- Game Mode: Basic + if (GAMEMODE.Config:GameMode() == GAMEMODE.Modes.Original) then + -- Swap Teams + local hiders, seekers = team.GetPlayers(GAMEMODE.Teams.Hiders), team.GetPlayers(GAMEMODE.Teams.Seekers) + for i, ply in ipairs(hiders) do + ply:SetTeam(GAMEMODE.Teams.Seekers) + player_manager.SetPlayerClass(ply, "Seeker") + end + for i, ply in ipairs(seekers) do + ply:SetTeam(GAMEMODE.Teams.Hiders) + player_manager.SetPlayerClass(ply, "Hider") + end + + -- TODO: Other Gamemodes + end +end \ No newline at end of file diff --git a/Source/gamemodes/prophuntextended/gamemode/server/states/state_prematch.lua b/Source/gamemodes/prophuntextended/gamemode/server/states/state_prematch.lua new file mode 100644 index 0000000..6947701 --- /dev/null +++ b/Source/gamemodes/prophuntextended/gamemode/server/states/state_prematch.lua @@ -0,0 +1,54 @@ +--[[ + The MIT License (MIT) + + Copyright (c) 2015 Xaymar + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +--]] + +-- Precache Network Message +StatePreMatch = {} + +function StatePreMatch:OnEnter(OldState) + if GAMEMODE.Config:Debug() then print("StatePreMatch: OnEnter") end + GAMEMODE:SetRoundState(GAMEMODE.States.PreMatch) + + SetGlobalInt("Round", GetGlobalInt("Round", 0) + 1) +end + +function StatePreMatch:Tick() + -- Debug: Auto Advance to PreRound State + if (GAMEMODE.Config:Debug()) then + print("StatePreMatch: Advancing to StatePreRound") + GAMEMODE.RoundManager:SetState(StatePreRound) + end + + -- Game Mode: Basic + if (GAMEMODE.Config:GameMode() == GAMEMODE.Modes.Original) then + -- Both Teams must have at least 1 player. + if ((team.NumPlayers(GAMEMODE.Teams.Seekers) >= 1) && (team.NumPlayers(GAMEMODE.Teams.Hiders) >= 1)) then + GAMEMODE.RoundManager:SetState(StatePreRound) + end + -- TODO: Other Gamemodes + end +end + +function StatePreMatch:OnLeave(NewState) + if GAMEMODE.Config:Debug() then print("StatePreMatch: OnLeave") end +end \ No newline at end of file diff --git a/Source/gamemodes/prophuntextended/gamemode/server/states/state_preround.lua b/Source/gamemodes/prophuntextended/gamemode/server/states/state_preround.lua new file mode 100644 index 0000000..479c3a5 --- /dev/null +++ b/Source/gamemodes/prophuntextended/gamemode/server/states/state_preround.lua @@ -0,0 +1,52 @@ +--[[ + The MIT License (MIT) + + Copyright (c) 2015 Xaymar + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +--]] + +StatePreRound = {} + +function StatePreRound:OnEnter(OldState) + if GAMEMODE.Config:Debug() then print("StatePreRound: OnEnter") end + GAMEMODE:SetRoundState(GAMEMODE.States.PreRound) + + -- Clean Up the Map + game.CleanUpMap() + +end +function StatePreRound:Tick() + -- Advance State + GAMEMODE.RoundManager:SetState(StateHide) +end +function StatePreRound:OnLeave(NewState) + if GAMEMODE.Config:Debug() then print("StatePreRound: OnLeave") end + + -- Game Mode: Basic + if (GAMEMODE.Config:GameMode() == GAMEMODE.Modes.Original) then + -- Respawn Everyone + for i, ply in ipairs(player.GetAll()) do + ply:KillSilent() + ply.Data.Alive = true + ply:Spawn() + end + -- TODO: Other Gamemodes + end +end \ No newline at end of file diff --git a/Source/gamemodes/prophuntextended/gamemode/server/states/state_seek.lua b/Source/gamemodes/prophuntextended/gamemode/server/states/state_seek.lua new file mode 100644 index 0000000..70e17db --- /dev/null +++ b/Source/gamemodes/prophuntextended/gamemode/server/states/state_seek.lua @@ -0,0 +1,83 @@ +--[[ + The MIT License (MIT) + + Copyright (c) 2015 Xaymar + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +--]] + +StateSeek = {} + +function StateSeek:OnEnter(OldState) + if GAMEMODE.Config:Debug() then print("StateSeek: OnEnter") end + GAMEMODE:SetRoundState(GAMEMODE.States.Seek) + + -- Round Data + GAMEMODE.Data.RoundTime = GAMEMODE.Config.Round:Time() + + -- Unfreeze Seekers + for i, ply in ipairs(team.GetPlayers(GAMEMODE.Teams.Seekers)) do + ply:Freeze(false) + ply:UnLock() + end +end + +function StateSeek:Tick() + -- Update Game Time + GAMEMODE.Data.RoundTime = GAMEMODE.Config.Round:Time() - (CurTime() - GAMEMODE.Data.RoundStartTime) + SetGlobalInt("RoundTime", math.ceil(GAMEMODE.Data.RoundTime)) + + -- Conditions for moving to the next State + if (GAMEMODE.Data.RoundTime <= 0) then -- No Time remaining + GAMEMODE.Data.Winner = GAMEMODE.Teams.Hiders + GAMEMODE.RoundManager:SetState(StatePostRound) + end + + -- Condition: No Seekers / Hiders alive. + local hiders, seekers = team.GetPlayers(GAMEMODE.Teams.Hiders), team.GetPlayers(GAMEMODE.Teams.Seekers) + local hiderAlive, seekerAlive = false, false + for i,ply in ipairs(hiders) do + if (ply.Data.Alive) then + hiderAlive = true + end + end + for i,ply in ipairs(seekers) do + if (ply.Data.Alive) then + seekerAlive = true + end + end + if (hiderAlive == false) then + if (seekerAlive == false) then + GAMEMODE.Data.Winner = GAMEMODE.Teams.Spectators -- Shows as Draw + GAMEMODE.RoundManager:SetState(StatePostRound) + else + GAMEMODE.Data.Winner = GAMEMODE.Teams.Seekers + GAMEMODE.RoundManager:SetState(StatePostRound) + end + else + if (seekerAlive == false) then + GAMEMODE.Data.Winner = GAMEMODE.Teams.Hiders + GAMEMODE.RoundManager:SetState(StatePostRound) + end + end +end + +function StateSeek:OnLeave(NewState) + if GAMEMODE.Config:Debug() then print("StateSeek: OnLeave") end +end \ No newline at end of file diff --git a/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/sh_config.lua b/Source/gamemodes/prophuntextended/gamemode/sh_config.lua similarity index 78% rename from Gamemode/gamemodes/xaymars_prop_hunt/gamemode/sh_config.lua rename to Source/gamemodes/prophuntextended/gamemode/sh_config.lua index dd91bc2..2324120 100644 --- a/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/sh_config.lua +++ b/Source/gamemodes/prophuntextended/gamemode/sh_config.lua @@ -1,23 +1,3 @@ -if !file.IsDir("prop_hunt", "DATA") then file.CreateDir("prop_hunt") end - --- These are Models that the Prop team can not become. --- Usually you'd put invisible or impossible to hit models in here. -BANNED_PROP_MODELS = { - "models/props/cs_assault/dollar.mdl", - "models/props/cs_assault/money.mdl", - "models/props/cs_office/snowman_arm.mdl", - "models/props_junk/garbage_plasticbottle001a.mdl", - "models/props/cs_office/projector_remote.mdl" -} -if (! file.Exists("prop_hunt/banned_props.txt", "DATA")) then - file.Write("prop_hunt/banned_props.txt", util.TableToKeyValues(BANNED_PROP_MODELS)) -end -local fileContent = file.Read("prop_hunt/banned_props.txt", "DATA"); -if fileContent then - local fileTable = util.KeyValuesToTable(fileContent) - if fileTable then BANNED_PROP_MODELS = fileTable end -end - -- Sounds played by members of the losing team at the end of the round. LOSS_SOUNDS = { "bot/aw_hell.wav", @@ -311,56 +291,4 @@ local fileContent = file.Read("prop_hunt/sounds_taunt_prop.txt", "DATA"); if fileContent then local fileTable = util.KeyValuesToTable(fileContent) if fileTable then PROP_TAUNTS = fileTable end -end - --- Maximum time (in minutes) for this fretta gamemode (Default: 30) -GAME_TIME = math.max(GetConVarNumber("mp_timelimit"),1) - --- Number of seconds hunters are blinded/locked at the beginning of the map (Default: 30) -CreateConVar("HUNTER_BLINDLOCK_TIME", "30", FCVAR_REPLICATED) - ---Create the convars here --- Health points removed from hunters when they shoot (Default: 5) -CreateConVar( "HUNTER_FIRE_PENALTY", "5", FCVAR_REPLICATED) - --- How much health to give back to the Hunter after killing a prop (Default: 20) -CreateConVar( "HUNTER_KILL_BONUS", "20", FCVAR_REPLICATED) - ---Whether or not we include grenade launcher ammo (default: 1) -CreateConVar( "WEAPONS_ALLOW_GRENADE", "1", FCVAR_REPLICATED) - --- Seconds a player has to wait before they can taunt again (Default: 5) -TAUNT_DELAY = 2 - --- Rounds played on a map (Default: 10) -ROUNDS_PER_MAP = 60 - --- Time (in seconds) for each round (Default: 300) -ROUND_TIME = 300 - --- Determains if players should be team swapped every round [0 = No, 1 = Yes] (Default: 1) -SWAP_TEAMS_EVERY_ROUND = 1 - --- Update above values with values from configuration. -if (! file.Exists("prop_hunt/config.txt", "DATA")) then - file.Write("prop_hunt/config.txt", util.TableToKeyValues({ --- GAME_TIME = 30, - TAUNT_DELAY = 2, - ROUNDS_PER_MAP = 60, - ROUND_TIME = 300, - SWAP_TEAM_EVERY_ROUND = 1 - })) -end -local fileContent = file.Read("prop_hunt/config.txt", "DATA"); -if fileContent then - local fileTable = util.KeyValuesToTable(fileContent) - if fileTable then --- if fileTable.GAME_TIME then GAME_TIME = fileTable.GAME_TIME end - if fileTable.TAUNT_DELAY then TAUNT_DELAY = fileTable.TAUNT_DELAY end - if fileTable.ROUNDS_PER_MAP then ROUNDS_PER_MAP = fileTable.ROUNDS_PER_MAP end - if fileTable.ROUND_TIME then ROUND_TIME = fileTable.ROUND_TIME end - if fileTable.SWAP_TEAM_EVERY_ROUND then ROUND_TIME = fileTable.SWAP_TEAM_EVERY_ROUND end - end -end - -GAME_TIME = math.max(GetConVarNumber("mp_timelimit"),1) +end \ No newline at end of file diff --git a/Source/gamemodes/prophuntextended/gamemode/sh_init.lua b/Source/gamemodes/prophuntextended/gamemode/sh_init.lua new file mode 100644 index 0000000..1ca3607 --- /dev/null +++ b/Source/gamemodes/prophuntextended/gamemode/sh_init.lua @@ -0,0 +1,130 @@ +--[[ + The MIT License (MIT) + + Copyright (c) 2015 Xaymar + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +--]] + +-- ------------------------------------------------------------------------- -- +--! Gamemode Information +-- ------------------------------------------------------------------------- -- +GM.Name = "Prop Hunt Extended" +GM.Author = "Michael 'Xaymar' Dirks (Based on Kow@lskis Version, Original by AMT)" +GM.Email = "michael.fabian.dirks@gmail.com" +GM.Website = "http://xaymar.com/" + +GM.TeamBased = true +GM.AllowAutoTeam = true +GM.SecondsBetweenTeamSwitches = 10 + +-- ------------------------------------------------------------------------- -- +--! Includes +-- ------------------------------------------------------------------------- -- +-- Player Classes +include "player_class/class_default.lua" +include "player_class/class_spectator.lua" +include "player_class/class_seeker.lua" +include "player_class/class_hider.lua" + +-- ------------------------------------------------------------------------- -- +--! Code +-- ------------------------------------------------------------------------- -- +-- Game States +GM.States = {} +GM.States.PreMatch = 0 +GM.States.PreRound = 1 +GM.States.Hide = 2 +GM.States.Seek = 3 +GM.States.PostRound = 4 +GM.States.PostMatch = 5 + +-- Game Modes +GM.Modes = {} +GM.Modes.Original = 0 +GM.Modes.SwizzleEffect = 1 -- Randomizes Teams each Round +GM.Modes.TheDeadHunt = 2 -- One Hunter, Dead Prop become Hunter, Props can't see each other. + +-- Teams +GM.Teams = {} +GM.Teams.Spectators = 0 +GM.Teams.Seekers = 1 +GM.Teams.Hiders = 2 + +function GM:CreateTeams() + -- Specators + team.SetUp(self.Teams.Spectators, "Spectators", Color(127, 127, 127, 255)) + team.SetSpawnPoint(self.Teams.Spectators, { + "info_player_deathmatch", + "info_player_axis", + "info_player_combine", + "info_player_counterterrorist", + "info_player_allies", + "info_player_terrorist" + }) + team.SetClass(self.Teams.Spectators, { "Spectator", "Spectator" }) + + -- Seekers: "Hunters" + team.SetUp(self.Teams.Seekers, "Seekers", Color(0, 128, 255, 255)) + team.SetSpawnPoint(self.Teams.Seekers, { + "info_player_spawn", + "info_player_deathmatch", + "info_player_axis", + "info_player_combine", + "info_player_counterterrorist" + }) + team.SetClass(self.Teams.Seekers, { "Seeker", "Spectator" }) + + -- Hiders: "Props" + team.SetUp(self.Teams.Hiders, "Hiders", Color(255, 128, 0, 255)) + team.SetSpawnPoint(self.Teams.Hiders, { + "info_player_spawn", + "info_player_deathmatch", + "info_player_allies", + "info_player_terrorist" + }) + team.SetClass(self.Teams.Hiders, { "Hider", "Spectator" }) +end + +-- ------------------------------------------------------------------------- -- +--! Player Manager Binding +-- ------------------------------------------------------------------------- -- +function GM:PlayerPostThink(ply) + return player_manager.RunClass(ply, "PostThink") +end + +function GM:PlayerTick(ply, mv) + return player_manager.RunClass(ply, "Tick", mv) +end + +function GM:PlayerHurt(victim, attacker, healthRemaining, damageTaken) + if (victim != nil && victim:IsPlayer()) then + player_manager.RunClass(victim, "Hurt", victim, attacker, healthRemaining, damageTaken) + end + if (attacker != nil && attacker:IsPlayer()) then + player_manager.RunClass(attacker, "Damage", victim, attacker, healthRemaining, damageTaken) + end +end + +-- ------------------------------------------------------------------------- -- +--! Gamemode Functionality +-- ------------------------------------------------------------------------- -- +function GM:GetRoundState() + return GetGlobalInt("RoundState", self.States.PreMatch) +end \ No newline at end of file diff --git a/Gamemode/gamemodes/xaymars_prop_hunt/gamemode/sh_player.lua b/Source/gamemodes/prophuntextended/gamemode/sh_player.lua similarity index 100% rename from Gamemode/gamemodes/xaymars_prop_hunt/gamemode/sh_player.lua rename to Source/gamemodes/prophuntextended/gamemode/sh_player.lua diff --git a/Gamemode/gamemodes/xaymars_prop_hunt/icon24.png b/Source/gamemodes/prophuntextended/icon24.png similarity index 100% rename from Gamemode/gamemodes/xaymars_prop_hunt/icon24.png rename to Source/gamemodes/prophuntextended/icon24.png diff --git a/Gamemode/gamemodes/xaymars_prop_hunt/logo.png b/Source/gamemodes/prophuntextended/logo.png similarity index 100% rename from Gamemode/gamemodes/xaymars_prop_hunt/logo.png rename to Source/gamemodes/prophuntextended/logo.png diff --git a/Gamemode/gamemodes/xaymars_prop_hunt/xaymars_prop_hunt.txt b/Source/gamemodes/prophuntextended/prophuntextended.txt similarity index 54% rename from Gamemode/gamemodes/xaymars_prop_hunt/xaymars_prop_hunt.txt rename to Source/gamemodes/prophuntextended/prophuntextended.txt index 90f354b..dfce58b 100644 --- a/Gamemode/gamemodes/xaymars_prop_hunt/xaymars_prop_hunt.txt +++ b/Source/gamemodes/prophuntextended/prophuntextended.txt @@ -1,18 +1,8 @@ -"xaymars_prop_hunt" +"prophuntextended" { "base" "base" - "title" "Prop Hunt" - "maps" "^ph_|^cs_|^de_|^ttt_" - - "fretta_maps" - { - "1" "ph_" - "2" "cs_" - "3" "de_" - "4" "ttt_" - } - "selectable" "1" - + "title" "Prop Hunt Extended" + "maps" "^ph_|^cs_|^de_|^ttt_" "menusystem" "1" "workshopid" "468149739" @@ -20,6 +10,15 @@ { // Game Settings 1 + { + "name" "ph_gamemode" + "text" "G: Game Mode" + "help" "0: Basic, 1: Swizzle Effect (Random Teams), 2: The Dead Hunt (One Hunter, Dead Props become Hunters)" + "type" "Numeric" + "default" "0" + } + + 2 { "name" "mp_timelimit" "text" "G: Time Limit" @@ -28,7 +27,7 @@ "default" "20" } - 2 + 3 { "name" "ph_sprinting" "text" "G: Enable Sprinting" @@ -37,9 +36,9 @@ "default" "0" } - 3 + 4 { - "name" "ph_tauntwaittime" + "name" "ph_tauntcooldown" "text" "G: Taunt Cooldown" "help" "How much time must pass before another taunt may be played." "type" "Numeric" @@ -47,53 +46,35 @@ } // Round Settings - 4 + 10 { - "name" "ph_rounds" + "name" "ph_round_limit" "text" "R: Rounds per Map" "help" "How many rounds are played per map." "type" "Numeric" "default" "10" } - 5 + 11 { - "name" "ph_rounds_time" + "name" "ph_round_timelimit" "text" "R: Round Duration (Seconds)" "help" "How long is each round going to last?" "type" "Numeric" "default" "300" } - 6 + 12 { - "name" "ph_rounds_blindtime" + "name" "ph_round_blindtime" "text" "R: Hiding Time (Seconds)" - "help" "How long are Seekers blinded in seconds?" + "help" "How long are hunters blinded? (positive values will be inside the round time limit, negative will add to the round time limit)" "type" "Numeric" "default" "30" } - 7 - { - "name" "ph_rounds_teams_swap" - "text" "R: Swap Teams every round?" - "help" "Should teams be swapped every round? (Can't be used with Randomize)" - "type" "CheckBox" - "default" "1" - } - - 8 - { - "name" "ph_rounds_teams_randomize" - "text" "R: Randomize Teams every round?" - "help" "Should teams be randomized every round? (Can't be used with Swap)" - "type" "CheckBox" - "default" "0" - } - // Seeker Settings - 9 + 20 { "name" "ph_seeker_health" "text" "S: Health" @@ -101,7 +82,7 @@ "default" "100" } - 10 + 21 { "name" "ph_seeker_health_max" "text" "S: Max Health" @@ -109,58 +90,44 @@ "default" "100" } - 11 + 22 { - "name" "ph_seeker_health_killbonus" + "name" "ph_seeker_health_bonus" "text" "S: Health Kill-Bonus" "help" "Health gained on kill." "type" "Numeric" - "default" "10" + "default" "20" } - 11 + 23 { "name" "ph_seeker_health_penalty" "text" "S: Health Penalty" "help" "Health lost on wrong shot." "type" "Numeric" - "default" "1" + "default" "5" } - 12 + 24 { - "name" "ph_seeker_ammo_pistol" - "text" "S: Ammo for Pistol" - "type" "Numeric" - "default" "40" + "name" "ph_seeker_weapons" + "text" "S: Weapons to be given to Seekers" + "help" "Format: Weapon,Weapon,..." + "type" "Text" + "default" "weapon_crowbar,weapon_pistol,weapon_ph_smg,weapon_shotgun,weapon_physcannon" } - 13 + 25 { - "name" "ph_seeker_ammo_smg" - "text" "S: Ammo for SMG" - "type" "Numeric" - "default" "300" - } - - 14 - { - "name" "ph_seeker_ammo_smggrenade" - "text" "S: Ammo for SMG Grenade" - "type" "Numeric" - "default" "1" - } - - 15 - { - "name" "ph_seeker_ammo_shotgun" - "text" "S: Ammo for Shotgun" - "type" "Numeric" - "default" "60" + "name" "ph_seeker_ammo" + "text" "S: Ammo to give to Seekers" + "help" "Format: Name:Amount,Name:Amount,..." + "type" "Text" + "default" "Pistol:100,SMG1:300,SMG1_Grenade:1,Buckshot:64" } // Hider Settings - 16 + 30 { "name" "ph_hider_health" "text" "H: Health" @@ -168,7 +135,7 @@ "default" "100" } - 17 + 31 { "name" "ph_hider_health_max" "text" "H: Max Health" @@ -176,21 +143,40 @@ "default" "100" } - 18 + 32 { - "name" "ph_hider_health_scale" + "name" "ph_hider_health_scaling" "text" "H: Enable Health Scaling" "help" "Larger & heavier objects have more health, smaller less." "type" "CheckBox" "default" "1" } - 19 + 33 { - "name" "ph_hider_health_scaled_max" + "name" "ph_hider_health_scaling_max" "text" "H: Scaled Max Health" "type" "Numeric" "default" "200" } + + // Whitelist & Blacklist + 40 + { + "name" "ph_list_class_whitelist" + "text" "L: Allowed Entity Classes" + "help" "Hiders can only use these for changing model and skin." + "type" "Text" + "default" "ph_prop,prop_physics,prop_physics_multiplayer,prop_physics_respawnable" + } + + 41 + { + "name" "ph_list_abuse_blacklist" + "text" "L: Abuse Blacklist" + "help" "Fix interact spam with certain entities so that all areas stay accessible." + "type" "Text" + "default" ""func_button,func_door,func_door_rotation,prop_door_rotation,func_tracktrain,func_tanktrain,func_breakable"" + } } } diff --git a/Tools.bat b/Tools.bat index 50cb207..2bde909 100644 --- a/Tools.bat +++ b/Tools.bat @@ -1,7 +1,7 @@ @ECHO OFF :: Retrieve Garry's Mod path from Regristry :: FOR /F "tokens=2* delims= " %%A IN ('REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 4000" /v InstallLocation') DO SET "GARRYSMODPATH=%%B" -SET "GARRYSMODPATH=D:\Program Files (x86)\Steam\steamapps\common\GarrysMod" +SET "GARRYSMODPATH=C:\Program Files (x86)\Steam\steamapps\common\GarrysMod" SET "PATH=%CD%;%GARRYSMODPATH%\bin;%PATH%" CMD diff --git a/Workshop Package.bat b/Workshop Package.bat index f3474d9..2988659 100644 --- a/Workshop Package.bat +++ b/Workshop Package.bat @@ -1,9 +1,9 @@ @ECHO OFF :: Fallback -SET "GARRYSMODPATH=D:\Program Files (x86)\Steam\steamapps\common\GarrysMod" +SET "GARRYSMODPATH=C:\Program Files (x86)\Steam\steamapps\common\GarrysMod" :: Retrieve Garry's Mod path from Regristry FOR /F "tokens=2* delims= " %%A IN ('REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 4000" /v InstallLocation') DO SET "GARRYSMODPATH=%%B" -"%GARRYSMODPATH%\bin\gmad.exe" create -folder "%CD%/Gamemode" -out "%CD%/Pack.gma" +"%GARRYSMODPATH%\bin\gmad.exe" create -folder "%CD%\Source" -out "%CD%\Pack.gma" PAUSE \ No newline at end of file diff --git a/Workshop Update.bat b/Workshop Update.bat index bbdd358..e01fd96 100644 --- a/Workshop Update.bat +++ b/Workshop Update.bat @@ -1,9 +1,9 @@ @ECHO OFF :: Fallback -SET "GARRYSMODPATH=D:\Program Files (x86)\Steam\steamapps\common\GarrysMod" +SET "GARRYSMODPATH=C:\Program Files (x86)\Steam\steamapps\common\GarrysMod" :: Retrieve Garry's Mod path from Regristry -FOR /F "tokens=2* delims= " %%A IN ('REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 4000" /v InstallLocation') DO SET "GARRYSMODPATH=%%B" +::FOR /F "tokens=2* delims= " %%A IN ('REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 4000" /v InstallLocation') DO SET "GARRYSMODPATH=%%B" SET /P CHANGES=Changes: "%GARRYSMODPATH%\bin\gmpublish.exe" update -id 468149739 -icon "Logo.jpg" -addon "Pack.gma" -changes "%CHANGES%