It's back bitches!

This commit is contained in:
Michael Fabain Dirks
2016-06-14 07:28:36 +02:00
parent 2d3360ab82
commit d625658c71
48 changed files with 2682 additions and 1760 deletions
+7
View File
@@ -0,0 +1,7 @@
{
"title" : "Prop Hunt Extended",
"type" : "gamemode",
"tags" : [ "fun" ],
"ignore" : [
]
}
@@ -0,0 +1,8 @@
"TableToKeyValues"
{
"1" "models/props/cs_assault/dollar.mdl"
"2" "models/props/cs_assault/money.mdl"
"3" "models/props/cs_office/snowman_arm.mdl"
"4" "models/props_junk/garbage_plasticbottle001a.mdl"
"5" "models/props/cs_office/projector_remote.mdl"
}
@@ -0,0 +1,8 @@
"TableToKeyValues"
{
"TAUNT_DELAY" "0.1"
"ROUNDS_PER_MAP" "20"
"ROUND_TIME" "240"
"SWAP_TEAM_EVERY_ROUND" "1"
"GAME_TIME" "20"
}
@@ -0,0 +1,26 @@
"TableToKeyValues"
{
"1" "bot/aw_hell.wav"
"2" "bot/aww_man.wav"
"3" "bot/anyone_see_anything.wav"
"4" "bot/anyone_see_them.wav"
"5" "bot/come_out_and_fight_like_a_man.wav"
"6" "bot/come_out_wherever_you_are.wav"
"7" "bot/he_got_away.wav"
"8" "bot/he_got_away2.wav"
"9" "bot/i_dont_know_where_he_went.wav"
"10" "bot/i_got_nothing.wav"
"11" "bot/nothing_happening_over_here.wav"
"12" "bot/nothing_here.wav"
"13" "bot/nothing_moving_over_here.wav"
"14" "bot/thats_not_good.wav"
"15" "bot/theres_too_many.wav"
"16" "bot/theres_too_many_of_them.wav"
"17" "bot/theyre_all_over_the_place2.wav"
"18" "bot/theyre_everywhere2.wav"
"19" "bot/too_many2.wav"
"20" "bot/what_happened.wav"
"21" "bot/what_have_you_done.wav"
"22" "bot/where_are_they.wav"
"23" "bot/where_are_you_hiding.wav"
}
@@ -0,0 +1,20 @@
"TableToKeyValues"
{
"1" "bot/a_bunch_of_them.wav"
"2" "bot/come_out_and_fight_like_a_man.wav"
"3" "bot/come_out_wherever_you_are.wav"
"4" "bot/come_to_papa.wav"
"5" "bot/dont_worry_hell_get_it.wav"
"6" "bot/hang_on_i_heard_something.wav"
"7" "bot/hang_on_im_coming.wav"
"8" "bot/i_dont_think_so.wav"
"9" "bot/i_have_the_hostages.wav"
"10" "bot/i_see_our_target.wav"
"11" "bot/im_waiting_here.wav"
"12" "bot/keeping_an_eye_on_the_hostages.wav"
"13" "bot/nnno_sir.wav"
"14" "bot/spotted_the_delivery_boy.wav"
"15" "bot/target_acquired.wav"
"16" "bot/target_spotted.wav"
"17" "bot/you_heard_the_man_lets_go.wav"
}
@@ -0,0 +1,131 @@
"TableToKeyValues"
{
"1" "ambient/alarms/apc_alarm_pass1.wav"
"2" "ambient/alarms/manhack_alert_pass1.wav"
"3" "ambient/alarms/razortrain_horn1.wav"
"4" "ambient/alarms/scanner_alert_pass1.wav"
"5" "ambient/alarms/train_horn2.wav"
"6" "ambient/alarms/train_horn_distant1.wav"
"7" "ambient/alarms/warningbell1.wav"
"8" "ambient/energy/whiteflash.wav"
"9" "ambient/intro/alyxremove.wav"
"10" "ambient/intro/logosfx.wav"
"11" "ambient/levels/launch/1stfiringwarning.wav"
"12" "ambient/levels/launch/rockettakeoffblast.wav"
"13" "ambient/misc/ambulance1.wav"
"14" "ambient/misc/carhonk1.wav"
"15" "ambient/misc/carhonk2.wav"
"16" "ambient/misc/carhonk3.wav"
"17" "ambient/outro/gunshipcrash.wav"
"18" "ambient/3dmeagle.wav"
"19" "beams/beamstart5.wav"
"20" "buttons/bell1.wav"
"21" "buttons/weapon_cant_buy.wav"
"22" "common/bass.wav"
"23" "common/bugreporter_failed.wav"
"24" "common/warning.wav"
"25" "doors/door_squeek1.wav"
"26" "friends/friend_join.wav"
"27" "friends/friend_online.wav"
"28" "friends/message.wav"
"29" "hostage/hunuse/comeback.wav"
"30" "hostage/hunuse/dontleaveme.wav"
"31" "hostage/hunuse/yeahillstay.wav"
"32" "items/gift_drop.wav"
"33" "music/radio1.mp3"
"34" "phx/eggcrack.wav"
"35" "plats/elevbell1.wav"
"36" "player/headshot1.wav"
"37" "player/headshot2.wav"
"38" "player/sprayer.wav"
"39" "radio/enemydown.wav"
"40" "radio/go.wav"
"41" "radio/locknload.wav"
"42" "radio/negative.wav"
"43" "radio/rounddraw.wav"
"44" "radio/takepoint.wav"
"45" "resource/warning.wav"
"46" "ui/achievement_earned.wav"
"47" "ui/freeze_cam.wav"
"48" "vehicles/junker/radar_ping_friendly1.wav"
"49" "weapons/c4/c4_beep1.wav"
"50" "weapons/c4/c4_click.wav"
"51" "weapons/awp/awp1.wav"
"52" "vo/canals/female01/gunboat_giveemhell.wav"
"53" "vo/canals/female01/gunboat_justintime.wav"
"54" "vo/canals/female01/stn6_incoming.wav"
"55" "vo/canals/male01/gunboat_giveemhell.wav"
"56" "vo/canals/male01/gunboat_justintime.wav"
"57" "vo/canals/male01/stn6_incoming.wav"
"58" "vo/canals/al_radio_stn6.wav"
"59" "vo/canals/arrest_getgoing.wav"
"60" "vo/canals/arrest_helpme.wav"
"61" "vo/canals/arrest_lookingforyou.wav"
"62" "vo/canals/boxcar_lethimhelp.wav"
"63" "vo/canals/matt_closecall.wav"
"64" "vo/canals/premassacre.wav"
"65" "vo/ravenholm/aimforhead.wav"
"66" "vo/ravenholm/bucket_patience.wav"
"67" "vo/ravenholm/madlaugh01.wav"
"68" "vo/ravenholm/madlaugh02.wav"
"69" "vo/ravenholm/madlaugh03.wav"
"70" "vo/ravenholm/madlaugh04.wav"
"71" "weapons/strider_buster/ol12_stickybombcreator.wav"
"72" "weapons/c4/c4_explode1.wav"
"73" "weapons/357/357_fire2.wav"
"74" "weapons/357/357_fire3.wav"
"75" "weapons/scout/scout_fire-1.wav"
"76" "weapons/smokegrenade/sg_explode.wav"
"77" "weapons/grenade_launcher1.wav"
"78" "weapons/explode3.wav"
"79" "weapons/underwater_explode3.wav"
"80" "items/nvg_on.wav"
"81" "hostage/huse/letsdoit.wav"
"82" "hostage/huse/illfollow.wav"
"83" "hostage/huse/getouttahere.wav"
"84" "doors/door_screen_move1.wav"
"85" "doors/heavy_metal_stop1.wav"
"86" "doors/default_move.wav"
"87" "common/stuck2.wav"
"88" "ambient/water_splash1.wav"
"89" "ambient/water_splash2.wav"
"90" "ambient/water_splash3.wav"
"91" "ambient/weather/thunder1.wav"
"92" "ambient/weather/thunder2.wav"
"93" "ambient/weather/thunder3.wav"
"94" "ambient/weather/thunder4.wav"
"95" "ambient/weather/thunder5.wav"
"96" "ambient/weather/thunder6.wav"
"97" "ambient/outro/thunder7.wav"
"98" "ambient/voices/crying_loop1.wav"
"99" "ambient/voices/playground_memory.wav"
"100" "ambient/voices/f_scream1.wav"
"101" "ambient/voices/m_scream1.wav"
"102" "ambient/voices/cough1.wav"
"103" "ambient/voices/cough2.wav"
"104" "ambient/voices/cough3.wav"
"105" "ambient/voices/cough4.wav"
"106" "ambient/overhead/plane1.wav"
"107" "ambient/overhead/plane2.wav"
"108" "ambient/overhead/plane3.wav"
"109" "ambient/overhead/hel1.wav"
"110" "ambient/overhead/hel2.wav"
"111" "ambient/misc/truck_backup1.wav"
"112" "ambient/misc/truck_drive1.wav"
"113" "ambient/misc/truck_drive2.wav"
"114" "ambient/machines/pneumatic_drill_1.wav"
"115" "ambient/machines/pneumatic_drill_2.wav"
"116" "ambient/machines/pneumatic_drill_3.wav"
"117" "ambient/machines/pneumatic_drill_4.wav"
"118" "ambient/machines/station_train_squeel.wav"
"119" "ambient/machines/ticktock.wav"
"120" "ambient/creatures/teddy.wav"
"121" "ambient/creatures/town_child_scream1.wav"
"122" "ambient/creatures/town_moan1.wav"
"123" "ambient/creatures/town_muffled_cry1.wav"
"124" "ambient/creatures/town_scared_breathing1.wav"
"125" "ambient/creatures/town_scared_breathing2.wav"
"126" "ambient/creatures/town_scared_sob1.wav"
"127" "ambient/creatures/town_scared_sob2.wav"
"128" "ambient/creatures/town_zombie_call1.wav"
}
@@ -0,0 +1,52 @@
"TableToKeyValues"
{
"1" "bot/and_thats_how_its_done.wav"
"2" "bot/come_to_papa.wav"
"3" "bot/do_not_mess_with_me.wav"
"4" "bot/dropped_him.wav"
"5" "bot/enemy_down.wav"
"6" "bot/enemy_down2.wav"
"7" "bot/good_job_team.wav"
"8" "bot/got_him.wav"
"9" "bot/hes_broken.wav"
"10" "bot/hes_dead.wav"
"11" "bot/hes_done.wav"
"12" "bot/hes_down.wav"
"13" "bot/its_a_party.wav"
"14" "bot/i_am_dangerous.wav"
"15" "bot/i_am_on_fire.wav"
"16" "bot/i_got_more_where_that_came_from.wav"
"17" "bot/i_wasnt_worried_for_a_minute.wav"
"18" "bot/killed_him.wav"
"19" "bot/look_out_brag.wav"
"20" "bot/made_him_cry.wav"
"21" "bot/oh_yea.wav"
"22" "bot/oh_yea2.wav"
"23" "bot/owned.wav"
"24" "bot/ruined_his_day.wav"
"25" "bot/tag_them_and_bag_them.wav"
"26" "bot/thats_the_way_this_is_done.wav"
"27" "bot/that_was_a_close_one.wav"
"28" "bot/that_was_it.wav"
"29" "bot/that_was_the_last_guy.wav"
"30" "bot/that_was_the_last_one.wav"
"31" "bot/they_never_knew_what_hit_them.wav"
"32" "bot/they_will_not_escape.wav"
"33" "bot/they_wont_get_away.wav"
"34" "bot/they_wont_get_away2.wav"
"35" "bot/this_is_my_house.wav"
"36" "bot/took_him_down.wav"
"37" "bot/took_him_out.wav"
"38" "bot/took_him_out2.wav"
"39" "bot/wasted_him.wav"
"40" "bot/way_to_be_team.wav"
"41" "bot/well_done.wav"
"42" "bot/we_owned_them.wav"
"43" "bot/whew_that_was_close.wav"
"44" "bot/whoo.wav"
"45" "bot/whoo2.wav"
"46" "bot/whos_the_man.wav"
"47" "bot/who_wants_some_more.wav"
"48" "bot/yesss.wav"
"49" "bot/yesss2.wav"
}
@@ -0,0 +1,7 @@
-- Include needed files
include("shared.lua")
-- Draw entity model.
function ENT:Draw()
self:DrawModel()
end
@@ -0,0 +1,8 @@
--Thanks to Blasteh for gmod update the fix and nifnat for spectate fix!
-- Send required files to client
AddCSLuaFile("cl_init.lua")
AddCSLuaFile("shared.lua")
-- Include needed files
include("shared.lua")
@@ -0,0 +1,24 @@
-- Entity information
ENT.Type = "anim"
ENT.Base = "base_anim"
-- Initialize
function ENT:Initialize()
self:SetModel("models/Kleiner.mdl")
self:SetCollisionGroup(COLLISION_GROUP_PLAYER)
self:SetSolid(SOLID_OBB)
self:SetRenderMode(RENDERMODE_TRANSALPHA)
self:SetColor(Color(255,255,255,255))
end
-- Update position
function ENT:Think()
local hullOBBMin = self:OBBMins()
local hullOBBMax = self:OBBMaxs()
local hullOBB = hullOBBMax - hullOBBMin
local pos = -Vector(0, 0, hullOBBMin.z)
self:SetPos(self.Owner:GetPos() + pos)
self:SetVelocity(self:GetOwner():GetVelocity())
end
--]]
@@ -0,0 +1,218 @@
-- SWEP Information
SWEP.Author = "Michael 'Xaymar' Dirks"
SWEP.Contact = "info@project-kube.de"
SWEP.Purpose = "More accurate SMG for Prop Hunt."
SWEP.Instructions = "Fire away! Alternative fire to fire a grenade."
SWEP.Category = "Prop Hunt Weapons"
-- Weapon Information
SWEP.Weight = 5
SWEP.AutoSwitchTo = false
SWEP.AutoSwitchFrom = false
SWEP.Slot = 2
SWEP.SlotPos = 1
SWEP.DrawAmmo = true
SWEP.DrawCrosshair = true
-- Weapon is spawnable for everyone, not just administrators.
SWEP.Spawnable = true
SWEP.AdminSpawnable = true
-- Model
SWEP.ViewModel = "models/weapons/c_smg1.mdl"
SWEP.WorldModel = "models/weapons/w_smg1.mdl"
SWEP.UseHands = true
-- Primary Ammunition: SMG
SWEP.Primary.ClipSize = 45
SWEP.Primary.DefaultClip = 45
SWEP.Primary.Automatic = true
SWEP.Primary.Ammo = "SMG1"
SWEP.Primary.Damage = 5
-- Secondary Ammunition: SMG Grenades
SWEP.Secondary.ClipSize = 1
SWEP.Secondary.DefaultClip = 0
SWEP.Secondary.Automatic = false
SWEP.Secondary.Ammo = "SMG1_Grenade"
SWEP.Secondary.Damage = 100
-- Recoil
SWEP.Recoil = {}
SWEP.Recoil.SingleFire = 1.0
SWEP.Recoil.BurstFire = 4.0
SWEP.Recoil.SecondaryFire = 8.0
-- Accuracy
SWEP.Accuracy = {}
SWEP.Accuracy.Primary = {}
SWEP.Accuracy.Primary.Min = 0.975
SWEP.Accuracy.Primary.Max = 1.00
SWEP.Accuracy.Primary.Reduction = 0.005
SWEP.Accuracy.Primary.Recovery = 0.0025
SWEP.Accuracy.Primary.Delay = 0.1
SWEP.Accuracy.Secondary = {}
SWEP.Accuracy.Secondary.Min = 1.00
SWEP.Accuracy.Secondary.Max = 1.00
SWEP.Accuracy.Secondary.Reduction = 0.00
SWEP.Accuracy.Secondary.Recovery = 0.00
SWEP.Accuracy.Secondary.Delay = 0.00
-- Sounds
SWEP.Sound = {}
SWEP.Sound.SwitchSingle = "weapons/smg1/switch_single.wav"
SWEP.Sound.SwitchBurst = "weapons/smg1/switch_burst.wav"
SWEP.Sound.SingleFire = "weapons/smg1/smg1_fire1.wav"
SWEP.Sound.BurstFire = "weapons/smg1/smg1_fireburst1.wav"
SWEP.Sound.SecondaryFire = "weapons/ar2/ar2_altfire.wav"
SWEP.Sound.Reload = "weapons/smg1/smg1_reload.wav"
SWEP.Sound.NoPrimaryAmmo = "weapons/pistol/pistol_empty.wav"
SWEP.Sound.NoSecondaryAmmo = "weapons/pistol/pistol_empty.wav"
-- Initialization
function SWEP:Initialize()
-- Set holding type to smg.
self:SetHoldType("smg");
-- Precache sounds for lagless experience.
for i,v in ipairs(self.Sound) do
util.PrecacheSound(v)
end
-- Initialize default values.
self.BurstFire = false
self.PrimaryAccuracy = self.Accuracy.Primary.Max
self.LastPrimaryAttack = CurTime()
self.SecondaryAccuracy = self.Accuracy.Secondary.Max
self.LastSecondaryAttack = CurTime()
end
-- Primary Attack
function SWEP:CanPrimaryAttack()
-- Check if there is ammo in the clip.
if (self:Clip1() <= 0) then
-- If not, check if there's ammo available.
if (self:Ammo1() > 0) then
-- If yes, reload and wait for weapon to be ready again.
self:EmitSound(self.Sound.NoPrimaryAmmo)
self:Reload()
return false
end
-- If no, emit empty sound for primary fire.
self:EmitSound(self.Sound.NoPrimaryAmmo)
self:SetNextPrimaryFire(CurTime() + 0.1)
return false
end
-- Otherwise, return true.
return true
end
function SWEP:PrimaryAttack()
-- Can't fire without Ammo
if (!self:CanPrimaryAttack()) then return end
if (self.BurstFire == false) then
-- Single Mode: fire and take one bullet from the clip.
self:ShootBullet(self.Primary.Damage, bullet_count, 1.0 - self.PrimaryAccuracy)
self:TakePrimaryAmmo(1)
self:EmitSound(self.Sound.SingleFire)
self:SetNextPrimaryFire( CurTime() + 0.1 )
-- Apply recoil
self.Owner:ViewPunch( Angle(-1, 0, 0) * self.Recoil.SingleFire * (1 + (1 - self.PrimaryAccuracy)) )
-- Decrease accuracy
self.PrimaryAccuracy = math.Clamp(self.PrimaryAccuracy - self.Accuracy.Primary.Reduction, self.Accuracy.Primary.Min, self.Accuracy.Primary.Max)
else
-- Burst Mode: fire and take up to three bullets from the clip
local bulletCount = math.Clamp(self:Clip1(), 1, 3)
self:ShootBullet(self.Primary.Damage, bullet_count, 1.0 - self.PrimaryAccuracy)
self:TakePrimaryAmmo(bulletCount)
self:EmitSound(self.Sound.BurstFire)
self:SetNextPrimaryFire( CurTime() + 0.5 * (bulletCount / 3.0) )
-- Apply recoil
self.Owner:ViewPunch(Angle(-1, 0, 0) * self.Recoil.BurstFire * (bulletCount / 3.0) * (1 + (1 - self.PrimaryAccuracy)))
-- Decrease accuracy
self.PrimaryAccuracy = math.Clamp(self.PrimaryAccuracy - self.Accuracy.Primary.Reduction * bulletCount, self.Accuracy.Primary.Min, self.Accuracy.Primary.Max)
end
-- Set Animation and attack time.
self:SendWeaponAnim(ACT_VM_PRIMARYATTACK)
self.LastPrimaryAttack = CurTime()
return
end
-- Secondary Attack
function SWEP:CanSecondaryAttack()
if (self:Clip2() == 0) then
if (self:Ammo2() == 0) then
self:EmitSound(self.Sound.NoSecondaryAmmo)
self:SetNextSecondaryFire( CurTime() + 1.0 )
return false
else
self:SetClip2( 1 )
self.Owner:SetAmmo( self.Owner:GetAmmoCount( self:GetSecondaryAmmoType() ) - 1, self:GetSecondaryAmmoType() )
end
end
return true
end
function SWEP:SecondaryAttack()
-- Can't fire without Ammo
if (!self:CanSecondaryAttack()) then return end
-- Emit a sound.
self:EmitSound(self.Sound.SecondaryFire)
self:SetNextSecondaryFire( CurTime() + 1.0 )
self:TakeSecondaryAmmo(1)
-- Create grenade
if SERVER then
local grenade = ents.Create("grenade_ar2")
if (!IsValid(grenade)) then return end
grenade:SetPos( self.Owner:GetShootPos() + self.Owner:GetAimVector() * 30 )
grenade:SetVelocity( self.Owner:GetAimVector() * 1000 )
grenade:SetAngles( self.Owner:GetAngles() )
grenade:SetOwner( self.Owner )
grenade:Spawn()
grenade:SetPhysicsAttacker( self.Owner, 60 )
end
-- Set Animation and attack time.
self:SendWeaponAnim(ACT_VM_SECONDARYATTACK)
self.LastSecondaryAttack = CurTime()
return
end
-- Reload: Combination of reloading and switching fire type.
function SWEP:Reload()
if self:DefaultReload(ACT_VM_RELOAD) then
self:EmitSound(self.Sound.Reload)
else
if (self.LastReload) && ((CurTime() - self.LastReload) > 1) then
self:GetOwner():ChatPrint("BurstToggle")
self.BurstFire = !self.BurstFire
end
end
self.LastReload = CurTime()
return
end
-- Think: Restore accuracy over time.
function SWEP:Think()
local ThinkTime = CurTime()
if (ThinkTime >= (self.LastPrimaryAttack + self.Accuracy.Primary.Delay)) then
self.PrimaryAccuracy = math.Clamp(self.PrimaryAccuracy + self.Accuracy.Primary.Recovery, self.Accuracy.Primary.Min, self.Accuracy.Primary.Max)
end
if (ThinkTime >= (self.LastSecondaryAttack + self.Accuracy.Secondary.Delay)) then
self.SecondaryAccuracy = math.Clamp(self.SecondaryAccuracy + self.Accuracy.Secondary.Recovery, self.Accuracy.Secondary.Min, self.Accuracy.Secondary.Max)
end
end
@@ -0,0 +1,290 @@
--[[
The MIT License (MIT)
Copyright (c) 2015 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
-- ------------------------------------------------------------------------- --
--! Includes
-- ------------------------------------------------------------------------- --
include("sh_init.lua")
include("client/cl_ui_teamselection.lua")
-- ------------------------------------------------------------------------- --
--! Code
-- ------------------------------------------------------------------------- --
function GM:Initialize()
print("-------------------------------------------------------------------------")
print("Prop Hunt CL: Initializing...")
print("Prop Hunt CL: Initializing Gamemode Data...")
self.Data = {}
print("Prop Hunt CL: Creating Huge Ass Font...")
surface.CreateFont("PHHugeAssFont", {font="Roboto Bold Condensed", extended=true, size=160, weight=800, antialias=true})
print("Prop Hunt CL: Complete.")
print("-------------------------------------------------------------------------")
end
function GM:Think() end
function GM:InitialPlayerSpawn()
print("Prop Hunt CL: InitialPlayerSpawn")
-- Delay execution until LocalPlayer() is valid.
if (!LocalPlayer()) || (!IsValid(LocalPlayer())) then
timer.Simple(.1, function() GAMEMODE:InitialPlayerSpawn() end)
return
end
print("Prop Hunt CL: InitialPlayerSpawn Valid")
player_manager.RunClass(LocalPlayer(), "InitialClientSpawn")
end
function GM:PlayerSpawn()
print("Prop Hunt CL: PlayerSpawn")
-- Delay execution until LocalPlayer() is valid.
if (!LocalPlayer()) || (!IsValid(LocalPlayer())) then
timer.Simple(.1, function() GAMEMODE:PlayerSpawn() end)
return
end
print("Prop Hunt CL: PlayerSpawn Valid")
if !(LocalPlayer().Data) then
LocalPlayer().Data = {}
LocalPlayer().Data.ThirdPerson = true
end
player_manager.RunClass(LocalPlayer(), "ClientSpawn")
end
function GM:HUDPaint()
local State = GetGlobalInt("RoundState", GAMEMODE.States.PreMatch)
-- Show Status at the top center
local statusX, statusY, statusW, statusH
statusW = 192
statusH = 64
statusX = ScrW() / 2 - statusW / 2
statusY = 16
--! States
-- Pre Match
if (State == GAMEMODE.States.PreMatch) then
-- Show Status at the top center
draw.RoundedBox(16, statusX, statusY, statusW, statusH, Color(0, 0, 0, 204))
surface.SetFont( "Trebuchet24" )
surface.SetTextColor( 255, 255, 255, 255 )
local w,h = surface.GetTextSize("Waiting...")
surface.SetTextPos( statusX + statusW/2 - w / 2, statusY + statusH/2 - h / 2)
surface.DrawText( "Waiting..." )
-- Pre Round
elseif (State == GAMEMODE.States.PreRound) then
-- Show Status at the top center
draw.RoundedBox(16, statusX, statusY, statusW, statusH, Color(0, 0, 0, 204))
surface.SetFont( "Trebuchet24" )
surface.SetTextColor( 255, 255, 255, 255 )
local w,h = surface.GetTextSize("Preparing...")
surface.SetTextPos( statusX + statusW/2 - w / 2, statusY + statusH/2 - h / 2)
surface.DrawText( "Preparing..." )
-- Hide!
elseif (State == GAMEMODE.States.Hide) then
local strTime = tostring(math.ceil(GetGlobalInt("RoundTime")))
-- Show Status at the top center
draw.RoundedBox(16, statusX, statusY, statusW, statusH, Color(0, 0, 0, 204))
surface.SetTextColor(255,255,255,255)
surface.SetFont("Trebuchet18")
local w,h = surface.GetTextSize("Seekers unblinded in:")
surface.SetTextPos(statusX + statusW/2 - w / 2, statusY + statusH/4 - h / 2)
surface.DrawText("Seekers unblinded in:")
surface.SetFont( "Trebuchet24" )
local w,h = surface.GetTextSize(strTime.." Seconds!")
surface.SetTextPos( statusX + statusW/2 - w / 2, statusY + statusH/1.5 - h / 2)
surface.DrawText(strTime.." Seconds!")
elseif (State == GAMEMODE.States.Seek) then
local intTime = math.ceil(GetGlobalInt("RoundTime"))
local strTime = string.format("%d:%02d", math.floor(intTime / 60), math.ceil(intTime % 60))
-- Show Status at the top center
draw.RoundedBox(16, statusX, statusY, statusW, statusH, Color(0, 0, 0, 204))
surface.SetTextColor(255,255,255,255)
surface.SetFont("Trebuchet18")
local w,h = surface.GetTextSize("Hunting Time!")
surface.SetTextPos(statusX + statusW/2 - w / 2, statusY + statusH/4 - h / 2)
surface.DrawText("Hunting Time!")
surface.SetFont( "Trebuchet24" )
local w,h = surface.GetTextSize(strTime)
surface.SetTextPos( statusX + statusW/2 - w / 2, statusY + statusH/1.5 - h / 2)
surface.DrawText(strTime)
elseif (State == GAMEMODE.States.PostRound) then
elseif (State == GAMEMODE.States.PostMatch) then
end
player_manager.RunClass(LocalPlayer(), "HUDPaint")
end
function GM:ShowTeamSelection()
TeamSelectionUI:Show()
end
concommand.Add("ph_select_team", function() GAMEMODE:ShowTeamSelection() end)
function GM:GetHandsModel()
return player_manager.RunClass(LocalPlayer(), "GetHandsModel")
end
function GM:PostDrawViewModel( vm, ply, weapon )
if ( weapon.UseHands || !weapon:IsScripted() ) then
local hands = LocalPlayer():GetHands()
if ( IsValid( hands ) ) then hands:DrawModel() end
end
end
-- ------------------------------------------------------------------------- --
--! Player Manager Binding
-- ------------------------------------------------------------------------- --
function GM:CalcView(ply, pos, ang, fov, nearZ, farZ)
return player_manager.RunClass(LocalPlayer(), "CalcView", {origin = pos, angles = ang, fov = fov, znear = nearZ, zfar = farZ})
end
-- ------------------------------------------------------------------------- --
--! Gamemode Functionality
-- ------------------------------------------------------------------------- --
function GM:PlayerSetViewOffset(vo, voduck)
-- Delay execution until LocalPlayer() is valid.
if (!LocalPlayer()) || (!IsValid(LocalPlayer())) then
if !(GAMEMODE.TempData) then GAMEMODE.TempData = {} end
GAMEMODE.TempData.ViewOffset = vo
GAMEMODE.TempData.ViewOffsetDuck = voduck
timer.Simple(.1, function() GAMEMODE:PlayerSetViewOffset(GAMEMODE.TempData.ViewOffset, GAMEMODE.TempData.ViewOffsetDuck) end)
return
end
LocalPlayer():SetViewOffset(vo)
LocalPlayer():SetViewOffsetDucked(voduck)
if LocalPlayer():Crouching() then
LocalPlayer():SetCurrentViewOffset(voduck)
else
LocalPlayer():SetCurrentViewOffset(vo)
end
end
function GM:PlayerSetHull(hullMin, hullMax)
-- Delay execution until LocalPlayer() is valid.
if (!LocalPlayer()) || (!IsValid(LocalPlayer())) then
if !(GAMEMODE.TempData) then GAMEMODE.TempData = {} end
GAMEMODE.TempData.HullMin = hullMin
GAMEMODE.TempData.HullMax = hullMax
timer.Simple(.1, function() GAMEMODE:PlayerSetHull(GAMEMODE.TempData.HullMin, GAMEMODE.TempData.HullMax) end)
return
end
if (hullMin == hullMax) && (hullMin == nil) then
LocalPlayer():ResetHull()
else
LocalPlayer():SetHull(hullMin, hullMax)
LocalPlayer():SetHullDuck(hullMin, hullMax)
end
end
-- ------------------------------------------------------------------------- --
--! Commands
-- ------------------------------------------------------------------------- --
function GM:OnContextMenuOpen()
end
function GM:OnContextMenuClose()
print("Prop Hunt CL: Toggled View Mode")
LocalPlayer().Data.ThirdPerson = !LocalPlayer().Data.ThirdPerson
end
-- ------------------------------------------------------------------------- --
--! Network Messages
-- ------------------------------------------------------------------------- --
net.Receive("PlayerManagerInitialClientSpawn", function(len, pl) GAMEMODE:InitialPlayerSpawn() end)
net.Receive("PlayerManagerClientSpawn", function(len, pl) GAMEMODE:PlayerSpawn() end)
net.Receive( "PlayerSetHull", function(len, pl)
local hullMin, hullMax = net.ReadVector(), net.ReadVector();
GAMEMODE:PlayerSetHull(hullMin, hullMax)
end)
net.Receive( "PlayerResetHull", function(len, pl) GAMEMODE:PlayerSetHull(nil, nil) end)
net.Receive( "PlayerViewOffset", function(len, pl)
local vo, voduck = net.ReadVector(), net.ReadVector()
GAMEMODE:PlayerSetViewOffset(vo, voduck)
end)
-- ------------------------------------------------------------------------- --
--! Old Code
-- ------------------------------------------------------------------------- --
--[[
-- Render halos and player names.
function DrawPlayerNames(bDrawingDepth, bDrawingSkybox)
for i,v in ipairs(player.GetAll()) do
if v:Alive() && v != LocalPlayer() then
local pos = v:GetPos() + v:GetViewOffset() + Vector(0, 0, 5)
local ang = Angle(0, LocalPlayer():EyeAngles().y - 90, 90 - LocalPlayer():EyeAngles().x)
local healthPrc = v:Health() / v:GetMaxHealth()
local healthCol = HSVToColor(120 * healthPrc, 1.0, 1.0)
if v:Team() == TEAM_HUNTERS || LocalPlayer():Team() == TEAM_PROPS then
cam.Start3D2D(pos, ang, 0.15)
draw.DrawText(v:GetName(), "Trebuchet24", 0, -draw.GetFontHeight("Trebuchet24"), healthCol, TEXT_ALIGN_CENTER)
cam.End3D2D()
end
end
end
end
hook.Add("PostDrawTranslucentRenderables", "PH_DrawPlayerNames", DrawPlayerNames)
function DrawPlayerHalos(bDrawingDepth, bDrawingSkybox)
for i,v in ipairs(player.GetAll()) do
if v:Alive() then
local pos = v:GetPos() + Vector(0, 0, 1) * (v:OBBMaxs().z - v:OBBMins().z + 5)
local ang = Angle(0, LocalPlayer():EyeAngles().y - 90, 90 - LocalPlayer():EyeAngles().x)
local healthPrc = v:Health() / v:GetMaxHealth()
local healthCol = HSVToColor(120 * healthPrc, 1.0, 1.0)
if v:Team() == TEAM_HUNTERS || LocalPlayer():Team() == TEAM_PROPS then
local ent = v
if v.ph_prop && v.ph_prop:IsValid() then ent = v.ph_prop end
halo.Add({ent}, healthCol, 2, 2, 1)
end
end
end
end
--hook.Add("PostDrawEffects", "PH_DrawPlayerHalos", DrawPlayerHalos)
]]
@@ -0,0 +1,75 @@
--[[
The MIT License (MIT)
Copyright (c) 2015 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
TeamSelectionUI = {}
TeamSelectionUI.Frame = vgui.Create("DFrame")
TeamSelectionUI.Frame:SetPos(0, 0)
TeamSelectionUI.Frame:SetSize(400, 320)
TeamSelectionUI.Frame:Center()
TeamSelectionUI.Frame:SetTitle("Select a Team")
TeamSelectionUI.Frame:SetVisible(false)
TeamSelectionUI.Frame:SetDraggable(true)
TeamSelectionUI.Frame:SetSizable(false)
TeamSelectionUI.Frame:ShowCloseButton(true)
TeamSelectionUI.Frame:SetDeleteOnClose(false)
function TeamSelectionUI.Frame:Paint(w, h)
draw.RoundedBox(0, 0, 0, w, h, Color(0, 0, 0, 225))
end
function TeamSelectionUI:Show()
self.Frame:MakePopup()
TeamSelectionUI.Frame:SetVisible(true)
end
function TeamSelectionUI:Hide()
TeamSelectionUI.Frame:Close()
TeamSelectionUI.Frame:SetVisible(false)
end
TeamSelectionUI.SelectSeeker = vgui.Create("DButton", TeamSelectionUI.Frame)
TeamSelectionUI.SelectSeeker:SetPos(0, 20)
TeamSelectionUI.SelectSeeker:SetSize(200, 200)
TeamSelectionUI.SelectSeeker:SetText("Seeker")
TeamSelectionUI.SelectSeeker.DoClick = function()
TeamSelectionUI:Hide()
LocalPlayer():ConCommand("changeteam " .. tostring(GAMEMODE.Teams.Seekers))
end
TeamSelectionUI.SelectHider = vgui.Create("DButton", TeamSelectionUI.Frame)
TeamSelectionUI.SelectHider:SetPos(200, 20)
TeamSelectionUI.SelectHider:SetSize(200, 200)
TeamSelectionUI.SelectHider:SetText("Hiders")
TeamSelectionUI.SelectHider.DoClick = function()
TeamSelectionUI:Hide()
LocalPlayer():ConCommand("changeteam " .. tostring(GAMEMODE.Teams.Hiders))
end
TeamSelectionUI.Spectate = vgui.Create("DButton", TeamSelectionUI.Frame)
TeamSelectionUI.Spectate:SetPos(0, 220)
TeamSelectionUI.Spectate:SetSize(400, 100)
TeamSelectionUI.Spectate:SetText("Spectate")
TeamSelectionUI.Spectate.DoClick = function()
TeamSelectionUI:Hide()
LocalPlayer():ConCommand("changeteam " .. tostring(GAMEMODE.Teams.Spectators))
end
@@ -0,0 +1,49 @@
--[[
The MIT License (MIT)
Copyright (c) 2015 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
-- This file adds compatability to the older Taunt Pack loader format, which
-- directly modifies the gamemode tables (something that shouldn't be done).
function CompatTauntPackLoader()
-- Prepare an empty table for the taunts.
GAMEMODE.Prop_Taunts = {}
GAMEMODE.Hunter_Taunts = {}
-- 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))
end
for k,v in ipairs(GAMEMODE.Prop_Taunts) do
--pcall(GAMEMODE.Config.Taunts.Add("TauntPackLoader."..string.GetFileFromFilename(v), v, TEAM_HIDERS, nil))
end
-- Clean up after ourselves
GAMEMODE.Prop_Taunts = nil
GAMEMODE.Hunter_Taunts = nil
end
hook.Add("OnPropHuntInitialized", "CompatTauntPackLoader", CompatTauntPackLoader)
@@ -0,0 +1,414 @@
--[[
The MIT License (MIT)
Copyright (c) 2015 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
-- ------------------------------------------------------------------------- --
--! Downloadable Lua
-- ------------------------------------------------------------------------- --
-- Shared
AddCSLuaFile("sh_init.lua")
AddCSLuaFile("sh_config.lua")
AddCSLuaFile("sh_player.lua")
AddCSLuaFile("player_class/class_default.lua")
AddCSLuaFile("player_class/class_spectator.lua")
AddCSLuaFile("player_class/class_seeker.lua")
AddCSLuaFile("player_class/class_hider.lua")
-- Client-Only
AddCSLuaFile("cl_init.lua")
AddCSLuaFile("client/cl_ui_teamselection.lua")
-- ------------------------------------------------------------------------- --
--! Code
-- ------------------------------------------------------------------------- --
-- Shared
include "sh_init.lua"
-- Server Only
include "server/config.lua"
include "compat/compat_tauntpackloader.lua"
include "server/roundmanager.lua"
include "server/states/state_prematch.lua"
include "server/states/state_preround.lua"
include "server/states/state_hide.lua"
include "server/states/state_seek.lua"
include "server/states/state_postround.lua"
function GM:Initialize()
print("-------------------------------------------------------------------------")
print("Prop Hunt: Initializing...")
print("Prop Hunt: Registering Networked Messages...")
util.AddNetworkString("PlayerManagerInitialClientSpawn")
util.AddNetworkString("PlayerManagerClientSpawn")
util.AddNetworkString("PlayerSetHull")
util.AddNetworkString("PlayerResetHull")
util.AddNetworkString("PlayerViewOffset")
util.AddNetworkString("PlayerRegisterPropEntity")
print("Prop Hunt: Initializing Gamemode Data...")
self.Data = {}
print("Prop Hunt: Setting initial RoundManager State...")
self.RoundManager:SetState(StatePreMatch)
print("Prop Hunt: Complete.")
print("-------------------------------------------------------------------------")
end
function GM:Think()
self.RoundManager:Tick()
end
-- Player Connected
function GM:PlayerConnect(name, ip)
print("Prop Hunt: Player '"..name.."' connecting from IP '"..ip.."'.")
end
-- Player Authenticated
function GM:PlayerAuthed(ply, steamid, uniqueid)
print("Prop Hunt: Player '"..ply:GetName().."' (SteamID: "..ply:SteamID()..") authenticated.")
end
-- Player Disconnected
function GM:PlayerDisconnected(ply)
print("Prop Hunt: Player '"..ply:GetName().."' (SteamID: "..ply:SteamID()..") disconnected.")
end
-- Player Spawn (Initial)
function GM:PlayerInitialSpawn(ply)
print("Prop Hunt: Player '"..ply:GetName().."' (SteamID: "..ply:SteamID()..") spawned for the first time, applying defaults...")
if (!ply.Data) then
-- Initialize Data Structure
ply.Data = {}
ply.Data.Alive = false
ply.Data.AliveTime = 0
end
-- Kill Silently
ply:KillSilent()
-- Show Team Selection Menu
ply:SetTeam(GAMEMODE.Teams.Spectators)
self:ShowTeam(ply)
-- Bot: Auto Assign to Team
if (ply:IsBot()) then
if team.NumPlayers(self.Teams.Hiders) > team.NumPlayers(self.Teams.Seekers) then
print("Prop Hunt: Bot '"..ply:GetName().."' assigned to Seekers.")
ply:SetTeam(self.Teams.Seekers)
else
print("Prop Hunt: Bot '"..ply:GetName().."' assigned to Hiders.")
ply:SetTeam(self.Teams.Hiders)
end
end
-- Notify Player Manager
player_manager.RunClass(ply, "InitialSpawn")
-- Signal Client
net.Start("PlayerManagerInitialClientSpawn");net.Send(ply)
end
-- Player Spawn
function GM:PlayerSpawn(ply)
print("Prop Hunt: Player '"..ply:GetName().."' (SteamID: "..ply:SteamID()..") spawned in.")
-- Player Manager: Assign Player Class
local class = team.GetClass(ply:Team())
if (class) then
if (ply.Data.Alive) then -- Alive Class
player_manager.SetPlayerClass(ply, class[1])
else -- Dead Class (Spectator)
player_manager.SetPlayerClass(ply, class[2])
end
else
player_manager.SetPlayerClass(ply, "Spectator")
end
-- Notify Player Manager
player_manager.OnPlayerSpawn(ply)
player_manager.RunClass(ply, "Spawn")
-- Some hooks are not called
hook.Call("PlayerSetModel", self, ply)
hook.Call("PlayerLoadout", self, ply)
-- Signal Client
net.Start("PlayerManagerClientSpawn");net.Send(ply)
end
-- Player requests Team Change
function GM:PlayerRequestTeam(ply, teamId)
if self:PlayerCanJoinTeam(ply, teamId) then
print("Prop Hunt: Player '"..ply:GetName().."' (SteamID: "..ply:SteamID()..") requested to join Team "..team.GetName(teamId)..".")
if (ply:Team() != teamId) then
ply:KillSilent()
ply:SetTeam(teamId)
if (GetGlobalInt("RoundState", GAMEMODE.States.PreMatch) <= GAMEMODE.States.PreRound) then
ply.Alive = true
ply.AliveTime = CurTime()
end
else
print("Prop Hunt: Player '"..ply:GetName().."' (SteamID: "..ply:SteamID()..") attempted to rejoin the Team it is already in.")
end
end
end
-- ------------------------------------------------------------------------- --
--! Player Manager Binding
-- ------------------------------------------------------------------------- --
function GM:PlayerLoadout(ply) player_manager.RunClass(ply, "Loadout") end
function GM:PlayerDeath(ply, inflictor, attacker) player_manager.RunClass(ply, "Death", inflictor, attacker) end
function GM:PlayerSilentDeath(ply) player_manager.RunClass(ply, "SilentDeath") end
function GM:PostPlayerDeath(ply)
player_manager.RunClass(ply, "PostDeath")
-- Debug Mode: Respawn after Death
if (GAMEMODE.Config:Debug()) then
ply.Data.Alive = true
print("Prop Hunt: Debug Mode active, Player "..ply:GetName().." was respawned.")
end
end
--function GM:DoPlayerDeath(ply, attacker, dmg) player_manager.RunClass(ply, "DoDeath", attacker, dmg) end
function GM:PlayerDeathThink(ply) return player_manager.RunClass(ply, "DeathThink") end
function GM:CanPlayerSuicide(ply) return player_manager.RunClass(ply, "CanSuicide") end
function GM:PlayerCanPickupWeapon(ply, weapon) return player_manager.RunClass(ply, "CanPickupWeapon", weapon) end
function GM:PlayerCanPickupItem(ply, item) return player_manager.RunClass(ply, "CanPickupItem", item) end
function GM:PlayerUse(ply, ent) return player_manager.RunClass(ply, "Use", ent) end
function GM:AllowPlayerPickup(ply, ent) return player_manager.RunClass(ply, "AllowPickup", ent) end
function GM:PlayerSetModel(ply) return player_manager.RunClass(ply, "SetModel") end
-- Called when an entity takes damage
function GM:EntityTakeDamage(ent, dmg)
local att = dmg:GetAttacker()
if (att) && (att:IsValid()) && (att:IsPlayer()) then
player_manager.RunClass(att, "DamageEntity", ent, att, dmg)
end
end
-- ------------------------------------------------------------------------- --
--! Gamemode Functionality
-- ------------------------------------------------------------------------- --
function GM:SetRoundState(State)
SetGlobalInt("RoundState", State)
end
function GM:PlayerHullFromEntity(ply, ent)
if (ent) && (ent:IsValid()) then
local hmin, hmax = ent:OBBMins(), ent:OBBMaxs()
local hull = Vector(hmax.x - hmin.x, hmax.y - hmin.y, hmax.z - hmin.z)
if hull.x <= hull.y then
hull.y = hull.x
else
hull.x = hull.y
end
hull:Mul(0.5)
local hullmin = Vector(-hull.x, -hull.y, 0)
local hullmax = Vector(hull.x, hull.y, hull.z * 2)
ply:SetHull(hullmin, hullmax)
ply:SetHullDuck(hullmin, hullmax)
net.Start("PlayerSetHull")
net.WriteVector(hullmin)
net.WriteVector(hullmax)
net.Send(ply)
return {hullmin, hullmax}
else
ply:ResetHull()
net.Start("PlayerResetHull")
net.Send(ply)
return nil
end
end
function GM:PlayerSetViewOffset(ply, vo, voduck)
ply:SetViewOffset(vo)
ply:SetViewOffsetDucked(voduck)
if ply:Crouching() then
ply:SetCurrentViewOffset(voduck)
else
ply:SetCurrentViewOffset(vo)
end
-- Signal Client
net.Start("PlayerViewOffset")
net.WriteVector(vo)
net.WriteVector(voduck)
net.Send(ply)
end
-- ------------------------------------------------------------------------- --
--! Commands
-- ------------------------------------------------------------------------- --
-- F1/ShowHelp
function GM:ShowHelp(ply) end
-- F2/ShowTeam - Select Team
function GM:ShowTeam(ply)
ply:ConCommand("ph_select_team")
end
-- F3/ShowSpare1
function GM:ShowSpare1(ply) end
-- F4/ShowSpare2
function GM:ShowSpare2(ply) end
-- Debug Command: Print All Players
concommand.Add("ph_debug_printplayers", function(ply, cmd, args, argStr)
print ("All Players:")
for i,ply in ipairs(player.GetAll()) do
print(" "..ply:GetName().." (SteamID: "..ply:SteamID()..") - Team "..team.GetName(ply:Team()).. " - Alive "..tostring(ply.Data.Alive))
end
print ("Spectators:")
for i,ply in ipairs(team.GetPlayers(GAMEMODE.Teams.Spectators)) do
print(" "..ply:GetName().." (SteamID: "..ply:SteamID()..")")
end
print ("Seekers:")
for i,ply in ipairs(team.GetPlayers(GAMEMODE.Teams.Seekers)) do
print(" "..ply:GetName().." (SteamID: "..ply:SteamID()..")")
end
print ("Hiders:")
for i,ply in ipairs(team.GetPlayers(GAMEMODE.Teams.Hiders)) do
print(" "..ply:GetName().." (SteamID: "..ply:SteamID()..")")
end
end, nil, nil, FCVAR_CLIENTCMD_CAN_EXECUTE + FCVAR_CHEAT)
-- ------------------------------------------------------------------------- --
--! LEGACY CODE - TO BE REPLACED SOON
-- ------------------------------------------------------------------------- --
--[[
function AnnounceVictory(players, force)
for i,pl in ipairs(players) do
if pl:Alive() || force || pl:Team() == TEAM_SPECTATOR then
announcer = table.Random(VICTORY_SOUNDS);
print("Prop Hunt: '"..pl:GetName().."' announcing victory with '"..announcer.."'.")
pl:EmitSound(announcer, 200, 100, 0.5, CHAN_VOICE2)
end
end
end
function AnnounceLoss(players, force)
for i,pl in ipairs(players) do
if pl:Alive() || force || pl:Team() == TEAM_SPECTATOR then
announcer = table.Random(LOSS_SOUNDS);
print("Prop Hunt: '"..pl:GetName().."' announcing loss with '"..announcer.."'.")
pl:EmitSound(announcer, 100, 100, 0.5, CHAN_VOICE2)
end
end
end
-- If there is a mapfile send it to the client (sometimes servers want to change settings for certain maps)
if file.Exists("maps/"..game.GetMap()..".lua", "LUA") then
AddCSLuaFile("maps/"..game.GetMap()..".lua")
end
-- Send the required resources to the client
for _, announcer in pairs(LOSS_SOUNDS) do resource.AddFile("sound/"..announcer) end
for _, announcer in pairs(VICTORY_SOUNDS) do resource.AddFile("source/"..announcer) end
for _, taunt in pairs(HUNTER_TAUNTS) do resource.AddFile("sound/"..taunt) end
for _, taunt in pairs(PROP_TAUNTS) do resource.AddFile("sound/"..taunt) end
-- Called alot
function GM:CheckPlayerDeathRoundEnd()
if !GAMEMODE.RoundBased || !GAMEMODE:InRound() then
return
end
local Teams = GAMEMODE:GetTeamAliveCounts()
if table.Count(Teams) == 0 then
GAMEMODE:RoundEndWithResult(1001, "Draw, everyone loses!")
AnnounceLoss(player.GetAll(), true)
return
end
if table.Count(Teams) == 1 then
-- Play victory and loss sounds.
if Teams[0] == TEAM_HUNTERS then
AnnounceVictory(team.GetPlayers(TEAM_HUNTERS))
AnnounceLoss(team.GetPlayers(TEAM_PROPS))
elseif Teams[0] == TEAM_PROPS then
AnnounceLoss(team.GetPlayers(TEAM_HUNTERS))
AnnounceVictory(team.GetPlayers(TEAM_PROPS))
end
local TeamID = table.GetFirstKey(Teams)
GAMEMODE:RoundEndWithResult(TeamID, team.GetName(TeamID).." win!")
return
end
end
-- Called when player presses [F3]. Plays a taunt for their team
function GM:ShowSpare1(pl)
if GAMEMODE:InRound() && pl:Alive() && (pl:Team() == TEAM_HUNTERS || pl:Team() == TEAM_PROPS) && pl.last_taunt_time + TAUNT_DELAY <= CurTime() && #PROP_TAUNTS > 1 && #HUNTER_TAUNTS > 1 then
-- repeat
if pl:Team() == TEAM_HUNTERS then
rand_taunt = table.Random(HUNTER_TAUNTS)
else
rand_taunt = table.Random(PROP_TAUNTS)
end
-- until rand_taunt != pl.last_taunt
pl.last_taunt_time = CurTime()
pl.last_taunt = rand_taunt
print("Prop Hunt: '"..pl:GetName().."' taunting with '"..rand_taunt.."'.")
local vol = 1.0
if pl:Team() == TEAM_HUNTERS then vol = vol * 0.5 end
pl:EmitSound(rand_taunt, 100, 100, vol, CHAN_VOICE2)
end
end
-- Allow player to rotate the prop. (Either F4 or ducking)
function GM:ShowSpare2(pl)
if pl:Alive() && (pl:Team() == TEAM_PROPS) then
pl.ph_prop:SetApplyNewAngles(!pl.ph_prop:GetApplyNewAngles())
-- pl.ph_prop:SetNewAngles(pl:GetAngles())
end
end
-- Removes all weapons on a map
function RemoveWeaponsAndItems()
for _, wep in pairs(ents.FindByClass("weapon_*")) do
wep:Remove()
end
for _, item in pairs(ents.FindByClass("item_*")) do
item:Remove()
end
end
hook.Add("InitPostEntity", "PH_RemoveWeaponsAndItems", RemoveWeaponsAndItems)
]]
@@ -0,0 +1,137 @@
--[[
The MIT License (MIT)
Copyright (c) 2015 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
DEFINE_BASECLASS("player_default")
local CLASS = {}
CLASS.DisplayName = "Default"
CLASS.WalkSpeed = 250 -- How fast to move when not running
CLASS.RunSpeed = 500 -- How fast to move when running
CLASS.CrouchedWalkSpeed = 0.5 -- Multiply move speed by this when crouching
CLASS.DuckSpeed = 0.2 -- How fast to go from not ducking, to ducking
CLASS.UnDuckSpeed = 0.2 -- How fast to go from ducking, to not ducking
CLASS.JumpPower = 200 -- How powerful our jump should be
CLASS.CanUseFlashlight = false -- Can we use the flashlight
CLASS.MaxHealth = 100 -- Max health we can have
CLASS.StartHealth = 100 -- How much health we start with
CLASS.StartArmor = 0 -- How much armour we start with
CLASS.DropWeaponOnDie = false -- Do we drop our weapon when we die
CLASS.TeammateNoCollide = true -- Do we collide with teammates or run straight through them
CLASS.AvoidPlayers = true -- Automatically swerves around other players
CLASS.UseVMHands = true -- Uses viewmodel hands
-- ------------------------------------------------------------------------- --
--! Server-Side
-- ------------------------------------------------------------------------- --
-- Spawn
function CLASS:InitialSpawn() end
function CLASS:Spawn() end
function CLASS:Loadout() end
-- Damage
function CLASS:Hurt(victim, attacker, healthRemaining, damageTaken) end -- Damage Taken
function CLASS:Damage(victim, attacker, healthRemaining, damageDealt) end -- Damage Dealt
function CLASS:DamageEntity(ent, attacker, dmginfo) end -- Damage Dealt To Entity
-- Death
function CLASS:Death(inflictor, attacker)
self.Player.Data.Alive = false
self.Player.Data.AliveTime = CurTime()
end
function CLASS:SilentDeath()
self.Player.Data.Alive = false
self.Player.Data.AliveTime = CurTime()
end
function CLASS:PostDeath() end
function CLASS:DoDeath() end
function CLASS:DeathThink()
if (CurTime() - self.Player.Data.AliveTime) > 2 then
self.Player:Spawn()
return true
end
return false
end
function CLASS:CanSuicide() return true end
-- Visible Stuff
function CLASS:SetModel() BaseClass.SetModel( self ) end
-- Interaction
function CLASS:Use(ent)
-- Entity must be valid and not a player.
if (!ent) || (!ent:IsValid()) || (ent:IsPlayer()) then
return false
end
-- Cool Down
if (self.Player.Data.UseTime) then
local timeSinceUse = (CurTime() - self.Player.Data.UseTime)
if (0.2 > timeSinceUse) then
return false
end
-- Abuse Blacklist (Buttons, Doors, etc)
if (5 > timeSinceUse) then
local abuseBlacklist = GAMEMODE.Config.Lists:AbuseBlacklist()
if (table.HasValue(abuseBlacklist, ent:GetClass())) then
return false
end
end
end
self.Player.Data.UseTime = CurTime()
return true
end
function CLASS:AllowPickup(ent) return false end
function CLASS:CanPickupWeapon(ent) return false end
function CLASS:CanPickupItem(ent) return false end
-- ------------------------------------------------------------------------- --
--! Shared
-- ------------------------------------------------------------------------- --
function CLASS:PostThink() end
function CLASS:Tick(mv) end
-- ------------------------------------------------------------------------- --
--! Client-Side
-- ------------------------------------------------------------------------- --
-- Spawn
function CLASS:InitialClientSpawn()
self.Player.Data = {}
self.Player.Data.ThirdPerson = false -- Default to FirstPerson View
end
function CLASS:ClientSpawn() end
-- View & HUD
function CLASS:GetHandsModel() return BaseClass.GetHandsModel(self) end
function CLASS:ShouldDrawLocal() return false end
function CLASS:HUDPaint() end
function CLASS:CalcView(camdata) return camdata end
-- ------------------------------------------------------------------------- --
--! Register
-- ------------------------------------------------------------------------- --
player_manager.RegisterClass( "Default", CLASS, "player_default")
@@ -0,0 +1,234 @@
--[[
The MIT License (MIT)
Copyright (c) 2015 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
DEFINE_BASECLASS( "Default" )
local CLASS = {}
CLASS.DisplayName = "Hider"
CLASS.DuckSpeed = 0.0 -- How fast to go from not ducking, to ducking
CLASS.UnDuckSpeed = 0.0 -- How fast to go from ducking, to not ducking
CLASS.CanUseFlashlight = false -- Can we use the flashlight
CLASS.UseVMHands = false -- Uses viewmodel hands
-- ------------------------------------------------------------------------- --
--! Server-Side
-- ------------------------------------------------------------------------- --
-- Spawn
function CLASS:Spawn()
print("Prop Hunt: Hider '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") spawned.")
BaseClass.Spawn(self, self.Player)
-- Sprinting
if (!GAMEMODE.Config:Sprinting()) then
self.Player:SetRunSpeed(self.WalkSpeed)
end
-- Settings
self.Player:SetMaxHealth(GAMEMODE.Config.Hider:HealthMax())
self.Player:SetHealth(GAMEMODE.Config.Hider:Health())
self.Player:SetRenderMode(RENDERMODE_TRANSALPHA)
self.Player:SetColor(Color(0,0,0,0))
-- Hull & View Offset
GAMEMODE:PlayerHullFromEntity(self.Player, nil)
GAMEMODE:PlayerSetViewOffset(self.Player, Vector(0,0,72), Vector(0,0,72))
-- Collision Group
self.Player:SetCollisionGroup(COLLISION_GROUP_PLAYER)
-- Prop Stuff
self.Player.Data.Prop = ents.Create("ph_prop")
self.Player.Data.Prop:SetOwner(self.Player)
self.Player.Data.Prop:Spawn()
self.Player:DeleteOnRemove(self.Player.Data.Prop)
-- Assign Hands (Auto Networked Sync!)
local oldhands = self.Player:GetHands()
if (IsValid(oldhands)) then oldhands:Remove() end
self.Player:SetHands(self.Player.Data.Prop)
end
-- Death
function CLASS:PostDeath(attacker, dmginfo)
print("Prop Hunt: Hider '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") died.")
BaseClass.PostDeath(self, inflictor, attacker)
-- Delete Hands Model
self.Player:GetHands():Remove()
-- Collision Group
self.Player:SetCollisionGroup(COLLISION_GROUP_PLAYER)
-- Hull
GAMEMODE:PlayerHullFromEntity(self.Player, nil)
-- Rendering
self.Player:SetRenderMode(RENDERMODE_NORMAL)
self.Player:SetColor(Color(255,255,255,255))
end
function CLASS:CanSuicide()
return true
end
function CLASS:DeathThink()
if 1 > (CurTime() - self.Player.Data.AliveTime) then
return false
end
self.Player:Spawn()
return true
end
-- Visible Stuff
function CLASS:SetModel() self.Player:SetModel("models/Gibs/Antlion_gib_small_3.mdl") end -- does "" even work?
-- Interaction
function CLASS:Use(ent)
if (!(BaseClass.Use(self, ent))) then
return false
end
-- Allow interacting while crouched instead of turning into the prop.
if (self.Player:Crouching()) then
return true
end
-- Check Lists and other Parameters
if (!table.HasValue(GAMEMODE.Config.Lists:ClassWhitelist(), ent:GetClass()))-- Class is not Whitelisted
|| (GAMEMODE.Config.Lists.ModelBlacklist[ent:GetModel()]) -- Model is Blacklisted
|| !((ent:GetPhysicsObject()) && (ent:GetPhysicsObject():IsValid())) -- Entity doesn't have Physics
then
print("Prop Hunt: Hider '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") attempted to turn into "..ent:GetClass().." ("..ent:GetModel()..").")
return true -- Use instead of erroring.
end
-- Turn into the prop
local eProp = self.Player:GetHands()
util.PrecacheModel(ent:GetModel())
eProp:SetModel(ent:GetModel())
eProp:SetSkin(ent:GetSkin())
eProp:SetHealth(100)
eProp:SetMaxHealth(100)
eProp:SetRenderMode(RENDERMODE_TRANSALPHA)
-- Hull (Optimize into single function? Code is repeated often)
local hull = GAMEMODE:PlayerHullFromEntity(self.Player, ent)
-- View Offset
local vo = Vector(0, 0, hull[2].z)
GAMEMODE:PlayerSetViewOffset(self.Player, vo, vo)
-- Health Scaling
if (GAMEMODE.Config.Hider:HealthScaling()) then
local prc = math.Clamp(self.Player:Health() / self.Player:GetMaxHealth(), 0, 1)
local maxhealth = math.Clamp(ent:GetPhysicsObject():GetVolume() / 250, 1, GAMEMODE.Config.Hider:HealthScalingMax())
local health = math.Clamp(maxhealth * prc, 1, maxhealth)
-- Set Health
self.Player:SetHealth(health)
self.Player:SetMaxHealth(maxhealth)
end
print("Prop Hunt: Hider '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") turned into "..ent:GetClass().." ("..ent:GetModel()..").")
end
function CLASS:AllowPickup(ent) return true end
-- ------------------------------------------------------------------------- --
--! Shared
-- ------------------------------------------------------------------------- --
-- ------------------------------------------------------------------------- --
--! Client-Side
-- ------------------------------------------------------------------------- --
function CLASS:ClientSpawn()
print("Prop Hunt CL: Hider '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") spawned.")
BaseClass.ClientSpawn(self, self.Player)
self.Player:SetRenderMode(RENDERMODE_TRANSALPHA)
end
function CLASS:ShouldDrawLocal()
return false
end
function CLASS:CalcView(camdata)
-- ThirdPerson Settings (ToDo: client config maybe?)
local maxViewDist = 100
local viewDist = self.Player.Data.ViewDistance or 0
-- First/Third
if (self.Player.Data.ThirdPerson) then
if (IsValid(self.Player:GetHands())) then
self.Player:GetHands():SetRenderMode(RENDERMODE_TRANSALPHA)
self.Player:GetHands():SetColor(Color(255, 255, 255, 127))
end
-- Incremental Distance instead of instant.
viewDist = math.Clamp(viewDist * 0.9 + maxViewDist * 0.1, 0, maxViewDist) -- Zoom Out
else
if (IsValid(self.Player:GetHands())) then
self.Player:GetHands():SetRenderMode(RENDERMODE_TRANSALPHA)
self.Player:GetHands():SetColor(Color(255, 255, 255, 0))
end
viewDist = math.Clamp(viewDist * 0.9, 0, maxViewDist) -- Zoom In
end
-- Trace from Player to would-be camera position
local trace = {
start = camdata.origin,
endpos = camdata.origin - (camdata.angles:Forward() * viewDist),
--filter = { "worldspawn", "ph_prop" },
filter = function(ent)
local filter = { "worldspawn", "ph_prop" }
if (ent:IsPlayer())
|| (table.HasValue(filter, ent:GetClass()))
|| (ent == LocalPlayer()) || (ent == LocalPlayer():GetHands()) then
return false
end
return true
end
}
local result = util.TraceLine(trace)
-- The Camera has a Sphere radius of 10.
if (result.Hit) then -- Configurable?
viewDist = math.Clamp(result.HitPos:Distance(camdata.origin), 0, maxViewDist)
end
-- Store ViewDistance
self.Player.Data.ViewDistance = viewDist
-- Adjust CamData
camdata.origin = camdata.origin - (camdata.angles:Forward() * math.Clamp(viewDist - 10, 0, maxViewDist))
camdata.drawviewer = false
-- Return
return camdata
end
-- Register
player_manager.RegisterClass("Hider", CLASS, "Default")
@@ -0,0 +1,235 @@
--[[
The MIT License (MIT)
Copyright (c) 2015 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
--! This file defines the Seeker player class.
-- A seeker is someone who is looking for the hiders, using weapons or other
-- means of detecting idiots. Also someone who looks like a diaper baby.
-- Weapons and Ammo are granted upon spawn and have to be used sparingly or
-- they'll be stuck with the crowbar. Bad seeker, bad.
-- Gain health upon killing a hider, lose health when attacking non-hiders.
-- Death upon health reaching 0.
DEFINE_BASECLASS( "Default" )
local CLASS = {}
CLASS.DisplayName = "Seeker"
CLASS.CanUseFlashlight = true -- Can we use the flashlight
CLASS.MaxHealth = 100
CLASS.StartHealth = 100
CLASS.StartArmor = 0
CLASS.DropWeaponOnDie = true
-- ------------------------------------------------------------------------- --
--! Server-Side
-- ------------------------------------------------------------------------- --
-- Spawn
function CLASS:Spawn()
print("Prop Hunt: Seeker '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") spawned.")
BaseClass.Spawn(self)
-- Sprinting
if (GAMEMODE.Config:Sprinting()) then
self.Player:SetRunSpeed(self.WalkSpeed)
end
-- Settings
self.Player:SetMaxHealth(GAMEMODE.Config.Seeker:HealthMax())
self.Player:SetHealth(GAMEMODE.Config.Seeker:Health())
self.Player:SetRenderMode(RENDERMODE_NORMAL)
self.Player:SetColor(Color(255,255,255,255))
-- Hull & View Offset
GAMEMODE:PlayerHullFromEntity(self.Player, nil)
GAMEMODE:PlayerSetViewOffset(self.Player, Vector(0,0,64), Vector(0,0,32))
end
function CLASS:Loadout()
-- Give the weapons the admin told us to.
local weapons = GAMEMODE.Config.Seeker:Weapons()
for i,weapon in ipairs(weapons) do
self.Player:Give(weapon)
end
-- Give the ammo the admin told us to.
local ammos = GAMEMODE.Config.Seeker:Ammo()
for i,ammo in ipairs(ammos) do
local typeCount = string.Split(ammo, ":")
self.Player:GiveAmmo(tonumber(typeCount[2]), typeCount[1], true)
end
-- Default weapon stuff
local cl_defaultweapon = self.Player:GetInfo("cl_defaultweapon")
if self.Player:HasWeapon(cl_defaultweapon) then
self.Player:SelectWeapon(cl_defaultweapon)
end
end
-- Damage
function CLASS:Damage(victim, attacker, healthRemaining, damageDealt) end
function CLASS:DamageEntity(ent, att, dmg)
print("Prop Hunt: Seeker '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") damaged entity "..ent:GetClass()..".")
-- Only take damage during this phase.
if (GAMEMODE:GetRoundState() == GAMEMODE.States.Seek) then
if IsValid(ent) && (!(ent:IsPlayer())) then
if (ent:GetClass() == "ph_prop") then
ent:GetOwner():TakeDamageInfo(dmg)
elseif (ent:GetClass() == "func_breakable") then -- ToDo: Make Configurable which entities don't hurt
else
att:TakeDamage(GAMEMODE.Config.Seeker:HealthPenalty(), ent, ent)
end
end
end
end
-- Death
function CLASS:Death(inflictor, attacker)
BaseClass.Death(self, inflictor, attacker)
self.Player:CreateRagdoll()
end
function CLASS:PostDeath()
print("Prop Hunt: Seeker '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") died.")
BaseClass.PostDeath(self, inflictor, attacker)
self.Player:UnLock()
end
function CLASS:CanSuicide()
return true
end
function CLASS:DeathThink()
if (CurTime() - self.Player.Data.AliveTime) > 1 then
self.Player:Spawn()
return true
end
return false
end
-- Visible Stuff
function CLASS:SetModel()
local cl_playermodel = self.Player:GetInfo( "cl_playermodel" )
local modelname = player_manager.TranslatePlayerModel( cl_playermodel )
if !(util.IsValidModel(modelname)) then
modelname = "models/player/combine_super_soldier.mdl"
end
util.PrecacheModel(modelname)
self.Player:SetModel(modelname)
-- Hands
self.Player:SetupHands()
end
-- Interaction
function CLASS:AllowPickup(ent) return true end
function CLASS:CanPickupItem(ent) return true end
function CLASS:CanPickupWeapon(ent) return true end
-- ------------------------------------------------------------------------- --
--! Client-Side
-- ------------------------------------------------------------------------- --
function CLASS:ClientSpawn()
print("Prop Hunt CL: Seeker '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") spawned.")
BaseClass.ClientSpawn(self)
end
function CLASS:HUDPaint()
local State = GetGlobalInt("RoundState", GAMEMODE.States.PreMatch)
if (State == GAMEMODE.States.Hide) then
local intTime = math.ceil(GetGlobalInt("RoundTime"))
local strTime = tostring(intTime)
-- Seekers are blinded in this Phase.
draw.RoundedBox(0, 0, 0, surface.ScreenWidth(), surface.ScreenHeight(), Color(0, 0, 0, 255))
-- Show Status at the center
surface.SetTextColor( 255, 255, 255, 255 )
if (intTime >= 1) then
surface.SetFont("CloseCaption_Bold")
local w,h = surface.GetTextSize("Unblinded in "..strTime.." seconds...")
surface.SetTextPos( ScrW()/2 - w / 2, ScrH()/2 - h / 2)
surface.DrawText("Unblinded in "..strTime.." seconds...")
else
surface.SetFont("PHHugeAssFont")
local w,h = surface.GetTextSize("NOW")
surface.SetTextPos( ScrW()/2 - w / 2, ScrH()/2 - h / 2)
surface.DrawText("NOW")
end
end
end
function CLASS:ShouldDrawLocal()
return self.Player.Data.ThirdPerson
end
function CLASS:CalcView(camdata)
-- ThirdPerson Settings (ToDo: client config maybe?)
local maxViewDist = 100
local viewDist = self.Player.Data.ViewDistance or 0
-- First/Third
if (self.Player.Data.ThirdPerson) then
viewDist = math.Clamp(viewDist * 0.9 + maxViewDist * 0.1, 0, maxViewDist) -- Zoom Out
else
viewDist = math.Clamp(viewDist * 0.9, 0, maxViewDist) -- Zoom In
end
-- Trace from Player to would-be camera position
local trace = {
start = camdata.origin,
endpos = camdata.origin - (camdata.angles:Forward() * viewDist),
--filter = { "worldspawn", "ph_prop" },
filter = function(ent)
local filter = { "worldspawn", "ph_prop" }
if (ent:IsPlayer())
|| (table.HasValue(filter, ent:GetClass()))
|| (ent == LocalPlayer()) || (ent == LocalPlayer():GetHands()) then
return false
end
return true
end
}
local result = util.TraceLine(trace)
-- The Camera has a Sphere radius of 10.
if (result.Hit) then -- Configurable?
viewDist = math.Clamp(result.HitPos:Distance(camdata.origin), 0, maxViewDist)
end
-- Store ViewDistance
self.Player.Data.ViewDistance = viewDist
-- Adjust CamData
camdata.origin = camdata.origin - (camdata.angles:Forward() * math.Clamp(viewDist - 10, 0, maxViewDist))
--camdata.drawviewer = false
-- Return
return camdata
end
-- Register
player_manager.RegisterClass("Seeker", CLASS, "Default")
@@ -0,0 +1,85 @@
--[[
The MIT License (MIT)
Copyright (c) 2015 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
DEFINE_BASECLASS("Default")
local CLASS = {}
CLASS.DisplayName = "Spectator"
CLASS.DuckSpeed = 0.0 -- How fast to go from not ducking, to ducking
CLASS.UnDuckSpeed = 0.0 -- How fast to go from ducking, to not ducking
CLASS.CanUseFlashlight = false -- Can we use the flashlight
CLASS.UseVMHands = false -- Uses viewmodel hands
-- ------------------------------------------------------------------------- --
--! Server-Side
-- ------------------------------------------------------------------------- --
-- Spawn
function CLASS:Spawn()
print("Prop Hunt: Spectator '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") spawned.")
BaseClass.Spawn(self)
self.Player:Spectate(OBS_MODE_ROAMING)
self.Player:SetRenderMode(RENDERMODE_NONE)
-- View Offset & Hull
GAMEMODE:PlayerSetViewOffset(self.Player, Vector(0,0,0), Vector(0,0,0))
GAMEMODE:PlayerHullFromEntity(self.Player, nil)
end
-- Death
function CLASS:PostDeath(inflictor, attacker)
print("Prop Hunt: Spectator '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") died.")
BaseClass.PostDeath(self, inflictor, attacker)
self.Player:Spectate(OBS_MODE_NONE)
self.Player:UnSpectate()
-- Hull
GAMEMODE:PlayerHullFromEntity(self.Player, nil)
self.Player:SetRenderMode(RENDERMODE_NORMAL)
end
-- Visible Stuff
function CLASS:SetModel()
self.Player:SetModel("")
-- Hands
self.Player:SetupHands()
end
-- Interaction
function CLASS:Use(ent) return false end
function CLASS:AllowPickup(ent) return false end
function CLASS:CanPickupWeapon(ent) return false end
function CLASS:CanPickupItem(ent) return false end
-- ------------------------------------------------------------------------- --
--! Client-Side
-- ------------------------------------------------------------------------- --
function CLASS:ClientSpawn()
print("Prop Hunt CL: Spectator '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") spawned.")
end
function CLASS:ShouldDrawLocal() return false end
player_manager.RegisterClass( "Spectator", CLASS, "Default")
@@ -0,0 +1,549 @@
--[[
The MIT License (MIT)
Copyright (c) 2015 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
--! Initialize configuration table.
GM.Config = { }
GM.Config.ConVars = {}
-- ------------------------------------------------------------------------- --
--! Basic Settings
-- ------------------------------------------------------------------------- --
-- Debug Mode
GM.Config.ConVars.Debug = CreateConVar("ph_debug", 0, FCVAR_CHEAT + FCVAR_REPLICATED)
function GM.Config:Debug()
return self.ConVars.Debug:GetBool()
end
-- Game Mode (See sh_init.lua)
GM.Config.ConVars.GameMode = CreateConVar("ph_gamemode", GM.Modes.Original, FCVAR_REPLICATED)
function GM.Config:GameMode()
return self.ConVars.GameMode:GetInt()
end
-- Timelimit in minutes
GM.Config.ConVars.TimeLimit = GetConVar("mp_timelimit")
function GM.Config:TimeLimit()
return self.ConVars.TimeLimit:GetFloat()
end
-- Enable Sprinting?
GM.Config.ConVars.Sprinting = CreateConVar("ph_sprinting", 0, FCVAR_REPLICATED)
function GM.Config:Sprinting()
return self.ConVars.Sprinting:GetBool()
end
-- Taunt Cooldown (Seconds)
GM.Config.ConVars.TauntCoolDown = CreateConVar("ph_tauntcooldown", 5, FCVAR_REPLICATED)
function GM.Config:TauntCoolDown()
return self.ConVars.TauntCoolDown:GetFloat()
end
-- ------------------------------------------------------------------------- --
--! Round Settings
-- ------------------------------------------------------------------------- --
GM.Config.Round = {}
GM.Config.Round.ConVars = {}
-- How many rounds should the gamemode attempt to fit into the map timelimit, if there is any?
GM.Config.Round.ConVars.Amount = CreateConVar("ph_round_limit", 10, FCVAR_REPLICATED)
function GM.Config.Round:Amount()
return self.ConVars.Amount:GetInt()
end
-- Round Time Limit (Seconds, Default 3 minutes)
GM.Config.Round.ConVars.Time = CreateConVar("ph_round_timelimit", 180, FCVAR_REPLICATED)
function GM.Config.Round:Time()
return self.ConVars.Time:GetInt() - GAMEMODE.Config.Round:BlindTime()
end
-- For how many seconds are the Seekers blinded? (Seconds)
GM.Config.Round.ConVars.BlindTime = CreateConVar("ph_round_blindtime", 30, FCVAR_REPLICATED, "How long are hunters blinded? (positive values will be inside the round time limit, negative will add to the round time limit)")
function GM.Config.Round:BlindTime()
return self.ConVars.BlindTime:GetInt()
end
-- ------------------------------------------------------------------------- --
--! Seeker Settings
-- ------------------------------------------------------------------------- --
GM.Config.Seeker = {}
GM.Config.Seeker.ConVars = {}
GM.Config.Seeker.ConVars.Health = CreateConVar("ph_seeker_health", 100, FCVAR_REPLICATED)
function GM.Config.Seeker:Health()
return self.ConVars.Health:GetInt()
end
GM.Config.Seeker.ConVars.HealthMax = CreateConVar("ph_seeker_health_max", 100, FCVAR_REPLICATED)
function GM.Config.Seeker:HealthMax()
return self.ConVars.HealthMax:GetInt()
end
GM.Config.Seeker.ConVars.HealthBonus = CreateConVar("ph_seeker_health_bonus", 20, FCVAR_REPLICATED)
function GM.Config.Seeker:HealthBonus()
return self.ConVars.HealthBonus:GetInt()
end
GM.Config.Seeker.ConVars.HealthPenalty = CreateConVar("ph_seeker_health_penalty", 5, FCVAR_REPLICATED)
function GM.Config.Seeker:HealthPenalty()
return self.ConVars.HealthPenalty:GetInt()
end
GM.Config.Seeker.ConVars.Weapons = CreateConVar("ph_seeker_weapons", "weapon_crowbar,weapon_pistol,weapon_ph_smg,weapon_shotgun", FCVAR_REPLICATED)
function GM.Config.Seeker:Weapons()
return string.Split(self.ConVars.Weapons:GetString(), ",")
end
GM.Config.Seeker.ConVars.Ammo = CreateConVar("ph_seeker_ammo", "Pistol:100,SMG1:300,SMG1_Grenade:1,Buckshot:64", FCVAR_REPLICATED)
function GM.Config.Seeker:Ammo()
return string.Split(self.ConVars.Ammo:GetString(), ",")
end
-- ------------------------------------------------------------------------- --
--! Hider Settings
-- ------------------------------------------------------------------------- --
GM.Config.Hider = {}
GM.Config.Hider.ConVars = {}
GM.Config.Hider.ConVars.Health = CreateConVar("ph_hider_health", 100, FCVAR_REPLICATED)
function GM.Config.Hider:Health()
return self.ConVars.Health:GetInt()
end
GM.Config.Hider.ConVars.HealthMax = CreateConVar("ph_hider_health_max", 100, FCVAR_REPLICATED)
function GM.Config.Hider:HealthMax()
return self.ConVars.HealthMax:GetInt()
end
GM.Config.Hider.ConVars.HealthScaling = CreateConVar("ph_hider_health_scaling", 100, FCVAR_REPLICATED)
function GM.Config.Hider:HealthScaling()
return self.ConVars.HealthScaling:GetBool()
end
GM.Config.Hider.ConVars.HealthScalingMax = CreateConVar("ph_hider_health_scaling_max", 200, FCVAR_REPLICATED)
function GM.Config.Hider:HealthScalingMax()
return self.ConVars.HealthScalingMax:GetInt()
end
-- ------------------------------------------------------------------------- --
--! Whitelist & Blacklist
-- ------------------------------------------------------------------------- --
GM.Config.Lists = {}
GM.Config.Lists.ConVars = {}
GM.Config.Lists.ConCmds = {}
GM.Config.Lists.ConVars.ClassWhitelist = CreateConVar("ph_list_class_whitelist", "prop_physics,prop_physics_multiplayer,prop_physics_respawnable", FCVAR_REPLICATED)
function GM.Config.Lists:ClassWhitelist()
return string.Split(self.ConVars.ClassWhitelist:GetString(), ",")
end
-- Use Abuse Blacklist
GM.Config.Lists.ConVars.AbuseBlacklist = CreateConVar("ph_list_abuse_blacklist", "func_button,func_door,func_door_rotation,prop_door_rotation,func_tracktrain,func_tanktrain,func_breakable", FCVAR_REPLICATED)
function GM.Config.Lists:AbuseBlacklist()
return string.Split(self.ConVars.AbuseBlacklist:GetString(), ",")
end
-- Model Blacklist
GM.Config.Lists.ModelBlacklist = {}
GM.Config.Lists.ModelBlacklist["models/props/cs_assault/dollar.mdl"] = true
GM.Config.Lists.ModelBlacklist["models/props/cs_assault/money.mdl"] = true
GM.Config.Lists.ModelBlacklist["models/props/cs_office/snowman_arm.mdl"] = true
GM.Config.Lists.ModelBlacklist["models/props_junk/garbage_plasticbottle001a.mdl"] = true
GM.Config.Lists.ModelBlacklist["models/props/cs_office/projector_remote.mdl"] = true
GM.Config.Lists.ConCmds.ModelBlacklistList = concommand.Add("ph_list_model_blacklist_list", function(ply, cmd, args, argStr)
print("Model Blacklist:")
for k,v in pairs(GAMEMODE.Config.Lists.ModelBlacklist) do
print(" "..k)
end
end, "List all blacklisted models.")
GM.Config.Lists.ConCmds.ModelBlacklistClear = concommand.Add("ph_list_model_blacklist_list", function(ply, cmd, args, argStr)
GM.Config.Lists.ModelBlacklist = {}
end, "Clear blacklisted models.")
GM.Config.Lists.ConCmds.ModelBlacklistAdd = concommand.Add("ph_list_model_blacklist_add", function(ply, cmd, args, argStr)
if (table.count(args) > 0) then
GAMEMODE.Config.Lists.ModelBlacklist[args[1]] = true
else
print("Missing model name")
end
end, "Add a new blacklisted model.")
GM.Config.Lists.ConCmds.ModelBlacklistRemove = concommand.Add("ph_list_model_blacklist_remove", function(ply, cmd, args, argStr)
if (table.count(args) > 0) then
GAMEMODE.Config.Lists.ModelBlacklist[args[1]] = nil
else
print("Missing model name")
end
end, "Removes a blacklisted model.")
-- ------------------------------------------------------------------------- --
--! Taunts
-- ------------------------------------------------------------------------- --
-- GM.Config.Taunts = {
-- Seeker = { },
-- Hider = { },
-- }
-- -- Taunts.Clear()
-- --@desc: Clears the current taunt list.
-- GM.Config.Taunts.Clear = function()
-- this.Seeker = {}
-- this.Hider = {}
-- end
-- -- Taunts.Load(sTauntListFile)
-- --@desc: Loads the taunt list from disk.
-- --@param:
-- -- sTauntListFile - A string containing the path to the taunt list to load.
-- --@return: true or false depending on success.
-- GM.Config.Taunts.Load = function(sTauntListFile)
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Load: Loading taunt list from file '"..sTauntListFile.."'...") end
-- -- Safeguard against idiots.
-- if type(sTauntListFile) != "string" then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Load: <sTauntListFile> is not a string.") end
-- return false
-- end
-- -- Given file must exist for us to continue.
-- if ! file.Exists(sTauntListFile, "GAME") then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Load: File not found.") end
-- return false
-- end
-- -- Read the file and check if it's empty.
-- sTauntListData = file.Read(sTauntListFile, "GAME")
-- if sTauntListData == "" then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Load: File is empty.") end
-- return false
-- end
-- -- Convert JSON to a table for us to use.
-- sTauntList = util.JSONToTable(sTauntListData)
-- -- Is it nil? Then it's not valid JSON
-- if sTauntList == nil then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Load: File contains invalid JSON.") end
-- return false
-- end
-- -- Finally, append the taunt lists.
-- if sTauntList.Seeker != nil then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Load: Adding Seeker taunts...") end
-- for k,v in pairs(sTauntList.Seeker) do
-- GAMEMODE.Taunts.Seeker[k] = v
-- end
-- end
-- if sTauntList.Hider != nil then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Load: Adding Hider taunts...") end
-- for k,v in pairs(sTauntList.Hider) do
-- GAMEMODE.Taunts.Hider[k] = v
-- end
-- end
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Load: Complete.") end
-- return true
-- end
-- -- Taunts.Save(sTauntListFile)
-- --@desc: Saves the current taunt list to disk.
-- --@param:
-- -- sTauntListFile - A string containing the path to the file to save to.
-- --@return: true or false depending on success.
-- GM.Config.Taunts.Save = function(sTauntListFile)
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Save: Saving taunt list to file '"..sTauntListFile.."'...") end
-- -- Safeguard against idiots.
-- if type(sTauntListFile) != "string" then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Save: <sTauntListFile> is not a string.") end
-- return false
-- end
-- -- File must not be nil, otherwise we can't write to it.
-- if sTauntListFile == nil then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Save: No file given.") end
-- return false
-- end
-- -- Convert our taunt table to JSON.
-- sTauntListData = util.TableToJSON(GAMEMODE.Taunts);
-- if sTauntListData == nil then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Save: Corrupted GAMEMODE table.") end
-- return false
-- end
-- -- Write out JSON out to file
-- if ! file.Write(sTauntListFile, sTauntListData) then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Save: Failed to write to file.") end
-- return false
-- end
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Save: Complete.") end
-- return true
-- end
-- -- Taunts.Add(sTauntName, sSoundFile, iTeamID, mPropFilter)
-- --@desc: Registers a new taunt with the given name, file, team and filter.
-- --@param:
-- -- sTauntName - The unique name of the taunt.
-- -- sSoundFile - A sound file to play when this taunt is selected.
-- -- iTeamID - The team that should receive the taunt or nil for all teams.
-- -- mPropFilter - A string or a table containing strings for props that should be able to use this taunt.
-- --@return: true or false depending on success.
-- GM.Config.Taunts.Add = function(sTauntName, sSoundFile, iTeamID, mPropFilter)
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Add: Adding new taunt '"..sTauntName.."'...") end
-- -- Safeguard against idiots.
-- if type(sTauntName) != "string" then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Add: <sTauntName> is not a string.") end
-- return false
-- end
-- if type(sSoundFile) != "string" then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Add: <sSoundFile> is not a string.") end
-- return false
-- end
-- if (type(iTeamID) != "number" && iTeamID != nil) then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Add: <iTeamID> is not a number or nil.") end
-- return false
-- end
-- if (type(mPropFilter) != "string" && type(mPropFilter) != "table" && mPropFilter != nil) then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Add: <mPropFilter> is not a string, table or nil.") end
-- return false
-- end
-- -- Check if the sound file actually exists
-- if !file.Exists("sound/"..sSoundFile, "GAME") then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Add: File '"..sSoundFile.."' does not exist.") end
-- return false
-- end
-- -- Make sure that our prop filter is a table listing the props it's supposed to work for.
-- if (mPropFilter == nil) then
-- mPropFilter = { }
-- elseif type(mPropFilter) == "string" then
-- mPropFilter = { mPropFilter }
-- end
-- -- Prepare Taunt table
-- Taunt = {
-- File = sSoundFile,
-- Filter = mPropFilter
-- }
-- -- If iTeamID is nil, both teams will receive the taunt.
-- if iTeamID == nil then
-- GAMEMODE.Taunts.Seeker[sTauntName] = Taunt
-- GAMEMODE.Taunts.Hider[sTauntName] = Taunt
-- else
-- -- Make sure that the team is valid.
-- if ! team.Valid(iTeamID) then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Add: Team "..iTeamID.."' does not exist.") end
-- return false
-- end
-- if (iTeamID == TEAM_SEEKERS) then
-- GAMEMODE.Taunts.Seeker[sTauntName] = Taunt
-- elseif (iTeamID == TEAM_HIDERS) then
-- GAMEMODE.Taunts.Hider[sTauntName] = Taunt
-- else
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Add: Team "..iTeamID.."' can't have taunts.") end
-- return false
-- end
-- end
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Add: Complete.") end
-- return true
-- end
-- -- Taunts.Remove(sTauntName, iTeamID)
-- --@desc: Removes a registered taunt with the given name and team.
-- --@param:
-- -- sTauntName - The unique name of the taunt.
-- -- iTeamID - The team that the taunt should be removed from or nil for all teams.
-- --@return: true or false depending on success.
-- GM.Config.Taunts.Remove = function(sTauntName, iTeamID)
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Remove: Removing taunt '"..sTauntName.."'...") end
-- -- Safeguard against idiots.
-- if type(sTauntName) != "string" then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Remove: <sTauntName> is not a string.") end
-- return false
-- end
-- if (type(iTeamID) != "number" && iTeamID != nil) then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Remove: <iTeamID> is not a number or nil.") end
-- return false
-- end
-- -- if iTeamID is nil, both teams will have the taunt removed.
-- if (iTeamID == nil) then
-- GAMEMODE.Taunts.Seeker[sTauntName] = nil
-- GAMEMODE.Taunts.Hider[sTauntName] = nil
-- else
-- -- Make sure we have a valid Team.
-- if ! team.Valid(iTeamID) then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Remove: Team "..iTeamID.."' does not exist.") end
-- return false
-- end
-- if iTeamID == TEAM_SEEKERS then
-- GAMEMODE.Taunts.Seeker[sTauntName] = nil
-- elseif iTeamID == TEAM_HIDERS then
-- GAMEMODE.Taunts.Hider[sTauntName] = nil
-- else
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Remove: Team "..iTeamID.."' can't have taunts.") end
-- return false
-- end
-- end
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Remove: Complete.") end
-- return true
-- end
-- -- ToDo: Taunts.Get(iTeamID, sPropName)
-- --! Announcers (Round Start, Unblind, Win, Loss)
-- GM.Config.Announcers = {
-- Start = { },
-- Unblind = { },
-- Win = { },
-- Loss = { }
-- }
-- -- Announcers.Clear()
-- --@desc: Clears the current announcer list.
-- GM.Config.Announcers.Clear = function()
-- Announcers.Start = { }
-- Announcers.Unblind = { }
-- Announcers.Win = { }
-- Announcers.Loss = { }
-- end
-- -- Announcers.Load(sAnnouncerListFile)
-- --@desc: Tries to load the given announcer list.
-- --@param:
-- -- sAnnouncerListFile - A string containing the path to the announcer list to load.
-- --@return: true or false depending on success.
-- GM.Config.Announcers.Load = function(sAnnouncerListFile)
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: Loading announcer list from file '"..sAnnouncerListFile.."'...") end
-- -- Safeguard against idiots.
-- if type(sAnnouncerListFile) != "string" then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: <sAnnouncerListFile> is not a string.") end
-- return false
-- end
-- -- Given file must exist for us to continue.
-- if ! file.Exists(sAnnouncerListFile, "GAME") then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: File not found.") end
-- return false
-- end
-- -- Read the file and check if it's empty.
-- sAnnouncerListData = file.Read(sAnnouncerListFile, "GAME")
-- if sAnnouncerListData == "" then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: File is empty.") end
-- return false
-- end
-- -- Convert JSON to a table for us to use.
-- sAnnouncerList = util.JSONToTable(sAnnouncerListData)
-- -- Is it nil? Then it's not valid JSON
-- if sAnnouncerList == nil then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: File contains invalid JSON.") end
-- return false
-- end
-- -- Finally, insert the announcer lists.
-- if sAnnouncerList.Start != nil then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: Adding Start announcers...") end
-- for k,v in pairs(sAnnouncerList.Start) do
-- GAMEMODE.Announcers.Start[k] = v
-- end
-- end
-- if sAnnouncerList.Unblind != nil then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: Adding Unblind announcers...") end
-- for k,v in pairs(sAnnouncerList.Unblind) do
-- GAMEMODE.Announcers.Unblind[k] = v
-- end
-- end
-- if sAnnouncerList.Win != nil then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: Adding Win announcers...") end
-- for k,v in pairs(sAnnouncerList.Win) do
-- GAMEMODE.Announcers.Win[k] = v
-- end
-- end
-- if sAnnouncerList.Loss != nil then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: Adding Loss announcers...") end
-- for k,v in pairs(sAnnouncerList.Loss) do
-- GAMEMODE.Announcers.Loss[k] = v
-- end
-- end
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: Complete.") end
-- return true
-- end
-- -- Announcers.Save(sAnnouncerListFile)
-- --@desc: Saves the current taunt list to disk.
-- --@param:
-- -- sAnnouncerListFile - A string containing the path to the file to save to.
-- --@return: true or false depending on success.
-- GM.Config.Announcers.Save = function(sAnnouncerListFile)
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Save: Saving announcer list to file '"..sAnnouncerListFile.."'...") end
-- -- Safeguard against idiots.
-- if type(sAnnouncerListFile) != "string" then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Save: <sAnnouncerListFile> is not a string.") end
-- return false
-- end
-- -- File must not be nil, otherwise we can't write to it.
-- if sAnnouncerListFile == nil then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Save: No file given.") end
-- return false
-- end
-- -- Convert our taunt table to JSON.
-- sAnnouncerListData = util.TableToJSON(GAMEMODE.Announcers);
-- if sAnnouncerListData == nil then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Save: Corrupted GAMEMODE table.") end
-- return false
-- end
-- -- Write out JSON out to file
-- if ! file.Write(sAnnouncerListFile, sAnnouncerListData) then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Save: Failed to write to file.") end
-- return false
-- end
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Save: Complete.") end
-- return true
-- end
-- -- ToDo: Announcers.Add
-- -- ToDo: Announcers.Remove
-- -- ToDo: Announcers.Get(iType)
@@ -0,0 +1,63 @@
--[[
The MIT License (MIT)
Copyright (c) 2015 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
GM.RoundManager = {}
GM.RoundManager.State = nil;
GM.RoundManager.NextState = nil;
function GM.RoundManager:Tick(...)
if (self.State != nil) then
if (self.State.Tick != nil) then
self.State:Tick(...)
end
end
-- Advance States
if (self.NextState != self.State) then
-- Call OnLeave(NewState)
if (self.State != nil) then
if (self.State.OnLeave != nil) then
self.State:OnLeave(self.NextState)
end
end
-- Call OnEnter(OldState)
if (self.NextState != nil) then
if (self.NextState.OnEnter != nil) then
self.NextState:OnEnter(self.State)
end
end
-- Set State
self.State = self.NextState
end
end
function GM.RoundManager:GetState()
return self.State
end
function GM.RoundManager:SetState(State)
self.NextState = State
end
@@ -0,0 +1,61 @@
--[[
The MIT License (MIT)
Copyright (c) 2015 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
StateHide = {}
function StateHide:OnEnter(OldState)
if GAMEMODE.Config:Debug() then print("StateHide: OnEnter") end
GAMEMODE:SetRoundState(GAMEMODE.States.Hide)
-- Round Data
GAMEMODE.Data.RoundTime = math.abs(GAMEMODE.Config.Round:BlindTime())
GAMEMODE.Data.RoundStartTime = CurTime()
SetGlobalInt("RoundTime", GAMEMODE.Data.RoundTime)
-- Freeze Seekers
for i, ply in ipairs(team.GetPlayers(GAMEMODE.Teams.Seekers)) do
ply:Freeze(true)
ply:Lock()
end
end
function StateHide:Tick()
-- Update Game Time
GAMEMODE.Data.RoundTime = math.abs(GAMEMODE.Config.Round:BlindTime()) - (CurTime() - GAMEMODE.Data.RoundStartTime)
SetGlobalInt("RoundTime", math.ceil(GAMEMODE.Data.RoundTime))
-- Advance to Seeking State
if (GAMEMODE.Data.RoundTime <= 0) then
if GAMEMODE.Config:Debug() then print("StateHide: Advancing to Seek stage.") end
GAMEMODE.RoundManager:SetState(StateSeek)
end
-- ToDo: Logic for more game modes here?
end
function StateHide:OnLeave(NewState)
if GAMEMODE.Config:Debug() then print("StateHide: OnLeave") end
end
@@ -0,0 +1,39 @@
--[[
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
@@ -0,0 +1,55 @@
--[[
The MIT License (MIT)
Copyright (c) 2015 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
StatePostRound = {}
function StatePostRound:OnEnter(OldState)
if GAMEMODE.Config:Debug() then print("StatePostRound: OnEnter") end
GAMEMODE:SetRoundState(GAMEMODE.States.PostRound)
end
function StatePostRound:Tick()
-- Advance State
GAMEMODE.RoundManager:SetState(StatePreRound) -- Test: Reset to Hide
end
function StatePostRound:OnLeave(NewState)
if GAMEMODE.Config:Debug() then print("StatePostRound: OnLeave") end
-- Game Mode: Basic
if (GAMEMODE.Config:GameMode() == GAMEMODE.Modes.Original) then
-- Swap Teams
local hiders, seekers = team.GetPlayers(GAMEMODE.Teams.Hiders), team.GetPlayers(GAMEMODE.Teams.Seekers)
for i, ply in ipairs(hiders) do
ply:SetTeam(GAMEMODE.Teams.Seekers)
player_manager.SetPlayerClass(ply, "Seeker")
end
for i, ply in ipairs(seekers) do
ply:SetTeam(GAMEMODE.Teams.Hiders)
player_manager.SetPlayerClass(ply, "Hider")
end
-- TODO: Other Gamemodes
end
end
@@ -0,0 +1,54 @@
--[[
The MIT License (MIT)
Copyright (c) 2015 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
-- Precache Network Message
StatePreMatch = {}
function StatePreMatch:OnEnter(OldState)
if GAMEMODE.Config:Debug() then print("StatePreMatch: OnEnter") end
GAMEMODE:SetRoundState(GAMEMODE.States.PreMatch)
SetGlobalInt("Round", GetGlobalInt("Round", 0) + 1)
end
function StatePreMatch:Tick()
-- Debug: Auto Advance to PreRound State
if (GAMEMODE.Config:Debug()) then
print("StatePreMatch: Advancing to StatePreRound")
GAMEMODE.RoundManager:SetState(StatePreRound)
end
-- Game Mode: Basic
if (GAMEMODE.Config:GameMode() == GAMEMODE.Modes.Original) then
-- Both Teams must have at least 1 player.
if ((team.NumPlayers(GAMEMODE.Teams.Seekers) >= 1) && (team.NumPlayers(GAMEMODE.Teams.Hiders) >= 1)) then
GAMEMODE.RoundManager:SetState(StatePreRound)
end
-- TODO: Other Gamemodes
end
end
function StatePreMatch:OnLeave(NewState)
if GAMEMODE.Config:Debug() then print("StatePreMatch: OnLeave") end
end
@@ -0,0 +1,52 @@
--[[
The MIT License (MIT)
Copyright (c) 2015 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
StatePreRound = {}
function StatePreRound:OnEnter(OldState)
if GAMEMODE.Config:Debug() then print("StatePreRound: OnEnter") end
GAMEMODE:SetRoundState(GAMEMODE.States.PreRound)
-- Clean Up the Map
game.CleanUpMap()
end
function StatePreRound:Tick()
-- Advance State
GAMEMODE.RoundManager:SetState(StateHide)
end
function StatePreRound:OnLeave(NewState)
if GAMEMODE.Config:Debug() then print("StatePreRound: OnLeave") end
-- Game Mode: Basic
if (GAMEMODE.Config:GameMode() == GAMEMODE.Modes.Original) then
-- Respawn Everyone
for i, ply in ipairs(player.GetAll()) do
ply:KillSilent()
ply.Data.Alive = true
ply:Spawn()
end
-- TODO: Other Gamemodes
end
end
@@ -0,0 +1,83 @@
--[[
The MIT License (MIT)
Copyright (c) 2015 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
StateSeek = {}
function StateSeek:OnEnter(OldState)
if GAMEMODE.Config:Debug() then print("StateSeek: OnEnter") end
GAMEMODE:SetRoundState(GAMEMODE.States.Seek)
-- Round Data
GAMEMODE.Data.RoundTime = GAMEMODE.Config.Round:Time()
-- Unfreeze Seekers
for i, ply in ipairs(team.GetPlayers(GAMEMODE.Teams.Seekers)) do
ply:Freeze(false)
ply:UnLock()
end
end
function StateSeek:Tick()
-- Update Game Time
GAMEMODE.Data.RoundTime = GAMEMODE.Config.Round:Time() - (CurTime() - GAMEMODE.Data.RoundStartTime)
SetGlobalInt("RoundTime", math.ceil(GAMEMODE.Data.RoundTime))
-- Conditions for moving to the next State
if (GAMEMODE.Data.RoundTime <= 0) then -- No Time remaining
GAMEMODE.Data.Winner = GAMEMODE.Teams.Hiders
GAMEMODE.RoundManager:SetState(StatePostRound)
end
-- Condition: No Seekers / Hiders alive.
local hiders, seekers = team.GetPlayers(GAMEMODE.Teams.Hiders), team.GetPlayers(GAMEMODE.Teams.Seekers)
local hiderAlive, seekerAlive = false, false
for i,ply in ipairs(hiders) do
if (ply.Data.Alive) then
hiderAlive = true
end
end
for i,ply in ipairs(seekers) do
if (ply.Data.Alive) then
seekerAlive = true
end
end
if (hiderAlive == false) then
if (seekerAlive == false) then
GAMEMODE.Data.Winner = GAMEMODE.Teams.Spectators -- Shows as Draw
GAMEMODE.RoundManager:SetState(StatePostRound)
else
GAMEMODE.Data.Winner = GAMEMODE.Teams.Seekers
GAMEMODE.RoundManager:SetState(StatePostRound)
end
else
if (seekerAlive == false) then
GAMEMODE.Data.Winner = GAMEMODE.Teams.Hiders
GAMEMODE.RoundManager:SetState(StatePostRound)
end
end
end
function StateSeek:OnLeave(NewState)
if GAMEMODE.Config:Debug() then print("StateSeek: OnLeave") end
end
@@ -0,0 +1,294 @@
-- Sounds played by members of the losing team at the end of the round.
LOSS_SOUNDS = {
"bot/aw_hell.wav",
"bot/aww_man.wav",
"bot/anyone_see_anything.wav",
"bot/anyone_see_them.wav",
"bot/come_out_and_fight_like_a_man.wav",
"bot/come_out_wherever_you_are.wav",
"bot/he_got_away.wav",
"bot/he_got_away2.wav",
"bot/i_dont_know_where_he_went.wav",
"bot/i_got_nothing.wav",
"bot/nothing_happening_over_here.wav",
"bot/nothing_here.wav",
"bot/nothing_moving_over_here.wav",
"bot/thats_not_good.wav",
"bot/theres_too_many.wav",
"bot/theres_too_many_of_them.wav",
"bot/theyre_all_over_the_place2.wav",
"bot/theyre_everywhere2.wav",
"bot/too_many2.wav",
"bot/what_happened.wav",
"bot/what_have_you_done.wav",
"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",
"bot/come_to_papa.wav",
"bot/do_not_mess_with_me.wav",
"bot/dropped_him.wav",
"bot/enemy_down.wav",
"bot/enemy_down2.wav",
"bot/good_job_team.wav",
"bot/got_him.wav",
"bot/hes_broken.wav",
"bot/hes_dead.wav",
"bot/hes_done.wav",
"bot/hes_down.wav",
"bot/its_a_party.wav",
"bot/i_am_dangerous.wav",
"bot/i_am_on_fire.wav",
"bot/i_got_more_where_that_came_from.wav",
"bot/i_wasnt_worried_for_a_minute.wav",
"bot/killed_him.wav",
"bot/look_out_brag.wav",
"bot/made_him_cry.wav",
"bot/oh_yea.wav",
"bot/oh_yea2.wav",
"bot/owned.wav",
"bot/ruined_his_day.wav",
"bot/tag_them_and_bag_them.wav",
"bot/thats_the_way_this_is_done.wav",
"bot/that_was_a_close_one.wav",
"bot/that_was_it.wav",
"bot/that_was_the_last_guy.wav",
"bot/that_was_the_last_one.wav",
"bot/they_never_knew_what_hit_them.wav",
"bot/they_will_not_escape.wav",
"bot/they_wont_get_away.wav",
"bot/they_wont_get_away2.wav",
"bot/this_is_my_house.wav",
"bot/took_him_down.wav",
"bot/took_him_out.wav",
"bot/took_him_out2.wav",
"bot/wasted_him.wav",
"bot/way_to_be_team.wav",
"bot/well_done.wav",
"bot/we_owned_them.wav",
"bot/whew_that_was_close.wav",
"bot/whoo.wav",
"bot/whoo2.wav",
"bot/whos_the_man.wav",
"bot/who_wants_some_more.wav",
"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",
"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"
}
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",
"ambient/alarms/apc_alarm_pass1.wav",
-- "ambient/alarms/citadel_alert_loop2.wav",
-- "ambient/alarms/city_firebell_loop1.wav",
-- "ambient/alarms/city_siren_loop2.wav",
-- "ambient/alarms/combine_bank_alarm_loop1.wav",
-- "ambient/alarms/combine_bank_alarm_loop4.wav",
-- "ambient/alarms/klaxon1.wav",
"ambient/alarms/manhack_alert_pass1.wav",
"ambient/alarms/razortrain_horn1.wav",
"ambient/alarms/scanner_alert_pass1.wav",
-- "ambient/alarms/siren.wav",
-- "ambient/alarms/train_crossing_bell_loop1.wav",
"ambient/alarms/train_horn2.wav",
"ambient/alarms/train_horn_distant1.wav",
"ambient/alarms/warningbell1.wav",
-- "ambient/chatter/cb_radio_chatter_1.wav",
-- "ambient/chatter/cb_radio_chatter_2.wav",
-- "ambient/chatter/cb_radio_chatter_3.wav",
"ambient/energy/whiteflash.wav",
"ambient/intro/alyxremove.wav",
"ambient/intro/logosfx.wav",
-- "ambient/levels/labs/teleport_alarm_loop1.wav",
"ambient/levels/launch/1stfiringwarning.wav",
"ambient/levels/launch/rockettakeoffblast.wav",
-- "ambient/levels/outland/basealarmloop.wav",
-- "ambient/machines/60hzhum.wav",
"ambient/misc/ambulance1.wav",
"ambient/misc/carhonk1.wav",
"ambient/misc/carhonk2.wav",
"ambient/misc/carhonk3.wav",
-- "ambient/music/bongo.wav",
-- "ambient/music/country_rock_am_radio_loop.wav",
-- "ambient/music/cubanmusic1.wav",
-- "ambient/music/dustmusic1.wav",
-- "ambient/music/dustmusic2.wav",
-- "ambient/music/dustmusic3.wav",
-- "ambient/music/flamenco.wav",
-- "ambient/music/latin.wav",
-- "ambient/music/mirame_radio_thru_wall.wav",
-- "ambient/music/piano1.wav",
-- "ambient/music/piano2.wav",
"ambient/outro/gunshipcrash.wav",
"ambient/3dmeagle.wav",
-- "ambient/guit1.wav",
-- "ambient/opera.wav",
-- "ambient/sheep.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",
-- "test/temp/soundscape_test/tv_music.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"
}
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
@@ -0,0 +1,130 @@
--[[
The MIT License (MIT)
Copyright (c) 2015 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
-- ------------------------------------------------------------------------- --
--! Gamemode Information
-- ------------------------------------------------------------------------- --
GM.Name = "Prop Hunt Extended"
GM.Author = "Michael 'Xaymar' Dirks (Based on Kow@lskis Version, Original by AMT)"
GM.Email = "michael.fabian.dirks@gmail.com"
GM.Website = "http://xaymar.com/"
GM.TeamBased = true
GM.AllowAutoTeam = true
GM.SecondsBetweenTeamSwitches = 10
-- ------------------------------------------------------------------------- --
--! Includes
-- ------------------------------------------------------------------------- --
-- Player Classes
include "player_class/class_default.lua"
include "player_class/class_spectator.lua"
include "player_class/class_seeker.lua"
include "player_class/class_hider.lua"
-- ------------------------------------------------------------------------- --
--! Code
-- ------------------------------------------------------------------------- --
-- Game States
GM.States = {}
GM.States.PreMatch = 0
GM.States.PreRound = 1
GM.States.Hide = 2
GM.States.Seek = 3
GM.States.PostRound = 4
GM.States.PostMatch = 5
-- Game Modes
GM.Modes = {}
GM.Modes.Original = 0
GM.Modes.SwizzleEffect = 1 -- Randomizes Teams each Round
GM.Modes.TheDeadHunt = 2 -- One Hunter, Dead Prop become Hunter, Props can't see each other.
-- Teams
GM.Teams = {}
GM.Teams.Spectators = 0
GM.Teams.Seekers = 1
GM.Teams.Hiders = 2
function GM:CreateTeams()
-- Specators
team.SetUp(self.Teams.Spectators, "Spectators", Color(127, 127, 127, 255))
team.SetSpawnPoint(self.Teams.Spectators, {
"info_player_deathmatch",
"info_player_axis",
"info_player_combine",
"info_player_counterterrorist",
"info_player_allies",
"info_player_terrorist"
})
team.SetClass(self.Teams.Spectators, { "Spectator", "Spectator" })
-- Seekers: "Hunters"
team.SetUp(self.Teams.Seekers, "Seekers", Color(0, 128, 255, 255))
team.SetSpawnPoint(self.Teams.Seekers, {
"info_player_spawn",
"info_player_deathmatch",
"info_player_axis",
"info_player_combine",
"info_player_counterterrorist"
})
team.SetClass(self.Teams.Seekers, { "Seeker", "Spectator" })
-- Hiders: "Props"
team.SetUp(self.Teams.Hiders, "Hiders", Color(255, 128, 0, 255))
team.SetSpawnPoint(self.Teams.Hiders, {
"info_player_spawn",
"info_player_deathmatch",
"info_player_allies",
"info_player_terrorist"
})
team.SetClass(self.Teams.Hiders, { "Hider", "Spectator" })
end
-- ------------------------------------------------------------------------- --
--! Player Manager Binding
-- ------------------------------------------------------------------------- --
function GM:PlayerPostThink(ply)
return player_manager.RunClass(ply, "PostThink")
end
function GM:PlayerTick(ply, mv)
return player_manager.RunClass(ply, "Tick", mv)
end
function GM:PlayerHurt(victim, attacker, healthRemaining, damageTaken)
if (victim != nil && victim:IsPlayer()) then
player_manager.RunClass(victim, "Hurt", victim, attacker, healthRemaining, damageTaken)
end
if (attacker != nil && attacker:IsPlayer()) then
player_manager.RunClass(attacker, "Damage", victim, attacker, healthRemaining, damageTaken)
end
end
-- ------------------------------------------------------------------------- --
--! Gamemode Functionality
-- ------------------------------------------------------------------------- --
function GM:GetRoundState()
return GetGlobalInt("RoundState", self.States.PreMatch)
end
@@ -0,0 +1,49 @@
-- 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.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

@@ -0,0 +1,182 @@
"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""
}
}
}