27 Commits

Author SHA1 Message Date
Michael Fabian 'Xaymar' Dirks eb3b7f3aef gamemode: Add new 'Selection Halo' feature
This feature allows Hiders to easily tell which prop they will turn into if they press Use. As always, it can be fully configured and even turned off. By default it is enabled and set to Approximate mode.

In Approximate mode, the client is responsible for guessing the best match to the Use key, but does not have any actual influence on what they will really turn into. This will in most cases be enough, as the internal Use test relies on the forward vector, which is checked by this mode. For those requiring more accuracy, there is the Accurate mode.

In Accurate mode, the server is responsible for exactly knowing the best match to the Use key and sending this to the user. This has a server performance impact that scales with the player base and the rate at which these updates are performed can be configured. This mode is affected by lag and packet loss, so only really useful for high performance LAN servers or testing.
2017-11-25 13:25:29 +01:00
Michael Fabian 'Xaymar' Dirks 785f55a017 gamemode: Add Player meta extension
The meta object is extended by some commonly used functionality that Garry's Mod does not expose directly. Some of these are Server only and will produce wrong results on the Client, also due to Garry's Mod not exposing things properly.
2017-11-25 13:14:57 +01:00
Michael Fabian 'Xaymar' Dirks 2691ca4e46 gamemode/compat: Remove old compatibility code 2017-11-25 09:21:59 +01:00
Michael Fabian 'Xaymar' Dirks 8413d8e08e gamemode: Add support for FindUseEntity hook 2017-11-25 09:18:59 +01:00
Michael Fabian 'Xaymar' Dirks 5a4791a097 gamemode/sh_player: Add proper license header 2017-11-25 09:16:20 +01:00
Michael Fabian 'Xaymar' Dirks cc820a89d3 gamemode: Add new and update existing cvars with help text
The command 'cvarlist ph_' should now actually be much more descriptive than before.
2017-11-25 01:30:06 +01:00
Michael Fabian 'Xaymar' Dirks e8f5fc4b92 compat/tauntpackloader: Fix support for third party taunt packs 2017-11-25 00:16:52 +01:00
Michael Fabian 'Xaymar' Dirks 0091281e90 media: Add wider version of the logo 2017-11-25 00:16:33 +01:00
Michael Fabian 'Xaymar' Dirks 0a1fa75a30 gamemode: Only show nameplates for alive players 2017-11-24 03:53:41 +01:00
Michael Fabian 'Xaymar' Dirks eac0c12d64 Ignore all gma files 2017-11-24 03:13:33 +01:00
Michael Fabian 'Xaymar' Dirks 74d77b5269 class/seeker: Ignore damage done to ragdolls 2017-11-24 03:10:50 +01:00
Michael Fabian 'Xaymar' Dirks 14e32383c4 class/seeker: Properly respect mp_friendlyfire 2
Support for the reflect setting (mp_friendlyfire 2) now properly works and will no longer spew lua errors into the console, while also logging who damaged who with how much damage. This info is critical to server owners that want to know what exactly went down in a match with this option enabled.
2017-11-24 03:10:30 +01:00
Michael Fabian 'Xaymar' Dirks 0efa3f12c0 gamemode: Fix PlayerHurt and PlayerShouldTakeDamage hooks 2017-11-24 03:07:19 +01:00
Michael Fabian 'Xaymar' Dirks f38e70dce9 Rename automated building scripts 2017-11-24 02:06:09 +01:00
Michael Fabian 'Xaymar' Dirks 67c91f9225 media: Add other media 2017-11-24 02:00:24 +01:00
Michael Fabian 'Xaymar' Dirks bc0068a79a media: Update Workshop Icon PSD 2017-11-24 02:00:18 +01:00
Michael Fabian 'Xaymar' Dirks 6ad75df85d Adjust paths to be lowercase (part 2)
Even though git internally knows the difference between upper and lower case, all of it's commands rely on the file system to do so as well. This results in incorrect behavior when renaming A to a for example, as the source and destination is identical on the file system according to git. Windows does support such renames, but git seems to shit itself.
2017-11-24 02:00:08 +01:00
Michael Fabian 'Xaymar' Dirks e8454d4d27 Adjust paths to be lowercase 2017-11-24 01:58:31 +01:00
Michael Fabian 'Xaymar' Dirks e609fb09f4 gamemode: Add support for name plates above players
Name plates are an easy way to identify other players without looking at them or relying on the Target id to appear (which should no longer happen). Several new cvars have been added to make this possible:

- ph_nameplates_show: Show or hide name plates.
- ph_nameplates_scale: World scale, a value of 1 makes 1 pixel equal 1 unit.
- ph_nameplates_height: Height above the player.
- ph_nameplates_tint_hue
- ph_nameplates_tint_saturation
- ph_nameplates_tint_value
- ph_nameplates_tint_health: Tint nameplate using the remaining health, 100% health = green, 0% health = red.
- ph_nameplates_tint_team: Tint nameplates using the players team.
2017-11-24 01:22:18 +01:00
Michael Fabian 'Xaymar' Dirks b5209f4b60 gamemode: Updated author and contact info
Before the 13th June 2016, the gamemode was indeed largely based on the version Kow@lski released to the Workshop (which was based on the original version AMT released). On 13th June 2016, I took it upon myself to completely rewrite the existing game mode to future proof it for years to come and make it incredibly easy to change.

This means that after the 13th June 2016, the sole author was and still is Michael Fabian 'Xaymar' Dirks.
2017-11-24 01:06:53 +01:00
Michael Fabian 'Xaymar' Dirks 3607102698 media: Use new and improved workshop logo 2017-11-20 05:03:21 +01:00
Michael Fabian 'Xaymar' Dirks 4ee354662f media: Improve ingame icon sharpness 2017-11-20 03:21:24 +01:00
Michael Fabian 'Xaymar' Dirks 98df2f2783 media: Convert ingame icon to Photoshop 2017-11-20 03:21:07 +01:00
Michael Fabian 'Xaymar' Dirks b8a7259d29 Merge code from old remote
The code was previously uploaded to GitLab on my own server, but that will soon no longer be available. Before this happens, here is the code and all updates that were done over there (matching the current released version).

# 27.12.2016 19:17

- Fixed ph_debug_log not showing player taunts.
- Fixed ph_taunt_hiders and ph_taunt_seekers showing left over code debugging messages.
- Fixed ph_teams_weighted the Seeker team, causing players winning Seekers to stay on the Seeker team.
- Added client and server camera ConVars (ph_camera_).
- Fixed camera collisions not using smooth transitions.
- Fixed player model incorrectly hiding too early.

# 18.12.2016 00:55

- Fixed ConVars not being taken from 'Start New Game' menu.
- Added descriptions for each Console Variable.
- Fixed Lua Error appearing when pressing Q as Spectator or Seeker.
- Fixed automatic Taunt Pack loading being overridden by ConVars.
- Fixed Blind Time being stuck at 0 seconds.

# 20.08.2016 18:24

- Fixed: Team Swapping now actually works instead of breaking when there is less than 4 players.
- Changed: Slightly reduced Prop Hitbox size to fix players getting stuck on each other.

# 20.07.2016 21:27

- Fixed a bug which would create both a clientside and a serverside ragdoll on listen servers.
- Added support for MapVote.
- Fixed PostMatch not checking for Round Limit and Map Limit properly.

# 20.06.2016 20:52

- Added taunting ability (ShowSpare1) and convars to define custom packs.
- Added ph_teams_weighted that will assign players using a weighted Score.
- Added convar to unlock Hider rotation to 3-Dimensional mode. (ph_hider_allow_full_rotation)
- Added debug command to print game statistics. (ph_debug_stats)
- Fixed Prop Rotation randomly being delayed by sending additional information.
- Fixed ph_teams_randomize that would assign all players to Seekers.
- Fixed a bug with ph_round_timelimit that made it ignore the blind time or double it.
- Changed Team convars to use the ph_teams_ prefix instead.
- Updated Game UI to look a little bit more modern.

# 19.06.2016 16:58

- Implemented a Gamemode hook to respect the current mp_friendlyfire setting. (0 = Off, 1 = On, 2 = Self-Damage)
- Implemented network messages for synchronized Kill Notifications.
- Implemented ConVars for Taunts for Seekers & Hiders. (ph_taunts_seekers,ph_taunts_hiders)
- Fixed a bug in which Seekers would be able to sprint while sprinting was disabled (and the other way around).
- Implemented Team randomization for 'Original' Gametype. (ph_round_randomizeteams)
2017-11-19 21:12:58 +01:00
Michael Fabian 'Xaymar' Dirks 704d38dd76 tools: Update logo location 2017-11-19 20:35:16 +01:00
Michael Fabian 'Xaymar' Dirks d331880199 Move Media to sub directory 2017-11-19 20:33:16 +01:00
Michael Fabian 'Xaymar' Dirks 282998baeb Automatically try both 32 and 64-bit paths for Tools 2017-11-19 20:32:08 +01:00
63 changed files with 2073 additions and 871 deletions
+2 -1
View File
@@ -1,3 +1,4 @@
Pack.gma
Changelog.txt
Description.txt
Description.txt
/*.gma
-15
View File
@@ -1,15 +0,0 @@
Changelist
-
ToDo:
- Replace all createconvar with getconvar?
- Other game modes
- UI stuff
- Scoreboard
- Custom Collisions for Hiders? Allows to copy the prop geometry/align with rotation
- Spectator: Spectate players(team only), first & third person
- UI: Proper Scoreboard replacement
- UI: Proper Team Selection replacement
- PostMatch: Implement Round Limit & Map Time Limit checking.
- PostMatch: Implement MapVoting? Or add support for MapVote addon?
- Seekers, Hiders: Taunts! And custom Taunts. And everything that belongs to that.
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 269 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

@@ -1,59 +0,0 @@
--[[
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)
GAMEMODE.Data.RoundStartTime = CurTime()
end
function StatePostRound:Tick()
-- Advance State
if (CurTime() - GAMEMODE.Data.RoundStartTime) >= 5 then -- ToDo: configureable time?
GAMEMODE.RoundManager:SetState(StatePostMatch)
end
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:KillSilent()
ply:SetTeam(GAMEMODE.Teams.Seekers)
end
for i, ply in ipairs(seekers) do
ply:KillSilent()
ply:SetTeam(GAMEMODE.Teams.Hiders)
end
-- TODO: Other Gamemodes
end
end
@@ -1,49 +0,0 @@
-- Finds the player meta table or terminates
local meta = FindMetaTable("Player")
if !meta then return end
-- Blinds the player by setting view out into the void
function meta:Blind(bool)
if !self:IsValid() then return end
if SERVER then
umsg.Start("SetBlind", self)
if bool then
umsg.Bool(true)
else
umsg.Bool(false)
end
umsg.End()
elseif CLIENT then
blind = bool
end
end
-- Blinds the player by setting view out into the void
function meta:RemoveProp()
if CLIENT || !self:IsValid() then return end
if self.ph_prop && self.ph_prop:IsValid() then
self.ph_prop:Remove()
self.ph_prop = nil
end
end
-- Sets a new Hull for a player.
function meta:NewHull(hullOBBMin, hullOBBMax)
if !self:IsValid() then return end
if hullOBBMax == nil then return end
if hullOBBMin == nil then return end
local hullOBB = hullOBBMax - hullOBBMin
local hullOBBXY = math.max(hullOBB.x, hullOBB.y)
local xyMul = 0.5
local hullMin = Vector(-hullOBBXY * xyMul, -hullOBBXY * xyMul, 0)
local hullMax = Vector( hullOBBXY * xyMul, hullOBBXY * xyMul, hullOBB.z)
self:SetHull(hullMin, hullMax)
self:SetHullDuck(hullMin, hullMax)
self:SetViewOffset(Vector(0, 0, hullOBB.z))
self:SetViewOffsetDucked(Vector(0, 0, hullOBB.z / 2.0))
end
Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

@@ -1,182 +0,0 @@
"prophuntextended"
{
"base" "base"
"title" "Prop Hunt Extended"
"maps" "^ph_|^cs_|^de_|^ttt_"
"menusystem" "1"
"workshopid" "468149739"
"settings"
{
// 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"
"help" "Time Limit in Minutes for how long should we stay on one map. (0 to disable)"
"type" "Numeric"
"default" "20"
}
3
{
"name" "ph_sprinting"
"text" "G: Enable Sprinting"
"help" "Should sprinting be possible?"
"type" "CheckBox"
"default" "0"
}
4
{
"name" "ph_tauntcooldown"
"text" "G: Taunt Cooldown"
"help" "How much time must pass before another taunt may be played."
"type" "Numeric"
"default" "5"
}
// Round Settings
10
{
"name" "ph_round_limit"
"text" "R: Rounds per Map"
"help" "How many rounds are played per map."
"type" "Numeric"
"default" "10"
}
11
{
"name" "ph_round_timelimit"
"text" "R: Round Duration (Seconds)"
"help" "How long is each round going to last?"
"type" "Numeric"
"default" "300"
}
12
{
"name" "ph_round_blindtime"
"text" "R: Hiding Time (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"
}
// Seeker Settings
20
{
"name" "ph_seeker_health"
"text" "S: Health"
"type" "Numeric"
"default" "100"
}
21
{
"name" "ph_seeker_health_max"
"text" "S: Max Health"
"type" "Numeric"
"default" "100"
}
22
{
"name" "ph_seeker_health_bonus"
"text" "S: Health Kill-Bonus"
"help" "Health gained on kill."
"type" "Numeric"
"default" "20"
}
23
{
"name" "ph_seeker_health_penalty"
"text" "S: Health Penalty"
"help" "Health lost on wrong shot."
"type" "Numeric"
"default" "5"
}
24
{
"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"
}
25
{
"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
30
{
"name" "ph_hider_health"
"text" "H: Health"
"type" "Numeric"
"default" "100"
}
31
{
"name" "ph_hider_health_max"
"text" "H: Max Health"
"type" "Numeric"
"default" "100"
}
32
{
"name" "ph_hider_health_scaling"
"text" "H: Enable Health Scaling"
"help" "Larger & heavier objects have more health, smaller less."
"type" "CheckBox"
"default" "1"
}
33
{
"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""
}
}
}
-7
View File
@@ -1,7 +0,0 @@
@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=C:\Program Files (x86)\Steam\steamapps\common\GarrysMod"
SET "PATH=%CD%;%GARRYSMODPATH%\bin;%PATH%"
CMD
-9
View File
@@ -1,9 +0,0 @@
@ECHO OFF
:: Fallback
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%\Source" -out "%CD%\Pack.gma"
PAUSE
-7
View File
@@ -1,7 +0,0 @@
@ECHO OFF
:: Fallback
SET "GARRYSMODPATH=C:\Program Files (x86)\Steam\steamapps\common\GarrysMod"
REM "%GARRYSMODPATH%\bin\gmpublish.exe" update -id 468149739
"%GARRYSMODPATH%\bin\gmpublish.exe" update -id 468149739 -icon "Logo.jpg" -addon "Pack.gma" -changes ""
PAUSE
+11
View File
@@ -0,0 +1,11 @@
@ECHO OFF
:: Garry's Mod
SET "GARRYSMODPATH=C:\Program Files (x86)\Steam\steamapps\common\GarrysMod"
FOR /F "tokens=2* delims= " %%A IN ('REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 4000" /v InstallLocation') DO SET "GARRYSMODPATH=%%B"
IF "%GARRYSMODPATH%" == "" (
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"
)
IF "%GARRYSMODPATH%" == "" (
ECHO Failed to figure out where Garry's Mod is installed.
)
+4
View File
@@ -0,0 +1,4 @@
@ECHO OFF
call env.win.bat
"%GARRYSMODPATH%\bin\gmpublish.exe" update -id 468149739 -icon "media\gamemode_workshop.jpg" -addon "pack.gma" -changes ""
PAUSE
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1003 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

+4
View File
@@ -0,0 +1,4 @@
@ECHO OFF
call env.win.bat
"%GARRYSMODPATH%\bin\gmad.exe" create -folder "%CD%\source" -out "%CD%\pack.gma"
PAUSE
+4
View File
@@ -0,0 +1,4 @@
@ECHO OFF
call env.win.bat
SET "PATH=%CD%;%GARRYSMODPATH%\bin;%PATH%"
CMD
Binary file not shown.

After

Width:  |  Height:  |  Size: 1003 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

@@ -23,7 +23,15 @@ function ENT:Think()
-- Angles
if (self.Owner:GetNWBool("PropRotation")) then
self:SetAngles(self.Owner:EyeAngles())
self:ApplyRotation(self.Owner:EyeAngles())
end
end
function ENT:ApplyRotation(ang)
if !(GAMEMODE.Config.Hider:AllowFullRotation()) then
ang.p = 0
ang.r = 0
end
self:SetAngles(ang)
end
@@ -24,15 +24,6 @@ LOSS_SOUNDS = {
"bot/where_are_they.wav",
"bot/where_are_you_hiding.wav"
}
if (! file.Exists("prop_hunt/sounds_loss.txt", "DATA")) then
file.Write("prop_hunt/sounds_loss.txt", util.TableToKeyValues(LOSS_SOUNDS))
end
local fileContent = file.Read("prop_hunt/sounds_loss.txt", "DATA");
if fileContent then
local fileTable = util.KeyValuesToTable(fileContent)
if fileTable then LOSS_SOUNDS = fileTable end
end
-- Sounds played by members of the winning team at the end of the round.
VICTORY_SOUNDS = {
"bot/and_thats_how_its_done.wav",
@@ -85,15 +76,6 @@ VICTORY_SOUNDS = {
"bot/yesss.wav",
"bot/yesss2.wav"
}
if (! file.Exists("prop_hunt/sounds_victory.txt", "DATA")) then
file.Write("prop_hunt/sounds_victory.txt", util.TableToKeyValues(VICTORY_SOUNDS))
end
local fileContent = file.Read("prop_hunt/sounds_victory.txt", "DATA");
if fileContent then
local fileTable = util.KeyValuesToTable(fileContent)
if fileTable then VICTORY_SOUNDS = fileTable end
end
-- Taunts played when Hunters hit their Spare1 binding.
HUNTER_TAUNTS = {
"bot/a_bunch_of_them.wav",
@@ -114,15 +96,6 @@ HUNTER_TAUNTS = {
"bot/target_spotted.wav",
"bot/you_heard_the_man_lets_go.wav"
}
if (! file.Exists("prop_hunt/sounds_taunt_hunter.txt", "DATA")) then
file.Write("prop_hunt/sounds_taunt_hunter.txt", util.TableToKeyValues(HUNTER_TAUNTS))
end
local fileContent = file.Read("prop_hunt/sounds_taunt_hunter.txt", "DATA");
if fileContent then
local fileTable = util.KeyValuesToTable(fileContent)
if fileTable then HUNTER_TAUNTS = fileTable end
end
-- Taunts played when Props hit their Spare1 binding.
PROP_TAUNTS = {
-- "ambient/alarms/apc_alarm_loop1.wav",
@@ -283,12 +256,4 @@ PROP_TAUNTS = {
"ambient/creatures/town_scared_sob1.wav",
"ambient/creatures/town_scared_sob2.wav",
"ambient/creatures/town_zombie_call1.wav"
}
if (! file.Exists("prop_hunt/sounds_taunt_prop.txt", "DATA")) then
file.Write("prop_hunt/sounds_taunt_prop.txt", util.TableToKeyValues(PROP_TAUNTS))
end
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
}
@@ -41,8 +41,8 @@ function GM:Initialize()
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: Creating Fonts...")
surface.CreateFont("RobotoBoldCondensed160", {font="Roboto Bold Condensed", extended=true, size=160, weight=800, antialias=true})
print("Prop Hunt CL: Complete.")
print("-------------------------------------------------------------------------")
@@ -51,7 +51,7 @@ end
function GM:Think() end
function GM:InitialPlayerSpawn()
print("Prop Hunt CL: InitialPlayerSpawn")
if GAMEMODE.Config:DebugLog() then print("Prop Hunt CL: InitialPlayerSpawn") end
-- Delay execution until LocalPlayer() is valid.
if (!LocalPlayer()) || (!IsValid(LocalPlayer())) then
@@ -59,13 +59,13 @@ function GM:InitialPlayerSpawn()
return
end
print("Prop Hunt CL: InitialPlayerSpawn Valid")
if GAMEMODE.Config:DebugLog() then print("Prop Hunt CL: InitialPlayerSpawn Valid") end
player_manager.RunClass(LocalPlayer(), "InitialClientSpawn")
end
function GM:PlayerSpawn()
print("Prop Hunt CL: PlayerSpawn")
if GAMEMODE.Config:DebugLog() then print("Prop Hunt CL: PlayerSpawn") end
-- Delay execution until LocalPlayer() is valid.
if (!LocalPlayer()) || (!IsValid(LocalPlayer())) then
@@ -73,7 +73,7 @@ function GM:PlayerSpawn()
return
end
print("Prop Hunt CL: PlayerSpawn Valid")
if GAMEMODE.Config:DebugLog() then print("Prop Hunt CL: PlayerSpawn Valid") end
if !(LocalPlayer().Data) then
LocalPlayer().Data = {}
@@ -106,8 +106,9 @@ function GM:PlayerSetViewOffset(vo, voduck)
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)
timer.Simple(.1, function()
GAMEMODE:PlayerSetViewOffset(GAMEMODE.TempData.ViewOffset, GAMEMODE.TempData.ViewOffsetDuck)
end)
return
end
@@ -126,8 +127,8 @@ function GM:PlayerSetHull(hullMin, hullMax)
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)
timer.Simple(.1, function()
GAMEMODE:PlayerSetHull(GAMEMODE.TempData.HullMin, GAMEMODE.TempData.HullMax) end)
return
end
@@ -146,20 +147,24 @@ function GM:OnContextMenuOpen()
end
function GM:OnContextMenuClose()
print("Prop Hunt CL: Toggled View Mode")
if GAMEMODE.Config:DebugLog() then print("Prop Hunt CL: Toggled View Mode") end
LocalPlayer().Data.ThirdPerson = !LocalPlayer().Data.ThirdPerson
end
function GM:OnSpawnMenuOpen()
print("Prop Hunt CL: Enabling Prop Rotation")
if GAMEMODE.Config:DebugLog() then print("Prop Hunt CL: Enabling Prop Rotation") end
LocalPlayer():SetNWBool("PropRotation", true)
net.Start("PlayerEnablePropRotation");net.SendToServer()
net.Start("PlayerEnablePropRotation")
net.WriteAngle(LocalPlayer():EyeAngles())
net.SendToServer()
end
function GM:OnSpawnMenuClose()
print("Prop Hunt CL: Disabling Prop Rotation")
if GAMEMODE.Config:DebugLog() then print("Prop Hunt CL: Disabling Prop Rotation") end
LocalPlayer():SetNWBool("PropRotation", false)
net.Start("PlayerDisablePropRotation");net.SendToServer()
net.Start("PlayerDisablePropRotation")
net.WriteAngle(LocalPlayer():EyeAngles())
net.SendToServer()
end
function GM:ShowHelpUI()
@@ -188,44 +193,91 @@ net.Receive( "PlayerViewOffset", function(len, pl)
end)
-- ------------------------------------------------------------------------- --
--! Old Code
--! Special Drawing
-- ------------------------------------------------------------------------- --
--[[
-- 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)
function DrawNamePlates(bDrawingDepth, bDrawingSkybox)
if (!GAMEMODE.Config.NamePlates:Show()) then
return
end
local scale = GAMEMODE.Config.NamePlates:Scale()
local pls = team.GetPlayers(GAMEMODE.Teams.Seekers)
if (LocalPlayer():Team() == GAMEMODE.Teams.Hiders) then
pls = table.Add(pls, team.GetPlayers(GAMEMODE.Teams.Hiders))
end
for i,v in ipairs(pls) do
if (v:Alive() && v != LocalPlayer()) then
if (player_manager.GetPlayerClass(v) != "Spectator") then
local color = HSVToColor(GAMEMODE.Config.NamePlates:TintHue(),
GAMEMODE.Config.NamePlates:TintSaturation(),
GAMEMODE.Config.NamePlates:TintValue())
if GAMEMODE.Config.NamePlates:TintHealth() then
local healthPrc = v:Health() / v:GetMaxHealth()
color = HSVToColor(120 * healthPrc, 1.0, 1.0)
elseif GAMEMODE.Config.NamePlates:TintTeam() then
color = team.GetColor(v:Team())
end
local pos = v:GetPos() + v:GetViewOffset() + Vector(0, 0, GAMEMODE.Config.NamePlates:Height())
local ang = Angle(0, LocalPlayer():EyeAngles().y - 90, 90 - LocalPlayer():EyeAngles().x)
cam.Start3D2D(pos, ang, scale)
draw.DrawText(v:GetName(), "RobotoBoldCondensed160", 0, -draw.GetFontHeight("RobotoBoldCondensed160") / 2, color, TEXT_ALIGN_CENTER)
cam.End3D2D()
end
end
end
end
end
hook.Add("PostDrawTranslucentRenderables", "PH_DrawPlayerNames", DrawPlayerNames)
hook.Add("PostDrawTranslucentRenderables", "PHDrawNamePlates", DrawNamePlates)
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)
function DrawSelectionHalo(bDrawingDepth, bDrawingSkybox)
if (!GAMEMODE.Config.SelectionHalo:Enabled()) then return end
local ent = nil
if (GAMEMODE.Config.SelectionHalo:Approximate()) then
local trace = {
start = LocalPlayer():EyePos(),
endpos = LocalPlayer():EyePos() + LocalPlayer():EyeAngles():Forward() * 80,
mins = Vector(-16, -16, -16),
maxs = Vector( 16, 16, 16),
mask = MASK_SOLID + CONTENTS_DEBRIS + CONTENTS_PLAYERCLIP,
filter = function(ent)
-- Ensure that we don't actually hit ourselves by accident, or our "hands" model.
if (!IsValid(ent)
|| (ent == LocalPlayer())
|| (ent == LocalPlayer():GetHands())) then
return false
end
if table.HasValue(GAMEMODE.Config.Lists:ClassWhitelist(), ent:GetClass()) then return true end
return false
end,
output = {}
}
util.TraceLine(trace)
if !IsValid(trace.output.Entity) then util.TraceHull(trace) end
if IsValid(trace.output.Entity) then
if (!table.HasValue(GAMEMODE.Config.Lists:ModelBlacklist(), trace.output.Entity:GetModel())) then
ent = trace.output.Entity
end
end
end
else
ent = LocalPlayer():GetNWEntity("SelectionHalo")
end
if IsValid(ent) then
local color = HSVToColor(
GAMEMODE.Config.SelectionHalo:TintHue(),
GAMEMODE.Config.SelectionHalo:TintSaturation(),
GAMEMODE.Config.SelectionHalo:TintValue()
)
halo.Add({ ent }, color,
GAMEMODE.Config.SelectionHalo:BlurX(), GAMEMODE.Config.SelectionHalo:BlurY(), GAMEMODE.Config.SelectionHalo:Passes(),
GAMEMODE.Config.SelectionHalo:Additive(), GAMEMODE.Config.SelectionHalo:IgnoreZ())
end
end
--hook.Add("PostDrawEffects", "PH_DrawPlayerHalos", DrawPlayerHalos)
hook.Add("PostDrawEffects", "PHDrawSelectionHalo", DrawSelectionHalo)
-- ------------------------------------------------------------------------- --
--! Old Code
-- ------------------------------------------------------------------------- --
--[[
]]
@@ -0,0 +1,82 @@
--[[
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.
--]]
local PANEL = vgui.Create("DFrame")
PANEL:SetSize(640, 480)
PANEL:SetTitle("Help")
PANEL:SetDraggable(true)
PANEL:SetVisible(false)
PANEL:SetDraggable(true)
PANEL:SetSizable(true)
PANEL:ShowCloseButton(true)
PANEL:SetDeleteOnClose(false)
function PANEL:Show()
--self:SetSize(ScrW(), ScrH())
self:Center()
self:SetVisible(true)
self:SetFocusTopLevel(true)
self:SlideDown(.5)
self:MakePopup()
end
function PANEL:Hide()
self:Close()
self:SetVisible(false)
end
function PANEL:Paint(w, h)
draw.RoundedBox(0, 0, 0, w, h, Color(0,0,0,240))
end
-- Sheets
local Element = vgui.Create("DPropertySheet", PANEL)
function Element:PAINT(w,h)
draw.RoundedBox(0, 0, 0, w, h, Color(0,0,0,240))
end
Element:Dock(FILL)
PANEL.Sheets = Element
PANEL.Sheet = {}
-- Basic Info
local Element = vgui.Create("DPanel", PANEL.Sheets)
function Element:Paint(w,h) end
PANEL.Sheets:AddSheet("The Gamemode", Element)
PANEL.Sheet.TheGamemode = Element
local Element = vgui.Create("DLabel", PANEL.Sheet.TheGamemode)
Element:Dock(TOP)
Element:SetMultiline(true)
Element:SetText([[
Prop Hunt Extended is a Gamemode based on the original Prop Hunt Gamemode. It changes many gameplay elements and features, adding the ability to easily integrate Taunt Packs, Configure Game parameters, rotate your prop and much more.
]])
-- Settings
PANEL.SettingsSheet = vgui.Create("DPanel", PANEL.Sheets)
PANEL.Sheets:AddSheet("Settings", PANEL.SettingsSheet)
GM.UI.Help = PANEL
@@ -22,6 +22,19 @@
SOFTWARE.
--]]
local PANEL = vgui.Create("DFrame")
PANEL:SetSize(400, 300)
PANEL:SetTitle("Select a Team")
PANEL:SetDraggable(true)
PANEL:SetVisible(false)
PANEL:SetDraggable(true)
PANEL:SetSizable(true)
PANEL:ShowCloseButton(true)
PANEL:SetDeleteOnClose(false)
TeamSelectionUI = {}
TeamSelectionUI.Frame = vgui.Create("DFrame")
TeamSelectionUI.Frame:SetPos(0, 0)
@@ -1,39 +1,30 @@
--[[
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
--[[
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.
--]]
local ELEMENT = {}
function ELEMENT:Paint()
end
vgui.Register("DMultilineLabel", ELEMENT, "Panel")
@@ -33,17 +33,30 @@ function CompatTauntPackLoader()
-- Run the old hook name.
hook.Run("ph_AddTaunts", nil)
-- Insert the taunts into the new structure.
for k,v in ipairs(GAMEMODE.Hunter_Taunts) do
-- ToDo: string.GetFileFromFilename is broken!
--pcall(GAMEMODE.Config.Taunts.Add("TauntPackLoader."..string.GetFileFromFilename(v), v, TEAM_SEEKERES, nil))
-- Insert the taunts into the new structure (cvar).
Taunts = {}
for i,t in ipairs(GAMEMODE.Prop_Taunts) do
ty = type(t)
if (ty == "string") then
Taunts[#Taunts+1] = t
elseif (ty == "table") then
Taunts[#Taunts+1] = t[1]
end
end
for k,v in ipairs(GAMEMODE.Prop_Taunts) do
--pcall(GAMEMODE.Config.Taunts.Add("TauntPackLoader."..string.GetFileFromFilename(v), v, TEAM_HIDERS, nil))
GAMEMODE.Config.Taunt.HidersCacheStatic = Taunts
Taunts = {}
for i,t in ipairs(GAMEMODE.Hunter_Taunts) do
ty = type(t)
if (ty == "string") then
Taunts[#Taunts+1] = t
elseif (ty == "table") then
Taunts[#Taunts+1] = t[1]
end
end
GAMEMODE.Config.Taunt.SeekersCacheStatic = Taunts
-- Clean up after ourselves
GAMEMODE.Prop_Taunts = nil
GAMEMODE.Hunter_Taunts = nil
end
hook.Add("OnPropHuntInitialized", "CompatTauntPackLoader", CompatTauntPackLoader)
hook.Add("Initialize", "CompatTauntPackLoader", CompatTauntPackLoader)
@@ -27,8 +27,8 @@
-- ------------------------------------------------------------------------- --
-- Shared
AddCSLuaFile("sh_init.lua")
AddCSLuaFile("meta/player.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")
@@ -46,7 +46,6 @@ AddCSLuaFile("client/cl_ui_teamselection.lua")
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"
@@ -63,7 +62,6 @@ function GM:Initialize()
print("Prop Hunt: Registering Networked Messages...")
util.AddNetworkString("PlayerManagerInitialClientSpawn")
util.AddNetworkString("PlayerManagerClientSpawn")
util.AddNetworkString("PlayerSetHull")
util.AddNetworkString("PlayerResetHull")
util.AddNetworkString("PlayerViewOffset")
@@ -73,10 +71,15 @@ function GM:Initialize()
print("Prop Hunt: Initializing Gamemode Data...")
self.Data = {}
self.Data.StartTime = CurTime()
print("Prop Hunt: Setting initial RoundManager State...")
self.RoundManager:SetState(StatePreMatch)
print("Prop Hunt: Precaching...")
GAMEMODE.Config.Taunt:Seekers()
GAMEMODE.Config.Taunt:Hiders()
print("Prop Hunt: Complete.")
print("-------------------------------------------------------------------------")
end
@@ -87,28 +90,29 @@ end
-- Player Connected
function GM:PlayerConnect(name, ip)
print("Prop Hunt: Player '"..name.."' connecting from IP '"..ip.."'.")
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Player '"..name.."' connecting from IP '"..ip.."'.") end
end
-- Player Authenticated
function GM:PlayerAuthed(ply, steamid, uniqueid)
print("Prop Hunt: Player '"..ply:GetName().."' (SteamID: "..ply:SteamID()..") authenticated.")
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Player '"..ply:GetName().."' (SteamID: "..ply:SteamID()..") authenticated.") end
end
-- Player Disconnected
function GM:PlayerDisconnected(ply)
print("Prop Hunt: Player '"..ply:GetName().."' (SteamID: "..ply:SteamID()..") disconnected.")
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Player '"..ply:GetName().."' (SteamID: "..ply:SteamID()..") disconnected.") end
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 GAMEMODE.Config:DebugLog() then print("Prop Hunt: Player '"..ply:GetName().."' (SteamID: "..ply:SteamID()..") spawned for the first time, applying defaults...") end
if (!ply.Data) then
-- Initialize Data Structure
ply.Data = {}
ply.Data.Alive = false
ply.Data.AliveTime = 0
ply.Data.RandomWeight = 0 -- Higher means higher chance of becoming Seeker instead of Hider.
end
-- Kill Silently
@@ -121,10 +125,10 @@ function GM:PlayerInitialSpawn(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.")
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Bot '"..ply:GetName().."' assigned to Seekers.") end
ply:SetTeam(self.Teams.Seekers)
else
print("Prop Hunt: Bot '"..ply:GetName().."' assigned to Hiders.")
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Bot '"..ply:GetName().."' assigned to Hiders.") end
ply:SetTeam(self.Teams.Hiders)
end
end
@@ -138,7 +142,7 @@ end
-- Player Spawn
function GM:PlayerSpawn(ply)
print("Prop Hunt: Player '"..ply:GetName().."' (SteamID: "..ply:SteamID()..") spawned in.")
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Player '"..ply:GetName().."' (SteamID: "..ply:SteamID()..") spawned in.") end
-- Player Manager: Assign Player Class
local class = team.GetClass(ply:Team())
@@ -167,7 +171,7 @@ 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 GAMEMODE.Config:DebugLog() then print("Prop Hunt: Player '"..ply:GetName().."' (SteamID: "..ply:SteamID()..") requested to join Team "..team.GetName(teamId)..".") end
if (ply:Team() != teamId) then
ply:KillSilent()
@@ -178,7 +182,7 @@ function GM:PlayerRequestTeam(ply, teamId)
ply.AliveTime = CurTime()
end
else
print("Prop Hunt: Player '"..ply:GetName().."' (SteamID: "..ply:SteamID()..") attempted to rejoin the Team it is already in.")
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Player '"..ply:GetName().."' (SteamID: "..ply:SteamID()..") attempted to rejoin the Team it is already in.") end
end
end
end
@@ -187,7 +191,38 @@ 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:PlayerDeath(ply, inflictor, attacker)
player_manager.RunClass(ply, "Death", inflictor, attacker)
-- Signal Client Stuff
if IsValid(attacker) then
if attacker:IsPlayer() then
if (attacker == ply) then
net.Start("PlayerKilledSelf")
net.WriteEntity(ply)
net.Broadcast()
else
net.Start("PlayerKilledByPlayer")
net.WriteEntity(ply)
net.WriteString(inflictor:GetName())
net.WriteEntity(attacker)
net.Broadcast()
end
else
net.Start("PlayerKilled")
net.WriteEntity(ply)
net.WriteString(inflictor:GetName())
net.WriteString(attacker:GetClass())
net.Broadcast()
end
else
net.Start("PlayerKilled")
net.WriteEntity(ply)
net.WriteString(inflictor:GetName())
net.WriteString("World")
net.Broadcast()
end
end
function GM:PlayerSilentDeath(ply) player_manager.RunClass(ply, "SilentDeath") end
function GM:PostPlayerDeath(ply)
player_manager.RunClass(ply, "PostDeath")
@@ -195,10 +230,10 @@ function GM:PostPlayerDeath(ply)
-- 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.")
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Debug Mode active, Player "..ply:GetName().." was respawned.") end
end
end
--function GM:DoPlayerDeath(ply, attacker, dmg) player_manager.RunClass(ply, "DoDeath", attacker, dmg) 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
@@ -207,7 +242,19 @@ function GM:PlayerUse(ply, ent) return player_manager.RunClass(ply, "Use", ent)
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
-- Damage
function GM:PlayerShouldTakeDamage(victim, attacker)
return player_manager.RunClass(victim, "ShouldTakeDamage", attacker)
end
function GM:PlayerHurt(victim, attacker, healthRemaining, damageTaken)
player_manager.RunClass(victim, "Hurt", victim, attacker, healthRemaining, damageTaken)
if (IsValid(attacker) && attacker:IsPlayer()) then
player_manager.RunClass(attacker, "Damage", victim, attacker, healthRemaining, damageTaken)
end
end
function GM:EntityTakeDamage(ent, dmg)
local att = dmg:GetAttacker()
@@ -219,6 +266,10 @@ end
-- ------------------------------------------------------------------------- --
--! Gamemode Functionality
-- ------------------------------------------------------------------------- --
function GM:SetRound(Round)
SetGlobalInt("Round", Round)
end
function GM:SetRoundState(State)
SetGlobalInt("RoundState", State)
end
@@ -241,6 +292,7 @@ function GM:PlayerHullFromEntity(ply, ent)
hull.x = hull.y
end
hull:Mul(0.5)
hull:Mul(0.95) -- Reduce size slightly
local hullmin = Vector(-hull.x, -hull.y, 0)
local hullmax = Vector(hull.x, hull.y, hull.z * 2)
@@ -289,153 +341,65 @@ function GM:ShowTeam(ply)
ply:ConCommand("ph_select_team")
end
-- F3/ShowSpare1
function GM:ShowSpare1(ply) end
-- F4/ShowSpare2
function GM:ShowSpare2(ply) end
function GM:ShowSpare1(ply) player_manager.RunClass(ply, "ShowSpare1") end -- F3/ShowSpare1
function GM:ShowSpare2(ply) player_manager.RunClass(ply, "ShowSpare2") end -- F4/ShowSpare2
-- 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))
if GAMEMODE.Config:DebugLog() then
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
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)
-- Debug Command: Print All Players
concommand.Add("ph_debug_stats", function(ply, cmd, args, argStr)
if GAMEMODE.Config:DebugLog() then
for i,ply in ipairs(player.GetAll()) do
print(ply:GetName().." (SteamID: "..ply:SteamID()..")")
print(" Team: "..team.GetName(ply:Team()))
print(" Alive: "..tostring(ply.Data.Alive))
print(" AliveTime: "..tostring(ply.Data.AliveTime))
print(" Score: "..tostring(ply.Data.RandomWeight))
end
end
end, nil, nil, FCVAR_CLIENTCMD_CAN_EXECUTE + FCVAR_CHEAT)
-- ------------------------------------------------------------------------- --
--! Network Messages
-- ------------------------------------------------------------------------- --
net.Receive("PlayerEnablePropRotation", function(len, ply)
if (ply:Team() != GAMEMODE.Teams.Hiders) then
return
end
print("Prop Hunt: Enabling Prop Rotation")
ply:SetNWBool("PropRotation", true)
ply.Data.Prop:ApplyRotation(net.ReadAngle())
end)
net.Receive("PlayerDisablePropRotation", function(len, ply)
if (ply:Team() != GAMEMODE.Teams.Hiders) then
return
end
print("Prop Hunt: Disabling Prop Rotation")
ply:SetNWBool("PropRotation", false)
end)
-- ------------------------------------------------------------------------- --
--! 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)
]]
ply.Data.Prop:ApplyRotation(net.ReadAngle())
end)
@@ -0,0 +1,259 @@
--[[
The MIT License (MIT)
Copyright (c) 2017 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.
--]]
-- Finds the player meta table or terminates
local meta = FindMetaTable("Player")
if !meta then print("FAILED TO FIND PLAYER META") return end
-- Blinds the player by setting view out into the void
function meta:Blind(bool)
if !self:IsValid() then return end
if SERVER then
umsg.Start("SetBlind", self)
if bool then
umsg.Bool(true)
else
umsg.Bool(false)
end
umsg.End()
elseif CLIENT then
blind = bool
end
end
-- Blinds the player by setting view out into the void
function meta:RemoveProp()
if CLIENT || !self:IsValid() then return end
if self.ph_prop && self.ph_prop:IsValid() then
self.ph_prop:Remove()
self.ph_prop = nil
end
end
-- Sets a new Hull for a player.
function meta:NewHull(hullOBBMin, hullOBBMax)
if !self:IsValid() then return end
if hullOBBMax == nil then return end
if hullOBBMin == nil then return end
local hullOBB = hullOBBMax - hullOBBMin
local hullOBBXY = math.max(hullOBB.x, hullOBB.y)
local xyMul = 0.5
local hullMin = Vector(-hullOBBXY * xyMul, -hullOBBXY * xyMul, 0)
local hullMax = Vector( hullOBBXY * xyMul, hullOBBXY * xyMul, hullOBB.z)
self:SetHull(hullMin, hullMax)
self:SetHullDuck(hullMin, hullMax)
self:SetViewOffset(Vector(0, 0, hullOBB.z))
self:SetViewOffsetDucked(Vector(0, 0, hullOBB.z / 2.0))
end
-- Can the passed entity be used by the player?
function testflag(set, flag)
if (flag == 0) then return true end -- Mod(%) by 0 is nan.
return (set % (2 * flag)) >= flag
end
function meta:IsUseableEntity(ent, requiredCaps)
if ((ent != nil) && (ent:IsValid())) then
local caps = ent:ObjectCaps()
local capsmask = 16 + 32 + 64 + 128
if (testflag(caps, 16)
|| testflag(caps, 32)
|| testflag(caps, 64)
|| testflag(caps, 128)
) && testflag(caps, requiredCaps) then
return true
end
end
return false
end
function IntervalDistance(x, x0, x1)
-- swap so x0 < x1
if ( x0 > x1 ) then
local tmp = x0
x0 = x1
x1 = tmp
end
if ( x < x0 ) then
return x0-x
elseif ( x > x1 ) then
return x - x1
end
return 0
end
-- Find useable entity (Lua version of CBasePlayer:FindUseEntity)
function meta:FindUseEntity()
-- https://raw.githubusercontent.com/ValveSoftware/source-sdk-2013/0d8dceea4310fde5706b3ce1c70609d72a38efdf/mp/src/game/shared/baseplayer_shared.cpp
local PLAYER_USE_RADIUS = 80
-- Vectors
local forward = self:EyeAngles():Forward()
local up = self:EyeAngles():Up()
local center = self:EyePos()
local trace = {
start = center,
endpos = center,
mins = Vector(-16, -16, -16),
maxs = Vector( 16, 16, 16),
mask = MASK_SOLID + CONTENTS_DEBRIS + CONTENTS_PLAYERCLIP,
filter = function(ent)
if (ent == self) then return false end
if (!ent:IsValid()) then return false end
if (ent:IsPlayer()) then return false end
if (ent == self:GetHands()) then return false end
return true
end,
output = {}
}
local foundEnt = nil
local nearestDist = 16777216
local nearestEnt = nil
local tangents_num = 8
local tangents = {}
tangents[1] = 0
tangents[2] = 1
tangents[3] = 0.57735026919
tangents[4] = 0.3639702342
tangents[5] = 0.267949192431
tangents[6] = 0.1763269807
tangents[7] = -0.1763269807
tangents[8] = -0.267949192431
for idx=1,tangents_num,1 do
if (idx == 1) then
trace.endpos = center + forward * 1024
util.TraceLine(trace)
else
local down = forward - (Vector(tangents[idx], tangents[idx], tangents[idx]) * up)
down:Normalize()
trace.endpos = center + down * 72
util.TraceHull(trace)
end
foundEnt = trace.output.Entity
local useable = self:IsUseableEntity(foundEnt, 0)
while ((foundEnt:IsValid()) && !useable && (foundEnt:GetMoveParent():IsValid())) do
foundEnt = foundEnt:GetMoveParent()
useable = self:IsUseableEntity(foundEnt, 0)
end
if (useable) then
local delta = trace.output.HitPos - trace.output.StartPos
local centerZ = foundEnt:WorldSpaceCenter().z
delta.z = IntervalDistance(trace.output.HitPos.z, centerZ + foundEnt:OBBMins().z, centerZ + foundEnt:OBBMaxs().z)
local dist = delta:Length()
if (dist < PLAYER_USE_RADIUS) then
if (foundEnt:IsNPC() && (foundEnt:Team() == self:Team())) then
foundEnt = self:DoubleCheckUseNPC(foundEnt, center, forward)
end
--if (dist < nearestDist) then -- Not identical to CBasePlayer
--nearestDist = dist
nearestEnt = foundEnt
--end
if (idx == 1) then return foundEnt end
end
end
end
-- check ground entity first
-- if you've got a useable ground entity, then shrink the cone of this search to 45 degrees
-- otherwise, search out in a 90 degree cone (hemisphere)
if (self:GetGroundEntity():IsValid() && self:IsUseableEntity(self:GetGroundEntity(), 256)) then
nearestEnt = self:GetGroundEntity()
end
if (nearestEnt) then
local point = self:NearestPoint(center)
nearestDist = util.DistanceToLine(point, center, forward)
end
local search = ents.FindInSphere(center, PLAYER_USE_RADIUS)
for k,v in ipairs(search) do
if (v) && (v:IsValid()) && (self:IsUseableEntity(v, 512)) then
local point = v:NearestPoint(center)
local dir = (point - center):GetNormalized()
local dot = dir:Dot(forward)
if (dot >= 0.8) then
local dist = util.DistanceToLine(point, center, forward)
if (dist < nearestDist) then
trace.endpos = point
util.TraceLine(trace)
if ((trace.output.Fraction == 1.0) || (trace.output.Entity == v)) then
nearestEnt = v
nearestDist = dist
end
end
end
end
end
if (!nearestEnt) then
trace.endpos = center + forward * PLAYER_USE_RADIUS
trace.mask = MASK_OPAQUE_AND_NPCS
util.TraceLine(trace)
if (trace.output.Entity
&& trace.output.Entity:IsValid()
&& self:IsUseableEntity(trace.output.Entity, 0)
&& trace.output.Entity:IsNPC()
&& (trace.output.Entity:Team() == self:Team())) then
nearestEnt = trace.output.Entity
end
end
if (foundEnt:IsNPC() && (foundEnt:Team() == self:Team())) then
foundEnt = self:DoubleCheckUseNPC(foundEnt, center, forward)
end
return nearestEnt
end
-- Double Check NPC
-- Perhaps a poorly-named function. This function traces against the supplied
-- NPC's hitboxes (instead of hull). If the trace hits a different NPC, the
-- new NPC is selected. Otherwise, the supplied NPC is determined to be the
-- one the citizen wants. This function allows the selection of a citizen over
-- another citizen's shoulder, which is impossible without tracing against
-- hitboxes instead of the hull (sjb)
function meta:DoubleCheckUseNPC(npc, src, dir)
local trace = {
start = src,
endpos = src + dir * 1024,
mask = MASK_SHOT,
result = {}
}
util.TraceLine(trace)
if ((trace.result.Entity != nil) && (trace.result.Entity:IsValid()) && (trace.result.Entity:IsNPC()) && (trace.result.Entity != npc)) then
-- Player is selecting a different NPC through some negative space
-- in the first NPC's hitboxes (between legs, over shoulder, etc).
return trace.result.Entity
end
return npc
end
@@ -44,11 +44,15 @@ CLASS.UseVMHands = true -- Uses viewmodel hands
--! Server-Side
-- ------------------------------------------------------------------------- --
-- Spawn
function CLASS:InitialSpawn() end
function CLASS:InitialSpawn()
self.Player.Data = {}
self.Player.Data.SelectionHaloTime = CurTime()
end
function CLASS:Spawn() end
function CLASS:Loadout() end
-- Damage
function CLASS:ShouldTakeDamage(attacker) return true end -- Should take damage from attacker?
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
@@ -63,9 +67,7 @@ function CLASS:SilentDeath()
self.Player.Data.AliveTime = CurTime()
end
function CLASS:PostDeath() end
function CLASS:DoDeath() end
function CLASS:DeathThink()
if (CurTime() - self.Player.Data.AliveTime) > 5 then
self.Player:Spawn()
@@ -73,7 +75,6 @@ function CLASS:DeathThink()
end
return false
end
function CLASS:CanSuicide() return true end
-- Visible Stuff
@@ -109,11 +110,22 @@ function CLASS:AllowPickup(ent) return false end
function CLASS:CanPickupWeapon(ent) return false end
function CLASS:CanPickupItem(ent) return false end
-- Menu (Always Server)
function CLASS:ShowSpare1()
local lastTaunt = (self.Player.Data.LastTaunt or 0)
if ((CurTime() - lastTaunt) <= GAMEMODE.Config.Taunt:Cooldown()) then
return true
end
self.Player.Data.LastTaunt = CurTime()
end
function CLASS:ShowSpare2() end
-- ------------------------------------------------------------------------- --
--! Shared
-- ------------------------------------------------------------------------- --
function CLASS:PostThink() end
function CLASS:Tick(mv) end
function CLASS:FindUseEntity(defEnt) return defEnt end
-- ------------------------------------------------------------------------- --
--! Client-Side
@@ -130,72 +142,52 @@ function CLASS:GetHandsModel() return BaseClass.GetHandsModel(self) end
function CLASS:ShouldDrawLocal() return false end
function CLASS:HUDPaint()
local State = GetGlobalInt("RoundState", GAMEMODE.States.PreMatch)
if State == -1 then
return
end
-- Show Status at the top center
local statusX, statusY, statusW, statusH
statusW = 192
statusH = 64
statusX = ScrW() / 2 - statusW / 2
statusY = 16
-- Status Box at the top.
local statusW, statusH = 256,48
local statusX, statusY = ScrW() / 2 - statusW / 2, 0
draw.RoundedBox(0, statusX, statusY, statusW, statusH, Color(0,0,0,204)) -- Background
draw.RoundedBox(0, statusX, statusY+statusH, statusW, 4, team.GetColor(LocalPlayer():Team())) -- Team Bar
-- Status
if (State == GAMEMODE.States.PreMatch) then -- Pre Match
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 for Players")
surface.SetTextPos( statusX + statusW/2 - w / 2, statusY + statusH/2 - h / 2)
surface.DrawText("Waiting for Players")
elseif (State == GAMEMODE.States.PreRound) then -- Pre Round
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..." )
-- Title
surface.SetFont("Trebuchet18")
surface.SetTextColor(Color(255,255,255,255))
local titleText = ""
if (State == GAMEMODE.States.PreMatch) then
titleText = "Waiting for Players"
elseif (State == GAMEMODE.States.PreRound) then
titleText = "Preparing Round..."
elseif (State == GAMEMODE.States.Hide) then -- Hide
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!")
titleText = "Seekers unblinded in:"
elseif (State == GAMEMODE.States.Seek) then -- Seek
titleText = "Seek Time!"
elseif (State == GAMEMODE.States.PostRound) then -- Post Round
titleText = "Match Result:"
elseif (State == GAMEMODE.States.PostMatch) then -- Post Match
end
local w,h = surface.GetTextSize(titleText)
surface.SetTextPos(statusX + statusW/2 - w/2, statusY)
surface.DrawText(titleText)
-- Subtitle
local stateText = ""
surface.SetFont("Trebuchet24")
surface.SetTextColor(Color(255,255,255,255))
if (State == GAMEMODE.States.PreMatch) then
stateText = tostring(team.NumPlayers(GAMEMODE.Teams.Seekers)) .. " Seeker(s), " .. tostring(team.NumPlayers(GAMEMODE.Teams.Hiders)) .. " Hider(s)"
elseif (State == GAMEMODE.States.PreRound) then
stateText = "Initiating..."
elseif (State == GAMEMODE.States.Hide) -- Hide
|| (State == GAMEMODE.States.Seek) then -- Seek
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)
stateText = strTime
elseif (State == GAMEMODE.States.PostRound) then -- Post Round
-- 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("Match Result")
surface.SetTextPos(statusX + statusW/2 - w / 2, statusY + statusH/4 - h / 2)
surface.DrawText("Match Result")
local victor = GAMEMODE:GetRoundWinner()
local victorName = "Unknown"
local victorName = "Draw"
if (victor == GAMEMODE.Teams.Spectator) then
victorName = "Draw"
elseif (victor == GAMEMODE.Teams.Hiders) then
@@ -203,17 +195,69 @@ function CLASS:HUDPaint()
elseif (victor == GAMEMODE.Teams.Seekers) then
victorName = "Seekers Win"
end
stateText = victorName
surface.SetTextColor(team.GetColor(victor))
surface.SetFont( "Trebuchet24" )
local w,h = surface.GetTextSize(victorName)
surface.SetTextPos( statusX + statusW/2 - w / 2, statusY + statusH/1.5 - h / 2)
surface.DrawText(victorName)
elseif (State == GAMEMODE.States.PostMatch) then -- Post Match
end
local w,h = surface.GetTextSize(stateText)
surface.SetTextPos(statusX + statusW/2 - w/2, statusY + 32 - h / 2)
surface.DrawText(stateText)
-- Death Notices
GAMEMODE:DrawDeathNotice((ScrW() - 192) / ScrW() , 24 / ScrH())
end
function CLASS:CalcView(camdata)
-- Config
local cameraCollision = GAMEMODE.Config.Camera:Collisions()
local cameraDistance = GAMEMODE.Config.Camera:Distance()
local cameraDistanceRight = GAMEMODE.Config.Camera:DistanceRight()
local cameraDistanceUp = GAMEMODE.Config.Camera:DistanceUp()
local cameraLag = GAMEMODE.Config.Camera:Lag()
local cameraLagInv = 1 - cameraLag
-- First/Third Person Target Distance
local targetDistance = 0
if (self.Player.Data.ThirdPerson) then -- Incremental Distance instead of instant.
targetDistance = cameraDistance
if (cameraCollision == true) then
-- Trace from Player to would-be camera position
local trace = {
start = camdata.origin,
endpos = camdata.origin - (camdata.angles:Forward() * cameraDistance),
--filter = { "worldspawn", "ph_prop", "player" },
--[-[
filter = function(ent)
local filter = { "worldspawn", "ph_prop", "player" }
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?
targetDistance = math.Clamp(result.HitPos:Distance(camdata.origin), 0, cameraDistance)
end
end
else
targetDistance = 0
end
-- Fade between Target and Current Distance
self.Player.Data.ViewDistance = math.Clamp(((self.Player.Data.ViewDistance or targetDistance) * cameraLag) + (targetDistance * cameraLagInv), 0, GAMEMODE.Config.Camera:DistanceMax())
-- Adjust CamData and return
camdata.origin = camdata.origin - (camdata.angles:Forward() * math.Clamp(self.Player.Data.ViewDistance - 10, 0, self.Player.Data.ViewDistance)) + (camdata.angles:Right() * cameraDistanceRight) + (camdata.angles:Up() * cameraDistanceUp)
return camdata
end
function CLASS:CalcView(camdata) return camdata end
-- ------------------------------------------------------------------------- --
--! Register
@@ -35,26 +35,31 @@ CLASS.UseVMHands = false -- Uses viewmodel hands
-- ------------------------------------------------------------------------- --
-- Spawn
function CLASS:Spawn()
print("Prop Hunt: Hider '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") spawned.")
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Hider '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") spawned.") end
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))
-- Speed and Jump Power
self.Player:SetWalkSpeed(GAMEMODE.Config.Hider:WalkSpeed())
if (GAMEMODE.Config.Hider:Sprint()) then
self.Player:SetRunSpeed(GAMEMODE.Config.Hider:SprintSpeed())
else
self.Player:SetRunSpeed(GAMEMODE.Config.Hider:WalkSpeed())
end
self.Player:SetJumpPower(GAMEMODE.Config.Hider:JumpPower())
-- 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)
self.Player:SetSolid(SOLID_VPHYSICS)
-- Prop Stuff
self.Player.Data.Prop = ents.Create("ph_prop")
@@ -70,7 +75,7 @@ end
-- Death
function CLASS:PostDeath(attacker, dmginfo)
print("Prop Hunt: Hider '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") died.")
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Hider '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") died.") end
BaseClass.PostDeath(self, inflictor, attacker)
-- Delete Hands Model
@@ -120,11 +125,11 @@ function CLASS:Use(ent)
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
if (!table.HasValue(GAMEMODE.Config.Lists:ClassWhitelist(), ent:GetClass())) -- Class is not Whitelisted
|| (table.HasValue(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()..").")
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Hider '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") attempted to turn into "..ent:GetClass().." ("..ent:GetModel()..").") end
return true -- Use instead of erroring.
end
@@ -155,84 +160,76 @@ function CLASS:Use(ent)
self.Player:SetMaxHealth(maxhealth)
end
print("Prop Hunt: Hider '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") turned into "..ent:GetClass().." ("..ent:GetModel()..").")
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Hider '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") turned into "..ent:GetClass().." ("..ent:GetModel()..").") end
end
function CLASS:AllowPickup(ent) return true end
-- Menu Buttons
function CLASS:ShowSpare1()
if BaseClass.ShowSpare1(self) then return end
-- Play a taunt
local tauntList = GAMEMODE.Config.Taunt:Hiders()
local index = math.random(#tauntList)
self.Player:EmitSound(tauntList[index], SNDLVL_NORM, 100, 1, CHAN_VOICE)
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Hider '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") taunted with sound '"..tauntList[index].."'.") end
end
-- ------------------------------------------------------------------------- --
--! Shared
-- ------------------------------------------------------------------------- --
if SERVER then
function CLASS:FindUseEntity(defEnt)
return self.Player:FindUseEntity()
end
function CLASS:Tick(mv)
if (self.Player.Data == nil) then return end
-- Selection Halo
if (GAMEMODE.Config.SelectionHalo:Allow()) && (!GAMEMODE.Config.SelectionHalo:Approximate()) then
if (self.Player.Data.SelectionHaloTime == nil) then
self.Player.Data.SelectionHaloTime = CurTime()
elseif ((CurTime() - self.Player.Data.SelectionHaloTime) > GAMEMODE.Config.SelectionHalo:Interval()) then
self.Player.Data.SelectionHaloTime = CurTime()
local ent = self.Player:FindUseEntity()
if (IsValid(ent)
&& table.HasValue(GAMEMODE.Config.Lists:ClassWhitelist(), ent:GetClass())
&& !table.HasValue(GAMEMODE.Config.Lists:ModelBlacklist(), ent:GetModel())) then
self.Player:SetNWEntity("SelectionHalo", ent)
else
self.Player:SetNWBool("SelectionHalo", false)
end
end
end
end
end
-- ------------------------------------------------------------------------- --
--! Client-Side
-- ------------------------------------------------------------------------- --
function CLASS:ClientSpawn()
print("Prop Hunt CL: Hider '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") spawned.")
if GAMEMODE.Config:DebugLog() then print("Prop Hunt CL: Hider '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") spawned.") end
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 (self.Player.Data.ViewDistance or 0) >= 10 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.95 + maxViewDist * 0.05, 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.95, 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
return (self.Player.Data.ViewDistance or 0) >= 10
end
-- Register
@@ -44,20 +44,24 @@ CLASS.DropWeaponOnDie = true
-- ------------------------------------------------------------------------- --
-- Spawn
function CLASS:Spawn()
print("Prop Hunt: Seeker '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") spawned.")
if (GAMEMODE.Config:DebugLog()) then print("Prop Hunt: Seeker '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") spawned.") end
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))
-- Speed and Jump Power
self.Player:SetWalkSpeed(GAMEMODE.Config.Seeker:WalkSpeed())
if (GAMEMODE.Config.Seeker:Sprint()) then
self.Player:SetRunSpeed(GAMEMODE.Config.Seeker:SprintSpeed())
else
self.Player:SetRunSpeed(GAMEMODE.Config.Seeker:WalkSpeed())
end
self.Player:SetJumpPower(GAMEMODE.Config.Seeker:JumpPower())
-- Hull & View Offset
GAMEMODE:PlayerHullFromEntity(self.Player, nil)
GAMEMODE:PlayerSetViewOffset(self.Player, Vector(0,0,64), Vector(0,0,32))
@@ -85,19 +89,58 @@ function CLASS:Loadout()
end
-- Damage
function CLASS:Damage(victim, attacker, healthRemaining, damageDealt) end
function CLASS:ShouldTakeDamage(attacker)
if (IsValid(attacker)) then
if (attacker:IsPlayer()) then
if (attacker:Team() == self.Player:Team()) then
local ffmode = GetConVarNumber("mp_friendlyfire")
if (ffmode == 0) then -- Not Allowed
return false
end
end
end
end
return true
end
function CLASS:Damage(victim, attacker, healthRemaining, damageDealt)
if ((victim != attacker) && victim:IsPlayer() && attacker:IsPlayer() && (attacker:Team() == victim:Team())) then
if (GAMEMODE.Config:DebugLog()) then
print("Prop Hunt: Seeker '"..attacker:GetName().."' (SteamID: "..attacker:SteamID()..") damaged seeker '"..victim:GetName().."' (SteamID: "..victim:SteamID()..") with "..damageDealt.." damage.")
end
end
end
function CLASS:Hurt(victim, attacker, healthRemaining, damageTaken)
if ((victim != attacker) && victim:IsPlayer() && attacker:IsPlayer() && (attacker:Team() == victim:Team())) then
if (GAMEMODE.Config:DebugLog()) then
print("Prop Hunt: Seeker '"..victim:GetName().."' (SteamID: "..victim:SteamID()..") was hurt by seeker '"..attacker:GetName().."' (SteamID: "..attacker:SteamID()..") with "..damageTaken.." damage.")
end
if (GetConVarNumber("mp_friendlyfire") == 2) then
victim:SetHealth(healthRemaining + damageTaken)
attacker:TakeDamage(damageTaken, attacker, attacker)
print("Prop Hunt: Seeker '"..victim:GetName().."' (SteamID: "..victim:SteamID()..") reflected "..damageTaken.." to seeker '"..attacker:GetName().."' (SteamID: "..attacker:SteamID()..").")
end
end
end
function CLASS:DamageEntity(ent, att, dmg)
print("Prop Hunt: Seeker '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") damaged entity "..ent:GetClass()..".")
if (GAMEMODE.Config:DebugLog()) then print("Prop Hunt: Seeker '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") damaged entity "..ent:GetClass()..".") end
if (GAMEMODE:GetRoundState() != GAMEMODE.States.Seek) then return end
if (!IsValid(ent) || !IsValid(att)) then return end
if (att == ent) then return end
-- 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
if IsValid(ent) && (!(ent:IsPlayer())) then
if (ent:GetClass() == "ph_prop") then
ent:GetOwner():TakeDamageInfo(dmg)
self.Player.Data.RandomWeight = self.Player.Data.RandomWeight - 1
elseif (ent:GetClass() == "func_breakable") then
elseif (ent:GetClass() == "prop_ragdoll") then
else
att:TakeDamage(GAMEMODE.Config.Seeker:HealthPenalty(), ent, ent)
end
end
end
@@ -106,11 +149,14 @@ end
function CLASS:Death(inflictor, attacker)
BaseClass.Death(self, inflictor, attacker)
self.Player:CreateRagdoll()
if SERVER then
self.Player:SetShouldServerRagdoll(true)
--self.Player:CreateRagdoll()
end
end
function CLASS:PostDeath()
print("Prop Hunt: Seeker '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") died.")
if (GAMEMODE.Config:DebugLog()) then print("Prop Hunt: Seeker '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") died.") end
BaseClass.PostDeath(self, inflictor, attacker)
self.Player:UnLock()
@@ -148,11 +194,22 @@ function CLASS:AllowPickup(ent) return true end
function CLASS:CanPickupItem(ent) return true end
function CLASS:CanPickupWeapon(ent) return true end
-- Menu Buttons
function CLASS:ShowSpare1()
if BaseClass.ShowSpare1(self) then return end
-- Play a taunt
local tauntList = GAMEMODE.Config.Taunt:Seekers()
local index = math.random(#tauntList)
self.Player:EmitSound(tauntList[index], SNDLVL_NORM, 100, 1, CHAN_VOICE)
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Seeker '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") taunted with sound '"..tauntList[index].."'.") end
end
-- ------------------------------------------------------------------------- --
--! Client-Side
-- ------------------------------------------------------------------------- --
function CLASS:ClientSpawn()
print("Prop Hunt CL: Seeker '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") spawned.")
if (GAMEMODE.Config:DebugLog()) then print("Prop Hunt CL: Seeker '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") spawned.") end
BaseClass.ClientSpawn(self)
end
@@ -181,53 +238,7 @@ function CLASS:HUDPaint()
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.95 + maxViewDist * 0.05, 0, maxViewDist) -- Zoom Out
else
viewDist = math.Clamp(viewDist * 0.95, 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
return (self.Player.Data.ViewDistance or 0) >= 10
end
-- Register
@@ -35,7 +35,7 @@ CLASS.UseVMHands = false -- Uses viewmodel hands
-- ------------------------------------------------------------------------- --
-- Spawn
function CLASS:Spawn()
print("Prop Hunt: Spectator '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") spawned.")
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Spectator '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") spawned.") end
BaseClass.Spawn(self)
self.Player:Spectate(OBS_MODE_ROAMING)
@@ -48,7 +48,7 @@ end
-- Death
function CLASS:PostDeath(inflictor, attacker)
print("Prop Hunt: Spectator '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") died.")
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Spectator '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") died.") end
BaseClass.PostDeath(self, inflictor, attacker)
self.Player:Spectate(OBS_MODE_NONE)
@@ -77,9 +77,10 @@ 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.")
if GAMEMODE.Config:DebugLog() then print("Prop Hunt CL: Spectator '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") spawned.") end
end
function CLASS:ShouldDrawLocal() return false end
function CLASS:CalcView(camdata) return camdata end
player_manager.RegisterClass( "Spectator", CLASS, "Default")
@@ -25,7 +25,7 @@
StateHide = {}
function StateHide:OnEnter(OldState)
if GAMEMODE.Config:Debug() then print("StateHide: OnEnter") end
if GAMEMODE.Config:DebugLog() then print("StateHide: OnEnter") end
GAMEMODE:SetRoundState(GAMEMODE.States.Hide)
-- Round Data
@@ -59,4 +59,7 @@ end
function StateHide:OnLeave(NewState)
if GAMEMODE.Config:Debug() then print("StateHide: OnLeave") end
-- Fretta Hooks
hook.Run("PropHuntUnblind")
end
@@ -22,40 +22,33 @@
SOFTWARE.
--]]
local PANEL = vgui.Create("DFrame")
PANEL:SetSize(400, 300)
PANEL:SetTitle("Help")
PANEL:SetDraggable(true)
PANEL:SetVisible(false)
PANEL:SetDraggable(true)
PANEL:SetSizable(true)
PANEL:ShowCloseButton(true)
PANEL:SetDeleteOnClose(false)
StatePostMatch = {}
function PANEL:Init()
DFrame.Init(self)
function StatePostMatch:OnEnter(OldState)
if GAMEMODE.Config:DebugLog() then print("StatePostMatch: OnEnter") end
GAMEMODE:SetRoundState(GAMEMODE.States.PostMatch)
-- Sheets
self.Sheets = vgui.Create("DPropertySheet", self)
self.Sheets:Dock(FILL)
self.NextState = StatePreMatch
-- Basic Info
self.BasicInfoSheet = vgui.Create("DPanel", self.Sheets)
function self.BasicInfoSheet:Paint(w, h)
draw.RoundedBox(4, 0, 0, 100, 100, Color(0,128,255))
-- Check Change map conditions.
if ((GAMEMODE.Config:TimeLimit() > 0) && ((CurTime() - GAMEMODE.Data.StartTime) >= (GAMEMODE.Config:TimeLimit() * 60))) -- Over Time
|| (GAMEMODE:GetRound() >= GAMEMODE.Config.Round:Limit()) -- Over Round Limit
then
-- Advance to nothing
GAMEMODE:SetRoundState(-1)
self.NextState = nil
-- MapVote
if (MapVote != nil) then MapVote.Start(30, true, 30, "ph_") return end
end
self.Sheets:AddSheet("The Gamemode", self.BasicInfoSheet)
end
function PANEL:Show()
self:SetSize(ScrW(), ScrH())
self:Center()
self:SetVisible(true)
self:SetFocusTopLevel(true)
self:SlideDown(.5)
self:MakePopup()
function StatePostMatch:Tick()
-- Advance State
GAMEMODE.RoundManager:SetState(self.NextState)
end
GAMEMODE.UI.Help = PANEL
function StatePostMatch:OnLeave(NewState)
if GAMEMODE.Config:DebugLog() then print("StatePostMatch: OnLeave") end
end
@@ -0,0 +1,142 @@
--[[
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:DebugLog() then print("StatePostRound: OnEnter") end
GAMEMODE:SetRoundState(GAMEMODE.States.PostRound)
GAMEMODE.Data.RoundStartTime = CurTime()
-- Fretta Hooks
hook.Run("RoundEnd")
end
function StatePostRound:Tick()
-- Advance State
if (CurTime() - GAMEMODE.Data.RoundStartTime) >= 5 then -- ToDo: configureable time?
GAMEMODE.RoundManager:SetState(StatePostMatch)
local players = team.GetPlayers(GAMEMODE.Teams.Seekers)
table.Add(players, team.GetPlayers(GAMEMODE.Teams.Hiders))
-- Assign end of round weighted points.
local aliveSeekers = 0
local aliveHiders = 0
for i,ply in ipairs(players) do
if ply:Alive() then
if (ply:Team() == GAMEMODE.Teams.Hiders) then
aliveHiders = aliveHiders + 1
elseif (ply:Team() == GAMEMODE.Teams.Seekers) then
aliveSeekers = aliveSeekers + 1
end
end
end
for i,ply in ipairs(players) do
local score = 0
if (ply:Team() == GAMEMODE:GetRoundWinner()) then
if (ply:Alive()) then
score = 2
else
score = 1
end
if (ply:Team() == GAMEMODE.Teams.Hiders) then
score = score * aliveHiders
elseif (ply:Team() == GAMEMODE.Teams.Seekers) then
score = -1 * score * aliveSeekers
end
end
ply.Data.RandomWeight = ply.Data.RandomWeight + score
end
-- Team Distribution
if (GAMEMODE.Config.Teams:Weighted() == true) then
-- Weighted Teams
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Randomizing Teams using weighted Score.") end
-- table.sort function returns true if it should a should be before b.
table.sort(players, function(a, b)
if (a.Data.RandomWeight == b.Data.RandomWeight) then
return math.random(100) > 50
else
return a.Data.RandomWeight > b.Data.RandomWeight
end
end)
elseif (GAMEMODE.Config.Teams:Randomize() == true) then
-- Randomize Teams
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Randomizing Teams.") end
table.sort(players, function(a,b)
return math.random(100) > 50
end)
else
-- Swap Teams
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Swapping Teams.") end
table.sort(players, function(a,b)
return math.random(100) > 50
end)
table.sort(players, function(a,b)
if (b:Team() == GAMEMODE.Teams.Seekers) then
return (a:Team() == GAMEMODE.Teams.Hiders)
end
return false
end)
end
-- Team Distribution Logic
local hiders, seekers = {}, {}
if (GAMEMODE.Config:GameType() == GAMEMODE.Types.Original) then
-- Game Mode: Basic
local plyCount, finalPlyCount = #players, math.max(math.ceil(#players / 2), 1)
for c = 1,finalPlyCount do
seekers[c] = table.remove(players, 1)
end
hiders = players
elseif (GAMEMODE.Config:GameType() == GAMEMODE.Types.TheDeadHunt) then
-- Game Mode: The Dead Hunt
local plyCount, finalPlyCount = #players, math.max(math.ceil(#players * GAMEMODE.Config.Teams:SeekerPercentage()), 1)
for c = 1,finalPlyCount do
seekers[c] = table.remove(players, 1)
end
hiders = players
end
-- Kill & Assign Teams
for i, ply in ipairs(hiders) do
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Assigned '"..ply:GetName().."' (SteamID: "..ply:SteamID()..") to Team Hiders.") end
ply:KillSilent()
ply:SetTeam(GAMEMODE.Teams.Hiders)
end
for i, ply in ipairs(seekers) do
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Assigned '"..ply:GetName().."' (SteamID: "..ply:SteamID()..") to Team Seekers.") end
ply:KillSilent()
ply:SetTeam(GAMEMODE.Teams.Seekers)
end
end
end
function StatePostRound:OnLeave(NewState)
if GAMEMODE.Config:DebugLog() then print("StatePostRound: OnLeave") end
end
@@ -26,29 +26,30 @@
StatePreMatch = {}
function StatePreMatch:OnEnter(OldState)
if GAMEMODE.Config:Debug() then print("StatePreMatch: OnEnter") end
if GAMEMODE.Config:DebugLog() then print("StatePreMatch: OnEnter") end
GAMEMODE:SetRoundState(GAMEMODE.States.PreMatch)
SetGlobalInt("Round", GetGlobalInt("Round", 0) + 1)
math.randomseed(CurTime())
end
function StatePreMatch:Tick()
-- Debug: Auto Advance to PreRound State
if (GAMEMODE.Config:Debug()) then
print("StatePreMatch: Advancing to StatePreRound")
if GAMEMODE.Config:DebugLog() then print("StatePreMatch: Advancing to StatePreRound") end
GAMEMODE.RoundManager:SetState(StatePreRound)
end
-- Game Mode: Basic
if (GAMEMODE.Config:GameMode() == GAMEMODE.Modes.Original) then
if (GAMEMODE.Config:GameType() == GAMEMODE.Types.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)
if GAMEMODE.Config:DebugLog() then print("StatePreMatch: <Original> Have enough players to start match.") end
end
-- TODO: Other Gamemodes
end
end
function StatePreMatch:OnLeave(NewState)
if GAMEMODE.Config:Debug() then print("StatePreMatch: OnLeave") end
if GAMEMODE.Config:DebugLog() then print("StatePreMatch: OnLeave") end
end
@@ -25,8 +25,9 @@
StatePreRound = {}
function StatePreRound:OnEnter(OldState)
if GAMEMODE.Config:Debug() then print("StatePreRound: OnEnter") end
if GAMEMODE.Config:DebugLog() then print("StatePreRound: OnEnter") end
GAMEMODE:SetRoundState(GAMEMODE.States.PreRound)
GAMEMODE:SetRound(GAMEMODE:GetRound() + 1)
-- Clean Up the Map
game.CleanUpMap()
@@ -37,7 +38,7 @@ function StatePreRound:Tick()
GAMEMODE.RoundManager:SetState(StateHide)
end
function StatePreRound:OnLeave(NewState)
if GAMEMODE.Config:Debug() then print("StatePreRound: OnLeave") end
if GAMEMODE.Config:DebugLog() then print("StatePreRound: OnLeave") end
-- Respawn Everyone
for i, ply in ipairs(player.GetAll()) do
@@ -46,5 +47,15 @@ function StatePreRound:OnLeave(NewState)
ply:Spawn()
ply:ScreenFade(SCREENFADE.PURGE, color_black, 0, 0)
ply:ScreenFade(SCREENFADE.IN, color_black, 1, 0)
-- Weighted Score: Adjust towards other Team.
if (ply:Team() == GAMEMODE.Teams.Hiders) then
ply.Data.RandomWeight = ply.Data.RandomWeight + 1
elseif (ply:Team() == GAMEMODE.Teams.Seekers) then
ply.Data.RandomWeight = ply.Data.RandomWeight - 1
end
end
-- Fretta Hooks
hook.Run("RoundStart")
end
@@ -25,7 +25,7 @@
StateSeek = {}
function StateSeek:OnEnter(OldState)
if GAMEMODE.Config:Debug() then print("StateSeek: OnEnter") end
if GAMEMODE.Config:DebugLog() then print("StateSeek: OnEnter") end
GAMEMODE:SetRoundState(GAMEMODE.States.Seek)
-- Round Data
@@ -75,7 +75,7 @@ function StateSeek:Tick()
GAMEMODE.RoundManager:SetState(StatePostRound)
else
if (GAMEMODE.Data.RoundTime <= 0) then -- No Time remaining
GAMEMODE:SetRoundWinner(GAMEMODE.Teams.Hiders)
GAMEMODE:SetRoundWinner(GAMEMODE.Teams.Hiders)
GAMEMODE.RoundManager:SetState(StatePostRound)
end
end
@@ -83,5 +83,13 @@ function StateSeek:Tick()
end
function StateSeek:OnLeave(NewState)
if GAMEMODE.Config:Debug() then print("StateSeek: OnLeave") end
if GAMEMODE.Config:DebugLog() then print("StateSeek: OnLeave") end
if GAMEMODE:GetRoundWinner() == GAMEMODE.Teams.Seekers then
hook.Run("RoundVictorySeeker")
elseif GAMEMODE:GetRoundWinner() == GAMEMODE.Teams.Hiders then
hook.Run("RoundVictoryHider")
else
hook.Run("RoundVictoryDraw")
end
end
@@ -0,0 +1,540 @@
--[[
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 = {}
function CreateConVarIfNotExists(name, value, flags, helptext)
cv = GetConVar(name)
if (cv == nil) then
cv = CreateConVar(name, value, flags, helptext)
-- else
-- ncv = CreateConVar(name, value, flags, helptext)
end
return cv
end
-- ------------------------------------------------------------------------- --
--! Debug Settings
-- ------------------------------------------------------------------------- --
-- Debug Mode
GM.Config.ConVars.Debug = CreateConVarIfNotExists("ph_debug", "0", FCVAR_CHEAT + FCVAR_REPLICATED, "Prop Hunt: Enable Debug Mode")
function GM.Config:Debug()
return self.ConVars.Debug:GetBool()
end
-- Debug Log
GM.Config.ConVars.DebugLog = CreateConVarIfNotExists("ph_debug_log", "0", FCVAR_REPLICATED, "Prop Hunt: Enable Debug Logging")
function GM.Config:DebugLog()
return self.ConVars.DebugLog:GetBool()
end
-- ------------------------------------------------------------------------- --
--! Basic Settings
-- ------------------------------------------------------------------------- --
-- Game Mode (See sh_init.lua)
GM.Config.ConVars.GameType = CreateConVarIfNotExists("ph_gametype", GM.Types.Original, FCVAR_REPLICATED, "Prop Hunt: Which Game Type should be played? ("..GM.Types.Original.." = Original Prop Hunt, "..GM.Types.TheDeadHunt.." = The Dead Hunt Mode)")
function GM.Config:GameType()
return self.ConVars.GameType:GetInt()
end
-- Timelimit in minutes
GM.Config.ConVars.TimeLimit = CreateConVarIfNotExists("mp_timelimit", "20", FCVAR_REPLICATED, "Map Time Limit (in Minutes)")
function GM.Config:TimeLimit()
return self.ConVars.TimeLimit:GetFloat()
end
-- ------------------------------------------------------------------------- --
--! Round Settings
-- ------------------------------------------------------------------------- --
GM.Config.Round = {}
GM.Config.Round.ConVars = {}
-- How many rounds should the GM attempt to fit into the map timelimit, if there is any?
GM.Config.Round.ConVars.Limit = CreateConVarIfNotExists("ph_round_limit", "10", FCVAR_REPLICATED, "Round Manager: Maximum Rounds to Play on a single Map")
function GM.Config.Round:Limit()
return self.ConVars.Limit:GetInt()
end
-- Round Time Limit (Seconds, Default 3 minutes)
GM.Config.Round.ConVars.Time = CreateConVarIfNotExists("ph_round_timelimit", "180", FCVAR_REPLICATED, "Round Manager: Time Limit per Round (in Seconds)")
function GM.Config.Round:Time()
return math.max(self.ConVars.Time:GetFloat() - math.min(self:BlindTime(),0),0)
end
-- For how many seconds are the Seekers blinded? (Seconds)
GM.Config.Round.ConVars.BlindTime = CreateConVarIfNotExists("ph_round_blindtime", "-30", FCVAR_REPLICATED, "Round Manager: Blind Time for Seekers (in Seconds, positive takes away from ph_round_timelimit, negative adds extra time to ph_round_timelimit)")
function GM.Config.Round:BlindTime()
return self.ConVars.BlindTime:GetFloat()
end
-- ------------------------------------------------------------------------- --
--! Team Settings
-- ------------------------------------------------------------------------- --
GM.Config.Teams = {}
GM.Config.Teams.ConVars = {}
-- Should teams be ranomized each round?
GM.Config.Teams.ConVars.Randomize = CreateConVarIfNotExists("ph_teams_randomize", "0", FCVAR_REPLICATED, "Teams: Randomize Teams instead of swapping each round")
function GM.Config.Teams:Randomize()
return self.ConVars.Randomize:GetBool()
end
-- Should teams be using weighted randomization?
-- Weighted randomization works by using a score calculated over the entire session.
-- * Round Start: Adjust Score towards the other Team by 1 (Positive = Seeker, Negative = Hider)
-- * Round Win: Adjust score by how many players are still alive on the winning team towards the other team.
-- * Alive players get double the score.
GM.Config.Teams.ConVars.Weighted = CreateConVarIfNotExists("ph_teams_weighted", "1", FCVAR_REPLICATED, "Teams: Use Weighted Randomization")
function GM.Config.Teams:Weighted()
return self.ConVars.Weighted:GetBool()
end
-- The Dead Hunt: Percent of players to assign to seeker.
GM.Config.Teams.ConVars.SeekerPercentage = CreateConVarIfNotExists("ph_teams_seekerpct", "25", FCVAR_REPLICATED, "Teams: Initial percentage of Seekers in Dead Hunt Game Type")
function GM.Config.Teams:SeekerPercentage()
return self.ConVars.Teams:GetFloat() / 100
end
-- ------------------------------------------------------------------------- --
--! Seeker Settings
-- ------------------------------------------------------------------------- --
GM.Config.Seeker = {}
GM.Config.Seeker.ConVars = {}
GM.Config.Seeker.ConVars.Health = CreateConVarIfNotExists("ph_seeker_health", "100", FCVAR_REPLICATED, "Seekers: Initial Health")
function GM.Config.Seeker:Health()
return self.ConVars.Health:GetInt()
end
GM.Config.Seeker.ConVars.HealthMax = CreateConVarIfNotExists("ph_seeker_health_max", "100", FCVAR_REPLICATED, "Seekers: Maximum Health")
function GM.Config.Seeker:HealthMax()
return self.ConVars.HealthMax:GetInt()
end
GM.Config.Seeker.ConVars.HealthBonus = CreateConVarIfNotExists("ph_seeker_health_bonus", "20", FCVAR_REPLICATED, "Seekers: Health Bonus per Kill")
function GM.Config.Seeker:HealthBonus()
return self.ConVars.HealthBonus:GetInt()
end
GM.Config.Seeker.ConVars.HealthPenalty = CreateConVarIfNotExists("ph_seeker_health_penalty", "5", FCVAR_REPLICATED, "Seekers: Health Penalty per wrong Shot")
function GM.Config.Seeker:HealthPenalty()
return self.ConVars.HealthPenalty:GetInt()
end
GM.Config.Seeker.ConVars.Weapons = CreateConVarIfNotExists("ph_seeker_weapons", "weapon_crowbar,weapon_pistol,weapon_ph_smg,weapon_shotgun", FCVAR_REPLICATED, "Seekers: Initial Weapons (Weapon,Weapon,...)")
function GM.Config.Seeker:Weapons()
return string.Split(self.ConVars.Weapons:GetString(), ",")
end
GM.Config.Seeker.ConVars.Ammo = CreateConVarIfNotExists("ph_seeker_ammo", "Pistol:100,SMG1:300,SMG1_Grenade:1,Buckshot:64", FCVAR_REPLICATED, "Seekers: Initial Ammo (Ammo:Amount,Ammo:Amount,...)")
function GM.Config.Seeker:Ammo()
return string.Split(self.ConVars.Ammo:GetString(), ",")
end
GM.Config.Seeker.ConVars.WalkSpeed = CreateConVarIfNotExists("ph_seeker_walk_speed", "250", 0, "Seekers: Walk Speed")
function GM.Config.Seeker:WalkSpeed()
return self.ConVars.WalkSpeed:GetFloat()
end
GM.Config.Seeker.ConVars.Sprint = CreateConVarIfNotExists("ph_seeker_sprint", "1", FCVAR_REPLICATED, "Seekers: Allow Sprinting")
function GM.Config.Seeker:Sprint()
return self.ConVars.Sprint:GetBool()
end
GM.Config.Seeker.ConVars.SprintSpeed = CreateConVarIfNotExists("ph_seeker_sprint_speed", "500", 0, "Seekers: Sprint Speed")
function GM.Config.Seeker:SprintSpeed()
return self.ConVars.SprintSpeed:GetFloat()
end
GM.Config.Seeker.ConVars.JumpPower = CreateConVarIfNotExists("ph_seeker_jump_power", "200", 0, "Seekers: Jump Power")
function GM.Config.Seeker:JumpPower()
return self.ConVars.JumpPower:GetFloat()
end
-- ------------------------------------------------------------------------- --
--! Hider Settings
-- ------------------------------------------------------------------------- --
GM.Config.Hider = {}
GM.Config.Hider.ConVars = {}
GM.Config.Hider.ConVars.Health = CreateConVarIfNotExists("ph_hider_health", "100", FCVAR_REPLICATED, "Hiders: Initial Health")
function GM.Config.Hider:Health()
return self.ConVars.Health:GetInt()
end
GM.Config.Hider.ConVars.HealthMax = CreateConVarIfNotExists("ph_hider_health_max", "100", FCVAR_REPLICATED, "Hiders: Maximum Health")
function GM.Config.Hider:HealthMax()
return self.ConVars.HealthMax:GetInt()
end
GM.Config.Hider.ConVars.HealthScaling = CreateConVarIfNotExists("ph_hider_health_scaling", "1", FCVAR_REPLICATED, "Hiders: Enable Health Scaling")
function GM.Config.Hider:HealthScaling()
return self.ConVars.HealthScaling:GetBool()
end
GM.Config.Hider.ConVars.HealthScalingMax = CreateConVarIfNotExists("ph_hider_health_scaling_max", "200", FCVAR_REPLICATED, "Hiders: Maximum scaled Health")
function GM.Config.Hider:HealthScalingMax()
return self.ConVars.HealthScalingMax:GetInt()
end
GM.Config.Hider.ConVars.AllowFullRotation = CreateConVarIfNotExists("ph_hider_allow_full_rotation", "0", FCVAR_REPLICATED, "Hiders: Enable full 3D Rotation")
function GM.Config.Hider:AllowFullRotation()
return self.ConVars.AllowFullRotation:GetBool()
end
GM.Config.Hider.ConVars.WalkSpeed = CreateConVarIfNotExists("ph_hider_walk_speed", "250", 0, "Hiders: Walk Speed")
function GM.Config.Hider:WalkSpeed()
return self.ConVars.WalkSpeed:GetFloat()
end
GM.Config.Hider.ConVars.Sprint = CreateConVarIfNotExists("ph_hider_sprint", "0", FCVAR_REPLICATED, "Hiders: Allow Sprinting")
function GM.Config.Hider:Sprint()
return self.ConVars.Sprint:GetBool()
end
GM.Config.Hider.ConVars.SprintSpeed = CreateConVarIfNotExists("ph_hider_sprint_speed", "500", 0, "Hiders: Sprint Speed")
function GM.Config.Hider:SprintSpeed()
return self.ConVars.SprintSpeed:GetFloat()
end
GM.Config.Hider.ConVars.JumpPower = CreateConVarIfNotExists("ph_hider_jump_power", "200", 0, "Hiders: Jump Power")
function GM.Config.Hider:JumpPower()
return self.ConVars.JumpPower:GetFloat()
end
-- ------------------------------------------------------------------------- --
--! Whitelist & Blacklist
-- ------------------------------------------------------------------------- --
GM.Config.Lists = {}
GM.Config.Lists.ConVars = {}
-- Class Whitelist
GM.Config.Lists.ConVars.ClassWhitelist = CreateConVarIfNotExists("ph_list_class_whitelist", "prop_physics,prop_physics_multiplayer,prop_physics_respawnable", FCVAR_REPLICATED, "Anti-Cheat: Whitelisted Hider Classes")
function GM.Config.Lists:ClassWhitelist()
local str = self.ConVars.ClassWhitelist:GetString()
if (self.ClassWhitelistCache != str) then
self.ClassWhitelistCache = str
self.ClassWhitelistCacheTbl = string.Split(self.ClassWhitelistCache, ",")
end
return self.ClassWhitelistCacheTbl
end
-- Abuse Blacklist
GM.Config.Lists.ConVars.AbuseBlacklist = CreateConVarIfNotExists("ph_list_abuse_blacklist", "func_button,func_door,func_door_rotation,prop_door_rotation,func_tracktrain,func_tanktrain,func_breakable", FCVAR_REPLICATED, "Anti-Cheat: Entity Abuse Blacklist")
function GM.Config.Lists:AbuseBlacklist()
local str = self.ConVars.AbuseBlacklist:GetString()
if (self.AbuseBlacklistCache != str) then
self.AbuseBlacklistCache = str
self.AbuseBlacklistCacheTbl = string.Split(self.AbuseBlacklistCache, ",")
end
return self.AbuseBlacklistCacheTbl
end
-- Model Blacklist
GM.Config.Lists.ConVars.ModelBlacklist = CreateConVarIfNotExists("ph_list_model_blacklist", "models/props/cs_assault/dollar.mdl,models/props/cs_assault/money.mdl,models/props/cs_office/snowman_arm.mdl,models/props/cs_office/projector_remote.mdl", FCVAR_REPLICATED, "Anti-Cheat: Model Abuse Blacklist")
function GM.Config.Lists:ModelBlacklist()
local str = self.ConVars.ModelBlacklist:GetString()
if (self.ModelBlacklistCache != str) then
self.ModelBlacklistCache = str
self.ModelBlacklistCacheTbl = string.Split(self.ModelBlacklistCache, ",")
end
return self.ModelBlacklistCacheTbl
end
-- ------------------------------------------------------------------------- --
--! Taunts
-- ------------------------------------------------------------------------- --
GM.Config.Taunt = {}
GM.Config.Taunt.ConVars = {}
-- Cooldown (Seconds)
GM.Config.Taunt.ConVars.Cooldown = CreateConVarIfNotExists("ph_taunt_cooldown", 5, FCVAR_REPLICATED, "Prop Hunt: Cooldown between Taunts")
function GM.Config.Taunt:Cooldown()
return self.ConVars.Cooldown:GetFloat()
end
-- Seeker
GM.Config.Taunt.SeekersCache = ""
GM.Config.Taunt.SeekersCacheDynamic = nil
GM.Config.Taunt.SeekersCacheStatic = nil
GM.Config.Taunt.SeekersCacheFull = nil
GM.Config.Taunt.ConVars.Seekers = CreateConVarIfNotExists("ph_taunt_seekers", "bot/a_bunch_of_them.wav,bot/come_out_and_fight_like_a_man.wav,bot/come_out_wherever_you_are.wav,bot/come_to_papa.wav,bot/dont_worry_hell_get_it.wav,bot/hang_on_i_heard_something.wav,bot/hang_on_im_coming.wav,bot/i_dont_think_so.wav,bot/i_have_the_hostages.wav,bot/i_see_our_target.wav,bot/im_waiting_here.wav,bot/keeping_an_eye_on_the_hostages.wav,bot/nnno_sir.wav,bot/spotted_the_delivery_boy.wav,bot/target_acquired.wav,bot/target_spotted.wav,bot/you_heard_the_man_lets_go.wav", 0, "Prop Hunt: Seeker Taunts")
function GM.Config.Taunt:Seekers()
local str = self.ConVars.Seekers:GetString()
if (self.SeekersCache != str) then
self.SeekersCache = str
self.SeekersCacheDynamic = string.Split(self.SeekersCache, ",")
self.SeekersCacheFull = table.Add(self.SeekersCacheDynamic, self.SeekersCacheStatic)
for i,snd in ipairs(self.SeekersCacheFull) do
util.PrecacheSound(snd)
end
end
return self.SeekersCacheFull
end
-- Hider
GM.Config.Taunt.HidersCache = ""
GM.Config.Taunt.HidersCacheDynamic = nil
GM.Config.Taunt.HidersCacheStatic = nil
GM.Config.Taunt.HidersCacheFull = nil
GM.Config.Taunt.ConVars.Hiders = CreateConVarIfNotExists("ph_taunt_hiders", "ambient/alarms/apc_alarm_pass1.wav,ambient/alarms/manhack_alert_pass1.wav,ambient/alarms/razortrain_horn1.wav,ambient/alarms/scanner_alert_pass1.wav,ambient/alarms/train_horn2.wav,ambient/alarms/train_horn_distant1.wav,ambient/alarms/warningbell1.wav,ambient/energy/whiteflash.wav,ambient/intro/alyxremove.wav,ambient/intro/logosfx.wav,ambient/levels/launch/1stfiringwarning.wav,ambient/levels/launch/rockettakeoffblast.wav,ambient/misc/ambulance1.wav,ambient/misc/carhonk1.wav,ambient/misc/carhonk2.wav,ambient/misc/carhonk3.wav,ambient/outro/gunshipcrash.wav,ambient/3dmeagle.wav,beams/beamstart5.wav,buttons/bell1.wav,buttons/weapon_cant_buy.wav,common/bass.wav,common/bugreporter_failed.wav,common/warning.wav,doors/door_squeek1.wav,friends/friend_join.wav,friends/friend_online.wav,friends/message.wav,hostage/hunuse/comeback.wav,hostage/hunuse/dontleaveme.wav,hostage/hunuse/yeahillstay.wav,items/gift_drop.wav,music/radio1.mp3,phx/eggcrack.wav,plats/elevbell1.wav,player/headshot1.wav,player/headshot2.wav,player/sprayer.wav,radio/enemydown.wav,radio/go.wav,radio/locknload.wav,radio/negative.wav,radio/rounddraw.wav,radio/takepoint.wav,resource/warning.wav,ui/achievement_earned.wav,ui/freeze_cam.wav,vehicles/junker/radar_ping_friendly1.wav,weapons/c4/c4_beep1.wav,weapons/c4/c4_click.wav,weapons/awp/awp1.wav,vo/canals/female01/gunboat_giveemhell.wav,vo/canals/female01/gunboat_justintime.wav,vo/canals/female01/stn6_incoming.wav,vo/canals/male01/gunboat_giveemhell.wav,vo/canals/male01/gunboat_justintime.wav,vo/canals/male01/stn6_incoming.wav,vo/canals/al_radio_stn6.wav,vo/canals/arrest_getgoing.wav,vo/canals/arrest_helpme.wav,vo/canals/arrest_lookingforyou.wav,vo/canals/boxcar_lethimhelp.wav,vo/canals/matt_closecall.wav,vo/canals/premassacre.wav,vo/ravenholm/aimforhead.wav,vo/ravenholm/bucket_patience.wav,vo/ravenholm/madlaugh01.wav,vo/ravenholm/madlaugh02.wav,vo/ravenholm/madlaugh03.wav,vo/ravenholm/madlaugh04.wav,weapons/strider_buster/ol12_stickybombcreator.wav,weapons/c4/c4_explode1.wav,weapons/357/357_fire2.wav,weapons/357/357_fire3.wav,weapons/scout/scout_fire-1.wav,weapons/smokegrenade/sg_explode.wav,weapons/grenade_launcher1.wav,weapons/explode3.wav,weapons/underwater_explode3.wav,items/nvg_on.wav,hostage/huse/letsdoit.wav,hostage/huse/illfollow.wav,hostage/huse/getouttahere.wav,doors/door_screen_move1.wav,doors/heavy_metal_stop1.wav,doors/default_move.wav,common/stuck2.wav,ambient/water_splash1.wav,ambient/water_splash2.wav,ambient/water_splash3.wav,ambient/weather/thunder1.wav,ambient/weather/thunder2.wav,ambient/weather/thunder3.wav,ambient/weather/thunder4.wav,ambient/weather/thunder5.wav,ambient/weather/thunder6.wav,ambient/outro/thunder7.wav,ambient/voices/crying_loop1.wav,ambient/voices/playground_memory.wav,ambient/voices/f_scream1.wav,ambient/voices/m_scream1.wav,ambient/voices/cough1.wav,ambient/voices/cough2.wav,ambient/voices/cough3.wav,ambient/voices/cough4.wav,ambient/overhead/plane1.wav,ambient/overhead/plane2.wav,ambient/overhead/plane3.wav,ambient/overhead/hel1.wav,ambient/overhead/hel2.wav,ambient/misc/truck_backup1.wav,ambient/misc/truck_drive1.wav,ambient/misc/truck_drive2.wav,ambient/machines/pneumatic_drill_1.wav,ambient/machines/pneumatic_drill_2.wav,ambient/machines/pneumatic_drill_3.wav,ambient/machines/pneumatic_drill_4.wav,ambient/machines/station_train_squeel.wav,ambient/machines/ticktock.wav,ambient/creatures/teddy.wav,ambient/creatures/town_child_scream1.wav,ambient/creatures/town_moan1.wav,ambient/creatures/town_muffled_cry1.wav,ambient/creatures/town_scared_breathing1.wav,ambient/creatures/town_scared_breathing2.wav,ambient/creatures/town_scared_sob1.wav,ambient/creatures/town_scared_sob2.wav,ambient/creatures/town_zombie_call1.wav", 0, "Prop Hunt: Hider Taunts")
function GM.Config.Taunt:Hiders()
local str = self.ConVars.Hiders:GetString()
if (self.HidersCacheDynamic == nil)
|| (self.HidersCache != str) then
self.HidersCache = str
self.HidersCacheDynamic = string.Split(self.HidersCache, ",")
self.HidersCacheFull = table.Add(self.HidersCacheDynamic, self.HidersCacheStatic)
for i,snd in ipairs(self.HidersCacheFull) do
util.PrecacheSound(snd)
end
end
return self.HidersCacheFull
end
-- ------------------------------------------------------------------------- --
--! Announcers
-- ------------------------------------------------------------------------- --
-- --! Announcers (Round Start, Unblind, Win, Loss)
-- GM.Config.Announcers = {
-- Start = { },
-- Unblind = { },
-- Win = { },
-- Loss = { }
-- }
-- ------------------------------------------------------------------------- --
--! Camera
-- ------------------------------------------------------------------------- --
GM.Config.Camera = {}
GM.Config.Camera.ConVars = {}
-- Allow Camera No Clip
GM.Config.Camera.ConVars.AllowNoClip = CreateConVarIfNotExists("ph_camera_allow_noclip", "0", FCVAR_REPLICATED, "Camera: Allow clients to disable camera collision.")
function GM.Config.Camera:AllowNoClip()
return self.ConVars.AllowNoClip:GetBool()
end
-- Camera Distance Maximum
GM.Config.Camera.ConVars.DistanceMax = CreateConVarIfNotExists("ph_camera_distance_max", "150", FCVAR_REPLICATED, "Camera: Maximum allowed distance to player.")
function GM.Config.Camera:DistanceMax()
return self.ConVars.DistanceMax:GetFloat()
end
-- Camera Distance Minimum
GM.Config.Camera.ConVars.DistanceMin = CreateConVarIfNotExists("ph_camera_distance_min", "30", FCVAR_REPLICATED, "Camera: Minimum allowed distance to player.")
function GM.Config.Camera:DistanceMin()
return self.ConVars.DistanceMin:GetFloat()
end
-- Camera Distance Right Maximum
GM.Config.Camera.ConVars.DistanceRightRange = CreateConVarIfNotExists("ph_camera_distance_right_range", "20", FCVAR_REPLICATED, "Camera: Horizontal allowed camera distance range.")
function GM.Config.Camera:DistanceRightRange()
return self.ConVars.DistanceRightRange:GetFloat()
end
-- Camera Distance Up Maximum
GM.Config.Camera.ConVars.DistanceUpRange = CreateConVarIfNotExists("ph_camera_distance_up_range", "20", FCVAR_REPLICATED, "Camera: Vertical allowed camera distance range.")
function GM.Config.Camera:DistanceUpRange()
return self.ConVars.DistanceUpRange:GetFloat()
end
-- Lag Minimum
GM.Config.Camera.ConVars.LagMinimum = CreateConVarIfNotExists("ph_camera_lag_min", "0.01", FCVAR_REPLICATED, "Camera: Minimum Camera Lag.")
function GM.Config.Camera:LagMinimum()
return self.ConVars.LagMinimum:GetFloat()
end
-- Lag Maximum
GM.Config.Camera.ConVars.LagMaximum = CreateConVarIfNotExists("ph_camera_lag_max", "0.95", FCVAR_REPLICATED, "Camera: Maximum Camera Lag.")
function GM.Config.Camera:LagMaximum()
return self.ConVars.LagMaximum:GetFloat()
end
if CLIENT then
-- Collisions
GM.Config.Camera.ConVars.Collisions = CreateConVarIfNotExists("ph_camera_collisions", "1", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Camera: Enable collisions with the world and objects in it.")
function GM.Config.Camera:Collisions()
if self:AllowNoClip() then
return self.ConVars.Collisions:GetBool()
else
return true
end
end
-- Distance
GM.Config.Camera.ConVars.Distance = CreateConVarIfNotExists("ph_camera_distance", "100", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Camera: Ideal Distance to player.")
function GM.Config.Camera:Distance()
return math.Clamp(self.ConVars.Distance:GetFloat(), self:DistanceMin(), self:DistanceMax())
end
-- Distance Right
GM.Config.Camera.ConVars.DistanceRight = CreateConVarIfNotExists("ph_camera_distance_right", "0", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Camera: Ideal Distance to player horizontally.")
function GM.Config.Camera:DistanceRight()
return math.Clamp(self.ConVars.DistanceRight:GetFloat(), -self:DistanceRightRange(), self:DistanceRightRange())
end
-- Distance Up
GM.Config.Camera.ConVars.DistanceUp = CreateConVarIfNotExists("ph_camera_distance_up", "0", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Camera: Ideal Distance to player vertically.")
function GM.Config.Camera:DistanceUp()
return math.Clamp(self.ConVars.DistanceUp:GetFloat(), -self:DistanceUpRange(), self:DistanceUpRange())
end
-- Lag
GM.Config.Camera.ConVars.Lag = CreateConVarIfNotExists("ph_camera_lag", "0.95", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Camera: Percentage of camera lag (higher = slower, lower = faster).")
function GM.Config.Camera:Lag()
return math.Clamp(self.ConVars.Lag:GetFloat(), self:LagMinimum(), self:LagMaximum())
end
end
-- ------------------------------------------------------------------------- --
--! Name Plates
-- ------------------------------------------------------------------------- --
GM.Config.NamePlates = {}
GM.Config.NamePlates.ConVars = {}
if CLIENT then
-- Show
GM.Config.NamePlates.ConVars.Show = CreateConVarIfNotExists("ph_nameplates_show", "1", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Nameplates: Show a name plate above each player in your team (or all players if spectating).")
function GM.Config.NamePlates:Show()
return self.ConVars.Show:GetBool()
end
-- Scale
GM.Config.NamePlates.ConVars.Scale = CreateConVarIfNotExists("ph_nameplates_scale", "0.05", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Nameplates: World scale of name plate, a setting of 1 means 1px = 1unit.")
function GM.Config.NamePlates:Scale()
return self.ConVars.Scale:GetFloat()
end
-- Height
GM.Config.NamePlates.ConVars.Height = CreateConVarIfNotExists("ph_nameplates_height", "10", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Nameplates: Height above player.")
function GM.Config.NamePlates:Height()
return self.ConVars.Height:GetFloat()
end
-- Tint Color
GM.Config.NamePlates.ConVars.TintHue = CreateConVarIfNotExists("ph_nameplates_tint_hue", "0", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Nameplates: Tint hue.")
function GM.Config.NamePlates:TintHue()
return self.ConVars.TintHue:GetFloat()
end
GM.Config.NamePlates.ConVars.TintSaturation = CreateConVarIfNotExists("ph_nameplates_tint_saturation", "0", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Nameplates: Tint saturation.")
function GM.Config.NamePlates:TintSaturation()
return self.ConVars.TintSaturation:GetFloat()
end
GM.Config.NamePlates.ConVars.TintValue = CreateConVarIfNotExists("ph_nameplates_tint_value", "1", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Nameplates: Tint value.")
function GM.Config.NamePlates:TintValue()
return self.ConVars.TintValue:GetFloat()
end
-- Tint By Health
GM.Config.NamePlates.ConVars.TintHealth = CreateConVarIfNotExists("ph_nameplates_tint_health", "0", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Nameplates: Tint the nameplate using their health percent.")
function GM.Config.NamePlates:TintHealth()
return self.ConVars.TintHealth:GetBool()
end
-- Tint By Team
GM.Config.NamePlates.ConVars.TintTeam = CreateConVarIfNotExists("ph_nameplates_tint_team", "0", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Nameplates: Tint the nameplate with the team colors.")
function GM.Config.NamePlates:TintTeam()
return self.ConVars.TintTeam:GetBool()
end
end
-- ------------------------------------------------------------------------- --
--! Selection Halo
-- ------------------------------------------------------------------------- --
GM.Config.SelectionHalo = {}
GM.Config.SelectionHalo.ConVars = {}
-- Allow
GM.Config.SelectionHalo.ConVars.Allow = CreateConVarIfNotExists("ph_selectionhalo_allow", "1", FCVAR_REPLICATED, "Selection Halo: Allow clients to enable halo around the currently looked at prop?")
function GM.Config.SelectionHalo:Allow()
return self.ConVars.Allow:GetBool()
end
-- Approximate
GM.Config.SelectionHalo.ConVars.Approximate = CreateConVarIfNotExists("ph_selectionhalo_approximate", "1", FCVAR_REPLICATED, "Selection Halo: Enable approximate selection halo, which only checks the forward vector on the client.")
function GM.Config.SelectionHalo:Approximate()
return self.ConVars.Approximate:GetBool()
end
if SERVER then
-- Update Interval
GM.Config.SelectionHalo.ConVars.Interval = CreateConVarIfNotExists("ph_selectionhalo_interval", "0.05", FCVAR_ARCHIVE, "Selection Halo: Interval for updates of the accuracte selection halo in seconds.")
function GM.Config.SelectionHalo:Interval()
return self.ConVars.Interval:GetFloat()
end
end
if CLIENT then
-- Enabled
GM.Config.SelectionHalo.ConVars.Enabled = CreateConVarIfNotExists("ph_selectionhalo_enabled", "1", FCVAR_ARCHIVE, "Selection Halo: Enable halo around prop you might become.")
function GM.Config.SelectionHalo:Enabled()
if (self:Allow()) then
return self.ConVars.Enabled:GetBool()
else
return false
end
end
-- Settings
GM.Config.SelectionHalo.ConVars.Passes = CreateConVarIfNotExists("ph_selectionhalo_passes", "1", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Selection Halo: Passes")
function GM.Config.SelectionHalo:Passes()
return self.ConVars.Passes:GetInt()
end
GM.Config.SelectionHalo.ConVars.Additive = CreateConVarIfNotExists("ph_selectionhalo_additive", "1", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Selection Halo: Additive")
function GM.Config.SelectionHalo:Additive()
return self.ConVars.Additive:GetBool()
end
GM.Config.SelectionHalo.ConVars.IgnoreZ = CreateConVarIfNotExists("ph_selectionhalo_ignorez", "0", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Selection Halo: Ignore Z")
function GM.Config.SelectionHalo:IgnoreZ()
return self.ConVars.IgnoreZ:GetBool()
end
-- Blur
GM.Config.SelectionHalo.ConVars.BlurX = CreateConVarIfNotExists("ph_selectionhalo_blur_x", "2", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Selection Halo: Blur X")
function GM.Config.SelectionHalo:BlurX()
return self.ConVars.BlurX:GetFloat()
end
GM.Config.SelectionHalo.ConVars.BlurY = CreateConVarIfNotExists("ph_selectionhalo_blur_y", "2", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Selection Halo: Blur Y")
function GM.Config.SelectionHalo:BlurY()
return self.ConVars.BlurY:GetFloat()
end
-- Tint Color
GM.Config.SelectionHalo.ConVars.TintHue = CreateConVarIfNotExists("ph_selectionhalo_tint_hue", "0", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Selection Halo: Tint Hue")
function GM.Config.SelectionHalo:TintHue()
return self.ConVars.TintHue:GetFloat()
end
GM.Config.SelectionHalo.ConVars.TintSaturation = CreateConVarIfNotExists("ph_selectionhalo_tint_saturation", "0", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Selection Halo: Tint Saturation")
function GM.Config.SelectionHalo:TintSaturation()
return self.ConVars.TintSaturation:GetFloat()
end
GM.Config.SelectionHalo.ConVars.TintValue = CreateConVarIfNotExists("ph_selectionhalo_tint_value", "1", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Selection Halo: Tint Value")
function GM.Config.SelectionHalo:TintValue()
return self.ConVars.TintValue:GetFloat()
end
end
@@ -26,23 +26,14 @@
--! 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.Author = "Michael Fabian 'Xaymar' Dirks"
GM.Email = "info@xaymar.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
-- ------------------------------------------------------------------------- --
@@ -56,10 +47,9 @@ 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.
GM.Types = {}
GM.Types.Original = 0
GM.Types.TheDeadHunt = 1 -- One Hunter, Dead Prop become Hunter, Props can't see each other.
-- Teams
GM.Teams = {}
@@ -75,13 +65,15 @@ function GM:CreateTeams()
"info_player_combine",
"info_player_counterterrorist",
"info_player_allies",
"info_player_terrorist"
"info_player_terrorist",
"info_player_start"
})
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_start",
"info_player_spawn",
"info_player_deathmatch",
"info_player_combine",
@@ -92,6 +84,7 @@ function GM:CreateTeams()
-- Hiders: "Props"
team.SetUp(self.Teams.Hiders, "Hiders", Color(255, 128, 0, 255))
team.SetSpawnPoint(self.Teams.Hiders, {
"info_player_start",
"info_player_spawn",
"info_player_deathmatch",
"info_player_allies",
@@ -111,18 +104,17 @@ 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
function GM:FindUseEntity(ply, defaultEnt)
return player_manager.RunClass(ply, "FindUseEntity", defaultEnt)
end
-- ------------------------------------------------------------------------- --
--! Gamemode Functionality
-- ------------------------------------------------------------------------- --
function GM:GetRound()
return GetGlobalInt("Round", 0)
end
function GM:GetRoundState()
return GetGlobalInt("RoundState", self.States.PreMatch)
end
@@ -133,4 +125,19 @@ end
function GM:GetRoundWinner()
return GetGlobalInt("RoundWinner", GAMEMODE.Teams.Spectator)
end
end
-- ------------------------------------------------------------------------- --
--! Includes
-- ------------------------------------------------------------------------- --
-- Meta
include "meta/player.lua"
-- Configuration
include "sh_config.lua"
-- 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"
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

@@ -0,0 +1,401 @@
"prophuntextended"
{
"base" "base"
"title" "Prop Hunt Extended"
"maps" "^ph_"
"menusystem" "1"
"workshopid" "468149739"
"settings"
{
// Debug Settings
1
{
"name" "ph_debug"
"text" "Enable Debug Mode"
"type" "CheckBox"
"default" "0"
"help" "Prop Hunt: Enable Debug Mode"
}
2
{
"name" "ph_debug_log"
"text" "Enable Debug Logging"
"type" "CheckBox"
"default" "1"
"help" "Prop Hunt: Enable Debug Logging"
}
// Basic Settings
100
{
"name" "ph_gametype"
"text" "Game Type to use"
"type" "Numeric"
"default" "0"
"help" "Prop Hunt: Which Game Type should be played?"
}
101
{
"name" "mp_timelimit"
"text" "Map Time Limit"
"type" "Numeric"
"default" "0"
"help" "Map Time Limit (in Minutes)"
}
102
{
"name" "mp_friendlyfire"
"text" "Friendly fire"
"type" "Numeric"
"default" "0"
"help" "Allow friendly fire? (0 = No, 1 = Yes, 2 = Reflect)"
}
// Round Settings
200
{
"name" "ph_round_limit"
"text" "Maximum Rounds Played"
"type" "Numeric"
"default" "10"
"help" "Round Manager: Maximum Rounds to Play on a single Map"
}
201
{
"name" "ph_round_timelimit"
"text" "Time Limit per Round"
"type" "Numeric"
"default" "180"
"help" "Round Manager: Time Limit per Round (in Seconds)"
}
202
{
"name" "ph_round_blindtime"
"text" "Seeker Blind time per Round"
"type" "Numeric"
"default" "-30"
"help" "Round Manager: Blind Time for Seekers (in Seconds, positive takes away from ph_round_timelimit, negative adds extra time to ph_round_timelimit)"
}
// Team Settings
300
{
"name" "ph_teams_randomize"
"text" "Randomize Teams"
"type" "CheckBox"
"default" "1"
"help" "Teams: Randomize Teams instead of swapping each round"
}
301
{
"name" "ph_teams_weighted"
"text" "Randomize with weighted Score"
"type" "CheckBox"
"default" "1"
"help" "Teams: Use Weighted Randomization"
}
302
{
"name" "ph_teams_seekerpct"
"text" "Pct of Pl. becoming Seeker"
"type" "Numeric"
"default" "25"
"help" "Teams: Initial percentage of Seekers in Dead Hunt Game Type"
}
// Seeker Settings
400
{
"name" "ph_seeker_health"
"text" "Seeker Health"
"type" "Numeric"
"default" "100"
"help" "Seekers: Initial Health"
}
401
{
"name" "ph_seeker_health_max"
"text" "Seeker Max Health"
"type" "Numeric"
"default" "100"
"help" "Seekers: Maximum Health"
}
402
{
"name" "ph_seeker_health_bonus"
"text" "Seeker Health Kill-Bonus"
"type" "Numeric"
"default" "20"
"help" "Seekers: Health Bonus per Kill"
}
403
{
"name" "ph_seeker_health_penalty"
"text" "Seeker Health Penalty"
"type" "Numeric"
"default" "5"
"help" "Seekers: Health Penalty per wrong Shot"
}
404
{
"name" "ph_seeker_weapons"
"text" "Seeker Weapons"
"type" "Text"
"default" "weapon_crowbar,weapon_pistol,weapon_ph_smg,weapon_shotgun"
"help" "Seekers: Initial Weapons (Weapon,Weapon,...)"
}
405
{
"name" "ph_seeker_ammo"
"text" "Seeker Ammo"
"type" "Text"
"default" "Pistol:100,SMG1:300,SMG1_Grenade:1,Buckshot:64"
"help" "Seekers: Initial Ammo (Ammo:Amount,Ammo:Amount,...)"
}
406
{
"name" "ph_seeker_walk_speed"
"text" "Seeker Walk Speed"
"type" "Numeric"
"default" "250"
"help" "Seekers: Walk Speed"
}
407
{
"name" "ph_seeker_sprint"
"text" "Seeker Sprint Allowed"
"type" "CheckBox"
"default" "1"
"help" "Seekers: Allow Sprinting"
}
408
{
"name" "ph_seeker_sprint_speed"
"text" "Seeker Sprint Speed"
"type" "Numeric"
"default" "500"
"help" "Seekers: Sprint Speed"
}
409
{
"name" "ph_seeker_jump_power"
"text" "Seeker Jump Power"
"type" "Numeric"
"default" "200"
"help" "Seekers: Jump Power"
}
// Hider Settings
500
{
"name" "ph_hider_health"
"text" "Hider Health"
"type" "Numeric"
"default" "100"
"help" "Hiders: Initial Health"
}
501
{
"name" "ph_hider_health_max"
"text" "Hider Max Health"
"type" "Numeric"
"default" "100"
"help" "Hiders: Maximum Health"
}
502
{
"name" "ph_hider_health_scaling"
"text" "Hider Enable Health Scaling"
"type" "CheckBox"
"default" "1"
"help" "Hiders: Enable Health Scaling"
}
503
{
"name" "ph_hider_health_scaling_max"
"text" "Hider Scaled Max Health"
"type" "Numeric"
"default" "200"
"help" "Hiders: Maximum scaled Health"
}
504
{
"name" "ph_hider_allow_full_rotation"
"text" "Hider 3-Dimensional Rotation"
"type" "CheckBox"
"default" "0"
"help" "Hiders: Enable full 3D Rotation"
}
505
{
"name" "ph_hider_walk_speed"
"text" "Hider Walk Speed"
"type" "Numeric"
"default" "250"
"help" "Hiders: Walk Speed"
}
506
{
"name" "ph_hider_sprint"
"text" "Hider Sprint Allowed"
"type" "CheckBox"
"default" "0"
"help" "Hiders: Allow Sprinting"
}
507
{
"name" "ph_hider_sprint_speed"
"text" "Hider Sprint Speed"
"type" "Numeric"
"default" "500"
"help" "Hiders: Sprint Speed"
}
507
{
"name" "ph_hider_jump_power"
"text" "Hider Jump Power"
"type" "Numeric"
"default" "200"
"help" "Hiders: Jump Power"
}
// Whitelist & Blacklist
600
{
"name" "ph_list_class_whitelist"
"text" "Allowed Entity Classes"
"type" "Text"
"default" "ph_prop,prop_physics,prop_physics_multiplayer,prop_physics_respawnable"
"help" "Anti-Cheat: Whitelisted Hider Classes"
}
601
{
"name" "ph_list_abuse_blacklist"
"text" "Abuse Blacklist"
"type" "Text"
"default" "func_button,func_door,func_door_rotation,prop_door_rotation,func_tracktrain,func_tanktrain,func_breakable"
"help" "Anti-Cheat: Entity Abuse Blacklist"
}
602
{
"name" "ph_list_model_blacklist"
"text" "Model Blacklist"
"type" "Text"
"default" "models/props/cs_assault/dollar.mdl,models/props/cs_assault/money.mdl,models/props/cs_office/snowman_arm.mdl,models/props/cs_office/projector_remote.mdl"
"help" "Anti-Cheat: Model Abuse Blacklist"
}
// Taunts
700
{
"name" "ph_taunt_cooldown"
"text" "Cooldown for Taunts"
"type" "Numeric"
"default" "5"
"help" "Prop Hunt: Cooldown between Taunts"
}
701
{
"name" "ph_taunt_seekers"
"text" "Seeker Taunts"
"type" "Text"
"default" "bot/a_bunch_of_them.wav,bot/come_out_and_fight_like_a_man.wav,bot/come_out_wherever_you_are.wav,bot/come_to_papa.wav,bot/dont_worry_hell_get_it.wav,bot/hang_on_i_heard_something.wav,bot/hang_on_im_coming.wav,bot/i_dont_think_so.wav,bot/i_have_the_hostages.wav,bot/i_see_our_target.wav,bot/im_waiting_here.wav,bot/keeping_an_eye_on_the_hostages.wav,bot/nnno_sir.wav,bot/spotted_the_delivery_boy.wav,bot/target_acquired.wav,bot/target_spotted.wav,bot/you_heard_the_man_lets_go.wav"
"help" "Prop Hunt: Seeker Taunts"
}
702
{
"name" "ph_taunt_hiders"
"text" "Hider Taunts"
"type" "Text"
"default" "ambient/alarms/apc_alarm_pass1.wav,ambient/alarms/manhack_alert_pass1.wav,ambient/alarms/razortrain_horn1.wav,ambient/alarms/scanner_alert_pass1.wav,ambient/alarms/train_horn2.wav,ambient/alarms/train_horn_distant1.wav,ambient/alarms/warningbell1.wav,ambient/energy/whiteflash.wav,ambient/intro/alyxremove.wav,ambient/intro/logosfx.wav,ambient/levels/launch/1stfiringwarning.wav,ambient/levels/launch/rockettakeoffblast.wav,ambient/misc/ambulance1.wav,ambient/misc/carhonk1.wav,ambient/misc/carhonk2.wav,ambient/misc/carhonk3.wav,ambient/outro/gunshipcrash.wav,ambient/3dmeagle.wav,beams/beamstart5.wav,buttons/bell1.wav,buttons/weapon_cant_buy.wav,common/bass.wav,common/bugreporter_failed.wav,common/warning.wav,doors/door_squeek1.wav,friends/friend_join.wav,friends/friend_online.wav,friends/message.wav,hostage/hunuse/comeback.wav,hostage/hunuse/dontleaveme.wav,hostage/hunuse/yeahillstay.wav,items/gift_drop.wav,music/radio1.mp3,phx/eggcrack.wav,plats/elevbell1.wav,player/headshot1.wav,player/headshot2.wav,player/sprayer.wav,radio/enemydown.wav,radio/go.wav,radio/locknload.wav,radio/negative.wav,radio/rounddraw.wav,radio/takepoint.wav,resource/warning.wav,ui/achievement_earned.wav,ui/freeze_cam.wav,vehicles/junker/radar_ping_friendly1.wav,weapons/c4/c4_beep1.wav,weapons/c4/c4_click.wav,weapons/awp/awp1.wav,vo/canals/female01/gunboat_giveemhell.wav,vo/canals/female01/gunboat_justintime.wav,vo/canals/female01/stn6_incoming.wav,vo/canals/male01/gunboat_giveemhell.wav,vo/canals/male01/gunboat_justintime.wav,vo/canals/male01/stn6_incoming.wav,vo/canals/al_radio_stn6.wav,vo/canals/arrest_getgoing.wav,vo/canals/arrest_helpme.wav,vo/canals/arrest_lookingforyou.wav,vo/canals/boxcar_lethimhelp.wav,vo/canals/matt_closecall.wav,vo/canals/premassacre.wav,vo/ravenholm/aimforhead.wav,vo/ravenholm/bucket_patience.wav,vo/ravenholm/madlaugh01.wav,vo/ravenholm/madlaugh02.wav,vo/ravenholm/madlaugh03.wav,vo/ravenholm/madlaugh04.wav,weapons/strider_buster/ol12_stickybombcreator.wav,weapons/c4/c4_explode1.wav,weapons/357/357_fire2.wav,weapons/357/357_fire3.wav,weapons/scout/scout_fire-1.wav,weapons/smokegrenade/sg_explode.wav,weapons/grenade_launcher1.wav,weapons/explode3.wav,weapons/underwater_explode3.wav,items/nvg_on.wav,hostage/huse/letsdoit.wav,hostage/huse/illfollow.wav,hostage/huse/getouttahere.wav,doors/door_screen_move1.wav,doors/heavy_metal_stop1.wav,doors/default_move.wav,common/stuck2.wav,ambient/water_splash1.wav,ambient/water_splash2.wav,ambient/water_splash3.wav,ambient/weather/thunder1.wav,ambient/weather/thunder2.wav,ambient/weather/thunder3.wav,ambient/weather/thunder4.wav,ambient/weather/thunder5.wav,ambient/weather/thunder6.wav,ambient/outro/thunder7.wav,ambient/voices/crying_loop1.wav,ambient/voices/playground_memory.wav,ambient/voices/f_scream1.wav,ambient/voices/m_scream1.wav,ambient/voices/cough1.wav,ambient/voices/cough2.wav,ambient/voices/cough3.wav,ambient/voices/cough4.wav,ambient/overhead/plane1.wav,ambient/overhead/plane2.wav,ambient/overhead/plane3.wav,ambient/overhead/hel1.wav,ambient/overhead/hel2.wav,ambient/misc/truck_backup1.wav,ambient/misc/truck_drive1.wav,ambient/misc/truck_drive2.wav,ambient/machines/pneumatic_drill_1.wav,ambient/machines/pneumatic_drill_2.wav,ambient/machines/pneumatic_drill_3.wav,ambient/machines/pneumatic_drill_4.wav,ambient/machines/station_train_squeel.wav,ambient/machines/ticktock.wav,ambient/creatures/teddy.wav,ambient/creatures/town_child_scream1.wav,ambient/creatures/town_moan1.wav,ambient/creatures/town_muffled_cry1.wav,ambient/creatures/town_scared_breathing1.wav,ambient/creatures/town_scared_breathing2.wav,ambient/creatures/town_scared_sob1.wav,ambient/creatures/town_scared_sob2.wav,ambient/creatures/town_zombie_call1.wav"
"help" "Prop Hunt: Hider Taunts"
}
// Camera
800
{
"name" "ph_camera_allow_noclip"
"text" "Camera Noclip Allowed"
"type" "CheckBox"
"default" "0"
"help" "Camera: Allow clients to disable camera collision"
}
801
{
"name" "ph_camera_distance_max"
"text" "Camera Distance Max."
"type" "Numeric"
"default" "150"
"help" "Camera: Maximum allowed distance to player."
}
802
{
"name" "ph_camera_distance_min"
"text" "Camera Distance Min."
"type" "Numeric"
"default" "30"
"help" "Camera: Minimum allowed distance to player."
}
803
{
"name" "ph_camera_distance_right_range"
"text" "Camera Horizontal Offset Range"
"type" "Numeric"
"default" "20"
"help" "Camera: Horizontal allowed camera distance range."
}
803
{
"name" "ph_camera_distance_up_range"
"text" "Camera Vertical Offset Range"
"type" "Numeric"
"default" "20"
"help" "Camera: Vertical allowed camera distance range."
}
803
{
"name" "ph_camera_lag_min"
"text" "Camera Lag Min."
"type" "Numeric"
"default" "0"
"help" "Camera: Minimum Camera Lag."
}
803
{
"name" "ph_camera_lag_max"
"text" "Camera Lag Max."
"type" "Numeric"
"default" "0.95"
"help" "Camera: Maximum Camera Lag."
}
// Selection Halo
900
{
"name" "ph_selectionhalo_allow"
"text" "Selection Halo Allowed"
"type" "CheckBox"
"default" "1"
"help" "Selection Halo: Allow clients to enable halo around the currently looked at prop?"
}
901
{
"name" "ph_selectionhalo_approximate"
"text" "Selection Approximate Mode"
"type" "CheckBox"
"default" "1"
"help" "Selection Halo: Enable approximate selection halo, which only checks the forward vector on the client."
}
902
{
"name" "ph_selectionhalo_interval"
"text" "Selection Halo Allowed"
"type" "Numeric"
"default" "0.05"
"help" "Selection Halo: Interval for updates of the accuracte selection halo in seconds."
}
}
}